/** * lh7a40x_in_epn - handle IN interrupt */ static void lh7a40x_in_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) { u32 csr; struct lh7a40x_ep *ep = &dev->ep[ep_idx]; struct lh7a40x_request *req; usb_set_index(ep_idx); csr = usb_read(ep->csr1); DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); if (csr & USB_IN_CSR1_SENT_STALL) { DEBUG("USB_IN_CSR1_SENT_STALL\n"); usb_set(USB_IN_CSR1_SENT_STALL /*|USB_IN_CSR1_SEND_STALL */ , ep->csr1); return; } if (!ep->desc) { DEBUG("%s: NO EP DESC\n", __FUNCTION__); return; } if (list_empty(&ep->queue)) req = 0; else req = list_entry(ep->queue.next, struct lh7a40x_request, queue); DEBUG("req: %p\n", req); if (!req) return; write_fifo(ep, req); }
/* * done - retire a request; caller blocked irqs * INDEX register is preserved to keep same */ static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, int status) { unsigned int stopped = ep->stopped; u32 index; DEBUG("%s, %p\n", __FUNCTION__, ep); list_del_init(&req->queue); if (likely(req->req.status == -EINPROGRESS)) req->req.status = status; else status = req->req.status; if (status && status != -ESHUTDOWN) DEBUG("complete %s req %p stat %d len %u/%u\n", ep->ep.name, &req->req, status, req->req.actual, req->req.length); /* don't modify queue heads during completion callback */ ep->stopped = 1; /* Read current index (completion may modify it) */ index = usb_read(USB_INDEX); spin_unlock(&ep->dev->lock); req->req.complete(&ep->ep, &req->req); spin_lock(&ep->dev->lock); /* Restore index */ usb_set_index(index); ep->stopped = stopped; }
static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) { struct lh7a40x_ep *ep = &dev->ep[ep_idx]; struct lh7a40x_request *req; DEBUG("%s: %d\n", __func__, ep_idx); usb_set_index(ep_idx); if (ep->desc) { u32 csr; csr = usb_read(ep->csr1); while ((csr = usb_read(ep-> csr1)) & (USB_OUT_CSR1_OUT_PKT_RDY | USB_OUT_CSR1_SENT_STALL)) { DEBUG("%s: %x\n", __func__, csr); if (csr & USB_OUT_CSR1_SENT_STALL) { DEBUG("%s: stall sent, flush fifo\n", __func__); /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ flush(ep); } else if (csr & USB_OUT_CSR1_OUT_PKT_RDY) { if (list_empty(&ep->queue)) req = 0; else req = list_entry(ep->queue.next, struct lh7a40x_request, queue); if (!req) { printk(KERN_WARNING "%s: NULL REQ %d\n", __func__, ep_idx); flush(ep); break; } else { read_fifo(ep, req); } } } } else {
/* until it's enabled, this UDC should be completely invisible * to any USB host. */ static void udc_enable(struct lh7a40x_udc *dev) { int ep; DEBUG("%s, %p\n", __FUNCTION__, dev); dev->gadget.speed = USB_SPEED_UNKNOWN; #ifdef CONFIG_ARCH_LH7A404 /* Set Port C bit 1 & 2 as output */ set_portc_ddr(1, 1); set_portc_ddr(2, 1); /* Enable USB power */ set_portc_dr(1, 0); #endif /* * C.f Chapter 18.1.3.1 Initializing the USB */ /* Disable the USB */ usb_clear(PM_USB_ENABLE, USB_PM); /* Reset APB & I/O sides of the USB */ usb_set(USB_RESET_APB | USB_RESET_IO, USB_RESET); mdelay(5); usb_clear(USB_RESET_APB | USB_RESET_IO, USB_RESET); /* Set MAXP values for each */ for (ep = 0; ep < UDC_MAX_ENDPOINTS; ep++) { struct lh7a40x_ep *ep_reg = &dev->ep[ep]; u32 csr; usb_set_index(ep); switch (ep_reg->ep_type) { case ep_bulk_in: case ep_interrupt: usb_clear(USB_IN_CSR2_USB_DMA_EN | USB_IN_CSR2_AUTO_SET, ep_reg->csr2); /* Fall through */ case ep_control: usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), USB_IN_MAXP); break; case ep_bulk_out: usb_clear(USB_OUT_CSR2_USB_DMA_EN | USB_OUT_CSR2_AUTO_CLR, ep_reg->csr2); usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), USB_OUT_MAXP); break; } /* Read & Write CSR1, just in case */ csr = usb_read(ep_reg->csr1); usb_write(csr, ep_reg->csr1); flush(ep_reg); } /* Disable interrupts */ usb_write(0, USB_IN_INT_EN); usb_write(0, USB_OUT_INT_EN); usb_write(0, USB_INT_EN); /* Enable interrupts */ usb_set(USB_IN_INT_EP0, USB_IN_INT_EN); usb_set(USB_INT_RESET_INT | USB_INT_RESUME_INT, USB_INT_EN); /* Dont enable rest of the interrupts */ /* usb_set(USB_IN_INT_EP3 | USB_IN_INT_EP1 | USB_IN_INT_EP0, USB_IN_INT_EN); usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); */ /* Enable SUSPEND */ usb_set(PM_ENABLE_SUSPEND, USB_PM); /* Enable the USB */ usb_set(PM_USB_ENABLE, USB_PM); #ifdef CONFIG_ARCH_LH7A404 /* NOTE: DOES NOT WORK! */ /* Let host detect UDC: * Software must write a 0 to the PMR:DCP_CTRL bit to turn this * transistor on and pull the USBDP pin HIGH. */ /* usb_clear(PM_USB_DCP, USB_PM); usb_set(PM_USB_DCP, USB_PM); */ #endif }