mmc: mxcmmc: DT support
Adding devicetree support for imx21-mmc and imx31-mmc. Based on generic
gpio helper functions by Guennadi and generic DMA devicetree bindings.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-mmc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-mmc.txt
new file mode 100644
index 0000000..db44235
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/fsl-imx-mmc.txt
@@ -0,0 +1,24 @@
+* Freescale Secure Digital Host Controller for i.MX2/3 series
+
+This file documents differences to the properties defined in mmc.txt.
+
+Required properties:
+- compatible : Should be "fsl,<chip>-mmc", chip can be imx21 or imx31
+
+Optional properties:
+- dmas: One DMA phandle with arguments as defined by the devicetree bindings
+ of the used DMA controller.
+- dma-names: Has to be "rx-tx".
+
+Example:
+
+sdhci1: sdhci@10014000 {
+ compatible = "fsl,imx27-mmc", "fsl,imx21-mmc";
+ reg = <0x10014000 0x1000>;
+ interrupts = <11>;
+ dmas = <&dma 7>;
+ dma-names = "rx-tx";
+ bus-width = <4>;
+ cd-gpios = <&gpio3 29>;
+ status = "okay";
+};
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 28e527e..848ab2c 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -34,6 +34,10 @@
#include <linux/regulator/consumer.h>
#include <linux/dmaengine.h>
#include <linux/types.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/of_gpio.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -173,6 +177,19 @@
};
MODULE_DEVICE_TABLE(platform, mxcmci_devtype);
+static const struct of_device_id mxcmci_of_match[] = {
+ {
+ .compatible = "fsl,imx21-mmc",
+ .data = &mxcmci_devtype[IMX21_MMC],
+ }, {
+ .compatible = "fsl,imx31-mmc",
+ .data = &mxcmci_devtype[IMX31_MMC],
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, mxcmci_of_match);
+
static inline int is_imx31_mmc(struct mxcmci_host *host)
{
return host->devtype == IMX31_MMC;
@@ -935,10 +952,15 @@
struct mxcmci_host *host = NULL;
struct resource *iores, *r;
int ret = 0, irq;
+ bool dat3_card_detect = false;
dma_cap_mask_t mask;
+ const struct of_device_id *of_id;
+ struct imxmmc_platform_data *pdata = pdev->dev.platform_data;
pr_info("i.MX SDHC driver\n");
+ of_id = of_match_device(mxcmci_of_match, &pdev->dev);
+
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!iores || irq < 0)
@@ -954,8 +976,14 @@
goto out_release_mem;
}
+ mmc_of_parse(mmc);
mmc->ops = &mxcmci_ops;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+
+ /* For devicetree parsing, the bus width is read from devicetree */
+ if (pdata)
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+ else
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
/* MMC core transfer sizes tunable parameters */
mmc->max_segs = 64;
@@ -971,14 +999,25 @@
goto out_free;
}
+ if (of_id) {
+ const struct platform_device_id *id_entry = of_id->data;
+ host->devtype = id_entry->driver_data;
+ } else {
+ host->devtype = pdev->id_entry->driver_data;
+ }
host->mmc = mmc;
- host->pdata = pdev->dev.platform_data;
- host->devtype = pdev->id_entry->driver_data;
+ host->pdata = pdata;
spin_lock_init(&host->lock);
+ if (pdata)
+ dat3_card_detect = pdata->dat3_card_detect;
+ else if (!(mmc->caps & MMC_CAP_NONREMOVABLE)
+ && !of_property_read_bool(pdev->dev.of_node, "cd-gpios"))
+ dat3_card_detect = true;
+
mxcmci_init_ocr(host);
- if (host->pdata && host->pdata->dat3_card_detect)
+ if (dat3_card_detect)
host->default_irq_mask =
INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN;
else
@@ -1020,21 +1059,24 @@
writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR);
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (r) {
- host->dmareq = r->start;
- host->dma_data.peripheral_type = IMX_DMATYPE_SDHC;
- host->dma_data.priority = DMA_PRIO_LOW;
- host->dma_data.dma_request = host->dmareq;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- host->dma = dma_request_channel(mask, filter, host);
- if (host->dma)
- mmc->max_seg_size = dma_get_max_seg_size(
- host->dma->device->dev);
+ if (!host->pdata) {
+ host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx");
+ } else {
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (r) {
+ host->dmareq = r->start;
+ host->dma_data.peripheral_type = IMX_DMATYPE_SDHC;
+ host->dma_data.priority = DMA_PRIO_LOW;
+ host->dma_data.dma_request = host->dmareq;
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ host->dma = dma_request_channel(mask, filter, host);
+ }
}
-
- if (!host->dma)
+ if (host->dma)
+ mmc->max_seg_size = dma_get_max_seg_size(
+ host->dma->device->dev);
+ else
dev_info(mmc_dev(host->mmc), "dma not available. Using PIO\n");
INIT_WORK(&host->datawork, mxcmci_datawork);
@@ -1153,6 +1195,7 @@
#ifdef CONFIG_PM
.pm = &mxcmci_pm_ops,
#endif
+ .of_match_table = mxcmci_of_match,
}
};