2020-03-08 15:34:19

by Anson Huang

[permalink] [raw]
Subject: [PATCH 1/3] dt-bindings: thermal: imx8mm-thermal: Add support for i.MX8MP

Add thermal binding doc for Freescale's i.MX8MP Thermal Monitoring Unit.

Signed-off-by: Anson Huang <[email protected]>
---
Documentation/devicetree/bindings/thermal/imx8mm-thermal.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/imx8mm-thermal.txt b/Documentation/devicetree/bindings/thermal/imx8mm-thermal.txt
index d09ae82..3629d3c 100644
--- a/Documentation/devicetree/bindings/thermal/imx8mm-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/imx8mm-thermal.txt
@@ -1,10 +1,10 @@
* Thermal Monitoring Unit (TMU) on Freescale i.MX8MM SoC

Required properties:
-- compatible : Must be "fsl,imx8mm-tmu".
+- compatible : Must be "fsl,imx8mm-tmu" or "fsl,imx8mp-tmu".
- reg : Address range of TMU registers.
- clocks : TMU's clock source.
-- #thermal-sensor-cells : Should be 0. See ./thermal.txt for a description.
+- #thermal-sensor-cells : Should be 0 or 1. See ./thermal.txt for a description.

Example:
tmu: tmu@30260000 {
--
2.7.4


2020-03-08 15:34:24

by Anson Huang

[permalink] [raw]
Subject: [PATCH 2/3] thermal: imx8mm: Add i.MX8MP support

i.MX8MP shares same TMU with i.MX8MM, the only difference is i.MX8MP
has two thermal sensors while i.MX8MM ONLY has one, add multiple sensors
support for i.MX8MM TMU driver.

Signed-off-by: Anson Huang <[email protected]>
---
drivers/thermal/imx8mm_thermal.c | 108 +++++++++++++++++++++++++++++++++------
1 file changed, 93 insertions(+), 15 deletions(-)

diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c
index d597ceb..8a87ed0 100644
--- a/drivers/thermal/imx8mm_thermal.c
+++ b/drivers/thermal/imx8mm_thermal.c
@@ -10,34 +10,75 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>

#include "thermal_core.h"

#define TER 0x0 /* TMU enable */
+#define TPS 0x4
#define TRITSR 0x20 /* TMU immediate temp */

#define TER_EN BIT(31)
#define TRITSR_VAL_MASK 0xff

-#define TEMP_LOW_LIMIT 10
+#define PROBE_SEL_ALL GENMASK(31, 30)

-struct imx8mm_tmu {
+#define PROBE0_STATUS_OFFSET 30
+#define PROBE0_VAL_OFFSET 16
+#define SIGN_BIT BIT(7)
+#define TEMP_VAL_MASK GENMASK(6, 0)
+
+#define VER1_TEMP_LOW_LIMIT 10
+#define VER2_TEMP_LOW_LIMIT -40
+#define VER2_TEMP_HIGH_LIMIT 125
+
+#define TMU_VER1 0x1
+#define TMU_VER2 0x2
+
+struct thermal_soc_data {
+ u32 num_sensors;
+ u32 version;
+};
+
+struct tmu_sensor {
+ struct imx8mm_tmu *priv;
+ u32 hw_id;
struct thermal_zone_device *tzd;
+};
+
+struct imx8mm_tmu {
void __iomem *base;
struct clk *clk;
+ const struct thermal_soc_data *socdata;
+ struct tmu_sensor sensors[0];
};

static int tmu_get_temp(void *data, int *temp)
{
- struct imx8mm_tmu *tmu = data;
+ struct tmu_sensor *sensor = data;
+ struct imx8mm_tmu *tmu = sensor->priv;
+ bool ready;
u32 val;

- val = readl_relaxed(tmu->base + TRITSR) & TRITSR_VAL_MASK;
- if (val < TEMP_LOW_LIMIT)
- return -EAGAIN;
+ if (tmu->socdata->version == TMU_VER1) {
+ val = readl_relaxed(tmu->base + TRITSR) & TRITSR_VAL_MASK;
+ if (val < VER1_TEMP_LOW_LIMIT)
+ return -EAGAIN;
+ } else {
+ val = readl_relaxed(tmu->base + TRITSR);
+ ready = val & (1 << (sensor->hw_id + PROBE0_STATUS_OFFSET));
+ val = (val >> (sensor->hw_id * PROBE0_VAL_OFFSET))
+ & TRITSR_VAL_MASK;
+ if (val & SIGN_BIT) /* negative */
+ val = (~(val & TEMP_VAL_MASK) + 1);
+
+ *temp = val;
+ if (!ready || *temp < VER2_TEMP_LOW_LIMIT ||
+ *temp > VER2_TEMP_HIGH_LIMIT)
+ return -EAGAIN;
+ }

*temp = val * 1000;

@@ -50,14 +91,21 @@ static struct thermal_zone_of_device_ops tmu_tz_ops = {

static int imx8mm_tmu_probe(struct platform_device *pdev)
{
+ const struct thermal_soc_data *data;
struct imx8mm_tmu *tmu;
u32 val;
int ret;
+ int i;
+
+ data = of_device_get_match_data(&pdev->dev);

- tmu = devm_kzalloc(&pdev->dev, sizeof(struct imx8mm_tmu), GFP_KERNEL);
+ tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors,
+ data->num_sensors), GFP_KERNEL);
if (!tmu)
return -ENOMEM;

+ tmu->socdata = data;
+
tmu->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tmu->base))
return PTR_ERR(tmu->base);
@@ -77,16 +125,35 @@ static int imx8mm_tmu_probe(struct platform_device *pdev)
return ret;
}

