|
@@ -490,6 +490,85 @@ 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_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|
|
{
|
|
|
int ret;
|
|
@@ -515,6 +594,10 @@ 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;
|
|
|
default:
|
|
|
dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
|
|
|
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|