]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/usb/musb/da8xx.c
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux...
[karo-tx-linux.git] / drivers / usb / musb / da8xx.c
index 2440f88e07a35781433ba501fd60d8cf0b246431..e89708d839e504d772727a6be7b0623964e6f6d1 100644 (file)
@@ -6,6 +6,9 @@
  * Based on the DaVinci "glue layer" code.
  * Copyright (C) 2005-2006 by Texas Instruments
  *
+ * DT support
+ * Copyright (c) 2016 Petr Kulhavy <petr@barix.com>
+ *
  * This file is part of the Inventra Controller Driver for Linux.
  *
  * The Inventra Controller Driver for Linux is free software; you
@@ -340,6 +343,13 @@ static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode)
        struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent);
        enum phy_mode phy_mode;
 
+       /*
+        * The PHY has some issues when it is forced in device or host mode.
+        * Unless the user request another mode, configure the PHY in OTG mode.
+        */
+       if (!musb->is_initialized)
+               return phy_set_mode(glue->phy, PHY_MODE_USB_OTG);
+
        switch (musb_mode) {
        case MUSB_HOST:         /* Force VBUS valid, ID = 0 */
                phy_mode = PHY_MODE_USB_HOST;
@@ -366,6 +376,12 @@ static int da8xx_musb_init(struct musb *musb)
 
        musb->mregs += DA8XX_MENTOR_CORE_OFFSET;
 
+       ret = clk_prepare_enable(glue->clk);
+       if (ret) {
+               dev_err(glue->dev, "failed to enable clock\n");
+               return ret;
+       }
+
        /* Returns zero if e.g. not clocked */
        rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG);
        if (!rev)
@@ -377,12 +393,6 @@ static int da8xx_musb_init(struct musb *musb)
                goto fail;
        }
 
-       ret = clk_prepare_enable(glue->clk);
-       if (ret) {
-               dev_err(glue->dev, "failed to enable clock\n");
-               goto fail;
-       }
-
        setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);
 
        /* Reset the controller */
@@ -392,7 +402,7 @@ static int da8xx_musb_init(struct musb *musb)
        ret = phy_init(glue->phy);
        if (ret) {
                dev_err(glue->dev, "Failed to init phy.\n");
-               goto err_phy_init;
+               goto fail;
        }
 
        ret = phy_power_on(glue->phy);
@@ -412,9 +422,8 @@ static int da8xx_musb_init(struct musb *musb)
 
 err_phy_power_on:
        phy_exit(glue->phy);
-err_phy_init:
-       clk_disable_unprepare(glue->clk);
 fail:
+       clk_disable_unprepare(glue->clk);
        return ret;
 }
 
@@ -433,6 +442,21 @@ static int da8xx_musb_exit(struct musb *musb)
        return 0;
 }
 
+static inline u8 get_vbus_power(struct device *dev)
+{
+       struct regulator *vbus_supply;
+       int current_uA;
+
+       vbus_supply = regulator_get_optional(dev, "vbus");
+       if (IS_ERR(vbus_supply))
+               return 255;
+       current_uA = regulator_get_current_limit(vbus_supply);
+       regulator_put(vbus_supply);
+       if (current_uA <= 0 || current_uA > 510000)
+               return 255;
+       return current_uA / 1000 / 2;
+}
+
 static const struct musb_platform_ops da8xx_ops = {
        .quirks         = MUSB_DMA_CPPI | MUSB_INDEXED_EP,
        .init           = da8xx_musb_init,
@@ -458,6 +482,12 @@ static const struct platform_device_info da8xx_dev_info = {
        .dma_mask       = DMA_BIT_MASK(32),
 };
 
+static const struct musb_hdrc_config da8xx_config = {
+       .ram_bits = 10,
+       .num_eps = 5,
+       .multipoint = 1,
+};
+
 static int da8xx_probe(struct platform_device *pdev)
 {
        struct resource musb_resources[2];
@@ -465,6 +495,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;
 
        glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
@@ -487,6 +518,16 @@ static int da8xx_probe(struct platform_device *pdev)
        glue->dev                       = &pdev->dev;
        glue->clk                       = clk;
 
+       if (IS_ENABLED(CONFIG_OF) && np) {
+               pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+
+               pdata->config   = &da8xx_config;
+               pdata->mode     = musb_get_mode(&pdev->dev);
+               pdata->power    = get_vbus_power(&pdev->dev);
+       }
+
        pdata->platform_ops             = &da8xx_ops;
 
        glue->usb_phy = usb_phy_generic_register();
@@ -537,11 +578,22 @@ static int da8xx_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id da8xx_id_table[] = {
+       {
+               .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",
+               .of_match_table = of_match_ptr(da8xx_id_table),
        },
 };