From patchwork Thu Jul 13 08:04:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Schulz X-Patchwork-Id: 107571 Delivered-To: patch@linaro.org Received: by 10.140.101.44 with SMTP id t41csp1895599qge; Thu, 13 Jul 2017 01:05:08 -0700 (PDT) X-Received: by 10.99.2.69 with SMTP id 66mr7903603pgc.61.1499933108570; Thu, 13 Jul 2017 01:05:08 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1499933108; cv=none; d=google.com; s=arc-20160816; b=SogadEpTtbqCDIpK5eAXgF/C+b14jfsggx5aSXYiQfcDdQk28ASoPqfO9MKxmWhcBe /JcC/ARlS28L7lPmJfjP4YMoWwYyyCwGx1r+XRv2KXLO0WjI5rVPk69khmjZ9SdOgOAA fpjYZ+8x0VuGdFu00gyQsqjuPEPYuaN2zlkk16izEOwVRc44OM+uJS05N1rAl4IBl5rK D6icKxDrqGYXDhMKmXSL6FQXrGE4AjD+Z64sRygTredU7IuJVOSWBIy/hKIsYza/4Np4 iwlTQsKyuKSvRkyrTf2vyG1HOy+7wBlrByl818LVIhvlXwRvD+m9cPcq0gi5f6h/+vyQ rTrQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=UCj1rIH/OUiQ9KjhYWRPIWQ9gSZ2xMGFXBVxuAN0YrY=; b=oPM1AT3SeviAV94hQlnBR3JkYWtCLSYkgQ+hHqeMImZ0rdD5QnZ0Zg2NTw0EusTOsu Pq5awkRzjNUws8l9aa7hLe8RlchoBcC+Zdf+wA+AtFscaY7QAduYopBjpa3eMs583zy1 cDZFu7hihjlcUHfwSMiaUih77IGeOoQoLw+yPSlAq3GsMFfv7So1SLUVOOTzF4dV94oR 3TL8vtkFhXBrw5CH2qEExOhszisdrgvPzJcC80FtSAAyJv6NkwfgHH7xk7GfbK5iFATX Z2BcuJp3zzWX64SZzyTUK/aiAkL8pZFqpY6mE5rkVoxsCyNYhHoy7qoExYS2/jHg7BPp tjew== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o12si3752152pgr.454.2017.07.13.01.05.08; Thu, 13 Jul 2017 01:05:08 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751319AbdGMIE4 (ORCPT + 25 others); Thu, 13 Jul 2017 04:04:56 -0400 Received: from mail.free-electrons.com ([62.4.15.54]:49244 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751029AbdGMIEw (ORCPT ); Thu, 13 Jul 2017 04:04:52 -0400 Received: by mail.free-electrons.com (Postfix, from userid 110) id F3DAE20881; Thu, 13 Jul 2017 10:04:48 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost.localdomain (LStLambert-657-1-97-87.w90-63.abo.wanadoo.fr [90.63.216.87]) by mail.free-electrons.com (Postfix) with ESMTPSA id C682C22005; Thu, 13 Jul 2017 10:04:30 +0200 (CEST) From: Quentin Schulz To: adrian.hunter@intel.com, ludovic.desroches@microchip.com, ulf.hansson@linaro.org Cc: Quentin Schulz , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@free-electrons.com, alexandre.belloni@free-electrons.com, nicolas.ferre@microchip.com, cyrille.pitchen@wedev4u.fr Subject: [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting Date: Thu, 13 Jul 2017 10:04:17 +0200 Message-Id: <20170713080418.12048-1-quentin.schulz@free-electrons.com> X-Mailer: git-send-email 2.11.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The setting of clocks and presets is currently done in probe only but once deep PM support is added, it'll be needed in the resume function. Let's create a function for this setting. Signed-off-by: Quentin Schulz Acked-by: Ludovic Desroches Acked-by: Adrian Hunter --- drivers/mmc/host/sdhci-of-at91.c | 147 ++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 65 deletions(-) -- 2.11.0 diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 7611fd679f1a..fb8c6011f13d 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -128,6 +128,84 @@ static const struct of_device_id sdhci_at91_dt_match[] = { }; MODULE_DEVICE_TABLE(of, sdhci_at91_dt_match); +static int sdhci_at91_set_clks_presets(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host); + int ret; + unsigned int caps0, caps1; + unsigned int clk_base, clk_mul; + unsigned int gck_rate, real_gck_rate; + unsigned int preset_div; + + /* + * The mult clock is provided by as a generated clock by the PMC + * controller. In order to set the rate of gck, we have to get the + * base clock rate and the clock mult from capabilities. + */ + clk_prepare_enable(priv->hclock); + caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES); + caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1); + clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; + clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; + gck_rate = clk_base * 1000000 * (clk_mul + 1); + ret = clk_set_rate(priv->gck, gck_rate); + if (ret < 0) { + dev_err(dev, "failed to set gck"); + clk_disable_unprepare(priv->hclock); + return ret; + } + /* + * We need to check if we have the requested rate for gck because in + * some cases this rate could be not supported. If it happens, the rate + * is the closest one gck can provide. We have to update the value + * of clk mul. + */ + real_gck_rate = clk_get_rate(priv->gck); + if (real_gck_rate != gck_rate) { + clk_mul = real_gck_rate / (clk_base * 1000000) - 1; + caps1 &= (~SDHCI_CLOCK_MUL_MASK); + caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & + SDHCI_CLOCK_MUL_MASK); + /* Set capabilities in r/w mode. */ + writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, + host->ioaddr + SDMMC_CACR); + writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1); + /* Set capabilities in ro mode. */ + writel(0, host->ioaddr + SDMMC_CACR); + dev_info(dev, "update clk mul to %u as gck rate is %u Hz\n", + clk_mul, real_gck_rate); + } + + /* + * We have to set preset values because it depends on the clk_mul + * value. Moreover, SDR104 is supported in a degraded mode since the + * maximum sd clock value is 120 MHz instead of 208 MHz. For that + * reason, we need to use presets to support SDR104. + */ + preset_div = DIV_ROUND_UP(real_gck_rate, 24000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR12); + preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR25); + preset_div = DIV_ROUND_UP(real_gck_rate, 100000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR50); + preset_div = DIV_ROUND_UP(real_gck_rate, 120000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR104); + preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_DDR50); + + clk_prepare_enable(priv->mainck); + clk_prepare_enable(priv->gck); + + return 0; +} + #ifdef CONFIG_PM static int sdhci_at91_runtime_suspend(struct device *dev) { @@ -192,11 +270,7 @@ static int sdhci_at91_probe(struct platform_device *pdev) struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_at91_priv *priv; - unsigned int caps0, caps1; - unsigned int clk_base, clk_mul; - unsigned int gck_rate, real_gck_rate; int ret; - unsigned int preset_div; match = of_match_device(sdhci_at91_dt_match, &pdev->dev); if (!match) @@ -228,66 +302,9 @@ static int sdhci_at91_probe(struct platform_device *pdev) return PTR_ERR(priv->gck); } - /* - * The mult clock is provided by as a generated clock by the PMC - * controller. In order to set the rate of gck, we have to get the - * base clock rate and the clock mult from capabilities. - */ - clk_prepare_enable(priv->hclock); - caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES); - caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1); - clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; - clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; - gck_rate = clk_base * 1000000 * (clk_mul + 1); - ret = clk_set_rate(priv->gck, gck_rate); - if (ret < 0) { - dev_err(&pdev->dev, "failed to set gck"); - goto hclock_disable_unprepare; - } - /* - * We need to check if we have the requested rate for gck because in - * some cases this rate could be not supported. If it happens, the rate - * is the closest one gck can provide. We have to update the value - * of clk mul. - */ - real_gck_rate = clk_get_rate(priv->gck); - if (real_gck_rate != gck_rate) { - clk_mul = real_gck_rate / (clk_base * 1000000) - 1; - caps1 &= (~SDHCI_CLOCK_MUL_MASK); - caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK); - /* Set capabilities in r/w mode. */ - writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR); - writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1); - /* Set capabilities in ro mode. */ - writel(0, host->ioaddr + SDMMC_CACR); - dev_info(&pdev->dev, "update clk mul to %u as gck rate is %u Hz\n", - clk_mul, real_gck_rate); - } - - /* - * We have to set preset values because it depends on the clk_mul - * value. Moreover, SDR104 is supported in a degraded mode since the - * maximum sd clock value is 120 MHz instead of 208 MHz. For that - * reason, we need to use presets to support SDR104. - */ - preset_div = DIV_ROUND_UP(real_gck_rate, 24000000) - 1; - writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, - host->ioaddr + SDHCI_PRESET_FOR_SDR12); - preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; - writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, - host->ioaddr + SDHCI_PRESET_FOR_SDR25); - preset_div = DIV_ROUND_UP(real_gck_rate, 100000000) - 1; - writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, - host->ioaddr + SDHCI_PRESET_FOR_SDR50); - preset_div = DIV_ROUND_UP(real_gck_rate, 120000000) - 1; - writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, - host->ioaddr + SDHCI_PRESET_FOR_SDR104); - preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; - writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, - host->ioaddr + SDHCI_PRESET_FOR_DDR50); - - clk_prepare_enable(priv->mainck); - clk_prepare_enable(priv->gck); + ret = sdhci_at91_set_clks_presets(&pdev->dev); + if (ret) + goto sdhci_pltfm_free; ret = mmc_of_parse(host->mmc); if (ret) @@ -335,8 +352,8 @@ static int sdhci_at91_probe(struct platform_device *pdev) clocks_disable_unprepare: clk_disable_unprepare(priv->gck); clk_disable_unprepare(priv->mainck); -hclock_disable_unprepare: clk_disable_unprepare(priv->hclock); +sdhci_pltfm_free: sdhci_pltfm_free(pdev); return ret; }