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
+ (step
* 200 / 255)) * 1000;
74 static inline long _temp_to_step(long temp
)
76 return ((temp
/ 1000 - HISI_TEMP_BASE
) * 255 / 200);
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
= 0, 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
].sensor_temp
>= max_temp
) {
172 max_temp
= data
->sensors
[i
].sensor_temp
;
177 mutex_lock(&data
->thermal_lock
);
178 data
->irq_bind_sensor
= sensor_id
;
179 mutex_unlock(&data
->thermal_lock
);
181 dev_dbg(&data
->pdev
->dev
, "id=%d, irq=%d, temp=%d, thres=%d\n",
182 sensor
->id
, data
->irq_enabled
, *temp
, sensor
->thres_temp
);
184 * Bind irq to sensor for two cases:
185 * Reenable alarm IRQ if temperature below threshold;
186 * if irq has been enabled, always set it;
188 if (data
->irq_enabled
) {
189 hisi_thermal_enable_bind_irq_sensor(data
);
193 if (max_temp
< sensor
->thres_temp
) {
194 data
->irq_enabled
= true;
195 hisi_thermal_enable_bind_irq_sensor(data
);
196 enable_irq(data
->irq
);
202 static struct thermal_zone_of_device_ops hisi_of_thermal_ops
= {
203 .get_temp
= hisi_thermal_get_temp
,
206 static irqreturn_t
hisi_thermal_alarm_irq(int irq
, void *dev
)
208 struct hisi_thermal_data
*data
= dev
;
210 disable_irq_nosync(irq
);
211 data
->irq_enabled
= false;
213 return IRQ_WAKE_THREAD
;
216 static irqreturn_t
hisi_thermal_alarm_irq_thread(int irq
, void *dev
)
218 struct hisi_thermal_data
*data
= dev
;
219 struct hisi_thermal_sensor
*sensor
;
222 mutex_lock(&data
->thermal_lock
);
223 sensor
= &data
->sensors
[data
->irq_bind_sensor
];
225 dev_crit(&data
->pdev
->dev
, "THERMAL ALARM: T > %d\n",
226 sensor
->thres_temp
/ 1000);
227 mutex_unlock(&data
->thermal_lock
);
229 for (i
= 0; i
< HISI_MAX_SENSORS
; i
++)
230 thermal_zone_device_update(data
->sensors
[i
].tzd
);
235 static int hisi_thermal_register_sensor(struct platform_device
*pdev
,
236 struct hisi_thermal_data
*data
,
237 struct hisi_thermal_sensor
*sensor
,
241 const struct thermal_trip
*trip
;
244 sensor
->thermal
= data
;
246 sensor
->tzd
= thermal_zone_of_sensor_register(&pdev
->dev
, sensor
->id
,
247 sensor
, &hisi_of_thermal_ops
);
248 if (IS_ERR(sensor
->tzd
)) {
249 ret
= PTR_ERR(sensor
->tzd
);
250 dev_err(&pdev
->dev
, "failed to register sensor id %d: %d\n",
255 trip
= of_thermal_get_trip_points(sensor
->tzd
);
257 for (i
= 0; i
< of_thermal_get_ntrips(sensor
->tzd
); i
++) {
258 if (trip
[i
].type
== THERMAL_TRIP_PASSIVE
) {
259 sensor
->thres_temp
= trip
[i
].temperature
;
267 static const struct of_device_id of_hisi_thermal_match
[] = {
268 { .compatible
= "hisilicon,tsensor" },
271 MODULE_DEVICE_TABLE(of
, of_hisi_thermal_match
);
273 static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor
*sensor
,
276 struct thermal_zone_device
*tzd
= sensor
->tzd
;
278 tzd
->ops
->set_mode(tzd
,
279 on
? THERMAL_DEVICE_ENABLED
: THERMAL_DEVICE_DISABLED
);
282 static int hisi_thermal_probe(struct platform_device
*pdev
)
284 struct hisi_thermal_data
*data
;
285 struct resource
*res
;
289 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
293 mutex_init(&data
->thermal_lock
);
296 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
297 data
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
298 if (IS_ERR(data
->regs
)) {
299 dev_err(&pdev
->dev
, "failed to get io address\n");
300 return PTR_ERR(data
->regs
);
303 data
->irq
= platform_get_irq(pdev
, 0);
307 ret
= devm_request_threaded_irq(&pdev
->dev
, data
->irq
,
308 hisi_thermal_alarm_irq
,
309 hisi_thermal_alarm_irq_thread
,
310 0, "hisi_thermal", data
);
312 dev_err(&pdev
->dev
, "failed to request alarm irq: %d\n", ret
);
316 platform_set_drvdata(pdev
, data
);
318 data
->clk
= devm_clk_get(&pdev
->dev
, "thermal_clk");
319 if (IS_ERR(data
->clk
)) {
320 ret
= PTR_ERR(data
->clk
);
321 if (ret
!= -EPROBE_DEFER
)
323 "failed to get thermal clk: %d\n", ret
);
327 /* enable clock for thermal */
328 ret
= clk_prepare_enable(data
->clk
);
330 dev_err(&pdev
->dev
, "failed to enable thermal clk: %d\n", ret
);
334 for (i
= 0; i
< HISI_MAX_SENSORS
; ++i
) {
335 ret
= hisi_thermal_register_sensor(pdev
, data
,
336 &data
->sensors
[i
], i
);
339 "failed to register thermal sensor: %d\n", ret
);
340 goto err_get_sensor_data
;
344 hisi_thermal_enable_bind_irq_sensor(data
);
345 data
->irq_enabled
= true;
347 for (i
= 0; i
< HISI_MAX_SENSORS
; i
++)
348 hisi_thermal_toggle_sensor(&data
->sensors
[i
], true);
353 clk_disable_unprepare(data
->clk
);
358 static int hisi_thermal_remove(struct platform_device
*pdev
)
360 struct hisi_thermal_data
*data
= platform_get_drvdata(pdev
);
363 for (i
= 0; i
< HISI_MAX_SENSORS
; i
++) {
364 struct hisi_thermal_sensor
*sensor
= &data
->sensors
[i
];
366 hisi_thermal_toggle_sensor(sensor
, false);
367 thermal_zone_of_sensor_unregister(&pdev
->dev
, sensor
->tzd
);
370 hisi_thermal_disable_sensor(data
);
371 clk_disable_unprepare(data
->clk
);
376 #ifdef CONFIG_PM_SLEEP
377 static int hisi_thermal_suspend(struct device
*dev
)
379 struct hisi_thermal_data
*data
= dev_get_drvdata(dev
);
381 hisi_thermal_disable_sensor(data
);
382 data
->irq_enabled
= false;
384 clk_disable_unprepare(data
->clk
);
389 static int hisi_thermal_resume(struct device
*dev
)
391 struct hisi_thermal_data
*data
= dev_get_drvdata(dev
);
393 clk_prepare_enable(data
->clk
);
395 data
->irq_enabled
= true;
396 hisi_thermal_enable_bind_irq_sensor(data
);
402 static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops
,
403 hisi_thermal_suspend
, hisi_thermal_resume
);
405 static struct platform_driver hisi_thermal_driver
= {
407 .name
= "hisi_thermal",
408 .pm
= &hisi_thermal_pm_ops
,
409 .of_match_table
= of_hisi_thermal_match
,
411 .probe
= hisi_thermal_probe
,
412 .remove
= hisi_thermal_remove
,
415 module_platform_driver(hisi_thermal_driver
);
417 MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
418 MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
419 MODULE_DESCRIPTION("Hisilicon thermal driver");
420 MODULE_LICENSE("GPL v2");