diff options
-rw-r--r-- | drivers/mmc/host/dw_mmc-pltfm.c | 12 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc-pltfm.h | 3 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 47 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc.h | 24 | ||||
-rw-r--r-- | include/linux/mmc/dw_mmc.h | 4 |
5 files changed, 86 insertions, 4 deletions
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index e17da912efff..c960ca7ffbe6 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c | |||
@@ -23,7 +23,8 @@ | |||
23 | 23 | ||
24 | #include "dw_mmc.h" | 24 | #include "dw_mmc.h" |
25 | 25 | ||
26 | int dw_mci_pltfm_register(struct platform_device *pdev) | 26 | int dw_mci_pltfm_register(struct platform_device *pdev, |
27 | struct dw_mci_drv_data *drv_data) | ||
27 | { | 28 | { |
28 | struct dw_mci *host; | 29 | struct dw_mci *host; |
29 | struct resource *regs; | 30 | struct resource *regs; |
@@ -41,6 +42,7 @@ int dw_mci_pltfm_register(struct platform_device *pdev) | |||
41 | if (host->irq < 0) | 42 | if (host->irq < 0) |
42 | return host->irq; | 43 | return host->irq; |
43 | 44 | ||
45 | host->drv_data = drv_data; | ||
44 | host->dev = &pdev->dev; | 46 | host->dev = &pdev->dev; |
45 | host->irq_flags = 0; | 47 | host->irq_flags = 0; |
46 | host->pdata = pdev->dev.platform_data; | 48 | host->pdata = pdev->dev.platform_data; |
@@ -48,6 +50,12 @@ int dw_mci_pltfm_register(struct platform_device *pdev) | |||
48 | if (!host->regs) | 50 | if (!host->regs) |
49 | return -ENOMEM; | 51 | return -ENOMEM; |
50 | 52 | ||
53 | if (host->drv_data->init) { | ||
54 | ret = host->drv_data->init(host); | ||
55 | if (ret) | ||
56 | return ret; | ||
57 | } | ||
58 | |||
51 | platform_set_drvdata(pdev, host); | 59 | platform_set_drvdata(pdev, host); |
52 | ret = dw_mci_probe(host); | 60 | ret = dw_mci_probe(host); |
53 | return ret; | 61 | return ret; |
@@ -56,7 +64,7 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_register); | |||
56 | 64 | ||
57 | static int __devinit dw_mci_pltfm_probe(struct platform_device *pdev) | 65 | static int __devinit dw_mci_pltfm_probe(struct platform_device *pdev) |
58 | { | 66 | { |
59 | return dw_mci_pltfm_register(pdev); | 67 | return dw_mci_pltfm_register(pdev, NULL); |
60 | } | 68 | } |
61 | 69 | ||
62 | static int __devexit dw_mci_pltfm_remove(struct platform_device *pdev) | 70 | static int __devexit dw_mci_pltfm_remove(struct platform_device *pdev) |
diff --git a/drivers/mmc/host/dw_mmc-pltfm.h b/drivers/mmc/host/dw_mmc-pltfm.h index 6c065d9c2dd6..301f24541fc2 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.h +++ b/drivers/mmc/host/dw_mmc-pltfm.h | |||
@@ -12,7 +12,8 @@ | |||
12 | #ifndef _DW_MMC_PLTFM_H_ | 12 | #ifndef _DW_MMC_PLTFM_H_ |
13 | #define _DW_MMC_PLTFM_H_ | 13 | #define _DW_MMC_PLTFM_H_ |
14 | 14 | ||
15 | extern int dw_mci_pltfm_register(struct platform_device *pdev); | 15 | extern int dw_mci_pltfm_register(struct platform_device *pdev, |
16 | struct dw_mci_drv_data *drv_data); | ||
16 | extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev); | 17 | extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev); |
17 | extern const struct dev_pm_ops dw_mci_pltfm_pmops; | 18 | extern const struct dev_pm_ops dw_mci_pltfm_pmops; |
18 | 19 | ||
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c792466fb8ac..9f8e487bfa97 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c | |||
@@ -231,6 +231,7 @@ static void dw_mci_set_timeout(struct dw_mci *host) | |||
231 | static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) | 231 | static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) |
232 | { | 232 | { |
233 | struct mmc_data *data; | 233 | struct mmc_data *data; |
234 | struct dw_mci_slot *slot = mmc_priv(mmc); | ||
234 | u32 cmdr; | 235 | u32 cmdr; |
235 | cmd->error = -EINPROGRESS; | 236 | cmd->error = -EINPROGRESS; |
236 | 237 | ||
@@ -260,6 +261,9 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) | |||
260 | cmdr |= SDMMC_CMD_DAT_WR; | 261 | cmdr |= SDMMC_CMD_DAT_WR; |
261 | } | 262 | } |
262 | 263 | ||
264 | if (slot->host->drv_data->prepare_command) | ||
265 | slot->host->drv_data->prepare_command(slot->host, &cmdr); | ||
266 | |||
263 | return cmdr; | 267 | return cmdr; |
264 | } | 268 | } |
265 | 269 | ||
@@ -815,6 +819,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
815 | slot->clock = ios->clock; | 819 | slot->clock = ios->clock; |
816 | } | 820 | } |
817 | 821 | ||
822 | if (slot->host->drv_data->set_ios) | ||
823 | slot->host->drv_data->set_ios(slot->host, ios); | ||
824 | |||
818 | switch (ios->power_mode) { | 825 | switch (ios->power_mode) { |
819 | case MMC_POWER_UP: | 826 | case MMC_POWER_UP: |
820 | set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); | 827 | set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); |
@@ -1820,6 +1827,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) | |||
1820 | { | 1827 | { |
1821 | struct mmc_host *mmc; | 1828 | struct mmc_host *mmc; |
1822 | struct dw_mci_slot *slot; | 1829 | struct dw_mci_slot *slot; |
1830 | int ctrl_id, ret; | ||
1823 | u8 bus_width; | 1831 | u8 bus_width; |
1824 | 1832 | ||
1825 | mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); | 1833 | mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); |
@@ -1851,6 +1859,16 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) | |||
1851 | if (host->pdata->caps) | 1859 | if (host->pdata->caps) |
1852 | mmc->caps = host->pdata->caps; | 1860 | mmc->caps = host->pdata->caps; |
1853 | 1861 | ||
1862 | if (host->dev->of_node) { | ||
1863 | ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); | ||
1864 | if (ctrl_id < 0) | ||
1865 | ctrl_id = 0; | ||
1866 | } else { | ||
1867 | ctrl_id = to_platform_device(host->dev)->id; | ||
1868 | } | ||
1869 | if (host->drv_data && host->drv_data->caps) | ||
1870 | mmc->caps |= host->drv_data->caps[ctrl_id]; | ||
1871 | |||
1854 | if (host->pdata->caps2) | 1872 | if (host->pdata->caps2) |
1855 | mmc->caps2 = host->pdata->caps2; | 1873 | mmc->caps2 = host->pdata->caps2; |
1856 | 1874 | ||
@@ -1861,6 +1879,14 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) | |||
1861 | else | 1879 | else |
1862 | bus_width = 1; | 1880 | bus_width = 1; |
1863 | 1881 | ||
1882 | if (host->drv_data->setup_bus) { | ||
1883 | struct device_node *slot_np; | ||
1884 | slot_np = dw_mci_of_find_slot_node(host->dev, slot->id); | ||
1885 | ret = host->drv_data->setup_bus(host, slot_np, bus_width); | ||
1886 | if (ret) | ||
1887 | goto err_setup_bus; | ||
1888 | } | ||
1889 | |||
1864 | switch (bus_width) { | 1890 | switch (bus_width) { |
1865 | case 8: | 1891 | case 8: |
1866 | mmc->caps |= MMC_CAP_8_BIT_DATA; | 1892 | mmc->caps |= MMC_CAP_8_BIT_DATA; |
@@ -1927,6 +1953,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) | |||
1927 | queue_work(host->card_workqueue, &host->card_work); | 1953 | queue_work(host->card_workqueue, &host->card_work); |
1928 | 1954 | ||
1929 | return 0; | 1955 | return 0; |
1956 | |||
1957 | err_setup_bus: | ||
1958 | mmc_free_host(mmc); | ||
1959 | return -EINVAL; | ||
1930 | } | 1960 | } |
1931 | 1961 | ||
1932 | static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) | 1962 | static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) |
@@ -2021,7 +2051,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) | |||
2021 | struct dw_mci_board *pdata; | 2051 | struct dw_mci_board *pdata; |
2022 | struct device *dev = host->dev; | 2052 | struct device *dev = host->dev; |
2023 | struct device_node *np = dev->of_node; | 2053 | struct device_node *np = dev->of_node; |
2024 | int idx; | 2054 | int idx, ret; |
2025 | 2055 | ||
2026 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | 2056 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); |
2027 | if (!pdata) { | 2057 | if (!pdata) { |
@@ -2048,6 +2078,12 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) | |||
2048 | 2078 | ||
2049 | of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); | 2079 | of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); |
2050 | 2080 | ||
2081 | if (host->drv_data->parse_dt) { | ||
2082 | ret = host->drv_data->parse_dt(host); | ||
2083 | if (ret) | ||
2084 | return ERR_PTR(ret); | ||
2085 | } | ||
2086 | |||
2051 | return pdata; | 2087 | return pdata; |
2052 | } | 2088 | } |
2053 | 2089 | ||
@@ -2107,6 +2143,15 @@ int dw_mci_probe(struct dw_mci *host) | |||
2107 | else | 2143 | else |
2108 | host->bus_hz = clk_get_rate(host->ciu_clk); | 2144 | host->bus_hz = clk_get_rate(host->ciu_clk); |
2109 | 2145 | ||
2146 | if (host->drv_data->setup_clock) { | ||
2147 | ret = host->drv_data->setup_clock(host); | ||
2148 | if (ret) { | ||
2149 | dev_err(host->dev, | ||
2150 | "implementation specific clock setup failed\n"); | ||
2151 | goto err_clk_ciu; | ||
2152 | } | ||
2153 | } | ||
2154 | |||
2110 | if (!host->bus_hz) { | 2155 | if (!host->bus_hz) { |
2111 | dev_err(host->dev, | 2156 | dev_err(host->dev, |
2112 | "Platform data must supply bus speed\n"); | 2157 | "Platform data must supply bus speed\n"); |
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 15c27e17c23f..53b8fd987e47 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h | |||
@@ -182,4 +182,28 @@ extern int dw_mci_suspend(struct dw_mci *host); | |||
182 | extern int dw_mci_resume(struct dw_mci *host); | 182 | extern int dw_mci_resume(struct dw_mci *host); |
183 | #endif | 183 | #endif |
184 | 184 | ||
185 | /** | ||
186 | * dw_mci driver data - dw-mshc implementation specific driver data. | ||
187 | * @caps: mmc subsystem specified capabilities of the controller(s). | ||
188 | * @init: early implementation specific initialization. | ||
189 | * @setup_clock: implementation specific clock configuration. | ||
190 | * @prepare_command: handle CMD register extensions. | ||
191 | * @set_ios: handle bus specific extensions. | ||
192 | * @parse_dt: parse implementation specific device tree properties. | ||
193 | * @setup_bus: initialize io-interface | ||
194 | * | ||
195 | * Provide controller implementation specific extensions. The usage of this | ||
196 | * data structure is fully optional and usage of each member in this structure | ||
197 | * is optional as well. | ||
198 | */ | ||
199 | struct dw_mci_drv_data { | ||
200 | unsigned long *caps; | ||
201 | int (*init)(struct dw_mci *host); | ||
202 | int (*setup_clock)(struct dw_mci *host); | ||
203 | void (*prepare_command)(struct dw_mci *host, u32 *cmdr); | ||
204 | void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); | ||
205 | int (*parse_dt)(struct dw_mci *host); | ||
206 | int (*setup_bus)(struct dw_mci *host, | ||
207 | struct device_node *slot_np, u8 bus_width); | ||
208 | }; | ||
185 | #endif /* _DW_MMC_H_ */ | 209 | #endif /* _DW_MMC_H_ */ |
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index b72e4aa91c11..6cb043e48953 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h | |||
@@ -78,6 +78,8 @@ struct mmc_data; | |||
78 | * @data_offset: Set the offset of DATA register according to VERID. | 78 | * @data_offset: Set the offset of DATA register according to VERID. |
79 | * @dev: Device associated with the MMC controller. | 79 | * @dev: Device associated with the MMC controller. |
80 | * @pdata: Platform data associated with the MMC controller. | 80 | * @pdata: Platform data associated with the MMC controller. |
81 | * @drv_data: Driver specific data for identified variant of the controller | ||
82 | * @priv: Implementation defined private data. | ||
81 | * @biu_clk: Pointer to bus interface unit clock instance. | 83 | * @biu_clk: Pointer to bus interface unit clock instance. |
82 | * @ciu_clk: Pointer to card interface unit clock instance. | 84 | * @ciu_clk: Pointer to card interface unit clock instance. |
83 | * @slot: Slots sharing this MMC controller. | 85 | * @slot: Slots sharing this MMC controller. |
@@ -160,6 +162,8 @@ struct dw_mci { | |||
160 | u16 data_offset; | 162 | u16 data_offset; |
161 | struct device *dev; | 163 | struct device *dev; |
162 | struct dw_mci_board *pdata; | 164 | struct dw_mci_board *pdata; |
165 | struct dw_mci_drv_data *drv_data; | ||
166 | void *priv; | ||
163 | struct clk *biu_clk; | 167 | struct clk *biu_clk; |
164 | struct clk *ciu_clk; | 168 | struct clk *ciu_clk; |
165 | struct dw_mci_slot *slot[MAX_MCI_SLOTS]; | 169 | struct dw_mci_slot *slot[MAX_MCI_SLOTS]; |