From 07fb76273db89d9340fa1fea2997d73fa3768ab9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?M=C3=A5rten=20Lindahl?= Date: Tue, 14 Jun 2022 11:38:54 +0200 Subject: [PATCH] hwmon: (pmbus) Introduce and use cached vout margins MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Link: https://lore.kernel.org/r/20220614093856.3470672-2-marten.lindahl@axis.com Signed-off-by: Guenter Roeck --- 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 4187dc20d2aad..8c6f44988ba5a 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 { @@ -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) -- 2.30.2