staticvoid init_table(int factors_size, int *table, const s64 *factors)
{ int i;
for (i = 0; i < TABLE_SIZE; i++)
table[i] = compute_value(i, factors, factors_size,
FACTORS_REDUCTION);
}
/** *structerr_values-structurecontainingerror/referencevalues *@refs:referenceerrorvaluesfor-40C,30C,125C&150C *@errs:Actualerrorvaluesfor-40C,30C,125C&150Creadfromtheefuse
*/ struct err_values { int refs[4]; int errs[4];
};
staticvoid create_table_segments(struct err_values *err_vals, int seg, int *ref_table)
{ int m = 0, c, num, den, i, err, idx1, idx2, err1, err2, ref1, ref2;
/* *Calculatetheslopewithadcvaluesreadfromtheregister *asthey-axisparamanderrinadcvalueasx-axisparam
*/
num = ref2 - ref1;
den = err2 - err1; if (den)
m = num / den;
c = ref2 - m * err2;
/* *Takecareofdividebyzeroerroriferrorvaluesaresame *Orwhentheslopeis0
*/ if (den != 0 && m != 0) { for (i = idx1; i <= idx2; i++) {
err = (i - c) / m; if (((i + err) < 0) || ((i + err) >= TABLE_SIZE)) continue;
derived_table[i] = ref_table[i + err];
}
} else { /* Constant error take care of divide by zero */ for (i = idx1; i <= idx2; i++) { if (((i + err1) < 0) || ((i + err1) >= TABLE_SIZE)) continue;
derived_table[i] = ref_table[i + err1];
}
}
}
staticint prep_lookup_table(struct err_values *err_vals, int *ref_table)
{ int inc, i, seg;
/* *Fillupthelookuptableunder3segments *region-40Cto+30C *region+30Cto+125C *region+125Cto+150C
*/ for (seg = 0; seg < 3; seg++)
create_table_segments(err_vals, seg, ref_table);
/* Get to the first valid temperature */
i = 0; while (!derived_table[i])
i++;
/* *Gettothelastzeroindexandbackfillthetemperaturefor *sakeofcontinuity
*/ if (i) { /* 300 milli celsius steps */ while (i--)
derived_table[i] = derived_table[i + 1] - 300;
}
/* *Fillthelasttrailing0swhichareunfilledwithincrementsof *100millicelsiustill1023code
*/
i = TABLE_SIZE - 1; while (!derived_table[i])
i--;
i++;
inc = 1; while (i < TABLE_SIZE) {
derived_table[i] = derived_table[i - 1] + inc * 100;
i++;
}
/* Get temperature callback function for thermal zone */ staticint k3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{ return k3_bgp_read_temp(thermal_zone_device_priv(tz), temp);
}
for (i = 0; i < 3; i++) { /* Extract the offset value using bit-mask */ if (ct_offsets[id][i] == -1 && i == 1) { /* 25C offset Case of Sensor 2 split between 2 regs */
tmp = (readl(fuse_base + 0x8) & 0xE0000000) >> (29);
tmp |= ((readl(fuse_base + 0xC) & 0x1F) << 3);
pow = tmp & 0x80;
} elseif (ct_offsets[id][i] == -1 && i == 2) { /* 125C Case of Sensor 3 split between 2 regs */
tmp = (readl(fuse_base + 0x4) & 0xF8000000) >> (27);
tmp |= ((readl(fuse_base + 0x8) & 0xF) << 5);
pow = tmp & 0x100;
} else {
tmp = readl(fuse_base + ct_offsets[id][i]);
tmp &= ct_bm[id][i];
tmp = tmp >> __ffs(ct_bm[id][i]);
/* Obtain the sign bit pow*/
pow = ct_bm[id][i] >> __ffs(ct_bm[id][i]);
pow += 1;
pow /= 2;
}
/* Check for negative value */ if (tmp & pow) { /* 2's complement value */
tmp = two_cmp(tmp, ct_bm[id][i] >> __ffs(ct_bm[id][i]));
}
err[i] = tmp;
}
/* Err value for 150C is set to 0 */
err[i] = 0;
}
staticvoid print_look_up_table(struct device *dev, int *ref_table)
{ int i;
dev_dbg(dev, "The contents of derived array\n");
dev_dbg(dev, "Code Temperature\n"); for (i = 0; i < TABLE_SIZE; i++)
dev_dbg(dev, "%d %d %d\n", i, derived_table[i], ref_table[i]);
}
bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL); if (!bgp) return -ENOMEM;
bgp->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bgp->base = devm_ioremap_resource(dev, res); if (IS_ERR(bgp->base)) return PTR_ERR(bgp->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
bgp->cfg2_base = devm_ioremap_resource(dev, res); if (IS_ERR(bgp->cfg2_base)) return PTR_ERR(bgp->cfg2_base);
driver_data = of_device_get_match_data(dev); if (driver_data)
workaround_needed = driver_data->has_errata_i2128;
/* *SomeofTI'sJ721ESoCsrequireasoftwaretrimmingprocedure *forthetemperaturemonitorstofunctionproperly.Todetermine *ifthisparticularSoCisNOTaffected,bothbitsinthe *WKUP_SPARE_FUSE0[31:30]willbeset(0xC0000000)indicating *whensoftwaretrimmingshouldNOTbeapplied. * *https://www.ti.com/lit/er/sprz455c/sprz455c.pdf
*/ if (workaround_needed) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
fuse_base = devm_ioremap_resource(dev, res); if (IS_ERR(fuse_base)) return PTR_ERR(fuse_base);
if ((readl(fuse_base) & 0xc0000000) == 0xc0000000)
workaround_needed = false;
}
dev_dbg(bgp->dev, "Work around %sneeded\n",
workaround_needed ? "" : "not ");
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev); if (ret < 0) {
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev); return ret;
}
/* Get the sensor count in the VTM */
val = readl(bgp->base + K3_VTM_DEVINFO_PWR0_OFFSET);
bgp->cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK;
bgp->cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK);
data = devm_kcalloc(bgp->dev, bgp->cnt, sizeof(*data), GFP_KERNEL); if (!data) {
ret = -ENOMEM; goto err_alloc;
}
ref_table = kcalloc(TABLE_SIZE, sizeof(*ref_table), GFP_KERNEL); if (!ref_table) {
ret = -ENOMEM; goto err_alloc;
}
derived_table = devm_kcalloc(bgp->dev, TABLE_SIZE, sizeof(*derived_table),
GFP_KERNEL); if (!derived_table) {
ret = -ENOMEM; goto err_free_ref_table;
}
if (!workaround_needed)
init_table(5, ref_table, golden_factors); else
init_table(3, ref_table, pvt_wa_factors);
/* Precompute the derived table & fill each thermal sensor struct */ for (id = 0; id < bgp->cnt; id++) {
data[id].bgp = bgp;
data[id].ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET + id * 0x20;
data[id].stat_offset = data[id].ctrl_offset +
K3_VTM_TMPSENS_STAT_OFFSET;
if (id == 0 && workaround_needed)
prep_lookup_table(&err_vals, ref_table); elseif (id == 0 && !workaround_needed)
memcpy(derived_table, ref_table, TABLE_SIZE * 4);
bgp->ts_data[id] = &data[id];
}
k3_j72xx_bandgap_init_hw(bgp);
/* Register the thermal sensors */ for (id = 0; id < bgp->cnt; id++) {
ti_thermal = devm_thermal_of_zone_register(bgp->dev, id, &data[id],
&k3_of_thermal_ops); if (IS_ERR(ti_thermal)) {
dev_err(bgp->dev, "thermal zone device is NULL\n");
ret = PTR_ERR(ti_thermal); goto err_free_ref_table;
}
}
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.