]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'usb-for-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Apr 2017 14:47:26 +0000 (16:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Apr 2017 14:47:26 +0000 (16:47 +0200)
Felipe writes:

usb: changes for v4.12

With 51 non-merge commits, this is one of the smallest USB Gadget pull
requests. Apart from your expected set of non-critical fixes, and
other miscellaneous items, we have most of the changes in dwc3 (52.5%)
with all other UDCs following with 34.8%.

As for the actual changes, the most important of them are all the
recent changes to reduce memory footprint of dwc3, bare minimum
dual-role support on dwc3 and reworked endpoint count and
initialization routines.

42 files changed:
Documentation/ABI/testing/sysfs-platform-renesas_usb3 [new file with mode: 0644]
drivers/usb/common/usb-otg-fsm.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hw.h
drivers/usb/dwc2/params.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/Makefile
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/debug.h
drivers/usb/dwc3/debugfs.c
drivers/usb/dwc3/drd.c [new file with mode: 0644]
drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/dwc3/trace.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/function/u_fs.h
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/Makefile
drivers/usb/gadget/udc/amd5536udc.c
drivers/usb/gadget/udc/amd5536udc.h
drivers/usb/gadget/udc/amd5536udc_pci.c [new file with mode: 0644]
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/core.c
drivers/usb/gadget/udc/dummy_hcd.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/mv_u3d_core.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/mtu3/mtu3_dr.c
drivers/usb/phy/phy-fsl-usb.c
include/linux/usb/otg-fsm.h
include/uapi/linux/usb/functionfs.h

diff --git a/Documentation/ABI/testing/sysfs-platform-renesas_usb3 b/Documentation/ABI/testing/sysfs-platform-renesas_usb3
new file mode 100644 (file)
index 0000000..5621c15
--- /dev/null
@@ -0,0 +1,15 @@
+What:          /sys/devices/platform/<renesas_usb3's name>/role
+Date:          March 2017
+KernelVersion: 4.13
+Contact:       Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Description:
+               This file can be read and write.
+               The file can show/change the drd mode of usb.
+
+               Write the following string to change the mode:
+                "host" - switching mode from peripheral to host.
+                "peripheral" - switching mode from host to peripheral.
+
+               Read the file, then it shows the following strings:
+                "host" - The mode is host now.
+                "peripheral" - The mode is peripheral now.
index 2f537bbdda093d90285789cd92f77da608dbbe14..b8fe31e409a5d6d13f04995a0707fafcf1e9daa0 100644 (file)
 #include <linux/usb/otg.h>
 #include <linux/usb/otg-fsm.h>
 
+#ifdef VERBOSE
+#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
+                                __func__, ## args)
+#else
+#define VDBG(stuff...) do {} while (0)
+#endif
+
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
 {
index 1a7e8300508251f8b0c2a7274acadc63c9c42111..8367d4f985c1220773a7c6efc38df94d837c7f28 100644 (file)
@@ -423,6 +423,10 @@ enum dwc2_ep0_state {
  *                     needed.
  *                     0 - No (default)
  *                     1 - Yes
+ * @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
+ *                     register.
+ *                     0 - Deactivate the transceiver (default)
+ *                     1 - Activate the transceiver
  * @g_dma:              Enables gadget dma usage (default: autodetect).
  * @g_dma_desc:         Enables gadget descriptor DMA (default: autodetect).
  * @g_rx_fifo_size:    The periodic rx fifo size for the device, in
@@ -477,6 +481,7 @@ struct dwc2_core_params {
        bool uframe_sched;
        bool external_id_pin_ctl;
        bool hibernation;
+       bool activate_stm_fs_transceiver;
        u16 max_packet_count;
        u32 max_transfer_size;
        u32 ahbcfg;
index a73722e27d07835f6a02f53fbc702c7e27fcf11a..740c7e86d31b912bf0f3c861a687b369acdc5b3d 100644 (file)
@@ -121,7 +121,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
 
 static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
 {
-       u32 usbcfg, i2cctl;
+       u32 usbcfg, ggpio, i2cctl;
        int retval = 0;
 
        /*
@@ -145,6 +145,19 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
                                return retval;
                        }
                }
+
+               if (hsotg->params.activate_stm_fs_transceiver) {
+                       ggpio = dwc2_readl(hsotg->regs + GGPIO);
+                       if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) {
+                               dev_dbg(hsotg->dev, "Activating transceiver\n");
+                               /*
+                                * STM32F4x9 uses the GGPIO register as general
+                                * core configuration register.
+                                */
+                               ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN;
+                               dwc2_writel(ggpio, hsotg->regs + GGPIO);
+                       }
+               }
        }
 
        /*
@@ -3264,6 +3277,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
                dwc2_core_init(hsotg, false);
                dwc2_enable_global_interrupts(hsotg);
                spin_lock_irqsave(&hsotg->lock, flags);
+               dwc2_hsotg_disconnect(hsotg);
                dwc2_hsotg_core_init_disconnected(hsotg, false);
                spin_unlock_irqrestore(&hsotg->lock, flags);
                dwc2_hsotg_core_connect(hsotg);
index bde72489ae6625b7a666f9a6e8c79e895d4d1441..4592012c47436c422e4840761717b48929e239bc 100644 (file)
 
 #define GPVNDCTL                       HSOTG_REG(0x0034)
 #define GGPIO                          HSOTG_REG(0x0038)
+#define GGPIO_STM32_OTG_GCCFG_PWRDWN   BIT(16)
+
 #define GUID                           HSOTG_REG(0x003c)
 #define GSNPSID                                HSOTG_REG(0x0040)
 #define GHWCFG1                                HSOTG_REG(0x0044)
index 2990c347289fcd877b831d12cc7372ee5f2b1166..9cd8722f24f65994d83cdb0378387c021e773e5f 100644 (file)
@@ -120,6 +120,22 @@ static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
        p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
 }
 
+static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_core_params *p = &hsotg->params;
+
+       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->speed = DWC2_SPEED_PARAM_FULL;
+       p->host_rx_fifo_size = 128;
+       p->host_nperio_tx_fifo_size = 96;
+       p->host_perio_tx_fifo_size = 96;
+       p->max_packet_count = 256;
+       p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
+       p->i2c_enable = false;
+       p->uframe_sched = false;
+       p->activate_stm_fs_transceiver = true;
+}
+
 const struct of_device_id dwc2_of_match_table[] = {
        { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
        { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params  },
@@ -133,6 +149,9 @@ const struct of_device_id dwc2_of_match_table[] = {
        { .compatible = "amlogic,meson-gxbb-usb",
          .data = dwc2_set_amlogic_params },
        { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
+       { .compatible = "st,stm32f4x9-fsotg",
+         .data = dwc2_set_stm32f4x9_fsotg_params },
+       { .compatible = "st,stm32f4x9-hsotg" },
        {},
 };
 MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
index 9564bc76c56f333fbb6535bdf2487f65c6241039..daf0d37acb37f2ccd2714e6be6bc14832b1cb937 100644 (file)
@@ -214,20 +214,11 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
        hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
        if (IS_ERR(hsotg->reset)) {
                ret = PTR_ERR(hsotg->reset);
-               switch (ret) {
-               case -ENOENT:
-               case -ENOTSUPP:
-                       hsotg->reset = NULL;
-                       break;
-               default:
-                       dev_err(hsotg->dev, "error getting reset control %d\n",
-                               ret);
-                       return ret;
-               }
+               dev_err(hsotg->dev, "error getting reset control %d\n", ret);
+               return ret;
        }
 
-       if (hsotg->reset)
-               reset_control_deassert(hsotg->reset);
+       reset_control_deassert(hsotg->reset);
 
        /* Set default UTMI width */
        hsotg->phyif = GUSBCFG_PHYIF16;
@@ -326,8 +317,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
        if (hsotg->ll_hw_enabled)
                dwc2_lowlevel_hw_disable(hsotg);
 
-       if (hsotg->reset)
-               reset_control_assert(hsotg->reset);
+       reset_control_assert(hsotg->reset);
 
        return 0;
 }
index 4c9e56d8776a1f17b8c64cc811a82b1d5479381c..ab8c0e0d3b60d54110c6a9a0daba4c10ef086eb1 100644 (file)
@@ -41,6 +41,7 @@ config USB_DWC3_GADGET
 config USB_DWC3_DUAL_ROLE
        bool "Dual Role mode"
        depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
+       depends on (EXTCON=y || EXTCON=USB_DWC3)
        help
          This is the default mode of working of DWC3 controller where
          both host and gadget features are enabled.
index ffca34029b21ff6c3bdb3e44ae5531c74d78856a..f15fabbd1e59e9d23e07936be6cfa05a3489975f 100644 (file)
@@ -17,6 +17,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
        dwc3-y                          += gadget.o ep0.o
 endif
 
+ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
+       dwc3-y                          += drd.o
+endif
+
 ifneq ($(CONFIG_USB_DWC3_ULPI),)
        dwc3-y                          += ulpi.o
 endif
index 369bab16a824599f2295dbdf91e825e1a69e4446..455d89a1cd6dbbb3e3f707bc42bada4a9569e5d7 100644 (file)
@@ -100,7 +100,10 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
        return 0;
 }
 
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
+static int dwc3_event_buffers_setup(struct dwc3 *dwc);
+
+static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
 {
        u32 reg;
 
@@ -110,6 +113,69 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
        dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 }
 
