spin_lock(&bgp->lock); for (i = 0; i < bgp->conf->sensor_count; i++) {
tsr = bgp->conf->sensors[i].registers;
ctrl = ti_bandgap_readl(bgp, tsr->bgap_status);
/* Read the status of t_hot */
t_hot = ctrl & tsr->status_hot_mask;
/* Read the status of t_cold */
t_cold = ctrl & tsr->status_cold_mask;
/*** Helper functions which manipulate conversion ADC <-> mi Celsius ***/
/** *ti_bandgap_adc_to_mcelsius()-convertsanADCvaluetomCelsiusscale *@bgp:structti_bandgappointer *@adc_val:valueinADCrepresentation *@t:addresswheretowritetheresultingtemperatureinmCelsius * *SimpleconversionfromADCrepresentationtomCelsius.IncasetheADCvalue *isoutoftheADCconvtablerange,itreturns-ERANGE,0onsuccess. *TheconversiontableisindexedbytheADCvalues. * *Return:0ifconversionwassuccessful,else-ERANGEincasethe@adc_val *argumentisoutoftheADCconvtablerange.
*/ static int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t)
{ conststruct ti_bandgap_data *conf = bgp->conf;
/* look up for temperature in the table and return the temperature */ if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) return -ERANGE;
if ((id < 0) || (id >= bgp->conf->sensor_count)) {
dev_err(bgp->dev, "%s: sensor id out of range (%d)\n",
__func__, id); return -ERANGE;
}
return0;
}
/** *ti_bandgap_read_counter()-readthesensorcounter *@bgp:pointertobandgapinstance *@id:sensorid *@interval:resultingupdateintervalinmiliseconds
*/ staticvoid ti_bandgap_read_counter(struct ti_bandgap *bgp, int id, int *interval)
{ struct temp_sensor_registers *tsr; int time;
tsr = bgp->conf->sensors[id].registers;
time = ti_bandgap_readl(bgp, tsr->bgap_counter);
time = (time & tsr->counter_mask) >>
__ffs(tsr->counter_mask);
time = time * 1000 / bgp->clk_rate;
*interval = time;
}
/** *ti_bandgap_read_counter_delay()-readthesensorcounterdelay *@bgp:pointertobandgapinstance *@id:sensorid *@interval:resultingupdateintervalinmiliseconds
*/ staticvoid ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id, int *interval)
{ struct temp_sensor_registers *tsr; int reg_val;
/** *ti_bandgap_read_update_interval()-readthesensorupdateinterval *@bgp:pointertobandgapinstance *@id:sensorid *@interval:resultingupdateintervalinmiliseconds * *Return:0onsuccessorthepropererrorcode
*/ int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id, int *interval)
{ int ret = 0;
ret = ti_bandgap_validate(bgp, id); if (ret) gotoexit;
if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
!TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
ret = -ENOTSUPP; gotoexit;
}
if (TI_BANDGAP_HAS(bgp, COUNTER)) {
ti_bandgap_read_counter(bgp, id, interval); gotoexit;
}
/** *ti_bandgap_write_update_interval()-settheupdateinterval *@bgp:pointertobandgapinstance *@id:sensorid *@interval:desiredupdateintervalinmiliseconds * *Return:0onsuccessorthepropererrorcode
*/ int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, int id, u32 interval)
{ int ret = ti_bandgap_validate(bgp, id); if (ret) gotoexit;
if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
!TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
ret = -ENOTSUPP; gotoexit;
}
if (TI_BANDGAP_HAS(bgp, COUNTER)) {
ti_bandgap_write_counter(bgp, id, interval); gotoexit;
}
ret = ti_bandgap_write_counter_delay(bgp, id, interval); exit: return ret;
}
/** *ti_bandgap_read_temperature()-reportcurrenttemperature *@bgp:pointertobandgapinstance *@id:sensorid *@temperature:resultingtemperature * *Return:0onsuccessorthepropererrorcode
*/ int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id, int *temperature)
{
u32 temp; int ret;
ret = ti_bandgap_validate(bgp, id); if (ret) return ret;
if (!TI_BANDGAP_HAS(bgp, MODE_CONFIG)) {
ret = ti_bandgap_force_single_read(bgp, id); if (ret) return ret;
}
/* Select continuous or single conversion mode */ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) { if (TI_BANDGAP_HAS(bgp, CONT_MODE_ONLY))
RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 1); else
RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0);
}
/* Set Start of Conversion if available */ if (tsr->bgap_soc_mask) {
RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1);
/* Wait for EOCZ going up */
error = readl_poll_timeout_atomic(temp_sensor_ctrl, val,
val & tsr->bgap_eocz_mask, 1, 1000); if (error)
dev_warn(bgp->dev, "eocz timed out waiting high\n");
/* Clear Start of Conversion if available */
RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0);
}
/* Wait for EOCZ going down, always needed even if no bgap_soc_mask */
error = readl_poll_timeout_atomic(temp_sensor_ctrl, val,
!(val & tsr->bgap_eocz_mask), 1, 1500); if (error)
dev_warn(bgp->dev, "eocz timed out waiting low\n");
for (i = 0; i < bgp->conf->sensor_count; i++) { /* Perform a single read just before enabling continuous */
ti_bandgap_force_single_read(bgp, i);
RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1);
}
return0;
}
/** *ti_bandgap_get_trend()-Tofetchthetemperaturetrendofasensor *@bgp:pointertostructti_bandgap *@id:idoftheindividualsensor *@trend:Pointertotrend. * *Thisfunctionneedstobecalledtofetchthetemperaturetrendofa *Particularsensor.Thefunctioncomputesthedifferenceintemperature *w.r.ttime.Forthebandgapswithbuiltinhistorybufferthetemperatures *arereadfromthebufferandforthosewithouttheBuffer-ENOTSUPPis *returned. * *Return:0ifnoerror,elsereturncorrespondingerror.Ifno *errorthenthetrendvalueispassedontotrendparameter
*/ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
{ struct temp_sensor_registers *tsr;
u32 temp1, temp2, reg1, reg2; int t1, t2, interval, ret = 0;
ret = ti_bandgap_validate(bgp, id); if (ret) gotoexit;
if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) ||
!TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
ret = -ENOTSUPP; gotoexit;
}
spin_lock(&bgp->lock);
tsr = bgp->conf->sensors[id].registers;
/* Freeze and read the last 2 valid readings */
RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
reg1 = tsr->ctrl_dtemp_1;
reg2 = tsr->ctrl_dtemp_2;
/* read temperature from history buffer */
temp1 = ti_bandgap_readl(bgp, reg1);
temp1 &= tsr->bgap_dtemp_mask;
status = request_irq(gpiod_to_irq(bgp->tshut_gpiod),
ti_bandgap_tshut_irq_handler,
IRQF_TRIGGER_RISING, "tshut", NULL); if (status)
dev_err(bgp->dev, "request irq failed for TSHUT");
/* just for the sake */ if (!node) {
dev_err(&pdev->dev, "no platform information available\n"); return ERR_PTR(-EINVAL);
}
bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL); if (!bgp) return ERR_PTR(-ENOMEM);
of_id = of_match_device(of_ti_bandgap_match, &pdev->dev); if (of_id)
bgp->conf = of_id->data;
/* register shadow for context save and restore */
bgp->regval = devm_kcalloc(&pdev->dev, bgp->conf->sensor_count, sizeof(*bgp->regval), GFP_KERNEL); if (!bgp->regval) return ERR_PTR(-ENOMEM);
i = 0; do { void __iomem *chunk;
res = platform_get_resource(pdev, IORESOURCE_MEM, i); if (!res) break;
chunk = devm_ioremap_resource(&pdev->dev, res); if (i == 0)
bgp->base = chunk; if (IS_ERR(chunk)) return ERR_CAST(chunk);
i++;
} while (res);
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
bgp->tshut_gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN); if (IS_ERR(bgp->tshut_gpiod)) {
dev_err(&pdev->dev, "invalid gpio for tshut\n"); return ERR_CAST(bgp->tshut_gpiod);
}
}
static int ti_bandgap_probe(struct platform_device *pdev)
{ struct ti_bandgap *bgp; int clk_rate, ret, i;
bgp = ti_bandgap_build(pdev); if (IS_ERR(bgp)) {
dev_err(&pdev->dev, "failed to fetch platform data\n"); return PTR_ERR(bgp);
}
bgp->dev = &pdev->dev;
if (TI_BANDGAP_HAS(bgp, UNRELIABLE))
dev_warn(&pdev->dev, "This OMAP thermal sensor is unreliable. You've been warned\n");
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
ret = ti_bandgap_tshut_init(bgp, pdev); if (ret) {
dev_err(&pdev->dev, "failed to initialize system tshut IRQ\n"); return ret;
}
}
bgp->fclock = clk_get(NULL, bgp->conf->fclock_name); if (IS_ERR(bgp->fclock)) {
dev_err(&pdev->dev, "failed to request fclock reference\n");
ret = PTR_ERR(bgp->fclock); goto free_irqs;
}
bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name); if (IS_ERR(bgp->div_clk)) {
dev_err(&pdev->dev, "failed to request div_ts_ck clock ref\n");
ret = PTR_ERR(bgp->div_clk); goto put_fclock;
}
for (i = 0; i < bgp->conf->sensor_count; i++) { struct temp_sensor_registers *tsr;
u32 val;
tsr = bgp->conf->sensors[i].registers; /* *checkiftheefusehasanon-zerovalueifnot *itisanuntrimmedsampleandthetemperatures *maynotbeaccurate
*/
val = ti_bandgap_readl(bgp, tsr->bgap_efuse); if (!val)
dev_info(&pdev->dev, "Non-trimmed BGAP, Temp not accurate\n");
}
/* Set default counter to 1 for now */ if (TI_BANDGAP_HAS(bgp, COUNTER)) for (i = 0; i < bgp->conf->sensor_count; i++)
RMW_BITS(bgp, i, bgap_counter, counter_mask, 1);
/* Set default thresholds for alert and shutdown */ for (i = 0; i < bgp->conf->sensor_count; i++) { struct temp_sensor_data *ts_data;
ts_data = bgp->conf->sensors[i].ts_data;
if (TI_BANDGAP_HAS(bgp, TALERT)) { /* Set initial Talert thresholds */
RMW_BITS(bgp, i, bgap_threshold,
threshold_tcold_mask, ts_data->t_cold);
RMW_BITS(bgp, i, bgap_threshold,
threshold_thot_mask, ts_data->t_hot); /* Enable the alert events */
RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1);
RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1);
}
if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) { /* Set initial Tshut thresholds */
RMW_BITS(bgp, i, tshut_threshold,
tshut_hot_mask, ts_data->tshut_hot);
RMW_BITS(bgp, i, tshut_threshold,
tshut_cold_mask, ts_data->tshut_cold);
}
}
if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
ti_bandgap_set_continuous_mode(bgp);
/* Set .250 seconds time as default counter */ if (TI_BANDGAP_HAS(bgp, COUNTER)) for (i = 0; i < bgp->conf->sensor_count; i++)
RMW_BITS(bgp, i, bgap_counter, counter_mask,
bgp->clk_rate / 4);
/* Every thing is good? Then expose the sensors */ for (i = 0; i < bgp->conf->sensor_count; i++) { char *domain;
if (bgp->conf->sensors[i].register_cooling) {
ret = bgp->conf->sensors[i].register_cooling(bgp, i); if (ret) goto remove_sensors;
}
if (bgp->conf->expose_sensor) {
domain = bgp->conf->sensors[i].domain;
ret = bgp->conf->expose_sensor(bgp, i, domain); if (ret) goto remove_last_cooling;
}
}
/* *EnabletheInterruptsonceeverythingisset.Otherwiseirqhandler *mightbecalledassoonasitisenabledwhereasrestofframework *isstillgettinginitialised.
*/ if (TI_BANDGAP_HAS(bgp, TALERT)) {
ret = ti_bandgap_talert_init(bgp, pdev); if (ret) {
dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
i = bgp->conf->sensor_count; goto disable_clk;
}
}
#ifdef CONFIG_PM_SLEEP
bgp->nb.notifier_call = bandgap_omap_cpu_notifier; if (!soc_device_match(soc_no_cpu_notifier))
cpu_pm_register_notifier(&bgp->nb); #endif
return0;
remove_last_cooling: if (bgp->conf->sensors[i].unregister_cooling)
bgp->conf->sensors[i].unregister_cooling(bgp, i);
remove_sensors: for (i--; i >= 0; i--) { if (bgp->conf->sensors[i].unregister_cooling)
bgp->conf->sensors[i].unregister_cooling(bgp, i); if (bgp->conf->remove_sensor)
bgp->conf->remove_sensor(bgp, i);
}
ti_bandgap_power(bgp, false);
disable_clk: if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
clk_disable_unprepare(bgp->fclock);
put_clks:
clk_put(bgp->div_clk);
put_fclock:
clk_put(bgp->fclock);
free_irqs: if (TI_BANDGAP_HAS(bgp, TSHUT))
free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
if (!soc_device_match(soc_no_cpu_notifier))
cpu_pm_unregister_notifier(&bgp->nb);
/* Remove sensor interfaces */ for (i = 0; i < bgp->conf->sensor_count; i++) { if (bgp->conf->sensors[i].unregister_cooling)
bgp->conf->sensors[i].unregister_cooling(bgp, i);
if (bgp->conf->remove_sensor)
bgp->conf->remove_sensor(bgp, i);
}
ti_bandgap_power(bgp, false);
if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
clk_disable_unprepare(bgp->fclock);
clk_put(bgp->fclock);
clk_put(bgp->div_clk);
if (TI_BANDGAP_HAS(bgp, TALERT))
free_irq(bgp->irq, bgp);
if (TI_BANDGAP_HAS(bgp, TSHUT))
free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
}
#ifdef CONFIG_PM_SLEEP staticint ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
{ int i;
for (i = 0; i < bgp->conf->sensor_count; i++) { struct temp_sensor_registers *tsr; struct temp_sensor_regval *rval;
rval = &bgp->regval[i];
tsr = bgp->conf->sensors[i].registers;
if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
rval->bg_mode_ctrl = ti_bandgap_readl(bgp,
tsr->bgap_mode_ctrl); if (TI_BANDGAP_HAS(bgp, COUNTER))
rval->bg_counter = ti_bandgap_readl(bgp,
tsr->bgap_counter); if (TI_BANDGAP_HAS(bgp, TALERT)) {
rval->bg_threshold = ti_bandgap_readl(bgp,
tsr->bgap_threshold);
rval->bg_ctrl = ti_bandgap_readl(bgp,
tsr->bgap_mask_ctrl);
}
if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
rval->tshut_threshold = ti_bandgap_readl(bgp,
tsr->tshut_threshold);
}
return0;
}
staticint ti_bandgap_restore_ctxt(struct ti_bandgap *bgp)
{ int i;
for (i = 0; i < bgp->conf->sensor_count; i++) { struct temp_sensor_registers *tsr; struct temp_sensor_regval *rval;
rval = &bgp->regval[i];
tsr = bgp->conf->sensors[i].registers;
if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
ti_bandgap_writel(bgp, rval->tshut_threshold,
tsr->tshut_threshold); /* Force immediate temperature measurement and update *oftheDTEMPfield
*/
ti_bandgap_force_single_read(bgp, i);
if (TI_BANDGAP_HAS(bgp, COUNTER))
ti_bandgap_writel(bgp, rval->bg_counter,
tsr->bgap_counter); if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
ti_bandgap_writel(bgp, rval->bg_mode_ctrl,
tsr->bgap_mode_ctrl); if (TI_BANDGAP_HAS(bgp, TALERT)) {
ti_bandgap_writel(bgp, rval->bg_threshold,
tsr->bgap_threshold);
ti_bandgap_writel(bgp, rval->bg_ctrl,
tsr->bgap_mask_ctrl);
}
}
spin_lock(&bgp->lock); switch (cmd) { case CPU_CLUSTER_PM_ENTER: if (bgp->is_suspended) break;
ti_bandgap_save_ctxt(bgp);
ti_bandgap_power(bgp, false); if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
clk_disable(bgp->fclock); break; case CPU_CLUSTER_PM_ENTER_FAILED: case CPU_CLUSTER_PM_EXIT: if (bgp->is_suspended) break; if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
clk_enable(bgp->fclock);
ti_bandgap_power(bgp, true);
ti_bandgap_restore_ctxt(bgp); break;
}
spin_unlock(&bgp->lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.