Merge tag 'v3.17-rc5' into next
authorFelipe Balbi <balbi@ti.com>
Tue, 16 Sep 2014 14:53:59 +0000 (09:53 -0500)
committerFelipe Balbi <balbi@ti.com>
Tue, 16 Sep 2014 14:53:59 +0000 (09:53 -0500)
Linux 3.17-rc5

Signed-off-by: Felipe Balbi <balbi@ti.com>
Conflicts:
Documentation/devicetree/bindings/usb/mxs-phy.txt
drivers/usb/phy/phy-mxs-usb.c

1  2 
Documentation/devicetree/bindings/usb/mxs-phy.txt
MAINTAINERS
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/musb/musb_cppi41.c
drivers/usb/phy/phy-mxs-usb.c

index fe3eed89e4c3b93d37c91857cbd67628aae94da1,96681c93b86df38788327df42c543738293265ea..379b84a567ccb82442b1275c43cdc9d6d518c075
@@@ -5,7 -5,7 +5,8 @@@ Required properties
        * "fsl,imx23-usbphy" for imx23 and imx28
        * "fsl,imx6q-usbphy" for imx6dq and imx6dl
        * "fsl,imx6sl-usbphy" for imx6sl
 +      * "fsl,vf610-usbphy" for Vybrid vf610
+       * "fsl,imx6sx-usbphy" for imx6sx
    "fsl,imx23-usbphy" is still a fallback for other strings
  - reg: Should contain registers location and length
  - interrupts: Should contain phy interrupt
diff --combined MAINTAINERS
index 96568a8f961bbbef541a727cd4dc47c212271ffd,809ecd680d8829f6148ababe654d30a7882b11fe..3ca017a3ddea4f029d8070b167d970c460a0b135
@@@ -1398,7 -1398,6 +1398,7 @@@ F:      drivers/media/rc/st_rc.
  F:    drivers/i2c/busses/i2c-st.c
  F:    drivers/tty/serial/st-asc.c
  F:    drivers/mmc/host/sdhci-st.c
 +F:    drivers/usb/dwc3/dwc3-st.c
  
  ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
  M:    Lennert Buytenhek <kernel@wantstofly.org>
@@@ -6425,7 -6424,8 +6425,8 @@@ F:      Documentation/scsi/NinjaSCSI.tx
  F:    drivers/scsi/nsp32*
  
  NTB DRIVER
- M:    Jon Mason <jon.mason@intel.com>
+ M:    Jon Mason <jdmason@kudzu.us>
+ M:    Dave Jiang <dave.jiang@intel.com>
  S:    Supported
  W:    https://github.com/jonmason/ntb/wiki
  T:    git git://github.com/jonmason/ntb.git
@@@ -7054,7 -7054,7 +7055,7 @@@ S:      Maintaine
  F:    drivers/pinctrl/sh-pfc/
  
  PIN CONTROLLER - SAMSUNG
- M:    Tomasz Figa <t.figa@samsung.com>
+ M:    Tomasz Figa <tomasz.figa@gmail.com>
  M:    Thomas Abraham <thomas.abraham@linaro.org>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  L:    linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
@@@ -7900,7 -7900,8 +7901,8 @@@ S:      Supporte
  F:    drivers/media/i2c/s5k5baf.c
  
  SAMSUNG SOC CLOCK DRIVERS
- M:    Tomasz Figa <t.figa@samsung.com>
+ M:    Sylwester Nawrocki <s.nawrocki@samsung.com>
+ M:    Tomasz Figa <tomasz.figa@gmail.com>
  S:    Supported
  L:    linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
  F:    drivers/clk/samsung/
@@@ -7913,6 -7914,19 +7915,19 @@@ S:    Supporte
  L:    netdev@vger.kernel.org
  F:    drivers/net/ethernet/samsung/sxgbe/
  
+ SAMSUNG USB2 PHY DRIVER
+ M:    Kamil Debski <k.debski@samsung.com>
+ L:    linux-kernel@vger.kernel.org
+ S:    Supported
+ F:    Documentation/devicetree/bindings/phy/samsung-phy.txt
+ F:    Documentation/phy/samsung-usb2.txt
+ F:    drivers/phy/phy-exynos4210-usb2.c
+ F:    drivers/phy/phy-exynos4x12-usb2.c
+ F:    drivers/phy/phy-exynos5250-usb2.c
+ F:    drivers/phy/phy-s5pv210-usb2.c
+ F:    drivers/phy/phy-samsung-usb2.c
+ F:    drivers/phy/phy-samsung-usb2.h
  SERIAL DRIVERS
  M:    Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  L:    linux-serial@vger.kernel.org
@@@ -9669,7 -9683,7 +9684,7 @@@ USB WEBCAM GADGE
  M:    Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  L:    linux-usb@vger.kernel.org
  S:    Maintained
 -F:    drivers/usb/gadget/function/*uvc*.c
 +F:    drivers/usb/gadget/function/*uvc*
  F:    drivers/usb/gadget/legacy/webcam.c
  
  USB WIRELESS RNDIS DRIVER (rndis_wlan)
diff --combined drivers/usb/dwc3/core.c
index f2050e844b4bae97dec305180287672c69781a92,9069984fe5cf0eae313a0dfb5faa2fe06ba9766c..b0f4d52b7f04a023b6d743c686a54eace4797047
@@@ -186,8 -186,10 +186,8 @@@ static int dwc3_alloc_event_buffers(str
  
        dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
                        GFP_KERNEL);
 -      if (!dwc->ev_buffs) {
 -              dev_err(dwc->dev, "can't allocate event buffers array\n");
 +      if (!dwc->ev_buffs)
                return -ENOMEM;
 -      }
  
        for (i = 0; i < num; i++) {
                struct dwc3_event_buffer        *evt;
@@@ -637,9 -639,10 +637,9 @@@ static int dwc3_probe(struct platform_d
        void                    *mem;
  
        mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
 -      if (!mem) {
 -              dev_err(dev, "not enough memory\n");
 +      if (!mem)
                return -ENOMEM;
 -      }
 +
        dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
        dwc->mem = mem;
        dwc->dev = dev;
@@@ -796,20 -799,21 +796,21 @@@ static int dwc3_remove(struct platform_
  {
        struct dwc3     *dwc = platform_get_drvdata(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);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
  
-       dwc3_debugfs_exit(dwc);
-       dwc3_core_exit_mode(dwc);
-       dwc3_event_buffers_cleanup(dwc);
-       dwc3_free_event_buffers(dwc);
-       dwc3_core_exit(dwc);
        return 0;
  }
  
index 3ef5e4fc315b19efcb9fb8c9a70828643c690163,fc0de3753648187ab9f1fd68ac121a83cd808e91..2f537d588225fd11bcab9c5b827ad488a1d93f22
@@@ -481,8 -481,10 +481,8 @@@ static int dwc3_omap_probe(struct platf
        }
  
        omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
 -      if (!omap) {
 -              dev_err(dev, "not enough memory\n");
 +      if (!omap)
                return -ENOMEM;
 -      }
  
        platform_set_drvdata(pdev, omap);
  
@@@ -574,9 -576,9 +574,9 @@@ static int dwc3_omap_remove(struct plat
        if (omap->extcon_id_dev.edev)
                extcon_unregister_interest(&omap->extcon_id_dev);
        dwc3_omap_disable_irqs(omap);
+       device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
  
        return 0;
  }
index f2dbaca5df2cf6de7afc958dcba50f67894f1ec6,490a6ca0073369844b40eff51f88b2cbfd353bce..0fcc0a35ae05fdc7df2f3c73422231c3ae8fa9ca
@@@ -30,7 -30,6 +30,7 @@@
  #include <linux/usb/ch9.h>
  #include <linux/usb/gadget.h>
  
 +#include "debug.h"
  #include "core.h"
  #include "gadget.h"
  #include "io.h"
@@@ -267,19 -266,107 +267,19 @@@ void dwc3_gadget_giveback(struct dwc3_e
        dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
                        req, dep->name, req->request.actual,
                        req->request.length, status);
 +      trace_dwc3_gadget_giveback(req);
  
        spin_unlock(&dwc->lock);
        req->request.complete(&dep->endpoint, &req->request);
        spin_lock(&dwc->lock);
  }
  
 -static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
 -{
 -      switch (cmd) {
 -      case DWC3_DEPCMD_DEPSTARTCFG:
 -              return "Start New Configuration";
 -      case DWC3_DEPCMD_ENDTRANSFER:
 -              return "End Transfer";
 -      case DWC3_DEPCMD_UPDATETRANSFER:
 -              return "Update Transfer";
 -      case DWC3_DEPCMD_STARTTRANSFER:
 -              return "Start Transfer";
 -      case DWC3_DEPCMD_CLEARSTALL:
 -              return "Clear Stall";
 -      case DWC3_DEPCMD_SETSTALL:
 -              return "Set Stall";
 -      case DWC3_DEPCMD_GETEPSTATE:
 -              return "Get Endpoint State";
 -      case DWC3_DEPCMD_SETTRANSFRESOURCE:
 -              return "Set Endpoint Transfer Resource";
 -      case DWC3_DEPCMD_SETEPCONFIG:
 -              return "Set Endpoint Configuration";
 -      default:
 -              return "UNKNOWN command";
 -      }
 -}
 -
 -static const char *dwc3_gadget_generic_cmd_string(u8 cmd)
 -{
 -      switch (cmd) {
 -      case DWC3_DGCMD_SET_LMP:
 -              return "Set LMP";
 -      case DWC3_DGCMD_SET_PERIODIC_PAR:
 -              return "Set Periodic Parameters";
 -      case DWC3_DGCMD_XMIT_FUNCTION:
 -              return "Transmit Function Wake Device Notification";
 -      case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
 -              return "Set Scratchpad Buffer Array Address Lo";
 -      case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
 -              return "Set Scratchpad Buffer Array Address Hi";
 -      case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
 -              return "Selected FIFO Flush";
 -      case DWC3_DGCMD_ALL_FIFO_FLUSH:
 -              return "All FIFO Flush";
 -      case DWC3_DGCMD_SET_ENDPOINT_NRDY:
 -              return "Set Endpoint NRDY";
 -      case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
 -              return "Run SoC Bus Loopback Test";
 -      default:
 -              return "UNKNOWN";
 -      }
 -}
 -
 -static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state)
 -{
 -      switch (link_state) {
 -      case DWC3_LINK_STATE_U0:
 -              return "U0";
 -      case DWC3_LINK_STATE_U1:
 -              return "U1";
 -      case DWC3_LINK_STATE_U2:
 -              return "U2";
 -      case DWC3_LINK_STATE_U3:
 -              return "U3";
 -      case DWC3_LINK_STATE_SS_DIS:
 -              return "SS.Disabled";
 -      case DWC3_LINK_STATE_RX_DET:
 -              return "RX.Detect";
 -      case DWC3_LINK_STATE_SS_INACT:
 -              return "SS.Inactive";
 -      case DWC3_LINK_STATE_POLL:
 -              return "Polling";
 -      case DWC3_LINK_STATE_RECOV:
 -              return "Recovery";
 -      case DWC3_LINK_STATE_HRESET:
 -              return "Hot Reset";
 -      case DWC3_LINK_STATE_CMPLY:
 -              return "Compliance";
 -      case DWC3_LINK_STATE_LPBK:
 -              return "Loopback";
 -      case DWC3_LINK_STATE_RESET:
 -              return "Reset";
 -      case DWC3_LINK_STATE_RESUME:
 -              return "Resume";
 -      default:
 -              return "UNKNOWN link state\n";
 -      }
 -}
 -
 -int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)
 +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
  {
        u32             timeout = 500;
        u32             reg;
  
 -      dev_vdbg(dwc->dev, "generic cmd '%s' [%d] param %08x\n",
 -                      dwc3_gadget_generic_cmd_string(cmd), cmd, param);
 +      trace_dwc3_gadget_generic_cmd(cmd, param);
  
        dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
        dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
@@@ -310,7 -397,10 +310,7 @@@ int dwc3_send_gadget_ep_cmd(struct dwc
        u32                     timeout = 500;
        u32                     reg;
  
 -      dev_vdbg(dwc->dev, "%s: cmd '%s' [%d] params %08x %08x %08x\n",
 -                      dep->name,
 -                      dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0,
 -                      params->param1, params->param2);
 +      trace_dwc3_gadget_ep_cmd(dep, cmd, params);
  
        dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
        dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
@@@ -437,7 -527,7 +437,7 @@@ static int dwc3_gadget_set_ep_config(st
                dep->stream_capable = true;
        }
  
-       if (usb_endpoint_xfer_isoc(desc))
+       if (!usb_endpoint_xfer_control(desc))
                params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
  
        /*
@@@ -699,16 -789,17 +699,16 @@@ static struct usb_request *dwc3_gadget_
  {
        struct dwc3_request             *req;
        struct dwc3_ep                  *dep = to_dwc3_ep(ep);
 -      struct dwc3                     *dwc = dep->dwc;
  
        req = kzalloc(sizeof(*req), gfp_flags);
 -      if (!req) {
 -              dev_err(dwc->dev, "not enough memory\n");
 +      if (!req)
                return NULL;
 -      }
  
        req->epnum      = dep->number;
        req->dep        = dep;
  
 +      trace_dwc3_alloc_request(req);
 +
        return &req->request;
  }
  
@@@ -717,7 -808,6 +717,7 @@@ static void dwc3_gadget_ep_free_request
  {
        struct dwc3_request             *req = to_dwc3_request(request);
  
 +      trace_dwc3_free_request(req);
        kfree(req);
  }
  
@@@ -799,8 -889,6 +799,8 @@@ static void dwc3_prepare_one_trb(struc
                trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
  
        trb->ctrl |= DWC3_TRB_CTRL_HWO;
 +
 +      trace_dwc3_prepare_trb(dep, trb);
  }
  
  /*
@@@ -1137,17 -1225,17 +1137,18 @@@ static int dwc3_gadget_ep_queue(struct 
  
        int                             ret;
  
+       spin_lock_irqsave(&dwc->lock, flags);
        if (!dep->endpoint.desc) {
                dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
                                request, ep->name);
+               spin_unlock_irqrestore(&dwc->lock, flags);
                return -ESHUTDOWN;
        }
  
        dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
                        request, ep->name, request->length);
 +      trace_dwc3_ep_queue(req);
  
-       spin_lock_irqsave(&dwc->lock, flags);
        ret = __dwc3_gadget_ep_queue(dep, req);
        spin_unlock_irqrestore(&dwc->lock, flags);
  
@@@ -1166,8 -1254,6 +1167,8 @@@ static int dwc3_gadget_ep_dequeue(struc
        unsigned long                   flags;
        int                             ret = 0;
  
 +      trace_dwc3_ep_dequeue(req);
 +
        spin_lock_irqsave(&dwc->lock, flags);
  
        list_for_each_entry(r, &dep->request_list, list) {
@@@ -1658,8 -1744,11 +1659,8 @@@ static int dwc3_gadget_init_hw_endpoint
                u8 epnum = (i << 1) | (!!direction);
  
                dep = kzalloc(sizeof(*dep), GFP_KERNEL);
 -              if (!dep) {
 -                      dev_err(dwc->dev, "can't allocate endpoint %d\n",
 -                                      epnum);
 +              if (!dep)
                        return -ENOMEM;
 -              }
  
                dep->dwc = dwc;
                dep->number = epnum;
@@@ -1758,8 -1847,6 +1759,8 @@@ static int __dwc3_cleanup_done_trbs(str
        unsigned int            s_pkt = 0;
        unsigned int            trb_status;
  
 +      trace_dwc3_complete_trb(dep, trb);
 +
        if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
                /*
                 * We continue despite the error. There is not much we
@@@ -1934,6 -2021,9 +1935,6 @@@ static void dwc3_endpoint_interrupt(str
        if (!(dep->flags & DWC3_EP_ENABLED))
                return;
  
 -      dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
 -                      dwc3_ep_event_string(event->endpoint_event));
 -
        if (epnum == 0 || epnum == 1) {
                dwc3_ep0_interrupt(dwc, event);
                return;
                dwc3_endpoint_transfer_complete(dwc, dep, event);
                break;
        case DWC3_DEPEVT_XFERINPROGRESS:
-               if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
-                       dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
-                                       dep->name);
-                       return;
-               }
                dwc3_endpoint_transfer_complete(dwc, dep, event);
                break;
        case DWC3_DEPEVT_XFERNOTREADY:
@@@ -2126,6 -2210,8 +2121,6 @@@ static void dwc3_gadget_disconnect_inte
  {
        int                     reg;
  
 -      dev_vdbg(dwc->dev, "%s\n", __func__);
 -
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        reg &= ~DWC3_DCTL_INITU1ENA;
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
@@@ -2144,6 -2230,8 +2139,6 @@@ static void dwc3_gadget_reset_interrupt
  {
        u32                     reg;
  
 -      dev_vdbg(dwc->dev, "%s\n", __func__);
 -
        /*
         * WORKAROUND: DWC3 revisions <1.88a have an issue which
         * would cause a missing Disconnect Event if there's a
@@@ -2228,6 -2316,8 +2223,6 @@@ static void dwc3_gadget_conndone_interr
        u32                     reg;
        u8                      speed;
  
 -      dev_vdbg(dwc->dev, "%s\n", __func__);
 -
        reg = dwc3_readl(dwc->regs, DWC3_DSTS);
        speed = reg & DWC3_DSTS_CONNECTSPD;
        dwc->speed = speed;
  
  static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
  {
 -      dev_vdbg(dwc->dev, "%s\n", __func__);
 -
        /*
         * TODO take core out of low power mode when that's
         * implemented.
@@@ -2429,6 -2521,10 +2424,6 @@@ static void dwc3_gadget_linksts_change_
                break;
        }
  
 -      dev_vdbg(dwc->dev, "link change: %s [%d] -> %s [%d]\n",
 -                      dwc3_gadget_link_string(dwc->link_state),
 -                      dwc->link_state, dwc3_gadget_link_string(next), next);
 -
        dwc->link_state = next;
  }
  
@@@ -2505,8 -2601,6 +2500,8 @@@ static void dwc3_gadget_interrupt(struc
  static void dwc3_process_event_entry(struct dwc3 *dwc,
                const union dwc3_event *event)
  {
 +      trace_dwc3_event(event->raw);
 +
        /* Endpoint IRQ, handle it and return early */
        if (event->type.is_devspec == 0) {
                /* depevt */
@@@ -2660,6 -2754,7 +2655,6 @@@ int dwc3_gadget_init(struct dwc3 *dwc
  
        dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
        if (!dwc->setup_buf) {
 -              dev_err(dwc->dev, "failed to allocate setup buffer\n");
                ret = -ENOMEM;
                goto err2;
        }
index a86b0a231a8c42f0c2b68edee7a8c9ec26c6213b,0dc3552d13603282d3d631aa1a7d06078bec0c3b..e4afe8df555345e457e11dd80ea91e10603f34af
@@@ -155,6 -155,12 +155,12 @@@ struct ffs_io_data 
        struct usb_request *req;
  };
  
+ struct ffs_desc_helper {
+       struct ffs_data *ffs;
+       unsigned interfaces_count;
+       unsigned eps_count;
+ };
  static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);
  static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
  
