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 | |
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>
-rw-r--r-- | drivers/usb/dwc3/core.h | 10 | ||||
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 83 |
2 files changed, 93 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 42641ada9e2d..39fbd154dc11 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h | |||
@@ -575,6 +575,10 @@ struct dwc3_request { | |||
575 | * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround | 575 | * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround |
576 | * @needs_fifo_resize: not all users might want fifo resizing, flag it | 576 | * @needs_fifo_resize: not all users might want fifo resizing, flag it |
577 | * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. | 577 | * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. |
578 | * @u2sel: parameter from Set SEL request. | ||
579 | * @u2pel: parameter from Set SEL request. | ||
580 | * @u1sel: parameter from Set SEL request. | ||
581 | * @u1pel: parameter from Set SEL request. | ||
578 | * @ep0_next_event: hold the next expected event | 582 | * @ep0_next_event: hold the next expected event |
579 | * @ep0state: state of endpoint zero | 583 | * @ep0state: state of endpoint zero |
580 | * @link_state: link state | 584 | * @link_state: link state |
@@ -641,7 +645,13 @@ struct dwc3 { | |||
641 | enum dwc3_link_state link_state; | 645 | enum dwc3_link_state link_state; |
642 | enum dwc3_device_state dev_state; | 646 | enum dwc3_device_state dev_state; |
643 | 647 | ||
648 | u16 u2sel; | ||
649 | u16 u2pel; | ||
650 | u8 u1sel; | ||
651 | u8 u1pel; | ||
652 | |||
644 | u8 speed; | 653 | u8 speed; |
654 | |||
645 | void *mem; | 655 | void *mem; |
646 | 656 | ||
647 | struct dwc3_hwparams hwparams; | 657 | struct dwc3_hwparams hwparams; |
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); |