diff options
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 14 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/at91_udc.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/ci13xxx_udc.c | 344 | ||||
-rw-r--r-- | drivers/usb/gadget/ci13xxx_udc.h | 9 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 14 | ||||
-rw-r--r-- | drivers/usb/gadget/dummy_hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/epautoconf.c | 7 | ||||
-rw-r--r-- | drivers/usb/gadget/f_fs.c | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_mxc_udc.c | 21 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_udc_core.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/fusb300_udc.c | 1744 | ||||
-rw-r--r-- | drivers/usb/gadget/fusb300_udc.h | 687 | ||||
-rw-r--r-- | drivers/usb/gadget/m66592-udc.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/pch_udc.c | 178 | ||||
-rw-r--r-- | drivers/usb/gadget/s3c2410_udc.c | 76 | ||||
-rw-r--r-- | drivers/usb/gadget/u_ether.c | 2 |
17 files changed, 2904 insertions, 213 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index d50099675f28..bfde50e20b30 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -176,6 +176,18 @@ config USB_FSL_USB2 default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_FUSB300 + boolean "Faraday FUSB300 USB Peripheral Controller" + select USB_GADGET_DUALSPEED + help + Faraday usb device controller FUSB300 driver + +config USB_FUSB300 + tristate + depends on USB_GADGET_FUSB300 + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_LH7A40X boolean "LH7A40X" depends on ARCH_LH7A40X @@ -540,7 +552,7 @@ config USB_GADGET_CI13XXX_MSM boolean "MIPS USB CI13xxx for MSM" depends on ARCH_MSM select USB_GADGET_DUALSPEED - select USB_MSM_OTG_72K + select USB_MSM_OTG help MSM SoC has chipidea USB controller. This driver uses ci13xxx_udc core. diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 55f5e8ae5924..305286e181d5 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o mv_udc-y := mv_udc_core.o mv_udc_phy.o obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o +obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o # # USB gadget drivers diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index bdec36acd0fa..bb8ddf0469f9 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1798,8 +1798,10 @@ static int __init at91udc_probe(struct platform_device *pdev) } retval = device_register(&udc->gadget.dev); - if (retval < 0) + if (retval < 0) { + put_device(&udc->gadget.dev); goto fail0b; + } /* don't do anything until we have both gadget driver and VBUS */ clk_enable(udc->iclk); diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index a1c67ae1572a..e09178bc1450 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -435,20 +435,6 @@ static int hw_ep_get_halt(int num, int dir) } /** - * hw_ep_is_primed: test if endpoint is primed (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns true if endpoint primed - */ -static int hw_ep_is_primed(int num, int dir) -{ - u32 reg = hw_cread(CAP_ENDPTPRIME, ~0) | hw_cread(CAP_ENDPTSTAT, ~0); - - return test_bit(hw_ep_bit(num, dir), (void *)®); -} - -/** * hw_test_and_clear_setup_status: test & clear setup status (execute without * interruption) * @n: bit number (endpoint) @@ -472,10 +458,6 @@ static int hw_ep_prime(int num, int dir, int is_ctrl) { int n = hw_ep_bit(num, dir); - /* the caller should flush first */ - if (hw_ep_is_primed(num, dir)) - return -EBUSY; - if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) return -EAGAIN; @@ -1434,6 +1416,8 @@ static inline u8 _usb_addr(struct ci13xxx_ep *ep) static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) { unsigned i; + int ret = 0; + unsigned length = mReq->req.length; trace("%p, %p", mEp, mReq); @@ -1441,53 +1425,91 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) if (mReq->req.status == -EALREADY) return -EALREADY; - if (hw_ep_is_primed(mEp->num, mEp->dir)) - return -EBUSY; - mReq->req.status = -EALREADY; - - if (mReq->req.length && !mReq->req.dma) { + if (length && !mReq->req.dma) { mReq->req.dma = \ dma_map_single(mEp->device, mReq->req.buf, - mReq->req.length, mEp->dir ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); + length, mEp->dir ? DMA_TO_DEVICE : + DMA_FROM_DEVICE); if (mReq->req.dma == 0) return -ENOMEM; mReq->map = 1; } + if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) { + mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC, + &mReq->zdma); + if (mReq->zptr == NULL) { + if (mReq->map) { + dma_unmap_single(mEp->device, mReq->req.dma, + length, mEp->dir ? DMA_TO_DEVICE : + DMA_FROM_DEVICE); + mReq->req.dma = 0; + mReq->map = 0; + } + return -ENOMEM; + } + memset(mReq->zptr, 0, sizeof(*mReq->zptr)); + mReq->zptr->next = TD_TERMINATE; + mReq->zptr->token = TD_STATUS_ACTIVE; + if (!mReq->req.no_interrupt) + mReq->zptr->token |= TD_IOC; + } /* * TD configuration * TODO - handle requests which spawns into several TDs */ memset(mReq->ptr, 0, sizeof(*mReq->ptr)); - mReq->ptr->next |= TD_TERMINATE; - mReq->ptr->token = mReq->req.length << ffs_nr(TD_TOTAL_BYTES); + mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES); mReq->ptr->token &= TD_TOTAL_BYTES; - mReq->ptr->token |= TD_IOC; mReq->ptr->token |= TD_STATUS_ACTIVE; + if (mReq->zptr) { + mReq->ptr->next = mReq->zdma; + } else { + mReq->ptr->next = TD_TERMINATE; + if (!mReq->req.no_interrupt) + mReq->ptr->token |= TD_IOC; + } mReq->ptr->page[0] = mReq->req.dma; for (i = 1; i < 5; i++) mReq->ptr->page[i] = (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; - /* - * QH configuration - * At this point it's guaranteed exclusive access to qhead - * (endpt is not primed) so it's no need to use tripwire - */ + if (!list_empty(&mEp->qh.queue)) { + struct ci13xxx_req *mReqPrev; + int n = hw_ep_bit(mEp->num, mEp->dir); + int tmp_stat; + + mReqPrev = list_entry(mEp->qh.queue.prev, + struct ci13xxx_req, queue); + if (mReqPrev->zptr) + mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; + else + mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; + wmb(); + if (hw_cread(CAP_ENDPTPRIME, BIT(n))) + goto done; + do { + hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW); + tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n)); + } while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW)); + hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0); + if (tmp_stat) + goto done; + } + + /* QH configuration */ mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ - if (mReq->req.zero == 0) - mEp->qh.ptr->cap |= QH_ZLT; - else - mEp->qh.ptr->cap &= ~QH_ZLT; + mEp->qh.ptr->cap |= QH_ZLT; wmb(); /* synchronize before ep prime */ - return hw_ep_prime(mEp->num, mEp->dir, + ret = hw_ep_prime(mEp->num, mEp->dir, mEp->type == USB_ENDPOINT_XFER_CONTROL); +done: + return ret; } /** @@ -1504,8 +1526,15 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) if (mReq->req.status != -EALREADY) return -EINVAL; - if (hw_ep_is_primed(mEp->num, mEp->dir)) - hw_ep_flush(mEp->num, mEp->dir); + if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) + return -EBUSY; + + if (mReq->zptr) { + if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) + return -EBUSY; + dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); + mReq->zptr = NULL; + } mReq->req.status = 0; @@ -1517,9 +1546,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) } mReq->req.status = mReq->ptr->token & TD_STATUS; - if ((TD_STATUS_ACTIVE & mReq->req.status) != 0) - mReq->req.status = -ECONNRESET; - else if ((TD_STATUS_HALTED & mReq->req.status) != 0) + if ((TD_STATUS_HALTED & mReq->req.status) != 0) mReq->req.status = -1; else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) mReq->req.status = -1; @@ -1581,12 +1608,19 @@ static int _gadget_stop_activity(struct usb_gadget *gadget) { struct usb_ep *ep; struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; trace("%p", gadget); if (gadget == NULL) return -EINVAL; + spin_lock_irqsave(udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->remote_wakeup = 0; + udc->suspended = 0; + spin_unlock_irqrestore(udc->lock, flags); + /* flush all endpoints */ gadget_for_each_ep(ep, gadget) { usb_ep_fifo_flush(ep); @@ -1720,7 +1754,8 @@ __acquires(mEp->lock) } if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* TODO: D1 - Remote Wakeup; D0 - Self Powered */ + /* Assume that device is bus powered for now. */ + *((u16 *)req->buf) = _udc->remote_wakeup << 1; retval = 0; } else if ((setup->bRequestType & USB_RECIP_MASK) \ == USB_RECIP_ENDPOINT) { @@ -1749,6 +1784,28 @@ __acquires(mEp->lock) } /** + * isr_setup_status_complete: setup_status request complete function + * @ep: endpoint + * @req: request handled + * + * Caller must release lock. Put the port in test mode if test mode + * feature is selected. + */ +static void +isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct ci13xxx *udc = req->context; + unsigned long flags; + + trace("%p, %p", ep, req); + + spin_lock_irqsave(udc->lock, flags); + if (udc->test_mode) + hw_port_test_set(udc->test_mode); + spin_unlock_irqrestore(udc->lock, flags); +} + +/** * isr_setup_status_phase: queues the status phase of a setup transation * @udc: udc struct * @@ -1764,6 +1821,8 @@ __acquires(mEp->lock) trace("%p", udc); mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in; + udc->status->context = udc; + udc->status->complete = isr_setup_status_complete; spin_unlock(mEp->lock); retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); @@ -1783,7 +1842,7 @@ static int isr_tr_complete_low(struct ci13xxx_ep *mEp) __releases(mEp->lock) __acquires(mEp->lock) { - struct ci13xxx_req *mReq; + struct ci13xxx_req *mReq, *mReqTemp; int retval; trace("%p", mEp); @@ -1791,34 +1850,25 @@ __acquires(mEp->lock) if (list_empty(&mEp->qh.queue)) return -EINVAL; - /* pop oldest request */ - mReq = list_entry(mEp->qh.queue.next, - struct ci13xxx_req, queue); - list_del_init(&mReq->queue); - - retval = _hardware_dequeue(mEp, mReq); - if (retval < 0) { - dbg_event(_usb_addr(mEp), "DONE", retval); - goto done; - } - - dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); - - if (!list_empty(&mEp->qh.queue)) { - struct ci13xxx_req* mReqEnq; - - mReqEnq = list_entry(mEp->qh.queue.next, - struct ci13xxx_req, queue); - _hardware_enqueue(mEp, mReqEnq); + list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, + queue) { + retval = _hardware_dequeue(mEp, mReq); + if (retval < 0) + break; + list_del_init(&mReq->queue); + dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); + if (mReq->req.complete != NULL) { + spin_unlock(mEp->lock); + mReq->req.complete(&mEp->ep, &mReq->req); + spin_lock(mEp->lock); + } } - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - mReq->req.complete(&mEp->ep, &mReq->req); - spin_lock(mEp->lock); - } + if (retval == EBUSY) + retval = 0; + if (retval < 0) + dbg_event(_usb_addr(mEp), "DONE", retval); - done: return retval; } @@ -1833,6 +1883,7 @@ __releases(udc->lock) __acquires(udc->lock) { unsigned i; + u8 tmode = 0; trace("%p", udc); @@ -1895,22 +1946,32 @@ __acquires(udc->lock) switch (req.bRequest) { case USB_REQ_CLEAR_FEATURE: - if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && - le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT) - goto delegate; - if (req.wLength != 0) - break; - num = le16_to_cpu(req.wIndex); - num &= USB_ENDPOINT_NUMBER_MASK; - if (!udc->ci13xxx_ep[num].wedge) { - spin_unlock(udc->lock); - err = usb_ep_clear_halt( - &udc->ci13xxx_ep[num].ep); - spin_lock(udc->lock); - if (err) + if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && + le16_to_cpu(req.wValue) == + USB_ENDPOINT_HALT) { + if (req.wLength != 0) break; + num = le16_to_cpu(req.wIndex); + num &= USB_ENDPOINT_NUMBER_MASK; + if (!udc->ci13xxx_ep[num].wedge) { + spin_unlock(udc->lock); + err = usb_ep_clear_halt( + &udc->ci13xxx_ep[num].ep); + spin_lock(udc->lock); + if (err) + break; + } + err = isr_setup_status_phase(udc); + } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && + le16_to_cpu(req.wValue) == + USB_DEVICE_REMOTE_WAKEUP) { + if (req.wLength != 0) + break; + udc->remote_wakeup = 0; + err = isr_setup_status_phase(udc); + } else { + goto delegate; } - err = isr_setup_status_phase(udc); break; case USB_REQ_GET_STATUS: if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && @@ -1934,20 +1995,48 @@ __acquires(udc->lock) err = isr_setup_status_phase(udc); break; case USB_REQ_SET_FEATURE: - if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && - le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT) - goto delegate; - if (req.wLength != 0) - break; - num = le16_to_cpu(req.wIndex); - num &= USB_ENDPOINT_NUMBER_MASK; + if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && + le16_to_cpu(req.wValue) == + USB_ENDPOINT_HALT) { + if (req.wLength != 0) + break; + num = le16_to_cpu(req.wIndex); + num &= USB_ENDPOINT_NUMBER_MASK; - spin_unlock(udc->lock); - err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); - spin_lock(udc->lock); - if (err) - break; - err = isr_setup_status_phase(udc); + spin_unlock(udc->lock); + err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); + spin_lock(udc->lock); + if (!err) + isr_setup_status_phase(udc); + } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { + if (req.wLength != 0) + break; + switch (le16_to_cpu(req.wValue)) { + case USB_DEVICE_REMOTE_WAKEUP: + udc->remote_wakeup = 1; + err = isr_setup_status_phase(udc); + break; + case USB_DEVICE_TEST_MODE: + tmode = le16_to_cpu(req.wIndex) >> 8; + switch (tmode) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + case TEST_FORCE_EN: + udc->test_mode = tmode; + err = isr_setup_status_phase( + udc); + break; + default: + break; + } + default: + goto delegate; + } + } else { + goto delegate; + } break; default: delegate: @@ -2178,15 +2267,15 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, /* push request */ mReq->req.status = -EINPROGRESS; mReq->req.actual = 0; - list_add_tail(&mReq->queue, &mEp->qh.queue); - if (list_is_singular(&mEp->qh.queue)) - retval = _hardware_enqueue(mEp, mReq); + retval = _hardware_enqueue(mEp, mReq); if (retval == -EALREADY) { dbg_event(_usb_addr(mEp), "QUEUE", retval); retval = 0; } + if (!retval) + list_add_tail(&mReq->queue, &mEp->qh.queue); done: spin_unlock_irqrestore(mEp->lock, flags); @@ -2206,19 +2295,25 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) trace("%p, %p", ep, req); - if (ep == NULL || req == NULL || mEp->desc == NULL || - list_empty(&mReq->queue) || list_empty(&mEp->qh.queue)) + if (ep == NULL || req == NULL || mReq->req.status != -EALREADY || + mEp->desc == NULL || list_empty(&mReq->queue) || + list_empty(&mEp->qh.queue)) return -EINVAL; spin_lock_irqsave(mEp->lock, flags); dbg_event(_usb_addr(mEp), "DEQUEUE", 0); - if (mReq->req.status == -EALREADY) - _hardware_dequeue(mEp, mReq); + hw_ep_flush(mEp->num, mEp->dir); /* pop request */ list_del_init(&mReq->queue); + if (mReq->map) { + dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, + mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + mReq->req.dma = 0; + mReq->map = 0; + } req->status = -ECONNRESET; if (mReq->req.complete != NULL) { @@ -2377,6 +2472,31 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) return 0; } +static int ci13xxx_wakeup(struct usb_gadget *_gadget) +{ + struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); + unsigned long flags; + int ret = 0; + + trace(); + + spin_lock_irqsave(udc->lock, flags); + if (!udc->remote_wakeup) { + ret = -EOPNOTSUPP; + dbg_trace("remote wakeup feature is not enabled\n"); + goto out; + } + if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) { + ret = -EINVAL; + dbg_trace("port is not suspended\n"); + goto out; + } + hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR); +out: + spin_unlock_irqrestore(udc->lock, flags); + return ret; +} + /** * Device operations part of the API to the USB controller hardware, * which don't involve endpoints (or i/o) @@ -2384,6 +2504,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) */ static const struct usb_gadget_ops usb_gadget_ops = { .vbus_session = ci13xxx_vbus_session, + .wakeup = ci13xxx_wakeup, }; /** @@ -2626,6 +2747,12 @@ static irqreturn_t udc_irq(void) isr_statistics.pci++; udc->gadget.speed = hw_port_is_high_speed() ? USB_SPEED_HIGH : USB_SPEED_FULL; + if (udc->suspended) { + spin_unlock(udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(udc->lock); + udc->suspended = 0; + } } if (USBi_UEI & intr) isr_statistics.uei++; @@ -2633,8 +2760,15 @@ static irqreturn_t udc_irq(void) isr_statistics.ui++; isr_tr_complete_handler(udc); } - if (USBi_SLI & intr) + if (USBi_SLI & intr) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + udc->suspended = 1; + spin_unlock(udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(udc->lock); + } isr_statistics.sli++; + } retval = IRQ_HANDLED; } else { isr_statistics.none++; diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h index a2492b65f98c..23707775cb43 100644 --- a/drivers/usb/gadget/ci13xxx_udc.h +++ b/drivers/usb/gadget/ci13xxx_udc.h @@ -33,6 +33,7 @@ struct ci13xxx_td { /* 0 */ u32 next; #define TD_TERMINATE BIT(0) +#define TD_ADDR_MASK (0xFFFFFFEUL << 5) /* 1 */ u32 token; #define TD_STATUS (0x00FFUL << 0) @@ -74,6 +75,8 @@ struct ci13xxx_req { struct list_head queue; struct ci13xxx_td *ptr; dma_addr_t dma; + struct ci13xxx_td *zptr; + dma_addr_t zdma; }; /* Extension of usb_ep */ @@ -125,6 +128,10 @@ struct ci13xxx { u32 ep0_dir; /* ep0 direction */ #define ep0out ci13xxx_ep[0] #define ep0in ci13xxx_ep[16] + u8 remote_wakeup; /* Is remote wakeup feature + enabled by the host? */ + u8 suspended; /* suspended by the host */ + u8 test_mode; /* the selected test mode */ struct usb_gadget_driver *driver; /* 3rd party gadget driver */ struct ci13xxx_udc_driver *udc_driver; /* device controller driver */ @@ -152,6 +159,7 @@ struct ci13xxx { #define USBCMD_RS BIT(0) #define USBCMD_RST BIT(1) #define USBCMD_SUTW BIT(13) +#define USBCMD_ATDTW BIT(14) /* USBSTS & USBINTR */ #define USBi_UI BIT(0) @@ -165,6 +173,7 @@ struct ci13xxx { #define DEVICEADDR_USBADR (0x7FUL << 25) /* PORTSC */ +#define PORTSC_FPR BIT(6) #define PORTSC_SUSP BIT(7) #define PORTSC_HSP BIT(9) #define PORTSC_PTC (0x0FUL << 16) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 1ba4befe336b..c2251c40a205 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -813,7 +813,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) */ req->zero = 0; req->complete = composite_setup_complete; - req->length = USB_BUFSIZ; + req->length = 0; gadget->ep0->driver_data = cdev; switch (ctrl->bRequest) { @@ -887,7 +887,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; - if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) break; f = cdev->config->interface[intf]; if (!f) @@ -899,7 +899,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) goto unknown; - if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) break; f = cdev->config->interface[intf]; if (!f) @@ -928,7 +928,7 @@ unknown: */ switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: - if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) + if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) break; f = cdev->config->interface[intf]; break; @@ -1258,16 +1258,16 @@ static struct usb_gadget_driver composite_driver = { * while it was binding. That would usually be done in order to wait for * some userspace participation. */ -extern int usb_composite_probe(struct usb_composite_driver *driver, +int usb_composite_probe(struct usb_composite_driver *driver, int (*bind)(struct usb_composite_dev *cdev)) { if (!driver || !driver->dev || !bind || composite) return -EINVAL; - if (!driver->iProduct) - driver->iProduct = driver->name; if (!driver->name) driver->name = "composite"; + if (!driver->iProduct) + driver->iProduct = driver->name; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; composite = driver; diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 13b9f47feecd..3214ca375d64 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1593,8 +1593,8 @@ hub_descriptor (struct usb_hub_descriptor *desc) desc->bDescLength = 9; desc->wHubCharacteristics = cpu_to_le16(0x0001); desc->bNbrPorts = 1; - desc->bitmap [0] = 0xff; - desc->bitmap [1] = 0xff; + desc->u.hs.DeviceRemovable[0] = 0xff; + desc->u.hs.DeviceRemovable[1] = 0xff; } static int dummy_hub_control ( diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 8a832488ccdd..9b7360ff5aa7 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -128,6 +128,13 @@ ep_matches ( } } + /* + * If the protocol driver hasn't yet decided on wMaxPacketSize + * and wants to know the maximum possible, provide the info. + */ + if (desc->wMaxPacketSize == 0) + desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket); + /* endpoint maxpacket size is an input parameter, except for bulk * where it's an output parameter representing the full speed limit. * the usb spec fixes high speed bulk maxpacket at 512 bytes. diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 1499f9e4afa8..19fffccc370d 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -368,6 +368,14 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) req->buf = data; req->length = len; + /* + * UDC layer requires to provide a buffer even for ZLP, but should + * not use it at all. Let's provide some poisoned pointer to catch + * possible bug in the driver. + */ + if (req->buf == NULL) + req->buf = (void *)0xDEADBABE; + INIT_COMPLETION(ffs->ep0req_completion); ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index 77b1eb577029..43a49ecc1f36 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c @@ -88,15 +88,18 @@ eenahb: void fsl_udc_clk_finalize(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; -#if defined(CONFIG_ARCH_MX35) - unsigned int v; - - /* workaround ENGcm09152 for i.MX35 */ - if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { - v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + - USBPHYCTRL_OTGBASE_OFFSET)); - writel(v | USBPHYCTRL_EVDO, MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + - USBPHYCTRL_OTGBASE_OFFSET)); +#if defined(CONFIG_SOC_IMX35) + if (cpu_is_mx35()) { + unsigned int v; + + /* workaround ENGcm09152 for i.MX35 */ + if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { + v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + + USBPHYCTRL_OTGBASE_OFFSET)); + writel(v | USBPHYCTRL_EVDO, + MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + + USBPHYCTRL_OTGBASE_OFFSET)); + } } #endif diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 4c55eda4bd20..912cb8e63fe3 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -766,7 +766,6 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) struct fsl_req *req = container_of(_req, struct fsl_req, req); struct fsl_udc *udc; unsigned long flags; - int is_iso = 0; /* catch various bogus parameters */ if (!_req || !req->req.complete || !req->req.buf @@ -781,7 +780,6 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE; - is_iso = 1; } udc = ep->udc; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c new file mode 100644 index 000000000000..763d462454b9 --- /dev/null +++ b/drivers/usb/gadget/fusb300_udc.c @@ -0,0 +1,1744 @@ +/* + * Fusb300 UDC (USB gadget) + * + * Copyright (C) 2010 Faraday Technology Corp. + * + * Author : Yuan-hsin Chen <yhchen@faraday-tech.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +#include "fusb300_udc.h" + +MODULE_DESCRIPTION("FUSB300 USB gadget driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yuan Hsin Chen <yhchen@faraday-tech.com>"); +MODULE_ALIAS("platform:fusb300_udc"); + +#define DRIVER_VERSION "20 October 2010" + +static const char udc_name[] = "fusb300_udc"; +static const char * const fusb300_ep_name[] = { + "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", "ep8", "ep9", + "ep10", "ep11", "ep12", "ep13", "ep14", "ep15" +}; + +static void done(struct fusb300_ep *ep, struct fusb300_request *req, + int status); + +static void fusb300_enable_bit(struct fusb300 *fusb300, u32 offset, + u32 value) +{ + u32 reg = ioread32(fusb300->reg + offset); + + reg |= value; + iowrite32(reg, fusb300->reg + offset); +} + +static void fusb300_disable_bit(struct fusb300 *fusb300, u32 offset, + u32 value) +{ + u32 reg = ioread32(fusb300->reg + offset); + + reg &= ~value; + iowrite32(reg, fusb300->reg + offset); +} + + +static void fusb300_ep_setting(struct fusb300_ep *ep, + struct fusb300_ep_info info) +{ + ep->epnum = info.epnum; + ep->type = info.type; +} + +static int fusb300_ep_release(struct fusb300_ep *ep) +{ + if (!ep->epnum) + return 0; + ep->epnum = 0; + ep->stall = 0; + ep->wedged = 0; + return 0; +} + +static void fusb300_set_fifo_entry(struct fusb300 *fusb300, + u32 ep) +{ + u32 val = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); + + val &= ~FUSB300_EPSET1_FIFOENTRY_MSK; + val |= FUSB300_EPSET1_FIFOENTRY(FUSB300_FIFO_ENTRY_NUM); + iowrite32(val, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); +} + +static void fusb300_set_start_entry(struct fusb300 *fusb300, + u8 ep) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); + u32 start_entry = fusb300->fifo_entry_num * FUSB300_FIFO_ENTRY_NUM; + + reg &= ~FUSB300_EPSET1_START_ENTRY_MSK ; + reg |= FUSB300_EPSET1_START_ENTRY(start_entry); + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); + if (fusb300->fifo_entry_num == FUSB300_MAX_FIFO_ENTRY) { + fusb300->fifo_entry_num = 0; + fusb300->addrofs = 0; + pr_err("fifo entry is over the maximum number!\n"); + } else + fusb300->fifo_entry_num++; +} + +/* set fusb300_set_start_entry first before fusb300_set_epaddrofs */ +static void fusb300_set_epaddrofs(struct fusb300 *fusb300, + struct fusb300_ep_info info) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); + + reg &= ~FUSB300_EPSET2_ADDROFS_MSK; + reg |= FUSB300_EPSET2_ADDROFS(fusb300->addrofs); + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); + fusb300->addrofs += (info.maxpacket + 7) / 8 * FUSB300_FIFO_ENTRY_NUM; +} + +static void ep_fifo_setting(struct fusb300 *fusb300, + struct fusb300_ep_info info) +{ + fusb300_set_fifo_entry(fusb300, info.epnum); + fusb300_set_start_entry(fusb300, info.epnum); + fusb300_set_epaddrofs(fusb300, info); +} + +static void fusb300_set_eptype(struct fusb300 *fusb300, + struct fusb300_ep_info info) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); + + reg &= ~FUSB300_EPSET1_TYPE_MSK; + reg |= FUSB300_EPSET1_TYPE(info.type); + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); +} + +static void fusb300_set_epdir(struct fusb300 *fusb300, + struct fusb300_ep_info info) +{ + u32 reg; + + if (!info.dir_in) + return; + reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); + reg &= ~FUSB300_EPSET1_DIR_MSK; + reg |= FUSB300_EPSET1_DIRIN; + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); +} + +static void fusb300_set_ep_active(struct fusb300 *fusb300, + u8 ep) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); + + reg |= FUSB300_EPSET1_ACTEN; + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); +} + +static void fusb300_set_epmps(struct fusb300 *fusb300, + struct fusb300_ep_info info) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); + + reg &= ~FUSB300_EPSET2_MPS_MSK; + reg |= FUSB300_EPSET2_MPS(info.maxpacket); + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); +} + +static void fusb300_set_interval(struct fusb300 *fusb300, + struct fusb300_ep_info info) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); + + reg &= ~FUSB300_EPSET1_INTERVAL(0x7); + reg |= FUSB300_EPSET1_INTERVAL(info.interval); + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); +} + +static void fusb300_set_bwnum(struct fusb300 *fusb300, + struct fusb300_ep_info info) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); + + reg &= ~FUSB300_EPSET1_BWNUM(0x3); + reg |= FUSB300_EPSET1_BWNUM(info.bw_num); + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); +} + +static void set_ep_reg(struct fusb300 *fusb300, + struct fusb300_ep_info info) +{ + fusb300_set_eptype(fusb300, info); + fusb300_set_epdir(fusb300, info); + fusb300_set_epmps(fusb300, info); + + if (info.interval) + fusb300_set_interval(fusb300, info); + + if (info.bw_num) + fusb300_set_bwnum(fusb300, info); + + fusb300_set_ep_active(fusb300, info.epnum); +} + +static int config_ep(struct fusb300_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct fusb300 *fusb300 = ep->fusb300; + struct fusb300_ep_info info; + + ep->desc = desc; + + info.interval = 0; + info.addrofs = 0; + info.bw_num = 0; + + info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; + info.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + + if ((info.type == USB_ENDPOINT_XFER_INT) || + (info.type == USB_ENDPOINT_XFER_ISOC)) { + info.interval = desc->bInterval; + if (info.type == USB_ENDPOINT_XFER_ISOC) + info.bw_num = ((desc->wMaxPacketSize & 0x1800) >> 11); + } + + ep_fifo_setting(fusb300, info); + + set_ep_reg(fusb300, info); + + fusb300_ep_setting(ep, info); + + fusb300->ep[info.epnum] = ep; + + return 0; +} + +static int fusb300_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct fusb300_ep *ep; + + ep = container_of(_ep, struct fusb300_ep, ep); + + if (ep->fusb300->reenum) { + ep->fusb300->fifo_entry_num = 0; + ep->fusb300->addrofs = 0; + ep->fusb300->reenum = 0; + } + + return config_ep(ep, desc); +} + +static int fusb300_disable(struct usb_ep *_ep) +{ + struct fusb300_ep *ep; + struct fusb300_request *req; + unsigned long flags; + + ep = container_of(_ep, struct fusb300_ep, ep); + + BUG_ON(!ep); + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct fusb300_request, queue); + spin_lock_irqsave(&ep->fusb300->lock, flags); + done(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&ep->fusb300->lock, flags); + } + + return fusb300_ep_release(ep); +} + +static struct usb_request *fusb300_alloc_request(struct usb_ep *_ep, + gfp_t gfp_flags) +{ + struct fusb300_request *req; + + req = kzalloc(sizeof(struct fusb300_request), gfp_flags); + if (!req) + return NULL; + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void fusb300_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct fusb300_request *req; + + req = container_of(_req, struct fusb300_request, req); + kfree(req); +} + +static int enable_fifo_int(struct fusb300_ep *ep) +{ + struct fusb300 *fusb300 = ep->fusb300; + + if (ep->epnum) { + fusb300_enable_bit(fusb300, FUSB300_OFFSET_IGER0, + FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum)); + } else { + pr_err("can't enable_fifo_int ep0\n"); + return -EINVAL; + } + + return 0; +} + +static int disable_fifo_int(struct fusb300_ep *ep) +{ + struct fusb300 *fusb300 = ep->fusb300; + + if (ep->epnum) { + fusb300_disable_bit(fusb300, FUSB300_OFFSET_IGER0, + FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum)); + } else { + pr_err("can't disable_fifo_int ep0\n"); + return -EINVAL; + } + + return 0; +} + +static void fusb300_set_cxlen(struct fusb300 *fusb300, u32 length) +{ + u32 reg; + + reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR); + reg &= ~FUSB300_CSR_LEN_MSK; + reg |= FUSB300_CSR_LEN(length); + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_CSR); +} + +/* write data to cx fifo */ +static void fusb300_wrcxf(struct fusb300_ep *ep, + struct fusb300_request *req) +{ + int i = 0; + u8 *tmp; + u32 data; + struct fusb300 *fusb300 = ep->fusb300; + u32 length = req->req.length - req->req.actual; + + tmp = req->req.buf + req->req.actual; + + if (length > SS_CTL_MAX_PACKET_SIZE) { + fusb300_set_cxlen(fusb300, SS_CTL_MAX_PACKET_SIZE); + for (i = (SS_CTL_MAX_PACKET_SIZE >> 2); i > 0; i--) { + data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 | + *(tmp + 3) << 24; + iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); + tmp += 4; + } + req->req.actual += SS_CTL_MAX_PACKET_SIZE; + } else { /* length is less than max packet size */ + fusb300_set_cxlen(fusb300, length); + for (i = length >> 2; i > 0; i--) { + data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 | + *(tmp + 3) << 24; + printk(KERN_DEBUG " 0x%x\n", data); + iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); + tmp = tmp + 4; + } + switch (length % 4) { + case 1: + data = *tmp; + printk(KERN_DEBUG " 0x%x\n", data); + iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); + break; + case 2: + data = *tmp | *(tmp + 1) << 8; + printk(KERN_DEBUG " 0x%x\n", data); + iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); + break; + case 3: + data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16; + printk(KERN_DEBUG " 0x%x\n", data); + iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); + break; + default: + break; + } + req->req.actual += length; + } +} + +static void fusb300_set_epnstall(struct fusb300 *fusb300, u8 ep) +{ + fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep), + FUSB300_EPSET0_STL); +} + +static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); + + if (reg & FUSB300_EPSET0_STL) { + printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep); + reg &= ~FUSB300_EPSET0_STL; + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); + } +} + +static void ep0_queue(struct fusb300_ep *ep, struct fusb300_request *req) +{ + if (ep->fusb300->ep0_dir) { /* if IN */ + if (req->req.length) { + fusb300_wrcxf(ep, req); + } else + printk(KERN_DEBUG "%s : req->req.length = 0x%x\n", + __func__, req->req.length); + if ((req->req.length == req->req.actual) || + (req->req.actual < ep->ep.maxpacket)) + done(ep, req, 0); + } else { /* OUT */ + if (!req->req.length) + done(ep, req, 0); + else + fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER1, + FUSB300_IGER1_CX_OUT_INT); + } +} + +static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct fusb300_ep *ep; + struct fusb300_request *req; + unsigned long flags; + int request = 0; + + ep = container_of(_ep, struct fusb300_ep, ep); + req = container_of(_req, struct fusb300_request, req); + + if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + spin_lock_irqsave(&ep->fusb300->lock, flags); + + if (list_empty(&ep->queue)) + request = 1; + + list_add_tail(&req->queue, &ep->queue); + + req->req.actual = 0; + req->req.status = -EINPROGRESS; + + if (ep->desc == NULL) /* ep0 */ + ep0_queue(ep, req); + else if (request && !ep->stall) + enable_fifo_int(ep); + + spin_unlock_irqrestore(&ep->fusb300->lock, flags); + + return 0; +} + +static int fusb300_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct fusb300_ep *ep; + struct fusb300_request *req; + unsigned long flags; + + ep = container_of(_ep, struct fusb300_ep, ep); + req = container_of(_req, struct fusb300_request, req); + + spin_lock_irqsave(&ep->fusb300->lock, flags); + if (!list_empty(&ep->queue)) + done(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&ep->fusb300->lock, flags); + + return 0; +} + +static int fusb300_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) +{ + struct fusb300_ep *ep; + struct fusb300 *fusb300; + unsigned long flags; + int ret = 0; + + ep = container_of(_ep, struct fusb300_ep, ep); + + fusb300 = ep->fusb300; + + spin_lock_irqsave(&ep->fusb300->lock, flags); + + if (!list_empty(&ep->queue)) { + ret = -EAGAIN; + goto out; + } + + if (value) { + fusb300_set_epnstall(fusb300, ep->epnum); + ep->stall = 1; + if (wedge) + ep->wedged = 1; + } else { + fusb300_clear_epnstall(fusb300, ep->epnum); + ep->stall = 0; + ep->wedged = 0; + } + +out: + spin_unlock_irqrestore(&ep->fusb300->lock, flags); + return ret; +} + +static int fusb300_set_halt(struct usb_ep *_ep, int value) +{ + return fusb300_set_halt_and_wedge(_ep, value, 0); +} + +static int fusb300_set_wedge(struct usb_ep *_ep) +{ + return fusb300_set_halt_and_wedge(_ep, 1, 1); +} + +static void fusb300_fifo_flush(struct usb_ep *_ep) +{ +} + +static struct usb_ep_ops fusb300_ep_ops = { + .enable = fusb300_enable, + .disable = fusb300_disable, + + .alloc_request = fusb300_alloc_request, + .free_request = fusb300_free_request, + + .queue = fusb300_queue, + .dequeue = fusb300_dequeue, + + .set_halt = fusb300_set_halt, + .fifo_flush = fusb300_fifo_flush, + .set_wedge = fusb300_set_wedge, +}; + +/*****************************************************************************/ +static void fusb300_clear_int(struct fusb300 *fusb300, u32 offset, + u32 value) +{ + iowrite32(value, fusb300->reg + offset); +} + +static void fusb300_reset(void) +{ +} + +static void fusb300_set_cxstall(struct fusb300 *fusb300) +{ + fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR, + FUSB300_CSR_STL); +} + +static void fusb300_set_cxdone(struct fusb300 *fusb300) +{ + fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR, + FUSB300_CSR_DONE); +} + +/* read data from cx fifo */ +void fusb300_rdcxf(struct fusb300 *fusb300, + u8 *buffer, u32 length) +{ + int i = 0; + u8 *tmp; + u32 data; + + tmp = buffer; + + for (i = (length >> 2); i > 0; i--) { + data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); + printk(KERN_DEBUG " 0x%x\n", data); + *tmp = data & 0xFF; + *(tmp + 1) = (data >> 8) & 0xFF; + *(tmp + 2) = (data >> 16) & 0xFF; + *(tmp + 3) = (data >> 24) & 0xFF; + tmp = tmp + 4; + } + + switch (length % 4) { + case 1: + data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); + printk(KERN_DEBUG " 0x%x\n", data); + *tmp = data & 0xFF; + break; + case 2: + data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); + printk(KERN_DEBUG " 0x%x\n", data); + *tmp = data & 0xFF; + *(tmp + 1) = (data >> 8) & 0xFF; + break; + case 3: + data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); + printk(KERN_DEBUG " 0x%x\n", data); + *tmp = data & 0xFF; + *(tmp + 1) = (data >> 8) & 0xFF; + *(tmp + 2) = (data >> 16) & 0xFF; + break; + default: + break; + } +} + +#if 0 +static void fusb300_dbg_fifo(struct fusb300_ep *ep, + u8 entry, u16 length) +{ + u32 reg; + u32 i = 0; + u32 j = 0; + + reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_GTM); + reg &= ~(FUSB300_GTM_TST_EP_ENTRY(0xF) | + FUSB300_GTM_TST_EP_NUM(0xF) | FUSB300_GTM_TST_FIFO_DEG); + reg |= (FUSB300_GTM_TST_EP_ENTRY(entry) | + FUSB300_GTM_TST_EP_NUM(ep->epnum) | FUSB300_GTM_TST_FIFO_DEG); + iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_GTM); + + for (i = 0; i < (length >> 2); i++) { + if (i * 4 == 1024) + break; + reg = ioread32(ep->fusb300->reg + + FUSB300_OFFSET_BUFDBG_START + i * 4); + printk(KERN_DEBUG" 0x%-8x", reg); + j++; + if ((j % 4) == 0) + printk(KERN_DEBUG "\n"); + } + + if (length % 4) { + reg = ioread32(ep->fusb300->reg + + FUSB300_OFFSET_BUFDBG_START + i * 4); + printk(KERN_DEBUG " 0x%x\n", reg); + } + + if ((j % 4) != 0) + printk(KERN_DEBUG "\n"); + + fusb300_disable_bit(ep->fusb300, FUSB300_OFFSET_GTM, + FUSB300_GTM_TST_FIFO_DEG); +} + +static void fusb300_cmp_dbg_fifo(struct fusb300_ep *ep, + u8 entry, u16 length, u8 *golden) +{ + u32 reg; + u32 i = 0; + u32 golden_value; + u8 *tmp; + + tmp = golden; + + printk(KERN_DEBUG "fusb300_cmp_dbg_fifo (entry %d) : start\n", entry); + + reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_GTM); + reg &= ~(FUSB300_GTM_TST_EP_ENTRY(0xF) | + FUSB300_GTM_TST_EP_NUM(0xF) | FUSB300_GTM_TST_FIFO_DEG); + reg |= (FUSB300_GTM_TST_EP_ENTRY(entry) | + FUSB300_GTM_TST_EP_NUM(ep->epnum) | FUSB300_GTM_TST_FIFO_DEG); + iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_GTM); + + for (i = 0; i < (length >> 2); i++) { + if (i * 4 == 1024) + break; + golden_value = *tmp | *(tmp + 1) << 8 | + *(tmp + 2) << 16 | *(tmp + 3) << 24; + + reg = ioread32(ep->fusb300->reg + + FUSB300_OFFSET_BUFDBG_START + i*4); + + if (reg != golden_value) { + printk(KERN_DEBUG "0x%x : ", (u32)(ep->fusb300->reg + + FUSB300_OFFSET_BUFDBG_START + i*4)); + printk(KERN_DEBUG " golden = 0x%x, reg = 0x%x\n", + golden_value, reg); + } + tmp += 4; + } + + switch (length % 4) { + case 1: + golden_value = *tmp; + case 2: + golden_value = *tmp | *(tmp + 1) << 8; + case 3: + golden_value = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16; + default: + break; + + reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_BUFDBG_START + i*4); + if (reg != golden_value) { + printk(KERN_DEBUG "0x%x:", (u32)(ep->fusb300->reg + + FUSB300_OFFSET_BUFDBG_START + i*4)); + printk(KERN_DEBUG " golden = 0x%x, reg = 0x%x\n", + golden_value, reg); + } + } + + printk(KERN_DEBUG "fusb300_cmp_dbg_fifo : end\n"); + fusb300_disable_bit(ep->fusb300, FUSB300_OFFSET_GTM, + FUSB300_GTM_TST_FIFO_DEG); +} +#endif + +static void fusb300_rdfifo(struct fusb300_ep *ep, + struct fusb300_request *req, + u32 length) +{ + int i = 0; + u8 *tmp; + u32 data, reg; + struct fusb300 *fusb300 = ep->fusb300; + + tmp = req->req.buf + req->req.actual; + req->req.actual += length; + + if (req->req.actual > req->req.length) + printk(KERN_DEBUG "req->req.actual > req->req.length\n"); + + for (i = (length >> 2); i > 0; i--) { + data = ioread32(fusb300->reg + + FUSB300_OFFSET_EPPORT(ep->epnum)); + *tmp = data & 0xFF; + *(tmp + 1) = (data >> 8) & 0xFF; + *(tmp + 2) = (data >> 16) & 0xFF; + *(tmp + 3) = (data >> 24) & 0xFF; + tmp = tmp + 4; + } + + switch (length % 4) { + case 1: + data = ioread32(fusb300->reg + + FUSB300_OFFSET_EPPORT(ep->epnum)); + *tmp = data & 0xFF; + break; + case 2: + data = ioread32(fusb300->reg + + FUSB300_OFFSET_EPPORT(ep->epnum)); + *tmp = data & 0xFF; + *(tmp + 1) = (data >> 8) & 0xFF; + break; + case 3: + data = ioread32(fusb300->reg + + FUSB300_OFFSET_EPPORT(ep->epnum)); + *tmp = data & 0xFF; + *(tmp + 1) = (data >> 8) & 0xFF; + *(tmp + 2) = (data >> 16) & 0xFF; + break; + default: + break; + } + + do { + reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); + reg &= FUSB300_IGR1_SYNF0_EMPTY_INT; + if (i) + printk(KERN_INFO "sync fifo is not empty!\n"); + i++; + } while (!reg); +} + +/* write data to fifo */ +static void fusb300_wrfifo(struct fusb300_ep *ep, + struct fusb300_request *req) +{ + int i = 0; + u8 *tmp; + u32 data, reg; + struct fusb300 *fusb300 = ep->fusb300; + + tmp = req->req.buf; + req->req.actual = req->req.length; + + for (i = (req->req.length >> 2); i > 0; i--) { + data = *tmp | *(tmp + 1) << 8 | + *(tmp + 2) << 16 | *(tmp + 3) << 24; + + iowrite32(data, fusb300->reg + + FUSB300_OFFSET_EPPORT(ep->epnum)); + tmp += 4; + } + + switch (req->req.length % 4) { + case 1: + data = *tmp; + iowrite32(data, fusb300->reg + + FUSB300_OFFSET_EPPORT(ep->epnum)); + break; + case 2: + data = *tmp | *(tmp + 1) << 8; + iowrite32(data, fusb300->reg + + FUSB300_OFFSET_EPPORT(ep->epnum)); + break; + case 3: + data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16; + iowrite32(data, fusb300->reg + + FUSB300_OFFSET_EPPORT(ep->epnum)); + break; + default: + break; + } + + do { + reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); + reg &= FUSB300_IGR1_SYNF0_EMPTY_INT; + if (i) + printk(KERN_INFO"sync fifo is not empty!\n"); + i++; + } while (!reg); +} + +static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep) +{ + u8 value; + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); + + value = reg & FUSB300_EPSET0_STL; + + return value; +} + +static u8 fusb300_get_cxstall(struct fusb300 *fusb300) +{ + u8 value; + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR); + + value = (reg & FUSB300_CSR_STL) >> 1; + + return value; +} + +static void request_error(struct fusb300 *fusb300) +{ + fusb300_set_cxstall(fusb300); + printk(KERN_DEBUG "request error!!\n"); +} + +static void get_status(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) +__releases(fusb300->lock) +__acquires(fusb300->lock) +{ + u8 ep; + u16 status = 0; + u16 w_index = ctrl->wIndex; + + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + status = 1 << USB_DEVICE_SELF_POWERED; + break; + case USB_RECIP_INTERFACE: + status = 0; + break; + case USB_RECIP_ENDPOINT: + ep = w_index & USB_ENDPOINT_NUMBER_MASK; + if (ep) { + if (fusb300_get_epnstall(fusb300, ep)) + status = 1 << USB_ENDPOINT_HALT; + } else { + if (fusb300_get_cxstall(fusb300)) + status = 0; + } + break; + + default: + request_error(fusb300); + return; /* exit */ + } + + fusb300->ep0_data = cpu_to_le16(status); + fusb300->ep0_req->buf = &fusb300->ep0_data; + fusb300->ep0_req->length = 2; + + spin_unlock(&fusb300->lock); + fusb300_queue(fusb300->gadget.ep0, fusb300->ep0_req, GFP_KERNEL); + spin_lock(&fusb300->lock); +} + +static void set_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) +{ + u8 ep; + + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + fusb300_set_cxdone(fusb300); + break; + case USB_RECIP_INTERFACE: + fusb300_set_cxdone(fusb300); + break; + case USB_RECIP_ENDPOINT: { + u16 w_index = le16_to_cpu(ctrl->wIndex); + + ep = w_index & USB_ENDPOINT_NUMBER_MASK; + if (ep) + fusb300_set_epnstall(fusb300, ep); + else + fusb300_set_cxstall(fusb300); + fusb300_set_cxdone(fusb300); + } + break; + default: + request_error(fusb300); + break; + } +} + +static void fusb300_clear_seqnum(struct fusb300 *fusb300, u8 ep) +{ + fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep), + FUSB300_EPSET0_CLRSEQNUM); +} + +static void clear_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) +{ + struct fusb300_ep *ep = + fusb300->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK]; + + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + fusb300_set_cxdone(fusb300); + break; + case USB_RECIP_INTERFACE: + fusb300_set_cxdone(fusb300); + break; + case USB_RECIP_ENDPOINT: + if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) { + if (ep->wedged) { + fusb300_set_cxdone(fusb300); + break; + } + if (ep->stall) { + ep->stall = 0; + fusb300_clear_seqnum(fusb300, ep->epnum); + fusb300_clear_epnstall(fusb300, ep->epnum); + if (!list_empty(&ep->queue)) + enable_fifo_int(ep); + } + } + fusb300_set_cxdone(fusb300); + break; + default: + request_error(fusb300); + break; + } +} + +static void fusb300_set_dev_addr(struct fusb300 *fusb300, u16 addr) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_DAR); + + reg &= ~FUSB300_DAR_DRVADDR_MSK; + reg |= FUSB300_DAR_DRVADDR(addr); + + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_DAR); +} + +static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) +{ + if (ctrl->wValue >= 0x0100) + request_error(fusb300); + else { + fusb300_set_dev_addr(fusb300, ctrl->wValue); + fusb300_set_cxdone(fusb300); + } +} + +#define UVC_COPY_DESCRIPTORS(mem, src) \ + do { \ + const struct usb_descriptor_header * const *__src; \ + for (__src = src; *__src; ++__src) { \ + memcpy(mem, *__src, (*__src)->bLength); \ + mem += (*__src)->bLength; \ + } \ + } while (0) + +static void fusb300_ep0_complete(struct usb_ep *ep, + struct usb_request *req) +{ +} + +static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) +{ + u8 *p = (u8 *)ctrl; + u8 ret = 0; + u8 i = 0; + + fusb300_rdcxf(fusb300, p, 8); + fusb300->ep0_dir = ctrl->bRequestType & USB_DIR_IN; + fusb300->ep0_length = ctrl->wLength; + + /* check request */ + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + switch (ctrl->bRequest) { + case USB_REQ_GET_STATUS: + get_status(fusb300, ctrl); + break; + case USB_REQ_CLEAR_FEATURE: + clear_feature(fusb300, ctrl); + break; + case USB_REQ_SET_FEATURE: + set_feature(fusb300, ctrl); + break; + case USB_REQ_SET_ADDRESS: + set_address(fusb300, ctrl); + break; + case USB_REQ_SET_CONFIGURATION: + fusb300_enable_bit(fusb300, FUSB300_OFFSET_DAR, + FUSB300_DAR_SETCONFG); + /* clear sequence number */ + for (i = 1; i <= FUSB300_MAX_NUM_EP; i++) + fusb300_clear_seqnum(fusb300, i); + fusb300->reenum = 1; + ret = 1; + break; + default: + ret = 1; + break; + } + } else + ret = 1; + + return ret; +} + +static void fusb300_set_ep_bycnt(struct fusb300_ep *ep, u32 bycnt) +{ + struct fusb300 *fusb300 = ep->fusb300; + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); + + reg &= ~FUSB300_FFR_BYCNT; + reg |= bycnt & FUSB300_FFR_BYCNT; + + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); +} + +static void done(struct fusb300_ep *ep, struct fusb300_request *req, + int status) +{ + list_del_init(&req->queue); + + /* don't modify queue heads during completion callback */ + if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN) + req->req.status = -ESHUTDOWN; + else + req->req.status = status; + + spin_unlock(&ep->fusb300->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&ep->fusb300->lock); + + if (ep->epnum) { + disable_fifo_int(ep); + if (!list_empty(&ep->queue)) + enable_fifo_int(ep); + } else + fusb300_set_cxdone(ep->fusb300); +} + +void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, + struct fusb300_request *req) +{ + u32 value; + u32 reg; + + /* wait SW owner */ + do { + reg = ioread32(ep->fusb300->reg + + FUSB300_OFFSET_EPPRD_W0(ep->epnum)); + reg &= FUSB300_EPPRD0_H; + } while (reg); + + iowrite32((u32) req->req.buf, ep->fusb300->reg + + FUSB300_OFFSET_EPPRD_W1(ep->epnum)); + + value = FUSB300_EPPRD0_BTC(req->req.length) | FUSB300_EPPRD0_H | + FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I; + iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum)); + + iowrite32(0x0, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W2(ep->epnum)); + + fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_EPPRDRDY, + FUSB300_EPPRDR_EP_PRD_RDY(ep->epnum)); +} + +static void fusb300_wait_idma_finished(struct fusb300_ep *ep) +{ + u32 reg; + + do { + reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR1); + if ((reg & FUSB300_IGR1_VBUS_CHG_INT) || + (reg & FUSB300_IGR1_WARM_RST_INT) || + (reg & FUSB300_IGR1_HOT_RST_INT) || + (reg & FUSB300_IGR1_USBRST_INT) + ) + goto IDMA_RESET; + reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR0); + reg &= FUSB300_IGR0_EPn_PRD_INT(ep->epnum); + } while (!reg); + + fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0, + FUSB300_IGR0_EPn_PRD_INT(ep->epnum)); +IDMA_RESET: + fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGER0, + FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); +} + +static void fusb300_set_idma(struct fusb300_ep *ep, + struct fusb300_request *req) +{ + dma_addr_t d; + u8 *tmp = NULL; + + d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE); + + if (dma_mapping_error(NULL, d)) { + kfree(req->req.buf); + printk(KERN_DEBUG "dma_mapping_error\n"); + } + + dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE); + + fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0, + FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); + + tmp = req->req.buf; + req->req.buf = (u8 *)d; + + fusb300_fill_idma_prdtbl(ep, req); + /* check idma is done */ + fusb300_wait_idma_finished(ep); + + req->req.buf = tmp; + + if (d) + dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE); +} + +static void in_ep_fifo_handler(struct fusb300_ep *ep) +{ + struct fusb300_request *req = list_entry(ep->queue.next, + struct fusb300_request, queue); + + if (req->req.length) { +#if 0 + fusb300_set_ep_bycnt(ep, req->req.length); + fusb300_wrfifo(ep, req); +#else + fusb300_set_idma(ep, req); +#endif + } + done(ep, req, 0); +} + +static void out_ep_fifo_handler(struct fusb300_ep *ep) +{ + struct fusb300 *fusb300 = ep->fusb300; + struct fusb300_request *req = list_entry(ep->queue.next, + struct fusb300_request, queue); + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); + u32 length = reg & FUSB300_FFR_BYCNT; + + fusb300_rdfifo(ep, req, length); + + /* finish out transfer */ + if ((req->req.length == req->req.actual) || (length < ep->ep.maxpacket)) + done(ep, req, 0); +} + +static void check_device_mode(struct fusb300 *fusb300) +{ + u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_GCR); + + switch (reg & FUSB300_GCR_DEVEN_MSK) { + case FUSB300_GCR_DEVEN_SS: + fusb300->gadget.speed = USB_SPEED_SUPER; + break; + case FUSB300_GCR_DEVEN_HS: + fusb300->gadget.speed = USB_SPEED_HIGH; + break; + case FUSB300_GCR_DEVEN_FS: + fusb300->gadget.speed = USB_SPEED_FULL; + break; + default: + fusb300->gadget.speed = USB_SPEED_UNKNOWN; + break; + } + printk(KERN_INFO "dev_mode = %d\n", (reg & FUSB300_GCR_DEVEN_MSK)); +} + + +static void fusb300_ep0out(struct fusb300 *fusb300) +{ + struct fusb300_ep *ep = fusb300->ep[0]; + u32 reg; + + if (!list_empty(&ep->queue)) { + struct fusb300_request *req; + + req = list_first_entry(&ep->queue, + struct fusb300_request, queue); + if (req->req.length) + fusb300_rdcxf(ep->fusb300, req->req.buf, + req->req.length); + done(ep, req, 0); + reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1); + reg &= ~FUSB300_IGER1_CX_OUT_INT; + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_IGER1); + } else + pr_err("%s : empty queue\n", __func__); +} + +static void fusb300_ep0in(struct fusb300 *fusb300) +{ + struct fusb300_request *req; + struct fusb300_ep *ep = fusb300->ep[0]; + + if ((!list_empty(&ep->queue)) && (fusb300->ep0_dir)) { + req = list_entry(ep->queue.next, + struct fusb300_request, queue); + if (req->req.length) + fusb300_wrcxf(ep, req); + if ((req->req.length - req->req.actual) < ep->ep.maxpacket) + done(ep, req, 0); + } else + fusb300_set_cxdone(fusb300); +} + +static void fusb300_grp2_handler(void) +{ +} + +static void fusb300_grp3_handler(void) +{ +} + +static void fusb300_grp4_handler(void) +{ +} + +static void fusb300_grp5_handler(void) +{ +} + +static irqreturn_t fusb300_irq(int irq, void *_fusb300) +{ + struct fusb300 *fusb300 = _fusb300; + u32 int_grp1 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); + u32 int_grp1_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1); + u32 int_grp0 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR0); + u32 int_grp0_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER0); + struct usb_ctrlrequest ctrl; + u8 in; + u32 reg; + int i; + + spin_lock(&fusb300->lock); + + int_grp1 &= int_grp1_en; + int_grp0 &= int_grp0_en; + + if (int_grp1 & FUSB300_IGR1_WARM_RST_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_WARM_RST_INT); + printk(KERN_INFO"fusb300_warmreset\n"); + fusb300_reset(); + } + + if (int_grp1 & FUSB300_IGR1_HOT_RST_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_HOT_RST_INT); + printk(KERN_INFO"fusb300_hotreset\n"); + fusb300_reset(); + } + + if (int_grp1 & FUSB300_IGR1_USBRST_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_USBRST_INT); + fusb300_reset(); + } + /* COMABT_INT has a highest priority */ + + if (int_grp1 & FUSB300_IGR1_CX_COMABT_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_CX_COMABT_INT); + printk(KERN_INFO"fusb300_ep0abt\n"); + } + + if (int_grp1 & FUSB300_IGR1_VBUS_CHG_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_VBUS_CHG_INT); + printk(KERN_INFO"fusb300_vbus_change\n"); + } + + if (int_grp1 & FUSB300_IGR1_U3_EXIT_FAIL_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U3_EXIT_FAIL_INT); + } + + if (int_grp1 & FUSB300_IGR1_U2_EXIT_FAIL_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U2_EXIT_FAIL_INT); + } + + if (int_grp1 & FUSB300_IGR1_U1_EXIT_FAIL_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U1_EXIT_FAIL_INT); + } + + if (int_grp1 & FUSB300_IGR1_U2_ENTRY_FAIL_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U2_ENTRY_FAIL_INT); + } + + if (int_grp1 & FUSB300_IGR1_U1_ENTRY_FAIL_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U1_ENTRY_FAIL_INT); + } + + if (int_grp1 & FUSB300_IGR1_U3_EXIT_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U3_EXIT_INT); + printk(KERN_INFO "FUSB300_IGR1_U3_EXIT_INT\n"); + } + + if (int_grp1 & FUSB300_IGR1_U2_EXIT_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U2_EXIT_INT); + printk(KERN_INFO "FUSB300_IGR1_U2_EXIT_INT\n"); + } + + if (int_grp1 & FUSB300_IGR1_U1_EXIT_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U1_EXIT_INT); + printk(KERN_INFO "FUSB300_IGR1_U1_EXIT_INT\n"); + } + + if (int_grp1 & FUSB300_IGR1_U3_ENTRY_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U3_ENTRY_INT); + printk(KERN_INFO "FUSB300_IGR1_U3_ENTRY_INT\n"); + fusb300_enable_bit(fusb300, FUSB300_OFFSET_SSCR1, + FUSB300_SSCR1_GO_U3_DONE); + } + + if (int_grp1 & FUSB300_IGR1_U2_ENTRY_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U2_ENTRY_INT); + printk(KERN_INFO "FUSB300_IGR1_U2_ENTRY_INT\n"); + } + + if (int_grp1 & FUSB300_IGR1_U1_ENTRY_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_U1_ENTRY_INT); + printk(KERN_INFO "FUSB300_IGR1_U1_ENTRY_INT\n"); + } + + if (int_grp1 & FUSB300_IGR1_RESM_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_RESM_INT); + printk(KERN_INFO "fusb300_resume\n"); + } + + if (int_grp1 & FUSB300_IGR1_SUSP_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_SUSP_INT); + printk(KERN_INFO "fusb300_suspend\n"); + } + + if (int_grp1 & FUSB300_IGR1_HS_LPM_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_HS_LPM_INT); + printk(KERN_INFO "fusb300_HS_LPM_INT\n"); + } + + if (int_grp1 & FUSB300_IGR1_DEV_MODE_CHG_INT) { + fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, + FUSB300_IGR1_DEV_MODE_CHG_INT); + check_device_mode(fusb300); + } + + if (int_grp1 & FUSB300_IGR1_CX_COMFAIL_INT) { + fusb300_set_cxstall(fusb300); + printk(KERN_INFO "fusb300_ep0fail\n"); + } + + if (int_grp1 & FUSB300_IGR1_CX_SETUP_INT) { + printk(KERN_INFO "fusb300_ep0setup\n"); + if (setup_packet(fusb300, &ctrl)) { + spin_unlock(&fusb300->lock); + if (fusb300->driver->setup(&fusb300->gadget, &ctrl) < 0) + fusb300_set_cxstall(fusb300); + spin_lock(&fusb300->lock); + } + } + + if (int_grp1 & FUSB300_IGR1_CX_CMDEND_INT) + printk(KERN_INFO "fusb300_cmdend\n"); + + + if (int_grp1 & FUSB300_IGR1_CX_OUT_INT) { + printk(KERN_INFO "fusb300_cxout\n"); + fusb300_ep0out(fusb300); + } + + if (int_grp1 & FUSB300_IGR1_CX_IN_INT) { + printk(KERN_INFO "fusb300_cxin\n"); + fusb300_ep0in(fusb300); + } + + if (int_grp1 & FUSB300_IGR1_INTGRP5) + fusb300_grp5_handler(); + + if (int_grp1 & FUSB300_IGR1_INTGRP4) + fusb300_grp4_handler(); + + if (int_grp1 & FUSB300_IGR1_INTGRP3) + fusb300_grp3_handler(); + + if (int_grp1 & FUSB300_IGR1_INTGRP2) + fusb300_grp2_handler(); + + if (int_grp0) { + for (i = 1; i < FUSB300_MAX_NUM_EP; i++) { + if (int_grp0 & FUSB300_IGR0_EPn_FIFO_INT(i)) { + reg = ioread32(fusb300->reg + + FUSB300_OFFSET_EPSET1(i)); + in = (reg & FUSB300_EPSET1_DIRIN) ? 1 : 0; + if (in) + in_ep_fifo_handler(fusb300->ep[i]); + else + out_ep_fifo_handler(fusb300->ep[i]); + } + } + } + + spin_unlock(&fusb300->lock); + + return IRQ_HANDLED; +} + +static void fusb300_set_u2_timeout(struct fusb300 *fusb300, + u32 time) +{ + u32 reg; + + reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT); + reg &= ~0xff; + reg |= FUSB300_SSCR2_U2TIMEOUT(time); + + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT); +} + +static void fusb300_set_u1_timeout(struct fusb300 *fusb300, + u32 time) +{ + u32 reg; + + reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT); + reg &= ~(0xff << 8); + reg |= FUSB300_SSCR2_U1TIMEOUT(time); + + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT); +} + +static void init_controller(struct fusb300 *fusb300) +{ + u32 reg; + u32 mask = 0; + u32 val = 0; + + /* split on */ + mask = val = FUSB300_AHBBCR_S0_SPLIT_ON | FUSB300_AHBBCR_S1_SPLIT_ON; + reg = ioread32(fusb300->reg + FUSB300_OFFSET_AHBCR); + reg &= ~mask; + reg |= val; + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_AHBCR); + + /* enable high-speed LPM */ + mask = val = FUSB300_HSCR_HS_LPM_PERMIT; + reg = ioread32(fusb300->reg + FUSB300_OFFSET_HSCR); + reg &= ~mask; + reg |= val; + iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR); + + /*set u1 u2 timmer*/ + fusb300_set_u2_timeout(fusb300, 0xff); + fusb300_set_u1_timeout(fusb300, 0xff); + + /* enable all grp1 interrupt */ + iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1); +} +/*------------------------------------------------------------------------*/ +static struct fusb300 *the_controller; + +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) +{ + struct fusb300 *fusb300 = the_controller; + int retval; + + if (!driver + || driver->speed < USB_SPEED_FULL + || !bind + || !driver->setup) + return -EINVAL; + + if (!fusb300) + return -ENODEV; + + if (fusb300->driver) + return -EBUSY; + + /* hook up the driver */ + driver->driver.bus = NULL; + fusb300->driver = driver; + fusb300->gadget.dev.driver = &driver->driver; + + retval = device_add(&fusb300->gadget.dev); + if (retval) { + pr_err("device_add error (%d)\n", retval); + goto error; + } + + retval = bind(&fusb300->gadget); + if (retval) { + pr_err("bind to driver error (%d)\n", retval); + device_del(&fusb300->gadget.dev); + goto error; + } + + return 0; + +error: + fusb300->driver = NULL; + fusb300->gadget.dev.driver = NULL; + + return retval; +} +EXPORT_SYMBOL(usb_gadget_probe_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct fusb300 *fusb300 = the_controller; + + if (driver != fusb300->driver || !driver->unbind) + return -EINVAL; + + driver->unbind(&fusb300->gadget); + fusb300->gadget.dev.driver = NULL; + + init_controller(fusb300); + device_del(&fusb300->gadget.dev); + fusb300->driver = NULL; + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); +/*--------------------------------------------------------------------------*/ + +static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active) +{ + return 0; +} + +static struct usb_gadget_ops fusb300_gadget_ops = { + .pullup = fusb300_udc_pullup, +}; + +static int __exit fusb300_remove(struct platform_device *pdev) +{ + struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev); + + iounmap(fusb300->reg); + free_irq(platform_get_irq(pdev, 0), fusb300); + + fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); + kfree(fusb300); + + return 0; +} + +static int __init fusb300_probe(struct platform_device *pdev) +{ + struct resource *res, *ires, *ires1; + void __iomem *reg = NULL; + struct fusb300 *fusb300 = NULL; + struct fusb300_ep *_ep[FUSB300_MAX_NUM_EP]; + int ret = 0; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + pr_err("platform_get_resource error.\n"); + goto clean_up; + } + + ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!ires) { + ret = -ENODEV; + dev_err(&pdev->dev, + "platform_get_resource IORESOURCE_IRQ error.\n"); + goto clean_up; + } + + ires1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!ires1) { + ret = -ENODEV; + dev_err(&pdev->dev, + "platform_get_resource IORESOURCE_IRQ 1 error.\n"); + goto clean_up; + } + + reg = ioremap(res->start, resource_size(res)); + if (reg == NULL) { + ret = -ENOMEM; + pr_err("ioremap error.\n"); + goto clean_up; + } + + /* initialize udc */ + fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL); + if (fusb300 == NULL) { + pr_err("kzalloc error\n"); + goto clean_up; + } + + for (i = 0; i < FUSB300_MAX_NUM_EP; i++) { + _ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL); + if (_ep[i] == NULL) { + pr_err("_ep kzalloc error\n"); + goto clean_up; + } + fusb300->ep[i] = _ep[i]; + } + + spin_lock_init(&fusb300->lock); + + dev_set_drvdata(&pdev->dev, fusb300); + + fusb300->gadget.ops = &fusb300_gadget_ops; + + device_initialize(&fusb300->gadget.dev); + + dev_set_name(&fusb300->gadget.dev, "gadget"); + + fusb300->gadget.is_dualspeed = 1; + fusb300->gadget.dev.parent = &pdev->dev; + fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask; + fusb300->gadget.dev.release = pdev->dev.release; + fusb300->gadget.name = udc_name; + fusb300->reg = reg; + + ret = request_irq(ires->start, fusb300_irq, IRQF_DISABLED | IRQF_SHARED, + udc_name, fusb300); + if (ret < 0) { + pr_err("request_irq error (%d)\n", ret); + goto clean_up; + } + + ret = request_irq(ires1->start, fusb300_irq, + IRQF_DISABLED | IRQF_SHARED, udc_name, fusb300); + if (ret < 0) { + pr_err("request_irq1 error (%d)\n", ret); + goto clean_up; + } + + INIT_LIST_HEAD(&fusb300->gadget.ep_list); + + for (i = 0; i < FUSB300_MAX_NUM_EP ; i++) { + struct fusb300_ep *ep = fusb300->ep[i]; + + if (i != 0) { + INIT_LIST_HEAD(&fusb300->ep[i]->ep.ep_list); + list_add_tail(&fusb300->ep[i]->ep.ep_list, + &fusb300->gadget.ep_list); + } + ep->fusb300 = fusb300; + INIT_LIST_HEAD(&ep->queue); + ep->ep.name = fusb300_ep_name[i]; + ep->ep.ops = &fusb300_ep_ops; + ep->ep.maxpacket = HS_BULK_MAX_PACKET_SIZE; + } + fusb300->ep[0]->ep.maxpacket = HS_CTL_MAX_PACKET_SIZE; + fusb300->ep[0]->epnum = 0; + fusb300->gadget.ep0 = &fusb300->ep[0]->ep; + INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list); + + the_controller = fusb300; + + fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep, + GFP_KERNEL); + if (fusb300->ep0_req == NULL) + goto clean_up3; + + init_controller(fusb300); + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); + + return 0; + +clean_up3: + free_irq(ires->start, fusb300); + +clean_up: + if (fusb300) { + if (fusb300->ep0_req) + fusb300_free_request(&fusb300->ep[0]->ep, + fusb300->ep0_req); + kfree(fusb300); + } + if (reg) + iounmap(reg); + + return ret; +} + +static struct platform_driver fusb300_driver = { + .remove = __exit_p(fusb300_remove), + .driver = { + .name = (char *) udc_name, + .owner = THIS_MODULE, + }, +}; + +static int __init fusb300_udc_init(void) +{ + return platform_driver_probe(&fusb300_driver, fusb300_probe); +} + +module_init(fusb300_udc_init); + +static void __exit fusb300_udc_cleanup(void) +{ + platform_driver_unregister(&fusb300_driver); +} +module_exit(fusb300_udc_cleanup); diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h new file mode 100644 index 000000000000..f51aa2ef1f90 --- /dev/null +++ b/drivers/usb/gadget/fusb300_udc.h @@ -0,0 +1,687 @@ +/* + * Fusb300 UDC (USB gadget) + * + * Copyright (C) 2010 Faraday Technology Corp. + * + * Author : Yuan-hsin Chen <yhchen@faraday-tech.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#ifndef __FUSB300_UDC_H__ +#define __FUSB300_UDC_H_ + +#include <linux/kernel.h> + +#define FUSB300_OFFSET_GCR 0x00 +#define FUSB300_OFFSET_GTM 0x04 +#define FUSB300_OFFSET_DAR 0x08 +#define FUSB300_OFFSET_CSR 0x0C +#define FUSB300_OFFSET_CXPORT 0x10 +#define FUSB300_OFFSET_EPSET0(n) (0x20 + (n - 1) * 0x30) +#define FUSB300_OFFSET_EPSET1(n) (0x24 + (n - 1) * 0x30) +#define FUSB300_OFFSET_EPSET2(n) (0x28 + (n - 1) * 0x30) +#define FUSB300_OFFSET_EPFFR(n) (0x2c + (n - 1) * 0x30) +#define FUSB300_OFFSET_EPSTRID(n) (0x40 + (n - 1) * 0x30) +#define FUSB300_OFFSET_HSPTM 0x300 +#define FUSB300_OFFSET_HSCR 0x304 +#define FUSB300_OFFSET_SSCR0 0x308 +#define FUSB300_OFFSET_SSCR1 0x30C +#define FUSB300_OFFSET_TT 0x310 +#define FUSB300_OFFSET_DEVNOTF 0x314 +#define FUSB300_OFFSET_DNC1 0x318 +#define FUSB300_OFFSET_CS 0x31C +#define FUSB300_OFFSET_SOF 0x324 +#define FUSB300_OFFSET_EFCS 0x328 +#define FUSB300_OFFSET_IGR0 0x400 +#define FUSB300_OFFSET_IGR1 0x404 +#define FUSB300_OFFSET_IGR2 0x408 +#define FUSB300_OFFSET_IGR3 0x40C +#define FUSB300_OFFSET_IGR4 0x410 +#define FUSB300_OFFSET_IGR5 0x414 +#define FUSB300_OFFSET_IGER0 0x420 +#define FUSB300_OFFSET_IGER1 0x424 +#define FUSB300_OFFSET_IGER2 0x428 +#define FUSB300_OFFSET_IGER3 0x42C +#define FUSB300_OFFSET_IGER4 0x430 +#define FUSB300_OFFSET_IGER5 0x434 +#define FUSB300_OFFSET_DMAHMER 0x500 +#define FUSB300_OFFSET_EPPRDRDY 0x504 +#define FUSB300_OFFSET_DMAEPMR 0x508 +#define FUSB300_OFFSET_DMAENR 0x50C +#define FUSB300_OFFSET_DMAAPR 0x510 +#define FUSB300_OFFSET_AHBCR 0x514 +#define FUSB300_OFFSET_EPPRD_W0(n) (0x520 + (n - 1) * 0x10) +#define FUSB300_OFFSET_EPPRD_W1(n) (0x524 + (n - 1) * 0x10) +#define FUSB300_OFFSET_EPPRD_W2(n) (0x528 + (n - 1) * 0x10) +#define FUSB300_OFFSET_EPRD_PTR(n) (0x52C + (n - 1) * 0x10) +#define FUSB300_OFFSET_BUFDBG_START 0x800 +#define FUSB300_OFFSET_BUFDBG_END 0xBFC +#define FUSB300_OFFSET_EPPORT(n) (0x1010 + (n - 1) * 0x10) + +/* + * * Global Control Register (offset = 000H) + * */ +#define FUSB300_GCR_SF_RST (1 << 8) +#define FUSB300_GCR_VBUS_STATUS (1 << 7) +#define FUSB300_GCR_FORCE_HS_SUSP (1 << 6) +#define FUSB300_GCR_SYNC_FIFO1_CLR (1 << 5) +#define FUSB300_GCR_SYNC_FIFO0_CLR (1 << 4) +#define FUSB300_GCR_FIFOCLR (1 << 3) +#define FUSB300_GCR_GLINTEN (1 << 2) +#define FUSB300_GCR_DEVEN_FS 0x3 +#define FUSB300_GCR_DEVEN_HS 0x2 +#define FUSB300_GCR_DEVEN_SS 0x1 +#define FUSB300_GCR_DEVDIS 0x0 +#define FUSB300_GCR_DEVEN_MSK 0x3 + + +/* + * *Global Test Mode (offset = 004H) + * */ +#define FUSB300_GTM_TST_DIS_SOFGEN (1 << 16) +#define FUSB300_GTM_TST_CUR_EP_ENTRY(n) ((n & 0xF) << 12) +#define FUSB300_GTM_TST_EP_ENTRY(n) ((n & 0xF) << 8) +#define FUSB300_GTM_TST_EP_NUM(n) ((n & 0xF) << 4) +#define FUSB300_GTM_TST_FIFO_DEG (1 << 1) +#define FUSB300_GTM_TSTMODE (1 << 0) + +/* + * * Device Address Register (offset = 008H) + * */ +#define FUSB300_DAR_SETCONFG (1 << 7) +#define FUSB300_DAR_DRVADDR(x) (x & 0x7F) +#define FUSB300_DAR_DRVADDR_MSK 0x7F + +/* + * *Control Transfer Configuration and Status Register + * (CX_Config_Status, offset = 00CH) + * */ +#define FUSB300_CSR_LEN(x) ((x & 0xFFFF) << 8) +#define FUSB300_CSR_LEN_MSK (0xFFFF << 8) +#define FUSB300_CSR_EMP (1 << 4) +#define FUSB300_CSR_FUL (1 << 3) +#define FUSB300_CSR_CLR (1 << 2) +#define FUSB300_CSR_STL (1 << 1) +#define FUSB300_CSR_DONE (1 << 0) + +/* + * * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 ) + * */ +#define FUSB300_EPSET0_CLRSEQNUM (1 << 2) +#define FUSB300_EPSET0_EPn_TX0BYTE (1 << 1) +#define FUSB300_EPSET0_STL (1 << 0) + +/* + * * EPn Setting 1 (EPn_SET1, offset = 024H+(n-1)*30H, n=1~15) + * */ +#define FUSB300_EPSET1_START_ENTRY(x) ((x & 0xFF) << 24) +#define FUSB300_EPSET1_START_ENTRY_MSK (0xFF << 24) +#define FUSB300_EPSET1_FIFOENTRY(x) ((x & 0x1F) << 12) +#define FUSB300_EPSET1_FIFOENTRY_MSK (0x1f << 12) +#define FUSB300_EPSET1_INTERVAL(x) ((x & 0x7) << 6) +#define FUSB300_EPSET1_BWNUM(x) ((x & 0x3) << 4) +#define FUSB300_EPSET1_TYPEISO (1 << 2) +#define FUSB300_EPSET1_TYPEBLK (2 << 2) +#define FUSB300_EPSET1_TYPEINT (3 << 2) +#define FUSB300_EPSET1_TYPE(x) ((x & 0x3) << 2) +#define FUSB300_EPSET1_TYPE_MSK (0x3 << 2) +#define FUSB300_EPSET1_DIROUT (0 << 1) +#define FUSB300_EPSET1_DIRIN (1 << 1) +#define FUSB300_EPSET1_DIR(x) ((x & 0x1) << 1) +#define FUSB300_EPSET1_DIRIN (1 << 1) +#define FUSB300_EPSET1_DIR_MSK ((0x1) << 1) +#define FUSB300_EPSET1_ACTDIS 0 +#define FUSB300_EPSET1_ACTEN 1 + +/* + * *EPn Setting 2 (EPn_SET2, offset = 028H+(n-1)*30H, n=1~15) + * */ +#define FUSB300_EPSET2_ADDROFS(x) ((x & 0x7FFF) << 16) +#define FUSB300_EPSET2_ADDROFS_MSK (0x7fff << 16) +#define FUSB300_EPSET2_MPS(x) (x & 0x7FF) +#define FUSB300_EPSET2_MPS_MSK 0x7FF + +/* + * * EPn FIFO Register (offset = 2cH+(n-1)*30H) + * */ +#define FUSB300_FFR_RST (1 << 31) +#define FUSB300_FF_FUL (1 << 30) +#define FUSB300_FF_EMPTY (1 << 29) +#define FUSB300_FFR_BYCNT 0x1FFFF + +/* + * *EPn Stream ID (EPn_STR_ID, offset = 040H+(n-1)*30H, n=1~15) + * */ +#define FUSB300_STRID_STREN (1 << 16) +#define FUSB300_STRID_STRID(x) (x & 0xFFFF) + +/* + * *HS PHY Test Mode (offset = 300H) + * */ +#define FUSB300_HSPTM_TSTPKDONE (1 << 4) +#define FUSB300_HSPTM_TSTPKT (1 << 3) +#define FUSB300_HSPTM_TSTSET0NAK (1 << 2) +#define FUSB300_HSPTM_TSTKSTA (1 << 1) +#define FUSB300_HSPTM_TSTJSTA (1 << 0) + +/* + * *HS Control Register (offset = 304H) + * */ +#define FUSB300_HSCR_HS_LPM_PERMIT (1 << 8) +#define FUSB300_HSCR_HS_LPM_RMWKUP (1 << 7) +#define FUSB300_HSCR_CAP_LPM_RMWKUP (1 << 6) +#define FUSB300_HSCR_HS_GOSUSP (1 << 5) +#define FUSB300_HSCR_HS_GORMWKU (1 << 4) +#define FUSB300_HSCR_CAP_RMWKUP (1 << 3) +#define FUSB300_HSCR_IDLECNT_0MS 0 +#define FUSB300_HSCR_IDLECNT_1MS 1 +#define FUSB300_HSCR_IDLECNT_2MS 2 +#define FUSB300_HSCR_IDLECNT_3MS 3 +#define FUSB300_HSCR_IDLECNT_4MS 4 +#define FUSB300_HSCR_IDLECNT_5MS 5 +#define FUSB300_HSCR_IDLECNT_6MS 6 +#define FUSB300_HSCR_IDLECNT_7MS 7 + +/* + * * SS Controller Register 0 (offset = 308H) + * */ +#define FUSB300_SSCR0_MAX_INTERVAL(x) ((x & 0x7) << 4) +#define FUSB300_SSCR0_U2_FUN_EN (1 << 1) +#define FUSB300_SSCR0_U1_FUN_EN (1 << 0) + +/* + * * SS Controller Register 1 (offset = 30CH) + * */ +#define FUSB300_SSCR1_GO_U3_DONE (1 << 8) +#define FUSB300_SSCR1_TXDEEMPH_LEVEL (1 << 7) +#define FUSB300_SSCR1_DIS_SCRMB (1 << 6) +#define FUSB300_SSCR1_FORCE_RECOVERY (1 << 5) +#define FUSB300_SSCR1_U3_WAKEUP_EN (1 << 4) +#define FUSB300_SSCR1_U2_EXIT_EN (1 << 3) +#define FUSB300_SSCR1_U1_EXIT_EN (1 << 2) +#define FUSB300_SSCR1_U2_ENTRY_EN (1 << 1) +#define FUSB300_SSCR1_U1_ENTRY_EN (1 << 0) + +/* + * *SS Controller Register 2 (offset = 310H) + * */ +#define FUSB300_SSCR2_SS_TX_SWING (1 << 25) +#define FUSB300_SSCR2_FORCE_LINKPM_ACCEPT (1 << 24) +#define FUSB300_SSCR2_U2_INACT_TIMEOUT(x) ((x & 0xFF) << 16) +#define FUSB300_SSCR2_U1TIMEOUT(x) ((x & 0xFF) << 8) +#define FUSB300_SSCR2_U2TIMEOUT(x) (x & 0xFF) + +/* + * *SS Device Notification Control (DEV_NOTF, offset = 314H) + * */ +#define FUSB300_DEVNOTF_CONTEXT0(x) ((x & 0xFFFFFF) << 8) +#define FUSB300_DEVNOTF_TYPE_DIS 0 +#define FUSB300_DEVNOTF_TYPE_FUNCWAKE 1 +#define FUSB300_DEVNOTF_TYPE_LTM 2 +#define FUSB300_DEVNOTF_TYPE_BUSINT_ADJMSG 3 + +/* + * *BFM Arbiter Priority Register (BFM_ARB offset = 31CH) + * */ +#define FUSB300_BFMARB_ARB_M1 (1 << 3) +#define FUSB300_BFMARB_ARB_M0 (1 << 2) +#define FUSB300_BFMARB_ARB_S1 (1 << 1) +#define FUSB300_BFMARB_ARB_S0 1 + +/* + * *Vendor Specific IO Control Register (offset = 320H) + * */ +#define FUSB300_VSIC_VCTLOAD_N (1 << 8) +#define FUSB300_VSIC_VCTL(x) (x & 0x3F) + +/* + * *SOF Mask Timer (offset = 324H) + * */ +#define FUSB300_SOF_MASK_TIMER_HS 0x044c +#define FUSB300_SOF_MASK_TIMER_FS 0x2710 + +/* + * *Error Flag and Control Status (offset = 328H) + * */ +#define FUSB300_EFCS_PM_STATE_U3 3 +#define FUSB300_EFCS_PM_STATE_U2 2 +#define FUSB300_EFCS_PM_STATE_U1 1 +#define FUSB300_EFCS_PM_STATE_U0 0 + +/* + * *Interrupt Group 0 Register (offset = 400H) + * */ +#define FUSB300_IGR0_EP15_PRD_INT (1 << 31) +#define FUSB300_IGR0_EP14_PRD_INT (1 << 30) +#define FUSB300_IGR0_EP13_PRD_INT (1 << 29) +#define FUSB300_IGR0_EP12_PRD_INT (1 << 28) +#define FUSB300_IGR0_EP11_PRD_INT (1 << 27) +#define FUSB300_IGR0_EP10_PRD_INT (1 << 26) +#define FUSB300_IGR0_EP9_PRD_INT (1 << 25) +#define FUSB300_IGR0_EP8_PRD_INT (1 << 24) +#define FUSB300_IGR0_EP7_PRD_INT (1 << 23) +#define FUSB300_IGR0_EP6_PRD_INT (1 << 22) +#define FUSB300_IGR0_EP5_PRD_INT (1 << 21) +#define FUSB300_IGR0_EP4_PRD_INT (1 << 20) +#define FUSB300_IGR0_EP3_PRD_INT (1 << 19) +#define FUSB300_IGR0_EP2_PRD_INT (1 << 18) +#define FUSB300_IGR0_EP1_PRD_INT (1 << 17) +#define FUSB300_IGR0_EPn_PRD_INT(n) (1 << (n + 16)) + +#define FUSB300_IGR0_EP15_FIFO_INT (1 << 15) +#define FUSB300_IGR0_EP14_FIFO_INT (1 << 14) +#define FUSB300_IGR0_EP13_FIFO_INT (1 << 13) +#define FUSB300_IGR0_EP12_FIFO_INT (1 << 12) +#define FUSB300_IGR0_EP11_FIFO_INT (1 << 11) +#define FUSB300_IGR0_EP10_FIFO_INT (1 << 10) +#define FUSB300_IGR0_EP9_FIFO_INT (1 << 9) +#define FUSB300_IGR0_EP8_FIFO_INT (1 << 8) +#define FUSB300_IGR0_EP7_FIFO_INT (1 << 7) +#define FUSB300_IGR0_EP6_FIFO_INT (1 << 6) +#define FUSB300_IGR0_EP5_FIFO_INT (1 << 5) +#define FUSB300_IGR0_EP4_FIFO_INT (1 << 4) +#define FUSB300_IGR0_EP3_FIFO_INT (1 << 3) +#define FUSB300_IGR0_EP2_FIFO_INT (1 << 2) +#define FUSB300_IGR0_EP1_FIFO_INT (1 << 1) +#define FUSB300_IGR0_EPn_FIFO_INT(n) (1 << n) + +/* + * *Interrupt Group 1 Register (offset = 404H) + * */ +#define FUSB300_IGR1_INTGRP5 (1 << 31) +#define FUSB300_IGR1_VBUS_CHG_INT (1 << 30) +#define FUSB300_IGR1_SYNF1_EMPTY_INT (1 << 29) +#define FUSB300_IGR1_SYNF0_EMPTY_INT (1 << 28) +#define FUSB300_IGR1_U3_EXIT_FAIL_INT (1 << 27) +#define FUSB300_IGR1_U2_EXIT_FAIL_INT (1 << 26) +#define FUSB300_IGR1_U1_EXIT_FAIL_INT (1 << 25) +#define FUSB300_IGR1_U2_ENTRY_FAIL_INT (1 << 24) +#define FUSB300_IGR1_U1_ENTRY_FAIL_INT (1 << 23) +#define FUSB300_IGR1_U3_EXIT_INT (1 << 22) +#define FUSB300_IGR1_U2_EXIT_INT (1 << 21) +#define FUSB300_IGR1_U1_EXIT_INT (1 << 20) +#define FUSB300_IGR1_U3_ENTRY_INT (1 << 19) +#define FUSB300_IGR1_U2_ENTRY_INT (1 << 18) +#define FUSB300_IGR1_U1_ENTRY_INT (1 << 17) +#define FUSB300_IGR1_HOT_RST_INT (1 << 16) +#define FUSB300_IGR1_WARM_RST_INT (1 << 15) +#define FUSB300_IGR1_RESM_INT (1 << 14) +#define FUSB300_IGR1_SUSP_INT (1 << 13) +#define FUSB300_IGR1_HS_LPM_INT (1 << 12) +#define FUSB300_IGR1_USBRST_INT (1 << 11) +#define FUSB300_IGR1_DEV_MODE_CHG_INT (1 << 9) +#define FUSB300_IGR1_CX_COMABT_INT (1 << 8) +#define FUSB300_IGR1_CX_COMFAIL_INT (1 << 7) +#define FUSB300_IGR1_CX_CMDEND_INT (1 << 6) +#define FUSB300_IGR1_CX_OUT_INT (1 << 5) +#define FUSB300_IGR1_CX_IN_INT (1 << 4) +#define FUSB300_IGR1_CX_SETUP_INT (1 << 3) +#define FUSB300_IGR1_INTGRP4 (1 << 2) +#define FUSB300_IGR1_INTGRP3 (1 << 1) +#define FUSB300_IGR1_INTGRP2 (1 << 0) + +/* + * *Interrupt Group 2 Register (offset = 408H) + * */ +#define FUSB300_IGR2_EP6_STR_ACCEPT_INT (1 << 29) +#define FUSB300_IGR2_EP6_STR_RESUME_INT (1 << 28) +#define FUSB300_IGR2_EP6_STR_REQ_INT (1 << 27) +#define FUSB300_IGR2_EP6_STR_NOTRDY_INT (1 << 26) +#define FUSB300_IGR2_EP6_STR_PRIME_INT (1 << 25) +#define FUSB300_IGR2_EP5_STR_ACCEPT_INT (1 << 24) +#define FUSB300_IGR2_EP5_STR_RESUME_INT (1 << 23) +#define FUSB300_IGR2_EP5_STR_REQ_INT (1 << 22) +#define FUSB300_IGR2_EP5_STR_NOTRDY_INT (1 << 21) +#define FUSB300_IGR2_EP5_STR_PRIME_INT (1 << 20) +#define FUSB300_IGR2_EP4_STR_ACCEPT_INT (1 << 19) +#define FUSB300_IGR2_EP4_STR_RESUME_INT (1 << 18) +#define FUSB300_IGR2_EP4_STR_REQ_INT (1 << 17) +#define FUSB300_IGR2_EP4_STR_NOTRDY_INT (1 << 16) +#define FUSB300_IGR2_EP4_STR_PRIME_INT (1 << 15) +#define FUSB300_IGR2_EP3_STR_ACCEPT_INT (1 << 14) +#define FUSB300_IGR2_EP3_STR_RESUME_INT (1 << 13) +#define FUSB300_IGR2_EP3_STR_REQ_INT (1 << 12) +#define FUSB300_IGR2_EP3_STR_NOTRDY_INT (1 << 11) +#define FUSB300_IGR2_EP3_STR_PRIME_INT (1 << 10) +#define FUSB300_IGR2_EP2_STR_ACCEPT_INT (1 << 9) +#define FUSB300_IGR2_EP2_STR_RESUME_INT (1 << 8) +#define FUSB300_IGR2_EP2_STR_REQ_INT (1 << 7) +#define FUSB300_IGR2_EP2_STR_NOTRDY_INT (1 << 6) +#define FUSB300_IGR2_EP2_STR_PRIME_INT (1 << 5) +#define FUSB300_IGR2_EP1_STR_ACCEPT_INT (1 << 4) +#define FUSB300_IGR2_EP1_STR_RESUME_INT (1 << 3) +#define FUSB300_IGR2_EP1_STR_REQ_INT (1 << 2) +#define FUSB300_IGR2_EP1_STR_NOTRDY_INT (1 << 1) +#define FUSB300_IGR2_EP1_STR_PRIME_INT (1 << 0) + +#define FUSB300_IGR2_EP_STR_ACCEPT_INT(n) (1 << (5 * n - 1)) +#define FUSB300_IGR2_EP_STR_RESUME_INT(n) (1 << (5 * n - 2)) +#define FUSB300_IGR2_EP_STR_REQ_INT(n) (1 << (5 * n - 3)) +#define FUSB300_IGR2_EP_STR_NOTRDY_INT(n) (1 << (5 * n - 4)) +#define FUSB300_IGR2_EP_STR_PRIME_INT(n) (1 << (5 * n - 5)) + +/* + * *Interrupt Group 3 Register (offset = 40CH) + * */ +#define FUSB300_IGR3_EP12_STR_ACCEPT_INT (1 << 29) +#define FUSB300_IGR3_EP12_STR_RESUME_INT (1 << 28) +#define FUSB300_IGR3_EP12_STR_REQ_INT (1 << 27) +#define FUSB300_IGR3_EP12_STR_NOTRDY_INT (1 << 26) +#define FUSB300_IGR3_EP12_STR_PRIME_INT (1 << 25) +#define FUSB300_IGR3_EP11_STR_ACCEPT_INT (1 << 24) +#define FUSB300_IGR3_EP11_STR_RESUME_INT (1 << 23) +#define FUSB300_IGR3_EP11_STR_REQ_INT (1 << 22) +#define FUSB300_IGR3_EP11_STR_NOTRDY_INT (1 << 21) +#define FUSB300_IGR3_EP11_STR_PRIME_INT (1 << 20) +#define FUSB300_IGR3_EP10_STR_ACCEPT_INT (1 << 19) +#define FUSB300_IGR3_EP10_STR_RESUME_INT (1 << 18) +#define FUSB300_IGR3_EP10_STR_REQ_INT (1 << 17) +#define FUSB300_IGR3_EP10_STR_NOTRDY_INT (1 << 16) +#define FUSB300_IGR3_EP10_STR_PRIME_INT (1 << 15) +#define FUSB300_IGR3_EP9_STR_ACCEPT_INT (1 << 14) +#define FUSB300_IGR3_EP9_STR_RESUME_INT (1 << 13) +#define FUSB300_IGR3_EP9_STR_REQ_INT (1 << 12) +#define FUSB300_IGR3_EP9_STR_NOTRDY_INT (1 << 11) +#define FUSB300_IGR3_EP9_STR_PRIME_INT (1 << 10) +#define FUSB300_IGR3_EP8_STR_ACCEPT_INT (1 << 9) +#define FUSB300_IGR3_EP8_STR_RESUME_INT (1 << 8) +#define FUSB300_IGR3_EP8_STR_REQ_INT (1 << 7) +#define FUSB300_IGR3_EP8_STR_NOTRDY_INT (1 << 6) +#define FUSB300_IGR3_EP8_STR_PRIME_INT (1 << 5) +#define FUSB300_IGR3_EP7_STR_ACCEPT_INT (1 << 4) +#define FUSB300_IGR3_EP7_STR_RESUME_INT (1 << 3) +#define FUSB300_IGR3_EP7_STR_REQ_INT (1 << 2) +#define FUSB300_IGR3_EP7_STR_NOTRDY_INT (1 << 1) +#define FUSB300_IGR3_EP7_STR_PRIME_INT (1 << 0) + +#define FUSB300_IGR3_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) +#define FUSB300_IGR3_EP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) +#define FUSB300_IGR3_EP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) +#define FUSB300_IGR3_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) +#define FUSB300_IGR3_EP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) + +/* + * *Interrupt Group 4 Register (offset = 410H) + * */ +#define FUSB300_IGR4_EP15_RX0_INT (1 << 31) +#define FUSB300_IGR4_EP14_RX0_INT (1 << 30) +#define FUSB300_IGR4_EP13_RX0_INT (1 << 29) +#define FUSB300_IGR4_EP12_RX0_INT (1 << 28) +#define FUSB300_IGR4_EP11_RX0_INT (1 << 27) +#define FUSB300_IGR4_EP10_RX0_INT (1 << 26) +#define FUSB300_IGR4_EP9_RX0_INT (1 << 25) +#define FUSB300_IGR4_EP8_RX0_INT (1 << 24) +#define FUSB300_IGR4_EP7_RX0_INT (1 << 23) +#define FUSB300_IGR4_EP6_RX0_INT (1 << 22) +#define FUSB300_IGR4_EP5_RX0_INT (1 << 21) +#define FUSB300_IGR4_EP4_RX0_INT (1 << 20) +#define FUSB300_IGR4_EP3_RX0_INT (1 << 19) +#define FUSB300_IGR4_EP2_RX0_INT (1 << 18) +#define FUSB300_IGR4_EP1_RX0_INT (1 << 17) +#define FUSB300_IGR4_EP_RX0_INT(x) (1 << (x + 16)) +#define FUSB300_IGR4_EP15_STR_ACCEPT_INT (1 << 14) +#define FUSB300_IGR4_EP15_STR_RESUME_INT (1 << 13) +#define FUSB300_IGR4_EP15_STR_REQ_INT (1 << 12) +#define FUSB300_IGR4_EP15_STR_NOTRDY_INT (1 << 11) +#define FUSB300_IGR4_EP15_STR_PRIME_INT (1 << 10) +#define FUSB300_IGR4_EP14_STR_ACCEPT_INT (1 << 9) +#define FUSB300_IGR4_EP14_STR_RESUME_INT (1 << 8) +#define FUSB300_IGR4_EP14_STR_REQ_INT (1 << 7) +#define FUSB300_IGR4_EP14_STR_NOTRDY_INT (1 << 6) +#define FUSB300_IGR4_EP14_STR_PRIME_INT (1 << 5) +#define FUSB300_IGR4_EP13_STR_ACCEPT_INT (1 << 4) +#define FUSB300_IGR4_EP13_STR_RESUME_INT (1 << 3) +#define FUSB300_IGR4_EP13_STR_REQ_INT (1 << 2) +#define FUSB300_IGR4_EP13_STR_NOTRDY_INT (1 << 1) +#define FUSB300_IGR4_EP13_STR_PRIME_INT (1 << 0) + +#define FUSB300_IGR4_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 12) - 1)) +#define FUSB300_IGR4_EP_STR_RESUME_INT(n) (1 << (5 * (n - 12) - 2)) +#define FUSB300_IGR4_EP_STR_REQ_INT(n) (1 << (5 * (n - 12) - 3)) +#define FUSB300_IGR4_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 12) - 4)) +#define FUSB300_IGR4_EP_STR_PRIME_INT(n) (1 << (5 * (n - 12) - 5)) + +/* + * *Interrupt Group 5 Register (offset = 414H) + * */ +#define FUSB300_IGR5_EP_STL_INT(n) (1 << n) + +/* + * *Interrupt Enable Group 0 Register (offset = 420H) + * */ +#define FUSB300_IGER0_EEP15_PRD_INT (1 << 31) +#define FUSB300_IGER0_EEP14_PRD_INT (1 << 30) +#define FUSB300_IGER0_EEP13_PRD_INT (1 << 29) +#define FUSB300_IGER0_EEP12_PRD_INT (1 << 28) +#define FUSB300_IGER0_EEP11_PRD_INT (1 << 27) +#define FUSB300_IGER0_EEP10_PRD_INT (1 << 26) +#define FUSB300_IGER0_EEP9_PRD_INT (1 << 25) +#define FUSB300_IGER0_EP8_PRD_INT (1 << 24) +#define FUSB300_IGER0_EEP7_PRD_INT (1 << 23) +#define FUSB300_IGER0_EEP6_PRD_INT (1 << 22) +#define FUSB300_IGER0_EEP5_PRD_INT (1 << 21) +#define FUSB300_IGER0_EEP4_PRD_INT (1 << 20) +#define FUSB300_IGER0_EEP3_PRD_INT (1 << 19) +#define FUSB300_IGER0_EEP2_PRD_INT (1 << 18) +#define FUSB300_IGER0_EEP1_PRD_INT (1 << 17) +#define FUSB300_IGER0_EEPn_PRD_INT(n) (1 << (n + 16)) + +#define FUSB300_IGER0_EEP15_FIFO_INT (1 << 15) +#define FUSB300_IGER0_EEP14_FIFO_INT (1 << 14) +#define FUSB300_IGER0_EEP13_FIFO_INT (1 << 13) +#define FUSB300_IGER0_EEP12_FIFO_INT (1 << 12) +#define FUSB300_IGER0_EEP11_FIFO_INT (1 << 11) +#define FUSB300_IGER0_EEP10_FIFO_INT (1 << 10) +#define FUSB300_IGER0_EEP9_FIFO_INT (1 << 9) +#define FUSB300_IGER0_EEP8_FIFO_INT (1 << 8) +#define FUSB300_IGER0_EEP7_FIFO_INT (1 << 7) +#define FUSB300_IGER0_EEP6_FIFO_INT (1 << 6) +#define FUSB300_IGER0_EEP5_FIFO_INT (1 << 5) +#define FUSB300_IGER0_EEP4_FIFO_INT (1 << 4) +#define FUSB300_IGER0_EEP3_FIFO_INT (1 << 3) +#define FUSB300_IGER0_EEP2_FIFO_INT (1 << 2) +#define FUSB300_IGER0_EEP1_FIFO_INT (1 << 1) +#define FUSB300_IGER0_EEPn_FIFO_INT(n) (1 << n) + +/* + * *Interrupt Enable Group 1 Register (offset = 424H) + * */ +#define FUSB300_IGER1_EINT_GRP5 (1 << 31) +#define FUSB300_IGER1_VBUS_CHG_INT (1 << 30) +#define FUSB300_IGER1_SYNF1_EMPTY_INT (1 << 29) +#define FUSB300_IGER1_SYNF0_EMPTY_INT (1 << 28) +#define FUSB300_IGER1_U3_EXIT_FAIL_INT (1 << 27) +#define FUSB300_IGER1_U2_EXIT_FAIL_INT (1 << 26) +#define FUSB300_IGER1_U1_EXIT_FAIL_INT (1 << 25) +#define FUSB300_IGER1_U2_ENTRY_FAIL_INT (1 << 24) +#define FUSB300_IGER1_U1_ENTRY_FAIL_INT (1 << 23) +#define FUSB300_IGER1_U3_EXIT_INT (1 << 22) +#define FUSB300_IGER1_U2_EXIT_INT (1 << 21) +#define FUSB300_IGER1_U1_EXIT_INT (1 << 20) +#define FUSB300_IGER1_U3_ENTRY_INT (1 << 19) +#define FUSB300_IGER1_U2_ENTRY_INT (1 << 18) +#define FUSB300_IGER1_U1_ENTRY_INT (1 << 17) +#define FUSB300_IGER1_HOT_RST_INT (1 << 16) +#define FUSB300_IGER1_WARM_RST_INT (1 << 15) +#define FUSB300_IGER1_RESM_INT (1 << 14) +#define FUSB300_IGER1_SUSP_INT (1 << 13) +#define FUSB300_IGER1_LPM_INT (1 << 12) +#define FUSB300_IGER1_HS_RST_INT (1 << 11) +#define FUSB300_IGER1_EDEV_MODE_CHG_INT (1 << 9) +#define FUSB300_IGER1_CX_COMABT_INT (1 << 8) +#define FUSB300_IGER1_CX_COMFAIL_INT (1 << 7) +#define FUSB300_IGER1_CX_CMDEND_INT (1 << 6) +#define FUSB300_IGER1_CX_OUT_INT (1 << 5) +#define FUSB300_IGER1_CX_IN_INT (1 << 4) +#define FUSB300_IGER1_CX_SETUP_INT (1 << 3) +#define FUSB300_IGER1_INTGRP4 (1 << 2) +#define FUSB300_IGER1_INTGRP3 (1 << 1) +#define FUSB300_IGER1_INTGRP2 (1 << 0) + +/* + * *Interrupt Enable Group 2 Register (offset = 428H) + * */ +#define FUSB300_IGER2_EEP_STR_ACCEPT_INT(n) (1 << (5 * n - 1)) +#define FUSB300_IGER2_EEP_STR_RESUME_INT(n) (1 << (5 * n - 2)) +#define FUSB300_IGER2_EEP_STR_REQ_INT(n) (1 << (5 * n - 3)) +#define FUSB300_IGER2_EEP_STR_NOTRDY_INT(n) (1 << (5 * n - 4)) +#define FUSB300_IGER2_EEP_STR_PRIME_INT(n) (1 << (5 * n - 5)) + +/* + * *Interrupt Enable Group 3 Register (offset = 42CH) + * */ + +#define FUSB300_IGER3_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) +#define FUSB300_IGER3_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) +#define FUSB300_IGER3_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) +#define FUSB300_IGER3_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) +#define FUSB300_IGER3_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) + +/* + * *Interrupt Enable Group 4 Register (offset = 430H) + * */ + +#define FUSB300_IGER4_EEP_RX0_INT(n) (1 << (n + 16)) +#define FUSB300_IGER4_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) +#define FUSB300_IGER4_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) +#define FUSB300_IGER4_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) +#define FUSB300_IGER4_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) +#define FUSB300_IGER4_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) + +/* EP PRD Ready (EP_PRD_RDY, offset = 504H) */ + +#define FUSB300_EPPRDR_EP15_PRD_RDY (1 << 15) +#define FUSB300_EPPRDR_EP14_PRD_RDY (1 << 14) +#define FUSB300_EPPRDR_EP13_PRD_RDY (1 << 13) +#define FUSB300_EPPRDR_EP12_PRD_RDY (1 << 12) +#define FUSB300_EPPRDR_EP11_PRD_RDY (1 << 11) +#define FUSB300_EPPRDR_EP10_PRD_RDY (1 << 10) +#define FUSB300_EPPRDR_EP9_PRD_RDY (1 << 9) +#define FUSB300_EPPRDR_EP8_PRD_RDY (1 << 8) +#define FUSB300_EPPRDR_EP7_PRD_RDY (1 << 7) +#define FUSB300_EPPRDR_EP6_PRD_RDY (1 << 6) +#define FUSB300_EPPRDR_EP5_PRD_RDY (1 << 5) +#define FUSB300_EPPRDR_EP4_PRD_RDY (1 << 4) +#define FUSB300_EPPRDR_EP3_PRD_RDY (1 << 3) +#define FUSB300_EPPRDR_EP2_PRD_RDY (1 << 2) +#define FUSB300_EPPRDR_EP1_PRD_RDY (1 << 1) +#define FUSB300_EPPRDR_EP_PRD_RDY(n) (1 << n) + +/* AHB Bus Control Register (offset = 514H) */ +#define FUSB300_AHBBCR_S1_SPLIT_ON (1 << 17) +#define FUSB300_AHBBCR_S0_SPLIT_ON (1 << 16) +#define FUSB300_AHBBCR_S1_1entry (0 << 12) +#define FUSB300_AHBBCR_S1_4entry (3 << 12) +#define FUSB300_AHBBCR_S1_8entry (5 << 12) +#define FUSB300_AHBBCR_S1_16entry (7 << 12) +#define FUSB300_AHBBCR_S0_1entry (0 << 8) +#define FUSB300_AHBBCR_S0_4entry (3 << 8) +#define FUSB300_AHBBCR_S0_8entry (5 << 8) +#define FUSB300_AHBBCR_S0_16entry (7 << 8) +#define FUSB300_AHBBCR_M1_BURST_SINGLE (0 << 4) +#define FUSB300_AHBBCR_M1_BURST_INCR (1 << 4) +#define FUSB300_AHBBCR_M1_BURST_INCR4 (3 << 4) +#define FUSB300_AHBBCR_M1_BURST_INCR8 (5 << 4) +#define FUSB300_AHBBCR_M1_BURST_INCR16 (7 << 4) +#define FUSB300_AHBBCR_M0_BURST_SINGLE 0 +#define FUSB300_AHBBCR_M0_BURST_INCR 1 +#define FUSB300_AHBBCR_M0_BURST_INCR4 3 +#define FUSB300_AHBBCR_M0_BURST_INCR8 5 +#define FUSB300_AHBBCR_M0_BURST_INCR16 7 +#define FUSB300_IGER5_EEP_STL_INT(n) (1 << n) + +/* WORD 0 Data Structure of PRD Table */ +#define FUSB300_EPPRD0_M (1 << 30) +#define FUSB300_EPPRD0_O (1 << 29) +/* The finished prd */ +#define FUSB300_EPPRD0_F (1 << 28) +#define FUSB300_EPPRD0_I (1 << 27) +#define FUSB300_EPPRD0_A (1 << 26) +/* To decide HW point to first prd at next time */ +#define FUSB300_EPPRD0_L (1 << 25) +#define FUSB300_EPPRD0_H (1 << 24) +#define FUSB300_EPPRD0_BTC(n) (n & 0xFFFFFF) + +/*----------------------------------------------------------------------*/ +#define FUSB300_MAX_NUM_EP 16 + +#define FUSB300_FIFO_ENTRY_NUM 8 +#define FUSB300_MAX_FIFO_ENTRY 8 + +#define SS_CTL_MAX_PACKET_SIZE 0x200 +#define SS_BULK_MAX_PACKET_SIZE 0x400 +#define SS_INT_MAX_PACKET_SIZE 0x400 +#define SS_ISO_MAX_PACKET_SIZE 0x400 + +#define HS_BULK_MAX_PACKET_SIZE 0x200 +#define HS_CTL_MAX_PACKET_SIZE 0x40 +#define HS_INT_MAX_PACKET_SIZE 0x400 +#define HS_ISO_MAX_PACKET_SIZE 0x400 + +struct fusb300_ep_info { + u8 epnum; + u8 type; + u8 interval; + u8 dir_in; + u16 maxpacket; + u16 addrofs; + u16 bw_num; +}; + +struct fusb300_request { + + struct usb_request req; + struct list_head queue; +}; + + +struct fusb300_ep { + struct usb_ep ep; + struct fusb300 *fusb300; + + struct list_head queue; + unsigned stall:1; + unsigned wedged:1; + unsigned use_dma:1; + + unsigned char epnum; + unsigned char type; + const struct usb_endpoint_descriptor *desc; +}; + +struct fusb300 { + spinlock_t lock; + void __iomem *reg; + + unsigned long irq_trigger; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + + struct fusb300_ep *ep[FUSB300_MAX_NUM_EP]; + + struct usb_request *ep0_req; /* for internal request */ + __le16 ep0_data; + u32 ep0_length; /* for internal request */ + u8 ep0_dir; /* 0/0x80 out/in */ + + u8 fifo_entry_num; /* next start fifo entry */ + u32 addrofs; /* next fifo address offset */ + u8 reenum; /* if re-enumeration */ +}; + +#endif diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 51b19f3027e7..084aa080a2d5 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -258,7 +258,7 @@ static int pipe_buffer_setting(struct m66592 *m66592, break; case M66592_BULK: /* isochronous pipes may be used as bulk pipes */ - if (info->pipe > M66592_BASE_PIPENUM_BULK) + if (info->pipe >= M66592_BASE_PIPENUM_BULK) bufnum = info->pipe - M66592_BASE_PIPENUM_BULK; else bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index b120dbb64d0f..3e4b35e50c24 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -367,7 +367,6 @@ struct pch_udc_dev { static const char ep0_string[] = "ep0in"; static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */ struct pch_udc_dev *pch_udc; /* pointer to device object */ - static int speed_fs; module_param_named(speed_fs, speed_fs, bool, S_IRUGO); MODULE_PARM_DESC(speed_fs, "true for Full speed operation"); @@ -383,6 +382,8 @@ MODULE_PARM_DESC(speed_fs, "true for Full speed operation"); * @dma_mapped: DMA memory mapped for request * @dma_done: DMA completed for request * @chain_len: chain length + * @buf: Buffer memory for align adjustment + * @dma: DMA memory for align adjustment */ struct pch_udc_request { struct usb_request req; @@ -394,6 +395,8 @@ struct pch_udc_request { dma_mapped:1, dma_done:1; unsigned chain_len; + void *buf; + dma_addr_t dma; }; static inline u32 pch_udc_readl(struct pch_udc_dev *dev, unsigned long reg) @@ -615,7 +618,7 @@ static inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep *ep, /** * pch_udc_ep_set_bufsz() - Set the maximum packet size for the endpoint * @ep: Reference to structure of type pch_udc_ep_regs - * @buf_size: The buffer size + * @buf_size: The buffer word size */ static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep, u32 buf_size, u32 ep_in) @@ -635,7 +638,7 @@ static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep, /** * pch_udc_ep_set_maxpkt() - Set the Max packet size for the endpoint * @ep: Reference to structure of type pch_udc_ep_regs - * @pkt_size: The packet size + * @pkt_size: The packet byte size */ static void pch_udc_ep_set_maxpkt(struct pch_udc_ep *ep, u32 pkt_size) { @@ -920,25 +923,10 @@ static void pch_udc_ep_clear_nak(struct pch_udc_ep *ep) */ static void pch_udc_ep_fifo_flush(struct pch_udc_ep *ep, int dir) { - unsigned int loopcnt = 0; - struct pch_udc_dev *dev = ep->dev; - if (dir) { /* IN ep */ pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F); return; } - - if (pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) - return; - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH); - /* Wait for RxFIFO Empty */ - loopcnt = 10000; - while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) && - --loopcnt) - udelay(5); - if (!loopcnt) - dev_err(&dev->pdev->dev, "RxFIFO not Empty\n"); - pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH); } /** @@ -1220,14 +1208,31 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, dev = ep->dev; if (req->dma_mapped) { - if (ep->in) - dma_unmap_single(&dev->pdev->dev, req->req.dma, - req->req.length, DMA_TO_DEVICE); - else - dma_unmap_single(&dev->pdev->dev, req->req.dma, - req->req.length, DMA_FROM_DEVICE); + if (req->dma == DMA_ADDR_INVALID) { + if (ep->in) + dma_unmap_single(&dev->pdev->dev, req->req.dma, + req->req.length, + DMA_TO_DEVICE); + else + dma_unmap_single(&dev->pdev->dev, req->req.dma, + req->req.length, + DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + } else { + if (ep->in) + dma_unmap_single(&dev->pdev->dev, req->dma, + req->req.length, + DMA_TO_DEVICE); + else { + dma_unmap_single(&dev->pdev->dev, req->dma, + req->req.length, + DMA_FROM_DEVICE); + memcpy(req->req.buf, req->buf, req->req.length); + } + kfree(req->buf); + req->dma = DMA_ADDR_INVALID; + } req->dma_mapped = 0; - req->req.dma = DMA_ADDR_INVALID; } ep->halted = 1; spin_unlock(&dev->lock); @@ -1268,12 +1273,18 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev, struct pch_udc_data_dma_desc *td = req->td_data; unsigned i = req->chain_len; + dma_addr_t addr2; + dma_addr_t addr = (dma_addr_t)td->next; + td->next = 0x00; for (; i > 1; --i) { - dma_addr_t addr = (dma_addr_t)td->next; /* do not free first desc., will be done by free for request */ td = phys_to_virt(addr); + addr2 = (dma_addr_t)td->next; pci_pool_free(dev->data_requests, td, addr); + td->next = 0x00; + addr = addr2; } + req->chain_len = 1; } /** @@ -1301,23 +1312,23 @@ static int pch_udc_create_dma_chain(struct pch_udc_ep *ep, if (req->chain_len > 1) pch_udc_free_dma_chain(ep->dev, req); - for (; ; bytes -= buf_len, ++len) { - if (ep->in) - td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes); - else - td->status = PCH_UDC_BS_HST_BSY; + if (req->dma == DMA_ADDR_INVALID) + td->dataptr = req->req.dma; + else + td->dataptr = req->dma; + td->status = PCH_UDC_BS_HST_BSY; + for (; ; bytes -= buf_len, ++len) { + td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes); if (bytes <= buf_len) break; - last = td; td = pci_pool_alloc(ep->dev->data_requests, gfp_flags, &dma_addr); if (!td) goto nomem; - i += buf_len; - td->dataptr = req->req.dma + i; + td->dataptr = req->td_data->dataptr + i; last->next = dma_addr; } @@ -1352,28 +1363,15 @@ static int prepare_dma(struct pch_udc_ep *ep, struct pch_udc_request *req, { int retval; - req->td_data->dataptr = req->req.dma; - req->td_data->status |= PCH_UDC_DMA_LAST; /* Allocate and create a DMA chain */ retval = pch_udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp); if (retval) { - pr_err("%s: could not create DMA chain: %d\n", - __func__, retval); + pr_err("%s: could not create DMA chain:%d\n", __func__, retval); return retval; } - if (!ep->in) - return 0; - if (req->req.length <= ep->ep.maxpacket) - req->td_data->status = PCH_UDC_DMA_LAST | PCH_UDC_BS_HST_BSY | - req->req.length; - /* if bytes < max packet then tx bytes must - * be written in packet per buffer mode - */ - if ((req->req.length < ep->ep.maxpacket) || !ep->num) + if (ep->in) req->td_data->status = (req->td_data->status & - ~PCH_UDC_RXTX_BYTES) | req->req.length; - req->td_data->status = (req->td_data->status & - ~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_BSY; + ~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_RDY; return 0; } @@ -1529,6 +1527,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, if (!req) return NULL; req->req.dma = DMA_ADDR_INVALID; + req->dma = DMA_ADDR_INVALID; INIT_LIST_HEAD(&req->queue); if (!ep->dev->dma_addr) return &req->req; @@ -1613,16 +1612,33 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, /* map the buffer for dma */ if (usbreq->length && ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) { - if (ep->in) - usbreq->dma = dma_map_single(&dev->pdev->dev, - usbreq->buf, - usbreq->length, - DMA_TO_DEVICE); - else - usbreq->dma = dma_map_single(&dev->pdev->dev, - usbreq->buf, - usbreq->length, - DMA_FROM_DEVICE); + if (!((unsigned long)(usbreq->buf) & 0x03)) { + if (ep->in) + usbreq->dma = dma_map_single(&dev->pdev->dev, + usbreq->buf, + usbreq->length, + DMA_TO_DEVICE); + else + usbreq->dma = dma_map_single(&dev->pdev->dev, + usbreq->buf, + usbreq->length, + DMA_FROM_DEVICE); + } else { + req->buf = kzalloc(usbreq->length, GFP_ATOMIC); + if (!req->buf) + return -ENOMEM; + if (ep->in) { + memcpy(req->buf, usbreq->buf, usbreq->length); + req->dma = dma_map_single(&dev->pdev->dev, + req->buf, + usbreq->length, + DMA_TO_DEVICE); + } else + req->dma = dma_map_single(&dev->pdev->dev, + req->buf, + usbreq->length, + DMA_FROM_DEVICE); + } req->dma_mapped = 1; } if (usbreq->length > 0) { @@ -1920,32 +1936,46 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep) struct pch_udc_request *req; struct pch_udc_dev *dev = ep->dev; unsigned int count; + struct pch_udc_data_dma_desc *td; + dma_addr_t addr; if (list_empty(&ep->queue)) return; - /* next request */ req = list_entry(ep->queue.next, struct pch_udc_request, queue); - if ((req->td_data_last->status & PCH_UDC_BUFF_STS) != - PCH_UDC_BS_DMA_DONE) - return; pch_udc_clear_dma(ep->dev, DMA_DIR_RX); pch_udc_ep_set_ddptr(ep, 0); - if ((req->td_data_last->status & PCH_UDC_RXTX_STS) != - PCH_UDC_RTS_SUCC) { - dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) " - "epstatus=0x%08x\n", - (req->td_data_last->status & PCH_UDC_RXTX_STS), - (int)(ep->epsts)); - return; - } - count = req->td_data_last->status & PCH_UDC_RXTX_BYTES; + if ((req->td_data_last->status & PCH_UDC_BUFF_STS) == + PCH_UDC_BS_DMA_DONE) + td = req->td_data_last; + else + td = req->td_data; + while (1) { + if ((td->status & PCH_UDC_RXTX_STS) != PCH_UDC_RTS_SUCC) { + dev_err(&dev->pdev->dev, "Invalid RXTX status=0x%08x " + "epstatus=0x%08x\n", + (req->td_data->status & PCH_UDC_RXTX_STS), + (int)(ep->epsts)); + return; + } + if ((td->status & PCH_UDC_BUFF_STS) == PCH_UDC_BS_DMA_DONE) + if (td->status | PCH_UDC_DMA_LAST) { + count = td->status & PCH_UDC_RXTX_BYTES; + break; + } + if (td == req->td_data_last) { + dev_err(&dev->pdev->dev, "Not complete RX descriptor"); + return; + } + addr = (dma_addr_t)td->next; + td = phys_to_virt(addr); + } /* on 64k packets the RXBYTES field is zero */ if (!count && (req->req.length == UDC_DMA_MAXPACKET)) count = UDC_DMA_MAXPACKET; req->td_data->status |= PCH_UDC_DMA_LAST; - req->td_data_last->status |= PCH_UDC_BS_HST_BSY; + td->status |= PCH_UDC_BS_HST_BSY; req->dma_going = 0; req->req.actual = count; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index c2448950a8d8..6d8b04061d5d 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -902,7 +902,7 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) int pwr_reg; int ep0csr; int i; - u32 idx; + u32 idx, idx2; unsigned long flags; spin_lock_irqsave(&dev->lock, flags); @@ -1017,6 +1017,20 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) } } + /* what else causes this interrupt? a receive! who is it? */ + if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) { + for (i = 1; i < S3C2410_ENDPOINTS; i++) { + idx2 = udc_read(S3C2410_UDC_INDEX_REG); + udc_write(i, S3C2410_UDC_INDEX_REG); + + if (udc_read(S3C2410_UDC_OUT_CSR1_REG) & 0x1) + s3c2410_udc_handle_ep(&dev->ep[i]); + + /* restore index */ + udc_write(idx2, S3C2410_UDC_INDEX_REG); + } + } + dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD); /* Restore old index */ @@ -1467,7 +1481,9 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on) { dprintk(DEBUG_NORMAL, "%s()\n", __func__); - if (udc_info && udc_info->udc_command) { + if (udc_info && (udc_info->udc_command || + gpio_is_valid(udc_info->pullup_pin))) { + if (is_on) s3c2410_udc_enable(udc); else { @@ -1544,6 +1560,32 @@ static const struct usb_gadget_ops s3c2410_ops = { .vbus_draw = s3c2410_vbus_draw, }; +static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) +{ + if (!udc_info) + return; + + if (udc_info->udc_command) { + udc_info->udc_command(S3C2410_UDC_P_DISABLE); + } else if (gpio_is_valid(udc_info->pullup_pin)) { + int value; + + switch (cmd) { + case S3C2410_UDC_P_ENABLE: + value = 1; + break; + case S3C2410_UDC_P_DISABLE: + value = 0; + break; + default: + return; + } + value ^= udc_info->pullup_pin_inverted; + + gpio_set_value(udc_info->pullup_pin, value); + } +} + /*------------------------- gadget driver handling---------------------------*/ /* * s3c2410_udc_disable @@ -1565,8 +1607,7 @@ static void s3c2410_udc_disable(struct s3c2410_udc *dev) udc_write(0x1F, S3C2410_UDC_EP_INT_REG); /* Good bye, cruel world */ - if (udc_info && udc_info->udc_command) - udc_info->udc_command(S3C2410_UDC_P_DISABLE); + s3c2410_udc_command(S3C2410_UDC_P_DISABLE); /* Set speed to unknown */ dev->gadget.speed = USB_SPEED_UNKNOWN; @@ -1627,8 +1668,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev) udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG); /* time to say "hello, world" */ - if (udc_info && udc_info->udc_command) - udc_info->udc_command(S3C2410_UDC_P_ENABLE); + s3c2410_udc_command(S3C2410_UDC_P_ENABLE); } /* @@ -1903,6 +1943,17 @@ static int s3c2410_udc_probe(struct platform_device *pdev) udc->vbus = 1; } + if (udc_info && !udc_info->udc_command && + gpio_is_valid(udc_info->pullup_pin)) { + + retval = gpio_request_one(udc_info->pullup_pin, + udc_info->vbus_pin_inverted ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, + "udc pullup"); + if (retval) + goto err_vbus_irq; + } + if (s3c2410_udc_debugfs_root) { udc->regs_info = debugfs_create_file("registers", S_IRUGO, s3c2410_udc_debugfs_root, @@ -1915,6 +1966,9 @@ static int s3c2410_udc_probe(struct platform_device *pdev) return 0; +err_vbus_irq: + if (udc_info && udc_info->vbus_pin > 0) + free_irq(gpio_to_irq(udc_info->vbus_pin), udc); err_gpio_claim: if (udc_info && udc_info->vbus_pin > 0) gpio_free(udc_info->vbus_pin); @@ -1942,6 +1996,10 @@ static int s3c2410_udc_remove(struct platform_device *pdev) debugfs_remove(udc->regs_info); + if (udc_info && !udc_info->udc_command && + gpio_is_valid(udc_info->pullup_pin)) + gpio_free(udc_info->pullup_pin); + if (udc_info && udc_info->vbus_pin > 0) { irq = gpio_to_irq(udc_info->vbus_pin); free_irq(irq, udc); @@ -1973,16 +2031,14 @@ static int s3c2410_udc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) { - if (udc_info && udc_info->udc_command) - udc_info->udc_command(S3C2410_UDC_P_DISABLE); + s3c2410_udc_command(S3C2410_UDC_P_DISABLE); return 0; } static int s3c2410_udc_resume(struct platform_device *pdev) { - if (udc_info && udc_info->udc_command) - udc_info->udc_command(S3C2410_UDC_P_ENABLE); + s3c2410_udc_command(S3C2410_UDC_P_ENABLE); return 0; } diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 1eda968b5644..2ac1d2147325 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -241,7 +241,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) size -= size % out->maxpacket; if (dev->port_usb->is_fixed) - size = max(size, dev->port_usb->fixed_out_len); + size = max_t(size_t, size, dev->port_usb->fixed_out_len); skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags); if (skb == NULL) { |