summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/controller/dwc_otg.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2012-09-09 17:23:57 +0000
committerhselasky <hselasky@FreeBSD.org>2012-09-09 17:23:57 +0000
commit7ea73aa912244bc9fcb5d57cf684c60efcde6401 (patch)
treeb04ccb6193f49a70b7375f8a5aa76985d94751b3 /sys/dev/usb/controller/dwc_otg.c
parent51aace4b7f74e9a5c255aaef825bc9834f83ce3b (diff)
downloadFreeBSD-src-7ea73aa912244bc9fcb5d57cf684c60efcde6401.zip
FreeBSD-src-7ea73aa912244bc9fcb5d57cf684c60efcde6401.tar.gz
Implement missing USB suspend and resume support for DWC OTG driver.
Diffstat (limited to 'sys/dev/usb/controller/dwc_otg.c')
-rw-r--r--sys/dev/usb/controller/dwc_otg.c66
1 files changed, 60 insertions, 6 deletions
diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c
index 7cc509e..ce784c1 100644
--- a/sys/dev/usb/controller/dwc_otg.c
+++ b/sys/dev/usb/controller/dwc_otg.c
@@ -557,7 +557,6 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td)
temp = sc->sc_hcchar[td->channel];
temp &= ~HCCHAR_EPDIR_IN;
- temp |= HCCHAR_CHENA;
/* must enable channel before writing data to FIFO */
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), temp);
@@ -878,7 +877,7 @@ not_complete:
sc->sc_haint_mask |= (1 << td->channel);
DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK, sc->sc_haint_mask);
- temp |= HCCHAR_CHENA | HCCHAR_EPDIR_IN;
+ temp |= HCCHAR_EPDIR_IN;
/* must enable channel before data can be received */
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), temp);
@@ -1114,8 +1113,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td)
/* TODO: HCTSIZ_DOPNG */
temp = sc->sc_hcchar[td->channel];
- temp &= ~(HCCHAR_EPDIR_IN);
- temp |= HCCHAR_CHENA;
+ temp &= ~HCCHAR_EPDIR_IN;
/* must enable before writing data to FIFO */
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), temp);
@@ -2066,7 +2064,8 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer)
(xfer->address << HCCHAR_DEVADDR_SHIFT) |
(xfer_type << HCCHAR_EPTYPE_SHIFT) |
((xfer->endpointno & UE_ADDR) << HCCHAR_EPNUM_SHIFT) |
- (xfer->max_packet_size << HCCHAR_MPS_SHIFT);
+ (xfer->max_packet_size << HCCHAR_MPS_SHIFT) |
+ HCCHAR_CHENA;
if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_LOW)
td->hcchar |= HCCHAR_LSPDDEV;
@@ -2281,7 +2280,6 @@ dwc_otg_device_done(struct usb_xfer *xfer, usb_error_t error)
sc->sc_haint_mask &= ~(1 << td->channel);
DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK, sc->sc_haint_mask);
- DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(td->channel), 0);
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel),
HCCHAR_CHENA | HCCHAR_CHDIS);
@@ -3565,13 +3563,69 @@ dwc_otg_get_dma_delay(struct usb_device *udev, uint32_t *pus)
static void
dwc_otg_device_resume(struct usb_device *udev)
{
+ struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(udev->bus);
+ struct usb_xfer *xfer;
+ struct dwc_otg_td *td;
+
DPRINTF("\n");
+
+ /* Disable relevant Host channels before going to suspend */
+
+ USB_BUS_LOCK(udev->bus);
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ if (xfer->xroot->udev == udev) {
+
+ td = xfer->td_transfer_cache;
+ if (td != NULL &&
+ td->channel < DWC_OTG_MAX_CHANNELS) {
+
+ sc->sc_hcchar[td->channel] =
+ (sc->sc_hcchar[td->channel] & ~HCCHAR_CHDIS) |
+ HCCHAR_CHENA;
+
+ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel),
+ sc->sc_hcchar[td->channel]);
+ }
+ }
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
}
static void
dwc_otg_device_suspend(struct usb_device *udev)
{
+ struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(udev->bus);
+ struct usb_xfer *xfer;
+ struct dwc_otg_td *td;
+
DPRINTF("\n");
+
+ /* Disable relevant Host channels before going to suspend */
+
+ USB_BUS_LOCK(udev->bus);
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ if (xfer->xroot->udev == udev) {
+
+ td = xfer->td_transfer_cache;
+ if (td != NULL &&
+ td->channel < DWC_OTG_MAX_CHANNELS) {
+
+ sc->sc_hcchar[td->channel] =
+ (DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)) |
+ HCCHAR_CHDIS) & ~HCCHAR_CHENA;
+
+ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel),
+ sc->sc_hcchar[td->channel]);
+ }
+ }
+ }
+
+ USB_BUS_UNLOCK(udev->bus);
}
struct usb_bus_methods dwc_otg_bus_methods =
OpenPOWER on IntegriCloud