From 749e8be71d6126b9219f17230e6d0c3eef5191a7 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 12 Feb 2014 18:06:35 +0800 Subject: [PATCH 1/4] thermal: imx: update formula for thermal sensor Thermal sensor used to need two calibration points which are in fuse map to get a slope for converting thermal sensor's raw data to real temperature in degree C. Due to the chip calibration limitation, hardware team provides an universal formula to get real temperature from internal thermal sensor raw data: Slope = 0.4297157 - (0.0015976 * 25C fuse); Update the formula, as there will be no hot point calibration data in fuse map from now on. Signed-off-by: Anson Huang Acked-by: Shawn Guo Signed-off-by: Zhang Rui --- drivers/thermal/imx_thermal.c | 39 +++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 45af765a3198..a99c63152b8d 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -62,12 +62,16 @@ enum imx_thermal_trip { #define IMX_POLLING_DELAY 2000 /* millisecond */ #define IMX_PASSIVE_DELAY 1000 +#define FACTOR0 10000000 +#define FACTOR1 15976 +#define FACTOR2 4297157 + struct imx_thermal_data { struct thermal_zone_device *tz; struct thermal_cooling_device *cdev; enum thermal_device_mode mode; struct regmap *tempmon; - int c1, c2; /* See formula in imx_get_sensor_data() */ + u32 c1, c2; /* See formula in imx_get_sensor_data() */ unsigned long temp_passive; unsigned long temp_critical; unsigned long alarm_temp; @@ -84,7 +88,7 @@ static void imx_set_alarm_temp(struct imx_thermal_data *data, int alarm_value; data->alarm_temp = alarm_temp; - alarm_value = (alarm_temp - data->c2) / data->c1; + alarm_value = (data->c2 - alarm_temp) / data->c1; regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK); regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value << TEMPSENSE0_ALARM_VALUE_SHIFT); @@ -136,7 +140,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp) n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT; /* See imx_get_sensor_data() for formula derivation */ - *temp = data->c2 + data->c1 * n_meas; + *temp = data->c2 - n_meas * data->c1; /* Update alarm value to next higher trip point */ if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive) @@ -305,6 +309,7 @@ static int imx_get_sensor_data(struct platform_device *pdev) int t1, t2, n1, n2; int ret; u32 val; + u64 temp64; map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon-data"); @@ -330,6 +335,8 @@ static int imx_get_sensor_data(struct platform_device *pdev) * [31:20] - sensor value @ 25C * [19:8] - sensor value of hot * [7:0] - hot temperature value + * Use universal formula now and only need sensor value @ 25C + * slope = 0.4297157 - (0.0015976 * 25C fuse) */ n1 = val >> 20; n2 = (val & 0xfff00) >> 8; @@ -337,20 +344,26 @@ static int imx_get_sensor_data(struct platform_device *pdev) t1 = 25; /* t1 always 25C */ /* - * Derived from linear interpolation, - * Tmeas = T2 + (Nmeas - N2) * (T1 - T2) / (N1 - N2) + * Derived from linear interpolation: + * slope = 0.4297157 - (0.0015976 * 25C fuse) + * slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0 + * (Nmeas - n1) / (Tmeas - t1) = slope * We want to reduce this down to the minimum computation necessary * for each temperature read. Also, we want Tmeas in millicelsius * and we don't want to lose precision from integer division. So... - * milli_Tmeas = 1000 * T2 + 1000 * (Nmeas - N2) * (T1 - T2) / (N1 - N2) - * Let constant c1 = 1000 * (T1 - T2) / (N1 - N2) - * milli_Tmeas = (1000 * T2) + c1 * (Nmeas - N2) - * milli_Tmeas = (1000 * T2) + (c1 * Nmeas) - (c1 * N2) - * Let constant c2 = (1000 * T2) - (c1 * N2) - * milli_Tmeas = c2 + (c1 * Nmeas) + * Tmeas = (Nmeas - n1) / slope + t1 + * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1 + * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1 + * Let constant c1 = (-1000 / slope) + * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1 + * Let constant c2 = n1 *c1 + 1000 * t1 + * milli_Tmeas = c2 - Nmeas * c1 */ - data->c1 = 1000 * (t1 - t2) / (n1 - n2); - data->c2 = 1000 * t2 - data->c1 * n2; + temp64 = FACTOR0; + temp64 *= 1000; + do_div(temp64, FACTOR1 * n1 - FACTOR2); + data->c1 = temp64; + data->c2 = n1 * data->c1 + 1000 * t1; /* * Set the default passive cooling trip point to 20 °C below the From 5204f8c0a7f0fbdc0fe0d1f614b2c436069c8a18 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 27 Feb 2014 20:43:02 +0900 Subject: [PATCH 2/4] thermal: ti-soc-thermal: Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro in order to make the code simpler. Signed-off-by: Jingoo Han Signed-off-by: Zhang Rui --- drivers/thermal/ti-soc-thermal/ti-bandgap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c index 74c0e3474d6e..3ab12ee359b7 100644 --- a/drivers/thermal/ti-soc-thermal/ti-bandgap.c +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c @@ -1500,10 +1500,8 @@ static int ti_bandgap_resume(struct device *dev) return ti_bandgap_restore_ctxt(bgp); } -static const struct dev_pm_ops ti_bandgap_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ti_bandgap_suspend, - ti_bandgap_resume) -}; +static SIMPLE_DEV_PM_OPS(ti_bandgap_dev_pm_ops, ti_bandgap_suspend, + ti_bandgap_resume); #define DEV_PM_OPS (&ti_bandgap_dev_pm_ops) #else From 206c0cba095acbb91d552d220207d690c9b29594 Mon Sep 17 00:00:00 2001 From: Patrick Titiano Date: Fri, 28 Feb 2014 14:10:03 +0100 Subject: [PATCH 3/4] thermal: rcar-thermal: fix same mask applied twice Mask is already applied preceding the if statement. Remove the second mask. Signed-off-by: Patrick Titiano Acked-by: Kuninori Morimoto Signed-off-by: Zhang Rui --- drivers/thermal/rcar_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 79a09d02bbca..88cfeec6a28f 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -313,7 +313,7 @@ static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status) status = (status >> rcar_id_to_shift(priv)) & 0x3; - if (status & 0x3) { + if (status) { dev_dbg(dev, "thermal%d %s%s\n", priv->id, (status & 0x2) ? "Rising " : "", From 9477165ec525d47abb1cb6523698e0cd89d65ddb Mon Sep 17 00:00:00 2001 From: Patrick Titiano Date: Fri, 28 Feb 2014 14:10:04 +0100 Subject: [PATCH 4/4] thermal: rcar-thermal: update thermal zone only when temperature changes Avoid updating the thermal zone in case an IRQ was triggered but the temperature didn't effectively change. Note this is not a driver issue. Below is a captured debug trace illustrating the purpose of this patch: out of 8 thermal zone updates, only 2 are actually necessary. [ 41.120000] rcar_thermal_work(): cctemp=25000 [ 41.120000] rcar_thermal_work(): nctemp=30000 [ 41.120000] rcar_thermal_work(): temp is now 30000C, update thermal zone [ 58.990000] rcar_thermal_work(): cctemp=30000 [ 58.990000] rcar_thermal_work(): nctemp=30000 [ 58.990000] rcar_thermal_work(): same temp, do not update thermal zone [ 59.290000] rcar_thermal_work(): cctemp=30000 [ 59.290000] rcar_thermal_work(): nctemp=30000 [ 59.290000] rcar_thermal_work(): same temp, do not update thermal zone [ 59.590000] rcar_thermal_work(): cctemp=30000 [ 59.590000] rcar_thermal_work(): nctemp=30000 [ 59.590000] rcar_thermal_work(): same temp, do not update thermal zone [ 59.890000] rcar_thermal_work(): cctemp=30000 [ 59.890000] rcar_thermal_work(): nctemp=30000 [ 59.890000] rcar_thermal_work(): same temp, do not update thermal zone [ 60.190000] rcar_thermal_work(): cctemp=30000 [ 60.190000] rcar_thermal_work(): nctemp=30000 [ 60.190000] rcar_thermal_work(): same temp, do not update thermal zone [ 60.490000] rcar_thermal_work(): cctemp=30000 [ 60.490000] rcar_thermal_work(): nctemp=30000 [ 60.490000] rcar_thermal_work(): same temp, do not update thermal zone [ 60.790000] rcar_thermal_work(): cctemp=30000 [ 60.790000] rcar_thermal_work(): nctemp=35000 [ 60.790000] rcar_thermal_work(): temp is now 35000C, update thermal zone I suspect this may be due to sensor sampling accuracy / fluctuation, but no formal proof. Signed-off-by: Patrick Titiano Acked-by: Kuninori Morimoto Signed-off-by: Zhang Rui --- drivers/thermal/rcar_thermal.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 88cfeec6a28f..5a37940b02c9 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -299,12 +299,17 @@ static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable) static void rcar_thermal_work(struct work_struct *work) { struct rcar_thermal_priv *priv; + unsigned long cctemp, nctemp; priv = container_of(work, struct rcar_thermal_priv, work.work); + rcar_thermal_get_temp(priv->zone, &cctemp); rcar_thermal_update_temp(priv); rcar_thermal_irq_enable(priv); - thermal_zone_device_update(priv->zone); + + rcar_thermal_get_temp(priv->zone, &nctemp); + if (nctemp != cctemp) + thermal_zone_device_update(priv->zone); } static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)