diff options
Diffstat (limited to 'drivers/mmc/host/pxamci.c')
| -rw-r--r-- | drivers/mmc/host/pxamci.c | 153 |
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"); |
