[U-Boot] [PATCH v7 0/4] add i.MX6 thermal sensor driver

This patch set adds i.MX6 thermal sensor driver and enables it for mx6sabre boards. Also adds various anadig bit definitions as required for upcoming drivers.
Changes in v7: -Convert the imx thermal driver to DM. -Enable DM drivers for mx6sabre boards.
Changes in v6: -Aligned imx thermal driver macro defines with kernel
Changes in v5: -Don't modify the copyright of cpu.c and crm_regs.h file
Changes in v4: -Added imx6 thermal sensor as a driver -Renamed the config define to be more meaningful -Move the clock code to clock.c -Reusing ocotp driver for reading fuse -Fix check for calibration fuse not programmed -Aligned the slope computation with kernel -Added Anadig register defines as seperate commit
Changes in v3: -adds the mx6 thermal driver support -adds the mx6 thermal support to mx6sabresd board.
Changes in v2: -run checkpatch and fix reported issues
Nitin Garg (1): mx6: clock: Add thermal clock enable function
Ye.Li (3): DM: thermal: Add imx thermal DM driver mx6: thermal: Check cpu temperature via thermal sensor mx6: mx6sabre common: Enable i.MX thermal DM driver
arch/arm/cpu/armv7/mx6/clock.c | 30 ++++++ arch/arm/cpu/armv7/mx6/soc.c | 15 +++ arch/arm/imx-common/cpu.c | 21 ++++ arch/arm/include/asm/arch-mx6/clock.h | 1 + drivers/Makefile | 1 + drivers/thermal/Makefile | 9 ++ drivers/thermal/imx_thermal.c | 177 +++++++++++++++++++++++++++++++++ drivers/thermal/thermal-uclass.c | 30 ++++++ include/configs/mx6sabre_common.h | 7 +- include/dm/uclass-id.h | 1 + include/imx_thermal.h | 17 +++ include/thermal.h | 42 ++++++++ 12 files changed, 350 insertions(+), 1 deletions(-) create mode 100644 drivers/thermal/Makefile create mode 100644 drivers/thermal/imx_thermal.c create mode 100644 drivers/thermal/thermal-uclass.c create mode 100644 include/imx_thermal.h create mode 100644 include/thermal.h

