[PATCH] mmc: pwrseq_simple: Fix regression with optional GPIOs
Ulf Hansson
ulf.hansson at linaro.org
Mon Dec 7 16:19:23 PST 2015
+Linus
On 7 December 2015 at 23:54, Tony Lindgren <tony at atomide.com> wrote:
> Commit ce037275861e ("mmc: pwrseq_simple: use GPIO descriptors array API")
> changed the handling MMC power sequence so GPIOs no longer are optional.
>
> This broke SDIO WLAN at least for omap5 that can't yet use the reset GPIOs
> with pwrseq_simple as a wait is needed after enabling the SDIO device.
Can you elaborate on this. Did it break omap5 or not? :-)
Also, I am interested to know more about the waiting period you need.
I assume that's because of the HW's characteristic?
Why can't we have that being described in DT and then make
pwrseq_simple *wait* if needed?
>
> Let's fix the problem by allocating the GPIO values array during init
> depending on the optional GPIOs found.
Certainly it shall be optional! I wonder how I could let that patch
slip through, my bad!
Thanks for fixing this!
>
> Note that depending on the board specific configuration, some of the GPIOs
> can be permanently set up with pulls, so we want to keep pwrseq_simple
> GPIOs optional.
>
> Cc: Javier Martinez Canillas <javier at osg.samsung.com>
> Signed-off-by: Tony Lindgren <tony at atomide.com>
> ---
> drivers/mmc/core/pwrseq_simple.c | 20 ++++++++++++++++----
> 1 file changed, 16 insertions(+), 4 deletions(-)
>
> --- a/drivers/mmc/core/pwrseq_simple.c
> +++ b/drivers/mmc/core/pwrseq_simple.c
> @@ -24,6 +24,7 @@ struct mmc_pwrseq_simple {
> bool clk_enabled;
> struct clk *ext_clk;
> struct gpio_descs *reset_gpios;
> + int *values;
> };
>
> static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
> @@ -31,13 +32,15 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
> {
> int i;
> struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
> - int values[reset_gpios->ndescs];
I would prefer if we don't need to keep this memory on the heap.
Can't we instead keep a local copy of the reset_gpios->ndesc and when
pwrseq->reset_gpios doesn't exist use a default value?
> +
> + if (!reset_gpios || !reset_gpios->ndescs)
> + return;
>
> for (i = 0; i < reset_gpios->ndescs; i++)
> - values[i] = value;
> + pwrseq->values[i] = value;
>
> gpiod_set_array_value_cansleep(reset_gpios->ndescs, reset_gpios->desc,
> - values);
> + pwrseq->values);
> }
>
> static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
> @@ -84,6 +87,7 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
> if (!IS_ERR(pwrseq->ext_clk))
> clk_put(pwrseq->ext_clk);
>
> + kfree(pwrseq->values);
> kfree(pwrseq);
> }
>
> @@ -111,12 +115,20 @@ struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
> goto free;
> }
>
> - pwrseq->reset_gpios = gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
> + pwrseq->reset_gpios = gpiod_get_array_optional(dev, "reset",
> + GPIOD_OUT_HIGH);
> if (IS_ERR(pwrseq->reset_gpios)) {
The original code also considered -ENOSYS, as that's the return code
you get when CONFIG_GPIOLIB is unset, I think we need that as well.
Although, perhaps it's more correct that the gpiolib API returns NULL
instead of ERR_PTR(-ENOSYS)?
I have added Linus, to see if he has any comments on this.
> ret = PTR_ERR(pwrseq->reset_gpios);
> goto clk_put;
> }
>
> + if (pwrseq->reset_gpios && pwrseq->reset_gpios->ndescs) {
> + pwrseq->values = kzalloc(pwrseq->reset_gpios->ndescs *
> + sizeof(int), GFP_KERNEL);
> + if (!pwrseq->values)
> + goto clk_put;
This will leak a gpio cookie as it needs a gpiod_put_array().
> + }
> +
> pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
>
> return &pwrseq->pwrseq;
> --
> 2.6.2
>
One final comment, gpiod_put_array() doesn't deal with NULL pointers.
You need to check that in mmc_pwrseq_simple_free().
Kind regards
Uffe
More information about the linux-arm-kernel
mailing list