diff options
Diffstat (limited to 'drivers/mmc/host/dw_mmc-pltfm.c')
-rw-r--r-- | drivers/mmc/host/dw_mmc-pltfm.c | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index d4a47a9f5584..b547f7ab18bd 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c | |||
@@ -21,17 +21,67 @@ | |||
21 | #include <linux/mmc/mmc.h> | 21 | #include <linux/mmc/mmc.h> |
22 | #include <linux/mmc/dw_mmc.h> | 22 | #include <linux/mmc/dw_mmc.h> |
23 | #include <linux/of.h> | 23 | #include <linux/of.h> |
24 | #include <linux/clk.h> | ||
24 | 25 | ||
25 | #include "dw_mmc.h" | 26 | #include "dw_mmc.h" |
26 | #include "dw_mmc-pltfm.h" | 27 | #include "dw_mmc-pltfm.h" |
27 | 28 | ||
29 | #define RK3288_CLKGEN_DIV 2 | ||
30 | |||
28 | static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr) | 31 | static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr) |
29 | { | 32 | { |
30 | *cmdr |= SDMMC_CMD_USE_HOLD_REG; | 33 | *cmdr |= SDMMC_CMD_USE_HOLD_REG; |
31 | } | 34 | } |
32 | 35 | ||
33 | static const struct dw_mci_drv_data rockchip_drv_data = { | 36 | static int dw_mci_rk3288_setup_clock(struct dw_mci *host) |
37 | { | ||
38 | host->bus_hz /= RK3288_CLKGEN_DIV; | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) | ||
44 | { | ||
45 | int ret; | ||
46 | unsigned int cclkin; | ||
47 | u32 bus_hz; | ||
48 | |||
49 | /* | ||
50 | * cclkin: source clock of mmc controller. | ||
51 | * bus_hz: card interface clock generated by CLKGEN. | ||
52 | * bus_hz = cclkin / RK3288_CLKGEN_DIV; | ||
53 | * ios->clock = (div == 0) ? bus_hz : (bus_hz / (2 * div)) | ||
54 | * | ||
55 | * Note: div can only be 0 or 1 | ||
56 | * if DDR50 8bit mode(only emmc work in 8bit mode), | ||
57 | * div must be set 1 | ||
58 | */ | ||
59 | if ((ios->bus_width == MMC_BUS_WIDTH_8) && | ||
60 | (ios->timing == MMC_TIMING_MMC_DDR52)) | ||
61 | cclkin = 2 * ios->clock * RK3288_CLKGEN_DIV; | ||
62 | else | ||
63 | cclkin = ios->clock * RK3288_CLKGEN_DIV; | ||
64 | |||
65 | ret = clk_set_rate(host->ciu_clk, cclkin); | ||
66 | if (ret) | ||
67 | dev_warn(host->dev, "failed to set rate %uHz\n", ios->clock); | ||
68 | |||
69 | bus_hz = clk_get_rate(host->ciu_clk) / RK3288_CLKGEN_DIV; | ||
70 | if (bus_hz != host->bus_hz) { | ||
71 | host->bus_hz = bus_hz; | ||
72 | /* force dw_mci_setup_bus() */ | ||
73 | host->current_speed = 0; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static const struct dw_mci_drv_data rk2928_drv_data = { | ||
78 | .prepare_command = dw_mci_pltfm_prepare_command, | ||
79 | }; | ||
80 | |||
81 | static const struct dw_mci_drv_data rk3288_drv_data = { | ||
34 | .prepare_command = dw_mci_pltfm_prepare_command, | 82 | .prepare_command = dw_mci_pltfm_prepare_command, |
83 | .set_ios = dw_mci_rk3288_set_ios, | ||
84 | .setup_clock = dw_mci_rk3288_setup_clock, | ||
35 | }; | 85 | }; |
36 | 86 | ||
37 | static const struct dw_mci_drv_data socfpga_drv_data = { | 87 | static const struct dw_mci_drv_data socfpga_drv_data = { |
@@ -95,7 +145,9 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops); | |||
95 | static const struct of_device_id dw_mci_pltfm_match[] = { | 145 | static const struct of_device_id dw_mci_pltfm_match[] = { |
96 | { .compatible = "snps,dw-mshc", }, | 146 | { .compatible = "snps,dw-mshc", }, |
97 | { .compatible = "rockchip,rk2928-dw-mshc", | 147 | { .compatible = "rockchip,rk2928-dw-mshc", |
98 | .data = &rockchip_drv_data }, | 148 | .data = &rk2928_drv_data }, |
149 | { .compatible = "rockchip,rk3288-dw-mshc", | ||
150 | .data = &rk3288_drv_data }, | ||
99 | { .compatible = "altr,socfpga-dw-mshc", | 151 | { .compatible = "altr,socfpga-dw-mshc", |
100 | .data = &socfpga_drv_data }, | 152 | .data = &socfpga_drv_data }, |
101 | {}, | 153 | {}, |