+static void __dwc3_set_mode(struct work_struct *work)
+{
+       struct dwc3 *dwc = work_to_dwc(work);
+       unsigned long flags;
+       int ret;
+
+       if (!dwc->desired_dr_role)
+               return;
+
+       if (dwc->desired_dr_role == dwc->current_dr_role)
+               return;
+
+       if (dwc->dr_mode != USB_DR_MODE_OTG)
+               return;
+
+       switch (dwc->current_dr_role) {
+       case DWC3_GCTL_PRTCAP_HOST:
+               dwc3_host_exit(dwc);
+               break;
+       case DWC3_GCTL_PRTCAP_DEVICE:
+               dwc3_gadget_exit(dwc);
+               dwc3_event_buffers_cleanup(dwc);
+               break;
+       default:
+               break;
+       }
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       dwc3_set_prtcap(dwc, dwc->desired_dr_role);
+
+       dwc->current_dr_role = dwc->desired_dr_role;
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       switch (dwc->desired_dr_role) {
+       case DWC3_GCTL_PRTCAP_HOST:
+               ret = dwc3_host_init(dwc);
+               if (ret)
+                       dev_err(dwc->dev, "failed to initialize host\n");
+               break;
+       case DWC3_GCTL_PRTCAP_DEVICE:
+               dwc3_event_buffers_setup(dwc);
+               ret = dwc3_gadget_init(dwc);
+               if (ret)
+                       dev_err(dwc->dev, "failed to initialize peripheral\n");
+               break;
+       default:
+               break;
+       }
+}
+
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc->desired_dr_role = mode;
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       queue_work(system_power_efficient_wq, &dwc->drd_work);
+}
+
 u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
 {
        struct dwc3             *dwc = dep->dwc;
@@ -397,8 +463,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
 {
        struct dwc3_hwparams    *parms = &dwc->hwparams;
 
-       dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
-       dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
+       dwc->num_eps = DWC3_NUM_EPS(parms);
 }
 
 static void dwc3_cache_hwparams(struct dwc3 *dwc)
@@ -431,6 +496,12 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
 
        reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 
+       /*
+        * Make sure UX_EXIT_PX is cleared as that causes issues with some
+        * PHYs. Also, this bit is not supposed to be used in normal operation.
+        */
+       reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
+
        /*
         * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
         * to '0' during coreConsultant configuration. So default value
@@ -714,21 +785,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
                goto err4;
        }
 
-       switch (dwc->dr_mode) {
-       case USB_DR_MODE_PERIPHERAL:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
-               break;
-       case USB_DR_MODE_HOST:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
-               break;
-       case USB_DR_MODE_OTG:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
-               break;
-       default:
-               dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
-               break;
-       }
-
        /*
         * ENDXFER polling is available on version 3.10a and later of
         * the DWC_usb3 controller. It is NOT available in the
@@ -846,6 +902,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
+               dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
@@ -854,6 +911,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                }
                break;
        case USB_DR_MODE_HOST:
+               dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
@@ -862,17 +920,11 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                }
                break;
        case USB_DR_MODE_OTG:
-               ret = dwc3_host_init(dwc);
-               if (ret) {
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(dev, "failed to initialize host\n");
-                       return ret;
-               }
-
-               ret = dwc3_gadget_init(dwc);
+               INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
+               ret = dwc3_drd_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
-                               dev_err(dev, "failed to initialize gadget\n");
+                               dev_err(dev, "failed to initialize dual-role\n");
                        return ret;
                }
                break;
@@ -894,8 +946,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
                dwc3_host_exit(dwc);
                break;
        case USB_DR_MODE_OTG:
-               dwc3_host_exit(dwc);
-               dwc3_gadget_exit(dwc);
+               dwc3_drd_exit(dwc);
                break;
        default:
                /* do nothing */
index 2b9e4ca3c932e5691376dc9504d870804cccc695..981c77f5628e105731b41756b798c988b6c6692d 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/ioport.h>
 #include <linux/list.h>
+#include <linux/bitops.h>
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
 #include <linux/debugfs.h>
 #include <linux/wait.h>
+#include <linux/workqueue.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -39,9 +41,8 @@
 
 /* Global constants */
 #define DWC3_PULL_UP_TIMEOUT   500     /* ms */
-#define DWC3_ZLP_BUF_SIZE      1024    /* size of a superspeed bulk */
 #define DWC3_BOUNCE_SIZE       1024    /* size of a superspeed bulk */
-#define DWC3_EP0_BOUNCE_SIZE   512
+#define DWC3_EP0_SETUP_SIZE    512
 #define DWC3_ENDPOINTS_NUM     32
 #define DWC3_XHCI_RESOURCES_NUM        2
 
@@ -66,7 +67,7 @@
 #define DWC3_DEVICE_EVENT_OVERFLOW             11
 
 #define DWC3_GEVNTCOUNT_MASK   0xfffc
-#define DWC3_GEVNTCOUNT_EHB    (1 << 31)
+#define DWC3_GEVNTCOUNT_EHB    BIT(31)
 #define DWC3_GSNPSID_MASK      0xffff0000
 #define DWC3_GSNPSREV_MASK     0xffff
 
 #define DWC3_VER_NUMBER                0xc1a0
 #define DWC3_VER_TYPE          0xc1a4
 
-#define DWC3_GUSB2PHYCFG(n)    (0xc200 + (n * 0x04))
-#define DWC3_GUSB2I2CCTL(n)    (0xc240 + (n * 0x04))
+#define DWC3_GUSB2PHYCFG(n)    (0xc200 + ((n) * 0x04))
+#define DWC3_GUSB2I2CCTL(n)    (0xc240 + ((n) * 0x04))
 
-#define DWC3_GUSB2PHYACC(n)    (0xc280 + (n * 0x04))
+#define DWC3_GUSB2PHYACC(n)    (0xc280 + ((n) * 0x04))
 
-#define DWC3_GUSB3PIPECTL(n)   (0xc2c0 + (n * 0x04))
+#define DWC3_GUSB3PIPECTL(n)   (0xc2c0 + ((n) * 0x04))
 
-#define DWC3_GTXFIFOSIZ(n)     (0xc300 + (n * 0x04))
-#define DWC3_GRXFIFOSIZ(n)     (0xc380 + (n * 0x04))
+#define DWC3_GTXFIFOSIZ(n)     (0xc300 + ((n) * 0x04))
+#define DWC3_GRXFIFOSIZ(n)     (0xc380 + ((n) * 0x04))
 
-#define DWC3_GEVNTADRLO(n)     (0xc400 + (n * 0x10))
-#define DWC3_GEVNTADRHI(n)     (0xc404 + (n * 0x10))
-#define DWC3_GEVNTSIZ(n)       (0xc408 + (n * 0x10))
-#define DWC3_GEVNTCOUNT(n)     (0xc40c + (n * 0x10))
+#define DWC3_GEVNTADRLO(n)     (0xc400 + ((n) * 0x10))
+#define DWC3_GEVNTADRHI(n)     (0xc404 + ((n) * 0x10))
+#define DWC3_GEVNTSIZ(n)       (0xc408 + ((n) * 0x10))
+#define DWC3_GEVNTCOUNT(n)     (0xc40c + ((n) * 0x10))
 
 #define DWC3_GHWPARAMS8                0xc600
 #define DWC3_GFLADJ            0xc630
 #define DWC3_DGCMD             0xc714
 #define DWC3_DALEPENA          0xc720
 
-#define DWC3_DEP_BASE(n)       (0xc800 + (n * 0x10))
+#define DWC3_DEP_BASE(n)       (0xc800 + ((n) * 0x10))
 #define DWC3_DEPCMDPAR2                0x00
 #define DWC3_DEPCMDPAR1                0x04
 #define DWC3_DEPCMDPAR0                0x08
 #define DWC3_DEPCMD            0x0c
 
-#define DWC3_DEV_IMOD(n)       (0xca00 + (n * 0x4))
+#define DWC3_DEV_IMOD(n)       (0xca00 + ((n) * 0x4))
 
 /* OTG Registers */
 #define DWC3_OCFG              0xcc00
 /* Global RX Threshold Configuration Register */
 #define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
 #define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
-#define DWC3_GRXTHRCFG_PKTCNTSEL (1 << 29)
+#define DWC3_GRXTHRCFG_PKTCNTSEL BIT(29)
 
 /* Global Configuration Register */
 #define DWC3_GCTL_PWRDNSCALE(n)        ((n) << 19)
-#define DWC3_GCTL_U2RSTECN     (1 << 16)
+#define DWC3_GCTL_U2RSTECN     BIT(16)
 #define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
 #define DWC3_GCTL_CLK_BUS      (0)
 #define DWC3_GCTL_CLK_PIPE     (1)
 #define DWC3_GCTL_PRTCAP_DEVICE        2
 #define DWC3_GCTL_PRTCAP_OTG   3
 
-#define DWC3_GCTL_CORESOFTRESET                (1 << 11)
-#define DWC3_GCTL_SOFITPSYNC           (1 << 10)
+#define DWC3_GCTL_CORESOFTRESET                BIT(11)
+#define DWC3_GCTL_SOFITPSYNC           BIT(10)
 #define DWC3_GCTL_SCALEDOWN(n)         ((n) << 4)
 #define DWC3_GCTL_SCALEDOWN_MASK       DWC3_GCTL_SCALEDOWN(3)
-#define DWC3_GCTL_DISSCRAMBLE          (1 << 3)
-#define DWC3_GCTL_U2EXIT_LFPS          (1 << 2)
-#define DWC3_GCTL_GBLHIBERNATIONEN     (1 << 1)
-#define DWC3_GCTL_DSBLCLKGTNG          (1 << 0)
+#define DWC3_GCTL_DISSCRAMBLE          BIT(3)
+#define DWC3_GCTL_U2EXIT_LFPS          BIT(2)
+#define DWC3_GCTL_GBLHIBERNATIONEN     BIT(1)
+#define DWC3_GCTL_DSBLCLKGTNG          BIT(0)
 
 /* Global User Control 1 Register */
-#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW  (1 << 24)
+#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW  BIT(24)
 
 /* Global USB2 PHY Configuration Register */
-#define DWC3_GUSB2PHYCFG_PHYSOFTRST    (1 << 31)
-#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS     (1 << 30)
-#define DWC3_GUSB2PHYCFG_SUSPHY                (1 << 6)
-#define DWC3_GUSB2PHYCFG_ULPI_UTMI     (1 << 4)
-#define DWC3_GUSB2PHYCFG_ENBLSLPM      (1 << 8)
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST    BIT(31)
+#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS     BIT(30)
+#define DWC3_GUSB2PHYCFG_SUSPHY                BIT(6)
+#define DWC3_GUSB2PHYCFG_ULPI_UTMI     BIT(4)
+#define DWC3_GUSB2PHYCFG_ENBLSLPM      BIT(8)
 #define DWC3_GUSB2PHYCFG_PHYIF(n)      (n << 3)
 #define DWC3_GUSB2PHYCFG_PHYIF_MASK    DWC3_GUSB2PHYCFG_PHYIF(1)
 #define DWC3_GUSB2PHYCFG_USBTRDTIM(n)  (n << 10)
 #define UTMI_PHYIF_8_BIT               0
 
 /* Global USB2 PHY Vendor Control Register */
-#define DWC3_GUSB2PHYACC_NEWREGREQ     (1 << 25)
-#define DWC3_GUSB2PHYACC_BUSY          (1 << 23)
-#define DWC3_GUSB2PHYACC_WRITE         (1 << 22)
+#define DWC3_GUSB2PHYACC_NEWREGREQ     BIT(25)
+#define DWC3_GUSB2PHYACC_BUSY          BIT(23)
+#define DWC3_GUSB2PHYACC_WRITE         BIT(22)
 #define DWC3_GUSB2PHYACC_ADDR(n)       (n << 16)
 #define DWC3_GUSB2PHYACC_EXTEND_ADDR(n)        (n << 8)
 #define DWC3_GUSB2PHYACC_DATA(n)       (n & 0xff)
 
 /* Global USB3 PIPE Control Register */
-#define DWC3_GUSB3PIPECTL_PHYSOFTRST   (1 << 31)
-#define DWC3_GUSB3PIPECTL_U2SSINP3OK   (1 << 29)
-#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28)
-#define DWC3_GUSB3PIPECTL_REQP1P2P3    (1 << 24)
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST   BIT(31)
+#define DWC3_GUSB3PIPECTL_U2SSINP3OK   BIT(29)
+#define DWC3_GUSB3PIPECTL_DISRXDETINP3 BIT(28)
+#define DWC3_GUSB3PIPECTL_UX_EXIT_PX   BIT(27)
+#define DWC3_GUSB3PIPECTL_REQP1P2P3    BIT(24)
 #define DWC3_GUSB3PIPECTL_DEP1P2P3(n)  ((n) << 19)
 #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK        DWC3_GUSB3PIPECTL_DEP1P2P3(7)
 #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN  DWC3_GUSB3PIPECTL_DEP1P2P3(1)
-#define DWC3_GUSB3PIPECTL_DEPOCHANGE   (1 << 18)
-#define DWC3_GUSB3PIPECTL_SUSPHY       (1 << 17)
-#define DWC3_GUSB3PIPECTL_LFPSFILT     (1 << 9)
-#define DWC3_GUSB3PIPECTL_RX_DETOPOLL  (1 << 8)
+#define DWC3_GUSB3PIPECTL_DEPOCHANGE   BIT(18)
+#define DWC3_GUSB3PIPECTL_SUSPHY       BIT(17)
+#define DWC3_GUSB3PIPECTL_LFPSFILT     BIT(9)
+#define DWC3_GUSB3PIPECTL_RX_DETOPOLL  BIT(8)
 #define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK        DWC3_GUSB3PIPECTL_TX_DEEPH(3)
 #define DWC3_GUSB3PIPECTL_TX_DEEPH(n)  ((n) << 1)
 
 #define DWC3_GTXFIFOSIZ_TXFSTADDR(n)   ((n) & 0xffff0000)
 
 /* Global Event Size Registers */
-#define DWC3_GEVNTSIZ_INTMASK          (1 << 31)
+#define DWC3_GEVNTSIZ_INTMASK          BIT(31)
 #define DWC3_GEVNTSIZ_SIZE(n)          ((n) & 0xffff)
 
 /* Global HWPARAMS0 Register */
 #define DWC3_MAX_HIBER_SCRATCHBUFS             15
 
 /* Global HWPARAMS6 Register */
-#define DWC3_GHWPARAMS6_EN_FPGA                        (1 << 7)
+#define DWC3_GHWPARAMS6_EN_FPGA                        BIT(7)
 
 /* Global HWPARAMS7 Register */
 #define DWC3_GHWPARAMS7_RAM1_DEPTH(n)  ((n) & 0xffff)
 #define DWC3_GHWPARAMS7_RAM2_DEPTH(n)  (((n) >> 16) & 0xffff)
 
 /* Global Frame Length Adjustment Register */
-#define DWC3_GFLADJ_30MHZ_SDBND_SEL            (1 << 7)
+#define DWC3_GFLADJ_30MHZ_SDBND_SEL            BIT(7)
 #define DWC3_GFLADJ_30MHZ_MASK                 0x3f
 
 /* Global User Control Register 2 */
-#define DWC3_GUCTL2_RST_ACTBITLATER            (1 << 14)
+#define DWC3_GUCTL2_RST_ACTBITLATER            BIT(14)
 
 /* Device Configuration Register */
 #define DWC3_DCFG_DEVADDR(addr)        ((addr) << 3)
 #define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0)  /* DWC_usb31 only */
 #define DWC3_DCFG_SUPERSPEED   (4 << 0)
 #define DWC3_DCFG_HIGHSPEED    (0 << 0)
-#define DWC3_DCFG_FULLSPEED    (1 << 0)
+#define DWC3_DCFG_FULLSPEED    BIT(0)
 #define DWC3_DCFG_LOWSPEED     (2 << 0)
 
 #define DWC3_DCFG_NUMP_SHIFT   17
 #define DWC3_DCFG_NUMP(n)      (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
 #define DWC3_DCFG_NUMP_MASK    (0x1f << DWC3_DCFG_NUMP_SHIFT)
-#define DWC3_DCFG_LPM_CAP      (1 << 22)
+#define DWC3_DCFG_LPM_CAP      BIT(22)
 
 /* Device Control Register */
-#define DWC3_DCTL_RUN_STOP     (1 << 31)
-#define DWC3_DCTL_CSFTRST      (1 << 30)
-#define DWC3_DCTL_LSFTRST      (1 << 29)
+#define DWC3_DCTL_RUN_STOP     BIT(31)
+#define DWC3_DCTL_CSFTRST      BIT(30)
+#define DWC3_DCTL_LSFTRST      BIT(29)
 
 #define DWC3_DCTL_HIRD_THRES_MASK      (0x1f << 24)
 #define DWC3_DCTL_HIRD_THRES(n)        ((n) << 24)
 
-#define DWC3_DCTL_APPL1RES     (1 << 23)
+#define DWC3_DCTL_APPL1RES     BIT(23)
 
 /* These apply for core versions 1.87a and earlier */
 #define DWC3_DCTL_TRGTULST_MASK                (0x0f << 17)
 #define DWC3_DCTL_LPM_ERRATA_MASK      DWC3_DCTL_LPM_ERRATA(0xf)
 #define DWC3_DCTL_LPM_ERRATA(n)                ((n) << 20)
 
-#define DWC3_DCTL_KEEP_CONNECT         (1 << 19)
-#define DWC3_DCTL_L1_HIBER_EN          (1 << 18)
-#define DWC3_DCTL_CRS                  (1 << 17)
-#define DWC3_DCTL_CSS                  (1 << 16)
+#define DWC3_DCTL_KEEP_CONNECT         BIT(19)
+#define DWC3_DCTL_L1_HIBER_EN          BIT(18)
+#define DWC3_DCTL_CRS                  BIT(17)
+#define DWC3_DCTL_CSS                  BIT(16)
 
-#define DWC3_DCTL_INITU2ENA            (1 << 12)
-#define DWC3_DCTL_ACCEPTU2ENA          (1 << 11)
-#define DWC3_DCTL_INITU1ENA            (1 << 10)
-#define DWC3_DCTL_ACCEPTU1ENA          (1 << 9)
+#define DWC3_DCTL_INITU2ENA            BIT(12)
+#define DWC3_DCTL_ACCEPTU2ENA          BIT(11)
+#define DWC3_DCTL_INITU1ENA            BIT(10)
+#define DWC3_DCTL_ACCEPTU1ENA          BIT(9)
 #define DWC3_DCTL_TSTCTRL_MASK         (0xf << 1)
 
 #define DWC3_DCTL_ULSTCHNGREQ_MASK     (0x0f << 5)
 #define DWC3_DCTL_ULSTCHNG_LOOPBACK    (DWC3_DCTL_ULSTCHNGREQ(11))
 
 /* Device Event Enable Register */
-#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN  (1 << 12)
-#define DWC3_DEVTEN_EVNTOVERFLOWEN     (1 << 11)
-#define DWC3_DEVTEN_CMDCMPLTEN         (1 << 10)
-#define DWC3_DEVTEN_ERRTICERREN                (1 << 9)
-#define DWC3_DEVTEN_SOFEN              (1 << 7)
-#define DWC3_DEVTEN_EOPFEN             (1 << 6)
-#define DWC3_DEVTEN_HIBERNATIONREQEVTEN        (1 << 5)
-#define DWC3_DEVTEN_WKUPEVTEN          (1 << 4)
-#define DWC3_DEVTEN_ULSTCNGEN          (1 << 3)
-#define DWC3_DEVTEN_CONNECTDONEEN      (1 << 2)
-#define DWC3_DEVTEN_USBRSTEN           (1 << 1)
-#define DWC3_DEVTEN_DISCONNEVTEN       (1 << 0)
+#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN  BIT(12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN     BIT(11)
+#define DWC3_DEVTEN_CMDCMPLTEN         BIT(10)
+#define DWC3_DEVTEN_ERRTICERREN                BIT(9)
+#define DWC3_DEVTEN_SOFEN              BIT(7)
+#define DWC3_DEVTEN_EOPFEN             BIT(6)
+#define DWC3_DEVTEN_HIBERNATIONREQEVTEN        BIT(5)
+#define DWC3_DEVTEN_WKUPEVTEN          BIT(4)
+#define DWC3_DEVTEN_ULSTCNGEN          BIT(3)
+#define DWC3_DEVTEN_CONNECTDONEEN      BIT(2)
+#define DWC3_DEVTEN_USBRSTEN           BIT(1)
+#define DWC3_DEVTEN_DISCONNEVTEN       BIT(0)
 
 /* Device Status Register */
-#define DWC3_DSTS_DCNRD                        (1 << 29)
+#define DWC3_DSTS_DCNRD                        BIT(29)
 
 /* This applies for core versions 1.87a and earlier */
-#define DWC3_DSTS_PWRUPREQ             (1 << 24)
+#define DWC3_DSTS_PWRUPREQ             BIT(24)
 
 /* These apply for core versions 1.94a and later */
-#define DWC3_DSTS_RSS                  (1 << 25)
-#define DWC3_DSTS_SSS                  (1 << 24)
+#define DWC3_DSTS_RSS                  BIT(25)
+#define DWC3_DSTS_SSS                  BIT(24)
 
-#define DWC3_DSTS_COREIDLE             (1 << 23)
-#define DWC3_DSTS_DEVCTRLHLT           (1 << 22)
+#define DWC3_DSTS_COREIDLE             BIT(23)
+#define DWC3_DSTS_DEVCTRLHLT           BIT(22)
 
 #define DWC3_DSTS_USBLNKST_MASK                (0x0f << 18)
 #define DWC3_DSTS_USBLNKST(n)          (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
 
-#define DWC3_DSTS_RXFIFOEMPTY          (1 << 17)
+#define DWC3_DSTS_RXFIFOEMPTY          BIT(17)
 
 #define DWC3_DSTS_SOFFN_MASK           (0x3fff << 3)
 #define DWC3_DSTS_SOFFN(n)             (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
 #define DWC3_DSTS_SUPERSPEED_PLUS      (5 << 0) /* DWC_usb31 only */
 #define DWC3_DSTS_SUPERSPEED           (4 << 0)
 #define DWC3_DSTS_HIGHSPEED            (0 << 0)
-#define DWC3_DSTS_FULLSPEED            (1 << 0)
+#define DWC3_DSTS_FULLSPEED            BIT(0)
 #define DWC3_DSTS_LOWSPEED             (2 << 0)
 
 /* Device Generic Command Register */
 #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK        0x10
 
 #define DWC3_DGCMD_STATUS(n)           (((n) >> 12) & 0x0F)
-#define DWC3_DGCMD_CMDACT              (1 << 10)
-#define DWC3_DGCMD_CMDIOC              (1 << 8)
+#define DWC3_DGCMD_CMDACT              BIT(10)
+#define DWC3_DGCMD_CMDIOC              BIT(8)
 
 /* Device Generic Command Parameter Register */
-#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT      (1 << 0)
+#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT      BIT(0)
 #define DWC3_DGCMDPAR_FIFO_NUM(n)              ((n) << 0)
 #define DWC3_DGCMDPAR_RX_FIFO                  (0 << 5)
-#define DWC3_DGCMDPAR_TX_FIFO                  (1 << 5)
+#define DWC3_DGCMDPAR_TX_FIFO                  BIT(5)
 #define DWC3_DGCMDPAR_LOOPBACK_DIS             (0 << 0)
-#define DWC3_DGCMDPAR_LOOPBACK_ENA             (1 << 0)
+#define DWC3_DGCMDPAR_LOOPBACK_ENA             BIT(0)
 
 /* Device Endpoint Command Register */
 #define DWC3_DEPCMD_PARAM_SHIFT                16
 #define DWC3_DEPCMD_PARAM(x)           ((x) << DWC3_DEPCMD_PARAM_SHIFT)
 #define DWC3_DEPCMD_GET_RSC_IDX(x)     (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
 #define DWC3_DEPCMD_STATUS(x)          (((x) >> 12) & 0x0F)
-#define DWC3_DEPCMD_HIPRI_FORCERM      (1 << 11)
-#define DWC3_DEPCMD_CLEARPENDIN                (1 << 11)
-#define DWC3_DEPCMD_CMDACT             (1 << 10)
-#define DWC3_DEPCMD_CMDIOC             (1 << 8)
+#define DWC3_DEPCMD_HIPRI_FORCERM      BIT(11)
+#define DWC3_DEPCMD_CLEARPENDIN                BIT(11)
+#define DWC3_DEPCMD_CMDACT             BIT(10)
+#define DWC3_DEPCMD_CMDIOC             BIT(8)
 
 #define DWC3_DEPCMD_DEPSTARTCFG                (0x09 << 0)
 #define DWC3_DEPCMD_ENDTRANSFER                (0x08 << 0)
 #define DWC3_DEPCMD_CMD(x)             ((x) & 0xf)
 
 /* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
-#define DWC3_DALEPENA_EP(n)            (1 << n)
+#define DWC3_DALEPENA_EP(n)            BIT(n)
 
 #define DWC3_DEPCMD_TYPE_CONTROL       0
 #define DWC3_DEPCMD_TYPE_ISOC          1
@@ -500,8 +502,8 @@ struct dwc3_event_buffer {
        struct dwc3             *dwc;
 };
 
-#define DWC3_EP_FLAG_STALLED   (1 << 0)
-#define DWC3_EP_FLAG_WEDGED    (1 << 1)
+#define DWC3_EP_FLAG_STALLED   BIT(0)
+#define DWC3_EP_FLAG_WEDGED    BIT(1)
 
 #define DWC3_EP_DIRECTION_TX   true
 #define DWC3_EP_DIRECTION_RX   false
@@ -550,17 +552,17 @@ struct dwc3_ep {
 
        u32                     saved_state;
        unsigned                flags;
-#define DWC3_EP_ENABLED                (1 << 0)
-#define DWC3_EP_STALL          (1 << 1)
-#define DWC3_EP_WEDGE          (1 << 2)
-#define DWC3_EP_BUSY           (1 << 4)
-#define DWC3_EP_PENDING_REQUEST        (1 << 5)
-#define DWC3_EP_MISSED_ISOC    (1 << 6)
-#define DWC3_EP_END_TRANSFER_PENDING   (1 << 7)
-#define DWC3_EP_TRANSFER_STARTED (1 << 8)
+#define DWC3_EP_ENABLED                BIT(0)
+#define DWC3_EP_STALL          BIT(1)
+#define DWC3_EP_WEDGE          BIT(2)
+#define DWC3_EP_BUSY           BIT(4)
+#define DWC3_EP_PENDING_REQUEST        BIT(5)
+#define DWC3_EP_MISSED_ISOC    BIT(6)
+#define DWC3_EP_END_TRANSFER_PENDING   BIT(7)
+#define DWC3_EP_TRANSFER_STARTED BIT(8)
 
        /* This last one is specific to EP0 */
-#define DWC3_EP0_DIR_IN                (1 << 31)
+#define DWC3_EP0_DIR_IN                BIT(31)
 
        /*
         * IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
@@ -638,13 +640,13 @@ enum dwc3_link_state {
 #define DWC3_TRB_STS_XFER_IN_PROG      4
 
 /* TRB Control */
-#define DWC3_TRB_CTRL_HWO              (1 << 0)
-#define DWC3_TRB_CTRL_LST              (1 << 1)
-#define DWC3_TRB_CTRL_CHN              (1 << 2)
-#define DWC3_TRB_CTRL_CSP              (1 << 3)
+#define DWC3_TRB_CTRL_HWO              BIT(0)
+#define DWC3_TRB_CTRL_LST              BIT(1)
+#define DWC3_TRB_CTRL_CHN              BIT(2)
+#define DWC3_TRB_CTRL_CSP              BIT(3)
 #define DWC3_TRB_CTRL_TRBCTL(n)                (((n) & 0x3f) << 4)
-#define DWC3_TRB_CTRL_ISP_IMI          (1 << 10)
-#define DWC3_TRB_CTRL_IOC              (1 << 11)
+#define DWC3_TRB_CTRL_ISP_IMI          BIT(10)
+#define DWC3_TRB_CTRL_IOC              BIT(11)
 #define DWC3_TRB_CTRL_SID_SOFN(n)      (((n) & 0xffff) << 14)
 
 #define DWC3_TRBCTL_TYPE(n)            ((n) & (0x3f << 4))
@@ -746,6 +748,7 @@ struct dwc3_request {
        unsigned                direction:1;
        unsigned                mapped:1;
        unsigned                started:1;
+       unsigned                zero:1;
 };
 
 /*
@@ -758,15 +761,11 @@ struct dwc3_scratchpad_array {
 
 /**
  * struct dwc3 - representation of our controller
- * @ctrl_req: usb control request which is used for ep0
+ * @drd_work - workqueue used for role swapping
  * @ep0_trb: trb which is used for the ctrl_req
- * @ep0_bounce: bounce buffer for ep0
- * @zlp_buf: used when request->zero is set
  * @setup_buf: used while precessing STD USB requests
- * @ctrl_req_addr: dma address of ctrl_req
  * @ep0_trb: dma address of ep0_trb
  * @ep0_usb_req: dummy req used while handling STD USB requests
- * @ep0_bounce_addr: dma address of ep0_bounce
  * @scratch_addr: dma address of scratchbuf
  * @ep0_in_setup: one control transfer is completed and enter setup phase
  * @lock: for synchronizing
@@ -784,6 +783,10 @@ struct dwc3_scratchpad_array {
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
  * @dr_mode: requested mode of operation
+ * @current_dr_role: current role of operation when in dual-role mode
+ * @desired_dr_role: desired role of operation when in dual-role mode
+ * @edev: extcon handle
+ * @edev_nb: extcon notifier
  * @hsphy_mode: UTMI phy mode, one of following:
  *             - USBPHY_INTERFACE_MODE_UTMI
  *             - USBPHY_INTERFACE_MODE_UTMIW
@@ -799,8 +802,7 @@ struct dwc3_scratchpad_array {
  * @u2pel: parameter from Set SEL request.
  * @u1sel: parameter from Set SEL request.
  * @u1pel: parameter from Set SEL request.
- * @num_out_eps: number of out endpoints
- * @num_in_eps: number of in endpoints
+ * @num_eps: number of endpoints
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -858,17 +860,13 @@ struct dwc3_scratchpad_array {
  *                 increments or 0 to disable.
  */
 struct dwc3 {
-       struct usb_ctrlrequest  *ctrl_req;
+       struct work_struct      drd_work;
        struct dwc3_trb         *ep0_trb;
        void                    *bounce;
-       void                    *ep0_bounce;
-       void                    *zlp_buf;
        void                    *scratchbuf;
        u8                      *setup_buf;
-       dma_addr_t              ctrl_req_addr;
        dma_addr_t              ep0_trb_addr;
        dma_addr_t              bounce_addr;
-       dma_addr_t              ep0_bounce_addr;
        dma_addr_t              scratch_addr;
        struct dwc3_request     ep0_usb_req;
        struct completion       ep0_in_setup;
@@ -900,6 +898,10 @@ struct dwc3 {
        size_t                  regs_size;
 
        enum usb_dr_mode        dr_mode;
+       u32                     current_dr_role;
+       u32                     desired_dr_role;
+       struct extcon_dev       *edev;
+       struct notifier_block   edev_nb;
        enum usb_phy_interface  hsphy_mode;
 
        u32                     fladj;
@@ -960,8 +962,7 @@ struct dwc3 {
 
        u8                      speed;
 
-       u8                      num_out_eps;
-       u8                      num_in_eps;
+       u8                      num_eps;
 
        struct dwc3_hwparams    hwparams;
        struct dentry           *root;
@@ -1010,7 +1011,7 @@ struct dwc3 {
        u16                     imod_interval;
 };
 
-/* -------------------------------------------------------------------------- */
+#define work_to_dwc(w)         (container_of((w), struct dwc3, drd_work))
 
 /* -------------------------------------------------------------------------- */
 
@@ -1054,13 +1055,13 @@ struct dwc3_event_depevt {
        u32     status:4;
 
 /* Within XferNotReady */
-#define DEPEVT_STATUS_TRANSFER_ACTIVE  (1 << 3)
+#define DEPEVT_STATUS_TRANSFER_ACTIVE  BIT(3)
 
 /* Within XferComplete */
-#define DEPEVT_STATUS_BUSERR   (1 << 0)
-#define DEPEVT_STATUS_SHORT    (1 << 1)
-#define DEPEVT_STATUS_IOC      (1 << 2)
-#define DEPEVT_STATUS_LST      (1 << 3)
+#define DEPEVT_STATUS_BUSERR   BIT(0)
+#define DEPEVT_STATUS_SHORT    BIT(1)
+#define DEPEVT_STATUS_IOC      BIT(2)
+#define DEPEVT_STATUS_LST      BIT(3)
 
 /* Stream event only */
 #define DEPEVT_STREAMEVT_FOUND         1
@@ -1221,6 +1222,16 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
 { return 0; }
 #endif
 
+#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_drd_init(struct dwc3 *dwc);
+void dwc3_drd_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_drd_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_drd_exit(struct dwc3 *dwc)
+{ }
+#endif
+
 /* power management interface */
 #if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
 int dwc3_gadget_suspend(struct dwc3 *dwc);
index eeed4ffd81312c9922c4fe2e4b83627a8c41059c..cb2d8d3f7f3d8d052bb3a94a924ce37100683bb4 100644 (file)
@@ -124,6 +124,34 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
        }
 }
 
+/**
+ * dwc3_trb_type_string - returns TRB type as a string
+ * @type: the type of the TRB
+ */
+static inline const char *dwc3_trb_type_string(unsigned int type)
+{
+       switch (type) {
+       case DWC3_TRBCTL_NORMAL:
+               return "normal";
+       case DWC3_TRBCTL_CONTROL_SETUP:
+               return "setup";
+       case DWC3_TRBCTL_CONTROL_STATUS2:
+               return "status2";
+       case DWC3_TRBCTL_CONTROL_STATUS3:
+               return "status3";
+       case DWC3_TRBCTL_CONTROL_DATA:
+               return "data";
+       case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
+               return "isoc-first";
+       case DWC3_TRBCTL_ISOCHRONOUS:
+               return "isoc";
+       case DWC3_TRBCTL_LINK_TRB:
+               return "link";
+       default:
+               return "UNKNOWN";
+       }
+}
+
 static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
 {
        switch (state) {
index 31926dda43c9638f96a3fa6a51a2f5ef6a6d2359..7be963dd8e3baecd4538a56c3179787cd9b85d29 100644 (file)
@@ -300,7 +300,7 @@ static int dwc3_mode_show(struct seq_file *s, void *unused)
                seq_printf(s, "device\n");
                break;
        case DWC3_GCTL_PRTCAP_OTG:
-               seq_printf(s, "OTG\n");
+               seq_printf(s, "otg\n");
                break;
        default:
                seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
@@ -319,7 +319,6 @@ static ssize_t dwc3_mode_write(struct file *file,
 {
        struct seq_file         *s = file->private_data;
        struct dwc3             *dwc = s->private;
-       unsigned long           flags;
        u32                     mode = 0;
        char                    buf[32];
 
@@ -327,19 +326,16 @@ static ssize_t dwc3_mode_write(struct file *file,
                return -EFAULT;
 
        if (!strncmp(buf, "host", 4))
-               mode |= DWC3_GCTL_PRTCAP_HOST;
+               mode = DWC3_GCTL_PRTCAP_HOST;
 
        if (!strncmp(buf, "device", 6))
-               mode |= DWC3_GCTL_PRTCAP_DEVICE;
+               mode = DWC3_GCTL_PRTCAP_DEVICE;
 
        if (!strncmp(buf, "otg", 3))
-               mode |= DWC3_GCTL_PRTCAP_OTG;
+               mode = DWC3_GCTL_PRTCAP_OTG;
+
+       dwc3_set_mode(dwc, mode);
 
-       if (mode) {
-               spin_lock_irqsave(&dwc->lock, flags);
-               dwc3_set_mode(dwc, mode);
-               spin_unlock_irqrestore(&dwc->lock, flags);
-       }
        return count;
 }
 
@@ -446,52 +442,7 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
        state = DWC3_DSTS_USBLNKST(reg);
        spin_unlock_irqrestore(&dwc->lock, flags);
 
-       switch (state) {
-       case DWC3_LINK_STATE_U0:
-               seq_printf(s, "U0\n");
-               break;
-       case DWC3_LINK_STATE_U1:
-               seq_printf(s, "U1\n");
-               break;
-       case DWC3_LINK_STATE_U2:
-               seq_printf(s, "U2\n");
-               break;
-       case DWC3_LINK_STATE_U3:
-               seq_printf(s, "U3\n");
-               break;
-       case DWC3_LINK_STATE_SS_DIS:
-               seq_printf(s, "SS.Disabled\n");
-               break;
-       case DWC3_LINK_STATE_RX_DET:
-               seq_printf(s, "Rx.Detect\n");
-               break;
-       case DWC3_LINK_STATE_SS_INACT:
-               seq_printf(s, "SS.Inactive\n");
-               break;
-       case DWC3_LINK_STATE_POLL:
-               seq_printf(s, "Poll\n");
-               break;
-       case DWC3_LINK_STATE_RECOV:
-               seq_printf(s, "Recovery\n");
-               break;
-       case DWC3_LINK_STATE_HRESET:
-               seq_printf(s, "HRESET\n");
-               break;
-       case DWC3_LINK_STATE_CMPLY:
-               seq_printf(s, "Compliance\n");
-               break;
-       case DWC3_LINK_STATE_LPBK:
-               seq_printf(s, "Loopback\n");
-               break;
-       case DWC3_LINK_STATE_RESET:
-               seq_printf(s, "Reset\n");
-               break;
-       case DWC3_LINK_STATE_RESUME:
-               seq_printf(s, "Resume\n");
-               break;
-       default:
-               seq_printf(s, "UNKNOWN %d\n", state);
-       }
+       seq_printf(s, "%s\n", dwc3_gadget_link_string(state));
 
        return 0;
 }
@@ -689,30 +640,6 @@ out:
        return 0;
 }
 
-static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb)
-{
-       switch (DWC3_TRBCTL_TYPE(trb->ctrl)) {
-       case DWC3_TRBCTL_NORMAL:
-               return "normal";
-       case DWC3_TRBCTL_CONTROL_SETUP:
-               return "control-setup";
-       case DWC3_TRBCTL_CONTROL_STATUS2:
-               return "control-status2";
-       case DWC3_TRBCTL_CONTROL_STATUS3:
-               return "control-status3";
-       case DWC3_TRBCTL_CONTROL_DATA:
-               return "control-data";
-       case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
-               return "isoc-first";
-       case DWC3_TRBCTL_ISOCHRONOUS:
-               return "isoc";
-       case DWC3_TRBCTL_LINK_TRB:
-               return "link";
-       default:
-               return "UNKNOWN";
-       }
-}
-
 static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
 {
        struct dwc3_ep          *dep = s->private;
@@ -733,10 +660,11 @@ static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
 
        for (i = 0; i < DWC3_TRB_NUM; i++) {
                struct dwc3_trb *trb = &dep->trb_pool[i];
+               unsigned int type = DWC3_TRBCTL_TYPE(trb->ctrl);
 
                seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n",
                                trb->bph, trb->bpl, trb->size,
-                               dwc3_trb_type_string(trb),
+                               dwc3_trb_type_string(type),
                                !!(trb->ctrl & DWC3_TRB_CTRL_IOC),
                                !!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
                                !!(trb->ctrl & DWC3_TRB_CTRL_CSP),
@@ -822,19 +750,8 @@ static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
 {
        int                     i;
 
-       for (i = 0; i < dwc->num_in_eps; i++) {
-               u8              epnum = (i << 1) | 1;
-               struct dwc3_ep  *dep = dwc->eps[epnum];
-
-               if (!dep)
-                       continue;
-
-               dwc3_debugfs_create_endpoint_dir(dep, parent);
-       }
-
-       for (i = 0; i < dwc->num_out_eps; i++) {
-               u8              epnum = (i << 1);
-               struct dwc3_ep  *dep = dwc->eps[epnum];
+       for (i = 0; i < dwc->num_eps; i++) {
+               struct dwc3_ep  *dep = dwc->eps[i];
 
                if (!dep)
                        continue;
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
new file mode 100644 (file)
index 0000000..2765c51
--- /dev/null
@@ -0,0 +1,85 @@
+/**
+ * drd.c - DesignWare USB3 DRD Controller Dual-role support
+ *
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/extcon.h>
+
+#include "debug.h"
+#include "core.h"
+#include "gadget.h"
+
+static void dwc3_drd_update(struct dwc3 *dwc)
+{
+       int id;
+
+       id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
+       if (id < 0)
+               id = 0;
+
+       dwc3_set_mode(dwc, id ?
+                     DWC3_GCTL_PRTCAP_HOST :
+                     DWC3_GCTL_PRTCAP_DEVICE);
+}
+
+static int dwc3_drd_notifier(struct notifier_block *nb,
+                            unsigned long event, void *ptr)
+{
+       struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
+
+       dwc3_set_mode(dwc, event ?
+                     DWC3_GCTL_PRTCAP_HOST :
+                     DWC3_GCTL_PRTCAP_DEVICE);
+
+       return NOTIFY_DONE;
+}
+
+int dwc3_drd_init(struct dwc3 *dwc)
+{
+       int ret;
+
+       if (dwc->dev->of_node) {
+               if (of_property_read_bool(dwc->dev->of_node, "extcon"))
+                       dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0);
+
+               if (IS_ERR(dwc->edev))
+                       return PTR_ERR(dwc->edev);
+
+               dwc->edev_nb.notifier_call = dwc3_drd_notifier;
+               ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
+                                              &dwc->edev_nb);
+               if (ret < 0) {
+                       dev_err(dwc->dev, "couldn't register cable notifier\n");
+                       return ret;
+               }
+       }
+
+       dwc3_drd_update(dwc);
+
+       return 0;
+}
+
+void dwc3_drd_exit(struct dwc3 *dwc)
+{
+       extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+                                  &dwc->edev_nb);
+
+       dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+       flush_work(&dwc->drd_work);
+       dwc3_gadget_exit(dwc);
+}
index 1515d45ebcec0dd412b52550930053ab9a9a2fe9..98f74ff66120936bad7bb166c8cd2c5fb040b460 100644 (file)
@@ -147,53 +147,53 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
        exynos->vdd33 = devm_regulator_get(dev, "vdd33");
        if (IS_ERR(exynos->vdd33)) {
                ret = PTR_ERR(exynos->vdd33);
-               goto err2;
+               goto vdd33_err;
        }
        ret = regulator_enable(exynos->vdd33);
        if (ret) {
                dev_err(dev, "Failed to enable VDD33 supply\n");
-               goto err2;
+               goto vdd33_err;
        }
 
        exynos->vdd10 = devm_regulator_get(dev, "vdd10");
        if (IS_ERR(exynos->vdd10)) {
                ret = PTR_ERR(exynos->vdd10);
-               goto err3;
+               goto vdd10_err;
        }
        ret = regulator_enable(exynos->vdd10);
        if (ret) {
                dev_err(dev, "Failed to enable VDD10 supply\n");
-               goto err3;
+               goto vdd10_err;
        }
 
        ret = dwc3_exynos_register_phys(exynos);
        if (ret) {
                dev_err(dev, "couldn't register PHYs\n");
-               goto err4;
+               goto phys_err;
        }
 
        if (node) {
                ret = of_platform_populate(node, NULL, NULL, dev);
                if (ret) {
                        dev_err(dev, "failed to add dwc3 core\n");
-                       goto err5;
+                       goto populate_err;
                }
        } else {
                dev_err(dev, "no device node, failed to add dwc3 core\n");
                ret = -ENODEV;
-               goto err5;
+               goto populate_err;
        }
 
        return 0;
 
-err5:
+populate_err:
        platform_device_unregister(exynos->usb2_phy);
        platform_device_unregister(exynos->usb3_phy);
-err4:
+phys_err:
        regulator_disable(exynos->vdd10);
-err3:
+vdd10_err:
        regulator_disable(exynos->vdd33);
-err2:
+vdd33_err:
        clk_disable_unprepare(exynos->axius_clk);
 axius_clk_err:
        clk_disable_unprepare(exynos->susp_clk);
index f8d0747810e78d7cc7930fed1b71cfc9c5aeb048..98926504b55b5b425eb3c9dce66e889a524d2152 100644 (file)
 #define USBOTGSS_DEBUG_OFFSET                  0x0600
 
 /* SYSCONFIG REGISTER */
-#define USBOTGSS_SYSCONFIG_DMADISABLE          (1 << 16)
+#define USBOTGSS_SYSCONFIG_DMADISABLE          BIT(16)
 
 /* IRQ_EOI REGISTER */
-#define USBOTGSS_IRQ_EOI_LINE_NUMBER           (1 << 0)
+#define USBOTGSS_IRQ_EOI_LINE_NUMBER           BIT(0)
 
 /* IRQS0 BITS */
-#define USBOTGSS_IRQO_COREIRQ_ST               (1 << 0)
+#define USBOTGSS_IRQO_COREIRQ_ST               BIT(0)
 
 /* IRQMISC BITS */
-#define USBOTGSS_IRQMISC_DMADISABLECLR         (1 << 17)
-#define USBOTGSS_IRQMISC_OEVT                  (1 << 16)
-#define USBOTGSS_IRQMISC_DRVVBUS_RISE          (1 << 13)
-#define USBOTGSS_IRQMISC_CHRGVBUS_RISE         (1 << 12)
-#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE      (1 << 11)
-#define USBOTGSS_IRQMISC_IDPULLUP_RISE         (1 << 8)
-#define USBOTGSS_IRQMISC_DRVVBUS_FALL          (1 << 5)
-#define USBOTGSS_IRQMISC_CHRGVBUS_FALL         (1 << 4)
-#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL              (1 << 3)
-#define USBOTGSS_IRQMISC_IDPULLUP_FALL         (1 << 0)
+#define USBOTGSS_IRQMISC_DMADISABLECLR         BIT(17)
+#define USBOTGSS_IRQMISC_OEVT                  BIT(16)
+#define USBOTGSS_IRQMISC_DRVVBUS_RISE          BIT(13)
+#define USBOTGSS_IRQMISC_CHRGVBUS_RISE         BIT(12)
+#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE      BIT(11)
+#define USBOTGSS_IRQMISC_IDPULLUP_RISE         BIT(8)
+#define USBOTGSS_IRQMISC_DRVVBUS_FALL          BIT(5)
+#define USBOTGSS_IRQMISC_CHRGVBUS_FALL         BIT(4)
+#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL              BIT(3)
+#define USBOTGSS_IRQMISC_IDPULLUP_FALL         BIT(0)
 
 /* UTMI_OTG_STATUS REGISTER */
-#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS       (1 << 5)
-#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS      (1 << 4)
-#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS   (1 << 3)
-#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP      (1 << 0)
+#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS       BIT(5)
+#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS      BIT(4)
+#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS   BIT(3)
+#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP      BIT(0)
 
 /* UTMI_OTG_CTRL REGISTER */
-#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE         (1 << 31)
-#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT    (1 << 9)
-#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE (1 << 8)
-#define USBOTGSS_UTMI_OTG_CTRL_IDDIG           (1 << 4)
-#define USBOTGSS_UTMI_OTG_CTRL_SESSEND         (1 << 3)
-#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID       (1 << 2)
-#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID       (1 << 1)
+#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE         BIT(31)
+#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT    BIT(9)
+#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE BIT(8)
+#define USBOTGSS_UTMI_OTG_CTRL_IDDIG           BIT(4)
+#define USBOTGSS_UTMI_OTG_CTRL_SESSEND         BIT(3)
+#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID       BIT(2)
+#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID       BIT(1)
 
 struct dwc3_omap {
        struct device           *dev;
index e689cede9b0e526ed4bc98e02d5e7b6294ce6d1d..a78c78e7a8c3c18ac3d50f1b4dc18ec9517ae248 100644 (file)
@@ -39,14 +39,13 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
 static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
                struct dwc3_ep *dep, struct dwc3_request *req);
 
-static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
+static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep,
                dma_addr_t buf_dma, u32 len, u32 type, bool chain)
 {
        struct dwc3_trb                 *trb;
-       struct dwc3_ep                  *dep;
-
-       dep = dwc->eps[epnum];
+       struct dwc3                     *dwc;
 
+       dwc = dep->dwc;
        trb = &dwc->ep0_trb[dep->trb_enqueue];
 
        if (chain)
@@ -69,16 +68,17 @@ static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
        trace_dwc3_prepare_trb(dep, trb);
 }
 
-static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum)
+static int dwc3_ep0_start_trans(struct dwc3_ep *dep)
 {
        struct dwc3_gadget_ep_cmd_params params;
-       struct dwc3_ep                  *dep;
+       struct dwc3                     *dwc;
        int                             ret;
 
-       dep = dwc->eps[epnum];
        if (dep->flags & DWC3_EP_BUSY)
                return 0;
 
+       dwc = dep->dwc;
+
        memset(&params, 0, sizeof(params));
        params.param0 = upper_32_bits(dwc->ep0_trb_addr);
        params.param1 = lower_32_bits(dwc->ep0_trb_addr);
@@ -279,13 +279,15 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
 
 void dwc3_ep0_out_start(struct dwc3 *dwc)
 {
+       struct dwc3_ep                  *dep;
        int                             ret;
 
        complete(&dwc->ep0_in_setup);
 
-       dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8,
+       dep = dwc->eps[0];
+       dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 8,
                        DWC3_TRBCTL_CONTROL_SETUP, false);
-       ret = dwc3_ep0_start_trans(dwc, 0);
+       ret = dwc3_ep0_start_trans(dep);
        WARN_ON(ret < 0);
 }
 
@@ -794,7 +796,7 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event)
 {
-       struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
+       struct usb_ctrlrequest *ctrl = (void *) dwc->ep0_trb;
        int ret = -EINVAL;
        u32 len;
 
@@ -834,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        struct usb_request      *ur;
        struct dwc3_trb         *trb;
        struct dwc3_ep          *ep0;
-       unsigned                transfer_size = 0;
        unsigned                maxp;
        unsigned                remaining_ur_length;
        void                    *buf;
@@ -847,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        ep0 = dwc->eps[0];
 
        dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
-
        trb = dwc->ep0_trb;
-
        trace_dwc3_complete_trb(ep0, trb);
 
        r = next_request(&ep0->pending_list);
@@ -870,58 +869,23 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        remaining_ur_length = ur->length;
 
        length = trb->size & DWC3_TRB_SIZE_MASK;
-
        maxp = ep0->endpoint.maxpacket;
-
-       if (dwc->ep0_bounced) {
-               /*
-                * Handle the first TRB before handling the bounce buffer if
-                * the request length is greater than the bounce buffer size
-                */
-               if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
-                       transfer_size = ALIGN(ur->length - maxp, maxp);
-                       transferred = transfer_size - length;
-                       buf = (u8 *)buf + transferred;
-                       ur->actual += transferred;
-                       remaining_ur_length -= transferred;
-
-                       trb++;
-                       length = trb->size & DWC3_TRB_SIZE_MASK;
-
-                       ep0->trb_enqueue = 0;
-               }
-
-               transfer_size = roundup((ur->length - transfer_size),
-                                       maxp);
-
-               transferred = min_t(u32, remaining_ur_length,
-                                   transfer_size - length);
-               memcpy(buf, dwc->ep0_bounce, transferred);
-       } else {
-               transferred = ur->length - length;
-       }
-
+       transferred = ur->length - length;
        ur->actual += transferred;
 
-       if ((epnum & 1) && ur->actual < ur->length) {
-               /* for some reason we did not get everything out */
+       if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
+            ur->length && ur->zero) || dwc->ep0_bounced) {
+               trb++;
+               trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+               trace_dwc3_complete_trb(ep0, trb);
+               ep0->trb_enqueue = 0;
+               dwc->ep0_bounced = false;
+       }
 
+       if ((epnum & 1) && ur->actual < ur->length)
                dwc3_ep0_stall_and_restart(dwc);
-       } else {
+       else
                dwc3_gadget_giveback(ep0, r, 0);
-
-               if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
-                               ur->length && ur->zero) {
-                       int ret;
-
-                       dwc->ep0_next_event = DWC3_EP0_COMPLETE;
-
-                       dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr,
-                                       0, DWC3_TRBCTL_CONTROL_DATA, false);
-                       ret = dwc3_ep0_start_trans(dwc, epnum);
-                       WARN_ON(ret < 0);
-               }
-       }
 }
 
 static void dwc3_ep0_complete_status(struct dwc3 *dwc,
@@ -997,14 +961,13 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
        req->direction = !!dep->number;
 
        if (req->request.length == 0) {
-               dwc3_ep0_prepare_one_trb(dwc, dep->number,
-                               dwc->ctrl_req_addr, 0,
+               dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0,
                                DWC3_TRBCTL_CONTROL_DATA, false);
-               ret = dwc3_ep0_start_trans(dwc, dep->number);
+               ret = dwc3_ep0_start_trans(dep);
        } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
                        && (dep->number == 0)) {
-               u32     transfer_size = 0;
                u32     maxpacket;
+               u32     rem;
 
                ret = usb_gadget_map_request_by_dev(dwc->sysdev,
                                &req->request, dep->number);
@@ -1012,36 +975,55 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
                        return;
 
                maxpacket = dep->endpoint.maxpacket;
+               rem = req->request.length % maxpacket;
+               dwc->ep0_bounced = true;
 
-               if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
-                       transfer_size = ALIGN(req->request.length - maxpacket,
-                                             maxpacket);
-                       dwc3_ep0_prepare_one_trb(dwc, dep->number,
-                                                  req->request.dma,
-                                                  transfer_size,
-                                                  DWC3_TRBCTL_CONTROL_DATA,
-                                                  true);
-               }
-
-               transfer_size = roundup((req->request.length - transfer_size),
-                                       maxpacket);
+               /* prepare normal TRB */
+               dwc3_ep0_prepare_one_trb(dep, req->request.dma,
+                                        req->request.length,
+                                        DWC3_TRBCTL_CONTROL_DATA,
+                                        true);
+
+               /* Now prepare one extra TRB to align transfer size */
+               dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
+                                        maxpacket - rem,
+                                        DWC3_TRBCTL_CONTROL_DATA,
+                                        false);
+               ret = dwc3_ep0_start_trans(dep);
+       } else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
+                  req->request.length && req->request.zero) {
+               u32     maxpacket;
+               u32     rem;
 
-               dwc->ep0_bounced = true;
+               ret = usb_gadget_map_request_by_dev(dwc->sysdev,
+                               &req->request, dep->number);
+               if (ret)
+                       return;
 
-               dwc3_ep0_prepare_one_trb(dwc, dep->number,
-                               dwc->ep0_bounce_addr, transfer_size,
-                               DWC3_TRBCTL_CONTROL_DATA, false);
-               ret = dwc3_ep0_start_trans(dwc, dep->number);
+               maxpacket = dep->endpoint.maxpacket;
+               rem = req->request.length % maxpacket;
+
+               /* prepare normal TRB */
+               dwc3_ep0_prepare_one_trb(dep, req->request.dma,
+                                        req->request.length,
+                                        DWC3_TRBCTL_CONTROL_DATA,
+                                        true);
+
+               /* Now prepare one extra TRB to align transfer size */
+               dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
+                                        0, DWC3_TRBCTL_CONTROL_DATA,
+                                        false);
+               ret = dwc3_ep0_start_trans(dep);
        } else {
                ret = usb_gadget_map_request_by_dev(dwc->sysdev,
                                &req->request, dep->number);
                if (ret)
                        return;
 
-               dwc3_ep0_prepare_one_trb(dwc, dep->number, req->request.dma,
+               dwc3_ep0_prepare_one_trb(dep, req->request.dma,
                                req->request.length, DWC3_TRBCTL_CONTROL_DATA,
                                false);
-               ret = dwc3_ep0_start_trans(dwc, dep->number);
+               ret = dwc3_ep0_start_trans(dep);
        }
 
        WARN_ON(ret < 0);
@@ -1055,9 +1037,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
        type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
                : DWC3_TRBCTL_CONTROL_STATUS2;
 
-       dwc3_ep0_prepare_one_trb(dwc, dep->number,
-                       dwc->ctrl_req_addr, 0, type, false);
-       return dwc3_ep0_start_trans(dwc, dep->number);
+       dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0, type, false);
+       return dwc3_ep0_start_trans(dep);
 }
 
 static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
