diff mbox

[13/14] mmc: sunxi: Convert MMC driver to the standard clock phase API

Message ID 1405588134-2396-14-git-send-email-maxime.ripard@free-electrons.com (mailing list archive)
State New, archived
Headers show

Commit Message

Maxime Ripard July 17, 2014, 9:08 a.m. UTC
Now that we have proper support to use the generic phase API in our clock
driver, switch the MMC driver to use it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 .../devicetree/bindings/mmc/sunxi-mmc.txt          |  8 +--
 drivers/mmc/host/sunxi-mmc.c                       | 72 +++++++++++++++-------
 2 files changed, 53 insertions(+), 27 deletions(-)

Comments

Ulf Hansson Aug. 13, 2014, 8:44 a.m. UTC | #1
On 17 July 2014 11:08, Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> Now that we have proper support to use the generic phase API in our clock
> driver, switch the MMC driver to use it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

I see there are a dependency of the clk patches with the mmc patch. I
suppose it's best to take this set through Mike's clk tree then.

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>  .../devicetree/bindings/mmc/sunxi-mmc.txt          |  8 +--
>  drivers/mmc/host/sunxi-mmc.c                       | 72 +++++++++++++++-------
>  2 files changed, 53 insertions(+), 27 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
> index 91b3a3467150..4bf41d833804 100644
> --- a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
> +++ b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
> @@ -10,8 +10,8 @@ Absolute maximum transfer rate is 200MB/s
>  Required properties:
>   - compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc"
>   - reg : mmc controller base registers
> - - clocks : a list with 2 phandle + clock specifier pairs
> - - clock-names : must contain "ahb" and "mmc"
> + - clocks : a list with 4 phandle + clock specifier pairs
> + - clock-names : must contain "ahb", "mmc", "output" and "sample"
>   - interrupts : mmc controller interrupt
>
>  Optional properties:
> @@ -25,8 +25,8 @@ Examples:
>         mmc0: mmc@01c0f000 {
>                 compatible = "allwinner,sun5i-a13-mmc";
>                 reg = <0x01c0f000 0x1000>;
> -               clocks = <&ahb_gates 8>, <&mmc0_clk>;
> -               clock-names = "ahb", "mod";
> +               clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>;
> +               clock-names = "ahb", "mod", "output", "sample";
>                 interrupts = <0 32 4>;
>                 status = "disabled";
>         };
> diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
> index 024f67c98cdc..8719cefa590d 100644
> --- a/drivers/mmc/host/sunxi-mmc.c
> +++ b/drivers/mmc/host/sunxi-mmc.c
> @@ -22,7 +22,6 @@
>
>  #include <linux/clk.h>
>  #include <linux/clk-private.h>
> -#include <linux/clk/sunxi.h>
>
>  #include <linux/gpio.h>
>  #include <linux/platform_device.h>
> @@ -230,6 +229,8 @@ struct sunxi_mmc_host {
>         /* clock management */
>         struct clk      *clk_ahb;
>         struct clk      *clk_mmc;
> +       struct clk      *clk_sample;
> +       struct clk      *clk_output;
>
>         /* irq */
>         spinlock_t      lock;
> @@ -617,7 +618,7 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
>  static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
>                                   struct mmc_ios *ios)
>  {
> -       u32 rate, oclk_dly, rval, sclk_dly, src_clk;
> +       u32 rate, oclk_dly, rval, sclk_dly;
>         int ret;
>
>         rate = clk_round_rate(host->clk_mmc, ios->clock);
> @@ -643,34 +644,31 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
>
>         /* determine delays */
>         if (rate <= 400000) {
> -               oclk_dly = 0;
> -               sclk_dly = 7;
> +               oclk_dly = 180;
> +               sclk_dly = 42;
>         } else if (rate <= 25000000) {
> -               oclk_dly = 0;
> -               sclk_dly = 5;
> +               oclk_dly = 180;
> +               sclk_dly = 75;
>         } else if (rate <= 50000000) {
>                 if (ios->timing == MMC_TIMING_UHS_DDR50) {
> -                       oclk_dly = 2;
> -                       sclk_dly = 4;
> +                       oclk_dly = 60;
> +                       sclk_dly = 120;
>                 } else {
> -                       oclk_dly = 3;
> -                       sclk_dly = 5;
> +                       oclk_dly = 90;
> +                       sclk_dly = 150;
>                 }
> +       } else if (rate <= 100000000) {
> +               oclk_dly = 6;
> +               sclk_dly = 24;
> +       } else if (rate <= 200000000) {
> +               oclk_dly = 3;
> +               sclk_dly = 12;
>         } else {
> -               /* rate > 50000000 */
> -               oclk_dly = 2;
> -               sclk_dly = 4;
> +               return -EINVAL;
>         }
>
> -       src_clk = clk_get_rate(clk_get_parent(host->clk_mmc));
> -       if (src_clk >= 300000000 && src_clk <= 400000000) {
> -               if (oclk_dly)
> -                       oclk_dly--;
> -               if (sclk_dly)
> -                       sclk_dly--;
> -       }
> -
> -       clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly);
> +       clk_set_phase(host->clk_sample, sclk_dly);
> +       clk_set_phase(host->clk_output, oclk_dly);
>
>         return sunxi_mmc_oclk_onoff(host, 1);
>  }
> @@ -909,6 +907,18 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
>                 return PTR_ERR(host->clk_mmc);
>         }
>
> +       host->clk_output = devm_clk_get(&pdev->dev, "output");
> +       if (IS_ERR(host->clk_output)) {
> +               dev_err(&pdev->dev, "Could not get output clock\n");
> +               return PTR_ERR(host->clk_output);
> +       }
> +
> +       host->clk_sample = devm_clk_get(&pdev->dev, "sample");
> +       if (IS_ERR(host->clk_sample)) {
> +               dev_err(&pdev->dev, "Could not get sample clock\n");
> +               return PTR_ERR(host->clk_sample);
> +       }
> +
>         host->reset = devm_reset_control_get(&pdev->dev, "ahb");
>
>         ret = clk_prepare_enable(host->clk_ahb);
> @@ -923,11 +933,23 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
>                 goto error_disable_clk_ahb;
>         }
>
> +       ret = clk_prepare_enable(host->clk_output);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Enable output clk err %d\n", ret);
> +               goto error_disable_clk_mmc;
> +       }
> +
> +       ret = clk_prepare_enable(host->clk_sample);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Enable sample clk err %d\n", ret);
> +               goto error_disable_clk_output;
> +       }
> +
>         if (!IS_ERR(host->reset)) {
>                 ret = reset_control_deassert(host->reset);
>                 if (ret) {
>                         dev_err(&pdev->dev, "reset err %d\n", ret);
> -                       goto error_disable_clk_mmc;
> +                       goto error_disable_clk_sample;
>                 }
>         }
>
> @@ -946,6 +968,10 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
>  error_assert_reset:
>         if (!IS_ERR(host->reset))
>                 reset_control_assert(host->reset);
> +error_disable_clk_sample:
> +       clk_disable_unprepare(host->clk_sample);
> +error_disable_clk_output:
> +       clk_disable_unprepare(host->clk_output);
>  error_disable_clk_mmc:
>         clk_disable_unprepare(host->clk_mmc);
>  error_disable_clk_ahb:
> --
> 2.0.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
index 91b3a3467150..4bf41d833804 100644
--- a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
@@ -10,8 +10,8 @@  Absolute maximum transfer rate is 200MB/s
 Required properties:
  - compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc"
  - reg : mmc controller base registers
