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

hwmon: (pmbus/adm1275) Fix power sampling support

Not every chip supported by this driver supports setting the number
of samples for power averaging. Also, the power monitoring register
is not always a 16-bit register, and the configuration bits used for
voltage sampling are different depending on the register width.
Some conditional code is needed to fix the problem.

On top of all that, the compiler complains about problems with
FIELD_GET and FIELD_PREP macros if the file is built with W=1.
Avoid using those macros to silence the warning.

Cc: Krzysztof Adamski <krzysztof.adamski@nokia.com>
Cc: Alexander Sverdlin <alexander.sverdlin@nokia.com>
Reviewed-by: Krzysztof Adamski <krzysztof.adamski@nokia.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

+63 -17
+63 -17
drivers/hwmon/pmbus/adm1275.c
··· 71 71 #define ADM1075_VAUX_OV_WARN BIT(7) 72 72 #define ADM1075_VAUX_UV_WARN BIT(6) 73 73 74 - #define ADM1275_PWR_AVG_MASK GENMASK(13, 11) 75 - #define ADM1275_VI_AVG_MASK GENMASK(10, 8) 76 - #define ADM1275_SAMPLES_AVG_MAX 128 74 + #define ADM1275_VI_AVG_SHIFT 0 75 + #define ADM1275_VI_AVG_MASK GENMASK(ADM1275_VI_AVG_SHIFT + 2, \ 76 + ADM1275_VI_AVG_SHIFT) 77 + #define ADM1275_SAMPLES_AVG_MAX 128 78 + 79 + #define ADM1278_PWR_AVG_SHIFT 11 80 + #define ADM1278_PWR_AVG_MASK GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \ 81 + ADM1278_PWR_AVG_SHIFT) 82 + #define ADM1278_VI_AVG_SHIFT 8 83 + #define ADM1278_VI_AVG_MASK GENMASK(ADM1278_VI_AVG_SHIFT + 2, \ 84 + ADM1278_VI_AVG_SHIFT) 77 85 78 86 struct adm1275_data { 79 87 int id; ··· 94 86 bool have_pin_min; 95 87 bool have_pin_max; 96 88 bool have_temp_max; 89 + bool have_power_sampling; 97 90 struct pmbus_driver_info info; 98 91 }; 99 92 ··· 170 161 [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ 171 162 }; 172 163 173 - static inline int adm1275_read_pmon_config(struct i2c_client *client, u16 mask) 164 + static int adm1275_read_pmon_config(const struct adm1275_data *data, 165 + struct i2c_client *client, bool is_power) 174 166 { 175 - int ret; 167 + int shift, ret; 168 + u16 mask; 176 169 177 - ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); 170 + /* 171 + * The PMON configuration register is a 16-bit register only on chips 172 + * supporting power average sampling. On other chips it is an 8-bit 173 + * register. 174 + */ 175 + if (data->have_power_sampling) { 176 + ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); 177 + mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; 178 + shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; 179 + } else { 180 + ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); 181 + mask = ADM1275_VI_AVG_MASK; 182 + shift = ADM1275_VI_AVG_SHIFT; 183 + } 178 184 if (ret < 0) 179 185 return ret; 180 186 181 - return FIELD_GET(mask, (u16)ret); 187 + return (ret & mask) >> shift; 182 188 } 183 189 184 - static inline int adm1275_write_pmon_config(struct i2c_client *client, u16 mask, 185 - u16 word) 190 + static int adm1275_write_pmon_config(const struct adm1275_data *data, 191 + struct i2c_client *client, 192 + bool is_power, u16 word) 186 193 { 187 - int ret; 194 + int shift, ret; 195 + u16 mask; 188 196 189 - ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); 197 + if (data->have_power_sampling) { 198 + ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); 199 + mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; 200 + shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; 201 + } else { 202 + ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); 203 + mask = ADM1275_VI_AVG_MASK; 204 + shift = ADM1275_VI_AVG_SHIFT; 205 + } 190 206 if (ret < 0) 191 207 return ret; 192 208 193 - word = FIELD_PREP(mask, word) | (ret & ~mask); 194 - ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, word); 209 + word = (ret & ~mask) | ((word << shift) & mask); 210 + if (data->have_power_sampling) 211 + ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, 212 + word); 213 + else 214 + ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, 215 + word); 195 216 196 217 return ret; 197 218 } ··· 305 266 return -ENXIO; 306 267 break; 307 268 case PMBUS_VIRT_POWER_SAMPLES: 308 - ret = adm1275_read_pmon_config(client, ADM1275_PWR_AVG_MASK); 269 + if (!data->have_power_sampling) 270 + return -ENXIO; 271 + ret = adm1275_read_pmon_config(data, client, true); 309 272 if (ret < 0) 310 273 break; 311 274 ret = BIT(ret); 312 275 break; 313 276 case PMBUS_VIRT_IN_SAMPLES: 314 277 case PMBUS_VIRT_CURR_SAMPLES: 315 - ret = adm1275_read_pmon_config(client, ADM1275_VI_AVG_MASK); 278 + ret = adm1275_read_pmon_config(data, client, false); 316 279 if (ret < 0) 317 280 break; 318 281 ret = BIT(ret); ··· 364 323 ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0); 365 324 break; 366 325 case PMBUS_VIRT_POWER_SAMPLES: 326 + if (!data->have_power_sampling) 327 + return -ENXIO; 367 328 word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); 368 - ret = adm1275_write_pmon_config(client, ADM1275_PWR_AVG_MASK, 329 + ret = adm1275_write_pmon_config(data, client, true, 369 330 ilog2(word)); 370 331 break; 371 332 case PMBUS_VIRT_IN_SAMPLES: 372 333 case PMBUS_VIRT_CURR_SAMPLES: 373 334 word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); 374 - ret = adm1275_write_pmon_config(client, ADM1275_VI_AVG_MASK, 335 + ret = adm1275_write_pmon_config(data, client, false, 375 336 ilog2(word)); 376 337 break; 377 338 default: ··· 571 528 data->have_vout = true; 572 529 data->have_pin_max = true; 573 530 data->have_temp_max = true; 531 + data->have_power_sampling = true; 574 532 575 533 coefficients = adm1272_coefficients; 576 534 vindex = (config & ADM1275_VRANGE) ? 1 : 0; ··· 657 613 data->have_vout = true; 658 614 data->have_pin_max = true; 659 615 data->have_temp_max = true; 616 + data->have_power_sampling = true; 660 617 661 618 coefficients = adm1278_coefficients; 662 619 vindex = 0; ··· 693 648 data->have_pin_min = true; 694 649 data->have_pin_max = true; 695 650 data->have_mfr_vaux_status = true; 651 + data->have_power_sampling = true; 696 652 697 653 coefficients = adm1293_coefficients; 698 654