diff options
-rw-r--r-- | drivers/hwmon/pmbus/adm1275.c | 84 |
1 files changed, 65 insertions, 19 deletions
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index a477ce0474bb..5caa37fbfc18 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -71,9 +71,17 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 }; #define ADM1075_VAUX_OV_WARN BIT(7) #define ADM1075_VAUX_UV_WARN BIT(6) -#define ADM1275_PWR_AVG_MASK GENMASK(13, 11) -#define ADM1275_VI_AVG_MASK GENMASK(10, 8) -#define ADM1275_SAMPLES_AVG_MAX 128 +#define ADM1275_VI_AVG_SHIFT 0 +#define ADM1275_VI_AVG_MASK GENMASK(ADM1275_VI_AVG_SHIFT + 2, \ + ADM1275_VI_AVG_SHIFT) +#define ADM1275_SAMPLES_AVG_MAX 128 + +#define ADM1278_PWR_AVG_SHIFT 11 +#define ADM1278_PWR_AVG_MASK GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \ + ADM1278_PWR_AVG_SHIFT) +#define ADM1278_VI_AVG_SHIFT 8 +#define ADM1278_VI_AVG_MASK GENMASK(ADM1278_VI_AVG_SHIFT + 2, \ + ADM1278_VI_AVG_SHIFT) struct adm1275_data { int id; @@ -86,6 +94,7 @@ struct adm1275_data { bool have_pin_min; bool have_pin_max; bool have_temp_max; + bool have_power_sampling; struct pmbus_driver_info info; }; @@ -161,28 +170,58 @@ static const struct coefficients adm1293_coefficients[] = { [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ }; -static inline int adm1275_read_pmon_config(struct i2c_client *client, u16 mask) +static int adm1275_read_pmon_config(const struct adm1275_data *data, + struct i2c_client *client, bool is_power) { - int ret; - - ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); + int shift, ret; + u16 mask; + + /* + * The PMON configuration register is a 16-bit register only on chips + * supporting power average sampling. On other chips it is an 8-bit + * register. + */ + if (data->have_power_sampling) { + ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); + mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; + shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; + } else { + ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); + mask = ADM1275_VI_AVG_MASK; + shift = ADM1275_VI_AVG_SHIFT; + } if (ret < 0) return ret; - return FIELD_GET(mask, (u16)ret); + return (ret & mask) >> shift; } -static inline int adm1275_write_pmon_config(struct i2c_client *client, u16 mask, - u16 word) +static int adm1275_write_pmon_config(const struct adm1275_data *data, + struct i2c_client *client, + bool is_power, u16 word) { - int ret; - - ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); + int shift, ret; + u16 mask; + + if (data->have_power_sampling) { + ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); + mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; + shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; + } else { + ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); + mask = ADM1275_VI_AVG_MASK; + shift = ADM1275_VI_AVG_SHIFT; + } if (ret < 0) return ret; - word = FIELD_PREP(mask, word) | (ret & ~mask); - ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, word); + word = (ret & ~mask) | ((word << shift) & mask); + if (data->have_power_sampling) + ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, + word); + else + ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, + word); return ret; } @@ -266,14 +305,16 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) return -ENXIO; break; case PMBUS_VIRT_POWER_SAMPLES: - ret = adm1275_read_pmon_config(client, ADM1275_PWR_AVG_MASK); + if (!data->have_power_sampling) + return -ENXIO; + ret = adm1275_read_pmon_config(data, client, true); if (ret < 0) break; ret = BIT(ret); break; case PMBUS_VIRT_IN_SAMPLES: case PMBUS_VIRT_CURR_SAMPLES: - ret = adm1275_read_pmon_config(client, ADM1275_VI_AVG_MASK); + ret = adm1275_read_pmon_config(data, client, false); if (ret < 0) break; ret = BIT(ret); @@ -323,14 +364,16 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0); break; case PMBUS_VIRT_POWER_SAMPLES: + if (!data->have_power_sampling) + return -ENXIO; word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); - ret = adm1275_write_pmon_config(client, ADM1275_PWR_AVG_MASK, + ret = adm1275_write_pmon_config(data, client, true, ilog2(word)); break; case PMBUS_VIRT_IN_SAMPLES: case PMBUS_VIRT_CURR_SAMPLES: word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); - ret = adm1275_write_pmon_config(client, ADM1275_VI_AVG_MASK, + ret = adm1275_write_pmon_config(data, client, false, ilog2(word)); break; default: @@ -528,6 +571,7 @@ static int adm1275_probe(struct i2c_client *client, data->have_vout = true; data->have_pin_max = true; data->have_temp_max = true; + data->have_power_sampling = true; coefficients = adm1272_coefficients; vindex = (config & ADM1275_VRANGE) ? 1 : 0; @@ -613,6 +657,7 @@ static int adm1275_probe(struct i2c_client *client, data->have_vout = true; data->have_pin_max = true; data->have_temp_max = true; + data->have_power_sampling = true; coefficients = adm1278_coefficients; vindex = 0; @@ -648,6 +693,7 @@ static int adm1275_probe(struct i2c_client *client, data->have_pin_min = true; data->have_pin_max = true; data->have_mfr_vaux_status = true; + data->have_power_sampling = true; coefficients = adm1293_coefficients; |