aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/pch_udc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/pch_udc.c')
-rw-r--r--drivers/usb/gadget/pch_udc.c70
1 files changed, 66 insertions, 4 deletions
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 842ca6349a90..c2f19752c074 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -311,6 +311,7 @@ struct pch_udc_ep {
311 * @registered: driver regsitered with system 311 * @registered: driver regsitered with system
312 * @suspended: driver in suspended state 312 * @suspended: driver in suspended state
313 * @connected: gadget driver associated 313 * @connected: gadget driver associated
314 * @vbus_session: required vbus_session state
314 * @set_cfg_not_acked: pending acknowledgement 4 setup 315 * @set_cfg_not_acked: pending acknowledgement 4 setup
315 * @waiting_zlp_ack: pending acknowledgement 4 ZLP 316 * @waiting_zlp_ack: pending acknowledgement 4 ZLP
316 * @data_requests: DMA pool for data requests 317 * @data_requests: DMA pool for data requests
@@ -337,6 +338,7 @@ struct pch_udc_dev {
337 registered:1, 338 registered:1,
338 suspended:1, 339 suspended:1,
339 connected:1, 340 connected:1,
341 vbus_session:1,
340 set_cfg_not_acked:1, 342 set_cfg_not_acked:1,
341 waiting_zlp_ack:1; 343 waiting_zlp_ack:1;
342 struct pci_pool *data_requests; 344 struct pci_pool *data_requests;
@@ -554,6 +556,31 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
554} 556}
555 557
556/** 558/**
559 * pch_udc_reconnect() - This API initializes usb device controller,
560 * and clear the disconnect status.
561 * @dev: Reference to pch_udc_regs structure
562 */
563static void pch_udc_init(struct pch_udc_dev *dev);
564static void pch_udc_reconnect(struct pch_udc_dev *dev)
565{
566 pch_udc_init(dev);
567
568 /* enable device interrupts */
569 /* pch_udc_enable_interrupts() */
570 pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR,
571 UDC_DEVINT_UR | UDC_DEVINT_US |
572 UDC_DEVINT_ENUM |
573 UDC_DEVINT_SI | UDC_DEVINT_SC);
574
575 /* Clear the disconnect */
576 pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
577 pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
578 mdelay(1);
579 /* Resume USB signalling */
580 pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
581}
582
583/**
557 * pch_udc_vbus_session() - set or clearr the disconnect status. 584 * pch_udc_vbus_session() - set or clearr the disconnect status.
558 * @dev: Reference to pch_udc_regs structure 585 * @dev: Reference to pch_udc_regs structure
559 * @is_active: Parameter specifying the action 586 * @is_active: Parameter specifying the action
@@ -563,10 +590,18 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
563static inline void pch_udc_vbus_session(struct pch_udc_dev *dev, 590static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
564 int is_active) 591 int is_active)
565{ 592{
566 if (is_active) 593 if (is_active) {
567 pch_udc_clear_disconnect(dev); 594 pch_udc_reconnect(dev);
568 else 595 dev->vbus_session = 1;
596 } else {
597 if (dev->driver && dev->driver->disconnect) {
598 spin_unlock(&dev->lock);
599 dev->driver->disconnect(&dev->gadget);
600 spin_lock(&dev->lock);
601 }
569 pch_udc_set_disconnect(dev); 602 pch_udc_set_disconnect(dev);
603 dev->vbus_session = 0;
604 }
570} 605}
571 606
572/** 607/**
@@ -1126,7 +1161,17 @@ static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
1126 if (!gadget) 1161 if (!gadget)
1127 return -EINVAL; 1162 return -EINVAL;
1128 dev = container_of(gadget, struct pch_udc_dev, gadget); 1163 dev = container_of(gadget, struct pch_udc_dev, gadget);
1129 pch_udc_vbus_session(dev, is_on); 1164 if (is_on) {
1165 pch_udc_reconnect(dev);
1166 } else {
1167 if (dev->driver && dev->driver->disconnect) {
1168 spin_unlock(&dev->lock);
1169 dev->driver->disconnect(&dev->gadget);
1170 spin_lock(&dev->lock);
1171 }
1172 pch_udc_set_disconnect(dev);
1173 }
1174
1130 return 0; 1175 return 0;
1131} 1176}
1132 1177
@@ -2482,6 +2527,15 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
2482 dev->driver->suspend(&dev->gadget); 2527 dev->driver->suspend(&dev->gadget);
2483 spin_lock(&dev->lock); 2528 spin_lock(&dev->lock);
2484 } 2529 }
2530
2531 if (dev->vbus_session == 0) {
2532 if (dev->driver && dev->driver->disconnect) {
2533 spin_unlock(&dev->lock);
2534 dev->driver->disconnect(&dev->gadget);
2535 spin_lock(&dev->lock);
2536 }
2537 pch_udc_reconnect(dev);
2538 }
2485 dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n"); 2539 dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
2486 } 2540 }
2487 /* Clear the SOF interrupt, if enabled */ 2541 /* Clear the SOF interrupt, if enabled */
@@ -2509,6 +2563,14 @@ static irqreturn_t pch_udc_isr(int irq, void *pdev)
2509 dev_intr = pch_udc_read_device_interrupts(dev); 2563 dev_intr = pch_udc_read_device_interrupts(dev);
2510 ep_intr = pch_udc_read_ep_interrupts(dev); 2564 ep_intr = pch_udc_read_ep_interrupts(dev);
2511 2565
2566 /* For a hot plug, this find that the controller is hung up. */
2567 if (dev_intr == ep_intr)
2568 if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
2569 dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
2570 /* The controller is reset */
2571 pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
2572 return IRQ_HANDLED;
2573 }
2512 if (dev_intr) 2574 if (dev_intr)
2513 /* Clear device interrupts */ 2575 /* Clear device interrupts */
2514 pch_udc_write_device_interrupts(dev, dev_intr); 2576 pch_udc_write_device_interrupts(dev, dev_intr);