Re: [PATCH 2/3] mmc: omap_hsmmc: Pin remux workaround to support SDIO interrupt on AM335x.
Hi On Mon, Nov 11, 2013 at 9:06 PM, Andreas Fenkart wrote: > The am335x can't detect pending cirq in PM runtime suspend. > This patch reconfigures dat1 as a GPIO before going to suspend. > SDIO interrupts are detected with the GPIO, the GPIO will only wake > the module from suspend, SDIO irq detection will still happen through the > IP block. > > Idea of remuxing the pins by Tony Lindgren as well as the implementation > of omap_hsmmc_pin_init. > > Signed-off-by: Andreas Fenkart > --- > .../devicetree/bindings/mmc/ti-omap-hsmmc.txt | 28 ++- > drivers/mmc/host/omap_hsmmc.c | 189 > ++-- > include/linux/platform_data/mmc-omap.h |4 + > 3 files changed, 207 insertions(+), 14 deletions(-) > > diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt > b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt > index 1136e6b..146f3ad 100644 > --- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt > +++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt > @@ -21,8 +21,11 @@ ti,non-removable: non-removable slot (like eMMC) > ti,needs-special-reset: Requires a special softreset sequence > ti,needs-special-hs-handling: HSMMC IP needs special setting for handling > High Speed > ti,quirk-swakup-missing: SOC missing the swakeup line, will not detect > -SDIO irq while in suspend. Fallback to polling. Affected chips are > -am335x, > +SDIO irq while in suspend. The workaround is to reconfigure the dat1 line as > a > +GPIO upon suspend. Beyond this option and the GPIO config, you also need to > set > +named pinctrl states "default", "active" and "idle ", see example below. The > +MMC driver will then then toggle between default and idle during the runtime > +Affected chips are am335x, > > -- > | PRCM | > @@ -49,3 +52,24 @@ Example: > vmmc-supply = <&vmmc>; /* phandle to regulator node */ > ti,non-removable; > }; > + > +[am335x with with gpio for sdio irq] > + > + mmc1_cirq_pin: pinmux_cirq_pin { > + pinctrl-single,pins = < > + 0x0f8 0x3f /* MMC0_DAT1 as GPIO2_28 */ > + >; > + }; > + > + mmc1: mmc@4806 { > + ti,non-removable; > + bus-width = <4>; > + vmmc-supply = <&ldo2_reg>; > + vmmc_aux-supply = <&vmmc>; > + ti,quirk-swakeup-missing; > + pinctrl-names = "default", "active", "idle"; > + pinctrl-0 = <&mmc1_pins>; > + pinctrl-1 = <&mmc1_pins>; > + pinctrl-2 = <&mmc1_cirq_pin>; > + ti,cirq-gpio = <&gpio3 28 0>; > + }; > diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c > index 6b0ec55..5a7fb4b 100644 > --- a/drivers/mmc/host/omap_hsmmc.c > +++ b/drivers/mmc/host/omap_hsmmc.c > @@ -36,6 +36,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -213,11 +214,30 @@ struct omap_hsmmc_host { > int req_in_progress; > int flags; > #define HSMMC_SDIO_IRQ_ENABLED (1 << 0)/* SDIO irq enabled */ > +#define HSMMC_SWAKEUP_QUIRK(1 << 1) > +#define HSMMC_CIRQ_GPIO_FIRED (1 << 2) > > struct omap_hsmmc_next next_data; > + struct pinctrl *pinctrl; > + struct pinctrl_state*fixed, *active, *idle; > struct omap_mmc_platform_data *pdata; > }; > > +static irqreturn_t omap_hsmmc_cirq(int irq, void *dev_id) > +{ > + struct omap_hsmmc_host *host = dev_id; > + unsigned long flags; > + > + spin_lock_irqsave(&host->irq_lock, flags); > + host->flags |= HSMMC_CIRQ_GPIO_FIRED; > + disable_irq_nosync(mmc_slot(host).sdio_irq); > + spin_unlock_irqrestore(&host->irq_lock, flags); > + > + pm_request_resume(host->dev); /* no use counter */ > + > + return IRQ_HANDLED; > +} > + > static int omap_hsmmc_card_detect(struct device *dev, int slot) > { > struct omap_hsmmc_host *host = dev_get_drvdata(dev); > @@ -452,10 +472,25 @@ static int omap_hsmmc_gpio_init(struct > omap_mmc_platform_data *pdata) > } else > pdata->slots[0].gpio_wp = -EINVAL; > > + if (gpio_is_valid(pdata->slots[0].gpio_cirq)) { > + pdata->slots[0].sdio_irq = > + gpio_to_irq(pdata->slots[0].gpio_cirq); > + ret = gpio_request_one(pdata->slots[0].gpio_cirq, > GPIOF_DIR_IN, > + "sdio_cirq"); > + if (ret) > + goto err_free_ro; > + > + } else { > + pdata->slots[0].gpio_cirq = -EINVAL; > + } > + > + > return 0; > > +err_free_ro: > + if (gpio_is_valid(pdata->slots[0].gpio_wp)) > err_free_wp: > - gpio_free(pdata->slots[0].gpio_wp); > +
Re: [PATCH 2/3] mmc: omap_hsmmc: Pin remux workaround to support SDIO interrupt on AM335x.
Hi On Mon, Nov 11, 2013 at 7:52 PM, wrote: > From: Andreas Fenkart > > The am335x can't detect pending cirq in PM runtime suspend. > This patch reconfigures dat1 as a GPIO before going to suspend. > SDIO interrupts are detected with the GPIO, the GPIO will only wake > the module from suspend, SDIO irq detection will still happen through the > IP block. > > Idea of remuxing the pins by Tony Lindgren as well as the implementation > of omap_hsmmc_pin_init. > > Signed-off-by: Andreas Fenkart > --- > .../devicetree/bindings/mmc/ti-omap-hsmmc.txt | 28 ++- > drivers/mmc/host/omap_hsmmc.c | 195 > ++-- > include/linux/platform_data/mmc-omap.h |4 + > 3 files changed, 213 insertions(+), 14 deletions(-) > > diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt > b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt > index 1136e6b..146f3ad 100644 > --- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt > +++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt > @@ -21,8 +21,11 @@ ti,non-removable: non-removable slot (like eMMC) > ti,needs-special-reset: Requires a special softreset sequence > ti,needs-special-hs-handling: HSMMC IP needs special setting for handling > High Speed > ti,quirk-swakup-missing: SOC missing the swakeup line, will not detect > -SDIO irq while in suspend. Fallback to polling. Affected chips are > -am335x, > +SDIO irq while in suspend. The workaround is to reconfigure the dat1 line as > a > +GPIO upon suspend. Beyond this option and the GPIO config, you also need to > set > +named pinctrl states "default", "active" and "idle ", see example below. The > +MMC driver will then then toggle between default and idle during the runtime > +Affected chips are am335x, > > -- > | PRCM | > @@ -49,3 +52,24 @@ Example: > vmmc-supply = <&vmmc>; /* phandle to regulator node */ > ti,non-removable; > }; > + > +[am335x with with gpio for sdio irq] > + > + mmc1_cirq_pin: pinmux_cirq_pin { > + pinctrl-single,pins = < > + 0x0f8 0x3f /* MMC0_DAT1 as GPIO2_28 */ > + >; > + }; > + > + mmc1: mmc@4806 { > + ti,non-removable; > + bus-width = <4>; > + vmmc-supply = <&ldo2_reg>; > + vmmc_aux-supply = <&vmmc>; > + ti,quirk-swakeup-missing; > + pinctrl-names = "default", "active", "idle"; > + pinctrl-0 = <&mmc1_pins>; > + pinctrl-1 = <&mmc1_pins>; > + pinctrl-2 = <&mmc1_cirq_pin>; > + ti,cirq-gpio = <&gpio3 28 0>; > + }; > diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c > index 6b0ec55..e880b44 100644 > --- a/drivers/mmc/host/omap_hsmmc.c > +++ b/drivers/mmc/host/omap_hsmmc.c > @@ -36,6 +36,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -213,11 +214,30 @@ struct omap_hsmmc_host { > int req_in_progress; > int flags; > #define HSMMC_SDIO_IRQ_ENABLED (1 << 0)/* SDIO irq enabled */ > +#define HSMMC_SWAKEUP_QUIRK(1 << 1) > +#define HSMMC_CIRQ_GPIO_FIRED (1 << 2) > > struct omap_hsmmc_next next_data; > + struct pinctrl *pinctrl; > + struct pinctrl_state*fixed, *active, *idle; > struct omap_mmc_platform_data *pdata; > }; > > +static irqreturn_t omap_hsmmc_cirq(int irq, void *dev_id) > +{ > + struct omap_hsmmc_host *host = dev_id; > + unsigned long flags; > + > + spin_lock_irqsave(&host->irq_lock, flags); > + host->flags |= HSMMC_CIRQ_GPIO_FIRED; > + disable_irq_nosync(mmc_slot(host).sdio_irq); > + spin_unlock_irqrestore(&host->irq_lock, flags); > + > + pm_request_resume(host->dev); /* no use counter */ > + > + return IRQ_HANDLED; > +} > + > static int omap_hsmmc_card_detect(struct device *dev, int slot) > { > struct omap_hsmmc_host *host = dev_get_drvdata(dev); > @@ -452,10 +472,31 @@ static int omap_hsmmc_gpio_init(struct > omap_mmc_platform_data *pdata) > } else > pdata->slots[0].gpio_wp = -EINVAL; > > + if (pdata->slots[0].gpio_cirq > 0 && > + gpio_is_valid(pdata->slots[0].gpio_cirq)) { Is ok only gpio_is_valid? > + pdata->slots[0].sdio_irq = > + gpio_to_irq(pdata->slots[0].gpio_cirq); > + > + ret = gpio_request(pdata->slots[0].gpio_cirq, "sdio_cirq"); > + if (ret) > + goto err_free_ro; > + ret = gpio_direction_input(pdata->slots[0].gpio_cirq); > + if (ret) > + goto err_free_cirq; Can you use gpio_request_one? Michael > + > + } else { > + pdata->s