]> Pileus Git - ~andy/linux/blobdiff - drivers/usb/dwc3/gadget.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[~andy/linux] / drivers / usb / dwc3 / gadget.c
index f77083fedc68d0d1bfc7afb579e6aae96edb1d63..f168eaebdef8fc6731de7c6994c658737495fdce 100644 (file)
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * 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.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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.
  */
 
 #include <linux/kernel.h>
@@ -520,6 +500,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
        u32                     reg;
        int                     ret = -ENOMEM;
 
+       dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
        if (!(dep->flags & DWC3_EP_ENABLED)) {
                ret = dwc3_gadget_start_config(dwc, dep);
                if (ret)
@@ -676,8 +658,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
                dev_err(dwc->dev, "invalid endpoint transfer type\n");
        }
 
-       dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
-
        spin_lock_irqsave(&dwc->lock, flags);
        ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
        spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1508,6 +1488,15 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        int                     irq;
        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);
+       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) {
@@ -1515,7 +1504,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
                                dwc->gadget.name,
                                dwc->gadget_driver->driver.name);
                ret = -EBUSY;
-               goto err0;
+               goto err1;
        }
 
        dwc->gadget_driver      = driver;
@@ -1536,10 +1525,25 @@ static int dwc3_gadget_start(struct usb_gadget *g,
         * STAR#9000525659: Clock Domain Crossing on DCTL in
         * USB 2.0 Mode
         */
-       if (dwc->revision < DWC3_REVISION_220A)
+       if (dwc->revision < DWC3_REVISION_220A) {
                reg |= DWC3_DCFG_SUPERSPEED;
-       else
-               reg |= dwc->maximum_speed;
+       } else {
+               switch (dwc->maximum_speed) {
+               case USB_SPEED_LOW:
+                       reg |= DWC3_DSTS_LOWSPEED;
+                       break;
+               case USB_SPEED_FULL:
+                       reg |= DWC3_DSTS_FULLSPEED1;
+                       break;
+               case USB_SPEED_HIGH:
+                       reg |= DWC3_DSTS_HIGHSPEED;
+                       break;
+               case USB_SPEED_SUPER:   /* FALLTHROUGH */
+               case USB_SPEED_UNKNOWN: /* FALTHROUGH */
+               default:
+                       reg |= DWC3_DSTS_SUPERSPEED;
+               }
+       }
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
        dwc->start_config_issued = false;
@@ -1551,42 +1555,38 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
-               goto err0;
+               goto err2;
        }
 
        dep = dwc->eps[1];
        ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
-               goto err1;
+               goto err3;
        }
 
        /* begin to receive SETUP packets */
        dwc->ep0state = EP0_SETUP_PHASE;
        dwc3_ep0_out_start(dwc);
 
-       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-       ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
-                       IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
-       if (ret) {
-               dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
-                               irq, ret);
-               goto err1;
-       }
-
        dwc3_gadget_enable_irq(dwc);
 
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
 
-err1:
+err3:
        __dwc3_gadget_ep_disable(dwc->eps[0]);
 
-err0:
+err2:
        dwc->gadget_driver = NULL;
+
+err1:
        spin_unlock_irqrestore(&dwc->lock, flags);
 
+       free_irq(irq, dwc);
+
+err0:
        return ret;
 }
 
@@ -1600,9 +1600,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
        spin_lock_irqsave(&dwc->lock, flags);
 
        dwc3_gadget_disable_irq(dwc);
-       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-       free_irq(irq, dwc);
-
        __dwc3_gadget_ep_disable(dwc->eps[0]);
        __dwc3_gadget_ep_disable(dwc->eps[1]);
 
@@ -1610,6 +1607,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
 
        spin_unlock_irqrestore(&dwc->lock, flags);
 
+       irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+       free_irq(irq, dwc);
+
        return 0;
 }
 
@@ -1642,13 +1642,15 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
 
                dep->dwc = dwc;
                dep->number = epnum;
+               dep->direction = !!direction;
                dwc->eps[epnum] = dep;
 
                snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
                                (epnum & 1) ? "in" : "out");
 
                dep->endpoint.name = dep->name;
-               dep->direction = (epnum & 1);
+
+               dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
 
                if (epnum == 0 || epnum == 1) {
                        dep->endpoint.maxpacket = 512;
@@ -2105,34 +2107,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        dwc->setup_packet_pending = false;
 }
 
-static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend)
-{
-       u32                     reg;
-
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
-
-       if (suspend)
-               reg |= DWC3_GUSB3PIPECTL_SUSPHY;
-       else
-               reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
-
-       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
-}
-
-static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend)
-{
-       u32                     reg;
-
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
-
-       if (suspend)
-               reg |= DWC3_GUSB2PHYCFG_SUSPHY;
-       else
-               reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
-
-       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
-}
-
 static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 {
        u32                     reg;
@@ -2173,13 +2147,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
        /* after reset -> Default State */
        usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
 
-       /* Recent versions support automatic phy suspend and don't need this */
-       if (dwc->revision < DWC3_REVISION_194A) {
-               /* Resume PHYs */
-               dwc3_gadget_usb2_phy_suspend(dwc, false);
-               dwc3_gadget_usb3_phy_suspend(dwc, false);
-       }
-
        if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
                dwc3_disconnect_gadget(dwc);
 
@@ -2223,20 +2190,6 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
        dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 }
 
