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 | |
| 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')
| -rw-r--r-- | drivers/usb/chipidea/ci.h | 1 | ||||
| -rw-r--r-- | drivers/usb/chipidea/udc.c | 39 |
2 files changed, 39 insertions, 1 deletions
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index d738603a2757..e25d1263da13 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h | |||
| @@ -139,6 +139,7 @@ struct ci13xxx { | |||
| 139 | enum ci_role role; | 139 | enum ci_role role; |
| 140 | bool is_otg; | 140 | bool is_otg; |
| 141 | struct work_struct work; | 141 | struct work_struct work; |
| 142 | struct work_struct vbus_work; | ||
| 142 | struct workqueue_struct *wq; | 143 | struct workqueue_struct *wq; |
| 143 | 144 | ||
| 144 | struct dma_pool *qh_pool; | 145 | struct dma_pool *qh_pool; |
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 | } |
