From patchwork Sat Jan 11 21:39:05 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Figa X-Patchwork-Id: 3470621 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.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 29847C02DC for ; Sat, 11 Jan 2014 21:43:15 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 425E12015A for ; Sat, 11 Jan 2014 21:43:14 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2B5332012F for ; Sat, 11 Jan 2014 21:43:13 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W26J1-0007Un-GU; Sat, 11 Jan 2014 21:41:25 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1W26IS-000201-JX; Sat, 11 Jan 2014 21:40:48 +0000 Received: from mail-ee0-x232.google.com ([2a00:1450:4013:c00::232]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W26HT-0001v2-98 for linux-arm-kernel@lists.infradead.org; Sat, 11 Jan 2014 21:39:54 +0000 Received: by mail-ee0-f50.google.com with SMTP id d17so30638eek.9 for ; Sat, 11 Jan 2014 13:39:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=P1sZZLBsOxwh0rhP1FOQ+AXwD0SMWHkX8y4Z/QVMWZg=; b=VPR4pNgLxsn6PZDCgKJPkgAcfSYjm2VADSGWv3Nf/Vj+ztI5kjHXiUdv74L1C6HxbO HKYb9KsuLU7bsGNArNiCFEaXVlYX9bFN5UMecCT4tBoBVz2H3ND+fWHTiI5g75YscETj A+/XYKMtRdEy2KtkySJY67yFCeDX/s6wcBk+Vb02ZGeq5R7nMuqvABDJrA1iTBBVSk6H UhHlw0VYkXDGFksvzr1TGp4CqxbNd7SuLJnNXrj3Qq6aW7VMjeM5RfoAjY2q9AJTD/rD +1G+l2mTAp3w1s1iRIAK2P/PnDcwJpQWtTw8WRQCuP8u7/0Lt9pp0OxcWiVGRXtEBs1b uOVQ== X-Received: by 10.14.208.199 with SMTP id q47mr18079808eeo.77.1389476364710; Sat, 11 Jan 2014 13:39:24 -0800 (PST) Received: from flatron.tomeq (87-207-52-162.dynamic.chello.pl. [87.207.52.162]) by mx.google.com with ESMTPSA id p45sm26014591eeg.1.2014.01.11.13.39.23 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 11 Jan 2014 13:39:24 -0800 (PST) From: Tomasz Figa To: linux-mmc@vger.kernel.org Subject: [PATCH 5/6] mmc: sdhci-s3c: Fix handling of bus clock switching Date: Sat, 11 Jan 2014 22:39:05 +0100 Message-Id: <1389476346-20396-6-git-send-email-tomasz.figa@gmail.com> X-Mailer: git-send-email 1.8.5.2 In-Reply-To: <1389476346-20396-1-git-send-email-tomasz.figa@gmail.com> References: <1389476346-20396-1-git-send-email-tomasz.figa@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140111_163947_904566_BAFF888B X-CRM114-Status: GOOD ( 17.25 ) X-Spam-Score: -2.0 (--) Cc: linux-samsung-soc@vger.kernel.org, Seungwon Jeon , Chris Ball , Tomasz Figa , Jaehoon Chung , Ben Dooks , linux-arm-kernel@lists.infradead.org, Marek Szyprowski X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, T_DKIM_INVALID, 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 Currently the driver assumes at probe that controller is configured for last valid enumerated bus clock. This assumption is completely wrong, as there is no way to ensure such configuration until the hardware gets first configured (by calling sdhci_s3c_set_clock()). This patch modifies the driver to set current clock at probe to unknown state (represented by negative value) and make sure that the hardware gets actually configured to selected clock in sdhci_s3c_set_clock(). Signed-off-by: Tomasz Figa --- drivers/mmc/host/sdhci-s3c.c | 78 ++++++++++---------------------------------- 1 file changed, 17 insertions(+), 61 deletions(-) diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 7e14db0..bad0e00 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -51,7 +51,7 @@ struct sdhci_s3c { struct platform_device *pdev; struct resource *ioarea; struct s3c_sdhci_platdata *pdata; - unsigned int cur_clk; + int cur_clk; int ext_cd_irq; int ext_cd_gpio; @@ -78,32 +78,6 @@ static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) } /** - * get_curclk - convert ctrl2 register to clock source number - * @ctrl2: Control2 register value. - */ -static u32 get_curclk(u32 ctrl2) -{ - ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK; - ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - - return ctrl2; -} - -static void sdhci_s3c_check_sclk(struct sdhci_host *host) -{ - struct sdhci_s3c *ourhost = to_s3c(host); - u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2); - - if (get_curclk(tmp) != ourhost->cur_clk) { - dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n"); - - tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; - tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2); - } -} - -/** * sdhci_s3c_get_max_clk - callback to get maximum clock frequency. * @host: The SDHCI host instance. * @@ -115,11 +89,6 @@ static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host) unsigned long rate, max = 0; int src; - /* note, a reset will reset the clock source */ - - sdhci_s3c_check_sclk(host); - - for (src = 0; src < MAX_BUS_CLK; src++) { rate = ourhost->clk_rates[src]; if (rate > max) @@ -206,20 +175,22 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) struct clk *clk = ourhost->clk_bus[best_src]; clk_prepare_enable(clk); - clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); - - /* turn clock off to card before changing clock source */ - writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); + if (ourhost->cur_clk >= 0) + clk_disable_unprepare( + ourhost->clk_bus[ourhost->cur_clk]); ourhost->cur_clk = best_src; host->max_clk = ourhost->clk_rates[best_src]; - - ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); - ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; - ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } + /* turn clock off to card before changing clock source */ + writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); + + ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); + ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; + ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; + writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); + /* reprogram default hardware configuration */ writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, host->ioaddr + S3C64XX_SDHCI_CONTROL4); @@ -573,6 +544,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) sc->host = host; sc->pdev = pdev; sc->pdata = pdata; + sc->cur_clk = -1; platform_set_drvdata(pdev, host); @@ -595,13 +567,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) continue; clks++; - - /* - * save current clock index to know which clock bus - * is used later in overriding functions. - */ - sc->cur_clk = ptr; - sc->clk_rates[ptr] = clk_get_rate(sc->clk_bus[ptr]); dev_info(dev, "clock source %d: %s (%ld Hz)\n", @@ -614,10 +579,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) goto err_no_busclks; } -#ifndef CONFIG_PM_RUNTIME - clk_prepare_enable(sc->clk_bus[sc->cur_clk]); -#endif - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->ioaddr = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(host->ioaddr)) { @@ -730,10 +691,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) return 0; err_req_regs: -#ifndef CONFIG_PM_RUNTIME - clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); -#endif - err_no_busclks: clk_disable_unprepare(sc->clk_io); @@ -764,9 +721,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); -#ifndef CONFIG_PM_RUNTIME - clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); -#endif clk_disable_unprepare(sc->clk_io); sdhci_free_host(host); @@ -800,7 +754,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev) ret = sdhci_runtime_suspend_host(host); - clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); + if (ourhost->cur_clk >= 0) + clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); clk_disable_unprepare(busclk); return ret; } @@ -813,7 +768,8 @@ static int sdhci_s3c_runtime_resume(struct device *dev) int ret; clk_prepare_enable(busclk); - clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]); + if (ourhost->cur_clk >= 0) + clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]); ret = sdhci_runtime_resume_host(host); return ret; }