Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -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;
}