From patchwork Thu Oct 15 16:25:43 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcin Wojtas X-Patchwork-Id: 7408061 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id F3AABBEEA4 for ; Thu, 15 Oct 2015 16:20:37 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D92A7206F2 for ; Thu, 15 Oct 2015 16:20:36 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A241020664 for ; Thu, 15 Oct 2015 16:20:35 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZmlF0-00078a-Bg; Thu, 15 Oct 2015 16:18:54 +0000 Received: from mail-lb0-f173.google.com ([209.85.217.173]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZmlEM-000651-OW for linux-arm-kernel@lists.infradead.org; Thu, 15 Oct 2015 16:18:18 +0000 Received: by lbbwb3 with SMTP id wb3so13271441lbb.1 for ; Thu, 15 Oct 2015 09:17:52 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=2PxAfF1tMBlu8KEYY/oskB8d5tq2mJRE3N+iREq5DUI=; b=d8CBc7A1rDSEKC1+f+FPxomV1ceoDdkmZd/P0tyQJF/82AKWYF454AIrZZtGfh4ub2 27ENkVCBhJkL+8grq/h9XKGo8wAKTC/yzTjOguhKuw6KQcPkNdbbdTLCLSSLEG70OpNN fMYxMmzVR3AR1RohdUGKmWrlBwtF4LuLOYlVKtmB0goSyTG8l4oMleC0dELDEmcI0BGY 43inMxc0SVozfPx3Oy3ugNOPe2M6i2zOOg40EcPLN8kTvzyxUG+ixHOM25GaB0aRx8XI qDaq5uc1mkhVdB4dK+Y7PhxV0eJQlVO1f5BZrG2vG0dlql7mwiy0tLk6ORuOCeIFHnPR 7xNQ== X-Gm-Message-State: ALoCoQljYEIXmmGNlyt6fhhmyO/cIg0uZK2Enku1W0esJYbsS80HqPogYxZwUt8iF7Ql1MJM+x6g X-Received: by 10.112.125.231 with SMTP id mt7mr4992501lbb.87.1444925872026; Thu, 15 Oct 2015 09:17:52 -0700 (PDT) Received: from enkidu.semihalf.local ([80.82.22.190]) by smtp.gmail.com with ESMTPSA id r137sm2185323lfe.34.2015.10.15.09.17.50 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 15 Oct 2015 09:17:51 -0700 (PDT) From: Marcin Wojtas To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mmc@vger.kernel.org Subject: [PATCH v3 2/5] mmc: sdhci-pxav3: enable usage of DAT3 pin as HW card detect Date: Thu, 15 Oct 2015 18:25:43 +0200 Message-Id: <1444926346-29763-3-git-send-email-mw@semihalf.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1444926346-29763-1-git-send-email-mw@semihalf.com> References: <1444926346-29763-1-git-send-email-mw@semihalf.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151015_091815_416649_002B39E9 X-CRM114-Status: GOOD ( 22.18 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thomas.petazzoni@free-electrons.com, andrew@lunn.ch, ulf.hansson@linaro.org, jason@lakedaemon.net, tawfik@marvell.com, jaz@semihalf.com, nadavh@marvell.com, alior@marvell.com, jszhang@marvell.com, gregory.clement@free-electrons.com, mw@semihalf.com, sebastian.hesselbarth@gmail.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Marvell Armada 38x SDHCI controller enable using DAT3 pin as a hardware card detection. According to the SD sdandard this signal can be used for this purpose combined with a pull-down resistor, implying inverted (active high) polarization of a card detect. MMC standard does not support this feature and does not operate with such connectivity of DAT3. When using DAT3-based detection Armada 38x SDIO IP expects its internal clock to be always on, which had to be ensured by: - Udating appropriate registers, each time controller is reset. On the occasion of adding new register @0x104, register @0x100 name is modified in order to the be aligned with Armada 38x documentation. - Leaving the clock enabled despite power-down. For this purpose a wrapper for sdhci_set_clock function is added. - Disabling pm_runtime - during suspend both io_clock and controller's bus power is switched off, hence it would prevent proper card detection. In addition to the changes above this commit adds a new property to Armada 38x SDHCI node ('dat3-cd') with an according binding documentation update. 'sdhci_pxa' structure is also extended with dedicated flag for checking if DAT3-based detection is in use. Signed-off-by: Marcin Wojtas --- .../devicetree/bindings/mmc/sdhci-pxa.txt | 5 ++ drivers/mmc/host/sdhci-pxav3.c | 100 +++++++++++++++++---- 2 files changed, 87 insertions(+), 18 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt index 3d1b449..ffd6b14 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt @@ -23,6 +23,11 @@ Required properties: Optional properties: - mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning. +- dat3-cd: use DAT3 pin as hardware card detect - option available for + "marvell,armada-380-sdhci" only. The detection is supposed to work with + active high polarity, which implies usage of "cd-inverted" property. + Note that according to the specifications DAT3-based card detection can be + used with SD cards only. MMC standard doesn't support this feature. Example: diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 54a253c0..d813233 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -46,10 +46,14 @@ #define SDCLK_DELAY_SHIFT 9 #define SDCLK_DELAY_MASK 0x1f -#define SD_CFG_FIFO_PARAM 0x100 +#define SD_EXTRA_PARAM_REG 0x100 #define SDCFG_GEN_PAD_CLK_ON (1<<6) #define SDCFG_GEN_PAD_CLK_CNT_MASK 0xFF #define SDCFG_GEN_PAD_CLK_CNT_SHIFT 24 +#define SD_FIFO_PARAM_REG 0x104 +#define SD_USE_DAT3 BIT(7) +#define SD_OVRRD_CLK_OEN BIT(11) +#define SD_FORCE_CLK_ON BIT(12) #define SD_SPI_MODE 0x108 #define SD_CE_ATA_1 0x10C @@ -64,6 +68,7 @@ struct sdhci_pxa { u8 power_mode; void __iomem *sdio3_conf_reg; void __iomem *mbus_win_regs; + bool dat3_cd_enabled; }; /* @@ -160,13 +165,36 @@ static int armada_38x_quirks(struct platform_device *pdev, } host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_USE_SDR50_TUNING); + if (of_property_read_bool(np, "dat3-cd") && + !of_property_read_bool(np, "broken-cd")) + pxa->dat3_cd_enabled = true; + return 0; } +static void pxav3_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; + + sdhci_set_clock(host, clock); + + /* + * The interface clock enable is also used as control + * for the A38x SDIO IP, so it can't be powered down + * when using HW-based card detection. + */ + if (clock == 0 && pxa->dat3_cd_enabled) + sdhci_writew(host, SDHCI_CLOCK_INT_EN, SDHCI_CLOCK_CONTROL); +} + static void pxav3_reset(struct sdhci_host *host, u8 mask) { struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; + u32 reg_val; sdhci_reset(host, mask); @@ -184,6 +212,21 @@ static void pxav3_reset(struct sdhci_host *host, u8 mask) tmp |= SDCLK_SEL; writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); } + + if (pxa->dat3_cd_enabled) { + reg_val = sdhci_readl(host, SD_FIFO_PARAM_REG); + reg_val |= SD_USE_DAT3 | SD_OVRRD_CLK_OEN | + SD_FORCE_CLK_ON; + sdhci_writel(host, reg_val, SD_FIFO_PARAM_REG); + + /* + * For HW detection based on DAT3 pin keep internal + * clk switched on after controller reset. + */ + reg_val = sdhci_readl(host, SDHCI_CLOCK_CONTROL); + reg_val |= SDHCI_CLOCK_INT_EN; + sdhci_writel(host, reg_val, SDHCI_CLOCK_CONTROL); + } } } @@ -211,9 +254,9 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) writew(tmp, host->ioaddr + SD_CE_ATA_2); /* start sending the 74 clocks */ - tmp = readw(host->ioaddr + SD_CFG_FIFO_PARAM); + tmp = readw(host->ioaddr + SD_EXTRA_PARAM_REG); tmp |= SDCFG_GEN_PAD_CLK_ON; - writew(tmp, host->ioaddr + SD_CFG_FIFO_PARAM); + writew(tmp, host->ioaddr + SD_EXTRA_PARAM_REG); /* slowest speed is about 100KHz or 10usec per clock */ udelay(740); @@ -298,7 +341,7 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) } static const struct sdhci_ops pxav3_sdhci_ops = { - .set_clock = sdhci_set_clock, + .set_clock = pxav3_set_clock, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .set_bus_width = sdhci_set_bus_width, @@ -407,6 +450,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); pdata = pxav3_get_mmc_pdata(dev); pdev->dev.platform_data = pdata; + } else if (pdata) { /* on-chip device */ if (pdata->flags & PXA_FLAG_CARD_PERMANENT) @@ -438,12 +482,15 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) } } - pm_runtime_get_noresume(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_enable(&pdev->dev); - pm_suspend_ignore_children(&pdev->dev, 1); + if (!pxa->dat3_cd_enabled) { + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, + PXAV3_RPM_DELAY_MS); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, 1); + } ret = sdhci_add_host(host); if (ret) { @@ -456,13 +503,16 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) if (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ) device_init_wakeup(&pdev->dev, 1); - pm_runtime_put_autosuspend(&pdev->dev); + if (!pxa->dat3_cd_enabled) + pm_runtime_put_autosuspend(&pdev->dev); return 0; err_add_host: - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + if (!pxa->dat3_cd_enabled) { + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + } err_of_parse: err_cd_req: err_mbus_win: @@ -479,9 +529,11 @@ static int sdhci_pxav3_remove(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = pltfm_host->priv; - pm_runtime_get_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + if (!pxa->dat3_cd_enabled) { + pm_runtime_get_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + } sdhci_remove_host(host, 1); @@ -498,9 +550,16 @@ static int sdhci_pxav3_suspend(struct device *dev) { int ret; struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; + + if (!pxa->dat3_cd_enabled) + pm_runtime_get_sync(dev); - pm_runtime_get_sync(dev); ret = sdhci_suspend_host(host); + if (pxa->dat3_cd_enabled) + return ret; + pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -518,8 +577,13 @@ static int sdhci_pxav3_resume(struct device *dev) ret = mv_conf_mbus_windows(dev, pxa->mbus_win_regs, mv_mbus_dram_info()); - pm_runtime_get_sync(dev); + if (!pxa->dat3_cd_enabled) + pm_runtime_get_sync(dev); + ret = sdhci_resume_host(host); + if (pxa->dat3_cd_enabled) + return ret; + pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev);