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