mmc: mxs-mmc: add device tree support

It adds device tree probe support for mxs-mmc driver.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
Shawn Guo 2012-05-06 13:30:44 +08:00
parent 31b0ff5e73
commit 6de4d817aa
2 changed files with 68 additions and 5 deletions

View File

@ -0,0 +1,25 @@
* Freescale MXS MMC controller
The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller
to support MMC, SD, and SDIO types of memory cards.
Required properties:
- compatible: Should be "fsl,<chip>-mmc". The supported chips include
imx23 and imx28.
- reg: Should contain registers location and length
- interrupts: Should contain ERROR and DMA interrupts
- fsl,ssp-dma-channel: APBH DMA channel for the SSP
- bus-width: Number of data lines, can be <1>, <4>, or <8>
Optional properties:
- wp-gpios: Specify GPIOs for write protection
Examples:
ssp0: ssp@80010000 {
compatible = "fsl,imx28-mmc";
reg = <0x80010000 2000>;
interrupts = <96 82>;
fsl,ssp-dma-channel = <0>;
bus-width = <8>;
};

View File

@ -23,6 +23,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
@ -685,8 +688,18 @@ static struct platform_device_id mxs_mmc_ids[] = {
}; };
MODULE_DEVICE_TABLE(platform, mxs_mmc_ids); MODULE_DEVICE_TABLE(platform, mxs_mmc_ids);
static const struct of_device_id mxs_mmc_dt_ids[] = {
{ .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_MMC, },
{ .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_MMC, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids);
static int mxs_mmc_probe(struct platform_device *pdev) static int mxs_mmc_probe(struct platform_device *pdev)
{ {
const struct of_device_id *of_id =
of_match_device(mxs_mmc_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct mxs_mmc_host *host; struct mxs_mmc_host *host;
struct mmc_host *mmc; struct mmc_host *mmc;
struct resource *iores, *dmares; struct resource *iores, *dmares;
@ -699,7 +712,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
irq_err = platform_get_irq(pdev, 0); irq_err = platform_get_irq(pdev, 0);
irq_dma = platform_get_irq(pdev, 1); irq_dma = platform_get_irq(pdev, 1);
if (!iores || !dmares || irq_err < 0 || irq_dma < 0) if (!iores || irq_err < 0 || irq_dma < 0)
return -EINVAL; return -EINVAL;
mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev);
@ -713,15 +726,31 @@ static int mxs_mmc_probe(struct platform_device *pdev)
goto out_mmc_free; goto out_mmc_free;
} }
host->devid = pdev->id_entry->driver_data; if (np) {
host->devid = (enum mxs_mmc_id) of_id->data;
/*
* TODO: This is a temporary solution and should be changed
* to use generic DMA binding later when the helpers get in.
*/
ret = of_property_read_u32(np, "fsl,ssp-dma-channel",
&host->dma_channel);
if (ret) {
dev_err(mmc_dev(host->mmc),
"failed to get dma channel\n");
goto out_mmc_free;
}
} else {
host->devid = pdev->id_entry->driver_data;
host->dma_channel = dmares->start;
}
host->mmc = mmc; host->mmc = mmc;
host->dma_channel = dmares->start;
host->sdio_irq_en = 0; host->sdio_irq_en = 0;
pinctrl = devm_pinctrl_get_select_default(&pdev->dev); pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) { if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl); ret = PTR_ERR(pinctrl);
goto out_iounmap; goto out_mmc_free;
} }
host->clk = clk_get(&pdev->dev, NULL); host->clk = clk_get(&pdev->dev, NULL);
@ -749,7 +778,15 @@ static int mxs_mmc_probe(struct platform_device *pdev)
MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
pdata = mmc_dev(host->mmc)->platform_data; pdata = mmc_dev(host->mmc)->platform_data;
if (pdata) { if (!pdata) {
u32 bus_width = 0;
of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
host->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
} else {
if (pdata->flags & SLOTF_8_BIT_CAPABLE) if (pdata->flags & SLOTF_8_BIT_CAPABLE)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
if (pdata->flags & SLOTF_4_BIT_CAPABLE) if (pdata->flags & SLOTF_4_BIT_CAPABLE)
@ -857,6 +894,7 @@ static struct platform_driver mxs_mmc_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.pm = &mxs_mmc_pm_ops, .pm = &mxs_mmc_pm_ops,
.of_match_table = mxs_mmc_dt_ids,
#endif #endif
}, },
}; };