aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorPavankumar Kondeti <pkondeti@codeaurora.org>2011-02-18 07:13:17 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-25 14:33:57 -0500
commite2b61c1df650595d0216c6d086024b5a98d949c7 (patch)
tree4f64e77a3a8aa9532f018169df2293b7d586438a /drivers/usb/gadget
parent0e6ca1998e4c803b0be98f97a1d1e1ea562b8964 (diff)
USB: gadget: Implement remote wakeup in ci13xxx_udc
This patch adds support for remote wakeup. The following things are handled: - Process SET_FEATURE/CLEAR_FEATURE control requests sent by host for enabling/disabling remote wakeup feature. - Report remote wakeup enable status in response to GET_STATUS control request. - Implement wakeup method defined in usb_gadget_ops for initiating remote wakeup. - Notify gadget driver about suspend and resume. Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c124
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.h4
2 files changed, 99 insertions, 29 deletions
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index da01f333a51c..17526759c9ce 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1608,12 +1608,19 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
1608{ 1608{
1609 struct usb_ep *ep; 1609 struct usb_ep *ep;
1610 struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); 1610 struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
1611 unsigned long flags;
1611 1612
1612 trace("%p", gadget); 1613 trace("%p", gadget);
1613 1614
1614 if (gadget == NULL) 1615 if (gadget == NULL)
1615 return -EINVAL; 1616 return -EINVAL;
1616 1617
1618 spin_lock_irqsave(udc->lock, flags);
1619 udc->gadget.speed = USB_SPEED_UNKNOWN;
1620 udc->remote_wakeup = 0;
1621 udc->suspended = 0;
1622 spin_unlock_irqrestore(udc->lock, flags);
1623
1617 /* flush all endpoints */ 1624 /* flush all endpoints */
1618 gadget_for_each_ep(ep, gadget) { 1625 gadget_for_each_ep(ep, gadget) {
1619 usb_ep_fifo_flush(ep); 1626 usb_ep_fifo_flush(ep);
@@ -1747,7 +1754,8 @@ __acquires(mEp->lock)
1747 } 1754 }
1748 1755
1749 if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { 1756 if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
1750 /* TODO: D1 - Remote Wakeup; D0 - Self Powered */ 1757 /* Assume that device is bus powered for now. */
1758 *((u16 *)req->buf) = _udc->remote_wakeup << 1;
1751 retval = 0; 1759 retval = 0;
1752 } else if ((setup->bRequestType & USB_RECIP_MASK) \ 1760 } else if ((setup->bRequestType & USB_RECIP_MASK) \
1753 == USB_RECIP_ENDPOINT) { 1761 == USB_RECIP_ENDPOINT) {
@@ -1913,22 +1921,32 @@ __acquires(udc->lock)
1913 1921
1914 switch (req.bRequest) { 1922 switch (req.bRequest) {
1915 case USB_REQ_CLEAR_FEATURE: 1923 case USB_REQ_CLEAR_FEATURE:
1916 if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && 1924 if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
1917 le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT) 1925 le16_to_cpu(req.wValue) ==
1918 goto delegate; 1926 USB_ENDPOINT_HALT) {
1919 if (req.wLength != 0) 1927 if (req.wLength != 0)
1920 break; 1928 break;
1921 num = le16_to_cpu(req.wIndex); 1929 num = le16_to_cpu(req.wIndex);
1922 num &= USB_ENDPOINT_NUMBER_MASK; 1930 num &= USB_ENDPOINT_NUMBER_MASK;
1923 if (!udc->ci13xxx_ep[num].wedge) { 1931 if (!udc->ci13xxx_ep[num].wedge) {
1924 spin_unlock(udc->lock); 1932 spin_unlock(udc->lock);
1925 err = usb_ep_clear_halt( 1933 err = usb_ep_clear_halt(
1926 &udc->ci13xxx_ep[num].ep); 1934 &udc->ci13xxx_ep[num].ep);
1927 spin_lock(udc->lock); 1935 spin_lock(udc->lock);
1928 if (err) 1936 if (err)
1937 break;
1938 }
1939 err = isr_setup_status_phase(udc);
1940 } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
1941 le16_to_cpu(req.wValue) ==
1942 USB_DEVICE_REMOTE_WAKEUP) {
1943 if (req.wLength != 0)
1929 break; 1944 break;
1945 udc->remote_wakeup = 0;
1946 err = isr_setup_status_phase(udc);
1947 } else {
1948 goto delegate;
1930 } 1949 }
1931 err = isr_setup_status_phase(udc);
1932 break; 1950 break;
1933 case USB_REQ_GET_STATUS: 1951 case USB_REQ_GET_STATUS:
1934 if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && 1952 if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
@@ -1952,20 +1970,29 @@ __acquires(udc->lock)
1952 err = isr_setup_status_phase(udc); 1970 err = isr_setup_status_phase(udc);
1953 break; 1971 break;
1954 case USB_REQ_SET_FEATURE: 1972 case USB_REQ_SET_FEATURE:
1955 if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && 1973 if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
1956 le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT) 1974 le16_to_cpu(req.wValue) ==
1957 goto delegate; 1975 USB_ENDPOINT_HALT) {
1958 if (req.wLength != 0) 1976 if (req.wLength != 0)
1959 break; 1977 break;
1960 num = le16_to_cpu(req.wIndex); 1978 num = le16_to_cpu(req.wIndex);
1961 num &= USB_ENDPOINT_NUMBER_MASK; 1979 num &= USB_ENDPOINT_NUMBER_MASK;
1962 1980
1963 spin_unlock(udc->lock); 1981 spin_unlock(udc->lock);
1964 err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); 1982 err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
1965 spin_lock(udc->lock); 1983 spin_lock(udc->lock);
1966 if (err) 1984 if (!err)
1967 break; 1985 err = isr_setup_status_phase(udc);
1968 err = isr_setup_status_phase(udc); 1986 } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
1987 le16_to_cpu(req.wValue) ==
1988 USB_DEVICE_REMOTE_WAKEUP) {
1989 if (req.wLength != 0)
1990 break;
1991 udc->remote_wakeup = 1;
1992 err = isr_setup_status_phase(udc);
1993 } else {
1994 goto delegate;
1995 }
1969 break; 1996 break;
1970 default: 1997 default:
1971delegate: 1998delegate:
@@ -2401,6 +2428,31 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
2401 return 0; 2428 return 0;
2402} 2429}
2403 2430
2431static int ci13xxx_wakeup(struct usb_gadget *_gadget)
2432{
2433 struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
2434 unsigned long flags;
2435 int ret = 0;
2436
2437 trace();
2438
2439 spin_lock_irqsave(udc->lock, flags);
2440 if (!udc->remote_wakeup) {
2441 ret = -EOPNOTSUPP;
2442 dbg_trace("remote wakeup feature is not enabled\n");
2443 goto out;
2444 }
2445 if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
2446 ret = -EINVAL;
2447 dbg_trace("port is not suspended\n");
2448 goto out;
2449 }
2450 hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
2451out:
2452 spin_unlock_irqrestore(udc->lock, flags);
2453 return ret;
2454}
2455
2404/** 2456/**
2405 * Device operations part of the API to the USB controller hardware, 2457 * Device operations part of the API to the USB controller hardware,
2406 * which don't involve endpoints (or i/o) 2458 * which don't involve endpoints (or i/o)
@@ -2408,6 +2460,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
2408 */ 2460 */
2409static const struct usb_gadget_ops usb_gadget_ops = { 2461static const struct usb_gadget_ops usb_gadget_ops = {
2410 .vbus_session = ci13xxx_vbus_session, 2462 .vbus_session = ci13xxx_vbus_session,
2463 .wakeup = ci13xxx_wakeup,
2411}; 2464};
2412 2465
2413/** 2466/**
@@ -2650,6 +2703,12 @@ static irqreturn_t udc_irq(void)
2650 isr_statistics.pci++; 2703 isr_statistics.pci++;
2651 udc->gadget.speed = hw_port_is_high_speed() ? 2704 udc->gadget.speed = hw_port_is_high_speed() ?
2652 USB_SPEED_HIGH : USB_SPEED_FULL; 2705 USB_SPEED_HIGH : USB_SPEED_FULL;
2706 if (udc->suspended) {
2707 spin_unlock(udc->lock);
2708 udc->driver->resume(&udc->gadget);
2709 spin_lock(udc->lock);
2710 udc->suspended = 0;
2711 }
2653 } 2712 }
2654 if (USBi_UEI & intr) 2713 if (USBi_UEI & intr)
2655 isr_statistics.uei++; 2714 isr_statistics.uei++;
@@ -2657,8 +2716,15 @@ static irqreturn_t udc_irq(void)
2657 isr_statistics.ui++; 2716 isr_statistics.ui++;
2658 isr_tr_complete_handler(udc); 2717 isr_tr_complete_handler(udc);
2659 } 2718 }
2660 if (USBi_SLI & intr) 2719 if (USBi_SLI & intr) {
2720 if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
2721 udc->suspended = 1;
2722 spin_unlock(udc->lock);
2723 udc->driver->suspend(&udc->gadget);
2724 spin_lock(udc->lock);
2725 }
2661 isr_statistics.sli++; 2726 isr_statistics.sli++;
2727 }
2662 retval = IRQ_HANDLED; 2728 retval = IRQ_HANDLED;
2663 } else { 2729 } else {
2664 isr_statistics.none++; 2730 isr_statistics.none++;
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 3fad3adeacc8..6cfab20db6bd 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -128,6 +128,9 @@ struct ci13xxx {
128 u32 ep0_dir; /* ep0 direction */ 128 u32 ep0_dir; /* ep0 direction */
129#define ep0out ci13xxx_ep[0] 129#define ep0out ci13xxx_ep[0]
130#define ep0in ci13xxx_ep[16] 130#define ep0in ci13xxx_ep[16]
131 u8 remote_wakeup; /* Is remote wakeup feature
132 enabled by the host? */
133 u8 suspended; /* suspended by the host */
131 134
132 struct usb_gadget_driver *driver; /* 3rd party gadget driver */ 135 struct usb_gadget_driver *driver; /* 3rd party gadget driver */
133 struct ci13xxx_udc_driver *udc_driver; /* device controller driver */ 136 struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
@@ -169,6 +172,7 @@ struct ci13xxx {
169#define DEVICEADDR_USBADR (0x7FUL << 25) 172#define DEVICEADDR_USBADR (0x7FUL << 25)
170 173
171/* PORTSC */ 174/* PORTSC */
175#define PORTSC_FPR BIT(6)
172#define PORTSC_SUSP BIT(7) 176#define PORTSC_SUSP BIT(7)
173#define PORTSC_HSP BIT(9) 177#define PORTSC_HSP BIT(9)
174#define PORTSC_PTC (0x0FUL << 16) 178#define PORTSC_PTC (0x0FUL << 16)