index 79e7a3480d51b07abf3988a51f1790f6caec7ca3..6f6f0b3be3ad7a3491d244ff5648a3ef852479c4 100644 (file)
@@ -171,7 +171,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                int status)
 {
        struct dwc3                     *dwc = dep->dwc;
-       unsigned int                    unmap_after_complete = false;
 
        req->started = false;
        list_del(&req->list);
@@ -181,19 +180,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
        if (req->request.status == -EINPROGRESS)
                req->request.status = status;
 
-       /*
-        * NOTICE we don't want to unmap before calling ->complete() if we're
-        * dealing with a bounced ep0 request. If we unmap it here, we would end
-        * up overwritting the contents of req->buf and this could confuse the
-        * gadget driver.
-        */
-       if (dwc->ep0_bounced && dep->number <= 1) {
-               dwc->ep0_bounced = false;
-               unmap_after_complete = true;
-       } else {
-               usb_gadget_unmap_request_by_dev(dwc->sysdev,
-                               &req->request, req->direction);
-       }
+       usb_gadget_unmap_request_by_dev(dwc->sysdev,
+                                       &req->request, req->direction);
 
        trace_dwc3_gadget_giveback(req);
 
@@ -201,10 +189,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
        usb_gadget_giveback_request(&dep->endpoint, &req->request);
        spin_lock(&dwc->lock);
 
-       if (unmap_after_complete)
-               usb_gadget_unmap_request_by_dev(dwc->sysdev,
-                               &req->request, req->direction);
-
        if (dep->number > 1)
                pm_runtime_put(dwc->dev);
 }
