mmc: sdhci-pxa: Add device tree support
authorChris Ball <cjb@laptop.org>
Wed, 11 Apr 2012 02:34:33 +0000 (22:34 -0400)
committerChris Ball <cjb@laptop.org>
Sat, 21 Jul 2012 04:01:47 +0000 (00:01 -0400)
Tested on an OLPC XO-1.75.  (MMP2, sdhci-pxav3, CONFIG_MACH_MMP2_DT=y)

Signed-off-by: Chris Ball <cjb@laptop.org>
Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Documentation/devicetree/bindings/mmc/sdhci-pxa.txt [new file with mode: 0644]
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
new file mode 100644 (file)
index 0000000..dbe98a3
--- /dev/null
@@ -0,0 +1,21 @@
+* Marvell sdhci-pxa v2/v3 controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
+
+Required properties:
+- compatible: Should be "mrvl,pxav2-mmc" or "mrvl,pxav3-mmc".
+
+Optional properties:
+- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
+
+Example:
+
+sdhci@d4280800 {
+       compatible = "mrvl,pxav3-mmc";
+       reg = <0xd4280800 0x800>;
+       bus-width = <8>;
+       interrupts = <27>;
+       non-removable;
+       mrvl,clk-delay-cycles = <31>;
+};
index dbb75bfbcffb3e181f6d0af195209e5187c3b210..b6ee8857e226fc163d53c1a66d52eda26121735d 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/mmc/host.h>
 #include <linux/platform_data/pxa_sdhci.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 
@@ -121,6 +124,48 @@ static struct sdhci_ops pxav2_sdhci_ops = {
        .platform_8bit_width = pxav2_mmc_set_width,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id sdhci_pxav2_of_match[] = {
+       {
+               .compatible = "mrvl,pxav2-mmc",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sdhci_pxav2_of_match);
+
+static struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev)
+{
+       struct sdhci_pxa_platdata *pdata;
+       struct device_node *np = dev->of_node;
+       u32 bus_width;
+       u32 clk_delay_cycles;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       if (of_find_property(np, "non-removable", NULL))
+               pdata->flags |= PXA_FLAG_CARD_PERMANENT;
+
+       of_property_read_u32(np, "bus-width", &bus_width);
+       if (bus_width == 8)
+               pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
+
+       of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
+       if (clk_delay_cycles > 0) {
+               pdata->clk_delay_sel = 1;
+               pdata->clk_delay_cycles = clk_delay_cycles;
+       }
+
+       return pdata;
+}
+#else
+static inline struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
 {
        struct sdhci_pltfm_host *pltfm_host;
@@ -128,6 +173,8 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct sdhci_host *host = NULL;
        struct sdhci_pxa *pxa = NULL;
+       const struct of_device_id *match;
+
        int ret;
        struct clk *clk;
 
@@ -156,6 +203,10 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
                | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
                | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
 
+       match = of_match_device(of_match_ptr(sdhci_pxav2_of_match), &pdev->dev);
+       if (match) {
+               pdata = pxav2_get_mmc_pdata(dev);
+       }
        if (pdata) {
                if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
                        /* on-chip device */
@@ -218,6 +269,9 @@ static struct platform_driver sdhci_pxav2_driver = {
        .driver         = {
                .name   = "sdhci-pxav2",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_OF
+               .of_match_table = sdhci_pxav2_of_match,
+#endif
                .pm     = SDHCI_PLTFM_PMOPS,
        },
        .probe          = sdhci_pxav2_probe,
index f29695683556df8f7c01ad6f145a9fc36583e410..07fe3834fe0b224119d0591672de48949dd18105 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 
@@ -164,6 +167,46 @@ static struct sdhci_ops pxav3_sdhci_ops = {
        .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id sdhci_pxav3_of_match[] = {
+       {
+               .compatible = "mrvl,pxav3-mmc",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
+
+static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
+{
+       struct sdhci_pxa_platdata *pdata;
+       struct device_node *np = dev->of_node;
+       u32 bus_width;
+       u32 clk_delay_cycles;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       if (of_find_property(np, "non-removable", NULL))
+               pdata->flags |= PXA_FLAG_CARD_PERMANENT;
+
+       of_property_read_u32(np, "bus-width", &bus_width);
+       if (bus_width == 8)
+               pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
+
+       of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
+       if (clk_delay_cycles > 0)
+               pdata->clk_delay_cycles = clk_delay_cycles;
+
+       return pdata;
+}
+#else
+static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
 {
        struct sdhci_pltfm_host *pltfm_host;
@@ -171,6 +214,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct sdhci_host *host = NULL;
        struct sdhci_pxa *pxa = NULL;
+       const struct of_device_id *match;
+
        int ret;
        struct clk *clk;
 
@@ -202,6 +247,10 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
        /* enable 1/8V DDR capable */
        host->mmc->caps |= MMC_CAP_1_8V_DDR;
 
+       match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
+       if (match)
+               pdata = pxav3_get_mmc_pdata(dev);
+
        if (pdata) {
                if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
                        /* on-chip device */
@@ -263,6 +312,9 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev)
 static struct platform_driver sdhci_pxav3_driver = {
        .driver         = {
                .name   = "sdhci-pxav3",
+#ifdef CONFIG_OF
+               .of_match_table = sdhci_pxav3_of_match,
+#endif
                .owner  = THIS_MODULE,
                .pm     = SDHCI_PLTFM_PMOPS,
        },