@@@ -1026,29 -1032,6 +1032,29 @@@ static long ffs_epfile_ioctl(struct fil
                case FUNCTIONFS_ENDPOINT_REVMAP:
                        ret = epfile->ep->num;
                        break;
 +              case FUNCTIONFS_ENDPOINT_DESC:
 +              {
 +                      int desc_idx;
 +                      struct usb_endpoint_descriptor *desc;
 +
 +                      switch (epfile->ffs->gadget->speed) {
 +                      case USB_SPEED_SUPER:
 +                              desc_idx = 2;
 +                              break;
 +                      case USB_SPEED_HIGH:
 +                              desc_idx = 1;
 +                              break;
 +                      default:
 +                              desc_idx = 0;
 +                      }
 +                      desc = epfile->ep->descs[desc_idx];
 +
 +                      spin_unlock_irq(&epfile->ffs->eps_lock);
 +                      ret = copy_to_user((void *)value, desc, sizeof(*desc));
 +                      if (ret)
 +                              ret = -EFAULT;
 +                      return ret;
 +              }
                default:
                        ret = -ENOTTY;
                }
@@@ -1853,7 -1836,8 +1859,8 @@@ static int __ffs_data_do_entity(enum ff
                                u8 *valuep, struct usb_descriptor_header *desc,
                                void *priv)
  {
-       struct ffs_data *ffs = priv;
+       struct ffs_desc_helper *helper = priv;
+       struct usb_endpoint_descriptor *d;
  
        ENTER();
  
                 * encountered interface "n" then there are at least
                 * "n+1" interfaces.
                 */
-               if (*valuep >= ffs->interfaces_count)
-                       ffs->interfaces_count = *valuep + 1;
+               if (*valuep >= helper->interfaces_count)
+                       helper->interfaces_count = *valuep + 1;
                break;
  
        case FFS_STRING:
                 * Strings are indexed from 1 (0 is magic ;) reserved
                 * for languages list or some such)
                 */
