Thread (13 messages) 13 messages, 4 authors, 2014-08-13

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

From: Ulf Hansson <hidden>
Date: 2014-08-13 08:44:42
Also in: linux-arm-kernel, linux-mmc

On 17 July 2014 11:08, Maxime Ripard [off-list ref] 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 <redacted>
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 <redacted>

Kind regards
Uffe
quoted hunk ↗ jump to hunk
---
 .../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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help