@@ -1060,6 +1044,22 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
                                false, 0, req->request.stream_id,
                                req->request.short_not_ok,
                                req->request.no_interrupt);
+       } else if (req->request.zero && req->request.length &&
+                  (IS_ALIGNED(req->request.length,dep->endpoint.maxpacket))) {
+               struct dwc3     *dwc = dep->dwc;
+               struct dwc3_trb *trb;
+
+               req->zero = true;
+
+               /* prepare normal TRB */
+               dwc3_prepare_one_trb(dep, req, true, 0);
+
+               /* Now prepare one extra TRB to handle ZLP */
+               trb = &dep->trb_pool[dep->trb_enqueue];
+               __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
+                               false, 0, req->request.stream_id,
+                               req->request.short_not_ok,
+                               req->request.no_interrupt);
        } else {
                dwc3_prepare_one_trb(dep, req, false, 0);
        }
@@ -1184,8 +1184,11 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
                return;
        }
 
-       /* 4 micro frames in the future */
-       uf = cur_uf + dep->interval * 4;
+       /*
+        * Schedule the first trb for one interval in the future or at
+        * least 4 microframes.
+        */
+       uf = cur_uf + max_t(u32, 4, dep->interval);
 
        __dwc3_gadget_kick_transfer(dep, uf);
 }
@@ -1272,31 +1275,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
        return ret;
 }
 
