aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/ep0.c
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2012-04-24 09:19:49 -0400
committerFelipe Balbi <balbi@ti.com>2012-05-02 02:43:08 -0400
commit865e09e71622f92a46b47019500632bf5bc010a8 (patch)
tree8f1074c7ae71c32c309bd014c9540e142908b58c /drivers/usb/dwc3/ep0.c
parentb09bb64239c83113b8b35fa6a1ecae43d8297eaa (diff)
usb: dwc3: ep0: implement Set SEL support
This patch implements Set SEL Standard Request support for dwc3 driver. It needs to issue a command to the controller passing the timing we received on the data phase of the Set SEL request. Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/dwc3/ep0.c')
-rw-r--r--drivers/usb/dwc3/ep0.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 18494b0d7d6e..9683d98bbb5d 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -490,6 +490,85 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
490 return ret; 490 return ret;
491} 491}
492 492
493static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
494{
495 struct dwc3_ep *dep = to_dwc3_ep(ep);
496 struct dwc3 *dwc = dep->dwc;
497
498 u32 param = 0;
499 u32 reg;
500
501 struct timing {
502 u8 u1sel;
503 u8 u1pel;
504 u16 u2sel;
505 u16 u2pel;
506 } __packed timing;
507
508 int ret;
509
510 memcpy(&timing, req->buf, sizeof(timing));
511
512 dwc->u1sel = timing.u1sel;
513 dwc->u1pel = timing.u1pel;
514 dwc->u2sel = timing.u2sel;
515 dwc->u2pel = timing.u2pel;
516
517 reg = dwc3_readl(dwc->regs, DWC3_DCTL);
518 if (reg & DWC3_DCTL_INITU2ENA)
519 param = dwc->u2pel;
520 if (reg & DWC3_DCTL_INITU1ENA)
521 param = dwc->u1pel;
522
523 /*
524 * According to Synopsys Databook, if parameter is
525 * greater than 125, a value of zero should be
526 * programmed in the register.
527 */
528 if (param > 125)
529 param = 0;
530
531 /* now that we have the time, issue DGCMD Set Sel */
532 ret = dwc3_send_gadget_generic_command(dwc,
533 DWC3_DGCMD_SET_PERIODIC_PAR, param);
534 WARN_ON(ret < 0);
535}
536
537static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
538{
539 struct dwc3_ep *dep;
540 u16 wLength;
541 u16 wValue;
542
543 if (dwc->dev_state == DWC3_DEFAULT_STATE)
544 return -EINVAL;
545
546 wValue = le16_to_cpu(ctrl->wValue);
547 wLength = le16_to_cpu(ctrl->wLength);
548
549 if (wLength != 6) {
550 dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n",
551 wLength);
552 return -EINVAL;
553 }
554
555 /*
556 * To handle Set SEL we need to receive 6 bytes from Host. So let's
557 * queue a usb_request for 6 bytes.
558 *
559 * Remember, though, this controller can't handle non-wMaxPacketSize
560 * aligned transfers on the OUT direction, so we queue a request for
561 * wMaxPacketSize instead.
562 */
563 dep = dwc->eps[0];
564 dwc->ep0_usb_req.dep = dep;
565 dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket;
566 dwc->ep0_usb_req.request.buf = dwc->setup_buf;
567 dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl;
568
569 return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
570}
571
493static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) 572static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
494{ 573{
495 int ret; 574 int ret;
@@ -515,6 +594,10 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
515 dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n"); 594 dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
516 ret = dwc3_ep0_set_config(dwc, ctrl); 595 ret = dwc3_ep0_set_config(dwc, ctrl);
517 break; 596 break;
597 case USB_REQ_SET_SEL:
598 dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n");
599 ret = dwc3_ep0_set_sel(dwc, ctrl);
600 break;
518 default: 601 default:
519 dev_vdbg(dwc->dev, "Forwarding to gadget driver\n"); 602 dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
520 ret = dwc3_ep0_delegate_req(dwc, ctrl); 603 ret = dwc3_ep0_delegate_req(dwc, ctrl);