From: Nitin Garg nitin.garg@freescale.com
Add api to check and enable pll3 as required for thermal sensor driver.
Signed-off-by: Ye.Li B37916@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com --- arch/arm/cpu/armv7/mx6/clock.c | 30 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/clock.h | 1 + 2 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 6c9c78c..144080e 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.c @@ -673,6 +673,36 @@ void hab_caam_clock_enable(unsigned char enable) } #endif
+static void enable_pll3(void) +{ + struct anatop_regs __iomem *anatop = + (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; + + /* make sure pll3 is enabled */ + if ((readl(&anatop->usb1_pll_480_ctrl) & + BM_ANADIG_USB1_PLL_480_CTRL_LOCK) == 0) { + /* enable pll's power */ + writel(BM_ANADIG_USB1_PLL_480_CTRL_POWER, + &anatop->usb1_pll_480_ctrl_set); + writel(0x80, &anatop->ana_misc2_clr); + /* wait for pll lock */ + while ((readl(&anatop->usb1_pll_480_ctrl) & + BM_ANADIG_USB1_PLL_480_CTRL_LOCK) == 0) + ; + /* disable bypass */ + writel(BM_ANADIG_USB1_PLL_480_CTRL_BYPASS, + &anatop->usb1_pll_480_ctrl_clr); + /* enable pll output */ + writel(BM_ANADIG_USB1_PLL_480_CTRL_ENABLE, + &anatop->usb1_pll_480_ctrl_set); + } +} + +void enable_thermal_clk() +{ + enable_pll3(); +} + unsigned int mxc_get_clock(enum mxc_clock clk) { switch (clk) { diff --git a/arch/arm/include/asm/arch-mx6/clock.h b/arch/arm/include/asm/arch-mx6/clock.h index 3c58a0a..8e51f9b 100644 --- a/arch/arm/include/asm/arch-mx6/clock.h +++ b/arch/arm/include/asm/arch-mx6/clock.h @@ -66,4 +66,5 @@ int enable_spi_clk(unsigned char enable, unsigned spi_num); void enable_ipu_clock(void); int enable_fec_anatop_clock(enum enet_freq freq); void enable_enet_clk(unsigned char enable); +void enable_thermal_clk(void); #endif /* __ASM_ARCH_CLOCK_H */

On 20/11/2014 14:14, Ye.Li wrote:
From: Nitin Garg nitin.garg@freescale.com
Add api to check and enable pll3 as required for thermal sensor driver.
Signed-off-by: Ye.Li B37916@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com
After fixing: ERROR: Bad function definition - void enable_thermal_clk() should probably be void enable_thermal_clk(void) #124: FILE: arch/arm/cpu/armv7/mx6/clock.c:701: +void enable_thermal_clk()
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic

Add a new thermal uclass for thermal sensor and implement the imx thermal driver basing on this uclass.
Signed-off-by: Ye.Li B37916@freescale.com --- drivers/Makefile | 1 + drivers/thermal/Makefile | 9 ++ drivers/thermal/imx_thermal.c | 177 ++++++++++++++++++++++++++++++++++++++ drivers/thermal/thermal-uclass.c | 30 +++++++ include/dm/uclass-id.h | 1 + include/imx_thermal.h | 17 ++++ include/thermal.h | 42 +++++++++ 7 files changed, 277 insertions(+), 0 deletions(-)
diff --git a/drivers/Makefile b/drivers/Makefile index 33227c8..7683c61 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -21,3 +21,4 @@ obj-y += pwm/ obj-y += input/ # SOC specific infrastructure drivers. obj-y += soc/ +obj-y += thermal/ diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile new file mode 100644 index 0000000..6d4cacd --- /dev/null +++ b/drivers/thermal/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2014 Freescale Semiconductor, Inc. +# Author: Nitin Garg nitin.garg@freescale.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o +obj-$(CONFIG_IMX6_THERMAL) += imx_thermal.o diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c new file mode 100644 index 0000000..1161585 --- /dev/null +++ b/drivers/thermal/imx_thermal.c @@ -0,0 +1,177 @@ +/* + * (C) Copyright 2014 Freescale Semiconductor, Inc. + * Author: Nitin Garg nitin.garg@freescale.com + * Ye Li Ye.Li@freescale.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <div64.h> +#include <fuse.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <dm.h> +#include <errno.h> +#include <malloc.h> +#include <thermal.h> +#include <imx_thermal.h> + +#define TEMPERATURE_MIN -40 +#define TEMPERATURE_HOT 80 +#define TEMPERATURE_MAX 125 +#define FACTOR0 10000000 +#define FACTOR1 15976 +#define FACTOR2 4297157 +#define MEASURE_FREQ 327 + +#define TEMPSENSE0_TEMP_CNT_SHIFT 8 +#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT) +#define TEMPSENSE0_FINISHED (1 << 2) +#define TEMPSENSE0_MEASURE_TEMP (1 << 1) +#define TEMPSENSE0_POWER_DOWN (1 << 0) +#define MISC0_REFTOP_SELBIASOFF (1 << 3) +#define TEMPSENSE1_MEASURE_FREQ 0xffff + +static int read_cpu_temperature(struct udevice *dev) +{ + int temperature; + unsigned int reg, n_meas; + const struct imx_thermal_plat *pdata = dev_get_platdata(dev); + struct anatop_regs *anatop = (struct anatop_regs *)pdata->regs; + unsigned int *priv = dev_get_priv(dev); + u32 fuse = *priv; + int t1, n1; + u32 c1, c2; + u64 temp64; + + /* + * Sensor data layout: + * [31:20] - sensor value @ 25C + * We use universal formula now and only need sensor value @ 25C + * slope = 0.4297157 - (0.0015976 * 25C fuse) + */ + n1 = fuse >> 20; + t1 = 25; /* t1 always 25C */ + + /* + * 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... + * 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 + */ + temp64 = FACTOR0; + temp64 *= 1000; + do_div(temp64, FACTOR1 * n1 - FACTOR2); + c1 = temp64; + c2 = n1 * c1 + 1000 * t1; + + /* + * now we only use single measure, every time we read + * the temperature, we will power on/down anadig thermal + * module + */ + writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_clr); + writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set); + + /* setup measure freq */ + reg = readl(&anatop->tempsense1); + reg &= ~TEMPSENSE1_MEASURE_FREQ; + reg |= MEASURE_FREQ; + writel(reg, &anatop->tempsense1); + + /* start the measurement process */ + writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr); + writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr); + writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set); + + /* make sure that the latest temp is valid */ + while ((readl(&anatop->tempsense0) & + TEMPSENSE0_FINISHED) == 0) + udelay(10000); + + /* read temperature count */ + reg = readl(&anatop->tempsense0); + n_meas = (reg & TEMPSENSE0_TEMP_CNT_MASK) + >> TEMPSENSE0_TEMP_CNT_SHIFT; + writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr); + + /* milli_Tmeas = c2 - Nmeas * c1 */ + temperature = (c2 - n_meas * c1)/1000; + + /* power down anatop thermal sensor */ + writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set); + writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_clr); + + return temperature; +} + +int imx_thermal_get_temp(struct udevice *dev, int *temp) +{ + int cpu_tmp = 0; + + cpu_tmp = read_cpu_temperature(dev); + while (cpu_tmp > TEMPERATURE_MIN && cpu_tmp < TEMPERATURE_MAX) { + if (cpu_tmp >= TEMPERATURE_HOT) { + printf("CPU Temperature is %d C, too hot to boot, waiting...\n", + cpu_tmp); + udelay(5000000); + cpu_tmp = read_cpu_temperature(dev); + } else { + break; + } + } + + *temp = cpu_tmp; + + return 0; +} + +static const struct dm_thermal_ops imx_thermal_ops = { + .get_temp = imx_thermal_get_temp, +}; + +static int imx_thermal_probe(struct udevice *dev) +{ + unsigned int fuse = ~0; + + const struct imx_thermal_plat *pdata = dev_get_platdata(dev); + unsigned int *priv = dev_get_priv(dev); + + /* Read Temperature calibration data fuse */ + fuse_read(pdata->fuse_bank, pdata->fuse_word, &fuse); + + /* Check for valid fuse */ + if (fuse == 0 || fuse == ~0) { + printf("CPU: Thermal invalid data, fuse: 0x%x\n", fuse); + return -EPERM; + } else { + printf("CPU: Thermal calibration data: 0x%x\n", fuse); + } + + *priv = fuse; + + enable_thermal_clk(); + + return 0; +} + +U_BOOT_DRIVER(imx_thermal) = { + .name = "imx_thermal", + .id = UCLASS_THERMAL, + .ops = &imx_thermal_ops, + .probe = imx_thermal_probe, + .priv_auto_alloc_size = sizeof(unsigned int), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/thermal/thermal-uclass.c b/drivers/thermal/thermal-uclass.c new file mode 100644 index 0000000..3bee1a7 --- /dev/null +++ b/drivers/thermal/thermal-uclass.c @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2014 Freescale Semiconductor, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <thermal.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/io.h> +#include <linux/list.h> + + +int thermal_get_temp(struct udevice *dev, int *temp) +{ + const struct dm_thermal_ops *ops = device_get_ops(dev); + + if (!ops->get_temp) + return -ENOSYS; + + return ops->get_temp(dev, temp); +} + +UCLASS_DRIVER(thermal) = { + .id = UCLASS_THERMAL, + .name = "thermal", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index a8944c9..202f59b 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -28,6 +28,7 @@ enum uclass_id { UCLASS_SPI_GENERIC, /* Generic SPI flash target */ UCLASS_SPI_FLASH, /* SPI flash */ UCLASS_CROS_EC, /* Chrome OS EC */ + UCLASS_THERMAL, /* Thermal sensor */
UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/imx_thermal.h b/include/imx_thermal.h new file mode 100644 index 0000000..be13652 --- /dev/null +++ b/include/imx_thermal.h @@ -0,0 +1,17 @@ +/* + * + * (C) Copyright 2014 Freescale Semiconductor, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _IMX_THERMAL_H_ +#define _IMX_THERMAL_H_ + +struct imx_thermal_plat { + void *regs; + int fuse_bank; + int fuse_word; +}; + +#endif /* _IMX_THERMAL_H_ */ diff --git a/include/thermal.h b/include/thermal.h new file mode 100644 index 0000000..80b549b --- /dev/null +++ b/include/thermal.h @@ -0,0 +1,42 @@ +/* + * + * (C) Copyright 2014 Freescale Semiconductor, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _THERMAL_H_ +#define _THERMAL_H_ + +#include <dm.h> + +int thermal_get_temp(struct udevice *dev, int *temp); + +/** + * struct struct dm_thermal_ops - Driver model Thermal operations + * + * The uclass interface is implemented by all Thermal devices which use + * driver model. + */ +struct dm_thermal_ops { + /** + * Get the current temperature + * + * The device provided is the slave device. It's parent controller + * will be used to provide the communication. + * + * This must be called before doing any transfers with a Thermal slave. It + * will enable and initialize any Thermal hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + * @dev: The Thermal device + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ + int (*get_temp)(struct udevice *dev, int *temp); +}; + +#endif /* _THERMAL_H_ */

Hi Ye,
On 20/11/2014 14:14, Ye.Li wrote:
Add a new thermal uclass for thermal sensor and implement the imx thermal driver basing on this uclass.
Thanks for doing this !
Signed-off-by: Ye.Li B37916@freescale.com
drivers/Makefile | 1 + drivers/thermal/Makefile | 9 ++ drivers/thermal/imx_thermal.c | 177 ++++++++++++++++++++++++++++++++++++++ drivers/thermal/thermal-uclass.c | 30 +++++++ include/dm/uclass-id.h | 1 + include/imx_thermal.h | 17 ++++ include/thermal.h | 42 +++++++++ 7 files changed, 277 insertions(+), 0 deletions(-)
diff --git a/drivers/Makefile b/drivers/Makefile index 33227c8..7683c61 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -21,3 +21,4 @@ obj-y += pwm/ obj-y += input/ # SOC specific infrastructure drivers. obj-y += soc/ +obj-y += thermal/ diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile new file mode 100644 index 0000000..6d4cacd --- /dev/null +++ b/drivers/thermal/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2014 Freescale Semiconductor, Inc. +# Author: Nitin Garg nitin.garg@freescale.com +# +# SPDX-License-Identifier: GPL-2.0+ +#
+obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o +obj-$(CONFIG_IMX6_THERMAL) += imx_thermal.o diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c new file mode 100644 index 0000000..1161585 --- /dev/null +++ b/drivers/thermal/imx_thermal.c @@ -0,0 +1,177 @@ +/*
- (C) Copyright 2014 Freescale Semiconductor, Inc.
- Author: Nitin Garg nitin.garg@freescale.com
Ye Li <Ye.Li@freescale.com>
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <config.h> +#include <common.h> +#include <div64.h> +#include <fuse.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <dm.h> +#include <errno.h> +#include <malloc.h> +#include <thermal.h> +#include <imx_thermal.h>
+#define TEMPERATURE_MIN -40 +#define TEMPERATURE_HOT 80 +#define TEMPERATURE_MAX 125 +#define FACTOR0 10000000 +#define FACTOR1 15976 +#define FACTOR2 4297157 +#define MEASURE_FREQ 327
+#define TEMPSENSE0_TEMP_CNT_SHIFT 8 +#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT) +#define TEMPSENSE0_FINISHED (1 << 2) +#define TEMPSENSE0_MEASURE_TEMP (1 << 1) +#define TEMPSENSE0_POWER_DOWN (1 << 0) +#define MISC0_REFTOP_SELBIASOFF (1 << 3) +#define TEMPSENSE1_MEASURE_FREQ 0xffff
+static int read_cpu_temperature(struct udevice *dev) +{
- int temperature;
- unsigned int reg, n_meas;
- const struct imx_thermal_plat *pdata = dev_get_platdata(dev);
- struct anatop_regs *anatop = (struct anatop_regs *)pdata->regs;
- unsigned int *priv = dev_get_priv(dev);
- u32 fuse = *priv;
- int t1, n1;
- u32 c1, c2;
- u64 temp64;
- /*
* Sensor data layout:
* [31:20] - sensor value @ 25C
* We use universal formula now and only need sensor value @ 25C
* slope = 0.4297157 - (0.0015976 * 25C fuse)
*/
- n1 = fuse >> 20;
- t1 = 25; /* t1 always 25C */
- /*
* 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...
* 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
*/
- temp64 = FACTOR0;
- temp64 *= 1000;
- do_div(temp64, FACTOR1 * n1 - FACTOR2);
- c1 = temp64;
- c2 = n1 * c1 + 1000 * t1;
- /*
* now we only use single measure, every time we read
* the temperature, we will power on/down anadig thermal
* module
*/
- writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_clr);
- writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set);
- /* setup measure freq */
- reg = readl(&anatop->tempsense1);
- reg &= ~TEMPSENSE1_MEASURE_FREQ;
- reg |= MEASURE_FREQ;
- writel(reg, &anatop->tempsense1);
- /* start the measurement process */
- writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr);
- writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
- writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set);
- /* make sure that the latest temp is valid */
- while ((readl(&anatop->tempsense0) &
TEMPSENSE0_FINISHED) == 0)
udelay(10000);
- /* read temperature count */
- reg = readl(&anatop->tempsense0);
- n_meas = (reg & TEMPSENSE0_TEMP_CNT_MASK)
>> TEMPSENSE0_TEMP_CNT_SHIFT;
- writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
- /* milli_Tmeas = c2 - Nmeas * c1 */
- temperature = (c2 - n_meas * c1)/1000;
- /* power down anatop thermal sensor */
- writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set);
- writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_clr);
- return temperature;
+}
+int imx_thermal_get_temp(struct udevice *dev, int *temp) +{
- int cpu_tmp = 0;
- cpu_tmp = read_cpu_temperature(dev);
- while (cpu_tmp > TEMPERATURE_MIN && cpu_tmp < TEMPERATURE_MAX) {
if (cpu_tmp >= TEMPERATURE_HOT) {
printf("CPU Temperature is %d C, too hot to boot, waiting...\n",
cpu_tmp);
udelay(5000000);
cpu_tmp = read_cpu_temperature(dev);
} else {
break;
}
- }
- *temp = cpu_tmp;
- return 0;
+}
+static const struct dm_thermal_ops imx_thermal_ops = {
- .get_temp = imx_thermal_get_temp,
+};
+static int imx_thermal_probe(struct udevice *dev) +{
- unsigned int fuse = ~0;
- const struct imx_thermal_plat *pdata = dev_get_platdata(dev);
- unsigned int *priv = dev_get_priv(dev);
- /* Read Temperature calibration data fuse */
- fuse_read(pdata->fuse_bank, pdata->fuse_word, &fuse);
- /* Check for valid fuse */
- if (fuse == 0 || fuse == ~0) {
printf("CPU: Thermal invalid data, fuse: 0x%x\n", fuse);
return -EPERM;
- } else {
printf("CPU: Thermal calibration data: 0x%x\n", fuse);
- }
- *priv = fuse;
- enable_thermal_clk();
- return 0;
+}
+U_BOOT_DRIVER(imx_thermal) = {
- .name = "imx_thermal",
- .id = UCLASS_THERMAL,
- .ops = &imx_thermal_ops,
- .probe = imx_thermal_probe,
- .priv_auto_alloc_size = sizeof(unsigned int),
- .flags = DM_FLAG_PRE_RELOC,
+}; diff --git a/drivers/thermal/thermal-uclass.c b/drivers/thermal/thermal-uclass.c new file mode 100644 index 0000000..3bee1a7 --- /dev/null +++ b/drivers/thermal/thermal-uclass.c @@ -0,0 +1,30 @@ +/*
- (C) Copyright 2014 Freescale Semiconductor, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <thermal.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/io.h> +#include <linux/list.h>
+int thermal_get_temp(struct udevice *dev, int *temp) +{
- const struct dm_thermal_ops *ops = device_get_ops(dev);
- if (!ops->get_temp)
return -ENOSYS;
- return ops->get_temp(dev, temp);
+}
+UCLASS_DRIVER(thermal) = {
- .id = UCLASS_THERMAL,
- .name = "thermal",
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index a8944c9..202f59b 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -28,6 +28,7 @@ enum uclass_id { UCLASS_SPI_GENERIC, /* Generic SPI flash target */ UCLASS_SPI_FLASH, /* SPI flash */ UCLASS_CROS_EC, /* Chrome OS EC */
UCLASS_THERMAL, /* Thermal sensor */
UCLASS_COUNT, UCLASS_INVALID = -1,
diff --git a/include/imx_thermal.h b/include/imx_thermal.h new file mode 100644 index 0000000..be13652 --- /dev/null +++ b/include/imx_thermal.h @@ -0,0 +1,17 @@ +/*
- (C) Copyright 2014 Freescale Semiconductor, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _IMX_THERMAL_H_ +#define _IMX_THERMAL_H_
+struct imx_thermal_plat {
- void *regs;
- int fuse_bank;
- int fuse_word;
+};
+#endif /* _IMX_THERMAL_H_ */ diff --git a/include/thermal.h b/include/thermal.h new file mode 100644 index 0000000..80b549b --- /dev/null +++ b/include/thermal.h @@ -0,0 +1,42 @@ +/*
- (C) Copyright 2014 Freescale Semiconductor, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _THERMAL_H_ +#define _THERMAL_H_
+#include <dm.h>
+int thermal_get_temp(struct udevice *dev, int *temp);
+/**
- struct struct dm_thermal_ops - Driver model Thermal operations
- The uclass interface is implemented by all Thermal devices which use
- driver model.
- */
+struct dm_thermal_ops {
- /**
* Get the current temperature
*
* The device provided is the slave device. It's parent controller
* will be used to provide the communication.
*
* This must be called before doing any transfers with a Thermal slave. It
* will enable and initialize any Thermal hardware as necessary, and make
* sure that the SCK line is in the correct idle state. It is not
* allowed to claim the same bus for several slaves without releasing
* the bus in between.
*
* @dev: The Thermal device
*
* Returns: 0 if the bus was claimed successfully, or a negative value
* if it wasn't.
*/
- int (*get_temp)(struct udevice *dev, int *temp);
+};
+#endif /* _THERMAL_H_ */
Fine with me.
Acked-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic

