2 * Generic ADC thermal driver
4 * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
6 * Author: Laxman Dewangan <ldewangan@nvidia.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 #include <linux/iio/consumer.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
17 #include <linux/thermal.h>
19 struct gadc_thermal_info
{
21 struct thermal_zone_device
*tz_dev
;
22 struct iio_channel
*channel
;
27 static int gadc_thermal_adc_to_temp(struct gadc_thermal_info
*gti
, int val
)
29 int temp
, temp_hi
, temp_lo
, adc_hi
, adc_lo
;
32 for (i
= 0; i
< gti
->nlookup_table
; i
++) {
33 if (val
>= gti
->lookup_table
[2 * i
+ 1])
38 temp
= gti
->lookup_table
[0];
39 } else if (i
>= gti
->nlookup_table
) {
40 temp
= gti
->lookup_table
[2 * (gti
->nlookup_table
- 1)];
42 adc_hi
= gti
->lookup_table
[2 * i
- 1];
43 adc_lo
= gti
->lookup_table
[2 * i
+ 1];
45 temp_hi
= gti
->lookup_table
[2 * i
- 2];
46 temp_lo
= gti
->lookup_table
[2 * i
];
48 temp
= temp_hi
+ mult_frac(temp_lo
- temp_hi
, val
- adc_hi
,
55 static int gadc_thermal_get_temp(void *data
, int *temp
)
57 struct gadc_thermal_info
*gti
= data
;
61 ret
= iio_read_channel_processed(gti
->channel
, &val
);
63 dev_err(gti
->dev
, "IIO channel read failed %d\n", ret
);
66 *temp
= gadc_thermal_adc_to_temp(gti
, val
);
71 static const struct thermal_zone_of_device_ops gadc_thermal_ops
= {
72 .get_temp
= gadc_thermal_get_temp
,
75 static int gadc_thermal_read_linear_lookup_table(struct device
*dev
,
76 struct gadc_thermal_info
*gti
)
78 struct device_node
*np
= dev
->of_node
;
82 ntable
= of_property_count_elems_of_size(np
, "temperature-lookup-table",
85 dev_err(dev
, "Lookup table is not provided\n");
90 dev_err(dev
, "Pair of temperature vs ADC read value missing\n");
94 gti
->lookup_table
= devm_kzalloc(dev
, sizeof(*gti
->lookup_table
) *
96 if (!gti
->lookup_table
)
99 ret
= of_property_read_u32_array(np
, "temperature-lookup-table",
100 (u32
*)gti
->lookup_table
, ntable
);
102 dev_err(dev
, "Failed to read temperature lookup table: %d\n",
107 gti
->nlookup_table
= ntable
/ 2;
112 static int gadc_thermal_probe(struct platform_device
*pdev
)
114 struct gadc_thermal_info
*gti
;
117 if (!pdev
->dev
.of_node
) {
118 dev_err(&pdev
->dev
, "Only DT based supported\n");
122 gti
= devm_kzalloc(&pdev
->dev
, sizeof(*gti
), GFP_KERNEL
);
126 ret
= gadc_thermal_read_linear_lookup_table(&pdev
->dev
, gti
);
130 gti
->dev
= &pdev
->dev
;
131 platform_set_drvdata(pdev
, gti
);
133 gti
->channel
= iio_channel_get(&pdev
->dev
, "sensor-channel");
134 if (IS_ERR(gti
->channel
)) {
135 ret
= PTR_ERR(gti
->channel
);
136 dev_err(&pdev
->dev
, "IIO channel not found: %d\n", ret
);
140 gti
->tz_dev
= thermal_zone_of_sensor_register(&pdev
->dev
, 0,
141 gti
, &gadc_thermal_ops
);
142 if (IS_ERR(gti
->tz_dev
)) {
143 ret
= PTR_ERR(gti
->tz_dev
);
144 dev_err(&pdev
->dev
, "Thermal zone sensor register failed: %d\n",
152 iio_channel_release(gti
->channel
);
157 static int gadc_thermal_remove(struct platform_device
*pdev
)
159 struct gadc_thermal_info
*gti
= platform_get_drvdata(pdev
);
161 thermal_zone_of_sensor_unregister(&pdev
->dev
, gti
->tz_dev
);
162 iio_channel_release(gti
->channel
);
167 static const struct of_device_id of_adc_thermal_match
[] = {
168 { .compatible
= "generic-adc-thermal", },
171 MODULE_DEVICE_TABLE(of
, of_adc_thermal_match
);
173 static struct platform_driver gadc_thermal_driver
= {
175 .name
= "generic-adc-thermal",
176 .of_match_table
= of_adc_thermal_match
,
178 .probe
= gadc_thermal_probe
,
179 .remove
= gadc_thermal_remove
,
182 module_platform_driver(gadc_thermal_driver
);
184 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
185 MODULE_DESCRIPTION("Generic ADC thermal driver using IIO framework with DT");
186 MODULE_LICENSE("GPL v2");