1 // SPDX-License-Identifier: GPL-2.0-only
3 * Generic ADC thermal driver
5 * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
7 * Author: Laxman Dewangan <ldewangan@nvidia.com>
9 #include <linux/iio/consumer.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/slab.h>
14 #include <linux/thermal.h>
16 #include "thermal_hwmon.h"
18 struct gadc_thermal_info
{
20 struct thermal_zone_device
*tz_dev
;
21 struct iio_channel
*channel
;
26 static int gadc_thermal_adc_to_temp(struct gadc_thermal_info
*gti
, int val
)
28 int temp
, temp_hi
, temp_lo
, adc_hi
, adc_lo
;
31 if (!gti
->lookup_table
)
34 for (i
= 0; i
< gti
->nlookup_table
; i
++) {
35 if (val
>= gti
->lookup_table
[2 * i
+ 1])
40 temp
= gti
->lookup_table
[0];
41 } else if (i
>= gti
->nlookup_table
) {
42 temp
= gti
->lookup_table
[2 * (gti
->nlookup_table
- 1)];
44 adc_hi
= gti
->lookup_table
[2 * i
- 1];
45 adc_lo
= gti
->lookup_table
[2 * i
+ 1];
47 temp_hi
= gti
->lookup_table
[2 * i
- 2];
48 temp_lo
= gti
->lookup_table
[2 * i
];
50 temp
= temp_hi
+ mult_frac(temp_lo
- temp_hi
, val
- adc_hi
,
57 static int gadc_thermal_get_temp(struct thermal_zone_device
*tz
, int *temp
)
59 struct gadc_thermal_info
*gti
= thermal_zone_device_priv(tz
);
63 ret
= iio_read_channel_processed(gti
->channel
, &val
);
67 *temp
= gadc_thermal_adc_to_temp(gti
, val
);
72 static const struct thermal_zone_device_ops gadc_thermal_ops
= {
73 .get_temp
= gadc_thermal_get_temp
,
76 static int gadc_thermal_read_linear_lookup_table(struct device
*dev
,
77 struct gadc_thermal_info
*gti
)
79 struct device_node
*np
= dev
->of_node
;
80 enum iio_chan_type chan_type
;
84 ntable
= of_property_count_elems_of_size(np
, "temperature-lookup-table",
87 ret
= iio_get_channel_type(gti
->channel
, &chan_type
);
88 if (ret
|| chan_type
!= IIO_TEMP
)
90 "no lookup table, assuming DAC channel returns milliCelcius\n");
95 dev_err(dev
, "Pair of temperature vs ADC read value missing\n");
99 gti
->lookup_table
= devm_kcalloc(dev
,
100 ntable
, sizeof(*gti
->lookup_table
),
102 if (!gti
->lookup_table
)
105 ret
= of_property_read_u32_array(np
, "temperature-lookup-table",
106 (u32
*)gti
->lookup_table
, ntable
);
108 dev_err(dev
, "Failed to read temperature lookup table: %d\n",
113 gti
->nlookup_table
= ntable
/ 2;
118 static int gadc_thermal_probe(struct platform_device
*pdev
)
120 struct device
*dev
= &pdev
->dev
;
121 struct gadc_thermal_info
*gti
;
125 dev_err(dev
, "Only DT based supported\n");
129 gti
= devm_kzalloc(dev
, sizeof(*gti
), GFP_KERNEL
);
133 gti
->channel
= devm_iio_channel_get(dev
, "sensor-channel");
134 if (IS_ERR(gti
->channel
))
135 return dev_err_probe(dev
, PTR_ERR(gti
->channel
), "IIO channel not found\n");
137 ret
= gadc_thermal_read_linear_lookup_table(dev
, gti
);
143 gti
->tz_dev
= devm_thermal_of_zone_register(dev
, 0, gti
,
145 if (IS_ERR(gti
->tz_dev
)) {
146 ret
= PTR_ERR(gti
->tz_dev
);
147 if (ret
!= -EPROBE_DEFER
)
149 "Thermal zone sensor register failed: %d\n",
154 devm_thermal_add_hwmon_sysfs(dev
, gti
->tz_dev
);
159 static const struct of_device_id of_adc_thermal_match
[] = {
160 { .compatible
= "generic-adc-thermal", },
163 MODULE_DEVICE_TABLE(of
, of_adc_thermal_match
);
165 static struct platform_driver gadc_thermal_driver
= {
167 .name
= "generic-adc-thermal",
168 .of_match_table
= of_adc_thermal_match
,
170 .probe
= gadc_thermal_probe
,
173 module_platform_driver(gadc_thermal_driver
);
175 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
176 MODULE_DESCRIPTION("Generic ADC thermal driver using IIO framework with DT");
177 MODULE_LICENSE("GPL v2");