Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / thermal / st / st_thermal.c
1 /*
2  * ST Thermal Sensor Driver core routines
3  * Author: Ajit Pal Singh <ajitpal.singh@st.com>
4  *
5  * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  */
13
14 #include <linux/clk.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_device.h>
18
19 #include "st_thermal.h"
20
21 /* The Thermal Framework expects millidegrees */
22 #define mcelsius(temp)                  ((temp) * 1000)
23
24 /*
25  * Function to allocate regfields which are common
26  * between syscfg and memory mapped based sensors
27  */
28 static int st_thermal_alloc_regfields(struct st_thermal_sensor *sensor)
29 {
30         struct device *dev = sensor->dev;
31         struct regmap *regmap = sensor->regmap;
32         const struct reg_field *reg_fields = sensor->cdata->reg_fields;
33
34         sensor->dcorrect = devm_regmap_field_alloc(dev, regmap,
35                                                    reg_fields[DCORRECT]);
36
37         sensor->overflow = devm_regmap_field_alloc(dev, regmap,
38                                                    reg_fields[OVERFLOW]);
39
40         sensor->temp_data = devm_regmap_field_alloc(dev, regmap,
41                                                     reg_fields[DATA]);
42
43         if (IS_ERR(sensor->dcorrect) ||
44             IS_ERR(sensor->overflow) ||
45             IS_ERR(sensor->temp_data)) {
46                 dev_err(dev, "failed to allocate common regfields\n");
47                 return -EINVAL;
48         }
49
50         return sensor->ops->alloc_regfields(sensor);
51 }
52
53 static int st_thermal_sensor_on(struct st_thermal_sensor *sensor)
54 {
55         int ret;
56         struct device *dev = sensor->dev;
57
58         ret = clk_prepare_enable(sensor->clk);
59         if (ret) {
60                 dev_err(dev, "failed to enable clk\n");
61                 return ret;
62         }
63
64         ret = sensor->ops->power_ctrl(sensor, POWER_ON);
65         if (ret) {
66                 dev_err(dev, "failed to power on sensor\n");
67                 clk_disable_unprepare(sensor->clk);
68         }
69
70         return ret;
71 }
72
73 static int st_thermal_sensor_off(struct st_thermal_sensor *sensor)
74 {
75         int ret;
76
77         ret = sensor->ops->power_ctrl(sensor, POWER_OFF);
78         if (ret)
79                 return ret;
80
81         clk_disable_unprepare(sensor->clk);
82
83         return 0;
84 }
85
86 static int st_thermal_calibration(struct st_thermal_sensor *sensor)
87 {
88         int ret;
89         unsigned int val;
90         struct device *dev = sensor->dev;
91
92         /* Check if sensor calibration data is already written */
93         ret = regmap_field_read(sensor->dcorrect, &val);
94         if (ret) {
95                 dev_err(dev, "failed to read calibration data\n");
96                 return ret;
97         }
98
99         if (!val) {
100                 /*
101                  * Sensor calibration value not set by bootloader,
102                  * default calibration data to be used
103                  */
104                 ret = regmap_field_write(sensor->dcorrect,
105                                          sensor->cdata->calibration_val);
106                 if (ret)
107                         dev_err(dev, "failed to set calibration data\n");
108         }
109
110         return ret;
111 }
112
113 /* Callback to get temperature from HW*/
114 static int st_thermal_get_temp(struct thermal_zone_device *th,
115                 unsigned long *temperature)
116 {
117         struct st_thermal_sensor *sensor = th->devdata;
118         struct device *dev = sensor->dev;
119         unsigned int temp;
120         unsigned int overflow;
121         int ret;
122
123         ret = regmap_field_read(sensor->overflow, &overflow);
124         if (ret)
125                 return ret;
126         if (overflow)
127                 return -EIO;
128
129         ret = regmap_field_read(sensor->temp_data, &temp);
130         if (ret)
131                 return ret;
132
133         temp += sensor->cdata->temp_adjust_val;
134         temp = mcelsius(temp);
135
136         dev_dbg(dev, "temperature: %d\n", temp);
137
138         *temperature = temp;
139
140         return 0;
141 }
142
143 static int st_thermal_get_trip_type(struct thermal_zone_device *th,
144                                 int trip, enum thermal_trip_type *type)
145 {
146         struct st_thermal_sensor *sensor = th->devdata;
147         struct device *dev = sensor->dev;
148
149         switch (trip) {
150         case 0:
151                 *type = THERMAL_TRIP_CRITICAL;
152                 break;
153         default:
154                 dev_err(dev, "invalid trip point\n");
155                 return -EINVAL;
156         }
157
158         return 0;
159 }
160
161 static int st_thermal_get_trip_temp(struct thermal_zone_device *th,
162                                     int trip, unsigned long *temp)
163 {
164         struct st_thermal_sensor *sensor = th->devdata;
165         struct device *dev = sensor->dev;
166
167         switch (trip) {
168         case 0:
169                 *temp = mcelsius(sensor->cdata->crit_temp);
170                 break;
171         default:
172                 dev_err(dev, "Invalid trip point\n");
173                 return -EINVAL;
174         }
175
176         return 0;
177 }
178
179 static struct thermal_zone_device_ops st_tz_ops = {
180         .get_temp       = st_thermal_get_temp,
181         .get_trip_type  = st_thermal_get_trip_type,
182         .get_trip_temp  = st_thermal_get_trip_temp,
183 };
184
185 int st_thermal_register(struct platform_device *pdev,
186                         const struct of_device_id *st_thermal_of_match)
187 {
188         struct st_thermal_sensor *sensor;
189         struct device *dev = &pdev->dev;
190         struct device_node *np = dev->of_node;
191         const struct of_device_id *match;
192
193         int polling_delay;
194         int ret;
195
196         if (!np) {
197                 dev_err(dev, "device tree node not found\n");
198                 return -EINVAL;
199         }
200
201         sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
202         if (!sensor)
203                 return -ENOMEM;
204
205         sensor->dev = dev;
206
207         match = of_match_device(st_thermal_of_match, dev);
208         if (!(match && match->data))
209                 return -EINVAL;
210
211         sensor->cdata = match->data;
212         if (!sensor->cdata->ops)
213                 return -EINVAL;
214
215         sensor->ops = sensor->cdata->ops;
216
217         ret = sensor->ops->regmap_init(sensor);
218         if (ret)
219                 return ret;
220
221         ret = st_thermal_alloc_regfields(sensor);
222         if (ret)
223                 return ret;
224
225         sensor->clk = devm_clk_get(dev, "thermal");
226         if (IS_ERR(sensor->clk)) {
227                 dev_err(dev, "failed to fetch clock\n");
228                 return PTR_ERR(sensor->clk);
229         }
230
231         if (sensor->ops->register_enable_irq) {
232                 ret = sensor->ops->register_enable_irq(sensor);
233                 if (ret)
234                         return ret;
235         }
236
237         ret = st_thermal_sensor_on(sensor);
238         if (ret)
239                 return ret;
240
241         ret = st_thermal_calibration(sensor);
242         if (ret)
243                 goto sensor_off;
244
245         polling_delay = sensor->ops->register_enable_irq ? 0 : 1000;
246
247         sensor->thermal_dev =
248                 thermal_zone_device_register(dev_name(dev), 1, 0, sensor,
249                                              &st_tz_ops, NULL, 0, polling_delay);
250         if (IS_ERR(sensor->thermal_dev)) {
251                 dev_err(dev, "failed to register thermal zone device\n");
252                 ret = PTR_ERR(sensor->thermal_dev);
253                 goto sensor_off;
254         }
255
256         platform_set_drvdata(pdev, sensor);
257
258         return 0;
259
260 sensor_off:
261         st_thermal_sensor_off(sensor);
262
263         return ret;
264 }
265 EXPORT_SYMBOL_GPL(st_thermal_register);
266
267 int st_thermal_unregister(struct platform_device *pdev)
268 {
269         struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
270
271         st_thermal_sensor_off(sensor);
272         thermal_zone_device_unregister(sensor->thermal_dev);
273
274         return 0;
275 }
276 EXPORT_SYMBOL_GPL(st_thermal_unregister);
277
278 #ifdef CONFIG_PM_SLEEP
279 static int st_thermal_suspend(struct device *dev)
280 {
281         struct platform_device *pdev = to_platform_device(dev);
282         struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
283
284         return st_thermal_sensor_off(sensor);
285 }
286
287 static int st_thermal_resume(struct device *dev)
288 {
289         int ret;
290         struct platform_device *pdev = to_platform_device(dev);
291         struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
292
293         ret = st_thermal_sensor_on(sensor);
294         if (ret)
295                 return ret;
296
297         ret = st_thermal_calibration(sensor);
298         if (ret)
299                 return ret;
300
301         if (sensor->ops->enable_irq) {
302                 ret = sensor->ops->enable_irq(sensor);
303                 if (ret)
304                         return ret;
305         }
306
307         return 0;
308 }
309 #endif
310
311 SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume);
312 EXPORT_SYMBOL_GPL(st_thermal_pm_ops);
313
314 MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
315 MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
316 MODULE_LICENSE("GPL v2");