This driver does not have regulator specific operations for getting or setting voltage. Add functions get/set voltage for the dynamic regulator framework. In order to register the regulator operations together with the default pmbus core functions enable/disable/is_enabled, the default core functions need to be exported. Signed-off-by: Mårten Lindahl <marten.lindahl@xxxxxxxx> --- drivers/hwmon/pmbus/ltc2978.c | 89 +++++++++++++++++++++++++++++--- drivers/hwmon/pmbus/pmbus.h | 3 ++ drivers/hwmon/pmbus/pmbus_core.c | 9 ++-- 3 files changed, 90 insertions(+), 11 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 531aa674a928..76f37de67602 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -562,15 +562,88 @@ 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_get_voltage(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_wait_ready(client); + if (ret < 0) + return ret; + + ret = pmbus_read_word_data(client, page, 0xff, PMBUS_READ_VOUT); + if (ret < 0) + return ret; + + ret *= 1000; + + return ((ret >> 13) * 1000); +} + +static int ltc2978_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned int *selector) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + u8 page = rdev_get_id(rdev); + long tmp = DIV_ROUND_CLOSEST(min_uV, 1000); + u32 val = DIV_ROUND_CLOSEST(tmp << 13, 1000); + int ret; + *selector = 0; + + ret = ltc_wait_ready(client); + if (ret < 0) + return ret; + + ret = pmbus_read_word_data(client, page, 0xff, PMBUS_VOUT_MARGIN_LOW); + if (ret < 0) + return ret; + + /* Select the voltage closest to min_uV */ + if (ret > val) + val = ret; + + ret = ltc_wait_ready(client); + if (ret < 0) + return ret; + + ret = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, + (u16)val); + + return ret; +} + +static const struct regulator_ops ltc2978_regulator_ops = { + .enable = pmbus_regulator_enable, + .disable = pmbus_regulator_disable, + .is_enabled = pmbus_regulator_is_enabled, + .get_voltage = ltc2978_regulator_get_voltage, + .set_voltage = ltc2978_regulator_set_voltage, +}; + +/* 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 */ diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index c031a9700ace..e504656ddd26 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -478,6 +478,9 @@ extern const struct regulator_ops pmbus_regulator_ops; /* Function declarations */ +int pmbus_regulator_enable(struct regulator_dev *rdev); +int pmbus_regulator_disable(struct regulator_dev *rdev); +int pmbus_regulator_is_enabled(struct regulator_dev *rdev); void pmbus_clear_cache(struct i2c_client *client); void pmbus_set_update(struct i2c_client *client, u8 reg, bool update); int pmbus_set_page(struct i2c_client *client, int page, int phase); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 1b0728c3c7d8..149282953734 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2405,7 +2405,7 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, } #if IS_ENABLED(CONFIG_REGULATOR) -static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) +int pmbus_regulator_is_enabled(struct regulator_dev *rdev) { struct device *dev = rdev_get_dev(rdev); struct i2c_client *client = to_i2c_client(dev->parent); @@ -2422,6 +2422,7 @@ static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) return !!(ret & PB_OPERATION_CONTROL_ON); } +EXPORT_SYMBOL_NS_GPL(pmbus_regulator_is_enabled, PMBUS); static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) { @@ -2440,15 +2441,17 @@ static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) return ret; } -static int pmbus_regulator_enable(struct regulator_dev *rdev) +int pmbus_regulator_enable(struct regulator_dev *rdev) { return _pmbus_regulator_on_off(rdev, 1); } +EXPORT_SYMBOL_NS_GPL(pmbus_regulator_enable, PMBUS); -static int pmbus_regulator_disable(struct regulator_dev *rdev) +int pmbus_regulator_disable(struct regulator_dev *rdev) { return _pmbus_regulator_on_off(rdev, 0); } +EXPORT_SYMBOL_NS_GPL(pmbus_regulator_disable, PMBUS); /* A PMBus status flag and the corresponding REGULATOR_ERROR_* flag */ struct pmbus_regulator_status_assoc { -- 2.30.2