summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/scmi-hwmon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/scmi-hwmon.c')
-rw-r--r--drivers/hwmon/scmi-hwmon.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c
index a80183a488c5..0c93fc5ca762 100644
--- a/drivers/hwmon/scmi-hwmon.c
+++ b/drivers/hwmon/scmi-hwmon.c
@@ -18,6 +18,50 @@ struct scmi_sensors {
18 const struct scmi_sensor_info **info[hwmon_max]; 18 const struct scmi_sensor_info **info[hwmon_max];
19}; 19};
20 20
21static inline u64 __pow10(u8 x)
22{
23 u64 r = 1;
24
25 while (x--)
26 r *= 10;
27
28 return r;
29}
30
31static int scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 *value)
32{
33 s8 scale = sensor->scale;
34 u64 f;
35
36 switch (sensor->type) {
37 case TEMPERATURE_C:
38 case VOLTAGE:
39 case CURRENT:
40 scale += 3;
41 break;
42 case POWER:
43 case ENERGY:
44 scale += 6;
45 break;
46 default:
47 break;
48 }
49
50 if (scale == 0)
51 return 0;
52
53 if (abs(scale) > 19)
54 return -E2BIG;
55
56 f = __pow10(abs(scale));
57 if (scale > 0)
58 *value *= f;
59 else
60 *value = div64_u64(*value, f);
61
62 return 0;
63}
64
21static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 65static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
22 u32 attr, int channel, long *val) 66 u32 attr, int channel, long *val)
23{ 67{
@@ -29,6 +73,10 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
29 73
30 sensor = *(scmi_sensors->info[type] + channel); 74 sensor = *(scmi_sensors->info[type] + channel);
31 ret = h->sensor_ops->reading_get(h, sensor->id, false, &value); 75 ret = h->sensor_ops->reading_get(h, sensor->id, false, &value);
76 if (ret)
77 return ret;
78
79 ret = scmi_hwmon_scale(sensor, &value);
32 if (!ret) 80 if (!ret)
33 *val = value; 81 *val = value;
34 82