- tmu->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
- tmu, &tmu_tz_ops);
- if (IS_ERR(tmu->tzd)) {
- dev_err(&pdev->dev,
- "failed to register thermal zone sensor: %d\n", ret);
- return PTR_ERR(tmu->tzd);
+ /* disable the monitor during initialization */
+ val = readl_relaxed(tmu->base + TER);
+ val &= ~TER_EN;
+ writel_relaxed(val, tmu->base + TER);
+
+ for (i = 0; i < data->num_sensors; i++) {
+ tmu->sensors[i].priv = tmu;
+ tmu->sensors[i].tzd =
+ devm_thermal_zone_of_sensor_register(&pdev->dev, i,
+ &tmu->sensors[i],
+ &tmu_tz_ops);
+ if (IS_ERR(tmu->sensors[i].tzd)) {
+ dev_err(&pdev->dev,
+ "failed to register thermal zone sensor[%d]: %d\n",
+ i, ret);
+ return PTR_ERR(tmu->sensors[i].tzd);
+ }
+ tmu->sensors[i].hw_id = i;
}

platform_set_drvdata(pdev, tmu);

+ /* enable all the probes for V2 TMU */
+ if (tmu->socdata->version == TMU_VER2) {
+ val = readl_relaxed(tmu->base + TPS);
+ val |= PROBE_SEL_ALL;
+ writel_relaxed(val, tmu->base + TPS);
+ }
+
/* enable the monitor */
val = readl_relaxed(tmu->base + TER);
val |= TER_EN;
@@ -111,8 +178,19 @@ static int imx8mm_tmu_remove(struct platform_device *pdev)
return 0;
}

+static struct thermal_soc_data imx8mm_tmu_data = {
+ .num_sensors = 1,
+ .version = TMU_VER1,
+};
+
+static struct thermal_soc_data imx8mp_tmu_data = {
+ .num_sensors = 2,
+ .version = TMU_VER2,
+};
+
static const struct of_device_id imx8mm_tmu_table[] = {
- { .compatible = "fsl,imx8mm-tmu", },
+ { .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, },
+ { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },
{ },
};

--
2.7.4

2020-03-08 15:34:26

by Anson Huang

[permalink] [raw]
Subject: [PATCH 3/3] arm64: dts: imx8mp: Add thermal zones support

i.MX8MP has a TMU inside which supports two thermal zones, add support
for them.

Signed-off-by: Anson Huang <[email protected]>
---
arch/arm64/boot/dts/freescale/imx8mp.dtsi | 63 +++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi
index a253c3f..c621988 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi
@@ -7,6 +7,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>

#include "imx8mp-pinfunc.h"

@@ -43,6 +44,7 @@
clocks = <&clk IMX8MP_CLK_ARM>;
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ #cooling-cells = <2>;
};

A53_1: cpu@1 {
@@ -53,6 +55,7 @@
clocks = <&clk IMX8MP_CLK_ARM>;
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ #cooling-cells = <2>;
};

