diff options
author | Richard Zhao <richard.zhao@freescale.com> | 2012-09-12 07:58:09 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-09-12 14:20:38 -0400 |
commit | 8c4fc031954b4eb72daf13d3c907a985a3eee208 (patch) | |
tree | 0c55afe1e363f14ec6847c3ea8b7d3b1d24e10db /drivers/usb/chipidea/udc.c | |
parent | 984f753cf120db60d97271e34cf16c95761f0278 (diff) |
USB: chipidea: add vbus detect for udc
Using vbus valid interrupt to detect vbus.
Tested-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Tested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Richard Zhao <richard.zhao@freescale.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/chipidea/udc.c')
-rw-r--r-- | drivers/usb/chipidea/udc.c | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index d214448b677e..2f45bba8561d 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c | |||
@@ -305,6 +305,18 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci) | |||
305 | return reg; | 305 | return reg; |
306 | } | 306 | } |
307 | 307 | ||
308 | static void hw_enable_vbus_intr(struct ci13xxx *ci) | ||
309 | { | ||
310 | hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS); | ||
311 | hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE); | ||
312 | queue_work(ci->wq, &ci->vbus_work); | ||
313 | } | ||
314 | |||
315 | static void hw_disable_vbus_intr(struct ci13xxx *ci) | ||
316 | { | ||
317 | hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0); | ||
318 | } | ||
319 | |||
308 | /** | 320 | /** |
309 | * hw_test_and_clear_setup_guard: test & clear setup guard (execute without | 321 | * hw_test_and_clear_setup_guard: test & clear setup guard (execute without |
310 | * interruption) | 322 | * interruption) |
@@ -371,6 +383,16 @@ static int hw_usb_reset(struct ci13xxx *ci) | |||
371 | return 0; | 383 | return 0; |
372 | } | 384 | } |
373 | 385 | ||
386 | static void vbus_work(struct work_struct *work) | ||
387 | { | ||
388 | struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work); | ||
389 | |||
390 | if (hw_read(ci, OP_OTGSC, OTGSC_AVV)) | ||
391 | usb_gadget_vbus_connect(&ci->gadget); | ||
392 | else | ||
393 | usb_gadget_vbus_disconnect(&ci->gadget); | ||
394 | } | ||
395 | |||
374 | /****************************************************************************** | 396 | /****************************************************************************** |
375 | * UTIL block | 397 | * UTIL block |
376 | *****************************************************************************/ | 398 | *****************************************************************************/ |
@@ -1370,6 +1392,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) | |||
1370 | if (is_active) { | 1392 | if (is_active) { |
1371 | pm_runtime_get_sync(&_gadget->dev); | 1393 | pm_runtime_get_sync(&_gadget->dev); |
1372 | hw_device_reset(ci, USBMODE_CM_DC); | 1394 | hw_device_reset(ci, USBMODE_CM_DC); |
1395 | hw_enable_vbus_intr(ci); | ||
1373 | hw_device_state(ci, ci->ep0out->qh.dma); | 1396 | hw_device_state(ci, ci->ep0out->qh.dma); |
1374 | } else { | 1397 | } else { |
1375 | hw_device_state(ci, 0); | 1398 | hw_device_state(ci, 0); |
@@ -1544,8 +1567,10 @@ static int ci13xxx_start(struct usb_gadget *gadget, | |||
1544 | pm_runtime_get_sync(&ci->gadget.dev); | 1567 | pm_runtime_get_sync(&ci->gadget.dev); |
1545 | if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) { | 1568 | if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) { |
1546 | if (ci->vbus_active) { | 1569 | if (ci->vbus_active) { |
1547 | if (ci->platdata->flags & CI13XXX_REGS_SHARED) | 1570 | if (ci->platdata->flags & CI13XXX_REGS_SHARED) { |
1548 | hw_device_reset(ci, USBMODE_CM_DC); | 1571 | hw_device_reset(ci, USBMODE_CM_DC); |
1572 | hw_enable_vbus_intr(ci); | ||
1573 | } | ||
1549 | } else { | 1574 | } else { |
1550 | pm_runtime_put_sync(&ci->gadget.dev); | 1575 | pm_runtime_put_sync(&ci->gadget.dev); |
1551 | goto done; | 1576 | goto done; |
@@ -1651,6 +1676,13 @@ static irqreturn_t udc_irq(struct ci13xxx *ci) | |||
1651 | } else { | 1676 | } else { |
1652 | retval = IRQ_NONE; | 1677 | retval = IRQ_NONE; |
1653 | } | 1678 | } |
1679 | |||
1680 | intr = hw_read(ci, OP_OTGSC, ~0); | ||
1681 | hw_write(ci, OP_OTGSC, ~0, intr); | ||
1682 | |||
1683 | if (intr & (OTGSC_AVVIE & OTGSC_AVVIS)) | ||
1684 | queue_work(ci->wq, &ci->vbus_work); | ||
1685 | |||
1654 | spin_unlock(&ci->lock); | 1686 | spin_unlock(&ci->lock); |
1655 | 1687 | ||
1656 | return retval; | 1688 | return retval; |
@@ -1726,6 +1758,7 @@ static int udc_start(struct ci13xxx *ci) | |||
1726 | retval = hw_device_reset(ci, USBMODE_CM_DC); | 1758 | retval = hw_device_reset(ci, USBMODE_CM_DC); |
1727 | if (retval) | 1759 | if (retval) |
1728 | goto put_transceiver; | 1760 | goto put_transceiver; |
1761 | hw_enable_vbus_intr(ci); | ||
1729 | } | 1762 | } |
1730 | 1763 | ||
1731 | retval = device_register(&ci->gadget.dev); | 1764 | retval = device_register(&ci->gadget.dev); |
@@ -1788,6 +1821,9 @@ static void udc_stop(struct ci13xxx *ci) | |||
1788 | if (ci == NULL) | 1821 | if (ci == NULL) |
1789 | return; | 1822 | return; |
1790 | 1823 | ||
1824 | hw_disable_vbus_intr(ci); | ||
1825 | cancel_work_sync(&ci->vbus_work); | ||
1826 | |||
1791 | usb_del_gadget_udc(&ci->gadget); | 1827 | usb_del_gadget_udc(&ci->gadget); |
1792 | 1828 | ||
1793 | destroy_eps(ci); | 1829 | destroy_eps(ci); |
@@ -1828,6 +1864,7 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci) | |||
1828 | rdrv->irq = udc_irq; | 1864 | rdrv->irq = udc_irq; |
1829 | rdrv->name = "gadget"; | 1865 | rdrv->name = "gadget"; |
1830 | ci->roles[CI_ROLE_GADGET] = rdrv; | 1866 | ci->roles[CI_ROLE_GADGET] = rdrv; |
1867 | INIT_WORK(&ci->vbus_work, vbus_work); | ||
1831 | 1868 | ||
1832 | return 0; | 1869 | return 0; |
1833 | } | 1870 | } |