From: Stefano Babic <sbabic@denx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v7 2/4] DM: thermal: Add imx thermal DM driver
Date: Thu, 20 Nov 2014 16:35:13 +0100 [thread overview]
Message-ID: <546E0A31.7020601@denx.de> (raw)
In-Reply-To: <1416489255-27370-3-git-send-email-B37916@freescale.com>
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
--
=====================================================================
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
=====================================================================
next prev parent reply other threads:[~2014-11-20 15:35 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-20 13:14 [U-Boot] [PATCH v7 0/4] add i.MX6 thermal sensor driver Ye.Li
2014-11-20 13:14 ` [U-Boot] [PATCH v7 1/4] mx6: clock: Add thermal clock enable function Ye.Li
2014-11-21 15:45 ` Stefano Babic
2014-11-20 13:14 ` [U-Boot] [PATCH v7 2/4] DM: thermal: Add imx thermal DM driver Ye.Li
2014-11-20 15:35 ` Stefano Babic [this message]
2014-11-21 15:45 ` Stefano Babic
2015-02-06 4:36 ` Simon Glass
2014-11-20 13:14 ` [U-Boot] [PATCH v7 3/4] mx6: thermal: Check cpu temperature via thermal sensor Ye.Li
2014-11-21 15:45 ` Stefano Babic
2014-11-20 13:14 ` [U-Boot] [PATCH v7 4/4] mx6: mx6sabre common: Enable i.MX thermal DM driver Ye.Li
2014-11-21 15:46 ` Stefano Babic
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=546E0A31.7020601@denx.de \
--to=sbabic@denx.de \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.