All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting
@ 2017-07-13  8:04 Quentin Schulz
  2017-07-13  8:04 ` [PATCH v3 2/2] mmc: sdhci-of-at91: set clocks and presets after resume from deepest PM Quentin Schulz
  2017-07-13 10:06 ` [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting Ulf Hansson
  0 siblings, 2 replies; 4+ messages in thread
From: Quentin Schulz @ 2017-07-13  8:04 UTC (permalink / raw)
  To: adrian.hunter, ludovic.desroches, ulf.hansson
  Cc: Quentin Schulz, linux-mmc, linux-kernel, thomas.petazzoni,
	alexandre.belloni, nicolas.ferre, cyrille.pitchen

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 <quentin.schulz@free-electrons.com>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-of-at91.c | 147 ++++++++++++++++++++++-----------------
 1 file changed, 82 insertions(+), 65 deletions(-)

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;
 }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v3 2/2] mmc: sdhci-of-at91: set clocks and presets after resume from deepest PM
  2017-07-13  8:04 [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting Quentin Schulz
@ 2017-07-13  8:04 ` Quentin Schulz
  2017-07-13 10:06   ` Ulf Hansson
  2017-07-13 10:06 ` [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting Ulf Hansson
  1 sibling, 1 reply; 4+ messages in thread
From: Quentin Schulz @ 2017-07-13  8:04 UTC (permalink / raw)
  To: adrian.hunter, ludovic.desroches, ulf.hansson
  Cc: Quentin Schulz, linux-mmc, linux-kernel, thomas.petazzoni,
	alexandre.belloni, nicolas.ferre, cyrille.pitchen

This adds deepest (Backup+Self-Refresh) PM support to the ATMEL SAMA5D2
SoC's SDHCI controller.

When resuming from deepest state, it is required to restore preset
registers as the registers are lost since VDD core has been shut down
when entering deepest state on the SAMA5D2. The clocks need to be
reconfigured as well.

The other registers and init process are taken care of by the SDHCI
core.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---

v3:
  - pm_runtime_force_suspend before setting restore_needed flag,

v2:
  - use runtime_resume as system_resume,
  - set a flag to tell when restoring presets is needed,
  - use a flag to tell runtime_resume to restore presets,
  - surround sdhci_at91_suspend with ifdef CONFIG_PM_SLEEP instead of CONFIG_PM,

 drivers/mmc/host/sdhci-of-at91.c | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index fb8c6011f13d..88e9b5f35a62 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -41,6 +41,7 @@ struct sdhci_at91_priv {
 	struct clk *hclock;
 	struct clk *gck;
 	struct clk *mainck;
+	bool restore_needed;
 };
 
 static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
@@ -206,6 +207,22 @@ static int sdhci_at91_set_clks_presets(struct device *dev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sdhci_at91_suspend(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;
+
+	ret = pm_runtime_force_suspend(dev);
+
+	priv->restore_needed = true;
+
+	return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
 #ifdef CONFIG_PM
 static int sdhci_at91_runtime_suspend(struct device *dev)
 {
@@ -233,6 +250,15 @@ static int sdhci_at91_runtime_resume(struct device *dev)
 	struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
 	int ret;
 
+	if (priv->restore_needed) {
+		ret = sdhci_at91_set_clks_presets(dev);
+		if (ret)
+			return ret;
+
+		priv->restore_needed = false;
+		goto out;
+	}
+
 	ret = clk_prepare_enable(priv->mainck);
 	if (ret) {
 		dev_err(dev, "can't enable mainck\n");
@@ -251,13 +277,13 @@ static int sdhci_at91_runtime_resume(struct device *dev)
 		return ret;
 	}
 
+out:
 	return sdhci_runtime_resume_host(host);
 }
 #endif /* CONFIG_PM */
 
 static const struct dev_pm_ops sdhci_at91_dev_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-				pm_runtime_force_resume)
+	SET_SYSTEM_SLEEP_PM_OPS(sdhci_at91_suspend, pm_runtime_force_resume)
 	SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend,
 			   sdhci_at91_runtime_resume,
 			   NULL)
@@ -306,6 +332,8 @@ static int sdhci_at91_probe(struct platform_device *pdev)
 	if (ret)
 		goto sdhci_pltfm_free;
 
+	priv->restore_needed = false;
+
 	ret = mmc_of_parse(host->mmc);
 	if (ret)
 		goto clocks_disable_unprepare;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting
  2017-07-13  8:04 [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting Quentin Schulz
  2017-07-13  8:04 ` [PATCH v3 2/2] mmc: sdhci-of-at91: set clocks and presets after resume from deepest PM Quentin Schulz
@ 2017-07-13 10:06 ` Ulf Hansson
  1 sibling, 0 replies; 4+ messages in thread
From: Ulf Hansson @ 2017-07-13 10:06 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: Adrian Hunter, Ludovic Desroches, linux-mmc, linux-kernel,
	Thomas Petazzoni, Alexandre Belloni, nicolas.ferre,
	cyrille.pitchen

On 13 July 2017 at 10:04, Quentin Schulz
<quentin.schulz@free-electrons.com> wrote:
> 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 <quentin.schulz@free-electrons.com>
> Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> Acked-by: Adrian Hunter <adrian.hunter@intel.com>

Thanks, applied for next!

Kind regards
Uffe

> ---
>  drivers/mmc/host/sdhci-of-at91.c | 147 ++++++++++++++++++++++-----------------
>  1 file changed, 82 insertions(+), 65 deletions(-)
>
> 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;
>  }
> --
> 2.11.0
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 2/2] mmc: sdhci-of-at91: set clocks and presets after resume from deepest PM
  2017-07-13  8:04 ` [PATCH v3 2/2] mmc: sdhci-of-at91: set clocks and presets after resume from deepest PM Quentin Schulz
@ 2017-07-13 10:06   ` Ulf Hansson
  0 siblings, 0 replies; 4+ messages in thread
From: Ulf Hansson @ 2017-07-13 10:06 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: Adrian Hunter, Ludovic Desroches, linux-mmc, linux-kernel,
	Thomas Petazzoni, Alexandre Belloni, nicolas.ferre,
	cyrille.pitchen

On 13 July 2017 at 10:04, Quentin Schulz
<quentin.schulz@free-electrons.com> wrote:
> This adds deepest (Backup+Self-Refresh) PM support to the ATMEL SAMA5D2
> SoC's SDHCI controller.
>
> When resuming from deepest state, it is required to restore preset
> registers as the registers are lost since VDD core has been shut down
> when entering deepest state on the SAMA5D2. The clocks need to be
> reconfigured as well.
>
> The other registers and init process are taken care of by the SDHCI
> core.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
> Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>

Thanks, applied for next!

Kind regards
Uffe


> ---
>
> v3:
>   - pm_runtime_force_suspend before setting restore_needed flag,
>
> v2:
>   - use runtime_resume as system_resume,
>   - set a flag to tell when restoring presets is needed,
>   - use a flag to tell runtime_resume to restore presets,
>   - surround sdhci_at91_suspend with ifdef CONFIG_PM_SLEEP instead of CONFIG_PM,
>
>  drivers/mmc/host/sdhci-of-at91.c | 32 ++++++++++++++++++++++++++++++--
>  1 file changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
> index fb8c6011f13d..88e9b5f35a62 100644
> --- a/drivers/mmc/host/sdhci-of-at91.c
> +++ b/drivers/mmc/host/sdhci-of-at91.c
> @@ -41,6 +41,7 @@ struct sdhci_at91_priv {
>         struct clk *hclock;
>         struct clk *gck;
>         struct clk *mainck;
> +       bool restore_needed;
>  };
>
>  static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
> @@ -206,6 +207,22 @@ static int sdhci_at91_set_clks_presets(struct device *dev)
>         return 0;
>  }
>
> +#ifdef CONFIG_PM_SLEEP
> +static int sdhci_at91_suspend(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;
> +
> +       ret = pm_runtime_force_suspend(dev);
> +
> +       priv->restore_needed = true;
> +
> +       return ret;
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
>  #ifdef CONFIG_PM
>  static int sdhci_at91_runtime_suspend(struct device *dev)
>  {
> @@ -233,6 +250,15 @@ static int sdhci_at91_runtime_resume(struct device *dev)
>         struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
>         int ret;
>
> +       if (priv->restore_needed) {
> +               ret = sdhci_at91_set_clks_presets(dev);
> +               if (ret)
> +                       return ret;
> +
> +               priv->restore_needed = false;
> +               goto out;
> +       }
> +
>         ret = clk_prepare_enable(priv->mainck);
>         if (ret) {
>                 dev_err(dev, "can't enable mainck\n");
> @@ -251,13 +277,13 @@ static int sdhci_at91_runtime_resume(struct device *dev)
>                 return ret;
>         }
>
> +out:
>         return sdhci_runtime_resume_host(host);
>  }
>  #endif /* CONFIG_PM */
>
>  static const struct dev_pm_ops sdhci_at91_dev_pm_ops = {
> -       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> -                               pm_runtime_force_resume)
> +       SET_SYSTEM_SLEEP_PM_OPS(sdhci_at91_suspend, pm_runtime_force_resume)
>         SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend,
>                            sdhci_at91_runtime_resume,
>                            NULL)
> @@ -306,6 +332,8 @@ static int sdhci_at91_probe(struct platform_device *pdev)
>         if (ret)
>                 goto sdhci_pltfm_free;
>
> +       priv->restore_needed = false;
> +
>         ret = mmc_of_parse(host->mmc);
>         if (ret)
>                 goto clocks_disable_unprepare;
> --
> 2.11.0
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-07-13 10:06 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-13  8:04 [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting Quentin Schulz
2017-07-13  8:04 ` [PATCH v3 2/2] mmc: sdhci-of-at91: set clocks and presets after resume from deepest PM Quentin Schulz
2017-07-13 10:06   ` Ulf Hansson
2017-07-13 10:06 ` [PATCH v3 1/2] mmc: sdhci-of-at91: factor out clks and presets setting Ulf Hansson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.