-static void __dwc3_gadget_ep_zlp_complete(struct usb_ep *ep,
-               struct usb_request *request)
-{
-       dwc3_gadget_ep_free_request(ep, request);
-}
-
-static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep)
-{
-       struct dwc3_request             *req;
-       struct usb_request              *request;
-       struct usb_ep                   *ep = &dep->endpoint;
-
-       request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC);
-       if (!request)
-               return -ENOMEM;
-
-       request->length = 0;
-       request->buf = dwc->zlp_buf;
-       request->complete = __dwc3_gadget_ep_zlp_complete;
-
-       req = to_dwc3_request(request);
-
-       return __dwc3_gadget_ep_queue(dep, req);
-}
-
 static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
        gfp_t gfp_flags)
 {
@@ -1310,17 +1288,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
 
        spin_lock_irqsave(&dwc->lock, flags);
        ret = __dwc3_gadget_ep_queue(dep, req);
-
-       /*
-        * Okay, here's the thing, if gadget driver has requested for a ZLP by
-        * setting request->zero, instead of doing magic, we will just queue an
-        * extra usb_request ourselves so that it gets handled the same way as
-        * any other request.
-        */
-       if (ret == 0 && request->zero && request->length &&
-           (request->length % ep->maxpacket == 0))
-               ret = __dwc3_gadget_ep_queue_zlp(dwc, dep);
-
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return ret;
@@ -1400,7 +1367,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
                                        dwc3_ep_inc_deq(dep);
                                }
 
-                               if (r->unaligned) {
+                               if (r->unaligned || r->zero) {
                                        trb = r->trb + r->num_pending_sgs + 1;
                                        trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
                                        dwc3_ep_inc_deq(dep);
@@ -1411,7 +1378,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
                                trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
                                dwc3_ep_inc_deq(dep);
 
-                               if (r->unaligned) {
+                               if (r->unaligned || r->zero) {
                                        trb = r->trb + 1;
                                        trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
                                        dwc3_ep_inc_deq(dep);
@@ -2006,14 +1973,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
 
 /* -------------------------------------------------------------------------- */
 
-static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
-               u8 num, u32 direction)
+static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 num)
 {
        struct dwc3_ep                  *dep;
-       u8                              i;
+       u8                              epnum;
+
+       INIT_LIST_HEAD(&dwc->gadget.ep_list);
 
-       for (i = 0; i < num; i++) {
-               u8 epnum = (i << 1) | (direction ? 1 : 0);
+       for (epnum = 0; epnum < num; epnum++) {
+               bool                    direction = epnum & 1;
 
                dep = kzalloc(sizeof(*dep), GFP_KERNEL);
                if (!dep)
@@ -2021,12 +1989,12 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 
                dep->dwc = dwc;
                dep->number = epnum;
-               dep->direction = !!direction;
+               dep->direction = direction;
                dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
                dwc->eps[epnum] = dep;
 
                snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
-                               (epnum & 1) ? "in" : "out");
+                               direction ? "in" : "out");
 
                dep->endpoint.name = dep->name;
 
@@ -2053,7 +2021,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
                        /* MDWIDTH is represented in bits, we need it in bytes */
                        mdwidth /= 8;
 
-                       size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(i));
+                       size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(epnum >> 1));
                        size = DWC3_GTXFIFOSIZ_TXFDEF(size);
 
                        /* FIFO Depth is in MDWDITH bytes. Multiply */
@@ -2103,7 +2071,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
                        dep->endpoint.caps.type_int = true;
                }
 
-               dep->endpoint.caps.dir_in = !!direction;
+               dep->endpoint.caps.dir_in = direction;
                dep->endpoint.caps.dir_out = !direction;
 
                INIT_LIST_HEAD(&dep->pending_list);
@@ -2113,27 +2081,6 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
        return 0;
 }
 
-static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
-{
-       int                             ret;
-
-       INIT_LIST_HEAD(&dwc->gadget.ep_list);
-
-       ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
-       if (ret < 0) {
-               dev_err(dwc->dev, "failed to initialize OUT endpoints\n");
-               return ret;
-       }
-
-       ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
-       if (ret < 0) {
-               dev_err(dwc->dev, "failed to initialize IN endpoints\n");
-               return ret;
-       }
-
-       return 0;
-}
-
 static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
 {
        struct dwc3_ep                  *dep;
@@ -2197,7 +2144,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
         * with one TRB pending in the ring. We need to manually clear HWO bit
         * from that TRB.
         */
-       if (req->unaligned && (trb->ctrl & DWC3_TRB_CTRL_HWO)) {
+       if ((req->zero || req->unaligned) && (trb->ctrl & DWC3_TRB_CTRL_HWO)) {
                trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
                return 1;
        }
@@ -2291,11 +2238,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                                        event, status, chain);
                }
 
-               if (req->unaligned) {
+               if (req->unaligned || req->zero) {
                        trb = &dep->trb_pool[dep->trb_dequeue];
                        ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
                                        event, status, false);
                        req->unaligned = false;
+                       req->zero = false;
                }
 
                req->request.actual = length - req->remaining;
@@ -3161,49 +3109,26 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 
        dwc->irq_gadget = irq;
 
-       dwc->ctrl_req = dma_alloc_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
-                       &dwc->ctrl_req_addr, GFP_KERNEL);
-       if (!dwc->ctrl_req) {
-               dev_err(dwc->dev, "failed to allocate ctrl request\n");
-               ret = -ENOMEM;
-               goto err0;
-       }
-
        dwc->ep0_trb = dma_alloc_coherent(dwc->sysdev,
                                          sizeof(*dwc->ep0_trb) * 2,
                                          &dwc->ep0_trb_addr, GFP_KERNEL);
        if (!dwc->ep0_trb) {
                dev_err(dwc->dev, "failed to allocate ep0 trb\n");
                ret = -ENOMEM;
-               goto err1;
+               goto err0;
        }
 
-       dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
+       dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL);
        if (!dwc->setup_buf) {
                ret = -ENOMEM;
-               goto err2;
-       }
-
-       dwc->ep0_bounce = dma_alloc_coherent(dwc->sysdev,
-                       DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
-                       GFP_KERNEL);
-       if (!dwc->ep0_bounce) {
-               dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
-               ret = -ENOMEM;
-               goto err3;
-       }
-
-       dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL);
-       if (!dwc->zlp_buf) {
-               ret = -ENOMEM;
-               goto err4;
+               goto err1;
        }
 
        dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
                        &dwc->bounce_addr, GFP_KERNEL);
        if (!dwc->bounce) {
                ret = -ENOMEM;
-               goto err5;
+               goto err2;
        }
 
        init_completion(&dwc->ep0_in_setup);
@@ -3241,39 +3166,31 @@ int dwc3_gadget_init(struct dwc3 *dwc)
         * sure we're starting from a well known location.
         */
 
-       ret = dwc3_gadget_init_endpoints(dwc);
+       ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
        if (ret)
-               goto err6;
+               goto err3;
 
        ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
        if (ret) {
                dev_err(dwc->dev, "failed to register udc\n");
-               goto err6;
+               goto err4;
        }
 
        return 0;
-err6:
-       dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
-                       dwc->bounce_addr);
-
-err5:
-       kfree(dwc->zlp_buf);
 
 err4:
        dwc3_gadget_free_endpoints(dwc);
-       dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
-                       dwc->ep0_bounce, dwc->ep0_bounce_addr);
 
 err3:
-       kfree(dwc->setup_buf);
+       dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
+                       dwc->bounce_addr);
 
 err2:
-       dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
-                       dwc->ep0_trb, dwc->ep0_trb_addr);
+       kfree(dwc->setup_buf);
 
 err1:
-       dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
-                       dwc->ctrl_req, dwc->ctrl_req_addr);
+       dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
+                       dwc->ep0_trb, dwc->ep0_trb_addr);
 
 err0:
        return ret;
@@ -3284,22 +3201,12 @@ err0:
 void dwc3_gadget_exit(struct dwc3 *dwc)
 {
        usb_del_gadget_udc(&dwc->gadget);
-
        dwc3_gadget_free_endpoints(dwc);
-
        dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
-                       dwc->bounce_addr);
-       dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
-                       dwc->ep0_bounce, dwc->ep0_bounce_addr);
-
+                         dwc->bounce_addr);
        kfree(dwc->setup_buf);
-       kfree(dwc->zlp_buf);
-
        dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
-                       dwc->ep0_trb, dwc->ep0_trb_addr);
-
-       dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
-                       dwc->ctrl_req, dwc->ctrl_req_addr);
+                         dwc->ep0_trb, dwc->ep0_trb_addr);
 }
 
 int dwc3_gadget_suspend(struct dwc3 *dwc)
index 265e223ab64554f6be78d37d15e36a86bb571c74..e4602d0e515bbd6473c534b227844a07bc792b30 100644 (file)
@@ -29,16 +29,16 @@ struct dwc3;
 
 /* DEPCFG parameter 1 */
 #define DWC3_DEPCFG_INT_NUM(n)         (((n) & 0x1f) << 0)
-#define DWC3_DEPCFG_XFER_COMPLETE_EN   (1 << 8)
-#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN        (1 << 9)
-#define DWC3_DEPCFG_XFER_NOT_READY_EN  (1 << 10)
-#define DWC3_DEPCFG_FIFO_ERROR_EN      (1 << 11)
-#define DWC3_DEPCFG_STREAM_EVENT_EN    (1 << 13)
+#define DWC3_DEPCFG_XFER_COMPLETE_EN   BIT(8)
+#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN        BIT(9)
+#define DWC3_DEPCFG_XFER_NOT_READY_EN  BIT(10)
+#define DWC3_DEPCFG_FIFO_ERROR_EN      BIT(11)
+#define DWC3_DEPCFG_STREAM_EVENT_EN    BIT(12)
 #define DWC3_DEPCFG_BINTERVAL_M1(n)    (((n) & 0xff) << 16)
-#define DWC3_DEPCFG_STREAM_CAPABLE     (1 << 24)
+#define DWC3_DEPCFG_STREAM_CAPABLE     BIT(24)
 #define DWC3_DEPCFG_EP_NUMBER(n)       (((n) & 0x1f) << 25)
-#define DWC3_DEPCFG_BULK_BASED         (1 << 30)
-#define DWC3_DEPCFG_FIFO_BASED         (1 << 31)
+#define DWC3_DEPCFG_BULK_BASED         BIT(30)
+#define DWC3_DEPCFG_FIFO_BASED         BIT(31)
 
 /* DEPCFG parameter 0 */
 #define DWC3_DEPCFG_EP_TYPE(n)         (((n) & 0x3) << 1)
@@ -47,10 +47,10 @@ struct dwc3;
 #define DWC3_DEPCFG_BURST_SIZE(n)      (((n) & 0xf) << 22)
 #define DWC3_DEPCFG_DATA_SEQ_NUM(n)    ((n) << 26)
 /* This applies for core versions earlier than 1.94a */
-#define DWC3_DEPCFG_IGN_SEQ_NUM                (1 << 31)
+#define DWC3_DEPCFG_IGN_SEQ_NUM                BIT(31)
 /* These apply for core versions 1.94a and later */
 #define DWC3_DEPCFG_ACTION_INIT                (0 << 30)
-#define DWC3_DEPCFG_ACTION_RESTORE     (1 << 30)
+#define DWC3_DEPCFG_ACTION_RESTORE     BIT(30)
 #define DWC3_DEPCFG_ACTION_MODIFY      (2 << 30)
 
 /* DEPXFERCFG parameter 0 */
index 2b124f94d858487ec9694683f618c0b1448e64d4..f1bd444d22a36b5a331bee6f2187d8a50094085d 100644 (file)
 #include "core.h"
 #include "debug.h"
 
-DECLARE_EVENT_CLASS(dwc3_log_msg,
-       TP_PROTO(struct va_format *vaf),
-       TP_ARGS(vaf),
-       TP_STRUCT__entry(__dynamic_array(char, msg, DWC3_MSG_MAX)),
-       TP_fast_assign(
-               vsnprintf(__get_str(msg), DWC3_MSG_MAX, vaf->fmt, *vaf->va);
-       ),
-       TP_printk("%s", __get_str(msg))
-);
-
-DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
-       TP_PROTO(struct va_format *vaf),
-       TP_ARGS(vaf)
-);
-
-DEFINE_EVENT(dwc3_log_msg, dwc3_core,
-       TP_PROTO(struct va_format *vaf),
-       TP_ARGS(vaf)
-);
-
-DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
-       TP_PROTO(struct va_format *vaf),
-       TP_ARGS(vaf)
-);
-
 DECLARE_EVENT_CLASS(dwc3_log_io,
        TP_PROTO(void *base, u32 offset, u32 value),
        TP_ARGS(base, offset, value),
@@ -198,7 +173,7 @@ DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
                __entry->param = param;
                __entry->status = status;
        ),
-       TP_printk("cmd '%s' [%d] param %08x --> status: %s",
+       TP_printk("cmd '%s' [%x] param %08x --> status: %s",
                dwc3_gadget_generic_cmd_string(__entry->cmd),
                __entry->cmd, __entry->param,
                dwc3_gadget_generic_cmd_status_string(__entry->status)
@@ -298,36 +273,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
                __entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
                __entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
                __entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
-               ({char *s;
-               switch (__entry->ctrl & 0x3f0) {
-               case DWC3_TRBCTL_NORMAL:
-                       s = "normal";
-                       break;
-               case DWC3_TRBCTL_CONTROL_SETUP:
-                       s = "setup";
-                       break;
-               case DWC3_TRBCTL_CONTROL_STATUS2:
-                       s = "status2";
-                       break;
-               case DWC3_TRBCTL_CONTROL_STATUS3:
-                       s = "status3";
-                       break;
-               case DWC3_TRBCTL_CONTROL_DATA:
-                       s = "data";
-                       break;
-               case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
-                       s = "isoc-first";
-                       break;
-               case DWC3_TRBCTL_ISOCHRONOUS:
-                       s = "isoc";
-                       break;
-               case DWC3_TRBCTL_LINK_TRB:
-                       s = "link";
-                       break;
-               default:
-                       s = "UNKNOWN";
-                       break;
-               } s; })
+                 dwc3_trb_type_string(DWC3_TRBCTL_TYPE(__entry->ctrl))
        )
 );
 
index 8ad203296079f6a9cf5e7457db1017784725a710..c164d6b788c31f9922836f407c21e50bfce73f5a 100644 (file)
@@ -212,7 +212,7 @@ config USB_F_TCM
 # this first set of drivers all depend on bulk-capable hardware.
 
 config USB_CONFIGFS
-       tristate "USB functions configurable through configfs"
+       tristate "USB Gadget functions configurable through configfs"
        select USB_LIBCOMPOSITE
        help
          A Linux USB "gadget" can be set up through configfs.
@@ -458,8 +458,9 @@ config USB_CONFIGFS_F_TCM
          UAS utilizes the USB 3.0 feature called streams support.
 
 choice
-       tristate "USB Gadget Drivers"
+       tristate "USB Gadget precomposed configurations"
        default USB_ETH
+       optional
        help
          A Linux "Gadget Driver" talks to the USB Peripheral Controller
          driver through the abstract "gadget" API.  Some other operating
@@ -476,6 +477,12 @@ choice
          not be able work with that controller, or might need to implement
          a less common variant of a device class protocol.
 
+         The available choices each represent a single precomposed USB
+         gadget configuration. In the device model, each option contains
+         both the device instantiation as a child for a USB gadget
+         controller, and the relevant drivers for each function declared
+         by the device.
+
 source "drivers/usb/gadget/legacy/Kconfig"
 
 endchoice
index a9b9f4c753fe7363eea48083e9220718585ebf40..71dd27c0d7f27daf9d2db08b6a0b72901844ba3f 100644 (file)
@@ -246,7 +246,6 @@ EXPORT_SYMBOL_GPL(ffs_lock);
 
 static struct ffs_dev *_ffs_find_dev(const char *name);
 static struct ffs_dev *_ffs_alloc_dev(void);
-static int _ffs_name_dev(struct ffs_dev *dev, const char *name);
 static void _ffs_free_dev(struct ffs_dev *dev);
 static void *ffs_acquire_dev(const char *dev_name);
 static void ffs_release_dev(struct ffs_data *ffs_data);
@@ -3302,9 +3301,10 @@ static struct ffs_dev *_ffs_do_find_dev(const char *name)
 {
        struct ffs_dev *dev;
 
+       if (!name)
+               return NULL;
+
        list_for_each_entry(dev, &ffs_devices, entry) {
-               if (!dev->name || !name)
-                       continue;
                if (strcmp(dev->name, name) == 0)
                        return dev;
        }
@@ -3380,42 +3380,11 @@ static void ffs_free_inst(struct usb_function_instance *f)
        kfree(opts);
 }
 
-#define MAX_INST_NAME_LEN      40
-
 static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
 {
-       struct f_fs_opts *opts;
-       char *ptr;
-       const char *tmp;
-       int name_len, ret;
-
-       name_len = strlen(name) + 1;
-       if (name_len > MAX_INST_NAME_LEN)
+       if (strlen(name) >= FIELD_SIZEOF(struct ffs_dev, name))
                return -ENAMETOOLONG;
-
-       ptr = kstrndup(name, name_len, GFP_KERNEL);
-       if (!ptr)
-               return -ENOMEM;
-
-       opts = to_f_fs_opts(fi);
-       tmp = NULL;
-
-       ffs_dev_lock();
-
-       tmp = opts->dev->name_allocated ? opts->dev->name : NULL;
-       ret = _ffs_name_dev(opts->dev, ptr);
-       if (ret) {
-               kfree(ptr);
-               ffs_dev_unlock();
-               return ret;
-       }
-       opts->dev->name_allocated = true;
-
-       ffs_dev_unlock();
-
-       kfree(tmp);
-
-       return 0;
+       return ffs_name_dev(to_f_fs_opts(fi)->dev, name);
 }
 
 static struct usb_function_instance *ffs_alloc_inst(void)
@@ -3545,32 +3514,19 @@ static struct ffs_dev *_ffs_alloc_dev(void)
        return dev;
 }
 