-static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed)
-{
-       switch (speed) {
-       case USB_SPEED_SUPER:
-               dwc3_gadget_usb2_phy_suspend(dwc, true);
-               break;
-       case USB_SPEED_HIGH:
-       case USB_SPEED_FULL:
-       case USB_SPEED_LOW:
-               dwc3_gadget_usb3_phy_suspend(dwc, true);
-               break;
-       }
-}
-
 static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 {
        struct dwc3_ep          *dep;
@@ -2312,12 +2265,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                dwc3_writel(dwc->regs, DWC3_DCTL, reg);
        }
 
-       /* Recent versions support automatic phy suspend and don't need this */
-       if (dwc->revision < DWC3_REVISION_194A) {
-               /* Suspend unneeded PHY */
-               dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed);
-       }
-
        dep = dwc->eps[0];
        ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
        if (ret) {
@@ -2495,61 +2442,75 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
        }
 }
 
-static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
 {
-       struct dwc3 *dwc = _dwc;
-       unsigned long flags;
+       struct dwc3_event_buffer *evt;
        irqreturn_t ret = IRQ_NONE;
-       int i;
+       int left;
+       u32 reg;
 
-       spin_lock_irqsave(&dwc->lock, flags);
+       evt = dwc->ev_buffs[buf];
+       left = evt->count;
 
-       for (i = 0; i < dwc->num_event_buffers; i++) {
-               struct dwc3_event_buffer *evt;
-               int                     left;
+       if (!(evt->flags & DWC3_EVENT_PENDING))
+               return IRQ_NONE;
 
-               evt = dwc->ev_buffs[i];
-               left = evt->count;
+       while (left > 0) {
+               union dwc3_event event;
 
-               if (!(evt->flags & DWC3_EVENT_PENDING))
-                       continue;
+               event.raw = *(u32 *) (evt->buf + evt->lpos);
 
-               while (left > 0) {
-                       union dwc3_event event;
+               dwc3_process_event_entry(dwc, &event);
 
-                       event.raw = *(u32 *) (evt->buf + evt->lpos);
+               /*
+                * FIXME we wrap around correctly to the next entry as
+                * almost all entries are 4 bytes in size. There is one
+                * entry which has 12 bytes which is a regular entry
+                * followed by 8 bytes data. ATM I don't know how
+                * things are organized if we get next to the a
+                * boundary so I worry about that once we try to handle
+                * that.
+                */
+               evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+               left -= 4;
 
-                       dwc3_process_event_entry(dwc, &event);
+               dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+       }
 
-                       /*
-                        * FIXME we wrap around correctly to the next entry as
-                        * almost all entries are 4 bytes in size. There is one
-                        * entry which has 12 bytes which is a regular entry
-                        * followed by 8 bytes data. ATM I don't know how
-                        * things are organized if we get next to the a
-                        * boundary so I worry about that once we try to handle
-                        * that.
-                        */
-                       evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
-                       left -= 4;
+       evt->count = 0;
+       evt->flags &= ~DWC3_EVENT_PENDING;
+       ret = IRQ_HANDLED;
 
-                       dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
-               }
+       /* Unmask interrupt */
+       reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+       reg &= ~DWC3_GEVNTSIZ_INTMASK;
+       dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
 
-               evt->count = 0;
-               evt->flags &= ~DWC3_EVENT_PENDING;
-               ret = IRQ_HANDLED;
-       }
+       return ret;
+}
+
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+{
+       struct dwc3 *dwc = _dwc;
+       unsigned long flags;
+       irqreturn_t ret = IRQ_NONE;
+       int i;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+
+       for (i = 0; i < dwc->num_event_buffers; i++)
+               ret |= dwc3_process_event_buf(dwc, i);
 
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return ret;
 }
 
-static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
 {
        struct dwc3_event_buffer *evt;
        u32 count;
+       u32 reg;
 
        evt = dwc->ev_buffs[buf];
 
@@ -2561,6 +2522,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
        evt->count = count;
        evt->flags |= DWC3_EVENT_PENDING;
 
+       /* Mask interrupt */
+       reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+       reg |= DWC3_GEVNTSIZ_INTMASK;
+       dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+
        return IRQ_WAKE_THREAD;
 }
 
@@ -2575,7 +2541,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
        for (i = 0; i < dwc->num_event_buffers; i++) {
                irqreturn_t status;
 
-               status = dwc3_process_event_buf(dwc, i);
+               status = dwc3_check_event_buf(dwc, i);
                if (status == IRQ_WAKE_THREAD)
                        ret = status;
        }
@@ -2593,7 +2559,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
  */
 int dwc3_gadget_init(struct dwc3 *dwc)
 {
-       u32                                     reg;
        int                                     ret;
 
        dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
@@ -2643,16 +2608,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        if (ret)
                goto err4;
 
-       reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-       reg |= DWC3_DCFG_LPM_CAP;
-       dwc3_writel(dwc->regs, DWC3_DCFG, reg);
-
-       /* Enable USB2 LPM and automatic phy suspend only on recent versions */
-       if (dwc->revision >= DWC3_REVISION_194A) {
-               dwc3_gadget_usb2_phy_suspend(dwc, false);
-               dwc3_gadget_usb3_phy_suspend(dwc, false);
-       }
-
        ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
        if (ret) {
                dev_err(dwc->dev, "failed to register udc\n");