diff options
author | Felipe Balbi <balbi@ti.com> | 2012-04-24 09:19:49 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-05-02 02:43:08 -0400 |
commit | 865e09e71622f92a46b47019500632bf5bc010a8 (patch) | |
tree | 8f1074c7ae71c32c309bd014c9540e142908b58c /drivers/usb/dwc3/ep0.c | |
parent | b09bb64239c83113b8b35fa6a1ecae43d8297eaa (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.c | 83 |
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 | ||
493 | static 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 | |||
537 | static 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 | |||
493 | static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) | 572 | static 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); |