Message ID | 20190507230917.21659-3-f.fainelli@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | hwmon: scmi: Scale values to target desired HWMON units | expand |
On 5/7/19 4:09 PM, Florian Fainelli wrote: > If the SCMI firmware implementation is reporting values in a scale that > is different from the HWMON units, we need to scale up or down the value > according to how far appart they are. > > Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> > --- > drivers/hwmon/scmi-hwmon.c | 43 +++++++++++++++++++++++++++++++++++++- > 1 file changed, 42 insertions(+), 1 deletion(-) > > diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c > index a80183a488c5..7820854e5954 100644 > --- a/drivers/hwmon/scmi-hwmon.c > +++ b/drivers/hwmon/scmi-hwmon.c > @@ -18,6 +18,47 @@ struct scmi_sensors { > const struct scmi_sensor_info **info[hwmon_max]; > }; > > +static inline u64 __pow10(u8 x) > +{ > + u64 r = 1; > + > + if (unlikely(x > 18)) > + return r; > + Strictly speaking that would be 19 (10^19=0x8AC7230489E80000), and I am not sure if returning 1 in that case is such a good idea. If you really want to handle over/underflow situations, it should be in the calling code. Thanks, Guenter > + while (x--) > + r *= 10; > + > + return r; > +} > + > +static u64 scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 value) > +{ > + s8 scale = sensor->scale; > + u64 f; > + > + switch (sensor->type) { > + case TEMPERATURE_C: > + case VOLTAGE: > + case CURRENT: > + scale += 3; > + break; > + case POWER: > + case ENERGY: > + scale += 6; > + break; > + default: > + break; > + } > + > + f = __pow10(abs(scale)); > + if (scale > 0) > + value *= f; > + else > + value = div64_u64(value, f); > + > + return value; > +} > + > static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, > u32 attr, int channel, long *val) > { > @@ -30,7 +71,7 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, > sensor = *(scmi_sensors->info[type] + channel); > ret = h->sensor_ops->reading_get(h, sensor->id, false, &value); > if (!ret) > - *val = value; > + *val = scmi_hwmon_scale(sensor, value); > > return ret; > } >
diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c index a80183a488c5..7820854e5954 100644 --- a/drivers/hwmon/scmi-hwmon.c +++ b/drivers/hwmon/scmi-hwmon.c @@ -18,6 +18,47 @@ struct scmi_sensors { const struct scmi_sensor_info **info[hwmon_max]; }; +static inline u64 __pow10(u8 x) +{ + u64 r = 1; + + if (unlikely(x > 18)) + return r; + + while (x--) + r *= 10; + + return r; +} + +static u64 scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 value) +{ + s8 scale = sensor->scale; + u64 f; + + switch (sensor->type) { + case TEMPERATURE_C: + case VOLTAGE: + case CURRENT: + scale += 3; + break; + case POWER: + case ENERGY: + scale += 6; + break; + default: + break; + } + + f = __pow10(abs(scale)); + if (scale > 0) + value *= f; + else + value = div64_u64(value, f); + + return value; +} + static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -30,7 +71,7 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, sensor = *(scmi_sensors->info[type] + channel); ret = h->sensor_ops->reading_get(h, sensor->id, false, &value); if (!ret) - *val = value; + *val = scmi_hwmon_scale(sensor, value); return ret; }
If the SCMI firmware implementation is reporting values in a scale that is different from the HWMON units, we need to scale up or down the value according to how far appart they are. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> --- drivers/hwmon/scmi-hwmon.c | 43 +++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-)