2 * drivers/staging/iio/generic_adc_thermal.c
4 * Generic ADC thermal driver
6 * Copyright (c) 2013-2014, NVIDIA Corporation. All rights reserved.
8 * Author: Jinyoung Park <jinyoungp@nvidia.com>
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.
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.
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
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>
37 struct gadc_thermal_driver_data {
39 struct thermal_zone_device *tz;
40 struct iio_channel *channel;
41 struct gadc_thermal_platform_data *pdata;
42 struct dentry *dentry;
44 unsigned int lookup_table_size;
51 static int gadc_thermal_thermistor_adc_to_temp(
52 struct gadc_thermal_driver_data *drvdata, int adc_raw)
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;
60 int temp, adc_low, adc_high, diff_temp;
61 int temp_decrement = (first_index_temp > last_index_temp);
63 for (i = 0; i < table_size - 1; ++i) {
65 if (adc_raw <= lookup_table[i])
68 if (adc_raw >= lookup_table[i])
74 return first_index_temp;
76 return last_index_temp;
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;
83 temp = (first_index_temp - i) * 1000;
84 temp += ((adc_high - adc_raw) * 1000) / (adc_high - adc_low);
86 temp = (first_index_temp + i - 1) * 1000;
87 temp += (adc_low - adc_raw) * 1000 / (adc_high - adc_low);
92 static int gadc_thermal_read_channel(struct gadc_thermal_driver_data *drvdata,
97 if (drvdata->dual_mode) {
98 ret = iio_read_channel_processed_dual(drvdata->channel, val,
101 ret = iio_read_channel_raw_dual(drvdata->channel, val,
104 ret = iio_read_channel_processed(drvdata->channel, val);
106 ret = iio_read_channel_raw(drvdata->channel, val);
111 static int gadc_thermal_bind(struct thermal_zone_device *tz,
112 struct thermal_cooling_device *cdev)
114 struct gadc_thermal_driver_data *drvdata = tz->devdata;
115 struct thermal_trip_info *trip_state;
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);
132 static int gadc_thermal_unbind(struct thermal_zone_device *tz,
133 struct thermal_cooling_device *cdev)
135 struct gadc_thermal_driver_data *drvdata = tz->devdata;
136 struct thermal_trip_info *trip_state;
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);
152 static int gadc_thermal_get_temp(struct thermal_zone_device *tz,
155 struct gadc_thermal_driver_data *drvdata = tz->devdata;
156 int val = 0, val2 = 0;
159 ret = gadc_thermal_read_channel(drvdata, &val, &val2);
161 dev_err(drvdata->dev, "%s: Failed to read channel, %d\n",
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);
173 *temp += drvdata->temp_offset;
177 static int gadc_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
178 enum thermal_trip_type *type)
180 struct gadc_thermal_driver_data *drvdata = tz->devdata;
181 struct thermal_trip_info *trip_state = &drvdata->pdata->trips[trip];
183 *type = trip_state->trip_type;
187 static int gadc_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
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;
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;
209 static int gadc_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
212 struct gadc_thermal_driver_data *drvdata = tz->devdata;
213 struct thermal_trip_info *trip_state = &drvdata->pdata->trips[trip];
215 trip_state->trip_temp = temp;
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,
228 #ifdef CONFIG_DEBUG_FS
229 static int iio_channel_name_show(struct seq_file *s, void *p)
231 struct gadc_thermal_driver_data *drvdata = s->private;
233 seq_printf(s, "%s\n", drvdata->pdata->iio_channel_name);
237 static int iio_channel_name_open(struct inode *inode, struct file *file)
239 return single_open(file, iio_channel_name_show, inode->i_private);
242 static const struct file_operations iio_channel_name_fops = {
243 .open = iio_channel_name_open,
246 .release = single_release,
249 static int tz_name_show(struct seq_file *s, void *p)
251 struct gadc_thermal_driver_data *drvdata = s->private;
253 seq_printf(s, "%s\n", drvdata->pdata->tz_name);
257 static int tz_name_open(struct inode *inode, struct file *file)
259 return single_open(file, tz_name_show, inode->i_private);
262 static const struct file_operations tz_name_fops = {
263 .open = tz_name_open,
266 .release = single_release,
269 static int adc_temp_show(struct seq_file *s, void *p)
271 struct gadc_thermal_driver_data *drvdata = s->private;
272 int val = 0, val2 = 0, temp = 0;
275 ret = gadc_thermal_read_channel(drvdata, &val, &val2);
277 dev_err(drvdata->dev, "%s: Failed to read channel, %d\n",
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);
289 temp += drvdata->temp_offset;
290 seq_printf(s, "%d %d %d\n", val, val2, temp);
294 static int adc_temp_open(struct inode *inode, struct file *file)
296 return single_open(file, adc_temp_show, inode->i_private);
299 static const struct file_operations adc_temp_fops = {
300 .open = adc_temp_open,
303 .release = single_release,
306 static int raw_adc_show(struct seq_file *s, void *p)
308 struct gadc_thermal_driver_data *drvdata = s->private;
309 int val = 0, val2 = 0;
312 if (drvdata->dual_mode)
313 ret = iio_read_channel_raw_dual(drvdata->channel, &val, &val2);
315 ret = iio_read_channel_raw(drvdata->channel, &val);
317 dev_err(drvdata->dev, "%s: Failed to read channel raw, %d\n",
322 seq_printf(s, "%d %d\n", val, val2);
326 static int raw_adc_open(struct inode *inode, struct file *file)
328 return single_open(file, raw_adc_show, inode->i_private);
331 static const struct file_operations raw_adc_fops = {
332 .open = raw_adc_open,
335 .release = single_release,
338 static int temp_offset_write(struct file *file, const char __user *user_buf,
339 size_t count, loff_t *ppos)
341 struct gadc_thermal_driver_data *drvdata =
342 ((struct seq_file *)(file->private_data))->private;
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",
356 while (*start == ' ')
359 if (kstrtol(start, 10, &val))
362 drvdata->pdata->temp_offset = val;
366 static int temp_offset_show(struct seq_file *s, void *p)
368 struct gadc_thermal_driver_data *drvdata = s->private;
370 seq_printf(s, "%d\n", drvdata->pdata->temp_offset);
374 static int temp_offset_open(struct inode *inode, struct file *file)
376 return single_open(file, temp_offset_show, inode->i_private);
379 static const struct file_operations temp_offset_fops = {
380 .open = temp_offset_open,
381 .write = temp_offset_write,
384 .release = single_release,
387 static int gadc_thermal_debugfs_init(struct gadc_thermal_driver_data *drvdata)
389 struct dentry *d_file;
391 drvdata->dentry = debugfs_create_dir(dev_name(drvdata->dev), NULL);
392 if (!drvdata->dentry)
395 d_file = debugfs_create_file("iio_channel_name", 0444, drvdata->dentry,
396 drvdata, &iio_channel_name_fops);
400 d_file = debugfs_create_file("tz_name", 0444, drvdata->dentry,
401 drvdata, &tz_name_fops);
405 d_file = debugfs_create_file("adc_temp", 0444, drvdata->dentry,
406 drvdata, &adc_temp_fops);
410 d_file = debugfs_create_file("raw_adc", 0444, drvdata->dentry,
411 drvdata, &raw_adc_fops);
415 d_file = debugfs_create_file("temp_offset", 0644, drvdata->dentry,
416 drvdata, &temp_offset_fops);
423 debugfs_remove_recursive(drvdata->dentry);
426 #endif /* CONFIG_DEBUG_FS */
428 static int gadc_thermal_probe(struct platform_device *pdev)
430 struct gadc_thermal_platform_data *pdata = dev_get_platdata(&pdev->dev);
431 struct gadc_thermal_driver_data *drvdata;
435 dev_err(&pdev->dev, "%s: No platform data\n", __func__);
439 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
442 "%s: Failed to alloc memory for driver data\n",
446 if (pdata->lookup_table_size) {
447 drvdata->adc_temp_lookup = devm_kzalloc(&pdev->dev,
448 pdata->lookup_table_size * sizeof(unsigned int),
450 if (!drvdata->adc_temp_lookup)
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));
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);
475 drvdata->tz = thermal_zone_device_register(pdata->tz_name,
477 (1ULL << pdata->num_trips) - 1,
478 drvdata, &gadc_thermal_ops,
479 pdata->tzp, 0, pdata->polling_delay);
480 if (IS_ERR(drvdata->tz)) {
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;
488 gadc_thermal_debugfs_init(drvdata);
492 error_release_channel:
493 iio_channel_release(drvdata->channel);
497 static int gadc_thermal_remove(struct platform_device *pdev)
499 struct gadc_thermal_driver_data *drvdata = platform_get_drvdata(pdev);
502 debugfs_remove_recursive(drvdata->dentry);
503 thermal_zone_device_unregister(drvdata->tz);
504 iio_channel_release(drvdata->channel);
508 static void gadc_thermal_shutdown(struct platform_device *pdev)
510 struct gadc_thermal_driver_data *drvdata = platform_get_drvdata(pdev);
511 thermal_zone_device_unregister(drvdata->tz);
514 static struct platform_driver gadc_thermal_driver = {
516 .name = "generic-adc-thermal",
517 .owner = THIS_MODULE,
519 .probe = gadc_thermal_probe,
520 .remove = gadc_thermal_remove,
521 .shutdown = gadc_thermal_shutdown,
524 module_platform_driver(gadc_thermal_driver);
526 MODULE_AUTHOR("Jinyoung Park <jinyoungp@nvidia.com>");
527 MODULE_DESCRIPTION("Generic ADC thermal driver using IIO framework");
528 MODULE_LICENSE("GPL v2");