]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/thermal/generic_adc_thermal.c
thermal: generic-adc-thermal: Add shutdown callback
[sojka/nv-tegra/linux-3.10.git] / drivers / thermal / generic_adc_thermal.c
1 /*
2  * drivers/staging/iio/generic_adc_thermal.c
3  *
4  * Generic ADC thermal driver
5  *
6  * Copyright (c) 2013-2014, NVIDIA Corporation. All rights reserved.
7  *
8  * Author: Jinyoung Park <jinyoungp@nvidia.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation version 2.
13  *
14  * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
15  * whether express or implied; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22  * 02111-1307, USA
23  */
24 #include <linux/kernel.h>
25 #include <linux/platform_device.h>
26 #include <linux/slab.h>
27 #include <linux/uaccess.h>
28 #include <linux/module.h>
29 #include <linux/debugfs.h>
30 #include <linux/seq_file.h>
31 #include <linux/err.h>
32 #include <linux/thermal.h>
33 #include <linux/iio/consumer.h>
34 #include <linux/iio/types.h>
35 #include <linux/generic_adc_thermal.h>
36
37 struct gadc_thermal_driver_data {
38         struct device *dev;
39         struct thermal_zone_device *tz;
40         struct iio_channel *channel;
41         struct gadc_thermal_platform_data *pdata;
42         struct dentry *dentry;
43         int *adc_temp_lookup;
44         unsigned int lookup_table_size;
45         int first_index_temp;
46         int last_index_temp;
47         int temp_offset;
48         bool dual_mode;
49 };
50
51 static int gadc_thermal_thermistor_adc_to_temp(
52         struct gadc_thermal_driver_data *drvdata, int adc_raw)
53 {
54
55         int *lookup_table = drvdata->adc_temp_lookup;
56         int table_size = drvdata->lookup_table_size;
57         int first_index_temp = drvdata->first_index_temp;
58         int last_index_temp = drvdata->last_index_temp;
59         int i;
60         int temp, adc_low, adc_high, diff_temp;
61         int temp_decrement = (first_index_temp > last_index_temp);
62
63         for (i = 0; i < table_size - 1; ++i) {
64                 if (temp_decrement) {
65                         if (adc_raw <= lookup_table[i])
66                                 break;
67                 } else {
68                         if (adc_raw >= lookup_table[i])
69                                 break;
70                 }
71         }
72
73         if (i == 0)
74                 return first_index_temp;
75         if (i == table_size)
76                 return last_index_temp;
77
78         /* Find temp with interpolate reading */
79         adc_low = lookup_table[i-1];
80         adc_high = lookup_table[i];
81         diff_temp = (adc_high - adc_low) * 1000;
82         if (temp_decrement) {
83                 temp = (first_index_temp - i) * 1000;
84                 temp += ((adc_high - adc_raw) * 1000) / (adc_high - adc_low);
85         } else {
86                 temp = (first_index_temp + i - 1) * 1000;
87                 temp += (adc_low - adc_raw) * 1000 / (adc_high - adc_low);
88         }
89         return temp;
90 }
91
92 static int gadc_thermal_read_channel(struct gadc_thermal_driver_data *drvdata,
93                                      int *val, int *val2)
94 {
95         int ret;
96
97         if (drvdata->dual_mode) {
98                 ret = iio_read_channel_processed_dual(drvdata->channel, val,
99                                                       val2);
100                 if (ret < 0)
101                         ret = iio_read_channel_raw_dual(drvdata->channel, val,
102                                                         val2);
103         } else {
104                 ret = iio_read_channel_processed(drvdata->channel, val);
105                 if (ret < 0)
106                         ret = iio_read_channel_raw(drvdata->channel, val);
107         }
108         return ret;
109 }
110
111 static int gadc_thermal_bind(struct thermal_zone_device *tz,
112                              struct thermal_cooling_device *cdev)
113 {
114         struct gadc_thermal_driver_data *drvdata = tz->devdata;
115         struct thermal_trip_info *trip_state;
116         int i, ret;
117
118         for (i = 0; i < drvdata->pdata->num_trips; i++) {
119                 trip_state = &drvdata->pdata->trips[i];
120                 if (trip_state->cdev_type &&
121                     !strncmp(trip_state->cdev_type, cdev->type,
122                              THERMAL_NAME_LENGTH)) {
123                         ret = thermal_zone_bind_cooling_device(tz, i, cdev,
124                                         trip_state->upper, trip_state->lower);
125                         if (ret < 0)
126                                 return ret;
127                 }
128         }
129         return 0;
130 }
131
132 static int gadc_thermal_unbind(struct thermal_zone_device *tz,
133                                struct thermal_cooling_device *cdev)
134 {
135         struct gadc_thermal_driver_data *drvdata = tz->devdata;
136         struct thermal_trip_info *trip_state;
137         int i, ret;
138
139         for (i = 0; i < drvdata->pdata->num_trips; i++) {
140                 trip_state = &drvdata->pdata->trips[i];
141                 if (trip_state->cdev_type &&
142                     !strncmp(trip_state->cdev_type, cdev->type,
143                              THERMAL_NAME_LENGTH)) {
144                         ret = thermal_zone_unbind_cooling_device(tz, i, cdev);
145                         if (ret < 0)
146                                 return ret;
147                 }
148         }
149         return 0;
150 }
151
152 static int gadc_thermal_get_temp(struct thermal_zone_device *tz,
153                                  unsigned long *temp)
154 {
155         struct gadc_thermal_driver_data *drvdata = tz->devdata;
156         int val = 0, val2 = 0;
157         int ret;
158
159         ret = gadc_thermal_read_channel(drvdata, &val, &val2);
160         if (ret < 0) {
161                 dev_err(drvdata->dev, "%s: Failed to read channel, %d\n",
162                         __func__, ret);
163                 return ret;
164         }
165
166         if (drvdata->pdata->adc_to_temp)
167                 *temp = drvdata->pdata->adc_to_temp(drvdata->pdata, val, val2);
168         else if (drvdata->pdata->adc_temp_lookup)
169                 *temp = gadc_thermal_thermistor_adc_to_temp(drvdata, val);
170         else
171                 *temp = val;
172
173         *temp += drvdata->temp_offset;
174         return 0;
175 }
176
177 static int gadc_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
178                                       enum thermal_trip_type *type)
179 {
180         struct gadc_thermal_driver_data *drvdata = tz->devdata;
181         struct thermal_trip_info *trip_state = &drvdata->pdata->trips[trip];
182
183         *type = trip_state->trip_type;
184         return 0;
185 }
186
187 static int gadc_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
188                                       unsigned long *temp)
189 {
190         struct gadc_thermal_driver_data *drvdata = tz->devdata;
191         struct thermal_trip_info *trip_state = &drvdata->pdata->trips[trip];
192         long zone_temp = tz->temperature;
193         long trip_temp = trip_state->trip_temp;
194         long hysteresis = trip_state->hysteresis;
195
196         if (zone_temp >= trip_temp) {
197                 trip_temp -= hysteresis;
198                 trip_state->tripped = true;
199         } else if (trip_state->tripped) {
200                 trip_temp -= hysteresis;
201                 if (zone_temp < trip_temp)
202                         trip_state->tripped = false;
203         }
204
205         *temp = trip_temp;
206         return 0;
207 }
208
209 static int gadc_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
210                                       unsigned long temp)
211 {
212         struct gadc_thermal_driver_data *drvdata = tz->devdata;
213         struct thermal_trip_info *trip_state = &drvdata->pdata->trips[trip];
214
215         trip_state->trip_temp = temp;
216         return 0;
217 }
218
219 static struct thermal_zone_device_ops gadc_thermal_ops = {
220         .bind = gadc_thermal_bind,
221         .unbind = gadc_thermal_unbind,
222         .get_temp = gadc_thermal_get_temp,
223         .get_trip_type = gadc_thermal_get_trip_type,
224         .get_trip_temp = gadc_thermal_get_trip_temp,
225         .set_trip_temp = gadc_thermal_set_trip_temp,
226 };
227
228 #ifdef CONFIG_DEBUG_FS
229 static int iio_channel_name_show(struct seq_file *s, void *p)
230 {
231         struct gadc_thermal_driver_data *drvdata = s->private;
232
233         seq_printf(s, "%s\n", drvdata->pdata->iio_channel_name);
234         return 0;
235 }
236
237 static int iio_channel_name_open(struct inode *inode, struct file *file)
238 {
239         return single_open(file, iio_channel_name_show, inode->i_private);
240 }
241
242 static const struct file_operations iio_channel_name_fops = {
243         .open           = iio_channel_name_open,
244         .read           = seq_read,
245         .llseek         = seq_lseek,
246         .release        = single_release,
247 };
248
249 static int tz_name_show(struct seq_file *s, void *p)
250 {
251         struct gadc_thermal_driver_data *drvdata = s->private;
252
253         seq_printf(s, "%s\n", drvdata->pdata->tz_name);
254         return 0;
255 }
256
257 static int tz_name_open(struct inode *inode, struct file *file)
258 {
259         return single_open(file, tz_name_show, inode->i_private);
260 }
261
262 static const struct file_operations tz_name_fops = {
263         .open           = tz_name_open,
264         .read           = seq_read,
265         .llseek         = seq_lseek,
266         .release        = single_release,
267 };
268
269 static int adc_temp_show(struct seq_file *s, void *p)
270 {
271         struct gadc_thermal_driver_data *drvdata = s->private;
272         int val = 0, val2 = 0, temp = 0;
273         int ret;
274
275         ret = gadc_thermal_read_channel(drvdata, &val, &val2);
276         if (ret < 0) {
277                 dev_err(drvdata->dev, "%s: Failed to read channel, %d\n",
278                         __func__, ret);
279                 return ret;
280         }
281
282         if (drvdata->pdata->adc_to_temp)
283                 temp = drvdata->pdata->adc_to_temp(drvdata->pdata, val, val2);
284         else if (drvdata->pdata->adc_temp_lookup)
285                 temp = gadc_thermal_thermistor_adc_to_temp(drvdata, val);
286         else
287                 temp = val;
288
289         temp += drvdata->temp_offset;
290         seq_printf(s, "%d %d %d\n", val, val2, temp);
291         return 0;
292 }
293
294 static int adc_temp_open(struct inode *inode, struct file *file)
295 {
296         return single_open(file, adc_temp_show, inode->i_private);
297 }
298
299 static const struct file_operations adc_temp_fops = {
300         .open           = adc_temp_open,
301         .read           = seq_read,
302         .llseek         = seq_lseek,
303         .release        = single_release,
304 };
305
306 static int raw_adc_show(struct seq_file *s, void *p)
307 {
308         struct gadc_thermal_driver_data *drvdata = s->private;
309         int val = 0, val2 = 0;
310         int ret;
311
312         if (drvdata->dual_mode)
313                 ret = iio_read_channel_raw_dual(drvdata->channel, &val, &val2);
314         else
315                 ret = iio_read_channel_raw(drvdata->channel, &val);
316         if (ret < 0) {
317                 dev_err(drvdata->dev, "%s: Failed to read channel raw, %d\n",
318                         __func__, ret);
319                 return ret;
320         }
321
322         seq_printf(s, "%d %d\n", val, val2);
323         return 0;
324 }
325
326 static int raw_adc_open(struct inode *inode, struct file *file)
327 {
328         return single_open(file, raw_adc_show, inode->i_private);
329 }
330
331 static const struct file_operations raw_adc_fops = {
332         .open           = raw_adc_open,
333         .read           = seq_read,
334         .llseek         = seq_lseek,
335         .release        = single_release,
336 };
337
338 static int temp_offset_write(struct file *file, const char __user *user_buf,
339                              size_t count, loff_t *ppos)
340 {
341         struct gadc_thermal_driver_data *drvdata =
342                         ((struct seq_file *)(file->private_data))->private;
343         char buf[32];
344         ssize_t buf_size;
345         char *start = buf;
346         long val;
347
348         buf_size = min(count, (sizeof(buf)-1));
349         if (copy_from_user(buf, user_buf, buf_size)) {
350                 dev_err(drvdata->dev, "%s: Failed to copy from user\n",
351                         __func__);
352                 return -EFAULT;
353         }
354         buf[buf_size] = 0;
355
356         while (*start == ' ')
357                 start++;
358
359         if (kstrtol(start, 10, &val))
360                 return -EINVAL;
361
362         drvdata->pdata->temp_offset = val;
363         return buf_size;
364 }
365
366 static int temp_offset_show(struct seq_file *s, void *p)
367 {
368         struct gadc_thermal_driver_data *drvdata = s->private;
369
370         seq_printf(s, "%d\n", drvdata->pdata->temp_offset);
371         return 0;
372 }
373
374 static int temp_offset_open(struct inode *inode, struct file *file)
375 {
376         return single_open(file, temp_offset_show, inode->i_private);
377 }
378
379 static const struct file_operations temp_offset_fops = {
380         .open           = temp_offset_open,
381         .write          = temp_offset_write,
382         .read           = seq_read,
383         .llseek         = seq_lseek,
384         .release        = single_release,
385 };
386
387 static int gadc_thermal_debugfs_init(struct gadc_thermal_driver_data *drvdata)
388 {
389         struct dentry *d_file;
390
391         drvdata->dentry = debugfs_create_dir(dev_name(drvdata->dev), NULL);
392         if (!drvdata->dentry)
393                 return -ENOMEM;
394
395         d_file = debugfs_create_file("iio_channel_name", 0444, drvdata->dentry,
396                                      drvdata, &iio_channel_name_fops);
397         if (!d_file)
398                 goto error;
399
400         d_file = debugfs_create_file("tz_name", 0444, drvdata->dentry,
401                                      drvdata, &tz_name_fops);
402         if (!d_file)
403                 goto error;
404
405         d_file = debugfs_create_file("adc_temp", 0444, drvdata->dentry,
406                                      drvdata, &adc_temp_fops);
407         if (!d_file)
408                 goto error;
409
410         d_file = debugfs_create_file("raw_adc", 0444, drvdata->dentry,
411                                      drvdata, &raw_adc_fops);
412         if (!d_file)
413                 goto error;
414
415         d_file = debugfs_create_file("temp_offset", 0644, drvdata->dentry,
416                                      drvdata, &temp_offset_fops);
417         if (!d_file)
418                 goto error;
419
420         return 0;
421
422 error:
423         debugfs_remove_recursive(drvdata->dentry);
424         return -ENOMEM;
425 }
426 #endif /*  CONFIG_DEBUG_FS */
427
428 static int gadc_thermal_probe(struct platform_device *pdev)
429 {
430         struct gadc_thermal_platform_data *pdata = dev_get_platdata(&pdev->dev);
431         struct gadc_thermal_driver_data *drvdata;
432         int ret;
433
434         if (!pdata) {
435                 dev_err(&pdev->dev, "%s: No platform data\n", __func__);
436                 return -ENODEV;
437         }
438
439         drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
440         if (!drvdata) {
441                 dev_err(&pdev->dev,
442                         "%s: Failed to alloc memory for driver data\n",
443                         __func__);
444                 return -ENOMEM;
445         }
446         if (pdata->lookup_table_size) {
447                 drvdata->adc_temp_lookup =  devm_kzalloc(&pdev->dev,
448                                 pdata->lookup_table_size * sizeof(unsigned int),
449                                 GFP_KERNEL);
450                 if (!drvdata->adc_temp_lookup)
451                         return -ENOMEM;
452         }
453
454         platform_set_drvdata(pdev, drvdata);
455         drvdata->dev = &pdev->dev;
456         drvdata->pdata = pdata;
457         drvdata->lookup_table_size = pdata->lookup_table_size;
458         drvdata->first_index_temp = pdata->first_index_temp;
459         drvdata->last_index_temp = pdata->last_index_temp;
460         drvdata->temp_offset = pdata->temp_offset;
461         drvdata->dual_mode = pdata->dual_mode;
462         if (drvdata->lookup_table_size)
463                 memcpy(drvdata->adc_temp_lookup, pdata->adc_temp_lookup,
464                         pdata->lookup_table_size * sizeof(unsigned int));
465
466         drvdata->channel = iio_channel_get(&pdev->dev,
467                                         pdata->iio_channel_name);
468         if (IS_ERR(drvdata->channel)) {
469                 dev_err(&pdev->dev, "%s: Failed to get channel %s, %ld\n",
470                         __func__, pdata->iio_channel_name,
471                         PTR_ERR(drvdata->channel));
472                 return PTR_ERR(drvdata->channel);
473         }
474
475         drvdata->tz = thermal_zone_device_register(pdata->tz_name,
476                                         pdata->num_trips,
477                                         (1ULL << pdata->num_trips) - 1,
478                                         drvdata, &gadc_thermal_ops,
479                                         pdata->tzp, 0, pdata->polling_delay);
480         if (IS_ERR(drvdata->tz)) {
481                 dev_err(&pdev->dev,
482                         "%s: Failed to register thermal zone %s, %ld\n",
483                         __func__, pdata->tz_name, PTR_ERR(drvdata->tz));
484                 ret = PTR_ERR(drvdata->tz);
485                 goto error_release_channel;
486         }
487
488         gadc_thermal_debugfs_init(drvdata);
489
490         return 0;
491
492 error_release_channel:
493         iio_channel_release(drvdata->channel);
494         return ret;
495 }
496
497 static int gadc_thermal_remove(struct platform_device *pdev)
498 {
499         struct gadc_thermal_driver_data *drvdata = platform_get_drvdata(pdev);
500
501         if (drvdata->dentry)
502                 debugfs_remove_recursive(drvdata->dentry);
503         thermal_zone_device_unregister(drvdata->tz);
504         iio_channel_release(drvdata->channel);
505         return 0;
506 }
507
508 static void gadc_thermal_shutdown(struct platform_device *pdev)
509 {
510         struct gadc_thermal_driver_data *drvdata = platform_get_drvdata(pdev);
511         thermal_zone_device_unregister(drvdata->tz);
512 }
513
514 static struct platform_driver gadc_thermal_driver = {
515         .driver = {
516                 .name = "generic-adc-thermal",
517                 .owner = THIS_MODULE,
518         },
519         .probe = gadc_thermal_probe,
520         .remove = gadc_thermal_remove,
521         .shutdown = gadc_thermal_shutdown,
522 };
523
524 module_platform_driver(gadc_thermal_driver);
525
526 MODULE_AUTHOR("Jinyoung Park <jinyoungp@nvidia.com>");
527 MODULE_DESCRIPTION("Generic ADC thermal driver using IIO framework");
528 MODULE_LICENSE("GPL v2");