Re: [PATCH v2 2/2] regulator: richtek,rt4801: use existing ena_gpiod feature

From: ChiYuan Huang
Date: Mon Apr 25 2022 - 01:50:28 EST


On Sat, Apr 23, 2022 at 08:14:19PM +0200, Krzysztof Kozlowski wrote:
> The driver duplicated regulator core feature of controlling
> regulators with GPIOs (of_parse_cb + ena_gpiod) and created its own
> enable-gpios property with multiple GPIOs.
>
> The core already does it. Keep old method for backwards compatibility.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@xxxxxxxxxx>
> ---
> drivers/regulator/rt4801-regulator.c | 68 ++++++++++++++++++++++++----
> 1 file changed, 58 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/regulator/rt4801-regulator.c b/drivers/regulator/rt4801-regulator.c
> index 7a87788d3f09..22efe44cd3a0 100644
> --- a/drivers/regulator/rt4801-regulator.c
> +++ b/drivers/regulator/rt4801-regulator.c
> @@ -29,17 +29,71 @@
>
> struct rt4801_priv {
> struct device *dev;
> + /*
> + * Driver supports enable GPIOs in two ways:
> + * 1. Legacy enable-gpios property with multiple entries and enable
> + * control handled by the driver.
> + * 2. Per-regulator enable-gpios property with enable control handled by
> + * the regulator core.
> + *
> + * The enable_gpios and enable_flag properties are for the (1) case.
> + */
> struct gpio_descs *enable_gpios;
> unsigned int enable_flag;
> unsigned int volt_sel[DSV_OUT_MAX];
> };
>
> +static int rt4801_of_parse_cb(struct device_node *np,
> + const struct regulator_desc *desc,
> + struct regulator_config *config)
> +{
> + struct rt4801_priv *priv = config->driver_data;
> +
> + if (priv->enable_gpios) {
> + dev_warn(priv->dev, "duplicated enable-gpios property\n");
> + return 0;
> + }
> + config->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(np),
> + "enable-gpios",
'enable' only, gpiod API will automatically concat it to 'enable-gpios'.
> + 0,
> + GPIOD_OUT_HIGH |
> + GPIOD_FLAGS_BIT_NONEXCLUSIVE,
> + "rt4801");
> + if (IS_ERR(config->ena_gpiod))
> + config->ena_gpiod = NULL;
> +
> + return 0;
> +}
> +
> +/*
> + * regulator_ops->is_enabled() implementation
> + */
> +static int rt4801_is_enabled(struct regulator_dev *rdev)
> +{
> + struct rt4801_priv *priv = rdev_get_drvdata(rdev);
> + int id = rdev_get_id(rdev);
> +
> + return !!(priv->enable_flag & BIT(id));
> +}
> +
> +/*
> + * Internally used only is_enabled() implementation using also ena_pin from
> + * regulator core.
> + */
> +static bool rt4801_is_enabled_ena_pin(struct regulator_dev *rdev)
> +{
> + if (rdev->ena_pin)
> + return rdev->ena_gpio_state;
> +
> + return rt4801_is_enabled(rdev);
> +}
> +
> static int rt4801_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
> {
> struct rt4801_priv *priv = rdev_get_drvdata(rdev);
> int id = rdev_get_id(rdev), ret;
>
> - if (priv->enable_flag & BIT(id)) {
> + if (rt4801_is_enabled_ena_pin(rdev)) {
> ret = regulator_set_voltage_sel_regmap(rdev, selector);
> if (ret)
> return ret;
> @@ -54,7 +108,7 @@ static int rt4801_get_voltage_sel(struct regulator_dev *rdev)
> struct rt4801_priv *priv = rdev_get_drvdata(rdev);
> int id = rdev_get_id(rdev);
>
> - if (priv->enable_flag & BIT(id))
> + if (rt4801_is_enabled_ena_pin(rdev))
> return regulator_get_voltage_sel_regmap(rdev);
>
> return priv->volt_sel[id];
> @@ -100,14 +154,6 @@ static int rt4801_disable(struct regulator_dev *rdev)
> return 0;
> }
>
> -static int rt4801_is_enabled(struct regulator_dev *rdev)
> -{
> - struct rt4801_priv *priv = rdev_get_drvdata(rdev);
> - int id = rdev_get_id(rdev);
> -
> - return !!(priv->enable_flag & BIT(id));
> -}
> -
> static const struct regulator_ops rt4801_regulator_ops = {
> .list_voltage = regulator_list_voltage_linear,
> .set_voltage_sel = rt4801_set_voltage_sel,
> @@ -122,6 +168,7 @@ static const struct regulator_desc rt4801_regulator_descs[] = {
> .name = "DSVP",
> .ops = &rt4801_regulator_ops,
> .of_match = of_match_ptr("DSVP"),
> + .of_parse_cb = rt4801_of_parse_cb,
> .type = REGULATOR_VOLTAGE,
> .id = DSV_OUT_POS,
> .min_uV = MIN_UV,
> @@ -135,6 +182,7 @@ static const struct regulator_desc rt4801_regulator_descs[] = {
> .name = "DSVN",
> .ops = &rt4801_regulator_ops,
> .of_match = of_match_ptr("DSVN"),
> + .of_parse_cb = rt4801_of_parse_cb,
> .type = REGULATOR_VOLTAGE,
> .id = DSV_OUT_NEG,
> .min_uV = MIN_UV,

There's one problem.
If 'ena_gpiod' is specified, it cannot be conexisted with ops
'enable/disable/is_enabled' by regulator framework.
It will cause no one to recover the voltage back.
You can check the original 'enable' ops.

How about to only parse gpio in 'of_parse_cb' and put it all into the
driver data, not to use regulator framework 'ena_gpiod'?

Best regards,
ChiYuan Huang.
> --
> 2.32.0
>