aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Abraham <thomas.abraham@linaro.org>2012-09-17 14:16:42 -0400
committerChris Ball <cjb@laptop.org>2012-10-03 10:05:19 -0400
commit800d78bfccb3d38116abfda2a5b9c8afdbd5ea21 (patch)
tree6f4d8375a86319adc67a0154baed8bd6253073a8
parent17403f235e94dcccf95b43138b197c4de2ab6816 (diff)
mmc: dw_mmc: add support for implementation specific callbacks
The core dw-mshc controller driver can let platform specific implementations of the dw-mshc controller to control the hardware as required by such implementations. This is acheived by invoking implementation specific (optional) callbacks. Define the list of callbacks supported the add invocation points for the same. Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Will Newton <will.newton@imgtec.com> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c12
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.h3
-rw-r--r--drivers/mmc/host/dw_mmc.c47
-rw-r--r--drivers/mmc/host/dw_mmc.h24
-rw-r--r--include/linux/mmc/dw_mmc.h4
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
26int dw_mci_pltfm_register(struct platform_device *pdev) 26int 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
57static int __devinit dw_mci_pltfm_probe(struct platform_device *pdev) 65static 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
62static int __devexit dw_mci_pltfm_remove(struct platform_device *pdev) 70static 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
15extern int dw_mci_pltfm_register(struct platform_device *pdev); 15extern int dw_mci_pltfm_register(struct platform_device *pdev,
16 struct dw_mci_drv_data *drv_data);
16extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev); 17extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev);
17extern const struct dev_pm_ops dw_mci_pltfm_pmops; 18extern 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)
231static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) 231static 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
1957err_setup_bus:
1958 mmc_free_host(mmc);
1959 return -EINVAL;
1930} 1960}
1931 1961
1932static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 1962static 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);
182extern int dw_mci_resume(struct dw_mci *host); 182extern 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 */
199struct 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];