1/*
2 * Hisilicon thermal sensor driver
3 *
4 * Copyright (c) 2014-2015 Hisilicon Limited.
5 * Copyright (c) 2014-2015 Linaro Limited.
6 *
7 * Xinwei Kong <kong.kongxinwei@hisilicon.com>
8 * Leo Yan <leo.yan@linaro.org>
9 *
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.
13 *
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.
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
27#include "thermal_core.h"
28
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)
37
38#define HISI_TEMP_BASE			(-60)
39#define HISI_TEMP_RESET			(100000)
40
41#define HISI_MAX_SENSORS		4
42
43struct hisi_thermal_sensor {
44	struct hisi_thermal_data *thermal;
45	struct thermal_zone_device *tzd;
46
47	long sensor_temp;
48	uint32_t id;
49	uint32_t thres_temp;
50};
51
52struct hisi_thermal_data {
53	struct mutex thermal_lock;    /* protects register data */
54	struct platform_device *pdev;
55	struct clk *clk;
56	struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];
57
58	int irq, irq_bind_sensor;
59	bool irq_enabled;
60
61	void __iomem *regs;
62};
63
64/* in millicelsius */
65static inline int _step_to_temp(int step)
66{
67	/*
68	 * Every step equals (1 * 200) / 255 celsius, and finally
69	 * need convert to millicelsius.
70	 */
71	return (HISI_TEMP_BASE + (step * 200 / 255)) * 1000;
72}
73
74static inline long _temp_to_step(long temp)
75{
76	return ((temp / 1000 - HISI_TEMP_BASE) * 255 / 200);
77}
78
79static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,
80					 struct hisi_thermal_sensor *sensor)
81{
82	long val;
83
84	mutex_lock(&data->thermal_lock);
85
86	/* disable interrupt */
87	writel(0x0, data->regs + TEMP0_INT_EN);
88	writel(0x1, data->regs + TEMP0_INT_CLR);
89
90	/* disable module firstly */
91	writel(0x0, data->regs + TEMP0_EN);
92
93	/* select sensor id */
94	writel((sensor->id << 12), data->regs + TEMP0_CFG);
95
96	/* enable module */
97	writel(0x1, data->regs + TEMP0_EN);
98
99	usleep_range(3000, 5000);
100
101	val = readl(data->regs + TEMP0_VALUE);
102	val = _step_to_temp(val);
103
104	mutex_unlock(&data->thermal_lock);
105
106	return val;
107}
108
109static void hisi_thermal_enable_bind_irq_sensor
110			(struct hisi_thermal_data *data)
111{
112	struct hisi_thermal_sensor *sensor;
113
114	mutex_lock(&data->thermal_lock);
115
116	sensor = &data->sensors[data->irq_bind_sensor];
117
118	/* setting the hdak time */
119	writel(0x0, data->regs + TEMP0_CFG);
120
121	/* disable module firstly */
122	writel(0x0, data->regs + TEMP0_RST_MSK);
123	writel(0x0, data->regs + TEMP0_EN);
124
125	/* select sensor id */
126	writel((sensor->id << 12), data->regs + TEMP0_CFG);
127
128	/* enable for interrupt */
129	writel(_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00,
130	       data->regs + TEMP0_TH);
131
132	writel(_temp_to_step(HISI_TEMP_RESET), data->regs + TEMP0_RST_TH);
133
134	/* enable module */
135	writel(0x1, data->regs + TEMP0_RST_MSK);
136	writel(0x1, data->regs + TEMP0_EN);
137
138	writel(0x0, data->regs + TEMP0_INT_CLR);
139	writel(0x1, data->regs + TEMP0_INT_EN);
140
141	usleep_range(3000, 5000);
142
143	mutex_unlock(&data->thermal_lock);
144}
145
146static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data)
147{
148	mutex_lock(&data->thermal_lock);
149
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);
154
155	mutex_unlock(&data->thermal_lock);
156}
157
158static int hisi_thermal_get_temp(void *_sensor, int *temp)
159{
160	struct hisi_thermal_sensor *sensor = _sensor;
161	struct hisi_thermal_data *data = sensor->thermal;
162
163	int sensor_id = 0, i;
164	long max_temp = 0;
165
166	*temp = hisi_thermal_get_sensor_temp(data, sensor);
167
168	sensor->sensor_temp = *temp;
169
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;
173			sensor_id = i;
174		}
175	}
176
177	mutex_lock(&data->thermal_lock);
178	data->irq_bind_sensor = sensor_id;
179	mutex_unlock(&data->thermal_lock);
180
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);
183	/*
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;
187	 */
188	if (data->irq_enabled) {
189		hisi_thermal_enable_bind_irq_sensor(data);
190		return 0;
191	}
192
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);
197	}
198
199	return 0;
200}
201
202static struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
203	.get_temp = hisi_thermal_get_temp,
204};
205
206static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
207{
208	struct hisi_thermal_data *data = dev;
209
210	disable_irq_nosync(irq);
211	data->irq_enabled = false;
212
213	return IRQ_WAKE_THREAD;
214}
215
216static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
217{
218	struct hisi_thermal_data *data = dev;
219	struct hisi_thermal_sensor *sensor;
220	int i;
221
222	mutex_lock(&data->thermal_lock);
223	sensor = &data->sensors[data->irq_bind_sensor];
224
225	dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
226		 sensor->thres_temp / 1000);
227	mutex_unlock(&data->thermal_lock);
228
229	for (i = 0; i < HISI_MAX_SENSORS; i++)
230		thermal_zone_device_update(data->sensors[i].tzd);
231
232	return IRQ_HANDLED;
233}
234
235static int hisi_thermal_register_sensor(struct platform_device *pdev,
236					struct hisi_thermal_data *data,
237					struct hisi_thermal_sensor *sensor,
238					int index)
239{
240	int ret, i;
241	const struct thermal_trip *trip;
242
243	sensor->id = index;
244	sensor->thermal = data;
245
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",
251			sensor->id, ret);
252		return ret;
253	}
254
255	trip = of_thermal_get_trip_points(sensor->tzd);
256
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;
260			break;
261		}
262	}
263
264	return 0;
265}
266
267static const struct of_device_id of_hisi_thermal_match[] = {
268	{ .compatible = "hisilicon,tsensor" },
269	{ /* end */ }
270};
271MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
272
273static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
274				       bool on)
275{
276	struct thermal_zone_device *tzd = sensor->tzd;
277
278	tzd->ops->set_mode(tzd,
279		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
280}
281
282static int hisi_thermal_probe(struct platform_device *pdev)
283{
284	struct hisi_thermal_data *data;
285	struct resource *res;
286	int i;
287	int ret;
288
289	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
290	if (!data)
291		return -ENOMEM;
292
293	mutex_init(&data->thermal_lock);
294	data->pdev = pdev;
295
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);
301	}
302
303	data->irq = platform_get_irq(pdev, 0);
304	if (data->irq < 0)
305		return data->irq;
306
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);
311	if (ret < 0) {
312		dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
313		return ret;
314	}
315
316	platform_set_drvdata(pdev, data);
317
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)
322			dev_err(&pdev->dev,
323				"failed to get thermal clk: %d\n", ret);
324		return ret;
325	}
326
327	/* enable clock for thermal */
328	ret = clk_prepare_enable(data->clk);
329	if (ret) {
330		dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
331		return ret;
332	}
333
334	for (i = 0; i < HISI_MAX_SENSORS; ++i) {
335		ret = hisi_thermal_register_sensor(pdev, data,
336						   &data->sensors[i], i);
337		if (ret) {
338			dev_err(&pdev->dev,
339				"failed to register thermal sensor: %d\n", ret);
340			goto err_get_sensor_data;
341		}
342	}
343
344	hisi_thermal_enable_bind_irq_sensor(data);
345	data->irq_enabled = true;
346
347	for (i = 0; i < HISI_MAX_SENSORS; i++)
348		hisi_thermal_toggle_sensor(&data->sensors[i], true);
349
350	return 0;
351
352err_get_sensor_data:
353	clk_disable_unprepare(data->clk);
354
355	return ret;
356}
357
358static int hisi_thermal_remove(struct platform_device *pdev)
359{
360	struct hisi_thermal_data *data = platform_get_drvdata(pdev);
361	int i;
362
363	for (i = 0; i < HISI_MAX_SENSORS; i++) {
364		struct hisi_thermal_sensor *sensor = &data->sensors[i];
365
366		hisi_thermal_toggle_sensor(sensor, false);
367		thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd);
368	}
369
370	hisi_thermal_disable_sensor(data);
371	clk_disable_unprepare(data->clk);
372
373	return 0;
374}
375
376#ifdef CONFIG_PM_SLEEP
377static int hisi_thermal_suspend(struct device *dev)
378{
379	struct hisi_thermal_data *data = dev_get_drvdata(dev);
380
381	hisi_thermal_disable_sensor(data);
382	data->irq_enabled = false;
383
384	clk_disable_unprepare(data->clk);
385
386	return 0;
387}
388
389static int hisi_thermal_resume(struct device *dev)
390{
391	struct hisi_thermal_data *data = dev_get_drvdata(dev);
392
393	clk_prepare_enable(data->clk);
394
395	data->irq_enabled = true;
396	hisi_thermal_enable_bind_irq_sensor(data);
397
398	return 0;
399}
400#endif
401
402static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
403			 hisi_thermal_suspend, hisi_thermal_resume);
404
405static struct platform_driver hisi_thermal_driver = {
406	.driver = {
407		.name		= "hisi_thermal",
408		.pm		= &hisi_thermal_pm_ops,
409		.of_match_table = of_hisi_thermal_match,
410	},
411	.probe	= hisi_thermal_probe,
412	.remove	= hisi_thermal_remove,
413};
414
415module_platform_driver(hisi_thermal_driver);
416
417MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
418MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
419MODULE_DESCRIPTION("Hisilicon thermal driver");
420MODULE_LICENSE("GPL v2");
421