Several of the manuals for devices supported by this driver describes the need for a minimum wait time before the chip is ready to receive next command. This wait time is already implemented in the driver as a ltc_wait_ready function with a driver defined wait time of 100 ms, and is considered for specific devices before reading/writing data on the pmbus. But this driver uses the default pmbus_regulator_ops for the enable/ disable/is_enabled functions. By using these functions it bypasses the wait time recommendations for several of the devices managed by the driver (ltc3880/ltc3882/ltc3883/ltc3884/ltc3886/ltc3887/ltc3889/ltm4664/ ltm4675/ltm4676/ltm4677/ltm4678/ltm4680/ltm4686/ltm4700/ltc7880). Lets add driver specific regulator enable/disable/is_enabled ops which takes the wait time into consideration for the specified devices, by overriding pmbus_read_byte_data with internal ltc_read_byte_data. Signed-off-by: Mårten Lindahl <marten.lindahl@xxxxxxxx> --- drivers/hwmon/pmbus/ltc2978.c | 79 +++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 0127273883f0..822edec33ba7 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -551,15 +551,78 @@ static const struct i2c_device_id ltc2978_id[] = { MODULE_DEVICE_TABLE(i2c, ltc2978_id); #if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR) +static int ltc2978_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + u8 page = rdev_get_id(rdev); + int ret; + + ret = ltc_read_byte_data(client, page, PMBUS_OPERATION); + if (ret < 0) + return ret; + + return !!(ret & PB_OPERATION_CONTROL_ON); +} + +static int ltc2978_regulator_on_off(struct regulator_dev *rdev, bool enable) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + u8 page = rdev_get_id(rdev); + unsigned int tmp; + int rv; + + rv = ltc_read_byte_data(client, page, PMBUS_OPERATION); + if (rv < 0) + return rv; + + tmp = (rv & ~PB_OPERATION_CONTROL_ON) | + (enable ? PB_OPERATION_CONTROL_ON : 0); + + if (tmp != rv) + rv = pmbus_write_byte_data(client, page, PMBUS_OPERATION, tmp); + + return rv; +} + +static int ltc2978_regulator_enable(struct regulator_dev *rdev) +{ + return ltc2978_regulator_on_off(rdev, 1); +} + +static int ltc2978_regulator_disable(struct regulator_dev *rdev) +{ + return ltc2978_regulator_on_off(rdev, 0); +} + +static const struct regulator_ops ltc2978_regulator_ops = { + .enable = ltc2978_regulator_enable, + .disable = ltc2978_regulator_disable, + .is_enabled = ltc2978_regulator_is_enabled, +}; + +/* Macro for filling in array of struct regulator_desc */ +#define PMBUS_LTC2978_REGULATOR(_name, _id) \ + [_id] = { \ + .name = (_name # _id), \ + .id = (_id), \ + .of_match = of_match_ptr(_name # _id), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = <c2978_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + static const struct regulator_desc ltc2978_reg_desc[] = { - PMBUS_REGULATOR("vout", 0), - PMBUS_REGULATOR("vout", 1), - PMBUS_REGULATOR("vout", 2), - PMBUS_REGULATOR("vout", 3), - PMBUS_REGULATOR("vout", 4), - PMBUS_REGULATOR("vout", 5), - PMBUS_REGULATOR("vout", 6), - PMBUS_REGULATOR("vout", 7), + PMBUS_LTC2978_REGULATOR("vout", 0), + PMBUS_LTC2978_REGULATOR("vout", 1), + PMBUS_LTC2978_REGULATOR("vout", 2), + PMBUS_LTC2978_REGULATOR("vout", 3), + PMBUS_LTC2978_REGULATOR("vout", 4), + PMBUS_LTC2978_REGULATOR("vout", 5), + PMBUS_LTC2978_REGULATOR("vout", 6), + PMBUS_LTC2978_REGULATOR("vout", 7), }; #endif /* CONFIG_SENSORS_LTC2978_REGULATOR */ -- 2.30.2