Adds DT support for the TI DA830 and DA850 USB driver.

Signed-off-by: Petr Kulhavy <[email protected]>
---
 drivers/usb/musb/da8xx.c     | 136 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/musb/musb_core.c |  24 ++++++++
 drivers/usb/musb/musb_core.h |   2 +
 3 files changed, 162 insertions(+)

diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index b03d3b8..6573600 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) 2016 Petr Kulhavy, Barix AG <[email protected]>
+ *
  * Copyright (c) 2008-2009 MontaVista Software, Inc. <[email protected]>
  *
  * 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
@@ -482,6 +515,8 @@ static const struct platform_device_info da8xx_dev_info = {
        .dma_mask       = DMA_BIT_MASK(32),
 };
 
+static const struct of_device_id da8xx_id_table[];
+
 static int da8xx_probe(struct platform_device *pdev)
 {
        struct resource musb_resources[2];
@@ -490,6 +525,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;
 
@@ -515,6 +551,90 @@ static int da8xx_probe(struct platform_device *pdev)
        glue->dev                       = &pdev->dev;
        glue->clk                       = clk;
 
+       if (IS_ENABLED(CONFIG_OF) && np) {
+               const struct of_device_id *match;
+               const struct musb_hdrc_config *matched_config;
+               struct musb_hdrc_config *config;
+               struct musb_hdrc_platform_data *data;
+               u32 phy20_refclock_freq, phy20_clkmux_cfg;
+               u32 cfgchip2;
+               unsigned power_ma;
+               int ret;
+
+               match = of_match_device(da8xx_id_table, &pdev->dev);
+               if (!match) {
+                       ret = -ENODEV;
+                       goto err5;
+               }
+               matched_config = match->data;
+
+               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;
+               }
+
+               config->num_eps         = matched_config->num_eps;
+               config->ram_bits        = matched_config->ram_bits;
+               config->multipoint      = matched_config->multipoint;
+               pdata->config           = config;
+               pdata->board_data       = data;
+               pdata->mode             = musb_get_dr_mode(&pdev->dev);
+
+               ret = of_property_read_u32(np, "mentor,power", &power_ma);
+               if (ret)
+                       power_ma = 0;
+
+               /* the "mentor,power" value is in milli-amps, whereas
+                * the mentor configuration is in 2mA units
+                */
+               pdata->power = power_ma / 2;
+
+               /* optional parameter reference clock frequency
+                * true = use PLL, false = use external clock pin
+                */
+               phy20_clkmux_cfg =
+                       of_property_read_bool(np, "ti,phy20-clkmux-pll") ?
+                       CFGCHIP2_USB2PHYCLKMUX : 0;
+
+               cfgchip2 = __raw_readl(CFGCHIP2);
+               cfgchip2 &= ~CFGCHIP2_USB2PHYCLKMUX;
+               cfgchip2 |=  phy20_clkmux_cfg;
+               __raw_writel(cfgchip2, CFGCHIP2);
+
+               /* optional parameter reference clock frequency */
+               if (!of_property_read_u32(np, "ti,phy20-refclock-frequency",
+                       &phy20_refclock_freq)) {
+                       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;
+                       }
+
+                       cfgchip2 = __raw_readl(CFGCHIP2);
+                       cfgchip2 &= ~CFGCHIP2_REFFREQ;
+                       cfgchip2 |=  phy20_refclk_cfg;
+                       __raw_writel(cfgchip2, CFGCHIP2);
+               }
+       }
+
        pdata->platform_ops             = &da8xx_ops;
 
        glue->phy = usb_phy_generic_register();
@@ -582,11 +702,27 @@ static int da8xx_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct musb_hdrc_config da830_config = {
+       .ram_bits = 10,
+       .num_eps = 5,
+       .multipoint = 1,
+};
+
+static const struct of_device_id da8xx_id_table[] = {
+       {
+               .compatible = "ti,da830-musb",
+               .data = &da830_config,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, da8xx_id_table);
+
 static struct platform_driver da8xx_driver = {
        .probe          = da8xx_probe,
        .remove         = da8xx_remove,
        .driver         = {
                .name   = "musb-da8xx",
+               .of_match_table = of_match_ptr(da8xx_id_table),
        },
 };
 
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index c3791a0..284bf66 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -100,6 +100,7 @@
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <linux/usb.h>
+#include <linux/usb/of.h>
 
 #include "musb_core.h"
 
@@ -129,6 +130,29 @@ static inline struct musb *dev_to_musb(struct device *dev)
        return dev_get_drvdata(dev);
 }
 
+enum musb_mode musb_get_dr_mode(struct device *dev)
+{
+       enum usb_dr_mode mode;
+
+       mode = usb_get_dr_mode(dev);
+       switch (mode) {
+       case USB_DR_MODE_HOST:
+               return MUSB_HOST;
+
+       case USB_DR_MODE_PERIPHERAL:
+               return MUSB_PERIPHERAL;
+
+       case USB_DR_MODE_OTG:
+               return MUSB_OTG;
+
+       default:
+               return MUSB_UNDEFINED;
+       }
+}
+EXPORT_SYMBOL_GPL(musb_get_dr_mode);
+
+
+
 /*-------------------------------------------------------------------------*/
 
 #ifndef CONFIG_BLACKFIN
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index fd215fb..7fcc104 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -614,4 +614,6 @@ static inline void musb_platform_post_root_reset_end(struct 
musb *musb)
                musb->ops->post_root_reset_end(musb);
 }
 
+extern enum musb_mode musb_get_dr_mode(struct device *dev);
+
 #endif /* __MUSB_CORE_H__ */
-- 
1.9.1

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

Reply via email to