- - clocks : a list with 2 phandle + clock specifier pairs
- - clock-names : must contain "ahb" and "mmc"
+ - clocks : a list with 4 phandle + clock specifier pairs
+ - clock-names : must contain "ahb", "mmc", "output" and "sample"
  - interrupts : mmc controller interrupt
 
 Optional properties:
@@ -25,8 +25,8 @@  Examples:
 	mmc0: mmc@01c0f000 {
 		compatible = "allwinner,sun5i-a13-mmc";
 		reg = <0x01c0f000 0x1000>;
-		clocks = <&ahb_gates 8>, <&mmc0_clk>;
-		clock-names = "ahb", "mod";
+		clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>;
+		clock-names = "ahb", "mod", "output", "sample";
 		interrupts = <0 32 4>;
 		status = "disabled";
 	};
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index 024f67c98cdc..8719cefa590d 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -22,7 +22,6 @@ 
 
 #include <linux/clk.h>
 #include <linux/clk-private.h>
-#include <linux/clk/sunxi.h>
 
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
@@ -230,6 +229,8 @@  struct sunxi_mmc_host {
 	/* clock management */
 	struct clk	*clk_ahb;
 	struct clk	*clk_mmc;
+	struct clk	*clk_sample;
+	struct clk	*clk_output;
 
 	/* irq */
 	spinlock_t	lock;
@@ -617,7 +618,7 @@  static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
 static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
 				  struct mmc_ios *ios)
 {
-	u32 rate, oclk_dly, rval, sclk_dly, src_clk;
+	u32 rate, oclk_dly, rval, sclk_dly;
 	int ret;
 
 	rate = clk_round_rate(host->clk_mmc, ios->clock);
@@ -643,34 +644,31 @@  static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
 
 	/* determine delays */
 	if (rate <= 400000) {
-		oclk_dly = 0;
-		sclk_dly = 7;
+		oclk_dly = 180;
+		sclk_dly = 42;
 	} else if (rate <= 25000000) {
-		oclk_dly = 0;
-		sclk_dly = 5;
+		oclk_dly = 180;
+		sclk_dly = 75;
 	} else if (rate <= 50000000) {
 		if (ios->timing == MMC_TIMING_UHS_DDR50) {
-			oclk_dly = 2;
-			sclk_dly = 4;
+			oclk_dly = 60;
+			sclk_dly = 120;
 		} else {
-			oclk_dly = 3;
-			sclk_dly = 5;
+			oclk_dly = 90;
+			sclk_dly = 150;
 		}
+	} else if (rate <= 100000000) {
+		oclk_dly = 6;
+		sclk_dly = 24;
+	} else if (rate <= 200000000) {
+		oclk_dly = 3;
+		sclk_dly = 12;
 	} else {
-		/* rate > 50000000 */
-		oclk_dly = 2;
-		sclk_dly = 4;
+		return -EINVAL;
 	}
 
-	src_clk = clk_get_rate(clk_get_parent(host->clk_mmc));
-	if (src_clk >= 300000000 && src_clk <= 400000000) {
-		if (oclk_dly)
-			oclk_dly--;
-		if (sclk_dly)
-			sclk_dly--;
-	}
-
-	clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly);
+	clk_set_phase(host->clk_sample, sclk_dly);
+	clk_set_phase(host->clk_output, oclk_dly);
 
 	return sunxi_mmc_oclk_onoff(host, 1);
 }