On 20/11/2014 14:14, Ye.Li wrote:
Add a new thermal uclass for thermal sensor and implement the imx thermal driver basing on this uclass.
Signed-off-by: Ye.Li B37916@freescale.com
After fixing:
WARNING: line over 80 characters #481: FILE: include/thermal.h:28: + * This must be called before doing any transfers with a Thermal slave. It
WARNING: line over 80 characters #482: FILE: include/thermal.h:29: + * will enable and initialize any Thermal hardware as necessary, and make
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic

Hi,
On 20 November 2014 at 06:14, Ye.Li B37916@freescale.com wrote:
Add a new thermal uclass for thermal sensor and implement the imx thermal driver basing on this uclass.
Signed-off-by: Ye.Li B37916@freescale.com
drivers/Makefile | 1 + drivers/thermal/Makefile | 9 ++ drivers/thermal/imx_thermal.c | 177 ++++++++++++++++++++++++++++++++++++++ drivers/thermal/thermal-uclass.c | 30 +++++++ include/dm/uclass-id.h | 1 + include/imx_thermal.h | 17 ++++ include/thermal.h | 42 +++++++++ 7 files changed, 277 insertions(+), 0 deletions(-)
[snip]
diff --git a/include/thermal.h b/include/thermal.h new file mode 100644 index 0000000..80b549b --- /dev/null +++ b/include/thermal.h @@ -0,0 +1,42 @@ +/*
- (C) Copyright 2014 Freescale Semiconductor, Inc
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _THERMAL_H_ +#define _THERMAL_H_
+#include <dm.h>
+int thermal_get_temp(struct udevice *dev, int *temp);
+/**
- struct struct dm_thermal_ops - Driver model Thermal operations
- The uclass interface is implemented by all Thermal devices which use
- driver model.
- */
+struct dm_thermal_ops {
/**
* Get the current temperature
*
* The device provided is the slave device. It's parent controller
* will be used to provide the communication.
*
* This must be called before doing any transfers with a Thermal slave. It
* will enable and initialize any Thermal hardware as necessary, and make
* sure that the SCK line is in the correct idle state. It is not
* allowed to claim the same bus for several slaves without releasing
* the bus in between.
*
* @dev: The Thermal device
*
* Returns: 0 if the bus was claimed successfully, or a negative value
* if it wasn't.
*/
I know this comment is very late - sorry but I did not see this uclass at the time.
Please can you fix up the command above? It seems to be copied from SPI and makes no sense. Also please document the @temp parameter.
int (*get_temp)(struct udevice *dev, int *temp);
+};
+#endif /* _THERMAL_H_ */
Finally, all uclasses should have test code. In this case there should be something like test/dm/thermal.c with a simple test to get the device and check its temperature. You can add a driver for sandbox to make this work. If we don't follow this rule right from the start then the next person to come along and add to your uclass will not feel obliged to write tests.
You will probably find test/dm/gpio.c helpful, although you will only need a few lines of it for your test (e.g. uclass_get_device() followed by thermal_get_temp()). For sandbox, drivers/misc/i2c_eeprom_emul.c might help although again it has more than you need.
Regards, Simon

