aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc/host/pxamci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/pxamci.c')
-rw-r--r--drivers/mmc/host/pxamci.c153
1 files changed, 93 insertions, 60 deletions
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 0d783f3e79e..32fe11323f3 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -29,12 +29,16 @@
#include <linux/io.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
#include <asm/sizes.h>
#include <mach/hardware.h>
#include <mach/dma.h>
-#include <mach/mmc.h>
+#include <linux/platform_data/mmc-pxamci.h>
#include "pxamci.h"
@@ -79,7 +83,7 @@ struct pxamci_host {
static inline void pxamci_init_ocr(struct pxamci_host *host)
{
#ifdef CONFIG_REGULATOR
- host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
+ host->vcc = regulator_get_optional(mmc_dev(host->mmc), "vmmc");
if (IS_ERR(host->vcc))
host->vcc = NULL;
@@ -98,14 +102,25 @@ static inline void pxamci_init_ocr(struct pxamci_host *host)
}
}
-static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
+static inline int pxamci_set_power(struct pxamci_host *host,
+ unsigned char power_mode,
+ unsigned int vdd)
{
int on;
-#ifdef CONFIG_REGULATOR
- if (host->vcc)
- mmc_regulator_set_ocr(host->vcc, vdd);
-#endif
+ if (host->vcc) {
+ int ret;
+
+ if (power_mode == MMC_POWER_UP) {
+ ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
+ if (ret)
+ return ret;
+ } else if (power_mode == MMC_POWER_OFF) {
+ ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
+ if (ret)
+ return ret;
+ }
+ }
if (!host->vcc && host->pdata &&
gpio_is_valid(host->pdata->gpio_power)) {
on = ((1 << vdd) & host->pdata->ocr_mask);
@@ -113,7 +128,9 @@ static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
!!on ^ host->pdata->gpio_power_invert);
}
if (!host->vcc && host->pdata && host->pdata->setpower)
- host->pdata->setpower(mmc_dev(host->mmc), vdd);
+ return host->pdata->setpower(mmc_dev(host->mmc), vdd);
+
+ return 0;
}
static void pxamci_stop_clock(struct pxamci_host *host)
@@ -489,9 +506,21 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (host->power_mode != ios->power_mode) {
+ int ret;
+
host->power_mode = ios->power_mode;
- pxamci_set_power(host, ios->vdd);
+ ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
+ if (ret) {
+ dev_err(mmc_dev(mmc), "unable to set power\n");
+ /*
+ * The .set_ios() function in the mmc_host_ops
+ * struct return void, and failing to set the
+ * power should be rare so we print an error and
+ * return here.
+ */
+ return;
+ }
if (ios->power_mode == MMC_POWER_ON)
host->cmdat |= CMDAT_INIT;
@@ -502,8 +531,8 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
host->cmdat &= ~CMDAT_SD_4DAT;
- pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
- host->clkrt, host->cmdat);
+ dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
+ host->clkrt, host->cmdat);
}
static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
@@ -532,7 +561,7 @@ static void pxamci_dma_irq(int dma, void *devid)
if (dcsr & DCSR_ENDINTR) {
writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
} else {
- printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+ pr_err("%s: DMA error on channel %d (DCSR=%#x)\n",
mmc_hostname(host->mmc), dma, dcsr);
host->data->error = -EIO;
pxamci_data_done(host, 0);
@@ -543,10 +572,54 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid)
{
struct pxamci_host *host = mmc_priv(devid);
- mmc_detect_change(devid, host->pdata->detect_delay);
+ mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms));
return IRQ_HANDLED;
}
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_mmc_dt_ids[] = {
+ { .compatible = "marvell,pxa-mmc" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
+
+static int pxamci_of_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct pxamci_platform_data *pdata;
+ u32 tmp;
+
+ if (!np)
+ return 0;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->gpio_card_detect =
+ of_get_named_gpio(np, "cd-gpios", 0);
+ pdata->gpio_card_ro =
+ of_get_named_gpio(np, "wp-gpios", 0);
+
+ /* pxa-mmc specific */
+ pdata->gpio_power =
+ of_get_named_gpio(np, "pxa-mmc,gpio-power", 0);
+
+ if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0)
+ pdata->detect_delay_ms = tmp;
+
+ pdev->dev.platform_data = pdata;
+
+ return 0;
+}
+#else
+static int pxamci_of_init(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
static int pxamci_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
@@ -554,6 +627,10 @@ static int pxamci_probe(struct platform_device *pdev)
struct resource *r, *dmarx, *dmatx;
int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
+ ret = pxamci_of_init(pdev);
+ if (ret)
+ return ret;
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!r || irq < 0)
@@ -575,7 +652,7 @@ static int pxamci_probe(struct platform_device *pdev)
* We can do SG-DMA, but we don't because we never know how much
* data we successfully wrote to the card.
*/
- mmc->max_phys_segs = NR_SG;
+ mmc->max_segs = NR_SG;
/*
* Our hardware DMA can handle a maximum of one page per SG entry.
@@ -757,8 +834,6 @@ static int pxamci_remove(struct platform_device *pdev)
struct mmc_host *mmc = platform_get_drvdata(pdev);
int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
- platform_set_drvdata(pdev, NULL);
-
if (mmc) {
struct pxamci_host *host = mmc_priv(mmc);
@@ -805,59 +880,17 @@ static int pxamci_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int pxamci_suspend(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- int ret = 0;
-
- if (mmc)
- ret = mmc_suspend_host(mmc, PMSG_SUSPEND);
-
- return ret;
-}
-
-static int pxamci_resume(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- int ret = 0;
-
- if (mmc)
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-
-static const struct dev_pm_ops pxamci_pm_ops = {
- .suspend = pxamci_suspend,
- .resume = pxamci_resume,
-};
-#endif
-
static struct platform_driver pxamci_driver = {
.probe = pxamci_probe,
.remove = pxamci_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &pxamci_pm_ops,
-#endif
+ .of_match_table = of_match_ptr(pxa_mmc_dt_ids),
},
};
-static int __init pxamci_init(void)
-{
- return platform_driver_register(&pxamci_driver);
-}
-
-static void __exit pxamci_exit(void)
-{
- platform_driver_unregister(&pxamci_driver);
-}
-
-module_init(pxamci_init);
-module_exit(pxamci_exit);
+module_platform_driver(pxamci_driver);
MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
MODULE_LICENSE("GPL");