-/*
- * ffs_lock must be taken by the caller of this function
- * The caller is responsible for "name" being available whenever f_fs needs it
- */
-static int _ffs_name_dev(struct ffs_dev *dev, const char *name)
+int ffs_name_dev(struct ffs_dev *dev, const char *name)
 {
        struct ffs_dev *existing;
+       int ret = 0;
 
-       existing = _ffs_do_find_dev(name);
-       if (existing)
-               return -EBUSY;
-
-       dev->name = name;
-
-       return 0;
-}
+       ffs_dev_lock();
 
-/*
- * The caller is responsible for "name" being available whenever f_fs needs it
- */
-int ffs_name_dev(struct ffs_dev *dev, const char *name)
-{
-       int ret;
+       existing = _ffs_do_find_dev(name);
+       if (!existing)
+               strlcpy(dev->name, name, ARRAY_SIZE(dev->name));
+       else if (existing != dev)
+               ret = -EBUSY;
 
-       ffs_dev_lock();
-       ret = _ffs_name_dev(dev, name);
        ffs_dev_unlock();
 
        return ret;
@@ -3600,8 +3556,6 @@ EXPORT_SYMBOL_GPL(ffs_single_dev);
 static void _ffs_free_dev(struct ffs_dev *dev)
 {
        list_del(&dev->entry);
-       if (dev->name_allocated)
-               kfree(dev->name);
 
        /* Clear the private_data pointer to stop incorrect dev access */
        if (dev->ffs_data)
index c3cab77181d4c2677ea5214d6c9abc0b120d83e8..a8b40d07e927bb78e835b40efeea9bb83fb19bf8 100644 (file)
@@ -178,6 +178,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req);
 static int
 rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
 {
+       struct usb_gadget *g = dev->gadget;
        struct sk_buff  *skb;
        int             retval = -ENOMEM;
        size_t          size = 0;
@@ -209,8 +210,11 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
         */
        size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
        size += dev->port_usb->header_len;
-       size += out->maxpacket - 1;
-       size -= size % out->maxpacket;
+
+       if (g->quirk_ep_out_aligned_size) {
+               size += out->maxpacket - 1;
+               size -= size % out->maxpacket;
+       }
 
        if (dev->port_usb->is_fixed)
                size = max_t(size_t, size, dev->port_usb->fixed_out_len);
@@ -401,13 +405,12 @@ done:
 static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
 {
        struct usb_request      *req;
+       struct usb_request      *tmp;
        unsigned long           flags;
 
        /* fill unused rxq slots with some skb */
        spin_lock_irqsave(&dev->req_lock, flags);
-       while (!list_empty(&dev->rx_reqs)) {
-               req = container_of(dev->rx_reqs.next,
-                               struct usb_request, list);
+       list_for_each_entry_safe(req, tmp, &dev->rx_reqs, list) {
                list_del_init(&req->list);
                spin_unlock_irqrestore(&dev->req_lock, flags);
 
@@ -527,7 +530,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
                return NETDEV_TX_BUSY;
        }
 
-       req = container_of(dev->tx_reqs.next, struct usb_request, list);
+       req = list_first_entry(&dev->tx_reqs, struct usb_request, list);
        list_del(&req->list);
 
        /* temporarily stop TX queue when the freelist empties */
@@ -1122,6 +1125,7 @@ void gether_disconnect(struct gether *link)
 {
        struct eth_dev          *dev = link->ioport;
        struct usb_request      *req;
+       struct usb_request      *tmp;
 
        WARN_ON(!dev);
        if (!dev)
@@ -1138,9 +1142,7 @@ void gether_disconnect(struct gether *link)
         */
        usb_ep_disable(link->in_ep);
        spin_lock(&dev->req_lock);
-       while (!list_empty(&dev->tx_reqs)) {
-               req = container_of(dev->tx_reqs.next,
-                                       struct usb_request, list);
+       list_for_each_entry_safe(req, tmp, &dev->tx_reqs, list) {
                list_del(&req->list);
 
                spin_unlock(&dev->req_lock);
@@ -1152,9 +1154,7 @@ void gether_disconnect(struct gether *link)
 
        usb_ep_disable(link->out_ep);
        spin_lock(&dev->req_lock);
-       while (!list_empty(&dev->rx_reqs)) {
-               req = container_of(dev->rx_reqs.next,
-                                       struct usb_request, list);
+       list_for_each_entry_safe(req, tmp, &dev->rx_reqs, list) {
                list_del(&req->list);
 
                spin_unlock(&dev->req_lock);
index abfca48544336735b3ffff02d2f86fc3577b749c..4378cc2fcac36fd69c71cdea53fef6e7ce6ce6e9 100644 (file)
 struct f_fs_opts;
 
 struct ffs_dev {
-       const char *name;
-       bool name_allocated;
-       bool mounted;
-       bool desc_ready;
-       bool single;
        struct ffs_data *ffs_data;
        struct f_fs_opts *opts;
        struct list_head entry;
 
+       char name[41];
+
+       bool mounted;
+       bool desc_ready;
+       bool single;
+
        int (*ffs_ready_callback)(struct ffs_data *ffs);
        void (*ffs_closed_callback)(struct ffs_data *ffs);
        void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
index 4e037d2a7a60c3eefdd9f6585def29b23c02984b..844cb738bafd00537b567038301beb7f5850f034 100644 (file)
@@ -2125,7 +2125,7 @@ static struct configfs_item_operations uvc_item_ops = {
        .release                = uvc_attr_release,
 };
 
-#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit)           \
+#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit)    \
 static ssize_t f_uvc_opts_##cname##_show(                              \
        struct config_item *item, char *page)                           \
 {                                                                      \
@@ -2168,16 +2168,16 @@ end:                                                                    \
        return ret;                                                     \
 }                                                                      \
                                                                        \
-UVC_ATTR(f_uvc_opts_, cname, aname)
+UVC_ATTR(f_uvc_opts_, cname, cname)
 
 #define identity_conv(x) (x)
 
-UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
-              16);
-UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
-              3072);
-UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
-              15);
+UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
+              kstrtou8, u8, identity_conv, 16);
+UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
+              kstrtou16, u16, le16_to_cpu, 3072);
+UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
+              kstrtou8, u8, identity_conv, 15);
 
 #undef identity_conv
 
index c6cc9d3270acd714f2471b85dddd392746101629..1c14c283cc47de111d8f6e4990b62f5906dc89a1 100644 (file)
@@ -62,8 +62,9 @@ config USB_ATMEL_USBA
 
          The fifo_mode parameter is used to select endpoint allocation mode.
          fifo_mode = 0 is used to let the driver autoconfigure the endpoints.
-         In this case 2 banks are allocated for isochronous endpoints and
-         only one bank is allocated for the rest of the endpoints.
+         In this case, for ep1 2 banks are allocated if it works in isochronous
+         mode and only 1 bank otherwise. For the rest of the endpoints
+         only 1 bank is allocated.
 
          fifo_mode = 1 is a generic maximum fifo size (1024 bytes) configuration
          allowing the usage of ep1 - ep6
@@ -191,6 +192,7 @@ config USB_RENESAS_USBHS_UDC
 config USB_RENESAS_USB3
        tristate 'Renesas USB3.0 Peripheral controller'
        depends on ARCH_RENESAS || COMPILE_TEST
+       depends on EXTCON
        help
           Renesas USB3.0 Peripheral controller is a USB peripheral controller
           that supports super, high, and full speed USB 3.0 data transfers.
@@ -253,6 +255,20 @@ config USB_MV_U3D
          MARVELL PXA2128 Processor series include a super speed USB3.0 device
          controller, which support super speed USB peripheral.
 
+config USB_SNP_CORE
+       depends on USB_AMD5536UDC
+       tristate
+       help
+         This enables core driver support for Synopsys USB 2.0 Device
+         controller.
+
+         This will be enabled when PCI or Platform driver for this UDC is
+         selected. Currently, this will be enabled by USB_SNP_UDC_PLAT or
+         USB_AMD5536UDC options.
+
+         This IP is different to the High Speed OTG IP that can be enabled
+         by selecting USB_DWC2 or USB_DWC3 options.
+
 #
 # Controllers available in both integrated and discrete versions
 #
@@ -278,6 +294,7 @@ source "drivers/usb/gadget/udc/bdc/Kconfig"
 config USB_AMD5536UDC
        tristate "AMD5536 UDC"
        depends on USB_PCI
+       select USB_SNP_CORE
        help
           The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
           It is a USB Highspeed DMA capable USB device controller. Beside ep0
@@ -285,6 +302,9 @@ config USB_AMD5536UDC
           The UDC port supports OTG operation, and may be used as a host port
           if it's not being used to implement peripheral or OTG roles.
 
+          This UDC is based on Synopsys USB device controller IP and selects
+          CONFIG_USB_SNP_CORE option to build the core driver.
+
           Say "y" to link the driver statically, or "m" to build a
           dynamically linked module called "amd5536udc" and force all
           gadget drivers to also be dynamically linked.
index 98e74ed9f555547d8d4b778bb7d2fc4d19e553f1..626e1f1c62da9ad0430b68bfd721a14f6f1965ab 100644 (file)
@@ -10,7 +10,8 @@ obj-$(CONFIG_USB_GADGET)      += udc-core.o
 obj-$(CONFIG_USB_DUMMY_HCD)    += dummy_hcd.o
 obj-$(CONFIG_USB_NET2272)      += net2272.o
 obj-$(CONFIG_USB_NET2280)      += net2280.o
-obj-$(CONFIG_USB_AMD5536UDC)   += amd5536udc.o
+obj-$(CONFIG_USB_SNP_CORE)     += amd5536udc.o
+obj-$(CONFIG_USB_AMD5536UDC)   += amd5536udc_pci.o
 obj-$(CONFIG_USB_PXA25X)       += pxa25x_udc.o
 obj-$(CONFIG_USB_PXA27X)       += pxa27x_udc.o
 obj-$(CONFIG_USB_GOKU)         += goku_udc.o
index 270876b438ab13dad359b6da19e777d27ad98745..4ecd2f20ea480082a5a3abf2f9a7f8e756e6c495 100644 (file)
  */
 
 /*
- * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
- * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
- * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
- *
- * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
- * be used as host port) and UOC bits PAD_EN and APU are set (should be done
- * by BIOS init).
- *
- * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
- * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
- * can be used with gadget ether.
+ * This file does the core driver implementation for the UDC that is based
+ * on Synopsys device controller IP (different than HS OTG IP) that is either
+ * connected through PCI bus or integrated to SoC platforms.
  */
 
-/* debug control */
-/* #define UDC_VERBOSE */
-
 /* Driver strings */
-#define UDC_MOD_DESCRIPTION            "AMD 5536 UDC - USB Device Controller"
+#define UDC_MOD_DESCRIPTION            "Synopsys USB Device Controller"
 #define UDC_DRIVER_VERSION_STRING      "01.00.0206"
 
-/* system */
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/ioctl.h>
 #include <linux/fs.h>
 #include <linux/dmapool.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/irq.h>
 #include <linux/prefetch.h>
-
+#include <linux/moduleparam.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
-
-/* gadget stack */
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-/* udc specific */
 #include "amd5536udc.h"
 
-
 static void udc_tasklet_disconnect(unsigned long);
 static void empty_req_queue(struct udc_ep *);
 static void udc_setup_endpoints(struct udc *dev);
@@ -72,7 +49,7 @@ static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
 
 /* description */
 static const char mod_desc[] = UDC_MOD_DESCRIPTION;
-static const char name[] = "amd5536udc";
+static const char name[] = "udc";
 
 /* structure to hold endpoint function pointers */
 static const struct usb_ep_ops udc_ep_ops;
@@ -208,30 +185,11 @@ static const struct {
 #undef EP_INFO
 };
 
-/* DMA usage flag */
-static bool use_dma = 1;
-/* packet per buffer dma */
-static bool use_dma_ppb = 1;
-/* with per descr. update */
-static bool use_dma_ppb_du;
 /* buffer fill mode */
 static int use_dma_bufferfill_mode;
-/* full speed only mode */
-static bool use_fullspeed;
 /* tx buffer size for high speed */
 static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
 
-/* module parameters */
-module_param(use_dma, bool, S_IRUGO);
-MODULE_PARM_DESC(use_dma, "true for DMA");
-module_param(use_dma_ppb, bool, S_IRUGO);
-MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
-module_param(use_dma_ppb_du, bool, S_IRUGO);
-MODULE_PARM_DESC(use_dma_ppb_du,
-       "true for DMA in packet per buffer mode with descriptor update");
-module_param(use_fullspeed, bool, S_IRUGO);
-MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
-
 /*---------------------------------------------------------------------------*/
 /* Prints UDC device registers and endpoint irq registers */
 static void print_regs(struct udc *dev)
@@ -267,7 +225,7 @@ static void print_regs(struct udc *dev)
 }
 
 /* Masks unused interrupts */
-static int udc_mask_unused_interrupts(struct udc *dev)
+int udc_mask_unused_interrupts(struct udc *dev)
 {
        u32 tmp;
 
@@ -287,6 +245,7 @@ static int udc_mask_unused_interrupts(struct udc *dev)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(udc_mask_unused_interrupts);
 
 /* Enables endpoint 0 interrupts */
 static int udc_enable_ep0_interrupts(struct udc *dev)
@@ -306,7 +265,7 @@ static int udc_enable_ep0_interrupts(struct udc *dev)
 }
 
 /* Enables device interrupts for SET_INTF and SET_CONFIG */
-static int udc_enable_dev_setup_interrupts(struct udc *dev)
+int udc_enable_dev_setup_interrupts(struct udc *dev)
 {
        u32 tmp;
 
@@ -325,6 +284,7 @@ static int udc_enable_dev_setup_interrupts(struct udc *dev)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(udc_enable_dev_setup_interrupts);
 
 /* Calculates fifo start of endpoint based on preceding endpoints */
 static int udc_set_txfifo_addr(struct udc_ep *ep)
@@ -608,27 +568,23 @@ udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
 }
 
 /* frees pci pool descriptors of a DMA chain */
-static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+static void udc_free_dma_chain(struct udc *dev, struct udc_request *req)
 {
-       int ret_val = 0;
-       struct udc_data_dma     *td;
-       struct udc_data_dma     *td_last = NULL;
+       struct udc_data_dma *td = req->td_data;
        unsigned int i;
 
+       dma_addr_t addr_next = 0x00;
+       dma_addr_t addr = (dma_addr_t)td->next;
+
        DBG(dev, "free chain req = %p\n", req);
 
        /* do not free first desc., will be done by free for request */
-       td_last = req->td_data;
-       td = phys_to_virt(td_last->next);
-
        for (i = 1; i < req->chain_len; i++) {
-               dma_pool_free(dev->data_requests, td,
-                             (dma_addr_t)td_last->next);
-               td_last = td;
-               td = phys_to_virt(td_last->next);
+               td = phys_to_virt(addr);
+               addr_next = (dma_addr_t)td->next;
+               dma_pool_free(dev->data_requests, td, addr);
+               addr = addr_next;
        }
-
-       return ret_val;
 }
 
 /* Frees request packet, called by gadget driver */
@@ -1507,7 +1463,7 @@ static void make_ep_lists(struct udc *dev)
 }
 
 /* Inits UDC context */
-static void udc_basic_init(struct udc *dev)
+void udc_basic_init(struct udc *dev)
 {
        u32     tmp;
 
@@ -1543,6 +1499,7 @@ static void udc_basic_init(struct udc *dev)
        dev->data_ep_enabled = 0;
        dev->data_ep_queued = 0;
 }
+EXPORT_SYMBOL_GPL(udc_basic_init);
 
 /* init registers at driver load time */
 static int startup_registers(struct udc *dev)
@@ -3031,7 +2988,7 @@ __acquires(dev->lock)
 }
 
 /* Interrupt Service Routine, see Linux Kernel Doc for parameters */
-static irqreturn_t udc_irq(int irq, void *pdev)
+irqreturn_t udc_irq(int irq, void *pdev)
 {
        struct udc *dev = pdev;
        u32 reg;
@@ -3083,16 +3040,18 @@ static irqreturn_t udc_irq(int irq, void *pdev)
        spin_unlock(&dev->lock);
        return ret_val;
 }
+EXPORT_SYMBOL_GPL(udc_irq);
 
 /* Tears down device */
-static void gadget_release(struct device *pdev)
+void gadget_release(struct device *pdev)
 {
        struct amd5536udc *dev = dev_get_drvdata(pdev);
        kfree(dev);
 }
+EXPORT_SYMBOL_GPL(gadget_release);
 
 /* Cleanup on device remove */
-static void udc_remove(struct udc *dev)
+void udc_remove(struct udc *dev)
 {
        /* remove timer */
        stop_timer++;
@@ -3108,9 +3067,10 @@ static void udc_remove(struct udc *dev)
                del_timer_sync(&udc_pollstall_timer);
        udc = NULL;
 }
+EXPORT_SYMBOL_GPL(udc_remove);
 
 /* free all the dma pools */
-static void free_dma_pools(struct udc *dev)
+void free_dma_pools(struct udc *dev)
 {
        dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td,
                      dev->ep[UDC_EP0OUT_IX].td_phys);
@@ -3119,35 +3079,10 @@ static void free_dma_pools(struct udc *dev)
        dma_pool_destroy(dev->stp_requests);
        dma_pool_destroy(dev->data_requests);
 }
