From: Balaji T K <balajitk@ti.com>
To: Andreas Fenkart <afenkart@gmail.com>
Cc: Tony Lindgren <tony@atomide.com>, Chris Ball <chris@printf.net>,
Grant Likely <grant.likely@secretlab.ca>,
Felipe Balbi <balbi@ti.com>,
zonque@gmail.com, galak@codeaurora.org,
linux-doc@vger.kernel.org, linux-mmc@vger.kernel.org,
linux-omap@vger.kernel.org
Subject: Re: [PATCH v9 resend 1/3] mmc: omap_hsmmc: Enable SDIO interrupt
Date: Fri, 21 Mar 2014 21:40:49 +0530 [thread overview]
Message-ID: <532C6489.4050307@ti.com> (raw)
In-Reply-To: <1395404448-30030-2-git-send-email-afenkart@gmail.com>
On Friday 21 March 2014 05:50 PM, Andreas Fenkart wrote:
Thanks Andreas for the patch series
I rebased against latest mmc-next, made few changes to your patch.
I have hosted your series along with devm cleanups on a branch[1] for testing
[1]
git://git.ti.com/~balajitk/ti-linux-kernel/omap-hsmmc.git omap_hsmmc_sdio_irq_devm_cleanup
Can you please test on your platform and provide feedback.
Details about the changes below.
> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
> @@ -1088,6 +1113,45 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
> return IRQ_HANDLED;
> }
>
> +static inline void hsmmc_enable_wake_irq(struct omap_hsmmc_host *host)
> +{
> + unsigned long flags;
> +
> + if (!host->wake_irq)
> + return;
> +
> + spin_lock_irqsave(&host->irq_lock, flags);
> + enable_irq(host->wake_irq);
> + host->wake_irq_en = true;
Using wake_irq_en flag leads to wake_irq enabled always after
suspend/resume due to unbalanced disable/enable_irq
so adding back HSMMC_WAKE_IRQ_ENABLED to host->flags
> + spin_unlock_irqrestore(&host->irq_lock, flags);
> +}
> +
> +static inline void hsmmc_disable_wake_irq(struct omap_hsmmc_host *host)
> +{
> + unsigned long flags;
> +
> + if (!host->wake_irq)
> + return;
> +
> + spin_lock_irqsave(&host->irq_lock, flags);
> + if (host->wake_irq_en)
> + disable_irq_nosync(host->wake_irq);
> + host->wake_irq_en = false;
> + spin_unlock_irqrestore(&host->irq_lock, flags);
> +}
> +
> +static irqreturn_t omap_hsmmc_wake_irq(int irq, void *dev_id)
> +{
> + struct omap_hsmmc_host *host = dev_id;
> +
> + /* cirq is level triggered, disable to avoid infinite loop */
> + hsmmc_disable_wake_irq(host);
> +
> + pm_request_resume(host->dev); /* no use counter */
> +
> + return IRQ_HANDLED;
> +}
> +
> static void set_sd_bus_power(struct omap_hsmmc_host *host)
> {
> unsigned long i;
> @@ -1591,6 +1655,72 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
> mmc_slot(host).init_card(card);
> }
>
> +static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> +{
> + struct omap_hsmmc_host *host = mmc_priv(mmc);
> + u32 irq_mask;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&host->irq_lock, flags);
> +
Introduced check for runtime suspend to be sure and explicitly
enable clocks using runtime_get_sync for enable sdio irq path.
> + irq_mask = OMAP_HSMMC_READ(host->base, ISE);
> + if (enable) {
> + host->flags |= HSMMC_SDIO_IRQ_ENABLED;
> + irq_mask |= CIRQ_EN;
> + } else {
> + host->flags &= ~HSMMC_SDIO_IRQ_ENABLED;
> + irq_mask &= ~CIRQ_EN;
> + }
> + OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
> +
> + /*
> + * if enable, piggy back detection on current request
> + * but always disable immediately
> + */
> + if (!host->req_in_progress || !enable)
> + OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
> +
> + /* flush posted write */
> + OMAP_HSMMC_READ(host->base, IE);
> +
> + spin_unlock_irqrestore(&host->irq_lock, flags);
> +}
> +
> +static int omap_hscmm_configure_wake_irq(struct omap_hsmmc_host *host)
> +{
> + struct mmc_host *mmc = host->mmc;
> + int ret;
> +
> + /*
> + * The wake-irq is needed for omaps with wake-up path and also
> + * when doing GPIO remuxing, because omap_hsmmc is doing runtime PM.
> + * So there's nothing stopping from shutting it down. And there's
> + * really no need to block runtime PM for it as it's working.
> + */
> + if (!host->dev->of_node || !host->wake_irq)
> + return -ENODEV;
> +
> + /* Prevent auto-enabling of IRQ */
> + irq_set_status_flags(host->wake_irq, IRQ_NOAUTOEN);
> + ret = request_irq(host->wake_irq, omap_hsmmc_wake_irq,
> + IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> + mmc_hostname(mmc), host);
Replaced request_irq with devm_request_irq
> + if (ret) {
> + dev_err(mmc_dev(host->mmc),
> + "Unable to request wake IRQ\n");
> + return ret;
> + }
> +
> + /*
> + * Some omaps don't have wake-up path from deeper idle states
> + * and need to remux SDIO DAT1 to GPIO for wake-up from idle.
> + */
> + if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING)
> + host->flags |= HSMMC_SWAKEUP_QUIRK;
> +
> + return 0;
> +}
> +
> static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
> {
> u32 hctl, capa, value;
> @@ -1643,7 +1773,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = {
> .get_cd = omap_hsmmc_get_cd,
> .get_ro = omap_hsmmc_get_ro,
> .init_card = omap_hsmmc_init_card,
> - /* NYET -- enable_sdio_irq */
> + .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
> };
>
> #ifdef CONFIG_DEBUG_FS
> @@ -1704,8 +1834,19 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc)
>
> #endif
>
> +struct of_data {
> + u16 offset;
> + int flags;
> +};
> +
> #ifdef CONFIG_OF
> -static u16 omap4_reg_offset = 0x100;
> +static struct of_data omap4_data = {
> + .offset = 0x100,
> +};
> +static struct of_data am33xx_data = {
> + .offset = 0x100,
> + .flags = OMAP_HSMMC_SWAKEUP_MISSING,
> +};
>
> static const struct of_device_id omap_mmc_of_match[] = {
> {
> @@ -1716,7 +1857,11 @@ static const struct of_device_id omap_mmc_of_match[] = {
> },
> {
> .compatible = "ti,omap4-hsmmc",
> - .data = &omap4_reg_offset,
> + .data = &omap4_data,
> + },
> + {
> + .compatible = "ti,am33xx-hsmmc",
> + .data = &am33xx_data,
> },
> {},
> };
> @@ -1779,6 +1924,7 @@ static inline struct omap_mmc_platform_data
> {
> return NULL;
> }
> +#define omap_mmc_of_match NULL
> #endif
>
> static int omap_hsmmc_probe(struct platform_device *pdev)
> @@ -1787,7 +1933,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
> struct mmc_host *mmc;
> struct omap_hsmmc_host *host = NULL;
> struct resource *res;
> - int ret, irq;
> + int ret, irq, _wake_irq = 0;
> const struct of_device_id *match;
> dma_cap_mask_t mask;
> unsigned tx_req, rx_req;
> @@ -1801,8 +1947,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
> return PTR_ERR(pdata);
>
> if (match->data) {
> - const u16 *offsetp = match->data;
> - pdata->reg_offset = *offsetp;
> + const struct of_data *d = match->data;
> + pdata->reg_offset = d->offset;
> + pdata->controller_flags |= d->flags;
> }
> }
>
> @@ -1821,6 +1968,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
> if (res == NULL || irq < 0)
> return -ENXIO;
>
> + if (pdev->dev.of_node)
> + _wake_irq = irq_of_parse_and_map(pdev->dev.of_node, 1);
> +
Moved this code further down to remove _wake_irq
> res = request_mem_region(res->start, resource_size(res), pdev->name);
> if (res == NULL)
> return -EBUSY;
> @@ -1842,6 +1992,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
> host->use_dma = 1;
> host->dma_ch = -1;
> host->irq = irq;
> + host->wake_irq = _wake_irq;
> host->slot_id = 0;
> host->mapbase = res->start + pdata->reg_offset;
> host->base = ioremap(host->mapbase, SZ_4K);
> @@ -2018,6 +2169,18 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
> dev_warn(&pdev->dev,
> "pins are not configured from the driver\n");
>
> + /*
> + * For now, only support SDIO interrupt if we have a separate
> + * wake-up interrupt configured from device tree. This is because
> + * the wake-up interrupt is needed for idle state and some
> + * platforms need special quirks. And we don't want to add new
> + * legacy mux platform init code callbacks any longer as we
> + * are moving to DT based booting anyways.
> + */
> + ret = omap_hscmm_configure_wake_irq(host);
fixed the typo in hsmmc :-)
> + if (!ret)
> + mmc->caps |= MMC_CAP_SDIO_IRQ;
> +
> omap_hsmmc_protect_card(host);
>
> mmc_add_host(mmc);
> @@ -2042,7 +2205,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
>
> err_slot_name:
> mmc_remove_host(mmc);
> - free_irq(mmc_slot(host).card_detect_irq, host);
> + if (host->wake_irq)
> + free_irq(host->wake_irq, host);
> + if (mmc_slot(host).card_detect_irq)
> + free_irq(mmc_slot(host).card_detect_irq, host);
> err_irq_cd:
> if (host->use_reg)
> omap_hsmmc_reg_put(host);
> @@ -2087,6 +2253,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
> if (host->pdata->cleanup)
> host->pdata->cleanup(&pdev->dev);
> free_irq(host->irq, host);
> + if (host->wake_irq)
> + free_irq(host->wake_irq, host);
> if (mmc_slot(host).card_detect_irq)
> free_irq(mmc_slot(host).card_detect_irq, host);
>
> @@ -2149,6 +2317,8 @@ static int omap_hsmmc_suspend(struct device *dev)
> OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
> }
>
> + hsmmc_disable_wake_irq(host);
> +
Made disable/enable_wake_irq conditional on MMC_PM_WAKE_SDIO_IRQ cap
> if (host->dbclk)
> clk_disable_unprepare(host->dbclk);
>
> @@ -2176,6 +2346,8 @@ static int omap_hsmmc_resume(struct device *dev)
>
> omap_hsmmc_protect_card(host);
>
> + hsmmc_enable_wake_irq(host);
> +
> pm_runtime_mark_last_busy(host->dev);
> pm_runtime_put_autosuspend(host->dev);
> return 0;
> @@ -2191,23 +2363,38 @@ static int omap_hsmmc_resume(struct device *dev)
> static int omap_hsmmc_runtime_suspend(struct device *dev)
> {
> struct omap_hsmmc_host *host;
> + int ret = 0;
>
> host = platform_get_drvdata(to_platform_device(dev));
> omap_hsmmc_context_save(host);
> dev_dbg(dev, "disabled\n");
>
> - return 0;
> + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
> + OMAP_HSMMC_WRITE(host->base, ISE, 0);
> + OMAP_HSMMC_WRITE(host->base, IE, 0);
> + OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
> + hsmmc_enable_wake_irq(host);
here too.
> + }
> +
> + return ret;
> }
>
> static int omap_hsmmc_runtime_resume(struct device *dev)
> {
> struct omap_hsmmc_host *host;
> + int ret = 0;
>
> host = platform_get_drvdata(to_platform_device(dev));
> omap_hsmmc_context_restore(host);
> dev_dbg(dev, "enabled\n");
>
> - return 0;
> + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
This leads to unconditional re-enabling sdio_irq/wake_irq
on next runtime resume, so replaced the check with HSMMC_SDIO_IRQ_ENABLED
> + hsmmc_disable_wake_irq(host);
> + OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
> + OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN);
> + OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN);
> + }
> + return ret;
> }
>
> static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
> diff --git a/include/linux/platform_data/mmc-omap.h b/include/linux/platform_data/mmc-omap.h
> index 2bf1b30..51e70cf 100644
> --- a/include/linux/platform_data/mmc-omap.h
> +++ b/include/linux/platform_data/mmc-omap.h
> @@ -28,6 +28,7 @@
> */
> #define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0)
> #define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ BIT(1)
> +#define OMAP_HSMMC_SWAKEUP_MISSING BIT(2)
>
> struct mmc_card;
>
>
next prev parent reply other threads:[~2014-03-21 16:10 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-21 12:20 [PATCH v9 resend 0/3] mmc: omap_hsmmc: Enable SDIO IRQ Andreas Fenkart
2014-03-21 12:20 ` [PATCH v9 resend 1/3] mmc: omap_hsmmc: Enable SDIO interrupt Andreas Fenkart
2014-03-21 16:10 ` Balaji T K [this message]
2014-03-24 9:30 ` Dmitry Lifshitz
2014-04-18 16:46 ` Tony Lindgren
2014-03-21 16:17 ` [PATCH 0/9] mmc: omap_hsmmc: convert to use devm_* and enable sdio irq Balaji T K
2014-03-21 16:17 ` [PATCH 1/9] mmc: omap_hsmmc: use devm_clk_get Balaji T K
2014-03-21 16:17 ` [PATCH 2/9] mmc: omap_hsmmc: use devm_request_irq Balaji T K
2014-03-21 16:17 ` [PATCH 3/9] mmc: omap_hsmmc: use devm_request_threaded_irq Balaji T K
2014-03-21 16:17 ` [PATCH 4/9] mmc: omap_hsmmc: use devm_request_mem_region Balaji T K
2014-03-21 16:18 ` Felipe Balbi
2014-03-21 16:27 ` Balaji T K
2014-03-21 16:30 ` Felipe Balbi
2014-03-21 16:17 ` [PATCH 5/9] mmc: omap_hsmmc: use devm_ioremap Balaji T K
2014-03-21 16:17 ` [PATCH 6/9] mmc: omap_hsmmc: Enable SDIO interrupt Balaji T K
2014-03-24 12:43 ` Ulf Hansson
2014-03-24 14:59 ` Andreas Fenkart
2014-03-24 16:02 ` Ulf Hansson
2014-03-24 16:34 ` Andreas Fenkart
2014-03-25 8:07 ` Ulf Hansson
2014-03-25 15:19 ` Balaji T K
2014-03-30 22:43 ` Andreas Fenkart
2014-03-21 16:17 ` [PATCH 7/9] mmc: omap_hsmmc: Pin remux workaround to support SDIO interrupt on AM335x Balaji T K
2014-03-21 16:17 ` [PATCH 8/9] mmc: omap_hsmmc: Extend debugfs for SDIO IRQ, GPIO and pinmux Balaji T K
2014-03-21 16:17 ` [PATCH 9/9] mmc: omap_hsmmc: enable wakeup event for sdio Balaji T K
2014-05-02 15:33 ` Balaji T K
2014-03-21 12:20 ` [PATCH v9 resend 2/3] mmc: omap_hsmmc: Pin remux workaround to support SDIO interrupt on AM335x Andreas Fenkart
2014-03-21 12:20 ` [PATCH v9 resend 3/3] mmc: omap_hsmmc: Extend debugfs for SDIO IRQ, GPIO and pinmux Andreas Fenkart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=532C6489.4050307@ti.com \
--to=balajitk@ti.com \
--cc=afenkart@gmail.com \
--cc=balbi@ti.com \
--cc=chris@printf.net \
--cc=galak@codeaurora.org \
--cc=grant.likely@secretlab.ca \
--cc=linux-doc@vger.kernel.org \
--cc=linux-mmc@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=tony@atomide.com \
--cc=zonque@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.