Skip to content

Commit 2b8f1f0

Browse files
Anson-Huangdlezcano
authored andcommitted
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]> Signed-off-by: Daniel Lezcano <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 526e6ef commit 2b8f1f0

File tree

1 file changed

+130
-24
lines changed

1 file changed

+130
-24
lines changed

drivers/thermal/imx8mm_thermal.c

Lines changed: 130 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,59 +5,143 @@
55
* Author: Anson Huang <[email protected]>
66
*/
77

8+
#include <linux/bitfield.h>
89
#include <linux/clk.h>
910
#include <linux/err.h>
1011
#include <linux/io.h>
1112
#include <linux/module.h>
1213
#include <linux/of.h>
13-
#include <linux/of_address.h>
14+
#include <linux/of_device.h>
1415
#include <linux/platform_device.h>
1516
#include <linux/thermal.h>
1617

1718
#include "thermal_core.h"
1819

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

2224
#define TER_EN BIT(31)
23-
#define TRITSR_VAL_MASK 0xff
25+
#define TRITSR_TEMP0_VAL_MASK 0xff
26+
#define TRITSR_TEMP1_VAL_MASK 0xff0000
2427

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

27-
struct imx8mm_tmu {
30+
#define probe_status_offset(x) (30 + x)
31+
#define SIGN_BIT BIT(7)
32+
#define TEMP_VAL_MASK GENMASK(6, 0)
33+
34+
#define VER1_TEMP_LOW_LIMIT 10000
35+
#define VER2_TEMP_LOW_LIMIT -40000
36+
#define VER2_TEMP_HIGH_LIMIT 125000
37+
38+
#define TMU_VER1 0x1
39+
#define TMU_VER2 0x2
40+
41+
struct thermal_soc_data {
42+
u32 num_sensors;
43+
u32 version;
44+
int (*get_temp)(void *, int *);
45+
};
46+
47+
struct tmu_sensor {
48+
struct imx8mm_tmu *priv;
49+
u32 hw_id;
2850
struct thermal_zone_device *tzd;
51+
};
52+
53+
struct imx8mm_tmu {
2954
void __iomem *base;
3055
struct clk *clk;
56+
const struct thermal_soc_data *socdata;
57+
struct tmu_sensor sensors[0];
3158
};
3259

33-
static int tmu_get_temp(void *data, int *temp)
60+
static int imx8mm_tmu_get_temp(void *data, int *temp)
3461
{
35-
struct imx8mm_tmu *tmu = data;
62+
struct tmu_sensor *sensor = data;
63+
struct imx8mm_tmu *tmu = sensor->priv;
3664
u32 val;
3765

38-
val = readl_relaxed(tmu->base + TRITSR) & TRITSR_VAL_MASK;
39-
if (val < TEMP_LOW_LIMIT)
66+
val = readl_relaxed(tmu->base + TRITSR) & TRITSR_TEMP0_VAL_MASK;
67+
*temp = val * 1000;
68+
if (*temp < VER1_TEMP_LOW_LIMIT)
4069
return -EAGAIN;
4170

71+
return 0;
72+
}
73+
74+
static int imx8mp_tmu_get_temp(void *data, int *temp)
75+
{
76+
struct tmu_sensor *sensor = data;
77+
struct imx8mm_tmu *tmu = sensor->priv;
78+
bool ready;
79+
u32 val;
80+
81+
ready = test_bit(probe_status_offset(sensor->hw_id),
82+
tmu->base + TRITSR);
83+
if (!ready)
84+
return -EAGAIN;
85+
86+
val = readl_relaxed(tmu->base + TRITSR);
87+
val = sensor->hw_id ? FIELD_GET(TRITSR_TEMP1_VAL_MASK, val) :
88+
FIELD_GET(TRITSR_TEMP0_VAL_MASK, val);
89+
if (val & SIGN_BIT) /* negative */
90+
val = (~(val & TEMP_VAL_MASK) + 1);
91+
4292
*temp = val * 1000;
93+
if (*temp < VER2_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)
94+
return -EAGAIN;
4395

4496
return 0;
4597
}
4698

99+
static int tmu_get_temp(void *data, int *temp)
100+
{
101+
struct tmu_sensor *sensor = data;
102+
struct imx8mm_tmu *tmu = sensor->priv;
103+
104+
return tmu->socdata->get_temp(data, temp);
105+
}
106+
47107
static struct thermal_zone_of_device_ops tmu_tz_ops = {
48108
.get_temp = tmu_get_temp,
49109
};
50110

111+
static void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable)
112+
{
113+
u32 val;
114+
115+
val = readl_relaxed(tmu->base + TER);
116+
val = enable ? (val | TER_EN) : (val & ~TER_EN);
117+
writel_relaxed(val, tmu->base + TER);
118+
}
119+
120+
static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu)
121+
{
122+
u32 val;
123+
124+
val = readl_relaxed(tmu->base + TPS);
125+
val |= PROBE_SEL_ALL;
126+
writel_relaxed(val, tmu->base + TPS);
127+
}
128+
51129
static int imx8mm_tmu_probe(struct platform_device *pdev)
52130
{
131+
const struct thermal_soc_data *data;
53132
struct imx8mm_tmu *tmu;
54-
u32 val;
55133
int ret;
134+
int i;
135+
136+
data = of_device_get_match_data(&pdev->dev);
56137

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

143+
tmu->socdata = data;
144+
61145
tmu->base = devm_platform_ioremap_resource(pdev, 0);
62146
if (IS_ERR(tmu->base))
63147
return PTR_ERR(tmu->base);
@@ -77,42 +161,64 @@ static int imx8mm_tmu_probe(struct platform_device *pdev)
77161
return ret;
78162
}
79163

80-
tmu->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
81-
tmu, &tmu_tz_ops);
82-
if (IS_ERR(tmu->tzd)) {
83-
dev_err(&pdev->dev,
84-
"failed to register thermal zone sensor: %d\n", ret);
85-
return PTR_ERR(tmu->tzd);
164+
/* disable the monitor during initialization */
165+
imx8mm_tmu_enable(tmu, false);
166+
167+
for (i = 0; i < data->num_sensors; i++) {
168+
tmu->sensors[i].priv = tmu;
169+
tmu->sensors[i].tzd =
170+
devm_thermal_zone_of_sensor_register(&pdev->dev, i,
171+
&tmu->sensors[i],
172+
&tmu_tz_ops);
173+
if (IS_ERR(tmu->sensors[i].tzd)) {
174+
dev_err(&pdev->dev,
175+
"failed to register thermal zone sensor[%d]: %d\n",
176+
i, ret);
177+
return PTR_ERR(tmu->sensors[i].tzd);
178+
}
179+
tmu->sensors[i].hw_id = i;
86180
}
87181

88182
platform_set_drvdata(pdev, tmu);
89183

184+
/* enable all the probes for V2 TMU */
185+
if (tmu->socdata->version == TMU_VER2)
186+
imx8mm_tmu_probe_sel_all(tmu);
187+
90188
/* enable the monitor */
91-
val = readl_relaxed(tmu->base + TER);
92-
val |= TER_EN;
93-
writel_relaxed(val, tmu->base + TER);
189+
imx8mm_tmu_enable(tmu, true);
94190

95191
return 0;
96192
}
97193

98194
static int imx8mm_tmu_remove(struct platform_device *pdev)
99195
{
100196
struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);
101-
u32 val;
102197

103198
/* disable TMU */
104-
val = readl_relaxed(tmu->base + TER);
105-
val &= ~TER_EN;
106-
writel_relaxed(val, tmu->base + TER);
199+
imx8mm_tmu_enable(tmu, false);
107200

108201
clk_disable_unprepare(tmu->clk);
109202
platform_set_drvdata(pdev, NULL);
110203

111204
return 0;
112205
}
113206

207+
static struct thermal_soc_data imx8mm_tmu_data = {
208+
.num_sensors = 1,
209+
.version = TMU_VER1,
210+
.get_temp = imx8mm_tmu_get_temp,
211+
};
212+
213+
static struct thermal_soc_data imx8mp_tmu_data = {
214+
.num_sensors = 2,
215+
.version = TMU_VER2,
216+
.get_temp = imx8mp_tmu_get_temp,
217+
};
218+
114219
static const struct of_device_id imx8mm_tmu_table[] = {
115-
{ .compatible = "fsl,imx8mm-tmu", },
220+
{ .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, },
221+
{ .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },
116222
{ },
117223
};
118224

0 commit comments

Comments
 (0)