-
-/* Reset all pci context */
-static void udc_pci_remove(struct pci_dev *pdev)
-{
-       struct udc              *dev;
-
-       dev = pci_get_drvdata(pdev);
-
-       usb_del_gadget_udc(&udc->gadget);
-       /* gadget driver must not be registered */
-       if (WARN_ON(dev->driver))
-               return;
-
-       /* dma pool cleanup */
-       free_dma_pools(dev);
-
-       /* reset controller */
-       writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
-       free_irq(pdev->irq, dev);
-       iounmap(dev->virt_addr);
-       release_mem_region(pci_resource_start(pdev, 0),
-                          pci_resource_len(pdev, 0));
-       pci_disable_device(pdev);
-
-       udc_remove(dev);
-}
+EXPORT_SYMBOL_GPL(free_dma_pools);
 
 /* create dma pools on init */
-static int init_dma_pools(struct udc *dev)
+int init_dma_pools(struct udc *dev)
 {
        struct udc_stp_dma      *td_stp;
        struct udc_data_dma     *td_data;
@@ -3210,9 +3145,10 @@ err_create_dma_pool:
        dev->data_requests = NULL;
        return retval;
 }
+EXPORT_SYMBOL_GPL(init_dma_pools);
 
 /* general probe */
-static int udc_probe(struct udc *dev)
+int udc_probe(struct udc *dev)
 {
        char            tmp[128];
        u32             reg;
@@ -3276,137 +3212,7 @@ static int udc_probe(struct udc *dev)
 finished:
        return retval;
 }
-
-/* Called by pci bus driver to init pci context */
-static int udc_pci_probe(
-       struct pci_dev *pdev,
-       const struct pci_device_id *id
-)
-{
-       struct udc              *dev;
-       unsigned long           resource;
-       unsigned long           len;
-       int                     retval = 0;
-
-       /* one udc only */
-       if (udc) {
-               dev_dbg(&pdev->dev, "already probed\n");
-               return -EBUSY;
-       }
-
-       /* init */
-       dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       /* pci setup */
-       if (pci_enable_device(pdev) < 0) {
-               retval = -ENODEV;
-               goto err_pcidev;
-       }
-
-       /* PCI resource allocation */
-       resource = pci_resource_start(pdev, 0);
-       len = pci_resource_len(pdev, 0);
-
-       if (!request_mem_region(resource, len, name)) {
-               dev_dbg(&pdev->dev, "pci device used already\n");
-               retval = -EBUSY;
-               goto err_memreg;
-       }
-
-       dev->virt_addr = ioremap_nocache(resource, len);
-       if (!dev->virt_addr) {
-               dev_dbg(&pdev->dev, "start address cannot be mapped\n");
-               retval = -EFAULT;
-               goto err_ioremap;
-       }
-
-       if (!pdev->irq) {
-               dev_err(&pdev->dev, "irq not set\n");
-               retval = -ENODEV;
-               goto err_irq;
-       }
-
-       spin_lock_init(&dev->lock);
-       /* udc csr registers base */
-       dev->csr = dev->virt_addr + UDC_CSR_ADDR;
-       /* dev registers base */
-       dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
-       /* ep registers base */
-       dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
-       /* fifo's base */
-       dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
-       dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
-
-       if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
-               dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
-               retval = -EBUSY;
-               goto err_irq;
-       }
-
-       pci_set_drvdata(pdev, dev);
-
-       /* chip revision for Hs AMD5536 */
-       dev->chiprev = pdev->revision;
-
-       pci_set_master(pdev);
-       pci_try_set_mwi(pdev);
-
-       /* init dma pools */
-       if (use_dma) {
-               retval = init_dma_pools(dev);
-               if (retval != 0)
-                       goto err_dma;
-       }
-
-       dev->phys_addr = resource;
-       dev->irq = pdev->irq;
-       dev->pdev = pdev;
-
-       /* general probing */
-       if (udc_probe(dev)) {
-               retval = -ENODEV;
-               goto err_probe;
-       }
-       return 0;
-
-err_probe:
-       if (use_dma)
-               free_dma_pools(dev);
-err_dma:
-       free_irq(pdev->irq, dev);
-err_irq:
-       iounmap(dev->virt_addr);
-err_ioremap:
-       release_mem_region(resource, len);
-err_memreg:
-       pci_disable_device(pdev);
-err_pcidev:
-       kfree(dev);
-       return retval;
-}
-
-/* PCI device parameters */
-static const struct pci_device_id pci_id[] = {
-       {
-               PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
-               .class =        PCI_CLASS_SERIAL_USB_DEVICE,
-               .class_mask =   0xffffffff,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(pci, pci_id);
-
-/* PCI functions */
-static struct pci_driver udc_pci_driver = {
-       .name =         (char *) name,
-       .id_table =     pci_id,
-       .probe =        udc_pci_probe,
-       .remove =       udc_pci_remove,
-};
-
-module_pci_driver(udc_pci_driver);
+EXPORT_SYMBOL_GPL(udc_probe);
 
 MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
 MODULE_AUTHOR("Thomas Dahlmann");
index 85d5aa5bae7b273abcf06479f1e9aeb817bf58d9..fae49bf3833e603a8bb7e0a305d0655bea97a73e 100644 (file)
 #ifndef AMD5536UDC_H
 #define AMD5536UDC_H
 
+/* debug control */
+/* #define UDC_VERBOSE */
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
 /* various constants */
 #define UDC_RDE_TIMER_SECONDS          1
 #define UDC_RDE_TIMER_DIV              10
@@ -567,6 +573,36 @@ union udc_setup_data {
        struct usb_ctrlrequest  request;
 };
 
+/* Function declarations */
+int udc_enable_dev_setup_interrupts(struct udc *dev);
+int udc_mask_unused_interrupts(struct udc *dev);
+irqreturn_t udc_irq(int irq, void *pdev);
+void gadget_release(struct device *pdev);
+void udc_basic_init(struct udc *dev);
+void free_dma_pools(struct udc *dev);
+int init_dma_pools(struct udc *dev);
+void udc_remove(struct udc *dev);
+int udc_probe(struct udc *dev);
+
+/* DMA usage flag */
+static bool use_dma = 1;
+/* packet per buffer dma */
+static bool use_dma_ppb = 1;
+/* with per descr. update */
+static bool use_dma_ppb_du;
+/* full speed only mode */
+static bool use_fullspeed;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+       "true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
 /*
  *---------------------------------------------------------------------------
  * SET and GET bitfields in u32 values
diff --git a/drivers/usb/gadget/udc/amd5536udc_pci.c b/drivers/usb/gadget/udc/amd5536udc_pci.c
new file mode 100644 (file)
index 0000000..2a2d0a9
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * amd5536udc_pci.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ *
+ * This file does pci device registration, and the core driver implementation
+ * is done in amd5536udc.c
+ *
+ * The driver is split so as to use the core UDC driver which is based on
+ * Synopsys device controller IP (different than HS OTG IP) in UDCs
+ * integrated to SoC platforms.
+ *
+ */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION            "AMD 5536 UDC - USB Device Controller"
+
+/* system */
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/prefetch.h>
+#include <linux/pci.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc-pci";
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+       struct udc              *dev;
+
+       dev = pci_get_drvdata(pdev);
+
+       usb_del_gadget_udc(&udc->gadget);
+       /* gadget driver must not be registered */
+       if (WARN_ON(dev->driver))
+               return;
+
+       /* dma pool cleanup */
+       free_dma_pools(dev);
+
+       /* reset controller */
+       writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+       free_irq(pdev->irq, dev);
+       iounmap(dev->virt_addr);
+       release_mem_region(pci_resource_start(pdev, 0),
+                          pci_resource_len(pdev, 0));
+       pci_disable_device(pdev);
+
+       udc_remove(dev);
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+       struct pci_dev *pdev,
+       const struct pci_device_id *id
+)
+{
+       struct udc              *dev;
+       unsigned long           resource;
+       unsigned long           len;
+       int                     retval = 0;
+
+       /* one udc only */
+       if (udc) {
+               dev_dbg(&pdev->dev, "already probed\n");
+               return -EBUSY;
+       }
+
+       /* init */
+       dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       /* pci setup */
+       if (pci_enable_device(pdev) < 0) {
+               retval = -ENODEV;
+               goto err_pcidev;
+       }
+
+       /* PCI resource allocation */
+       resource = pci_resource_start(pdev, 0);
+       len = pci_resource_len(pdev, 0);
+
+       if (!request_mem_region(resource, len, name)) {
+               dev_dbg(&pdev->dev, "pci device used already\n");
+               retval = -EBUSY;
+               goto err_memreg;
+       }
+
+       dev->virt_addr = ioremap_nocache(resource, len);
+       if (!dev->virt_addr) {
+               dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+               retval = -EFAULT;
+               goto err_ioremap;
+       }
+
+       if (!pdev->irq) {
+               dev_err(&pdev->dev, "irq not set\n");
+               retval = -ENODEV;
+               goto err_irq;
+       }
+
+       spin_lock_init(&dev->lock);
+       /* udc csr registers base */
+       dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+       /* dev registers base */
+       dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+       /* ep registers base */
+       dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+       /* fifo's base */
+       dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+       dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+       if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+               dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+               retval = -EBUSY;
+               goto err_irq;
+       }
+
+       pci_set_drvdata(pdev, dev);
+
+       /* chip revision for Hs AMD5536 */
+       dev->chiprev = pdev->revision;
+
+       pci_set_master(pdev);
+       pci_try_set_mwi(pdev);
+
+       /* init dma pools */
+       if (use_dma) {
+               retval = init_dma_pools(dev);
+               if (retval != 0)
+                       goto err_dma;
+       }
+
+       dev->phys_addr = resource;
+       dev->irq = pdev->irq;
+       dev->pdev = pdev;
+
+       /* general probing */
+       if (udc_probe(dev)) {
+               retval = -ENODEV;
+               goto err_probe;
+       }
+       return 0;
+
+err_probe:
+       if (use_dma)
+               free_dma_pools(dev);
+err_dma:
+       free_irq(pdev->irq, dev);
+err_irq:
+       iounmap(dev->virt_addr);
+err_ioremap:
+       release_mem_region(resource, len);
+err_memreg:
+       pci_disable_device(pdev);
+err_pcidev:
+       kfree(dev);
+       return retval;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+               .class =        PCI_CLASS_SERIAL_USB_DEVICE,
+               .class_mask =   0xffffffff,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+       .name =         (char *) name,
+       .id_table =     pci_id,
+       .probe =        udc_pci_probe,
+       .remove =       udc_pci_remove,
+};
+module_pci_driver(udc_pci_driver);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
index 2035906b8ced173c2e869a3272334d4265acf79c..3ccc34176a5aabb43cc4ee0bba90efa6fb32f551 100644 (file)
@@ -321,7 +321,6 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
 
 static ushort fifo_mode;
 
-/* "modprobe ... fifo_mode=1" etc */
 module_param(fifo_mode, ushort, 0x0);
 MODULE_PARM_DESC(fifo_mode, "Endpoint configuration mode");
 
@@ -371,7 +370,7 @@ static struct usba_fifo_cfg mode_4_cfg[] = {
 };
 /* Add additional configurations here */
 
-int usba_config_fifo_table(struct usba_udc *udc)
+static int usba_config_fifo_table(struct usba_udc *udc)
 {
        int n;
 
@@ -1076,11 +1075,9 @@ static int atmel_usba_start(struct usb_gadget *gadget,
                struct usb_gadget_driver *driver);
 static int atmel_usba_stop(struct usb_gadget *gadget);
 
-static struct usb_ep *atmel_usba_match_ep(
-               struct usb_gadget               *gadget,
-               struct usb_endpoint_descriptor  *desc,
-               struct usb_ss_ep_comp_descriptor *ep_comp
-)
+static struct usb_ep *atmel_usba_match_ep(struct usb_gadget *gadget,
+                               struct usb_endpoint_descriptor  *desc,
+                               struct usb_ss_ep_comp_descriptor *ep_comp)
 {
        struct usb_ep   *_ep;
        struct usba_ep *ep;
@@ -1100,7 +1097,6 @@ found_ep:
                ep = to_usba_ep(_ep);
 
                switch (usb_endpoint_type(desc)) {
-
                case USB_ENDPOINT_XFER_CONTROL:
                        break;
 
@@ -1141,7 +1137,7 @@ found_ep:
                ep->udc->configured_ep++;
        }
 
-return _ep;
+       return _ep;
 }
 
 static const struct usb_gadget_ops usba_udc_ops = {
@@ -1855,8 +1851,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
                 * but it's clearly harmless...
                 */
                if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
-                       dev_dbg(&udc->pdev->dev,
-                                "ODD: EP0 configuration is invalid!\n");
+                       dev_err(&udc->pdev->dev,
+                               "ODD: EP0 configuration is invalid!\n");
 
                /* Preallocate other endpoints */
                n = fifo_mode ? udc->num_ep : udc->configured_ep;
@@ -1864,8 +1860,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
                        ep = &udc->usba_ep[i];
                        usba_ep_writel(ep, CFG, ep->ept_cfg);
                        if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED))
-                               dev_dbg(&udc->pdev->dev,
-                                "ODD: EP%d configuration is invalid!\n", i);
+                               dev_err(&udc->pdev->dev,
+                                       "ODD: EP%d configuration is invalid!\n", i);
                }
        }
 
@@ -2089,8 +2085,9 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
                while ((pp = of_get_next_child(np, pp)))
                        udc->num_ep++;
                udc->configured_ep = 1;
-       } else
+       } else {
                udc->num_ep = usba_config_fifo_table(udc);
+       }
 
        eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep,
                           GFP_KERNEL);
@@ -2118,14 +2115,34 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
                        dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret);
                        goto err;
                }
-               ep->fifo_size = fifo_mode ? udc->fifo_cfg[i].fifo_size : val;
+               if (fifo_mode) {
+                       if (val < udc->fifo_cfg[i].fifo_size) {
+                               dev_warn(&pdev->dev,
+                                        "Using max fifo-size value from DT\n");
+                               ep->fifo_size = val;
+                       } else {
+                               ep->fifo_size = udc->fifo_cfg[i].fifo_size;
+                       }
+               } else {
+                       ep->fifo_size = val;
+               }
 
                ret = of_property_read_u32(pp, "atmel,nb-banks", &val);
                if (ret) {
                        dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret);
                        goto err;
                }
-               ep->nr_banks = fifo_mode ? udc->fifo_cfg[i].nr_banks : val;
+               if (fifo_mode) {
+                       if (val < udc->fifo_cfg[i].nr_banks) {
+                               dev_warn(&pdev->dev,
+                                        "Using max nb-banks value from DT\n");
+                               ep->nr_banks = val;
+                       } else {
+                               ep->nr_banks = udc->fifo_cfg[i].nr_banks;
+                       }
+               } else {
+                       ep->nr_banks = val;
+               }
 
                ep->can_dma = of_property_read_bool(pp, "atmel,can-dma");
                ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc");
index d685d82dcf487c9f53bb3cd821424159d2e445d1..efce68e9a8e038557bdc36c8263bad03cef7e108 100644 (file)
@@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
        flush_work(&gadget->work);
        device_unregister(&udc->dev);
        device_unregister(&gadget->dev);
+       memset(&gadget->dev, 0x00, sizeof(gadget->dev));
 }
 EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
index 8cabc5944d5f1d834db7dd2186777cd79536016b..c79081952ea068c770887298ed1c5483f0e61dac 100644 (file)
@@ -2062,16 +2062,13 @@ static int dummy_hub_control(
                        }
                        break;
                case USB_PORT_FEAT_POWER:
-                       if (hcd->speed == HCD_USB3) {
-                               if (dum_hcd->port_status & USB_PORT_STAT_POWER)
-                                       dev_dbg(dummy_dev(dum_hcd),
-                                               "power-off\n");
-                       } else
-                               if (dum_hcd->port_status &
-                                                       USB_SS_PORT_STAT_POWER)
-                                       dev_dbg(dummy_dev(dum_hcd),
-                                               "power-off\n");
-                       /* FALLS THROUGH */
+                       dev_dbg(dummy_dev(dum_hcd), "power-off\n");
+                       if (hcd->speed == HCD_USB3)
+                               dum_hcd->port_status &= ~USB_SS_PORT_STAT_POWER;
+                       else
+                               dum_hcd->port_status &= ~USB_PORT_STAT_POWER;
+                       set_link_state(dum_hcd);
+                       break;
                default:
                        dum_hcd->port_status &= ~(1 << wValue);
                        set_link_state(dum_hcd);
@@ -2242,14 +2239,13 @@ static int dummy_hub_control(
                                if ((dum_hcd->port_status &
                                     USB_SS_PORT_STAT_POWER) != 0) {
                                        dum_hcd->port_status |= (1 << wValue);
-                                       set_link_state(dum_hcd);
                                }
                        } else
                                if ((dum_hcd->port_status &
                                     USB_PORT_STAT_POWER) != 0) {
                                        dum_hcd->port_status |= (1 << wValue);
-                                       set_link_state(dum_hcd);
                                }
+                       set_link_state(dum_hcd);
                }
                break;
        case GetPortErrorCount:
index b76fcdb763a0d27c5606e97807b18bf14e05ba9f..6f2f71c054be27f66cf56d56012aaf7332d2dad4 100644 (file)
@@ -2675,6 +2675,8 @@ static const struct platform_device_id fsl_udc_devtype[] = {
                .name = "imx-udc-mx27",
        }, {
                .name = "imx-udc-mx51",
+       }, {
+               .name = "fsl-usb2-udc",
        }, {
                /* sentinel */
        }
