cell = nvmem_cell_get(dev, cname); if (IS_ERR(cell)) return ERR_CAST(cell);
ret = nvmem_cell_read(cell, &data);
nvmem_cell_put(cell);
return ret;
}
int tsens_read_calibration(struct tsens_priv *priv, int shift, u32 *p1, u32 *p2, bool backup)
{
u32 mode;
u32 base1, base2; char name[] = "sXX_pY_backup"; /* s10_p1_backup */ int i, ret;
if (priv->num_sensors > MAX_SENSORS) return -EINVAL;
ret = snprintf(name, sizeof(name), "mode%s", backup ? "_backup" : ""); if (ret < 0) return ret;
ret = nvmem_cell_read_variable_le_u32(priv->dev, name, &mode); if (ret == -ENOENT)
dev_warn(priv->dev, "Please migrate to separate nvmem cells for calibration data\n"); if (ret < 0) return ret;
dev_dbg(priv->dev, "calibration mode is %d\n", mode);
ret = snprintf(name, sizeof(name), "base1%s", backup ? "_backup" : ""); if (ret < 0) return ret;
ret = nvmem_cell_read_variable_le_u32(priv->dev, name, &base1); if (ret < 0) return ret;
ret = snprintf(name, sizeof(name), "base2%s", backup ? "_backup" : ""); if (ret < 0) return ret;
ret = nvmem_cell_read_variable_le_u32(priv->dev, name, &base2); if (ret < 0) return ret;
for (i = 0; i < priv->num_sensors; i++) {
ret = snprintf(name, sizeof(name), "s%d_p1%s", priv->sensor[i].hw_id,
backup ? "_backup" : ""); if (ret < 0) return ret;
ret = nvmem_cell_read_variable_le_u32(priv->dev, name, &p1[i]); if (ret) return ret;
ret = snprintf(name, sizeof(name), "s%d_p2%s", priv->sensor[i].hw_id,
backup ? "_backup" : ""); if (ret < 0) return ret;
ret = nvmem_cell_read_variable_le_u32(priv->dev, name, &p2[i]); if (ret) return ret;
}
switch (mode) { case ONE_PT_CALIB: for (i = 0; i < priv->num_sensors; i++)
p1[i] = p1[i] + (base1 << shift); break; case TWO_PT_CALIB: case TWO_PT_CALIB_NO_OFFSET: for (i = 0; i < priv->num_sensors; i++)
p2[i] = (p2[i] + base2) << shift;
fallthrough; case ONE_PT_CALIB2: case ONE_PT_CALIB2_NO_OFFSET: for (i = 0; i < priv->num_sensors; i++)
p1[i] = (p1[i] + base1) << shift; break; default:
dev_dbg(priv->dev, "calibrationless mode\n"); for (i = 0; i < priv->num_sensors; i++) {
p1[i] = 500;
p2[i] = 780;
}
}
/* Apply calibration offset workaround except for _NO_OFFSET modes */ switch (mode) { case TWO_PT_CALIB: for (i = 0; i < priv->num_sensors; i++)
p2[i] += priv->sensor[i].p2_calib_offset;
fallthrough; case ONE_PT_CALIB2: for (i = 0; i < priv->num_sensors; i++)
p1[i] += priv->sensor[i].p1_calib_offset; break;
}
return mode;
}
int tsens_calibrate_nvmem(struct tsens_priv *priv, int shift)
{
u32 p1[MAX_SENSORS], p2[MAX_SENSORS]; int mode;
ret = regmap_field_read(priv->rf[UPPER_STATUS_0 + hw_id], &d->up_viol); if (ret) return ret;
ret = regmap_field_read(priv->rf[LOWER_STATUS_0 + hw_id], &d->low_viol); if (ret) return ret;
if (priv->feat->crit_int) {
ret = regmap_field_read(priv->rf[CRITICAL_STATUS_0 + hw_id],
&d->crit_viol); if (ret) return ret;
}
if (d->up_viol || d->low_viol || d->crit_viol) return1;
ret = regmap_field_read(priv->rf[UP_INT_CLEAR_0 + hw_id], &d->up_irq_clear); if (ret) return ret;
ret = regmap_field_read(priv->rf[LOW_INT_CLEAR_0 + hw_id], &d->low_irq_clear); if (ret) return ret; if (tsens_version(priv) >= VER_2_X) {
ret = regmap_field_read(priv->rf[UP_INT_MASK_0 + hw_id], &d->up_irq_mask); if (ret) return ret;
ret = regmap_field_read(priv->rf[LOW_INT_MASK_0 + hw_id], &d->low_irq_mask); if (ret) return ret;
ret = regmap_field_read(priv->rf[CRIT_INT_CLEAR_0 + hw_id],
&d->crit_irq_clear); if (ret) return ret;
ret = regmap_field_read(priv->rf[CRIT_INT_MASK_0 + hw_id],
&d->crit_irq_mask); if (ret) return ret;
if (tsens_version(priv) < VER_0_1) { /* Constraint: There is only 1 interrupt control register for all *11temperaturesensor.Somonitoringmorethan1sensorbased *oninterruptswillyieldinconsistentresult.Toovercomethis *issuewewillmonitoronlysensor0whichisthemastersensor.
*/ break;
}
}
int get_temp_tsens_valid(conststruct tsens_sensor *s, int *temp)
{ struct tsens_priv *priv = s->priv; int hw_id = s->hw_id;
u32 temp_idx = LAST_TEMP_0 + hw_id;
u32 valid_idx = VALID_0 + hw_id;
u32 valid; int ret;
/* VER_0 doesn't have VALID bit */ if (tsens_version(priv) == VER_0) goto get_temp;
/* Valid bit is 0 for 6 AHB clock cycles. *At19.2MHz,1AHBclockis~60ns. *Weshouldenterthisloopvery,veryrarely. *Wait1ussinceit'stheminofpoll_timeoutmacro. *Oldvaluewas400ns.
*/
ret = regmap_field_read_poll_timeout(priv->rf[valid_idx], valid,
valid, 1, 20 * USEC_PER_MSEC); if (ret) return ret;
get_temp: /* Valid bit is set, OK to read the temperature */
*temp = tsens_hw_to_mC(s, temp_idx);
return0;
}
int get_temp_common(conststruct tsens_sensor *s, int *temp)
{ struct tsens_priv *priv = s->priv; int hw_id = s->hw_id; int last_temp = 0, ret, trdy; unsignedlong timeout;
timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); do { if (tsens_version(priv) == VER_0) {
ret = regmap_field_read(priv->rf[TRDY], &trdy); if (ret) return ret; if (!trdy) continue;
}
ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); if (ret) return ret;
if (op->num_resources > 1) { /* DT with separate SROT and TM address space */
priv->tm_offset = 0;
res = platform_get_resource(op, IORESOURCE_MEM, 1);
srot_base = devm_ioremap_resource(dev, res); if (IS_ERR(srot_base)) {
ret = PTR_ERR(srot_base); goto err_put_device;
}
priv->srot_map = devm_regmap_init_mmio(dev, srot_base,
&tsens_srot_config); if (IS_ERR(priv->srot_map)) {
ret = PTR_ERR(priv->srot_map); goto err_put_device;
}
} else { /* old DTs where SROT and TM were in a contiguous 2K block */
priv->tm_offset = 0x1000;
}
if (tsens_version(priv) >= VER_0_1) {
res = platform_get_resource(op, IORESOURCE_MEM, 0);
tm_base = devm_ioremap_resource(dev, res); if (IS_ERR(tm_base)) {
ret = PTR_ERR(tm_base); goto err_put_device;
}
priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
} else { /* VER_0 share the same gcc regs using a syscon */ struct device *parent = priv->dev->parent;
if (parent)
priv->tm_map = syscon_node_to_regmap(parent->of_node);
}
if (IS_ERR_OR_NULL(priv->tm_map)) { if (!priv->tm_map)
ret = -ENODEV; else
ret = PTR_ERR(priv->tm_map); goto err_put_device;
}
/* VER_0 have only tm_map */ if (!priv->srot_map)
priv->srot_map = priv->tm_map;
if (tsens_version(priv) > VER_0_1) { for (i = VER_MAJOR; i <= VER_STEP; i++) {
priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map,
priv->fields[i]); if (IS_ERR(priv->rf[i])) {
ret = PTR_ERR(priv->rf[i]); goto err_put_device;
}
}
ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor); if (ret) goto err_put_device;
}
priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
priv->fields[TSENS_EN]); if (IS_ERR(priv->rf[TSENS_EN])) {
ret = PTR_ERR(priv->rf[TSENS_EN]); goto err_put_device;
} /* in VER_0 TSENS need to be explicitly enabled */ if (tsens_version(priv) == VER_0)
regmap_field_write(priv->rf[TSENS_EN], 1);
ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); if (ret) goto err_put_device; if (!enabled) { switch (tsens_version(priv)) { case VER_1_X_NO_RPM: case VER_2_X_NO_RPM: break; default:
dev_err(dev, "%s: device not enabled\n", __func__);
ret = -ENODEV; goto err_put_device;
}
}
priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
priv->fields[SENSOR_EN]); if (IS_ERR(priv->rf[SENSOR_EN])) {
ret = PTR_ERR(priv->rf[SENSOR_EN]); goto err_put_device;
}
priv->rf[INT_EN] = devm_regmap_field_alloc(dev, priv->tm_map,
priv->fields[INT_EN]); if (IS_ERR(priv->rf[INT_EN])) {
ret = PTR_ERR(priv->rf[INT_EN]); goto err_put_device;
}
priv->rf[TSENS_SW_RST] =
devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]); if (IS_ERR(priv->rf[TSENS_SW_RST])) {
ret = PTR_ERR(priv->rf[TSENS_SW_RST]); goto err_put_device;
}
priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]); if (IS_ERR(priv->rf[TRDY])) {
ret = PTR_ERR(priv->rf[TRDY]); goto err_put_device;
}
/* This loop might need changes if enum regfield_ids is reordered */ for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { for (i = 0; i < priv->feat->max_sensors; i++) { int idx = j + i;
priv->rf[idx] = devm_regmap_field_alloc(dev,
priv->tm_map,
priv->fields[idx]); if (IS_ERR(priv->rf[idx])) {
ret = PTR_ERR(priv->rf[idx]); goto err_put_device;
}
}
}
if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) { /* Loop might need changes if enum regfield_ids is reordered */ for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { for (i = 0; i < priv->feat->max_sensors; i++) { int idx = j + i;
priv->rf[idx] =
devm_regmap_field_alloc(dev,
priv->tm_map,
priv->fields[idx]); if (IS_ERR(priv->rf[idx])) {
ret = PTR_ERR(priv->rf[idx]); goto err_put_device;
}
}
}
}
if (tsens_version(priv) >= VER_2_X && ver_minor > 2) { /* Watchdog is present only on v2.3+ */
priv->feat->has_watchdog = 1; for (i = WDOG_BARK_STATUS; i <= CC_MON_MASK; i++) {
priv->rf[i] = devm_regmap_field_alloc(dev, priv->tm_map,
priv->fields[i]); if (IS_ERR(priv->rf[i])) {
ret = PTR_ERR(priv->rf[i]); goto err_put_device;
}
} /* *Watchdogisalreadyenabled,unmaskthebark. *Disablecyclecompletionmonitoring
*/
regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
regmap_field_write(priv->rf[CC_MON_MASK], 1);
}
spin_lock_init(&priv->ul_lock);
/* VER_0 interrupt doesn't need to be enabled */ if (tsens_version(priv) >= VER_0_1)
tsens_enable_irq(priv);
pdev = of_find_device_by_node(priv->dev->of_node); if (!pdev) return -ENODEV;
irq = platform_get_irq_byname(pdev, irqname); if (irq < 0) {
ret = irq; /* For old DTs with no IRQ defined */ if (irq == -ENXIO)
ret = 0;
} else { /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */ if (tsens_version(priv) == VER_0)
ret = devm_request_threaded_irq(&pdev->dev, irq,
thread_fn, NULL,
IRQF_TRIGGER_RISING,
dev_name(&pdev->dev),
priv); else
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
thread_fn, IRQF_ONESHOT,
dev_name(&pdev->dev),
priv);
if (ret)
dev_err(&pdev->dev, "%s: failed to get irq\n",
__func__); else
enable_irq_wake(irq);
}
int tsens_resume_common(struct tsens_priv *priv)
{ if (pm_suspend_target_state == PM_SUSPEND_MEM)
tsens_reinit(priv);
return0;
}
#endif/* !CONFIG_SUSPEND */
staticint tsens_register(struct tsens_priv *priv)
{ int i, ret; struct thermal_zone_device *tzd;
for (i = 0; i < priv->num_sensors; i++) {
priv->sensor[i].priv = priv;
tzd = devm_thermal_of_zone_register(priv->dev, priv->sensor[i].hw_id,
&priv->sensor[i],
&tsens_of_ops); if (IS_ERR(tzd)) continue;
priv->sensor[i].tzd = tzd; if (priv->ops->enable)
priv->ops->enable(priv, i);
devm_thermal_add_hwmon_sysfs(priv->dev, tzd);
}
/* VER_0 require to set MIN and MAX THRESH *These2regsaresetusingthe: *-CRIT_THRESH_0forMAXTHRESHhardcodedto120°C *-CRIT_THRESH_1forMINTHRESHhardcodedto0°C
*/ if (tsens_version(priv) < VER_0_1) {
regmap_field_write(priv->rf[CRIT_THRESH_0],
tsens_mC_to_hw(priv->sensor, 120000));
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.