diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2012-05-06 01:30:44 -0400 |
---|---|---|
committer | Shawn Guo <shawn.guo@linaro.org> | 2012-05-12 20:27:37 -0400 |
commit | 6de4d817aa38ea74dd446d015c8ed62a3ebaeafb (patch) | |
tree | b2eb13af33b8be6030348eecc78a5e6dd3483399 | |
parent | 31b0ff5e7390a955f0d7279ab922e4b41469729d (diff) |
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>
-rw-r--r-- | Documentation/devicetree/bindings/mmc/mxs-mmc.txt | 25 | ||||
-rw-r--r-- | drivers/mmc/host/mxs-mmc.c | 48 |
2 files changed, 68 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/mmc/mxs-mmc.txt b/Documentation/devicetree/bindings/mmc/mxs-mmc.txt new file mode 100644 index 000000000000..14d870a9e3db --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/mxs-mmc.txt | |||
@@ -0,0 +1,25 @@ | |||
1 | * Freescale MXS MMC controller | ||
2 | |||
3 | The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller | ||
4 | to support MMC, SD, and SDIO types of memory cards. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: Should be "fsl,<chip>-mmc". The supported chips include | ||
8 | imx23 and imx28. | ||
9 | - reg: Should contain registers location and length | ||
10 | - interrupts: Should contain ERROR and DMA interrupts | ||
11 | - fsl,ssp-dma-channel: APBH DMA channel for the SSP | ||
12 | - bus-width: Number of data lines, can be <1>, <4>, or <8> | ||
13 | |||
14 | Optional properties: | ||
15 | - wp-gpios: Specify GPIOs for write protection | ||
16 | |||
17 | Examples: | ||
18 | |||
19 | ssp0: ssp@80010000 { | ||
20 | compatible = "fsl,imx28-mmc"; | ||
21 | reg = <0x80010000 2000>; | ||
22 | interrupts = <96 82>; | ||
23 | fsl,ssp-dma-channel = <0>; | ||
24 | bus-width = <8>; | ||
25 | }; | ||
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 76232dd277c9..34a90266ab11 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c | |||
@@ -23,6 +23,9 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <linux/of.h> | ||
27 | #include <linux/of_device.h> | ||
28 | #include <linux/of_gpio.h> | ||
26 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
27 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
28 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
@@ -685,8 +688,18 @@ static struct platform_device_id mxs_mmc_ids[] = { | |||
685 | }; | 688 | }; |
686 | MODULE_DEVICE_TABLE(platform, mxs_mmc_ids); | 689 | MODULE_DEVICE_TABLE(platform, mxs_mmc_ids); |
687 | 690 | ||
691 | static const struct of_device_id mxs_mmc_dt_ids[] = { | ||
692 | { .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_MMC, }, | ||
693 | { .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_MMC, }, | ||
694 | { /* sentinel */ } | ||
695 | }; | ||
696 | MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids); | ||
697 | |||
688 | static int mxs_mmc_probe(struct platform_device *pdev) | 698 | static int mxs_mmc_probe(struct platform_device *pdev) |
689 | { | 699 | { |
700 | const struct of_device_id *of_id = | ||
701 | of_match_device(mxs_mmc_dt_ids, &pdev->dev); | ||
702 | struct device_node *np = pdev->dev.of_node; | ||
690 | struct mxs_mmc_host *host; | 703 | struct mxs_mmc_host *host; |
691 | struct mmc_host *mmc; | 704 | struct mmc_host *mmc; |
692 | struct resource *iores, *dmares; | 705 | struct resource *iores, *dmares; |
@@ -699,7 +712,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) | |||
699 | dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 712 | dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
700 | irq_err = platform_get_irq(pdev, 0); | 713 | irq_err = platform_get_irq(pdev, 0); |
701 | irq_dma = platform_get_irq(pdev, 1); | 714 | irq_dma = platform_get_irq(pdev, 1); |
702 | if (!iores || !dmares || irq_err < 0 || irq_dma < 0) | 715 | if (!iores || irq_err < 0 || irq_dma < 0) |
703 | return -EINVAL; | 716 | return -EINVAL; |
704 | 717 | ||
705 | mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); | 718 | mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); |
@@ -713,15 +726,31 @@ static int mxs_mmc_probe(struct platform_device *pdev) | |||
713 | goto out_mmc_free; | 726 | goto out_mmc_free; |
714 | } | 727 | } |
715 | 728 | ||
716 | host->devid = pdev->id_entry->driver_data; | 729 | if (np) { |
730 | host->devid = (enum mxs_mmc_id) of_id->data; | ||
731 | /* | ||
732 | * TODO: This is a temporary solution and should be changed | ||
733 | * to use generic DMA binding later when the helpers get in. | ||
734 | */ | ||
735 | ret = of_property_read_u32(np, "fsl,ssp-dma-channel", | ||
736 | &host->dma_channel); | ||
737 | if (ret) { | ||
738 | dev_err(mmc_dev(host->mmc), | ||
739 | "failed to get dma channel\n"); | ||
740 | goto out_mmc_free; | ||
741 | } | ||
742 | } else { | ||
743 | host->devid = pdev->id_entry->driver_data; | ||
744 | host->dma_channel = dmares->start; | ||
745 | } | ||
746 | |||
717 | host->mmc = mmc; | 747 | host->mmc = mmc; |
718 | host->dma_channel = dmares->start; | ||
719 | host->sdio_irq_en = 0; | 748 | host->sdio_irq_en = 0; |
720 | 749 | ||
721 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | 750 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); |
722 | if (IS_ERR(pinctrl)) { | 751 | if (IS_ERR(pinctrl)) { |
723 | ret = PTR_ERR(pinctrl); | 752 | ret = PTR_ERR(pinctrl); |
724 | goto out_iounmap; | 753 | goto out_mmc_free; |
725 | } | 754 | } |
726 | 755 | ||
727 | host->clk = clk_get(&pdev->dev, NULL); | 756 | host->clk = clk_get(&pdev->dev, NULL); |
@@ -749,7 +778,15 @@ static int mxs_mmc_probe(struct platform_device *pdev) | |||
749 | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; | 778 | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; |
750 | 779 | ||
751 | pdata = mmc_dev(host->mmc)->platform_data; | 780 | pdata = mmc_dev(host->mmc)->platform_data; |
752 | if (pdata) { | 781 | if (!pdata) { |
782 | u32 bus_width = 0; | ||
783 | of_property_read_u32(np, "bus-width", &bus_width); | ||
784 | if (bus_width == 4) | ||
785 | mmc->caps |= MMC_CAP_4_BIT_DATA; | ||
786 | else if (bus_width == 8) | ||
787 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; | ||
788 | host->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); | ||
789 | } else { | ||
753 | if (pdata->flags & SLOTF_8_BIT_CAPABLE) | 790 | if (pdata->flags & SLOTF_8_BIT_CAPABLE) |
754 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; | 791 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; |
755 | if (pdata->flags & SLOTF_4_BIT_CAPABLE) | 792 | if (pdata->flags & SLOTF_4_BIT_CAPABLE) |
@@ -857,6 +894,7 @@ static struct platform_driver mxs_mmc_driver = { | |||
857 | .owner = THIS_MODULE, | 894 | .owner = THIS_MODULE, |
858 | #ifdef CONFIG_PM | 895 | #ifdef CONFIG_PM |
859 | .pm = &mxs_mmc_pm_ops, | 896 | .pm = &mxs_mmc_pm_ops, |
897 | .of_match_table = mxs_mmc_dt_ids, | ||
860 | #endif | 898 | #endif |
861 | }, | 899 | }, |
862 | }; | 900 | }; |