TI DaVinci MUSB driver equipped with DeviceTree support.
Tested with AM1808 board and USB2.0 (OTG) in host mode.

Signed-off-by: Petr Kulhavy <p...@barix.com>
---
 .../devicetree/bindings/usb/da8xx-usb.txt          |  52 +++++++
 drivers/usb/musb/da8xx.c                           | 166 +++++++++++++++++++++
 include/linux/platform_data/usb-davinci.h          |   3 +-
 3 files changed, 220 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/usb/da8xx-usb.txt

diff --git a/Documentation/devicetree/bindings/usb/da8xx-usb.txt 
b/Documentation/devicetree/bindings/usb/da8xx-usb.txt
new file mode 100644
index 0000000..c81d665
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/da8xx-usb.txt
@@ -0,0 +1,52 @@
+TI DaVinci MUSB
+
+Required properties:
+
+ - compatible : Should be "ti,da850-musb" or "ti,da830-musb"
+
+ - mode : USB mode. "1" signifies HOST, "2" represents PERIPHERAL,
+     "3" represents OTG.
+
+ - power : This signifies the maximum current the controller can
+     supply in host mode. The unit size is 2mA, the maximum value is 510mA.
+
+ - num-eps : Specifies the number of endpoints. This is also a
+     MUSB configuration-specific setting.
+
+ - multipoint : Should be "1" indicating the musb controller supports
+     multipoint. This is a MUSB configuration-specific setting.
+
+ - ram-bits : Specifies the ram address size.
+
+
+Optional properties:
+
+ - da8xx,phy20-clkmux-cfg: Integer. Defines the USB 2.0 PHY reference clock 
source.
+     Supported values: "0" for external pin, "1" for internal PLL.
+
+ - da8xx,phy20-refclock-frequency : Integer. Defines the USB 2.0 PHY reference 
clock input
+     frequency in Hz in case the clock is generated by the internal PLL.
+     Supported values are 12MHz, 13MHz, 19.2MHz, 20MHz, 24MHz, 26MHz, 38.4MHz, 
40MHz, 48MHz
+
+
+Example:
+
+       usb20: usb@1e00000 {
+               compatible = "ti,da850-musb";
+               ti,hwmods = "usb_otg_hs";
+               reg =   <0x00200000 0x10000>;
+               interrupt-parent = <&intc>;
+               interrupts = <58>;
+               interrupt-names = "mc";
+
+               multipoint = <1>;
+               num-eps = <5>;
+               ram-bits = <10>;
+               mode = <1>;             /* host */
+               power = <250>;          /* max power 500mA */
+
+               da8xx,phy20-clkmux-cfg = <1>;   /* PHY clock internally 
generated from the PLL */
+               da8xx,phy20-refclock-frequency = <24000000>;
+
+               status = "okay";
+       };
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 4e13fe2..2c00e98 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -1,6 +1,9 @@
 /*
  * Texas Instruments DA8xx/OMAP-L1x "glue layer"
  *
+ * DT support
+ * Copyright (c) 2015-2016 Petr Kulhavy, Barix AG <p...@barix.com>
+ *
  * Copyright (c) 2008-2009 MontaVista Software, Inc. <sou...@mvista.com>
  *
  * Based on the DaVinci "glue layer" code.
@@ -36,6 +39,7 @@
 
 #include <mach/da8xx.h>
 #include <linux/platform_data/usb-davinci.h>
+#include <linux/of_platform.h>
 
 #include "musb_core.h"
 
@@ -134,6 +138,35 @@ static inline void phy_off(void)
        __raw_writel(cfgchip2, CFGCHIP2);
 }
 
+/* converts PHY refclk frequency in HZ into USB0REF_FREQ config value
+ * on unsupported frequency returns -1
+ */
+static inline int phy_refclk_cfg(int frequency)
+{
+       switch (frequency) {
+       case 12000000:
+               return 0x01;
+       case 13000000:
+               return 0x06;
+       case 19200000:
+               return 0x05;
+       case 20000000:
+               return 0x08;
+       case 24000000:
+               return 0x02;
+       case 26000000:
+               return 0x07;
+       case 38400000:
+               return 0x05;
+       case 40000000:
+               return 0x09;
+       case 48000000:
+               return 0x03;
+       default:
+               return -1;
+       }
+}
+
 /*
  * Because we don't set CTRL.UINT, it's "important" to:
  *     - not read/write INTRUSB/INTRUSBE (except during
@@ -527,6 +560,8 @@ static const struct platform_device_info da8xx_dev_info = {
        .dma_mask       = DMA_BIT_MASK(32),
 };
 
+static u64 da8xx_dmamask = DMA_BIT_MASK(32);
+
 static int da8xx_probe(struct platform_device *pdev)
 {
        struct resource musb_resources[2];
@@ -535,6 +570,7 @@ static int da8xx_probe(struct platform_device *pdev)
        struct da8xx_glue               *glue;
        struct platform_device_info     pinfo;
        struct clk                      *clk;
+       struct device_node              *np = pdev->dev.of_node;
 
        int                             ret = -ENOMEM;
 
@@ -560,6 +596,120 @@ static int da8xx_probe(struct platform_device *pdev)
        glue->dev                       = &pdev->dev;
        glue->clk                       = clk;
 
+       if (np) {
+               struct musb_hdrc_config *config;
+               struct musb_hdrc_platform_data *data;
+               u32 phy20_refclock_freq, phy20_clkmux_cfg;
+
+               pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+               if (!pdata) {
+                       ret = -ENOMEM;
+                       goto err5;
+               }
+
+               data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+               if (!data) {
+                       ret = -ENOMEM;
+                       goto err5;
+               }
+
+               config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
+               if (!config) {
+                       ret = -ENOMEM;
+                       goto err5;
+               }
+
+               if (of_property_read_u32(np, "mode", (u32 *)&pdata->mode)) {
+                       dev_err(&pdev->dev,
+                               "failed to read the USB mode parameter\n");
+                       ret = -EINVAL;
+                       goto err5;
+               }
+
+               if (of_property_read_u32(np, "num-eps",
+                       (u32 *)&config->num_eps)) {
+                       dev_err(&pdev->dev,
+                               "failed to read the number of endpoints\n");
+                       ret = -EINVAL;
+                       goto err5;
+               }
+
+               if (of_property_read_u32(np, "ram-bits",
+                       (u32 *)&config->ram_bits)) {
+                       dev_err(&pdev->dev,
+                               "failed to read the ram-bits parameter\n");
+                       ret = -EINVAL;
+                       goto err5;
+               }
+
+               if (of_property_read_u32(np, "power", (u32 *)&pdata->power)) {
+                       dev_err(&pdev->dev,
+                               "failed to read the maximum power parameter\n");
+                       ret = -EINVAL;
+                       goto err5;
+               }
+
+               config->multipoint = of_property_read_bool(np, "multipoint");
+
+               pdata->board_data       = data;
+               pdata->config           = config;
+
+               /* optional parameter reference clock frequency */
+               if (!of_property_read_u32(np, "da8xx,phy20-clkmux-cfg",
+                       &phy20_clkmux_cfg)) {
+                       u32 cfgchip2;
+
+                       /*
+                        * Select internal reference clock for USB 2.0 PHY
+                        * and use it as a clock source for USB 1.1 PHY
+                        * (this is the default setting anyway).
+                        */
+
+                       cfgchip2 = __raw_readl(
+                               DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+                       cfgchip2 &= ~CFGCHIP2_USB2PHYCLKMUX;
+                       cfgchip2 |=  (phy20_clkmux_cfg & 1) <<
+                                       CFGCHIP2_USB2PHYCLKMUX_OFFSET;
+
+                       __raw_writel(cfgchip2,
+                                    DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+               }
+
+               /* optional parameter reference clock frequency */
+               if (!of_property_read_u32(np, "da8xx,phy20-refclock-frequency",
+                       &phy20_refclock_freq)) {
+                       u32 cfgchip2;
+                       int phy20_refclk_cfg;
+
+                       phy20_refclk_cfg = phy_refclk_cfg(phy20_refclock_freq);
+                       if (phy20_refclk_cfg < 0) {
+                               dev_err(&pdev->dev,
+                                       "invalid PHY clock frequency %u Hz\n",
+                                       phy20_refclock_freq);
+                               ret = -EINVAL;
+                               goto err5;
+                       }
+
+                       /*
+                        * Set up USB clock/mode in the CFGCHIP2 register.
+                        */
+                       cfgchip2 = __raw_readl(
+                               DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+                       /* USB2.0 PHY reference clock is 24 MHz */
+                       cfgchip2 &= ~CFGCHIP2_REFFREQ;
+                       cfgchip2 |=  phy20_refclk_cfg;
+
+                       __raw_writel(cfgchip2,
+                                    DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+               }
+
+               musb->dev.dma_mask = &da8xx_dmamask;
+               musb->dev.coherent_dma_mask = da8xx_dmamask;
+       }
+
        pdata->platform_ops             = &da8xx_ops;
 
        glue->phy = usb_phy_generic_register();
@@ -627,11 +777,27 @@ static int da8xx_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id da8xx_id_table[] = {
+       {
+               .compatible = "ti,da850-musb"
+       },
+       {
+               .compatible = "ti,da830-musb"
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, da8xx_id_table);
+#endif
+
 static struct platform_driver da8xx_driver = {
        .probe          = da8xx_probe,
        .remove         = da8xx_remove,
        .driver         = {
                .name   = "musb-da8xx",
+#ifdef CONFIG_OF
+               .of_match_table = of_match_ptr(da8xx_id_table),
+#endif
        },
 };
 
diff --git a/include/linux/platform_data/usb-davinci.h 
b/include/linux/platform_data/usb-davinci.h
index e0bc4ab..bd2a5a9 100644
--- a/include/linux/platform_data/usb-davinci.h
+++ b/include/linux/platform_data/usb-davinci.h
@@ -21,7 +21,8 @@
 #define CFGCHIP2_FORCE_DEVICE  (2 << 13)
 #define CFGCHIP2_FORCE_HOST_VBUS_LOW (3 << 13)
 #define CFGCHIP2_USB1PHYCLKMUX (1 << 12)
-#define CFGCHIP2_USB2PHYCLKMUX (1 << 11)
+#define CFGCHIP2_USB2PHYCLKMUX_OFFSET  (11)
+#define CFGCHIP2_USB2PHYCLKMUX (1 << CFGCHIP2_USB2PHYCLKMUX_OFFSET)
 #define CFGCHIP2_PHYPWRDN      (1 << 10)
 #define CFGCHIP2_OTGPWRDN      (1 << 9)
 #define CFGCHIP2_DATPOL        (1 << 8)
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to