2 * Hisilicon thermal sensor driver
4 * Copyright (c) 2014-2015 Hisilicon Limited.
5 * Copyright (c) 2014-2015 Linaro Limited.
7 * Xinwei Kong <kong.kongxinwei@hisilicon.com>
8 * Leo Yan <leo.yan@linaro.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
15 * kind, whether express or implied; without even the implied warranty
16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
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>
27 #include "thermal_core.h"
29 #define TEMP0_TH (0x4)
30 #define TEMP0_RST_TH (0x8)
31 #define TEMP0_CFG (0xC)
32 #define TEMP0_EN (0x10)
33 #define TEMP0_INT_EN (0x14)
34 #define TEMP0_INT_CLR (0x18)
35 #define TEMP0_RST_MSK (0x1C)
36 #define TEMP0_VALUE (0x28)
38 #define HISI_TEMP_BASE (-60)
39 #define HISI_TEMP_RESET (100000)
41 #define HISI_MAX_SENSORS 4
43 struct hisi_thermal_sensor
{
44 struct hisi_thermal_data
*thermal
;
45 struct thermal_zone_device
*tzd
;
52 struct hisi_thermal_data
{
53 struct mutex thermal_lock
; /* protects register data */
54 struct platform_device
*pdev
;
56 struct hisi_thermal_sensor sensors
[HISI_MAX_SENSORS
];
58 int irq
, irq_bind_sensor
;
65 static inline int _step_to_temp(int step
)
68 * Every step equals (1 * 200) / 255 celsius, and finally
69 * need convert to millicelsius.
71 return (HISI_TEMP_BASE
* 1000 + (step
* 200000 / 255));
74 static inline long _temp_to_step(long temp
)
76 return ((temp
- HISI_TEMP_BASE
* 1000) * 255) / 200000;
79 static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data
*data
,
80 struct hisi_thermal_sensor
*sensor
)
84 mutex_lock(&data
->thermal_lock
);
86 /* disable interrupt */
87 writel(0x0, data
->regs
+ TEMP0_INT_EN
);
88 writel(0x1, data
->regs
+ TEMP0_INT_CLR
);
90 /* disable module firstly */
91 writel(0x0, data
->regs
+ TEMP0_EN
);
93 /* select sensor id */
94 writel((sensor
->id
<< 12), data
->regs
+ TEMP0_CFG
);
97 writel(0x1, data
->regs
+ TEMP0_EN
);
99 usleep_range(3000, 5000);
101 val
= readl(data
->regs
+ TEMP0_VALUE
);
102 val
= _step_to_temp(val
);
104 mutex_unlock(&data
->thermal_lock
);
109 static void hisi_thermal_enable_bind_irq_sensor
110 (struct hisi_thermal_data
*data
)
112 struct hisi_thermal_sensor
*sensor
;
114 mutex_lock(&data
->thermal_lock
);
116 sensor
= &data
->sensors
[data
->irq_bind_sensor
];
118 /* setting the hdak time */
119 writel(0x0, data
->regs
+ TEMP0_CFG
);
121 /* disable module firstly */
122 writel(0x0, data
->regs
+ TEMP0_RST_MSK
);
123 writel(0x0, data
->regs
+ TEMP0_EN
);
125 /* select sensor id */
126 writel((sensor
->id
<< 12), data
->regs
+ TEMP0_CFG
);
128 /* enable for interrupt */
129 writel(_temp_to_step(sensor
->thres_temp
) | 0x0FFFFFF00,
130 data
->regs
+ TEMP0_TH
);
132 writel(_temp_to_step(HISI_TEMP_RESET
), data
->regs
+ TEMP0_RST_TH
);
135 writel(0x1, data
->regs
+ TEMP0_RST_MSK
);
136 writel(0x1, data
->regs
+ TEMP0_EN
);
138 writel(0x0, data
->regs
+ TEMP0_INT_CLR
);
139 writel(0x1, data
->regs
+ TEMP0_INT_EN
);
141 usleep_range(3000, 5000);
143 mutex_unlock(&data
->thermal_lock
);
146 static void hisi_thermal_disable_sensor(struct hisi_thermal_data
*data
)
148 mutex_lock(&data
->thermal_lock
);
150 /* disable sensor module */
151 writel(0x0, data
->regs
+ TEMP0_INT_EN
);
152 writel(0x0, data
->regs
+ TEMP0_RST_MSK
);
153 writel(0x0, data
->regs
+ TEMP0_EN
);
155 mutex_unlock(&data
->thermal_lock
);
158 static int hisi_thermal_get_temp(void *_sensor
, int *temp
)
160 struct hisi_thermal_sensor
*sensor
= _sensor
;
161 struct hisi_thermal_data
*data
= sensor
->thermal
;
163 int sensor_id
= -1, i
;
166 *temp
= hisi_thermal_get_sensor_temp(data
, sensor
);
168 sensor
->sensor_temp
= *temp
;
170 for (i
= 0; i
< HISI_MAX_SENSORS
; i
++) {
171 if (!data
->sensors
[i
].tzd
)
174 if (data
->sensors
[i
].sensor_temp
>= max_temp
) {
175 max_temp
= data
->sensors
[i
].sensor_temp
;
180 /* If no sensor has been enabled, then skip to enable irq */
184 mutex_lock(&data
->thermal_lock
);
185 data
->irq_bind_sensor
= sensor_id
;
186 mutex_unlock(&data
->thermal_lock
);
188 dev_dbg(&data
->pdev
->dev
, "id=%d, irq=%d, temp=%d, thres=%d\n",
189 sensor
->id
, data
->irq_enabled
, *temp
, sensor
->thres_temp
);
191 * Bind irq to sensor for two cases:
192 * Reenable alarm IRQ if temperature below threshold;
193 * if irq has been enabled, always set it;
195 if (data
->irq_enabled
) {
196 hisi_thermal_enable_bind_irq_sensor(data
);
200 if (max_temp
< sensor
->thres_temp
) {
201 data
->irq_enabled
= true;
202 hisi_thermal_enable_bind_irq_sensor(data
);
203 enable_irq(data
->irq
);
209 static struct thermal_zone_of_device_ops hisi_of_thermal_ops
= {
210 .get_temp
= hisi_thermal_get_temp
,
213 static irqreturn_t
hisi_thermal_alarm_irq(int irq
, void *dev
)
215 struct hisi_thermal_data
*data
= dev
;
217 disable_irq_nosync(irq
);
218 data
->irq_enabled
= false;
220 return IRQ_WAKE_THREAD
;
223 static irqreturn_t
hisi_thermal_alarm_irq_thread(int irq
, void *dev
)
225 struct hisi_thermal_data
*data
= dev
;
226 struct hisi_thermal_sensor
*sensor
;
229 mutex_lock(&data
->thermal_lock
);
230 sensor
= &data
->sensors
[data
->irq_bind_sensor
];
232 dev_crit(&data
->pdev
->dev
, "THERMAL ALARM: T > %d\n",
233 sensor
->thres_temp
/ 1000);
234 mutex_unlock(&data
->thermal_lock
);
236 for (i
= 0; i
< HISI_MAX_SENSORS
; i
++) {
237 if (!data
->sensors
[i
].tzd
)
240 thermal_zone_device_update(data
->sensors
[i
].tzd
,
241 THERMAL_EVENT_UNSPECIFIED
);
247 static int hisi_thermal_register_sensor(struct platform_device
*pdev
,
248 struct hisi_thermal_data
*data
,
249 struct hisi_thermal_sensor
*sensor
,
253 const struct thermal_trip
*trip
;
256 sensor
->thermal
= data
;
258 sensor
->tzd
= devm_thermal_zone_of_sensor_register(&pdev
->dev
,
259 sensor
->id
, sensor
, &hisi_of_thermal_ops
);
260 if (IS_ERR(sensor
->tzd
)) {
261 ret
= PTR_ERR(sensor
->tzd
);
263 dev_err(&pdev
->dev
, "failed to register sensor id %d: %d\n",
268 trip
= of_thermal_get_trip_points(sensor
->tzd
);
270 for (i
= 0; i
< of_thermal_get_ntrips(sensor
->tzd
); i
++) {
271 if (trip
[i
].type
== THERMAL_TRIP_PASSIVE
) {
272 sensor
->thres_temp
= trip
[i
].temperature
;
280 static const struct of_device_id of_hisi_thermal_match
[] = {
281 { .compatible
= "hisilicon,tsensor" },
284 MODULE_DEVICE_TABLE(of
, of_hisi_thermal_match
);
286 static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor
*sensor
,
289 struct thermal_zone_device
*tzd
= sensor
->tzd
;
291 tzd
->ops
->set_mode(tzd
,
292 on
? THERMAL_DEVICE_ENABLED
: THERMAL_DEVICE_DISABLED
);
295 static int hisi_thermal_probe(struct platform_device
*pdev
)
297 struct hisi_thermal_data
*data
;
298 struct resource
*res
;
302 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
306 mutex_init(&data
->thermal_lock
);
309 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
310 data
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
311 if (IS_ERR(data
->regs
)) {
312 dev_err(&pdev
->dev
, "failed to get io address\n");
313 return PTR_ERR(data
->regs
);
316 data
->irq
= platform_get_irq(pdev
, 0);
320 ret
= devm_request_threaded_irq(&pdev
->dev
, data
->irq
,
321 hisi_thermal_alarm_irq
,
322 hisi_thermal_alarm_irq_thread
,
323 0, "hisi_thermal", data
);
325 dev_err(&pdev
->dev
, "failed to request alarm irq: %d\n", ret
);
329 platform_set_drvdata(pdev
, data
);
331 data
->clk
= devm_clk_get(&pdev
->dev
, "thermal_clk");
332 if (IS_ERR(data
->clk
)) {
333 ret
= PTR_ERR(data
->clk
);
334 if (ret
!= -EPROBE_DEFER
)
336 "failed to get thermal clk: %d\n", ret
);
340 /* enable clock for thermal */
341 ret
= clk_prepare_enable(data
->clk
);
343 dev_err(&pdev
->dev
, "failed to enable thermal clk: %d\n", ret
);
347 hisi_thermal_enable_bind_irq_sensor(data
);
348 irq_get_irqchip_state(data
->irq
, IRQCHIP_STATE_MASKED
,
351 for (i
= 0; i
< HISI_MAX_SENSORS
; ++i
) {
352 ret
= hisi_thermal_register_sensor(pdev
, data
,
353 &data
->sensors
[i
], i
);
356 "failed to register thermal sensor: %d\n", ret
);
358 hisi_thermal_toggle_sensor(&data
->sensors
[i
], true);
364 static int hisi_thermal_remove(struct platform_device
*pdev
)
366 struct hisi_thermal_data
*data
= platform_get_drvdata(pdev
);
369 for (i
= 0; i
< HISI_MAX_SENSORS
; i
++) {
370 struct hisi_thermal_sensor
*sensor
= &data
->sensors
[i
];
375 hisi_thermal_toggle_sensor(sensor
, false);
378 hisi_thermal_disable_sensor(data
);
379 clk_disable_unprepare(data
->clk
);
384 #ifdef CONFIG_PM_SLEEP
385 static int hisi_thermal_suspend(struct device
*dev
)
387 struct hisi_thermal_data
*data
= dev_get_drvdata(dev
);
389 hisi_thermal_disable_sensor(data
);
390 data
->irq_enabled
= false;
392 clk_disable_unprepare(data
->clk
);
397 static int hisi_thermal_resume(struct device
*dev
)
399 struct hisi_thermal_data
*data
= dev_get_drvdata(dev
);
401 clk_prepare_enable(data
->clk
);
403 data
->irq_enabled
= true;
404 hisi_thermal_enable_bind_irq_sensor(data
);
410 static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops
,
411 hisi_thermal_suspend
, hisi_thermal_resume
);
413 static struct platform_driver hisi_thermal_driver
= {
415 .name
= "hisi_thermal",
416 .pm
= &hisi_thermal_pm_ops
,
417 .of_match_table
= of_hisi_thermal_match
,
419 .probe
= hisi_thermal_probe
,
420 .remove
= hisi_thermal_remove
,
423 module_platform_driver(hisi_thermal_driver
);
425 MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
426 MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
427 MODULE_DESCRIPTION("Hisilicon thermal driver");
428 MODULE_LICENSE("GPL v2");