1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Thermal sensor driver for Allwinner SOC |
4 | * Copyright (C) 2019 Yangtao Li |
5 | * |
6 | * Based on the work of Icenowy Zheng <icenowy@aosc.io> |
7 | * Based on the work of Ondrej Jirman <megous@megous.com> |
8 | * Based on the work of Josef Gajdusek <atx@atx.name> |
9 | */ |
10 | |
11 | #include <linux/bitmap.h> |
12 | #include <linux/clk.h> |
13 | #include <linux/device.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/module.h> |
16 | #include <linux/nvmem-consumer.h> |
17 | #include <linux/of.h> |
18 | #include <linux/of_platform.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/regmap.h> |
21 | #include <linux/reset.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/thermal.h> |
24 | |
25 | #include "thermal_hwmon.h" |
26 | |
27 | #define MAX_SENSOR_NUM 4 |
28 | |
29 | #define FT_TEMP_MASK GENMASK(11, 0) |
30 | #define TEMP_CALIB_MASK GENMASK(11, 0) |
31 | #define CALIBRATE_DEFAULT 0x800 |
32 | |
33 | #define SUN8I_THS_CTRL0 0x00 |
34 | #define SUN8I_THS_CTRL2 0x40 |
35 | #define SUN8I_THS_IC 0x44 |
36 | #define SUN8I_THS_IS 0x48 |
37 | #define SUN8I_THS_MFC 0x70 |
38 | #define SUN8I_THS_TEMP_CALIB 0x74 |
39 | #define SUN8I_THS_TEMP_DATA 0x80 |
40 | |
41 | #define SUN50I_THS_CTRL0 0x00 |
42 | #define SUN50I_H6_THS_ENABLE 0x04 |
43 | #define SUN50I_H6_THS_PC 0x08 |
44 | #define SUN50I_H6_THS_DIC 0x10 |
45 | #define SUN50I_H6_THS_DIS 0x20 |
46 | #define SUN50I_H6_THS_MFC 0x30 |
47 | #define SUN50I_H6_THS_TEMP_CALIB 0xa0 |
48 | #define SUN50I_H6_THS_TEMP_DATA 0xc0 |
49 | |
50 | #define SUN8I_THS_CTRL0_T_ACQ0(x) (GENMASK(15, 0) & (x)) |
51 | #define SUN8I_THS_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) & (x)) << 16) |
52 | #define SUN8I_THS_DATA_IRQ_STS(x) BIT(x + 8) |
53 | |
54 | #define SUN50I_THS_CTRL0_T_ACQ(x) (GENMASK(15, 0) & ((x) - 1)) |
55 | #define SUN50I_THS_CTRL0_T_SAMPLE_PER(x) ((GENMASK(15, 0) & ((x) - 1)) << 16) |
56 | #define SUN50I_THS_FILTER_EN BIT(2) |
57 | #define SUN50I_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x)) |
58 | #define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12) |
59 | #define SUN50I_H6_THS_DATA_IRQ_STS(x) BIT(x) |
60 | |
61 | struct tsensor { |
62 | struct ths_device *tmdev; |
63 | struct thermal_zone_device *tzd; |
64 | int id; |
65 | }; |
66 | |
67 | struct ths_thermal_chip { |
68 | bool has_mod_clk; |
69 | bool has_bus_clk_reset; |
70 | bool needs_sram; |
71 | int sensor_num; |
72 | int offset; |
73 | int scale; |
74 | int ft_deviation; |
75 | int temp_data_base; |
76 | int (*calibrate)(struct ths_device *tmdev, |
77 | u16 *caldata, int callen); |
78 | int (*init)(struct ths_device *tmdev); |
79 | unsigned long (*irq_ack)(struct ths_device *tmdev); |
80 | int (*calc_temp)(struct ths_device *tmdev, |
81 | int id, int reg); |
82 | }; |
83 | |
84 | struct ths_device { |
85 | const struct ths_thermal_chip *chip; |
86 | struct device *dev; |
87 | struct regmap *regmap; |
88 | struct regmap_field *sram_regmap_field; |
89 | struct reset_control *reset; |
90 | struct clk *bus_clk; |
91 | struct clk *mod_clk; |
92 | struct tsensor sensor[MAX_SENSOR_NUM]; |
93 | }; |
94 | |
95 | /* The H616 needs to have a bit 16 in the SRAM control register cleared. */ |
96 | static const struct reg_field sun8i_ths_sram_reg_field = REG_FIELD(0x0, 16, 16); |
97 | |
98 | /* Temp Unit: millidegree Celsius */ |
99 | static int sun8i_ths_calc_temp(struct ths_device *tmdev, |
100 | int id, int reg) |
101 | { |
102 | return tmdev->chip->offset - (reg * tmdev->chip->scale / 10); |
103 | } |
104 | |
105 | static int sun50i_h5_calc_temp(struct ths_device *tmdev, |
106 | int id, int reg) |
107 | { |
108 | if (reg >= 0x500) |
109 | return -1191 * reg / 10 + 223000; |
110 | else if (!id) |
111 | return -1452 * reg / 10 + 259000; |
112 | else |
113 | return -1590 * reg / 10 + 276000; |
114 | } |
115 | |
116 | static int sun8i_ths_get_temp(struct thermal_zone_device *tz, int *temp) |
117 | { |
118 | struct tsensor *s = thermal_zone_device_priv(tzd: tz); |
119 | struct ths_device *tmdev = s->tmdev; |
120 | int val = 0; |
121 | |
122 | regmap_read(map: tmdev->regmap, reg: tmdev->chip->temp_data_base + |
123 | 0x4 * s->id, val: &val); |
124 | |
125 | /* ths have no data yet */ |
126 | if (!val) |
127 | return -EAGAIN; |
128 | |
129 | *temp = tmdev->chip->calc_temp(tmdev, s->id, val); |
130 | /* |
131 | * According to the original sdk, there are some platforms(rarely) |
132 | * that add a fixed offset value after calculating the temperature |
133 | * value. We can't simply put it on the formula for calculating the |
134 | * temperature above, because the formula for calculating the |
135 | * temperature above is also used when the sensor is calibrated. If |
136 | * do this, the correct calibration formula is hard to know. |
137 | */ |
138 | *temp += tmdev->chip->ft_deviation; |
139 | |
140 | return 0; |
141 | } |
142 | |
143 | static const struct thermal_zone_device_ops ths_ops = { |
144 | .get_temp = sun8i_ths_get_temp, |
145 | }; |
146 | |
147 | static const struct regmap_config config = { |
148 | .reg_bits = 32, |
149 | .val_bits = 32, |
150 | .reg_stride = 4, |
151 | .fast_io = true, |
152 | .max_register = 0xfc, |
153 | }; |
154 | |
155 | static unsigned long sun8i_h3_irq_ack(struct ths_device *tmdev) |
156 | { |
157 | unsigned long irq_bitmap = 0; |
158 | int i, state; |
159 | |
160 | regmap_read(map: tmdev->regmap, SUN8I_THS_IS, val: &state); |
161 | |
162 | for (i = 0; i < tmdev->chip->sensor_num; i++) { |
163 | if (state & SUN8I_THS_DATA_IRQ_STS(i)) { |
164 | regmap_write(map: tmdev->regmap, SUN8I_THS_IS, |
165 | SUN8I_THS_DATA_IRQ_STS(i)); |
166 | bitmap_set(map: &irq_bitmap, start: i, nbits: 1); |
167 | } |
168 | } |
169 | |
170 | return irq_bitmap; |
171 | } |
172 | |
173 | static unsigned long sun50i_h6_irq_ack(struct ths_device *tmdev) |
174 | { |
175 | unsigned long irq_bitmap = 0; |
176 | int i, state; |
177 | |
178 | regmap_read(map: tmdev->regmap, SUN50I_H6_THS_DIS, val: &state); |
179 | |
180 | for (i = 0; i < tmdev->chip->sensor_num; i++) { |
181 | if (state & SUN50I_H6_THS_DATA_IRQ_STS(i)) { |
182 | regmap_write(map: tmdev->regmap, SUN50I_H6_THS_DIS, |
183 | SUN50I_H6_THS_DATA_IRQ_STS(i)); |
184 | bitmap_set(map: &irq_bitmap, start: i, nbits: 1); |
185 | } |
186 | } |
187 | |
188 | return irq_bitmap; |
189 | } |
190 | |
191 | static irqreturn_t sun8i_irq_thread(int irq, void *data) |
192 | { |
193 | struct ths_device *tmdev = data; |
194 | unsigned long irq_bitmap = tmdev->chip->irq_ack(tmdev); |
195 | int i; |
196 | |
197 | for_each_set_bit(i, &irq_bitmap, tmdev->chip->sensor_num) { |
198 | /* We allow some zones to not register. */ |
199 | if (IS_ERR(ptr: tmdev->sensor[i].tzd)) |
200 | continue; |
201 | thermal_zone_device_update(tmdev->sensor[i].tzd, |
202 | THERMAL_EVENT_UNSPECIFIED); |
203 | } |
204 | |
205 | return IRQ_HANDLED; |
206 | } |
207 | |
208 | static int sun8i_h3_ths_calibrate(struct ths_device *tmdev, |
209 | u16 *caldata, int callen) |
210 | { |
211 | int i; |
212 | |
213 | if (!caldata[0] || callen < 2 * tmdev->chip->sensor_num) |
214 | return -EINVAL; |
215 | |
216 | for (i = 0; i < tmdev->chip->sensor_num; i++) { |
217 | int offset = (i % 2) << 4; |
218 | |
219 | regmap_update_bits(map: tmdev->regmap, |
220 | SUN8I_THS_TEMP_CALIB + (4 * (i >> 1)), |
221 | TEMP_CALIB_MASK << offset, |
222 | val: caldata[i] << offset); |
223 | } |
224 | |
225 | return 0; |
226 | } |
227 | |
228 | static int sun50i_h6_ths_calibrate(struct ths_device *tmdev, |
229 | u16 *caldata, int callen) |
230 | { |
231 | struct device *dev = tmdev->dev; |
232 | int i, ft_temp; |
233 | |
234 | if (!caldata[0]) |
235 | return -EINVAL; |
236 | |
237 | /* |
238 | * efuse layout: |
239 | * |
240 | * 0 11 16 27 32 43 48 57 |
241 | * +----------+-----------+-----------+-----------+ |
242 | * | temp | |sensor0| |sensor1| |sensor2| | |
243 | * +----------+-----------+-----------+-----------+ |
244 | * ^ ^ ^ |
245 | * | | | |
246 | * | | sensor3[11:8] |
247 | * | sensor3[7:4] |
248 | * sensor3[3:0] |
249 | * |
250 | * The calibration data on the H6 is the ambient temperature and |
251 | * sensor values that are filled during the factory test stage. |
252 | * |
253 | * The unit of stored FT temperature is 0.1 degree celsius. |
254 | * |
255 | * We need to calculate a delta between measured and caluclated |
256 | * register values and this will become a calibration offset. |
257 | */ |
258 | ft_temp = (caldata[0] & FT_TEMP_MASK) * 100; |
259 | |
260 | for (i = 0; i < tmdev->chip->sensor_num; i++) { |
261 | int sensor_reg, sensor_temp, cdata, offset; |
262 | |
263 | if (i == 3) |
264 | sensor_reg = (caldata[1] >> 12) |
265 | | ((caldata[2] >> 12) << 4) |
266 | | ((caldata[3] >> 12) << 8); |
267 | else |
268 | sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK; |
269 | |
270 | sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg); |
271 | |
272 | /* |
273 | * Calibration data is CALIBRATE_DEFAULT - (calculated |
274 | * temperature from sensor reading at factory temperature |
275 | * minus actual factory temperature) * 14.88 (scale from |
276 | * temperature to register values) |
277 | */ |
278 | cdata = CALIBRATE_DEFAULT - |
279 | ((sensor_temp - ft_temp) * 10 / tmdev->chip->scale); |
280 | if (cdata & ~TEMP_CALIB_MASK) { |
281 | /* |
282 | * Calibration value more than 12-bit, but calibration |
283 | * register is 12-bit. In this case, ths hardware can |
284 | * still work without calibration, although the data |
285 | * won't be so accurate. |
286 | */ |
287 | dev_warn(dev, "sensor%d is not calibrated.\n" , i); |
288 | continue; |
289 | } |
290 | |
291 | offset = (i % 2) * 16; |
292 | regmap_update_bits(map: tmdev->regmap, |
293 | SUN50I_H6_THS_TEMP_CALIB + (i / 2 * 4), |
294 | TEMP_CALIB_MASK << offset, |
295 | val: cdata << offset); |
296 | } |
297 | |
298 | return 0; |
299 | } |
300 | |
301 | static int sun8i_ths_calibrate(struct ths_device *tmdev) |
302 | { |
303 | struct nvmem_cell *calcell; |
304 | struct device *dev = tmdev->dev; |
305 | u16 *caldata; |
306 | size_t callen; |
307 | int ret = 0; |
308 | |
309 | calcell = nvmem_cell_get(dev, id: "calibration" ); |
310 | if (IS_ERR(ptr: calcell)) { |
311 | if (PTR_ERR(ptr: calcell) == -EPROBE_DEFER) |
312 | return -EPROBE_DEFER; |
313 | /* |
314 | * Even if the external calibration data stored in sid is |
315 | * not accessible, the THS hardware can still work, although |
316 | * the data won't be so accurate. |
317 | * |
318 | * The default value of calibration register is 0x800 for |
319 | * every sensor, and the calibration value is usually 0x7xx |
320 | * or 0x8xx, so they won't be away from the default value |
321 | * for a lot. |
322 | * |
323 | * So here we do not return error if the calibration data is |
324 | * not available, except the probe needs deferring. |
325 | */ |
326 | goto out; |
327 | } |
328 | |
329 | caldata = nvmem_cell_read(cell: calcell, len: &callen); |
330 | if (IS_ERR(ptr: caldata)) { |
331 | ret = PTR_ERR(ptr: caldata); |
332 | goto out; |
333 | } |
334 | |
335 | tmdev->chip->calibrate(tmdev, caldata, callen); |
336 | |
337 | kfree(objp: caldata); |
338 | out: |
339 | if (!IS_ERR(ptr: calcell)) |
340 | nvmem_cell_put(cell: calcell); |
341 | return ret; |
342 | } |
343 | |
344 | static void sun8i_ths_reset_control_assert(void *data) |
345 | { |
346 | reset_control_assert(rstc: data); |
347 | } |
348 | |
349 | static struct regmap *sun8i_ths_get_sram_regmap(struct device_node *node) |
350 | { |
351 | struct device_node *sram_node; |
352 | struct platform_device *sram_pdev; |
353 | struct regmap *regmap = NULL; |
354 | |
355 | sram_node = of_parse_phandle(np: node, phandle_name: "allwinner,sram" , index: 0); |
356 | if (!sram_node) |
357 | return ERR_PTR(error: -ENODEV); |
358 | |
359 | sram_pdev = of_find_device_by_node(np: sram_node); |
360 | if (!sram_pdev) { |
361 | /* platform device might not be probed yet */ |
362 | regmap = ERR_PTR(error: -EPROBE_DEFER); |
363 | goto out_put_node; |
364 | } |
365 | |
366 | /* If no regmap is found then the other device driver is at fault */ |
367 | regmap = dev_get_regmap(dev: &sram_pdev->dev, NULL); |
368 | if (!regmap) |
369 | regmap = ERR_PTR(error: -EINVAL); |
370 | |
371 | platform_device_put(pdev: sram_pdev); |
372 | out_put_node: |
373 | of_node_put(node: sram_node); |
374 | return regmap; |
375 | } |
376 | |
377 | static int sun8i_ths_resource_init(struct ths_device *tmdev) |
378 | { |
379 | struct device *dev = tmdev->dev; |
380 | struct platform_device *pdev = to_platform_device(dev); |
381 | void __iomem *base; |
382 | int ret; |
383 | |
384 | base = devm_platform_ioremap_resource(pdev, index: 0); |
385 | if (IS_ERR(ptr: base)) |
386 | return PTR_ERR(ptr: base); |
387 | |
388 | tmdev->regmap = devm_regmap_init_mmio(dev, base, &config); |
389 | if (IS_ERR(ptr: tmdev->regmap)) |
390 | return PTR_ERR(ptr: tmdev->regmap); |
391 | |
392 | if (tmdev->chip->has_bus_clk_reset) { |
393 | tmdev->reset = devm_reset_control_get(dev, NULL); |
394 | if (IS_ERR(ptr: tmdev->reset)) |
395 | return PTR_ERR(ptr: tmdev->reset); |
396 | |
397 | ret = reset_control_deassert(rstc: tmdev->reset); |
398 | if (ret) |
399 | return ret; |
400 | |
401 | ret = devm_add_action_or_reset(dev, sun8i_ths_reset_control_assert, |
402 | tmdev->reset); |
403 | if (ret) |
404 | return ret; |
405 | |
406 | tmdev->bus_clk = devm_clk_get_enabled(dev: &pdev->dev, id: "bus" ); |
407 | if (IS_ERR(ptr: tmdev->bus_clk)) |
408 | return PTR_ERR(ptr: tmdev->bus_clk); |
409 | } |
410 | |
411 | if (tmdev->chip->has_mod_clk) { |
412 | tmdev->mod_clk = devm_clk_get_enabled(dev: &pdev->dev, id: "mod" ); |
413 | if (IS_ERR(ptr: tmdev->mod_clk)) |
414 | return PTR_ERR(ptr: tmdev->mod_clk); |
415 | } |
416 | |
417 | ret = clk_set_rate(clk: tmdev->mod_clk, rate: 24000000); |
418 | if (ret) |
419 | return ret; |
420 | |
421 | if (tmdev->chip->needs_sram) { |
422 | struct regmap *regmap; |
423 | |
424 | regmap = sun8i_ths_get_sram_regmap(node: dev->of_node); |
425 | if (IS_ERR(ptr: regmap)) |
426 | return PTR_ERR(ptr: regmap); |
427 | tmdev->sram_regmap_field = devm_regmap_field_alloc(dev, |
428 | regmap, |
429 | reg_field: sun8i_ths_sram_reg_field); |
430 | if (IS_ERR(ptr: tmdev->sram_regmap_field)) |
431 | return PTR_ERR(ptr: tmdev->sram_regmap_field); |
432 | } |
433 | |
434 | ret = sun8i_ths_calibrate(tmdev); |
435 | if (ret) |
436 | return ret; |
437 | |
438 | return 0; |
439 | } |
440 | |
441 | static int sun8i_h3_thermal_init(struct ths_device *tmdev) |
442 | { |
443 | int val; |
444 | |
445 | /* average over 4 samples */ |
446 | regmap_write(map: tmdev->regmap, SUN8I_THS_MFC, |
447 | SUN50I_THS_FILTER_EN | |
448 | SUN50I_THS_FILTER_TYPE(1)); |
449 | /* |
450 | * clkin = 24MHz |
451 | * filter_samples = 4 |
452 | * period = 0.25s |
453 | * |
454 | * x = period * clkin / 4096 / filter_samples - 1 |
455 | * = 365 |
456 | */ |
457 | val = GENMASK(7 + tmdev->chip->sensor_num, 8); |
458 | regmap_write(map: tmdev->regmap, SUN8I_THS_IC, |
459 | SUN50I_H6_THS_PC_TEMP_PERIOD(365) | val); |
460 | /* |
461 | * T_acq = 20us |
462 | * clkin = 24MHz |
463 | * |
464 | * x = T_acq * clkin - 1 |
465 | * = 479 |
466 | */ |
467 | regmap_write(map: tmdev->regmap, SUN8I_THS_CTRL0, |
468 | SUN8I_THS_CTRL0_T_ACQ0(479)); |
469 | val = GENMASK(tmdev->chip->sensor_num - 1, 0); |
470 | regmap_write(map: tmdev->regmap, SUN8I_THS_CTRL2, |
471 | SUN8I_THS_CTRL2_T_ACQ1(479) | val); |
472 | |
473 | return 0; |
474 | } |
475 | |
476 | static int sun50i_h6_thermal_init(struct ths_device *tmdev) |
477 | { |
478 | int val; |
479 | |
480 | /* The H616 needs to have a bit in the SRAM control register cleared. */ |
481 | if (tmdev->sram_regmap_field) |
482 | regmap_field_write(field: tmdev->sram_regmap_field, val: 0); |
483 | |
484 | /* |
485 | * The manual recommends an overall sample frequency of 50 KHz (20us, |
486 | * 480 cycles at 24 MHz), which provides plenty of time for both the |
487 | * acquisition time (>24 cycles) and the actual conversion time |
488 | * (>14 cycles). |
489 | * The lower half of the CTRL register holds the "acquire time", in |
490 | * clock cycles, which the manual recommends to be 2us: |
491 | * 24MHz * 2us = 48 cycles. |
492 | * The high half of THS_CTRL encodes the sample frequency, in clock |
493 | * cycles: 24MHz * 20us = 480 cycles. |
494 | * This is explained in the H616 manual, but apparently wrongly |
495 | * described in the H6 manual, although the BSP code does the same |
496 | * for both SoCs. |
497 | */ |
498 | regmap_write(map: tmdev->regmap, SUN50I_THS_CTRL0, |
499 | SUN50I_THS_CTRL0_T_ACQ(48) | |
500 | SUN50I_THS_CTRL0_T_SAMPLE_PER(480)); |
501 | /* average over 4 samples */ |
502 | regmap_write(map: tmdev->regmap, SUN50I_H6_THS_MFC, |
503 | SUN50I_THS_FILTER_EN | |
504 | SUN50I_THS_FILTER_TYPE(1)); |
505 | /* |
506 | * clkin = 24MHz |
507 | * filter_samples = 4 |
508 | * period = 0.25s |
509 | * |
510 | * x = period * clkin / 4096 / filter_samples - 1 |
511 | * = 365 |
512 | */ |
513 | regmap_write(map: tmdev->regmap, SUN50I_H6_THS_PC, |
514 | SUN50I_H6_THS_PC_TEMP_PERIOD(365)); |
515 | /* enable sensor */ |
516 | val = GENMASK(tmdev->chip->sensor_num - 1, 0); |
517 | regmap_write(map: tmdev->regmap, SUN50I_H6_THS_ENABLE, val); |
518 | /* thermal data interrupt enable */ |
519 | val = GENMASK(tmdev->chip->sensor_num - 1, 0); |
520 | regmap_write(map: tmdev->regmap, SUN50I_H6_THS_DIC, val); |
521 | |
522 | return 0; |
523 | } |
524 | |
525 | static int sun8i_ths_register(struct ths_device *tmdev) |
526 | { |
527 | int i; |
528 | |
529 | for (i = 0; i < tmdev->chip->sensor_num; i++) { |
530 | tmdev->sensor[i].tmdev = tmdev; |
531 | tmdev->sensor[i].id = i; |
532 | tmdev->sensor[i].tzd = |
533 | devm_thermal_of_zone_register(dev: tmdev->dev, |
534 | id: i, |
535 | data: &tmdev->sensor[i], |
536 | ops: &ths_ops); |
537 | |
538 | /* |
539 | * If an individual zone fails to register for reasons |
540 | * other than probe deferral (eg, a bad DT) then carry |
541 | * on, other zones might register successfully. |
542 | */ |
543 | if (IS_ERR(ptr: tmdev->sensor[i].tzd)) { |
544 | if (PTR_ERR(ptr: tmdev->sensor[i].tzd) == -EPROBE_DEFER) |
545 | return PTR_ERR(ptr: tmdev->sensor[i].tzd); |
546 | continue; |
547 | } |
548 | |
549 | devm_thermal_add_hwmon_sysfs(dev: tmdev->dev, tz: tmdev->sensor[i].tzd); |
550 | } |
551 | |
552 | return 0; |
553 | } |
554 | |
555 | static int sun8i_ths_probe(struct platform_device *pdev) |
556 | { |
557 | struct ths_device *tmdev; |
558 | struct device *dev = &pdev->dev; |
559 | int ret, irq; |
560 | |
561 | tmdev = devm_kzalloc(dev, size: sizeof(*tmdev), GFP_KERNEL); |
562 | if (!tmdev) |
563 | return -ENOMEM; |
564 | |
565 | tmdev->dev = dev; |
566 | tmdev->chip = of_device_get_match_data(dev: &pdev->dev); |
567 | if (!tmdev->chip) |
568 | return -EINVAL; |
569 | |
570 | ret = sun8i_ths_resource_init(tmdev); |
571 | if (ret) |
572 | return ret; |
573 | |
574 | irq = platform_get_irq(pdev, 0); |
575 | if (irq < 0) |
576 | return irq; |
577 | |
578 | ret = tmdev->chip->init(tmdev); |
579 | if (ret) |
580 | return ret; |
581 | |
582 | ret = sun8i_ths_register(tmdev); |
583 | if (ret) |
584 | return ret; |
585 | |
586 | /* |
587 | * Avoid entering the interrupt handler, the thermal device is not |
588 | * registered yet, we deffer the registration of the interrupt to |
589 | * the end. |
590 | */ |
591 | ret = devm_request_threaded_irq(dev, irq, NULL, |
592 | thread_fn: sun8i_irq_thread, |
593 | IRQF_ONESHOT, devname: "ths" , dev_id: tmdev); |
594 | if (ret) |
595 | return ret; |
596 | |
597 | return 0; |
598 | } |
599 | |
600 | static const struct ths_thermal_chip sun8i_a83t_ths = { |
601 | .sensor_num = 3, |
602 | .scale = 705, |
603 | .offset = 191668, |
604 | .temp_data_base = SUN8I_THS_TEMP_DATA, |
605 | .calibrate = sun8i_h3_ths_calibrate, |
606 | .init = sun8i_h3_thermal_init, |
607 | .irq_ack = sun8i_h3_irq_ack, |
608 | .calc_temp = sun8i_ths_calc_temp, |
609 | }; |
610 | |
611 | static const struct ths_thermal_chip sun8i_h3_ths = { |
612 | .sensor_num = 1, |
613 | .scale = 1211, |
614 | .offset = 217000, |
615 | .has_mod_clk = true, |
616 | .has_bus_clk_reset = true, |
617 | .temp_data_base = SUN8I_THS_TEMP_DATA, |
618 | .calibrate = sun8i_h3_ths_calibrate, |
619 | .init = sun8i_h3_thermal_init, |
620 | .irq_ack = sun8i_h3_irq_ack, |
621 | .calc_temp = sun8i_ths_calc_temp, |
622 | }; |
623 | |
624 | static const struct ths_thermal_chip sun8i_r40_ths = { |
625 | .sensor_num = 2, |
626 | .offset = 251086, |
627 | .scale = 1130, |
628 | .has_mod_clk = true, |
629 | .has_bus_clk_reset = true, |
630 | .temp_data_base = SUN8I_THS_TEMP_DATA, |
631 | .calibrate = sun8i_h3_ths_calibrate, |
632 | .init = sun8i_h3_thermal_init, |
633 | .irq_ack = sun8i_h3_irq_ack, |
634 | .calc_temp = sun8i_ths_calc_temp, |
635 | }; |
636 | |
637 | static const struct ths_thermal_chip sun50i_a64_ths = { |
638 | .sensor_num = 3, |
639 | .offset = 260890, |
640 | .scale = 1170, |
641 | .has_mod_clk = true, |
642 | .has_bus_clk_reset = true, |
643 | .temp_data_base = SUN8I_THS_TEMP_DATA, |
644 | .calibrate = sun8i_h3_ths_calibrate, |
645 | .init = sun8i_h3_thermal_init, |
646 | .irq_ack = sun8i_h3_irq_ack, |
647 | .calc_temp = sun8i_ths_calc_temp, |
648 | }; |
649 | |
650 | static const struct ths_thermal_chip sun50i_a100_ths = { |
651 | .sensor_num = 3, |
652 | .has_bus_clk_reset = true, |
653 | .ft_deviation = 8000, |
654 | .offset = 187744, |
655 | .scale = 672, |
656 | .temp_data_base = SUN50I_H6_THS_TEMP_DATA, |
657 | .calibrate = sun50i_h6_ths_calibrate, |
658 | .init = sun50i_h6_thermal_init, |
659 | .irq_ack = sun50i_h6_irq_ack, |
660 | .calc_temp = sun8i_ths_calc_temp, |
661 | }; |
662 | |
663 | static const struct ths_thermal_chip sun50i_h5_ths = { |
664 | .sensor_num = 2, |
665 | .has_mod_clk = true, |
666 | .has_bus_clk_reset = true, |
667 | .temp_data_base = SUN8I_THS_TEMP_DATA, |
668 | .calibrate = sun8i_h3_ths_calibrate, |
669 | .init = sun8i_h3_thermal_init, |
670 | .irq_ack = sun8i_h3_irq_ack, |
671 | .calc_temp = sun50i_h5_calc_temp, |
672 | }; |
673 | |
674 | static const struct ths_thermal_chip sun50i_h6_ths = { |
675 | .sensor_num = 2, |
676 | .has_bus_clk_reset = true, |
677 | .ft_deviation = 7000, |
678 | .offset = 187744, |
679 | .scale = 672, |
680 | .temp_data_base = SUN50I_H6_THS_TEMP_DATA, |
681 | .calibrate = sun50i_h6_ths_calibrate, |
682 | .init = sun50i_h6_thermal_init, |
683 | .irq_ack = sun50i_h6_irq_ack, |
684 | .calc_temp = sun8i_ths_calc_temp, |
685 | }; |
686 | |
687 | static const struct ths_thermal_chip sun20i_d1_ths = { |
688 | .sensor_num = 1, |
689 | .has_bus_clk_reset = true, |
690 | .offset = 188552, |
691 | .scale = 673, |
692 | .temp_data_base = SUN50I_H6_THS_TEMP_DATA, |
693 | .calibrate = sun50i_h6_ths_calibrate, |
694 | .init = sun50i_h6_thermal_init, |
695 | .irq_ack = sun50i_h6_irq_ack, |
696 | .calc_temp = sun8i_ths_calc_temp, |
697 | }; |
698 | |
699 | static const struct ths_thermal_chip sun50i_h616_ths = { |
700 | .sensor_num = 4, |
701 | .has_bus_clk_reset = true, |
702 | .needs_sram = true, |
703 | .ft_deviation = 8000, |
704 | .offset = 263655, |
705 | .scale = 810, |
706 | .temp_data_base = SUN50I_H6_THS_TEMP_DATA, |
707 | .calibrate = sun50i_h6_ths_calibrate, |
708 | .init = sun50i_h6_thermal_init, |
709 | .irq_ack = sun50i_h6_irq_ack, |
710 | .calc_temp = sun8i_ths_calc_temp, |
711 | }; |
712 | |
713 | static const struct of_device_id of_ths_match[] = { |
714 | { .compatible = "allwinner,sun8i-a83t-ths" , .data = &sun8i_a83t_ths }, |
715 | { .compatible = "allwinner,sun8i-h3-ths" , .data = &sun8i_h3_ths }, |
716 | { .compatible = "allwinner,sun8i-r40-ths" , .data = &sun8i_r40_ths }, |
717 | { .compatible = "allwinner,sun50i-a64-ths" , .data = &sun50i_a64_ths }, |
718 | { .compatible = "allwinner,sun50i-a100-ths" , .data = &sun50i_a100_ths }, |
719 | { .compatible = "allwinner,sun50i-h5-ths" , .data = &sun50i_h5_ths }, |
720 | { .compatible = "allwinner,sun50i-h6-ths" , .data = &sun50i_h6_ths }, |
721 | { .compatible = "allwinner,sun20i-d1-ths" , .data = &sun20i_d1_ths }, |
722 | { .compatible = "allwinner,sun50i-h616-ths" , .data = &sun50i_h616_ths }, |
723 | { /* sentinel */ }, |
724 | }; |
725 | MODULE_DEVICE_TABLE(of, of_ths_match); |
726 | |
727 | static struct platform_driver ths_driver = { |
728 | .probe = sun8i_ths_probe, |
729 | .driver = { |
730 | .name = "sun8i-thermal" , |
731 | .of_match_table = of_ths_match, |
732 | }, |
733 | }; |
734 | module_platform_driver(ths_driver); |
735 | |
736 | MODULE_DESCRIPTION("Thermal sensor driver for Allwinner SOC" ); |
737 | MODULE_LICENSE("GPL v2" ); |
738 | |