diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 21:58:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 21:58:42 -0400 |
commit | 943c2acea53784c45fb291498d04d5188fdea891 (patch) | |
tree | 063fac3e584f8f4a5babbc329499f84b3da291d7 /drivers/mmc/host/sdhci-spear.c | |
parent | 10f39f04b2cb7a06ba5d4ea0f20bd156d0367bee (diff) | |
parent | e6c085863f97f0a8f009753e1baaf83e4aac7b42 (diff) |
Merge tag 'mmc-merge-for-3.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC updates from Chris Ball:
"Core:
- Add DT properties for card detection (broken-cd, cd-gpios,
non-removable)
- Don't poll non-removable devices
- Fixup/rework eMMC sleep mode/"power off notify" feature
- Support eMMC background operations (BKOPS). To set the one-time
programmable fuse that enables bkops on an eMMC that doesn't
already have it set, you can use the "mmc bkops enable" command in:
git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc-utils.git
Drivers:
- atmel-mci, dw_mmc, pxa-mci, dove, s3c, spear: Add device tree
support
- bfin_sdh: Add support for the controller in bf60x
- dw_mmc: Support Samsung Exynos SoCs
- eSDHC: Add ADMA support
- sdhci: Support testing a cd-gpio (from slot-gpio) instead of
presence bit
- sdhci-pltfm: Support broken-cd DT property
- tegra: Convert to only supporting DT (mach-tegra has gone DT-only)"
* tag 'mmc-merge-for-3.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (67 commits)
mmc: core: Fixup broken suspend and eMMC4.5 power off notify
mmc: sdhci-spear: Add clk_{un}prepare() support
mmc: sdhci-spear: add device tree bindings
mmc: sdhci-s3c: Add clk_(enable/disable) in runtime suspend/resume
mmc: core: Replace MMC_CAP2_BROKEN_VOLTAGE with test for fixed regulator
mmc: sdhci-pxav3: Use sdhci_get_of_property for parsing DT quirks
mmc: dt: Support "broken-cd" property in sdhci-pltfm
mmc: sdhci-s3c: fix the wrong number of max bus clocks
mmc: sh-mmcif: avoid oops on spurious interrupts
mmc: sh-mmcif: properly handle MMC_WRITE_MULTIPLE_BLOCK completion IRQ
mmc: sdhci-s3c: Fix crash on module insertion for second time
mmc: sdhci-s3c: Enable only required bus clock
mmc: Revert "mmc: dw_mmc: Add check for IDMAC configuration"
mmc: mxcmmc: fix bug that may block a data transfer forever
mmc: omap_hsmmc: Pass on the suspend failure to the PM core
mmc: atmel-mci: AP700x PDC is not connected to MCI
mmc: atmel-mci: DMA can be used with other controllers
mmc: mmci: use clk_prepare_enable and clk_disable_unprepare
mmc: sdhci-s3c: Add device tree support
mmc: dw_mmc: add support for exynos specific implementation of dw-mshc
...
Diffstat (limited to 'drivers/mmc/host/sdhci-spear.c')
-rw-r--r-- | drivers/mmc/host/sdhci-spear.c | 67 |
1 files changed, 60 insertions, 7 deletions
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 423da8194cd8..6be89c032deb 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
23 | #include <linux/of.h> | ||
24 | #include <linux/of_gpio.h> | ||
23 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
24 | #include <linux/pm.h> | 26 | #include <linux/pm.h> |
25 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
@@ -68,8 +70,42 @@ static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) | |||
68 | return IRQ_HANDLED; | 70 | return IRQ_HANDLED; |
69 | } | 71 | } |
70 | 72 | ||
73 | #ifdef CONFIG_OF | ||
74 | static struct sdhci_plat_data * __devinit | ||
75 | sdhci_probe_config_dt(struct platform_device *pdev) | ||
76 | { | ||
77 | struct device_node *np = pdev->dev.of_node; | ||
78 | struct sdhci_plat_data *pdata = NULL; | ||
79 | int cd_gpio; | ||
80 | |||
81 | cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); | ||
82 | if (!gpio_is_valid(cd_gpio)) | ||
83 | cd_gpio = -1; | ||
84 | |||
85 | /* If pdata is required */ | ||
86 | if (cd_gpio != -1) { | ||
87 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
88 | if (!pdata) { | ||
89 | dev_err(&pdev->dev, "DT: kzalloc failed\n"); | ||
90 | return ERR_PTR(-ENOMEM); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | pdata->card_int_gpio = cd_gpio; | ||
95 | |||
96 | return pdata; | ||
97 | } | ||
98 | #else | ||
99 | static struct sdhci_plat_data * __devinit | ||
100 | sdhci_probe_config_dt(struct platform_device *pdev) | ||
101 | { | ||
102 | return ERR_PTR(-ENOSYS); | ||
103 | } | ||
104 | #endif | ||
105 | |||
71 | static int __devinit sdhci_probe(struct platform_device *pdev) | 106 | static int __devinit sdhci_probe(struct platform_device *pdev) |
72 | { | 107 | { |
108 | struct device_node *np = pdev->dev.of_node; | ||
73 | struct sdhci_host *host; | 109 | struct sdhci_host *host; |
74 | struct resource *iomem; | 110 | struct resource *iomem; |
75 | struct spear_sdhci *sdhci; | 111 | struct spear_sdhci *sdhci; |
@@ -104,14 +140,22 @@ static int __devinit sdhci_probe(struct platform_device *pdev) | |||
104 | goto err; | 140 | goto err; |
105 | } | 141 | } |
106 | 142 | ||
107 | ret = clk_enable(sdhci->clk); | 143 | ret = clk_prepare_enable(sdhci->clk); |
108 | if (ret) { | 144 | if (ret) { |
109 | dev_dbg(&pdev->dev, "Error enabling clock\n"); | 145 | dev_dbg(&pdev->dev, "Error enabling clock\n"); |
110 | goto put_clk; | 146 | goto put_clk; |
111 | } | 147 | } |
112 | 148 | ||
113 | /* overwrite platform_data */ | 149 | if (np) { |
114 | sdhci->data = dev_get_platdata(&pdev->dev); | 150 | sdhci->data = sdhci_probe_config_dt(pdev); |
151 | if (IS_ERR(sdhci->data)) { | ||
152 | dev_err(&pdev->dev, "DT: Failed to get pdata\n"); | ||
153 | return -ENODEV; | ||
154 | } | ||
155 | } else { | ||
156 | sdhci->data = dev_get_platdata(&pdev->dev); | ||
157 | } | ||
158 | |||
115 | pdev->dev.platform_data = sdhci; | 159 | pdev->dev.platform_data = sdhci; |
116 | 160 | ||
117 | if (pdev->dev.parent) | 161 | if (pdev->dev.parent) |
@@ -216,7 +260,7 @@ set_drvdata: | |||
216 | free_host: | 260 | free_host: |
217 | sdhci_free_host(host); | 261 | sdhci_free_host(host); |
218 | disable_clk: | 262 | disable_clk: |
219 | clk_disable(sdhci->clk); | 263 | clk_disable_unprepare(sdhci->clk); |
220 | put_clk: | 264 | put_clk: |
221 | clk_put(sdhci->clk); | 265 | clk_put(sdhci->clk); |
222 | err: | 266 | err: |
@@ -238,7 +282,7 @@ static int __devexit sdhci_remove(struct platform_device *pdev) | |||
238 | 282 | ||
239 | sdhci_remove_host(host, dead); | 283 | sdhci_remove_host(host, dead); |
240 | sdhci_free_host(host); | 284 | sdhci_free_host(host); |
241 | clk_disable(sdhci->clk); | 285 | clk_disable_unprepare(sdhci->clk); |
242 | clk_put(sdhci->clk); | 286 | clk_put(sdhci->clk); |
243 | 287 | ||
244 | return 0; | 288 | return 0; |
@@ -253,7 +297,7 @@ static int sdhci_suspend(struct device *dev) | |||
253 | 297 | ||
254 | ret = sdhci_suspend_host(host); | 298 | ret = sdhci_suspend_host(host); |
255 | if (!ret) | 299 | if (!ret) |
256 | clk_disable(sdhci->clk); | 300 | clk_disable_unprepare(sdhci->clk); |
257 | 301 | ||
258 | return ret; | 302 | return ret; |
259 | } | 303 | } |
@@ -264,7 +308,7 @@ static int sdhci_resume(struct device *dev) | |||
264 | struct spear_sdhci *sdhci = dev_get_platdata(dev); | 308 | struct spear_sdhci *sdhci = dev_get_platdata(dev); |
265 | int ret; | 309 | int ret; |
266 | 310 | ||
267 | ret = clk_enable(sdhci->clk); | 311 | ret = clk_prepare_enable(sdhci->clk); |
268 | if (ret) { | 312 | if (ret) { |
269 | dev_dbg(dev, "Resume: Error enabling clock\n"); | 313 | dev_dbg(dev, "Resume: Error enabling clock\n"); |
270 | return ret; | 314 | return ret; |
@@ -276,11 +320,20 @@ static int sdhci_resume(struct device *dev) | |||
276 | 320 | ||
277 | static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume); | 321 | static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume); |
278 | 322 | ||
323 | #ifdef CONFIG_OF | ||
324 | static const struct of_device_id sdhci_spear_id_table[] = { | ||
325 | { .compatible = "st,spear300-sdhci" }, | ||
326 | {} | ||
327 | }; | ||
328 | MODULE_DEVICE_TABLE(of, sdhci_spear_id_table); | ||
329 | #endif | ||
330 | |||
279 | static struct platform_driver sdhci_driver = { | 331 | static struct platform_driver sdhci_driver = { |
280 | .driver = { | 332 | .driver = { |
281 | .name = "sdhci", | 333 | .name = "sdhci", |
282 | .owner = THIS_MODULE, | 334 | .owner = THIS_MODULE, |
283 | .pm = &sdhci_pm_ops, | 335 | .pm = &sdhci_pm_ops, |
336 | .of_match_table = of_match_ptr(sdhci_spear_id_table), | ||
284 | }, | 337 | }, |
285 | .probe = sdhci_probe, | 338 | .probe = sdhci_probe, |
286 | .remove = __devexit_p(sdhci_remove), | 339 | .remove = __devexit_p(sdhci_remove), |