diff options
Diffstat (limited to 'drivers/mmc/host/sunxi-mmc.c')
-rw-r--r-- | drivers/mmc/host/sunxi-mmc.c | 63 |
1 files changed, 48 insertions, 15 deletions
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 6af0a28ba37d..e8a4218b5726 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c | |||
@@ -21,8 +21,6 @@ | |||
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | 22 | ||
23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
24 | #include <linux/clk/sunxi.h> | ||
25 | |||
26 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
27 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
28 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
@@ -229,6 +227,8 @@ struct sunxi_mmc_host { | |||
229 | /* clock management */ | 227 | /* clock management */ |
230 | struct clk *clk_ahb; | 228 | struct clk *clk_ahb; |
231 | struct clk *clk_mmc; | 229 | struct clk *clk_mmc; |
230 | struct clk *clk_sample; | ||
231 | struct clk *clk_output; | ||
232 | 232 | ||
233 | /* irq */ | 233 | /* irq */ |
234 | spinlock_t lock; | 234 | spinlock_t lock; |
@@ -653,26 +653,31 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, | |||
653 | 653 | ||
654 | /* determine delays */ | 654 | /* determine delays */ |
655 | if (rate <= 400000) { | 655 | if (rate <= 400000) { |
656 | oclk_dly = 0; | 656 | oclk_dly = 180; |
657 | sclk_dly = 7; | 657 | sclk_dly = 42; |
658 | } else if (rate <= 25000000) { | 658 | } else if (rate <= 25000000) { |
659 | oclk_dly = 0; | 659 | oclk_dly = 180; |
660 | sclk_dly = 5; | 660 | sclk_dly = 75; |
661 | } else if (rate <= 50000000) { | 661 | } else if (rate <= 50000000) { |
662 | if (ios->timing == MMC_TIMING_UHS_DDR50) { | 662 | if (ios->timing == MMC_TIMING_UHS_DDR50) { |
663 | oclk_dly = 2; | 663 | oclk_dly = 60; |
664 | sclk_dly = 4; | 664 | sclk_dly = 120; |
665 | } else { | 665 | } else { |
666 | oclk_dly = 3; | 666 | oclk_dly = 90; |
667 | sclk_dly = 5; | 667 | sclk_dly = 150; |
668 | } | 668 | } |
669 | } else if (rate <= 100000000) { | ||
670 | oclk_dly = 6; | ||
671 | sclk_dly = 24; | ||
672 | } else if (rate <= 200000000) { | ||
673 | oclk_dly = 3; | ||
674 | sclk_dly = 12; | ||
669 | } else { | 675 | } else { |
670 | /* rate > 50000000 */ | 676 | return -EINVAL; |
671 | oclk_dly = 2; | ||
672 | sclk_dly = 4; | ||
673 | } | 677 | } |
674 | 678 | ||
675 | clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly); | 679 | clk_set_phase(host->clk_sample, sclk_dly); |
680 | clk_set_phase(host->clk_output, oclk_dly); | ||
676 | 681 | ||
677 | return sunxi_mmc_oclk_onoff(host, 1); | 682 | return sunxi_mmc_oclk_onoff(host, 1); |
678 | } | 683 | } |
@@ -913,6 +918,18 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, | |||
913 | return PTR_ERR(host->clk_mmc); | 918 | return PTR_ERR(host->clk_mmc); |
914 | } | 919 | } |
915 | 920 | ||
921 | host->clk_output = devm_clk_get(&pdev->dev, "output"); | ||
922 | if (IS_ERR(host->clk_output)) { | ||
923 | dev_err(&pdev->dev, "Could not get output clock\n"); | ||
924 | return PTR_ERR(host->clk_output); | ||
925 | } | ||
926 | |||
927 | host->clk_sample = devm_clk_get(&pdev->dev, "sample"); | ||
928 | if (IS_ERR(host->clk_sample)) { | ||
929 | dev_err(&pdev->dev, "Could not get sample clock\n"); | ||
930 | return PTR_ERR(host->clk_sample); | ||
931 | } | ||
932 | |||
916 | host->reset = devm_reset_control_get(&pdev->dev, "ahb"); | 933 | host->reset = devm_reset_control_get(&pdev->dev, "ahb"); |
917 | 934 | ||
918 | ret = clk_prepare_enable(host->clk_ahb); | 935 | ret = clk_prepare_enable(host->clk_ahb); |
@@ -927,11 +944,23 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, | |||
927 | goto error_disable_clk_ahb; | 944 | goto error_disable_clk_ahb; |
928 | } | 945 | } |
929 | 946 | ||
947 | ret = clk_prepare_enable(host->clk_output); | ||
948 | if (ret) { | ||
949 | dev_err(&pdev->dev, "Enable output clk err %d\n", ret); | ||
950 | goto error_disable_clk_mmc; | ||
951 | } | ||
952 | |||
953 | ret = clk_prepare_enable(host->clk_sample); | ||
954 | if (ret) { | ||
955 | dev_err(&pdev->dev, "Enable sample clk err %d\n", ret); | ||
956 | goto error_disable_clk_output; | ||
957 | } | ||
958 | |||
930 | if (!IS_ERR(host->reset)) { | 959 | if (!IS_ERR(host->reset)) { |
931 | ret = reset_control_deassert(host->reset); | 960 | ret = reset_control_deassert(host->reset); |
932 | if (ret) { | 961 | if (ret) { |
933 | dev_err(&pdev->dev, "reset err %d\n", ret); | 962 | dev_err(&pdev->dev, "reset err %d\n", ret); |
934 | goto error_disable_clk_mmc; | 963 | goto error_disable_clk_sample; |
935 | } | 964 | } |
936 | } | 965 | } |
937 | 966 | ||
@@ -950,6 +979,10 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, | |||
950 | error_assert_reset: | 979 | error_assert_reset: |
951 | if (!IS_ERR(host->reset)) | 980 | if (!IS_ERR(host->reset)) |
952 | reset_control_assert(host->reset); | 981 | reset_control_assert(host->reset); |
982 | error_disable_clk_sample: | ||
983 | clk_disable_unprepare(host->clk_sample); | ||
984 | error_disable_clk_output: | ||
985 | clk_disable_unprepare(host->clk_output); | ||
953 | error_disable_clk_mmc: | 986 | error_disable_clk_mmc: |
954 | clk_disable_unprepare(host->clk_mmc); | 987 | clk_disable_unprepare(host->clk_mmc); |
955 | error_disable_clk_ahb: | 988 | error_disable_clk_ahb: |