Add imx6 thermal device to mx6 soc file. Read the cpu temperature using this device to access onchip thermal sensor.
Signed-off-by: Ye.Li B37916@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com --- arch/arm/cpu/armv7/mx6/soc.c | 15 +++++++++++++++ arch/arm/imx-common/cpu.c | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 5fd2a63..5f5f497 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -22,6 +22,8 @@ #include <asm/arch/mxc_hdmi.h> #include <asm/arch/crm_regs.h> #include <asm/bootm.h> +#include <dm.h> +#include <imx_thermal.h>
enum ldo_reg { LDO_ARM, @@ -37,6 +39,19 @@ struct scu_regs { u32 fpga_rev; };
+#if defined(CONFIG_IMX6_THERMAL) +static const struct imx_thermal_plat imx6_thermal_plat = { + .regs = (void *)ANATOP_BASE_ADDR, + .fuse_bank = 1, + .fuse_word = 6, +}; + +U_BOOT_DEVICE(imx6_thermal) = { + .name = "imx_thermal", + .platdata = &imx6_thermal_plat, +}; +#endif + u32 get_nr_cpus(void) { struct scu_regs *scu = (struct scu_regs *)SCU_BASE_ADDR; diff --git a/arch/arm/imx-common/cpu.c b/arch/arm/imx-common/cpu.c index 09fc227..e43f188 100644 --- a/arch/arm/imx-common/cpu.c +++ b/arch/arm/imx-common/cpu.c @@ -17,6 +17,7 @@ #include <asm/arch/sys_proto.h> #include <asm/arch/crm_regs.h> #include <ipu_pixfmt.h> +#include <thermal.h>
#ifdef CONFIG_FSL_ESDHC #include <fsl_esdhc.h> @@ -134,6 +135,11 @@ int print_cpuinfo(void) { u32 cpurev;
+#if defined(CONFIG_MX6) && defined(CONFIG_IMX6_THERMAL) + struct udevice *thermal_dev; + int cpu_tmp, ret; +#endif + cpurev = get_cpu_rev();
printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n", @@ -141,6 +147,21 @@ int print_cpuinfo(void) (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0, mxc_get_clock(MXC_ARM_CLK) / 1000000); + +#if defined(CONFIG_MX6) && defined(CONFIG_IMX6_THERMAL) + ret = uclass_get_device(UCLASS_THERMAL, 0, &thermal_dev); + if (!ret) { + ret = thermal_get_temp(thermal_dev, &cpu_tmp); + + if (!ret) + printf("CPU: Temperature %d C\n", cpu_tmp); + else + printf("CPU: Temperature: invalid sensor data\n"); + } else { + printf("CPU: Temperature: Can't find sensor device\n"); + } +#endif + printf("Reset cause: %s\n", get_reset_cause()); return 0; }

On 20/11/2014 14:14, Ye.Li wrote:
Add imx6 thermal device to mx6 soc file. Read the cpu temperature using this device to access onchip thermal sensor.
Signed-off-by: Ye.Li B37916@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic

Enable i.MX thermal DM driver to mx6sabre_common.h file. Since the thermal is used in init_sequence_f, so define the CONFIG_SYS_MALLOC_F_LEN to support DM driver using in pre relocation phase.
Additional, thermal driver depends on ocotp, make sure to enable CONFIG_MXC_OCOTP when CONFIG_IMX6_THERMAL is selected.
Signed-off-by: Ye.Li B37916@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com --- include/configs/mx6sabre_common.h | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/include/configs/mx6sabre_common.h b/include/configs/mx6sabre_common.h index 1e10422..9fdd841 100644 --- a/include/configs/mx6sabre_common.h +++ b/include/configs/mx6sabre_common.h @@ -25,6 +25,11 @@ #define CONFIG_INITRD_TAG #define CONFIG_REVISION_TAG
+#define CONFIG_DM +#define CONFIG_DM_THERMAL +#define CONFIG_SYS_MALLOC_F_LEN (1 << 10) +#define CONFIG_IMX6_THERMAL + #define CONFIG_SYS_GENERIC_BOARD
/* Size of malloc() pool */ @@ -37,7 +42,7 @@ #define CONFIG_MXC_UART
#define CONFIG_CMD_FUSE -#ifdef CONFIG_CMD_FUSE +#if defined(CONFIG_CMD_FUSE) || defined(CONFIG_IMX6_THERMAL) #define CONFIG_MXC_OCOTP #endif

On 20/11/2014 14:14, Ye.Li wrote:
Enable i.MX thermal DM driver to mx6sabre_common.h file. Since the thermal is used in init_sequence_f, so define the CONFIG_SYS_MALLOC_F_LEN to support DM driver using in pre relocation phase.
Additional, thermal driver depends on ocotp, make sure to enable CONFIG_MXC_OCOTP when CONFIG_IMX6_THERMAL is selected.
Signed-off-by: Ye.Li B37916@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic
participants (3)
-
Simon Glass
-
Stefano Babic
-
Ye.Li