xref: /linux/drivers/thermal/spacemit/k1_tsensor.c (revision b81e34131907d2c243c51117a4aff8dbe22ccc9c)
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