Linux-libre 4.4.228-gnu
[librecmc/linux-libre.git] / 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, int *temperature)
115 {
116         struct st_thermal_sensor *sensor = th->devdata;
117         struct device *dev = sensor->dev;
118         unsigned int temp;
119         unsigned int overflow;
120         int ret;
121
122         ret = regmap_field_read(sensor->overflow, &overflow);
123         if (ret)
124                 return ret;
125         if (overflow)
126                 return -EIO;
127
128         ret = regmap_field_read(sensor->temp_data, &temp);
129         if (ret)
130                 return ret;
131
132         temp += sensor->cdata->temp_adjust_val;
133         temp = mcelsius(temp);
134
135         dev_dbg(dev, "temperature: %d\n", temp);
136
137         *temperature = temp;
138
139         return 0;
140 }
141
142 static int st_thermal_get_trip_type(struct thermal_zone_device *th,
143                                 int trip, enum thermal_trip_type *type)
144 {
145         struct st_thermal_sensor *sensor = th->devdata;
146         struct device *dev = sensor->dev;
147
148         switch (trip) {
149         case 0:
150                 *type = THERMAL_TRIP_CRITICAL;
151                 break;
152         default:
153                 dev_err(dev, "invalid trip point\n");
154                 return -EINVAL;
155         }
156
157         return 0;
158 }
159
160 static int st_thermal_get_trip_temp(struct thermal_zone_device *th,
161                                     int trip, int *temp)
162 {
163         struct st_thermal_sensor *sensor = th->devdata;
164         struct device *dev = sensor->dev;
165
166         switch (trip) {
167         case 0:
168                 *temp = mcelsius(sensor->cdata->crit_temp);
169                 break;
170         default:
171                 dev_err(dev, "Invalid trip point\n");
172                 return -EINVAL;
173         }
174
175         return 0;
176 }
177
178 static struct thermal_zone_device_ops st_tz_ops = {
179         .get_temp       = st_thermal_get_temp,
180         .get_trip_type  = st_thermal_get_trip_type,
181         .get_trip_temp  = st_thermal_get_trip_temp,
182 };
183
184 int st_thermal_register(struct platform_device *pdev,
185                         const struct of_device_id *st_thermal_of_match)
186 {
187         struct st_thermal_sensor *sensor;
188         struct device *dev = &pdev->dev;
189         struct device_node *np = dev->of_node;
190         const struct of_device_id *match;
191
192         int polling_delay;
193         int ret;
194
195         if (!np) {
196                 dev_err(dev, "device tree node not found\n");
197                 return -EINVAL;
198         }
199
200         sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
201         if (!sensor)
202                 return -ENOMEM;
203
204         sensor->dev = dev;
205
206         match = of_match_device(st_thermal_of_match, dev);
207         if (!(match && match->data))
208                 return -EINVAL;
209
210         sensor->cdata = match->data;
211         if (!sensor->cdata->ops)
212                 return -EINVAL;
213
214         sensor->ops = sensor->cdata->ops;
215
216         ret = (sensor->ops->regmap_init)(sensor);
217         if (ret)
218                 return ret;
219
220         ret = st_thermal_alloc_regfields(sensor);
221         if (ret)
222                 return ret;
223
224         sensor->clk = devm_clk_get(dev, "thermal");
225         if (IS_ERR(sensor->clk)) {
226                 dev_err(dev, "failed to fetch clock\n");
227                 return PTR_ERR(sensor->clk);
228         }
229
230         if (sensor->ops->register_enable_irq) {
231                 ret = sensor->ops->register_enable_irq(sensor);
232                 if (ret)
233                         return ret;
234         }
235
236         ret = st_thermal_sensor_on(sensor);
237         if (ret)
238                 return ret;
239
240         ret = st_thermal_calibration(sensor);
241         if (ret)
242                 goto sensor_off;
243
244         polling_delay = sensor->ops->register_enable_irq ? 0 : 1000;
245
246         sensor->thermal_dev =
247                 thermal_zone_device_register(dev_name(dev), 1, 0, sensor,
248                                              &st_tz_ops, NULL, 0, polling_delay);
249         if (IS_ERR(sensor->thermal_dev)) {
250                 dev_err(dev, "failed to register thermal zone device\n");
251                 ret = PTR_ERR(sensor->thermal_dev);
252                 goto sensor_off;
253         }
254
255         platform_set_drvdata(pdev, sensor);
256
257         return 0;
258
259 sensor_off:
260         st_thermal_sensor_off(sensor);
261
262         return ret;
263 }
264 EXPORT_SYMBOL_GPL(st_thermal_register);
265
266 int st_thermal_unregister(struct platform_device *pdev)
267 {
268         struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
269
270         st_thermal_sensor_off(sensor);
271         thermal_zone_device_unregister(sensor->thermal_dev);
272
273         return 0;
274 }
275 EXPORT_SYMBOL_GPL(st_thermal_unregister);
276
277 #ifdef CONFIG_PM_SLEEP
278 static int st_thermal_suspend(struct device *dev)
279 {
280         struct platform_device *pdev = to_platform_device(dev);
281         struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
282
283         return st_thermal_sensor_off(sensor);
284 }
285
286 static int st_thermal_resume(struct device *dev)
287 {
288         int ret;
289         struct platform_device *pdev = to_platform_device(dev);
290         struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
291
292         ret = st_thermal_sensor_on(sensor);
293         if (ret)
294                 return ret;
295
296         ret = st_thermal_calibration(sensor);
297         if (ret)
298                 return ret;
299
300         if (sensor->ops->enable_irq) {
301                 ret = sensor->ops->enable_irq(sensor);
302                 if (ret)
303                         return ret;
304         }
305
306         return 0;
307 }
308 #endif
309
310 SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume);
311 EXPORT_SYMBOL_GPL(st_thermal_pm_ops);
312
313 MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
314 MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
315 MODULE_LICENSE("GPL v2");