1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Power Interface(SCPI) based hwmon sensor driver
5 * Copyright (C) 2015 ARM Ltd.
6 * Punit Agrawal <punit.agrawal@arm.com>
9 #include <linux/hwmon.h>
10 #include <linux/module.h>
11 #include <linux/of_device.h>
12 #include <linux/platform_device.h>
13 #include <linux/scpi_protocol.h>
14 #include <linux/slab.h>
15 #include <linux/sysfs.h>
16 #include <linux/thermal.h>
20 struct scpi_sensor_info info
;
21 struct device_attribute dev_attr_input
;
22 struct device_attribute dev_attr_label
;
27 struct scpi_thermal_zone
{
29 struct scpi_sensors
*scpi_sensors
;
33 struct scpi_ops
*scpi_ops
;
34 struct sensor_data
*data
;
35 struct list_head thermal_zones
;
36 struct attribute
**attrs
;
37 struct attribute_group group
;
38 const struct attribute_group
*groups
[2];
41 static const u32 gxbb_scpi_scale
[] = {
42 [TEMPERATURE
] = 1, /* (celsius) */
43 [VOLTAGE
] = 1000, /* (millivolts) */
44 [CURRENT
] = 1000, /* (milliamperes) */
45 [POWER
] = 1000000, /* (microwatts) */
46 [ENERGY
] = 1000000, /* (microjoules) */
49 static const u32 scpi_scale
[] = {
50 [TEMPERATURE
] = 1000, /* (millicelsius) */
51 [VOLTAGE
] = 1000, /* (millivolts) */
52 [CURRENT
] = 1000, /* (milliamperes) */
53 [POWER
] = 1000000, /* (microwatts) */
54 [ENERGY
] = 1000000, /* (microjoules) */
57 static void scpi_scale_reading(u64
*value
, struct sensor_data
*sensor
)
59 if (scpi_scale
[sensor
->info
.class] != sensor
->scale
) {
60 *value
*= scpi_scale
[sensor
->info
.class];
61 do_div(*value
, sensor
->scale
);
65 static int scpi_read_temp(void *dev
, int *temp
)
67 struct scpi_thermal_zone
*zone
= dev
;
68 struct scpi_sensors
*scpi_sensors
= zone
->scpi_sensors
;
69 struct scpi_ops
*scpi_ops
= scpi_sensors
->scpi_ops
;
70 struct sensor_data
*sensor
= &scpi_sensors
->data
[zone
->sensor_id
];
74 ret
= scpi_ops
->sensor_get_value(sensor
->info
.sensor_id
, &value
);
78 scpi_scale_reading(&value
, sensor
);
84 /* hwmon callback functions */
86 scpi_show_sensor(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
88 struct scpi_sensors
*scpi_sensors
= dev_get_drvdata(dev
);
89 struct scpi_ops
*scpi_ops
= scpi_sensors
->scpi_ops
;
90 struct sensor_data
*sensor
;
94 sensor
= container_of(attr
, struct sensor_data
, dev_attr_input
);
96 ret
= scpi_ops
->sensor_get_value(sensor
->info
.sensor_id
, &value
);
100 scpi_scale_reading(&value
, sensor
);
102 return sprintf(buf
, "%llu\n", value
);
106 scpi_show_label(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
108 struct sensor_data
*sensor
;
110 sensor
= container_of(attr
, struct sensor_data
, dev_attr_label
);
112 return sprintf(buf
, "%s\n", sensor
->info
.name
);
115 static const struct thermal_zone_of_device_ops scpi_sensor_ops
= {
116 .get_temp
= scpi_read_temp
,
119 static const struct of_device_id scpi_of_match
[] = {
120 {.compatible
= "arm,scpi-sensors", .data
= &scpi_scale
},
121 {.compatible
= "amlogic,meson-gxbb-scpi-sensors", .data
= &gxbb_scpi_scale
},
124 MODULE_DEVICE_TABLE(of
, scpi_of_match
);
126 static int scpi_hwmon_probe(struct platform_device
*pdev
)
130 int num_temp
= 0, num_volt
= 0, num_current
= 0, num_power
= 0;
132 struct scpi_ops
*scpi_ops
;
133 struct device
*hwdev
, *dev
= &pdev
->dev
;
134 struct scpi_sensors
*scpi_sensors
;
135 const struct of_device_id
*of_id
;
138 scpi_ops
= get_scpi_ops();
140 return -EPROBE_DEFER
;
142 ret
= scpi_ops
->sensor_get_capability(&nr_sensors
);
149 scpi_sensors
= devm_kzalloc(dev
, sizeof(*scpi_sensors
), GFP_KERNEL
);
153 scpi_sensors
->data
= devm_kcalloc(dev
, nr_sensors
,
154 sizeof(*scpi_sensors
->data
), GFP_KERNEL
);
155 if (!scpi_sensors
->data
)
158 scpi_sensors
->attrs
= devm_kcalloc(dev
, (nr_sensors
* 2) + 1,
159 sizeof(*scpi_sensors
->attrs
), GFP_KERNEL
);
160 if (!scpi_sensors
->attrs
)
163 scpi_sensors
->scpi_ops
= scpi_ops
;
165 of_id
= of_match_device(scpi_of_match
, &pdev
->dev
);
167 dev_err(&pdev
->dev
, "Unable to initialize scpi-hwmon data\n");
172 for (i
= 0, idx
= 0; i
< nr_sensors
; i
++) {
173 struct sensor_data
*sensor
= &scpi_sensors
->data
[idx
];
175 ret
= scpi_ops
->sensor_get_info(i
, &sensor
->info
);
179 switch (sensor
->info
.class) {
181 snprintf(sensor
->input
, sizeof(sensor
->input
),
182 "temp%d_input", num_temp
+ 1);
183 snprintf(sensor
->label
, sizeof(sensor
->input
),
184 "temp%d_label", num_temp
+ 1);
188 snprintf(sensor
->input
, sizeof(sensor
->input
),
189 "in%d_input", num_volt
);
190 snprintf(sensor
->label
, sizeof(sensor
->input
),
191 "in%d_label", num_volt
);
195 snprintf(sensor
->input
, sizeof(sensor
->input
),
196 "curr%d_input", num_current
+ 1);
197 snprintf(sensor
->label
, sizeof(sensor
->input
),
198 "curr%d_label", num_current
+ 1);
202 snprintf(sensor
->input
, sizeof(sensor
->input
),
203 "power%d_input", num_power
+ 1);
204 snprintf(sensor
->label
, sizeof(sensor
->input
),
205 "power%d_label", num_power
+ 1);
209 snprintf(sensor
->input
, sizeof(sensor
->input
),
210 "energy%d_input", num_energy
+ 1);
211 snprintf(sensor
->label
, sizeof(sensor
->input
),
212 "energy%d_label", num_energy
+ 1);
219 sensor
->scale
= scale
[sensor
->info
.class];
221 sensor
->dev_attr_input
.attr
.mode
= 0444;
222 sensor
->dev_attr_input
.show
= scpi_show_sensor
;
223 sensor
->dev_attr_input
.attr
.name
= sensor
->input
;
225 sensor
->dev_attr_label
.attr
.mode
= 0444;
226 sensor
->dev_attr_label
.show
= scpi_show_label
;
227 sensor
->dev_attr_label
.attr
.name
= sensor
->label
;
229 scpi_sensors
->attrs
[idx
<< 1] = &sensor
->dev_attr_input
.attr
;
230 scpi_sensors
->attrs
[(idx
<< 1) + 1] = &sensor
->dev_attr_label
.attr
;
232 sysfs_attr_init(scpi_sensors
->attrs
[idx
<< 1]);
233 sysfs_attr_init(scpi_sensors
->attrs
[(idx
<< 1) + 1]);
237 scpi_sensors
->group
.attrs
= scpi_sensors
->attrs
;
238 scpi_sensors
->groups
[0] = &scpi_sensors
->group
;
240 platform_set_drvdata(pdev
, scpi_sensors
);
242 hwdev
= devm_hwmon_device_register_with_groups(dev
,
243 "scpi_sensors", scpi_sensors
, scpi_sensors
->groups
);
246 return PTR_ERR(hwdev
);
249 * Register the temperature sensors with the thermal framework
250 * to allow their usage in setting up the thermal zones from
253 * NOTE: Not all temperature sensors maybe used for thermal
256 INIT_LIST_HEAD(&scpi_sensors
->thermal_zones
);
257 for (i
= 0; i
< nr_sensors
; i
++) {
258 struct sensor_data
*sensor
= &scpi_sensors
->data
[i
];
259 struct thermal_zone_device
*z
;
260 struct scpi_thermal_zone
*zone
;
262 if (sensor
->info
.class != TEMPERATURE
)
265 zone
= devm_kzalloc(dev
, sizeof(*zone
), GFP_KERNEL
);
270 zone
->scpi_sensors
= scpi_sensors
;
271 z
= devm_thermal_zone_of_sensor_register(dev
,
272 sensor
->info
.sensor_id
,
276 * The call to thermal_zone_of_sensor_register returns
277 * an error for sensors that are not associated with
278 * any thermal zones or if the thermal subsystem is
282 devm_kfree(dev
, zone
);
288 static struct platform_driver scpi_hwmon_platdrv
= {
290 .name
= "scpi-hwmon",
291 .of_match_table
= scpi_of_match
,
293 .probe
= scpi_hwmon_probe
,
295 module_platform_driver(scpi_hwmon_platdrv
);
297 MODULE_AUTHOR("Punit Agrawal <punit.agrawal@arm.com>");
298 MODULE_DESCRIPTION("ARM SCPI HWMON interface driver");
299 MODULE_LICENSE("GPL v2");