Commit ac778e62 authored by Florian Fainelli's avatar Florian Fainelli Committed by Sudeep Holla
Browse files

hwmon: scmi: Scale values to target desired HWMON units



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 apart they are.

Reviewed-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
[sudeep.holla: added check of scale = 0 for early exit in scmi_hwmon_scale]
Signed-off-by: default avatarSudeep Holla <sudeep.holla@arm.com>
parent 0b673b64
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -18,6 +18,50 @@ struct scmi_sensors {
	const struct scmi_sensor_info **info[hwmon_max];
};

static inline u64 __pow10(u8 x)
{
	u64 r = 1;

	while (x--)
		r *= 10;

	return r;
}

static int 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;
	}

	if (scale == 0)
		return 0;

	if (abs(scale) > 19)
		return -E2BIG;

	f = __pow10(abs(scale));
	if (scale > 0)
		*value *= f;
	else
		*value = div64_u64(*value, f);

	return 0;
}

static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
			   u32 attr, int channel, long *val)
{
@@ -29,6 +73,10 @@ 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)
		return ret;

	ret = scmi_hwmon_scale(sensor, &value);
	if (!ret)
		*val = value;