/* interrupt, error, port change, reset, sleep/suspend */
hw_write(ci, OP_USBINTR, ~0,
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
- hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
} else {
hw_write(ci, OP_USBINTR, ~0, 0);
- hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
}
return 0;
}
kfree(pending);
}
+static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep,
+ struct td_node *node)
+{
+ hwep->qh.ptr->td.next = node->dma;
+ hwep->qh.ptr->td.token &=
+ cpu_to_le32(~(TD_STATUS_HALTED | TD_STATUS_ACTIVE));
+
+ /* Synchronize before ep prime */
+ wmb();
+
+ return hw_ep_prime(ci, hwep->num, hwep->dir,
+ hwep->type == USB_ENDPOINT_XFER_CONTROL);
+}
+
/**
* _hardware_dequeue: handles a request at hardware level
* @gadget: gadget
struct td_node *node, *tmpnode;
unsigned remaining_length;
unsigned actual = hwreq->req.length;
+ struct ci_hdrc *ci = hwep->ci;
if (hwreq->req.status != -EALREADY)
return -EINVAL;
list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
tmptoken = le32_to_cpu(node->ptr->token);
if ((TD_STATUS_ACTIVE & tmptoken) != 0) {
+ int n = hw_ep_bit(hwep->num, hwep->dir);
+
+ if (ci->rev == CI_REVISION_24)
+ if (!hw_read(ci, OP_ENDPTSTAT, BIT(n)))
+ reprime_dtd(ci, hwep, node);
hwreq->req.status = -EALREADY;
return -EBUSY;
}
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;
}
/* only internal SW should enable ctrl endpts */
- hwep->ep.desc = desc;
-
- if (!list_empty(&hwep->qh.queue))
+ if (!list_empty(&hwep->qh.queue)) {
dev_warn(hwep->ci->dev, "enabling a non-empty endpoint!\n");
+ spin_unlock_irqrestore(hwep->lock, flags);
+ return -EBUSY;
+ }
+
+ hwep->ep.desc = desc;
hwep->dir = usb_endpoint_dir_in(desc) ? TX : RX;
hwep->num = usb_endpoint_num(desc);
hw_device_reset(ci);
hw_device_state(ci, ci->ep0out->qh.dma);
usb_gadget_set_state(_gadget, USB_STATE_POWERED);
+ usb_udc_vbus_handler(_gadget, true);
} else {
+ usb_udc_vbus_handler(_gadget, false);
if (ci->driver)
ci->driver->disconnect(&ci->gadget);
hw_device_state(ci, 0);
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
- if (!ci->vbus_active)
- return -EOPNOTSUPP;
+ /* Data+ pullup controlled by OTG state machine in OTG fsm mode */
+ if (ci_otg_is_fsm_mode(ci))
+ return 0;
+ pm_runtime_get_sync(&ci->gadget.dev);
if (is_on)
hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
else
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+ pm_runtime_put_sync(&ci->gadget.dev);
return 0;
}
spin_lock_irqsave(&ci->lock, flags);
hw_device_reset(ci);
} else {
+ usb_udc_vbus_handler(&ci->gadget, false);
pm_runtime_put_sync(&ci->gadget.dev);
return retval;
}