usb: dwc2: add 'mode' which based on Kconfig select or dts setting
authorKever Yang <kever.yang@rock-chips.com>
Wed, 6 Aug 2014 01:01:50 +0000 (09:01 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Sep 2014 22:43:28 +0000 (15:43 -0700)
According to the "dr_mode", the otg controller can work as
device role and host role. Some boards always want to use host mode
and some other boards want to use gadget mode. We use the dts setting
to set dwc2's mode, rather than fixing it to whatever hardware says.

Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
Acked-by: Paul Zimmerman <paulz@synopsys.com>
Tested-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/platform.c

index c184ed430e67f6e8203651f6776f04ea9d9ae16a..ea0048a724cff0bdbb9b79be028996716301a562 100644 (file)
@@ -118,6 +118,7 @@ static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
 {
        u32 greset;
        int count = 0;
+       u32 gusbcfg;
 
        dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
@@ -148,6 +149,23 @@ static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
                }
        } while (greset & GRSTCTL_CSFTRST);
 
+       if (hsotg->dr_mode == USB_DR_MODE_HOST) {
+               gusbcfg = readl(hsotg->regs + GUSBCFG);
+               gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
+               gusbcfg |= GUSBCFG_FORCEHOSTMODE;
+               writel(gusbcfg, hsotg->regs + GUSBCFG);
+       } else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
+               gusbcfg = readl(hsotg->regs + GUSBCFG);
+               gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
+               gusbcfg |= GUSBCFG_FORCEDEVMODE;
+               writel(gusbcfg, hsotg->regs + GUSBCFG);
+       } else if (hsotg->dr_mode == USB_DR_MODE_OTG) {
+               gusbcfg = readl(hsotg->regs + GUSBCFG);
+               gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
+               gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
+               writel(gusbcfg, hsotg->regs + GUSBCFG);
+       }
+
        /*
         * NOTE: This long sleep is _very_ important, otherwise the core will
         * not stay in host mode after a connector ID change!
index 1efd10cc962918898d7cc2d827f616ad02719eae..52a4fd2ff208dfc5d34a2e7ab8eb8dc42410088e 100644 (file)
@@ -501,6 +501,10 @@ struct dwc2_hw_params {
  *                      a_peripheral and b_device=>b_host) this may not match
  *                      the core, but allows the software to determine
  *                      transitions
+ * @dr_mode:            Requested mode of operation, one of following:
+ *                      - USB_DR_MODE_PERIPHERAL
+ *                      - USB_DR_MODE_HOST
+ *                      - USB_DR_MODE_OTG
  * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
  *                      transfer are in process of being queued
  * @srp_success:        Stores status of SRP request in the case of a FS PHY
@@ -592,6 +596,7 @@ struct dwc2_hsotg {
        /** Params to actually use */
        struct dwc2_core_params *core_params;
        enum usb_otg_state op_state;
+       enum usb_dr_mode dr_mode;
 
        unsigned int queuing_high_bandwidth:1;
        unsigned int srp_success:1;
index 2f859bdd1fc4cbd79547460f3b69a5230ac11b65..121dbdafc06b7f0f189d0d438387eb256482daf3 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
+#include <linux/usb/of.h>
+
 #include "core.h"
 #include "hcd.h"
 
@@ -200,6 +202,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
        dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
                (unsigned long)res->start, hsotg->regs);
 
+       hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
+
        retval = dwc2_hcd_init(hsotg, irq, params);
        if (retval)
                return retval;