hwmon: (pmbus/adm1275) Prepare for protected write to PMON_CONFIG
authorGuenter Roeck <linux@roeck-us.net>
Wed, 14 Jun 2023 16:36:04 +0000 (09:36 -0700)
committerGuenter Roeck <linux@roeck-us.net>
Thu, 22 Jun 2023 17:39:41 +0000 (10:39 -0700)
According to ADI, changing PMON_CONFIG while ADC is running can have
unexpected results. ADI recommends halting the ADC with PMON_CONTROL
before setting PMON_CONFIG and then resume after.

To prepare for this change, rename adm1275_read_pmon_config()
and adm1275_write_pmon_config() to adm1275_read_samples() and
adm1275_write_samples() to more accurately reflect the functionality
of the code. Introduce new function adm1275_write_pmon_config()
and use it for all code writing into the PMON_CONFIG register.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20230614163605.3688964-2-linux@roeck-us.net
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/pmbus/adm1275.c

index 49d59b7..84a1b3a 100644 (file)
@@ -173,8 +173,8 @@ static const struct coefficients adm1293_coefficients[] = {
        [18] = { 7658, 0, -3 },         /* power, 21V, irange200 */
 };
 
-static int adm1275_read_pmon_config(const struct adm1275_data *data,
-                                   struct i2c_client *client, bool is_power)
+static int adm1275_read_samples(const struct adm1275_data *data,
+                               struct i2c_client *client, bool is_power)
 {
        int shift, ret;
        u16 mask;
@@ -200,8 +200,23 @@ static int adm1275_read_pmon_config(const struct adm1275_data *data,
 }
 
 static int adm1275_write_pmon_config(const struct adm1275_data *data,
-                                    struct i2c_client *client,
-                                    bool is_power, u16 word)
+                                    struct i2c_client *client, u16 word)
+{
+       int ret;
+
+       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;
+}
+
+static int adm1275_write_samples(const struct adm1275_data *data,
+                                struct i2c_client *client,
+                                bool is_power, u16 word)
 {
        int shift, ret;
        u16 mask;
@@ -219,14 +234,8 @@ static int adm1275_write_pmon_config(const struct adm1275_data *data,
                return ret;
 
        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;
+       return adm1275_write_pmon_config(data, client, word);
 }
 
 static int adm1275_read_word_data(struct i2c_client *client, int page,
@@ -321,14 +330,14 @@ static int adm1275_read_word_data(struct i2c_client *client, int page,
        case PMBUS_VIRT_POWER_SAMPLES:
                if (!data->have_power_sampling)
                        return -ENXIO;
-               ret = adm1275_read_pmon_config(data, client, true);
+               ret = adm1275_read_samples(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(data, client, false);
+               ret = adm1275_read_samples(data, client, false);
                if (ret < 0)
                        break;
                ret = BIT(ret);
@@ -381,14 +390,12 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
                if (!data->have_power_sampling)
                        return -ENXIO;
                word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
-               ret = adm1275_write_pmon_config(data, client, true,
-                                               ilog2(word));
+               ret = adm1275_write_samples(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(data, client, false,
-                                               ilog2(word));
+               ret = adm1275_write_samples(data, client, false, ilog2(word));
                break;
        default:
                ret = -ENODATA;
@@ -466,13 +473,14 @@ static const struct i2c_device_id adm1275_id[] = {
 MODULE_DEVICE_TABLE(i2c, adm1275_id);
 
 /* Enable VOUT & TEMP1 if not enabled (disabled by default) */
-static int adm1275_enable_vout_temp(struct i2c_client *client, int config)
+static int adm1275_enable_vout_temp(struct adm1275_data *data,
+                                   struct i2c_client *client, int config)
 {
        int ret;
 
        if ((config & ADM1278_PMON_DEFCONFIG) != ADM1278_PMON_DEFCONFIG) {
                config |= ADM1278_PMON_DEFCONFIG;
-               ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, config);
+               ret = adm1275_write_pmon_config(data, client, config);
                if (ret < 0) {
                        dev_err(&client->dev, "Failed to enable VOUT/TEMP1 monitoring\n");
                        return ret;
@@ -634,7 +642,7 @@ static int adm1275_probe(struct i2c_client *client)
                        PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
                        PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 
-               ret = adm1275_enable_vout_temp(client, config);
+               ret = adm1275_enable_vout_temp(data, client, config);
                if (ret)
                        return ret;
 
@@ -694,7 +702,7 @@ static int adm1275_probe(struct i2c_client *client)
                        PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
                        PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 
-               ret = adm1275_enable_vout_temp(client, config);
+               ret = adm1275_enable_vout_temp(data, client, config);
                if (ret)
                        return ret;
 
@@ -766,8 +774,7 @@ static int adm1275_probe(struct i2c_client *client)
                                "Invalid number of power samples");
                        return -EINVAL;
                }
-               ret = adm1275_write_pmon_config(data, client, true,
-                                               ilog2(avg));
+               ret = adm1275_write_samples(data, client, true, ilog2(avg));
                if (ret < 0) {
                        dev_err(&client->dev,
                                "Setting power sample averaging failed with error %d",
@@ -784,8 +791,7 @@ static int adm1275_probe(struct i2c_client *client)
                                "Invalid number of voltage/current samples");
                        return -EINVAL;
                }
-               ret = adm1275_write_pmon_config(data, client, false,
-                                               ilog2(avg));
+               ret = adm1275_write_samples(data, client, false, ilog2(avg));
                if (ret < 0) {
                        dev_err(&client->dev,
                                "Setting voltage and current sample averaging failed with error %d",