diff options
-rw-r--r-- | arch/arm/mach-at91/include/mach/board.h | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/at91_udc.c | 66 | ||||
-rw-r--r-- | drivers/usb/gadget/at91_udc.h | 2 |
3 files changed, 57 insertions, 13 deletions
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index df2ed848c9f8..58528aa9c8a8 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h | |||
@@ -44,6 +44,8 @@ | |||
44 | /* USB Device */ | 44 | /* USB Device */ |
45 | struct at91_udc_data { | 45 | struct at91_udc_data { |
46 | u8 vbus_pin; /* high == host powering us */ | 46 | u8 vbus_pin; /* high == host powering us */ |
47 | u8 vbus_active_low; /* vbus polarity */ | ||
48 | u8 vbus_polled; /* Use polling, not interrupt */ | ||
47 | u8 pullup_pin; /* active == D+ pulled up */ | 49 | u8 pullup_pin; /* active == D+ pulled up */ |
48 | u8 pullup_active_low; /* true == pullup_pin is active low */ | 50 | u8 pullup_active_low; /* true == pullup_pin is active low */ |
49 | }; | 51 | }; |
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index fd6a7577ad25..93ead19507b6 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c | |||
@@ -76,6 +76,7 @@ | |||
76 | static const char driver_name [] = "at91_udc"; | 76 | static const char driver_name [] = "at91_udc"; |
77 | static const char ep0name[] = "ep0"; | 77 | static const char ep0name[] = "ep0"; |
78 | 78 | ||
79 | #define VBUS_POLL_TIMEOUT msecs_to_jiffies(1000) | ||
79 | 80 | ||
80 | #define at91_udp_read(udc, reg) \ | 81 | #define at91_udp_read(udc, reg) \ |
81 | __raw_readl((udc)->udp_baseaddr + (reg)) | 82 | __raw_readl((udc)->udp_baseaddr + (reg)) |
@@ -1585,20 +1586,48 @@ static struct at91_udc controller = { | |||
1585 | /* ep6 and ep7 are also reserved (custom silicon might use them) */ | 1586 | /* ep6 and ep7 are also reserved (custom silicon might use them) */ |
1586 | }; | 1587 | }; |
1587 | 1588 | ||
1589 | static void at91_vbus_update(struct at91_udc *udc, unsigned value) | ||
1590 | { | ||
1591 | value ^= udc->board.vbus_active_low; | ||
1592 | if (value != udc->vbus) | ||
1593 | at91_vbus_session(&udc->gadget, value); | ||
1594 | } | ||
1595 | |||
1588 | static irqreturn_t at91_vbus_irq(int irq, void *_udc) | 1596 | static irqreturn_t at91_vbus_irq(int irq, void *_udc) |
1589 | { | 1597 | { |
1590 | struct at91_udc *udc = _udc; | 1598 | struct at91_udc *udc = _udc; |
1591 | unsigned value; | ||
1592 | 1599 | ||
1593 | /* vbus needs at least brief debouncing */ | 1600 | /* vbus needs at least brief debouncing */ |
1594 | udelay(10); | 1601 | udelay(10); |
1595 | value = gpio_get_value(udc->board.vbus_pin); | 1602 | at91_vbus_update(udc, gpio_get_value(udc->board.vbus_pin)); |
1596 | if (value != udc->vbus) | ||
1597 | at91_vbus_session(&udc->gadget, value); | ||
1598 | 1603 | ||
1599 | return IRQ_HANDLED; | 1604 | return IRQ_HANDLED; |
1600 | } | 1605 | } |
1601 | 1606 | ||
1607 | static void at91_vbus_timer_work(struct work_struct *work) | ||
1608 | { | ||
1609 | struct at91_udc *udc = container_of(work, struct at91_udc, | ||
1610 | vbus_timer_work); | ||
1611 | |||
1612 | at91_vbus_update(udc, gpio_get_value_cansleep(udc->board.vbus_pin)); | ||
1613 | |||
1614 | if (!timer_pending(&udc->vbus_timer)) | ||
1615 | mod_timer(&udc->vbus_timer, jiffies + VBUS_POLL_TIMEOUT); | ||
1616 | } | ||
1617 | |||
1618 | static void at91_vbus_timer(unsigned long data) | ||
1619 | { | ||
1620 | struct at91_udc *udc = (struct at91_udc *)data; | ||
1621 | |||
1622 | /* | ||
1623 | * If we are polling vbus it is likely that the gpio is on an | ||
1624 | * bus such as i2c or spi which may sleep, so schedule some work | ||
1625 | * to read the vbus gpio | ||
1626 | */ | ||
1627 | if (!work_pending(&udc->vbus_timer_work)) | ||
1628 | schedule_work(&udc->vbus_timer_work); | ||
1629 | } | ||
1630 | |||
1602 | int usb_gadget_register_driver (struct usb_gadget_driver *driver) | 1631 | int usb_gadget_register_driver (struct usb_gadget_driver *driver) |
1603 | { | 1632 | { |
1604 | struct at91_udc *udc = &controller; | 1633 | struct at91_udc *udc = &controller; |
@@ -1800,13 +1829,23 @@ static int __init at91udc_probe(struct platform_device *pdev) | |||
1800 | * Get the initial state of VBUS - we cannot expect | 1829 | * Get the initial state of VBUS - we cannot expect |
1801 | * a pending interrupt. | 1830 | * a pending interrupt. |
1802 | */ | 1831 | */ |
1803 | udc->vbus = gpio_get_value(udc->board.vbus_pin); | 1832 | udc->vbus = gpio_get_value_cansleep(udc->board.vbus_pin) ^ |
1804 | if (request_irq(udc->board.vbus_pin, at91_vbus_irq, | 1833 | udc->board.vbus_active_low; |
1805 | IRQF_DISABLED, driver_name, udc)) { | 1834 | |
1806 | DBG("request vbus irq %d failed\n", | 1835 | if (udc->board.vbus_polled) { |
1807 | udc->board.vbus_pin); | 1836 | INIT_WORK(&udc->vbus_timer_work, at91_vbus_timer_work); |
1808 | retval = -EBUSY; | 1837 | setup_timer(&udc->vbus_timer, at91_vbus_timer, |
1809 | goto fail3; | 1838 | (unsigned long)udc); |
1839 | mod_timer(&udc->vbus_timer, | ||
1840 | jiffies + VBUS_POLL_TIMEOUT); | ||
1841 | } else { | ||
1842 | if (request_irq(udc->board.vbus_pin, at91_vbus_irq, | ||
1843 | IRQF_DISABLED, driver_name, udc)) { | ||
1844 | DBG("request vbus irq %d failed\n", | ||
1845 | udc->board.vbus_pin); | ||
1846 | retval = -EBUSY; | ||
1847 | goto fail3; | ||
1848 | } | ||
1810 | } | 1849 | } |
1811 | } else { | 1850 | } else { |
1812 | DBG("no VBUS detection, assuming always-on\n"); | 1851 | DBG("no VBUS detection, assuming always-on\n"); |
@@ -1898,7 +1937,7 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) | |||
1898 | enable_irq_wake(udc->udp_irq); | 1937 | enable_irq_wake(udc->udp_irq); |
1899 | 1938 | ||
1900 | udc->active_suspend = wake; | 1939 | udc->active_suspend = wake; |
1901 | if (udc->board.vbus_pin > 0 && wake) | 1940 | if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled && wake) |
1902 | enable_irq_wake(udc->board.vbus_pin); | 1941 | enable_irq_wake(udc->board.vbus_pin); |
1903 | return 0; | 1942 | return 0; |
1904 | } | 1943 | } |
@@ -1908,7 +1947,8 @@ static int at91udc_resume(struct platform_device *pdev) | |||
1908 | struct at91_udc *udc = platform_get_drvdata(pdev); | 1947 | struct at91_udc *udc = platform_get_drvdata(pdev); |
1909 | unsigned long flags; | 1948 | unsigned long flags; |
1910 | 1949 | ||
1911 | if (udc->board.vbus_pin > 0 && udc->active_suspend) | 1950 | if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled && |
1951 | udc->active_suspend) | ||
1912 | disable_irq_wake(udc->board.vbus_pin); | 1952 | disable_irq_wake(udc->board.vbus_pin); |
1913 | 1953 | ||
1914 | /* maybe reconnect to host; if so, clocks on */ | 1954 | /* maybe reconnect to host; if so, clocks on */ |
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index bc76a39c2bb1..108ca54f9092 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h | |||
@@ -145,6 +145,8 @@ struct at91_udc { | |||
145 | void __iomem *udp_baseaddr; | 145 | void __iomem *udp_baseaddr; |
146 | int udp_irq; | 146 | int udp_irq; |
147 | spinlock_t lock; | 147 | spinlock_t lock; |
148 | struct timer_list vbus_timer; | ||
149 | struct work_struct vbus_timer_work; | ||
148 | }; | 150 | }; |
149 | 151 | ||
150 | static inline struct at91_udc *to_udc(struct usb_gadget *g) | 152 | static inline struct at91_udc *to_udc(struct usb_gadget *g) |