Skip to content

Commit 68acc77

Browse files
punitagrawalsudeep-holla
authored andcommitted
hwmon: Support thermal zones registration for SCP temperature sensors
Add support to create thermal zones based on the temperature sensors provided by the SCP. The thermal zones can be defined using the thermal DT bindings and should refer to the SCP sensor id to select the sensor. Signed-off-by: Punit Agrawal <[email protected]> Acked-by: Guenter Roeck <[email protected]> Cc: Eduardo Valentin <[email protected]>
1 parent ea98b29 commit 68acc77

File tree

1 file changed

+103
-1
lines changed

1 file changed

+103
-1
lines changed

drivers/hwmon/scpi-hwmon.c

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/scpi_protocol.h>
2121
#include <linux/slab.h>
2222
#include <linux/sysfs.h>
23+
#include <linux/thermal.h>
2324

2425
struct sensor_data {
2526
struct scpi_sensor_info info;
@@ -29,14 +30,39 @@ struct sensor_data {
2930
char label[20];
3031
};
3132

33+
struct scpi_thermal_zone {
34+
struct list_head list;
35+
int sensor_id;
36+
struct scpi_sensors *scpi_sensors;
37+
struct thermal_zone_device *tzd;
38+
};
39+
3240
struct scpi_sensors {
3341
struct scpi_ops *scpi_ops;
3442
struct sensor_data *data;
43+
struct list_head thermal_zones;
3544
struct attribute **attrs;
3645
struct attribute_group group;
3746
const struct attribute_group *groups[2];
3847
};
3948

49+
static int scpi_read_temp(void *dev, int *temp)
50+
{
51+
struct scpi_thermal_zone *zone = dev;
52+
struct scpi_sensors *scpi_sensors = zone->scpi_sensors;
53+
struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
54+
struct sensor_data *sensor = &scpi_sensors->data[zone->sensor_id];
55+
u32 value;
56+
int ret;
57+
58+
ret = scpi_ops->sensor_get_value(sensor->info.sensor_id, &value);
59+
if (ret)
60+
return ret;
61+
62+
*temp = value;
63+
return 0;
64+
}
65+
4066
/* hwmon callback functions */
4167
static ssize_t
4268
scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf)
@@ -66,6 +92,24 @@ scpi_show_label(struct device *dev, struct device_attribute *attr, char *buf)
6692
return sprintf(buf, "%s\n", sensor->info.name);
6793
}
6894

95+
static void
96+
unregister_thermal_zones(struct platform_device *pdev,
97+
struct scpi_sensors *scpi_sensors)
98+
{
99+
struct list_head *pos;
100+
101+
list_for_each(pos, &scpi_sensors->thermal_zones) {
102+
struct scpi_thermal_zone *zone;
103+
104+
zone = list_entry(pos, struct scpi_thermal_zone, list);
105+
thermal_zone_of_sensor_unregister(&pdev->dev, zone->tzd);
106+
}
107+
}
108+
109+
static struct thermal_zone_of_device_ops scpi_sensor_ops = {
110+
.get_temp = scpi_read_temp,
111+
};
112+
69113
static int scpi_hwmon_probe(struct platform_device *pdev)
70114
{
71115
u16 nr_sensors, i;
@@ -160,10 +204,67 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
160204
scpi_sensors->group.attrs = scpi_sensors->attrs;
161205
scpi_sensors->groups[0] = &scpi_sensors->group;
162206

207+
platform_set_drvdata(pdev, scpi_sensors);
208+
163209
hwdev = devm_hwmon_device_register_with_groups(dev,
164210
"scpi_sensors", scpi_sensors, scpi_sensors->groups);
165211

166-
return PTR_ERR_OR_ZERO(hwdev);
212+
if (IS_ERR(hwdev))
213+
return PTR_ERR(hwdev);
214+
215+
/*
216+
* Register the temperature sensors with the thermal framework
217+
* to allow their usage in setting up the thermal zones from
218+
* device tree.
219+
*
220+
* NOTE: Not all temperature sensors maybe used for thermal
221+
* control
222+
*/
223+
INIT_LIST_HEAD(&scpi_sensors->thermal_zones);
224+
for (i = 0; i < nr_sensors; i++) {
225+
struct sensor_data *sensor = &scpi_sensors->data[i];
226+
struct scpi_thermal_zone *zone;
227+
228+
if (sensor->info.class != TEMPERATURE)
229+
continue;
230+
231+
zone = devm_kzalloc(dev, sizeof(*zone), GFP_KERNEL);
232+
if (!zone) {
233+
ret = -ENOMEM;
234+
goto unregister_tzd;
235+
}
236+
237+
zone->sensor_id = i;
238+
zone->scpi_sensors = scpi_sensors;
239+
zone->tzd = thermal_zone_of_sensor_register(dev, i, zone,
240+
&scpi_sensor_ops);
241+
/*
242+
* The call to thermal_zone_of_sensor_register returns
243+
* an error for sensors that are not associated with
244+
* any thermal zones or if the thermal subsystem is
245+
* not configured.
246+
*/
247+
if (IS_ERR(zone->tzd)) {
248+
devm_kfree(dev, zone);
249+
continue;
250+
}
251+
list_add(&zone->list, &scpi_sensors->thermal_zones);
252+
}
253+
254+
return 0;
255+
256+
unregister_tzd:
257+
unregister_thermal_zones(pdev, scpi_sensors);
258+
return ret;
259+
}
260+
261+
static int scpi_hwmon_remove(struct platform_device *pdev)
262+
{
263+
struct scpi_sensors *scpi_sensors = platform_get_drvdata(pdev);
264+
265+
unregister_thermal_zones(pdev, scpi_sensors);
266+
267+
return 0;
167268
}
168269

169270
static const struct of_device_id scpi_of_match[] = {
@@ -178,6 +279,7 @@ static struct platform_driver scpi_hwmon_platdrv = {
178279
.of_match_table = scpi_of_match,
179280
},
180281
.probe = scpi_hwmon_probe,
282+
.remove = scpi_hwmon_remove,
181283
};
182284
module_platform_driver(scpi_hwmon_platdrv);
183285

0 commit comments

Comments
 (0)