A53_2: cpu@2 {
@@ -63,6 +66,7 @@
clocks = <&clk IMX8MP_CLK_ARM>;
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ #cooling-cells = <2>;
};

A53_3: cpu@3 {
@@ -73,6 +77,7 @@
clocks = <&clk IMX8MP_CLK_ARM>;
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ #cooling-cells = <2>;
};

A53_L2: l2-cache0 {
@@ -127,6 +132,57 @@
method = "smc";
};

+ thermal-zones {
+ cpu-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <2000>;
+ thermal-sensors = <&tmu 0x0>;
+ trips {
+ cpu_alert0: trip0 {
+ temperature = <85000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit0: trip1 {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device =
+ <&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ soc-thermal {
+ polling-delay-passive = <250>;
+ polling-delay = <2000>;
+ thermal-sensors = <&tmu 0x1>;
+ trips {
+ soc_alert0: trip0 {
+ temperature = <85000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ soc_crit0: trip1 {
+ temperature = <95000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
@@ -215,6 +271,13 @@
gpio-ranges = <&iomuxc 0 114 30>;
};

+ tmu: tmu@30260000 {
+ compatible = "fsl,imx8mp-tmu";
+ reg = <0x30260000 0x10000>;
+ clocks = <&clk IMX8MP_CLK_TSENSOR_ROOT>;
+ #thermal-sensor-cells = <1>;
+ };
+
wdog1: watchdog@30280000 {
compatible = "fsl,imx8mp-wdt", "fsl,imx21-wdt";
reg = <0x30280000 0x10000>;
--
2.7.4

2020-03-19 18:25:55

by Daniel Lezcano

[permalink] [raw]
Subject: Re: [PATCH 2/3] thermal: imx8mm: Add i.MX8MP support

On 08/03/2020 16:27, Anson Huang wrote:
> i.MX8MP shares same TMU with i.MX8MM, the only difference is i.MX8MP
> has two thermal sensors while i.MX8MM ONLY has one, add multiple sensors
> support for i.MX8MM TMU driver.
>
> Signed-off-by: Anson Huang <[email protected]>
> ---
> drivers/thermal/imx8mm_thermal.c | 108 +++++++++++++++++++++++++++++++++------
> 1 file changed, 93 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c
> index d597ceb..8a87ed0 100644
> --- a/drivers/thermal/imx8mm_thermal.c
> +++ b/drivers/thermal/imx8mm_thermal.c
> @@ -10,34 +10,75 @@
> #include <linux/io.h>
> #include <linux/module.h>
> #include <linux/of.h>
> -#include <linux/of_address.h>
> +#include <linux/of_device.h>
> #include <linux/platform_device.h>
> #include <linux/thermal.h>
>
> #include "thermal_core.h"
>
> #define TER 0x0 /* TMU enable */
> +#define TPS 0x4
> #define TRITSR 0x20 /* TMU immediate temp */
>
> #define TER_EN BIT(31)
> #define TRITSR_VAL_MASK 0xff
>
> -#define TEMP_LOW_LIMIT 10
> +#define PROBE_SEL_ALL GENMASK(31, 30)
>
> -struct imx8mm_tmu {
> +#define PROBE0_STATUS_OFFSET 30
> +#define PROBE0_VAL_OFFSET 16
> +#define SIGN_BIT BIT(7)
> +#define TEMP_VAL_MASK GENMASK(6, 0)
> +
> +#define VER1_TEMP_LOW_LIMIT 10
> +#define VER2_TEMP_LOW_LIMIT -40
> +#define VER2_TEMP_HIGH_LIMIT 125
> +
> +#define TMU_VER1 0x1
> +#define TMU_VER2 0x2
> +
> +struct thermal_soc_data {
> + u32 num_sensors;
> + u32 version;
> +};
> +
> +struct tmu_sensor {
> + struct imx8mm_tmu *priv;
> + u32 hw_id;
> struct thermal_zone_device *tzd;
> +};
> +
> +struct imx8mm_tmu {
> void __iomem *base;
> struct clk *clk;
> + const struct thermal_soc_data *socdata;
> + struct tmu_sensor sensors[0];
> };
>
> static int tmu_get_temp(void *data, int *temp)
> {
> - struct imx8mm_tmu *tmu = data;
> + struct tmu_sensor *sensor = data;
> + struct imx8mm_tmu *tmu = sensor->priv;
> + bool ready;
> u32 val;
>
> - val = readl_relaxed(tmu->base + TRITSR) & TRITSR_VAL_MASK;
> - if (val < TEMP_LOW_LIMIT)
> - return -EAGAIN;
> + if (tmu->socdata->version == TMU_VER1) {

Don't do this here, implement a callback to read the temp, store it in
the socdata and call it directly from here.

So you end up with something simple like:

*temp = tmu->socdata->get_temp(...);

> + val = readl_relaxed(tmu->base + TRITSR) & TRITSR_VAL_MASK;
> + if (val < VER1_TEMP_LOW_LIMIT)
> + return -EAGAIN;> + } else {
> + val = readl_relaxed(tmu->base + TRITSR);
> + ready = val & (1 << (sensor->hw_id + PROBE0_STATUS_OFFSET));

test_bit()?

> + val = (val >> (sensor->hw_id * PROBE0_VAL_OFFSET))
> + & TRITSR_VAL_MASK;
> + if (val & SIGN_BIT) /* negative */
> + val = (~(val & TEMP_VAL_MASK) + 1);

Please have a look at the different bitops available to simplify this
decoding.

> + *temp = val;
> + if (!ready || *temp < VER2_TEMP_LOW_LIMIT ||
> + *temp > VER2_TEMP_HIGH_LIMIT)
> + return -EAGAIN;
> + }
>
> *temp = val * 1000;
>
> @@ -50,14 +91,21 @@ static struct thermal_zone_of_device_ops tmu_tz_ops = {
>
> static int imx8mm_tmu_probe(struct platform_device *pdev)
> {
> + const struct thermal_soc_data *data;
> struct imx8mm_tmu *tmu;
> u32 val;
> int ret;
> + int i;
> +
> + data = of_device_get_match_data(&pdev->dev);
>
> - tmu = devm_kzalloc(&pdev->dev, sizeof(struct imx8mm_tmu), GFP_KERNEL);
> + tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors,
> + data->num_sensors), GFP_KERNEL);
> if (!tmu)
> return -ENOMEM;
>
> + tmu->socdata = data;
> +
> tmu->base = devm_platform_ioremap_resource(pdev, 0);
> if (IS_ERR(tmu->base))
> return PTR_ERR(tmu->base);
> @@ -77,16 +125,35 @@ static int imx8mm_tmu_probe(struct platform_device *pdev)
> return ret;
> }
>
> - tmu->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
> - tmu, &tmu_tz_ops);
> - if (IS_ERR(tmu->tzd)) {
> - dev_err(&pdev->dev,
> - "failed to register thermal zone sensor: %d\n", ret);
> - return PTR_ERR(tmu->tzd);
> + /* disable the monitor during initialization */
> + val = readl_relaxed(tmu->base + TER);
> + val &= ~TER_EN;
> + writel_relaxed(val, tmu->base + TER);

Could you wrap those calls inside a small helper function with a self
described name?

> +
> + for (i = 0; i < data->num_sensors; i++) {
> + tmu->sensors[i].priv = tmu;
> + tmu->sensors[i].tzd =
> + devm_thermal_zone_of_sensor_register(&pdev->dev, i,
> + &tmu->sensors[i],
> + &tmu_tz_ops);
> + if (IS_ERR(tmu->sensors[i].tzd)) {
> + dev_err(&pdev->dev,
> + "failed to register thermal zone sensor[%d]: %d\n",
> + i, ret);
> + return PTR_ERR(tmu->sensors[i].tzd);
> + }
> + tmu->sensors[i].hw_id = i;

May be you can store the offset directly, so it is not computed every
time the temperature is read?

> }
>
> platform_set_drvdata(pdev, tmu);
>
> + /* enable all the probes for V2 TMU */
> + if (tmu->socdata->version == TMU_VER2) {
> + val = readl_relaxed(tmu->base + TPS);
> + val |= PROBE_SEL_ALL;
> + writel_relaxed(val, tmu->base + TPS);
> + }

Same comment as before about putting these in a helper

> /* enable the monitor */
> val = readl_relaxed(tmu->base + TER);
> val |= TER_EN;
> @@ -111,8 +178,19 @@ static int imx8mm_tmu_remove(struct platform_device *pdev)
> return 0;
> }
>
> +static struct thermal_soc_data imx8mm_tmu_data = {
> + .num_sensors = 1,
> + .version = TMU_VER1,
> +};
> +
> +static struct thermal_soc_data imx8mp_tmu_data = {
> + .num_sensors = 2,
> + .version = TMU_VER2,
> +};
> +
> static const struct of_device_id imx8mm_tmu_table[] = {
> - { .compatible = "fsl,imx8mm-tmu", },
> + { .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, },
> + { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },
> { },
> };
>
>


--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

2020-03-20 03:43:36

by Anson Huang

[permalink] [raw]
Subject: RE: [PATCH 2/3] thermal: imx8mm: Add i.MX8MP support

Hi, Daniel

> Subject: Re: [PATCH 2/3] thermal: imx8mm: Add i.MX8MP support
>
> On 08/03/2020 16:27, Anson Huang wrote:
> > i.MX8MP shares same TMU with i.MX8MM, the only difference is i.MX8MP
> > has two thermal sensors while i.MX8MM ONLY has one, add multiple
> > sensors support for i.MX8MM TMU driver.
> >
> > Signed-off-by: Anson Huang <[email protected]>
> > ---
> > drivers/thermal/imx8mm_thermal.c | 108
> > +++++++++++++++++++++++++++++++++------
> > 1 file changed, 93 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/thermal/imx8mm_thermal.c
> > b/drivers/thermal/imx8mm_thermal.c
> > index d597ceb..8a87ed0 100644
> > --- a/drivers/thermal/imx8mm_thermal.c
> > +++ b/drivers/thermal/imx8mm_thermal.c
> > @@ -10,34 +10,75 @@
> > #include <linux/io.h>
> > #include <linux/module.h>
> > #include <linux/of.h>
> > -#include <linux/of_address.h>
> > +#include <linux/of_device.h>
> > #include <linux/platform_device.h>
> > #include <linux/thermal.h>
> >
> > #include "thermal_core.h"
> >
> > #define TER 0x0 /* TMU enable */
> > +#define TPS 0x4
> > #define TRITSR 0x20 /* TMU immediate temp */
> >
> > #define TER_EN BIT(31)
> > #define TRITSR_VAL_MASK 0xff
> >
> > -#define TEMP_LOW_LIMIT 10
> > +#define PROBE_SEL_ALL GENMASK(31, 30)
> >
> > -struct imx8mm_tmu {
> > +#define PROBE0_STATUS_OFFSET 30
> > +#define PROBE0_VAL_OFFSET 16
> > +#define SIGN_BIT BIT(7)
> > +#define TEMP_VAL_MASK GENMASK(6, 0)
> > +
> > +#define VER1_TEMP_LOW_LIMIT 10
> > +#define VER2_TEMP_LOW_LIMIT -40
> > +#define VER2_TEMP_HIGH_LIMIT 125
> > +
> > +#define TMU_VER1 0x1
> > +#define TMU_VER2 0x2
> > +
> > +struct thermal_soc_data {
> > + u32 num_sensors;
> > + u32 version;
> > +};
> > +
> > +struct tmu_sensor {
> > + struct imx8mm_tmu *priv;
> > + u32 hw_id;
> > struct thermal_zone_device *tzd;
> > +};
> > +
> > +struct imx8mm_tmu {
> > void __iomem *base;
> > struct clk *clk;
> > + const struct thermal_soc_data *socdata;
> > + struct tmu_sensor sensors[0];
> > };
> >
> > static int tmu_get_temp(void *data, int *temp) {
> > - struct imx8mm_tmu *tmu = data;
> > + struct tmu_sensor *sensor = data;
> > + struct imx8mm_tmu *tmu = sensor->priv;
> > + bool ready;
> > u32 val;
> >
> > - val = readl_relaxed(tmu->base + TRITSR) & TRITSR_VAL_MASK;
> > - if (val < TEMP_LOW_LIMIT)
> > - return -EAGAIN;
> > + if (tmu->socdata->version == TMU_VER1) {
>
> Don't do this here, implement a callback to read the temp, store it in the
> socdata and call it directly from here.
>
> So you end up with something simple like:
>
> *temp = tmu->socdata->get_temp(...);
>

Make sense, do it in V2.


> > + val = readl_relaxed(tmu->base + TRITSR) &
> TRITSR_VAL_MASK;
> > + if (val < VER1_TEMP_LOW_LIMIT)
> > + return -EAGAIN;> + } else {
> > + val = readl_relaxed(tmu->base + TRITSR);
> > + ready = val & (1 << (sensor->hw_id +
> PROBE0_STATUS_OFFSET));
>
> test_bit()?

OK.

>
> > + val = (val >> (sensor->hw_id * PROBE0_VAL_OFFSET))
> > + & TRITSR_VAL_MASK;
> > + if (val & SIGN_BIT) /* negative */
> > + val = (~(val & TEMP_VAL_MASK) + 1);
>
> Please have a look at the different bitops available to simplify this decoding.

I can ONLY find the FIELD_GET for getting the temperature value field, for the positive
and negative value check, I can't find any API for it.


>
> > + *temp = val;
> > + if (!ready || *temp < VER2_TEMP_LOW_LIMIT ||
> > + *temp > VER2_TEMP_HIGH_LIMIT)
> > + return -EAGAIN;
> > + }
> >
> > *temp = val * 1000;
> >
> > @@ -50,14 +91,21 @@ static struct thermal_zone_of_device_ops
> > tmu_tz_ops = {
> >
> > static int imx8mm_tmu_probe(struct platform_device *pdev) {
> > + const struct thermal_soc_data *data;
> > struct imx8mm_tmu *tmu;
> > u32 val;
> > int ret;
> > + int i;
> > +
> > + data = of_device_get_match_data(&pdev->dev);
> >
> > - tmu = devm_kzalloc(&pdev->dev, sizeof(struct imx8mm_tmu),
> GFP_KERNEL);
> > + tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors,
> > + data->num_sensors), GFP_KERNEL);
> > if (!tmu)
> > return -ENOMEM;
> >
> > + tmu->socdata = data;
> > +
> > tmu->base = devm_platform_ioremap_resource(pdev, 0);
> > if (IS_ERR(tmu->base))
> > return PTR_ERR(tmu->base);
> > @@ -77,16 +125,35 @@ static int imx8mm_tmu_probe(struct
> platform_device *pdev)
> > return ret;
> > }
> >
> > - tmu->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
> > - tmu, &tmu_tz_ops);
> > - if (IS_ERR(tmu->tzd)) {
> > - dev_err(&pdev->dev,
> > - "failed to register thermal zone sensor: %d\n", ret);
> > - return PTR_ERR(tmu->tzd);
> > + /* disable the monitor during initialization */
> > + val = readl_relaxed(tmu->base + TER);
> > + val &= ~TER_EN;
> > + writel_relaxed(val, tmu->base + TER);
>
> Could you wrap those calls inside a small helper function with a self
> described name?

OK.

>
> > +
> > + for (i = 0; i < data->num_sensors; i++) {
> > + tmu->sensors[i].priv = tmu;
> > + tmu->sensors[i].tzd =
> > + devm_thermal_zone_of_sensor_register(&pdev->dev,
> i,
> > + &tmu->sensors[i],
> > + &tmu_tz_ops);
> > + if (IS_ERR(tmu->sensors[i].tzd)) {
> > + dev_err(&pdev->dev,
> > + "failed to register thermal zone
> sensor[%d]: %d\n",
> > + i, ret);
> > + return PTR_ERR(tmu->sensors[i].tzd);
> > + }
> > + tmu->sensors[i].hw_id = i;
>
> May be you can store the offset directly, so it is not computed every time the
> temperature is read?

There are 2 place need to identify the sensor ID, the ready bit and the temperature
value field, so I think the hw_id is necessary, and it also make the logic easy to read.


>
> > }
> >
> > platform_set_drvdata(pdev, tmu);
> >
> > + /* enable all the probes for V2 TMU */
> > + if (tmu->socdata->version == TMU_VER2) {
> > + val = readl_relaxed(tmu->base + TPS);
> > + val |= PROBE_SEL_ALL;
> > + writel_relaxed(val, tmu->base + TPS);
> > + }
>
> Same comment as before about putting these in a helper

OK

Please help review V2 patch.

Thanks,
Anson