aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/hwmon/pmbus/adm1275.c84
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;