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 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; }
/* 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); }
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; }
/* 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; }
static int omap_bandgap_restore_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; 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 (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); } } 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; }
/* 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; }