-               if (*valuep > ffs->strings_count)
-                       ffs->strings_count = *valuep;
+               if (*valuep > helper->ffs->strings_count)
+                       helper->ffs->strings_count = *valuep;
                break;
  
        case FFS_ENDPOINT:
-               /* Endpoints are indexed from 1 as well. */
-               if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count)
-                       ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK);
+               d = (void *)desc;
+               helper->eps_count++;
+               if (helper->eps_count >= 15)
+                       return -EINVAL;
+               /* Check if descriptors for any speed were already parsed */
+               if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
+                       helper->ffs->eps_addrmap[helper->eps_count] =
+                               d->bEndpointAddress;
+               else if (helper->ffs->eps_addrmap[helper->eps_count] !=
+                               d->bEndpointAddress)
+                       return -EINVAL;
                break;
        }
  
@@@ -2076,6 -2068,7 +2091,7 @@@ static int __ffs_data_got_descs(struct 
        char *data = _data, *raw_descs;
        unsigned os_descs_count = 0, counts[3], flags;
        int ret = -EINVAL, i;
+       struct ffs_desc_helper helper;
  
        ENTER();
  
  
        /* Read descriptors */
        raw_descs = data;
+       helper.ffs = ffs;
        for (i = 0; i < 3; ++i) {
                if (!counts[i])
                        continue;
+               helper.interfaces_count = 0;
+               helper.eps_count = 0;
                ret = ffs_do_descs(counts[i], data, len,
-                                  __ffs_data_do_entity, ffs);
+                                  __ffs_data_do_entity, &helper);
                if (ret < 0)
                        goto error;
+               if (!ffs->eps_count && !ffs->interfaces_count) {
+                       ffs->eps_count = helper.eps_count;
+                       ffs->interfaces_count = helper.interfaces_count;
+               } else {
+                       if (ffs->eps_count != helper.eps_count) {
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       if (ffs->interfaces_count != helper.interfaces_count) {
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               }
                data += ret;
                len  -= ret;
        }
@@@ -2337,8 -2346,7 +2369,8 @@@ static void __ffs_event_add(struct ffs_
                break;
  
        default:
 -              BUG();
 +              WARN(1, "%d: unknown event, this should not happen\n", type);
 +              return;
        }
  
        {
@@@ -2366,9 -2374,18 +2398,18 @@@ static void ffs_event_add(struct ffs_da
        spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
  }
  
  /* Bind/unbind USB function hooks *******************************************/
  
+ static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
+ {
+       int i;
+       for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
+               if (ffs->eps_addrmap[i] == endpoint_address)
+                       return i;
+       return -ENOENT;
+ }
  static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
                                    struct usb_descriptor_header *desc,
                                    void *priv)
        struct usb_endpoint_descriptor *ds = (void *)desc;
        struct ffs_function *func = priv;
        struct ffs_ep *ffs_ep;
 -      unsigned ep_desc_id, idx;
 +      unsigned ep_desc_id;
 +      int idx;
        static const char *speed_names[] = { "full", "high", "super" };
  
        if (type != FFS_DESCRIPTOR)
        if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
                return 0;
  
-       idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
+       idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
+       if (idx < 0)
+               return idx;
        ffs_ep = func->eps + idx;
  
        if (unlikely(ffs_ep->descs[ep_desc_id])) {
index ecdd6328aafbb1013ae995ef545f5ec4472ad522,3ee133f675abee3e9c6921c4fa034855f57efba8..acdfb3e68a90a69dd842dcb32414612e69c47de0
@@@ -39,6 -39,7 +39,7 @@@ struct cppi41_dma_channel 
        u32 transferred;
        u32 packet_sz;
        struct list_head tx_check;
+       int tx_zlp;
  };
  
  #define MUSB_DMA_NUM_CHANNELS 15
@@@ -122,6 -123,8 +123,8 @@@ static void cppi41_trans_done(struct cp
  {
        struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
        struct musb *musb = hw_ep->musb;
+       void __iomem *epio = hw_ep->regs;
+       u16 csr;
  
        if (!cppi41_channel->prog_len ||
            (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) {
                        cppi41_channel->transferred;
                cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
                cppi41_channel->channel.rx_packet_done = true;
+               /*
+                * transmit ZLP using PIO mode for transfers which size is
+                * multiple of EP packet size.
+                */
+               if (cppi41_channel->tx_zlp && (cppi41_channel->transferred %
+                                       cppi41_channel->packet_sz) == 0) {
+                       musb_ep_select(musb->mregs, hw_ep->epnum);
+                       csr = MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY;
+                       musb_writew(epio, MUSB_TXCSR, csr);
+               }
                musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
        } else {
                /* next iteration, reload */
                struct dma_chan *dc = cppi41_channel->dc;
                struct dma_async_tx_descriptor *dma_desc;
                enum dma_transfer_direction direction;
-               u16 csr;
                u32 remain_bytes;
-               void __iomem *epio = cppi41_channel->hw_ep->regs;
  
                cppi41_channel->buf_addr += cppi41_channel->packet_sz;
  
@@@ -200,7 -212,7 +212,7 @@@ static enum hrtimer_restart cppi41_rech
        if (!list_empty(&controller->early_tx_list)) {
                ret = HRTIMER_RESTART;
                hrtimer_forward_now(&controller->early_tx,
 -                              ktime_set(0, 50 * NSEC_PER_USEC));
 +                              ktime_set(0, 20 * NSEC_PER_USEC));
        }
  
        spin_unlock_irqrestore(&musb->lock, flags);
@@@ -278,7 -290,7 +290,7 @@@ static void cppi41_dma_callback(void *p
  
                        hrtimer_start_range_ns(&controller->early_tx,
                                ktime_set(0, usecs * NSEC_PER_USEC),
 -                              40 * NSEC_PER_USEC,
 +                              20 * NSEC_PER_USEC,
                                HRTIMER_MODE_REL);
                }
        }
@@@ -363,6 -375,7 +375,7 @@@ static bool cppi41_configure_channel(st
        cppi41_channel->total_len = len;
        cppi41_channel->transferred = 0;
        cppi41_channel->packet_sz = packet_sz;
+       cppi41_channel->tx_zlp = (cppi41_channel->is_tx && mode) ? 1 : 0;
  
        /*
         * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
index 8c2f23b75d6d19267f532513ab4ef1811d3b9a7f,00972eca04e7f5d4965f32fd0944c453f5291f07..0e0c41587a08b77cea9e49178de1c420a67405dc
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright 2012-2013 Freescale Semiconductor, Inc.
+  * Copyright 2012-2014 Freescale Semiconductor, Inc.
   * Copyright (C) 2012 Marek Vasut <marex@denx.de>
   * on behalf of DENX Software Engineering GmbH
   *
@@@ -125,16 -125,16 +125,22 @@@ static const struct mxs_phy_data imx6sl
                MXS_PHY_NEED_IP_FIX,
  };
  
 +static const struct mxs_phy_data vf610_phy_data = {
 +      .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
 +              MXS_PHY_NEED_IP_FIX,
 +};
 +
+ static const struct mxs_phy_data imx6sx_phy_data = {
+       .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
+               MXS_PHY_NEED_IP_FIX,
+ };
  static const struct of_device_id mxs_phy_dt_ids[] = {
+       { .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
        { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
        { .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
        { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
 +      { .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
        { /* sentinel */ }
  };
  MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);