usb: musb: ux500: add device tree probing support
authorLee Jones <lee.jones@linaro.org>
Wed, 15 May 2013 09:51:48 +0000 (10:51 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 4 Jun 2013 09:12:05 +0000 (11:12 +0200)
This patch will allow ux500-musb to be probed and configured solely from
configuration found in Device Tree.

Cc: Rob Herring <rob.herring@calxeda.com>
Cc: linux-usb@vger.kernel.org
Cc: devicetree-discuss@lists.ozlabs.org
Acked-by: Felipe Balbi <balbi@ti.com>
Acked-by: Fabio Baltieri <fabio.baltieri@linaro.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Documentation/devicetree/bindings/usb/ux500-usb.txt [new file with mode: 0644]
drivers/usb/musb/ux500.c

diff --git a/Documentation/devicetree/bindings/usb/ux500-usb.txt b/Documentation/devicetree/bindings/usb/ux500-usb.txt
new file mode 100644 (file)
index 0000000..330d6ec
--- /dev/null
@@ -0,0 +1,50 @@
+Ux500 MUSB
+
+Required properties:
+ - compatible : Should be "stericsson,db8500-musb"
+ - reg        : Offset and length of registers
+ - interrupts : Interrupt; mode, number and trigger
+ - dr_mode    : Dual-role; either host mode "host", peripheral mode "peripheral"
+                or both "otg"
+
+Optional properties:
+ - dmas       : A list of dma channels;
+                dma-controller, event-line, fixed-channel, flags
+ - dma-names  : An ordered list of channel names affiliated to the above
+
+Example:
+
+usb_per5@a03e0000 {
+       compatible = "stericsson,db8500-musb", "mentor,musb";
+       reg = <0xa03e0000 0x10000>;
+       interrupts = <0 23 0x4>;
+       interrupt-names = "mc";
+
+       dr_mode = "otg";
+
+       dmas = <&dma 38 0 0x2>, /* Logical - DevToMem */
+              <&dma 38 0 0x0>, /* Logical - MemToDev */
+              <&dma 37 0 0x2>, /* Logical - DevToMem */
+              <&dma 37 0 0x0>, /* Logical - MemToDev */
+              <&dma 36 0 0x2>, /* Logical - DevToMem */
+              <&dma 36 0 0x0>, /* Logical - MemToDev */
+              <&dma 19 0 0x2>, /* Logical - DevToMem */
+              <&dma 19 0 0x0>, /* Logical - MemToDev */
+              <&dma 18 0 0x2>, /* Logical - DevToMem */
+              <&dma 18 0 0x0>, /* Logical - MemToDev */
+              <&dma 17 0 0x2>, /* Logical - DevToMem */
+              <&dma 17 0 0x0>, /* Logical - MemToDev */
+              <&dma 16 0 0x2>, /* Logical - DevToMem */
+              <&dma 16 0 0x0>, /* Logical - MemToDev */
+              <&dma 39 0 0x2>, /* Logical - DevToMem */
+              <&dma 39 0 0x0>; /* Logical - MemToDev */
+
+       dma-names = "iep_1_9",  "oep_1_9",
+                   "iep_2_10", "oep_2_10",
+                   "iep_3_11", "oep_3_11",
+                   "iep_4_12", "oep_4_12",
+                   "iep_5_13", "oep_5_13",
+                   "iep_6_14", "oep_6_14",
+                   "iep_7_15", "oep_7_15",
+                   "iep_8",    "oep_8";
+};
index 3cf10bc..f0beee7 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/usb/musb-ux500.h>
 
@@ -194,14 +195,57 @@ static const struct musb_platform_ops ux500_ops = {
        .set_vbus       = ux500_musb_set_vbus,
 };
 
+static struct musb_hdrc_platform_data *
+ux500_of_probe(struct platform_device *pdev, struct device_node *np)
+{
+       struct musb_hdrc_platform_data *pdata;
+       const char *mode;
+       int strlen;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       mode = of_get_property(np, "dr_mode", &strlen);
+       if (!mode) {
+               dev_err(&pdev->dev, "No 'dr_mode' property found\n");
+               return NULL;
+       }
+
+       if (strlen > 0) {
+               if (!strcmp(mode, "host"))
+                       pdata->mode = MUSB_HOST;
+               if (!strcmp(mode, "otg"))
+                       pdata->mode = MUSB_OTG;
+               if (!strcmp(mode, "peripheral"))
+                       pdata->mode = MUSB_PERIPHERAL;
+       }
+
+       return pdata;
+}
+
 static int ux500_probe(struct platform_device *pdev)
 {
        struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
+       struct device_node              *np = pdev->dev.of_node;
        struct platform_device          *musb;
        struct ux500_glue               *glue;
        struct clk                      *clk;
        int                             ret = -ENOMEM;
 
+       if (!pdata) {
+               if (np) {
+                       pdata = ux500_of_probe(pdev, np);
+                       if (!pdata)
+                               goto err0;
+
+                       pdev->dev.platform_data = pdata;
+               } else {
+                       dev_err(&pdev->dev, "no pdata or device tree found\n");
+                       goto err0;
+               }
+       }
+
        glue = kzalloc(sizeof(*glue), GFP_KERNEL);
        if (!glue) {
                dev_err(&pdev->dev, "failed to allocate glue context\n");
@@ -230,6 +274,7 @@ static int ux500_probe(struct platform_device *pdev)
        musb->dev.parent                = &pdev->dev;
        musb->dev.dma_mask              = &pdev->dev.coherent_dma_mask;
        musb->dev.coherent_dma_mask     = pdev->dev.coherent_dma_mask;
+       musb->dev.of_node               = pdev->dev.of_node;
 
        glue->dev                       = &pdev->dev;
        glue->musb                      = musb;
@@ -328,12 +373,18 @@ static const struct dev_pm_ops ux500_pm_ops = {
 #define DEV_PM_OPS     NULL
 #endif
 
+static const struct of_device_id ux500_match[] = {
+        { .compatible = "stericsson,db8500-musb", },
+        {}
+};
+
 static struct platform_driver ux500_driver = {
        .probe          = ux500_probe,
        .remove         = ux500_remove,
        .driver         = {
                .name   = "musb-ux500",
                .pm     = DEV_PM_OPS,
+               .of_match_table = ux500_match,
        },
 };