summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeng Fan <Peng.Fan@freescale.com>2015-05-06 14:47:02 +0800
committerPeng Fan <Peng.Fan@freescale.com>2015-06-10 17:15:25 +0800
commit0130e6433130fb5b10c7821f476673d9c94a033b (patch)
treee7480a74a14f39929c8c788721910f775c26243f
parent307dd82d6236dc5ebdc228528e6eaed31e8a2d3d (diff)
downloadu-boot-imx-0130e6433130fb5b10c7821f476673d9c94a033b.zip
u-boot-imx-0130e6433130fb5b10c7821f476673d9c94a033b.tar.gz
u-boot-imx-0130e6433130fb5b10c7821f476673d9c94a033b.tar.bz2
MLK-10827 imx: mx6 update thermal driver according new equation
From IC guys: " After a thorough accuracy study of the Temp sense circuit, we found that with our current equation, an average part can read 7 degrees lower than a known forced temperature. We also found out that the standard variance was around 2C; which is the tightest distribution that we could create. We need to change the temp sense equation to center the average part around the target temperature. Old Equation: Temp = Troom,cal – slope*(Count measured – Count room fuse) Where Troom,cal = 25C and Slope = 0.4297157 – (0.0015974 * Count room fuse) New Equation: Temp = Troom,cal – slope*(Count measured – Count room fuse) +offset Where Troom,cal = 25C and Slope = 0.4445388 – (0.0016549 * Count room fuse) Offset = 3.580661 " According the new equation, update the thermal driver. c1 and c2 changed to u64 type and update comments. Conflicts: drivers/thermal/imx_thermal.c since to imx_v2014.04, there is no imx_thermal driver, implement the new equation in arch/arm/cpu/armv7/mx6/soc.c. Also drop the orignial way to calculate temp, but use the way in imx_v2015.04 which aligns with linux kernel Signed-off-by: Peng Fan <Peng.Fan@freescale.com> (cherry picked from commit 87723f903454aaf17336e0fe9098ea7911c19f3c) (cherry picked from commit 7f8fa8b46f90d41fe3f37fbac40d8d773cdee5ce)
-rw-r--r--arch/arm/cpu/armv7/mx6/soc.c59
1 files changed, 36 insertions, 23 deletions
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c
index 3cb5bdf..6af6b4c 100644
--- a/arch/arm/cpu/armv7/mx6/soc.c
+++ b/arch/arm/cpu/armv7/mx6/soc.c
@@ -17,6 +17,7 @@
#include <asm/arch/sys_proto.h>
#include <asm/imx-common/boot_mode.h>
#include <asm/imx-common/dma.h>
+#include <div64.h>
#include <libfdt.h>
#include <stdbool.h>
#include <asm/arch/mxc_hdmi.h>
@@ -48,13 +49,12 @@ struct scu_regs {
#define TEMPERATURE_MIN -40
#define TEMPERATURE_HOT 80
#define TEMPERATURE_MAX 125
-#define FACTOR1 15976
-#define FACTOR2 4297157
+#define FACTOR0 10000000
+#define FACTOR1 16549
+#define FACTOR2 4445388
+#define OFFSET 3580661
#define MEASURE_FREQ 327
-#define REG_VALUE_TO_CEL(ratio, raw) \
- ((raw_n40c - raw) * 100 / ratio - 40)
-
static unsigned int fuse = ~0;
u32 get_cpu_rev(void)
@@ -243,8 +243,9 @@ static void imx_set_wdog_powerdown(bool enable)
static int read_cpu_temperature(int *temperature)
{
unsigned int ccm_ccgr2;
- unsigned int reg, tmp;
- unsigned int raw_25c, raw_n40c, ratio;
+ unsigned int reg, n_meas;
+ int t1, n1;
+ u64 temp64, c1, c2;
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
struct fuse_bank *bank = &ocotp->bank[1];
@@ -287,20 +288,33 @@ static int read_cpu_temperature(int *temperature)
* [19:8] sensor value of hot
* [7:0] hot temperature value
*/
- raw_25c = fuse >> 20;
+ n1 = fuse >> 20;
+ t1 = 25; /* t1 always 25C */
/*
- * The universal equation for thermal sensor
- * is slope = 0.4297157 - (0.0015976 * 25C fuse),
- * here we convert them to integer to make them
- * easy for counting, FACTOR1 is 15976,
- * FACTOR2 is 4297157. Our ratio = -100 * slope
+ * Derived from linear interpolation:
+ * slope = 0.4445388 - (0.0016549 * 25C fuse)
+ * slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0
+ * offset = 3.580661
+ * offset = OFFSET / 1000000
+ * (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...
+ * Tmeas = (Nmeas - n1) / slope + t1 + offset
+ * milli_Tmeas = 1000000 * (Nmeas - n1) / slope + 1000000 * t1 + OFFSET
+ * milli_Tmeas = -1000000 * (n1 - Nmeas) / slope + 1000000 * t1 + OFFSET
+ * Let constant c1 = (-1000000 / slope)
+ * milli_Tmeas = (n1 - Nmeas) * c1 + 1000000 * t1 + OFFSET
+ * Let constant c2 = n1 *c1 + 1000000 * t1
+ * milli_Tmeas = (c2 - Nmeas * c1) / 1000000 + OFFSET
+ * Tmeas = ((c2 - Nmeas * c1) + OFFSET) / 1000000
*/
- ratio = ((FACTOR1 * raw_25c - FACTOR2) + 50000) / 100000;
-
- debug("Thermal sensor with ratio = %d\n", ratio);
-
- raw_n40c = raw_25c + (13 * ratio) / 20;
+ temp64 = FACTOR0;
+ temp64 *= 1000000;
+ do_div(temp64, FACTOR1 * n1 - FACTOR2);
+ c1 = temp64;
+ c2 = n1 * c1 + 1000000 * t1;
/*
* now we only use single measure, every time we read
@@ -325,14 +339,13 @@ static int read_cpu_temperature(int *temperature)
udelay(10000);
reg = readl(&mxc_ccm->tempsense0);
- tmp = (reg & BM_ANADIG_TEMPSENSE0_TEMP_VALUE)
+ n_meas = (reg & BM_ANADIG_TEMPSENSE0_TEMP_VALUE)
>> BP_ANADIG_TEMPSENSE0_TEMP_VALUE;
writel(BM_ANADIG_TEMPSENSE0_FINISHED, &mxc_ccm->tempsense0_clr);
- if (tmp <= raw_n40c)
- *temperature = REG_VALUE_TO_CEL(ratio, tmp);
- else
- *temperature = TEMPERATURE_MIN;
+ /* Tmeas = (c2 - Nmeas * c1 + OFFSET) / 1000000 */
+ *temperature = lldiv(c2 - n_meas * c1 + OFFSET, 1000000);
+
/* power down anatop thermal sensor */
writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN, &mxc_ccm->tempsense0_set);
writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &mxc_ccm->ana_misc0_clr);