From patchwork Fri Oct 8 08:46:21 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kim Kukjin X-Patchwork-Id: 240901 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o988t5Tg007056 for ; Fri, 8 Oct 2010 08:55:06 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756313Ab0JHIzF (ORCPT ); Fri, 8 Oct 2010 04:55:05 -0400 Received: from ganesha.gnumonks.org ([213.95.27.120]:34502 "EHLO ganesha.gnumonks.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755885Ab0JHIzD (ORCPT ); Fri, 8 Oct 2010 04:55:03 -0400 Received: from uucp by ganesha.gnumonks.org with local-bsmtp (Exim 4.69) (envelope-from ) id 1P48jB-00021c-BM; Fri, 08 Oct 2010 10:54:57 +0200 Received: from [12.23.102.184] (helo=localhost.localdomain) by jackpot.kr.gnumonks.org with esmtp (Exim 4.69) (envelope-from ) id 1P47zK-0005oJ-Pj; Fri, 08 Oct 2010 17:07:34 +0900 From: Kukjin Kim To: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-mmc@vger.kernel.org Cc: ben-linux@fluff.org, akpm@linux-foundation.org, cjb@laptop.org, Jeongbae Seo , Jaehoon Chung , Kukjin Kim Subject: [PATCH V3 2/2] sdhci-s3c: Add support no internal clock divider in host controller Date: Fri, 8 Oct 2010 17:46:21 +0900 Message-Id: <1286527581-24903-3-git-send-email-kgene.kim@samsung.com> X-Mailer: git-send-email 1.6.2.5 In-Reply-To: <1286527581-24903-1-git-send-email-kgene.kim@samsung.com> References: <1286527581-24903-1-git-send-email-kgene.kim@samsung.com> Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 08 Oct 2010 08:55:06 +0000 (UTC) diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index a7710f5..1720358 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -130,6 +130,15 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, if (!clksrc) return UINT_MAX; + /* + * Clock divider's step is different as 1 from that of host controller + * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL. + */ + if (ourhost->pdata->clk_type) { + rate = clk_round_rate(clksrc, wanted); + return wanted - rate; + } + rate = clk_get_rate(clksrc); for (div = 1; div < 256; div *= 2) { @@ -232,6 +241,42 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host) return min; } +/* sdhci_cmu_get_max_clk - callback to get maximum clock frequency.*/ +static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + + return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX); +} + +/* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */ +static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + + /* + * initial clock can be in the frequency range of + * 100KHz-400KHz, so we set it as max value. + */ + return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000); +} + +/* sdhci_cmu_set_clock - callback on clock change.*/ +static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + + /* don't bother if the clock is going off */ + if (clock == 0) + return; + + sdhci_s3c_set_clock(host, clock); + + clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + + host->clock = clock; +} + static struct sdhci_ops sdhci_s3c_ops = { .get_max_clock = sdhci_s3c_get_max_clk, .set_clock = sdhci_s3c_set_clock, @@ -361,6 +406,13 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) clks++; sc->clk_bus[ptr] = clk; + + /* + * save current clock index to know which clock bus + * is used later in overriding functions. + */ + sc->cur_clk = ptr; + clk_enable(clk); dev_info(dev, "clock source %d: %s (%ld Hz)\n", @@ -427,6 +479,16 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; + /* + * If controller does not have internal clock divider, + * we can use overriding functions instead of default. + */ + if (pdata->clk_type) { + sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; + sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; + sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; + } + /* It supports additional host capabilities if needed */ if (pdata->host_caps) host->mmc->caps |= pdata->host_caps;