diff mbox

thermal: imx: update formula for thermal sensor

Message ID 1392199595-1054-1-git-send-email-b20788@freescale.com (mailing list archive)
State Accepted, archived
Delegated to: Zhang Rui
Headers show

Commit Message

Anson Huang Feb. 12, 2014, 10:06 a.m. UTC
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 <b20788@freescale.com>
---
 drivers/thermal/imx_thermal.c |   39 ++++++++++++++++++++++++++-------------
 1 file changed, 26 insertions(+), 13 deletions(-)

Comments

Shawn Guo Feb. 13, 2014, 1:02 p.m. UTC | #1
Copy LAKML and pengutronix folks in case they have comments.

On Wed, Feb 12, 2014 at 06:06:35PM +0800, Anson Huang wrote:
> 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 <b20788@freescale.com>

Acked-by: Shawn Guo <shawn.guo@linaro.org>

Shawn

> ---
>  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 45af765..a99c631 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
> -- 
> 1.7.9.5
> 
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Philipp Zabel Feb. 13, 2014, 7:09 p.m. UTC | #2
Hi,

On Thu, Feb 13, 2014 at 2:02 PM, Shawn Guo <shawn.guo@linaro.org> wrote:
>
> Copy LAKML and pengutronix folks in case they have comments.
>
> On Wed, Feb 12, 2014 at 06:06:35PM +0800, Anson Huang wrote:
> > 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);

I have an i.MX6Q 1.2 with 1417 counts at 25°C and 1296 counts at 105°C fused.
Assuming that those values are fused correctly, with the old formula I get:

t1=25, n1=1417, t2=105, n2=1296
c1=1000*(t1-t2)/(n1-n2)=-662, c2=1000*t2-c1*n2=962952
T_meas=c2+c1*N_meas=962952-662*N_meas

N_meas=1417 --> T_meas = 24898
N_meas=1296 --> T_meas = 105000

With the new formula, on the other hand, I would get:

t1=25, n1=1417
F0=10000000, F1=15976, 4297157
c1=F0*1000/(F1*n1-F2)=545, c2=n1*c1+1000*25=797265
T_meas=c2-N_meas*c1=797265-N_meas*545

N_meas=1417 --> T_meas = 25000
N_meas=1296 --> T_meas = 90945

That's off by over 14°C!

The default passive cooling trip point is at 85°C,
which translated to 1326 counts before:
alarm_value=(alarm_temp-c2)/c1=(85000-962952)/(-662)=1326

With the new formula the trip count is only
alarm_value=(c2-alarm_temp)/c1=(797265-85000)/545=1306
That translates to 98.4°C according to the old formula. I think
that is awfully close to the critical trip point at 100°C, which,
according to the old formula, corresponded to 1303 counts.

The new critical trip point for 100°C is at 1279 counts. According
to the old formula this corresponds to 116.2°C, well over the
rated maximum of 105°C.

Do I need to be afraid for my old silicon?

> > Update the formula, as there will be no hot point calibration
> > data in fuse map from now on.

I wonder if it would be better to keep using the high temperature
calibration point if it is fused at all.

regards
Philipp
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Anson.Huang@freescale.com Feb. 13, 2014, 11:39 p.m. UTC | #3
Hi, philipp
        I know your concern, but from hardware team, they said due to the calibration tool's limitation, the high point calibration data is not reliable even the fuse data is there.  If so, then comparing to old formula is not making sense, we should read the temperature in an oven and compare the oven environment's temperature to the result read from thermal sensor using new formula.

We have done the test, and this new formula is included in our BSP release already.

Sent from Anson's iPhone

> ? 2014?2?14??3:09?"Philipp Zabel" <philipp.zabel@gmail.com> ???

> 

> Hi,

> 

>> On Thu, Feb 13, 2014 at 2:02 PM, Shawn Guo <shawn.guo@linaro.org> wrote:

>> 

>> Copy LAKML and pengutronix folks in case they have comments.

>> 

>>> On Wed, Feb 12, 2014 at 06:06:35PM +0800, Anson Huang wrote:

>>> 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);

> 

> I have an i.MX6Q 1.2 with 1417 counts at 25°C and 1296 counts at 105°C fused.

> Assuming that those values are fused correctly, with the old formula I get:

> 

> t1=25, n1=1417, t2=105, n2=1296

> c1=1000*(t1-t2)/(n1-n2)=-662, c2=1000*t2-c1*n2=962952

> T_meas=c2+c1*N_meas=962952-662*N_meas

> 

> N_meas=1417 --> T_meas = 24898

> N_meas=1296 --> T_meas = 105000

> 

> With the new formula, on the other hand, I would get:

> 

> t1=25, n1=1417

> F0=10000000, F1=15976, 4297157

> c1=F0*1000/(F1*n1-F2)=545, c2=n1*c1+1000*25=797265

> T_meas=c2-N_meas*c1=797265-N_meas*545

> 

> N_meas=1417 --> T_meas = 25000

> N_meas=1296 --> T_meas = 90945

> 

> That's off by over 14°C!

> 

> The default passive cooling trip point is at 85°C,

> which translated to 1326 counts before:

> alarm_value=(alarm_temp-c2)/c1=(85000-962952)/(-662)=1326

> 

> With the new formula the trip count is only

> alarm_value=(c2-alarm_temp)/c1=(797265-85000)/545=1306

> That translates to 98.4°C according to the old formula. I think

> that is awfully close to the critical trip point at 100°C, which,

> according to the old formula, corresponded to 1303 counts.

> 

> The new critical trip point for 100°C is at 1279 counts. According

> to the old formula this corresponds to 116.2°C, well over the

> rated maximum of 105°C.

> 

> Do I need to be afraid for my old silicon?

> 

>>> Update the formula, as there will be no hot point calibration

>>> data in fuse map from now on.

> 

> I wonder if it would be better to keep using the high temperature

> calibration point if it is fused at all.

> 

> regards

> Philipp

> 

>
Zhang Rui Feb. 27, 2014, 6:54 a.m. UTC | #4
On Thu, 2014-02-13 at 21:02 +0800, Shawn Guo wrote:
> Copy LAKML and pengutronix folks in case they have comments.
> 
> On Wed, Feb 12, 2014 at 06:06:35PM +0800, Anson Huang wrote:
> > 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 <b20788@freescale.com>
> 
> Acked-by: Shawn Guo <shawn.guo@linaro.org>
> 
applied.

thanks,
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 45af765..a99c631 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
> > -- 
> > 1.7.9.5
> > 
> > 
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 45af765..a99c631 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