Merge tag 'usb-v4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 1 Jul 2016 15:59:01 +0000 (08:59 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 1 Jul 2016 15:59:01 +0000 (08:59 -0700)
Peter writes:

Hi Greg,

Below are changes for v4.8-rc1, none is important, only the documentation
update for chipidea.

67 files changed:
drivers/phy/Kconfig
drivers/power/Kconfig
drivers/usb/common/common.c
drivers/usb/dwc2/Kconfig
drivers/usb/dwc2/core.h
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/hcd_queue.c
drivers/usb/dwc2/hw.h
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/debug.h
drivers/usb/dwc3/debugfs.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/dwc3/host.c
drivers/usb/dwc3/io.h
drivers/usb/dwc3/platform_data.h [deleted file]
drivers/usb/dwc3/trace.h
drivers/usb/early/ehci-dbgp.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/config.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/u_serial.c
drivers/usb/gadget/legacy/g_ffs.c
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/Makefile
drivers/usb/gadget/udc/amd5536udc.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/bdc/bdc_cmd.c
drivers/usb/gadget/udc/bdc/bdc_ep.c
drivers/usb/gadget/udc/core.c [new file with mode: 0644]
drivers/usb/gadget/udc/dummy_hcd.c
drivers/usb/gadget/udc/m66592-udc.c
drivers/usb/gadget/udc/mv_u3d_core.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/gadget/udc/net2272.c
drivers/usb/gadget/udc/net2280.c
drivers/usb/gadget/udc/net2280.h
drivers/usb/gadget/udc/pch_udc.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/gadget/udc/r8a66597-udc.c
drivers/usb/gadget/udc/trace.c [new file with mode: 0644]
drivers/usb/gadget/udc/trace.h [new file with mode: 0644]
drivers/usb/gadget/udc/udc-core.c [deleted file]
drivers/usb/gadget/udc/udc-xilinx.c
drivers/usb/host/Kconfig
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/phy/Kconfig
drivers/usb/phy/phy-am335x.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-omap-otg.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/renesas_usbhs/rcar3.c
include/linux/usb/gadget.h
include/linux/usb/msm_hsusb.h [deleted file]
include/linux/usb/of.h
include/linux/usb/xhci_pdriver.h [deleted file]

index b869b98..8d1cfb7 100644 (file)
@@ -176,6 +176,7 @@ config TWL4030_USB
        tristate "TWL4030 USB Transceiver Driver"
        depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
        depends on USB_SUPPORT
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't 'y'
        select GENERIC_PHY
        select USB_PHY
        help
index 421770d..0f11a0f 100644 (file)
@@ -309,6 +309,7 @@ config BATTERY_RX51
 config CHARGER_ISP1704
        tristate "ISP1704 USB Charger Detection"
        depends on USB_PHY
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        help
          Say Y to enable support for USB Charger Detection with
          ISP1707/ISP1704 USB transceivers.
index e3d0161..5ef8da6 100644 (file)
@@ -131,15 +131,17 @@ EXPORT_SYMBOL_GPL(usb_get_dr_mode);
  * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device
  * which is associated with the given phy device_node
  * @np:        Pointer to the given phy device_node
+ * @arg0: phandle args[0] for phy's with #phy-cells >= 1, or -1 for
+ *        phys which do not have phy-cells
  *
  * In dts a usb controller associates with phy devices.  The function gets
  * the string from property 'dr_mode' of the controller associated with the
  * given phy device node, and returns the correspondig enum usb_dr_mode.
  */
-enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
+enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0)
 {
        struct device_node *controller = NULL;
-       struct device_node *phy;
+       struct of_phandle_args args;
        const char *dr_mode;
        int index;
        int err;
@@ -148,12 +150,24 @@ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
                controller = of_find_node_with_property(controller, "phys");
                index = 0;
                do {
-                       phy = of_parse_phandle(controller, "phys", index);
-                       of_node_put(phy);
-                       if (phy == phy_np)
+                       if (arg0 == -1) {
+                               args.np = of_parse_phandle(controller, "phys",
+                                                       index);
+                               args.args_count = 0;
+                       } else {
+                               err = of_parse_phandle_with_args(controller,
+                                                       "phys", "#phy-cells",
+                                                       index, &args);
+                               if (err)
+                                       break;
+                       }
+
+                       of_node_put(args.np);
+                       if (args.np == np && (args.args_count == 0 ||
+                                             args.args[0] == arg0))
                                goto finish;
                        index++;
-               } while (phy);
+               } while (args.np);
        } while (controller);
 
 finish:
index c1f29ca..e838701 100644 (file)
@@ -55,6 +55,7 @@ endchoice
 config USB_DWC2_PCI
        tristate "DWC2 PCI"
        depends on PCI
+       depends on USB_GADGET || !USB_GADGET
        default n
        select NOP_USB_XCEIV
        help
index dec0b21..9fae029 100644 (file)
@@ -166,7 +166,7 @@ struct dwc2_hsotg_req;
  *          means that it is sending data to the Host.
  * @index: The index for the endpoint registers.
  * @mc: Multi Count - number of transactions per microframe
- * @interval - Interval for periodic endpoints
+ * @interval - Interval for periodic endpoints, in frames or microframes.
  * @name: The name array passed to the USB core.
  * @halted: Set if the endpoint has been halted.
  * @periodic: Set if this is a periodic ep, such as Interrupt
@@ -177,6 +177,8 @@ struct dwc2_hsotg_req;
  * @fifo_load: The amount of data loaded into the FIFO (periodic IN)
  * @last_load: The offset of data for the last start of request.
  * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN
+ * @target_frame: Targeted frame num to setup next ISOC transfer
+ * @frame_overrun: Indicates SOF number overrun in DSTS
  *
  * This is the driver's state for each registered enpoint, allowing it
  * to keep track of transactions that need doing. Each endpoint has a
@@ -213,7 +215,9 @@ struct dwc2_hsotg_ep {
        unsigned int            periodic:1;
        unsigned int            isochronous:1;
        unsigned int            send_zlp:1;
-       unsigned int            has_correct_parity:1;
+       unsigned int            target_frame;
+#define TARGET_FRAME_INITIAL   0xFFFFFFFF
+       bool                    frame_overrun;
 
        char                    name[10];
 };
index 26cf09d..af46adf 100644 (file)
@@ -96,6 +96,25 @@ static inline bool using_dma(struct dwc2_hsotg *hsotg)
        return hsotg->g_using_dma;
 }
 
+/**
+ * dwc2_gadget_incr_frame_num - Increments the targeted frame number.
+ * @hs_ep: The endpoint
+ * @increment: The value to increment by
+ *
+ * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT.
+ * If an overrun occurs it will wrap the value and set the frame_overrun flag.
+ */
+static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep)
+{
+       hs_ep->target_frame += hs_ep->interval;
+       if (hs_ep->target_frame > DSTS_SOFFN_LIMIT) {
+               hs_ep->frame_overrun = 1;
+               hs_ep->target_frame &= DSTS_SOFFN_LIMIT;
+       } else {
+               hs_ep->frame_overrun = 0;
+       }
+}
+
 /**
  * dwc2_hsotg_en_gsint - enable one or more of the general interrupt
  * @hsotg: The device state
@@ -503,6 +522,23 @@ static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep)
        return maxsize;
 }
 
+/**
+* dwc2_hsotg_read_frameno - read current frame number
+* @hsotg: The device instance
+*
+* Return the current frame number
+*/
+static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg)
+{
+       u32 dsts;
+
+       dsts = dwc2_readl(hsotg->regs + DSTS);
+       dsts &= DSTS_SOFFN_MASK;
+       dsts >>= DSTS_SOFFN_SHIFT;
+
+       return dsts;
+}
+
 /**
  * dwc2_hsotg_start_req - start a USB request from an endpoint's queue
  * @hsotg: The controller state.
@@ -631,8 +667,17 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
                        __func__, &ureq->dma, dma_reg);
        }
 
+       if (hs_ep->isochronous && hs_ep->interval == 1) {
+               hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
+               dwc2_gadget_incr_frame_num(hs_ep);
+
+               if (hs_ep->target_frame & 0x1)
+                       ctrl |= DXEPCTL_SETODDFR;
+               else
+                       ctrl |= DXEPCTL_SETEVENFR;
+       }
+
        ctrl |= DXEPCTL_EPENA;  /* ensure ep enabled */
-       ctrl |= DXEPCTL_USBACTEP;
 
        dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state);
 
@@ -658,14 +703,6 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
                dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req);
        }
 
-       /*
-        * clear the INTknTXFEmpMsk when we start request, more as a aide
-        * to debugging to see what is going on.
-        */
-       if (dir_in)
-               dwc2_writel(DIEPMSK_INTKNTXFEMPMSK,
-                      hsotg->regs + DIEPINT(index));
-
        /*
         * Note, trying to clear the NAK here causes problems with transmit
         * on the S3C6400 ending up with the TXFIFO becoming full.
@@ -773,6 +810,30 @@ static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg,
        hs_req->saved_req_buf = NULL;
 }
 
+/**
+ * dwc2_gadget_target_frame_elapsed - Checks target frame
+ * @hs_ep: The driver endpoint to check
+ *
+ * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop
+ * corresponding transfer.
+ */
+static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep)
+{
+       struct dwc2_hsotg *hsotg = hs_ep->parent;
+       u32 target_frame = hs_ep->target_frame;
+       u32 current_frame = dwc2_hsotg_read_frameno(hsotg);
+       bool frame_overrun = hs_ep->frame_overrun;
+
+       if (!frame_overrun && current_frame >= target_frame)
+               return true;
+
+       if (frame_overrun && current_frame >= target_frame &&
+           ((current_frame - target_frame) < DSTS_SOFFN_LIMIT / 2))
+               return true;
+
+       return false;
+}
+
 static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
                              gfp_t gfp_flags)
 {
@@ -812,9 +873,18 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
        first = list_empty(&hs_ep->queue);
        list_add_tail(&hs_req->queue, &hs_ep->queue);
 
-       if (first)
-               dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
+       if (first) {
+               if (!hs_ep->isochronous) {
+                       dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
+                       return 0;
+               }
+
+               while (dwc2_gadget_target_frame_elapsed(hs_ep))
+                       dwc2_gadget_incr_frame_num(hs_ep);
 
+               if (hs_ep->target_frame != TARGET_FRAME_INITIAL)
+                       dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
+       }
        return 0;
 }
 
@@ -1034,6 +1104,42 @@ static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep)
        return list_first_entry(&hs_ep->queue, struct dwc2_hsotg_req, queue);
 }
 
+/**
+ * dwc2_gadget_start_next_request - Starts next request from ep queue
+ * @hs_ep: Endpoint structure
+ *
+ * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked
+ * in its handler. Hence we need to unmask it here to be able to do
+ * resynchronization.
+ */
+static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep)
+{
+       u32 mask;
+       struct dwc2_hsotg *hsotg = hs_ep->parent;
+       int dir_in = hs_ep->dir_in;
+       struct dwc2_hsotg_req *hs_req;
+       u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK;
+
+       if (!list_empty(&hs_ep->queue)) {
+               hs_req = get_ep_head(hs_ep);
+               dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false);
+               return;
+       }
+       if (!hs_ep->isochronous)
+               return;
+
+       if (dir_in) {
+               dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n",
+                       __func__);
+       } else {
+               dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n",
+                       __func__);
+               mask = dwc2_readl(hsotg->regs + epmsk_reg);
+               mask |= DOEPMSK_OUTTKNEPDISMSK;
+               dwc2_writel(mask, hsotg->regs + epmsk_reg);
+       }
+}
+
 /**
  * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE
  * @hsotg: The device state
@@ -1044,7 +1150,6 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
 {
        struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0];
        struct dwc2_hsotg_req *hs_req;
-       bool restart;
        bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
        struct dwc2_hsotg_ep *ep;
        int ret;
@@ -1127,12 +1232,7 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
 
                                /* If we have pending request, then start it */
                                if (!ep->req) {
-                                       restart = !list_empty(&ep->queue);
-                                       if (restart) {
-                                               hs_req = get_ep_head(ep);
-                                               dwc2_hsotg_start_req(hsotg, ep,
-                                                               hs_req, false);
-                                       }
+                                       dwc2_gadget_start_next_request(ep);
                                }
                        }
 
@@ -1373,7 +1473,6 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg,
                                       struct dwc2_hsotg_req *hs_req,
                                       int result)
 {
-       bool restart;
 
        if (!hs_req) {
                dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__);
@@ -1417,11 +1516,7 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg,
         */
 
        if (!hs_ep->req && result >= 0) {
-               restart = !list_empty(&hs_ep->queue);
-               if (restart) {
-                       hs_req = get_ep_head(hs_ep);
-                       dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false);
-               }
+               dwc2_gadget_start_next_request(hs_ep);
        }
 }
 
@@ -1597,31 +1692,15 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
         * adjust the ISOC parity here.
         */
        if (!using_dma(hsotg)) {
-               hs_ep->has_correct_parity = 1;
                if (hs_ep->isochronous && hs_ep->interval == 1)
                        dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum));
+               else if (hs_ep->isochronous && hs_ep->interval > 1)
+                       dwc2_gadget_incr_frame_num(hs_ep);
        }
 
        dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
 }
 
-/**
- * dwc2_hsotg_read_frameno - read current frame number
- * @hsotg: The device instance
- *
- * Return the current frame number
- */
-static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg)
-{
-       u32 dsts;
-
-       dsts = dwc2_readl(hsotg->regs + DSTS);
-       dsts &= DSTS_SOFFN_MASK;
-       dsts >>= DSTS_SOFFN_SHIFT;
-
-       return dsts;
-}
-
 /**
  * dwc2_hsotg_handle_rx - RX FIFO has data
  * @hsotg: The device instance
@@ -1936,6 +2015,190 @@ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg,
        dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
 }
 
+/**
+ * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep
+ * @hsotg: The device state.
+ * @idx: Index of ep.
+ * @dir_in: Endpoint direction 1-in 0-out.
+ *
+ * Reads for endpoint with given index and direction, by masking
+ * epint_reg with coresponding mask.
+ */
+static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg,
+                                         unsigned int idx, int dir_in)
+{
+       u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK;
+       u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
+       u32 ints;
+       u32 mask;
+       u32 diepempmsk;
+
+       mask = dwc2_readl(hsotg->regs + epmsk_reg);
+       diepempmsk = dwc2_readl(hsotg->regs + DIEPEMPMSK);
+       mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0;
+       mask |= DXEPINT_SETUP_RCVD;
+
+       ints = dwc2_readl(hsotg->regs + epint_reg);
+       ints &= mask;
+       return ints;
+}
+
+/**
+ * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD
+ * @hs_ep: The endpoint on which interrupt is asserted.
+ *
+ * This interrupt indicates that the endpoint has been disabled per the
+ * application's request.
+ *
+ * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK,
+ * in case of ISOC completes current request.
+ *
+ * For ISOC-OUT endpoints completes expired requests. If there is remaining
+ * request starts it.
+ */
+static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep)
+{
+       struct dwc2_hsotg *hsotg = hs_ep->parent;
+       struct dwc2_hsotg_req *hs_req;
+       unsigned char idx = hs_ep->index;
+       int dir_in = hs_ep->dir_in;
+       u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
+       int dctl = dwc2_readl(hsotg->regs + DCTL);
+
+       dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
+
+       if (dir_in) {
+               int epctl = dwc2_readl(hsotg->regs + epctl_reg);
+
+               dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
+
+               if (hs_ep->isochronous) {
+                       dwc2_hsotg_complete_in(hsotg, hs_ep);
+                       return;
+               }
+
+               if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) {
+                       int dctl = dwc2_readl(hsotg->regs + DCTL);
+
+                       dctl |= DCTL_CGNPINNAK;
+                       dwc2_writel(dctl, hsotg->regs + DCTL);
+               }
+               return;
+       }
+
+       if (dctl & DCTL_GOUTNAKSTS) {
+               dctl |= DCTL_CGOUTNAK;
+               dwc2_writel(dctl, hsotg->regs + DCTL);
+       }
+
+       if (!hs_ep->isochronous)
+               return;
+
+       if (list_empty(&hs_ep->queue)) {
+               dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n",
+                       __func__, hs_ep);
+               return;
+       }
+
+       do {
+               hs_req = get_ep_head(hs_ep);
+               if (hs_req)
+                       dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req,
+                                                   -ENODATA);
+               dwc2_gadget_incr_frame_num(hs_ep);
+       } while (dwc2_gadget_target_frame_elapsed(hs_ep));
+
+       dwc2_gadget_start_next_request(hs_ep);
+}
+
+/**
+ * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS
+ * @hs_ep: The endpoint on which interrupt is asserted.
+ *
+ * This is starting point for ISOC-OUT transfer, synchronization done with
+ * first out token received from host while corresponding EP is disabled.
+ *
+ * Device does not know initial frame in which out token will come. For this
+ * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon
+ * getting this interrupt SW starts calculation for next transfer frame.
+ */
+static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep)
+{
+       struct dwc2_hsotg *hsotg = ep->parent;
+       int dir_in = ep->dir_in;
+       u32 doepmsk;
+
+       if (dir_in || !ep->isochronous)
+               return;
+
+       dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), -ENODATA);
+
+       if (ep->interval > 1 &&
+           ep->target_frame == TARGET_FRAME_INITIAL) {
+               u32 dsts;
+               u32 ctrl;
+
+               dsts = dwc2_readl(hsotg->regs + DSTS);
+               ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
+               dwc2_gadget_incr_frame_num(ep);
+
+               ctrl = dwc2_readl(hsotg->regs + DOEPCTL(ep->index));
+               if (ep->target_frame & 0x1)
+                       ctrl |= DXEPCTL_SETODDFR;
+               else
+                       ctrl |= DXEPCTL_SETEVENFR;
+
+               dwc2_writel(ctrl, hsotg->regs + DOEPCTL(ep->index));
+       }
+
+       dwc2_gadget_start_next_request(ep);
+       doepmsk = dwc2_readl(hsotg->regs + DOEPMSK);
+       doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK;
+       dwc2_writel(doepmsk, hsotg->regs + DOEPMSK);
+}
+
+/**
+* dwc2_gadget_handle_nak - handle NAK interrupt
+* @hs_ep: The endpoint on which interrupt is asserted.
+*
+* This is starting point for ISOC-IN transfer, synchronization done with
+* first IN token received from host while corresponding EP is disabled.
+*
+* Device does not know when first one token will arrive from host. On first
+* token arrival HW generates 2 interrupts: 'in token received while FIFO empty'
+* and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was
+* sent in response to that as there was no data in FIFO. SW is basing on this
+* interrupt to obtain frame in which token has come and then based on the
+* interval calculates next frame for transfer.
+*/
+static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
+{
+       struct dwc2_hsotg *hsotg = hs_ep->parent;
+       int dir_in = hs_ep->dir_in;
+
+       if (!dir_in || !hs_ep->isochronous)
+               return;
+
+       if (hs_ep->target_frame == TARGET_FRAME_INITIAL) {
+               hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
+               if (hs_ep->interval > 1) {
+                       u32 ctrl = dwc2_readl(hsotg->regs +
+                                             DIEPCTL(hs_ep->index));
+                       if (hs_ep->target_frame & 0x1)
+                               ctrl |= DXEPCTL_SETODDFR;
+                       else
+                               ctrl |= DXEPCTL_SETEVENFR;
+
+                       dwc2_writel(ctrl, hsotg->regs + DIEPCTL(hs_ep->index));
+               }
+
+               dwc2_hsotg_complete_request(hsotg, hs_ep,
+                                           get_ep_head(hs_ep), 0);
+       }
+
+       dwc2_gadget_incr_frame_num(hs_ep);
+}
+
 /**
  * dwc2_hsotg_epint - handle an in/out endpoint interrupt
  * @hsotg: The driver state
@@ -1954,7 +2217,7 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
        u32 ints;
        u32 ctrl;
 
-       ints = dwc2_readl(hsotg->regs + epint_reg);
+       ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in);
        ctrl = dwc2_readl(hsotg->regs + epctl_reg);
 
        /* Clear endpoint interrupts */
@@ -1973,11 +2236,10 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
        if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD)))
                ints &= ~DXEPINT_XFERCOMPL;
 
-       if (ints & DXEPINT_XFERCOMPL) {
-               hs_ep->has_correct_parity = 1;
-               if (hs_ep->isochronous && hs_ep->interval == 1)
-                       dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
+       if (ints & DXEPINT_STSPHSERCVD)
+               dev_dbg(hsotg->dev, "%s: StsPhseRcvd asserted\n", __func__);
 
+       if (ints & DXEPINT_XFERCOMPL) {
                dev_dbg(hsotg->dev,
                        "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n",
                        __func__, dwc2_readl(hsotg->regs + epctl_reg),
@@ -1988,7 +2250,12 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
                 * at completing IN requests here
                 */
                if (dir_in) {
+                       if (hs_ep->isochronous && hs_ep->interval > 1)
+                               dwc2_gadget_incr_frame_num(hs_ep);
+
                        dwc2_hsotg_complete_in(hsotg, hs_ep);
+                       if (ints & DXEPINT_NAKINTRPT)
+                               ints &= ~DXEPINT_NAKINTRPT;
 
                        if (idx == 0 && !hs_ep->req)
                                dwc2_hsotg_enqueue_setup(hsotg);
@@ -1997,28 +2264,21 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
                         * We're using DMA, we need to fire an OutDone here
                         * as we ignore the RXFIFO.
                         */
+                       if (hs_ep->isochronous && hs_ep->interval > 1)
+                               dwc2_gadget_incr_frame_num(hs_ep);
 
                        dwc2_hsotg_handle_outdone(hsotg, idx);
                }
        }
 
-       if (ints & DXEPINT_EPDISBLD) {
-               dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
+       if (ints & DXEPINT_EPDISBLD)
+               dwc2_gadget_handle_ep_disabled(hs_ep);
 
-               if (dir_in) {
-                       int epctl = dwc2_readl(hsotg->regs + epctl_reg);
+       if (ints & DXEPINT_OUTTKNEPDIS)
+               dwc2_gadget_handle_out_token_ep_disabled(hs_ep);
 
-                       dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
-
-                       if ((epctl & DXEPCTL_STALL) &&
-                               (epctl & DXEPCTL_EPTYPE_BULK)) {
-                               int dctl = dwc2_readl(hsotg->regs + DCTL);
-
-                               dctl |= DCTL_CGNPINNAK;
-                               dwc2_writel(dctl, hsotg->regs + DCTL);
-                       }
-               }
-       }
+       if (ints & DXEPINT_NAKINTRPT)
+               dwc2_gadget_handle_nak(hs_ep);
 
        if (ints & DXEPINT_AHBERR)
                dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
@@ -2046,20 +2306,20 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
 
        if (dir_in && !hs_ep->isochronous) {
                /* not sure if this is important, but we'll clear it anyway */
-               if (ints & DIEPMSK_INTKNTXFEMPMSK) {
+               if (ints & DXEPINT_INTKNTXFEMP) {
                        dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
                                __func__, idx);
                }
 
                /* this probably means something bad is happening */
-               if (ints & DIEPMSK_INTKNEPMISMSK) {
+               if (ints & DXEPINT_INTKNEPMIS) {
                        dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
                                 __func__, idx);
                }
 
                /* FIFO has space or is empty (see GAHBCFG) */
                if (hsotg->dedicated_fifos &&
-                   ints & DIEPMSK_TXFIFOEMPTY) {
+                   ints & DXEPINT_TXFEMP) {
                        dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
                                __func__, idx);
                        if (!using_dma(hsotg))
@@ -2322,18 +2582,16 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
        dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
                DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) |
                DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
-               DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
-               DIEPMSK_INTKNEPMISMSK,
+               DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK,
                hsotg->regs + DIEPMSK);
 
        /*
         * don't need XferCompl, we get that from RXFIFO in slave mode. In
         * DMA mode we may need this.
         */
-       dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK |
-                                   DIEPMSK_TIMEOUTMSK) : 0) |
+       dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK) : 0) |
                DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK |
-               DOEPMSK_SETUPMSK,
+               DOEPMSK_SETUPMSK | DOEPMSK_STSPHSERCVDMSK,
                hsotg->regs + DOEPMSK);
 
        dwc2_writel(0, hsotg->regs + DAINTMSK);
@@ -2413,6 +2671,85 @@ void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg)
        __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON);
 }
 
+/**
+ * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt.
+ * @hsotg: The device state:
+ *
+ * This interrupt indicates one of the following conditions occurred while
+ * transmitting an ISOC transaction.
+ * - Corrupted IN Token for ISOC EP.
+ * - Packet not complete in FIFO.
+ *
+ * The following actions will be taken:
+ * - Determine the EP
+ * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO
+ */
+static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_hsotg_ep *hs_ep;
+       u32 epctrl;
+       u32 idx;
+
+       dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n");
+
+       for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
+               hs_ep = hsotg->eps_in[idx];
+               epctrl = dwc2_readl(hsotg->regs + DIEPCTL(idx));
+               if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous &&
+                   dwc2_gadget_target_frame_elapsed(hs_ep)) {
+                       epctrl |= DXEPCTL_SNAK;
+                       epctrl |= DXEPCTL_EPDIS;
+                       dwc2_writel(epctrl, hsotg->regs + DIEPCTL(idx));
+               }
+       }
+
+       /* Clear interrupt */
+       dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS);
+}
+
+/**
+ * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt
+ * @hsotg: The device state:
+ *
+ * This interrupt indicates one of the following conditions occurred while
+ * transmitting an ISOC transaction.
+ * - Corrupted OUT Token for ISOC EP.
+ * - Packet not complete in FIFO.
+ *
+ * The following actions will be taken:
+ * - Determine the EP
+ * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed.
+ */
+static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg)
+{
+       u32 gintsts;
+       u32 gintmsk;
+       u32 epctrl;
+       struct dwc2_hsotg_ep *hs_ep;
+       int idx;
+
+       dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__);
+
+       for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
+               hs_ep = hsotg->eps_out[idx];
+               epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));
+               if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous &&
+                   dwc2_gadget_target_frame_elapsed(hs_ep)) {
+                       /* Unmask GOUTNAKEFF interrupt */
+                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                       gintmsk |= GINTSTS_GOUTNAKEFF;
+                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+
+                       gintsts = dwc2_readl(hsotg->regs + GINTSTS);
+                       if (!(gintsts & GINTSTS_GOUTNAKEFF))
+                               __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
+               }
+       }
+
+       /* Clear interrupt */
+       dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS);
+}
+
 /**
  * dwc2_hsotg_irq - handle device interrupt
  * @irq: The IRQ number triggered
@@ -2545,11 +2882,29 @@ irq_retry:
         */
 
        if (gintsts & GINTSTS_GOUTNAKEFF) {
-               dev_info(hsotg->dev, "GOUTNakEff triggered\n");
+               u8 idx;
+               u32 epctrl;
+               u32 gintmsk;
+               struct dwc2_hsotg_ep *hs_ep;
 
-               __orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK);
+               /* Mask this interrupt */
+               gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+               gintmsk &= ~GINTSTS_GOUTNAKEFF;
+               dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
 
-               dwc2_hsotg_dump(hsotg);
+               dev_dbg(hsotg->dev, "GOUTNakEff triggered\n");
+               for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
+                       hs_ep = hsotg->eps_out[idx];
+                       epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));
+
+                       if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) {
+                               epctrl |= DXEPCTL_SNAK;
+                               epctrl |= DXEPCTL_EPDIS;
+                               dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx));
+                       }
+               }
+
+               /* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */
        }
 
        if (gintsts & GINTSTS_GINNAKEFF) {
@@ -2560,39 +2915,11 @@ irq_retry:
                dwc2_hsotg_dump(hsotg);
        }
 
-       if (gintsts & GINTSTS_INCOMPL_SOIN) {
-               u32 idx, epctl_reg;
-               struct dwc2_hsotg_ep *hs_ep;
-
-               dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOIN\n", __func__);
-               for (idx = 1; idx < hsotg->num_of_eps; idx++) {
-                       hs_ep = hsotg->eps_in[idx];
-
-                       if (!hs_ep->isochronous || hs_ep->has_correct_parity)
-                               continue;
+       if (gintsts & GINTSTS_INCOMPL_SOIN)
+               dwc2_gadget_handle_incomplete_isoc_in(hsotg);
 
-                       epctl_reg = DIEPCTL(idx);
-                       dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
-               }
-               dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS);
-       }
-
-       if (gintsts & GINTSTS_INCOMPL_SOOUT) {
-               u32 idx, epctl_reg;
-               struct dwc2_hsotg_ep *hs_ep;
-
-               dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__);
-               for (idx = 1; idx < hsotg->num_of_eps; idx++) {
-                       hs_ep = hsotg->eps_out[idx];
-
-                       if (!hs_ep->isochronous || hs_ep->has_correct_parity)
-                               continue;
-
-                       epctl_reg = DOEPCTL(idx);
-                       dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
-               }
-               dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS);
-       }
+       if (gintsts & GINTSTS_INCOMPL_SOOUT)
+               dwc2_gadget_handle_incomplete_isoc_out(hsotg);
 
        /*
         * if we've had fifo events, we should try and go around the
@@ -2624,6 +2951,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
        u32 epctrl_reg;
        u32 epctrl;
        u32 mps;
+       u32 mask;
        unsigned int dir_in;
        unsigned int i, val, size;
        int ret = 0;
@@ -2666,15 +2994,6 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
         */
        epctrl |= DXEPCTL_USBACTEP;
 
-       /*
-        * set the NAK status on the endpoint, otherwise we might try and
-        * do something with data that we've yet got a request to process
-        * since the RXFIFO will take data for an endpoint even if the
-        * size register hasn't been set.
-        */
-
-       epctrl |= DXEPCTL_SNAK;
-
        /* update the endpoint state */
        dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in);
 
@@ -2683,18 +3002,24 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
        hs_ep->periodic = 0;
        hs_ep->halted = 0;
        hs_ep->interval = desc->bInterval;
-       hs_ep->has_correct_parity = 0;
-
-       if (hs_ep->interval > 1 && hs_ep->mc > 1)
-               dev_err(hsotg->dev, "MC > 1 when interval is not 1\n");
 
        switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
        case USB_ENDPOINT_XFER_ISOC:
                epctrl |= DXEPCTL_EPTYPE_ISO;
                epctrl |= DXEPCTL_SETEVENFR;
                hs_ep->isochronous = 1;
-               if (dir_in)
+               hs_ep->interval = 1 << (desc->bInterval - 1);
+               hs_ep->target_frame = TARGET_FRAME_INITIAL;
+               if (dir_in) {
                        hs_ep->periodic = 1;
+                       mask = dwc2_readl(hsotg->regs + DIEPMSK);
+                       mask |= DIEPMSK_NAKMSK;
+                       dwc2_writel(mask, hsotg->regs + DIEPMSK);
+               } else {
+                       mask = dwc2_readl(hsotg->regs + DOEPMSK);
+                       mask |= DOEPMSK_OUTTKNEPDISMSK;
+                       dwc2_writel(mask, hsotg->regs + DOEPMSK);
+               }
                break;
 
        case USB_ENDPOINT_XFER_BULK:
@@ -2705,6 +3030,9 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
                if (dir_in)
                        hs_ep->periodic = 1;
 
+               if (hsotg->gadget.speed == USB_SPEED_HIGH)
+                       hs_ep->interval = 1 << (desc->bInterval - 1);
+
                epctrl |= DXEPCTL_EPTYPE_INTERRUPT;
                break;
 
@@ -2758,7 +3086,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
        }
 
        /* for non control endpoints, set PID to D0 */
-       if (index)
+       if (index && !hs_ep->isochronous)
                epctrl |= DXEPCTL_SETD0PID;
 
        dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
@@ -2875,10 +3203,8 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
                        dev_warn(hsotg->dev,
                                "%s: timeout DIEPINT.NAKEFF\n", __func__);
        } else {
-               /* Clear any pending nak effect interrupt */
-               dwc2_writel(GINTSTS_GOUTNAKEFF, hsotg->regs + GINTSTS);
-
-               __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
+               if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF))
+                       __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
 
                /* Wait for global nak to take effect */
                if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
index b5c7793..1375435 100644 (file)
@@ -367,7 +367,8 @@ static void pmap_unschedule(unsigned long *map, int bits_per_period,
  * @fmt:   The format for printf.
  * @...:   The args for printf.
  */
-static void cat_printf(char **buf, size_t *size, const char *fmt, ...)
+static __printf(3, 4)
+void cat_printf(char **buf, size_t *size, const char *fmt, ...)
 {
        va_list args;
        int i;
index 281b57b..efc3bcd 100644 (file)
 #define DSTS_SUSPSTS                   (1 << 0)
 
 #define DIEPMSK                                HSOTG_REG(0x810)
+#define DIEPMSK_NAKMSK                 (1 << 13)
+#define DIEPMSK_BNAININTRMSK           (1 << 9)
+#define DIEPMSK_TXFIFOUNDRNMSK         (1 << 8)
 #define DIEPMSK_TXFIFOEMPTY            (1 << 7)
 #define DIEPMSK_INEPNAKEFFMSK          (1 << 6)
 #define DIEPMSK_INTKNEPMISMSK          (1 << 5)
 
 #define DOEPMSK                                HSOTG_REG(0x814)
 #define DOEPMSK_BACK2BACKSETUP         (1 << 6)
+#define DOEPMSK_STSPHSERCVDMSK         (1 << 5)
 #define DOEPMSK_OUTTKNEPDISMSK         (1 << 4)
 #define DOEPMSK_SETUPMSK               (1 << 3)
 #define DOEPMSK_AHBERRMSK              (1 << 2)
 #define DTKNQR2                                HSOTG_REG(0x824)
 #define DTKNQR3                                HSOTG_REG(0x830)
 #define DTKNQR4                                HSOTG_REG(0x834)
+#define DIEPEMPMSK                     HSOTG_REG(0x834)
 
 #define DVBUSDIS                       HSOTG_REG(0x828)
 #define DVBUSPULSE                     HSOTG_REG(0x82C)
 #define DIEPINT(_a)                    HSOTG_REG(0x908 + ((_a) * 0x20))
 #define DOEPINT(_a)                    HSOTG_REG(0xB08 + ((_a) * 0x20))
 #define DXEPINT_SETUP_RCVD             (1 << 15)
+#define DXEPINT_NYETINTRPT             (1 << 14)
+#define DXEPINT_NAKINTRPT              (1 << 13)
+#define DXEPINT_BBLEERRINTRPT          (1 << 12)
+#define DXEPINT_PKTDRPSTS              (1 << 11)
+#define DXEPINT_BNAINTR                        (1 << 9)
+#define DXEPINT_TXFIFOUNDRN            (1 << 8)
+#define DXEPINT_OUTPKTERR              (1 << 8)
+#define DXEPINT_TXFEMP                 (1 << 7)
 #define DXEPINT_INEPNAKEFF             (1 << 6)
 #define DXEPINT_BACK2BACKSETUP         (1 << 6)
 #define DXEPINT_INTKNEPMIS             (1 << 5)
+#define DXEPINT_STSPHSERCVD            (1 << 5)
 #define DXEPINT_INTKNTXFEMP            (1 << 4)
 #define DXEPINT_OUTTKNEPDIS            (1 << 4)
 #define DXEPINT_TIMEOUT                        (1 << 3)
index a590cd2..9466431 100644 (file)
 #include <linux/usb/of.h>
 #include <linux/usb/otg.h>
 
-#include "platform_data.h"
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
 
 #include "debug.h"
 
-/* -------------------------------------------------------------------------- */
+#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
 
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
 {
@@ -149,9 +148,8 @@ static int dwc3_soft_reset(struct dwc3 *dwc)
 /*
  * dwc3_frame_length_adjustment - Adjusts frame length if required
  * @dwc3: Pointer to our controller context structure
- * @fladj: Value of GFLADJ_30MHZ to adjust frame length
  */
-static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
+static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
 {
        u32 reg;
        u32 dft;
@@ -159,15 +157,15 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
        if (dwc->revision < DWC3_REVISION_250A)
                return;
 
-       if (fladj == 0)
+       if (dwc->fladj == 0)
                return;
 
        reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
        dft = reg & DWC3_GFLADJ_30MHZ_MASK;
-       if (!dev_WARN_ONCE(dwc->dev, dft == fladj,
+       if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj,
            "request value same as default, ignoring\n")) {
                reg &= ~DWC3_GFLADJ_30MHZ_MASK;
-               reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj;
+               reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
                dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
        }
 }
@@ -507,6 +505,21 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        return 0;
 }
 
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+       dwc3_event_buffers_cleanup(dwc);
+
+       usb_phy_shutdown(dwc->usb2_phy);
+       usb_phy_shutdown(dwc->usb3_phy);
+       phy_exit(dwc->usb2_generic_phy);
+       phy_exit(dwc->usb3_generic_phy);
+
+       usb_phy_set_suspend(dwc->usb2_phy, 1);
+       usb_phy_set_suspend(dwc->usb3_phy, 1);
+       phy_power_off(dwc->usb2_generic_phy);
+       phy_power_off(dwc->usb3_generic_phy);
+}
+
 /**
  * dwc3_core_init - Low-level initialization of DWC3 Core
  * @dwc: Pointer to our controller context structure
@@ -556,6 +569,10 @@ static int dwc3_core_init(struct dwc3 *dwc)
        if (ret)
                goto err0;
 
+       ret = dwc3_phy_setup(dwc);
+       if (ret)
+               goto err0;
+
        reg = dwc3_readl(dwc->regs, DWC3_GCTL);
        reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
 
@@ -622,22 +639,45 @@ static int dwc3_core_init(struct dwc3 *dwc)
        if (dwc->revision < DWC3_REVISION_190A)
                reg |= DWC3_GCTL_U2RSTECN;
 
-       dwc3_core_num_eps(dwc);
-
        dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
-       ret = dwc3_alloc_scratch_buffers(dwc);
-       if (ret)
-               goto err1;
+       dwc3_core_num_eps(dwc);
 
        ret = dwc3_setup_scratch_buffers(dwc);
        if (ret)
+               goto err1;
+
+       /* Adjust Frame Length */
+       dwc3_frame_length_adjustment(dwc);
+
+       usb_phy_set_suspend(dwc->usb2_phy, 0);
+       usb_phy_set_suspend(dwc->usb3_phy, 0);
+       ret = phy_power_on(dwc->usb2_generic_phy);
+       if (ret < 0)
                goto err2;
 
+       ret = phy_power_on(dwc->usb3_generic_phy);
+       if (ret < 0)
+               goto err3;
+
+       ret = dwc3_event_buffers_setup(dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to setup event buffers\n");
+               goto err4;
+       }
+
        return 0;
 
+err4:
+       phy_power_off(dwc->usb2_generic_phy);
+
+err3:
+       phy_power_off(dwc->usb3_generic_phy);
+
 err2:
-       dwc3_free_scratch_buffers(dwc);
+       usb_phy_set_suspend(dwc->usb2_phy, 1);
+       usb_phy_set_suspend(dwc->usb3_phy, 1);
+       dwc3_core_exit(dwc);
 
 err1:
        usb_phy_shutdown(dwc->usb2_phy);
@@ -649,15 +689,6 @@ err0:
        return ret;
 }
 
-static void dwc3_core_exit(struct dwc3 *dwc)
-{
-       dwc3_free_scratch_buffers(dwc);
-       usb_phy_shutdown(dwc->usb2_phy);
-       usb_phy_shutdown(dwc->usb3_phy);
-       phy_exit(dwc->usb2_generic_phy);
-       phy_exit(dwc->usb3_generic_phy);
-}
-
 static int dwc3_core_get_phy(struct dwc3 *dwc)
 {
        struct device           *dev = dwc->dev;
@@ -735,7 +766,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(dev, "failed to initialize gadget\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to initialize gadget\n");
                        return ret;
                }
                break;
@@ -743,7 +775,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
-                       dev_err(dev, "failed to initialize host\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to initialize host\n");
                        return ret;
                }
                break;
@@ -751,13 +784,15 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
                ret = dwc3_host_init(dwc);
                if (ret) {
-                       dev_err(dev, "failed to initialize host\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to initialize host\n");
                        return ret;
                }
 
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(dev, "failed to initialize gadget\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to initialize gadget\n");
                        return ret;
                }
                break;
@@ -793,13 +828,11 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
 static int dwc3_probe(struct platform_device *pdev)
 {
        struct device           *dev = &pdev->dev;
-       struct dwc3_platform_data *pdata = dev_get_platdata(dev);
        struct resource         *res;
        struct dwc3             *dwc;
        u8                      lpm_nyet_threshold;
        u8                      tx_de_emphasis;
        u8                      hird_threshold;
-       u32                     fladj = 0;
 
        int                     ret;
 
@@ -814,16 +847,6 @@ static int dwc3_probe(struct platform_device *pdev)
        dwc->mem = mem;
        dwc->dev = dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(dev, "missing IRQ\n");
-               return -ENODEV;
-       }
-       dwc->xhci_resources[1].start = res->start;
-       dwc->xhci_resources[1].end = res->end;
-       dwc->xhci_resources[1].flags = res->flags;
-       dwc->xhci_resources[1].name = res->name;
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "missing memory resource\n");
@@ -909,40 +932,7 @@ static int dwc3_probe(struct platform_device *pdev)
        device_property_read_string(dev, "snps,hsphy_interface",
                                    &dwc->hsphy_interface);
        device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
-                                &fladj);
-
-       if (pdata) {
-               dwc->maximum_speed = pdata->maximum_speed;
-               dwc->has_lpm_erratum = pdata->has_lpm_erratum;
-               if (pdata->lpm_nyet_threshold)
-                       lpm_nyet_threshold = pdata->lpm_nyet_threshold;
-               dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
-               if (pdata->hird_threshold)
-                       hird_threshold = pdata->hird_threshold;
-
-               dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
-               dwc->dr_mode = pdata->dr_mode;
-
-               dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
-               dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
-               dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
-               dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
-               dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
-               dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
-               dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
-               dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
-               dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
-               dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
-               dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
-               dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
-
-               dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
-               if (pdata->tx_de_emphasis)
-                       tx_de_emphasis = pdata->tx_de_emphasis;
-
-               dwc->hsphy_interface = pdata->hsphy_interface;
-               fladj = pdata->fladj_value;
-       }
+                                &dwc->fladj);
 
        dwc->lpm_nyet_threshold = lpm_nyet_threshold;
        dwc->tx_de_emphasis = tx_de_emphasis;
@@ -953,10 +943,6 @@ static int dwc3_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, dwc);
        dwc3_cache_hwparams(dwc);
 
-       ret = dwc3_phy_setup(dwc);
-       if (ret)
-               goto err0;
-
        ret = dwc3_core_get_phy(dwc);
        if (ret)
                goto err0;
@@ -969,29 +955,43 @@ static int dwc3_probe(struct platform_device *pdev)
                dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
        }
 
+       pm_runtime_set_active(dev);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
        pm_runtime_enable(dev);
-       pm_runtime_get_sync(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               goto err1;
+
        pm_runtime_forbid(dev);
 
        ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
        if (ret) {
                dev_err(dwc->dev, "failed to allocate event buffers\n");
                ret = -ENOMEM;
-               goto err1;
+               goto err2;
        }
 
-       if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+       if (IS_ENABLED(CONFIG_USB_DWC3_HOST) &&
+                       (dwc->dr_mode == USB_DR_MODE_OTG ||
+                                       dwc->dr_mode == USB_DR_MODE_UNKNOWN))
                dwc->dr_mode = USB_DR_MODE_HOST;
-       else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+       else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) &&
+                       (dwc->dr_mode == USB_DR_MODE_OTG ||
+                                       dwc->dr_mode == USB_DR_MODE_UNKNOWN))
                dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
 
        if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
                dwc->dr_mode = USB_DR_MODE_OTG;
 
+       ret = dwc3_alloc_scratch_buffers(dwc);
+       if (ret)
+               goto err3;
+
        ret = dwc3_core_init(dwc);
        if (ret) {
                dev_err(dev, "failed to initialize core\n");
-               goto err1;
+               goto err4;
        }
 
        /* Check the maximum_speed parameter */
@@ -1021,31 +1021,12 @@ static int dwc3_probe(struct platform_device *pdev)
                break;
        }
 
-       /* Adjust Frame Length */
-       dwc3_frame_length_adjustment(dwc, fladj);
-
-       usb_phy_set_suspend(dwc->usb2_phy, 0);
-       usb_phy_set_suspend(dwc->usb3_phy, 0);
-       ret = phy_power_on(dwc->usb2_generic_phy);
-       if (ret < 0)
-               goto err2;
-
-       ret = phy_power_on(dwc->usb3_generic_phy);
-       if (ret < 0)
-               goto err3;
-
-       ret = dwc3_event_buffers_setup(dwc);
-       if (ret) {
-               dev_err(dwc->dev, "failed to setup event buffers\n");
-               goto err4;
-       }
-
        ret = dwc3_core_init_mode(dwc);
        if (ret)
                goto err5;
 
        dwc3_debugfs_init(dwc);
-       pm_runtime_allow(dev);
+       pm_runtime_put(dev);
 
        return 0;
 
@@ -1053,19 +1034,18 @@ err5:
        dwc3_event_buffers_cleanup(dwc);
 
 err4:
-       phy_power_off(dwc->usb3_generic_phy);
+       dwc3_free_scratch_buffers(dwc);
 
 err3:
-       phy_power_off(dwc->usb2_generic_phy);
+       dwc3_free_event_buffers(dwc);
+       dwc3_ulpi_exit(dwc);
 
 err2:
-       usb_phy_set_suspend(dwc->usb2_phy, 1);
-       usb_phy_set_suspend(dwc->usb3_phy, 1);
-       dwc3_core_exit(dwc);
+       pm_runtime_allow(&pdev->dev);
 
 err1:
-       dwc3_free_event_buffers(dwc);
-       dwc3_ulpi_exit(dwc);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
 err0:
        /*
@@ -1083,6 +1063,7 @@ static int dwc3_remove(struct platform_device *pdev)
        struct dwc3     *dwc = platform_get_drvdata(pdev);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
+       pm_runtime_get_sync(&pdev->dev);
        /*
         * restore res->start back to its original value so that, in case the
         * probe is deferred, we don't end up getting error in request the
@@ -1092,133 +1073,192 @@ static int dwc3_remove(struct platform_device *pdev)
 
        dwc3_debugfs_exit(dwc);
        dwc3_core_exit_mode(dwc);
-       dwc3_event_buffers_cleanup(dwc);
-       dwc3_free_event_buffers(dwc);
-
-       usb_phy_set_suspend(dwc->usb2_phy, 1);
-       usb_phy_set_suspend(dwc->usb3_phy, 1);
-       phy_power_off(dwc->usb2_generic_phy);
-       phy_power_off(dwc->usb3_generic_phy);
 
        dwc3_core_exit(dwc);
        dwc3_ulpi_exit(dwc);
 
        pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_allow(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
+       dwc3_free_event_buffers(dwc);
+       dwc3_free_scratch_buffers(dwc);
+
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int dwc3_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int dwc3_suspend_common(struct dwc3 *dwc)
 {
-       struct dwc3     *dwc = dev_get_drvdata(dev);
        unsigned long   flags;
 
-       spin_lock_irqsave(&dwc->lock, flags);
-
        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
        case USB_DR_MODE_OTG:
+               spin_lock_irqsave(&dwc->lock, flags);
                dwc3_gadget_suspend(dwc);
-               /* FALLTHROUGH */
+               spin_unlock_irqrestore(&dwc->lock, flags);
+               break;
        case USB_DR_MODE_HOST:
        default:
-               dwc3_event_buffers_cleanup(dwc);
+               /* do nothing */
                break;
        }
 
-       dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
-       spin_unlock_irqrestore(&dwc->lock, flags);
+       dwc3_core_exit(dwc);
 
-       usb_phy_shutdown(dwc->usb3_phy);
-       usb_phy_shutdown(dwc->usb2_phy);
-       phy_exit(dwc->usb2_generic_phy);
-       phy_exit(dwc->usb3_generic_phy);
+       return 0;
+}
 
-       usb_phy_set_suspend(dwc->usb2_phy, 1);
-       usb_phy_set_suspend(dwc->usb3_phy, 1);
-       WARN_ON(phy_power_off(dwc->usb2_generic_phy) < 0);
-       WARN_ON(phy_power_off(dwc->usb3_generic_phy) < 0);
+static int dwc3_resume_common(struct dwc3 *dwc)
+{
+       unsigned long   flags;
+       int             ret;
 
-       pinctrl_pm_select_sleep_state(dev);
+       ret = dwc3_core_init(dwc);
+       if (ret)
+               return ret;
+
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
+               spin_lock_irqsave(&dwc->lock, flags);
+               dwc3_gadget_resume(dwc);
+               spin_unlock_irqrestore(&dwc->lock, flags);
+               /* FALLTHROUGH */
+       case USB_DR_MODE_HOST:
+       default:
+               /* do nothing */
+               break;
+       }
 
        return 0;
 }
 
-static int dwc3_resume(struct device *dev)
+static int dwc3_runtime_checks(struct dwc3 *dwc)
 {
-       struct dwc3     *dwc = dev_get_drvdata(dev);
-       unsigned long   flags;
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
+               if (dwc->connected)
+                       return -EBUSY;
+               break;
+       case USB_DR_MODE_HOST:
+       default:
+               /* do nothing */
+               break;
+       }
+
+       return 0;
+}
+
+static int dwc3_runtime_suspend(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
        int             ret;
 
-       pinctrl_pm_select_default_state(dev);
+       if (dwc3_runtime_checks(dwc))
+               return -EBUSY;
 
-       usb_phy_set_suspend(dwc->usb2_phy, 0);
-       usb_phy_set_suspend(dwc->usb3_phy, 0);
-       ret = phy_power_on(dwc->usb2_generic_phy);
-       if (ret < 0)
+       ret = dwc3_suspend_common(dwc);
+       if (ret)
                return ret;
 
-       ret = phy_power_on(dwc->usb3_generic_phy);
-       if (ret < 0)
-               goto err_usb2phy_power;
+       device_init_wakeup(dev, true);
 
-       usb_phy_init(dwc->usb3_phy);
-       usb_phy_init(dwc->usb2_phy);
-       ret = phy_init(dwc->usb2_generic_phy);
-       if (ret < 0)
-               goto err_usb3phy_power;
+       return 0;
+}
 
-       ret = phy_init(dwc->usb3_generic_phy);
-       if (ret < 0)
-               goto err_usb2phy_init;
+static int dwc3_runtime_resume(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       int             ret;
 
-       spin_lock_irqsave(&dwc->lock, flags);
+       device_init_wakeup(dev, false);
 
-       dwc3_event_buffers_setup(dwc);
-       dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
+       ret = dwc3_resume_common(dwc);
+       if (ret)
+               return ret;
 
        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
        case USB_DR_MODE_OTG:
-               dwc3_gadget_resume(dwc);
-               /* FALLTHROUGH */
+               dwc3_gadget_process_pending_events(dwc);
+               break;
        case USB_DR_MODE_HOST:
        default:
                /* do nothing */
                break;
        }
 
-       spin_unlock_irqrestore(&dwc->lock, flags);
+       pm_runtime_mark_last_busy(dev);
 
-       pm_runtime_disable(dev);
-       pm_runtime_set_active(dev);
-       pm_runtime_enable(dev);
+       return 0;
+}
+
+static int dwc3_runtime_idle(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
+               if (dwc3_runtime_checks(dwc))
+                       return -EBUSY;
+               break;
+       case USB_DR_MODE_HOST:
+       default:
+               /* do nothing */
+               break;
+       }
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_autosuspend(dev);
 
        return 0;
+}
+#endif /* CONFIG_PM */
 
-err_usb2phy_init:
-       phy_exit(dwc->usb2_generic_phy);
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_suspend(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       int             ret;
 
-err_usb3phy_power:
-       phy_power_off(dwc->usb3_generic_phy);
+       ret = dwc3_suspend_common(dwc);
+       if (ret)
+               return ret;
 
-err_usb2phy_power:
-       phy_power_off(dwc->usb2_generic_phy);
+       pinctrl_pm_select_sleep_state(dev);
 
-       return ret;
+       return 0;
 }
 
+static int dwc3_resume(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       int             ret;
+
+       pinctrl_pm_select_default_state(dev);
+
+       ret = dwc3_resume_common(dwc);
+       if (ret)
+               return ret;
+
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
 static const struct dev_pm_ops dwc3_dev_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
+       SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
+                       dwc3_runtime_idle)
 };
 
-#define DWC3_PM_OPS    &(dwc3_dev_pm_ops)
-#else
-#define DWC3_PM_OPS    NULL
-#endif
-
 #ifdef CONFIG_OF
 static const struct of_device_id of_dwc3_match[] = {
        {
@@ -1250,7 +1290,7 @@ static struct platform_driver dwc3_driver = {
                .name   = "dwc3",
                .of_match_table = of_match_ptr(of_dwc3_match),
                .acpi_match_table = ACPI_PTR(dwc3_acpi_match),
-               .pm     = DWC3_PM_OPS,
+               .pm     = &dwc3_dev_pm_ops,
        },
 };
 
index 6540506..45d6de5 100644 (file)
@@ -86,6 +86,7 @@
 #define DWC3_GCTL              0xc110
 #define DWC3_GEVTEN            0xc114
 #define DWC3_GSTS              0xc118
+#define DWC3_GUCTL1            0xc11c
 #define DWC3_GSNPSID           0xc120
 #define DWC3_GGPIO             0xc124
 #define DWC3_GUID              0xc128
 #define DWC3_DGCMDPAR          0xc710
 #define DWC3_DGCMD             0xc714
 #define DWC3_DALEPENA          0xc720
-#define DWC3_DEPCMDPAR2(n)     (0xc800 + (n * 0x10))
-#define DWC3_DEPCMDPAR1(n)     (0xc804 + (n * 0x10))
-#define DWC3_DEPCMDPAR0(n)     (0xc808 + (n * 0x10))
-#define DWC3_DEPCMD(n)         (0xc80c + (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
 
 /* OTG Registers */
 #define DWC3_OCFG              0xcc00
 #define DWC3_GEVNTSIZ_INTMASK          (1 << 31)
 #define DWC3_GEVNTSIZ_SIZE(n)          ((n) & 0xffff)
 
+/* Global HWPARAMS0 Register */
+#define DWC3_GHWPARAMS0_USB3_MODE(n)   ((n) & 0x3)
+#define DWC3_GHWPARAMS0_MBUS_TYPE(n)   (((n) >> 3) & 0x7)
+#define DWC3_GHWPARAMS0_SBUS_TYPE(n)   (((n) >> 6) & 0x3)
+#define DWC3_GHWPARAMS0_MDWIDTH(n)     (((n) >> 8) & 0xff)
+#define DWC3_GHWPARAMS0_SDWIDTH(n)     (((n) >> 16) & 0xff)
+#define DWC3_GHWPARAMS0_AWIDTH(n)      (((n) >> 24) & 0xff)
+
 /* Global HWPARAMS1 Register */
 #define DWC3_GHWPARAMS1_EN_PWROPT(n)   (((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO   0
 /* Global HWPARAMS6 Register */
 #define DWC3_GHWPARAMS6_EN_FPGA                        (1 << 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_MASK                 0x3f
@@ -468,6 +483,8 @@ struct dwc3_event_buffer {
  * @endpoint: usb endpoint
  * @pending_list: list of pending requests for this endpoint
  * @started_list: list of started requests on this endpoint
+ * @lock: spinlock for endpoint request queue traversal
+ * @regs: pointer to first endpoint register
  * @trb_pool: array of transaction buffers
  * @trb_pool_dma: dma address of @trb_pool
  * @trb_enqueue: enqueue 'pointer' into TRB array
@@ -480,6 +497,8 @@ struct dwc3_event_buffer {
  * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
  * @resource_index: Resource transfer index
  * @interval: the interval on which the ISOC transfer is started
+ * @allocated_requests: number of requests allocated
+ * @queued_requests: number of requests queued for transfer
  * @name: a human readable name e.g. ep1out-bulk
  * @direction: true for TX, false for RX
  * @stream_capable: true when streams are enabled
@@ -489,6 +508,9 @@ struct dwc3_ep {
        struct list_head        pending_list;
        struct list_head        started_list;
 
+       spinlock_t              lock;
+       void __iomem            *regs;
+
        struct dwc3_trb         *trb_pool;
        dma_addr_t              trb_pool_dma;
        const struct usb_ss_ep_comp_descriptor *comp_desc;
@@ -521,6 +543,8 @@ struct dwc3_ep {
        u8                      number;
        u8                      type;
        u8                      resource_index;
+       u32                     allocated_requests;
+       u32                     queued_requests;
        u32                     interval;
 
        char                    name[20];
@@ -712,6 +736,8 @@ struct dwc3_scratchpad_array {
  * @gadget_driver: pointer to the gadget driver
  * @regs: base address for our registers
  * @regs_size: address space size
+ * @fladj: frame length adjustment
+ * @irq_gadget: peripheral controller's IRQ number
  * @nr_scratch: number of scratch buffers
  * @u1u2: only used on revisions <1.83a for workaround
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
@@ -744,6 +770,7 @@ struct dwc3_scratchpad_array {
  * @lpm_nyet_threshold: LPM NYET response threshold
  * @hird_threshold: HIRD threshold
  * @hsphy_interface: "utmi" or "ulpi"
+ * @connected: true when we're connected to a host, false otherwise
  * @delayed_status: true when gadget driver asks for delayed status
  * @ep0_bounced: true when we used bounce buffer
  * @ep0_expect_in: true when we expect a DATA IN transfer
@@ -754,6 +781,7 @@ struct dwc3_scratchpad_array {
  *     0       - utmi_sleep_n
  *     1       - utmi_l1_suspend_n
  * @is_fpga: true when we are using the FPGA board
+ * @pending_events: true when we have pending IRQs to be handled
  * @pullups_connected: true when Run/Stop bit is set
  * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
  * @start_config_issued: true when StartConfig command has been issued
@@ -818,10 +846,8 @@ struct dwc3 {
 
        enum usb_dr_mode        dr_mode;
 
-       /* used for suspend/resume */
-       u32                     dcfg;
-       u32                     gctl;
-
+       u32                     fladj;
+       u32                     irq_gadget;
        u32                     nr_scratch;
        u32                     u1u2;
        u32                     maximum_speed;
@@ -860,7 +886,7 @@ struct dwc3 {
  * just so dwc31 revisions are always larger than dwc3.
  */
 #define DWC3_REVISION_IS_DWC31         0x80000000
-#define DWC3_USB31_REVISION_110A       (0x3131302a | DWC3_REVISION_IS_USB31)
+#define DWC3_USB31_REVISION_110A       (0x3131302a | DWC3_REVISION_IS_DWC31)
 
        enum dwc3_ep0_next      ep0_next_event;
        enum dwc3_ep0_state     ep0state;
@@ -890,6 +916,7 @@ struct dwc3 {
 
        const char              *hsphy_interface;
 
+       unsigned                connected:1;
        unsigned                delayed_status:1;
        unsigned                ep0_bounced:1;
        unsigned                ep0_expect_in:1;
@@ -897,6 +924,7 @@ struct dwc3 {
        unsigned                has_lpm_erratum:1;
        unsigned                is_utmi_l1_suspend:1;
        unsigned                is_fpga:1;
+       unsigned                pending_events:1;
        unsigned                pullups_connected:1;
        unsigned                setup_packet_pending:1;
        unsigned                three_stage_setup:1;
@@ -1094,8 +1122,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc);
 int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
 int dwc3_gadget_get_link_state(struct dwc3 *dwc);
 int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
-int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
-               unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
+               struct dwc3_gadget_ep_cmd_params *params);
 int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param);
 #else
 static inline int dwc3_gadget_init(struct dwc3 *dwc)
@@ -1110,8 +1138,8 @@ static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc,
                enum dwc3_link_state state)
 { return 0; }
 
-static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
-               unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
+               struct dwc3_gadget_ep_cmd_params *params)
 { return 0; }
 static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
                int cmd, u32 param)
@@ -1122,6 +1150,7 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
 #if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
 int dwc3_gadget_suspend(struct dwc3 *dwc);
 int dwc3_gadget_resume(struct dwc3 *dwc);
+void dwc3_gadget_process_pending_events(struct dwc3 *dwc);
 #else
 static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
 {
@@ -1132,6 +1161,10 @@ static inline int dwc3_gadget_resume(struct dwc3 *dwc)
 {
        return 0;
 }
+
+static inline void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
+{
+}
 #endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
 
 #if IS_ENABLED(CONFIG_USB_DWC3_ULPI)
index 71e3180..22dfc3d 100644 (file)
@@ -128,56 +128,112 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
  * dwc3_gadget_event_string - returns event name
  * @event: the event code
  */
-static inline const char *dwc3_gadget_event_string(u8 event)
+static inline const char *
+dwc3_gadget_event_string(const struct dwc3_event_devt *event)
 {
-       switch (event) {
+       static char str[256];
+       enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK;
+
+       switch (event->type) {
        case DWC3_DEVICE_EVENT_DISCONNECT:
-               return "Disconnect";
+               sprintf(str, "Disconnect: [%s]",
+                               dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_RESET:
-               return "Reset";
+               sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_CONNECT_DONE:
-               return "Connection Done";
+               sprintf(str, "Connection Done [%s]",
+                               dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
-               return "Link Status Change";
+               sprintf(str, "Link Change [%s]",
+                               dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_WAKEUP:
-               return "WakeUp";
+               sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_EOPF:
-               return "End-Of-Frame";
+               sprintf(str, "End-Of-Frame [%s]",
+                               dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_SOF:
-               return "Start-Of-Frame";
+               sprintf(str, "Start-Of-Frame [%s]",
+                               dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
-               return "Erratic Error";
+               sprintf(str, "Erratic Error [%s]",
+                               dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_CMD_CMPL:
-               return "Command Complete";
+               sprintf(str, "Command Complete [%s]",
+                               dwc3_gadget_link_string(state));
+               break;
        case DWC3_DEVICE_EVENT_OVERFLOW:
-               return "Overflow";
+               sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state));
+               break;
+       default:
+               sprintf(str, "UNKNOWN");
        }
 
-       return "UNKNOWN";
+       return str;
 }
 
 /**
  * dwc3_ep_event_string - returns event name
  * @event: then event code
  */
-static inline const char *dwc3_ep_event_string(u8 event)
+static inline const char *
+dwc3_ep_event_string(const struct dwc3_event_depevt *event)
 {
-       switch (event) {
+       u8 epnum = event->endpoint_number;
+       static char str[256];
+       int status;
+       int ret;
+
+       ret = sprintf(str, "ep%d%s: ", epnum >> 1,
+                       (epnum & 1) ? "in" : "in");
+       if (ret < 0)
+               return "UNKNOWN";
+
+       switch (event->endpoint_event) {
        case DWC3_DEPEVT_XFERCOMPLETE:
-               return "Transfer Complete";
+               strcat(str, "Transfer Complete");
+               break;
        case DWC3_DEPEVT_XFERINPROGRESS:
-               return "Transfer In-Progress";
+               strcat(str, "Transfer In-Progress");
+               break;
        case DWC3_DEPEVT_XFERNOTREADY:
-               return "Transfer Not Ready";
+               strcat(str, "Transfer Not Ready");
+               status = event->status & DEPEVT_STATUS_TRANSFER_ACTIVE;
+               strcat(str, status ? " (Active)" : " (Not Active)");
+               break;
        case DWC3_DEPEVT_RXTXFIFOEVT:
-               return "FIFO";
+               strcat(str, "FIFO");
+               break;
        case DWC3_DEPEVT_STREAMEVT:
-               return "Stream";
+               status = event->status;
+
+               switch (status) {
+               case DEPEVT_STREAMEVT_FOUND:
+                       sprintf(str + ret, " Stream %d Found",
+                                       event->parameters);
+                       break;
+               case DEPEVT_STREAMEVT_NOTFOUND:
+               default:
+                       strcat(str, " Stream Not Found");
+                       break;
+               }
+
+               break;
        case DWC3_DEPEVT_EPCMDCMPLT:
-               return "Endpoint Command Complete";
+               strcat(str, "Endpoint Command Complete");
+               break;
+       default:
+               sprintf(str, "UNKNOWN");
        }
 
-       return "UNKNOWN";
+       return str;
 }
 
 /**
@@ -214,6 +270,46 @@ static inline const char *dwc3_gadget_event_type_string(u8 event)
        }
 }
 
+static inline const char *dwc3_decode_event(u32 event)
+{
+       const union dwc3_event evt = (union dwc3_event) event;
+
+       if (evt.type.is_devspec)
+               return dwc3_gadget_event_string(&evt.devt);
+       else
+               return dwc3_ep_event_string(&evt.depevt);
+}
+
+static inline const char *dwc3_ep_cmd_status_string(int status)
+{
+       switch (status) {
+       case -ETIMEDOUT:
+               return "Timed Out";
+       case 0:
+               return "Successful";
+       case DEPEVT_TRANSFER_NO_RESOURCE:
+               return "No Resource";
+       case DEPEVT_TRANSFER_BUS_EXPIRY:
+               return "Bus Expiry";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static inline const char *dwc3_gadget_generic_cmd_status_string(int status)
+{
+       switch (status) {
+       case -ETIMEDOUT:
+               return "Timed Out";
+       case 0:
+               return "Successful";
+       case 1:
+               return "Error";
+       default:
+               return "UNKNOWN";
+       }
+}
+
 void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);
 
 #ifdef CONFIG_DEBUG_FS
index b1dd3c6..31926dd 100644 (file)
 #define dump_register(nm)                              \
 {                                                      \
        .name   = __stringify(nm),                      \
-       .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
+       .offset = DWC3_ ##nm,                           \
 }
 
+#define dump_ep_register_set(n)                        \
+       {                                       \
+               .name = "DEPCMDPAR2("__stringify(n)")", \
+               .offset = DWC3_DEP_BASE(n) +    \
+                       DWC3_DEPCMDPAR2,        \
+       },                                      \
+       {                                       \
+               .name = "DEPCMDPAR1("__stringify(n)")", \
+               .offset = DWC3_DEP_BASE(n) +    \
+                       DWC3_DEPCMDPAR1,        \
+       },                                      \
+       {                                       \
+               .name = "DEPCMDPAR0("__stringify(n)")", \
+               .offset = DWC3_DEP_BASE(n) +    \
+                       DWC3_DEPCMDPAR0,        \
+       },                                      \
+       {                                       \
+               .name = "DEPCMD("__stringify(n)")",     \
+               .offset = DWC3_DEP_BASE(n) +    \
+                       DWC3_DEPCMD,            \
+       }
+
+
 static const struct debugfs_reg32 dwc3_regs[] = {
        dump_register(GSBUSCFG0),
        dump_register(GSBUSCFG1),
@@ -47,6 +70,7 @@ static const struct debugfs_reg32 dwc3_regs[] = {
        dump_register(GCTL),
        dump_register(GEVTEN),
        dump_register(GSTS),
+       dump_register(GUCTL1),
        dump_register(GSNPSID),
        dump_register(GGPIO),
        dump_register(GUID),
@@ -218,137 +242,38 @@ static const struct debugfs_reg32 dwc3_regs[] = {
        dump_register(DGCMD),
        dump_register(DALEPENA),
 
-       dump_register(DEPCMDPAR2(0)),
-       dump_register(DEPCMDPAR2(1)),
-       dump_register(DEPCMDPAR2(2)),
-       dump_register(DEPCMDPAR2(3)),
-       dump_register(DEPCMDPAR2(4)),
-       dump_register(DEPCMDPAR2(5)),
-       dump_register(DEPCMDPAR2(6)),
-       dump_register(DEPCMDPAR2(7)),
-       dump_register(DEPCMDPAR2(8)),
-       dump_register(DEPCMDPAR2(9)),
-       dump_register(DEPCMDPAR2(10)),
-       dump_register(DEPCMDPAR2(11)),
-       dump_register(DEPCMDPAR2(12)),
-       dump_register(DEPCMDPAR2(13)),
-       dump_register(DEPCMDPAR2(14)),
-       dump_register(DEPCMDPAR2(15)),
-       dump_register(DEPCMDPAR2(16)),
-       dump_register(DEPCMDPAR2(17)),
-       dump_register(DEPCMDPAR2(18)),
-       dump_register(DEPCMDPAR2(19)),
-       dump_register(DEPCMDPAR2(20)),
-       dump_register(DEPCMDPAR2(21)),
-       dump_register(DEPCMDPAR2(22)),
-       dump_register(DEPCMDPAR2(23)),
-       dump_register(DEPCMDPAR2(24)),
-       dump_register(DEPCMDPAR2(25)),
-       dump_register(DEPCMDPAR2(26)),
-       dump_register(DEPCMDPAR2(27)),
-       dump_register(DEPCMDPAR2(28)),
-       dump_register(DEPCMDPAR2(29)),
-       dump_register(DEPCMDPAR2(30)),
-       dump_register(DEPCMDPAR2(31)),
-
-       dump_register(DEPCMDPAR1(0)),
-       dump_register(DEPCMDPAR1(1)),
-       dump_register(DEPCMDPAR1(2)),
-       dump_register(DEPCMDPAR1(3)),
-       dump_register(DEPCMDPAR1(4)),
-       dump_register(DEPCMDPAR1(5)),
-       dump_register(DEPCMDPAR1(6)),
-       dump_register(DEPCMDPAR1(7)),
-       dump_register(DEPCMDPAR1(8)),
-       dump_register(DEPCMDPAR1(9)),
-       dump_register(DEPCMDPAR1(10)),
-       dump_register(DEPCMDPAR1(11)),
-       dump_register(DEPCMDPAR1(12)),
-       dump_register(DEPCMDPAR1(13)),
-       dump_register(DEPCMDPAR1(14)),
-       dump_register(DEPCMDPAR1(15)),
-       dump_register(DEPCMDPAR1(16)),
-       dump_register(DEPCMDPAR1(17)),
-       dump_register(DEPCMDPAR1(18)),
-       dump_register(DEPCMDPAR1(19)),
-       dump_register(DEPCMDPAR1(20)),
-       dump_register(DEPCMDPAR1(21)),
-       dump_register(DEPCMDPAR1(22)),
-       dump_register(DEPCMDPAR1(23)),
-       dump_register(DEPCMDPAR1(24)),
-       dump_register(DEPCMDPAR1(25)),
-       dump_register(DEPCMDPAR1(26)),
-       dump_register(DEPCMDPAR1(27)),
-       dump_register(DEPCMDPAR1(28)),
-       dump_register(DEPCMDPAR1(29)),
-       dump_register(DEPCMDPAR1(30)),
-       dump_register(DEPCMDPAR1(31)),
-
-       dump_register(DEPCMDPAR0(0)),
-       dump_register(DEPCMDPAR0(1)),
-       dump_register(DEPCMDPAR0(2)),
-       dump_register(DEPCMDPAR0(3)),
-       dump_register(DEPCMDPAR0(4)),
-       dump_register(DEPCMDPAR0(5)),
-       dump_register(DEPCMDPAR0(6)),
-       dump_register(DEPCMDPAR0(7)),
-       dump_register(DEPCMDPAR0(8)),
-       dump_register(DEPCMDPAR0(9)),
-       dump_register(DEPCMDPAR0(10)),
-       dump_register(DEPCMDPAR0(11)),
-       dump_register(DEPCMDPAR0(12)),
-       dump_register(DEPCMDPAR0(13)),
-       dump_register(DEPCMDPAR0(14)),
-       dump_register(DEPCMDPAR0(15)),
-       dump_register(DEPCMDPAR0(16)),
-       dump_register(DEPCMDPAR0(17)),
-       dump_register(DEPCMDPAR0(18)),
-       dump_register(DEPCMDPAR0(19)),
-       dump_register(DEPCMDPAR0(20)),
-       dump_register(DEPCMDPAR0(21)),
-       dump_register(DEPCMDPAR0(22)),
-       dump_register(DEPCMDPAR0(23)),
-       dump_register(DEPCMDPAR0(24)),
-       dump_register(DEPCMDPAR0(25)),
-       dump_register(DEPCMDPAR0(26)),
-       dump_register(DEPCMDPAR0(27)),
-       dump_register(DEPCMDPAR0(28)),
-       dump_register(DEPCMDPAR0(29)),
-       dump_register(DEPCMDPAR0(30)),
-       dump_register(DEPCMDPAR0(31)),
-
-       dump_register(DEPCMD(0)),
-       dump_register(DEPCMD(1)),
-       dump_register(DEPCMD(2)),
-       dump_register(DEPCMD(3)),
-       dump_register(DEPCMD(4)),
-       dump_register(DEPCMD(5)),
-       dump_register(DEPCMD(6)),
-       dump_register(DEPCMD(7)),
-       dump_register(DEPCMD(8)),
-       dump_register(DEPCMD(9)),
-       dump_register(DEPCMD(10)),
-       dump_register(DEPCMD(11)),
-       dump_register(DEPCMD(12)),
-       dump_register(DEPCMD(13)),
-       dump_register(DEPCMD(14)),
-       dump_register(DEPCMD(15)),
-       dump_register(DEPCMD(16)),
-       dump_register(DEPCMD(17)),
-       dump_register(DEPCMD(18)),
-       dump_register(DEPCMD(19)),
-       dump_register(DEPCMD(20)),
-       dump_register(DEPCMD(21)),
-       dump_register(DEPCMD(22)),
-       dump_register(DEPCMD(23)),
-       dump_register(DEPCMD(24)),
-       dump_register(DEPCMD(25)),
-       dump_register(DEPCMD(26)),
-       dump_register(DEPCMD(27)),
-       dump_register(DEPCMD(28)),
-       dump_register(DEPCMD(29)),
-       dump_register(DEPCMD(30)),
-       dump_register(DEPCMD(31)),
+       dump_ep_register_set(0),
+       dump_ep_register_set(1),
+       dump_ep_register_set(2),
+       dump_ep_register_set(3),
+       dump_ep_register_set(4),
+       dump_ep_register_set(5),
+       dump_ep_register_set(6),
+       dump_ep_register_set(7),
+       dump_ep_register_set(8),
+       dump_ep_register_set(9),
+       dump_ep_register_set(10),
+       dump_ep_register_set(11),
+       dump_ep_register_set(12),
+       dump_ep_register_set(13),
+       dump_ep_register_set(14),
+       dump_ep_register_set(15),
+       dump_ep_register_set(16),
+       dump_ep_register_set(17),
+       dump_ep_register_set(18),
+       dump_ep_register_set(19),
+       dump_ep_register_set(20),
+       dump_ep_register_set(21),
+       dump_ep_register_set(22),
+       dump_ep_register_set(23),
+       dump_ep_register_set(24),
+       dump_ep_register_set(25),
+       dump_ep_register_set(26),
+       dump_ep_register_set(27),
+       dump_ep_register_set(28),
+       dump_ep_register_set(29),
+       dump_ep_register_set(30),
+       dump_ep_register_set(31),
 
        dump_register(OCFG),
        dump_register(OCTL),
@@ -939,7 +864,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
 
        dwc->regset->regs = dwc3_regs;
        dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
-       dwc->regset->base = dwc->regs;
+       dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
 
        file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
        if (!file)
index af26449..29e80cc 100644 (file)
@@ -165,7 +165,7 @@ static void dwc3_omap_write_utmi_ctrl(struct dwc3_omap *omap, u32 value)
 
 static u32 dwc3_omap_read_irq0_status(struct dwc3_omap *omap)
 {
-       return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0 -
+       return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_RAW_0 -
                                                omap->irq0_offset);
 }
 
@@ -178,7 +178,7 @@ static void dwc3_omap_write_irq0_status(struct dwc3_omap *omap, u32 value)
 
 static u32 dwc3_omap_read_irqmisc_status(struct dwc3_omap *omap)
 {
-       return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_MISC +
+       return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_RAW_MISC +
                                                omap->irqmisc_offset);
 }
 
@@ -231,35 +231,30 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
                }
 
                val = dwc3_omap_read_utmi_ctrl(omap);
-               val &= ~(USBOTGSS_UTMI_OTG_CTRL_IDDIG
-                               | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
-                               | USBOTGSS_UTMI_OTG_CTRL_SESSEND);
-               val |= USBOTGSS_UTMI_OTG_CTRL_SESSVALID
-                               | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT;
+               val &= ~USBOTGSS_UTMI_OTG_CTRL_IDDIG;
                dwc3_omap_write_utmi_ctrl(omap, val);
                break;
 
        case OMAP_DWC3_VBUS_VALID:
                val = dwc3_omap_read_utmi_ctrl(omap);
                val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND;
-               val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG
-                               | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
-                               | USBOTGSS_UTMI_OTG_CTRL_SESSVALID
-                               | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT;
+               val |= USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
+                               | USBOTGSS_UTMI_OTG_CTRL_SESSVALID;
                dwc3_omap_write_utmi_ctrl(omap, val);
                break;
 
        case OMAP_DWC3_ID_FLOAT:
                if (omap->vbus_reg)
                        regulator_disable(omap->vbus_reg);
+               val = dwc3_omap_read_utmi_ctrl(omap);
+               val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG;
+               dwc3_omap_write_utmi_ctrl(omap, val);
 
        case OMAP_DWC3_VBUS_OFF:
                val = dwc3_omap_read_utmi_ctrl(omap);
                val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID
-                               | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
-                               | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT);
-               val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND
-                               | USBOTGSS_UTMI_OTG_CTRL_IDDIG;
+                               | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID);
+               val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND;
                dwc3_omap_write_utmi_ctrl(omap, val);
                break;
 
@@ -268,19 +263,38 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
        }
 }
 
+static void dwc3_omap_enable_irqs(struct dwc3_omap *omap);
+static void dwc3_omap_disable_irqs(struct dwc3_omap *omap);
+
 static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
+{
+       struct dwc3_omap        *omap = _omap;
+
+       if (dwc3_omap_read_irqmisc_status(omap) ||
+           dwc3_omap_read_irq0_status(omap)) {
+               /* mask irqs */
+               dwc3_omap_disable_irqs(omap);
+               return IRQ_WAKE_THREAD;
+       }
+
+       return IRQ_NONE;
+}
+
+static irqreturn_t dwc3_omap_interrupt_thread(int irq, void *_omap)
 {
        struct dwc3_omap        *omap = _omap;
        u32                     reg;
 
+       /* clear irq status flags */
        reg = dwc3_omap_read_irqmisc_status(omap);
-
        dwc3_omap_write_irqmisc_status(omap, reg);
 
        reg = dwc3_omap_read_irq0_status(omap);
-
        dwc3_omap_write_irq0_status(omap, reg);
 
+       /* unmask irqs */
+       dwc3_omap_enable_irqs(omap);
+
        return IRQ_HANDLED;
 }
 
@@ -497,8 +511,9 @@ static int dwc3_omap_probe(struct platform_device *pdev)
        /* check the DMA Status */
        reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
 
-       ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
-                       "dwc3-omap", omap);
+       ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt,
+                                       dwc3_omap_interrupt_thread, IRQF_SHARED,
+                                       "dwc3-omap", omap);
        if (ret) {
                dev_err(dev, "failed to request IRQ #%d --> %d\n",
                                omap->irq, ret);
index 14196cd..45f5a23 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
 #include <linux/gpio/consumer.h>
 #include <linux/acpi.h>
-
-#include "platform_data.h"
+#include <linux/delay.h>
 
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3                0xabcd
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI    0xabce
@@ -51,62 +51,70 @@ static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
 {
        if (pdev->vendor == PCI_VENDOR_ID_AMD &&
            pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
-               struct dwc3_platform_data pdata;
-
-               memset(&pdata, 0, sizeof(pdata));
-
-               pdata.has_lpm_erratum = true;
-               pdata.lpm_nyet_threshold = 0xf;
-
-               pdata.u2exit_lfps_quirk = true;
-               pdata.u2ss_inp3_quirk = true;
-               pdata.req_p1p2p3_quirk = true;
-               pdata.del_p1p2p3_quirk = true;
-               pdata.del_phy_power_chg_quirk = true;
-               pdata.lfps_filter_quirk = true;
-               pdata.rx_detect_poll_quirk = true;
-
-               pdata.tx_de_emphasis_quirk = true;
-               pdata.tx_de_emphasis = 1;
-
-               /*
-                * FIXME these quirks should be removed when AMD NL
-                * taps out
-                */
-               pdata.disable_scramble_quirk = true;
-               pdata.dis_u3_susphy_quirk = true;
-               pdata.dis_u2_susphy_quirk = true;
-
-               return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
+               struct property_entry properties[] = {
+                       PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+                       PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
+                       PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
+                       PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
+                       /*
+                        * FIXME these quirks should be removed when AMD NL
+                        * tapes out
+                        */
+                       PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
+                       PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+                       { },
+               };
+
+               return platform_device_add_properties(dwc3, properties);
        }
 
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
-           pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
-               struct gpio_desc *gpio;
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+               int ret;
 
-               acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
-                                         acpi_dwc3_byt_gpios);
+               struct property_entry properties[] = {
+                       PROPERTY_ENTRY_STRING("dr-mode", "peripheral"),
+                       { }
+               };
 
-               /*
-                * These GPIOs will turn on the USB2 PHY. Note that we have to
-                * put the gpio descriptors again here because the phy driver
-                * might want to grab them, too.
-                */
-               gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
-               if (IS_ERR(gpio))
-                       return PTR_ERR(gpio);
+               ret = platform_device_add_properties(dwc3, properties);
+               if (ret < 0)
+                       return ret;
 
-               gpiod_set_value_cansleep(gpio, 1);
-               gpiod_put(gpio);
+               if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
+                       struct gpio_desc *gpio;
 
-               gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
-               if (IS_ERR(gpio))
-                       return PTR_ERR(gpio);
+                       acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
+                                       acpi_dwc3_byt_gpios);
+
+                       /*
+                        * These GPIOs will turn on the USB2 PHY. Note that we have to
+                        * put the gpio descriptors again here because the phy driver
+                        * might want to grab them, too.
+                        */
+                       gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
+                       if (IS_ERR(gpio))
+                               return PTR_ERR(gpio);
 
-               if (gpio) {
                        gpiod_set_value_cansleep(gpio, 1);
                        gpiod_put(gpio);
-                       usleep_range(10000, 11000);
+
+                       gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+                       if (IS_ERR(gpio))
+                               return PTR_ERR(gpio);
+
+                       if (gpio) {
+                               gpiod_set_value_cansleep(gpio, 1);
+                               gpiod_put(gpio);
+                               usleep_range(10000, 11000);
+                       }
                }
        }
 
@@ -114,15 +122,14 @@ static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
            (pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
             pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
             pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {
-
-               struct dwc3_platform_data pdata;
-
-               memset(&pdata, 0, sizeof(pdata));
-               pdata.usb3_lpm_capable = true;
-               pdata.has_lpm_erratum = true;
-               pdata.dis_enblslpm_quirk = true;
-
-               return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
+               struct property_entry properties[] = {
+                       PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
+                       PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+                       PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
+                       { },
+               };
+
+               return platform_device_add_properties(dwc3, properties);
        }
 
        return 0;
@@ -180,7 +187,11 @@ static int dwc3_pci_probe(struct pci_dev *pci,
                goto err;
        }
 
+       device_init_wakeup(dev, true);
+       device_set_run_wake(dev, true);
        pci_set_drvdata(pci, dwc3);
+       pm_runtime_put(dev);
+
        return 0;
 err:
        platform_device_put(dwc3);
@@ -189,6 +200,8 @@ err:
 
 static void dwc3_pci_remove(struct pci_dev *pci)
 {
+       device_init_wakeup(&pci->dev, false);
+       pm_runtime_get(&pci->dev);
        acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pci->dev));
        platform_device_unregister(pci_get_drvdata(pci));
 }
@@ -219,11 +232,43 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
 };
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 
+#ifdef CONFIG_PM
+static int dwc3_pci_runtime_suspend(struct device *dev)
+{
+       if (device_run_wake(dev))
+               return 0;
+
+       return -EBUSY;
+}
+
+static int dwc3_pci_pm_dummy(struct device *dev)
+{
+       /*
+        * There's nothing to do here. No, seriously. Everything is either taken
+        * care either by PCI subsystem or dwc3/core.c, so we have nothing
+        * missing here.
+        *
+        * So you'd think we didn't need this at all, but PCI subsystem will
+        * bail out if we don't have a valid callback :-s
+        */
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct dev_pm_ops dwc3_pci_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_pm_dummy, dwc3_pci_pm_dummy)
+       SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_pm_dummy,
+               NULL)
+};
+
 static struct pci_driver dwc3_pci_driver = {
        .name           = "dwc3-pci",
        .id_table       = dwc3_pci_id_table,
        .probe          = dwc3_pci_probe,
        .remove         = dwc3_pci_remove,
+       .driver         = {
+               .pm     = &dwc3_pci_dev_pm_ops,
+       }
 };
 
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
index 51b52a7..fe79d77 100644 (file)
@@ -98,8 +98,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
 
        trace_dwc3_prepare_trb(dep, trb);
 
-       ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
-                       DWC3_DEPCMD_STARTTRANSFER, &params);
+       ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, &params);
        if (ret < 0) {
                dwc3_trace(trace_dwc3_ep0, "%s STARTTRANSFER failed",
                                dep->name);
@@ -107,9 +106,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
        }
 
        dep->flags |= DWC3_EP_BUSY;
-       dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
-                       dep->number);
-
+       dep->resource_index = dwc3_gadget_ep_get_transfer_index(dep);
        dwc->ep0_next_event = DWC3_EP0_COMPLETE;
 
        return 0;
@@ -499,7 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        case USB_RECIP_ENDPOINT:
                switch (wValue) {
                case USB_ENDPOINT_HALT:
-                       dep = dwc3_wIndex_to_dep(dwc, wIndex);
+                       dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
                        if (!dep)
                                return -EINVAL;
                        if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
@@ -622,8 +619,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
        struct timing {
                u8      u1sel;
                u8      u1pel;
-               u16     u2sel;
-               u16     u2pel;
+               __le16  u2sel;
+               __le16  u2pel;
        } __packed timing;
 
        int             ret;
@@ -980,7 +977,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
                ret = usb_gadget_map_request(&dwc->gadget, &req->request,
                                dep->number);
                if (ret) {
-                       dwc3_trace(trace_dwc3_ep0, "failed to map request\n");
+                       dwc3_trace(trace_dwc3_ep0, "failed to map request");
                        return;
                }
 
@@ -1008,7 +1005,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
                ret = usb_gadget_map_request(&dwc->gadget, &req->request,
                                dep->number);
                if (ret) {
-                       dwc3_trace(trace_dwc3_ep0, "failed to map request\n");
+                       dwc3_trace(trace_dwc3_ep0, "failed to map request");
                        return;
                }
 
@@ -1058,7 +1055,7 @@ static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep)
        cmd |= DWC3_DEPCMD_CMDIOC;
        cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
        memset(&params, 0, sizeof(params));
-       ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+       ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
        WARN_ON_ONCE(ret);
        dep->resource_index = 0;
 }
@@ -1112,11 +1109,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event)
 {
-       u8                      epnum = event->endpoint_number;
-
-       dwc3_trace(trace_dwc3_ep0, "%s while ep%d%s in state '%s'",
-                       dwc3_ep_event_string(event->endpoint_event),
-                       epnum >> 1, (epnum & 1) ? "in" : "out",
+       dwc3_trace(trace_dwc3_ep0, "%s: state '%s'",
+                       dwc3_ep_event_string(event),
                        dwc3_ep0_state_string(dwc->ep0state));
 
        switch (event->endpoint_event) {
index 07248ff..8f8c215 100644 (file)
@@ -145,21 +145,29 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
        return -ETIMEDOUT;
 }
 
-static void dwc3_ep_inc_enq(struct dwc3_ep *dep)
+/**
+ * dwc3_ep_inc_trb() - Increment a TRB index.
+ * @index - Pointer to the TRB index to increment.
+ *
+ * The index should never point to the link TRB. After incrementing,
+ * if it is point to the link TRB, wrap around to the beginning. The
+ * link TRB is always at the last TRB entry.
+ */
+static void dwc3_ep_inc_trb(u8 *index)
 {
-       dep->trb_enqueue++;
-       dep->trb_enqueue %= DWC3_TRB_NUM;
+       (*index)++;
+       if (*index == (DWC3_TRB_NUM - 1))
+               *index = 0;
 }
 
-static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
+static void dwc3_ep_inc_enq(struct dwc3_ep *dep)
 {
-       dep->trb_dequeue++;
-       dep->trb_dequeue %= DWC3_TRB_NUM;
+       dwc3_ep_inc_trb(&dep->trb_enqueue);
 }
 
-static int dwc3_ep_is_last_trb(unsigned int index)
+static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
 {
-       return index == DWC3_TRB_NUM - 1;
+       dwc3_ep_inc_trb(&dep->trb_dequeue);
 }
 
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
@@ -172,13 +180,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                i = 0;
                do {
                        dwc3_ep_inc_deq(dep);
-                       /*
-                        * Skip LINK TRB. We can't use req->trb and check for
-                        * DWC3_TRBCTL_LINK_TRB because it points the TRB we
-                        * just completed (not the LINK TRB).
-                        */
-                       if (dwc3_ep_is_last_trb(dep->trb_dequeue))
-                               dwc3_ep_inc_deq(dep);
                } while(++i < req->request.num_mapped_sgs);
                req->started = false;
        }
@@ -199,57 +200,54 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
        spin_unlock(&dwc->lock);
        usb_gadget_giveback_request(&dep->endpoint, &req->request);
        spin_lock(&dwc->lock);
+
+       if (dep->number > 1)
+               pm_runtime_put(dwc->dev);
 }
 
 int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
 {
        u32             timeout = 500;
+       int             status = 0;
+       int             ret = 0;
        u32             reg;
 
-       trace_dwc3_gadget_generic_cmd(cmd, param);
-
        dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
        dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
 
        do {
                reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
                if (!(reg & DWC3_DGCMD_CMDACT)) {
-                       dwc3_trace(trace_dwc3_gadget,
-                                       "Command Complete --> %d",
-                                       DWC3_DGCMD_STATUS(reg));
-                       if (DWC3_DGCMD_STATUS(reg))
-                               return -EINVAL;
-                       return 0;
+                       status = DWC3_DGCMD_STATUS(reg);
+                       if (status)
+                               ret = -EINVAL;
+                       break;
                }
+       } while (timeout--);
 
-               /*
-                * We can't sleep here, because it's also called from
-                * interrupt context.
-                */
-               timeout--;
-               if (!timeout) {
-                       dwc3_trace(trace_dwc3_gadget,
-                                       "Command Timed Out");
-                       return -ETIMEDOUT;
-               }
-               udelay(1);
-       } while (1);
+       if (!timeout) {
+               ret = -ETIMEDOUT;
+               status = -ETIMEDOUT;
+       }
+
+       trace_dwc3_gadget_generic_cmd(cmd, param, status);
+
+       return ret;
 }
 
 static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
 
-int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
-               unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
+               struct dwc3_gadget_ep_cmd_params *params)
 {
-       struct dwc3_ep          *dep = dwc->eps[ep];
+       struct dwc3             *dwc = dep->dwc;
        u32                     timeout = 500;
        u32                     reg;
 
+       int                     cmd_status = 0;
        int                     susphy = false;
        int                     ret = -EINVAL;
 
-       trace_dwc3_gadget_ep_cmd(dep, cmd, params);
-
        /*
         * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if
         * we're issuing an endpoint command, we must check if
@@ -258,11 +256,13 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
         * We will also set SUSPHY bit to what it was before returning as stated
         * by the same section on Synopsys databook.
         */
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
-       if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
-               susphy = true;
-               reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
-               dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+       if (dwc->gadget.speed <= USB_SPEED_HIGH) {
+               reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+               if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
+                       susphy = true;
+                       reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+                       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+               }
        }
 
        if (cmd == DWC3_DEPCMD_STARTTRANSFER) {
@@ -279,26 +279,21 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
                }
        }
 
-       dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
-       dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
-       dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
+       dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0);
+       dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1);
+       dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2);
 
-       dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT);
+       dwc3_writel(dep->regs, DWC3_DEPCMD, cmd | DWC3_DEPCMD_CMDACT);
        do {
-               reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
+               reg = dwc3_readl(dep->regs, DWC3_DEPCMD);
                if (!(reg & DWC3_DEPCMD_CMDACT)) {
-                       int cmd_status = DWC3_DEPCMD_STATUS(reg);
-
-                       dwc3_trace(trace_dwc3_gadget,
-                                       "Command Complete --> %d",
-                                       cmd_status);
+                       cmd_status = DWC3_DEPCMD_STATUS(reg);
 
                        switch (cmd_status) {
                        case 0:
                                ret = 0;
                                break;
                        case DEPEVT_TRANSFER_NO_RESOURCE:
-                               dwc3_trace(trace_dwc3_gadget, "%s: no resource available");
                                ret = -EINVAL;
                                break;
                        case DEPEVT_TRANSFER_BUS_EXPIRY:
@@ -313,7 +308,6 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
                                 * give a hint to the gadget driver that this is
                                 * the case by returning -EAGAIN.
                                 */
-                               dwc3_trace(trace_dwc3_gadget, "%s: bus expiry");
                                ret = -EAGAIN;
                                break;
                        default:
@@ -322,21 +316,14 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 
                        break;
                }
+       } while (--timeout);
 
-               /*
-                * We can't sleep here, because it is also called from
-                * interrupt context.
-                */
-               timeout--;
-               if (!timeout) {
-                       dwc3_trace(trace_dwc3_gadget,
-                                       "Command Timed Out");
-                       ret = -ETIMEDOUT;
-                       break;
-               }
+       if (timeout == 0) {
+               ret = -ETIMEDOUT;
+               cmd_status = -ETIMEDOUT;
+       }
 
-               udelay(1);
-       } while (1);
+       trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status);
 
        if (unlikely(susphy)) {
                reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
@@ -366,7 +353,7 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep)
 
        memset(&params, 0, sizeof(params));
 
-       return dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+       return dwc3_send_gadget_ep_cmd(dep, cmd, &params);
 }
 
 static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
@@ -454,7 +441,7 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
        memset(&params, 0x00, sizeof(params));
        cmd = DWC3_DEPCMD_DEPSTARTCFG;
 
-       ret = dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+       ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
        if (ret)
                return ret;
 
@@ -475,10 +462,14 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
 static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
                const struct usb_endpoint_descriptor *desc,
                const struct usb_ss_ep_comp_descriptor *comp_desc,
-               bool ignore, bool restore)
+               bool modify, bool restore)
 {
        struct dwc3_gadget_ep_cmd_params params;
 
+       if (dev_WARN_ONCE(dwc->dev, modify && restore,
+                                       "Can't modify and restore\n"))
+               return -EINVAL;
+
        memset(&params, 0x00, sizeof(params));
 
        params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
@@ -487,30 +478,22 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
        /* Burst size is only needed in SuperSpeed mode */
        if (dwc->gadget.speed >= USB_SPEED_SUPER) {
                u32 burst = dep->endpoint.maxburst;
-               u32 nump;
-               u32 reg;
-
-               /* update NumP */
-               reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-               nump = DWC3_DCFG_NUMP(reg);
-               nump = max(nump, burst);
-               reg &= ~DWC3_DCFG_NUMP_MASK;
-               reg |= nump << DWC3_DCFG_NUMP_SHIFT;
-               dwc3_writel(dwc->regs, DWC3_DCFG, reg);
-
                params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1);
        }
 
-       if (ignore)
-               params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
-
-       if (restore) {
+       if (modify) {
+               params.param0 |= DWC3_DEPCFG_ACTION_MODIFY;
+       } else if (restore) {
                params.param0 |= DWC3_DEPCFG_ACTION_RESTORE;
                params.param2 |= dep->saved_state;
+       } else {
+               params.param0 |= DWC3_DEPCFG_ACTION_INIT;
        }
 
-       params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
-               | DWC3_DEPCFG_XFER_NOT_READY_EN;
+       params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN;
+
+       if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc))
+               params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN;
 
        if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
                params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
@@ -541,8 +524,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
                dep->interval = 1 << (desc->bInterval - 1);
        }
 
-       return dwc3_send_gadget_ep_cmd(dwc, dep->number,
-                       DWC3_DEPCMD_SETEPCONFIG, &params);
+       return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, &params);
 }
 
 static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
@@ -553,8 +535,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
 
        params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
 
-       return dwc3_send_gadget_ep_cmd(dwc, dep->number,
-                       DWC3_DEPCMD_SETTRANSFRESOURCE, &params);
+       return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE,
+                       &params);
 }
 
 /**
@@ -567,7 +549,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
 static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                const struct usb_endpoint_descriptor *desc,
                const struct usb_ss_ep_comp_descriptor *comp_desc,
-               bool ignore, bool restore)
+               bool modify, bool restore)
 {
        struct dwc3             *dwc = dep->dwc;
        u32                     reg;
@@ -581,7 +563,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                        return ret;
        }
 
-       ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore,
+       ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, modify,
                        restore);
        if (ret)
                return ret;
@@ -600,38 +582,24 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
 
                if (usb_endpoint_xfer_control(desc))
-                       goto out;
+                       return 0;
+
+               /* Initialize the TRB ring */
+               dep->trb_dequeue = 0;
+               dep->trb_enqueue = 0;
+               memset(dep->trb_pool, 0,
+                      sizeof(struct dwc3_trb) * DWC3_TRB_NUM);
 
                /* Link TRB. The HWO bit is never reset */
                trb_st_hw = &dep->trb_pool[0];
 
                trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
-               memset(trb_link, 0, sizeof(*trb_link));
-
                trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
                trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
                trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
                trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
        }
 
-out:
-       switch (usb_endpoint_type(desc)) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               /* don't change name */
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               strlcat(dep->name, "-isoc", sizeof(dep->name));
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               strlcat(dep->name, "-bulk", sizeof(dep->name));
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               strlcat(dep->name, "-int", sizeof(dep->name));
-               break;
-       default:
-               dev_err(dwc->dev, "invalid endpoint transfer type\n");
-       }
-
        return 0;
 }
 
@@ -640,15 +608,13 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
        struct dwc3_request             *req;
 
-       if (!list_empty(&dep->started_list)) {
-               dwc3_stop_active_transfer(dwc, dep->number, true);
+       dwc3_stop_active_transfer(dwc, dep->number, true);
 
-               /* - giveback all requests to gadget driver */
-               while (!list_empty(&dep->started_list)) {
-                       req = next_request(&dep->started_list);
+       /* - giveback all requests to gadget driver */
+       while (!list_empty(&dep->started_list)) {
+               req = next_request(&dep->started_list);
 
-                       dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
-               }
+               dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
        }
 
        while (!list_empty(&dep->pending_list)) {
@@ -689,10 +655,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
        dep->type = 0;
        dep->flags = 0;
 
-       snprintf(dep->name, sizeof(dep->name), "ep%d%s",
-                       dep->number >> 1,
-                       (dep->number & 1) ? "in" : "out");
-
        return 0;
 }
 
@@ -784,6 +746,8 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
        req->epnum      = dep->number;
        req->dep        = dep;
 
+       dep->allocated_requests++;
+
        trace_dwc3_alloc_request(req);
 
        return &req->request;
@@ -793,7 +757,9 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
                struct usb_request *request)
 {
        struct dwc3_request             *req = to_dwc3_request(request);
+       struct dwc3_ep                  *dep = to_dwc3_ep(ep);
 
+       dep->allocated_requests--;
        trace_dwc3_free_request(req);
        kfree(req);
 }
@@ -825,9 +791,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
        }
 
        dwc3_ep_inc_enq(dep);
-       /* Skip the LINK-TRB */
-       if (dwc3_ep_is_last_trb(dep->trb_enqueue))
-               dwc3_ep_inc_enq(dep);
 
        trb->size = DWC3_TRB_SIZE_LENGTH(length);
        trb->bpl = lower_32_bits(dma);
@@ -877,137 +840,169 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 
        trb->ctrl |= DWC3_TRB_CTRL_HWO;
 
+       dep->queued_requests++;
+
        trace_dwc3_prepare_trb(dep, trb);
 }
 
-/*
- * dwc3_prepare_trbs - setup TRBs from requests
- * @dep: endpoint for which requests are being prepared
- * @starting: true if the endpoint is idle and no requests are queued.
+/**
+ * dwc3_ep_prev_trb() - Returns the previous TRB in the ring
+ * @dep: The endpoint with the TRB ring
+ * @index: The index of the current TRB in the ring
  *
- * The function goes through the requests list and sets up TRBs for the
- * transfers. The function returns once there are no more TRBs available or
- * it runs out of requests.
+ * Returns the TRB prior to the one pointed to by the index. If the
+ * index is 0, we will wrap backwards, skip the link TRB, and return
+ * the one just before that.
  */
-static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
+static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index)
 {
-       struct dwc3_request     *req, *n;
-       u32                     trbs_left;
-       unsigned int            last_one = 0;
+       if (!index)
+               index = DWC3_TRB_NUM - 2;
+       else
+               index = dep->trb_enqueue - 1;
 
-       BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+       return &dep->trb_pool[index];
+}
 
-       trbs_left = dep->trb_dequeue - dep->trb_enqueue;
+static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
+{
+       struct dwc3_trb         *tmp;
+       u8                      trbs_left;
 
        /*
-        * If enqueue & dequeue are equal than it is either full or empty. If we
-        * are starting to process requests then we are empty. Otherwise we are
-        * full and don't do anything
+        * If enqueue & dequeue are equal than it is either full or empty.
+        *
+        * One way to know for sure is if the TRB right before us has HWO bit
+        * set or not. If it has, then we're definitely full and can't fit any
+        * more transfers in our ring.
         */
-       if (!trbs_left) {
-               if (!starting)
-                       return;
+       if (dep->trb_enqueue == dep->trb_dequeue) {
+               tmp = dwc3_ep_prev_trb(dep, dep->trb_enqueue);
+               if (tmp->ctrl & DWC3_TRB_CTRL_HWO)
+                       return 0;
 
-               trbs_left = DWC3_TRB_NUM;
+               return DWC3_TRB_NUM - 1;
        }
 
-       /* The last TRB is a link TRB, not used for xfer */
-       if (trbs_left <= 1)
-               return;
+       trbs_left = dep->trb_dequeue - dep->trb_enqueue;
+       trbs_left &= (DWC3_TRB_NUM - 1);
 
-       list_for_each_entry_safe(req, n, &dep->pending_list, list) {
-               unsigned        length;
-               dma_addr_t      dma;
-               last_one = false;
-
-               if (req->request.num_mapped_sgs > 0) {
-                       struct usb_request *request = &req->request;
-                       struct scatterlist *sg = request->sg;
-                       struct scatterlist *s;
-                       int             i;
-
-                       for_each_sg(sg, s, request->num_mapped_sgs, i) {
-                               unsigned chain = true;
-
-                               length = sg_dma_len(s);
-                               dma = sg_dma_address(s);
-
-                               if (i == (request->num_mapped_sgs - 1) ||
-                                               sg_is_last(s)) {
-                                       if (list_empty(&dep->pending_list))
-                                               last_one = true;
-                                       chain = false;
-                               }
+       if (dep->trb_dequeue < dep->trb_enqueue)
+               trbs_left--;
 
-                               trbs_left--;
-                               if (!trbs_left)
-                                       last_one = true;
+       return trbs_left;
+}
 
-                               if (last_one)
-                                       chain = false;
+static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
+               struct dwc3_request *req, unsigned int trbs_left,
+               unsigned int more_coming)
+{
+       struct usb_request *request = &req->request;
+       struct scatterlist *sg = request->sg;
+       struct scatterlist *s;
+       unsigned int    last = false;
+       unsigned int    length;
+       dma_addr_t      dma;
+       int             i;
 
-                               dwc3_prepare_one_trb(dep, req, dma, length,
-                                               last_one, chain, i);
+       for_each_sg(sg, s, request->num_mapped_sgs, i) {
+               unsigned chain = true;
 
-                               if (last_one)
-                                       break;
-                       }
+               length = sg_dma_len(s);
+               dma = sg_dma_address(s);
 
-                       if (last_one)
-                               break;
-               } else {
-                       dma = req->request.dma;
-                       length = req->request.length;
-                       trbs_left--;
+               if (sg_is_last(s)) {
+                       if (usb_endpoint_xfer_int(dep->endpoint.desc) ||
+                               !more_coming)
+                               last = true;
 
-                       if (!trbs_left)
-                               last_one = 1;
+                       chain = false;
+               }
 
-                       /* Is this the last request? */
-                       if (list_is_last(&req->list, &dep->pending_list))
-                               last_one = 1;
+               if (!trbs_left--)
+                       last = true;
 
-                       dwc3_prepare_one_trb(dep, req, dma, length,
-                                       last_one, false, 0);
+               if (last)
+                       chain = false;
 
-                       if (last_one)
-                               break;
-               }
+               dwc3_prepare_one_trb(dep, req, dma, length,
+                               last, chain, i);
+
+               if (last)
+                       break;
        }
 }
 
-static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
-               int start_new)
+static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
+               struct dwc3_request *req, unsigned int trbs_left,
+               unsigned int more_coming)
+{
+       unsigned int    last = false;
+       unsigned int    length;
+       dma_addr_t      dma;
+
+       dma = req->request.dma;
+       length = req->request.length;
+
+       if (!trbs_left)
+               last = true;
+
+       /* Is this the last request? */
+       if (usb_endpoint_xfer_int(dep->endpoint.desc) || !more_coming)
+               last = true;
+
+       dwc3_prepare_one_trb(dep, req, dma, length,
+                       last, false, 0);
+}
+
+/*
+ * dwc3_prepare_trbs - setup TRBs from requests
+ * @dep: endpoint for which requests are being prepared
+ *
+ * The function goes through the requests list and sets up TRBs for the
+ * transfers. The function returns once there are no more TRBs available or
+ * it runs out of requests.
+ */
+static void dwc3_prepare_trbs(struct dwc3_ep *dep)
+{
+       struct dwc3_request     *req, *n;
+       unsigned int            more_coming;
+       u32                     trbs_left;
+
+       BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+
+       trbs_left = dwc3_calc_trbs_left(dep);
+       if (!trbs_left)
+               return;
+
+       more_coming = dep->allocated_requests - dep->queued_requests;
+
+       list_for_each_entry_safe(req, n, &dep->pending_list, list) {
+               if (req->request.num_mapped_sgs > 0)
+                       dwc3_prepare_one_trb_sg(dep, req, trbs_left--,
+                                       more_coming);
+               else
+                       dwc3_prepare_one_trb_linear(dep, req, trbs_left--,
+                                       more_coming);
+
+               if (!trbs_left)
+                       return;
+       }
+}
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
 {
        struct dwc3_gadget_ep_cmd_params params;
        struct dwc3_request             *req;
        struct dwc3                     *dwc = dep->dwc;
+       int                             starting;
        int                             ret;
        u32                             cmd;
 
-       if (start_new && (dep->flags & DWC3_EP_BUSY)) {
-               dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
-               return -EBUSY;
-       }
-
-       /*
-        * If we are getting here after a short-out-packet we don't enqueue any
-        * new requests as we try to set the IOC bit only on the last request.
-        */
-       if (start_new) {
-               if (list_empty(&dep->started_list))
-                       dwc3_prepare_trbs(dep, start_new);
-
-               /* req points to the first request which will be sent */
-               req = next_request(&dep->started_list);
-       } else {
-               dwc3_prepare_trbs(dep, start_new);
+       starting = !(dep->flags & DWC3_EP_BUSY);
 
-               /*
-                * req points to the first request where HWO changed from 0 to 1
-                */
-               req = next_request(&dep->started_list);
-       }
+       dwc3_prepare_trbs(dep);
+       req = next_request(&dep->started_list);
        if (!req) {
                dep->flags |= DWC3_EP_PENDING_REQUEST;
                return 0;
@@ -1015,16 +1010,17 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
 
        memset(&params, 0, sizeof(params));
 
-       if (start_new) {
+       if (starting) {
                params.param0 = upper_32_bits(req->trb_dma);
                params.param1 = lower_32_bits(req->trb_dma);
-               cmd = DWC3_DEPCMD_STARTTRANSFER;
+               cmd = DWC3_DEPCMD_STARTTRANSFER |
+                       DWC3_DEPCMD_PARAM(cmd_param);
        } else {
-               cmd = DWC3_DEPCMD_UPDATETRANSFER;
+               cmd = DWC3_DEPCMD_UPDATETRANSFER |
+                       DWC3_DEPCMD_PARAM(dep->resource_index);
        }
 
-       cmd |= DWC3_DEPCMD_PARAM(cmd_param);
-       ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+       ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
        if (ret < 0) {
                /*
                 * FIXME we need to iterate over the list of requests
@@ -1039,9 +1035,8 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
 
        dep->flags |= DWC3_EP_BUSY;
 
-       if (start_new) {
-               dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
-                               dep->number);
+       if (starting) {
+               dep->resource_index = dwc3_gadget_ep_get_transfer_index(dep);
                WARN_ON_ONCE(!dep->resource_index);
        }
 
@@ -1064,7 +1059,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
        /* 4 micro frames in the future */
        uf = cur_uf + dep->interval * 4;
 
-       __dwc3_gadget_kick_transfer(dep, uf, 1);
+       __dwc3_gadget_kick_transfer(dep, uf);
 }
 
 static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
@@ -1085,18 +1080,20 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 
        if (!dep->endpoint.desc) {
                dwc3_trace(trace_dwc3_gadget,
-                               "trying to queue request %p to disabled %s\n",
+                               "trying to queue request %p to disabled %s",
                                &req->request, dep->endpoint.name);
                return -ESHUTDOWN;
        }
 
        if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
                                &req->request, req->dep->name)) {
-               dwc3_trace(trace_dwc3_gadget, "request %p belongs to '%s'\n",
+               dwc3_trace(trace_dwc3_gadget, "request %p belongs to '%s'",
                                &req->request, req->dep->name);
                return -EINVAL;
        }
 
+       pm_runtime_get(dwc->dev);
+
        req->request.actual     = 0;
        req->request.status     = -EINPROGRESS;
        req->direction          = dep->direction;
@@ -1131,9 +1128,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
         * little bit faster.
         */
        if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-                       !usb_endpoint_xfer_int(dep->endpoint.desc) &&
-                       !(dep->flags & DWC3_EP_BUSY)) {
-               ret = __dwc3_gadget_kick_transfer(dep, 0, true);
+                       !usb_endpoint_xfer_int(dep->endpoint.desc)) {
+               ret = __dwc3_gadget_kick_transfer(dep, 0);
                goto out;
        }
 
@@ -1163,7 +1159,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
                        return 0;
                }
 
-               ret = __dwc3_gadget_kick_transfer(dep, 0, true);
+               ret = __dwc3_gadget_kick_transfer(dep, 0);
                if (!ret)
                        dep->flags &= ~DWC3_EP_PENDING_REQUEST;
 
@@ -1179,8 +1175,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
                        (dep->flags & DWC3_EP_BUSY) &&
                        !(dep->flags & DWC3_EP_MISSED_ISOC)) {
                WARN_ON_ONCE(!dep->resource_index);
-               ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
-                               false);
+               ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index);
                goto out;
        }
 
@@ -1190,12 +1185,12 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
         * handled.
         */
        if (dep->stream_capable)
-               ret = __dwc3_gadget_kick_transfer(dep, 0, true);
+               ret = __dwc3_gadget_kick_transfer(dep, 0);
 
 out:
        if (ret && ret != -EBUSY)
                dwc3_trace(trace_dwc3_gadget,
-                               "%s: failed to kick transfers\n",
+                               "%s: failed to kick transfers",
                                dep->name);
        if (ret == -EBUSY)
                ret = 0;
@@ -1215,7 +1210,7 @@ static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep)
        struct usb_request              *request;
        struct usb_ep                   *ep = &dep->endpoint;
 
-       dwc3_trace(trace_dwc3_gadget, "queueing ZLP\n");
+       dwc3_trace(trace_dwc3_gadget, "queueing ZLP");
        request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC);
        if (!request)
                return -ENOMEM;
@@ -1319,23 +1314,36 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
        memset(&params, 0x00, sizeof(params));
 
        if (value) {
-               if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
-                               (!list_empty(&dep->started_list) ||
-                                !list_empty(&dep->pending_list)))) {
+               struct dwc3_trb *trb;
+
+               unsigned transfer_in_flight;
+               unsigned started;
+
+               if (dep->number > 1)
+                       trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue);
+               else
+                       trb = &dwc->ep0_trb[dep->trb_enqueue];
+
+               transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO;
+               started = !list_empty(&dep->started_list);
+
+               if (!protocol && ((dep->direction && transfer_in_flight) ||
+                               (!dep->direction && started))) {
                        dwc3_trace(trace_dwc3_gadget,
                                        "%s: pending request, cannot halt",
                                        dep->name);
                        return -EAGAIN;
                }
 
-               ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
-                       DWC3_DEPCMD_SETSTALL, &params);
+               ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETSTALL,
+                               &params);
                if (ret)
                        dev_err(dwc->dev, "failed to set STALL on %s\n",
                                        dep->name);
                else
                        dep->flags |= DWC3_EP_STALL;
        } else {
+
                ret = dwc3_send_clear_stall_ep_cmd(dep);
                if (ret)
                        dev_err(dwc->dev, "failed to clear STALL on %s\n",
@@ -1444,8 +1452,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
        speed = reg & DWC3_DSTS_CONNECTSPD;
        if ((speed == DWC3_DSTS_SUPERSPEED) ||
            (speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
-               dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n");
-               return -EINVAL;
+               dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed");
+               return 0;
        }
 
        link_state = DWC3_DSTS_USBLNKST(reg);
@@ -1456,7 +1464,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
                break;
        default:
                dwc3_trace(trace_dwc3_gadget,
-                               "can't wakeup from '%s'\n",
+                               "can't wakeup from '%s'",
                                dwc3_gadget_link_string(link_state));
                return -EINVAL;
        }
@@ -1525,6 +1533,9 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
        u32                     reg;
        u32                     timeout = 500;
 
+       if (pm_runtime_suspended(dwc->dev))
+               return 0;
+
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        if (is_on) {
                if (dwc->revision <= DWC3_REVISION_187A) {
@@ -1553,18 +1564,11 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 
        do {
                reg = dwc3_readl(dwc->regs, DWC3_DSTS);
-               if (is_on) {
-                       if (!(reg & DWC3_DSTS_DEVCTRLHLT))
-                               break;
-               } else {
-                       if (reg & DWC3_DSTS_DEVCTRLHLT)
-                               break;
-               }
-               timeout--;
-               if (!timeout)
-                       return -ETIMEDOUT;
-               udelay(1);
-       } while (1);
+               reg &= DWC3_DSTS_DEVCTRLHLT;
+       } while (--timeout && !(!is_on ^ !reg));
+
+       if (!timeout)
+               return -ETIMEDOUT;
 
        dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
                        dwc->gadget_driver
@@ -1616,36 +1620,52 @@ static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
 static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
 static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
 
-static int dwc3_gadget_start(struct usb_gadget *g,
-               struct usb_gadget_driver *driver)
+/**
+ * dwc3_gadget_setup_nump - Calculate and initialize NUMP field of DCFG
+ * dwc: pointer to our context structure
+ *
+ * The following looks like complex but it's actually very simple. In order to
+ * calculate the number of packets we can burst at once on OUT transfers, we're
+ * gonna use RxFIFO size.
+ *
+ * To calculate RxFIFO size we need two numbers:
+ * MDWIDTH = size, in bits, of the internal memory bus
+ * RAM2_DEPTH = depth, in MDWIDTH, of internal RAM2 (where RxFIFO sits)
+ *
+ * Given these two numbers, the formula is simple:
+ *
+ * RxFIFO Size = (RAM2_DEPTH * MDWIDTH / 8) - 24 - 16;
+ *
+ * 24 bytes is for 3x SETUP packets
+ * 16 bytes is a clock domain crossing tolerance
+ *
+ * Given RxFIFO Size, NUMP = RxFIFOSize / 1024;
+ */
+static void dwc3_gadget_setup_nump(struct dwc3 *dwc)
 {
-       struct dwc3             *dwc = gadget_to_dwc(g);
-       struct dwc3_ep          *dep;
-       unsigned long           flags;
-       int                     ret = 0;
-       int                     irq;
-       u32                     reg;
+       u32 ram2_depth;
+       u32 mdwidth;
+       u32 nump;
+       u32 reg;
 
-       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-       ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
-                       IRQF_SHARED, "dwc3", dwc->ev_buf);
-       if (ret) {
-               dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
-                               irq, ret);
-               goto err0;
-       }
+       ram2_depth = DWC3_GHWPARAMS7_RAM2_DEPTH(dwc->hwparams.hwparams7);
+       mdwidth = DWC3_GHWPARAMS0_MDWIDTH(dwc->hwparams.hwparams0);
 
-       spin_lock_irqsave(&dwc->lock, flags);
+       nump = ((ram2_depth * mdwidth / 8) - 24 - 16) / 1024;
+       nump = min_t(u32, nump, 16);
 
-       if (dwc->gadget_driver) {
-               dev_err(dwc->dev, "%s is already bound to %s\n",
-                               dwc->gadget.name,
-                               dwc->gadget_driver->driver.name);
-               ret = -EBUSY;
-               goto err1;
-       }
+       /* update NumP */
+       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+       reg &= ~DWC3_DCFG_NUMP_MASK;
+       reg |= nump << DWC3_DCFG_NUMP_SHIFT;
+       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
 
-       dwc->gadget_driver      = driver;
+static int __dwc3_gadget_start(struct dwc3 *dwc)
+{
+       struct dwc3_ep          *dep;
+       int                     ret = 0;
+       u32                     reg;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCFG);
        reg &= ~(DWC3_DCFG_SPEED_MASK);
@@ -1668,16 +1688,16 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        } else {
                switch (dwc->maximum_speed) {
                case USB_SPEED_LOW:
-                       reg |= DWC3_DSTS_LOWSPEED;
+                       reg |= DWC3_DCFG_LOWSPEED;
                        break;
                case USB_SPEED_FULL:
-                       reg |= DWC3_DSTS_FULLSPEED1;
+                       reg |= DWC3_DCFG_FULLSPEED1;
                        break;
                case USB_SPEED_HIGH:
-                       reg |= DWC3_DSTS_HIGHSPEED;
+                       reg |= DWC3_DCFG_HIGHSPEED;
                        break;
                case USB_SPEED_SUPER_PLUS:
-                       reg |= DWC3_DSTS_SUPERSPEED_PLUS;
+                       reg |= DWC3_DCFG_SUPERSPEED_PLUS;
                        break;
                default:
                        dev_err(dwc->dev, "invalid dwc->maximum_speed (%d)\n",
@@ -1701,6 +1721,8 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
        dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
 
+       dwc3_gadget_setup_nump(dwc);
+
        /* Start with SuperSpeed Default */
        dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
@@ -1709,7 +1731,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
                        false);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
-               goto err2;
+               goto err0;
        }
 
        dep = dwc->eps[1];
@@ -1717,7 +1739,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
                        false);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
-               goto err3;
+               goto err1;
        }
 
        /* begin to receive SETUP packets */
@@ -1726,43 +1748,79 @@ static int dwc3_gadget_start(struct usb_gadget *g,
 
        dwc3_gadget_enable_irq(dwc);
 
-       spin_unlock_irqrestore(&dwc->lock, flags);
-
        return 0;
 
-err3:
-       __dwc3_gadget_ep_disable(dwc->eps[0]);
-
-err2:
-       dwc->gadget_driver = NULL;
-
 err1:
-       spin_unlock_irqrestore(&dwc->lock, flags);
-
-       free_irq(irq, dwc->ev_buf);
+       __dwc3_gadget_ep_disable(dwc->eps[0]);
 
 err0:
        return ret;
 }
 
-static int dwc3_gadget_stop(struct usb_gadget *g)
+static int dwc3_gadget_start(struct usb_gadget *g,
+               struct usb_gadget_driver *driver)
 {
        struct dwc3             *dwc = gadget_to_dwc(g);
        unsigned long           flags;
+       int                     ret = 0;
        int                     irq;
 
+       irq = dwc->irq_gadget;
+       ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+                       IRQF_SHARED, "dwc3", dwc->ev_buf);
+       if (ret) {
+               dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+                               irq, ret);
+               goto err0;
+       }
+
        spin_lock_irqsave(&dwc->lock, flags);
+       if (dwc->gadget_driver) {
+               dev_err(dwc->dev, "%s is already bound to %s\n",
+                               dwc->gadget.name,
+                               dwc->gadget_driver->driver.name);
+               ret = -EBUSY;
+               goto err1;
+       }
+
+       dwc->gadget_driver      = driver;
+
+       if (pm_runtime_active(dwc->dev))
+               __dwc3_gadget_start(dwc);
+
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return 0;
+
+err1:
+       spin_unlock_irqrestore(&dwc->lock, flags);
+       free_irq(irq, dwc);
+
+err0:
+       return ret;
+}
+
+static void __dwc3_gadget_stop(struct dwc3 *dwc)
+{
+       if (pm_runtime_suspended(dwc->dev))
+               return;
 
        dwc3_gadget_disable_irq(dwc);
        __dwc3_gadget_ep_disable(dwc->eps[0]);
        __dwc3_gadget_ep_disable(dwc->eps[1]);
+}
 
-       dwc->gadget_driver      = NULL;
+static int dwc3_gadget_stop(struct usb_gadget *g)
+{
+       struct dwc3             *dwc = gadget_to_dwc(g);
+       unsigned long           flags;
 
+       spin_lock_irqsave(&dwc->lock, flags);
+       __dwc3_gadget_stop(dwc);
+       dwc->gadget_driver      = NULL;
        spin_unlock_irqrestore(&dwc->lock, flags);
 
-       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-       free_irq(irq, dwc->ev_buf);
+       free_irq(dwc->irq_gadget, dwc->ev_buf);
 
        return 0;
 }
@@ -1785,7 +1843,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
        u8                              i;
 
        for (i = 0; i < num; i++) {
-               u8 epnum = (i << 1) | (!!direction);
+               u8 epnum = (i << 1) | (direction ? 1 : 0);
 
                dep = kzalloc(sizeof(*dep), GFP_KERNEL);
                if (!dep)
@@ -1794,12 +1852,14 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
                dep->dwc = dwc;
                dep->number = epnum;
                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");
 
                dep->endpoint.name = dep->name;
+               spin_lock_init(&dep->lock);
 
                dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name);
 
@@ -1901,6 +1961,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
        unsigned int            s_pkt = 0;
        unsigned int            trb_status;
 
+       dep->queued_requests--;
        trace_dwc3_complete_trb(dep, trb);
 
        if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
@@ -1921,7 +1982,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
                        trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
                        if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
                                dwc3_trace(trace_dwc3_gadget,
-                                               "%s: incomplete IN transfer\n",
+                                               "%s: incomplete IN transfer",
                                                dep->name);
                                /*
                                 * If missed isoc occurred and there is
@@ -2006,6 +2067,14 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                        break;
        } while (1);
 
+       /*
+        * Our endpoint might get disabled by another thread during
+        * dwc3_gadget_giveback(). If that happens, we're just gonna return 1
+        * early on so DWC3_EP_BUSY flag gets cleared
+        */
+       if (!dep->endpoint.desc)
+               return 1;
+
        if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
                        list_empty(&dep->started_list)) {
                if (list_empty(&dep->pending_list)) {
@@ -2023,6 +2092,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                return 1;
        }
 
+       if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
+               if ((event->status & DEPEVT_STATUS_IOC) &&
+                               (trb->ctrl & DWC3_TRB_CTRL_IOC))
+                       return 0;
        return 1;
 }
 
@@ -2039,7 +2112,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
                status = -ECONNRESET;
 
        clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
-       if (clean_busy && (is_xfer_complete ||
+       if (clean_busy && (!dep->endpoint.desc || is_xfer_complete ||
                                usb_endpoint_xfer_isoc(dep->endpoint.desc)))
                dep->flags &= ~DWC3_EP_BUSY;
 
@@ -2068,10 +2141,18 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
                dwc->u1u2 = 0;
        }
 
+       /*
+        * Our endpoint might get disabled by another thread during
+        * dwc3_gadget_giveback(). If that happens, we're just gonna return 1
+        * early on so DWC3_EP_BUSY flag gets cleared
+        */
+       if (!dep->endpoint.desc)
+               return;
+
        if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
                int ret;
 
-               ret = __dwc3_gadget_kick_transfer(dep, 0, is_xfer_complete);
+               ret = __dwc3_gadget_kick_transfer(dep, 0);
                if (!ret || ret == -EBUSY)
                        return;
        }
@@ -2099,7 +2180,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 
                if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
                        dwc3_trace(trace_dwc3_gadget,
-                                       "%s is an Isochronous endpoint\n",
+                                       "%s is an Isochronous endpoint",
                                        dep->name);
                        return;
                }
@@ -2122,12 +2203,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
                                        dep->name, active ? "Transfer Active"
                                        : "Transfer Not Active");
 
-                       ret = __dwc3_gadget_kick_transfer(dep, 0, !active);
+                       ret = __dwc3_gadget_kick_transfer(dep, 0);
                        if (!ret || ret == -EBUSY)
                                return;
 
                        dwc3_trace(trace_dwc3_gadget,
-                                       "%s: failed to kick transfers\n",
+                                       "%s: failed to kick transfers",
                                        dep->name);
                }
 
@@ -2150,11 +2231,11 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
                        /* FALLTHROUGH */
                default:
                        dwc3_trace(trace_dwc3_gadget,
-                                       "unable to find suitable stream\n");
+                                       "unable to find suitable stream");
                }
                break;
        case DWC3_DEPEVT_RXTXFIFOEVT:
-               dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun\n", dep->name);
+               dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun", dep->name);
                break;
        case DWC3_DEPEVT_EPCMDCMPLT:
                dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
@@ -2237,7 +2318,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
        cmd |= DWC3_DEPCMD_CMDIOC;
        cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
        memset(&params, 0, sizeof(params));
-       ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+       ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
        WARN_ON_ONCE(ret);
        dep->resource_index = 0;
        dep->flags &= ~DWC3_EP_BUSY;
@@ -2300,12 +2381,16 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        dwc->gadget.speed = USB_SPEED_UNKNOWN;
        dwc->setup_packet_pending = false;
        usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED);
+
+       dwc->connected = false;
 }
 
 static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 {
        u32                     reg;
 
+       dwc->connected = true;
+
        /*
         * WORKAROUND: DWC3 revisions <1.88a have an issue which
         * would cause a missing Disconnect Event if there's a
@@ -2393,12 +2478,12 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
        dwc3_update_ram_clk_sel(dwc, speed);
 
        switch (speed) {
-       case DWC3_DCFG_SUPERSPEED_PLUS:
+       case DWC3_DSTS_SUPERSPEED_PLUS:
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
                dwc->gadget.ep0->maxpacket = 512;
                dwc->gadget.speed = USB_SPEED_SUPER_PLUS;
                break;
-       case DWC3_DCFG_SUPERSPEED:
+       case DWC3_DSTS_SUPERSPEED:
                /*
                 * WORKAROUND: DWC3 revisions <1.90a have an issue which
                 * would cause a missing USB3 Reset event.
@@ -2419,18 +2504,18 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                dwc->gadget.ep0->maxpacket = 512;
                dwc->gadget.speed = USB_SPEED_SUPER;
                break;
-       case DWC3_DCFG_HIGHSPEED:
+       case DWC3_DSTS_HIGHSPEED:
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
                dwc->gadget.ep0->maxpacket = 64;
                dwc->gadget.speed = USB_SPEED_HIGH;
                break;
-       case DWC3_DCFG_FULLSPEED2:
-       case DWC3_DCFG_FULLSPEED1:
+       case DWC3_DSTS_FULLSPEED2:
+       case DWC3_DSTS_FULLSPEED1:
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
                dwc->gadget.ep0->maxpacket = 64;
                dwc->gadget.speed = USB_SPEED_FULL;
                break;
-       case DWC3_DCFG_LOWSPEED:
+       case DWC3_DSTS_LOWSPEED:
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
                dwc->gadget.ep0->maxpacket = 8;
                dwc->gadget.speed = USB_SPEED_LOW;
@@ -2440,8 +2525,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
        /* Enable USB2 LPM Capability */
 
        if ((dwc->revision > DWC3_REVISION_194A) &&
-           (speed != DWC3_DCFG_SUPERSPEED) &&
-           (speed != DWC3_DCFG_SUPERSPEED_PLUS)) {
+           (speed != DWC3_DSTS_SUPERSPEED) &&
+           (speed != DWC3_DSTS_SUPERSPEED_PLUS)) {
                reg = dwc3_readl(dwc->regs, DWC3_DCFG);
                reg |= DWC3_DCFG_LPM_CAP;
                dwc3_writel(dwc->regs, DWC3_DCFG, reg);
@@ -2610,6 +2695,17 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
        dwc->link_state = next;
 }
 
+static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
+                                         unsigned int evtinfo)
+{
+       enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
+
+       if (dwc->link_state != next && next == DWC3_LINK_STATE_U3)
+               dwc3_suspend_gadget(dwc);
+
+       dwc->link_state = next;
+}
+
 static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
                unsigned int evtinfo)
 {
@@ -2661,7 +2757,20 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
                dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
                break;
        case DWC3_DEVICE_EVENT_EOPF:
-               dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
+               /* It changed to be suspend event for version 2.30a and above */
+               if (dwc->revision < DWC3_REVISION_230A) {
+                       dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
+               } else {
+                       dwc3_trace(trace_dwc3_gadget, "U3/L1-L2 Suspend Event");
+
+                       /*
+                        * Ignore suspend event until the gadget enters into
+                        * USB_STATE_CONFIGURED state.
+                        */
+                       if (dwc->gadget.state >= USB_STATE_CONFIGURED)
+                               dwc3_gadget_suspend_interrupt(dwc,
+                                               event->event_info);
+               }
                break;
        case DWC3_DEVICE_EVENT_SOF:
                dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame");
@@ -2767,6 +2876,13 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
        u32 count;
        u32 reg;
 
+       if (pm_runtime_suspended(dwc->dev)) {
+               pm_runtime_get(dwc->dev);
+               disable_irq_nosync(dwc->irq_gadget);
+               dwc->pending_events = true;
+               return IRQ_HANDLED;
+       }
+
        count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
        count &= DWC3_GEVNTCOUNT_MASK;
        if (!count)
@@ -2798,7 +2914,33 @@ static irqreturn_t dwc3_interrupt(int irq, void *_evt)
  */
 int dwc3_gadget_init(struct dwc3 *dwc)
 {
-       int                                     ret;
+       int ret, irq;
+       struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
+
+       irq = platform_get_irq_byname(dwc3_pdev, "peripheral");
+       if (irq == -EPROBE_DEFER)
+               return irq;
+
+       if (irq <= 0) {
+               irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
+               if (irq == -EPROBE_DEFER)
+                       return irq;
+
+               if (irq <= 0) {
+                       irq = platform_get_irq(dwc3_pdev, 0);
+                       if (irq <= 0) {
+                               if (irq != -EPROBE_DEFER) {
+                                       dev_err(dwc->dev,
+                                               "missing peripheral IRQ\n");
+                               }
+                               if (!irq)
+                                       irq = -EINVAL;
+                               return irq;
+                       }
+               }
+       }
+
+       dwc->irq_gadget = irq;
 
        dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
                        &dwc->ctrl_req_addr, GFP_KERNEL);
@@ -2861,7 +3003,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
         */
        if (dwc->revision < DWC3_REVISION_220A)
                dwc3_trace(trace_dwc3_gadget,
-                               "Changing max_speed on rev %08x\n",
+                               "Changing max_speed on rev %08x",
                                dwc->revision);
 
        dwc->gadget.max_speed           = dwc->maximum_speed;
@@ -2935,61 +3077,50 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
 
 int dwc3_gadget_suspend(struct dwc3 *dwc)
 {
+       int ret;
+
        if (!dwc->gadget_driver)
                return 0;
 
-       if (dwc->pullups_connected) {
-               dwc3_gadget_disable_irq(dwc);
-               dwc3_gadget_run_stop(dwc, true, true);
-       }
-
-       __dwc3_gadget_ep_disable(dwc->eps[0]);
-       __dwc3_gadget_ep_disable(dwc->eps[1]);
+       ret = dwc3_gadget_run_stop(dwc, false, false);
+       if (ret < 0)
+               return ret;
 
-       dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
+       dwc3_disconnect_gadget(dwc);
+       __dwc3_gadget_stop(dwc);
 
        return 0;
 }
 
 int dwc3_gadget_resume(struct dwc3 *dwc)
 {
-       struct dwc3_ep          *dep;
        int                     ret;
 
        if (!dwc->gadget_driver)
                return 0;
 
-       /* Start with SuperSpeed Default */
-       dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
-
-       dep = dwc->eps[0];
-       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
-                       false);
-       if (ret)
+       ret = __dwc3_gadget_start(dwc);
+       if (ret < 0)
                goto err0;
 
-       dep = dwc->eps[1];
-       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
-                       false);
-       if (ret)
+       ret = dwc3_gadget_run_stop(dwc, true, false);
+       if (ret < 0)
                goto err1;
 
-       /* begin to receive SETUP packets */
-       dwc->ep0state = EP0_SETUP_PHASE;
-       dwc3_ep0_out_start(dwc);
-
-       dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
-
-       if (dwc->pullups_connected) {
-               dwc3_gadget_enable_irq(dwc);
-               dwc3_gadget_run_stop(dwc, true, false);
-       }
-
        return 0;
 
 err1:
-       __dwc3_gadget_ep_disable(dwc->eps[0]);
+       __dwc3_gadget_stop(dwc);
 
 err0:
        return ret;
 }
+
+void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
+{
+       if (dwc->pending_events) {
+               dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf);
+               dwc->pending_events = false;
+               enable_irq(dwc->irq_gadget);
+       }
+}
index f21c0fc..e4a1d97 100644 (file)
@@ -95,11 +95,11 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
  *
  * Caller should take care of locking
  */
-static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
+static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep)
 {
        u32                     res_id;
 
-       res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
+       res_id = dwc3_readl(dep->regs, DWC3_DEPCMD);
 
        return DWC3_DEPCMD_GET_RSC_IDX(res_id);
 }
index c679f63..67f90d7 100644 (file)
  */
 
 #include <linux/platform_device.h>
-#include <linux/usb/xhci_pdriver.h>
 
 #include "core.h"
 
 int dwc3_host_init(struct dwc3 *dwc)
 {
+       struct property_entry   props[2];
        struct platform_device  *xhci;
-       struct usb_xhci_pdata   pdata;
        int                     ret;
 
        xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
@@ -47,14 +46,15 @@ int dwc3_host_init(struct dwc3 *dwc)
                goto err1;
        }
 
-       memset(&pdata, 0, sizeof(pdata));
+       memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
 
-       pdata.usb3_lpm_capable = dwc->usb3_lpm_capable;
-
-       ret = platform_device_add_data(xhci, &pdata, sizeof(pdata));
-       if (ret) {
-               dev_err(dwc->dev, "couldn't add platform data to xHCI device\n");
-               goto err1;
+       if (dwc->usb3_lpm_capable) {
+               props[0].name = "usb3-lpm-capable";
+               ret = platform_device_add_properties(xhci, props);
+               if (ret) {
+                       dev_err(dwc->dev, "failed to add properties to xHCI\n");
+                       goto err1;
+               }
        }
 
        phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy",
index 6a79c8e..a06f9a8 100644 (file)
@@ -26,7 +26,6 @@
 
 static inline u32 dwc3_readl(void __iomem *base, u32 offset)
 {
-       u32 offs = offset - DWC3_GLOBALS_REGS_START;
        u32 value;
 
        /*
@@ -34,7 +33,7 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset)
         * space, see dwc3_probe in core.c.
         * However, the offsets are given starting from xHCI address space.
         */
-       value = readl(base + offs);
+       value = readl(base + offset - DWC3_GLOBALS_REGS_START);
 
        /*
         * When tracing we want to make it easy to find the correct address on
@@ -49,14 +48,12 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset)
 
 static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
 {
-       u32 offs = offset - DWC3_GLOBALS_REGS_START;
-
        /*
         * We requested the mem region starting from the Globals address
         * space, see dwc3_probe in core.c.
         * However, the offsets are given starting from xHCI address space.
         */
-       writel(value, base + offs);
+       writel(value, base + offset - DWC3_GLOBALS_REGS_START);
 
        /*
         * When tracing we want to make it easy to find the correct address on
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
deleted file mode 100644 (file)
index 8826cca..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * platform_data.h - USB DWC3 Platform Data Support
- *
- * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
- * Author: Felipe Balbi <balbi@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/usb/ch9.h>
-#include <linux/usb/otg.h>
-
-struct dwc3_platform_data {
-       enum usb_device_speed maximum_speed;
-       enum usb_dr_mode dr_mode;
-       bool usb3_lpm_capable;
-
-       unsigned is_utmi_l1_suspend:1;
-       u8 hird_threshold;
-
-       u8 lpm_nyet_threshold;
-
-       unsigned disable_scramble_quirk:1;
-       unsigned has_lpm_erratum:1;
-       unsigned u2exit_lfps_quirk:1;
-       unsigned u2ss_inp3_quirk:1;
-       unsigned req_p1p2p3_quirk:1;
-       unsigned del_p1p2p3_quirk:1;
-       unsigned del_phy_power_chg_quirk:1;
-       unsigned lfps_filter_quirk:1;
-       unsigned rx_detect_poll_quirk:1;
-       unsigned dis_u3_susphy_quirk:1;
-       unsigned dis_u2_susphy_quirk:1;
-       unsigned dis_enblslpm_quirk:1;
-       unsigned dis_rxdet_inp3_quirk:1;
-
-       unsigned tx_de_emphasis_quirk:1;
-       unsigned tx_de_emphasis:2;
-
-       u32 fladj_value;
-
-       const char *hsphy_interface;
-};
index 3ac7252..d24cefd 100644 (file)
@@ -71,7 +71,8 @@ DECLARE_EVENT_CLASS(dwc3_log_event,
        TP_fast_assign(
                __entry->event = event;
        ),
-       TP_printk("event %08x", __entry->event)
+       TP_printk("event (%08x): %s", __entry->event,
+                       dwc3_decode_event(__entry->event))
 );
 
 DEFINE_EVENT(dwc3_log_event, dwc3_event,
@@ -85,21 +86,21 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
        TP_STRUCT__entry(
                __field(__u8, bRequestType)
                __field(__u8, bRequest)
-               __field(__le16, wValue)
-               __field(__le16, wIndex)
-               __field(__le16, wLength)
+               __field(__u16, wValue)
+               __field(__u16, wIndex)
+               __field(__u16, wLength)
        ),
        TP_fast_assign(
                __entry->bRequestType = ctrl->bRequestType;
                __entry->bRequest = ctrl->bRequest;
-               __entry->wValue = ctrl->wValue;
-               __entry->wIndex = ctrl->wIndex;
-               __entry->wLength = ctrl->wLength;
+               __entry->wValue = le16_to_cpu(ctrl->wValue);
+               __entry->wIndex = le16_to_cpu(ctrl->wIndex);
+               __entry->wLength = le16_to_cpu(ctrl->wLength);
        ),
        TP_printk("bRequestType %02x bRequest %02x wValue %04x wIndex %04x wLength %d",
                __entry->bRequestType, __entry->bRequest,
-               le16_to_cpu(__entry->wValue), le16_to_cpu(__entry->wIndex),
-               le16_to_cpu(__entry->wLength)
+               __entry->wValue, __entry->wIndex,
+               __entry->wLength
        )
 );
 
@@ -166,37 +167,41 @@ DEFINE_EVENT(dwc3_log_request, dwc3_gadget_giveback,
 );
 
 DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
-       TP_PROTO(unsigned int cmd, u32 param),
-       TP_ARGS(cmd, param),
+       TP_PROTO(unsigned int cmd, u32 param, int status),
+       TP_ARGS(cmd, param, status),
        TP_STRUCT__entry(
                __field(unsigned int, cmd)
                __field(u32, param)
+               __field(int, status)
        ),
        TP_fast_assign(
                __entry->cmd = cmd;
                __entry->param = param;
+               __entry->status = status;
        ),
-       TP_printk("cmd '%s' [%d] param %08x",
+       TP_printk("cmd '%s' [%d] param %08x --> status: %s",
                dwc3_gadget_generic_cmd_string(__entry->cmd),
-               __entry->cmd, __entry->param
+               __entry->cmd, __entry->param,
+               dwc3_gadget_generic_cmd_status_string(__entry->status)
        )
 );
 
 DEFINE_EVENT(dwc3_log_generic_cmd, dwc3_gadget_generic_cmd,
-       TP_PROTO(unsigned int cmd, u32 param),
-       TP_ARGS(cmd, param)
+       TP_PROTO(unsigned int cmd, u32 param, int status),
+       TP_ARGS(cmd, param, status)
 );
 
 DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
        TP_PROTO(struct dwc3_ep *dep, unsigned int cmd,
-               struct dwc3_gadget_ep_cmd_params *params),
-       TP_ARGS(dep, cmd, params),
+               struct dwc3_gadget_ep_cmd_params *params, int cmd_status),
+       TP_ARGS(dep, cmd, params, cmd_status),
        TP_STRUCT__entry(
                __dynamic_array(char, name, DWC3_MSG_MAX)
                __field(unsigned int, cmd)
                __field(u32, param0)
                __field(u32, param1)
                __field(u32, param2)
+               __field(int, cmd_status)
        ),
        TP_fast_assign(
                snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
@@ -204,18 +209,20 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
                __entry->param0 = params->param0;
                __entry->param1 = params->param1;
                __entry->param2 = params->param2;
+               __entry->cmd_status = cmd_status;
        ),
-       TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x",
+       TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x --> status: %s",
                __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
                __entry->cmd, __entry->param0,
-               __entry->param1, __entry->param2
+               __entry->param1, __entry->param2,
+               dwc3_ep_cmd_status_string(__entry->cmd_status)
        )
 );
 
 DEFINE_EVENT(dwc3_log_gadget_ep_cmd, dwc3_gadget_ep_cmd,
        TP_PROTO(struct dwc3_ep *dep, unsigned int cmd,
-               struct dwc3_gadget_ep_cmd_params *params),
-       TP_ARGS(dep, cmd, params)
+               struct dwc3_gadget_ep_cmd_params *params, int cmd_status),
+       TP_ARGS(dep, cmd, params, cmd_status)
 );
 
 DECLARE_EVENT_CLASS(dwc3_log_trb,
@@ -224,6 +231,8 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
        TP_STRUCT__entry(
                __dynamic_array(char, name, DWC3_MSG_MAX)
                __field(struct dwc3_trb *, trb)
+               __field(u32, allocated)
+               __field(u32, queued)
                __field(u32, bpl)
                __field(u32, bph)
                __field(u32, size)
@@ -232,14 +241,53 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
        TP_fast_assign(
                snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
                __entry->trb = trb;
+               __entry->allocated = dep->allocated_requests;
+               __entry->queued = dep->queued_requests;
                __entry->bpl = trb->bpl;
                __entry->bph = trb->bph;
                __entry->size = trb->size;
                __entry->ctrl = trb->ctrl;
        ),
-       TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x",
-               __get_str(name), __entry->trb, __entry->bph, __entry->bpl,
-               __entry->size, __entry->ctrl
+       TP_printk("%s: %d/%d trb %p buf %08x%08x size %d ctrl %08x (%c%c%c%c:%c%c:%s)",
+               __get_str(name), __entry->queued, __entry->allocated,
+               __entry->trb, __entry->bph, __entry->bpl,
+               __entry->size, __entry->ctrl,
+               __entry->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h',
+               __entry->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l',
+               __entry->ctrl & DWC3_TRB_CTRL_CHN ? 'C' : 'c',
+               __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; })
        )
 );
 
index 8cfc319..12731e6 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <linux/console.h>
 #include <linux/errno.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/pci_regs.h>
 #include <linux/pci_ids.h>
 #include <linux/usb/ch9.h>
@@ -1093,5 +1093,5 @@ static int __init kgdbdbgp_start_thread(void)
 
        return 0;
 }
-module_init(kgdbdbgp_start_thread);
+device_initcall(kgdbdbgp_start_thread);
 #endif /* CONFIG_KGDB */
index 2057add..3c3f31c 100644 (file)
@@ -114,7 +114,7 @@ config USB_GADGET_VBUS_DRAW
 
 config USB_GADGET_STORAGE_NUM_BUFFERS
        int "Number of storage pipeline buffers"
-       range 2 32
+       range 2 256
        default 2
        help
           Usually 2 buffers are enough to establish a good buffering
index e6c0542..17a6077 100644 (file)
@@ -93,7 +93,7 @@ int usb_gadget_config_buf(
        *cp = *config;
 
        /* then interface/endpoint/class/vendor/... */
-       len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
+       len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf,
                        length - USB_DT_CONFIG_SIZE, desc);
        if (len < 0)
                return len;
index cc33d26..5c8429f 100644 (file)
@@ -130,6 +130,12 @@ struct ffs_epfile {
 
        struct dentry                   *dentry;
 
+       /*
+        * Buffer for holding data from partial reads which may happen since
+        * we’re rounding user read requests to a multiple of a max packet size.
+        */
+       struct ffs_buffer               *read_buffer;   /* P: epfile->mutex */
+
        char                            name[5];
 
        unsigned char                   in;     /* P: ffs->eps_lock */
@@ -138,6 +144,12 @@ struct ffs_epfile {
        unsigned char                   _pad;
 };
 
+struct ffs_buffer {
+       size_t length;
+       char *data;
+       char storage[];
+};
+
 /*  ffs_io_data structure ***************************************************/
 
 struct ffs_io_data {
@@ -640,6 +652,49 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
        }
 }
 
+static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
+{
+       ssize_t ret = copy_to_iter(data, data_len, iter);
+       if (likely(ret == data_len))
+               return ret;
+
+       if (unlikely(iov_iter_count(iter)))
+               return -EFAULT;
+
+       /*
+        * Dear user space developer!
+        *
+        * TL;DR: To stop getting below error message in your kernel log, change
+        * user space code using functionfs to align read buffers to a max
+        * packet size.
+        *
+        * Some UDCs (e.g. dwc3) require request sizes to be a multiple of a max
+        * packet size.  When unaligned buffer is passed to functionfs, it
+        * internally uses a larger, aligned buffer so that such UDCs are happy.
+        *
+        * Unfortunately, this means that host may send more data than was
+        * requested in read(2) system call.  f_fs doesn’t know what to do with
+        * that excess data so it simply drops it.
+        *
+        * Was the buffer aligned in the first place, no such problem would
+        * happen.
+        *
+        * Data may be dropped only in AIO reads.  Synchronous reads are handled
+        * by splitting a request into multiple parts.  This splitting may still
+        * be a problem though so it’s likely best to align the buffer
+        * regardless of it being AIO or not..
+        *
+        * This only affects OUT endpoints, i.e. reading data with a read(2),
+        * aio_read(2) etc. system calls.  Writing data to an IN endpoint is not
+        * affected.
+        */
+       pr_err("functionfs read size %d > requested size %zd, dropping excess data. "
+              "Align read buffer size to max packet size to avoid the problem.\n",
+              data_len, ret);
+
+       return ret;
+}
+
 static void ffs_user_copy_worker(struct work_struct *work)
 {
        struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
@@ -650,9 +705,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
 
        if (io_data->read && ret > 0) {
                use_mm(io_data->mm);
-               ret = copy_to_iter(io_data->buf, ret, &io_data->data);
-               if (ret != io_data->req->actual && iov_iter_count(&io_data->data))
-                       ret = -EFAULT;
+               ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data);
                unuse_mm(io_data->mm);
        }
 
@@ -680,6 +733,58 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
        schedule_work(&io_data->work);
 }
 
+/* Assumes epfile->mutex is held. */
+static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile,
+                                         struct iov_iter *iter)
+{
+       struct ffs_buffer *buf = epfile->read_buffer;
+       ssize_t ret;
+       if (!buf)
+               return 0;
+
+       ret = copy_to_iter(buf->data, buf->length, iter);
+       if (buf->length == ret) {
+               kfree(buf);
+               epfile->read_buffer = NULL;
+       } else if (unlikely(iov_iter_count(iter))) {
+               ret = -EFAULT;
+       } else {
+               buf->length -= ret;
+               buf->data += ret;
+       }
+       return ret;
+}
+
+/* Assumes epfile->mutex is held. */
+static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
+                                     void *data, int data_len,
+                                     struct iov_iter *iter)
+{
+       struct ffs_buffer *buf;
+
+       ssize_t ret = copy_to_iter(data, data_len, iter);
+       if (likely(data_len == ret))
+               return ret;
+
+       if (unlikely(iov_iter_count(iter)))
+               return -EFAULT;
+
+       /* See ffs_copy_to_iter for more context. */
+       pr_warn("functionfs read size %d > requested size %zd, splitting request into multiple reads.",
+               data_len, ret);
+
+       data_len -= ret;
+       buf = kmalloc(sizeof(*buf) + data_len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       buf->length = data_len;
+       buf->data = buf->storage;
+       memcpy(buf->storage, data + ret, data_len);
+       epfile->read_buffer = buf;
+
+       return ret;
+}
+
 static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 {
        struct ffs_epfile *epfile = file->private_data;
@@ -709,21 +814,40 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
        if (halt && epfile->isoc)
                return -EINVAL;
 
+       /* We will be using request and read_buffer */
+       ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
+       if (unlikely(ret))
+               goto error;
+
        /* Allocate & copy */
        if (!halt) {
+               struct usb_gadget *gadget;
+
+               /*
+                * Do we have buffered data from previous partial read?  Check
+                * that for synchronous case only because we do not have
+                * facility to â€˜wake up’ a pending asynchronous read and push
+                * buffered data to it which we would need to make things behave
+                * consistently.
+                */
+               if (!io_data->aio && io_data->read) {
+                       ret = __ffs_epfile_read_buffered(epfile, &io_data->data);
+                       if (ret)
+                               goto error_mutex;
+               }
+
                /*
                 * if we _do_ wait above, the epfile->ffs->gadget might be NULL
                 * before the waiting completes, so do not assign to 'gadget'
                 * earlier
                 */
-               struct usb_gadget *gadget = epfile->ffs->gadget;
-               size_t copied;
+               gadget = epfile->ffs->gadget;
 
                spin_lock_irq(&epfile->ffs->eps_lock);
                /* In the meantime, endpoint got disabled or changed. */
                if (epfile->ep != ep) {
-                       spin_unlock_irq(&epfile->ffs->eps_lock);
-                       return -ESHUTDOWN;
+                       ret = -ESHUTDOWN;
+                       goto error_lock;
                }
                data_len = iov_iter_count(&io_data->data);
                /*
@@ -735,22 +859,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                spin_unlock_irq(&epfile->ffs->eps_lock);
 
                data = kmalloc(data_len, GFP_KERNEL);
-               if (unlikely(!data))
-                       return -ENOMEM;
-               if (!io_data->read) {
-                       copied = copy_from_iter(data, data_len, &io_data->data);
-                       if (copied != data_len) {
-                               ret = -EFAULT;
-                               goto error;
-                       }
+               if (unlikely(!data)) {
+                       ret = -ENOMEM;
+                       goto error_mutex;
+               }
+               if (!io_data->read &&
+                   copy_from_iter(data, data_len, &io_data->data) != data_len) {
+                       ret = -EFAULT;
+                       goto error_mutex;
                }
        }
 
-       /* We will be using request */
-       ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
-       if (unlikely(ret))
-               goto error;
-
        spin_lock_irq(&epfile->ffs->eps_lock);
 
        if (epfile->ep != ep) {
@@ -803,18 +922,13 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                        interrupted = ep->status < 0;
                }
 
-               /*
-                * XXX We may end up silently droping data here.  Since data_len
-                * (i.e. req->length) may be bigger than len (after being
-                * rounded up to maxpacketsize), we may end up with more data
-                * then user space has space for.
-                */
-               ret = interrupted ? -EINTR : ep->status;
-               if (io_data->read && ret > 0) {
-                       ret = copy_to_iter(data, ret, &io_data->data);
-                       if (!ret)
-                               ret = -EFAULT;
-               }
+               if (interrupted)
+                       ret = -EINTR;
+               else if (io_data->read && ep->status > 0)
+                       ret = __ffs_epfile_read_data(epfile, data, ep->status,
+                                                    &io_data->data);
+               else
+                       ret = ep->status;
                goto error_mutex;
        } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) {
                ret = -ENOMEM;
@@ -980,6 +1094,8 @@ ffs_epfile_release(struct inode *inode, struct file *file)
 
        ENTER();
 
+       kfree(epfile->read_buffer);
+       epfile->read_buffer = NULL;
        ffs_data_closed(epfile->ffs);
 
        return 0;
@@ -1605,19 +1721,24 @@ static void ffs_func_eps_disable(struct ffs_function *func)
        unsigned count            = func->ffs->eps_count;
        unsigned long flags;
 
-       spin_lock_irqsave(&func->ffs->eps_lock, flags);
        do {
+               if (epfile)
+                       mutex_lock(&epfile->mutex);
+               spin_lock_irqsave(&func->ffs->eps_lock, flags);
                /* pending requests get nuked */
                if (likely(ep->ep))
                        usb_ep_disable(ep->ep);
                ++ep;
+               spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
 
                if (epfile) {
                        epfile->ep = NULL;
+                       kfree(epfile->read_buffer);
+                       epfile->read_buffer = NULL;
+                       mutex_unlock(&epfile->mutex);
                        ++epfile;
                }
        } while (--count);
-       spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
 }
 
 static int ffs_func_eps_enable(struct ffs_function *func)
@@ -2227,8 +2348,8 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
 {
        u32 str_count, needed_count, lang_count;
        struct usb_gadget_strings **stringtabs, *t;
-       struct usb_string *strings, *s;
        const char *data = _data;
+       struct usb_string *s;
 
        ENTER();
 
@@ -2286,7 +2407,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
                stringtabs = vla_ptr(vlabuf, d, stringtabs);
                t = vla_ptr(vlabuf, d, stringtab);
                s = vla_ptr(vlabuf, d, strings);
-               strings = s;
        }
 
        /* For each language */
index 5c6d4d7..2505117 100644 (file)
@@ -2655,18 +2655,6 @@ void fsg_common_put(struct fsg_common *common)
 }
 EXPORT_SYMBOL_GPL(fsg_common_put);
 
-/* check if fsg_num_buffers is within a valid range */
-static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers)
-{
-#define FSG_MAX_NUM_BUFFERS    32
-
-       if (fsg_num_buffers >= 2 && fsg_num_buffers <= FSG_MAX_NUM_BUFFERS)
-               return 0;
-       pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
-              fsg_num_buffers, 2, FSG_MAX_NUM_BUFFERS);
-       return -EINVAL;
-}
-
 static struct fsg_common *fsg_common_setup(struct fsg_common *common)
 {
        if (!common) {
@@ -2709,11 +2697,7 @@ static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n)
 int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n)
 {
        struct fsg_buffhd *bh, *buffhds;
-       int i, rc;
-
-       rc = fsg_num_buffers_validate(n);
-       if (rc != 0)
-               return rc;
+       int i;
 
        buffhds = kcalloc(n, sizeof(*buffhds), GFP_KERNEL);
        if (!buffhds)
@@ -3401,10 +3385,6 @@ static ssize_t fsg_opts_num_buffers_store(struct config_item *item,
        if (ret)
                goto end;
 
-       ret = fsg_num_buffers_validate(num);
-       if (ret)
-               goto end;
-
        fsg_common_set_num_buffers(opts->common, num);
        ret = len;
 
index 3580f19..6ded634 100644 (file)
@@ -907,7 +907,6 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        struct gs_port  *port = tty->driver_data;
        unsigned long   flags;
-       int             status;
 
        pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n",
                        port->port_num, tty, count);
@@ -917,7 +916,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
                count = gs_buf_put(&port->port_write_buf, buf, count);
        /* treat count == 0 as flush_chars() */
        if (port->port_usb)
-               status = gs_start_tx(port);
+               gs_start_tx(port);
        spin_unlock_irqrestore(&port->port_lock, flags);
 
        return count;
index f85639e..6da7316 100644 (file)
@@ -265,7 +265,7 @@ static void *functionfs_acquire_dev(struct ffs_dev *dev)
 {
        if (!try_module_get(THIS_MODULE))
                return ERR_PTR(-ENOENT);
-       
+
        return NULL;
 }
 
@@ -275,7 +275,7 @@ static void functionfs_release_dev(struct ffs_dev *dev)
 }
 
 /*
- * The caller of this function takes ffs_lock 
+ * The caller of this function takes ffs_lock
  */
 static int functionfs_ready_callback(struct ffs_data *ffs)
 {
@@ -294,12 +294,12 @@ static int functionfs_ready_callback(struct ffs_data *ffs)
                ++missing_funcs;
                gfs_registered = false;
        }
-       
+
        return ret;
 }
 
 /*
- * The caller of this function takes ffs_lock 
+ * The caller of this function takes ffs_lock
  */
 static void functionfs_closed_callback(struct ffs_data *ffs)
 {
@@ -347,17 +347,14 @@ static int gfs_bind(struct usb_composite_dev *cdev)
 
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        {
-               struct f_rndis_opts *rndis_opts;
-
                fi_rndis = usb_get_function_instance("rndis");
                if (IS_ERR(fi_rndis)) {
                        ret = PTR_ERR(fi_rndis);
                        goto error;
                }
-               rndis_opts = container_of(fi_rndis, struct f_rndis_opts,
-                                         func_inst);
 #ifndef CONFIG_USB_FUNCTIONFS_ETH
-               net = rndis_opts->net;
+               net = container_of(fi_rndis, struct f_rndis_opts,
+                                  func_inst)->net;
 #endif
        }
 #endif
index 7c28941..658b8da 100644 (file)
@@ -312,7 +312,7 @@ config USB_NET2272_DMA
          If unsure, say "N" here.  The driver works fine in PIO mode.
 
 config USB_NET2280
-       tristate "NetChip 228x / PLX USB338x"
+       tristate "NetChip NET228x / PLX USB3x8x"
        depends on PCI
        help
           NetChip 2280 / 2282 is a PCI based USB peripheral controller which
@@ -322,6 +322,8 @@ config USB_NET2280
           (for control transfers) and several endpoints with dedicated
           functions.
 
+          PLX 2380 is a PCIe version of the PLX 2380.
+
           PLX 3380 / 3382 is a PCIe based USB peripheral controller which
           supports full, high speed USB 2.0 and super speed USB 3.0
           data transfers.
index dfee534..98e74ed 100644 (file)
@@ -1,3 +1,8 @@
+# define_trace.h needs to know how to find our header
+CFLAGS_trace.o                 := -I$(src)
+
+udc-core-y                     := core.o trace.o
+
 #
 # USB peripheral controller drivers
 #
index 39d70b4..ea03ca7 100644 (file)
@@ -2340,7 +2340,6 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
        struct udc_ep *ep;
        struct udc_request *req;
        struct udc_data_dma *td;
-       unsigned dma_done;
        unsigned len;
 
        ep = &dev->ep[ep_ix];
@@ -2385,13 +2384,8 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
                         */
                        if (use_dma_ppb_du) {
                                td = udc_get_last_dma_desc(req);
-                               if (td) {
-                                       dma_done =
-                                               AMD_GETBITS(td->status,
-                                               UDC_DMA_IN_STS_BS);
-                                       /* don't care DMA done */
+                               if (td)
                                        req->req.actual = req->req.length;
-                               }
                        } else {
                                /* assume all bytes transferred */
                                req->req.actual = req->req.length;
@@ -3417,4 +3411,3 @@ module_pci_driver(udc_pci_driver);
 MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
 MODULE_AUTHOR("Thomas Dahlmann");
 MODULE_LICENSE("GPL");
-
index 18569de..bb1f6c8 100644 (file)
@@ -1920,6 +1920,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
 
        udc->errata = match->data;
        udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc");
+       if (IS_ERR(udc->pmc))
+               udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9x5-pmc");
        if (udc->errata && IS_ERR(udc->pmc))
                return ERR_CAST(udc->pmc);
 
index 6a4155c..4d5e918 100644 (file)
@@ -57,7 +57,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc,
                                        u32 param0, u32 param1, u32 param2)
 {
        u32 temp, cmd_status;
-       int reset_bdc = 0;
        int ret;
 
        temp = bdc_readl(bdc->regs, BDC_CMDSC);
@@ -94,7 +93,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc,
 
        case BDC_CMDS_INTL:
                dev_err(bdc->dev, "BDC Internal error\n");
-               reset_bdc = 1;
                ret = -ECONNRESET;
                break;
 
@@ -102,7 +100,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc,
                dev_err(bdc->dev,
                        "command timedout waited for %dusec\n",
                        BDC_CMD_TIMEOUT);
-               reset_bdc = 1;
                ret = -ECONNRESET;
                break;
        default:
index d619950..ccaa74a 100644 (file)
@@ -81,7 +81,7 @@ static void ep_bd_list_free(struct bdc_ep *ep, u32 num_tabs)
                        continue;
                }
                if (!bd_table->start_bd) {
-                       dev_dbg(bdc->dev, "bd dma pool not allocted\n");
+                       dev_dbg(bdc->dev, "bd dma pool not allocated\n");
                        continue;
                }
 
@@ -702,11 +702,9 @@ static int ep0_queue(struct bdc_ep *ep, struct bdc_req *req)
 /* Queue data stage */
 static int ep0_queue_data_stage(struct bdc *bdc)
 {
-       struct usb_request *ep0_usb_req;
        struct bdc_ep *ep;
 
        dev_dbg(bdc->dev, "%s\n", __func__);
-       ep0_usb_req = &bdc->ep0_req.usb_req;
        ep = bdc->bdc_ep_array[1];
        bdc->ep0_req.ep = ep;
        bdc->ep0_req.usb_req.complete = NULL;
@@ -1393,10 +1391,8 @@ static int ep0_set_sel(struct bdc *bdc,
 {
        struct bdc_ep   *ep;
        u16     wLength;
-       u16     wValue;
 
        dev_dbg(bdc->dev, "%s\n", __func__);
-       wValue = le16_to_cpu(setup_pkt->wValue);
        wLength = le16_to_cpu(setup_pkt->wLength);
        if (unlikely(wLength != 6)) {
                dev_err(bdc->dev, "%s Wrong wLength:%d\n", __func__, wLength);
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
new file mode 100644 (file)
index 0000000..ff8685e
--- /dev/null
@@ -0,0 +1,1523 @@
+/**
+ * udc.c - Core UDC Framework
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Felipe Balbi <balbi@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/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb.h>
+
+#include "trace.h"
+
+/**
+ * struct usb_udc - describes one usb device controller
+ * @driver - the gadget driver pointer. For use by the class code
+ * @dev - the child device to the actual controller
+ * @gadget - the gadget. For use by the class code
+ * @list - for use by the udc class driver
+ * @vbus - for udcs who care about vbus status, this value is real vbus status;
+ * for udcs who do not care about vbus status, this value is always true
+ *
+ * This represents the internal data structure which is used by the UDC-class
+ * to hold information about udc driver and gadget together.
+ */
+struct usb_udc {
+       struct usb_gadget_driver        *driver;
+       struct usb_gadget               *gadget;
+       struct device                   dev;
+       struct list_head                list;
+       bool                            vbus;
+};
+
+static struct class *udc_class;
+static LIST_HEAD(udc_list);
+static LIST_HEAD(gadget_driver_pending_list);
+static DEFINE_MUTEX(udc_lock);
+
+static int udc_bind_to_driver(struct usb_udc *udc,
+               struct usb_gadget_driver *driver);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint
+ * @ep:the endpoint being configured
+ * @maxpacket_limit:value of maximum packet size limit
+ *
+ * This function should be used only in UDC drivers to initialize endpoint
+ * (usually in probe function).
+ */
+void usb_ep_set_maxpacket_limit(struct usb_ep *ep,
+                                             unsigned maxpacket_limit)
+{
+       ep->maxpacket_limit = maxpacket_limit;
+       ep->maxpacket = maxpacket_limit;
+
+       trace_usb_ep_set_maxpacket_limit(ep, 0);
+}
+EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit);
+
+/**
+ * usb_ep_enable - configure endpoint, making it usable
+ * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
+ *     drivers discover endpoints through the ep_list of a usb_gadget.
+ *
+ * When configurations are set, or when interface settings change, the driver
+ * will enable or disable the relevant endpoints.  while it is enabled, an
+ * endpoint may be used for i/o until the driver receives a disconnect() from
+ * the host or until the endpoint is disabled.
+ *
+ * the ep0 implementation (which calls this routine) must ensure that the
+ * hardware capabilities of each endpoint match the descriptor provided
+ * for it.  for example, an endpoint named "ep2in-bulk" would be usable
+ * for interrupt transfers as well as bulk, but it likely couldn't be used
+ * for iso transfers or for endpoint 14.  some endpoints are fully
+ * configurable, with more generic names like "ep-a".  (remember that for
+ * USB, "in" means "towards the USB master".)
+ *
+ * returns zero, or a negative error code.
+ */
+int usb_ep_enable(struct usb_ep *ep)
+{
+       int ret = 0;
+
+       if (ep->enabled)
+               goto out;
+
+       ret = ep->ops->enable(ep, ep->desc);
+       if (ret) {
+               ret = ret;
+               goto out;
+       }
+
+       ep->enabled = true;
+
+out:
+       trace_usb_ep_enable(ep, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_ep_enable);
+
+/**
+ * usb_ep_disable - endpoint is no longer usable
+ * @ep:the endpoint being unconfigured.  may not be the endpoint named "ep0".
+ *
+ * no other task may be using this endpoint when this is called.
+ * any pending and uncompleted requests will complete with status
+ * indicating disconnect (-ESHUTDOWN) before this call returns.
+ * gadget drivers must call usb_ep_enable() again before queueing
+ * requests to the endpoint.
+ *
+ * returns zero, or a negative error code.
+ */
+int usb_ep_disable(struct usb_ep *ep)
+{
+       int ret = 0;
+
+       if (!ep->enabled)
+               goto out;
+
+       ret = ep->ops->disable(ep);
+       if (ret) {
+               ret = ret;
+               goto out;
+       }
+
+       ep->enabled = false;
+
+out:
+       trace_usb_ep_disable(ep, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_ep_disable);
+
+/**
+ * usb_ep_alloc_request - allocate a request object to use with this endpoint
+ * @ep:the endpoint to be used with with the request
+ * @gfp_flags:GFP_* flags to use
+ *
+ * Request objects must be allocated with this call, since they normally
+ * need controller-specific setup and may even need endpoint-specific
+ * resources such as allocation of DMA descriptors.
+ * Requests may be submitted with usb_ep_queue(), and receive a single
+ * completion callback.  Free requests with usb_ep_free_request(), when
+ * they are no longer needed.
+ *
+ * Returns the request, or null if one could not be allocated.
+ */
+struct usb_request *usb_ep_alloc_request(struct usb_ep *ep,
+                                                      gfp_t gfp_flags)
+{
+       struct usb_request *req = NULL;
+
+       req = ep->ops->alloc_request(ep, gfp_flags);
+
+       trace_usb_ep_alloc_request(ep, req, req ? 0 : -ENOMEM);
+
+       return req;
+}
+EXPORT_SYMBOL_GPL(usb_ep_alloc_request);
+
+/**
+ * usb_ep_free_request - frees a request object
+ * @ep:the endpoint associated with the request
+ * @req:the request being freed
+ *
+ * Reverses the effect of usb_ep_alloc_request().
+ * Caller guarantees the request is not queued, and that it will
+ * no longer be requeued (or otherwise used).
+ */
+void usb_ep_free_request(struct usb_ep *ep,
+                                      struct usb_request *req)
+{
+       ep->ops->free_request(ep, req);
+       trace_usb_ep_free_request(ep, req, 0);
+}
+EXPORT_SYMBOL_GPL(usb_ep_free_request);
+
+/**
+ * usb_ep_queue - queues (submits) an I/O request to an endpoint.
+ * @ep:the endpoint associated with the request
+ * @req:the request being submitted
+ * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
+ *     pre-allocate all necessary memory with the request.
+ *
+ * This tells the device controller to perform the specified request through
+ * that endpoint (reading or writing a buffer).  When the request completes,
+ * including being canceled by usb_ep_dequeue(), the request's completion
+ * routine is called to return the request to the driver.  Any endpoint
+ * (except control endpoints like ep0) may have more than one transfer
+ * request queued; they complete in FIFO order.  Once a gadget driver
+ * submits a request, that request may not be examined or modified until it
+ * is given back to that driver through the completion callback.
+ *
+ * Each request is turned into one or more packets.  The controller driver
+ * never merges adjacent requests into the same packet.  OUT transfers
+ * will sometimes use data that's already buffered in the hardware.
+ * Drivers can rely on the fact that the first byte of the request's buffer
+ * always corresponds to the first byte of some USB packet, for both
+ * IN and OUT transfers.
+ *
+ * Bulk endpoints can queue any amount of data; the transfer is packetized
+ * automatically.  The last packet will be short if the request doesn't fill it
+ * out completely.  Zero length packets (ZLPs) should be avoided in portable
+ * protocols since not all usb hardware can successfully handle zero length
+ * packets.  (ZLPs may be explicitly written, and may be implicitly written if
+ * the request 'zero' flag is set.)  Bulk endpoints may also be used
+ * for interrupt transfers; but the reverse is not true, and some endpoints
+ * won't support every interrupt transfer.  (Such as 768 byte packets.)
+ *
+ * Interrupt-only endpoints are less functional than bulk endpoints, for
+ * example by not supporting queueing or not handling buffers that are
+ * larger than the endpoint's maxpacket size.  They may also treat data
+ * toggle differently.
+ *
+ * Control endpoints ... after getting a setup() callback, the driver queues
+ * one response (even if it would be zero length).  That enables the
+ * status ack, after transferring data as specified in the response.  Setup
+ * functions may return negative error codes to generate protocol stalls.
+ * (Note that some USB device controllers disallow protocol stall responses
+ * in some cases.)  When control responses are deferred (the response is
+ * written after the setup callback returns), then usb_ep_set_halt() may be
+ * used on ep0 to trigger protocol stalls.  Depending on the controller,
+ * it may not be possible to trigger a status-stage protocol stall when the
+ * data stage is over, that is, from within the response's completion
+ * routine.
+ *
+ * For periodic endpoints, like interrupt or isochronous ones, the usb host
+ * arranges to poll once per interval, and the gadget driver usually will
+ * have queued some data to transfer at that time.
+ *
+ * Returns zero, or a negative error code.  Endpoints that are not enabled
+ * report errors; errors will also be
+ * reported when the usb peripheral is disconnected.
+ */
+int usb_ep_queue(struct usb_ep *ep,
+                              struct usb_request *req, gfp_t gfp_flags)
+{
+       int ret = 0;
+
+       if (WARN_ON_ONCE(!ep->enabled && ep->address)) {
+               ret = -ESHUTDOWN;
+               goto out;
+       }
+
+       ret = ep->ops->queue(ep, req, gfp_flags);
+
+out:
+       trace_usb_ep_queue(ep, req, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_ep_queue);
+
+/**
+ * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint
+ * @ep:the endpoint associated with the request
+ * @req:the request being canceled
+ *
+ * If the request is still active on the endpoint, it is dequeued and its
+ * completion routine is called (with status -ECONNRESET); else a negative
+ * error code is returned. This is guaranteed to happen before the call to
+ * usb_ep_dequeue() returns.
+ *
+ * Note that some hardware can't clear out write fifos (to unlink the request
+ * at the head of the queue) except as part of disconnecting from usb. Such
+ * restrictions prevent drivers from supporting configuration changes,
+ * even to configuration zero (a "chapter 9" requirement).
+ */
+int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+       int ret;
+
+       ret = ep->ops->dequeue(ep, req);
+       trace_usb_ep_dequeue(ep, req, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_ep_dequeue);
+
+/**
+ * usb_ep_set_halt - sets the endpoint halt feature.
+ * @ep: the non-isochronous endpoint being stalled
+ *
+ * Use this to stall an endpoint, perhaps as an error report.
+ * Except for control endpoints,
+ * the endpoint stays halted (will not stream any data) until the host
+ * clears this feature; drivers may need to empty the endpoint's request
+ * queue first, to make sure no inappropriate transfers happen.
+ *
+ * Note that while an endpoint CLEAR_FEATURE will be invisible to the
+ * gadget driver, a SET_INTERFACE will not be.  To reset endpoints for the
+ * current altsetting, see usb_ep_clear_halt().  When switching altsettings,
+ * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints.
+ *
+ * Returns zero, or a negative error code.  On success, this call sets
+ * underlying hardware state that blocks data transfers.
+ * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
+ * transfer requests are still queued, or if the controller hardware
+ * (usually a FIFO) still holds bytes that the host hasn't collected.
+ */
+int usb_ep_set_halt(struct usb_ep *ep)
+{
+       int ret;
+
+       ret = ep->ops->set_halt(ep, 1);
+       trace_usb_ep_set_halt(ep, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_ep_set_halt);
+
+/**
+ * usb_ep_clear_halt - clears endpoint halt, and resets toggle
+ * @ep:the bulk or interrupt endpoint being reset
+ *
+ * Use this when responding to the standard usb "set interface" request,
+ * for endpoints that aren't reconfigured, after clearing any other state
+ * in the endpoint's i/o queue.
+ *
+ * Returns zero, or a negative error code.  On success, this call clears
+ * the underlying hardware state reflecting endpoint halt and data toggle.
+ * Note that some hardware can't support this request (like pxa2xx_udc),
+ * and accordingly can't correctly implement interface altsettings.
+ */
+int usb_ep_clear_halt(struct usb_ep *ep)
+{
+       int ret;
+
+       ret = ep->ops->set_halt(ep, 0);
+       trace_usb_ep_clear_halt(ep, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_ep_clear_halt);
+
+/**
+ * usb_ep_set_wedge - sets the halt feature and ignores clear requests
+ * @ep: the endpoint being wedged
+ *
+ * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
+ * requests. If the gadget driver clears the halt status, it will
+ * automatically unwedge the endpoint.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_ep_set_wedge(struct usb_ep *ep)
+{
+       int ret;
+
+       if (ep->ops->set_wedge)
+               ret = ep->ops->set_wedge(ep);
+       else
+               ret = ep->ops->set_halt(ep, 1);
+
+       trace_usb_ep_set_wedge(ep, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_ep_set_wedge);
+
+/**
+ * usb_ep_fifo_status - returns number of bytes in fifo, or error
+ * @ep: the endpoint whose fifo status is being checked.
+ *
+ * FIFO endpoints may have "unclaimed data" in them in certain cases,
+ * such as after aborted transfers.  Hosts may not have collected all
+ * the IN data written by the gadget driver (and reported by a request
+ * completion).  The gadget driver may not have collected all the data
+ * written OUT to it by the host.  Drivers that need precise handling for
+ * fault reporting or recovery may need to use this call.
+ *
+ * This returns the number of such bytes in the fifo, or a negative
+ * errno if the endpoint doesn't use a FIFO or doesn't support such
+ * precise handling.
+ */
+int usb_ep_fifo_status(struct usb_ep *ep)
+{
+       int ret;
+
+       if (ep->ops->fifo_status)
+               ret = ep->ops->fifo_status(ep);
+       else
+               ret = -EOPNOTSUPP;
+
+       trace_usb_ep_fifo_status(ep, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_ep_fifo_status);
+
+/**
+ * usb_ep_fifo_flush - flushes contents of a fifo
+ * @ep: the endpoint whose fifo is being flushed.
+ *
+ * This call may be used to flush the "unclaimed data" that may exist in
+ * an endpoint fifo after abnormal transaction terminations.  The call
+ * must never be used except when endpoint is not being used for any
+ * protocol translation.
+ */
+void usb_ep_fifo_flush(struct usb_ep *ep)
+{
+       if (ep->ops->fifo_flush)
+               ep->ops->fifo_flush(ep);
+
+       trace_usb_ep_fifo_flush(ep, 0);
+}
+EXPORT_SYMBOL_GPL(usb_ep_fifo_flush);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_gadget_frame_number - returns the current frame number
+ * @gadget: controller that reports the frame number
+ *
+ * Returns the usb frame number, normally eleven bits from a SOF packet,
+ * or negative errno if this device doesn't support this capability.
+ */
+int usb_gadget_frame_number(struct usb_gadget *gadget)
+{
+       int ret;
+
+       ret = gadget->ops->get_frame(gadget);
+
+       trace_usb_gadget_frame_number(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_frame_number);
+
+/**
+ * usb_gadget_wakeup - tries to wake up the host connected to this gadget
+ * @gadget: controller used to wake up the host
+ *
+ * Returns zero on success, else negative error code if the hardware
+ * doesn't support such attempts, or its support has not been enabled
+ * by the usb host.  Drivers must return device descriptors that report
+ * their ability to support this, or hosts won't enable it.
+ *
+ * This may also try to use SRP to wake the host and start enumeration,
+ * even if OTG isn't otherwise in use.  OTG devices may also start
+ * remote wakeup even when hosts don't explicitly enable it.
+ */
+int usb_gadget_wakeup(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (!gadget->ops->wakeup) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       ret = gadget->ops->wakeup(gadget);
+
+out:
+       trace_usb_gadget_wakeup(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_wakeup);
+
+/**
+ * usb_gadget_set_selfpowered - sets the device selfpowered feature.
+ * @gadget:the device being declared as self-powered
+ *
+ * this affects the device status reported by the hardware driver
+ * to reflect that it now has a local power supply.
+ *
+ * returns zero on success, else negative errno.
+ */
+int usb_gadget_set_selfpowered(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (!gadget->ops->set_selfpowered) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       ret = gadget->ops->set_selfpowered(gadget, 1);
+
+out:
+       trace_usb_gadget_set_selfpowered(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_set_selfpowered);
+
+/**
+ * usb_gadget_clear_selfpowered - clear the device selfpowered feature.
+ * @gadget:the device being declared as bus-powered
+ *
+ * this affects the device status reported by the hardware driver.
+ * some hardware may not support bus-powered operation, in which
+ * case this feature's value can never change.
+ *
+ * returns zero on success, else negative errno.
+ */
+int usb_gadget_clear_selfpowered(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (!gadget->ops->set_selfpowered) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       ret = gadget->ops->set_selfpowered(gadget, 0);
+
+out:
+       trace_usb_gadget_clear_selfpowered(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_clear_selfpowered);
+
+/**
+ * usb_gadget_vbus_connect - Notify controller that VBUS is powered
+ * @gadget:The device which now has VBUS power.
+ * Context: can sleep
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session starting.  Common responses include
+ * resuming the controller, activating the D+ (or D-) pullup to let the
+ * host detect that a USB device is attached, and starting to draw power
+ * (8mA or possibly more, especially after SET_CONFIGURATION).
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_vbus_connect(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (!gadget->ops->vbus_session) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       ret = gadget->ops->vbus_session(gadget, 1);
+
+out:
+       trace_usb_gadget_vbus_connect(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_vbus_connect);
+
+/**
+ * usb_gadget_vbus_draw - constrain controller's VBUS power usage
+ * @gadget:The device whose VBUS usage is being described
+ * @mA:How much current to draw, in milliAmperes.  This should be twice
+ *     the value listed in the configuration descriptor bMaxPower field.
+ *
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume.  For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       int ret = 0;
+
+       if (!gadget->ops->vbus_draw) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       ret = gadget->ops->vbus_draw(gadget, mA);
+       if (!ret)
+               gadget->mA = mA;
+
+out:
+       trace_usb_gadget_vbus_draw(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_vbus_draw);
+
+/**
+ * usb_gadget_vbus_disconnect - notify controller about VBUS session end
+ * @gadget:the device whose VBUS supply is being described
+ * Context: can sleep
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session ending.  Common responses include
+ * reversing everything done in usb_gadget_vbus_connect().
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (!gadget->ops->vbus_session) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       ret = gadget->ops->vbus_session(gadget, 0);
+
+out:
+       trace_usb_gadget_vbus_disconnect(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect);
+
+/**
+ * usb_gadget_connect - software-controlled connect to USB host
+ * @gadget:the peripheral being connected
+ *
+ * Enables the D+ (or potentially D-) pullup.  The host will start
+ * enumerating this gadget when the pullup is active and a VBUS session
+ * is active (the link is powered).  This pullup is always enabled unless
+ * usb_gadget_disconnect() has been used to disable it.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_connect(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (!gadget->ops->pullup) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (gadget->deactivated) {
+               /*
+                * If gadget is deactivated we only save new state.
+                * Gadget will be connected automatically after activation.
+                */
+               gadget->connected = true;
+               goto out;
+       }
+
+       ret = gadget->ops->pullup(gadget, 1);
+       if (!ret)
+               gadget->connected = 1;
+
+out:
+       trace_usb_gadget_connect(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_connect);
+
+/**
+ * usb_gadget_disconnect - software-controlled disconnect from USB host
+ * @gadget:the peripheral being disconnected
+ *
+ * Disables the D+ (or potentially D-) pullup, which the host may see
+ * as a disconnect (when a VBUS session is active).  Not all systems
+ * support software pullup controls.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_disconnect(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (!gadget->ops->pullup) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (gadget->deactivated) {
+               /*
+                * If gadget is deactivated we only save new state.
+                * Gadget will stay disconnected after activation.
+                */
+               gadget->connected = false;
+               goto out;
+       }
+
+       ret = gadget->ops->pullup(gadget, 0);
+       if (!ret)
+               gadget->connected = 0;
+
+out:
+       trace_usb_gadget_disconnect(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
+
+/**
+ * usb_gadget_deactivate - deactivate function which is not ready to work
+ * @gadget: the peripheral being deactivated
+ *
+ * This routine may be used during the gadget driver bind() call to prevent
+ * the peripheral from ever being visible to the USB host, unless later
+ * usb_gadget_activate() is called.  For example, user mode components may
+ * need to be activated before the system can talk to hosts.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_deactivate(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (gadget->deactivated)
+               goto out;
+
+       if (gadget->connected) {
+               ret = usb_gadget_disconnect(gadget);
+               if (ret)
+                       goto out;
+
+               /*
+                * If gadget was being connected before deactivation, we want
+                * to reconnect it in usb_gadget_activate().
+                */
+               gadget->connected = true;
+       }
+       gadget->deactivated = true;
+
+out:
+       trace_usb_gadget_deactivate(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_deactivate);
+
+/**
+ * usb_gadget_activate - activate function which is not ready to work
+ * @gadget: the peripheral being activated
+ *
+ * This routine activates gadget which was previously deactivated with
+ * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_activate(struct usb_gadget *gadget)
+{
+       int ret = 0;
+
+       if (!gadget->deactivated)
+               goto out;
+
+       gadget->deactivated = false;
+
+       /*
+        * If gadget has been connected before deactivation, or became connected
+        * while it was being deactivated, we call usb_gadget_connect().
+        */
+       if (gadget->connected)
+               ret = usb_gadget_connect(gadget);
+
+out:
+       trace_usb_gadget_activate(gadget, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_activate);
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_HAS_DMA
+
+int usb_gadget_map_request_by_dev(struct device *dev,
+               struct usb_request *req, int is_in)
+{
+       if (req->length == 0)
+               return 0;
+
+       if (req->num_sgs) {
+               int     mapped;
+
+               mapped = dma_map_sg(dev, req->sg, req->num_sgs,
+                               is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               if (mapped == 0) {
+                       dev_err(dev, "failed to map SGs\n");
+                       return -EFAULT;
+               }
+
+               req->num_mapped_sgs = mapped;
+       } else {
+               req->dma = dma_map_single(dev, req->buf, req->length,
+                               is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+               if (dma_mapping_error(dev, req->dma)) {
+                       dev_err(dev, "failed to map buffer\n");
+                       return -EFAULT;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev);
+
+int usb_gadget_map_request(struct usb_gadget *gadget,
+               struct usb_request *req, int is_in)
+{
+       return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_map_request);
+
+void usb_gadget_unmap_request_by_dev(struct device *dev,
+               struct usb_request *req, int is_in)
+{
+       if (req->length == 0)
+               return;
+
+       if (req->num_mapped_sgs) {
+               dma_unmap_sg(dev, req->sg, req->num_mapped_sgs,
+                               is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+               req->num_mapped_sgs = 0;
+       } else {
+               dma_unmap_single(dev, req->dma, req->length,
+                               is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       }
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev);
+
+void usb_gadget_unmap_request(struct usb_gadget *gadget,
+               struct usb_request *req, int is_in)
+{
+       usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
+
+#endif /* CONFIG_HAS_DMA */
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_gadget_giveback_request - give the request back to the gadget layer
+ * Context: in_interrupt()
+ *
+ * This is called by device controller drivers in order to return the
+ * completed request back to the gadget layer.
+ */
+void usb_gadget_giveback_request(struct usb_ep *ep,
+               struct usb_request *req)
+{
+       if (likely(req->status == 0))
+               usb_led_activity(USB_LED_EVENT_GADGET);
+
+       trace_usb_gadget_giveback_request(ep, req, 0);
+
+       req->complete(ep, req);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * gadget_find_ep_by_name - returns ep whose name is the same as sting passed
+ *     in second parameter or NULL if searched endpoint not found
+ * @g: controller to check for quirk
+ * @name: name of searched endpoint
+ */
+struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name)
+{
+       struct usb_ep *ep;
+
+       gadget_for_each_ep(ep, g) {
+               if (!strcmp(ep->name, name))
+                       return ep;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(gadget_find_ep_by_name);
+
+/* ------------------------------------------------------------------------- */
+
+int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
+               struct usb_ep *ep, struct usb_endpoint_descriptor *desc,
+               struct usb_ss_ep_comp_descriptor *ep_comp)
+{
+       u8              type;
+       u16             max;
+       int             num_req_streams = 0;
+
+       /* endpoint already claimed? */
+       if (ep->claimed)
+               return 0;
+
+       type = usb_endpoint_type(desc);
+       max = 0x7ff & usb_endpoint_maxp(desc);
+
+       if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
+               return 0;
+       if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
+               return 0;
+
+       if (max > ep->maxpacket_limit)
+               return 0;
+
+       /* "high bandwidth" works only at high speed */
+       if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11))
+               return 0;
+
+       switch (type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               /* only support ep0 for portable CONTROL traffic */
+               return 0;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (!ep->caps.type_iso)
+                       return 0;
+               /* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
+               if (!gadget_is_dualspeed(gadget) && max > 1023)
+                       return 0;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               if (!ep->caps.type_bulk)
+                       return 0;
+               if (ep_comp && gadget_is_superspeed(gadget)) {
+                       /* Get the number of required streams from the
+                        * EP companion descriptor and see if the EP
+                        * matches it
+                        */
+                       num_req_streams = ep_comp->bmAttributes & 0x1f;
+                       if (num_req_streams > ep->max_streams)
+                               return 0;
+               }
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               /* Bulk endpoints handle interrupt transfers,
+                * except the toggle-quirky iso-synch kind
+                */
+               if (!ep->caps.type_int && !ep->caps.type_bulk)
+                       return 0;
+               /* INT:  limit 64 bytes full speed, 1024 high/super speed */
+               if (!gadget_is_dualspeed(gadget) && max > 64)
+                       return 0;
+               break;
+       }
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc);
+
+/* ------------------------------------------------------------------------- */
+
+static void usb_gadget_state_work(struct work_struct *work)
+{
+       struct usb_gadget *gadget = work_to_gadget(work);
+       struct usb_udc *udc = gadget->udc;
+
+       if (udc)
+               sysfs_notify(&udc->dev.kobj, NULL, "state");
+}
+
+void usb_gadget_set_state(struct usb_gadget *gadget,
+               enum usb_device_state state)
+{
+       gadget->state = state;
+       schedule_work(&gadget->work);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_set_state);
+
+/* ------------------------------------------------------------------------- */
+
+static void usb_udc_connect_control(struct usb_udc *udc)
+{
+       if (udc->vbus)
+               usb_gadget_connect(udc->gadget);
+       else
+               usb_gadget_disconnect(udc->gadget);
+}
+
+/**
+ * usb_udc_vbus_handler - updates the udc core vbus status, and try to
+ * connect or disconnect gadget
+ * @gadget: The gadget which vbus change occurs
+ * @status: The vbus status
+ *
+ * The udc driver calls it when it wants to connect or disconnect gadget
+ * according to vbus status.
+ */
+void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
+{
+       struct usb_udc *udc = gadget->udc;
+
+       if (udc) {
+               udc->vbus = status;
+               usb_udc_connect_control(udc);
+       }
+}
+EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
+
+/**
+ * usb_gadget_udc_reset - notifies the udc core that bus reset occurs
+ * @gadget: The gadget which bus reset occurs
+ * @driver: The gadget driver we want to notify
+ *
+ * If the udc driver has bus reset handler, it needs to call this when the bus
+ * reset occurs, it notifies the gadget driver that the bus reset occurs as
+ * well as updates gadget state.
+ */
+void usb_gadget_udc_reset(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
+{
+       driver->reset(gadget);
+       usb_gadget_set_state(gadget, USB_STATE_DEFAULT);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
+
+/**
+ * usb_gadget_udc_start - tells usb device controller to start up
+ * @udc: The UDC to be started
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_udc_start(struct usb_udc *udc)
+{
+       return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
+}
+
+/**
+ * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_udc_stop(struct usb_udc *udc)
+{
+       udc->gadget->ops->udc_stop(udc->gadget);
+}
+
+/**
+ * usb_udc_release - release the usb_udc struct
+ * @dev: the dev member within usb_udc
+ *
+ * This is called by driver's core in order to free memory once the last
+ * reference is released.
+ */
+static void usb_udc_release(struct device *dev)
+{
+       struct usb_udc *udc;
+
+       udc = container_of(dev, struct usb_udc, dev);
+       dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+       kfree(udc);
+}
+
+static const struct attribute_group *usb_udc_attr_groups[];
+
+static void usb_udc_nop_release(struct device *dev)
+{
+       dev_vdbg(dev, "%s\n", __func__);
+}
+
+/**
+ * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller driver's
+ * device.
+ * @gadget: the gadget to be added to the list.
+ * @release: a gadget release function.
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
+               void (*release)(struct device *dev))
+{
+       struct usb_udc          *udc;
+       struct usb_gadget_driver *driver;
+       int                     ret = -ENOMEM;
+
+       udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+       if (!udc)
+               goto err1;
+
+       dev_set_name(&gadget->dev, "gadget");
+       INIT_WORK(&gadget->work, usb_gadget_state_work);
+       gadget->dev.parent = parent;
+
+       if (release)
+               gadget->dev.release = release;
+       else
+               gadget->dev.release = usb_udc_nop_release;
+
+       ret = device_register(&gadget->dev);
+       if (ret)
+               goto err2;
+
+       device_initialize(&udc->dev);
+       udc->dev.release = usb_udc_release;
+       udc->dev.class = udc_class;
+       udc->dev.groups = usb_udc_attr_groups;
+       udc->dev.parent = parent;
+       ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
+       if (ret)
+               goto err3;
+
+       udc->gadget = gadget;
+       gadget->udc = udc;
+
+       mutex_lock(&udc_lock);
+       list_add_tail(&udc->list, &udc_list);
+
+       ret = device_add(&udc->dev);
+       if (ret)
+               goto err4;
+
+       usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
+       udc->vbus = true;
+
+       /* pick up one of pending gadget drivers */
+       list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
+               if (!driver->udc_name || strcmp(driver->udc_name,
+                                               dev_name(&udc->dev)) == 0) {
+                       ret = udc_bind_to_driver(udc, driver);
+                       if (ret != -EPROBE_DEFER)
+                               list_del(&driver->pending);
+                       if (ret)
+                               goto err4;
+                       break;
+               }
+       }
+
+       mutex_unlock(&udc_lock);
+
+       return 0;
+
+err4:
+       list_del(&udc->list);
+       mutex_unlock(&udc_lock);
+
+err3:
+       put_device(&udc->dev);
+       device_del(&gadget->dev);
+
+err2:
+       put_device(&gadget->dev);
+       kfree(udc);
+
+err1:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
+
+/**
+ * usb_get_gadget_udc_name - get the name of the first UDC controller
+ * This functions returns the name of the first UDC controller in the system.
+ * Please note that this interface is usefull only for legacy drivers which
+ * assume that there is only one UDC controller in the system and they need to
+ * get its name before initialization. There is no guarantee that the UDC
+ * of the returned name will be still available, when gadget driver registers
+ * itself.
+ *
+ * Returns pointer to string with UDC controller name on success, NULL
+ * otherwise. Caller should kfree() returned string.
+ */
+char *usb_get_gadget_udc_name(void)
+{
+       struct usb_udc *udc;
+       char *name = NULL;
+
+       /* For now we take the first available UDC */
+       mutex_lock(&udc_lock);
+       list_for_each_entry(udc, &udc_list, list) {
+               if (!udc->driver) {
+                       name = kstrdup(udc->gadget->name, GFP_KERNEL);
+                       break;
+               }
+       }
+       mutex_unlock(&udc_lock);
+       return name;
+}
+EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name);
+
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+       return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
+
+static void usb_gadget_remove_driver(struct usb_udc *udc)
+{
+       dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
+                       udc->driver->function);
+
+       kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+
+       usb_gadget_disconnect(udc->gadget);
+       udc->driver->disconnect(udc->gadget);
+       udc->driver->unbind(udc->gadget);
+       usb_gadget_udc_stop(udc);
+
+       udc->driver = NULL;
+       udc->dev.driver = NULL;
+       udc->gadget->dev.driver = NULL;
+}
+
+/**
+ * usb_del_gadget_udc - deletes @udc from udc_list
+ * @gadget: the gadget to be removed.
+ *
+ * This, will call usb_gadget_unregister_driver() if
+ * the @udc is still busy.
+ */
+void usb_del_gadget_udc(struct usb_gadget *gadget)
+{
+       struct usb_udc *udc = gadget->udc;
+
+       if (!udc)
+               return;
+
+       dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
+
+       mutex_lock(&udc_lock);
+       list_del(&udc->list);
+
+       if (udc->driver) {
+               struct usb_gadget_driver *driver = udc->driver;
+
+               usb_gadget_remove_driver(udc);
+               list_add(&driver->pending, &gadget_driver_pending_list);
+       }
+       mutex_unlock(&udc_lock);
+
+       kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
+       flush_work(&gadget->work);
+       device_unregister(&udc->dev);
+       device_unregister(&gadget->dev);
+}
+EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
+
+/* ------------------------------------------------------------------------- */
+
+static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
+{
+       int ret;
+
+       dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
+                       driver->function);
+
+       udc->driver = driver;
+       udc->dev.driver = &driver->driver;
+       udc->gadget->dev.driver = &driver->driver;
+
+       ret = driver->bind(udc->gadget, driver);
+       if (ret)
+               goto err1;
+       ret = usb_gadget_udc_start(udc);
+       if (ret) {
+               driver->unbind(udc->gadget);
+               goto err1;
+       }
+       usb_udc_connect_control(udc);
+
+       kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+       return 0;
+err1:
+       if (ret != -EISNAM)
+               dev_err(&udc->dev, "failed to start %s: %d\n",
+                       udc->driver->function, ret);
+       udc->driver = NULL;
+       udc->dev.driver = NULL;
+       udc->gadget->dev.driver = NULL;
+       return ret;
+}
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
+{
+       struct usb_udc          *udc = NULL;
+       int                     ret = -ENODEV;
+
+       if (!driver || !driver->bind || !driver->setup)
+               return -EINVAL;
+
+       mutex_lock(&udc_lock);
+       if (driver->udc_name) {
+               list_for_each_entry(udc, &udc_list, list) {
+                       ret = strcmp(driver->udc_name, dev_name(&udc->dev));
+                       if (!ret)
+                               break;
+               }
+               if (!ret && !udc->driver)
+                       goto found;
+       } else {
+               list_for_each_entry(udc, &udc_list, list) {
+                       /* For now we take the first one */
+                       if (!udc->driver)
+                               goto found;
+               }
+       }
+
+       if (!driver->match_existing_only) {
+               list_add_tail(&driver->pending, &gadget_driver_pending_list);
+               pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
+                       driver->function);
+               ret = 0;
+       }
+
+       mutex_unlock(&udc_lock);
+       return ret;
+found:
+       ret = udc_bind_to_driver(udc, driver);
+       mutex_unlock(&udc_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct usb_udc          *udc = NULL;
+       int                     ret = -ENODEV;
+
+       if (!driver || !driver->unbind)
+               return -EINVAL;
+
+       mutex_lock(&udc_lock);
+       list_for_each_entry(udc, &udc_list, list)
+               if (udc->driver == driver) {
+                       usb_gadget_remove_driver(udc);
+                       usb_gadget_set_state(udc->gadget,
+                                       USB_STATE_NOTATTACHED);
+                       ret = 0;
+                       break;
+               }
+
+       if (ret) {
+               list_del(&driver->pending);
+               ret = 0;
+       }
+       mutex_unlock(&udc_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
+
+/* ------------------------------------------------------------------------- */
+
+static ssize_t usb_udc_srp_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t n)
+{
+       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
+
+       if (sysfs_streq(buf, "1"))
+               usb_gadget_wakeup(udc->gadget);
+
+       return n;
+}
+static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
+
+static ssize_t usb_udc_softconn_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t n)
+{
+       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
+
+       if (!udc->driver) {
+               dev_err(dev, "soft-connect without a gadget driver\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (sysfs_streq(buf, "connect")) {
+               usb_gadget_udc_start(udc);
+               usb_gadget_connect(udc->gadget);
+       } else if (sysfs_streq(buf, "disconnect")) {
+               usb_gadget_disconnect(udc->gadget);
+               udc->driver->disconnect(udc->gadget);
+               usb_gadget_udc_stop(udc);
+       } else {
+               dev_err(dev, "unsupported command '%s'\n", buf);
+               return -EINVAL;
+       }
+
+       return n;
+}
+static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
+       struct usb_gadget       *gadget = udc->gadget;
+
+       return sprintf(buf, "%s\n", usb_state_string(gadget->state));
+}
+static DEVICE_ATTR_RO(state);
+
+#define USB_UDC_SPEED_ATTR(name, param)                                        \
+ssize_t name##_show(struct device *dev,                                        \
+               struct device_attribute *attr, char *buf)               \
+{                                                                      \
+       struct usb_udc *udc = container_of(dev, struct usb_udc, dev);   \
+       return snprintf(buf, PAGE_SIZE, "%s\n",                         \
+                       usb_speed_string(udc->gadget->param));          \
+}                                                                      \
+static DEVICE_ATTR_RO(name)
+
+static USB_UDC_SPEED_ATTR(current_speed, speed);
+static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
+
+#define USB_UDC_ATTR(name)                                     \
+ssize_t name##_show(struct device *dev,                                \
+               struct device_attribute *attr, char *buf)       \
+{                                                              \
+       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev); \
+       struct usb_gadget       *gadget = udc->gadget;          \
+                                                               \
+       return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name);  \
+}                                                              \
+static DEVICE_ATTR_RO(name)
+
+static USB_UDC_ATTR(is_otg);
+static USB_UDC_ATTR(is_a_peripheral);
+static USB_UDC_ATTR(b_hnp_enable);
+static USB_UDC_ATTR(a_hnp_support);
+static USB_UDC_ATTR(a_alt_hnp_support);
+static USB_UDC_ATTR(is_selfpowered);
+
+static struct attribute *usb_udc_attrs[] = {
+       &dev_attr_srp.attr,
+       &dev_attr_soft_connect.attr,
+       &dev_attr_state.attr,
+       &dev_attr_current_speed.attr,
+       &dev_attr_maximum_speed.attr,
+
+       &dev_attr_is_otg.attr,
+       &dev_attr_is_a_peripheral.attr,
+       &dev_attr_b_hnp_enable.attr,
+       &dev_attr_a_hnp_support.attr,
+       &dev_attr_a_alt_hnp_support.attr,
+       &dev_attr_is_selfpowered.attr,
+       NULL,
+};
+
+static const struct attribute_group usb_udc_attr_group = {
+       .attrs = usb_udc_attrs,
+};
+
+static const struct attribute_group *usb_udc_attr_groups[] = {
+       &usb_udc_attr_group,
+       NULL,
+};
+
+static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
+       int                     ret;
+
+       ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name);
+       if (ret) {
+               dev_err(dev, "failed to add uevent USB_UDC_NAME\n");
+               return ret;
+       }
+
+       if (udc->driver) {
+               ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
+                               udc->driver->function);
+               if (ret) {
+                       dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int __init usb_udc_init(void)
+{
+       udc_class = class_create(THIS_MODULE, "udc");
+       if (IS_ERR(udc_class)) {
+               pr_err("failed to create udc class --> %ld\n",
+                               PTR_ERR(udc_class));
+               return PTR_ERR(udc_class);
+       }
+
+       udc_class->dev_uevent = usb_udc_uevent;
+       return 0;
+}
+subsys_initcall(usb_udc_init);
+
+static void __exit usb_udc_exit(void)
+{
+       class_destroy(udc_class);
+}
+module_exit(usb_udc_exit);
+
+MODULE_DESCRIPTION("UDC Framework");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
index dde4445..77d0790 100644 (file)
@@ -647,12 +647,10 @@ static int dummy_disable(struct usb_ep *_ep)
 static struct usb_request *dummy_alloc_request(struct usb_ep *_ep,
                gfp_t mem_flags)
 {
-       struct dummy_ep         *ep;
        struct dummy_request    *req;
 
        if (!_ep)
                return NULL;
-       ep = usb_ep_to_dummy_ep(_ep);
 
        req = kzalloc(sizeof(*req), mem_flags);
        if (!req)
@@ -2444,9 +2442,6 @@ static int dummy_start(struct usb_hcd *hcd)
 
 static void dummy_stop(struct usb_hcd *hcd)
 {
-       struct dummy            *dum;
-
-       dum = hcd_to_dummy_hcd(hcd)->dum;
        device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
        dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
 }
index b1cfa96..6e977dc 100644 (file)
@@ -1199,8 +1199,6 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
        struct m66592 *m66592 = _m66592;
        u16 intsts0;
        u16 intenb0;
-       u16 brdysts, nrdysts, bempsts;
-       u16 brdyenb, nrdyenb, bempenb;
        u16 savepipe;
        u16 mask0;
 
@@ -1224,12 +1222,10 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
 
        mask0 = intsts0 & intenb0;
        if (mask0) {
-               brdysts = m66592_read(m66592, M66592_BRDYSTS);
-               nrdysts = m66592_read(m66592, M66592_NRDYSTS);
-               bempsts = m66592_read(m66592, M66592_BEMPSTS);
-               brdyenb = m66592_read(m66592, M66592_BRDYENB);
-               nrdyenb = m66592_read(m66592, M66592_NRDYENB);
-               bempenb = m66592_read(m66592, M66592_BEMPENB);
+               u16 brdysts = m66592_read(m66592, M66592_BRDYSTS);
+               u16 bempsts = m66592_read(m66592, M66592_BEMPSTS);
+               u16 brdyenb = m66592_read(m66592, M66592_BRDYENB);
+               u16 bempenb = m66592_read(m66592, M66592_BEMPENB);
 
                if (mask0 & M66592_VBINT) {
                        m66592_write(m66592,  0xffff & ~M66592_VBINT,
@@ -1408,28 +1404,20 @@ static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 
 static int m66592_set_halt(struct usb_ep *_ep, int value)
 {
-       struct m66592_ep *ep;
-       struct m66592_request *req;
+       struct m66592_ep *ep = container_of(_ep, struct m66592_ep, ep);
        unsigned long flags;
        int ret = 0;
 
-       ep = container_of(_ep, struct m66592_ep, ep);
-       req = list_entry(ep->queue.next, struct m66592_request, queue);
-
        spin_lock_irqsave(&ep->m66592->lock, flags);
        if (!list_empty(&ep->queue)) {
                ret = -EAGAIN;
-               goto out;
-       }
-       if (value) {
+       } else if (value) {
                ep->busy = 1;
                pipe_stall(ep->m66592, ep->pipenum);
        } else {
                ep->busy = 0;
                pipe_stop(ep->m66592, ep->pipenum);
        }
-
-out:
        spin_unlock_irqrestore(&ep->m66592->lock, flags);
        return ret;
 }
index dafe74e..b9e19a5 100644 (file)
@@ -119,18 +119,14 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
        struct mv_u3d_req *curr_req)
 {
        struct mv_u3d_trb       *curr_trb;
-       dma_addr_t cur_deq_lo;
-       struct mv_u3d_ep_context        *curr_ep_context;
-       int trb_complete, actual, remaining_length = 0;
+       int actual, remaining_length = 0;
        int direction, ep_num;
        int retval = 0;
        u32 tmp, status, length;
 
-       curr_ep_context = &u3d->ep_context[index];
        direction = index % 2;
        ep_num = index / 2;
 
-       trb_complete = 0;
        actual = curr_req->req.length;
 
        while (!list_empty(&curr_req->trb_list)) {
@@ -143,15 +139,10 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
                }
 
                curr_trb->trb_hw->ctrl.own = 0;
-               if (direction == MV_U3D_EP_DIR_OUT) {
+               if (direction == MV_U3D_EP_DIR_OUT)
                        tmp = ioread32(&u3d->vuc_regs->rxst[ep_num].statuslo);
-                       cur_deq_lo =
-                               ioread32(&u3d->vuc_regs->rxst[ep_num].curdeqlo);
-               } else {
+               else
                        tmp = ioread32(&u3d->vuc_regs->txst[ep_num].statuslo);
-                       cur_deq_lo =
-                               ioread32(&u3d->vuc_regs->txst[ep_num].curdeqlo);
-               }
 
                status = tmp >> MV_U3D_XFERSTATUS_COMPLETE_SHIFT;
                length = tmp & MV_U3D_XFERSTATUS_TRB_LENGTH_MASK;
@@ -527,7 +518,6 @@ static int mv_u3d_ep_enable(struct usb_ep *_ep,
 {
        struct mv_u3d *u3d;
        struct mv_u3d_ep *ep;
-       struct mv_u3d_ep_context *ep_context;
        u16 max = 0;
        unsigned maxburst = 0;
        u32 epxcr, direction;
@@ -548,9 +538,6 @@ static int mv_u3d_ep_enable(struct usb_ep *_ep,
                _ep->maxburst = 1;
        maxburst = _ep->maxburst;
 
-       /* Get the endpoint context address */
-       ep_context = (struct mv_u3d_ep_context *)ep->ep_context;
-
        /* Set the max burst size */
        switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
        case USB_ENDPOINT_XFER_BULK:
@@ -633,7 +620,6 @@ static int  mv_u3d_ep_disable(struct usb_ep *_ep)
 {
        struct mv_u3d *u3d;
        struct mv_u3d_ep *ep;
-       struct mv_u3d_ep_context *ep_context;
        u32 epxcr, direction;
        unsigned long flags;
 
@@ -646,9 +632,6 @@ static int  mv_u3d_ep_disable(struct usb_ep *_ep)
 
        u3d = ep->u3d;
 
-       /* Get the endpoint context address */
-       ep_context = ep->ep_context;
-
        direction = mv_u3d_ep_dir(ep);
 
        /* nuke all pending requests (does flush) */
index 81b6229..ce73b35 100644 (file)
@@ -129,7 +129,7 @@ static int process_ep_req(struct mv_udc *udc, int index,
 {
        struct mv_dtd   *curr_dtd;
        struct mv_dqh   *curr_dqh;
-       int td_complete, actual, remaining_length;
+       int actual, remaining_length;
        int i, direction;
        int retval = 0;
        u32 errors;
@@ -139,7 +139,6 @@ static int process_ep_req(struct mv_udc *udc, int index,
        direction = index % 2;
 
        curr_dtd = curr_req->head;
-       td_complete = 0;
        actual = curr_req->req.length;
 
        for (i = 0; i < curr_req->dtd_count; i++) {
@@ -412,11 +411,8 @@ static int req_to_dtd(struct mv_req *req)
        unsigned count;
        int is_last, is_first = 1;
        struct mv_dtd *dtd, *last_dtd = NULL;
-       struct mv_udc *udc;
        dma_addr_t dma;
 
-       udc = req->ep->udc;
-
        do {
                dtd = build_dtd(req, &count, &dma, &is_last);
                if (dtd == NULL)
@@ -567,7 +563,7 @@ static int  mv_ep_disable(struct usb_ep *_ep)
        struct mv_udc *udc;
        struct mv_ep *ep;
        struct mv_dqh *dqh;
-       u32 bit_pos, epctrlx, direction;
+       u32 epctrlx, direction;
        unsigned long flags;
 
        ep = container_of(_ep, struct mv_ep, ep);
@@ -582,7 +578,6 @@ static int  mv_ep_disable(struct usb_ep *_ep)
        spin_lock_irqsave(&udc->lock, flags);
 
        direction = ep_dir(ep);
-       bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
 
        /* Reset the max packet length and the interrupt on Setup */
        dqh->max_packet_length = 0;
index 18f5ebd..7c61134 100644 (file)
@@ -329,12 +329,10 @@ static int net2272_disable(struct usb_ep *_ep)
 static struct usb_request *
 net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
 {
-       struct net2272_ep *ep;
        struct net2272_request *req;
 
        if (!_ep)
                return NULL;
-       ep = container_of(_ep, struct net2272_ep, ep);
 
        req = kzalloc(sizeof(*req), gfp_flags);
        if (!req)
@@ -348,10 +346,8 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
 static void
 net2272_free_request(struct usb_ep *_ep, struct usb_request *_req)
 {
-       struct net2272_ep *ep;
        struct net2272_request *req;
 
-       ep = container_of(_ep, struct net2272_ep, ep);
        if (!_ep || !_req)
                return;
 
index c894b94..614ab95 100644 (file)
@@ -211,7 +211,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                goto print_err;
        }
 
-       if (dev->quirks & PLX_SUPERSPEED) {
+       if (dev->quirks & PLX_PCIE) {
                if ((desc->bEndpointAddress & 0x0f) >= 0x0c) {
                        ret = -EDOM;
                        goto print_err;
@@ -245,7 +245,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        /* set type, direction, address; reset fifo counters */
        writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
 
-       if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) {
+       if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) {
                tmp = readl(&ep->cfg->ep_cfg);
                /* If USB ep number doesn't match hardware ep number */
                if ((tmp & 0xf) != usb_endpoint_num(desc)) {
@@ -316,7 +316,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                        BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
        }
 
-       if (dev->quirks & PLX_SUPERSPEED)
+       if (dev->quirks & PLX_PCIE)
                ep_clear_seqnum(ep);
        writel(tmp, &ep->cfg->ep_cfg);
 
@@ -527,7 +527,7 @@ static int net2280_disable(struct usb_ep *_ep)
        spin_lock_irqsave(&ep->dev->lock, flags);
        nuke(ep);
 
-       if (ep->dev->quirks & PLX_SUPERSPEED)
+       if (ep->dev->quirks & PLX_PCIE)
                ep_reset_338x(ep->dev->regs, ep);
        else
                ep_reset_228x(ep->dev->regs, ep);
@@ -862,7 +862,7 @@ static void start_queue(struct net2280_ep *ep, u32 dmactl, u32 td_dma)
        writel(readl(&dma->dmastat), &dma->dmastat);
 
        writel(td_dma, &dma->dmadesc);
-       if (ep->dev->quirks & PLX_SUPERSPEED)
+       if (ep->dev->quirks & PLX_PCIE)
                dmactl |= BIT(DMA_REQUEST_OUTSTANDING);
        writel(dmactl, &dma->dmactl);
 
@@ -1046,7 +1046,7 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
        /* kickstart this i/o queue? */
        if  (list_empty(&ep->queue) && !ep->stopped &&
-               !((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
+               !((dev->quirks & PLX_PCIE) && ep->dma &&
                  (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
 
                /* use DMA if the endpoint supports it, else pio */
@@ -1169,7 +1169,7 @@ static void scan_dma_completions(struct net2280_ep *ep)
                        break;
                } else if (!ep->is_in &&
                           (req->req.length % ep->ep.maxpacket) &&
-                          !(ep->dev->quirks & PLX_SUPERSPEED)) {
+                          !(ep->dev->quirks & PLX_PCIE)) {
 
                        tmp = readl(&ep->regs->ep_stat);
                        /* AVOID TROUBLE HERE by not issuing short reads from
@@ -1367,7 +1367,7 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
                                ep->wedged = 1;
                } else {
                        clear_halt(ep);
-                       if (ep->dev->quirks & PLX_SUPERSPEED &&
+                       if (ep->dev->quirks & PLX_PCIE &&
                                !list_empty(&ep->queue) && ep->td_dma)
                                        restart_dma(ep);
                        ep->wedged = 0;
@@ -2394,7 +2394,7 @@ static int net2280_start(struct usb_gadget *_gadget,
         */
        net2280_led_active(dev, 1);
 
-       if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
+       if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched)
                defect7374_enable_data_eps_zero(dev);
 
        ep0_start(dev);
@@ -3063,7 +3063,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
                }
                ep->stopped = 0;
                dev->protocol_stall = 0;
-               if (!(dev->quirks & PLX_SUPERSPEED)) {
+               if (!(dev->quirks & PLX_PCIE)) {
                        if (ep->dev->quirks & PLX_2280)
                                tmp = BIT(FIFO_OVERFLOW) |
                                    BIT(FIFO_UNDERFLOW);
@@ -3090,7 +3090,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
                cpu_to_le32s(&u.raw[0]);
                cpu_to_le32s(&u.raw[1]);
 
-               if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
+               if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched)
                        defect7374_workaround(dev, u.r);
 
                tmp = 0;
@@ -3173,7 +3173,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
                        } else {
                                ep_vdbg(dev, "%s clear halt\n", e->ep.name);
                                clear_halt(e);
-                               if ((ep->dev->quirks & PLX_SUPERSPEED) &&
+                               if ((ep->dev->quirks & PLX_PCIE) &&
                                        !list_empty(&e->queue) && e->td_dma)
                                                restart_dma(e);
                        }
@@ -3195,7 +3195,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
                        if (e->ep.name == ep0name)
                                goto do_stall;
                        set_halt(e);
-                       if ((dev->quirks & PLX_SUPERSPEED) && e->dma)
+                       if ((dev->quirks & PLX_PCIE) && e->dma)
                                abort_dma(e);
                        allow_status(ep);
                        ep_vdbg(dev, "%s set halt\n", ep->ep.name);
@@ -3234,7 +3234,7 @@ do_stall:
 #undef w_length
 
 next_endpoints:
-       if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) {
+       if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) {
                u32 mask = (BIT(ENDPOINT_0_INTERRUPT) |
                        USB3380_IRQSTAT0_EP_INTR_MASK_IN |
                        USB3380_IRQSTAT0_EP_INTR_MASK_OUT);
@@ -3399,7 +3399,7 @@ __acquires(dev->lock)
                writel(tmp, &dma->dmastat);
 
                /* dma sync*/
-               if (dev->quirks & PLX_SUPERSPEED) {
+               if (dev->quirks & PLX_PCIE) {
                        u32 r_dmacount = readl(&dma->dmacount);
                        if (!ep->is_in &&  (r_dmacount & 0x00FFFFFF) &&
                            (tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT)))
@@ -3468,7 +3468,7 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
        /* control requests and PIO */
        handle_stat0_irqs(dev, readl(&dev->regs->irqstat0));
 
-       if (dev->quirks & PLX_SUPERSPEED) {
+       if (dev->quirks & PLX_PCIE) {
                /* re-enable interrupt to trigger any possible new interrupt */
                u32 pciirqenb1 = readl(&dev->regs->pciirqenb1);
                writel(pciirqenb1 & 0x7FFFFFFF, &dev->regs->pciirqenb1);
@@ -3513,7 +3513,7 @@ static void net2280_remove(struct pci_dev *pdev)
        }
        if (dev->got_irq)
                free_irq(pdev->irq, dev);
-       if (dev->quirks & PLX_SUPERSPEED)
+       if (dev->quirks & PLX_PCIE)
                pci_disable_msi(pdev);
        if (dev->regs)
                iounmap(dev->regs);
@@ -3593,7 +3593,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200);
        dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300);
 
-       if (dev->quirks & PLX_SUPERSPEED) {
+       if (dev->quirks & PLX_PCIE) {
                u32 fsmvalue;
                u32 usbstat;
                dev->usb_ext = (struct usb338x_usb_ext_regs __iomem *)
@@ -3637,7 +3637,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto done;
        }
 
-       if (dev->quirks & PLX_SUPERSPEED)
+       if (dev->quirks & PLX_PCIE)
                if (pci_enable_msi(pdev))
                        ep_err(dev, "Failed to enable MSI mode\n");
 
@@ -3755,10 +3755,19 @@ static const struct pci_device_id pci_ids[] = { {
        .class =        PCI_CLASS_SERIAL_USB_DEVICE,
        .class_mask =   ~0,
        .vendor =       PCI_VENDOR_ID_PLX,
+       .device =       0x2380,
+       .subvendor =    PCI_ANY_ID,
+       .subdevice =    PCI_ANY_ID,
+       .driver_data =  PLX_PCIE,
+        },
+       {
+       .class =        ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+       .class_mask =   ~0,
+       .vendor =       PCI_VENDOR_ID_PLX,
        .device =       0x3380,
        .subvendor =    PCI_ANY_ID,
        .subdevice =    PCI_ANY_ID,
-       .driver_data =  PLX_SUPERSPEED,
+       .driver_data =  PLX_PCIE | PLX_SUPERSPEED,
         },
        {
        .class =        PCI_CLASS_SERIAL_USB_DEVICE,
@@ -3767,7 +3776,7 @@ static const struct pci_device_id pci_ids[] = { {
        .device =       0x3382,
        .subvendor =    PCI_ANY_ID,
        .subdevice =    PCI_ANY_ID,
-       .driver_data =  PLX_SUPERSPEED,
+       .driver_data =  PLX_PCIE | PLX_SUPERSPEED,
         },
 { /* end: all zeroes */ }
 };
index 0d32052..2736a95 100644 (file)
@@ -47,6 +47,7 @@ set_idx_reg(struct net2280_regs __iomem *regs, u32 index, u32 value)
 #define PLX_LEGACY             BIT(0)
 #define PLX_2280               BIT(1)
 #define PLX_SUPERSPEED         BIT(2)
+#define PLX_PCIE               BIT(3)
 
 #define REG_DIAG               0x0
 #define     RETRY_COUNTER                                       16
index ebc51ec..a97da64 100644 (file)
@@ -1477,11 +1477,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
                req->dma_mapped = 0;
        }
        ep->halted = 1;
-       spin_lock(&dev->lock);
+       spin_unlock(&dev->lock);
        if (!ep->in)
                pch_udc_ep_clear_rrdy(ep);
        usb_gadget_giveback_request(&ep->ep, &req->req);
-       spin_unlock(&dev->lock);
+       spin_lock(&dev->lock);
        ep->halted = halted;
 }
 
@@ -1984,9 +1984,8 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
                        if (ep->num == PCH_UDC_EP0)
                                ep->dev->stall = 1;
                        pch_udc_ep_set_stall(ep);
-                       pch_udc_enable_ep_interrupts(ep->dev,
-                                                    PCH_UDC_EPINT(ep->in,
-                                                                  ep->num));
+                       pch_udc_enable_ep_interrupts(
+                               ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
                } else {
                        pch_udc_ep_clear_stall(ep);
                }
@@ -2451,16 +2450,11 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
  */
 static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num)
 {
-       struct pch_udc_ep       *ep;
-       struct pch_udc_request *req;
-
-       ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
-       if (!list_empty(&ep->queue)) {
-               req = list_entry(ep->queue.next, struct pch_udc_request, queue);
-               pch_udc_enable_ep_interrupts(ep->dev,
-                                            PCH_UDC_EPINT(ep->in, ep->num));
-               pch_udc_ep_clear_nak(ep);
-       }
+       struct pch_udc_ep       *ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
+       if (list_empty(&ep->queue))
+               return;
+       pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
+       pch_udc_ep_clear_nak(ep);
 }
 
 /**
@@ -2573,9 +2567,9 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
                empty_req_queue(ep);
        }
        if (dev->driver) {
-               spin_lock(&dev->lock);
-               usb_gadget_udc_reset(&dev->gadget, dev->driver);
                spin_unlock(&dev->lock);
+               usb_gadget_udc_reset(&dev->gadget, dev->driver);
+               spin_lock(&dev->lock);
        }
 }
 
@@ -2654,9 +2648,9 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
                dev->ep[i].halted = 0;
        }
        dev->stall = 0;
-       spin_lock(&dev->lock);
-       dev->driver->setup(&dev->gadget, &dev->setup_data);
        spin_unlock(&dev->lock);
+       dev->driver->setup(&dev->gadget, &dev->setup_data);
+       spin_lock(&dev->lock);
 }
 
 /**
@@ -2691,9 +2685,9 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
        dev->stall = 0;
 
        /* call gadget zero with setup data received */
-       spin_lock(&dev->lock);
-       dev->driver->setup(&dev->gadget, &dev->setup_data);
        spin_unlock(&dev->lock);
+       dev->driver->setup(&dev->gadget, &dev->setup_data);
+       spin_lock(&dev->lock);
 }
 
 /**
index 001a3b7..ad140aa 100644 (file)
@@ -1825,13 +1825,10 @@ fail:
  * Disables all udc endpoints (even control endpoint), report disconnect to
  * the gadget user.
  */
-static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
+static void stop_activity(struct pxa_udc *udc)
 {
        int i;
 
-       /* don't disconnect drivers more than once */
-       if (udc->gadget.speed == USB_SPEED_UNKNOWN)
-               driver = NULL;
        udc->gadget.speed = USB_SPEED_UNKNOWN;
 
        for (i = 0; i < NR_USB_ENDPOINTS; i++)
@@ -1848,7 +1845,7 @@ static int pxa27x_udc_stop(struct usb_gadget *g)
 {
        struct pxa_udc *udc = to_pxa(g);
 
-       stop_activity(udc, NULL);
+       stop_activity(udc);
        udc_disable(udc);
 
        udc->driver = NULL;
@@ -2296,7 +2293,7 @@ static void irq_udc_reset(struct pxa_udc *udc)
 
        if ((udccr & UDCCR_UDA) == 0) {
                dev_dbg(udc->dev, "USB reset start\n");
-               stop_activity(udc, udc->driver);
+               stop_activity(udc);
        }
        udc->gadget.speed = USB_SPEED_FULL;
        memset(&udc->stats, 0, sizeof udc->stats);
index 8b300e6..f2c8862 100644 (file)
@@ -1464,8 +1464,6 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
        struct r8a66597 *r8a66597 = _r8a66597;
        u16 intsts0;
        u16 intenb0;
-       u16 brdysts, nrdysts, bempsts;
-       u16 brdyenb, nrdyenb, bempenb;
        u16 savepipe;
        u16 mask0;
 
@@ -1481,12 +1479,10 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
 
        mask0 = intsts0 & intenb0;
        if (mask0) {
-               brdysts = r8a66597_read(r8a66597, BRDYSTS);
-               nrdysts = r8a66597_read(r8a66597, NRDYSTS);
-               bempsts = r8a66597_read(r8a66597, BEMPSTS);
-               brdyenb = r8a66597_read(r8a66597, BRDYENB);
-               nrdyenb = r8a66597_read(r8a66597, NRDYENB);
-               bempenb = r8a66597_read(r8a66597, BEMPENB);
+               u16 brdysts = r8a66597_read(r8a66597, BRDYSTS);
+               u16 bempsts = r8a66597_read(r8a66597, BEMPSTS);
+               u16 brdyenb = r8a66597_read(r8a66597, BRDYENB);
+               u16 bempenb = r8a66597_read(r8a66597, BEMPENB);
 
                if (mask0 & VBINT) {
                        r8a66597_write(r8a66597,  0xffff & ~VBINT,
@@ -1658,20 +1654,14 @@ static int r8a66597_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 
 static int r8a66597_set_halt(struct usb_ep *_ep, int value)
 {
-       struct r8a66597_ep *ep;
-       struct r8a66597_request *req;
+       struct r8a66597_ep *ep = container_of(_ep, struct r8a66597_ep, ep);
        unsigned long flags;
        int ret = 0;
 
-       ep = container_of(_ep, struct r8a66597_ep, ep);
-       req = get_request_from_ep(ep);
-
        spin_lock_irqsave(&ep->r8a66597->lock, flags);
        if (!list_empty(&ep->queue)) {
                ret = -EAGAIN;
-               goto out;
-       }
-       if (value) {
+       } else if (value) {
                ep->busy = 1;
                pipe_stall(ep->r8a66597, ep->pipenum);
        } else {
@@ -1679,8 +1669,6 @@ static int r8a66597_set_halt(struct usb_ep *_ep, int value)
                ep->wedge = 0;
                pipe_stop(ep->r8a66597, ep->pipenum);
        }
-
-out:
        spin_unlock_irqrestore(&ep->r8a66597->lock, flags);
        return ret;
 }
diff --git a/drivers/usb/gadget/udc/trace.c b/drivers/usb/gadget/udc/trace.c
new file mode 100644 (file)
index 0000000..8c551ab
--- /dev/null
@@ -0,0 +1,18 @@
+/**
+ * trace.c - USB Gadget Framework Trace Support
+ *
+ * Copyright (C) 2016 Intel Corporation
+ * Author: Felipe Balbi <felipe.balbi@linux.intel.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.
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h
new file mode 100644 (file)
index 0000000..da29874
--- /dev/null
@@ -0,0 +1,298 @@
+/**
+ * udc.c - Core UDC Framework
+ *
+ * Copyright (C) 2016 Intel Corporation
+ * Author: Felipe Balbi <felipe.balbi@linux.intel.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/>.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM gadget
+
+#if !defined(__UDC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __UDC_TRACE_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+#include <asm/byteorder.h>
+#include <linux/usb/gadget.h>
+
+DECLARE_EVENT_CLASS(udc_log_gadget,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret),
+       TP_STRUCT__entry(
+               __field(enum usb_device_speed, speed)
+               __field(enum usb_device_speed, max_speed)
+               __field(enum usb_device_state, state)
+               __field(unsigned, mA)
+               __field(unsigned, sg_supported)
+               __field(unsigned, is_otg)
+               __field(unsigned, is_a_peripheral)
+               __field(unsigned, b_hnp_enable)
+               __field(unsigned, a_hnp_support)
+               __field(unsigned, hnp_polling_support)
+               __field(unsigned, host_request_flag)
+               __field(unsigned, quirk_ep_out_aligned_size)
+               __field(unsigned, quirk_altset_not_supp)
+               __field(unsigned, quirk_stall_not_supp)
+               __field(unsigned, quirk_zlp_not_supp)
+               __field(unsigned, is_selfpowered)
+               __field(unsigned, deactivated)
+               __field(unsigned, connected)
+               __field(int, ret)
+       ),
+       TP_fast_assign(
+               __entry->speed = g->speed;
+               __entry->max_speed = g->max_speed;
+               __entry->state = g->state;
+               __entry->mA = g->mA;
+               __entry->sg_supported = g->sg_supported;
+               __entry->is_otg = g->is_otg;
+               __entry->is_a_peripheral = g->is_a_peripheral;
+               __entry->b_hnp_enable = g->b_hnp_enable;
+               __entry->a_hnp_support = g->a_hnp_support;
+               __entry->hnp_polling_support = g->hnp_polling_support;
+               __entry->host_request_flag = g->host_request_flag;
+               __entry->quirk_ep_out_aligned_size = g->quirk_ep_out_aligned_size;
+               __entry->quirk_altset_not_supp = g->quirk_altset_not_supp;
+               __entry->quirk_stall_not_supp = g->quirk_stall_not_supp;
+               __entry->quirk_zlp_not_supp = g->quirk_zlp_not_supp;
+               __entry->is_selfpowered = g->is_selfpowered;
+               __entry->deactivated = g->deactivated;
+               __entry->connected = g->connected;
+               __entry->ret = ret;
+       ),
+       TP_printk("speed %d/%d state %d %dmA [%s%s%s%s%s%s%s%s%s%s%s%s%s%s] --> %d",
+               __entry->speed, __entry->max_speed, __entry->state, __entry->mA,
+               __entry->sg_supported ? "sg:" : "",
+               __entry->is_otg ? "OTG:" : "",
+               __entry->is_a_peripheral ? "a_peripheral:" : "",
+               __entry->b_hnp_enable ? "b_hnp:" : "",
+               __entry->a_hnp_support ? "a_hnp:" : "",
+               __entry->hnp_polling_support ? "hnp_poll:" : "",
+               __entry->host_request_flag ? "hostreq:" : "",
+               __entry->quirk_ep_out_aligned_size ? "out_aligned:" : "",
+               __entry->quirk_altset_not_supp ? "no_altset:" : "",
+               __entry->quirk_stall_not_supp ? "no_stall:" : "",
+               __entry->quirk_zlp_not_supp ? "no_zlp" : "",
+               __entry->is_selfpowered ? "self-powered:" : "bus-powered:",
+               __entry->deactivated ? "deactivated:" : "activated:",
+               __entry->connected ? "connected" : "disconnected",
+               __entry->ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_frame_number,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_wakeup,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_set_selfpowered,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_clear_selfpowered,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_connect,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_draw,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_disconnect,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_connect,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_disconnect,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_deactivate,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DEFINE_EVENT(udc_log_gadget, usb_gadget_activate,
+       TP_PROTO(struct usb_gadget *g, int ret),
+       TP_ARGS(g, ret)
+);
+
+DECLARE_EVENT_CLASS(udc_log_ep,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret),
+       TP_STRUCT__entry(
+               __dynamic_array(char, name, UDC_TRACE_STR_MAX)
+               __field(unsigned, maxpacket)
+               __field(unsigned, maxpacket_limit)
+               __field(unsigned, max_streams)
+               __field(unsigned, mult)
+               __field(unsigned, maxburst)
+               __field(u8, address)
+               __field(bool, claimed)
+               __field(bool, enabled)
+               __field(int, ret)
+       ),
+       TP_fast_assign(
+               snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name);
+               __entry->maxpacket = ep->maxpacket;
+               __entry->maxpacket_limit = ep->maxpacket_limit;
+               __entry->max_streams = ep->max_streams;
+               __entry->mult = ep->mult;
+               __entry->maxburst = ep->maxburst;
+               __entry->address = ep->address,
+               __entry->claimed = ep->claimed;
+               __entry->enabled = ep->enabled;
+               __entry->ret = ret;
+       ),
+       TP_printk("%s: mps %d/%d streams %d mult %d burst %d addr %02x %s%s --> %d",
+               __get_str(name), __entry->maxpacket, __entry->maxpacket_limit,
+               __entry->max_streams, __entry->mult, __entry->maxburst,
+               __entry->address, __entry->claimed ? "claimed:" : "released:",
+               __entry->enabled ? "enabled" : "disabled", ret)
+);
+
+DEFINE_EVENT(udc_log_ep, usb_ep_set_maxpacket_limit,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret)
+);
+
+DEFINE_EVENT(udc_log_ep, usb_ep_enable,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret)
+);
+
+DEFINE_EVENT(udc_log_ep, usb_ep_disable,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret)
+);
+
+DEFINE_EVENT(udc_log_ep, usb_ep_set_halt,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret)
+);
+
+DEFINE_EVENT(udc_log_ep, usb_ep_clear_halt,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret)
+);
+
+DEFINE_EVENT(udc_log_ep, usb_ep_set_wedge,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret)
+);
+
+DEFINE_EVENT(udc_log_ep, usb_ep_fifo_status,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret)
+);
+
+DEFINE_EVENT(udc_log_ep, usb_ep_fifo_flush,
+       TP_PROTO(struct usb_ep *ep, int ret),
+       TP_ARGS(ep, ret)
+);
+
+DECLARE_EVENT_CLASS(udc_log_req,
+       TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
+       TP_ARGS(ep, req, ret),
+       TP_STRUCT__entry(
+               __dynamic_array(char, name, UDC_TRACE_STR_MAX)
+               __field(unsigned, length)
+               __field(unsigned, actual)
+               __field(unsigned, num_sgs)
+               __field(unsigned, num_mapped_sgs)
+               __field(unsigned, stream_id)
+               __field(unsigned, no_interrupt)
+               __field(unsigned, zero)
+               __field(unsigned, short_not_ok)
+               __field(int, status)
+               __field(int, ret)
+       ),
+       TP_fast_assign(
+               snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name);
+               __entry->length = req->length;
+               __entry->actual = req->actual;
+               __entry->num_sgs = req->num_sgs;
+               __entry->num_mapped_sgs = req->num_mapped_sgs;
+               __entry->stream_id = req->stream_id;
+               __entry->no_interrupt = req->no_interrupt;
+               __entry->zero = req->zero;
+               __entry->short_not_ok = req->short_not_ok;
+               __entry->status = req->status;
+               __entry->ret = ret;
+       ),
+       TP_printk("%s: length %d/%d sgs %d/%d stream %d %s%s%s status %d --> %d",
+               __get_str(name), __entry->actual, __entry->length,
+               __entry->num_mapped_sgs, __entry->num_sgs, __entry->stream_id,
+               __entry->zero ? "Z" : "z",
+               __entry->short_not_ok ? "S" : "s",
+               __entry->no_interrupt ? "i" : "I",
+               __entry->status, __entry->ret
+       )
+);
+
+DEFINE_EVENT(udc_log_req, usb_ep_alloc_request,
+       TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
+       TP_ARGS(ep, req, ret)
+);
+
+DEFINE_EVENT(udc_log_req, usb_ep_free_request,
+       TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
+       TP_ARGS(ep, req, ret)
+);
+
+DEFINE_EVENT(udc_log_req, usb_ep_queue,
+       TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
+       TP_ARGS(ep, req, ret)
+);
+
+DEFINE_EVENT(udc_log_req, usb_ep_dequeue,
+       TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
+       TP_ARGS(ep, req, ret)
+);
+
+DEFINE_EVENT(udc_log_req, usb_gadget_giveback_request,
+       TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
+       TP_ARGS(ep, req, ret)
+);
+
+#endif /* __UDC_TRACE_H */
+
+/* this part has to be here */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
deleted file mode 100644 (file)
index e1b2dce..0000000
+++ /dev/null
@@ -1,800 +0,0 @@
-/**
- * udc.c - Core UDC Framework
- *
- * Copyright (C) 2010 Texas Instruments
- * Author: Felipe Balbi <balbi@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/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/err.h>
-#include <linux/dma-mapping.h>
-#include <linux/workqueue.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb.h>
-
-/**
- * struct usb_udc - describes one usb device controller
- * @driver - the gadget driver pointer. For use by the class code
- * @dev - the child device to the actual controller
- * @gadget - the gadget. For use by the class code
- * @list - for use by the udc class driver
- * @vbus - for udcs who care about vbus status, this value is real vbus status;
- * for udcs who do not care about vbus status, this value is always true
- *
- * This represents the internal data structure which is used by the UDC-class
- * to hold information about udc driver and gadget together.
- */
-struct usb_udc {
-       struct usb_gadget_driver        *driver;
-       struct usb_gadget               *gadget;
-       struct device                   dev;
-       struct list_head                list;
-       bool                            vbus;
-};
-
-static struct class *udc_class;
-static LIST_HEAD(udc_list);
-static LIST_HEAD(gadget_driver_pending_list);
-static DEFINE_MUTEX(udc_lock);
-
-static int udc_bind_to_driver(struct usb_udc *udc,
-               struct usb_gadget_driver *driver);
-
-/* ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_HAS_DMA
-
-int usb_gadget_map_request_by_dev(struct device *dev,
-               struct usb_request *req, int is_in)
-{
-       if (req->length == 0)
-               return 0;
-
-       if (req->num_sgs) {
-               int     mapped;
-
-               mapped = dma_map_sg(dev, req->sg, req->num_sgs,
-                               is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               if (mapped == 0) {
-                       dev_err(dev, "failed to map SGs\n");
-                       return -EFAULT;
-               }
-
-               req->num_mapped_sgs = mapped;
-       } else {
-               req->dma = dma_map_single(dev, req->buf, req->length,
-                               is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
-               if (dma_mapping_error(dev, req->dma)) {
-                       dev_err(dev, "failed to map buffer\n");
-                       return -EFAULT;
-               }
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev);
-
-int usb_gadget_map_request(struct usb_gadget *gadget,
-               struct usb_request *req, int is_in)
-{
-       return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in);
-}
-EXPORT_SYMBOL_GPL(usb_gadget_map_request);
-
-void usb_gadget_unmap_request_by_dev(struct device *dev,
-               struct usb_request *req, int is_in)
-{
-       if (req->length == 0)
-               return;
-
-       if (req->num_mapped_sgs) {
-               dma_unmap_sg(dev, req->sg, req->num_mapped_sgs,
-                               is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
-               req->num_mapped_sgs = 0;
-       } else {
-               dma_unmap_single(dev, req->dma, req->length,
-                               is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-       }
-}
-EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev);
-
-void usb_gadget_unmap_request(struct usb_gadget *gadget,
-               struct usb_request *req, int is_in)
-{
-       usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in);
-}
-EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
-
-#endif /* CONFIG_HAS_DMA */
-
-/* ------------------------------------------------------------------------- */
-
-/**
- * usb_gadget_giveback_request - give the request back to the gadget layer
- * Context: in_interrupt()
- *
- * This is called by device controller drivers in order to return the
- * completed request back to the gadget layer.
- */
-void usb_gadget_giveback_request(struct usb_ep *ep,
-               struct usb_request *req)
-{
-       if (likely(req->status == 0))
-               usb_led_activity(USB_LED_EVENT_GADGET);
-
-       req->complete(ep, req);
-}
-EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
-
-/* ------------------------------------------------------------------------- */
-
-/**
- * gadget_find_ep_by_name - returns ep whose name is the same as sting passed
- *     in second parameter or NULL if searched endpoint not found
- * @g: controller to check for quirk
- * @name: name of searched endpoint
- */
-struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name)
-{
-       struct usb_ep *ep;
-
-       gadget_for_each_ep(ep, g) {
-               if (!strcmp(ep->name, name))
-                       return ep;
-       }
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(gadget_find_ep_by_name);
-
-/* ------------------------------------------------------------------------- */
-
-int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
-               struct usb_ep *ep, struct usb_endpoint_descriptor *desc,
-               struct usb_ss_ep_comp_descriptor *ep_comp)
-{
-       u8              type;
-       u16             max;
-       int             num_req_streams = 0;
-
-       /* endpoint already claimed? */
-       if (ep->claimed)
-               return 0;
-
-       type = usb_endpoint_type(desc);
-       max = 0x7ff & usb_endpoint_maxp(desc);
-
-       if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
-               return 0;
-       if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
-               return 0;
-
-       if (max > ep->maxpacket_limit)
-               return 0;
-
-       /* "high bandwidth" works only at high speed */
-       if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11))
-               return 0;
-
-       switch (type) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               /* only support ep0 for portable CONTROL traffic */
-               return 0;
-       case USB_ENDPOINT_XFER_ISOC:
-               if (!ep->caps.type_iso)
-                       return 0;
-               /* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
-               if (!gadget_is_dualspeed(gadget) && max > 1023)
-                       return 0;
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               if (!ep->caps.type_bulk)
-                       return 0;
-               if (ep_comp && gadget_is_superspeed(gadget)) {
-                       /* Get the number of required streams from the
-                        * EP companion descriptor and see if the EP
-                        * matches it
-                        */
-                       num_req_streams = ep_comp->bmAttributes & 0x1f;
-                       if (num_req_streams > ep->max_streams)
-                               return 0;
-               }
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               /* Bulk endpoints handle interrupt transfers,
-                * except the toggle-quirky iso-synch kind
-                */
-               if (!ep->caps.type_int && !ep->caps.type_bulk)
-                       return 0;
-               /* INT:  limit 64 bytes full speed, 1024 high/super speed */
-               if (!gadget_is_dualspeed(gadget) && max > 64)
-                       return 0;
-               break;
-       }
-
-       return 1;
-}
-EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc);
-
-/* ------------------------------------------------------------------------- */
-
-static void usb_gadget_state_work(struct work_struct *work)
-{
-       struct usb_gadget *gadget = work_to_gadget(work);
-       struct usb_udc *udc = gadget->udc;
-
-       if (udc)
-               sysfs_notify(&udc->dev.kobj, NULL, "state");
-}
-
-void usb_gadget_set_state(struct usb_gadget *gadget,
-               enum usb_device_state state)
-{
-       gadget->state = state;
-       schedule_work(&gadget->work);
-}
-EXPORT_SYMBOL_GPL(usb_gadget_set_state);
-
-/* ------------------------------------------------------------------------- */
-
-static void usb_udc_connect_control(struct usb_udc *udc)
-{
-       if (udc->vbus)
-               usb_gadget_connect(udc->gadget);
-       else
-               usb_gadget_disconnect(udc->gadget);
-}
-
-/**
- * usb_udc_vbus_handler - updates the udc core vbus status, and try to
- * connect or disconnect gadget
- * @gadget: The gadget which vbus change occurs
- * @status: The vbus status
- *
- * The udc driver calls it when it wants to connect or disconnect gadget
- * according to vbus status.
- */
-void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
-{
-       struct usb_udc *udc = gadget->udc;
-
-       if (udc) {
-               udc->vbus = status;
-               usb_udc_connect_control(udc);
-       }
-}
-EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
-
-/**
- * usb_gadget_udc_reset - notifies the udc core that bus reset occurs
- * @gadget: The gadget which bus reset occurs
- * @driver: The gadget driver we want to notify
- *
- * If the udc driver has bus reset handler, it needs to call this when the bus
- * reset occurs, it notifies the gadget driver that the bus reset occurs as
- * well as updates gadget state.
- */
-void usb_gadget_udc_reset(struct usb_gadget *gadget,
-               struct usb_gadget_driver *driver)
-{
-       driver->reset(gadget);
-       usb_gadget_set_state(gadget, USB_STATE_DEFAULT);
-}
-EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
-
-/**
- * usb_gadget_udc_start - tells usb device controller to start up
- * @udc: The UDC to be started
- *
- * This call is issued by the UDC Class driver when it's about
- * to register a gadget driver to the device controller, before
- * calling gadget driver's bind() method.
- *
- * It allows the controller to be powered off until strictly
- * necessary to have it powered on.
- *
- * Returns zero on success, else negative errno.
- */
-static inline int usb_gadget_udc_start(struct usb_udc *udc)
-{
-       return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
-}
-
-/**
- * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
- * @gadget: The device we want to stop activity
- * @driver: The driver to unbind from @gadget
- *
- * This call is issued by the UDC Class driver after calling
- * gadget driver's unbind() method.
- *
- * The details are implementation specific, but it can go as
- * far as powering off UDC completely and disable its data
- * line pullups.
- */
-static inline void usb_gadget_udc_stop(struct usb_udc *udc)
-{
-       udc->gadget->ops->udc_stop(udc->gadget);
-}
-
-/**
- * usb_udc_release - release the usb_udc struct
- * @dev: the dev member within usb_udc
- *
- * This is called by driver's core in order to free memory once the last
- * reference is released.
- */
-static void usb_udc_release(struct device *dev)
-{
-       struct usb_udc *udc;
-
-       udc = container_of(dev, struct usb_udc, dev);
-       dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
-       kfree(udc);
-}
-
-static const struct attribute_group *usb_udc_attr_groups[];
-
-static void usb_udc_nop_release(struct device *dev)
-{
-       dev_vdbg(dev, "%s\n", __func__);
-}
-
-/**
- * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
- * @parent: the parent device to this udc. Usually the controller driver's
- * device.
- * @gadget: the gadget to be added to the list.
- * @release: a gadget release function.
- *
- * Returns zero on success, negative errno otherwise.
- */
-int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
-               void (*release)(struct device *dev))
-{
-       struct usb_udc          *udc;
-       struct usb_gadget_driver *driver;
-       int                     ret = -ENOMEM;
-
-       udc = kzalloc(sizeof(*udc), GFP_KERNEL);
-       if (!udc)
-               goto err1;
-
-       dev_set_name(&gadget->dev, "gadget");
-       INIT_WORK(&gadget->work, usb_gadget_state_work);
-       gadget->dev.parent = parent;
-
-       if (release)
-               gadget->dev.release = release;
-       else
-               gadget->dev.release = usb_udc_nop_release;
-
-       ret = device_register(&gadget->dev);
-       if (ret)
-               goto err2;
-
-       device_initialize(&udc->dev);
-       udc->dev.release = usb_udc_release;
-       udc->dev.class = udc_class;
-       udc->dev.groups = usb_udc_attr_groups;
-       udc->dev.parent = parent;
-       ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
-       if (ret)
-               goto err3;
-
-       udc->gadget = gadget;
-       gadget->udc = udc;
-
-       mutex_lock(&udc_lock);
-       list_add_tail(&udc->list, &udc_list);
-
-       ret = device_add(&udc->dev);
-       if (ret)
-               goto err4;
-
-       usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
-       udc->vbus = true;
-
-       /* pick up one of pending gadget drivers */
-       list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
-               if (!driver->udc_name || strcmp(driver->udc_name,
-                                               dev_name(&udc->dev)) == 0) {
-                       ret = udc_bind_to_driver(udc, driver);
-                       if (ret != -EPROBE_DEFER)
-                               list_del(&driver->pending);
-                       if (ret)
-                               goto err4;
-                       break;
-               }
-       }
-
-       mutex_unlock(&udc_lock);
-
-       return 0;
-
-err4:
-       list_del(&udc->list);
-       mutex_unlock(&udc_lock);
-
-err3:
-       put_device(&udc->dev);
-       device_del(&gadget->dev);
-
-err2:
-       put_device(&gadget->dev);
-       kfree(udc);
-
-err1:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
-
-/**
- * usb_get_gadget_udc_name - get the name of the first UDC controller
- * This functions returns the name of the first UDC controller in the system.
- * Please note that this interface is usefull only for legacy drivers which
- * assume that there is only one UDC controller in the system and they need to
- * get its name before initialization. There is no guarantee that the UDC
- * of the returned name will be still available, when gadget driver registers
- * itself.
- *
- * Returns pointer to string with UDC controller name on success, NULL
- * otherwise. Caller should kfree() returned string.
- */
-char *usb_get_gadget_udc_name(void)
-{
-       struct usb_udc *udc;
-       char *name = NULL;
-
-       /* For now we take the first available UDC */
-       mutex_lock(&udc_lock);
-       list_for_each_entry(udc, &udc_list, list) {
-               if (!udc->driver) {
-                       name = kstrdup(udc->gadget->name, GFP_KERNEL);
-                       break;
-               }
-       }
-       mutex_unlock(&udc_lock);
-       return name;
-}
-EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name);
-
-/**
- * usb_add_gadget_udc - adds a new gadget to the udc class driver list
- * @parent: the parent device to this udc. Usually the controller
- * driver's device.
- * @gadget: the gadget to be added to the list
- *
- * Returns zero on success, negative errno otherwise.
- */
-int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
-{
-       return usb_add_gadget_udc_release(parent, gadget, NULL);
-}
-EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
-
-static void usb_gadget_remove_driver(struct usb_udc *udc)
-{
-       dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
-                       udc->driver->function);
-
-       kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
-
-       usb_gadget_disconnect(udc->gadget);
-       udc->driver->disconnect(udc->gadget);
-       udc->driver->unbind(udc->gadget);
-       usb_gadget_udc_stop(udc);
-
-       udc->driver = NULL;
-       udc->dev.driver = NULL;
-       udc->gadget->dev.driver = NULL;
-}
-
-/**
- * usb_del_gadget_udc - deletes @udc from udc_list
- * @gadget: the gadget to be removed.
- *
- * This, will call usb_gadget_unregister_driver() if
- * the @udc is still busy.
- */
-void usb_del_gadget_udc(struct usb_gadget *gadget)
-{
-       struct usb_udc *udc = gadget->udc;
-
-       if (!udc)
-               return;
-
-       dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
-
-       mutex_lock(&udc_lock);
-       list_del(&udc->list);
-
-       if (udc->driver) {
-               struct usb_gadget_driver *driver = udc->driver;
-
-               usb_gadget_remove_driver(udc);
-               list_add(&driver->pending, &gadget_driver_pending_list);
-       }
-       mutex_unlock(&udc_lock);
-
-       kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
-       flush_work(&gadget->work);
-       device_unregister(&udc->dev);
-       device_unregister(&gadget->dev);
-}
-EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
-
-/* ------------------------------------------------------------------------- */
-
-static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
-{
-       int ret;
-
-       dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
-                       driver->function);
-
-       udc->driver = driver;
-       udc->dev.driver = &driver->driver;
-       udc->gadget->dev.driver = &driver->driver;
-
-       ret = driver->bind(udc->gadget, driver);
-       if (ret)
-               goto err1;
-       ret = usb_gadget_udc_start(udc);
-       if (ret) {
-               driver->unbind(udc->gadget);
-               goto err1;
-       }
-       usb_udc_connect_control(udc);
-
-       kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
-       return 0;
-err1:
-       if (ret != -EISNAM)
-               dev_err(&udc->dev, "failed to start %s: %d\n",
-                       udc->driver->function, ret);
-       udc->driver = NULL;
-       udc->dev.driver = NULL;
-       udc->gadget->dev.driver = NULL;
-       return ret;
-}
-
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
-{
-       struct usb_udc          *udc = NULL;
-       int                     ret = -ENODEV;
-
-       if (!driver || !driver->bind || !driver->setup)
-               return -EINVAL;
-
-       mutex_lock(&udc_lock);
-       if (driver->udc_name) {
-               list_for_each_entry(udc, &udc_list, list) {
-                       ret = strcmp(driver->udc_name, dev_name(&udc->dev));
-                       if (!ret)
-                               break;
-               }
-               if (!ret && !udc->driver)
-                       goto found;
-       } else {
-               list_for_each_entry(udc, &udc_list, list) {
-                       /* For now we take the first one */
-                       if (!udc->driver)
-                               goto found;
-               }
-       }
-
-       if (!driver->match_existing_only) {
-               list_add_tail(&driver->pending, &gadget_driver_pending_list);
-               pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
-                       driver->function);
-               ret = 0;
-       }
-
-       mutex_unlock(&udc_lock);
-       return ret;
-found:
-       ret = udc_bind_to_driver(udc, driver);
-       mutex_unlock(&udc_lock);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
-
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
-{
-       struct usb_udc          *udc = NULL;
-       int                     ret = -ENODEV;
-
-       if (!driver || !driver->unbind)
-               return -EINVAL;
-
-       mutex_lock(&udc_lock);
-       list_for_each_entry(udc, &udc_list, list)
-               if (udc->driver == driver) {
-                       usb_gadget_remove_driver(udc);
-                       usb_gadget_set_state(udc->gadget,
-                                       USB_STATE_NOTATTACHED);
-                       ret = 0;
-                       break;
-               }
-
-       if (ret) {
-               list_del(&driver->pending);
-               ret = 0;
-       }
-       mutex_unlock(&udc_lock);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
-
-/* ------------------------------------------------------------------------- */
-
-static ssize_t usb_udc_srp_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t n)
-{
-       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
-
-       if (sysfs_streq(buf, "1"))
-               usb_gadget_wakeup(udc->gadget);
-
-       return n;
-}
-static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
-
-static ssize_t usb_udc_softconn_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t n)
-{
-       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
-
-       if (!udc->driver) {
-               dev_err(dev, "soft-connect without a gadget driver\n");
-               return -EOPNOTSUPP;
-       }
-
-       if (sysfs_streq(buf, "connect")) {
-               usb_gadget_udc_start(udc);
-               usb_gadget_connect(udc->gadget);
-       } else if (sysfs_streq(buf, "disconnect")) {
-               usb_gadget_disconnect(udc->gadget);
-               udc->driver->disconnect(udc->gadget);
-               usb_gadget_udc_stop(udc);
-       } else {
-               dev_err(dev, "unsupported command '%s'\n", buf);
-               return -EINVAL;
-       }
-
-       return n;
-}
-static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
-       struct usb_gadget       *gadget = udc->gadget;
-
-       return sprintf(buf, "%s\n", usb_state_string(gadget->state));
-}
-static DEVICE_ATTR_RO(state);
-
-#define USB_UDC_SPEED_ATTR(name, param)                                        \
-ssize_t name##_show(struct device *dev,                                        \
-               struct device_attribute *attr, char *buf)               \
-{                                                                      \
-       struct usb_udc *udc = container_of(dev, struct usb_udc, dev);   \
-       return snprintf(buf, PAGE_SIZE, "%s\n",                         \
-                       usb_speed_string(udc->gadget->param));          \
-}                                                                      \
-static DEVICE_ATTR_RO(name)
-
-static USB_UDC_SPEED_ATTR(current_speed, speed);
-static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
-
-#define USB_UDC_ATTR(name)                                     \
-ssize_t name##_show(struct device *dev,                                \
-               struct device_attribute *attr, char *buf)       \
-{                                                              \
-       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev); \
-       struct usb_gadget       *gadget = udc->gadget;          \
-                                                               \
-       return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name);  \
-}                                                              \
-static DEVICE_ATTR_RO(name)
-
-static USB_UDC_ATTR(is_otg);
-static USB_UDC_ATTR(is_a_peripheral);
-static USB_UDC_ATTR(b_hnp_enable);
-static USB_UDC_ATTR(a_hnp_support);
-static USB_UDC_ATTR(a_alt_hnp_support);
-static USB_UDC_ATTR(is_selfpowered);
-
-static struct attribute *usb_udc_attrs[] = {
-       &dev_attr_srp.attr,
-       &dev_attr_soft_connect.attr,
-       &dev_attr_state.attr,
-       &dev_attr_current_speed.attr,
-       &dev_attr_maximum_speed.attr,
-
-       &dev_attr_is_otg.attr,
-       &dev_attr_is_a_peripheral.attr,
-       &dev_attr_b_hnp_enable.attr,
-       &dev_attr_a_hnp_support.attr,
-       &dev_attr_a_alt_hnp_support.attr,
-       &dev_attr_is_selfpowered.attr,
-       NULL,
-};
-
-static const struct attribute_group usb_udc_attr_group = {
-       .attrs = usb_udc_attrs,
-};
-
-static const struct attribute_group *usb_udc_attr_groups[] = {
-       &usb_udc_attr_group,
-       NULL,
-};
-
-static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
-       int                     ret;
-
-       ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name);
-       if (ret) {
-               dev_err(dev, "failed to add uevent USB_UDC_NAME\n");
-               return ret;
-       }
-
-       if (udc->driver) {
-               ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
-                               udc->driver->function);
-               if (ret) {
-                       dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static int __init usb_udc_init(void)
-{
-       udc_class = class_create(THIS_MODULE, "udc");
-       if (IS_ERR(udc_class)) {
-               pr_err("failed to create udc class --> %ld\n",
-                               PTR_ERR(udc_class));
-               return PTR_ERR(udc_class);
-       }
-
-       udc_class->dev_uevent = usb_udc_uevent;
-       return 0;
-}
-subsys_initcall(usb_udc_init);
-
-static void __exit usb_udc_exit(void)
-{
-       class_destroy(udc_class);
-}
-module_exit(usb_udc_exit);
-
-MODULE_DESCRIPTION("UDC Framework");
-MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("GPL v2");
index 1cbb0ac..f8bf290 100644 (file)
@@ -2055,7 +2055,6 @@ static int xudc_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct resource *res;
        struct xusb_udc *udc;
-       struct xusb_ep *ep0;
        int irq;
        int ret;
        u32 ier;
@@ -2119,8 +2118,6 @@ static int xudc_probe(struct platform_device *pdev)
 
        xudc_eps_init(udc);
 
-       ep0 = &udc->ep[0];
-
        /* Set device address to 0.*/
        udc->write_fn(udc->addr, XUSB_ADDRESS_OFFSET, 0);
 
index d8f5674..2e710a4 100644 (file)
@@ -180,7 +180,7 @@ config USB_EHCI_MXC
 config USB_EHCI_HCD_OMAP
        tristate "EHCI support for OMAP3 and later chips"
        depends on ARCH_OMAP
-       select NOP_USB_XCEIV
+       depends on NOP_USB_XCEIV
        default y
        ---help---
          Enables support for the on-chip EHCI controller on
index bad0d1f..6afe323 100644 (file)
@@ -37,7 +37,9 @@
  * "All components of all Command and Transfer TRBs shall be initialized to '0'"
  */
 static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
-                                       unsigned int cycle_state, gfp_t flags)
+                                              unsigned int cycle_state,
+                                              unsigned int max_packet,
+                                              gfp_t flags)
 {
        struct xhci_segment *seg;
        dma_addr_t      dma;
@@ -53,6 +55,14 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
                return NULL;
        }
 
+       if (max_packet) {
+               seg->bounce_buf = kzalloc(max_packet, flags | GFP_DMA);
+               if (!seg->bounce_buf) {
+                       dma_pool_free(xhci->segment_pool, seg->trbs, dma);
+                       kfree(seg);
+                       return NULL;
+               }
+       }
        /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
        if (cycle_state == 0) {
                for (i = 0; i < TRBS_PER_SEGMENT; i++)
@@ -70,6 +80,7 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
                dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
                seg->trbs = NULL;
        }
+       kfree(seg->bounce_buf);
        kfree(seg);
 }
 
@@ -317,11 +328,11 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring,
 static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
                struct xhci_segment **first, struct xhci_segment **last,
                unsigned int num_segs, unsigned int cycle_state,
-               enum xhci_ring_type type, gfp_t flags)
+               enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
 {
        struct xhci_segment *prev;
 
-       prev = xhci_segment_alloc(xhci, cycle_state, flags);
+       prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
        if (!prev)
                return -ENOMEM;
        num_segs--;
@@ -330,7 +341,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
        while (num_segs > 0) {
                struct xhci_segment     *next;
 
-               next = xhci_segment_alloc(xhci, cycle_state, flags);
+               next = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
                if (!next) {
                        prev = *first;
                        while (prev) {
@@ -360,7 +371,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
  */
 static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
                unsigned int num_segs, unsigned int cycle_state,
-               enum xhci_ring_type type, gfp_t flags)
+               enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
 {
        struct xhci_ring        *ring;
        int ret;
@@ -370,13 +381,15 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
                return NULL;
 
        ring->num_segs = num_segs;
+       ring->bounce_buf_len = max_packet;
        INIT_LIST_HEAD(&ring->td_list);
        ring->type = type;
        if (num_segs == 0)
                return ring;
 
        ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
-                       &ring->last_seg, num_segs, cycle_state, type, flags);
+                       &ring->last_seg, num_segs, cycle_state, type,
+                       max_packet, flags);
        if (ret)
                goto fail;
 
@@ -470,7 +483,8 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
                        ring->num_segs : num_segs_needed;
 
        ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
-                       num_segs, ring->cycle_state, ring->type, flags);
+                       num_segs, ring->cycle_state, ring->type,
+                       ring->bounce_buf_len, flags);
        if (ret)
                return -ENOMEM;
 
@@ -652,7 +666,8 @@ struct xhci_ring *xhci_stream_id_to_ring(
  */
 struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
                unsigned int num_stream_ctxs,
-               unsigned int num_streams, gfp_t mem_flags)
+               unsigned int num_streams,
+               unsigned int max_packet, gfp_t mem_flags)
 {
        struct xhci_stream_info *stream_info;
        u32 cur_stream;
@@ -704,9 +719,11 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
         * and add their segment DMA addresses to the radix tree.
         * Stream 0 is reserved.
         */
+
        for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
                stream_info->stream_rings[cur_stream] =
-                       xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, mem_flags);
+                       xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, max_packet,
+                                       mem_flags);
                cur_ring = stream_info->stream_rings[cur_stream];
                if (!cur_ring)
                        goto cleanup_rings;
@@ -1003,7 +1020,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
        }
 
        /* Allocate endpoint 0 ring */
-       dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, flags);
+       dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, 0, flags);
        if (!dev->eps[0].ring)
                goto fail;
 
@@ -1434,22 +1451,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
                return -EINVAL;
 
        ring_type = usb_endpoint_type(&ep->desc);
-       /* Set up the endpoint ring */
-       virt_dev->eps[ep_index].new_ring =
-               xhci_ring_alloc(xhci, 2, 1, ring_type, mem_flags);
-       if (!virt_dev->eps[ep_index].new_ring) {
-               /* Attempt to use the ring cache */
-               if (virt_dev->num_rings_cached == 0)
-                       return -ENOMEM;
-               virt_dev->num_rings_cached--;
-               virt_dev->eps[ep_index].new_ring =
-                       virt_dev->ring_cache[virt_dev->num_rings_cached];
-               virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
-               xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
-                                       1, ring_type);
-       }
-       virt_dev->eps[ep_index].skip = false;
-       ep_ring = virt_dev->eps[ep_index].new_ring;
 
        /*
         * Get values to fill the endpoint context, mostly from ep descriptor.
@@ -1479,6 +1480,23 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
        if ((xhci->hci_version > 0x100) && HCC2_LEC(xhci->hcc_params2))
                mult = 0;
 
+       /* Set up the endpoint ring */
+       virt_dev->eps[ep_index].new_ring =
+               xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags);
+       if (!virt_dev->eps[ep_index].new_ring) {
+               /* Attempt to use the ring cache */
+               if (virt_dev->num_rings_cached == 0)
+                       return -ENOMEM;
+               virt_dev->num_rings_cached--;
+               virt_dev->eps[ep_index].new_ring =
+                       virt_dev->ring_cache[virt_dev->num_rings_cached];
+               virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
+               xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
+                                       1, ring_type);
+       }
+       virt_dev->eps[ep_index].skip = false;
+       ep_ring = virt_dev->eps[ep_index].new_ring;
+
        /* Fill the endpoint context */
        ep_ctx->ep_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
                                      EP_INTERVAL(interval) |
@@ -2409,7 +2427,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
                goto fail;
 
        /* Set up the command ring to have one segments for now. */
-       xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
+       xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, 0, flags);
        if (!xhci->cmd_ring)
                goto fail;
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@@ -2454,7 +2472,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
         */
        xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
        xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
-                                               flags);
+                                       0, flags);
        if (!xhci->event_ring)
                goto fail;
        if (xhci_check_trb_in_td_math(xhci) < 0)
index 1f3f981..ed56bf9 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/platform_device.h>
 #include <linux/usb/phy.h>
 #include <linux/slab.h>
-#include <linux/usb/xhci_pdriver.h>
 #include <linux/acpi.h>
 
 #include "xhci.h"
@@ -138,8 +137,6 @@ MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
 
 static int xhci_plat_probe(struct platform_device *pdev)
 {
-       struct device_node      *node = pdev->dev.of_node;
-       struct usb_xhci_pdata   *pdata = dev_get_platdata(&pdev->dev);
        const struct of_device_id *match;
        const struct hc_driver  *driver;
        struct xhci_hcd         *xhci;
@@ -202,7 +199,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
        }
 
        xhci = hcd_to_xhci(hcd);
-       match = of_match_node(usb_xhci_of_match, node);
+       match = of_match_node(usb_xhci_of_match, pdev->dev.of_node);
        if (match) {
                const struct xhci_plat_priv *priv_match = match->data;
                struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
@@ -223,8 +220,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
                goto disable_clk;
        }
 
-       if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
-                       (pdata && pdata->usb3_lpm_capable))
+       if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable"))
                xhci->quirks |= XHCI_LPM_SUPPORT;
 
        if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
index d7d5025..21e1dd6 100644 (file)
@@ -66,6 +66,7 @@
 
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/dma-mapping.h>
 #include "xhci.h"
 #include "xhci-trace.h"
 #include "xhci-mtk.h"
@@ -88,36 +89,25 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
        return seg->dma + (segment_offset * sizeof(*trb));
 }
 
-/* Does this link TRB point to the first segment in a ring,
- * or was the previous TRB the last TRB on the last segment in the ERST?
- */
-static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring,
-               struct xhci_segment *seg, union xhci_trb *trb)
+static bool trb_is_link(union xhci_trb *trb)
 {
-       if (ring == xhci->event_ring)
-               return (trb == &seg->trbs[TRBS_PER_SEGMENT]) &&
-                       (seg->next == xhci->event_ring->first_seg);
-       else
-               return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
+       return TRB_TYPE_LINK_LE32(trb->link.control);
 }
 
-/* Is this TRB a link TRB or was the last TRB the last TRB in this event ring
- * segment?  I.e. would the updated event TRB pointer step off the end of the
- * event seg?
- */
-static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
-               struct xhci_segment *seg, union xhci_trb *trb)
+static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb)
 {
-       if (ring == xhci->event_ring)
-               return trb == &seg->trbs[TRBS_PER_SEGMENT];
-       else
-               return TRB_TYPE_LINK_LE32(trb->link.control);
+       return trb == &seg->trbs[TRBS_PER_SEGMENT - 1];
 }
 
-static int enqueue_is_link_trb(struct xhci_ring *ring)
+static bool last_trb_on_ring(struct xhci_ring *ring,
+                       struct xhci_segment *seg, union xhci_trb *trb)
 {
-       struct xhci_link_trb *link = &ring->enqueue->link;
-       return TRB_TYPE_LINK_LE32(link->control);
+       return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg);
+}
+
+static bool link_trb_toggles_cycle(union xhci_trb *trb)
+{
+       return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
 }
 
 /* Updates trb to point to the next TRB in the ring, and updates seg if the next
@@ -129,7 +119,7 @@ static void next_trb(struct xhci_hcd *xhci,
                struct xhci_segment **seg,
                union xhci_trb **trb)
 {
-       if (last_trb(xhci, ring, *seg, *trb)) {
+       if (trb_is_link(*trb)) {
                *seg = (*seg)->next;
                *trb = ((*seg)->trbs);
        } else {
@@ -145,32 +135,29 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
        ring->deq_updates++;
 
-       /*
-        * If this is not event ring, and the dequeue pointer
-        * is not on a link TRB, there is one more usable TRB
-        */
-       if (ring->type != TYPE_EVENT &&
-                       !last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
-               ring->num_trbs_free++;
-
-       do {
-               /*
-                * Update the dequeue pointer further if that was a link TRB or
-                * we're at the end of an event ring segment (which doesn't have
-                * link TRBS)
-                */
-               if (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) {
-                       if (ring->type == TYPE_EVENT &&
-                                       last_trb_on_last_seg(xhci, ring,
-                                               ring->deq_seg, ring->dequeue)) {
-                               ring->cycle_state ^= 1;
-                       }
-                       ring->deq_seg = ring->deq_seg->next;
-                       ring->dequeue = ring->deq_seg->trbs;
-               } else {
+       /* event ring doesn't have link trbs, check for last trb */
+       if (ring->type == TYPE_EVENT) {
+               if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
                        ring->dequeue++;
+                       return;
                }
-       } while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue));
+               if (last_trb_on_ring(ring, ring->deq_seg, ring->dequeue))
+                       ring->cycle_state ^= 1;
+               ring->deq_seg = ring->deq_seg->next;
+               ring->dequeue = ring->deq_seg->trbs;
+               return;
+       }
+
+       /* All other rings have link trbs */
+       if (!trb_is_link(ring->dequeue)) {
+               ring->dequeue++;
+               ring->num_trbs_free++;
+       }
+       while (trb_is_link(ring->dequeue)) {
+               ring->deq_seg = ring->deq_seg->next;
+               ring->dequeue = ring->deq_seg->trbs;
+       }
+       return;
 }
 
 /*
@@ -198,50 +185,42 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
 
        chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
        /* If this is not event ring, there is one less usable TRB */
-       if (ring->type != TYPE_EVENT &&
-                       !last_trb(xhci, ring, ring->enq_seg, ring->enqueue))
+       if (!trb_is_link(ring->enqueue))
                ring->num_trbs_free--;
        next = ++(ring->enqueue);
 
        ring->enq_updates++;
-       /* Update the dequeue pointer further if that was a link TRB or we're at
-        * the end of an event ring segment (which doesn't have link TRBS)
-        */
-       while (last_trb(xhci, ring, ring->enq_seg, next)) {
-               if (ring->type != TYPE_EVENT) {
-                       /*
-                        * If the caller doesn't plan on enqueueing more
-                        * TDs before ringing the doorbell, then we
-                        * don't want to give the link TRB to the
-                        * hardware just yet.  We'll give the link TRB
-                        * back in prepare_ring() just before we enqueue
-                        * the TD at the top of the ring.
-                        */
-                       if (!chain && !more_trbs_coming)
-                               break;
+       /* Update the dequeue pointer further if that was a link TRB */
+       while (trb_is_link(next)) {
 
-                       /* If we're not dealing with 0.95 hardware or
-                        * isoc rings on AMD 0.96 host,
-                        * carry over the chain bit of the previous TRB
-                        * (which may mean the chain bit is cleared).
-                        */
-                       if (!(ring->type == TYPE_ISOC &&
-                                       (xhci->quirks & XHCI_AMD_0x96_HOST))
-                                               && !xhci_link_trb_quirk(xhci)) {
-                               next->link.control &=
-                                       cpu_to_le32(~TRB_CHAIN);
-                               next->link.control |=
-                                       cpu_to_le32(chain);
-                       }
-                       /* Give this link TRB to the hardware */
-                       wmb();
-                       next->link.control ^= cpu_to_le32(TRB_CYCLE);
+               /*
+                * If the caller doesn't plan on enqueueing more TDs before
+                * ringing the doorbell, then we don't want to give the link TRB
+                * to the hardware just yet. We'll give the link TRB back in
+                * prepare_ring() just before we enqueue the TD at the top of
+                * the ring.
+                */
+               if (!chain && !more_trbs_coming)
+                       break;
 
-                       /* Toggle the cycle bit after the last ring segment. */
-                       if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
-                               ring->cycle_state ^= 1;
-                       }
+               /* If we're not dealing with 0.95 hardware or isoc rings on
+                * AMD 0.96 host, carry over the chain bit of the previous TRB
+                * (which may mean the chain bit is cleared).
+                */
+               if (!(ring->type == TYPE_ISOC &&
+                     (xhci->quirks & XHCI_AMD_0x96_HOST)) &&
+                   !xhci_link_trb_quirk(xhci)) {
+                       next->link.control &= cpu_to_le32(~TRB_CHAIN);
+                       next->link.control |= cpu_to_le32(chain);
                }
+               /* Give this link TRB to the hardware */
+               wmb();
+               next->link.control ^= cpu_to_le32(TRB_CYCLE);
+
+               /* Toggle the cycle bit after the last ring segment. */
+               if (link_trb_toggles_cycle(next))
+                       ring->cycle_state ^= 1;
+
                ring->enq_seg = ring->enq_seg->next;
                ring->enqueue = ring->enq_seg->trbs;
                next = ring->enqueue;
@@ -626,6 +605,31 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
        }
 }
 
+void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct xhci_ring *ring,
+                                struct xhci_td *td)
+{
+       struct device *dev = xhci_to_hcd(xhci)->self.controller;
+       struct xhci_segment *seg = td->bounce_seg;
+       struct urb *urb = td->urb;
+
+       if (!seg || !urb)
+               return;
+
+       if (usb_urb_dir_out(urb)) {
+               dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
+                                DMA_TO_DEVICE);
+               return;
+       }
+
+       /* for in tranfers we need to copy the data from bounce to sg */
+       sg_pcopy_from_buffer(urb->sg, urb->num_mapped_sgs, seg->bounce_buf,
+                            seg->bounce_len, seg->bounce_offs);
+       dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
+                        DMA_FROM_DEVICE);
+       seg->bounce_len = 0;
+       seg->bounce_offs = 0;
+}
+
 /*
  * When we get a command completion for a Stop Endpoint Command, we need to
  * unlink any cancelled TDs from the ring.  There are two ways to do that:
@@ -745,6 +749,8 @@ remove_finished_td:
                /* Doesn't matter what we pass for status, since the core will
                 * just overwrite it (because the URB has been unlinked).
                 */
+               if (ep_ring && cur_td->bounce_seg)
+                       xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td);
                xhci_giveback_urb_in_irq(xhci, cur_td, 0);
 
                /* Stop processing the cancelled list if the watchdog timer is
@@ -767,6 +773,9 @@ static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring)
                list_del_init(&cur_td->td_list);
                if (!list_empty(&cur_td->cancelled_td_list))
                        list_del_init(&cur_td->cancelled_td_list);
+
+               if (cur_td->bounce_seg)
+                       xhci_unmap_td_bounce_buffer(xhci, ring, cur_td);
                xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN);
        }
 }
@@ -917,7 +926,7 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
         * the dequeue pointer one segment further, or we'll jump off
         * the segment into la-la-land.
         */
-       if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) {
+       if (trb_is_link(ep_ring->dequeue)) {
                ep_ring->deq_seg = ep_ring->deq_seg->next;
                ep_ring->dequeue = ep_ring->deq_seg->trbs;
        }
@@ -926,8 +935,7 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
                /* We have more usable TRBs */
                ep_ring->num_trbs_free++;
                ep_ring->dequeue++;
-               if (last_trb(xhci, ep_ring, ep_ring->deq_seg,
-                               ep_ring->dequeue)) {
+               if (trb_is_link(ep_ring->dequeue)) {
                        if (ep_ring->dequeue ==
                                        dev->eps[ep_index].queued_deq_ptr)
                                break;
@@ -1865,6 +1873,10 @@ td_cleanup:
        urb = td->urb;
        urb_priv = urb->hcpriv;
 
+       /* if a bounce buffer was used to align this td then unmap it */
+       if (td->bounce_seg)
+               xhci_unmap_td_bounce_buffer(xhci, ep_ring, td);
+
        /* Do one last check of the actual transfer length.
         * If the host controller said we transferred more data than the buffer
         * length, urb->actual_length will be a very big number (since it's
@@ -2865,36 +2877,29 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                }
        }
 
-       if (enqueue_is_link_trb(ep_ring)) {
-               struct xhci_ring *ring = ep_ring;
-               union xhci_trb *next;
-
-               next = ring->enqueue;
+       while (trb_is_link(ep_ring->enqueue)) {
+               /* If we're not dealing with 0.95 hardware or isoc rings
+                * on AMD 0.96 host, clear the chain bit.
+                */
+               if (!xhci_link_trb_quirk(xhci) &&
+                   !(ep_ring->type == TYPE_ISOC &&
+                     (xhci->quirks & XHCI_AMD_0x96_HOST)))
+                       ep_ring->enqueue->link.control &=
+                               cpu_to_le32(~TRB_CHAIN);
+               else
+                       ep_ring->enqueue->link.control |=
+                               cpu_to_le32(TRB_CHAIN);
 
-               while (last_trb(xhci, ring, ring->enq_seg, next)) {
-                       /* If we're not dealing with 0.95 hardware or isoc rings
-                        * on AMD 0.96 host, clear the chain bit.
-                        */
-                       if (!xhci_link_trb_quirk(xhci) &&
-                                       !(ring->type == TYPE_ISOC &&
-                                        (xhci->quirks & XHCI_AMD_0x96_HOST)))
-                               next->link.control &= cpu_to_le32(~TRB_CHAIN);
-                       else
-                               next->link.control |= cpu_to_le32(TRB_CHAIN);
+               wmb();
+               ep_ring->enqueue->link.control ^= cpu_to_le32(TRB_CYCLE);
 
-                       wmb();
-                       next->link.control ^= cpu_to_le32(TRB_CYCLE);
+               /* Toggle the cycle bit after the last ring segment. */
+               if (link_trb_toggles_cycle(ep_ring->enqueue))
+                       ep_ring->cycle_state ^= 1;
 
-                       /* Toggle the cycle bit after the last ring segment. */
-                       if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
-                               ring->cycle_state ^= 1;
-                       }
-                       ring->enq_seg = ring->enq_seg->next;
-                       ring->enqueue = ring->enq_seg->trbs;
-                       next = ring->enqueue;
-               }
+               ep_ring->enq_seg = ep_ring->enq_seg->next;
+               ep_ring->enqueue = ep_ring->enq_seg->trbs;
        }
-
        return 0;
 }
 
@@ -3092,7 +3097,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
  */
 static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
                              int trb_buff_len, unsigned int td_total_len,
-                             struct urb *urb, unsigned int num_trbs_left)
+                             struct urb *urb, bool more_trbs_coming)
 {
        u32 maxp, total_packet_count;
 
@@ -3101,7 +3106,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
                return ((td_total_len - transferred) >> 10);
 
        /* One TRB with a zero-length data packet. */
-       if (num_trbs_left == 0 || (transferred == 0 && trb_buff_len == 0) ||
+       if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) ||
            trb_buff_len == td_total_len)
                return 0;
 
@@ -3116,37 +3121,103 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
        return (total_packet_count - ((transferred + trb_buff_len) / maxp));
 }
 
+
+static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
+                        u32 *trb_buff_len, struct xhci_segment *seg)
+{
+       struct device *dev = xhci_to_hcd(xhci)->self.controller;
+       unsigned int unalign;
+       unsigned int max_pkt;
+       u32 new_buff_len;
+
+       max_pkt = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
+       unalign = (enqd_len + *trb_buff_len) % max_pkt;
+
+       /* we got lucky, last normal TRB data on segment is packet aligned */
+       if (unalign == 0)
+               return 0;
+
+       xhci_dbg(xhci, "Unaligned %d bytes, buff len %d\n",
+                unalign, *trb_buff_len);
+
+       /* is the last nornal TRB alignable by splitting it */
+       if (*trb_buff_len > unalign) {
+               *trb_buff_len -= unalign;
+               xhci_dbg(xhci, "split align, new buff len %d\n", *trb_buff_len);
+               return 0;
+       }
+
+       /*
+        * We want enqd_len + trb_buff_len to sum up to a number aligned to
+        * number which is divisible by the endpoint's wMaxPacketSize. IOW:
+        * (size of currently enqueued TRBs + remainder) % wMaxPacketSize == 0.
+        */
+       new_buff_len = max_pkt - (enqd_len % max_pkt);
+
+       if (new_buff_len > (urb->transfer_buffer_length - enqd_len))
+               new_buff_len = (urb->transfer_buffer_length - enqd_len);
+
+       /* create a max max_pkt sized bounce buffer pointed to by last trb */
+       if (usb_urb_dir_out(urb)) {
+               sg_pcopy_to_buffer(urb->sg, urb->num_mapped_sgs,
+                                  seg->bounce_buf, new_buff_len, enqd_len);
+               seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
+                                                max_pkt, DMA_TO_DEVICE);
+       } else {
+               seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
+                                                max_pkt, DMA_FROM_DEVICE);
+       }
+
+       if (dma_mapping_error(dev, seg->bounce_dma)) {
+               /* try without aligning. Some host controllers survive */
+               xhci_warn(xhci, "Failed mapping bounce buffer, not aligning\n");
+               return 0;
+       }
+       *trb_buff_len = new_buff_len;
+       seg->bounce_len = new_buff_len;
+       seg->bounce_offs = enqd_len;
+
+       xhci_dbg(xhci, "Bounce align, new buff len %d\n", *trb_buff_len);
+
+       return 1;
+}
+
 /* This is very similar to what ehci-q.c qtd_fill() does */
 int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                struct urb *urb, int slot_id, unsigned int ep_index)
 {
-       struct xhci_ring *ep_ring;
+       struct xhci_ring *ring;
        struct urb_priv *urb_priv;
        struct xhci_td *td;
        struct xhci_generic_trb *start_trb;
        struct scatterlist *sg = NULL;
-       bool more_trbs_coming;
-       bool zero_length_needed;
-       unsigned int num_trbs, last_trb_num, i;
+       bool more_trbs_coming = true;
+       bool need_zero_pkt = false;
+       bool first_trb = true;
+       unsigned int num_trbs;
        unsigned int start_cycle, num_sgs = 0;
-       unsigned int running_total, block_len, trb_buff_len;
-       unsigned int full_len;
-       int ret;
+       unsigned int enqd_len, block_len, trb_buff_len, full_len;
+       int sent_len, ret;
        u32 field, length_field, remainder;
-       u64 addr;
+       u64 addr, send_addr;
 
-       ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
-       if (!ep_ring)
+       ring = xhci_urb_to_transfer_ring(xhci, urb);
+       if (!ring)
                return -EINVAL;
 
+       full_len = urb->transfer_buffer_length;
        /* If we have scatter/gather list, we use it. */
        if (urb->num_sgs) {
                num_sgs = urb->num_mapped_sgs;
                sg = urb->sg;
+               addr = (u64) sg_dma_address(sg);
+               block_len = sg_dma_len(sg);
                num_trbs = count_sg_trbs_needed(urb);
-       } else
+       } else {
                num_trbs = count_trbs_needed(urb);
-
+               addr = (u64) urb->transfer_dma;
+               block_len = full_len;
+       }
        ret = prepare_transfer(xhci, xhci->devs[slot_id],
                        ep_index, urb->stream_id,
                        num_trbs, urb, 0, mem_flags);
@@ -3155,20 +3226,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
        urb_priv = urb->hcpriv;
 
-       last_trb_num = num_trbs - 1;
-
        /* Deal with URB_ZERO_PACKET - need one more td/trb */
-       zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET &&
-               urb_priv->length == 2;
-       if (zero_length_needed) {
-               num_trbs++;
-               xhci_dbg(xhci, "Creating zero length td.\n");
-               ret = prepare_transfer(xhci, xhci->devs[slot_id],
-                               ep_index, urb->stream_id,
-                               1, urb, 1, mem_flags);
-               if (unlikely(ret < 0))
-                       return ret;
-       }
+       if (urb->transfer_flags & URB_ZERO_PACKET && urb_priv->length > 1)
+               need_zero_pkt = true;
 
        td = urb_priv->td[0];
 
@@ -3177,102 +3237,97 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
         * until we've finished creating all the other TRBs.  The ring's cycle
         * state may change as we enqueue the other TRBs, so save it too.
         */
-       start_trb = &ep_ring->enqueue->generic;
-       start_cycle = ep_ring->cycle_state;
-
-       full_len = urb->transfer_buffer_length;
-       running_total = 0;
-       block_len = 0;
+       start_trb = &ring->enqueue->generic;
+       start_cycle = ring->cycle_state;
+       send_addr = addr;
 
        /* Queue the TRBs, even if they are zero-length */
-       for (i = 0; i < num_trbs; i++) {
+       for (enqd_len = 0; enqd_len < full_len; enqd_len += trb_buff_len) {
                field = TRB_TYPE(TRB_NORMAL);
 
-               if (block_len == 0) {
-                       /* A new contiguous block. */
-                       if (sg) {
-                               addr = (u64) sg_dma_address(sg);
-                               block_len = sg_dma_len(sg);
-                       } else {
-                               addr = (u64) urb->transfer_dma;
-                               block_len = full_len;
-                       }
-                       /* TRB buffer should not cross 64KB boundaries */
-                       trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
-                       trb_buff_len = min_t(unsigned int,
-                                                               trb_buff_len,
-                                                               block_len);
-               } else {
-                       /* Further through the contiguous block. */
-                       trb_buff_len = block_len;
-                       if (trb_buff_len > TRB_MAX_BUFF_SIZE)
-                               trb_buff_len = TRB_MAX_BUFF_SIZE;
-               }
+               /* TRB buffer should not cross 64KB boundaries */
+               trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
+               trb_buff_len = min_t(unsigned int, trb_buff_len, block_len);
 
-               if (running_total + trb_buff_len > full_len)
-                       trb_buff_len = full_len - running_total;
+               if (enqd_len + trb_buff_len > full_len)
+                       trb_buff_len = full_len - enqd_len;
 
                /* Don't change the cycle bit of the first TRB until later */
-               if (i == 0) {
+               if (first_trb) {
+                       first_trb = false;
                        if (start_cycle == 0)
                                field |= TRB_CYCLE;
                } else
-                       field |= ep_ring->cycle_state;
+                       field |= ring->cycle_state;
 
                /* Chain all the TRBs together; clear the chain bit in the last
                 * TRB to indicate it's the last TRB in the chain.
                 */
-               if (i < last_trb_num) {
+               if (enqd_len + trb_buff_len < full_len) {
                        field |= TRB_CHAIN;
-               } else {
-                       field |= TRB_IOC;
-                       if (i == last_trb_num)
-                               td->last_trb = ep_ring->enqueue;
-                       else if (zero_length_needed) {
-                               trb_buff_len = 0;
-                               urb_priv->td[1]->last_trb = ep_ring->enqueue;
+                       if (trb_is_link(ring->enqueue + 1)) {
+                               if (xhci_align_td(xhci, urb, enqd_len,
+                                                 &trb_buff_len,
+                                                 ring->enq_seg)) {
+                                       send_addr = ring->enq_seg->bounce_dma;
+                                       /* assuming TD won't span 2 segs */
+                                       td->bounce_seg = ring->enq_seg;
+                               }
                        }
                }
+               if (enqd_len + trb_buff_len >= full_len) {
+                       field &= ~TRB_CHAIN;
+                       field |= TRB_IOC;
+                       more_trbs_coming = false;
+                       td->last_trb = ring->enqueue;
+               }
 
                /* Only set interrupt on short packet for IN endpoints */
                if (usb_urb_dir_in(urb))
                        field |= TRB_ISP;
 
                /* Set the TRB length, TD size, and interrupter fields. */
-               remainder = xhci_td_remainder(xhci, running_total,
-                                                       trb_buff_len, full_len,
-                                                       urb, num_trbs - i - 1);
+               remainder = xhci_td_remainder(xhci, enqd_len, trb_buff_len,
+                                             full_len, urb, more_trbs_coming);
 
                length_field = TRB_LEN(trb_buff_len) |
                        TRB_TD_SIZE(remainder) |
                        TRB_INTR_TARGET(0);
 
-               if (i < num_trbs - 1)
-                       more_trbs_coming = true;
-               else
-                       more_trbs_coming = false;
-               queue_trb(xhci, ep_ring, more_trbs_coming,
-                               lower_32_bits(addr),
-                               upper_32_bits(addr),
+               queue_trb(xhci, ring, more_trbs_coming | need_zero_pkt,
+                               lower_32_bits(send_addr),
+                               upper_32_bits(send_addr),
                                length_field,
                                field);
 
-               running_total += trb_buff_len;
                addr += trb_buff_len;
-               block_len -= trb_buff_len;
-
-               if (sg) {
-                       if (block_len == 0) {
-                               /* New sg entry */
-                               --num_sgs;
-                               if (num_sgs == 0)
-                                       break;
+               sent_len = trb_buff_len;
+
+               while (sg && sent_len >= block_len) {
+                       /* New sg entry */
+                       --num_sgs;
+                       sent_len -= block_len;
+                       if (num_sgs != 0) {
                                sg = sg_next(sg);
+                               block_len = sg_dma_len(sg);
+                               addr = (u64) sg_dma_address(sg);
+                               addr += sent_len;
                        }
                }
+               block_len -= sent_len;
+               send_addr = addr;
+       }
+
+       if (need_zero_pkt) {
+               ret = prepare_transfer(xhci, xhci->devs[slot_id],
+                                      ep_index, urb->stream_id,
+                                      1, urb, 1, mem_flags);
+               urb_priv->td[1]->last_trb = ring->enqueue;
+               field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC;
+               queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field);
        }
 
-       check_trb_math(urb, running_total);
+       check_trb_math(urb, enqd_len);
        giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
                        start_cycle, start_trb);
        return 0;
@@ -3666,7 +3721,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                        /* Set the TRB length, TD size, & interrupter fields. */
                        remainder = xhci_td_remainder(xhci, running_total,
                                                   trb_buff_len, td_len,
-                                                  urb, trbs_per_td - j - 1);
+                                                  urb, more_trbs_coming);
 
                        length_field = TRB_LEN(trb_buff_len) |
                                TRB_INTR_TARGET(0);
index f2f9518..9da9832 100644 (file)
@@ -3139,6 +3139,7 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
        struct xhci_input_control_ctx *ctrl_ctx;
        unsigned int ep_index;
        unsigned int num_stream_ctxs;
+       unsigned int max_packet;
        unsigned long flags;
        u32 changed_ep_bitmask = 0;
 
@@ -3212,9 +3213,11 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
 
        for (i = 0; i < num_eps; i++) {
                ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+               max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&eps[i]->desc));
                vdev->eps[ep_index].stream_info = xhci_alloc_stream_info(xhci,
                                num_stream_ctxs,
-                               num_streams, mem_flags);
+                               num_streams,
+                               max_packet, mem_flags);
                if (!vdev->eps[ep_index].stream_info)
                        goto cleanup;
                /* Set maxPstreams in endpoint context and update deq ptr to
index b0b8d0f..b2c1dc5 100644 (file)
@@ -1347,6 +1347,11 @@ struct xhci_segment {
        /* private to HCD */
        struct xhci_segment     *next;
        dma_addr_t              dma;
+       /* Max packet sized bounce buffer for td-fragmant alignment */
+       dma_addr_t              bounce_dma;
+       void                    *bounce_buf;
+       unsigned int            bounce_offs;
+       unsigned int            bounce_len;
 };
 
 struct xhci_td {
@@ -1356,6 +1361,7 @@ struct xhci_td {
        struct xhci_segment     *start_seg;
        union xhci_trb          *first_trb;
        union xhci_trb          *last_trb;
+       struct xhci_segment     *bounce_seg;
        /* actual_length of the URB has already been set */
        bool                    urb_length_set;
 };
@@ -1405,6 +1411,7 @@ struct xhci_ring {
        unsigned int            num_segs;
        unsigned int            num_trbs_free;
        unsigned int            num_trbs_free_temp;
+       unsigned int            bounce_buf_len;
        enum xhci_ring_type     type;
        bool                    last_td_was_short;
        struct radix_tree_root  *trb_address_map;
@@ -1807,7 +1814,8 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
                unsigned int ep_index);
 struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
                unsigned int num_stream_ctxs,
-               unsigned int num_streams, gfp_t flags);
+               unsigned int num_streams,
+               unsigned int max_packet, gfp_t flags);
 void xhci_free_stream_info(struct xhci_hcd *xhci,
                struct xhci_stream_info *stream_info);
 void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
index c690474..b9c409a 100644 (file)
@@ -21,6 +21,7 @@ config AB8500_USB
 config FSL_USB2_OTG
        bool "Freescale USB OTG Transceiver Driver"
        depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        select USB_PHY
        help
          Enable this to support Freescale USB OTG transceiver.
@@ -29,6 +30,7 @@ config ISP1301_OMAP
        tristate "Philips ISP1301 with OMAP OTG"
        depends on I2C && ARCH_OMAP_OTG
        depends on USB
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        select USB_PHY
        help
          If you say yes here you get support for the Philips ISP1301
@@ -43,7 +45,7 @@ config ISP1301_OMAP
 config KEYSTONE_USB_PHY
        tristate "Keystone USB PHY Driver"
        depends on ARCH_KEYSTONE || COMPILE_TEST
-       select NOP_USB_XCEIV
+       depends on NOP_USB_XCEIV
        help
          Enable this to support Keystone USB phy. This driver provides
          interface to interact with USB 2.0 and USB 3.0 PHY that is part
@@ -51,6 +53,7 @@ config KEYSTONE_USB_PHY
 
 config NOP_USB_XCEIV
        tristate "NOP USB Transceiver Driver"
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, NOP can't be built-in
        select USB_PHY
        help
          This driver is to be used by all the usb transceiver which are either
@@ -63,9 +66,9 @@ config AM335X_CONTROL_USB
 config AM335X_PHY_USB
        tristate "AM335x USB PHY Driver"
        depends on ARM || COMPILE_TEST
+       depends on NOP_USB_XCEIV
        select USB_PHY
        select AM335X_CONTROL_USB
-       select NOP_USB_XCEIV
        select USB_COMMON
        help
          This driver provides PHY support for that phy which part for the
@@ -92,6 +95,7 @@ config TWL6030_USB
 config USB_GPIO_VBUS
        tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
        depends on GPIOLIB || COMPILE_TEST
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        select USB_PHY
        help
          Provides simple GPIO VBUS sensing for controllers with an
@@ -112,6 +116,7 @@ config OMAP_OTG
 config TAHVO_USB
        tristate "Tahvo USB transceiver driver"
        depends on MFD_RETU && EXTCON
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        select USB_PHY
        help
          Enable this to support USB transceiver on Tahvo. This is used
@@ -140,6 +145,7 @@ config USB_ISP1301
 config USB_MSM_OTG
        tristate "Qualcomm on-chip USB OTG controller support"
        depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        depends on RESET_CONTROLLER
        depends on EXTCON
        select USB_PHY
@@ -169,6 +175,7 @@ config USB_QCOM_8X16_PHY
 config USB_MV_OTG
        tristate "Marvell USB OTG support"
        depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG
+       depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
        select USB_PHY
        help
          Say Y here if you want to build Marvell USB OTG transciever
index a262a43..7e5aece 100644 (file)
@@ -54,7 +54,7 @@ static int am335x_phy_probe(struct platform_device *pdev)
                return am_phy->id;
        }
 
-       am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node);
+       am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1);
 
        ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL);
        if (ret)
index 72b387d..8a34759 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/extcon.h>
 #include <linux/gpio/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
@@ -35,6 +36,8 @@
 #include <linux/of_device.h>
 #include <linux/reboot.h>
 #include <linux/reset.h>
+#include <linux/types.h>
+#include <linux/usb/otg.h>
 
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/hcd.h>
-#include <linux/usb/msm_hsusb.h>
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/regulator/consumer.h>
 
+/**
+ * OTG control
+ *
+ * OTG_NO_CONTROL      Id/VBUS notifications not required. Useful in host
+ *                      only configuration.
+ * OTG_PHY_CONTROL     Id/VBUS notifications comes form USB PHY.
+ * OTG_PMIC_CONTROL    Id/VBUS notifications comes from PMIC hardware.
+ * OTG_USER_CONTROL    Id/VBUS notifcations comes from User via sysfs.
+ *
+ */
+enum otg_control_type {
+       OTG_NO_CONTROL = 0,
+       OTG_PHY_CONTROL,
+       OTG_PMIC_CONTROL,
+       OTG_USER_CONTROL,
+};
+
+/**
+ * PHY used in
+ *
+ * INVALID_PHY                 Unsupported PHY
+ * CI_45NM_INTEGRATED_PHY      Chipidea 45nm integrated PHY
+ * SNPS_28NM_INTEGRATED_PHY    Synopsis 28nm integrated PHY
+ *
+ */
+enum msm_usb_phy_type {
+       INVALID_PHY = 0,
+       CI_45NM_INTEGRATED_PHY,
+       SNPS_28NM_INTEGRATED_PHY,
+};
+
+#define IDEV_CHG_MAX   1500
+#define IUNIT          100
+
+/**
+ * Different states involved in USB charger detection.
+ *
+ * USB_CHG_STATE_UNDEFINED     USB charger is not connected or detection
+ *                              process is not yet started.
+ * USB_CHG_STATE_WAIT_FOR_DCD  Waiting for Data pins contact.
+ * USB_CHG_STATE_DCD_DONE      Data pin contact is detected.
+ * USB_CHG_STATE_PRIMARY_DONE  Primary detection is completed (Detects
+ *                              between SDP and DCP/CDP).
+ * USB_CHG_STATE_SECONDARY_DONE        Secondary detection is completed (Detects
+ *                              between DCP and CDP).
+ * USB_CHG_STATE_DETECTED      USB charger type is determined.
+ *
+ */
+enum usb_chg_state {
+       USB_CHG_STATE_UNDEFINED = 0,
+       USB_CHG_STATE_WAIT_FOR_DCD,
+       USB_CHG_STATE_DCD_DONE,
+       USB_CHG_STATE_PRIMARY_DONE,
+       USB_CHG_STATE_SECONDARY_DONE,
+       USB_CHG_STATE_DETECTED,
+};
+
+/**
+ * USB charger types
+ *
+ * USB_INVALID_CHARGER Invalid USB charger.
+ * USB_SDP_CHARGER     Standard downstream port. Refers to a downstream port
+ *                      on USB2.0 compliant host/hub.
+ * USB_DCP_CHARGER     Dedicated charger port (AC charger/ Wall charger).
+ * USB_CDP_CHARGER     Charging downstream port. Enumeration can happen and
+ *                      IDEV_CHG_MAX can be drawn irrespective of USB state.
+ *
+ */
+enum usb_chg_type {
+       USB_INVALID_CHARGER = 0,
+       USB_SDP_CHARGER,
+       USB_DCP_CHARGER,
+       USB_CDP_CHARGER,
+};
+
+/**
+ * struct msm_otg_platform_data - platform device data
+ *              for msm_otg driver.
+ * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as
+ *              "do not overwrite default vaule at this address".
+ * @phy_init_sz: PHY configuration sequence size.
+ * @vbus_power: VBUS power on/off routine.
+ * @power_budget: VBUS power budget in mA (0 will be treated as 500mA).
+ * @mode: Supported mode (OTG/peripheral/host).
+ * @otg_control: OTG switch controlled by user/Id pin
+ */
+struct msm_otg_platform_data {
+       int *phy_init_seq;
+       int phy_init_sz;
+       void (*vbus_power)(bool on);
+       unsigned power_budget;
+       enum usb_dr_mode mode;
+       enum otg_control_type otg_control;
+       enum msm_usb_phy_type phy_type;
+       void (*setup_gpio)(enum usb_otg_state state);
+};
+
+/**
+ * struct msm_usb_cable - structure for exteternal connector cable
+ *                       state tracking
+ * @nb: hold event notification callback
+ * @conn: used for notification registration
+ */
+struct msm_usb_cable {
+       struct notifier_block           nb;
+       struct extcon_dev               *extcon;
+};
+
+/**
+ * struct msm_otg: OTG driver data. Shared by HCD and DCD.
+ * @otg: USB OTG Transceiver structure.
+ * @pdata: otg device platform data.
+ * @irq: IRQ number assigned for HSUSB controller.
+ * @clk: clock struct of usb_hs_clk.
+ * @pclk: clock struct of usb_hs_pclk.
+ * @core_clk: clock struct of usb_hs_core_clk.
+ * @regs: ioremapped register base address.
+ * @inputs: OTG state machine inputs(Id, SessValid etc).
+ * @sm_work: OTG state machine work.
+ * @in_lpm: indicates low power mode (LPM) state.
+ * @async_int: Async interrupt arrived.
+ * @cur_power: The amount of mA available from downstream port.
+ * @chg_work: Charger detection work.
+ * @chg_state: The state of charger detection process.
+ * @chg_type: The type of charger attached.
+ * @dcd_retires: The retry count used to track Data contact
+ *               detection process.
+ * @manual_pullup: true if VBUS is not routed to USB controller/phy
+ *     and controller driver therefore enables pull-up explicitly before
+ *     starting controller using usbcmd run/stop bit.
+ * @vbus: VBUS signal state trakining, using extcon framework
+ * @id: ID signal state trakining, using extcon framework
+ * @switch_gpio: Descriptor for GPIO used to control external Dual
+ *               SPDT USB Switch.
+ * @reboot: Used to inform the driver to route USB D+/D- line to Device
+ *         connector
+ */
+struct msm_otg {
+       struct usb_phy phy;
+       struct msm_otg_platform_data *pdata;
+       int irq;
+       struct clk *clk;
+       struct clk *pclk;
+       struct clk *core_clk;
+       void __iomem *regs;
+#define ID             0
+#define B_SESS_VLD     1
+       unsigned long inputs;
+       struct work_struct sm_work;
+       atomic_t in_lpm;
+       int async_int;
+       unsigned cur_power;
+       int phy_number;
+       struct delayed_work chg_work;
+       enum usb_chg_state chg_state;
+       enum usb_chg_type chg_type;
+       u8 dcd_retries;
+       struct regulator *v3p3;
+       struct regulator *v1p8;
+       struct regulator *vddcx;
+
+       struct reset_control *phy_rst;
+       struct reset_control *link_rst;
+       int vdd_levels[3];
+
+       bool manual_pullup;
+
+       struct msm_usb_cable vbus;
+       struct msm_usb_cable id;
+
+       struct gpio_desc *switch_gpio;
+       struct notifier_block reboot;
+};
+
 #define MSM_USB_BASE   (motg->regs)
 #define DRIVER_NAME    "msm_otg"
 
index c4bf2de..6f6d2a7 100644 (file)
@@ -148,7 +148,7 @@ static int omap_otg_remove(struct platform_device *pdev)
        struct otg_device *otg_dev = platform_get_drvdata(pdev);
        struct extcon_dev *edev = otg_dev->extcon;
 
-       extcon_unregister_notifier(edev, EXTCON_USB_HOST,&otg_dev->id_nb);
+       extcon_unregister_notifier(edev, EXTCON_USB_HOST, &otg_dev->id_nb);
        extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb);
 
        return 0;
index baeb7d2..8fbbc2d 100644 (file)
@@ -697,7 +697,7 @@ probe_end_fifo_exit:
 probe_end_pipe_exit:
        usbhs_pipe_remove(priv);
 
-       dev_info(&pdev->dev, "probe failed\n");
+       dev_info(&pdev->dev, "probe failed (%d)\n", ret);
 
        return ret;
 }
index 7be4e7d..280ed5f 100644 (file)
@@ -810,20 +810,27 @@ static void xfer_work(struct work_struct *work)
 {
        struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
        struct usbhs_pipe *pipe = pkt->pipe;
-       struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
+       struct usbhs_fifo *fifo;
        struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
        struct dma_async_tx_descriptor *desc;
-       struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
+       struct dma_chan *chan;
        struct device *dev = usbhs_priv_to_dev(priv);
        enum dma_transfer_direction dir;
+       unsigned long flags;
 
+       usbhs_lock(priv, flags);
+       fifo = usbhs_pipe_to_fifo(pipe);
+       if (!fifo)
+               goto xfer_work_end;
+
+       chan = usbhsf_dma_chan_get(fifo, pkt);
        dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
 
        desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual,
                                        pkt->trans, dir,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc)
-               return;
+               goto xfer_work_end;
 
        desc->callback          = usbhsf_dma_complete;
        desc->callback_param    = pipe;
@@ -831,7 +838,7 @@ static void xfer_work(struct work_struct *work)
        pkt->cookie = dmaengine_submit(desc);
        if (pkt->cookie < 0) {
                dev_err(dev, "Failed to submit dma descriptor\n");
-               return;
+               goto xfer_work_end;
        }
 
        dev_dbg(dev, "  %s %d (%d/ %d)\n",
@@ -842,6 +849,9 @@ static void xfer_work(struct work_struct *work)
        usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
        dma_async_issue_pending(chan);
        usbhs_pipe_enable(pipe);
+
+xfer_work_end:
+       usbhs_unlock(priv, flags);
 }
 
 /*
index 30345c2..50f3363 100644 (file)
@@ -585,6 +585,9 @@ static int usbhsg_ep_enable(struct usb_ep *ep,
        struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
        struct usbhs_pipe *pipe;
        int ret = -EIO;
+       unsigned long flags;
+
+       usbhs_lock(priv, flags);
 
        /*
         * if it already have pipe,
@@ -593,7 +596,8 @@ static int usbhsg_ep_enable(struct usb_ep *ep,
        if (uep->pipe) {
                usbhs_pipe_clear(uep->pipe);
                usbhs_pipe_sequence_data0(uep->pipe);
-               return 0;
+               ret = 0;
+               goto usbhsg_ep_enable_end;
        }
 
        pipe = usbhs_pipe_malloc(priv,
@@ -621,6 +625,9 @@ static int usbhsg_ep_enable(struct usb_ep *ep,
                ret = 0;
        }
 
+usbhsg_ep_enable_end:
+       usbhs_unlock(priv, flags);
+
        return ret;
 }
 
index 38b01f2..1d70add 100644 (file)
@@ -23,7 +23,7 @@
 #define UGCTRL2_RESERVED_3     0x00000001      /* bit[3:0] should be B'0001 */
 #define UGCTRL2_USB0SEL_OTG    0x00000030
 
-void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
+static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
 {
        iowrite32(data, priv->base + reg);
 }
index fefe8b0..612dbdf 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/workqueue.h>
 #include <linux/usb/ch9.h>
 
+#define UDC_TRACE_STR_MAX      512
+
 struct usb_ep;
 
 /**
@@ -228,307 +230,49 @@ struct usb_ep {
 
 /*-------------------------------------------------------------------------*/
 
-/**
- * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint
- * @ep:the endpoint being configured
- * @maxpacket_limit:value of maximum packet size limit
- *
- * This function should be used only in UDC drivers to initialize endpoint
- * (usually in probe function).
- */
+#if IS_ENABLED(CONFIG_USB_GADGET)
+void usb_ep_set_maxpacket_limit(struct usb_ep *ep, unsigned maxpacket_limit);
+int usb_ep_enable(struct usb_ep *ep);
+int usb_ep_disable(struct usb_ep *ep);
+struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
+void usb_ep_free_request(struct usb_ep *ep, struct usb_request *req);
+int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags);
+int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req);
+int usb_ep_set_halt(struct usb_ep *ep);
+int usb_ep_clear_halt(struct usb_ep *ep);
+int usb_ep_set_wedge(struct usb_ep *ep);
+int usb_ep_fifo_status(struct usb_ep *ep);
+void usb_ep_fifo_flush(struct usb_ep *ep);
+#else
 static inline void usb_ep_set_maxpacket_limit(struct usb_ep *ep,
-                                             unsigned maxpacket_limit)
-{
-       ep->maxpacket_limit = maxpacket_limit;
-       ep->maxpacket = maxpacket_limit;
-}
-
-/**
- * usb_ep_enable - configure endpoint, making it usable
- * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
- *     drivers discover endpoints through the ep_list of a usb_gadget.
- *
- * When configurations are set, or when interface settings change, the driver
- * will enable or disable the relevant endpoints.  while it is enabled, an
- * endpoint may be used for i/o until the driver receives a disconnect() from
- * the host or until the endpoint is disabled.
- *
- * the ep0 implementation (which calls this routine) must ensure that the
- * hardware capabilities of each endpoint match the descriptor provided
- * for it.  for example, an endpoint named "ep2in-bulk" would be usable
- * for interrupt transfers as well as bulk, but it likely couldn't be used
- * for iso transfers or for endpoint 14.  some endpoints are fully
- * configurable, with more generic names like "ep-a".  (remember that for
- * USB, "in" means "towards the USB master".)
- *
- * returns zero, or a negative error code.
- */
+               unsigned maxpacket_limit)
+{ }
 static inline int usb_ep_enable(struct usb_ep *ep)
-{
-       int ret;
-
-       if (ep->enabled)
-               return 0;
-
-       ret = ep->ops->enable(ep, ep->desc);
-       if (ret)
-               return ret;
-
-       ep->enabled = true;
-
-       return 0;
-}
-
-/**
- * usb_ep_disable - endpoint is no longer usable
- * @ep:the endpoint being unconfigured.  may not be the endpoint named "ep0".
- *
- * no other task may be using this endpoint when this is called.
- * any pending and uncompleted requests will complete with status
- * indicating disconnect (-ESHUTDOWN) before this call returns.
- * gadget drivers must call usb_ep_enable() again before queueing
- * requests to the endpoint.
- *
- * returns zero, or a negative error code.
- */
+{ return 0; }
 static inline int usb_ep_disable(struct usb_ep *ep)
-{
-       int ret;
-
-       if (!ep->enabled)
-               return 0;
-
-       ret = ep->ops->disable(ep);
-       if (ret)
-               return ret;
-
-       ep->enabled = false;
-
-       return 0;
-}
-
-/**
- * usb_ep_alloc_request - allocate a request object to use with this endpoint
- * @ep:the endpoint to be used with with the request
- * @gfp_flags:GFP_* flags to use
- *
- * Request objects must be allocated with this call, since they normally
- * need controller-specific setup and may even need endpoint-specific
- * resources such as allocation of DMA descriptors.
- * Requests may be submitted with usb_ep_queue(), and receive a single
- * completion callback.  Free requests with usb_ep_free_request(), when
- * they are no longer needed.
- *
- * Returns the request, or null if one could not be allocated.
- */
+{ return 0; }
 static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep,
-                                                      gfp_t gfp_flags)
-{
-       return ep->ops->alloc_request(ep, gfp_flags);
-}
-
-/**
- * usb_ep_free_request - frees a request object
- * @ep:the endpoint associated with the request
- * @req:the request being freed
- *
- * Reverses the effect of usb_ep_alloc_request().
- * Caller guarantees the request is not queued, and that it will
- * no longer be requeued (or otherwise used).
- */
+               gfp_t gfp_flags)
+{ return NULL; }
 static inline void usb_ep_free_request(struct usb_ep *ep,
-                                      struct usb_request *req)
-{
-       ep->ops->free_request(ep, req);
-}
-
-/**
- * usb_ep_queue - queues (submits) an I/O request to an endpoint.
- * @ep:the endpoint associated with the request
- * @req:the request being submitted
- * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
- *     pre-allocate all necessary memory with the request.
- *
- * This tells the device controller to perform the specified request through
- * that endpoint (reading or writing a buffer).  When the request completes,
- * including being canceled by usb_ep_dequeue(), the request's completion
- * routine is called to return the request to the driver.  Any endpoint
- * (except control endpoints like ep0) may have more than one transfer
- * request queued; they complete in FIFO order.  Once a gadget driver
- * submits a request, that request may not be examined or modified until it
- * is given back to that driver through the completion callback.
- *
- * Each request is turned into one or more packets.  The controller driver
- * never merges adjacent requests into the same packet.  OUT transfers
- * will sometimes use data that's already buffered in the hardware.
- * Drivers can rely on the fact that the first byte of the request's buffer
- * always corresponds to the first byte of some USB packet, for both
- * IN and OUT transfers.
- *
- * Bulk endpoints can queue any amount of data; the transfer is packetized
- * automatically.  The last packet will be short if the request doesn't fill it
- * out completely.  Zero length packets (ZLPs) should be avoided in portable
- * protocols since not all usb hardware can successfully handle zero length
- * packets.  (ZLPs may be explicitly written, and may be implicitly written if
- * the request 'zero' flag is set.)  Bulk endpoints may also be used
- * for interrupt transfers; but the reverse is not true, and some endpoints
- * won't support every interrupt transfer.  (Such as 768 byte packets.)
- *
- * Interrupt-only endpoints are less functional than bulk endpoints, for
- * example by not supporting queueing or not handling buffers that are
- * larger than the endpoint's maxpacket size.  They may also treat data
- * toggle differently.
- *
- * Control endpoints ... after getting a setup() callback, the driver queues
- * one response (even if it would be zero length).  That enables the
- * status ack, after transferring data as specified in the response.  Setup
- * functions may return negative error codes to generate protocol stalls.
- * (Note that some USB device controllers disallow protocol stall responses
- * in some cases.)  When control responses are deferred (the response is
- * written after the setup callback returns), then usb_ep_set_halt() may be
- * used on ep0 to trigger protocol stalls.  Depending on the controller,
- * it may not be possible to trigger a status-stage protocol stall when the
- * data stage is over, that is, from within the response's completion
- * routine.
- *
- * For periodic endpoints, like interrupt or isochronous ones, the usb host
- * arranges to poll once per interval, and the gadget driver usually will
- * have queued some data to transfer at that time.
- *
- * Returns zero, or a negative error code.  Endpoints that are not enabled
- * report errors; errors will also be
- * reported when the usb peripheral is disconnected.
- */
-static inline int usb_ep_queue(struct usb_ep *ep,
-                              struct usb_request *req, gfp_t gfp_flags)
-{
-       if (WARN_ON_ONCE(!ep->enabled && ep->address))
-               return -ESHUTDOWN;
-
-       return ep->ops->queue(ep, req, gfp_flags);
-}
-
-/**
- * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint
- * @ep:the endpoint associated with the request
- * @req:the request being canceled
- *
- * If the request is still active on the endpoint, it is dequeued and its
- * completion routine is called (with status -ECONNRESET); else a negative
- * error code is returned. This is guaranteed to happen before the call to
- * usb_ep_dequeue() returns.
- *
- * Note that some hardware can't clear out write fifos (to unlink the request
- * at the head of the queue) except as part of disconnecting from usb. Such
- * restrictions prevent drivers from supporting configuration changes,
- * even to configuration zero (a "chapter 9" requirement).
- */
+               struct usb_request *req)
+{ }
+static inline int usb_ep_queue(struct usb_ep *ep, struct usb_request *req,
+               gfp_t gfp_flags)
+{ return 0; }
 static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
-{
-       return ep->ops->dequeue(ep, req);
-}
-
-/**
- * usb_ep_set_halt - sets the endpoint halt feature.
- * @ep: the non-isochronous endpoint being stalled
- *
- * Use this to stall an endpoint, perhaps as an error report.
- * Except for control endpoints,
- * the endpoint stays halted (will not stream any data) until the host
- * clears this feature; drivers may need to empty the endpoint's request
- * queue first, to make sure no inappropriate transfers happen.
- *
- * Note that while an endpoint CLEAR_FEATURE will be invisible to the
- * gadget driver, a SET_INTERFACE will not be.  To reset endpoints for the
- * current altsetting, see usb_ep_clear_halt().  When switching altsettings,
- * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints.
- *
- * Returns zero, or a negative error code.  On success, this call sets
- * underlying hardware state that blocks data transfers.
- * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
- * transfer requests are still queued, or if the controller hardware
- * (usually a FIFO) still holds bytes that the host hasn't collected.
- */
+{ return 0; }
 static inline int usb_ep_set_halt(struct usb_ep *ep)
-{
-       return ep->ops->set_halt(ep, 1);
-}
-
-/**
- * usb_ep_clear_halt - clears endpoint halt, and resets toggle
- * @ep:the bulk or interrupt endpoint being reset
- *
- * Use this when responding to the standard usb "set interface" request,
- * for endpoints that aren't reconfigured, after clearing any other state
- * in the endpoint's i/o queue.
- *
- * Returns zero, or a negative error code.  On success, this call clears
- * the underlying hardware state reflecting endpoint halt and data toggle.
- * Note that some hardware can't support this request (like pxa2xx_udc),
- * and accordingly can't correctly implement interface altsettings.
- */
+{ return 0; }
 static inline int usb_ep_clear_halt(struct usb_ep *ep)
-{
-       return ep->ops->set_halt(ep, 0);
-}
-
-/**
- * usb_ep_set_wedge - sets the halt feature and ignores clear requests
- * @ep: the endpoint being wedged
- *
- * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
- * requests. If the gadget driver clears the halt status, it will
- * automatically unwedge the endpoint.
- *
- * Returns zero on success, else negative errno.
- */
-static inline int
-usb_ep_set_wedge(struct usb_ep *ep)
-{
-       if (ep->ops->set_wedge)
-               return ep->ops->set_wedge(ep);
-       else
-               return ep->ops->set_halt(ep, 1);
-}
-
-/**
- * usb_ep_fifo_status - returns number of bytes in fifo, or error
- * @ep: the endpoint whose fifo status is being checked.
- *
- * FIFO endpoints may have "unclaimed data" in them in certain cases,
- * such as after aborted transfers.  Hosts may not have collected all
- * the IN data written by the gadget driver (and reported by a request
- * completion).  The gadget driver may not have collected all the data
- * written OUT to it by the host.  Drivers that need precise handling for
- * fault reporting or recovery may need to use this call.
- *
- * This returns the number of such bytes in the fifo, or a negative
- * errno if the endpoint doesn't use a FIFO or doesn't support such
- * precise handling.
- */
+{ return 0; }
+static inline int usb_ep_set_wedge(struct usb_ep *ep)
+{ return 0; }
 static inline int usb_ep_fifo_status(struct usb_ep *ep)
-{
-       if (ep->ops->fifo_status)
-               return ep->ops->fifo_status(ep);
-       else
-               return -EOPNOTSUPP;
-}
-
-/**
- * usb_ep_fifo_flush - flushes contents of a fifo
- * @ep: the endpoint whose fifo is being flushed.
- *
- * This call may be used to flush the "unclaimed data" that may exist in
- * an endpoint fifo after abnormal transaction terminations.  The call
- * must never be used except when endpoint is not being used for any
- * protocol translation.
- */
+{ return 0; }
 static inline void usb_ep_fifo_flush(struct usb_ep *ep)
-{
-       if (ep->ops->fifo_flush)
-               ep->ops->fifo_flush(ep);
-}
-
+{ }
+#endif /* USB_GADGET */
 
 /*-------------------------------------------------------------------------*/
 
@@ -582,6 +326,7 @@ struct usb_gadget_ops {
  * @dev: Driver model state for this abstract device.
  * @out_epnum: last used out ep number
  * @in_epnum: last used in ep number
+ * @mA: last set mA value
  * @otg_caps: OTG capabilities of this gadget.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
@@ -638,6 +383,7 @@ struct usb_gadget {
        struct device                   dev;
        unsigned                        out_epnum;
        unsigned                        in_epnum;
+       unsigned                        mA;
        struct usb_otg_caps             *otg_caps;
 
        unsigned                        sg_supported:1;
@@ -760,251 +506,44 @@ static inline int gadget_is_otg(struct usb_gadget *g)
 #endif
 }
 
-/**
- * usb_gadget_frame_number - returns the current frame number
- * @gadget: controller that reports the frame number
- *
- * Returns the usb frame number, normally eleven bits from a SOF packet,
- * or negative errno if this device doesn't support this capability.
- */
-static inline int usb_gadget_frame_number(struct usb_gadget *gadget)
-{
-       return gadget->ops->get_frame(gadget);
-}
+/*-------------------------------------------------------------------------*/
 
-/**
- * usb_gadget_wakeup - tries to wake up the host connected to this gadget
- * @gadget: controller used to wake up the host
- *
- * Returns zero on success, else negative error code if the hardware
- * doesn't support such attempts, or its support has not been enabled
- * by the usb host.  Drivers must return device descriptors that report
- * their ability to support this, or hosts won't enable it.
- *
- * This may also try to use SRP to wake the host and start enumeration,
- * even if OTG isn't otherwise in use.  OTG devices may also start
- * remote wakeup even when hosts don't explicitly enable it.
- */
+#if IS_ENABLED(CONFIG_USB_GADGET)
+int usb_gadget_frame_number(struct usb_gadget *gadget);
+int usb_gadget_wakeup(struct usb_gadget *gadget);
+int usb_gadget_set_selfpowered(struct usb_gadget *gadget);
+int usb_gadget_clear_selfpowered(struct usb_gadget *gadget);
+int usb_gadget_vbus_connect(struct usb_gadget *gadget);
+int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA);
+int usb_gadget_vbus_disconnect(struct usb_gadget *gadget);
+int usb_gadget_connect(struct usb_gadget *gadget);
+int usb_gadget_disconnect(struct usb_gadget *gadget);
+int usb_gadget_deactivate(struct usb_gadget *gadget);
+int usb_gadget_activate(struct usb_gadget *gadget);
+#else
+static inline int usb_gadget_frame_number(struct usb_gadget *gadget)
+{ return 0; }
 static inline int usb_gadget_wakeup(struct usb_gadget *gadget)
-{
-       if (!gadget->ops->wakeup)
-               return -EOPNOTSUPP;
-       return gadget->ops->wakeup(gadget);
-}
-
-/**
- * usb_gadget_set_selfpowered - sets the device selfpowered feature.
- * @gadget:the device being declared as self-powered
- *
- * this affects the device status reported by the hardware driver
- * to reflect that it now has a local power supply.
- *
- * returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget)
-{
-       if (!gadget->ops->set_selfpowered)
-               return -EOPNOTSUPP;
-       return gadget->ops->set_selfpowered(gadget, 1);
-}
-
-/**
- * usb_gadget_clear_selfpowered - clear the device selfpowered feature.
- * @gadget:the device being declared as bus-powered
- *
- * this affects the device status reported by the hardware driver.
- * some hardware may not support bus-powered operation, in which
- * case this feature's value can never change.
- *
- * returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget)
-{
-       if (!gadget->ops->set_selfpowered)
-               return -EOPNOTSUPP;
-       return gadget->ops->set_selfpowered(gadget, 0);
-}
-
-/**
- * usb_gadget_vbus_connect - Notify controller that VBUS is powered
- * @gadget:The device which now has VBUS power.
- * Context: can sleep
- *
- * This call is used by a driver for an external transceiver (or GPIO)
- * that detects a VBUS power session starting.  Common responses include
- * resuming the controller, activating the D+ (or D-) pullup to let the
- * host detect that a USB device is attached, and starting to draw power
- * (8mA or possibly more, especially after SET_CONFIGURATION).
- *
- * Returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget)
-{
-       if (!gadget->ops->vbus_session)
-               return -EOPNOTSUPP;
-       return gadget->ops->vbus_session(gadget, 1);
-}
-
-/**
- * usb_gadget_vbus_draw - constrain controller's VBUS power usage
- * @gadget:The device whose VBUS usage is being described
- * @mA:How much current to draw, in milliAmperes.  This should be twice
- *     the value listed in the configuration descriptor bMaxPower field.
- *
- * This call is used by gadget drivers during SET_CONFIGURATION calls,
- * reporting how much power the device may consume.  For example, this
- * could affect how quickly batteries are recharged.
- *
- * Returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
-{
-       if (!gadget->ops->vbus_draw)
-               return -EOPNOTSUPP;
-       return gadget->ops->vbus_draw(gadget, mA);
-}
-
-/**
- * usb_gadget_vbus_disconnect - notify controller about VBUS session end
- * @gadget:the device whose VBUS supply is being described
- * Context: can sleep
- *
- * This call is used by a driver for an external transceiver (or GPIO)
- * that detects a VBUS power session ending.  Common responses include
- * reversing everything done in usb_gadget_vbus_connect().
- *
- * Returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
-{
-       if (!gadget->ops->vbus_session)
-               return -EOPNOTSUPP;
-       return gadget->ops->vbus_session(gadget, 0);
-}
-
-/**
- * usb_gadget_connect - software-controlled connect to USB host
- * @gadget:the peripheral being connected
- *
- * Enables the D+ (or potentially D-) pullup.  The host will start
- * enumerating this gadget when the pullup is active and a VBUS session
- * is active (the link is powered).  This pullup is always enabled unless
- * usb_gadget_disconnect() has been used to disable it.
- *
- * Returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_connect(struct usb_gadget *gadget)
-{
-       int ret;
-
-       if (!gadget->ops->pullup)
-               return -EOPNOTSUPP;
-
-       if (gadget->deactivated) {
-               /*
-                * If gadget is deactivated we only save new state.
-                * Gadget will be connected automatically after activation.
-                */
-               gadget->connected = true;
-               return 0;
-       }
-
-       ret = gadget->ops->pullup(gadget, 1);
-       if (!ret)
-               gadget->connected = 1;
-       return ret;
-}
-
-/**
- * usb_gadget_disconnect - software-controlled disconnect from USB host
- * @gadget:the peripheral being disconnected
- *
- * Disables the D+ (or potentially D-) pullup, which the host may see
- * as a disconnect (when a VBUS session is active).  Not all systems
- * support software pullup controls.
- *
- * Returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
-{
-       int ret;
-
-       if (!gadget->ops->pullup)
-               return -EOPNOTSUPP;
-
-       if (gadget->deactivated) {
-               /*
-                * If gadget is deactivated we only save new state.
-                * Gadget will stay disconnected after activation.
-                */
-               gadget->connected = false;
-               return 0;
-       }
-
-       ret = gadget->ops->pullup(gadget, 0);
-       if (!ret)
-               gadget->connected = 0;
-       return ret;
-}
-
-/**
- * usb_gadget_deactivate - deactivate function which is not ready to work
- * @gadget: the peripheral being deactivated
- *
- * This routine may be used during the gadget driver bind() call to prevent
- * the peripheral from ever being visible to the USB host, unless later
- * usb_gadget_activate() is called.  For example, user mode components may
- * need to be activated before the system can talk to hosts.
- *
- * Returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_deactivate(struct usb_gadget *gadget)
-{
-       int ret;
-
-       if (gadget->deactivated)
-               return 0;
-
-       if (gadget->connected) {
-               ret = usb_gadget_disconnect(gadget);
-               if (ret)
-                       return ret;
-               /*
-                * If gadget was being connected before deactivation, we want
-                * to reconnect it in usb_gadget_activate().
-                */
-               gadget->connected = true;
-       }
-       gadget->deactivated = true;
-
-       return 0;
-}
-
-/**
- * usb_gadget_activate - activate function which is not ready to work
- * @gadget: the peripheral being activated
- *
- * This routine activates gadget which was previously deactivated with
- * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed.
- *
- * Returns zero on success, else negative errno.
- */
+{ return 0; }
 static inline int usb_gadget_activate(struct usb_gadget *gadget)
-{
-       if (!gadget->deactivated)
-               return 0;
-
-       gadget->deactivated = false;
-
-       /*
-        * If gadget has been connected before deactivation, or became connected
-        * while it was being deactivated, we call usb_gadget_connect().
-        */
-       if (gadget->connected)
-               return usb_gadget_connect(gadget);
-
-       return 0;
-}
+{ return 0; }
+#endif /* CONFIG_USB_GADGET */
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
deleted file mode 100644 (file)
index 8c8f685..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/* linux/include/asm-arm/arch-msm/hsusb.h
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef __ASM_ARCH_MSM_HSUSB_H
-#define __ASM_ARCH_MSM_HSUSB_H
-
-#include <linux/extcon.h>
-#include <linux/types.h>
-#include <linux/usb/otg.h>
-#include <linux/clk.h>
-
-/**
- * OTG control
- *
- * OTG_NO_CONTROL      Id/VBUS notifications not required. Useful in host
- *                      only configuration.
- * OTG_PHY_CONTROL     Id/VBUS notifications comes form USB PHY.
- * OTG_PMIC_CONTROL    Id/VBUS notifications comes from PMIC hardware.
- * OTG_USER_CONTROL    Id/VBUS notifcations comes from User via sysfs.
- *
- */
-enum otg_control_type {
-       OTG_NO_CONTROL = 0,
-       OTG_PHY_CONTROL,
-       OTG_PMIC_CONTROL,
-       OTG_USER_CONTROL,
-};
-
-/**
- * PHY used in
- *
- * INVALID_PHY                 Unsupported PHY
- * CI_45NM_INTEGRATED_PHY      Chipidea 45nm integrated PHY
- * SNPS_28NM_INTEGRATED_PHY    Synopsis 28nm integrated PHY
- *
- */
-enum msm_usb_phy_type {
-       INVALID_PHY = 0,
-       CI_45NM_INTEGRATED_PHY,
-       SNPS_28NM_INTEGRATED_PHY,
-};
-
-#define IDEV_CHG_MAX   1500
-#define IUNIT          100
-
-/**
- * Different states involved in USB charger detection.
- *
- * USB_CHG_STATE_UNDEFINED     USB charger is not connected or detection
- *                              process is not yet started.
- * USB_CHG_STATE_WAIT_FOR_DCD  Waiting for Data pins contact.
- * USB_CHG_STATE_DCD_DONE      Data pin contact is detected.
- * USB_CHG_STATE_PRIMARY_DONE  Primary detection is completed (Detects
- *                              between SDP and DCP/CDP).
- * USB_CHG_STATE_SECONDARY_DONE        Secondary detection is completed (Detects
- *                              between DCP and CDP).
- * USB_CHG_STATE_DETECTED      USB charger type is determined.
- *
- */
-enum usb_chg_state {
-       USB_CHG_STATE_UNDEFINED = 0,
-       USB_CHG_STATE_WAIT_FOR_DCD,
-       USB_CHG_STATE_DCD_DONE,
-       USB_CHG_STATE_PRIMARY_DONE,
-       USB_CHG_STATE_SECONDARY_DONE,
-       USB_CHG_STATE_DETECTED,
-};
-
-/**
- * USB charger types
- *
- * USB_INVALID_CHARGER Invalid USB charger.
- * USB_SDP_CHARGER     Standard downstream port. Refers to a downstream port
- *                      on USB2.0 compliant host/hub.
- * USB_DCP_CHARGER     Dedicated charger port (AC charger/ Wall charger).
- * USB_CDP_CHARGER     Charging downstream port. Enumeration can happen and
- *                      IDEV_CHG_MAX can be drawn irrespective of USB state.
- *
- */
-enum usb_chg_type {
-       USB_INVALID_CHARGER = 0,
-       USB_SDP_CHARGER,
-       USB_DCP_CHARGER,
-       USB_CDP_CHARGER,
-};
-
-/**
- * struct msm_otg_platform_data - platform device data
- *              for msm_otg driver.
- * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as
- *              "do not overwrite default vaule at this address".
- * @phy_init_sz: PHY configuration sequence size.
- * @vbus_power: VBUS power on/off routine.
- * @power_budget: VBUS power budget in mA (0 will be treated as 500mA).
- * @mode: Supported mode (OTG/peripheral/host).
- * @otg_control: OTG switch controlled by user/Id pin
- */
-struct msm_otg_platform_data {
-       int *phy_init_seq;
-       int phy_init_sz;
-       void (*vbus_power)(bool on);
-       unsigned power_budget;
-       enum usb_dr_mode mode;
-       enum otg_control_type otg_control;
-       enum msm_usb_phy_type phy_type;
-       void (*setup_gpio)(enum usb_otg_state state);
-};
-
-/**
- * struct msm_usb_cable - structure for exteternal connector cable
- *                       state tracking
- * @nb: hold event notification callback
- * @conn: used for notification registration
- */
-struct msm_usb_cable {
-       struct notifier_block           nb;
-       struct extcon_dev               *extcon;
-};
-
-/**
- * struct msm_otg: OTG driver data. Shared by HCD and DCD.
- * @otg: USB OTG Transceiver structure.
- * @pdata: otg device platform data.
- * @irq: IRQ number assigned for HSUSB controller.
- * @clk: clock struct of usb_hs_clk.
- * @pclk: clock struct of usb_hs_pclk.
- * @core_clk: clock struct of usb_hs_core_clk.
- * @regs: ioremapped register base address.
- * @inputs: OTG state machine inputs(Id, SessValid etc).
- * @sm_work: OTG state machine work.
- * @in_lpm: indicates low power mode (LPM) state.
- * @async_int: Async interrupt arrived.
- * @cur_power: The amount of mA available from downstream port.
- * @chg_work: Charger detection work.
- * @chg_state: The state of charger detection process.
- * @chg_type: The type of charger attached.
- * @dcd_retires: The retry count used to track Data contact
- *               detection process.
- * @manual_pullup: true if VBUS is not routed to USB controller/phy
- *     and controller driver therefore enables pull-up explicitly before
- *     starting controller using usbcmd run/stop bit.
- * @vbus: VBUS signal state trakining, using extcon framework
- * @id: ID signal state trakining, using extcon framework
- * @switch_gpio: Descriptor for GPIO used to control external Dual
- *               SPDT USB Switch.
- * @reboot: Used to inform the driver to route USB D+/D- line to Device
- *         connector
- */
-struct msm_otg {
-       struct usb_phy phy;
-       struct msm_otg_platform_data *pdata;
-       int irq;
-       struct clk *clk;
-       struct clk *pclk;
-       struct clk *core_clk;
-       void __iomem *regs;
-#define ID             0
-#define B_SESS_VLD     1
-       unsigned long inputs;
-       struct work_struct sm_work;
-       atomic_t in_lpm;
-       int async_int;
-       unsigned cur_power;
-       int phy_number;
-       struct delayed_work chg_work;
-       enum usb_chg_state chg_state;
-       enum usb_chg_type chg_type;
-       u8 dcd_retries;
-       struct regulator *v3p3;
-       struct regulator *v1p8;
-       struct regulator *vddcx;
-
-       struct reset_control *phy_rst;
-       struct reset_control *link_rst;
-       int vdd_levels[3];
-
-       bool manual_pullup;
-
-       struct msm_usb_cable vbus;
-       struct msm_usb_cable id;
-
-       struct gpio_desc *switch_gpio;
-       struct notifier_block reboot;
-};
-
-#endif
index de3237f..5ff9032 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/usb/phy.h>
 
 #if IS_ENABLED(CONFIG_OF)
-enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np);
+enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0);
 bool of_usb_host_tpl_support(struct device_node *np);
 int of_usb_update_otg_caps(struct device_node *np,
                        struct usb_otg_caps *otg_caps);
@@ -20,7 +20,7 @@ struct device_node *usb_of_get_child_node(struct device_node *parent,
                        int portnum);
 #else
 static inline enum usb_dr_mode
-of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
+of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0)
 {
        return USB_DR_MODE_UNKNOWN;
 }
diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h
deleted file mode 100644 (file)
index 376654b..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 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.
- *
- */
-
-#ifndef __USB_CORE_XHCI_PDRIVER_H
-#define __USB_CORE_XHCI_PDRIVER_H
-
-/**
- * struct usb_xhci_pdata - platform_data for generic xhci platform driver
- *
- * @usb3_lpm_capable:  determines if this xhci platform supports USB3
- *                     LPM capability
- *
- */
-struct usb_xhci_pdata {
-       unsigned        usb3_lpm_capable:1;
-};
-
-#endif /* __USB_CORE_XHCI_PDRIVER_H */