static int omap_bandgap_force_single_read(struct omap_bandgap *bg_ptr, int id) { struct temp_sensor_registers *tsr; u32 temp = 0, counter = 1000; tsr = bg_ptr->conf->sensors[id].registers; /* Select single conversion mode */ if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG)) { temp = omap_bandgap_readl(bg_ptr, tsr->bgap_mode_ctrl); temp &= ~(1 << __ffs(tsr->mode_ctrl_mask)); omap_bandgap_writel(bg_ptr, temp, tsr->bgap_mode_ctrl); } /* Start of Conversion = 1 */ temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); temp |= 1 << __ffs(tsr->bgap_soc_mask); omap_bandgap_writel(bg_ptr, temp, tsr->temp_sensor_ctrl); /* Wait until DTEMP is updated */ temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); temp &= (tsr->bgap_dtemp_mask); while ((temp == 0) && --counter) { temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); temp &= (tsr->bgap_dtemp_mask); } /* Start of Conversion = 0 */ temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); temp &= ~(1 << __ffs(tsr->bgap_soc_mask)); omap_bandgap_writel(bg_ptr, temp, tsr->temp_sensor_ctrl); return 0; }
/* Talert masks. Call it only if HAS(TALERT) is set */ static int temp_sensor_unmask_interrupts(struct omap_bandgap *bg_ptr, int id, u32 t_hot, u32 t_cold) { struct temp_sensor_registers *tsr; u32 temp, reg_val; /* Read the current on die temperature */ tsr = bg_ptr->conf->sensors[id].registers; temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); temp &= tsr->bgap_dtemp_mask; reg_val = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl); if (temp < t_hot) reg_val |= tsr->mask_hot_mask; else reg_val &= ~tsr->mask_hot_mask; if (t_cold < temp) reg_val |= tsr->mask_cold_mask; else reg_val &= ~tsr->mask_cold_mask; omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_mask_ctrl); return 0; }
/* Talert Thot and Tcold thresholds. Call it only if HAS(TALERT) is set */ static int temp_sensor_init_talert_thresholds(struct omap_bandgap *bg_ptr, int id, int t_hot, int t_cold) { struct temp_sensor_registers *tsr; u32 reg_val, thresh_val; tsr = bg_ptr->conf->sensors[id].registers; thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold); /* write the new t_cold value */ reg_val = thresh_val & ~tsr->threshold_tcold_mask; reg_val |= (t_cold << __ffs(tsr->threshold_tcold_mask)); omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold); thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold); /* write the new t_hot value */ reg_val = thresh_val & ~tsr->threshold_thot_mask; reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)); omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold); reg_val = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl); reg_val |= tsr->mask_hot_mask; reg_val |= tsr->mask_cold_mask; omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_mask_ctrl); return 0; }
static int omap_bandgap_save_ctxt(struct omap_bandgap *bg_ptr) { int i; for (i = 0; i < bg_ptr->conf->sensor_count; i++) { struct temp_sensor_registers *tsr; struct temp_sensor_regval *rval; rval = &bg_ptr->conf->sensors[i].regval; tsr = bg_ptr->conf->sensors[i].registers; if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG)) rval->bg_mode_ctrl = omap_bandgap_readl(bg_ptr, tsr->bgap_mode_ctrl); if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER)) rval->bg_counter = omap_bandgap_readl(bg_ptr, tsr->bgap_counter); if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) { rval->bg_threshold = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold); rval->bg_ctrl = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl); } if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG)) rval->tshut_threshold = omap_bandgap_readl(bg_ptr, tsr->tshut_threshold); } return 0; }
static u32 omap_bandgap_read_temp(struct omap_bandgap *bg_ptr, int id) { struct temp_sensor_registers *tsr; u32 temp, ctrl, reg; tsr = bg_ptr->conf->sensors[id].registers; reg = tsr->temp_sensor_ctrl; if (OMAP_BANDGAP_HAS(bg_ptr, FREEZE_BIT)) { ctrl = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl); ctrl |= tsr->mask_freeze_mask; omap_bandgap_writel(bg_ptr, ctrl, tsr->bgap_mask_ctrl); /* * In case we cannot read from cur_dtemp / dtemp_0, * then we read from the last valid temp read */ reg = tsr->ctrl_dtemp_1; } /* read temperature */ temp = omap_bandgap_readl(bg_ptr, reg); temp &= tsr->bgap_dtemp_mask; if (OMAP_BANDGAP_HAS(bg_ptr, FREEZE_BIT)) { ctrl = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl); ctrl &= ~tsr->mask_freeze_mask; omap_bandgap_writel(bg_ptr, ctrl, tsr->bgap_mask_ctrl); } return temp; }
static int omap_bandgap_restore_ctxt(struct omap_bandgap *bg_ptr) { int i; u32 temp = 0; for (i = 0; i < bg_ptr->conf->sensor_count; i++) { struct temp_sensor_registers *tsr; struct temp_sensor_regval *rval; u32 val = 0; rval = &bg_ptr->conf->sensors[i].regval; tsr = bg_ptr->conf->sensors[i].registers; if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER)) val = omap_bandgap_readl(bg_ptr, tsr->bgap_counter); if (val == 0) { if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG)) omap_bandgap_writel(bg_ptr, rval->tshut_threshold, tsr->tshut_threshold); /* Force immediate temperature measurement and update * of the DTEMP field */ omap_bandgap_force_single_read(bg_ptr, i); if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER)) omap_bandgap_writel(bg_ptr, rval->bg_counter, tsr->bgap_counter); if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG)) omap_bandgap_writel(bg_ptr, rval->bg_mode_ctrl, tsr->bgap_mode_ctrl); if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) { omap_bandgap_writel(bg_ptr, rval->bg_threshold, tsr->bgap_threshold); omap_bandgap_writel(bg_ptr, rval->bg_ctrl, tsr->bgap_mask_ctrl); } } else { temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); temp &= (tsr->bgap_dtemp_mask); omap_bandgap_force_single_read(bg_ptr, i); if (temp == 0 && OMAP_BANDGAP_HAS(bg_ptr, TALERT)) { temp = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl); temp |= 1 << __ffs(tsr->mode_ctrl_mask); omap_bandgap_writel(bg_ptr, temp, tsr->bgap_mask_ctrl); } } } return 0; }
/* This is the Talert handler. Call it only if HAS(TALERT) is set */ static irqreturn_t talert_irq_handler(int irq, void *data) { struct omap_bandgap *bg_ptr = data; struct temp_sensor_registers *tsr; u32 t_hot = 0, t_cold = 0, temp, ctrl; int i; bg_ptr = data; /* Read the status of t_hot */ for (i = 0; i < bg_ptr->conf->sensor_count; i++) { tsr = bg_ptr->conf->sensors[i].registers; t_hot = omap_bandgap_readl(bg_ptr, tsr->bgap_status); t_hot &= tsr->status_hot_mask; /* Read the status of t_cold */ t_cold = omap_bandgap_readl(bg_ptr, tsr->bgap_status); t_cold &= tsr->status_cold_mask; if (!t_cold && !t_hot) continue; ctrl = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl); /* * One TALERT interrupt: Two sources * If the interrupt is due to t_hot then mask t_hot and * and unmask t_cold else mask t_cold and unmask t_hot */ if (t_hot) { ctrl &= ~tsr->mask_hot_mask; ctrl |= tsr->mask_cold_mask; } else if (t_cold) { ctrl &= ~tsr->mask_cold_mask; ctrl |= tsr->mask_hot_mask; } omap_bandgap_writel(bg_ptr, ctrl, tsr->bgap_mask_ctrl); dev_dbg(bg_ptr->dev, "%s: IRQ from %s sensor: hotevent %d coldevent %d\n", __func__, bg_ptr->conf->sensors[i].domain, t_hot, t_cold); /* read temperature */ temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); temp &= tsr->bgap_dtemp_mask; /* report temperature to whom may concern */ if (bg_ptr->conf->report_temperature) bg_ptr->conf->report_temperature(bg_ptr, i); } return IRQ_HANDLED; }
/** * omap_bandgap_read_update_interval() - read the sensor update interval * @bg_ptr - pointer to bandgap instance * @id - sensor id * @interval - resulting update interval in miliseconds * * returns 0 on success or the proper error code */ int omap_bandgap_read_update_interval(struct omap_bandgap *bg_ptr, int id, int *interval) { struct temp_sensor_registers *tsr; u32 time; int ret; ret = omap_bandgap_validate(bg_ptr, id); if (ret) return ret; if (!OMAP_BANDGAP_HAS(bg_ptr, COUNTER)) return -ENOTSUPP; tsr = bg_ptr->conf->sensors[id].registers; time = omap_bandgap_readl(bg_ptr, tsr->bgap_counter); if (ret) return ret; time = (time & tsr->counter_mask) >> __ffs(tsr->counter_mask); time = time * 1000 / bg_ptr->clk_rate; *interval = time; return 0; }
/** * omap_bandgap_read_tcold() - reads sensor current tcold * @bg_ptr - pointer to bandgap instance * @id - sensor id * @tcold - resulting current tcold value * * returns 0 on success or the proper error code */ int omap_bandgap_read_tcold(struct omap_bandgap *bg_ptr, int id, int *tcold) { struct temp_sensor_registers *tsr; u32 temp; int ret; ret = omap_bandgap_validate(bg_ptr, id); if (ret) return ret; if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT)) return -ENOTSUPP; tsr = bg_ptr->conf->sensors[id].registers; temp = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold); temp = (temp & tsr->threshold_tcold_mask) >> __ffs(tsr->threshold_tcold_mask); ret |= adc_to_temp_conversion(bg_ptr, id, temp, &temp); if (ret) return -EIO; *tcold = temp; return 0; }
/* Talert Thot threshold. Call it only if HAS(TALERT) is set */ static int temp_sensor_configure_thot(struct omap_bandgap *bg_ptr, int id, int t_hot) { struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[id].ts_data; struct temp_sensor_registers *tsr; u32 thresh_val, reg_val; int cold, err = 0; tsr = bg_ptr->conf->sensors[id].registers; /* obtain the T cold value */ thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold); cold = (thresh_val & tsr->threshold_tcold_mask) >> __ffs(tsr->threshold_tcold_mask); if (t_hot <= cold) { /* change the t_cold to t_hot - 5000 millidegrees */ err |= add_hyst(t_hot, -ts_data->hyst_val, bg_ptr, id, &cold); /* write the new t_cold value */ reg_val = thresh_val & (~tsr->threshold_tcold_mask); reg_val |= cold << __ffs(tsr->threshold_tcold_mask); omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold); thresh_val = reg_val; } /* write the new t_hot value */ reg_val = thresh_val & ~tsr->threshold_thot_mask; reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)); omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold); if (err) { dev_err(bg_ptr->dev, "failed to reprogram thot threshold\n"); return -EIO; } return temp_sensor_unmask_interrupts(bg_ptr, id, t_hot, cold); }
/* This is counter config. Call it only if HAS(COUNTER) is set */ static int configure_temp_sensor_counter(struct omap_bandgap *bg_ptr, int id, u32 counter) { struct temp_sensor_registers *tsr; u32 val; tsr = bg_ptr->conf->sensors[id].registers; val = omap_bandgap_readl(bg_ptr, tsr->bgap_counter); val &= ~tsr->counter_mask; val |= counter << __ffs(tsr->counter_mask); omap_bandgap_writel(bg_ptr, val, tsr->bgap_counter); return 0; }
/* This is Tshut Tcold config. Call it only if HAS(TSHUT_CONFIG) is set */ static int temp_sensor_configure_tshut_cold(struct omap_bandgap *bg_ptr, int id, int tshut_cold) { struct temp_sensor_registers *tsr; u32 reg_val; tsr = bg_ptr->conf->sensors[id].registers; reg_val = omap_bandgap_readl(bg_ptr, tsr->tshut_threshold); reg_val &= ~tsr->tshut_cold_mask; reg_val |= tshut_cold << __ffs(tsr->tshut_cold_mask); omap_bandgap_writel(bg_ptr, reg_val, tsr->tshut_threshold); return 0; }
/** * enable_continuous_mode() - One time enabling of continuous conversion mode * @bg_ptr - pointer to scm instance * * Call this function only if HAS(MODE_CONFIG) is set */ static int enable_continuous_mode(struct omap_bandgap *bg_ptr) { struct temp_sensor_registers *tsr; int i; u32 val; for (i = 0; i < bg_ptr->conf->sensor_count; i++) { /* Perform a single read just before enabling continuous */ omap_bandgap_force_single_read(bg_ptr, i); tsr = bg_ptr->conf->sensors[i].registers; val = omap_bandgap_readl(bg_ptr, tsr->bgap_mode_ctrl); val |= 1 << __ffs(tsr->mode_ctrl_mask); omap_bandgap_writel(bg_ptr, val, tsr->bgap_mode_ctrl); } return 0; }
static int omap_bandgap_power(struct omap_bandgap *bg_ptr, bool on) { struct temp_sensor_registers *tsr; int i; u32 ctrl; if (!OMAP_BANDGAP_HAS(bg_ptr, POWER_SWITCH)) return 0; for (i = 0; i < bg_ptr->conf->sensor_count; i++) { tsr = bg_ptr->conf->sensors[i].registers; ctrl = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); ctrl &= ~tsr->bgap_tempsoff_mask; /* active on 0 */ ctrl |= !on << __ffs(tsr->bgap_tempsoff_mask); /* write BGAP_TEMPSOFF should be reset to 0 */ omap_bandgap_writel(bg_ptr, ctrl, tsr->temp_sensor_ctrl); } return 0; }
/** * omap_bandgap_read_temperature() - report current temperature * @bg_ptr - pointer to bandgap instance * @id - sensor id * @temperature - resulting temperature * * returns 0 on success or the proper error code */ int omap_bandgap_read_temperature(struct omap_bandgap *bg_ptr, int id, int *temperature) { struct temp_sensor_registers *tsr; u32 temp; int ret; ret = omap_bandgap_validate(bg_ptr, id); if (ret) return ret; tsr = bg_ptr->conf->sensors[id].registers; temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl); temp &= tsr->bgap_dtemp_mask; ret |= adc_to_temp_conversion(bg_ptr, id, temp, &temp); if (ret) return -EIO; *temperature = temp; return 0; }
static int __devinit omap_bandgap_probe(struct platform_device *pdev) { struct omap_bandgap *bg_ptr; int clk_rate, ret = 0, i; bg_ptr = omap_bandgap_build(pdev); if (IS_ERR_OR_NULL(bg_ptr)) { dev_err(&pdev->dev, "failed to fetch platform data\n"); return PTR_ERR(bg_ptr); } bg_ptr->dev = &pdev->dev; if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) { ret = omap_bandgap_tshut_init(bg_ptr, pdev); if (ret) { dev_err(&pdev->dev, "failed to initialize system tshut IRQ\n"); return ret; } } bg_ptr->fclock = clk_get(NULL, bg_ptr->conf->fclock_name); ret = IS_ERR_OR_NULL(bg_ptr->fclock); if (ret) { dev_err(&pdev->dev, "failed to request fclock reference\n"); goto free_irqs; } bg_ptr->div_clk = clk_get(NULL, bg_ptr->conf->div_ck_name); ret = IS_ERR_OR_NULL(bg_ptr->div_clk); if (ret) { dev_err(&pdev->dev, "failed to request div_ts_ck clock ref\n"); goto free_irqs; } bg_ptr->conv_table = bg_ptr->conf->conv_table; for (i = 0; i < bg_ptr->conf->sensor_count; i++) { struct temp_sensor_registers *tsr; u32 val; tsr = bg_ptr->conf->sensors[i].registers; /* * check if the efuse has a non-zero value if not * it is an untrimmed sample and the temperatures * may not be accurate */ val = omap_bandgap_readl(bg_ptr, tsr->bgap_efuse); if (ret || !val) dev_info(&pdev->dev, "Non-trimmed BGAP, Temp not accurate\n"); } clk_rate = clk_round_rate(bg_ptr->div_clk, bg_ptr->conf->sensors[0].ts_data->max_freq); if (clk_rate < bg_ptr->conf->sensors[0].ts_data->min_freq || clk_rate == 0xffffffff) { ret = -ENODEV; dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate); goto put_clks; } ret = clk_set_rate(bg_ptr->div_clk, clk_rate); if (ret) dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n"); bg_ptr->clk_rate = clk_rate; clk_enable(bg_ptr->fclock); mutex_init(&bg_ptr->bg_mutex); bg_ptr->dev = &pdev->dev; platform_set_drvdata(pdev, bg_ptr); omap_bandgap_power(bg_ptr, true); /* Set default counter to 1 for now */ if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER)) for (i = 0; i < bg_ptr->conf->sensor_count; i++) configure_temp_sensor_counter(bg_ptr, i, 1); for (i = 0; i < bg_ptr->conf->sensor_count; i++) { struct temp_sensor_data *ts_data; ts_data = bg_ptr->conf->sensors[i].ts_data; if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) temp_sensor_init_talert_thresholds(bg_ptr, i, ts_data->t_hot, ts_data->t_cold); if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG)) { temp_sensor_configure_tshut_hot(bg_ptr, i, ts_data->tshut_hot); temp_sensor_configure_tshut_cold(bg_ptr, i, ts_data->tshut_cold); } } if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG)) enable_continuous_mode(bg_ptr); /* Set .250 seconds time as default counter */ if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER)) for (i = 0; i < bg_ptr->conf->sensor_count; i++) configure_temp_sensor_counter(bg_ptr, i, bg_ptr->clk_rate / 4); /* Every thing is good? Then expose the sensors */ for (i = 0; i < bg_ptr->conf->sensor_count; i++) { char *domain; if (bg_ptr->conf->sensors[i].register_cooling) bg_ptr->conf->sensors[i].register_cooling(bg_ptr, i); domain = bg_ptr->conf->sensors[i].domain; if (bg_ptr->conf->expose_sensor) bg_ptr->conf->expose_sensor(bg_ptr, i, domain); } /* * Enable the Interrupts once everything is set. Otherwise irq handler * might be called as soon as it is enabled where as rest of framework * is still getting initialised. */ if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) { ret = omap_bandgap_talert_init(bg_ptr, pdev); if (ret) { dev_err(&pdev->dev, "failed to initialize Talert IRQ\n"); i = bg_ptr->conf->sensor_count; goto disable_clk; } } return 0; disable_clk: clk_disable(bg_ptr->fclock); put_clks: clk_put(bg_ptr->fclock); clk_put(bg_ptr->div_clk); free_irqs: if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) { free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL); gpio_free(bg_ptr->tshut_gpio); } return ret; }