Merge tag 'dwc3-for-v3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
[pandora-kernel.git] / drivers / usb / dwc3 / ep0.c
index 3453ca1..9e8a3dc 100644 (file)
@@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
 {
        struct dwc3_ep          *dep;
        u32                     recip;
+       u32                     reg;
        u16                     usb_status = 0;
        __le16                  *response_pkt;
 
@@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
        switch (recip) {
        case USB_RECIP_DEVICE:
                /*
-                * We are self-powered. U1/U2/LTM will be set later
-                * once we handle this states. RemoteWakeup is 0 on SS
+                * LTM will be set once we know how to set this in HW.
                 */
                usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+
+               if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
+                       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+                       if (reg & DWC3_DCTL_INITU1ENA)
+                               usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
+                       if (reg & DWC3_DCTL_INITU2ENA)
+                               usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
+               }
+
                break;
 
        case USB_RECIP_INTERFACE:
@@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        u32                     recip;
        u32                     wValue;
        u32                     wIndex;
+       u32                     reg;
        int                     ret;
 
        wValue = le16_to_cpu(ctrl->wValue);
@@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        switch (recip) {
        case USB_RECIP_DEVICE:
 
+               switch (wValue) {
+               case USB_DEVICE_REMOTE_WAKEUP:
+                       break;
                /*
                 * 9.4.1 says only only for SS, in AddressState only for
                 * default control pipe
                 */
-               switch (wValue) {
                case USB_DEVICE_U1_ENABLE:
-               case USB_DEVICE_U2_ENABLE:
-               case USB_DEVICE_LTM_ENABLE:
                        if (dwc->dev_state != DWC3_CONFIGURED_STATE)
                                return -EINVAL;
                        if (dwc->speed != DWC3_DSTS_SUPERSPEED)
                                return -EINVAL;
-               }
 
-               /* XXX add U[12] & LTM */
-               switch (wValue) {
-               case USB_DEVICE_REMOTE_WAKEUP:
-                       break;
-               case USB_DEVICE_U1_ENABLE:
+                       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+                       if (set)
+                               reg |= DWC3_DCTL_INITU1ENA;
+                       else
+                               reg &= ~DWC3_DCTL_INITU1ENA;
+                       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
                        break;
+
                case USB_DEVICE_U2_ENABLE:
+                       if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+                               return -EINVAL;
+                       if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+                               return -EINVAL;
+
+                       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+                       if (set)
+                               reg |= DWC3_DCTL_INITU2ENA;
+                       else
+                               reg &= ~DWC3_DCTL_INITU2ENA;
+                       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
                        break;
+
                case USB_DEVICE_LTM_ENABLE:
+                       return -EINVAL;
                        break;
 
                case USB_DEVICE_TEST_MODE:
@@ -469,6 +493,107 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
        return ret;
 }
 
+static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+       struct dwc3_ep  *dep = to_dwc3_ep(ep);
+       struct dwc3     *dwc = dep->dwc;
+
+       u32             param = 0;
+       u32             reg;
+
+       struct timing {
+               u8      u1sel;
+               u8      u1pel;
+               u16     u2sel;
+               u16     u2pel;
+       } __packed timing;
+
+       int             ret;
+
+       memcpy(&timing, req->buf, sizeof(timing));
+
+       dwc->u1sel = timing.u1sel;
+       dwc->u1pel = timing.u1pel;
+       dwc->u2sel = timing.u2sel;
+       dwc->u2pel = timing.u2pel;
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       if (reg & DWC3_DCTL_INITU2ENA)
+               param = dwc->u2pel;
+       if (reg & DWC3_DCTL_INITU1ENA)
+               param = dwc->u1pel;
+
+       /*
+        * According to Synopsys Databook, if parameter is
+        * greater than 125, a value of zero should be
+        * programmed in the register.
+        */
+       if (param > 125)
+               param = 0;
+
+       /* now that we have the time, issue DGCMD Set Sel */
+       ret = dwc3_send_gadget_generic_command(dwc,
+                       DWC3_DGCMD_SET_PERIODIC_PAR, param);
+       WARN_ON(ret < 0);
+}
+
+static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+       struct dwc3_ep  *dep;
+       u16             wLength;
+       u16             wValue;
+
+       if (dwc->dev_state == DWC3_DEFAULT_STATE)
+               return -EINVAL;
+
+       wValue = le16_to_cpu(ctrl->wValue);
+       wLength = le16_to_cpu(ctrl->wLength);
+
+       if (wLength != 6) {
+               dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n",
+                               wLength);
+               return -EINVAL;
+       }
+
+       /*
+        * To handle Set SEL we need to receive 6 bytes from Host. So let's
+        * queue a usb_request for 6 bytes.
+        *
+        * Remember, though, this controller can't handle non-wMaxPacketSize
+        * aligned transfers on the OUT direction, so we queue a request for
+        * wMaxPacketSize instead.
+        */
+       dep = dwc->eps[0];
+       dwc->ep0_usb_req.dep = dep;
+       dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket;
+       dwc->ep0_usb_req.request.buf = dwc->setup_buf;
+       dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl;
+
+       return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
+}
+
+static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+       u16             wLength;
+       u16             wValue;
+       u16             wIndex;
+
+       wValue = le16_to_cpu(ctrl->wValue);
+       wLength = le16_to_cpu(ctrl->wLength);
+       wIndex = le16_to_cpu(ctrl->wIndex);
+
+       if (wIndex || wLength)
+               return -EINVAL;
+
+       /*
+        * REVISIT It's unclear from Databook what to do with this
+        * value. For now, just cache it.
+        */
+       dwc->isoch_delay = wValue;
+
+       return 0;
+}
+
 static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
        int ret;
@@ -494,6 +619,14 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
                ret = dwc3_ep0_set_config(dwc, ctrl);
                break;
+       case USB_REQ_SET_SEL:
+               dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n");
+               ret = dwc3_ep0_set_sel(dwc, ctrl);
+               break;
+       case USB_REQ_SET_ISOCH_DELAY:
+               dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n");
+               ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
+               break;
        default:
                dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
                ret = dwc3_ep0_delegate_req(dwc, ctrl);