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: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Reviewed-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
This commit is contained in:
Родитель
8c96f89c62
Коммит
862b5dcf9f
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче