hwmon: (pmbus) Introduce and use cached vout margins

When setting a new voltage the voltage boundaries are read every time to
check that the new voltage is within the proper range. Checking these
voltage boundaries consists of reading one of PMBUS_MFR_VOUT_MIN/
PMBUS_VOUT_MARGIN_LOW registers and then PMBUS_MFR_VOUT_MAX/
PMBUS_VOUT_MARGIN_HIGH together with writing the PMBUS_CLEAR_FAULTS
register.

Since these boundaries are never being changed, it can be cached and
thus saving unnecessary smbus transmissions.

Signed-off-by: Mårten Lindahl <marten.lindahl@axis.com>
Link: https://lore.kernel.org/r/20220614093856.3470672-2-marten.lindahl@axis.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Mårten Lindahl 2022-06-14 11:38:54 +02:00 committed by Guenter Roeck
parent b674bcb13f
commit 07fb76273d

View file

@ -104,6 +104,9 @@ struct pmbus_data {
s16 currpage; /* current page, -1 for unknown/unset */
s16 currphase; /* current phase, 0xff for all, -1 for unknown/unset */
int vout_low[PMBUS_PAGES]; /* voltage low margin */
int vout_high[PMBUS_PAGES]; /* voltage high margin */
};
struct pmbus_debugfs_entry {
@ -2848,6 +2851,58 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
return 0;
}
static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
{
struct pmbus_data *data = i2c_get_clientdata(client);
struct pmbus_sensor s = {
.page = page,
.class = PSC_VOLTAGE_OUT,
.convert = true,
.data = -1,
};
if (!data->vout_low[page]) {
if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MIN))
s.data = _pmbus_read_word_data(client, page, 0xff,
PMBUS_MFR_VOUT_MIN);
if (s.data < 0) {
s.data = _pmbus_read_word_data(client, page, 0xff,
PMBUS_VOUT_MARGIN_LOW);
if (s.data < 0)
return s.data;
}
data->vout_low[page] = pmbus_reg2data(data, &s);
}
return data->vout_low[page];
}
static int pmbus_regulator_get_high_margin(struct i2c_client *client, int page)
{
struct pmbus_data *data = i2c_get_clientdata(client);
struct pmbus_sensor s = {
.page = page,
.class = PSC_VOLTAGE_OUT,
.convert = true,
.data = -1,
};
if (!data->vout_high[page]) {
if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MAX))
s.data = _pmbus_read_word_data(client, page, 0xff,
PMBUS_MFR_VOUT_MAX);
if (s.data < 0) {
s.data = _pmbus_read_word_data(client, page, 0xff,
PMBUS_VOUT_MARGIN_HIGH);
if (s.data < 0)
return s.data;
}
data->vout_high[page] = pmbus_reg2data(data, &s);
}
return data->vout_high[page];
}
static int pmbus_regulator_get_voltage(struct regulator_dev *rdev)
{
struct device *dev = rdev_get_dev(rdev);
@ -2883,24 +2938,13 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
*selector = 0;
if (pmbus_check_word_register(client, s.page, PMBUS_MFR_VOUT_MIN))
s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_MFR_VOUT_MIN);
if (s.data < 0) {
s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_VOUT_MARGIN_LOW);
if (s.data < 0)
return s.data;
}
low = pmbus_reg2data(data, &s);
low = pmbus_regulator_get_low_margin(client, s.page);
if (low < 0)
return low;
s.data = -1;
if (pmbus_check_word_register(client, s.page, PMBUS_MFR_VOUT_MAX))
s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_MFR_VOUT_MAX);
if (s.data < 0) {
s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_VOUT_MARGIN_HIGH);
if (s.data < 0)
return s.data;
}
high = pmbus_reg2data(data, &s);
high = pmbus_regulator_get_high_margin(client, s.page);
if (high < 0)
return high;
/* Make sure we are within margins */
if (low > val)