1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface(SCMI) based hwmon sensor driver
5 * Copyright (C) 2018-2021 ARM Ltd.
6 * Sudeep Holla <sudeep.holla@arm.com>
9 #include <linux/hwmon.h>
10 #include <linux/module.h>
11 #include <linux/scmi_protocol.h>
12 #include <linux/slab.h>
13 #include <linux/sysfs.h>
14 #include <linux/thermal.h>
16 static const struct scmi_sensor_proto_ops
*sensor_ops
;
19 const struct scmi_protocol_handle
*ph
;
20 const struct scmi_sensor_info
**info
[hwmon_max
];
23 struct scmi_thermal_sensor
{
24 const struct scmi_protocol_handle
*ph
;
25 const struct scmi_sensor_info
*info
;
28 static inline u64
__pow10(u8 x
)
38 static int scmi_hwmon_scale(const struct scmi_sensor_info
*sensor
, u64
*value
)
40 int scale
= sensor
->scale
;
43 switch (sensor
->type
) {
63 f
= __pow10(abs(scale
));
67 *value
= div64_u64(*value
, f
);
72 static int scmi_hwmon_read_scaled_value(const struct scmi_protocol_handle
*ph
,
73 const struct scmi_sensor_info
*sensor
,
79 ret
= sensor_ops
->reading_get(ph
, sensor
->id
, &value
);
83 ret
= scmi_hwmon_scale(sensor
, &value
);
90 static int scmi_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
,
91 u32 attr
, int channel
, long *val
)
93 const struct scmi_sensor_info
*sensor
;
94 struct scmi_sensors
*scmi_sensors
= dev_get_drvdata(dev
);
96 sensor
= *(scmi_sensors
->info
[type
] + channel
);
98 return scmi_hwmon_read_scaled_value(scmi_sensors
->ph
, sensor
, val
);
102 scmi_hwmon_read_string(struct device
*dev
, enum hwmon_sensor_types type
,
103 u32 attr
, int channel
, const char **str
)
105 const struct scmi_sensor_info
*sensor
;
106 struct scmi_sensors
*scmi_sensors
= dev_get_drvdata(dev
);
108 sensor
= *(scmi_sensors
->info
[type
] + channel
);
115 scmi_hwmon_is_visible(const void *drvdata
, enum hwmon_sensor_types type
,
116 u32 attr
, int channel
)
118 const struct scmi_sensor_info
*sensor
;
119 const struct scmi_sensors
*scmi_sensors
= drvdata
;
121 sensor
= *(scmi_sensors
->info
[type
] + channel
);
128 static const struct hwmon_ops scmi_hwmon_ops
= {
129 .is_visible
= scmi_hwmon_is_visible
,
130 .read
= scmi_hwmon_read
,
131 .read_string
= scmi_hwmon_read_string
,
134 static struct hwmon_chip_info scmi_chip_info
= {
135 .ops
= &scmi_hwmon_ops
,
139 static int scmi_hwmon_thermal_get_temp(struct thermal_zone_device
*tz
,
144 struct scmi_thermal_sensor
*th_sensor
= thermal_zone_device_priv(tz
);
146 ret
= scmi_hwmon_read_scaled_value(th_sensor
->ph
, th_sensor
->info
,
154 static const struct thermal_zone_device_ops scmi_hwmon_thermal_ops
= {
155 .get_temp
= scmi_hwmon_thermal_get_temp
,
158 static int scmi_hwmon_add_chan_info(struct hwmon_channel_info
*scmi_hwmon_chan
,
159 struct device
*dev
, int num
,
160 enum hwmon_sensor_types type
, u32 config
)
163 u32
*cfg
= devm_kcalloc(dev
, num
+ 1, sizeof(*cfg
), GFP_KERNEL
);
168 scmi_hwmon_chan
->type
= type
;
169 scmi_hwmon_chan
->config
= cfg
;
170 for (i
= 0; i
< num
; i
++, cfg
++)
176 static enum hwmon_sensor_types scmi_types
[] = {
177 [TEMPERATURE_C
] = hwmon_temp
,
178 [VOLTAGE
] = hwmon_in
,
179 [CURRENT
] = hwmon_curr
,
180 [POWER
] = hwmon_power
,
181 [ENERGY
] = hwmon_energy
,
184 static u32 hwmon_attributes
[hwmon_max
] = {
185 [hwmon_temp
] = HWMON_T_INPUT
| HWMON_T_LABEL
,
186 [hwmon_in
] = HWMON_I_INPUT
| HWMON_I_LABEL
,
187 [hwmon_curr
] = HWMON_C_INPUT
| HWMON_C_LABEL
,
188 [hwmon_power
] = HWMON_P_INPUT
| HWMON_P_LABEL
,
189 [hwmon_energy
] = HWMON_E_INPUT
| HWMON_E_LABEL
,
192 static int scmi_thermal_sensor_register(struct device
*dev
,
193 const struct scmi_protocol_handle
*ph
,
194 const struct scmi_sensor_info
*sensor
)
196 struct scmi_thermal_sensor
*th_sensor
;
197 struct thermal_zone_device
*tzd
;
199 th_sensor
= devm_kzalloc(dev
, sizeof(*th_sensor
), GFP_KERNEL
);
204 th_sensor
->info
= sensor
;
207 * Try to register a temperature sensor with the Thermal Framework:
208 * skip sensors not defined as part of any thermal zone (-ENODEV) but
209 * report any other errors related to misconfigured zones/sensors.
211 tzd
= devm_thermal_of_zone_register(dev
, th_sensor
->info
->id
, th_sensor
,
212 &scmi_hwmon_thermal_ops
);
214 devm_kfree(dev
, th_sensor
);
216 if (PTR_ERR(tzd
) != -ENODEV
)
219 dev_dbg(dev
, "Sensor '%s' not attached to any thermal zone.\n",
222 dev_dbg(dev
, "Sensor '%s' attached to thermal zone ID:%d\n",
223 sensor
->name
, thermal_zone_device_id(tzd
));
229 static int scmi_hwmon_probe(struct scmi_device
*sdev
)
233 enum hwmon_sensor_types type
;
234 struct scmi_sensors
*scmi_sensors
;
235 const struct scmi_sensor_info
*sensor
;
236 int nr_count
[hwmon_max
] = {0}, nr_types
= 0, nr_count_temp
= 0;
237 const struct hwmon_chip_info
*chip_info
;
238 struct device
*hwdev
, *dev
= &sdev
->dev
;
239 struct hwmon_channel_info
*scmi_hwmon_chan
;
240 const struct hwmon_channel_info
**ptr_scmi_ci
;
241 const struct scmi_handle
*handle
= sdev
->handle
;
242 struct scmi_protocol_handle
*ph
;
247 sensor_ops
= handle
->devm_protocol_get(sdev
, SCMI_PROTOCOL_SENSOR
, &ph
);
248 if (IS_ERR(sensor_ops
))
249 return PTR_ERR(sensor_ops
);
251 nr_sensors
= sensor_ops
->count_get(ph
);
255 scmi_sensors
= devm_kzalloc(dev
, sizeof(*scmi_sensors
), GFP_KERNEL
);
259 scmi_sensors
->ph
= ph
;
261 for (i
= 0; i
< nr_sensors
; i
++) {
262 sensor
= sensor_ops
->info_get(ph
, i
);
266 switch (sensor
->type
) {
272 type
= scmi_types
[sensor
->type
];
280 if (nr_count
[hwmon_temp
])
281 nr_count_temp
= nr_count
[hwmon_temp
];
283 scmi_hwmon_chan
= devm_kcalloc(dev
, nr_types
, sizeof(*scmi_hwmon_chan
),
285 if (!scmi_hwmon_chan
)
288 ptr_scmi_ci
= devm_kcalloc(dev
, nr_types
+ 1, sizeof(*ptr_scmi_ci
),
293 scmi_chip_info
.info
= ptr_scmi_ci
;
294 chip_info
= &scmi_chip_info
;
296 for (type
= 0; type
< hwmon_max
; type
++) {
300 scmi_hwmon_add_chan_info(scmi_hwmon_chan
, dev
, nr_count
[type
],
301 type
, hwmon_attributes
[type
]);
302 *ptr_scmi_ci
++ = scmi_hwmon_chan
++;
304 scmi_sensors
->info
[type
] =
305 devm_kcalloc(dev
, nr_count
[type
],
306 sizeof(*scmi_sensors
->info
), GFP_KERNEL
);
307 if (!scmi_sensors
->info
[type
])
311 for (i
= nr_sensors
- 1; i
>= 0 ; i
--) {
312 sensor
= sensor_ops
->info_get(ph
, i
);
316 switch (sensor
->type
) {
322 type
= scmi_types
[sensor
->type
];
323 idx
= --nr_count
[type
];
324 *(scmi_sensors
->info
[type
] + idx
) = sensor
;
329 hwdev
= devm_hwmon_device_register_with_info(dev
, "scmi_sensors",
330 scmi_sensors
, chip_info
,
333 return PTR_ERR(hwdev
);
335 for (i
= 0; i
< nr_count_temp
; i
++) {
338 sensor
= *(scmi_sensors
->info
[hwmon_temp
] + i
);
343 * Warn on any misconfiguration related to thermal zones but
344 * bail out of probing only on memory errors.
346 ret
= scmi_thermal_sensor_register(dev
, ph
, sensor
);
351 "Thermal zone misconfigured for %s. err=%d\n",
359 static const struct scmi_device_id scmi_id_table
[] = {
360 { SCMI_PROTOCOL_SENSOR
, "hwmon" },
363 MODULE_DEVICE_TABLE(scmi
, scmi_id_table
);
365 static struct scmi_driver scmi_hwmon_drv
= {
366 .name
= "scmi-hwmon",
367 .probe
= scmi_hwmon_probe
,
368 .id_table
= scmi_id_table
,
370 module_scmi_driver(scmi_hwmon_drv
);
372 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
373 MODULE_DESCRIPTION("ARM SCMI HWMON interface driver");
374 MODULE_LICENSE("GPL v2");