From patchwork Thu Jul 14 10:16:59 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 974842 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p6EAHhoM027275 for ; Thu, 14 Jul 2011 10:17:43 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754213Ab1GNKRm (ORCPT ); Thu, 14 Jul 2011 06:17:42 -0400 Received: from moutng.kundenserver.de ([212.227.17.9]:64069 "EHLO moutng.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754200Ab1GNKRm (ORCPT ); Thu, 14 Jul 2011 06:17:42 -0400 Received: from axis700.grange (dslb-178-006-253-037.pools.arcor-ip.net [178.6.253.37]) by mrelayeu.kundenserver.de (node=mreu3) with ESMTP (Nemesis) id 0Lirr0-1RCWiz32Za-00dDS2; Thu, 14 Jul 2011 12:16:59 +0200 Received: by axis700.grange (Postfix, from userid 1000) id 5E293189B6E; Thu, 14 Jul 2011 12:16:59 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by axis700.grange (Postfix) with ESMTP id 52800189B6D; Thu, 14 Jul 2011 12:16:59 +0200 (CEST) Date: Thu, 14 Jul 2011 12:16:59 +0200 (CEST) From: Guennadi Liakhovetski X-X-Sender: lyakh@axis700.grange To: linux-mmc@vger.kernel.org cc: linux-sh@vger.kernel.org, Magnus Damm , "Rafael J. Wysocki" , Chris Ball , Ian Molton , Simon Horman Subject: [PATCH v3] mmc: tmio: maximize power saving In-Reply-To: Message-ID: References: MIME-Version: 1.0 X-Provags-ID: V02:K0:yj7eFW8wTmpQEx3nLDgiDxt/I8gAblFMZXhsmdhV6Re a1vn2j/1PxsPo9LZysjf6GbGPpVCBI4KAp39eWfE0qUbPrh73m mZcXA8aV3PJUM+01ZNM1zhhywzNKq0x78Zl4tAGelh2/S+8W/M Q1K1kEASp2CytPn0qhwQtC97fvIA57qWoXrIGFloaj6HPAfxpj 6YOdcEfDsLCTwfhs1NjqI/Pi/NrRMnX4WKYFK+DB0E= Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Thu, 14 Jul 2011 10:17:43 +0000 (UTC) This patch uses runtime PM to allow the system to power down the MMC controller, when the MMC closk is switched off. Signed-off-by: Guennadi Liakhovetski --- v3: updated on top of current mmc-next plus my earlier patch "mmc: tmio: fix recursive spinlock, don't schedule with interrupts disabled" v2: Primarily tested on mackerel, with runtime PM and system-wide suspend, updated to the current core and sh-mobile runtime PM code. To avoid regression should go in after "ARM: mach-shmobile: use GPIO interrupt also for card eject on SDHI0 on mackerel": http://article.gmane.org/gmane.linux.kernel.mmc/9230 drivers/mmc/host/tmio_mmc.h | 2 + drivers/mmc/host/tmio_mmc_pio.c | 64 ++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index a2d6f9f..551d1ef 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -53,6 +53,8 @@ struct tmio_mmc_host { void (*set_clk_div)(struct platform_device *host, int state); int pm_error; + /* recognise system-wide suspend in runtime PM methods */ + bool pm_global; /* pio related stuff */ struct scatterlist *sg_ptr; diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index a2f76ad..221ffb7 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -546,6 +546,7 @@ out: irqreturn_t tmio_mmc_irq(int irq, void *devid) { struct tmio_mmc_host *host = devid; + struct mmc_host *mmc = host->mmc; struct tmio_mmc_data *pdata = host->pdata; unsigned int ireg, irq_mask, status; unsigned int sdio_ireg, sdio_irq_mask, sdio_status; @@ -567,13 +568,13 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) if (sdio_ireg && !host->sdio_irq_enabled) { pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", sdio_status, sdio_irq_mask, sdio_ireg); - tmio_mmc_enable_sdio_irq(host->mmc, 0); + tmio_mmc_enable_sdio_irq(mmc, 0); goto out; } - if (host->mmc->caps & MMC_CAP_SDIO_IRQ && + if (mmc->caps & MMC_CAP_SDIO_IRQ && sdio_ireg & TMIO_SDIO_STAT_IOIRQ) - mmc_signal_sdio_irq(host->mmc); + mmc_signal_sdio_irq(mmc); if (sdio_ireg) goto out; @@ -586,7 +587,9 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE); - if (!work_pending(&host->mmc->detect.work)) + if ((((ireg & TMIO_STAT_CARD_REMOVE) && mmc->card) || + ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) && + !work_pending(&mmc->detect.work)) mmc_detect_change(host->mmc, msecs_to_jiffies(100)); goto out; } @@ -743,33 +746,30 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_unlock_irqrestore(&host->lock, flags); - if (ios->clock) - tmio_mmc_set_clock(host, ios->clock); - - /* Power sequence - OFF -> UP -> ON */ - if (ios->power_mode == MMC_POWER_UP) { - if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && !pdata->power) { + /* + * pdata->power == false only if COLD_CD is available, otherwise only + * in short time intervals during probing or resuming + */ + if (ios->power_mode == MMC_POWER_ON && ios->clock) { + if (!pdata->power) { pm_runtime_get_sync(&host->pdev->dev); pdata->power = true; } + tmio_mmc_set_clock(host, ios->clock); /* power up SD bus */ if (host->set_pwr) host->set_pwr(host->pdev, 1); - } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { - /* power down SD bus */ - if (ios->power_mode == MMC_POWER_OFF) { - if (host->set_pwr) - host->set_pwr(host->pdev, 0); - if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && - pdata->power) { - pdata->power = false; - pm_runtime_put(&host->pdev->dev); - } - } - tmio_mmc_clk_stop(host); - } else { /* start bus clock */ tmio_mmc_clk_start(host); + } else if (ios->power_mode != MMC_POWER_UP) { + if (host->set_pwr) + host->set_pwr(host->pdev, 0); + if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && + pdata->power) { + pdata->power = false; + pm_runtime_put(&host->pdev->dev); + } + tmio_mmc_clk_stop(host); } switch (ios->bus_width) { @@ -897,8 +897,10 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, tmio_mmc_request_dma(_host, pdata); /* We have to keep the device powered for its card detection to work */ - if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) + if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) { + pdata->power = true; pm_runtime_get_noresume(&pdev->dev); + } mmc_add_host(mmc); @@ -975,11 +977,16 @@ int tmio_mmc_host_resume(struct device *dev) /* The MMC core will perform the complete set up */ host->pdata->power = false; + host->pm_global = true; if (!host->pm_error) pm_runtime_get_sync(dev); - tmio_mmc_reset(mmc_priv(mmc)); - tmio_mmc_request_dma(host, host->pdata); + if (host->pm_global) { + /* Runtime PM resume callback didn't run */ + tmio_mmc_reset(host); + tmio_mmc_request_dma(host, host->pdata); + host->pm_global = false; + } return mmc_resume_host(mmc); } @@ -1000,12 +1007,15 @@ int tmio_mmc_host_runtime_resume(struct device *dev) struct tmio_mmc_data *pdata = host->pdata; tmio_mmc_reset(host); + tmio_mmc_request_dma(host, host->pdata); if (pdata->power) { /* Only entered after a card-insert interrupt */ - tmio_mmc_set_ios(mmc, &mmc->ios); + if (!mmc->card) + tmio_mmc_set_ios(mmc, &mmc->ios); mmc_detect_change(mmc, msecs_to_jiffies(100)); } + host->pm_global = false; return 0; }