On 3 February 2015 at 14:07, Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> wrote: > This patch provides a simple mmc-pwrseq-emmc driver, which controls > single gpio line. It perform standard eMMC hw reset procedure, as > descibed by Jedec 4.4 specification. This procedure is performed just > after MMC core enabled power to the given mmc host (to fix possible > issues if bootloader has left eMMC card in initialized or unknown > state), and before performing complete system reboot (also in case of > emergency reboot call). The latter is needed on boards, which doesn't > have hardware reset logic connected to emmc card and (limited or broken) > ROM bootloaders are unable to read second stage from the emmc card if > the card is left in unknown or already initialized state. > > Signed-off-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> Thanks! Applied for next, with a minor fix for a checkpatch warning. See below. Kind regards Uffe > --- > Changelog: > v4: > - fixed minor issues reported by Ulf Hansson (comment adjustments, > removed .shutdown callback, reduced delay time) > > v3: http://www.spinics.net/lists/linux-samsung-soc/msg41956.html > - removed optional support for reset-gpio, reported by Javier Martinez Canillas > > v2: http://www.spinics.net/lists/linux-mmc/msg30621.html > --- > .../devicetree/bindings/mmc/mmc-pwrseq-emmc.txt | 25 +++++ > drivers/mmc/core/Makefile | 2 +- > drivers/mmc/core/pwrseq.c | 3 + > drivers/mmc/core/pwrseq.h | 1 + > drivers/mmc/core/pwrseq_emmc.c | 101 +++++++++++++++++++++ > 5 files changed, 131 insertions(+), 1 deletion(-) > create mode 100644 Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt > create mode 100644 drivers/mmc/core/pwrseq_emmc.c > > diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt > new file mode 100644 > index 0000000..0cb827b > --- /dev/null > +++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt > @@ -0,0 +1,25 @@ > +* The simple eMMC hardware reset provider > + > +The purpose of this driver is to perform standard eMMC hw reset > +procedure, as descibed by Jedec 4.4 specification. This procedure is > +performed just after MMC core enabled power to the given mmc host (to > +fix possible issues if bootloader has left eMMC card in initialized or > +unknown state), and before performing complete system reboot (also in > +case of emergency reboot call). The latter is needed on boards, which > +doesn't have hardware reset logic connected to emmc card and (limited or > +broken) ROM bootloaders are unable to read second stage from the emmc > +card if the card is left in unknown or already initialized state. > + > +Required properties: > +- compatible : contains "mmc-pwrseq-emmc". > +- reset-gpios : contains a GPIO specifier. The reset GPIO is asserted > + and then deasserted to perform eMMC card reset. To perform > + reset procedure as described in Jedec 4.4 specification, the > + gpio line should be defined as GPIO_ACTIVE_LOW. > + > +Example: > + > + sdhci0_pwrseq { > + compatible = "mmc-pwrseq-emmc"; > + reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; > + } > diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile > index b39cbd2..2c25138 100644 > --- a/drivers/mmc/core/Makefile > +++ b/drivers/mmc/core/Makefile > @@ -8,5 +8,5 @@ mmc_core-y := core.o bus.o host.o \ > sdio.o sdio_ops.o sdio_bus.o \ > sdio_cis.o sdio_io.o sdio_irq.o \ > quirks.o slot-gpio.o > -mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o > +mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o > mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o > diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c > index 2cea00e..8623561 100644 > --- a/drivers/mmc/core/pwrseq.c > +++ b/drivers/mmc/core/pwrseq.c > @@ -26,6 +26,9 @@ static struct mmc_pwrseq_match pwrseq_match[] = { > { > .compatible = "mmc-pwrseq-simple", > .alloc = mmc_pwrseq_simple_alloc, > + }, { > + .compatible = "mmc-pwrseq-emmc", > + .alloc = mmc_pwrseq_emmc_alloc, > }, > }; > > diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h > index bd860d8..aba3409 100644 > --- a/drivers/mmc/core/pwrseq.h > +++ b/drivers/mmc/core/pwrseq.h > @@ -28,6 +28,7 @@ void mmc_pwrseq_power_off(struct mmc_host *host); > void mmc_pwrseq_free(struct mmc_host *host); > > int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev); > +int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev); > > #else > > diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c > new file mode 100644 > index 0000000..8a434d7 > --- /dev/null > +++ b/drivers/mmc/core/pwrseq_emmc.c > @@ -0,0 +1,101 @@ > +/* > + * Copyright (C) 2015, Samsung Electronics Co., Ltd. > + * > + * Author: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> > + * > + * License terms: GNU General Public License (GPL) version 2 > + * > + * Simple eMMC hardware reset provider > + */ > +#include <linux/delay.h> > +#include <linux/kernel.h> > +#include <linux/slab.h> > +#include <linux/device.h> > +#include <linux/err.h> > +#include <linux/gpio/consumer.h> > +#include <linux/reboot.h> > + > +#include <linux/mmc/host.h> > + > +#include "pwrseq.h" > + > +struct mmc_pwrseq_emmc { > + struct mmc_pwrseq pwrseq; > + struct notifier_block reset_nb; > + struct gpio_desc *reset_gpio; > +}; > + > +static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) > +{ > + gpiod_set_value(pwrseq->reset_gpio, 1); > + udelay(1); > + gpiod_set_value(pwrseq->reset_gpio, 0); > + udelay(200); > +} > + > +static void mmc_pwrseq_emmc_reset(struct mmc_host *host) > +{ > + struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, > + struct mmc_pwrseq_emmc, pwrseq); > + > + __mmc_pwrseq_emmc_reset(pwrseq); > +} > + > +static void mmc_pwrseq_emmc_free(struct mmc_host *host) > +{ > + struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, > + struct mmc_pwrseq_emmc, pwrseq); > + > + unregister_restart_handler(&pwrseq->reset_nb); > + gpiod_put(pwrseq->reset_gpio); > + kfree(pwrseq); > + host->pwrseq = NULL; > +} > + > +static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { > + .post_power_on = mmc_pwrseq_emmc_reset, > + .free = mmc_pwrseq_emmc_free, > +}; > + > +static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, > + unsigned long mode, void *cmd) > +{ > + struct mmc_pwrseq_emmc *pwrseq; > + pwrseq = container_of(this, struct mmc_pwrseq_emmc, reset_nb); Assign pwrseq while declaring it, will follow the looks from other functions and silence a checkpatch warning. > + > + __mmc_pwrseq_emmc_reset(pwrseq); > + return NOTIFY_DONE; > +} > + > +int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev) > +{ > + struct mmc_pwrseq_emmc *pwrseq; > + int ret = 0; > + > + pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL); > + if (!pwrseq) > + return -ENOMEM; > + > + pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW); > + if (IS_ERR(pwrseq->reset_gpio)) { > + ret = PTR_ERR(pwrseq->reset_gpio); > + goto free; > + } > + > + /* > + * register reset handler to ensure emmc reset also from > + * emergency_reboot(), priority 129 schedules it just before > + * system reboot > + */ > + pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; > + pwrseq->reset_nb.priority = 129; > + register_restart_handler(&pwrseq->reset_nb); > + > + pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; > + host->pwrseq = &pwrseq->pwrseq; > + > + return 0; > +free: > + kfree(pwrseq); > + return ret; > +} > -- > 1.9.2 > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html