Message ID | 1405588134-2396-14-git-send-email-maxime.ripard@free-electrons.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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 --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:
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(-)