diff options
| -rw-r--r-- | drivers/usb/fotg210/fotg210-udc.c | 97 | ||||
| -rw-r--r-- | drivers/usb/fotg210/fotg210-udc.h | 2 |
2 files changed, 62 insertions, 37 deletions
diff --git a/drivers/usb/fotg210/fotg210-udc.c b/drivers/usb/fotg210/fotg210-udc.c index d9e024873a42..fdd2cf82fde5 100644 --- a/drivers/usb/fotg210/fotg210-udc.c +++ b/drivers/usb/fotg210/fotg210-udc.c @@ -124,6 +124,7 @@ static void fotg210_set_fifo_dir(struct fotg210_ep *ep, u32 epnum, u32 dir_in) u32 val; val = ioread32(fotg210->reg + FOTG210_FIFOMAP); + val &= ~FIFOMAP_NA(epnum - 1); val |= (dir_in ? FIFOMAP_DIRIN(epnum - 1) : FIFOMAP_DIROUT(epnum - 1)); iowrite32(val, fotg210->reg + FOTG210_FIFOMAP); } @@ -134,6 +135,7 @@ static void fotg210_set_tfrtype(struct fotg210_ep *ep, u32 epnum, u32 type) u32 val; val = ioread32(fotg210->reg + FOTG210_FIFOCF); + val &= ~FIFOCF_TYPE(3, epnum - 1); val |= FIFOCF_TYPE(type, epnum - 1); iowrite32(val, fotg210->reg + FOTG210_FIFOCF); } @@ -147,6 +149,7 @@ static void fotg210_set_mps(struct fotg210_ep *ep, u32 epnum, u32 mps, FOTG210_OUTEPMPSR(epnum); val = ioread32(fotg210->reg + offset); + val &= ~INOUTEPMPSR_MPS(~0); val |= INOUTEPMPSR_MPS(mps); iowrite32(val, fotg210->reg + offset); } @@ -209,12 +212,13 @@ static int fotg210_ep_release(struct fotg210_ep *ep) { if (!ep->epnum) return 0; + + fotg210_reset_tseq(ep->fotg210, ep->epnum); + ep->epnum = 0; ep->stall = 0; ep->wedged = 0; - fotg210_reset_tseq(ep->fotg210, ep->epnum); - return 0; } @@ -338,6 +342,7 @@ static void fotg210_start_dma(struct fotg210_ep *ep, struct fotg210_request *req) { struct device *dev = &ep->fotg210->gadget.dev; + enum dma_data_direction direction; dma_addr_t d; u8 *buffer; u32 length; @@ -361,8 +366,8 @@ static void fotg210_start_dma(struct fotg210_ep *ep, length = req->req.length - req->req.actual; } - d = dma_map_single(dev, buffer, length, - ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + direction = ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + d = dma_map_single(dev, buffer, length, direction); if (dma_mapping_error(dev, d)) { pr_err("dma_mapping_error\n"); @@ -379,7 +384,7 @@ static void fotg210_start_dma(struct fotg210_ep *ep, /* update actual transfer length */ req->req.actual += length; - dma_unmap_single(dev, d, length, DMA_TO_DEVICE); + dma_unmap_single(dev, d, length, direction); } static void fotg210_ep0_queue(struct fotg210_ep *ep, @@ -445,7 +450,7 @@ static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) req = container_of(_req, struct fotg210_request, req); spin_lock_irqsave(&ep->fotg210->lock, flags); - if (!list_empty(&ep->queue)) + if (!list_empty(&req->queue)) fotg210_done(ep, req, -ECONNRESET); spin_unlock_irqrestore(&ep->fotg210->lock, flags); @@ -886,6 +891,8 @@ static irqreturn_t fotg210_irq(int irq, void *_fotg210) u32 int_msk = ioread32(fotg210->reg + FOTG210_DMIGR); int_grp &= ~int_msk; + if (!int_grp) + return IRQ_NONE; spin_lock(&fotg210->lock); @@ -1002,6 +1009,14 @@ static void fotg210_disable_unplug(struct fotg210_udc *fotg210) iowrite32(reg, fotg210->reg + FOTG210_PHYTMSR); } +static void fotg210_enable_unplug(struct fotg210_udc *fotg210) +{ + u32 reg = ioread32(fotg210->reg + FOTG210_PHYTMSR); + + reg |= PHYTMSR_UNPLUG; + iowrite32(reg, fotg210->reg + FOTG210_PHYTMSR); +} + static int fotg210_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { @@ -1009,20 +1024,23 @@ static int fotg210_udc_start(struct usb_gadget *g, u32 value; int ret; - /* hook up the driver */ + /* Hook up the driver before enabling device interrupts. */ fotg210->driver = driver; fotg210->gadget.dev.of_node = fotg210->dev->of_node; fotg210->gadget.speed = USB_SPEED_UNKNOWN; - dev_info(fotg210->dev, "bound driver %s\n", driver->driver.name); - if (!IS_ERR_OR_NULL(fotg210->phy)) { ret = otg_set_peripheral(fotg210->phy->otg, &fotg210->gadget); - if (ret) - dev_err(fotg210->dev, "can't bind to phy\n"); + if (ret) { + fotg210->driver = NULL; + return dev_err_probe(fotg210->dev, ret, + "can't bind to PHY\n"); + } } + dev_info(fotg210->dev, "bound driver %s\n", driver->driver.name); + /* chip enable */ value = ioread32(fotg210->reg + FOTG210_DMCR); value |= DMCR_CHIP_EN; @@ -1076,20 +1094,23 @@ static void fotg210_init(struct fotg210_udc *fotg210) static int fotg210_udc_stop(struct usb_gadget *g) { struct fotg210_udc *fotg210 = gadget_to_fotg210(g); - unsigned long flags; + unsigned long flags; + int ret = 0; if (!IS_ERR_OR_NULL(fotg210->phy)) - return otg_set_peripheral(fotg210->phy->otg, NULL); + ret = otg_set_peripheral(fotg210->phy->otg, NULL); + + /* fotg210_init() sleeps, so it must run outside the spinlock. */ + fotg210_init(fotg210); spin_lock_irqsave(&fotg210->lock, flags); - fotg210_init(fotg210); fotg210->driver = NULL; fotg210->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock_irqrestore(&fotg210->lock, flags); - return 0; + return ret; } /** @@ -1103,8 +1124,12 @@ static int fotg210_vbus_session(struct usb_gadget *g, int is_active) { struct fotg210_udc *fotg210 = gadget_to_fotg210(g); - /* Call down to core integration layer to drive or disable VBUS */ - fotg210_vbus(fotg210->fotg, is_active); + /* A peripheral must never source VBUS; only control its pull-up. */ + if (is_active) + fotg210_disable_unplug(fotg210); + else + fotg210_enable_unplug(fotg210); + return 0; } @@ -1144,28 +1169,24 @@ static int fotg210_phy_event(struct notifier_block *nb, unsigned long action, } } -static struct notifier_block fotg210_phy_notifier = { - .notifier_call = fotg210_phy_event, -}; - int fotg210_udc_remove(struct platform_device *pdev) { struct fotg210_udc *fotg210 = platform_get_drvdata(pdev); int i; usb_del_gadget_udc(&fotg210->gadget); - if (!IS_ERR_OR_NULL(fotg210->phy)) { - usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier); - usb_put_phy(fotg210->phy); - } - iounmap(fotg210->reg); + if (!IS_ERR_OR_NULL(fotg210->phy)) + usb_unregister_notifier(fotg210->phy, + &fotg210->phy_notifier); free_irq(platform_get_irq(pdev, 0), fotg210); + usb_phy_shutdown(fotg210->phy); fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); for (i = 0; i < FOTG210_MAX_NUM_EP; i++) kfree(fotg210->ep[i]); kfree(fotg210); + platform_set_drvdata(pdev, NULL); return 0; } @@ -1188,7 +1209,6 @@ int fotg210_udc_probe(struct platform_device *pdev, struct fotg210 *fotg) return -ENOMEM; fotg210->dev = dev; - fotg210->fotg = fotg; fotg210->phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); if (IS_ERR(fotg210->phy)) { @@ -1216,8 +1236,6 @@ int fotg210_udc_probe(struct platform_device *pdev, struct fotg210 *fotg) spin_lock_init(&fotg210->lock); - platform_set_drvdata(pdev, fotg210); - fotg210->gadget.ops = &fotg210_gadget_ops; fotg210->gadget.max_speed = USB_SPEED_HIGH; @@ -1267,38 +1285,45 @@ int fotg210_udc_probe(struct platform_device *pdev, struct fotg210 *fotg) fotg210_disable_unplug(fotg210); - ret = request_irq(irq, fotg210_irq, IRQF_SHARED, - udc_name, fotg210); + ret = request_irq(irq, fotg210_irq, 0, udc_name, fotg210); if (ret < 0) { dev_err_probe(dev, ret, "request_irq error\n"); goto err_req; } - if (!IS_ERR_OR_NULL(fotg210->phy)) - usb_register_notifier(fotg210->phy, &fotg210_phy_notifier); + if (!IS_ERR_OR_NULL(fotg210->phy)) { + fotg210->phy_notifier.notifier_call = fotg210_phy_event; + ret = usb_register_notifier(fotg210->phy, + &fotg210->phy_notifier); + if (ret) + goto err_notifier; + } ret = usb_add_gadget_udc(dev, &fotg210->gadget); if (ret) goto err_add_udc; + platform_set_drvdata(pdev, fotg210); + dev_info(dev, "version %s\n", DRIVER_VERSION); return 0; err_add_udc: if (!IS_ERR_OR_NULL(fotg210->phy)) - usb_unregister_notifier(fotg210->phy, &fotg210_phy_notifier); + usb_unregister_notifier(fotg210->phy, + &fotg210->phy_notifier); +err_notifier: free_irq(irq, fotg210); err_req: fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); err_map: - iounmap(fotg210->reg); - err_alloc: for (i = 0; i < FOTG210_MAX_NUM_EP; i++) kfree(fotg210->ep[i]); + usb_phy_shutdown(fotg210->phy); err_free: kfree(fotg210); diff --git a/drivers/usb/fotg210/fotg210-udc.h b/drivers/usb/fotg210/fotg210-udc.h index 252cb2b8e2fe..11fe67802537 100644 --- a/drivers/usb/fotg210/fotg210-udc.h +++ b/drivers/usb/fotg210/fotg210-udc.h @@ -237,8 +237,8 @@ struct fotg210_udc { unsigned long irq_trigger; struct device *dev; - struct fotg210 *fotg; struct usb_phy *phy; + struct notifier_block phy_notifier; struct usb_gadget gadget; struct usb_gadget_driver *driver; |
