/* * On i.MX7D, we only use the calibration data at 25C to get the temp, * Tmeas = ( Nmeas - n1) + 25; n1 is the fuse value for 25C.
*/ if (data->socdata->version == TEMPMON_IMX7D) {
data->c1 = (ocotp_ana1 >> 9) & 0x1ff; return 0;
}
/* * The sensor is calibrated at 25 °C (aka T1) and the value measured * (aka N1) at this temperature is provided in bits [31:20] in the * i.MX's OCOTP value ANA1. * To find the actual temperature T, the following formula has to be used * when reading value n from the sensor: * * T = T1 + (N - N1) / (0.4148468 - 0.0015423 * N1) °C + 3.580661 °C * = [T1' - N1 / (0.4148468 - 0.0015423 * N1) °C] + N / (0.4148468 - 0.0015423 * N1) °C * = [T1' + N1 / (0.0015423 * N1 - 0.4148468) °C] - N / (0.0015423 * N1 - 0.4148468) °C * = c2 - c1 * N * * with * * T1' = 28.580661 °C * c1 = 1 / (0.0015423 * N1 - 0.4297157) °C * c2 = T1' + N1 / (0.0015423 * N1 - 0.4148468) °C * = T1' + N1 * c1
*/
n1 = ocotp_ana1 >> 20;
temp64 = 10000000; /* use 10^7 as fixed point constant for values in formula */
temp64 *= 1000; /* to get result in °mC */
do_div(temp64, 15423 * n1 - 4148468);
data->c1 = temp64;
data->c2 = n1 * data->c1 + 28581;
/* The maximum die temp is specified by the Temperature Grade */ switch ((ocotp_mem0 >> 6) & 0x3) { case 0: /* Commercial (0 to 95 °C) */
data->temp_grade = "Commercial";
data->temp_max = 95000; break; case 1: /* Extended Commercial (-20 °C to 105 °C) */
data->temp_grade = "Extended Commercial";
data->temp_max = 105000; break; case 2: /* Industrial (-40 °C to 105 °C) */
data->temp_grade = "Industrial";
data->temp_max = 105000; break; case 3: /* Automotive (-40 °C to 125 °C) */
data->temp_grade = "Automotive";
data->temp_max = 125000; break;
}
/* * Set the critical trip point at 5 °C under max * Set the passive trip point at 10 °C under max (changeable via sysfs)
*/
trips[IMX_TRIP_PASSIVE].temperature = data->temp_max - (1000 * 10);
trips[IMX_TRIP_CRITICAL].temperature = data->temp_max - (1000 * 5);
}
#ifdef CONFIG_CPU_FREQ /* * Create cooling device in case no #cooling-cells property is available in * CPU node
*/ staticint imx_thermal_register_legacy_cooling(struct imx_thermal_data *data)
{ struct device_node *np; int ret = 0;
data->policy = cpufreq_cpu_get(0); if (!data->policy) {
pr_debug("%s: CPUFreq policy not found\n", __func__); return -EPROBE_DEFER;
}
np = of_get_cpu_node(data->policy->cpu, NULL);
if (!np || !of_property_present(np, "#cooling-cells")) {
data->cdev = cpufreq_cooling_register(data->policy); if (IS_ERR(data->cdev)) {
ret = PTR_ERR(data->cdev);
cpufreq_cpu_put(data->policy);
}
}
staticint imx_thermal_probe(struct platform_device *pdev)
{ struct device *dev = &pdev->dev; struct imx_thermal_data *data; struct regmap *map; int measure_freq; int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;
data->dev = dev;
map = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,tempmon"); if (IS_ERR(map)) {
ret = PTR_ERR(map);
dev_err(dev, "failed to get tempmon regmap: %d\n", ret); return ret;
}
data->tempmon = map;
data->socdata = of_device_get_match_data(dev); if (!data->socdata) {
dev_err(dev, "no device match found\n"); return -ENODEV;
}
/* make sure the IRQ flag is clear before enabling irq on i.MX6SX */ if (data->socdata->version == TEMPMON_IMX6SX) {
regmap_write(map, IMX6_MISC1 + REG_CLR,
IMX6_MISC1_IRQ_TEMPHIGH | IMX6_MISC1_IRQ_TEMPLOW
| IMX6_MISC1_IRQ_TEMPPANIC); /* * reset value of LOW ALARM is incorrect, set it to lowest * value to avoid false trigger of low alarm.
*/
regmap_write(map, data->socdata->low_alarm_ctrl + REG_SET,
data->socdata->low_alarm_mask);
}
data->irq = platform_get_irq(pdev, 0); if (data->irq < 0) return data->irq;
platform_set_drvdata(pdev, data);
if (of_property_present(dev->of_node, "nvmem-cells")) {
ret = imx_init_from_nvmem_cells(pdev); if (ret) return dev_err_probe(dev, ret, "failed to init from nvmem\n");
} else {
ret = imx_init_from_tempmon_data(pdev); if (ret) {
dev_err(dev, "failed to init from fsl,tempmon-data\n"); return ret;
}
}
/* Make sure sensor is in known good state for measurements */
regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
data->socdata->power_down_mask);
regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
data->socdata->measure_temp_mask);
regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR,
data->socdata->measure_freq_mask); if (data->socdata->version != TEMPMON_IMX7D)
regmap_write(map, IMX6_MISC0 + REG_SET,
IMX6_MISC0_REFTOP_SELBIASOFF);
regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->power_down_mask);
ret = imx_thermal_register_legacy_cooling(data); if (ret) return dev_err_probe(dev, ret, "failed to register cpufreq cooling device\n");
data->thermal_clk = devm_clk_get(dev, NULL); if (IS_ERR(data->thermal_clk)) {
ret = dev_err_probe(dev, PTR_ERR(data->thermal_clk), "failed to get thermal clk\n"); goto legacy_cleanup;
}
/* * Thermal sensor needs clk on to get correct value, normally * we should enable its clk before taking measurement and disable * clk after measurement is done, but if alarm function is enabled, * hardware will auto measure the temperature periodically, so we * need to keep the clk always on for alarm function.
*/
ret = clk_prepare_enable(data->thermal_clk); if (ret) {
dev_err(dev, "failed to enable thermal clk: %d\n", ret); goto legacy_cleanup;
}
data->tz = thermal_zone_device_register_with_trips("imx_thermal_zone",
trips,
ARRAY_SIZE(trips),
data,
&imx_tz_ops, NULL,
IMX_PASSIVE_DELAY,
IMX_POLLING_DELAY); if (IS_ERR(data->tz)) {
ret = PTR_ERR(data->tz);
dev_err(dev, "failed to register thermal zone device %d\n",
ret); goto clk_disable;
}
dev_info(dev, "%s CPU temperature grade - max:%dC" " critical:%dC passive:%dC\n", data->temp_grade,
data->temp_max / 1000, trips[IMX_TRIP_CRITICAL].temperature / 1000,
trips[IMX_TRIP_PASSIVE].temperature / 1000);
if (data->socdata->version == TEMPMON_IMX6SX)
imx_set_panic_temp(data, trips[IMX_TRIP_CRITICAL].temperature);
regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
data->socdata->power_down_mask);
regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->measure_temp_mask); /* After power up, we need a delay before first access can be done. */
usleep_range(20, 50);
/* the core was configured and enabled just before */
pm_runtime_set_active(dev);
pm_runtime_enable(data->dev);
ret = pm_runtime_resume_and_get(data->dev); if (ret < 0) goto disable_runtime_pm;
data->irq_enabled = true;
ret = thermal_zone_device_enable(data->tz); if (ret) goto thermal_zone_unregister;
ret = devm_request_threaded_irq(dev, data->irq,
imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
0, "imx_thermal", data); if (ret < 0) {
dev_err(dev, "failed to request alarm irq: %d\n", ret); goto thermal_zone_unregister;
}
/* * Need to disable thermal sensor, otherwise, when thermal core * try to get temperature before thermal sensor resume, a wrong * temperature will be read as the thermal sensor is powered * down. This is done in change_mode() operation called from * thermal_zone_device_disable()
*/
ret = thermal_zone_device_disable(data->tz); if (ret) return ret;
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.