diff options
Diffstat (limited to 'drivers/usb/chipidea/udc.c')
-rw-r--r-- | drivers/usb/chipidea/udc.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 6e53c24fa..391a1225b 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -445,7 +445,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) rest -= count; } - if (hwreq->req.zero && hwreq->req.length + if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX && (hwreq->req.length % hwep->ep.maxpacket == 0)) add_td_to_list(hwep, hwreq, 0); @@ -1128,6 +1128,13 @@ __acquires(ci->lock) if (ci_otg_is_fsm_mode(ci)) err = otg_a_alt_hnp_support(ci); break; + case USB_DEVICE_A_HNP_SUPPORT: + if (ci_otg_is_fsm_mode(ci)) { + ci->gadget.a_hnp_support = 1; + err = isr_setup_status_phase( + ci); + } + break; default: goto delegate; } @@ -1628,6 +1635,20 @@ static int init_eps(struct ci_hdrc *ci) hwep->ep.name = hwep->name; hwep->ep.ops = &usb_ep_ops; + + if (i == 0) { + hwep->ep.caps.type_control = true; + } else { + hwep->ep.caps.type_iso = true; + hwep->ep.caps.type_bulk = true; + hwep->ep.caps.type_int = true; + } + + if (j == TX) + hwep->ep.caps.dir_in = true; + else + hwep->ep.caps.dir_out = true; + /* * for ep0: maxP defined in desc, for other * eps, maxP is set by epautoconfig() called @@ -1730,6 +1751,22 @@ static int ci_udc_start(struct usb_gadget *gadget, return retval; } +static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci) +{ + if (!ci_otg_is_fsm_mode(ci)) + return; + + mutex_lock(&ci->fsm.lock); + if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) { + ci->fsm.a_bidl_adis_tmout = 1; + ci_hdrc_otg_fsm_start(ci); + } else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) { + ci->fsm.protocol = PROTO_UNDEF; + ci->fsm.otg->state = OTG_STATE_UNDEFINED; + } + mutex_unlock(&ci->fsm.lock); +} + /** * ci_udc_stop: unregister a gadget driver */ @@ -1754,6 +1791,7 @@ static int ci_udc_stop(struct usb_gadget *gadget) ci->driver = NULL; spin_unlock_irqrestore(&ci->lock, flags); + ci_udc_stop_for_otg_fsm(ci); return 0; } @@ -1831,6 +1869,7 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci) static int udc_start(struct ci_hdrc *ci) { struct device *dev = ci->dev; + struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps; int retval = 0; spin_lock_init(&ci->lock); @@ -1838,8 +1877,12 @@ static int udc_start(struct ci_hdrc *ci) ci->gadget.ops = &usb_gadget_ops; ci->gadget.speed = USB_SPEED_UNKNOWN; ci->gadget.max_speed = USB_SPEED_HIGH; - ci->gadget.is_otg = ci->is_otg ? 1 : 0; ci->gadget.name = ci->platdata->name; + ci->gadget.otg_caps = otg_caps; + + if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support || + otg_caps->adp_support)) + ci->gadget.is_otg = 1; INIT_LIST_HEAD(&ci->gadget.ep_list); |