From 6e9ef8ca687e69e9d4cc89033d98e06350b0f3e0 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 16 Jun 2021 15:42:18 +1200 Subject: hwmon: (pmbus/bpa-rs600) Handle Vin readings >= 256V The BPA-RS600 doesn't follow the PMBus spec for linear data. Specifically it treats the mantissa as an unsigned 11-bit value instead of a two's complement 11-bit value. At this point it's unclear whether this only affects Vin or if Pin/Pout1 are affected as well. Erring on the side of caution only Vin is dealt with here. Fixes: 15b2703e5e02 ("hwmon: (pmbus) Add driver for BluTek BPA-RS600") Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20210616034218.25821-1-chris.packham@alliedtelesis.co.nz Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/bpa-rs600.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/pmbus/bpa-rs600.c b/drivers/hwmon/pmbus/bpa-rs600.c index f6558ee9dec3..2be69fedfa36 100644 --- a/drivers/hwmon/pmbus/bpa-rs600.c +++ b/drivers/hwmon/pmbus/bpa-rs600.c @@ -46,6 +46,32 @@ static int bpa_rs600_read_byte_data(struct i2c_client *client, int page, int reg return ret; } +/* + * The BPA-RS600 violates the PMBus spec. Specifically it treats the + * mantissa as unsigned. Deal with this here to allow the PMBus core + * to work with correctly encoded data. + */ +static int bpa_rs600_read_vin(struct i2c_client *client) +{ + int ret, exponent, mantissa; + + ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_READ_VIN); + if (ret < 0) + return ret; + + if (ret & BIT(10)) { + exponent = ret >> 11; + mantissa = ret & 0x7ff; + + exponent++; + mantissa >>= 1; + + ret = (exponent << 11) | mantissa; + } + + return ret; +} + static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int phase, int reg) { int ret; @@ -85,6 +111,9 @@ static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int pha /* These commands return data but it is invalid/un-documented */ ret = -ENXIO; break; + case PMBUS_READ_VIN: + ret = bpa_rs600_read_vin(client); + break; default: if (reg >= PMBUS_VIRT_BASE) ret = -ENXIO; -- cgit v1.2.3