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@xxxxxxxx> --- drivers/hwmon/pmbus/pmbus_core.c | 78 +++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 02912022853d..5e0d16512fa6 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -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 { @@ -2636,6 +2639,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); @@ -2671,24 +2726,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) -- 2.30.2