From patchwork Fri Sep 17 09:45:01 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kim Kukjin X-Patchwork-Id: 187792 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 o8HA43Np006100 for ; Fri, 17 Sep 2010 10:04:04 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752798Ab0IQKEB (ORCPT ); Fri, 17 Sep 2010 06:04:01 -0400 Received: from ganesha.gnumonks.org ([213.95.27.120]:43919 "EHLO ganesha.gnumonks.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753163Ab0IQKEA (ORCPT ); Fri, 17 Sep 2010 06:04:00 -0400 Received: from uucp by ganesha.gnumonks.org with local-bsmtp (Exim 4.69) (envelope-from ) id 1OwXnQ-0003Kh-Af; Fri, 17 Sep 2010 12:03:56 +0200 Received: from [12.23.102.184] (helo=localhost.localdomain) by jackpot.kr.gnumonks.org with esmtp (Exim 4.69) (envelope-from ) id 1OwWoh-0000gR-U5; Fri, 17 Sep 2010 18:01:11 +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, Hyuk Lee , Jeongbae Seo , Kukjin Kim Subject: [PATCH v2 2/2] sdhci-s3c: Add support no internal clock divider in host controller Date: Fri, 17 Sep 2010 18:45:01 +0900 Message-Id: <1284716701-5140-3-git-send-email-kgene.kim@samsung.com> X-Mailer: git-send-email 1.6.2.5 In-Reply-To: <1284716701-5140-1-git-send-email-kgene.kim@samsung.com> References: <1284716701-5140-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, 17 Sep 2010 10:04:04 +0000 (UTC) diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index e6e0438..5ad5ed7 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -96,6 +96,13 @@ static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host) unsigned int rate, max; int clk; + /* + * There is only one clock source(sclk) if there is no clock divider + * in the host controller + */ + if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) + return clk_round_rate(ourhost->clk_bus[2], UINT_MAX); + /* note, a reset will reset the clock source */ sdhci_s3c_check_sclk(host); @@ -130,6 +137,15 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, if (!clksrc) return UINT_MAX; + /* + * There is only one clock source(sclk) if there is no clock divider + * in the host controller + */ + if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { + rate = clk_round_rate(clksrc, wanted); + return wanted - rate; + } + rate = clk_get_rate(clksrc); for (div = 1; div < 256; div *= 2) { @@ -159,6 +175,7 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) int best_src = 0; int src; u32 ctrl; + unsigned int timeout; /* don't bother if the clock is going off. */ if (clock == 0) @@ -204,6 +221,35 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, &ios, NULL); } + + /* + * There is only one clock source(sclk) if there is no clock divider + * in the host controller + */ + if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { + writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); + clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + + writew(SDHCI_CLOCK_INT_EN, host->ioaddr + SDHCI_CLOCK_CONTROL); + + /* Wait max 20 ms */ + timeout = 20; + while (!((sdhci_readw(host, SDHCI_CLOCK_CONTROL)) + & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + printk(KERN_ERR "%s: clock never stabilised.\n" + , mmc_hostname(host->mmc)); + return; + } + timeout--; + mdelay(1); + } + + writew(SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN, + host->ioaddr + SDHCI_CLOCK_CONTROL); + + host->clock = clock; + } } /** @@ -221,6 +267,13 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host) unsigned int delta, min = UINT_MAX; int src; + /* + * There is only one clock source(sclk) if there is no clock divider + * in the host controller + */ + if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) + return clk_round_rate(ourhost->clk_bus[2], 400000); + for (src = 0; src < MAX_BUS_CLK; src++) { delta = sdhci_s3c_consider_clock(ourhost, src, 0); if (delta == UINT_MAX) @@ -425,6 +478,13 @@ 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 need to use another method with setup a quirk. + */ + if (pdata->clk_type) + host->quirks |= SDHCI_QUIRK_NONSTANDARD_CLOCK; + /* It supports additional host capabilities if needed */ if (pdata->host_caps) host->mmc->caps |= pdata->host_caps;