diff options
author | addy ke <addy.ke@rock-chips.com> | 2014-08-19 00:36:14 -0400 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2014-09-09 07:59:16 -0400 |
commit | 4cdc2ec1da322776215c4d6bca0717a7a103a4dd (patch) | |
tree | 1761d2c46974933b3a604f37308e23f75da7c856 | |
parent | da29fe2bf573f0ae56fdc2e790387cb73fc8c6f8 (diff) |
mmc: dw_mmc: move rockchip related code to a separate file
To support HS200 and UHS-1, we need add a big hunk of code,
as shown in the following patches. So a separate file for
rockchip SOCs is suitable.
Signed-off-by: Addy Ke <addy.ke@rock-chips.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Tested-by: Doug Anderson <dianders@chromium.org>
Reviewed-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r-- | drivers/mmc/host/Kconfig | 9 | ||||
-rw-r--r-- | drivers/mmc/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc-pltfm.c | 57 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc-rockchip.c | 136 |
4 files changed, 146 insertions, 57 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index a43295c49a44..13860656104b 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
@@ -638,6 +638,15 @@ config MMC_DW_PCI | |||
638 | 638 | ||
639 | If unsure, say N. | 639 | If unsure, say N. |
640 | 640 | ||
641 | config MMC_DW_ROCKCHIP | ||
642 | tristate "Rockchip specific extensions for Synopsys DW Memory Card Interface" | ||
643 | depends on MMC_DW && ARCH_ROCKCHIP | ||
644 | select MMC_DW_PLTFM | ||
645 | help | ||
646 | This selects support for Rockchip SoC specific extensions to the | ||
647 | Synopsys DesignWare Memory Card Interface driver. Select this option | ||
648 | for platforms based on RK3066, RK3188 and RK3288 SoC's. | ||
649 | |||
641 | config MMC_SH_MMCIF | 650 | config MMC_SH_MMCIF |
642 | tristate "SuperH Internal MMCIF support" | 651 | tristate "SuperH Internal MMCIF support" |
643 | depends on MMC_BLOCK && HAS_DMA | 652 | depends on MMC_BLOCK && HAS_DMA |
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 2d223463e6c5..b09ecfb88269 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile | |||
@@ -46,6 +46,7 @@ obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o | |||
46 | obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o | 46 | obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o |
47 | obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o | 47 | obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o |
48 | obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o | 48 | obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o |
49 | obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o | ||
49 | obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o | 50 | obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o |
50 | obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o | 51 | obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o |
51 | obj-$(CONFIG_MMC_VUB300) += vub300.o | 52 | obj-$(CONFIG_MMC_VUB300) += vub300.o |
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 1cd02828e5a3..8b6572162ed9 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c | |||
@@ -26,64 +26,11 @@ | |||
26 | #include "dw_mmc.h" | 26 | #include "dw_mmc.h" |
27 | #include "dw_mmc-pltfm.h" | 27 | #include "dw_mmc-pltfm.h" |
28 | 28 | ||
29 | #define RK3288_CLKGEN_DIV 2 | ||
30 | |||
31 | static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr) | 29 | static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr) |
32 | { | 30 | { |
33 | *cmdr |= SDMMC_CMD_USE_HOLD_REG; | 31 | *cmdr |= SDMMC_CMD_USE_HOLD_REG; |
34 | } | 32 | } |
35 | 33 | ||
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 = { | ||
82 | .prepare_command = dw_mci_pltfm_prepare_command, | ||
83 | .set_ios = dw_mci_rk3288_set_ios, | ||
84 | .setup_clock = dw_mci_rk3288_setup_clock, | ||
85 | }; | ||
86 | |||
87 | static const struct dw_mci_drv_data socfpga_drv_data = { | 34 | static const struct dw_mci_drv_data socfpga_drv_data = { |
88 | .prepare_command = dw_mci_pltfm_prepare_command, | 35 | .prepare_command = dw_mci_pltfm_prepare_command, |
89 | }; | 36 | }; |
@@ -141,10 +88,6 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops); | |||
141 | 88 | ||
142 | static const struct of_device_id dw_mci_pltfm_match[] = { | 89 | static const struct of_device_id dw_mci_pltfm_match[] = { |
143 | { .compatible = "snps,dw-mshc", }, | 90 | { .compatible = "snps,dw-mshc", }, |
144 | { .compatible = "rockchip,rk2928-dw-mshc", | ||
145 | .data = &rk2928_drv_data }, | ||
146 | { .compatible = "rockchip,rk3288-dw-mshc", | ||
147 | .data = &rk3288_drv_data }, | ||
148 | { .compatible = "altr,socfpga-dw-mshc", | 91 | { .compatible = "altr,socfpga-dw-mshc", |
149 | .data = &socfpga_drv_data }, | 92 | .data = &socfpga_drv_data }, |
150 | {}, | 93 | {}, |
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c new file mode 100644 index 000000000000..f0c2cb1a210d --- /dev/null +++ b/drivers/mmc/host/dw_mmc-rockchip.c | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/clk.h> | ||
13 | #include <linux/mmc/host.h> | ||
14 | #include <linux/mmc/dw_mmc.h> | ||
15 | #include <linux/of_address.h> | ||
16 | |||
17 | #include "dw_mmc.h" | ||
18 | #include "dw_mmc-pltfm.h" | ||
19 | |||
20 | #define RK3288_CLKGEN_DIV 2 | ||
21 | |||
22 | static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr) | ||
23 | { | ||
24 | *cmdr |= SDMMC_CMD_USE_HOLD_REG; | ||
25 | } | ||
26 | |||
27 | static int dw_mci_rk3288_setup_clock(struct dw_mci *host) | ||
28 | { | ||
29 | host->bus_hz /= RK3288_CLKGEN_DIV; | ||
30 | |||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) | ||
35 | { | ||
36 | int ret; | ||
37 | unsigned int cclkin; | ||
38 | u32 bus_hz; | ||
39 | |||
40 | /* | ||
41 | * cclkin: source clock of mmc controller | ||
42 | * bus_hz: card interface clock generated by CLKGEN | ||
43 | * bus_hz = cclkin / RK3288_CLKGEN_DIV | ||
44 | * ios->clock = (div == 0) ? bus_hz : (bus_hz / (2 * div)) | ||
45 | * | ||
46 | * Note: div can only be 0 or 1 | ||
47 | * if DDR50 8bit mode(only emmc work in 8bit mode), | ||
48 | * div must be set 1 | ||
49 | */ | ||
50 | if (ios->bus_width == MMC_BUS_WIDTH_8 && | ||
51 | ios->timing == MMC_TIMING_MMC_DDR52) | ||
52 | cclkin = 2 * ios->clock * RK3288_CLKGEN_DIV; | ||
53 | else | ||
54 | cclkin = ios->clock * RK3288_CLKGEN_DIV; | ||
55 | |||
56 | ret = clk_set_rate(host->ciu_clk, cclkin); | ||
57 | if (ret) | ||
58 | dev_warn(host->dev, "failed to set rate %uHz\n", ios->clock); | ||
59 | |||
60 | bus_hz = clk_get_rate(host->ciu_clk) / RK3288_CLKGEN_DIV; | ||
61 | if (bus_hz != host->bus_hz) { | ||
62 | host->bus_hz = bus_hz; | ||
63 | /* force dw_mci_setup_bus() */ | ||
64 | host->current_speed = 0; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | static const struct dw_mci_drv_data rk2928_drv_data = { | ||
69 | .prepare_command = dw_mci_rockchip_prepare_command, | ||
70 | }; | ||
71 | |||
72 | static const struct dw_mci_drv_data rk3288_drv_data = { | ||
73 | .prepare_command = dw_mci_rockchip_prepare_command, | ||
74 | .set_ios = dw_mci_rk3288_set_ios, | ||
75 | .setup_clock = dw_mci_rk3288_setup_clock, | ||
76 | }; | ||
77 | |||
78 | static const struct of_device_id dw_mci_rockchip_match[] = { | ||
79 | { .compatible = "rockchip,rk2928-dw-mshc", | ||
80 | .data = &rk2928_drv_data }, | ||
81 | { .compatible = "rockchip,rk3288-dw-mshc", | ||
82 | .data = &rk3288_drv_data }, | ||
83 | {}, | ||
84 | }; | ||
85 | MODULE_DEVICE_TABLE(of, dw_mci_rockchip_match); | ||
86 | |||
87 | static int dw_mci_rockchip_probe(struct platform_device *pdev) | ||
88 | { | ||
89 | const struct dw_mci_drv_data *drv_data; | ||
90 | const struct of_device_id *match; | ||
91 | |||
92 | if (!pdev->dev.of_node) | ||
93 | return -ENODEV; | ||
94 | |||
95 | match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node); | ||
96 | drv_data = match->data; | ||
97 | |||
98 | return dw_mci_pltfm_register(pdev, drv_data); | ||
99 | } | ||
100 | |||
101 | #ifdef CONFIG_PM_SLEEP | ||
102 | static int dw_mci_rockchip_suspend(struct device *dev) | ||
103 | { | ||
104 | struct dw_mci *host = dev_get_drvdata(dev); | ||
105 | |||
106 | return dw_mci_suspend(host); | ||
107 | } | ||
108 | |||
109 | static int dw_mci_rockchip_resume(struct device *dev) | ||
110 | { | ||
111 | struct dw_mci *host = dev_get_drvdata(dev); | ||
112 | |||
113 | return dw_mci_resume(host); | ||
114 | } | ||
115 | #endif /* CONFIG_PM_SLEEP */ | ||
116 | |||
117 | static SIMPLE_DEV_PM_OPS(dw_mci_rockchip_pmops, | ||
118 | dw_mci_rockchip_suspend, | ||
119 | dw_mci_rockchip_resume); | ||
120 | |||
121 | static struct platform_driver dw_mci_rockchip_pltfm_driver = { | ||
122 | .probe = dw_mci_rockchip_probe, | ||
123 | .remove = __exit_p(dw_mci_pltfm_remove), | ||
124 | .driver = { | ||
125 | .name = "dwmmc_rockchip", | ||
126 | .of_match_table = dw_mci_rockchip_match, | ||
127 | .pm = &dw_mci_rockchip_pmops, | ||
128 | }, | ||
129 | }; | ||
130 | |||
131 | module_platform_driver(dw_mci_rockchip_pltfm_driver); | ||
132 | |||
133 | MODULE_AUTHOR("Addy Ke <addy.ke@rock-chips.com>"); | ||
134 | MODULE_DESCRIPTION("Rockchip Specific DW-MSHC Driver Extension"); | ||
135 | MODULE_ALIAS("platform:dwmmc-rockchip"); | ||
136 | MODULE_LICENSE("GPL v2"); | ||