index d365449a295a8ab823f9358146a0a910bcabba2d..772049afe1666404dcdf0ee1310feb344d574f33 100644 (file)
@@ -1835,13 +1835,18 @@ static int mv_u3d_probe(struct platform_device *dev)
        }
 
        /* we will access controller register, so enable the u3d controller */
-       clk_enable(u3d->clk);
+       retval = clk_enable(u3d->clk);
+       if (retval) {
+               dev_err(&dev->dev, "clk_enable error %d\n", retval);
+               goto err_u3d_enable;
+       }
 
        if (pdata->phy_init) {
                retval = pdata->phy_init(u3d->phy_regs);
                if (retval) {
                        dev_err(&dev->dev, "init phy error %d\n", retval);
-                       goto err_u3d_enable;
+                       clk_disable(u3d->clk);
+                       goto err_phy_init;
                }
        }
 
@@ -1974,15 +1979,13 @@ err_alloc_trb_pool:
        dma_free_coherent(&dev->dev, u3d->ep_context_size,
                u3d->ep_context, u3d->ep_context_dma);
 err_alloc_ep_context:
-       if (pdata->phy_deinit)
-               pdata->phy_deinit(u3d->phy_regs);
-       clk_disable(u3d->clk);
+err_phy_init:
 err_u3d_enable:
        iounmap(u3d->cap_regs);
 err_map_cap_regs:
 err_get_cap_regs:
-err_get_clk:
        clk_put(u3d->clk);
+err_get_clk:
        kfree(u3d);
 err_alloc_private:
 err_pdata:
index 27ebb0d5449d0dda58863ffb28bcbd8f3514f93f..76f56c5762f9659e27aeb1304a4ff145986685ab 100644 (file)
@@ -445,7 +445,8 @@ static int mv_ep_enable(struct usb_ep *_ep,
        struct mv_dqh *dqh;
        u16 max = 0;
        u32 bit_pos, epctrlx, direction;
-       unsigned char zlt = 0, ios = 0, mult = 0;
+       const unsigned char zlt = 1;
+       unsigned char ios, mult;
        unsigned long flags;
 
        ep = container_of(_ep, struct mv_ep, ep);
@@ -465,8 +466,6 @@ static int mv_ep_enable(struct usb_ep *_ep,
         * disable HW zero length termination select
         * driver handles zero length packet through req->req.zero
         */
-       zlt = 1;
-
        bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
 
        /* Check if the Endpoint is Primed */
@@ -481,16 +480,16 @@ static int mv_ep_enable(struct usb_ep *_ep,
                        (unsigned)bit_pos);
                goto en_done;
        }
+
        /* Set the max packet length, interrupt on Setup and Mult fields */
+       ios = 0;
+       mult = 0;
        switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
        case USB_ENDPOINT_XFER_BULK:
-               zlt = 1;
-               mult = 0;
+       case USB_ENDPOINT_XFER_INT:
                break;
        case USB_ENDPOINT_XFER_CONTROL:
                ios = 1;
-       case USB_ENDPOINT_XFER_INT:
-               mult = 0;
                break;
        case USB_ENDPOINT_XFER_ISOC:
                /* Calculate transactions needed for high bandwidth iso */
index 832c4fdbe98512a2b70b6b9e9424acc21a09b83b..d48e239660c31170696042313ebd1a66e79621db 100644 (file)
@@ -1608,9 +1608,6 @@ static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active)
        return 0;
 }
 
-static void udc_enable(struct pxa_udc *udc);
-static void udc_disable(struct pxa_udc *udc);
-
 /**
  * pxa_udc_vbus_session - Called by external transceiver to enable/disable udc
  * @_gadget: usb gadget
index 2218f91e92a61cd8078afe857ba347463aa8ff63..5a2d845fb1a68708a3ea27b3822ae8de7afb85df 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/extcon.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -37,6 +38,9 @@
 #define USB3_USB_INT_ENA_2     0x22c
 #define USB3_STUP_DAT_0                0x230
 #define USB3_STUP_DAT_1                0x234
+#define USB3_USB_OTG_STA       0x268
+#define USB3_USB_OTG_INT_STA   0x26c
+#define USB3_USB_OTG_INT_ENA   0x270
 #define USB3_P0_MOD            0x280
 #define USB3_P0_CON            0x288
 #define USB3_P0_STA            0x28c
 /* USB_INT_ENA_2 and USB_INT_STA_2 */
 #define USB_INT_2_PIPE(n)      BIT(n)
 
+/* USB_OTG_STA, USB_OTG_INT_STA and USB_OTG_INT_ENA */
+#define USB_OTG_IDMON          BIT(4)
+
 /* P0_MOD */
 #define P0_MOD_DIR             BIT(6)
 
@@ -257,6 +264,8 @@ struct renesas_usb3 {
 
        struct usb_gadget gadget;
        struct usb_gadget_driver *driver;
+       struct extcon_dev *extcon;
+       struct work_struct extcon_work;
 
        struct renesas_usb3_ep *usb3_ep;
        int num_usb3_eps;
@@ -269,6 +278,8 @@ struct renesas_usb3 {
        u8 ep0_buf[USB3_EP0_BUF_SIZE];
        bool softconnect;
        bool workaround_for_vbus;
+       bool extcon_host;               /* check id and set EXTCON_USB_HOST */
+       bool extcon_usb;                /* check vbus and set EXTCON_USB */
 };
 
 #define gadget_to_renesas_usb3(_gadget)        \
@@ -332,6 +343,15 @@ static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask,
        return -EBUSY;
 }
 
+static void renesas_usb3_extcon_work(struct work_struct *work)
+{
+       struct renesas_usb3 *usb3 = container_of(work, struct renesas_usb3,
+                                                extcon_work);
+
+       extcon_set_state_sync(usb3->extcon, EXTCON_USB_HOST, usb3->extcon_host);
+       extcon_set_state_sync(usb3->extcon, EXTCON_USB, usb3->extcon_usb);
+}
+
 static void usb3_enable_irq_1(struct renesas_usb3 *usb3, u32 bits)
 {
        usb3_set_bit(usb3, bits, USB3_USB_INT_ENA_1);
@@ -352,6 +372,11 @@ static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num)
        usb3_clear_bit(usb3, USB_INT_2_PIPE(num), USB3_USB_INT_ENA_2);
 }
 
+static bool usb3_is_host(struct renesas_usb3 *usb3)
+{
+       return !(usb3_read(usb3, USB3_DRD_CON) & DRD_CON_PERI_CON);
+}
+
 static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
 {
        /* Set AXI_INT */
@@ -362,10 +387,6 @@ static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
 
 static void usb3_init_epc_registers(struct renesas_usb3 *usb3)
 {
-       /* FIXME: How to change host / peripheral mode as well? */
-       usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
-       usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
-
        usb3_write(usb3, ~0, USB3_USB_INT_STA_1);
        usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG);
 }
@@ -531,18 +552,70 @@ static void usb3_check_vbus(struct renesas_usb3 *usb3)
        if (usb3->workaround_for_vbus) {
                usb3_connect(usb3);
        } else {
-               if (usb3_read(usb3, USB3_USB_STA) & USB_STA_VBUS_STA)
+               usb3->extcon_usb = !!(usb3_read(usb3, USB3_USB_STA) &
+                                                       USB_STA_VBUS_STA);
+               if (usb3->extcon_usb)
                        usb3_connect(usb3);
                else
                        usb3_disconnect(usb3);
+
+               schedule_work(&usb3->extcon_work);
        }
 }
 
+static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
+{
+       if (host)
+               usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+       else
+               usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+}
+
+static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
+{
+       if (enable)
+               usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
+       else
+               usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
+}
+
+static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&usb3->lock, flags);
+       usb3_set_mode(usb3, host);
+       usb3_vbus_out(usb3, a_dev);
+       if (!host && a_dev)             /* for A-Peripheral */
+               usb3_connect(usb3);
+       spin_unlock_irqrestore(&usb3->lock, flags);
+}
+
+static bool usb3_is_a_device(struct renesas_usb3 *usb3)
+{
+       return !(usb3_read(usb3, USB3_USB_OTG_STA) & USB_OTG_IDMON);
+}
+
+static void usb3_check_id(struct renesas_usb3 *usb3)
+{
+       usb3->extcon_host = usb3_is_a_device(usb3);
+
+       if (usb3->extcon_host)
+               usb3_mode_config(usb3, true, true);
+       else
+               usb3_mode_config(usb3, false, false);
+
+       schedule_work(&usb3->extcon_work);
+}
+
 static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
 {
        usb3_init_axi_bridge(usb3);
        usb3_init_epc_registers(usb3);
+       usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_STA);
+       usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_ENA);
 
+       usb3_check_id(usb3);
        usb3_check_vbus(usb3);
 }
 
@@ -551,6 +624,7 @@ static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3)
        usb3_disconnect(usb3);
        usb3_write(usb3, 0, USB3_P0_INT_ENA);
        usb3_write(usb3, 0, USB3_PN_INT_ENA);
+       usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA);
        usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
        usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
        usb3_write(usb3, 0, USB3_AXI_INT_ENA);
@@ -1474,10 +1548,22 @@ static void usb3_irq_epc_int_2(struct renesas_usb3 *usb3, u32 int_sta_2)
        }
 }
 
+static void usb3_irq_idmon_change(struct renesas_usb3 *usb3)
+{
+       usb3_check_id(usb3);
+}
+
+static void usb3_irq_otg_int(struct renesas_usb3 *usb3, u32 otg_int_sta)
+{
+       if (otg_int_sta & USB_OTG_IDMON)
+               usb3_irq_idmon_change(usb3);
+}
+
 static void usb3_irq_epc(struct renesas_usb3 *usb3)
 {
        u32 int_sta_1 = usb3_read(usb3, USB3_USB_INT_STA_1);
        u32 int_sta_2 = usb3_read(usb3, USB3_USB_INT_STA_2);
+       u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA);
 
        int_sta_1 &= usb3_read(usb3, USB3_USB_INT_ENA_1);
        if (int_sta_1) {
@@ -1488,6 +1574,12 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3)
        int_sta_2 &= usb3_read(usb3, USB3_USB_INT_ENA_2);
        if (int_sta_2)
                usb3_irq_epc_int_2(usb3, int_sta_2);
+
+       otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA);
+       if (otg_int_sta) {
+               usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA);
+               usb3_irq_otg_int(usb3, otg_int_sta);
+       }
 }
 
 static irqreturn_t renesas_usb3_irq(int irq, void *_usb3)
@@ -1756,11 +1848,49 @@ static const struct usb_gadget_ops renesas_usb3_gadget_ops = {
        .set_selfpowered        = renesas_usb3_set_selfpowered,
 };
 
+static ssize_t role_store(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+       bool new_mode_is_host;
+
+       if (!usb3->driver)
+               return -ENODEV;
+
+       if (!strncmp(buf, "host", strlen("host")))
+               new_mode_is_host = true;
+       else if (!strncmp(buf, "peripheral", strlen("peripheral")))
+               new_mode_is_host = false;
+       else
+               return -EINVAL;
+
+       if (new_mode_is_host == usb3_is_host(usb3))
+               return -EINVAL;
+
+       usb3_mode_config(usb3, new_mode_is_host, usb3_is_a_device(usb3));
+
+       return count;
+}
+
+static ssize_t role_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+
+       if (!usb3->driver)
+               return -ENODEV;
+
+       return sprintf(buf, "%s\n", usb3_is_host(usb3) ? "host" : "peripheral");
+}
+static DEVICE_ATTR_RW(role);
+
 /*------- platform_driver ------------------------------------------------*/
 static int renesas_usb3_remove(struct platform_device *pdev)
 {
        struct renesas_usb3 *usb3 = platform_get_drvdata(pdev);
 
+       device_remove_file(&pdev->dev, &dev_attr_role);
+
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
@@ -1894,6 +2024,12 @@ static const struct of_device_id usb3_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, usb3_of_match);
 
+static const unsigned int renesas_usb3_cable[] = {
+       EXTCON_USB,
+       EXTCON_USB_HOST,
+       EXTCON_NONE,
+};
+
 static int renesas_usb3_probe(struct platform_device *pdev)
 {
        struct renesas_usb3 *usb3;
@@ -1937,6 +2073,17 @@ static int renesas_usb3_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
+       INIT_WORK(&usb3->extcon_work, renesas_usb3_extcon_work);
+       usb3->extcon = devm_extcon_dev_allocate(&pdev->dev, renesas_usb3_cable);
+       if (IS_ERR(usb3->extcon))
+               return PTR_ERR(usb3->extcon);
+
+       ret = devm_extcon_dev_register(&pdev->dev, usb3->extcon);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register extcon\n");
+               return ret;
+       }
+
        /* for ep0 handling */
        usb3->ep0_req = __renesas_usb3_ep_alloc_request(GFP_KERNEL);
        if (!usb3->ep0_req)
@@ -1946,6 +2093,10 @@ static int renesas_usb3_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_add_udc;
 
+       ret = device_create_file(&pdev->dev, &dev_attr_role);
+       if (ret < 0)
+               goto err_dev_create;
+
        usb3->workaround_for_vbus = priv->workaround_for_vbus;
 
        pm_runtime_enable(&pdev->dev);
@@ -1955,6 +2106,9 @@ static int renesas_usb3_probe(struct platform_device *pdev)
 
        return 0;
 
+err_dev_create:
+       usb_del_gadget_udc(&usb3->gadget);
+
 err_add_udc:
        __renesas_usb3_ep_free_request(usb3->ep0_req);
 
index 1a8987e7c5b0648c031fb5aece274a4939fc2ead..11a0d3b84c5eaef31217fd0645edf197ed2f29da 100644 (file)
@@ -223,25 +223,25 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
                return 0;
 
        otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
-       ret = extcon_register_notifier(edev, EXTCON_USB,
+       ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB,
                                        &otg_sx->vbus_nb);
        if (ret < 0)
                dev_err(ssusb->dev, "failed to register notifier for USB\n");
 
        otg_sx->id_nb.notifier_call = ssusb_id_notifier;
-       ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
+       ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST,
                                        &otg_sx->id_nb);
        if (ret < 0)
                dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n");
 
        dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
-               extcon_get_cable_state_(edev, EXTCON_USB),
-               extcon_get_cable_state_(edev, EXTCON_USB_HOST));
+               extcon_get_state(edev, EXTCON_USB),
+               extcon_get_state(edev, EXTCON_USB_HOST));
 
        /* default as host, switch to device mode if needed */
-       if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == false)
+       if (extcon_get_state(edev, EXTCON_USB_HOST) == false)
                ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
-       if (extcon_get_cable_state_(edev, EXTCON_USB) == true)
+       if (extcon_get_state(edev, EXTCON_USB) == true)
                ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
 
        return 0;
@@ -367,13 +367,6 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
 
        cancel_delayed_work(&otg_sx->extcon_reg_dwork);
 
-       if (otg_sx->edev) {
-               extcon_unregister_notifier(otg_sx->edev,
-                       EXTCON_USB, &otg_sx->vbus_nb);
-               extcon_unregister_notifier(otg_sx->edev,
-                       EXTCON_USB_HOST, &otg_sx->id_nb);
-       }
-
        if (otg_sx->manual_drd_enabled)
                ssusb_debugfs_exit(ssusb);
 }
index 392ab422163c236084f73252fe8577f386c1d7c1..cf8f40ae6e017943c9ae97e50fca17d50304d51e 100644 (file)
 
 #include "phy-fsl-usb.h"
 
+#ifdef VERBOSE
+#define VDBG(fmt, args...) pr_debug("[%s]  " fmt, \
+                                __func__, ## args)
+#else
+#define VDBG(stuff...) do {} while (0)
+#endif
+
 #define DRIVER_VERSION "Rev. 1.55"
 #define DRIVER_AUTHOR "Jerry Huang/Li Yang"
 #define DRIVER_DESC "Freescale USB OTG Transceiver Driver"
index 7a0350535cb10146ffd4e1936da7dced6bc477ca..a0a8f878503c959442608d09e1f0495a6319e03a 100644 (file)
 #include <linux/mutex.h>
 #include <linux/errno.h>
 
-#undef VERBOSE
-
-#ifdef VERBOSE
-#define VDBG(fmt, args...) pr_debug("[%s]  " fmt , \
-                                __func__, ## args)
-#else
-#define VDBG(stuff...) do {} while (0)
-#endif
-
-#ifdef VERBOSE
-#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__)
-#else
-#define MPC_LOC do {} while (0)
-#endif
-
 #define PROTO_UNDEF    (0)
 #define PROTO_HOST     (1)
 #define PROTO_GADGET   (2)
index b2a31a55a61237e65e4939a9d2722e136cc73ca0..062606f02309f814ffd7c9a4e5ef5a0f4f31abe5 100644 (file)
@@ -158,7 +158,7 @@ struct usb_ext_prop_desc {
  * |-----+-----------------------+------+-------------------------------------|
  * |   0 | bFirstInterfaceNumber | U8   | index of the interface or of the 1st|
  * |     |                       |      | interface in an IAD group           |
- * |   1 | Reserved              | U8   | 0                                   |
+ * |   1 | Reserved              | U8   | 1                                   |
  * |   2 | CompatibleID          | U8[8]| compatible ID string                |
  * |  10 | SubCompatibleID       | U8[8]| subcompatible ID string             |
  * |  18 | Reserved              | U8[6]| 0                                   |