Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: (pmbus/fsp-3y) Fix FSP-3Y YH-5151E non-compliant vout encoding

I didn't properly test the driver for YH-5151E, so it was completely
broken. Firstly, the log/real mapping was incorrect in one case.
Secondly, PMBus specifies that output voltages should be in the linear16
encoding. However, the YH-5151E is non-compliant and uses linear11.
YM-2151E isn't affected by this. Fix this by converting the values
inside the read functions. linear16 gets the exponent from the VOUT_MODE
command. The device doesn't support it, so I have to manually supply the
value for it.

Both supported devices have now been tested to report correct vout
values.

Fixes: 1734b4135a62 ("hwmon: Add driver for fsp-3y PSUs and PDUs")
Signed-off-by: Václav Kubernát <kubernat@cesnet.cz>
Link: https://lore.kernel.org/r/20210429075337.110502-1-kubernat@cesnet.cz
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Václav Kubernát and committed by
Guenter Roeck
2d101db3 5216dff2

+25 -2
+25 -2
drivers/hwmon/pmbus/fsp-3y.c
··· 57 57 case YH5151E_PAGE_12V_LOG: 58 58 return YH5151E_PAGE_12V_REAL; 59 59 case YH5151E_PAGE_5V_LOG: 60 - return YH5151E_PAGE_5V_LOG; 60 + return YH5151E_PAGE_5V_REAL; 61 61 case YH5151E_PAGE_3V3_LOG: 62 62 return YH5151E_PAGE_3V3_REAL; 63 63 } ··· 103 103 104 104 static int fsp3y_read_byte_data(struct i2c_client *client, int page, int reg) 105 105 { 106 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 107 + struct fsp3y_data *data = to_fsp3y_data(info); 106 108 int rv; 109 + 110 + /* 111 + * YH5151-E outputs vout in linear11. The conversion is done when 112 + * reading. Here, we have to inject pmbus_core with the correct 113 + * exponent (it is -6). 114 + */ 115 + if (data->chip == yh5151e && reg == PMBUS_VOUT_MODE) 116 + return 0x1A; 107 117 108 118 rv = set_page(client, page); 109 119 if (rv < 0) ··· 124 114 125 115 static int fsp3y_read_word_data(struct i2c_client *client, int page, int phase, int reg) 126 116 { 117 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 118 + struct fsp3y_data *data = to_fsp3y_data(info); 127 119 int rv; 128 120 129 121 /* ··· 156 144 if (rv < 0) 157 145 return rv; 158 146 159 - return i2c_smbus_read_word_data(client, reg); 147 + rv = i2c_smbus_read_word_data(client, reg); 148 + if (rv < 0) 149 + return rv; 150 + 151 + /* 152 + * YH-5151E is non-compliant and outputs output voltages in linear11 153 + * instead of linear16. 154 + */ 155 + if (data->chip == yh5151e && reg == PMBUS_READ_VOUT) 156 + rv = sign_extend32(rv, 10) & 0xffff; 157 + 158 + return rv; 160 159 } 161 160 162 161 static struct pmbus_driver_info fsp3y_info[] = {