@@ -909,6 +907,18 @@  static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
 		return PTR_ERR(host->clk_mmc);
 	}
 
+	host->clk_output = devm_clk_get(&pdev->dev, "output");
+	if (IS_ERR(host->clk_output)) {
+		dev_err(&pdev->dev, "Could not get output clock\n");
+		return PTR_ERR(host->clk_output);
+	}
+
+	host->clk_sample = devm_clk_get(&pdev->dev, "sample");
+	if (IS_ERR(host->clk_sample)) {
+		dev_err(&pdev->dev, "Could not get sample clock\n");
+		return PTR_ERR(host->clk_sample);
+	}
+
 	host->reset = devm_reset_control_get(&pdev->dev, "ahb");
 
 	ret = clk_prepare_enable(host->clk_ahb);
@@ -923,11 +933,23 @@  static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
 		goto error_disable_clk_ahb;
 	}
 
+	ret = clk_prepare_enable(host->clk_output);
+	if (ret) {
+		dev_err(&pdev->dev, "Enable output clk err %d\n", ret);
+		goto error_disable_clk_mmc;
+	}
+
+	ret = clk_prepare_enable(host->clk_sample);
+	if (ret) {
+		dev_err(&pdev->dev, "Enable sample clk err %d\n", ret);
+		goto error_disable_clk_output;
+	}
+
 	if (!IS_ERR(host->reset)) {
 		ret = reset_control_deassert(host->reset);
 		if (ret) {
 			dev_err(&pdev->dev, "reset err %d\n", ret);
-			goto error_disable_clk_mmc;
+			goto error_disable_clk_sample;
 		}
 	}
 
@@ -946,6 +968,10 @@  static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
 error_assert_reset:
 	if (!IS_ERR(host->reset))
 		reset_control_assert(host->reset);
+error_disable_clk_sample:
+	clk_disable_unprepare(host->clk_sample);
+error_disable_clk_output:
+	clk_disable_unprepare(host->clk_output);
 error_disable_clk_mmc:
 	clk_disable_unprepare(host->clk_mmc);
 error_disable_clk_ahb: