1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Thermal sensor driver for SpacemiT K1 SoC
4 *
5 * Copyright (C) 2026 Shuwei Wu <shuwei.wu@mailbox.org>
6 */
7 #include <linux/bitfield.h>
8 #include <linux/clk.h>
9 #include <linux/err.h>
10 #include <linux/interrupt.h>
11 #include <linux/io.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/platform_device.h>
16 #include <linux/reset.h>
17 #include <linux/slab.h>
18 #include <linux/thermal.h>
19
20 #include "../thermal_hwmon.h"
21
22 #define K1_TSENSOR_PCTRL_REG 0x00
23 #define K1_TSENSOR_PCTRL_ENABLE BIT(0)
24 #define K1_TSENSOR_PCTRL_TEMP_MODE BIT(3)
25 #define K1_TSENSOR_PCTRL_RAW_SEL BIT(7)
26
27 #define K1_TSENSOR_PCTRL_CTUNE GENMASK(11, 8)
28 #define K1_TSENSOR_PCTRL_SW_CTRL GENMASK(21, 18)
29 #define K1_TSENSOR_PCTRL_HW_AUTO_MODE BIT(23)
30
31 #define K1_TSENSOR_EN_REG 0x08
32 #define K1_TSENSOR_EN_ALL GENMASK(MAX_SENSOR_NUMBER - 1, 0)
33
34 #define K1_TSENSOR_TIME_REG 0x0C
35 #define K1_TSENSOR_TIME_WAIT_REF_CNT GENMASK(3, 0)
36 #define K1_TSENSOR_TIME_ADC_CNT_RST GENMASK(7, 4)
37 #define K1_TSENSOR_TIME_FILTER_PERIOD GENMASK(21, 20)
38 #define K1_TSENSOR_TIME_MASK GENMASK(23, 0)
39
40 #define K1_TSENSOR_INT_CLR_REG 0x10
41 #define K1_TSENSOR_INT_EN_REG 0x14
42 #define K1_TSENSOR_INT_STA_REG 0x18
43
44 #define K1_TSENSOR_INT_EN_MASK BIT(0)
45 #define K1_TSENSOR_INT_MASK(x) (GENMASK(2, 1) << ((x) * 2))
46
47 #define K1_TSENSOR_DATA_BASE_REG 0x20
48 #define K1_TSENSOR_DATA_REG(x) (K1_TSENSOR_DATA_BASE_REG + ((x) / 2) * 4)
49 #define K1_TSENSOR_DATA_LOW_MASK GENMASK(15, 0)
50 #define K1_TSENSOR_DATA_HIGH_MASK GENMASK(31, 16)
51
52 #define K1_TSENSOR_THRSH_BASE_REG 0x40
53 #define K1_TSENSOR_THRSH_REG(x) (K1_TSENSOR_THRSH_BASE_REG + ((x) * 4))
54 #define K1_TSENSOR_THRSH_LOW_MASK GENMASK(15, 0)
55 #define K1_TSENSOR_THRSH_HIGH_MASK GENMASK(31, 16)
56
57 #define MAX_SENSOR_NUMBER 5
58
59 /* Hardware offset value required for temperature calculation */
60 #define TEMPERATURE_OFFSET 278
61
62 struct k1_tsensor_channel {
63 struct k1_tsensor *ts;
64 struct thermal_zone_device *tzd;
65 int id;
66 };
67
68 struct k1_tsensor {
69 void __iomem *base;
70 struct k1_tsensor_channel ch[MAX_SENSOR_NUMBER];
71 };
72
k1_tsensor_init(struct k1_tsensor * ts)73 static void k1_tsensor_init(struct k1_tsensor *ts)
74 {
75 u32 val;
76
77 /* Disable all the interrupts */
78 writel(0xffffffff, ts->base + K1_TSENSOR_INT_EN_REG);
79
80 /* Configure ADC sampling time and filter period */
81 val = readl(ts->base + K1_TSENSOR_TIME_REG);
82 val &= ~K1_TSENSOR_TIME_MASK;
83 val |= K1_TSENSOR_TIME_FILTER_PERIOD |
84 K1_TSENSOR_TIME_ADC_CNT_RST |
85 K1_TSENSOR_TIME_WAIT_REF_CNT;
86 writel(val, ts->base + K1_TSENSOR_TIME_REG);
87
88 /*
89 * Enable all sensors' auto mode, enable dither control,
90 * consecutive mode, and power up sensor.
91 */
92 val = readl(ts->base + K1_TSENSOR_PCTRL_REG);
93 val &= ~K1_TSENSOR_PCTRL_SW_CTRL;
94 val &= ~K1_TSENSOR_PCTRL_CTUNE;
95 val |= K1_TSENSOR_PCTRL_RAW_SEL |
96 K1_TSENSOR_PCTRL_TEMP_MODE |
97 K1_TSENSOR_PCTRL_HW_AUTO_MODE |
98 K1_TSENSOR_PCTRL_ENABLE;
99 writel(val, ts->base + K1_TSENSOR_PCTRL_REG);
100
101 /* Enable each sensor */
102 val = readl(ts->base + K1_TSENSOR_EN_REG);
103 val |= K1_TSENSOR_EN_ALL;
104 writel(val, ts->base + K1_TSENSOR_EN_REG);
105 }
106
k1_tsensor_enable_irq(struct k1_tsensor_channel * ch)107 static void k1_tsensor_enable_irq(struct k1_tsensor_channel *ch)
108 {
109 struct k1_tsensor *ts = ch->ts;
110 u32 val;
111
112 val = readl(ts->base + K1_TSENSOR_INT_CLR_REG);
113 val |= K1_TSENSOR_INT_MASK(ch->id);
114 writel(val, ts->base + K1_TSENSOR_INT_CLR_REG);
115
116 val = readl(ts->base + K1_TSENSOR_INT_EN_REG);
117 val &= ~K1_TSENSOR_INT_MASK(ch->id);
118 writel(val, ts->base + K1_TSENSOR_INT_EN_REG);
119
120 /* Enable thermal interrupt */
121 val = readl(ts->base + K1_TSENSOR_INT_EN_REG);
122 val |= K1_TSENSOR_INT_EN_MASK;
123 writel(val, ts->base + K1_TSENSOR_INT_EN_REG);
124 }
125
126 /*
127 * The conversion formula used is:
128 * T(m°C) = (((raw_value & mask) >> shift) - TEMPERATURE_OFFSET) * 1000
129 */
k1_tsensor_get_temp(struct thermal_zone_device * tz,int * temp)130 static int k1_tsensor_get_temp(struct thermal_zone_device *tz, int *temp)
131 {
132 struct k1_tsensor_channel *ch = thermal_zone_device_priv(tz);
133 struct k1_tsensor *ts = ch->ts;
134 u32 val;
135
136 val = readl(ts->base + K1_TSENSOR_DATA_REG(ch->id));
137 if (ch->id % 2)
138 *temp = FIELD_GET(K1_TSENSOR_DATA_HIGH_MASK, val);
139 else
140 *temp = FIELD_GET(K1_TSENSOR_DATA_LOW_MASK, val);
141
142 *temp -= TEMPERATURE_OFFSET;
143 *temp *= 1000;
144
145 return 0;
146 }
147
148 /*
149 * For each sensor, the hardware threshold register is 32 bits:
150 * - Lower 16 bits [15:0] configure the low threshold temperature.
151 * - Upper 16 bits [31:16] configure the high threshold temperature.
152 */
k1_tsensor_set_trips(struct thermal_zone_device * tz,int low,int high)153 static int k1_tsensor_set_trips(struct thermal_zone_device *tz, int low, int high)
154 {
155 struct k1_tsensor_channel *ch = thermal_zone_device_priv(tz);
156 struct k1_tsensor *ts = ch->ts;
157 u32 val;
158
159 low = clamp_val(low / 1000 + TEMPERATURE_OFFSET, TEMPERATURE_OFFSET,
160 FIELD_MAX(K1_TSENSOR_THRSH_LOW_MASK));
161 high = clamp_val(high / 1000 + TEMPERATURE_OFFSET, TEMPERATURE_OFFSET,
162 FIELD_MAX(K1_TSENSOR_THRSH_HIGH_MASK));
163 if (low >= high)
164 return -EINVAL;
165
166 val = readl(ts->base + K1_TSENSOR_THRSH_REG(ch->id));
167
168 val &= ~(K1_TSENSOR_THRSH_LOW_MASK | K1_TSENSOR_THRSH_HIGH_MASK);
169 val |= FIELD_PREP(K1_TSENSOR_THRSH_LOW_MASK, low);
170 val |= FIELD_PREP(K1_TSENSOR_THRSH_HIGH_MASK, high);
171
172 writel(val, ts->base + K1_TSENSOR_THRSH_REG(ch->id));
173
174 return 0;
175 }
176
177 static const struct thermal_zone_device_ops k1_tsensor_ops = {
178 .get_temp = k1_tsensor_get_temp,
179 .set_trips = k1_tsensor_set_trips,
180 };
181
k1_tsensor_irq_thread(int irq,void * data)182 static irqreturn_t k1_tsensor_irq_thread(int irq, void *data)
183 {
184 struct k1_tsensor *ts = (struct k1_tsensor *)data;
185 int mask, status, i;
186
187 status = readl(ts->base + K1_TSENSOR_INT_STA_REG);
188
189 for (i = 0; i < MAX_SENSOR_NUMBER; i++) {
190 if (status & K1_TSENSOR_INT_MASK(i)) {
191 mask = readl(ts->base + K1_TSENSOR_INT_CLR_REG);
192 mask |= K1_TSENSOR_INT_MASK(i);
193 writel(mask, ts->base + K1_TSENSOR_INT_CLR_REG);
194 thermal_zone_device_update(ts->ch[i].tzd, THERMAL_EVENT_UNSPECIFIED);
195 }
196 }
197
198 return IRQ_HANDLED;
199 }
200
k1_tsensor_shutdown(struct k1_tsensor * ts)201 static void k1_tsensor_shutdown(struct k1_tsensor *ts)
202 {
203 u32 val;
204
205 /* Disable all interrupts */
206 writel(0xffffffff, ts->base + K1_TSENSOR_INT_EN_REG);
207
208 /* Disable all sensors */
209 val = readl(ts->base + K1_TSENSOR_EN_REG);
210 val &= ~K1_TSENSOR_EN_ALL;
211 writel(val, ts->base + K1_TSENSOR_EN_REG);
212
213 /* Clear the sampling configuration set by k1_tsensor_init() */
214 val = readl(ts->base + K1_TSENSOR_TIME_REG);
215 val &= ~(K1_TSENSOR_TIME_FILTER_PERIOD |
216 K1_TSENSOR_TIME_ADC_CNT_RST |
217 K1_TSENSOR_TIME_WAIT_REF_CNT);
218 writel(val, ts->base + K1_TSENSOR_TIME_REG);
219
220 /* Clear the control bits configured by k1_tsensor_init() */
221 val = readl(ts->base + K1_TSENSOR_PCTRL_REG);
222 val &= ~(K1_TSENSOR_PCTRL_RAW_SEL |
223 K1_TSENSOR_PCTRL_TEMP_MODE |
224 K1_TSENSOR_PCTRL_HW_AUTO_MODE |
225 K1_TSENSOR_PCTRL_ENABLE);
226 writel(val, ts->base + K1_TSENSOR_PCTRL_REG);
227 }
228
k1_tsensor_shutdown_action(void * data)229 static void k1_tsensor_shutdown_action(void *data)
230 {
231 k1_tsensor_shutdown(data);
232 }
233
k1_tsensor_probe(struct platform_device * pdev)234 static int k1_tsensor_probe(struct platform_device *pdev)
235 {
236 struct device *dev = &pdev->dev;
237 struct k1_tsensor *ts;
238 struct reset_control *reset;
239 struct clk *clk;
240 int i, irq, ret;
241
242 ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
243 if (!ts)
244 return -ENOMEM;
245
246 ts->base = devm_platform_ioremap_resource(pdev, 0);
247 if (IS_ERR(ts->base))
248 return dev_err_probe(dev, PTR_ERR(ts->base), "Failed to get reg\n");
249
250 reset = devm_reset_control_get_exclusive_deasserted(dev, NULL);
251 if (IS_ERR(reset))
252 return dev_err_probe(dev, PTR_ERR(reset), "Failed to get/deassert reset control\n");
253
254 clk = devm_clk_get_enabled(dev, "core");
255 if (IS_ERR(clk))
256 return dev_err_probe(dev, PTR_ERR(clk), "Failed to get core clock\n");
257
258 clk = devm_clk_get_enabled(dev, "bus");
259 if (IS_ERR(clk))
260 return dev_err_probe(dev, PTR_ERR(clk), "Failed to get bus clock\n");
261
262 k1_tsensor_init(ts);
263
264 for (i = 0; i < MAX_SENSOR_NUMBER; ++i) {
265 ts->ch[i].id = i;
266 ts->ch[i].ts = ts;
267 ts->ch[i].tzd = devm_thermal_of_zone_register(dev, i, ts->ch + i, &k1_tsensor_ops);
268 if (IS_ERR(ts->ch[i].tzd)) {
269 ret = PTR_ERR(ts->ch[i].tzd);
270 goto err_shutdown;
271 }
272
273 /* Attach sysfs hwmon attributes for userspace monitoring */
274 ret = devm_thermal_add_hwmon_sysfs(dev, ts->ch[i].tzd);
275 if (ret)
276 dev_warn(dev, "Failed to add hwmon sysfs attributes\n");
277 }
278
279 irq = platform_get_irq(pdev, 0);
280 if (irq < 0) {
281 ret = irq;
282 goto err_shutdown;
283 }
284
285 ret = devm_request_threaded_irq(dev, irq, NULL,
286 k1_tsensor_irq_thread,
287 IRQF_ONESHOT, "k1_tsensor", ts);
288 if (ret < 0)
289 goto err_shutdown;
290
291 ret = devm_add_action_or_reset(dev, k1_tsensor_shutdown_action, ts);
292 if (ret)
293 return ret;
294
295 /* Enable interrupts only after all zones and the handler are ready */
296 for (i = 0; i < MAX_SENSOR_NUMBER; ++i)
297 k1_tsensor_enable_irq(ts->ch + i);
298
299 platform_set_drvdata(pdev, ts);
300
301 return 0;
302
303 err_shutdown:
304 k1_tsensor_shutdown(ts);
305 return ret;
306 }
307
308 static const struct of_device_id k1_tsensor_dt_ids[] = {
309 { .compatible = "spacemit,k1-tsensor" },
310 { /* sentinel */ }
311 };
312
313 MODULE_DEVICE_TABLE(of, k1_tsensor_dt_ids);
314
315 static struct platform_driver k1_tsensor_driver = {
316 .driver = {
317 .name = "k1_tsensor",
318 .of_match_table = k1_tsensor_dt_ids,
319 },
320 .probe = k1_tsensor_probe,
321 };
322 module_platform_driver(k1_tsensor_driver);
323
324 MODULE_DESCRIPTION("SpacemiT K1 Thermal Sensor Driver");
325 MODULE_AUTHOR("Shuwei Wu <shuwei.wu@mailbox.org>");
326 MODULE_LICENSE("GPL");
327