Commit 862b5dcf authored by Ulf Hansson's avatar Ulf Hansson

mmc: pwrseq_simple: Add support for a reset GPIO pin

The need for reset GPIOs has several times been pointed out from
erlier posted patchsets. Especially some WLAN chips which are
attached to an SDIO interface may use a GPIO reset.

The reset GPIO is asserted at initialization and prior we start the
power up procedure. The GPIO will be de-asserted right after the power
has been provided to the card, from the ->post_power_on() callback.

Note, the reset GPIO is optional. Thus we don't return an error even if
we can't find a GPIO for the consumer.
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Tested-by: default avatarJavier Martinez Canillas <javier.martinez@collabora.co.uk>
Reviewed-by: default avatarJavier Martinez Canillas <javier.martinez@collabora.co.uk>
parent 8c96f89c
......@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/mmc/host.h>
......@@ -18,31 +19,68 @@
struct mmc_pwrseq_simple {
struct mmc_pwrseq pwrseq;
struct gpio_desc *reset_gpio;
};
static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
{
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
struct mmc_pwrseq_simple, pwrseq);
if (!IS_ERR(pwrseq->reset_gpio))
gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
}
static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
{
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
struct mmc_pwrseq_simple, pwrseq);
if (!IS_ERR(pwrseq->reset_gpio))
gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
}
static void mmc_pwrseq_simple_free(struct mmc_host *host)
{
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
struct mmc_pwrseq_simple, pwrseq);
if (!IS_ERR(pwrseq->reset_gpio))
gpiod_put(pwrseq->reset_gpio);
kfree(pwrseq);
host->pwrseq = NULL;
}
static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
.pre_power_on = mmc_pwrseq_simple_pre_power_on,
.post_power_on = mmc_pwrseq_simple_post_power_on,
.power_off = mmc_pwrseq_simple_pre_power_on,
.free = mmc_pwrseq_simple_free,
};
int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
{
struct mmc_pwrseq_simple *pwrseq;
int ret = 0;
pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple), GFP_KERNEL);
if (!pwrseq)
return -ENOMEM;
pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_HIGH);
if (IS_ERR(pwrseq->reset_gpio) &&
PTR_ERR(pwrseq->reset_gpio) != -ENOENT &&
PTR_ERR(pwrseq->reset_gpio) != -ENOSYS) {
ret = PTR_ERR(pwrseq->reset_gpio);
goto free;
}
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
host->pwrseq = &pwrseq->pwrseq;
return 0;
free:
kfree(pwrseq);
return ret;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment