20
20
#include <linux/scpi_protocol.h>
21
21
#include <linux/slab.h>
22
22
#include <linux/sysfs.h>
23
+ #include <linux/thermal.h>
23
24
24
25
struct sensor_data {
25
26
struct scpi_sensor_info info ;
@@ -29,14 +30,39 @@ struct sensor_data {
29
30
char label [20 ];
30
31
};
31
32
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
+
32
40
struct scpi_sensors {
33
41
struct scpi_ops * scpi_ops ;
34
42
struct sensor_data * data ;
43
+ struct list_head thermal_zones ;
35
44
struct attribute * * attrs ;
36
45
struct attribute_group group ;
37
46
const struct attribute_group * groups [2 ];
38
47
};
39
48
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
+
40
66
/* hwmon callback functions */
41
67
static ssize_t
42
68
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)
66
92
return sprintf (buf , "%s\n" , sensor -> info .name );
67
93
}
68
94
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
+
69
113
static int scpi_hwmon_probe (struct platform_device * pdev )
70
114
{
71
115
u16 nr_sensors , i ;
@@ -160,10 +204,67 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
160
204
scpi_sensors -> group .attrs = scpi_sensors -> attrs ;
161
205
scpi_sensors -> groups [0 ] = & scpi_sensors -> group ;
162
206
207
+ platform_set_drvdata (pdev , scpi_sensors );
208
+
163
209
hwdev = devm_hwmon_device_register_with_groups (dev ,
164
210
"scpi_sensors" , scpi_sensors , scpi_sensors -> groups );
165
211
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 ;
167
268
}
168
269
169
270
static const struct of_device_id scpi_of_match [] = {
@@ -178,6 +279,7 @@ static struct platform_driver scpi_hwmon_platdrv = {
178
279
.of_match_table = scpi_of_match ,
179
280
},
180
281
.probe = scpi_hwmon_probe ,
282
+ .remove = scpi_hwmon_remove ,
181
283
};
182
284
module_platform_driver (scpi_hwmon_platdrv );
183
285
0 commit comments