1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/cpufreq.h>
21#include <linux/delay.h>
22#include <linux/interrupt.h>
23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/io.h>
26#include <linux/of_device.h>
27
28#include "thermal_core.h"
29
30#define HI6220_TEMP0_LAG (0x0)
31#define HI6220_TEMP0_TH (0x4)
32#define HI6220_TEMP0_RST_TH (0x8)
33#define HI6220_TEMP0_CFG (0xC)
34#define HI6220_TEMP0_CFG_SS_MSK (0xF000)
35#define HI6220_TEMP0_CFG_HDAK_MSK (0x30)
36#define HI6220_TEMP0_EN (0x10)
37#define HI6220_TEMP0_INT_EN (0x14)
38#define HI6220_TEMP0_INT_CLR (0x18)
39#define HI6220_TEMP0_RST_MSK (0x1C)
40#define HI6220_TEMP0_VALUE (0x28)
41
42#define HI3660_OFFSET(chan) ((chan) * 0x40)
43#define HI3660_TEMP(chan) (HI3660_OFFSET(chan) + 0x1C)
44#define HI3660_TH(chan) (HI3660_OFFSET(chan) + 0x20)
45#define HI3660_LAG(chan) (HI3660_OFFSET(chan) + 0x28)
46#define HI3660_INT_EN(chan) (HI3660_OFFSET(chan) + 0x2C)
47#define HI3660_INT_CLR(chan) (HI3660_OFFSET(chan) + 0x30)
48
49#define HI6220_TEMP_BASE (-60000)
50#define HI6220_TEMP_RESET (100000)
51#define HI6220_TEMP_STEP (785)
52#define HI6220_TEMP_LAG (3500)
53
54#define HI3660_TEMP_BASE (-63780)
55#define HI3660_TEMP_STEP (205)
56#define HI3660_TEMP_LAG (4000)
57
58#define HI6220_CLUSTER0_SENSOR 2
59#define HI6220_CLUSTER1_SENSOR 1
60
61#define HI3660_LITTLE_SENSOR 0
62#define HI3660_BIG_SENSOR 1
63#define HI3660_G3D_SENSOR 2
64#define HI3660_MODEM_SENSOR 3
65
66struct hisi_thermal_data;
67
68struct hisi_thermal_sensor {
69 struct hisi_thermal_data *data;
70 struct thermal_zone_device *tzd;
71 const char *irq_name;
72 uint32_t id;
73 uint32_t thres_temp;
74};
75
76struct hisi_thermal_ops {
77 int (*get_temp)(struct hisi_thermal_sensor *sensor);
78 int (*enable_sensor)(struct hisi_thermal_sensor *sensor);
79 int (*disable_sensor)(struct hisi_thermal_sensor *sensor);
80 int (*irq_handler)(struct hisi_thermal_sensor *sensor);
81 int (*probe)(struct hisi_thermal_data *data);
82};
83
84struct hisi_thermal_data {
85 const struct hisi_thermal_ops *ops;
86 struct hisi_thermal_sensor *sensor;
87 struct platform_device *pdev;
88 struct clk *clk;
89 void __iomem *regs;
90 int nr_sensors;
91};
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111static inline int hi6220_thermal_step_to_temp(int step)
112{
113 return HI6220_TEMP_BASE + (step * HI6220_TEMP_STEP);
114}
115
116static inline int hi6220_thermal_temp_to_step(int temp)
117{
118 return DIV_ROUND_UP(temp - HI6220_TEMP_BASE, HI6220_TEMP_STEP);
119}
120
121
122
123
124
125
126
127
128
129static inline int hi3660_thermal_step_to_temp(int step)
130{
131 return HI3660_TEMP_BASE + step * HI3660_TEMP_STEP;
132}
133
134static inline int hi3660_thermal_temp_to_step(int temp)
135{
136 return DIV_ROUND_UP(temp - HI3660_TEMP_BASE, HI3660_TEMP_STEP);
137}
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170static inline void hi6220_thermal_set_lag(void __iomem *addr, int value)
171{
172 writel(DIV_ROUND_UP(value, HI6220_TEMP_STEP) & 0x1F,
173 addr + HI6220_TEMP0_LAG);
174}
175
176static inline void hi6220_thermal_alarm_clear(void __iomem *addr, int value)
177{
178 writel(value, addr + HI6220_TEMP0_INT_CLR);
179}
180
181static inline void hi6220_thermal_alarm_enable(void __iomem *addr, int value)
182{
183 writel(value, addr + HI6220_TEMP0_INT_EN);
184}
185
186static inline void hi6220_thermal_alarm_set(void __iomem *addr, int temp)
187{
188 writel(hi6220_thermal_temp_to_step(temp) | 0x0FFFFFF00,
189 addr + HI6220_TEMP0_TH);
190}
191
192static inline void hi6220_thermal_reset_set(void __iomem *addr, int temp)
193{
194 writel(hi6220_thermal_temp_to_step(temp), addr + HI6220_TEMP0_RST_TH);
195}
196
197static inline void hi6220_thermal_reset_enable(void __iomem *addr, int value)
198{
199 writel(value, addr + HI6220_TEMP0_RST_MSK);
200}
201
202static inline void hi6220_thermal_enable(void __iomem *addr, int value)
203{
204 writel(value, addr + HI6220_TEMP0_EN);
205}
206
207static inline int hi6220_thermal_get_temperature(void __iomem *addr)
208{
209 return hi6220_thermal_step_to_temp(readl(addr + HI6220_TEMP0_VALUE));
210}
211
212
213
214
215
216
217
218
219
220
221static inline void hi3660_thermal_set_lag(void __iomem *addr,
222 int id, int value)
223{
224 writel(DIV_ROUND_UP(value, HI3660_TEMP_STEP) & 0x7F,
225 addr + HI3660_LAG(id));
226}
227
228static inline void hi3660_thermal_alarm_clear(void __iomem *addr,
229 int id, int value)
230{
231 writel(value, addr + HI3660_INT_CLR(id));
232}
233
234static inline void hi3660_thermal_alarm_enable(void __iomem *addr,
235 int id, int value)
236{
237 writel(value, addr + HI3660_INT_EN(id));
238}
239
240static inline void hi3660_thermal_alarm_set(void __iomem *addr,
241 int id, int value)
242{
243 writel(value, addr + HI3660_TH(id));
244}
245
246static inline int hi3660_thermal_get_temperature(void __iomem *addr, int id)
247{
248 return hi3660_thermal_step_to_temp(readl(addr + HI3660_TEMP(id)));
249}
250
251
252
253
254
255
256
257
258
259
260
261static inline void hi6220_thermal_sensor_select(void __iomem *addr, int sensor)
262{
263 writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_SS_MSK) |
264 (sensor << 12), addr + HI6220_TEMP0_CFG);
265}
266
267
268
269
270
271
272
273
274
275
276
277static inline void hi6220_thermal_hdak_set(void __iomem *addr, int value)
278{
279 writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_HDAK_MSK) |
280 (value << 4), addr + HI6220_TEMP0_CFG);
281}
282
283static int hi6220_thermal_irq_handler(struct hisi_thermal_sensor *sensor)
284{
285 struct hisi_thermal_data *data = sensor->data;
286
287 hi6220_thermal_alarm_clear(data->regs, 1);
288 return 0;
289}
290
291static int hi3660_thermal_irq_handler(struct hisi_thermal_sensor *sensor)
292{
293 struct hisi_thermal_data *data = sensor->data;
294
295 hi3660_thermal_alarm_clear(data->regs, sensor->id, 1);
296 return 0;
297}
298
299static int hi6220_thermal_get_temp(struct hisi_thermal_sensor *sensor)
300{
301 struct hisi_thermal_data *data = sensor->data;
302
303 return hi6220_thermal_get_temperature(data->regs);
304}
305
306static int hi3660_thermal_get_temp(struct hisi_thermal_sensor *sensor)
307{
308 struct hisi_thermal_data *data = sensor->data;
309
310 return hi3660_thermal_get_temperature(data->regs, sensor->id);
311}
312
313static int hi6220_thermal_disable_sensor(struct hisi_thermal_sensor *sensor)
314{
315 struct hisi_thermal_data *data = sensor->data;
316
317
318 hi6220_thermal_enable(data->regs, 0);
319 hi6220_thermal_alarm_enable(data->regs, 0);
320 hi6220_thermal_reset_enable(data->regs, 0);
321
322 clk_disable_unprepare(data->clk);
323
324 return 0;
325}
326
327static int hi3660_thermal_disable_sensor(struct hisi_thermal_sensor *sensor)
328{
329 struct hisi_thermal_data *data = sensor->data;
330
331
332 hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
333 return 0;
334}
335
336static int hi6220_thermal_enable_sensor(struct hisi_thermal_sensor *sensor)
337{
338 struct hisi_thermal_data *data = sensor->data;
339 int ret;
340
341
342 ret = clk_prepare_enable(data->clk);
343 if (ret)
344 return ret;
345
346
347 hi6220_thermal_reset_enable(data->regs, 0);
348 hi6220_thermal_enable(data->regs, 0);
349
350
351 hi6220_thermal_sensor_select(data->regs, sensor->id);
352
353
354 hi6220_thermal_hdak_set(data->regs, 0);
355
356
357 hi6220_thermal_set_lag(data->regs, HI6220_TEMP_LAG);
358
359
360 hi6220_thermal_alarm_set(data->regs, sensor->thres_temp);
361
362 hi6220_thermal_reset_set(data->regs, HI6220_TEMP_RESET);
363
364
365 hi6220_thermal_reset_enable(data->regs, 1);
366 hi6220_thermal_enable(data->regs, 1);
367
368 hi6220_thermal_alarm_clear(data->regs, 0);
369 hi6220_thermal_alarm_enable(data->regs, 1);
370
371 return 0;
372}
373
374static int hi3660_thermal_enable_sensor(struct hisi_thermal_sensor *sensor)
375{
376 unsigned int value;
377 struct hisi_thermal_data *data = sensor->data;
378
379
380 hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
381
382
383 hi3660_thermal_set_lag(data->regs, sensor->id, HI3660_TEMP_LAG);
384
385
386 value = hi3660_thermal_temp_to_step(sensor->thres_temp);
387 hi3660_thermal_alarm_set(data->regs, sensor->id, value);
388
389
390 hi3660_thermal_alarm_clear(data->regs, sensor->id, 1);
391 hi3660_thermal_alarm_enable(data->regs, sensor->id, 1);
392
393 return 0;
394}
395
396static int hi6220_thermal_probe(struct hisi_thermal_data *data)
397{
398 struct platform_device *pdev = data->pdev;
399 struct device *dev = &pdev->dev;
400 int ret;
401
402 data->clk = devm_clk_get(dev, "thermal_clk");
403 if (IS_ERR(data->clk)) {
404 ret = PTR_ERR(data->clk);
405 if (ret != -EPROBE_DEFER)
406 dev_err(dev, "failed to get thermal clk: %d\n", ret);
407 return ret;
408 }
409
410 data->sensor = devm_kzalloc(dev, sizeof(*data->sensor), GFP_KERNEL);
411 if (!data->sensor)
412 return -ENOMEM;
413
414 data->sensor[0].id = HI6220_CLUSTER0_SENSOR;
415 data->sensor[0].irq_name = "tsensor_intr";
416 data->sensor[0].data = data;
417 data->nr_sensors = 1;
418
419 return 0;
420}
421
422static int hi3660_thermal_probe(struct hisi_thermal_data *data)
423{
424 struct platform_device *pdev = data->pdev;
425 struct device *dev = &pdev->dev;
426
427 data->nr_sensors = 1;
428
429 data->sensor = devm_kzalloc(dev, sizeof(*data->sensor) *
430 data->nr_sensors, GFP_KERNEL);
431 if (!data->sensor)
432 return -ENOMEM;
433
434 data->sensor[0].id = HI3660_BIG_SENSOR;
435 data->sensor[0].irq_name = "tsensor_a73";
436 data->sensor[0].data = data;
437
438 data->sensor[1].id = HI3660_LITTLE_SENSOR;
439 data->sensor[1].irq_name = "tsensor_a53";
440 data->sensor[1].data = data;
441
442 return 0;
443}
444
445static int hisi_thermal_get_temp(void *__data, int *temp)
446{
447 struct hisi_thermal_sensor *sensor = __data;
448 struct hisi_thermal_data *data = sensor->data;
449
450 *temp = data->ops->get_temp(sensor);
451
452 dev_dbg(&data->pdev->dev, "tzd=%p, id=%d, temp=%d, thres=%d\n",
453 sensor->tzd, sensor->id, *temp, sensor->thres_temp);
454
455 return 0;
456}
457
458static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
459 .get_temp = hisi_thermal_get_temp,
460};
461
462static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
463{
464 struct hisi_thermal_sensor *sensor = dev;
465 struct hisi_thermal_data *data = sensor->data;
466 int temp = 0;
467
468 data->ops->irq_handler(sensor);
469
470 hisi_thermal_get_temp(sensor, &temp);
471
472 if (temp >= sensor->thres_temp) {
473 dev_crit(&data->pdev->dev,
474 "sensor <%d> THERMAL ALARM: %d > %d\n",
475 sensor->id, temp, sensor->thres_temp);
476
477 thermal_zone_device_update(sensor->tzd,
478 THERMAL_EVENT_UNSPECIFIED);
479
480 } else {
481 dev_crit(&data->pdev->dev,
482 "sensor <%d> THERMAL ALARM stopped: %d < %d\n",
483 sensor->id, temp, sensor->thres_temp);
484 }
485
486 return IRQ_HANDLED;
487}
488
489static int hisi_thermal_register_sensor(struct platform_device *pdev,
490 struct hisi_thermal_sensor *sensor)
491{
492 int ret, i;
493 const struct thermal_trip *trip;
494
495 sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
496 sensor->id, sensor,
497 &hisi_of_thermal_ops);
498 if (IS_ERR(sensor->tzd)) {
499 ret = PTR_ERR(sensor->tzd);
500 sensor->tzd = NULL;
501 dev_err(&pdev->dev, "failed to register sensor id %d: %d\n",
502 sensor->id, ret);
503 return ret;
504 }
505
506 trip = of_thermal_get_trip_points(sensor->tzd);
507
508 for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {
509 if (trip[i].type == THERMAL_TRIP_PASSIVE) {
510 sensor->thres_temp = trip[i].temperature;
511 break;
512 }
513 }
514
515 return 0;
516}
517
518static const struct hisi_thermal_ops hi6220_ops = {
519 .get_temp = hi6220_thermal_get_temp,
520 .enable_sensor = hi6220_thermal_enable_sensor,
521 .disable_sensor = hi6220_thermal_disable_sensor,
522 .irq_handler = hi6220_thermal_irq_handler,
523 .probe = hi6220_thermal_probe,
524};
525
526static const struct hisi_thermal_ops hi3660_ops = {
527 .get_temp = hi3660_thermal_get_temp,
528 .enable_sensor = hi3660_thermal_enable_sensor,
529 .disable_sensor = hi3660_thermal_disable_sensor,
530 .irq_handler = hi3660_thermal_irq_handler,
531 .probe = hi3660_thermal_probe,
532};
533
534static const struct of_device_id of_hisi_thermal_match[] = {
535 {
536 .compatible = "hisilicon,tsensor",
537 .data = &hi6220_ops,
538 },
539 {
540 .compatible = "hisilicon,hi3660-tsensor",
541 .data = &hi3660_ops,
542 },
543 { }
544};
545MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
546
547static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
548 bool on)
549{
550 struct thermal_zone_device *tzd = sensor->tzd;
551
552 if (on)
553 thermal_zone_device_enable(tzd);
554 else
555 thermal_zone_device_disable(tzd);
556}
557
558static int hisi_thermal_probe(struct platform_device *pdev)
559{
560 struct hisi_thermal_data *data;
561 struct device *dev = &pdev->dev;
562 struct resource *res;
563 int i, ret;
564
565 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
566 if (!data)
567 return -ENOMEM;
568
569 data->pdev = pdev;
570 platform_set_drvdata(pdev, data);
571 data->ops = of_device_get_match_data(dev);
572
573 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
574 data->regs = devm_ioremap_resource(dev, res);
575 if (IS_ERR(data->regs)) {
576 dev_err(dev, "failed to get io address\n");
577 return PTR_ERR(data->regs);
578 }
579
580 ret = data->ops->probe(data);
581 if (ret)
582 return ret;
583
584 for (i = 0; i < data->nr_sensors; i++) {
585 struct hisi_thermal_sensor *sensor = &data->sensor[i];
586
587 ret = hisi_thermal_register_sensor(pdev, sensor);
588 if (ret) {
589 dev_err(dev, "failed to register thermal sensor: %d\n",
590 ret);
591 return ret;
592 }
593
594 ret = platform_get_irq(pdev, 0);
595 if (ret < 0)
596 return ret;
597
598 ret = devm_request_threaded_irq(dev, ret, NULL,
599 hisi_thermal_alarm_irq_thread,
600 IRQF_ONESHOT, sensor->irq_name,
601 sensor);
602 if (ret < 0) {
603 dev_err(dev, "Failed to request alarm irq: %d\n", ret);
604 return ret;
605 }
606
607 ret = data->ops->enable_sensor(sensor);
608 if (ret) {
609 dev_err(dev, "Failed to setup the sensor: %d\n", ret);
610 return ret;
611 }
612
613 hisi_thermal_toggle_sensor(sensor, true);
614 }
615
616 return 0;
617}
618
619static int hisi_thermal_remove(struct platform_device *pdev)
620{
621 struct hisi_thermal_data *data = platform_get_drvdata(pdev);
622 int i;
623
624 for (i = 0; i < data->nr_sensors; i++) {
625 struct hisi_thermal_sensor *sensor = &data->sensor[i];
626
627 hisi_thermal_toggle_sensor(sensor, false);
628 data->ops->disable_sensor(sensor);
629 }
630
631 return 0;
632}
633
634#ifdef CONFIG_PM_SLEEP
635static int hisi_thermal_suspend(struct device *dev)
636{
637 struct hisi_thermal_data *data = dev_get_drvdata(dev);
638 int i;
639
640 for (i = 0; i < data->nr_sensors; i++)
641 data->ops->disable_sensor(&data->sensor[i]);
642
643 return 0;
644}
645
646static int hisi_thermal_resume(struct device *dev)
647{
648 struct hisi_thermal_data *data = dev_get_drvdata(dev);
649 int i, ret = 0;
650
651 for (i = 0; i < data->nr_sensors; i++)
652 ret |= data->ops->enable_sensor(&data->sensor[i]);
653
654 return ret;
655}
656#endif
657
658static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
659 hisi_thermal_suspend, hisi_thermal_resume);
660
661static struct platform_driver hisi_thermal_driver = {
662 .driver = {
663 .name = "hisi_thermal",
664 .pm = &hisi_thermal_pm_ops,
665 .of_match_table = of_hisi_thermal_match,
666 },
667 .probe = hisi_thermal_probe,
668 .remove = hisi_thermal_remove,
669};
670
671module_platform_driver(hisi_thermal_driver);
672
673MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
674MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
675MODULE_DESCRIPTION("Hisilicon thermal driver");
676MODULE_LICENSE("GPL v2");
677