From 260eba39bcfb5681115ec934cdfbd97e0b3a1775 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Jun 2013 17:38:09 +0200 Subject: [PATCH 001/101] usb: musb: replace ifndef with ifdef for CONFIG_MUSB_PIO_ONLY The ifdef reads somehow better than an ifndef Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dma.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 1b6b827b769f..8919ce28c3d4 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -62,10 +62,10 @@ struct musb_hw_ep; #define DMA_ADDR_INVALID (~(dma_addr_t)0) -#ifndef CONFIG_MUSB_PIO_ONLY -#define is_dma_capable() (1) -#else +#ifdef CONFIG_MUSB_PIO_ONLY #define is_dma_capable() (0) +#else +#define is_dma_capable() (1) #endif #ifdef CONFIG_USB_TI_CPPI_DMA From ff2283229da616d9a029eaa0d483fa8b0ad55e77 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Jun 2013 17:38:10 +0200 Subject: [PATCH 002/101] usb: musb: musbhsdma: drop the controller check in dma_controller_destroy() This check is hardly required and alas is wrong. 'c' might be NULL but the chances are low that 'controller' after the container_of() becomes NULL. Since no other DMA implementation is doing that and musb-core does not call it with a NULL pointer it can dropped. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musbhsdma.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 3d1fd52a15a9..3f5e121dc154 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -371,9 +371,6 @@ void dma_controller_destroy(struct dma_controller *c) struct musb_dma_controller *controller = container_of(c, struct musb_dma_controller, controller); - if (!controller) - return; - if (controller->irq) free_irq(controller->irq, c); From 66c01883ef19bf4537b16931567b7d35c65356ad Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Jun 2013 17:38:11 +0200 Subject: [PATCH 003/101] usb: musb: dma: merge ->start/stop into create/destroy The core code creates a controller and immediately after that it calls the ->start() callback. This one might drop an error but nobody cares. The same thing happens in the destroy corner: First ->stop() called followed by destroy callback. So why not merge those two into the same function since there is no difference. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/cppi_dma.c | 18 +++++------------- drivers/usb/musb/musb_core.c | 18 ++++-------------- drivers/usb/musb/musb_dma.h | 2 -- drivers/usb/musb/musbhsdma.c | 16 +++------------- drivers/usb/musb/tusb6010_omap.c | 24 ------------------------ drivers/usb/musb/ux500_dma.c | 19 ++++++++----------- 6 files changed, 20 insertions(+), 77 deletions(-) diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 9db211ee15b5..904fb85d85a6 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -150,14 +150,11 @@ static void cppi_pool_free(struct cppi_channel *c) c->last_processed = NULL; } -static int cppi_controller_start(struct dma_controller *c) +static void cppi_controller_start(struct cppi *controller) { - struct cppi *controller; void __iomem *tibase; int i; - controller = container_of(c, struct cppi, controller); - /* do whatever is necessary to start controller */ for (i = 0; i < ARRAY_SIZE(controller->tx); i++) { controller->tx[i].transmit = true; @@ -212,8 +209,6 @@ static int cppi_controller_start(struct dma_controller *c) /* disable RNDIS mode, also host rx RNDIS autorequest */ musb_writel(tibase, DAVINCI_RNDIS_REG, 0); musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0); - - return 0; } /* @@ -222,14 +217,12 @@ static int cppi_controller_start(struct dma_controller *c) * De-Init the DMA controller as necessary. */ -static int cppi_controller_stop(struct dma_controller *c) +static void cppi_controller_stop(struct cppi *controller) { - struct cppi *controller; void __iomem *tibase; int i; struct musb *musb; - controller = container_of(c, struct cppi, controller); musb = controller->musb; tibase = controller->tibase; @@ -255,8 +248,6 @@ static int cppi_controller_stop(struct dma_controller *c) /*disable tx/rx cppi */ musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); - - return 0; } /* While dma channel is allocated, we only want the core irqs active @@ -1321,8 +1312,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr controller->tibase = mregs - DAVINCI_BASE_OFFSET; controller->musb = musb; - controller->controller.start = cppi_controller_start; - controller->controller.stop = cppi_controller_stop; controller->controller.channel_alloc = cppi_channel_allocate; controller->controller.channel_release = cppi_channel_release; controller->controller.channel_program = cppi_channel_program; @@ -1351,6 +1340,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr controller->irq = irq; } + cppi_controller_start(controller); return &controller->controller; } @@ -1363,6 +1353,8 @@ void dma_controller_destroy(struct dma_controller *c) cppi = container_of(c, struct cppi, controller); + cppi_controller_stop(cppi); + if (cppi->irq) free_irq(cppi->irq, cppi->musb); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 29a24ced6748..a4434d22ef13 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1764,12 +1764,8 @@ static void musb_free(struct musb *musb) disable_irq_wake(musb->nIrq); free_irq(musb->nIrq, musb); } - if (is_dma_capable() && musb->dma_controller) { - struct dma_controller *c = musb->dma_controller; - - (void) c->stop(c); - dma_controller_destroy(c); - } + if (is_dma_capable() && musb->dma_controller) + dma_controller_destroy(musb->dma_controller); musb_host_free(musb); } @@ -1845,14 +1841,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_get_sync(musb->controller); #ifndef CONFIG_MUSB_PIO_ONLY - if (use_dma && dev->dma_mask) { - struct dma_controller *c; - - c = dma_controller_create(musb, musb->mregs); - musb->dma_controller = c; - if (c) - (void) c->start(c); - } + if (use_dma && dev->dma_mask) + musb->dma_controller = dma_controller_create(musb, musb->mregs); #endif /* ideally this would be abstracted in platform setup */ if (!is_dma_capable() || !musb->dma_controller) diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 8919ce28c3d4..36037114ad4a 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -159,8 +159,6 @@ dma_channel_status(struct dma_channel *c) * Controllers manage dma channels. */ struct dma_controller { - int (*start)(struct dma_controller *); - int (*stop)(struct dma_controller *); struct dma_channel *(*channel_alloc)(struct dma_controller *, struct musb_hw_ep *, u8 is_tx); void (*channel_release)(struct dma_channel *); diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 3f5e121dc154..e8e9f9aab203 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -37,18 +37,10 @@ #include "musb_core.h" #include "musbhsdma.h" -static int dma_controller_start(struct dma_controller *c) -{ - /* nothing to do */ - return 0; -} - static void dma_channel_release(struct dma_channel *channel); -static int dma_controller_stop(struct dma_controller *c) +static void dma_controller_stop(struct musb_dma_controller *controller) { - struct musb_dma_controller *controller = container_of(c, - struct musb_dma_controller, controller); struct musb *musb = controller->private_data; struct dma_channel *channel; u8 bit; @@ -67,8 +59,6 @@ static int dma_controller_stop(struct dma_controller *c) } } } - - return 0; } static struct dma_channel *dma_channel_allocate(struct dma_controller *c, @@ -371,6 +361,8 @@ void dma_controller_destroy(struct dma_controller *c) struct musb_dma_controller *controller = container_of(c, struct musb_dma_controller, controller); + dma_controller_stop(controller); + if (controller->irq) free_irq(controller->irq, c); @@ -397,8 +389,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba controller->private_data = musb; controller->base = base; - controller->controller.start = dma_controller_start; - controller->controller.stop = dma_controller_stop; controller->controller.channel_alloc = dma_channel_allocate; controller->controller.channel_release = dma_channel_release; controller->controller.channel_program = dma_channel_program; diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index 98df17c984a8..b8794eb81e9c 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -66,28 +66,6 @@ struct tusb_omap_dma { unsigned multichannel:1; }; -static int tusb_omap_dma_start(struct dma_controller *c) -{ - struct tusb_omap_dma *tusb_dma; - - tusb_dma = container_of(c, struct tusb_omap_dma, controller); - - /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */ - - return 0; -} - -static int tusb_omap_dma_stop(struct dma_controller *c) -{ - struct tusb_omap_dma *tusb_dma; - - tusb_dma = container_of(c, struct tusb_omap_dma, controller); - - /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */ - - return 0; -} - /* * Allocate dmareq0 to the current channel unless it's already taken */ @@ -695,8 +673,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba tusb_dma->dmareq = -1; tusb_dma->sync_dev = -1; - tusb_dma->controller.start = tusb_omap_dma_start; - tusb_dma->controller.stop = tusb_omap_dma_stop; tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate; tusb_dma->controller.channel_release = tusb_omap_dma_release; tusb_dma->controller.channel_program = tusb_omap_dma_program; diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index bfb7a65d83cc..1ce214e5b7ad 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -254,10 +254,8 @@ static int ux500_dma_channel_abort(struct dma_channel *channel) return 0; } -static int ux500_dma_controller_stop(struct dma_controller *c) +static void ux500_dma_controller_stop(struct ux500_dma_controller *controller) { - struct ux500_dma_controller *controller = container_of(c, - struct ux500_dma_controller, controller); struct ux500_dma_channel *ux500_channel; struct dma_channel *channel; u8 ch_num; @@ -281,14 +279,10 @@ static int ux500_dma_controller_stop(struct dma_controller *c) if (ux500_channel->dma_chan) dma_release_channel(ux500_channel->dma_chan); } - - return 0; } -static int ux500_dma_controller_start(struct dma_controller *c) +static int ux500_dma_controller_start(struct ux500_dma_controller *controller) { - struct ux500_dma_controller *controller = container_of(c, - struct ux500_dma_controller, controller); struct ux500_dma_channel *ux500_channel = NULL; struct musb *musb = controller->private_data; struct device *dev = musb->controller; @@ -347,7 +341,7 @@ static int ux500_dma_controller_start(struct dma_controller *c) dir, ch_num); /* Release already allocated channels */ - ux500_dma_controller_stop(c); + ux500_dma_controller_stop(controller); return -EBUSY; } @@ -369,6 +363,7 @@ void dma_controller_destroy(struct dma_controller *c) struct ux500_dma_controller *controller = container_of(c, struct ux500_dma_controller, controller); + ux500_dma_controller_stop(controller); kfree(controller); } @@ -378,6 +373,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, struct ux500_dma_controller *controller; struct platform_device *pdev = to_platform_device(musb->controller); struct resource *iomem; + int ret; controller = kzalloc(sizeof(*controller), GFP_KERNEL); if (!controller) @@ -394,14 +390,15 @@ struct dma_controller *dma_controller_create(struct musb *musb, controller->phy_base = (dma_addr_t) iomem->start; - controller->controller.start = ux500_dma_controller_start; - controller->controller.stop = ux500_dma_controller_stop; controller->controller.channel_alloc = ux500_dma_channel_allocate; controller->controller.channel_release = ux500_dma_channel_release; controller->controller.channel_program = ux500_dma_channel_program; controller->controller.channel_abort = ux500_dma_channel_abort; controller->controller.is_compatible = ux500_dma_is_compatible; + ret = ux500_dma_controller_start(controller); + if (ret) + goto plat_get_fail; return &controller->controller; plat_get_fail: From a6a20885f1e13340e30ec35acfdcf14756ecf03c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Jun 2013 17:38:12 +0200 Subject: [PATCH 004/101] usb: musb: provide empty dma_controller_create() in PIO mode Add a dma_controller_create() returning NULL so a few ifdefs can dropped. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dma.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 36037114ad4a..c8e67fde2156 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -175,9 +175,20 @@ struct dma_controller { /* called after channel_program(), may indicate a fault */ extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); +#ifdef CONFIG_MUSB_PIO_ONLY +static inline struct dma_controller *dma_controller_create(struct musb *m, + void __iomem *io) +{ + return NULL; +} + +static inline void dma_controller_destroy(struct dma_controller *d) { } + +#else extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *); extern void dma_controller_destroy(struct dma_controller *); +#endif #endif /* __MUSB_DMA_H__ */ From 6904b845e27830ea0dc8d00fada5a3f478924ea3 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Jun 2013 17:38:13 +0200 Subject: [PATCH 005/101] usb: musb: remove a few is_dma_capable() in init/exit code This patch removes is_dma_capable() and an ifdef in the init/exit path around init/de-init of the dma_controller. Since we have the empty stubs in the PIO code we can call it without gcc trouble. Earlier we had an ifdef and the is_dma_capable() macro where gcc ignored the if (0) path even that the function was not around :) Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index a4434d22ef13..b33bed5b0dc8 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1764,7 +1764,7 @@ static void musb_free(struct musb *musb) disable_irq_wake(musb->nIrq); free_irq(musb->nIrq, musb); } - if (is_dma_capable() && musb->dma_controller) + if (musb->dma_controller) dma_controller_destroy(musb->dma_controller); musb_host_free(musb); @@ -1840,12 +1840,11 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_get_sync(musb->controller); -#ifndef CONFIG_MUSB_PIO_ONLY if (use_dma && dev->dma_mask) musb->dma_controller = dma_controller_create(musb, musb->mregs); -#endif + /* ideally this would be abstracted in platform setup */ - if (!is_dma_capable() || !musb->dma_controller) + if (!musb->dma_controller) dev->dma_mask = NULL; /* be sure interrupts are disabled before connecting ISR */ From f3ce4d5b2d8d714407a646c07505c5174afd7574 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Jun 2013 17:38:14 +0200 Subject: [PATCH 006/101] usb: musb: core: call dma_controller_destroy() in the err path The cleanup in the error is missing the dma controller. The structure is allocated at runtime and ux500 allocates even a little more than just this struct. So cleanup! Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b33bed5b0dc8..9b774e72c0e4 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1933,6 +1933,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb_gadget_cleanup(musb); fail3: + if (musb->dma_controller) + dma_controller_destroy(musb->dma_controller); pm_runtime_put_sync(musb->controller); fail2: From 23a53d9008251825a4c8eea64503ed676e1d0f04 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 19 Jun 2013 17:38:15 +0200 Subject: [PATCH 007/101] usb: musb: unmap reqs in musb_gadget_queue()'s error case If the descriptor is missing the reqeust is never unmapped. This patch changes this and renames the cleanup label to unlock since there is no cleanup done. The cleanup would revert the allocation of ressource (i.e. this dma mapping) but it does not, it simply unlocks and returns. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 0414bc19d009..96632f9e3eeb 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1266,7 +1266,8 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, dev_dbg(musb->controller, "req %p queued to %s while ep %s\n", req, ep->name, "disabled"); status = -ESHUTDOWN; - goto cleanup; + unmap_dma_buffer(request, musb); + goto unlock; } /* add request to the list */ @@ -1276,7 +1277,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, if (!musb_ep->busy && &request->list == musb_ep->req_list.next) musb_ep_restart(musb, request); -cleanup: +unlock: spin_unlock_irqrestore(&musb->lock, lockflags); return status; } From 1a356dbc6465b0a87474993dafcd7a101ef57ff9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 26 Jun 2013 15:14:06 +0300 Subject: [PATCH 008/101] usb: dwc3: make glue layers selectable Glue layers are starting to have separate requirements. For example, OMAP's glue layer is starting to use extcon framework which no one else needs. In order to make it clear the proper dependencies, we are now allowing glue layers to be selectable so that each glue layer can list their own dependencies without messing with the core IP driver. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/Kconfig | 32 ++++++++++++++++++++++++++++++++ drivers/usb/dwc3/Makefile | 13 +++---------- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 2378958ea63e..3e225d5846f6 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -40,6 +40,38 @@ config USB_DWC3_DUAL_ROLE endchoice +comment "Platform Glue Driver Support" + +config USB_DWC3_OMAP + tristate "Texas Instruments OMAP5 and similar Platforms" + depends on EXTCON + default USB_DWC3 + help + Some platforms from Texas Instruments like OMAP5, DRA7xxx and + AM437x use this IP for USB2/3 functionality. + + Say 'Y' or 'M' here if you have one such device + +config USB_DWC3_EXYNOS + tristate "Samsung Exynos Platform" + default USB_DWC3 + help + Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, + say 'Y' or 'M' if you have one such device. + +config USB_DWC3_PCI + tristate "PCIe-based Platforms" + depends on PCI + default USB_DWC3 + help + If you're using the DesignWare Core IP with a PCIe, please say + 'Y' or 'M' here. + + One such PCIe-based platform is Synopsys' PCIe HAPS model of + this IP. + +comment "Debugging features" + config USB_DWC3_DEBUG bool "Enable Debugging Messages" help diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 0c7ac92582be..dd1760145c46 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -27,15 +27,8 @@ endif # the entire driver (with all its glue layers) on several architectures # and make sure it compiles fine. This will also help with allmodconfig # and allyesconfig builds. -# -# The only exception is the PCI glue layer, but that's only because -# PCI doesn't provide nops if CONFIG_PCI isn't enabled. ## -obj-$(CONFIG_USB_DWC3) += dwc3-omap.o -obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o - -ifneq ($(CONFIG_PCI),) - obj-$(CONFIG_USB_DWC3) += dwc3-pci.o -endif - +obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o +obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o +obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o From 2b0c49530bc5fdbde93295e5c8f26f55d0de1e04 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 27 Jun 2013 10:20:44 +0300 Subject: [PATCH 009/101] usb: gadget: remove imx_udc That driver hasn't been really maintained for a long time. It doesn't compile in any way, it includes non-existent headers, has no users, and is just plain broken. The person who used to work with that driver has publicly stated that he has no plans to touch that driver again and is ok with removal[1]. Due to these factors, imx_udc is now removed from the tree, if someone really believe it needs to be kept, please fix the bugs in that driver. [1] http://marc.info/?l=linux-usb&m=136197620417636&w=2 Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 15 - drivers/usb/gadget/Makefile | 1 - drivers/usb/gadget/imx_udc.c | 1544 ---------------------------------- drivers/usb/gadget/imx_udc.h | 351 -------- 4 files changed, 1911 deletions(-) delete mode 100644 drivers/usb/gadget/imx_udc.c delete mode 100644 drivers/usb/gadget/imx_udc.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 8e9368330b10..08dab3c640fd 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -287,21 +287,6 @@ config USB_S3C_HSOTG The Samsung S3C64XX USB2.0 high-speed gadget controller integrated into the S3C64XX series SoC. -config USB_IMX - tristate "Freescale i.MX1 USB Peripheral Controller" - depends on ARCH_MXC - depends on BROKEN - help - Freescale's i.MX1 includes an integrated full speed - USB 1.1 device controller. - - It has Six fixed-function endpoints, as well as endpoint - zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "imx_udc" and force all - gadget drivers to also be dynamically linked. - config USB_S3C2410 tristate "S3C2410 USB Device Controller" depends on ARCH_S3C24XX diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index bad08e66f369..386db9daf1d9 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o -obj-$(CONFIG_USB_IMX) += imx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c deleted file mode 100644 index 9b2d24e4c95f..000000000000 --- a/drivers/usb/gadget/imx_udc.c +++ /dev/null @@ -1,1544 +0,0 @@ -/* - * driver/usb/gadget/imx_udc.c - * - * Copyright (C) 2005 Mike Lee - * Copyright (C) 2008 Darius Augulis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "imx_udc.h" - -static const char driver_name[] = "imx_udc"; -static const char ep0name[] = "ep0"; - -void ep0_chg_stat(const char *label, struct imx_udc_struct *imx_usb, - enum ep0_state stat); - -/******************************************************************************* - * IMX UDC hardware related functions - ******************************************************************************* - */ - -void imx_udc_enable(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA, - imx_usb->base + USB_CTRL); - imx_usb->gadget.speed = USB_SPEED_FULL; -} - -void imx_udc_disable(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_CTRL); - - __raw_writel(temp & ~(CTRL_FE_ENA | CTRL_AFE_ENA), - imx_usb->base + USB_CTRL); - - ep0_chg_stat(__func__, imx_usb, EP0_IDLE); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; -} - -void imx_udc_reset(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_ENAB); - - /* set RST bit */ - __raw_writel(temp | ENAB_RST, imx_usb->base + USB_ENAB); - - /* wait RST bit to clear */ - do {} while (__raw_readl(imx_usb->base + USB_ENAB) & ENAB_RST); - - /* wait CFG bit to assert */ - do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG)); - - /* udc module is now ready */ -} - -void imx_udc_config(struct imx_udc_struct *imx_usb) -{ - u8 ep_conf[5]; - u8 i, j, cfg; - struct imx_ep_struct *imx_ep; - - /* wait CFG bit to assert */ - do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG)); - - /* Download the endpoint buffer for endpoint 0. */ - for (j = 0; j < 5; j++) { - i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00); - __raw_writeb(i, imx_usb->base + USB_DDAT); - do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY); - } - - /* Download the endpoint buffers for endpoints 1-5. - * We specify two configurations, one interface - */ - for (cfg = 1; cfg < 3; cfg++) { - for (i = 1; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - /* EP no | Config no */ - ep_conf[0] = (i << 4) | (cfg << 2); - /* Type | Direction */ - ep_conf[1] = (imx_ep->bmAttributes << 3) | - (EP_DIR(imx_ep) << 2); - /* Max packet size */ - ep_conf[2] = imx_ep->fifosize; - /* TRXTYP */ - ep_conf[3] = 0xC0; - /* FIFO no */ - ep_conf[4] = i; - - D_INI(imx_usb->dev, - "<%s> ep%d_conf[%d]:" - "[%02x-%02x-%02x-%02x-%02x]\n", - __func__, i, cfg, - ep_conf[0], ep_conf[1], ep_conf[2], - ep_conf[3], ep_conf[4]); - - for (j = 0; j < 5; j++) { - __raw_writeb(ep_conf[j], - imx_usb->base + USB_DDAT); - do {} while (__raw_readl(imx_usb->base - + USB_DADR) - & DADR_BSY); - } - } - } - - /* wait CFG bit to clear */ - do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG); -} - -void imx_udc_init_irq(struct imx_udc_struct *imx_usb) -{ - int i; - - /* Mask and clear all irqs */ - __raw_writel(0xFFFFFFFF, imx_usb->base + USB_MASK); - __raw_writel(0xFFFFFFFF, imx_usb->base + USB_INTR); - for (i = 0; i < IMX_USB_NB_EP; i++) { - __raw_writel(0x1FF, imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_usb->base + USB_EP_INTR(i)); - } - - /* Enable USB irqs */ - __raw_writel(INTR_MSOF | INTR_FRAME_MATCH, imx_usb->base + USB_MASK); - - /* Enable EP0 irqs */ - __raw_writel(0x1FF & ~(EPINTR_DEVREQ | EPINTR_MDEVREQ | EPINTR_EOT - | EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL), - imx_usb->base + USB_EP_MASK(0)); -} - -void imx_udc_init_ep(struct imx_udc_struct *imx_usb) -{ - int i, max, temp; - struct imx_ep_struct *imx_ep; - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - switch (imx_ep->fifosize) { - case 8: - max = 0; - break; - case 16: - max = 1; - break; - case 32: - max = 2; - break; - case 64: - max = 3; - break; - default: - max = 1; - break; - } - temp = (EP_DIR(imx_ep) << 7) | (max << 5) - | (imx_ep->bmAttributes << 3); - __raw_writel(temp, imx_usb->base + USB_EP_STAT(i)); - __raw_writel(temp | EPSTAT_FLUSH, - imx_usb->base + USB_EP_STAT(i)); - D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_STAT(i))); - } -} - -void imx_udc_init_fifo(struct imx_udc_struct *imx_usb) -{ - int i, temp; - struct imx_ep_struct *imx_ep; - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - - /* Fifo control */ - temp = EP_DIR(imx_ep) ? 0x0B000000 : 0x0F000000; - __raw_writel(temp, imx_usb->base + USB_EP_FCTRL(i)); - D_INI(imx_usb->dev, "<%s> ep%d_fctrl %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_FCTRL(i))); - - /* Fifo alarm */ - temp = (i ? imx_ep->fifosize / 2 : 0); - __raw_writel(temp, imx_usb->base + USB_EP_FALRM(i)); - D_INI(imx_usb->dev, "<%s> ep%d_falrm %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_FALRM(i))); - } -} - -static void imx_udc_init(struct imx_udc_struct *imx_usb) -{ - /* Reset UDC */ - imx_udc_reset(imx_usb); - - /* Download config to enpoint buffer */ - imx_udc_config(imx_usb); - - /* Setup interrups */ - imx_udc_init_irq(imx_usb); - - /* Setup endpoints */ - imx_udc_init_ep(imx_usb); - - /* Setup fifos */ - imx_udc_init_fifo(imx_usb); -} - -void imx_ep_irq_enable(struct imx_ep_struct *imx_ep) -{ - - int i = EP_NO(imx_ep); - - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i)); - __raw_writel(0x1FF & ~(EPINTR_EOT | EPINTR_EOF), - imx_ep->imx_usb->base + USB_EP_MASK(i)); -} - -void imx_ep_irq_disable(struct imx_ep_struct *imx_ep) -{ - - int i = EP_NO(imx_ep); - - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i)); -} - -int imx_ep_empty(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - return __raw_readl(imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))) - & FSTAT_EMPTY; -} - -unsigned imx_fifo_bcount(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - return (__raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))) - & EPSTAT_BCOUNT) >> 16; -} - -void imx_flush(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - int temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_FLUSH, - imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); -} - -void imx_ep_stall(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - int temp, i; - - D_ERR(imx_usb->dev, - "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name); - - imx_flush(imx_ep); - - /* Special care for ep0 */ - if (!EP_NO(imx_ep)) { - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, - imx_usb->base + USB_CTRL); - do { } while (__raw_readl(imx_usb->base + USB_CTRL) - & CTRL_CMDOVER); - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL); - } - else { - temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_STALL, - imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - - for (i = 0; i < 100; i ++) { - temp = __raw_readl(imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - if (!(temp & EPSTAT_STALL)) - break; - udelay(20); - } - if (i == 100) - D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n", - __func__, imx_ep->ep.name); - } -} - -static int imx_udc_get_frame(struct usb_gadget *_gadget) -{ - struct imx_udc_struct *imx_usb = container_of(_gadget, - struct imx_udc_struct, gadget); - - return __raw_readl(imx_usb->base + USB_FRAME) & 0x7FF; -} - -static int imx_udc_wakeup(struct usb_gadget *_gadget) -{ - return 0; -} - -/******************************************************************************* - * USB request control functions - ******************************************************************************* - */ - -static void ep_add_request(struct imx_ep_struct *imx_ep, - struct imx_request *req) -{ - if (unlikely(!req)) - return; - - req->in_use = 1; - list_add_tail(&req->queue, &imx_ep->queue); -} - -static void ep_del_request(struct imx_ep_struct *imx_ep, - struct imx_request *req) -{ - if (unlikely(!req)) - return; - - list_del_init(&req->queue); - req->in_use = 0; -} - -static void done(struct imx_ep_struct *imx_ep, - struct imx_request *req, int status) -{ - ep_del_request(imx_ep, req); - - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - if (status && status != -ESHUTDOWN) - D_ERR(imx_ep->imx_usb->dev, - "<%s> complete %s req %p stat %d len %u/%u\n", __func__, - imx_ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - req->req.complete(&imx_ep->ep, &req->req); -} - -static void nuke(struct imx_ep_struct *imx_ep, int status) -{ - struct imx_request *req; - - while (!list_empty(&imx_ep->queue)) { - req = list_entry(imx_ep->queue.next, struct imx_request, queue); - done(imx_ep, req, status); - } -} - -/******************************************************************************* - * Data tansfer over USB functions - ******************************************************************************* - */ -static int read_packet(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - u8 *buf; - int bytes_ep, bufferspace, count, i; - - bytes_ep = imx_fifo_bcount(imx_ep); - bufferspace = req->req.length - req->req.actual; - - buf = req->req.buf + req->req.actual; - prefetchw(buf); - - if (unlikely(imx_ep_empty(imx_ep))) - count = 0; /* zlp */ - else - count = min(bytes_ep, bufferspace); - - for (i = count; i > 0; i--) - *buf++ = __raw_readb(imx_ep->imx_usb->base - + USB_EP_FDAT0(EP_NO(imx_ep))); - req->req.actual += count; - - return count; -} - -static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - u8 *buf; - int length, count, temp; - - if (unlikely(__raw_readl(imx_ep->imx_usb->base + - USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) { - D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n", - __func__, imx_ep->ep.name); - return -1; - } - - buf = req->req.buf + req->req.actual; - prefetch(buf); - - length = min(req->req.length - req->req.actual, (u32)imx_ep->fifosize); - - if (imx_fifo_bcount(imx_ep) + length > imx_ep->fifosize) { - D_TRX(imx_ep->imx_usb->dev, "<%s> packet overfill %s fifo\n", - __func__, imx_ep->ep.name); - return -1; - } - - req->req.actual += length; - count = length; - - if (!count && req->req.zero) { /* zlp */ - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_ZLPS, imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - D_TRX(imx_ep->imx_usb->dev, "<%s> zero packet\n", __func__); - return 0; - } - - while (count--) { - if (count == 0) { /* last byte */ - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_FCTRL(EP_NO(imx_ep))); - __raw_writel(temp | FCTRL_WFR, imx_ep->imx_usb->base - + USB_EP_FCTRL(EP_NO(imx_ep))); - } - __raw_writeb(*buf++, - imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep))); - } - - return length; -} - -static int read_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - int bytes = 0, - count, - completed = 0; - - while (__raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))) - & FSTAT_FR) { - count = read_packet(imx_ep, req); - bytes += count; - - completed = (count != imx_ep->fifosize); - if (completed || req->req.actual == req->req.length) { - completed = 1; - break; - } - } - - if (completed || !req->req.length) { - done(imx_ep, req, 0); - D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n", - __func__, imx_ep->ep.name, req, - completed ? "completed" : "not completed"); - if (!EP_NO(imx_ep)) - ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE); - } - - D_TRX(imx_ep->imx_usb->dev, "<%s> bytes read: %d\n", __func__, bytes); - - return completed; -} - -static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - int bytes = 0, - count, - completed = 0; - - while (!completed) { - count = write_packet(imx_ep, req); - if (count < 0) - break; /* busy */ - bytes += count; - - /* last packet "must be" short (or a zlp) */ - completed = (count != imx_ep->fifosize); - - if (unlikely(completed)) { - done(imx_ep, req, 0); - D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n", - __func__, imx_ep->ep.name, req, - completed ? "completed" : "not completed"); - if (!EP_NO(imx_ep)) - ep0_chg_stat(__func__, - imx_ep->imx_usb, EP0_IDLE); - } - } - - D_TRX(imx_ep->imx_usb->dev, "<%s> bytes sent: %d\n", __func__, bytes); - - return completed; -} - -/******************************************************************************* - * Endpoint handlers - ******************************************************************************* - */ -static int handle_ep(struct imx_ep_struct *imx_ep) -{ - struct imx_request *req; - int completed = 0; - - do { - if (!list_empty(&imx_ep->queue)) - req = list_entry(imx_ep->queue.next, - struct imx_request, queue); - else { - D_REQ(imx_ep->imx_usb->dev, "<%s> no request on %s\n", - __func__, imx_ep->ep.name); - return 0; - } - - if (EP_DIR(imx_ep)) /* to host */ - completed = write_fifo(imx_ep, req); - else /* to device */ - completed = read_fifo(imx_ep, req); - - dump_ep_stat(__func__, imx_ep); - - } while (completed); - - return 0; -} - -static int handle_ep0(struct imx_ep_struct *imx_ep) -{ - struct imx_request *req = NULL; - int ret = 0; - - if (!list_empty(&imx_ep->queue)) { - req = list_entry(imx_ep->queue.next, struct imx_request, queue); - - switch (imx_ep->imx_usb->ep0state) { - - case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR */ - write_fifo(imx_ep, req); - break; - case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR */ - read_fifo(imx_ep, req); - break; - default: - D_EP0(imx_ep->imx_usb->dev, - "<%s> ep0 i/o, odd state %d\n", - __func__, imx_ep->imx_usb->ep0state); - ep_del_request(imx_ep, req); - ret = -EL2HLT; - break; - } - } - - else - D_ERR(imx_ep->imx_usb->dev, "<%s> no request on %s\n", - __func__, imx_ep->ep.name); - - return ret; -} - -static void handle_ep0_devreq(struct imx_udc_struct *imx_usb) -{ - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0]; - union { - struct usb_ctrlrequest r; - u8 raw[8]; - u32 word[2]; - } u; - int temp, i; - - nuke(imx_ep, -EPROTO); - - /* read SETUP packet */ - for (i = 0; i < 2; i++) { - if (imx_ep_empty(imx_ep)) { - D_ERR(imx_usb->dev, - "<%s> no setup packet received\n", __func__); - goto stall; - } - u.word[i] = __raw_readl(imx_usb->base - + USB_EP_FDAT(EP_NO(imx_ep))); - } - - temp = imx_ep_empty(imx_ep); - while (!imx_ep_empty(imx_ep)) { - i = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep))); - D_ERR(imx_usb->dev, - "<%s> wrong to have extra bytes for setup : 0x%08x\n", - __func__, i); - } - if (!temp) - goto stall; - - le16_to_cpus(&u.r.wValue); - le16_to_cpus(&u.r.wIndex); - le16_to_cpus(&u.r.wLength); - - D_REQ(imx_usb->dev, "<%s> SETUP %02x.%02x v%04x i%04x l%04x\n", - __func__, u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, u.r.wLength); - - if (imx_usb->set_config) { - /* NACK the host by using CMDOVER */ - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL); - - D_ERR(imx_usb->dev, - "<%s> set config req is pending, NACK the host\n", - __func__); - return; - } - - if (u.r.bRequestType & USB_DIR_IN) - ep0_chg_stat(__func__, imx_usb, EP0_IN_DATA_PHASE); - else - ep0_chg_stat(__func__, imx_usb, EP0_OUT_DATA_PHASE); - - i = imx_usb->driver->setup(&imx_usb->gadget, &u.r); - if (i < 0) { - D_ERR(imx_usb->dev, "<%s> device setup error %d\n", - __func__, i); - goto stall; - } - - return; -stall: - D_ERR(imx_usb->dev, "<%s> protocol STALL\n", __func__); - imx_ep_stall(imx_ep); - ep0_chg_stat(__func__, imx_usb, EP0_STALL); - return; -} - -/******************************************************************************* - * USB gadget callback functions - ******************************************************************************* - */ - -static int imx_ep_enable(struct usb_ep *usb_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct imx_ep_struct *imx_ep = container_of(usb_ep, - struct imx_ep_struct, ep); - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - unsigned long flags; - - if (!usb_ep - || !desc - || !EP_NO(imx_ep) - || desc->bDescriptorType != USB_DT_ENDPOINT - || imx_ep->bEndpointAddress != desc->bEndpointAddress) { - D_ERR(imx_usb->dev, - "<%s> bad ep or descriptor\n", __func__); - return -EINVAL; - } - - if (imx_ep->bmAttributes != desc->bmAttributes) { - D_ERR(imx_usb->dev, - "<%s> %s type mismatch\n", __func__, usb_ep->name); - return -EINVAL; - } - - if (imx_ep->fifosize < usb_endpoint_maxp(desc)) { - D_ERR(imx_usb->dev, - "<%s> bad %s maxpacket\n", __func__, usb_ep->name); - return -ERANGE; - } - - if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) { - D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__); - return -ESHUTDOWN; - } - - local_irq_save(flags); - - imx_ep->stopped = 0; - imx_flush(imx_ep); - imx_ep_irq_enable(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_usb->dev, "<%s> ENABLED %s\n", __func__, usb_ep->name); - return 0; -} - -static int imx_ep_disable(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of(usb_ep, - struct imx_ep_struct, ep); - unsigned long flags; - - if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) { - D_ERR(imx_ep->imx_usb->dev, "<%s> %s can not be disabled\n", - __func__, usb_ep ? imx_ep->ep.name : NULL); - return -EINVAL; - } - - local_irq_save(flags); - - imx_ep->stopped = 1; - nuke(imx_ep, -ESHUTDOWN); - imx_flush(imx_ep); - imx_ep_irq_disable(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_ep->imx_usb->dev, - "<%s> DISABLED %s\n", __func__, usb_ep->name); - return 0; -} - -static struct usb_request *imx_ep_alloc_request - (struct usb_ep *usb_ep, gfp_t gfp_flags) -{ - struct imx_request *req; - - if (!usb_ep) - return NULL; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - req->in_use = 0; - - return &req->req; -} - -static void imx_ep_free_request - (struct usb_ep *usb_ep, struct usb_request *usb_req) -{ - struct imx_request *req; - - req = container_of(usb_req, struct imx_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -static int imx_ep_queue - (struct usb_ep *usb_ep, struct usb_request *usb_req, gfp_t gfp_flags) -{ - struct imx_ep_struct *imx_ep; - struct imx_udc_struct *imx_usb; - struct imx_request *req; - unsigned long flags; - int ret = 0; - - imx_ep = container_of(usb_ep, struct imx_ep_struct, ep); - imx_usb = imx_ep->imx_usb; - req = container_of(usb_req, struct imx_request, req); - - /* - Special care on IMX udc. - Ignore enqueue when after set configuration from the - host. This assume all gadget drivers reply set - configuration with the next ep0 req enqueue. - */ - if (imx_usb->set_config && !EP_NO(imx_ep)) { - imx_usb->set_config = 0; - D_ERR(imx_usb->dev, - "<%s> gadget reply set config\n", __func__); - return 0; - } - - if (unlikely(!usb_req || !req || !usb_req->complete || !usb_req->buf)) { - D_ERR(imx_usb->dev, "<%s> bad params\n", __func__); - return -EINVAL; - } - - if (unlikely(!usb_ep || !imx_ep)) { - D_ERR(imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) { - D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__); - return -ESHUTDOWN; - } - - /* Debug */ - D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n", - __func__, EP_NO(imx_ep), - ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state - == EP0_IN_DATA_PHASE) - || (EP_NO(imx_ep) && EP_DIR(imx_ep))) - ? "IN" : "OUT", usb_req->length); - dump_req(__func__, imx_ep, usb_req); - - if (imx_ep->stopped) { - usb_req->status = -ESHUTDOWN; - return -ESHUTDOWN; - } - - if (req->in_use) { - D_ERR(imx_usb->dev, - "<%s> refusing to queue req %p (already queued)\n", - __func__, req); - return 0; - } - - local_irq_save(flags); - - usb_req->status = -EINPROGRESS; - usb_req->actual = 0; - - ep_add_request(imx_ep, req); - - if (!EP_NO(imx_ep)) - ret = handle_ep0(imx_ep); - else - ret = handle_ep(imx_ep); - - local_irq_restore(flags); - return ret; -} - -static int imx_ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req) -{ - - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - struct imx_request *req; - unsigned long flags; - - if (unlikely(!usb_ep || !EP_NO(imx_ep))) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - local_irq_save(flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &imx_ep->queue, queue) { - if (&req->req == usb_req) - break; - } - if (&req->req != usb_req) { - local_irq_restore(flags); - return -EINVAL; - } - - done(imx_ep, req, -ECONNRESET); - - local_irq_restore(flags); - return 0; -} - -static int imx_ep_set_halt(struct usb_ep *usb_ep, int value) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - unsigned long flags; - - if (unlikely(!usb_ep || !EP_NO(imx_ep))) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - local_irq_save(flags); - - if ((imx_ep->bEndpointAddress & USB_DIR_IN) - && !list_empty(&imx_ep->queue)) { - local_irq_restore(flags); - return -EAGAIN; - } - - imx_ep_stall(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_ep->imx_usb->dev, "<%s> %s halt\n", __func__, usb_ep->name); - return 0; -} - -static int imx_ep_fifo_status(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - - if (!usb_ep) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -ENODEV; - } - - if (imx_ep->imx_usb->gadget.speed == USB_SPEED_UNKNOWN) - return 0; - else - return imx_fifo_bcount(imx_ep); -} - -static void imx_ep_fifo_flush(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - unsigned long flags; - - local_irq_save(flags); - - if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - local_irq_restore(flags); - return; - } - - /* toggle and halt bits stay unchanged */ - imx_flush(imx_ep); - - local_irq_restore(flags); -} - -static struct usb_ep_ops imx_ep_ops = { - .enable = imx_ep_enable, - .disable = imx_ep_disable, - - .alloc_request = imx_ep_alloc_request, - .free_request = imx_ep_free_request, - - .queue = imx_ep_queue, - .dequeue = imx_ep_dequeue, - - .set_halt = imx_ep_set_halt, - .fifo_status = imx_ep_fifo_status, - .fifo_flush = imx_ep_fifo_flush, -}; - -/******************************************************************************* - * USB endpoint control functions - ******************************************************************************* - */ - -void ep0_chg_stat(const char *label, - struct imx_udc_struct *imx_usb, enum ep0_state stat) -{ - D_EP0(imx_usb->dev, "<%s> from %15s to %15s\n", - label, state_name[imx_usb->ep0state], state_name[stat]); - - if (imx_usb->ep0state == stat) - return; - - imx_usb->ep0state = stat; -} - -static void usb_init_data(struct imx_udc_struct *imx_usb) -{ - struct imx_ep_struct *imx_ep; - u8 i; - - /* device/ep0 records init */ - INIT_LIST_HEAD(&imx_usb->gadget.ep_list); - INIT_LIST_HEAD(&imx_usb->gadget.ep0->ep_list); - ep0_chg_stat(__func__, imx_usb, EP0_IDLE); - - /* basic endpoint records init */ - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - - if (i) { - list_add_tail(&imx_ep->ep.ep_list, - &imx_usb->gadget.ep_list); - imx_ep->stopped = 1; - } else - imx_ep->stopped = 0; - - INIT_LIST_HEAD(&imx_ep->queue); - } -} - -static void udc_stop_activity(struct imx_udc_struct *imx_usb, - struct usb_gadget_driver *driver) -{ - struct imx_ep_struct *imx_ep; - int i; - - if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - /* prevent new request submissions, kill any outstanding requests */ - for (i = 1; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - imx_flush(imx_ep); - imx_ep->stopped = 1; - imx_ep_irq_disable(imx_ep); - nuke(imx_ep, -ESHUTDOWN); - } - - imx_usb->cfg = 0; - imx_usb->intf = 0; - imx_usb->alt = 0; - - if (driver) - driver->disconnect(&imx_usb->gadget); -} - -/******************************************************************************* - * Interrupt handlers - ******************************************************************************* - */ - -/* - * Called when timer expires. - * Timer is started when CFG_CHG is received. - */ -static void handle_config(unsigned long data) -{ - struct imx_udc_struct *imx_usb = (void *)data; - struct usb_ctrlrequest u; - int temp, cfg, intf, alt; - - local_irq_disable(); - - temp = __raw_readl(imx_usb->base + USB_STAT); - cfg = (temp & STAT_CFG) >> 5; - intf = (temp & STAT_INTF) >> 3; - alt = temp & STAT_ALTSET; - - D_REQ(imx_usb->dev, - "<%s> orig config C=%d, I=%d, A=%d / " - "req config C=%d, I=%d, A=%d\n", - __func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt, - cfg, intf, alt); - - if (cfg == 1 || cfg == 2) { - - if (imx_usb->cfg != cfg) { - u.bRequest = USB_REQ_SET_CONFIGURATION; - u.bRequestType = USB_DIR_OUT | - USB_TYPE_STANDARD | - USB_RECIP_DEVICE; - u.wValue = cfg; - u.wIndex = 0; - u.wLength = 0; - imx_usb->cfg = cfg; - imx_usb->driver->setup(&imx_usb->gadget, &u); - - } - if (imx_usb->intf != intf || imx_usb->alt != alt) { - u.bRequest = USB_REQ_SET_INTERFACE; - u.bRequestType = USB_DIR_OUT | - USB_TYPE_STANDARD | - USB_RECIP_INTERFACE; - u.wValue = alt; - u.wIndex = intf; - u.wLength = 0; - imx_usb->intf = intf; - imx_usb->alt = alt; - imx_usb->driver->setup(&imx_usb->gadget, &u); - } - } - - imx_usb->set_config = 0; - - local_irq_enable(); -} - -static irqreturn_t imx_udc_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - int intr = __raw_readl(imx_usb->base + USB_INTR); - int temp; - - if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START - | INTR_RESET_STOP | INTR_CFG_CHG)) { - dump_intr(__func__, intr, imx_usb->dev); - dump_usb_stat(__func__, imx_usb); - } - - if (!imx_usb->driver) - goto end_irq; - - if (intr & INTR_SOF) { - /* Copy from Freescale BSP. - We must enable SOF intr and set CMDOVER. - Datasheet don't specifiy this action, but it - is done in Freescale BSP, so just copy it. - */ - if (imx_usb->ep0state == EP0_IDLE) { - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER, - imx_usb->base + USB_CTRL); - } - } - - if (intr & INTR_CFG_CHG) { - /* A workaround of serious IMX UDC bug. - Handling of CFG_CHG should be delayed for some time, because - IMX does not NACK the host when CFG_CHG interrupt is pending. - There is no time to handle current CFG_CHG - if next CFG_CHG or SETUP packed is send immediately. - We have to clear CFG_CHG, start the timer and - NACK the host by setting CTRL_CMDOVER - if it sends any SETUP packet. - When timer expires, handler is called to handle configuration - changes. While CFG_CHG is not handled (set_config=1), - we must NACK the host to every SETUP packed. - This delay prevents from going out of sync with host. - */ - __raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR); - imx_usb->set_config = 1; - mod_timer(&imx_usb->timer, jiffies + 5); - goto end_irq; - } - - if (intr & INTR_WAKEUP) { - if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN - && imx_usb->driver && imx_usb->driver->resume) - imx_usb->driver->resume(&imx_usb->gadget); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_FULL; - } - - if (intr & INTR_SUSPEND) { - if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN - && imx_usb->driver && imx_usb->driver->suspend) - imx_usb->driver->suspend(&imx_usb->gadget); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; - } - - if (intr & INTR_RESET_START) { - __raw_writel(intr, imx_usb->base + USB_INTR); - udc_stop_activity(imx_usb, imx_usb->driver); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; - } - - if (intr & INTR_RESET_STOP) - imx_usb->gadget.speed = USB_SPEED_FULL; - -end_irq: - __raw_writel(intr, imx_usb->base + USB_INTR); - return IRQ_HANDLED; -} - -static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0]; - int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0)); - - dump_ep_intr(__func__, 0, intr, imx_usb->dev); - - if (!imx_usb->driver) { - __raw_writel(intr, imx_usb->base + USB_EP_INTR(0)); - return IRQ_HANDLED; - } - - /* DEVREQ has highest priority */ - if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ)) - handle_ep0_devreq(imx_usb); - /* Seem i.MX is missing EOF interrupt sometimes. - * Therefore we don't monitor EOF. - * We call handle_ep0() only if a request is queued for ep0. - */ - else if (!list_empty(&imx_ep->queue)) - handle_ep0(imx_ep); - - __raw_writel(intr, imx_usb->base + USB_EP_INTR(0)); - - return IRQ_HANDLED; -} - -#ifndef MX1_INT_USBD0 -#define MX1_INT_USBD0 MX1_USBD_INT0 -#endif - -static irqreturn_t imx_udc_bulk_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - MX1_INT_USBD0]; - int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - - dump_ep_intr(__func__, irq - MX1_INT_USBD0, intr, imx_usb->dev); - - if (!imx_usb->driver) { - __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - return IRQ_HANDLED; - } - - handle_ep(imx_ep); - - __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - - return IRQ_HANDLED; -} - -irq_handler_t intr_handler(int i) -{ - switch (i) { - case 0: - return imx_udc_ctrl_irq; - case 1: - case 2: - case 3: - case 4: - case 5: - return imx_udc_bulk_irq; - default: - return imx_udc_irq; - } -} - -/******************************************************************************* - * Static defined IMX UDC structure - ******************************************************************************* - */ - -static int imx_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver); -static int imx_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver); -static const struct usb_gadget_ops imx_udc_ops = { - .get_frame = imx_udc_get_frame, - .wakeup = imx_udc_wakeup, - .udc_start = imx_udc_start, - .udc_stop = imx_udc_stop, -}; - -static struct imx_udc_struct controller = { - .gadget = { - .ops = &imx_udc_ops, - .ep0 = &controller.imx_ep[0].ep, - .name = driver_name, - .dev = { - .init_name = "gadget", - }, - }, - - .imx_ep[0] = { - .ep = { - .name = ep0name, - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - }, - .imx_ep[1] = { - .ep = { - .name = "ep1in-bulk", - .ops = &imx_ep_ops, - .maxpacket = 64, - }, - .imx_usb = &controller, - .fifosize = 64, - .bEndpointAddress = USB_DIR_IN | 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[2] = { - .ep = { - .name = "ep2out-bulk", - .ops = &imx_ep_ops, - .maxpacket = 64, - }, - .imx_usb = &controller, - .fifosize = 64, - .bEndpointAddress = USB_DIR_OUT | 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[3] = { - .ep = { - .name = "ep3out-bulk", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_OUT | 3, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[4] = { - .ep = { - .name = "ep4in-int", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_IN | 4, - .bmAttributes = USB_ENDPOINT_XFER_INT, - }, - .imx_ep[5] = { - .ep = { - .name = "ep5out-int", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_OUT | 5, - .bmAttributes = USB_ENDPOINT_XFER_INT, - }, -}; - -/******************************************************************************* - * USB gadget driver functions - ******************************************************************************* - */ -static int imx_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct imx_udc_struct *imx_usb; - - imx_usb = container_of(gadget, struct imx_udc_struct, gadget); - /* first hook up the driver ... */ - imx_usb->driver = driver; - - D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n", - __func__, driver->driver.name); - - imx_udc_enable(imx_usb); - - return 0; -} - -static int imx_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct imx_udc_struct *imx_usb = container_of(gadget, - struct imx_udc_struct, gadget); - - udc_stop_activity(imx_usb, driver); - imx_udc_disable(imx_usb); - del_timer(&imx_usb->timer); - - imx_usb->driver = NULL; - - D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n", - __func__, driver->driver.name); - - return 0; -} - -/******************************************************************************* - * Module functions - ******************************************************************************* - */ - -static int __init imx_udc_probe(struct platform_device *pdev) -{ - struct imx_udc_struct *imx_usb = &controller; - struct resource *res; - struct imxusb_platform_data *pdata; - struct clk *clk; - void __iomem *base; - int ret = 0; - int i; - resource_size_t res_size; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "can't get device resources\n"); - return -ENODEV; - } - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "driver needs platform data\n"); - return -ENODEV; - } - - res_size = resource_size(res); - if (!request_mem_region(res->start, res_size, res->name)) { - dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n", - res_size, res->start); - return -ENOMEM; - } - - if (pdata->init) { - ret = pdata->init(&pdev->dev); - if (ret) - goto fail0; - } - - base = ioremap(res->start, res_size); - if (!base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -EIO; - goto fail1; - } - - clk = clk_get(NULL, "usbd_clk"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(&pdev->dev, "can't get USB clock\n"); - goto fail2; - } - clk_prepare_enable(clk); - - if (clk_get_rate(clk) != 48000000) { - D_INI(&pdev->dev, - "Bad USB clock (%d Hz), changing to 48000000 Hz\n", - (int)clk_get_rate(clk)); - if (clk_set_rate(clk, 48000000)) { - dev_err(&pdev->dev, - "Unable to set correct USB clock (48MHz)\n"); - ret = -EIO; - goto fail3; - } - } - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) { - imx_usb->usbd_int[i] = platform_get_irq(pdev, i); - if (imx_usb->usbd_int[i] < 0) { - dev_err(&pdev->dev, "can't get irq number\n"); - ret = -ENODEV; - goto fail3; - } - } - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) { - ret = request_irq(imx_usb->usbd_int[i], intr_handler(i), - 0, driver_name, imx_usb); - if (ret) { - dev_err(&pdev->dev, "can't get irq %i, err %d\n", - imx_usb->usbd_int[i], ret); - for (--i; i >= 0; i--) - free_irq(imx_usb->usbd_int[i], imx_usb); - goto fail3; - } - } - - imx_usb->res = res; - imx_usb->base = base; - imx_usb->clk = clk; - imx_usb->dev = &pdev->dev; - - platform_set_drvdata(pdev, imx_usb); - - usb_init_data(imx_usb); - imx_udc_init(imx_usb); - - init_timer(&imx_usb->timer); - imx_usb->timer.function = handle_config; - imx_usb->timer.data = (unsigned long)imx_usb; - - ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget); - if (ret) - goto fail4; - - return 0; -fail4: - for (i = 0; i < IMX_USB_NB_EP + 1; i++) - free_irq(imx_usb->usbd_int[i], imx_usb); -fail3: - clk_put(clk); - clk_disable_unprepare(clk); -fail2: - iounmap(base); -fail1: - if (pdata->exit) - pdata->exit(&pdev->dev); -fail0: - release_mem_region(res->start, res_size); - return ret; -} - -static int __exit imx_udc_remove(struct platform_device *pdev) -{ - struct imx_udc_struct *imx_usb = platform_get_drvdata(pdev); - struct imxusb_platform_data *pdata = pdev->dev.platform_data; - int i; - - usb_del_gadget_udc(&imx_usb->gadget); - imx_udc_disable(imx_usb); - del_timer(&imx_usb->timer); - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) - free_irq(imx_usb->usbd_int[i], imx_usb); - - clk_put(imx_usb->clk); - clk_disable_unprepare(imx_usb->clk); - iounmap(imx_usb->base); - - release_mem_region(imx_usb->res->start, resource_size(imx_usb->res)); - - if (pdata->exit) - pdata->exit(&pdev->dev); - - return 0; -} - -/*----------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM -#define imx_udc_suspend NULL -#define imx_udc_resume NULL -#else -#define imx_udc_suspend NULL -#define imx_udc_resume NULL -#endif - -/*----------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .driver = { - .name = driver_name, - .owner = THIS_MODULE, - }, - .remove = __exit_p(imx_udc_remove), - .suspend = imx_udc_suspend, - .resume = imx_udc_resume, -}; - -module_platform_driver_probe(udc_driver, imx_udc_probe); - -MODULE_DESCRIPTION("IMX USB Device Controller driver"); -MODULE_AUTHOR("Darius Augulis "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx_udc"); diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h deleted file mode 100644 index d118fb777840..000000000000 --- a/drivers/usb/gadget/imx_udc.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (C) 2005 Mike Lee(eemike@gmail.com) - * - * This udc driver is now under testing and code is based on pxa2xx_udc.h - * Please use it with your own risk! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __LINUX_USB_GADGET_IMX_H -#define __LINUX_USB_GADGET_IMX_H - -#include - -/* Helper macros */ -#define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */ -#define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0) -#define IMX_USB_NB_EP 6 - -/* Driver structures */ -struct imx_request { - struct usb_request req; - struct list_head queue; - unsigned int in_use; -}; - -enum ep0_state { - EP0_IDLE, - EP0_IN_DATA_PHASE, - EP0_OUT_DATA_PHASE, - EP0_CONFIG, - EP0_STALL, -}; - -struct imx_ep_struct { - struct usb_ep ep; - struct imx_udc_struct *imx_usb; - struct list_head queue; - unsigned char stopped; - unsigned char fifosize; - unsigned char bEndpointAddress; - unsigned char bmAttributes; -}; - -struct imx_udc_struct { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct device *dev; - struct imx_ep_struct imx_ep[IMX_USB_NB_EP]; - struct clk *clk; - struct timer_list timer; - enum ep0_state ep0state; - struct resource *res; - void __iomem *base; - unsigned char set_config; - int cfg, - intf, - alt, - usbd_int[7]; -}; - -/* USB registers */ -#define USB_FRAME (0x00) /* USB frame */ -#define USB_SPEC (0x04) /* USB Spec */ -#define USB_STAT (0x08) /* USB Status */ -#define USB_CTRL (0x0C) /* USB Control */ -#define USB_DADR (0x10) /* USB Desc RAM addr */ -#define USB_DDAT (0x14) /* USB Desc RAM/EP buffer data */ -#define USB_INTR (0x18) /* USB interrupt */ -#define USB_MASK (0x1C) /* USB Mask */ -#define USB_ENAB (0x24) /* USB Enable */ -#define USB_EP_STAT(x) (0x30 + (x*0x30)) /* USB status/control */ -#define USB_EP_INTR(x) (0x34 + (x*0x30)) /* USB interrupt */ -#define USB_EP_MASK(x) (0x38 + (x*0x30)) /* USB mask */ -#define USB_EP_FDAT(x) (0x3C + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT0(x) (0x3C + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT1(x) (0x3D + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT2(x) (0x3E + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT3(x) (0x3F + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FSTAT(x) (0x40 + (x*0x30)) /* USB FIFO status */ -#define USB_EP_FCTRL(x) (0x44 + (x*0x30)) /* USB FIFO control */ -#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last rd f. pointer */ -#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last wr f. pointer */ -#define USB_EP_FALRM(x) (0x50 + (x*0x30)) /* USB FIFO alarm */ -#define USB_EP_FRDP(x) (0x54 + (x*0x30)) /* USB FIFO read pointer */ -#define USB_EP_FWRP(x) (0x58 + (x*0x30)) /* USB FIFO write pointer */ -/* USB Control Register Bit Fields.*/ -#define CTRL_CMDOVER (1<<6) /* UDC status */ -#define CTRL_CMDERROR (1<<5) /* UDC status */ -#define CTRL_FE_ENA (1<<3) /* Enable Font End logic */ -#define CTRL_UDC_RST (1<<2) /* UDC reset */ -#define CTRL_AFE_ENA (1<<1) /* Analog Font end enable */ -#define CTRL_RESUME (1<<0) /* UDC resume */ -/* USB Status Register Bit Fields.*/ -#define STAT_RST (1<<8) -#define STAT_SUSP (1<<7) -#define STAT_CFG (3<<5) -#define STAT_INTF (3<<3) -#define STAT_ALTSET (7<<0) -/* USB Interrupt Status/Mask Registers Bit fields */ -#define INTR_WAKEUP (1<<31) /* Wake up Interrupt */ -#define INTR_MSOF (1<<7) /* Missed Start of Frame */ -#define INTR_SOF (1<<6) /* Start of Frame */ -#define INTR_RESET_STOP (1<<5) /* Reset Signaling stop */ -#define INTR_RESET_START (1<<4) /* Reset Signaling start */ -#define INTR_RESUME (1<<3) /* Suspend to resume */ -#define INTR_SUSPEND (1<<2) /* Active to suspend */ -#define INTR_FRAME_MATCH (1<<1) /* Frame matched */ -#define INTR_CFG_CHG (1<<0) /* Configuration change occurred */ -/* USB Enable Register Bit Fields.*/ -#define ENAB_RST (1<<31) /* Reset USB modules */ -#define ENAB_ENAB (1<<30) /* Enable USB modules*/ -#define ENAB_SUSPEND (1<<29) /* Suspend USB modules */ -#define ENAB_ENDIAN (1<<28) /* Endian of USB modules */ -#define ENAB_PWRMD (1<<0) /* Power mode of USB modules */ -/* USB Descriptor Ram Address Register bit fields */ -#define DADR_CFG (1<<31) /* Configuration */ -#define DADR_BSY (1<<30) /* Busy status */ -#define DADR_DADR (0x1FF) /* Descriptor Ram Address */ -/* USB Descriptor RAM/Endpoint Buffer Data Register bit fields */ -#define DDAT_DDAT (0xFF) /* Descriptor Endpoint Buffer */ -/* USB Endpoint Status Register bit fields */ -#define EPSTAT_BCOUNT (0x7F<<16) /* Endpoint FIFO byte count */ -#define EPSTAT_SIP (1<<8) /* Endpoint setup in progress */ -#define EPSTAT_DIR (1<<7) /* Endpoint transfer direction */ -#define EPSTAT_MAX (3<<5) /* Endpoint Max packet size */ -#define EPSTAT_TYP (3<<3) /* Endpoint type */ -#define EPSTAT_ZLPS (1<<2) /* Send zero length packet */ -#define EPSTAT_FLUSH (1<<1) /* Endpoint FIFO Flush */ -#define EPSTAT_STALL (1<<0) /* Force stall */ -/* USB Endpoint FIFO Status Register bit fields */ -#define FSTAT_FRAME_STAT (0xF<<24) /* Frame status bit [0-3] */ -#define FSTAT_ERR (1<<22) /* FIFO error */ -#define FSTAT_UF (1<<21) /* FIFO underflow */ -#define FSTAT_OF (1<<20) /* FIFO overflow */ -#define FSTAT_FR (1<<19) /* FIFO frame ready */ -#define FSTAT_FULL (1<<18) /* FIFO full */ -#define FSTAT_ALRM (1<<17) /* FIFO alarm */ -#define FSTAT_EMPTY (1<<16) /* FIFO empty */ -/* USB Endpoint FIFO Control Register bit fields */ -#define FCTRL_WFR (1<<29) /* Write frame end */ -/* USB Endpoint Interrupt Status Regsiter bit fields */ -#define EPINTR_FIFO_FULL (1<<8) /* fifo full */ -#define EPINTR_FIFO_EMPTY (1<<7) /* fifo empty */ -#define EPINTR_FIFO_ERROR (1<<6) /* fifo error */ -#define EPINTR_FIFO_HIGH (1<<5) /* fifo high */ -#define EPINTR_FIFO_LOW (1<<4) /* fifo low */ -#define EPINTR_MDEVREQ (1<<3) /* multi Device request */ -#define EPINTR_EOT (1<<2) /* fifo end of transfer */ -#define EPINTR_DEVREQ (1<<1) /* Device request */ -#define EPINTR_EOF (1<<0) /* fifo end of frame */ - -/* Debug macros */ -#ifdef DEBUG - -/* #define DEBUG_REQ */ -/* #define DEBUG_TRX */ -/* #define DEBUG_INIT */ -/* #define DEBUG_EP0 */ -/* #define DEBUG_EPX */ -/* #define DEBUG_IRQ */ -/* #define DEBUG_EPIRQ */ -/* #define DEBUG_DUMP */ -/* #define DEBUG_ERR */ - -#ifdef DEBUG_REQ - #define D_REQ(dev, args...) dev_dbg(dev, ## args) -#else - #define D_REQ(dev, args...) do {} while (0) -#endif /* DEBUG_REQ */ - -#ifdef DEBUG_TRX - #define D_TRX(dev, args...) dev_dbg(dev, ## args) -#else - #define D_TRX(dev, args...) do {} while (0) -#endif /* DEBUG_TRX */ - -#ifdef DEBUG_INIT - #define D_INI(dev, args...) dev_dbg(dev, ## args) -#else - #define D_INI(dev, args...) do {} while (0) -#endif /* DEBUG_INIT */ - -#ifdef DEBUG_EP0 - static const char *state_name[] = { - "EP0_IDLE", - "EP0_IN_DATA_PHASE", - "EP0_OUT_DATA_PHASE", - "EP0_CONFIG", - "EP0_STALL" - }; - #define D_EP0(dev, args...) dev_dbg(dev, ## args) -#else - #define D_EP0(dev, args...) do {} while (0) -#endif /* DEBUG_EP0 */ - -#ifdef DEBUG_EPX - #define D_EPX(dev, args...) dev_dbg(dev, ## args) -#else - #define D_EPX(dev, args...) do {} while (0) -#endif /* DEBUG_EP0 */ - -#ifdef DEBUG_IRQ - static void dump_intr(const char *label, int irqreg, struct device *dev) - { - dev_dbg(dev, "<%s> USB_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, - (irqreg & INTR_WAKEUP) ? " wake" : "", - (irqreg & INTR_MSOF) ? " msof" : "", - (irqreg & INTR_SOF) ? " sof" : "", - (irqreg & INTR_RESUME) ? " resume" : "", - (irqreg & INTR_SUSPEND) ? " suspend" : "", - (irqreg & INTR_RESET_STOP) ? " noreset" : "", - (irqreg & INTR_RESET_START) ? " reset" : "", - (irqreg & INTR_FRAME_MATCH) ? " fmatch" : "", - (irqreg & INTR_CFG_CHG) ? " config" : ""); - } -#else - #define dump_intr(x, y, z) do {} while (0) -#endif /* DEBUG_IRQ */ - -#ifdef DEBUG_EPIRQ - static void dump_ep_intr(const char *label, int nr, int irqreg, - struct device *dev) - { - dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr, - (irqreg & EPINTR_FIFO_FULL) ? " full" : "", - (irqreg & EPINTR_FIFO_EMPTY) ? " fempty" : "", - (irqreg & EPINTR_FIFO_ERROR) ? " ferr" : "", - (irqreg & EPINTR_FIFO_HIGH) ? " fhigh" : "", - (irqreg & EPINTR_FIFO_LOW) ? " flow" : "", - (irqreg & EPINTR_MDEVREQ) ? " mreq" : "", - (irqreg & EPINTR_EOF) ? " eof" : "", - (irqreg & EPINTR_DEVREQ) ? " devreq" : "", - (irqreg & EPINTR_EOT) ? " eot" : ""); - } -#else - #define dump_ep_intr(x, y, z, i) do {} while (0) -#endif /* DEBUG_IRQ */ - -#ifdef DEBUG_DUMP - static void dump_usb_stat(const char *label, - struct imx_udc_struct *imx_usb) - { - int temp = __raw_readl(imx_usb->base + USB_STAT); - - dev_dbg(imx_usb->dev, - "<%s> USB_STAT=[%s%s CFG=%d, INTF=%d, ALTR=%d]\n", label, - (temp & STAT_RST) ? " reset" : "", - (temp & STAT_SUSP) ? " suspend" : "", - (temp & STAT_CFG) >> 5, - (temp & STAT_INTF) >> 3, - (temp & STAT_ALTSET)); - } - - static void dump_ep_stat(const char *label, - struct imx_ep_struct *imx_ep) - { - int temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_INTR(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", - label, EP_NO(imx_ep), - (temp & EPINTR_FIFO_FULL) ? " full" : "", - (temp & EPINTR_FIFO_EMPTY) ? " fempty" : "", - (temp & EPINTR_FIFO_ERROR) ? " ferr" : "", - (temp & EPINTR_FIFO_HIGH) ? " fhigh" : "", - (temp & EPINTR_FIFO_LOW) ? " flow" : "", - (temp & EPINTR_MDEVREQ) ? " mreq" : "", - (temp & EPINTR_EOF) ? " eof" : "", - (temp & EPINTR_DEVREQ) ? " devreq" : "", - (temp & EPINTR_EOT) ? " eot" : ""); - - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_STAT=[%s%s bcount=%d]\n", - label, EP_NO(imx_ep), - (temp & EPSTAT_SIP) ? " sip" : "", - (temp & EPSTAT_STALL) ? " stall" : "", - (temp & EPSTAT_BCOUNT) >> 16); - - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_FSTAT(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n", - label, EP_NO(imx_ep), - (temp & FSTAT_ERR) ? " ferr" : "", - (temp & FSTAT_UF) ? " funder" : "", - (temp & FSTAT_OF) ? " fover" : "", - (temp & FSTAT_FR) ? " fready" : "", - (temp & FSTAT_FULL) ? " ffull" : "", - (temp & FSTAT_ALRM) ? " falarm" : "", - (temp & FSTAT_EMPTY) ? " fempty" : ""); - } - - static void dump_req(const char *label, struct imx_ep_struct *imx_ep, - struct usb_request *req) - { - int i; - - if (!req || !req->buf) { - dev_dbg(imx_ep->imx_usb->dev, - "<%s> req or req buf is free\n", label); - return; - } - - if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state - == EP0_IN_DATA_PHASE) - || (EP_NO(imx_ep) && EP_DIR(imx_ep))) { - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> request dump <", label); - for (i = 0; i < req->length; i++) - printk("%02x-", *((u8 *)req->buf + i)); - printk(">\n"); - } - } - -#else - #define dump_ep_stat(x, y) do {} while (0) - #define dump_usb_stat(x, y) do {} while (0) - #define dump_req(x, y, z) do {} while (0) -#endif /* DEBUG_DUMP */ - -#ifdef DEBUG_ERR - #define D_ERR(dev, args...) dev_dbg(dev, ## args) -#else - #define D_ERR(dev, args...) do {} while (0) -#endif - -#else - #define D_REQ(dev, args...) do {} while (0) - #define D_TRX(dev, args...) do {} while (0) - #define D_INI(dev, args...) do {} while (0) - #define D_EP0(dev, args...) do {} while (0) - #define D_EPX(dev, args...) do {} while (0) - #define dump_ep_intr(x, y, z, i) do {} while (0) - #define dump_intr(x, y, z) do {} while (0) - #define dump_ep_stat(x, y) do {} while (0) - #define dump_usb_stat(x, y) do {} while (0) - #define dump_req(x, y, z) do {} while (0) - #define D_ERR(dev, args...) do {} while (0) -#endif /* DEBUG */ - -#endif /* __LINUX_USB_GADGET_IMX_H */ From b0d7ffd44ba9cd2dfbf299674418193a5f9ed21a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 27 Jun 2013 10:00:18 +0300 Subject: [PATCH 010/101] usb: dwc3: gadget: don't request IRQs in atomic We cannot request an IRQ with spinlocks held as that would trigger a sleeping inside spinlock warning. Cc: # v3.10 Reported-by: Stephen Boyd Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f77083fedc68..14d28d6184f6 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1508,6 +1508,15 @@ static int dwc3_gadget_start(struct usb_gadget *g, int irq; u32 reg; + irq = platform_get_irq(to_platform_device(dwc->dev), 0); + ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, + IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); + if (ret) { + dev_err(dwc->dev, "failed to request irq #%d --> %d\n", + irq, ret); + goto err0; + } + spin_lock_irqsave(&dwc->lock, flags); if (dwc->gadget_driver) { @@ -1515,7 +1524,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc->gadget.name, dwc->gadget_driver->driver.name); ret = -EBUSY; - goto err0; + goto err1; } dwc->gadget_driver = driver; @@ -1551,42 +1560,38 @@ static int dwc3_gadget_start(struct usb_gadget *g, ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); - goto err0; + goto err2; } dep = dwc->eps[1]; ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); - goto err1; + goto err3; } /* begin to receive SETUP packets */ dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, - IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); - if (ret) { - dev_err(dwc->dev, "failed to request irq #%d --> %d\n", - irq, ret); - goto err1; - } - dwc3_gadget_enable_irq(dwc); spin_unlock_irqrestore(&dwc->lock, flags); return 0; -err1: +err3: __dwc3_gadget_ep_disable(dwc->eps[0]); -err0: +err2: dwc->gadget_driver = NULL; + +err1: spin_unlock_irqrestore(&dwc->lock, flags); + free_irq(irq, dwc); + +err0: return ret; } @@ -1600,9 +1605,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g, spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_disable_irq(dwc); - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - free_irq(irq, dwc); - __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); @@ -1610,6 +1612,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g, spin_unlock_irqrestore(&dwc->lock, flags); + irq = platform_get_irq(to_platform_device(dwc->dev), 0); + free_irq(irq, dwc); + return 0; } From 7bc5a6ba369217e0137833f5955cf0b0f08b0712 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Thu, 27 Jun 2013 01:08:10 +0800 Subject: [PATCH 011/101] usb: dwc3: clean up redundant parameter comment @list is not as a parameter of dwc3_event_buffer, so remove it in comments. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 27dad993b007..00a72e37397d 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -367,7 +367,6 @@ struct dwc3_trb; /** * struct dwc3_event_buffer - Software event buffer representation - * @list: a list of event buffers * @buf: _THE_ buffer * @length: size of this buffer * @lpos: event offset From 5945f789c864d8676b297880cc6961fea4511a7a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sun, 30 Jun 2013 14:15:11 +0300 Subject: [PATCH 012/101] usb: dwc3: switch to GPL v2 only This is a Linux-only driver which makes use of GPL-only symbols. It makes no sense to maintain Dual BSD/GPL licensing for this driver. Considering that the amount of work to use this driver in any different operating system would likely be as large as developing the driver from scratch and considering that we depend on GPL-only symbols, we will switch over to a GPL v2-only license. Cc: Anton Tikhomirov Acked-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 37 +++++++++------------------------- drivers/usb/dwc3/core.h | 34 +++++++------------------------ drivers/usb/dwc3/debug.h | 34 +++++++------------------------ drivers/usb/dwc3/debugfs.c | 34 +++++++------------------------ drivers/usb/dwc3/dwc3-exynos.c | 14 ++++++++----- drivers/usb/dwc3/dwc3-omap.c | 36 ++++++++------------------------- drivers/usb/dwc3/dwc3-pci.c | 36 ++++++++------------------------- drivers/usb/dwc3/ep0.c | 34 +++++++------------------------ drivers/usb/dwc3/gadget.c | 34 +++++++------------------------ drivers/usb/dwc3/gadget.h | 34 +++++++------------------------ drivers/usb/dwc3/host.c | 34 +++++++------------------------ drivers/usb/dwc3/io.h | 34 +++++++------------------------ 12 files changed, 91 insertions(+), 304 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 358375e0b291..f69e45a50039 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -6,34 +6,17 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #include @@ -775,5 +758,5 @@ module_platform_driver(dwc3_driver); MODULE_ALIAS("platform:dwc3"); MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 00a72e37397d..22ada27ad3ff 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DRIVERS_USB_DWC3_CORE_H diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 5894ee8222af..fceb39dc4bba 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include "core.h" diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 9e9f122162f2..9ac37fe1b6a7 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 8ce9d7fd6cfc..9a8a5e1f394f 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -6,10 +6,14 @@ * * Author: Anton Tikhomirov * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include @@ -228,5 +232,5 @@ module_platform_driver(dwc3_exynos_driver); MODULE_ALIAS("platform:exynos-dwc3"); MODULE_AUTHOR("Anton Tikhomirov "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 077f110bd746..cf209086f3e8 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include @@ -610,5 +590,5 @@ module_platform_driver(dwc3_omap_driver); MODULE_ALIAS("platform:omap-dwc3"); MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index ed07ec04a962..5d746e5d6a0a 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include @@ -257,7 +237,7 @@ static struct pci_driver dwc3_pci_driver = { }; MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); module_pci_driver(dwc3_pci_driver); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 5acbb948b704..e9d099cee636 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 14d28d6184f6..033419be26d4 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 99e6d7248820..febe1aa7b714 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DRIVERS_USB_DWC3_GADGET_H diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 0fa1846eda4c..32db328cc769 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -5,34 +5,14 @@ * * Authors: Felipe Balbi , * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index a50f76b9d19b..d94441c14d8c 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -6,34 +6,14 @@ * Authors: Felipe Balbi , * Sebastian Andrzej Siewior * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DRIVERS_USB_DWC3_IO_H From 410aee70f06da60dd8f78c3ec3346cc74c9bed46 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sun, 30 Jun 2013 15:27:26 +0300 Subject: [PATCH 013/101] usb: phy: protect against NULL phy pointers In order to decrease the amount of work done by PHY users, allow NULL phy pointers to be passed. Signed-off-by: Felipe Balbi --- include/linux/usb/phy.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 44036808bf0f..6c0b1c513db7 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -142,7 +142,7 @@ extern void usb_remove_phy(struct usb_phy *); /* helpers for direct access thru low-level io interface */ static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) { - if (x->io_ops && x->io_ops->read) + if (x && x->io_ops && x->io_ops->read) return x->io_ops->read(x, reg); return -EINVAL; @@ -150,7 +150,7 @@ static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) { - if (x->io_ops && x->io_ops->write) + if (x && x->io_ops && x->io_ops->write) return x->io_ops->write(x, val, reg); return -EINVAL; @@ -159,7 +159,7 @@ static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) static inline int usb_phy_init(struct usb_phy *x) { - if (x->init) + if (x && x->init) return x->init(x); return 0; @@ -168,14 +168,14 @@ usb_phy_init(struct usb_phy *x) static inline void usb_phy_shutdown(struct usb_phy *x) { - if (x->shutdown) + if (x && x->shutdown) x->shutdown(x); } static inline int usb_phy_vbus_on(struct usb_phy *x) { - if (!x->set_vbus) + if (!x || !x->set_vbus) return 0; return x->set_vbus(x, true); @@ -184,7 +184,7 @@ usb_phy_vbus_on(struct usb_phy *x) static inline int usb_phy_vbus_off(struct usb_phy *x) { - if (!x->set_vbus) + if (!x || !x->set_vbus) return 0; return x->set_vbus(x, false); @@ -258,7 +258,7 @@ usb_phy_set_power(struct usb_phy *x, unsigned mA) static inline int usb_phy_set_suspend(struct usb_phy *x, int suspend) { - if (x->set_suspend != NULL) + if (x && x->set_suspend != NULL) return x->set_suspend(x, suspend); else return 0; @@ -267,7 +267,7 @@ usb_phy_set_suspend(struct usb_phy *x, int suspend) static inline int usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) { - if (x->notify_connect) + if (x && x->notify_connect) return x->notify_connect(x, speed); else return 0; @@ -276,7 +276,7 @@ usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) static inline int usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed) { - if (x->notify_disconnect) + if (x && x->notify_disconnect) return x->notify_disconnect(x, speed); else return 0; From 1494a1f62bf7cf57345e9282c8189fe2a21fab64 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sun, 30 Jun 2013 13:56:45 +0300 Subject: [PATCH 014/101] usb: common: introduce of_usb_get_maximum_speed() this helper will be used for controllers which want to work at a lower speed even though they support higher USB transfer rates. One such case is Texas Instruments' AM437x SoC where it uses a USB3 controller without a USB3 PHY, rendering the controller USB2-only. Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/generic.txt | 24 +++++++++ drivers/usb/usb-common.c | 49 ++++++++++++++----- include/linux/usb/of.h | 8 +++ 3 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/generic.txt diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt new file mode 100644 index 000000000000..477d5bb5e51c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/generic.txt @@ -0,0 +1,24 @@ +Generic USB Properties + +Optional properties: + - maximum-speed: tells USB controllers we want to work up to a certain + speed. Valid arguments are "super-speed", "high-speed", + "full-speed" and "low-speed". In case this isn't passed + via DT, USB controllers should default to their maximum + HW capability. + - dr_mode: tells Dual-Role USB controllers that we want to work on a + particular mode. Valid arguments are "host", + "peripheral" and "otg". In case this attribute isn't + passed via DT, USB DRD controllers should default to + OTG. + +This is an attribute to a USB controller such as: + +dwc3@4a030000 { + compatible = "synopsys,dwc3"; + reg = <0x4a030000 0xcfff>; + interrupts = <0 92 4> + usb-phy = <&usb2_phy>, <&usb3,phy>; + maximum-speed = "super-speed"; + dr_mode = "otg"; +}; diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c index 675384dabfe9..d771870a819e 100644 --- a/drivers/usb/usb-common.c +++ b/drivers/usb/usb-common.c @@ -43,20 +43,20 @@ const char *usb_otg_state_string(enum usb_otg_state state) } EXPORT_SYMBOL_GPL(usb_otg_state_string); +static const char *const speed_names[] = { + [USB_SPEED_UNKNOWN] = "UNKNOWN", + [USB_SPEED_LOW] = "low-speed", + [USB_SPEED_FULL] = "full-speed", + [USB_SPEED_HIGH] = "high-speed", + [USB_SPEED_WIRELESS] = "wireless", + [USB_SPEED_SUPER] = "super-speed", +}; + const char *usb_speed_string(enum usb_device_speed speed) { - static const char *const names[] = { - [USB_SPEED_UNKNOWN] = "UNKNOWN", - [USB_SPEED_LOW] = "low-speed", - [USB_SPEED_FULL] = "full-speed", - [USB_SPEED_HIGH] = "high-speed", - [USB_SPEED_WIRELESS] = "wireless", - [USB_SPEED_SUPER] = "super-speed", - }; - - if (speed < 0 || speed >= ARRAY_SIZE(names)) + if (speed < 0 || speed >= ARRAY_SIZE(speed_names)) speed = USB_SPEED_UNKNOWN; - return names[speed]; + return speed_names[speed]; } EXPORT_SYMBOL_GPL(usb_speed_string); @@ -112,6 +112,33 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) return USB_DR_MODE_UNKNOWN; } EXPORT_SYMBOL_GPL(of_usb_get_dr_mode); + +/** + * of_usb_get_maximum_speed - Get maximum requested speed for a given USB + * controller. + * @np: Pointer to the given device_node + * + * The function gets the maximum speed string from property "maximum-speed", + * and returns the corresponding enum usb_device_speed. + */ +enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np) +{ + const char *maximum_speed; + int err; + int i; + + err = of_property_read_string(np, "maximum-speed", &maximum_speed); + if (err < 0) + return USB_SPEED_UNKNOWN; + + for (i = 0; i < ARRAY_SIZE(speed_names); i++) + if (strcmp(maximum_speed, speed_names[i]) == 0) + return i; + + return USB_SPEED_UNKNOWN; +} +EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed); + #endif MODULE_LICENSE("GPL"); diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index a0ef405368b8..5a7cb9ebf0ef 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -7,16 +7,24 @@ #ifndef __LINUX_USB_OF_H #define __LINUX_USB_OF_H +#include #include #include #if IS_ENABLED(CONFIG_OF) enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np); +enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np); #else static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) { return USB_DR_MODE_UNKNOWN; } + +static inline enum usb_device_speed +of_usb_get_maximum_speed(struct device_node *np) +{ + return USB_SPEED_UNKNOWN; +} #endif #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_PHY) From 6462cbd54d2fa649b27633267d8ddf835705e47a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sun, 30 Jun 2013 14:19:33 +0300 Subject: [PATCH 015/101] usb: dwc3: let non-DT platforms pass tx-fifo-resize flag; in case we're not in a DT boot, we should still be able to tell the driver how to behave. In order to be able to pass flags to the driver, we introduce platform_data structure which the core driver should use. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 8 ++++++-- drivers/usb/dwc3/platform_data.h | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/dwc3/platform_data.h diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index f69e45a50039..cb1eb37c6d6c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -37,6 +37,7 @@ #include #include +#include "platform_data.h" #include "core.h" #include "gadget.h" #include "io.h" @@ -350,6 +351,7 @@ static void dwc3_core_exit(struct dwc3 *dwc) static int dwc3_probe(struct platform_device *pdev) { + struct dwc3_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; struct resource *res; struct dwc3 *dwc; @@ -412,9 +414,13 @@ static int dwc3_probe(struct platform_device *pdev) if (node) { dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); + + dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); + + dwc->needs_fifo_resize = pdata->tx_fifo_resize; } if (IS_ERR(dwc->usb2_phy)) { @@ -472,8 +478,6 @@ static int dwc3_probe(struct platform_device *pdev) else dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; - dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); - pm_runtime_enable(dev); pm_runtime_get_sync(dev); pm_runtime_forbid(dev); diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h new file mode 100644 index 000000000000..038516489539 --- /dev/null +++ b/drivers/usb/dwc3/platform_data.h @@ -0,0 +1,22 @@ +/** + * platform_data.h - USB DWC3 Platform Data Support + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Author: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +struct dwc3_platform_data { + bool tx_fifo_resize; +}; From f7e846f0956917888b28b52726ee8779a39d84b6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sun, 30 Jun 2013 14:29:51 +0300 Subject: [PATCH 016/101] usb: dwc3: make maximum-speed a per-instance attribute in order to allow different instances of the core work in different maximum speeds, we will move the maximum_speed module_parameter to both DeviceTree (making use the new maximum-speed DT property) and platform_data. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 24 +++++++++--------------- drivers/usb/dwc3/gadget.c | 21 ++++++++++++++++++--- drivers/usb/dwc3/platform_data.h | 3 +++ 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index cb1eb37c6d6c..0686acff1e22 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "platform_data.h" #include "core.h" @@ -44,10 +45,6 @@ #include "debug.h" -static char *maximum_speed = "super"; -module_param(maximum_speed, charp, 0); -MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); - /* -------------------------------------------------------------------------- */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) @@ -412,17 +409,25 @@ static int dwc3_probe(struct platform_device *pdev) } if (node) { + dwc->maximum_speed = of_usb_get_maximum_speed(node); + dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); } else { + dwc->maximum_speed = pdata->maximum_speed; + dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); dwc->needs_fifo_resize = pdata->tx_fifo_resize; } + /* default to superspeed if no maximum_speed passed */ + if (dwc->maximum_speed == USB_SPEED_UNKNOWN) + dwc->maximum_speed = USB_SPEED_SUPER; + if (IS_ERR(dwc->usb2_phy)) { ret = PTR_ERR(dwc->usb2_phy); @@ -467,17 +472,6 @@ static int dwc3_probe(struct platform_device *pdev) dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); - if (!strncmp("super", maximum_speed, 5)) - dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; - else if (!strncmp("high", maximum_speed, 4)) - dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; - else if (!strncmp("full", maximum_speed, 4)) - dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; - else if (!strncmp("low", maximum_speed, 3)) - dwc->maximum_speed = DWC3_DCFG_LOWSPEED; - else - dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; - pm_runtime_enable(dev); pm_runtime_get_sync(dev); pm_runtime_forbid(dev); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 033419be26d4..4ca5706f3a86 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1525,10 +1525,25 @@ static int dwc3_gadget_start(struct usb_gadget *g, * STAR#9000525659: Clock Domain Crossing on DCTL in * USB 2.0 Mode */ - if (dwc->revision < DWC3_REVISION_220A) + if (dwc->revision < DWC3_REVISION_220A) { reg |= DWC3_DCFG_SUPERSPEED; - else - reg |= dwc->maximum_speed; + } else { + switch (dwc->maximum_speed) { + case USB_SPEED_LOW: + reg |= DWC3_DSTS_LOWSPEED; + break; + case USB_SPEED_FULL: + reg |= DWC3_DSTS_FULLSPEED1; + break; + case USB_SPEED_HIGH: + reg |= DWC3_DSTS_HIGHSPEED; + break; + case USB_SPEED_SUPER: /* FALLTHROUGH */ + case USB_SPEED_UNKNOWN: /* FALTHROUGH */ + default: + reg |= DWC3_DSTS_SUPERSPEED; + } + } dwc3_writel(dwc->regs, DWC3_DCFG, reg); dwc->start_config_issued = false; diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 038516489539..16ffe1912523 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -17,6 +17,9 @@ * along with this program. If not, see . */ +#include + struct dwc3_platform_data { + enum usb_device_speed maximum_speed; bool tx_fifo_resize; }; From 22a5aa170c5231e64e1598a55dee92ea9a26183e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 2 Jul 2013 21:20:24 +0300 Subject: [PATCH 017/101] usb: dwc3: core: switch to snps,dwc3 all other drivers using Synopsys IPs with DT have a compatible of snps,$driver, in order to add consistency, we are switching over to snps,dwc3 but keeping synopsys,dwc3 in the core driver to maintain backwards compatibility. New DTS bindings should NOT use synopsys,dwc3. Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 4 ++-- arch/arm/boot/dts/omap5.dtsi | 2 +- drivers/usb/dwc3/core.c | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 7a95c651ceb3..3a64e20f6c32 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -3,7 +3,7 @@ synopsys DWC3 CORE DWC3- USB3 CONTROLLER Required properties: - - compatible: must be "synopsys,dwc3" + - compatible: must be "snps,dwc3" - reg : Address and length of the register set for the device - interrupts: Interrupts used by the dwc3 controller. - usb-phy : array of phandle for the PHY device @@ -14,7 +14,7 @@ Optional properties: This is usually a subnode to DWC3 glue to which it is connected. dwc3@4a030000 { - compatible = "synopsys,dwc3"; + compatible = "snps,dwc3"; reg = <0x4a030000 0xcfff>; interrupts = <0 92 4> usb-phy = <&usb2_phy>, <&usb3,phy>; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index e643620417a9..07be2cd7b318 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -644,7 +644,7 @@ omap_dwc3@4a020000 { utmi-mode = <2>; ranges; dwc3@4a030000 { - compatible = "synopsys,dwc3"; + compatible = "snps,dwc3"; reg = <0x4a030000 0x1000>; interrupts = ; usb-phy = <&usb2_phy>, <&usb3_phy>; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 0686acff1e22..2f5632730ffb 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -734,6 +734,9 @@ static const struct dev_pm_ops dwc3_dev_pm_ops = { #ifdef CONFIG_OF static const struct of_device_id of_dwc3_match[] = { + { + .compatible = "snps,dwc3" + }, { .compatible = "synopsys,dwc3" }, From c50f056c360673ef196b49bfa161d841f0fbe92e Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 25 Jun 2013 17:38:23 +0200 Subject: [PATCH 018/101] usb: gadget: s3c-hsotg: Allow driver instantiation using device tree This patch adds OF match table to the driver to allow instantiating it using device tree. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/samsung-hsotg.txt | 40 +++++++++++++++++++ drivers/usb/gadget/s3c-hsotg.c | 10 +++++ 2 files changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/samsung-hsotg.txt diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt new file mode 100644 index 000000000000..b83d428a265e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt @@ -0,0 +1,40 @@ +Samsung High Speed USB OTG controller +----------------------------- + +The Samsung HSOTG IP can be found on Samsung SoCs, from S3C6400 onwards. +It gives functionality of OTG-compliant USB 2.0 host and device with +support for USB 2.0 high-speed (480Mbps) and full-speed (12 Mbps) +operation. + +Currently only device mode is supported. + +Binding details +----- + +Required properties: +- compatible: "samsung,s3c6400-hsotg" should be used for all currently + supported SoC, +- interrupt-parent: phandle for the interrupt controller to which the + interrupt signal of the HSOTG block is routed, +- interrupts: specifier of interrupt signal of interrupt controller, + according to bindings of interrupt controller, +- clocks: contains an array of clock specifiers: + - first entry: OTG clock +- clock-names: contains array of clock names: + - first entry: must be "otg" +- vusb_d-supply: phandle to voltage regulator of digital section, +- vusb_a-supply: phandle to voltage regulator of analog section. + +Example +----- + + hsotg@12480000 { + compatible = "samsung,s3c6400-hsotg"; + reg = <0x12480000 0x20000>; + interrupts = <0 71 0>; + clocks = <&clock 305>; + clock-names = "otg"; + vusb_d-supply = <&vusb_reg>; + vusb_a-supply = <&vusbdac_reg>; + }; + diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index af22f24046b2..616ed51f8585 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -3648,10 +3649,19 @@ static int s3c_hsotg_remove(struct platform_device *pdev) #define s3c_hsotg_resume NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id s3c_hsotg_of_ids[] = { + { .compatible = "samsung,s3c6400-hsotg", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids); +#endif + static struct platform_driver s3c_hsotg_driver = { .driver = { .name = "s3c-hsotg", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(s3c_hsotg_of_ids), }, .probe = s3c_hsotg_probe, .remove = s3c_hsotg_remove, From 24dc3538bcfb353741e653fab550c4bf0a8dc07d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 1 Jul 2013 21:34:58 -0700 Subject: [PATCH 019/101] usb: musb: get rid of unused proc_dir_entry The musb driver no longer uses procfs, so get rid of the proc_dir_entry variable in struct musb. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 7d341c387eab..65f3917b4fc5 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -83,11 +83,6 @@ enum { MUSB_PORT_MODE_DUAL_ROLE, }; -#ifdef CONFIG_PROC_FS -#include -#define MUSB_CONFIG_PROC_FS -#endif - /****************************** CONSTANTS ********************************/ #ifndef MUSB_C_NUM_EPS @@ -425,9 +420,6 @@ struct musb { struct musb_hdrc_config *config; -#ifdef MUSB_CONFIG_PROC_FS - struct proc_dir_entry *proc_entry; -#endif int xceiv_old_state; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; From 51e563e3c11492748d11d3846b6d325426427a95 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 3 Jul 2013 16:34:13 -0300 Subject: [PATCH 020/101] usb: phy: phy-mxs-usb: Check the return value from stmp_reset_block() stmp_reset_block() may fail, so let's check its return value and propagate it in the case of error. Acked-by: Shawn Guo Signed-off-by: Fabio Estevam Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-mxs-usb.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index bd601c537c8d..fdd33b44dbd3 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -41,11 +41,14 @@ struct mxs_phy { #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) -static void mxs_phy_hw_init(struct mxs_phy *mxs_phy) +static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) { + int ret; void __iomem *base = mxs_phy->phy.io_priv; - stmp_reset_block(base + HW_USBPHY_CTRL); + ret = stmp_reset_block(base + HW_USBPHY_CTRL); + if (ret) + return ret; /* Power up the PHY */ writel(0, base + HW_USBPHY_PWD); @@ -54,6 +57,8 @@ static void mxs_phy_hw_init(struct mxs_phy *mxs_phy) writel(BM_USBPHY_CTRL_ENUTMILEVEL2 | BM_USBPHY_CTRL_ENUTMILEVEL3, base + HW_USBPHY_CTRL_SET); + + return 0; } static int mxs_phy_init(struct usb_phy *phy) @@ -61,9 +66,7 @@ static int mxs_phy_init(struct usb_phy *phy) struct mxs_phy *mxs_phy = to_mxs_phy(phy); clk_prepare_enable(mxs_phy->clk); - mxs_phy_hw_init(mxs_phy); - - return 0; + return mxs_phy_hw_init(mxs_phy); } static void mxs_phy_shutdown(struct usb_phy *phy) From a45c82b84c844cd85b2ed1aa32596f1bffa32716 Mon Sep 17 00:00:00 2001 From: Ruchika Kharwar Date: Sat, 6 Jul 2013 07:52:49 -0500 Subject: [PATCH 021/101] usb: dwc3: adapt to use dr_mode device tree helper This patch adapts the dwc3 to use the device tree helper "of_usb_get_dr_mode" for the mode of operation of the dwc3 instance being probed. [ balbi@ti.com : make of_usb_get_dr_mode() conditional on dev->of_node and let pdata pass dr_mode too ] Reviewed-by: Roger Quadros Signed-off-by: Ruchika Kharwar Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 73 ++++++++++++++++---------------- drivers/usb/dwc3/core.h | 11 ++--- drivers/usb/dwc3/platform_data.h | 2 + 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 2f5632730ffb..df3723a1023e 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "platform_data.h" #include "core.h" @@ -359,8 +360,6 @@ static int dwc3_probe(struct platform_device *pdev) void __iomem *regs; void *mem; - u8 mode; - mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(dev, "not enough memory\n"); @@ -415,6 +414,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); + dwc->dr_mode = of_usb_get_dr_mode(node); } else { dwc->maximum_speed = pdata->maximum_speed; @@ -422,6 +422,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); dwc->needs_fifo_resize = pdata->tx_fifo_resize; + dwc->dr_mode = pdata->dr_mode; } /* default to superspeed if no maximum_speed passed */ @@ -498,14 +499,15 @@ static int dwc3_probe(struct platform_device *pdev) } if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) - mode = DWC3_MODE_HOST; + dwc->dr_mode = USB_DR_MODE_HOST; else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) - mode = DWC3_MODE_DEVICE; - else - mode = DWC3_MODE_DRD; + dwc->dr_mode = USB_DR_MODE_PERIPHERAL; - switch (mode) { - case DWC3_MODE_DEVICE: + if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) + dwc->dr_mode = USB_DR_MODE_OTG; + + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { @@ -513,7 +515,7 @@ static int dwc3_probe(struct platform_device *pdev) goto err2; } break; - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { @@ -521,7 +523,7 @@ static int dwc3_probe(struct platform_device *pdev) goto err2; } break; - case DWC3_MODE_DRD: + case USB_DR_MODE_OTG: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { @@ -536,10 +538,9 @@ static int dwc3_probe(struct platform_device *pdev) } break; default: - dev_err(dev, "Unsupported mode of operation %d\n", mode); + dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); goto err2; } - dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { @@ -552,14 +553,14 @@ static int dwc3_probe(struct platform_device *pdev) return 0; err3: - switch (mode) { - case DWC3_MODE_DEVICE: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: dwc3_gadget_exit(dwc); break; - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: dwc3_host_exit(dwc); break; - case DWC3_MODE_DRD: + case USB_DR_MODE_OTG: dwc3_host_exit(dwc); dwc3_gadget_exit(dwc); break; @@ -592,14 +593,14 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_debugfs_exit(dwc); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: dwc3_gadget_exit(dwc); break; - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: dwc3_host_exit(dwc); break; - case DWC3_MODE_DRD: + case USB_DR_MODE_OTG: dwc3_host_exit(dwc); dwc3_gadget_exit(dwc); break; @@ -623,12 +624,12 @@ static int dwc3_prepare(struct device *dev) spin_lock_irqsave(&dwc->lock, flags); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - case DWC3_MODE_DRD: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: dwc3_gadget_prepare(dwc); /* FALLTHROUGH */ - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: default: dwc3_event_buffers_cleanup(dwc); break; @@ -646,12 +647,12 @@ static void dwc3_complete(struct device *dev) spin_lock_irqsave(&dwc->lock, flags); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - case DWC3_MODE_DRD: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: dwc3_gadget_complete(dwc); /* FALLTHROUGH */ - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: default: dwc3_event_buffers_setup(dwc); break; @@ -667,12 +668,12 @@ static int dwc3_suspend(struct device *dev) spin_lock_irqsave(&dwc->lock, flags); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - case DWC3_MODE_DRD: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: dwc3_gadget_suspend(dwc); /* FALLTHROUGH */ - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: default: /* do nothing */ break; @@ -700,12 +701,12 @@ static int dwc3_resume(struct device *dev) dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - case DWC3_MODE_DRD: + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: dwc3_gadget_resume(dwc); /* FALLTHROUGH */ - case DWC3_MODE_HOST: + case USB_DR_MODE_HOST: default: /* do nothing */ break; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 22ada27ad3ff..db385bda3095 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -29,6 +29,7 @@ #include #include +#include /* Global constants */ #define DWC3_EP0_BOUNCE_SIZE 512 @@ -545,11 +546,6 @@ struct dwc3_hwparams { /* HWPARAMS0 */ #define DWC3_MODE(n) ((n) & 0x7) -#define DWC3_MODE_DEVICE 0 -#define DWC3_MODE_HOST 1 -#define DWC3_MODE_DRD 2 -#define DWC3_MODE_HUB 3 - #define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8) /* HWPARAMS1 */ @@ -611,7 +607,7 @@ struct dwc3_scratchpad_array { * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents - * @mode: mode of operation + * @dr_mode: requested mode of operation * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY * @dcfg: saved contents of DCFG register @@ -669,6 +665,8 @@ struct dwc3 { void __iomem *regs; size_t regs_size; + enum usb_dr_mode dr_mode; + /* used for suspend/resume */ u32 dcfg; u32 gctl; @@ -677,7 +675,6 @@ struct dwc3 { u32 u1u2; u32 maximum_speed; u32 revision; - u32 mode; #define DWC3_REVISION_173A 0x5533173a #define DWC3_REVISION_175A 0x5533175a diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 16ffe1912523..7db34f00b89a 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -18,8 +18,10 @@ */ #include +#include struct dwc3_platform_data { enum usb_device_speed maximum_speed; + enum usb_dr_mode dr_mode; bool tx_fifo_resize; }; From 636e2a2caeafcb1b55b6799b29fe436039819eb9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Jul 2013 13:19:52 +0300 Subject: [PATCH 022/101] usb: dwc3: gadget: drop dwc3 manual phy control Recent versions of the core, can suspend and resume the PHYs automatically, so we don't need to fiddle with dwc3's Global PHY registers at all. On versions prior to 1.94a this patch will mean that we will never ask dwc3 to suspend the PHY. This is an acceptable behavior or such old versions of the core, specially considering that the only chip known to have a version prior to 1.94a was OMAP5 ES1.0 and that's not supported in mainline kernel, because it was just a test spin of OMAP5. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 61 --------------------------------------- 1 file changed, 61 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4ca5706f3a86..c7be039d8551 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2105,34 +2105,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->setup_packet_pending = false; } -static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - - if (suspend) - reg |= DWC3_GUSB3PIPECTL_SUSPHY; - else - reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; - - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); -} - -static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - - if (suspend) - reg |= DWC3_GUSB2PHYCFG_SUSPHY; - else - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); -} - static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { u32 reg; @@ -2173,13 +2145,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) /* after reset -> Default State */ usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT); - /* Recent versions support automatic phy suspend and don't need this */ - if (dwc->revision < DWC3_REVISION_194A) { - /* Resume PHYs */ - dwc3_gadget_usb2_phy_suspend(dwc, false); - dwc3_gadget_usb3_phy_suspend(dwc, false); - } - if (dwc->gadget.speed != USB_SPEED_UNKNOWN) dwc3_disconnect_gadget(dwc); @@ -2223,20 +2188,6 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed) dwc3_writel(dwc->regs, DWC3_GCTL, reg); } -static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed) -{ - switch (speed) { - case USB_SPEED_SUPER: - dwc3_gadget_usb2_phy_suspend(dwc, true); - break; - case USB_SPEED_HIGH: - case USB_SPEED_FULL: - case USB_SPEED_LOW: - dwc3_gadget_usb3_phy_suspend(dwc, true); - break; - } -} - static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) { struct dwc3_ep *dep; @@ -2312,12 +2263,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); } - /* Recent versions support automatic phy suspend and don't need this */ - if (dwc->revision < DWC3_REVISION_194A) { - /* Suspend unneeded PHY */ - dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed); - } - dep = dwc->eps[0]; ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); if (ret) { @@ -2647,12 +2592,6 @@ int dwc3_gadget_init(struct dwc3 *dwc) reg |= DWC3_DCFG_LPM_CAP; dwc3_writel(dwc->regs, DWC3_DCFG, reg); - /* Enable USB2 LPM and automatic phy suspend only on recent versions */ - if (dwc->revision >= DWC3_REVISION_194A) { - dwc3_gadget_usb2_phy_suspend(dwc, false); - dwc3_gadget_usb3_phy_suspend(dwc, false); - } - ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); From 8bbcd17d6be41a5c0e4a8562e30c8f15c1ceb836 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Jul 2013 15:33:35 +0300 Subject: [PATCH 023/101] usb: dwc3: omap: switch over to devm_ioremap_resource() use the new devm_ioremap_resource on dwc3-omap.c Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index cf209086f3e8..ecd99451ee90 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -389,11 +389,9 @@ static int dwc3_omap_probe(struct platform_device *pdev) return -EINVAL; } - base = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!base) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); spin_lock_init(&omap->lock); From 6c76e6cb48b240ae3062949cf352971b7b03b106 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Jul 2013 15:34:12 +0300 Subject: [PATCH 024/101] usb: dwc3: core: switch over to devm_ioremap_resource() use the new devm_ioremap_resource() on core.c Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index df3723a1023e..25d374c54d73 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -389,23 +389,15 @@ static int dwc3_probe(struct platform_device *pdev) dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; + res->start += DWC3_GLOBALS_REGS_START; + /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. */ - res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START, - resource_size(res) - DWC3_GLOBALS_REGS_START, - dev_name(dev)); - if (!res) { - dev_err(dev, "can't request mem region\n"); - return -ENOMEM; - } - - regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!regs) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); From ff62d6b6727360ae73382213bc1ebac6cf5160d7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Jul 2013 19:09:39 +0300 Subject: [PATCH 025/101] usb: dwc3: gadget: move debugging print around by moving that dev_vdbg() to the internal __dwc3_gadget_ep_enable() we get the print even when enable ep0, which calls the internal function directly. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c7be039d8551..c8d47c12ce33 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -500,6 +500,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, u32 reg; int ret = -ENOMEM; + dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); + if (!(dep->flags & DWC3_EP_ENABLED)) { ret = dwc3_gadget_start_config(dwc, dep); if (ret) @@ -656,8 +658,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dev_err(dwc->dev, "invalid endpoint transfer type\n"); } - dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); - spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false); spin_unlock_irqrestore(&dwc->lock, flags); From 9aa62ae4292a2450634345d79a7fa1461bf7b39c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Jul 2013 19:10:59 +0300 Subject: [PATCH 026/101] usb: dwc3: gadget: move direction setting up no functional changes, just grouping dep initialization. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c8d47c12ce33..f5efa03972bc 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1642,13 +1642,13 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dep->dwc = dwc; dep->number = epnum; + dep->direction = !!direction; dwc->eps[epnum] = dep; snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1, (epnum & 1) ? "in" : "out"); dep->endpoint.name = dep->name; - dep->direction = (epnum & 1); if (epnum == 0 || epnum == 1) { dep->endpoint.maxpacket = 512; From 653df35e6b3c0df875999a9b842327301269f55d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Jul 2013 19:11:57 +0300 Subject: [PATCH 027/101] usb: dwc3: gadget: add a debugging print when initializing endpoints that way we get debugging information when enabling verbose debug of the driver. It will be no-op otherwise. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f5efa03972bc..3850ff0b853e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1650,6 +1650,8 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dep->endpoint.name = dep->name; + dev_vdbg(dwc->dev, "initializing %s\n", dep->name); + if (epnum == 0 || epnum == 1) { dep->endpoint.maxpacket = 512; dep->endpoint.maxburst = 1; From aff310d91b537c29b979f975d4d9b5f26e978378 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 15 Jul 2013 11:30:45 +0300 Subject: [PATCH 028/101] usb: dwc3: core: don't redefine DWC3_DCFG_LPM_CAP the macro DWC3_DCFG_LPM_CAP was defined twice. This patch just removes one of the definitions, no functional changes. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index db385bda3095..cb6f8d803bc5 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -188,7 +188,6 @@ #define DWC3_MAX_HIBER_SCRATCHBUFS 15 /* Device Configuration Register */ -#define DWC3_DCFG_LPM_CAP (1 << 22) #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) From fb49740d72a305f2e4110b4dfb53fdd9130d8878 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 15 Jul 2013 11:31:27 +0300 Subject: [PATCH 029/101] usb: dwc3: gadget: don't enable LPM early LPM is enabled in Connection Done interrupt, there's no need to enable it early. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3850ff0b853e..95ef20c5b53b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2540,7 +2540,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) */ int dwc3_gadget_init(struct dwc3 *dwc) { - u32 reg; int ret; dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), @@ -2590,10 +2589,6 @@ int dwc3_gadget_init(struct dwc3 *dwc) if (ret) goto err4; - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - reg |= DWC3_DCFG_LPM_CAP; - dwc3_writel(dwc->regs, DWC3_DCFG, reg); - ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); From 68d6a01bdd2a9ebae858271129d0a8d4ae865e93 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Jun 2013 21:09:26 +0300 Subject: [PATCH 030/101] usb: dwc3: core: introduce and use macros for Event Size register That register has more than just the event buffer size; we can also mask and unmask that particular interrupter on bit 31 of that register. In this patch we introduce the necessary macros and make sure to use the new macros while also making sure we mask interrupts during driver removal. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 5 +++-- drivers/usb/dwc3/core.h | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 25d374c54d73..dfbc1f0fc0e3 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -218,7 +218,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), upper_32_bits(evt->dma)); dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), - evt->length & 0xffff); + DWC3_GEVNTSIZ_SIZE(evt->length)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); } @@ -237,7 +237,8 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK + | DWC3_GEVNTSIZ_SIZE(0)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); } } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index cb6f8d803bc5..d30e094faa58 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -175,6 +175,10 @@ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) #define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) +/* Global Event Size Registers */ +#define DWC3_GEVNTSIZ_INTMASK (1 << 31) +#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff) + /* Global HWPARAMS1 Register */ #define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24) #define DWC3_GHWPARAMS1_EN_PWROPT_NO 0 From e8adfc30ff9282a728fd8b666b6418308164c415 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Jun 2013 21:11:14 +0300 Subject: [PATCH 031/101] usb: dwc3: gadget: get rid of IRQF_ONESHOT We can make use of bit 31 of the GEVNTSIZ(n) registers to mask/unmask interrupts from that particular interrupter. With that feature, we can easily drop IRQF_ONESHOT from our driver which makes it possible to properly change IRQ priorities when using RT patchset *and* it allows us to make use of the scheduler to choose the proper time to handle this IRQ thread. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 95ef20c5b53b..bdca5a255a1d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1490,7 +1490,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, irq = platform_get_irq(to_platform_device(dwc->dev), 0); ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, - IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); + IRQF_SHARED, "dwc3", dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); @@ -2447,6 +2447,7 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) struct dwc3 *dwc = _dwc; unsigned long flags; irqreturn_t ret = IRQ_NONE; + u32 reg; int i; spin_lock_irqsave(&dwc->lock, flags); @@ -2486,6 +2487,11 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) evt->count = 0; evt->flags &= ~DWC3_EVENT_PENDING; ret = IRQ_HANDLED; + + /* Unmask interrupt */ + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(i)); + reg &= ~DWC3_GEVNTSIZ_INTMASK; + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(i), reg); } spin_unlock_irqrestore(&dwc->lock, flags); @@ -2497,6 +2503,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) { struct dwc3_event_buffer *evt; u32 count; + u32 reg; evt = dwc->ev_buffs[buf]; @@ -2508,6 +2515,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) evt->count = count; evt->flags |= DWC3_EVENT_PENDING; + /* Mask interrupt */ + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); + reg |= DWC3_GEVNTSIZ_INTMASK; + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + return IRQ_WAKE_THREAD; } From 7f97aa9865800766e570d0e1be772a034dd30388 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Jun 2013 21:16:11 +0300 Subject: [PATCH 032/101] usb: dwc3: gadget: rename dwc3_process_event_buf that function isn't really processing any event buffer, rather just checking whether it contains events to be processed. Due to that reason, we're reaning it to dwc3_check_event_buf() instead. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index bdca5a255a1d..8e47eefffeee 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2499,7 +2499,7 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) return ret; } -static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) +static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) { struct dwc3_event_buffer *evt; u32 count; @@ -2534,7 +2534,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) for (i = 0; i < dwc->num_event_buffers; i++) { irqreturn_t status; - status = dwc3_process_event_buf(dwc, i); + status = dwc3_check_event_buf(dwc, i); if (status == IRQ_WAKE_THREAD) ret = status; } From f42f2447d66233a5bf86e8631e4eb4e863b2ff0b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 12 Jun 2013 21:25:08 +0300 Subject: [PATCH 033/101] usb: dwc3: gadget: introduce dwc3_process_event_buf in order to make our IRQ handler thread easier to read, we re-factor the inner loop to a separate function. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 91 +++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8e47eefffeee..f168eaebdef8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2442,57 +2442,64 @@ static void dwc3_process_event_entry(struct dwc3 *dwc, } } +static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) +{ + struct dwc3_event_buffer *evt; + irqreturn_t ret = IRQ_NONE; + int left; + u32 reg; + + evt = dwc->ev_buffs[buf]; + left = evt->count; + + if (!(evt->flags & DWC3_EVENT_PENDING)) + return IRQ_NONE; + + while (left > 0) { + union dwc3_event event; + + event.raw = *(u32 *) (evt->buf + evt->lpos); + + dwc3_process_event_entry(dwc, &event); + + /* + * FIXME we wrap around correctly to the next entry as + * almost all entries are 4 bytes in size. There is one + * entry which has 12 bytes which is a regular entry + * followed by 8 bytes data. ATM I don't know how + * things are organized if we get next to the a + * boundary so I worry about that once we try to handle + * that. + */ + evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; + left -= 4; + + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); + } + + evt->count = 0; + evt->flags &= ~DWC3_EVENT_PENDING; + ret = IRQ_HANDLED; + + /* Unmask interrupt */ + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); + reg &= ~DWC3_GEVNTSIZ_INTMASK; + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + + return ret; +} + static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) { struct dwc3 *dwc = _dwc; unsigned long flags; irqreturn_t ret = IRQ_NONE; - u32 reg; int i; spin_lock_irqsave(&dwc->lock, flags); - for (i = 0; i < dwc->num_event_buffers; i++) { - struct dwc3_event_buffer *evt; - int left; - - evt = dwc->ev_buffs[i]; - left = evt->count; - - if (!(evt->flags & DWC3_EVENT_PENDING)) - continue; - - while (left > 0) { - union dwc3_event event; - - event.raw = *(u32 *) (evt->buf + evt->lpos); - - dwc3_process_event_entry(dwc, &event); - - /* - * FIXME we wrap around correctly to the next entry as - * almost all entries are 4 bytes in size. There is one - * entry which has 12 bytes which is a regular entry - * followed by 8 bytes data. ATM I don't know how - * things are organized if we get next to the a - * boundary so I worry about that once we try to handle - * that. - */ - evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; - left -= 4; - - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4); - } - - evt->count = 0; - evt->flags &= ~DWC3_EVENT_PENDING; - ret = IRQ_HANDLED; - - /* Unmask interrupt */ - reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(i)); - reg &= ~DWC3_GEVNTSIZ_INTMASK; - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(i), reg); - } + for (i = 0; i < dwc->num_event_buffers; i++) + ret |= dwc3_process_event_buf(dwc, i); spin_unlock_irqrestore(&dwc->lock, flags); From c75f52fb26aa9c10b3f5ee157bc0c6c8e8e9bb1a Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Wed, 12 Jun 2013 23:43:11 +0800 Subject: [PATCH 034/101] usb: dwc3: fix typo in comment of dwc3_ep Change intervall into interval. Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index d30e094faa58..f8af8d44af85 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -398,7 +398,7 @@ struct dwc3_event_buffer { * @number: endpoint number (1 - 15) * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK * @resource_index: Resource transfer index - * @interval: the intervall on which the ISOC transfer is started + * @interval: the interval on which the ISOC transfer is started * @name: a human readable name e.g. ep1out-bulk * @direction: true for TX, false for RX * @stream_capable: true when streams are enabled From 5702f75375aa9ecf8ad3431aef3fe6ce8c8dbd15 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 17 Jul 2013 11:09:49 +0300 Subject: [PATCH 035/101] usb: gadget: udc-core: move sysfs_notify() to a workqueue usb_gadget_set_state() will call sysfs_notify() which might sleep. Some users might want to call usb_gadget_set_state() from the very IRQ handler which actually changes the gadget state. Instead of having every UDC driver add their own workqueue for such a simple notification, we're adding it generically to our struct usb_gadget, so the details are hidden from all UDC drivers. Acked-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc-core.c | 12 +++++++++++- include/linux/usb/gadget.h | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index c28ac9872030..3122ab942f75 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -105,11 +106,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); /* ------------------------------------------------------------------------- */ +static void usb_gadget_state_work(struct work_struct *work) +{ + struct usb_gadget *gadget = work_to_gadget(work); + + sysfs_notify(&gadget->dev.kobj, NULL, "status"); +} + void usb_gadget_set_state(struct usb_gadget *gadget, enum usb_device_state state) { gadget->state = state; - sysfs_notify(&gadget->dev.kobj, NULL, "status"); + schedule_work(&gadget->work); } EXPORT_SYMBOL_GPL(usb_gadget_set_state); @@ -196,6 +204,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, goto err1; dev_set_name(&gadget->dev, "gadget"); + INIT_WORK(&gadget->work, usb_gadget_state_work); gadget->dev.parent = parent; #ifdef CONFIG_HAS_DMA @@ -315,6 +324,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) usb_gadget_remove_driver(udc); kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); + flush_work(&gadget->work); device_unregister(&udc->dev); device_unregister(&gadget->dev); } diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index f1b0dca60f12..942ef5e053bf 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -22,6 +22,7 @@ #include #include #include +#include #include struct usb_ep; @@ -475,6 +476,7 @@ struct usb_gadget_ops { /** * struct usb_gadget - represents a usb slave device + * @work: (internal use) Workqueue to be used for sysfs_notify() * @ops: Function pointers used to access hardware-specific operations. * @ep0: Endpoint zero, used when reading or writing responses to * driver setup() requests @@ -520,6 +522,7 @@ struct usb_gadget_ops { * device is acting as a B-Peripheral (so is_a_peripheral is false). */ struct usb_gadget { + struct work_struct work; /* readonly to gadget driver */ const struct usb_gadget_ops *ops; struct usb_ep *ep0; @@ -538,6 +541,7 @@ struct usb_gadget { unsigned out_epnum; unsigned in_epnum; }; +#define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) static inline void set_gadget_data(struct usb_gadget *gadget, void *data) { dev_set_drvdata(&gadget->dev, data); } From 7a42d83536a5ea7ea7b4ad279c34c4c4ce509b5a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 22 Jul 2013 12:31:31 +0300 Subject: [PATCH 036/101] usb: dwc3: ep0: only change to ADDRESS if set_config() succeeds In case we're switching back to USB_STATE_ADDRESS from USB_STATE_CONFIGURED (if host sends a set configuration command for configuration zero), we should only switch if the request is successfully processed by the gadget driver. Reported-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index e9d099cee636..007651c21638 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -551,7 +551,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) case USB_STATE_CONFIGURED: ret = dwc3_ep0_delegate_req(dwc, ctrl); - if (!cfg) + if (!cfg && !ret) usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS); break; From 7c81290e87bf01b507deabf0f478e051367cb416 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 22 Jul 2013 12:41:47 +0300 Subject: [PATCH 037/101] usb: dwc3: ep0: don't change to configured state too early before changing to configured state, we need to wait until gadget driver has had a chance to process the request. In case of USB_GADGET_DELAYED_STATUS, that means we need to defer usb_gadget_set_state() until the upcoming usb_ep_queue(). Reported-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 007651c21638..7fa93f4bc507 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -148,6 +148,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, direction = !dwc->ep0_expect_in; dwc->delayed_status = false; + usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED); if (dwc->ep0state == EP0_STATUS_PHASE) __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]); @@ -533,8 +534,16 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { - usb_gadget_set_state(&dwc->gadget, - USB_STATE_CONFIGURED); + + /* + * only change state if set_config has already + * been processed. If gadget driver returns + * USB_GADGET_DELAYED_STATUS, we will wait + * to change the state on the next usb_ep_queue() + */ + if (ret == 0) + usb_gadget_set_state(&dwc->gadget, + USB_STATE_CONFIGURED); /* * Enable transition to U1/U2 state when From 052a11d13bdecb77ee4cdbdccfce5434a12209af Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 14 Jun 2013 12:51:41 +0300 Subject: [PATCH 038/101] usb: phy: make PHY driver selection possible by controller drivers Convert PHY Drivers from menuconfig to menu so that the PHY drivers can be explicitely selected by the controller drivers. USB_PHY is no longer a user visible option. It is upto to the PHY drivers to select it if needed. This patch does so for the existing PHY drivers that use the USB_PHY library. Doing so moves the USB_PHY and PHY driver selection problem from the end user to the PHY and controller driver developer. e.g. Earlier, a controller driver (e.g. EHCI_OMAP) that needs to select a PHY driver (e.g. NOP_PHY) couldn't do so because the PHY driver depended on USB_PHY. Making the controller driver depend on USB_PHY has a negative effect i.e. it becomes invisible to the user till USB_PHY is enabled. Most end users will not familiar with this. With this patch, the end user just needs to select the controller driver needed for his/her platform without worrying about which PHY driver to select. Also update USB_EHCI_MSM, USB_LPC32XX and USB_OMAP to not depend on USB_PHY any more. They can safely select the necessary PHY drivers. [ balbi@ti.com : refreshed on top of my next branch. Changed bool followed by default n into def_bool n ] CC: Pavankumar Kondeti Acked-by: Roland Stigge Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/Makefile | 2 +- drivers/usb/gadget/Kconfig | 2 -- drivers/usb/host/Kconfig | 1 - drivers/usb/phy/Kconfig | 36 ++++++++++++++++++++---------------- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 238c5d47cadb..2b3132ede23a 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -45,7 +45,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB) += misc/ -obj-$(CONFIG_USB_PHY) += phy/ +obj-$(CONFIG_USB_SUPPORT) += phy/ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ obj-$(CONFIG_USB_ATM) += atm/ diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 08dab3c640fd..1e3f52574367 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -144,7 +144,6 @@ config USB_AT91 config USB_LPC32XX tristate "LPC32XX USB Peripheral Controller" depends on ARCH_LPC32XX - depends on USB_PHY select USB_ISP1301 help This option selects the USB device controller in the LPC32xx SoC. @@ -206,7 +205,6 @@ config USB_FOTG210_UDC config USB_OMAP tristate "OMAP USB Device Controller" depends on ARCH_OMAP1 - depends on USB_PHY select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG help Many Texas Instruments OMAP processors have flexible full diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 4263d011392c..3102b522ca02 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -186,7 +186,6 @@ config USB_EHCI_HCD_AT91 config USB_EHCI_MSM tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller" depends on ARCH_MSM - depends on USB_PHY select USB_EHCI_ROOT_HUB_TT select USB_MSM_OTG ---help--- diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 3622fff8b798..f5ea339ec155 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -1,22 +1,10 @@ # # Physical Layer USB driver configuration # -menuconfig USB_PHY - bool "USB Physical Layer drivers" - help - Most USB controllers have the physical layer signalling part - (commonly called a PHY) built in. However, dual-role devices - (a.k.a. USB on-the-go) which support being USB master or slave - with the same connector often use an external PHY. +menu "USB Physical Layer drivers" - The drivers in this submenu add support for such PHY devices. - They are not needed for standard master-only (or the vast - majority of slave-only) USB interfaces. - - If you're not sure if this applies to you, it probably doesn't; - say N here. - -if USB_PHY +config USB_PHY + def_bool n # # USB Transceiver Drivers @@ -24,6 +12,7 @@ if USB_PHY config AB8500_USB tristate "AB8500 USB Transceiver Driver" depends on AB8500_CORE + select USB_PHY help Enable this to support the USB OTG transceiver in AB8500 chip. This transceiver supports high and full speed devices plus, @@ -33,12 +22,14 @@ config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME select USB_OTG + select USB_PHY help Enable this to support Freescale USB OTG transceiver. config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" depends on I2C && ARCH_OMAP_OTG + select USB_PHY help If you say yes here you get support for the Philips ISP1301 USB-On-The-Go transceiver working with the OMAP OTG controller. @@ -52,12 +43,14 @@ config ISP1301_OMAP config MV_U3D_PHY bool "Marvell USB 3.0 PHY controller Driver" depends on CPU_MMP3 + select USB_PHY help Enable this to support Marvell USB 3.0 phy controller for Marvell SoC. config NOP_USB_XCEIV tristate "NOP USB Transceiver Driver" + select USB_PHY help This driver is to be used by all the usb transceiver which are either built-in with usb ip or which are autonomous and doesn't require any @@ -76,6 +69,7 @@ config OMAP_USB2 tristate "OMAP USB2 PHY Driver" depends on ARCH_OMAP2PLUS select OMAP_CONTROL_USB + select USB_PHY help Enable this to support the transceiver that is part of SOC. This driver takes care of all the PHY functionality apart from comparator. @@ -85,6 +79,7 @@ config OMAP_USB2 config OMAP_USB3 tristate "OMAP USB3 PHY Driver" select OMAP_CONTROL_USB + select USB_PHY help Enable this to support the USB3 PHY that is part of SOC. This driver takes care of all the PHY functionality apart from comparator. @@ -101,6 +96,7 @@ config SAMSUNG_USBPHY config SAMSUNG_USB2PHY tristate "Samsung USB 2.0 PHY controller Driver" select SAMSUNG_USBPHY + select USB_PHY help Enable this to support Samsung USB 2.0 (High Speed) PHY controller driver for Samsung SoCs. @@ -108,6 +104,7 @@ config SAMSUNG_USB2PHY config SAMSUNG_USB3PHY tristate "Samsung USB 3.0 PHY controller Driver" select SAMSUNG_USBPHY + select USB_PHY help Enable this to support Samsung USB 3.0 (Super Speed) phy controller for samsung SoCs. @@ -115,6 +112,7 @@ config SAMSUNG_USB3PHY config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS + select USB_PHY help Enable this to support the USB OTG transceiver on TWL4030 family chips (including the TWL5030 and TPS659x0 devices). @@ -135,6 +133,7 @@ config TWL6030_USB config USB_GPIO_VBUS tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" depends on GPIOLIB + select USB_PHY help Provides simple GPIO VBUS sensing for controllers with an internal transceiver via the usb_phy interface, and @@ -145,6 +144,7 @@ config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET depends on I2C + select USB_PHY help Say Y here to add support for the NXP ISP1301 USB transceiver driver. This chip is typically used as USB transceiver for USB host, gadget @@ -156,6 +156,7 @@ config USB_ISP1301 config USB_MSM_OTG tristate "OTG support for Qualcomm on-chip USB controller" depends on (USB || USB_GADGET) && ARCH_MSM + select USB_PHY help Enable this to support the USB OTG transceiver on MSM chips. It handles PHY initialization, clock management, and workarounds @@ -169,6 +170,7 @@ config USB_MV_OTG tristate "Marvell USB OTG support" depends on USB_EHCI_MV && USB_MV_UDC && PM_RUNTIME select USB_OTG + select USB_PHY help Say Y here if you want to build Marvell USB OTG transciever driver in kernel (including PXA and MMP series). This driver @@ -180,6 +182,7 @@ config USB_MXS_PHY tristate "Freescale MXS USB PHY support" depends on ARCH_MXC || ARCH_MXS select STMP_DEVICE + select USB_PHY help Enable this to support the Freescale MXS USB PHY. @@ -188,6 +191,7 @@ config USB_MXS_PHY config USB_RCAR_PHY tristate "Renesas R-Car USB PHY support" depends on USB || USB_GADGET + select USB_PHY help Say Y here to add support for the Renesas R-Car USB common PHY driver. This chip is typically used as USB PHY for USB host, gadget. @@ -210,4 +214,4 @@ config USB_ULPI_VIEWPORT Provides read/write operations to the ULPI phy register set for controllers with a viewport register (e.g. Chipidea/ARC controllers). -endif # USB_PHY +endmenu From 88650d62a12de7fb9437b5508cc7f6b28da58cbf Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 14 Jun 2013 12:51:42 +0300 Subject: [PATCH 039/101] usb: ehci-omap: select NOP_USB_XCEIV PHY driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ehci-omap needs NOP_USB_XCEIV PHY driver to function properly, so select it. As the USB PHY drivers no longer depend on USB_PHY, it is safe to select the PHY drivers. Signed-off-by: Roger Quadros Tested-by: Adrien Vergé Signed-off-by: Felipe Balbi --- drivers/usb/host/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3102b522ca02..5064e06e25b4 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -148,13 +148,11 @@ config USB_EHCI_MXC config USB_EHCI_HCD_OMAP tristate "EHCI support for OMAP3 and later chips" depends on ARCH_OMAP + select NOP_USB_XCEIV default y ---help--- Enables support for the on-chip EHCI controller on OMAP3 and later chips. - If your system uses a PHY on the USB port, you will need to - enable USB_PHY and the appropriate PHY driver as well. Most - boards need the NOP_USB_XCEIV PHY driver. config USB_EHCI_HCD_ORION tristate "Support for Marvell EBU on-chip EHCI USB controller" From 519c6013d356fef95c9e45cfb533b3e68b47dbf4 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Tue, 9 Jul 2013 14:38:31 +0300 Subject: [PATCH 040/101] usb: phy: omap-usb3: Improve DPLL parameter lookup code Use a mapping table (dpll_map) to match the possible system clock rates to the appropriate DPLL parameters. Introduce a function "omap_usb3_get_dpll_params()" that will return the matching DPLL parameters for the given clock rate. Also, bail out on phy init if DPLL locking fails. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-omap-usb3.c | 87 ++++++++++++++------------------- 1 file changed, 38 insertions(+), 49 deletions(-) diff --git a/drivers/usb/phy/phy-omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c index a2fb30bbb971..fc15694d3031 100644 --- a/drivers/usb/phy/phy-omap-usb3.c +++ b/drivers/usb/phy/phy-omap-usb3.c @@ -27,7 +27,6 @@ #include #include -#define NUM_SYS_CLKS 6 #define PLL_STATUS 0x00000004 #define PLL_GO 0x00000008 #define PLL_CONFIGURATION1 0x0000000C @@ -57,26 +56,32 @@ */ # define PLL_IDLE_TIME 100; -enum sys_clk_rate { - CLK_RATE_UNDEFINED = -1, - CLK_RATE_12MHZ, - CLK_RATE_16MHZ, - CLK_RATE_19MHZ, - CLK_RATE_20MHZ, - CLK_RATE_26MHZ, - CLK_RATE_38MHZ +struct usb_dpll_map { + unsigned long rate; + struct usb_dpll_params params; }; -static struct usb_dpll_params omap_usb3_dpll_params[NUM_SYS_CLKS] = { - {1250, 5, 4, 20, 0}, /* 12 MHz */ - {3125, 20, 4, 20, 0}, /* 16.8 MHz */ - {1172, 8, 4, 20, 65537}, /* 19.2 MHz */ - {1000, 7, 4, 10, 0}, /* 20 MHz */ - {1250, 12, 4, 20, 0}, /* 26 MHz */ - {3125, 47, 4, 20, 92843}, /* 38.4 MHz */ - +static struct usb_dpll_map dpll_map[] = { + {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */ + {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */ + {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */ + {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */ + {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */ + {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */ }; +static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dpll_map); i++) { + if (rate == dpll_map[i].rate) + return &dpll_map[i].params; + } + + return 0; +} + static int omap_usb3_suspend(struct usb_phy *x, int suspend) { struct omap_usb *phy = phy_to_omapusb(x); @@ -116,26 +121,6 @@ static int omap_usb3_suspend(struct usb_phy *x, int suspend) return 0; } -static inline enum sys_clk_rate __get_sys_clk_index(unsigned long rate) -{ - switch (rate) { - case 12000000: - return CLK_RATE_12MHZ; - case 16800000: - return CLK_RATE_16MHZ; - case 19200000: - return CLK_RATE_19MHZ; - case 20000000: - return CLK_RATE_20MHZ; - case 26000000: - return CLK_RATE_26MHZ; - case 38400000: - return CLK_RATE_38MHZ; - default: - return CLK_RATE_UNDEFINED; - } -} - static void omap_usb_dpll_relock(struct omap_usb *phy) { u32 val; @@ -155,39 +140,39 @@ static int omap_usb_dpll_lock(struct omap_usb *phy) { u32 val; unsigned long rate; - enum sys_clk_rate clk_index; + struct usb_dpll_params *dpll_params; - rate = clk_get_rate(phy->sys_clk); - clk_index = __get_sys_clk_index(rate); - - if (clk_index == CLK_RATE_UNDEFINED) { - pr_err("dpll cannot be locked for sys clk freq:%luHz\n", rate); + rate = clk_get_rate(phy->sys_clk); + dpll_params = omap_usb3_get_dpll_params(rate); + if (!dpll_params) { + dev_err(phy->dev, + "No DPLL configuration for %lu Hz SYS CLK\n", rate); return -EINVAL; } val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); val &= ~PLL_REGN_MASK; - val |= omap_usb3_dpll_params[clk_index].n << PLL_REGN_SHIFT; + val |= dpll_params->n << PLL_REGN_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); val &= ~PLL_SELFREQDCO_MASK; - val |= omap_usb3_dpll_params[clk_index].freq << PLL_SELFREQDCO_SHIFT; + val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); val &= ~PLL_REGM_MASK; - val |= omap_usb3_dpll_params[clk_index].m << PLL_REGM_SHIFT; + val |= dpll_params->m << PLL_REGM_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4); val &= ~PLL_REGM_F_MASK; - val |= omap_usb3_dpll_params[clk_index].mf << PLL_REGM_F_SHIFT; + val |= dpll_params->mf << PLL_REGM_F_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val); val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3); val &= ~PLL_SD_MASK; - val |= omap_usb3_dpll_params[clk_index].sd << PLL_SD_SHIFT; + val |= dpll_params->sd << PLL_SD_SHIFT; omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val); omap_usb_dpll_relock(phy); @@ -198,8 +183,12 @@ static int omap_usb_dpll_lock(struct omap_usb *phy) static int omap_usb3_init(struct usb_phy *x) { struct omap_usb *phy = phy_to_omapusb(x); + int ret; + + ret = omap_usb_dpll_lock(phy); + if (ret) + return ret; - omap_usb_dpll_lock(phy); omap_control_usb3_phy_power(phy->control_dev, 1); return 0; From 925403f425a4a9c503f2fc295652647b1eb10d82 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 11 Jul 2013 22:32:31 -0700 Subject: [PATCH 041/101] usb: renesas_usbhs: tidyup original usbhsx_for_each_xxx macro Current usbhsx_for_each_xxx macro will read out-of-array's memory after last loop operation. It was not good C language operation, and the binary which was compiled by (at least) gcc 4.8.1 is broken This patch tidyup these issues Reported-by: Yusuke Goda Reviewed-by: Takashi Yoshii Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 6 +++--- drivers/usb/renesas_usbhs/mod_host.c | 6 +++--- drivers/usb/renesas_usbhs/pipe.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 805940c37353..3385aeb5a364 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -77,9 +77,9 @@ struct usbhsg_recip_handle { struct usbhsg_gpriv, mod) #define __usbhsg_for_each_uep(start, pos, g, i) \ - for (i = start, pos = (g)->uep + i; \ - i < (g)->uep_size; \ - i++, pos = (g)->uep + i) + for ((i) = start; \ + ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i)); \ + (i)++) #define usbhsg_for_each_uep(pos, gpriv, i) \ __usbhsg_for_each_uep(1, pos, gpriv, i) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index b86815421c8d..e40f565004d0 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -111,9 +111,9 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod) #define __usbhsh_for_each_udev(start, pos, h, i) \ - for (i = start, pos = (h)->udev + i; \ - i < USBHSH_DEVICE_MAX; \ - i++, pos = (h)->udev + i) + for ((i) = start; \ + ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i)); \ + (i)++) #define usbhsh_for_each_udev(pos, hpriv, i) \ __usbhsh_for_each_udev(1, pos, hpriv, i) diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index b476fde955bf..3e5349879838 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -54,9 +54,9 @@ struct usbhs_pipe_info { * pipe list */ #define __usbhs_for_each_pipe(start, pos, info, i) \ - for (i = start, pos = (info)->pipe + i; \ - i < (info)->size; \ - i++, pos = (info)->pipe + i) + for ((i) = start; \ + ((i) < (info)->size) && ((pos) = (info)->pipe + (i)); \ + (i)++) #define usbhs_for_each_pipe(pos, priv, i) \ __usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i) From 0d98b9d6429c21132fa08c452e62127fd5032b55 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Thu, 18 Jul 2013 09:43:08 +0200 Subject: [PATCH 042/101] usb: gadget: atmel_usba: prepare clk before calling enable Replace clk_enable/disable with clk_prepare_enable/disable_unprepare to avoid common clk framework warnings. Signed-off-by: Boris BREZILLON Signed-off-by: Felipe Balbi --- drivers/usb/gadget/atmel_usba_udc.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 1d9722203ca6..f018017e3a77 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1772,6 +1772,7 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid) static int atmel_usba_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { + int ret = 0; struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); unsigned long flags; @@ -1781,8 +1782,14 @@ static int atmel_usba_start(struct usb_gadget *gadget, udc->driver = driver; spin_unlock_irqrestore(&udc->lock, flags); - clk_enable(udc->pclk); - clk_enable(udc->hclk); + ret = clk_prepare_enable(udc->pclk); + if (ret) + goto out; + ret = clk_prepare_enable(udc->hclk); + if (ret) { + clk_disable_unprepare(udc->pclk); + goto out; + } DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); @@ -1797,9 +1804,11 @@ static int atmel_usba_start(struct usb_gadget *gadget, usba_writel(udc, CTRL, USBA_ENABLE_MASK); usba_writel(udc, INT_ENB, USBA_END_OF_RESET); } + +out: spin_unlock_irqrestore(&udc->lock, flags); - return 0; + return ret; } static int atmel_usba_stop(struct usb_gadget *gadget, @@ -1822,8 +1831,8 @@ static int atmel_usba_stop(struct usb_gadget *gadget, udc->driver = NULL; - clk_disable(udc->hclk); - clk_disable(udc->pclk); + clk_disable_unprepare(udc->hclk); + clk_disable_unprepare(udc->pclk); DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); @@ -2022,10 +2031,14 @@ static int __init usba_udc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, udc); /* Make sure we start from a clean slate */ - clk_enable(pclk); + ret = clk_prepare_enable(pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n"); + goto err_clk_enable; + } toggle_bias(0); usba_writel(udc, CTRL, USBA_DISABLE_MASK); - clk_disable(pclk); + clk_disable_unprepare(pclk); if (pdev->dev.of_node) udc->usba_ep = atmel_udc_of_init(pdev, udc); @@ -2081,6 +2094,7 @@ static int __init usba_udc_probe(struct platform_device *pdev) free_irq(irq, udc); err_request_irq: err_alloc_ep: +err_clk_enable: iounmap(udc->fifo); err_map_fifo: iounmap(udc->regs); From fda7130354271b55eea50a4f58ea8540c9971295 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 23 Jul 2013 20:01:52 +0200 Subject: [PATCH 043/101] usb: phy: don't check resource with devm_ioremap_resource devm_ioremap_resource does sanity checks on the given resource. No need to duplicate this in the driver. Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-rcar-usb.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c index ae909408958d..deb7f97f37c7 100644 --- a/drivers/usb/phy/phy-rcar-usb.c +++ b/drivers/usb/phy/phy-rcar-usb.c @@ -190,11 +190,6 @@ static int rcar_usb_phy_probe(struct platform_device *pdev) } res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res0) { - dev_err(dev, "Not enough platform resources\n"); - return -EINVAL; - } - reg0 = devm_ioremap_resource(dev, res0); if (IS_ERR(reg0)) return PTR_ERR(reg0); From 7557a57f5e649c99239975529e2b30dc4990c548 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Jul 2013 20:09:52 +0200 Subject: [PATCH 044/101] usb: musb: dsps: init / shutdown the phy If the init / shutdown function of the phy moves out of dsps into the phy driver, then dsps needs to call the callbacks of the phy driver to ensure that this happens. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 5233804d66b1..603ea747d882 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -428,6 +428,8 @@ static int dsps_musb_init(struct musb *musb) goto err0; } + usb_phy_init(musb->xceiv); + setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb); /* Reset the musb */ @@ -463,6 +465,7 @@ static int dsps_musb_exit(struct musb *musb) /* Shutdown the on-chip PHY and its PLL. */ musb_dsps_phy_control(glue, pdev->id, 0); + usb_phy_shutdown(musb->xceiv); /* NOP driver needs change if supporting dual instance */ usb_put_phy(musb->xceiv); From e9eb2e08d93afc8f334ffe269fc84ea6257ff02c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Jul 2013 20:09:55 +0200 Subject: [PATCH 045/101] usb: musb: remove ti81xx pieces from musb ti81xx does not have a baseport mainline i.e. it should not boot. The amount of rework that is required makes it easier to simply remove that platform (i.e. that possible platform device) and add it later once it comes back with DT support. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 603ea747d882..55f5ff9351d6 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -46,9 +46,7 @@ #include "musb_core.h" -#ifdef CONFIG_OF static const struct of_device_id musb_dsps_of_match[]; -#endif /** * avoid using musb_readx()/musb_writex() as glue layer should not be @@ -753,23 +751,12 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = { .instances = 1, }; -static const struct platform_device_id musb_dsps_id_table[] = { - { - .name = "musb-ti81xx", - .driver_data = (kernel_ulong_t) &ti81xx_driver_data, - }, - { }, /* Terminating Entry */ -}; -MODULE_DEVICE_TABLE(platform, musb_dsps_id_table); - -#ifdef CONFIG_OF static const struct of_device_id musb_dsps_of_match[] = { { .compatible = "ti,musb-am33xx", .data = (void *) &ti81xx_driver_data, }, { }, }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); -#endif static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, @@ -779,7 +766,6 @@ static struct platform_driver dsps_usbss_driver = { .pm = &dsps_pm_ops, .of_match_table = of_match_ptr(musb_dsps_of_match), }, - .id_table = musb_dsps_id_table, }; MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer"); From 63c5b4ca7d0daadf11662d6419eb7a1c0ce42eb7 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 22 Jul 2013 20:10:04 +0200 Subject: [PATCH 046/101] usb: musb: do not change dev's dma_mask Commit 8d2421e ("usb: musb: kill global and static for multi instance") removed the global dma_mask copy and replaced by parent's DMA mask. The problem here is that if the parent does not have a dma_mask then musb_remove() goes kaboom. Instead trying to fix this I was thinking we do we need to erase dma_mask in the first place? Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 9b774e72c0e4..80ffd7ee55df 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1843,10 +1843,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (use_dma && dev->dma_mask) musb->dma_controller = dma_controller_create(musb, musb->mregs); - /* ideally this would be abstracted in platform setup */ - if (!musb->dma_controller) - dev->dma_mask = NULL; - /* be sure interrupts are disabled before connecting ISR */ musb_platform_disable(musb); musb_generic_disable(musb); @@ -1993,9 +1989,6 @@ static int musb_remove(struct platform_device *pdev) musb_free(musb); device_init_wakeup(dev, 0); -#ifndef CONFIG_MUSB_PIO_ONLY - dma_set_mask(dev, *dev->parent->dma_mask); -#endif return 0; } From c49667e56fcb5e92efcbe816c34c3e373b33cd01 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 17 Jul 2013 09:31:00 +0300 Subject: [PATCH 047/101] arm: dts: tegra20: Rename USB UTMI parameters according to new definitions This patch changes the Tegra20 USB PHY nodes to use the UTMI configuration parameter names as specified in the device tree binding documentation after patch "ARM: tegra: finalize USB EHCI and PHY bindings". Signed-off-by: Mikko Perttunen Acked-by: Stephen Warren Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- arch/arm/boot/dts/tegra20.dtsi | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 9653fd8288d2..e4570834512e 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -477,13 +477,13 @@ phy1: usb-phy@c5000000 { <&tegra_car TEGRA20_CLK_USBD>; clock-names = "reg", "pll_u", "timer", "utmi-pads"; nvidia,has-legacy-mode; - hssync_start_delay = <9>; - idle_wait_delay = <17>; - elastic_limit = <16>; - term_range_adj = <6>; - xcvr_setup = <9>; - xcvr_lsfslew = <1>; - xcvr_lsrslew = <1>; + nvidia,hssync-start-delay = <9>; + nvidia,idle-wait-delay = <17>; + nvidia,elastic-limit = <16>; + nvidia,term-range-adj = <6>; + nvidia,xcvr-setup = <9>; + nvidia,xcvr-lsfslew = <1>; + nvidia,xcvr-lsrslew = <1>; status = "disabled"; }; @@ -527,13 +527,13 @@ phy3: usb-phy@c5008000 { <&tegra_car TEGRA20_CLK_CLK_M>, <&tegra_car TEGRA20_CLK_USBD>; clock-names = "reg", "pll_u", "timer", "utmi-pads"; - hssync_start_delay = <9>; - idle_wait_delay = <17>; - elastic_limit = <16>; - term_range_adj = <6>; - xcvr_setup = <9>; - xcvr_lsfslew = <2>; - xcvr_lsrslew = <2>; + nvidia,hssync-start-delay = <9>; + nvidia,idle-wait-delay = <17>; + nvidia,elastic-limit = <16>; + nvidia,term-range-adj = <6>; + nvidia,xcvr-setup = <9>; + nvidia,xcvr-lsfslew = <2>; + nvidia,xcvr-lsrslew = <2>; status = "disabled"; }; From 81d5dfe6d8b3ba48ffcaa882783185c07b5d2384 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 17 Jul 2013 09:31:01 +0300 Subject: [PATCH 048/101] usb: phy: tegra: Read UTMIP parameters from device tree UTMIP parameters used to be hardcoded into tables in the PHY driver. This patch reads them from the device tree instead in accordance with the phy-tegra-usb DT documentation. Signed-off-by: Mikko Perttunen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 129 +++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 42 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index cec0855ed248..3ecd49871b88 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -184,27 +184,6 @@ static const struct tegra_xtal_freq tegra_freq_table[] = { }, }; -static struct tegra_utmip_config utmip_default[] = { - [0] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 9, - .xcvr_lsfslew = 1, - .xcvr_lsrslew = 1, - }, - [2] = { - .hssync_start_delay = 9, - .idle_wait_delay = 17, - .elastic_limit = 16, - .term_range_adj = 6, - .xcvr_setup = 9, - .xcvr_lsfslew = 2, - .xcvr_lsrslew = 2, - }, -}; - static void set_pts(struct tegra_usb_phy *phy, u8 pts_val) { void __iomem *base = phy->regs; @@ -703,13 +682,6 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) int i; int err; - if (!phy->is_ulpi_phy) { - if (phy->is_legacy_phy) - phy->config = &utmip_default[0]; - else - phy->config = &utmip_default[2]; - } - phy->pll_u = devm_clk_get(phy->dev, "pll_u"); if (IS_ERR(phy->pll_u)) { pr_err("Can't get pll_u clock\n"); @@ -784,6 +756,88 @@ void tegra_ehci_phy_restore_end(struct usb_phy *x) } EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); +static int read_utmi_param(struct platform_device *pdev, const char *param, + u8 *dest) +{ + u32 value; + int err = of_property_read_u32(pdev->dev.of_node, param, &value); + *dest = (u8)value; + if (err < 0) + dev_err(&pdev->dev, "Failed to read USB UTMI parameter %s: %d\n", + param, err); + return err; +} + +static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, + struct platform_device *pdev) +{ + struct resource *res; + int err; + struct tegra_utmip_config *config; + + tegra_phy->is_ulpi_phy = false; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n"); + return -ENXIO; + } + + tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!tegra_phy->regs) { + dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n"); + return -ENOMEM; + } + + tegra_phy->config = devm_kzalloc(&pdev->dev, + sizeof(*tegra_phy->config), GFP_KERNEL); + if (!tegra_phy->config) { + dev_err(&pdev->dev, + "unable to allocate memory for USB UTMIP config\n"); + return -ENOMEM; + } + + config = tegra_phy->config; + + err = read_utmi_param(pdev, "nvidia,hssync-start-delay", + &config->hssync_start_delay); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,elastic-limit", + &config->elastic_limit); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,idle-wait-delay", + &config->idle_wait_delay); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,term-range-adj", + &config->term_range_adj); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,xcvr-setup", + &config->xcvr_setup); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew", + &config->xcvr_lsfslew); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,xcvr-lsrslew", + &config->xcvr_lsrslew); + if (err < 0) + return err; + + return 0; +} + static int tegra_usb_phy_probe(struct platform_device *pdev) { struct resource *res; @@ -815,20 +869,9 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) err = of_property_match_string(np, "phy_type", "ulpi"); if (err < 0) { - tegra_phy->is_ulpi_phy = false; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n"); - return -ENXIO; - } - - tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!tegra_phy->regs) { - dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n"); - return -ENOMEM; - } + err = utmi_phy_probe(tegra_phy, pdev); + if (err < 0) + return err; } else { tegra_phy->is_ulpi_phy = true; @@ -839,6 +882,8 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->reset_gpio); return tegra_phy->reset_gpio; } + + tegra_phy->config = NULL; } err = of_property_match_string(np, "dr_mode", "otg"); From f5b8c8b6d3b4697f28b818d8784e3e4b2a290022 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 17 Jul 2013 10:37:49 +0300 Subject: [PATCH 049/101] usb: tegra: Use regulators instead of GPIOs for USB PHY VBUS The tegra ehci driver has enabled USB vbus regulators directly using GPIOs and the device tree attribute nvidia,vbus-gpio. This is ugly and causes error messages on boot when both the regulator driver and the ehci driver want access to the same GPIO. After this patch, usb vbus regulators for tegra usb phy devices are specified with the device tree attribute vbus-supply = <&x> where x is a regulator defined in the device tree. The old nvidia,vbus-gpio property is no longer supported. Signed-off-by: Mikko Perttunen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/host/ehci-tegra.c | 34 +------------------------------ drivers/usb/phy/phy-tegra-usb.c | 24 ++++++++++++++++++++++ include/linux/usb/tegra_usb_phy.h | 1 + 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 6ee7ef79b4f8..14c1f35a4b10 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -322,33 +322,6 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) free_dma_aligned_buffer(urb); } -static int setup_vbus_gpio(struct platform_device *pdev, - struct tegra_ehci_platform_data *pdata) -{ - int err = 0; - int gpio; - - gpio = pdata->vbus_gpio; - if (!gpio_is_valid(gpio)) - gpio = of_get_named_gpio(pdev->dev.of_node, - "nvidia,vbus-gpio", 0); - if (!gpio_is_valid(gpio)) - return 0; - - err = gpio_request(gpio, "vbus_gpio"); - if (err) { - dev_err(&pdev->dev, "can't request vbus gpio %d", gpio); - return err; - } - err = gpio_direction_output(gpio, 1); - if (err) { - dev_err(&pdev->dev, "can't enable vbus\n"); - return err; - } - - return err; -} - static int tegra_ehci_probe(struct platform_device *pdev) { struct resource *res; @@ -376,14 +349,11 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (!pdev->dev.coherent_dma_mask) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - setup_vbus_gpio(pdev, pdata); - hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); - err = -ENOMEM; - goto cleanup_vbus_gpio; + return -ENOMEM; } platform_set_drvdata(pdev, hcd); ehci = hcd_to_ehci(hcd); @@ -494,8 +464,6 @@ static int tegra_ehci_probe(struct platform_device *pdev) clk_put(tegra->clk); cleanup_hcd_create: usb_put_hcd(hcd); -cleanup_vbus_gpio: - /* FIXME: Undo setup_vbus_gpio() here */ return err; } diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 3ecd49871b88..d92a63a5b0c9 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -34,6 +34,7 @@ #include #include #include +#include #define ULPI_VIEWPORT 0x170 @@ -613,6 +614,9 @@ static void tegra_usb_phy_close(struct usb_phy *x) { struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + if (!IS_ERR(phy->vbus)) + regulator_disable(phy->vbus); + clk_disable_unprepare(phy->pll_u); } @@ -705,6 +709,16 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) goto fail; } + if (!IS_ERR(phy->vbus)) { + err = regulator_enable(phy->vbus); + if (err) { + dev_err(phy->dev, + "failed to enable usb vbus regulator: %d\n", + err); + goto fail; + } + } + if (phy->is_ulpi_phy) err = ulpi_open(phy); else @@ -896,6 +910,16 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) } else tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG; + /* On some boards, the VBUS regulator doesn't need to be controlled */ + if (of_find_property(np, "vbus-supply", NULL)) { + tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus"); + if (IS_ERR(tegra_phy->vbus)) + return PTR_ERR(tegra_phy->vbus); + } else { + dev_notice(&pdev->dev, "no vbus regulator"); + tegra_phy->vbus = ERR_PTR(-ENODEV); + } + tegra_phy->dev = &pdev->dev; err = tegra_usb_phy_init(tegra_phy); if (err < 0) diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d2ca919a5b73..2b5fa947980a 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -55,6 +55,7 @@ struct tegra_usb_phy { struct clk *clk; struct clk *pll_u; struct clk *pad_clk; + struct regulator *vbus; enum tegra_usb_phy_mode mode; void *config; struct usb_phy *ulpi; From 80bd8a94712a0a9f2baeb03ad0546dd70f27ac4e Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 17 Jul 2013 10:37:50 +0300 Subject: [PATCH 050/101] usb: tegra: Add vbus-supply property for host mode PHYs Document vbus-supply as an optional property for host mode phy-tegra-usb PHYs. Signed-off-by: Mikko Perttunen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt index c4c9e9e664aa..59c48542abb9 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -48,5 +48,5 @@ Optional properties: peripheral means it is device controller otg means it can operate as either ("on the go") -Required properties for dr_mode == otg: +VBUS control (required for dr_mode == host, optional for dr_mode == otg): - vbus-supply: regulator for VBUS From 103566e40d0a57b028a51671d852b2650947a5ec Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 17 Jul 2013 10:37:51 +0300 Subject: [PATCH 051/101] arm: tegra: Remove obsolete nvidia,vbus-gpio properties USB VBUS regulators are now specified with the vbus-supply property instead of nvidia,vbus-gpio, so remove the obsolete properties. The equivalent vbus-supply properties were already added in patch "ARM: tegra: update device trees for USB binding rework". Signed-off-by: Mikko Perttunen Acked-by: Stephen Warren Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- arch/arm/boot/dts/tegra20-seaboard.dts | 1 - arch/arm/boot/dts/tegra20-trimslice.dts | 1 - arch/arm/boot/dts/tegra20-whistler.dts | 2 -- 3 files changed, 4 deletions(-) diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index 365760b33a26..52526c9a1329 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts @@ -566,7 +566,6 @@ emc-table@380000 { usb@c5000000 { status = "okay"; - nvidia,vbus-gpio = <&gpio TEGRA_GPIO(D, 0) GPIO_ACTIVE_HIGH>; dr_mode = "otg"; }; diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts index ed4b901b0227..3e57b87cc75f 100644 --- a/arch/arm/boot/dts/tegra20-trimslice.dts +++ b/arch/arm/boot/dts/tegra20-trimslice.dts @@ -312,7 +312,6 @@ pmc { usb@c5000000 { status = "okay"; - nvidia,vbus-gpio = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>; }; usb-phy@c5000000 { diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts index ab67c94db280..a6b1b5bdf288 100644 --- a/arch/arm/boot/dts/tegra20-whistler.dts +++ b/arch/arm/boot/dts/tegra20-whistler.dts @@ -509,7 +509,6 @@ pmc { usb@c5000000 { status = "okay"; - nvidia,vbus-gpio = <&tca6416 0 GPIO_ACTIVE_HIGH>; }; usb-phy@c5000000 { @@ -519,7 +518,6 @@ usb-phy@c5000000 { usb@c5008000 { status = "okay"; - nvidia,vbus-gpio = <&tca6416 1 GPIO_ACTIVE_HIGH>; }; usb-phy@c5008000 { From 185d0fd570c121c0c3d4527842a097e50e3e7a79 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:01 +0300 Subject: [PATCH 052/101] usb: phy: tegra: Remove unnecessary 'dev' field struct usb_phy already has a field for the device pointer, so this unnecessary field can be removed. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 27 +++++++++++++++------------ include/linux/usb/tegra_usb_phy.h | 1 - 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index d92a63a5b0c9..311fe03f16e1 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -211,7 +211,7 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable) static int utmip_pad_open(struct tegra_usb_phy *phy) { - phy->pad_clk = devm_clk_get(phy->dev, "utmi-pads"); + phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads"); if (IS_ERR(phy->pad_clk)) { pr_err("%s: can't get utmip pad clock\n", __func__); return PTR_ERR(phy->pad_clk); @@ -540,13 +540,15 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) ret = gpio_direction_output(phy->reset_gpio, 0); if (ret < 0) { - dev_err(phy->dev, "gpio %d not set to 0\n", phy->reset_gpio); + dev_err(phy->u_phy.dev, "gpio %d not set to 0\n", + phy->reset_gpio); return ret; } msleep(5); ret = gpio_direction_output(phy->reset_gpio, 1); if (ret < 0) { - dev_err(phy->dev, "gpio %d not set to 1\n", phy->reset_gpio); + dev_err(phy->u_phy.dev, "gpio %d not set to 1\n", + phy->reset_gpio); return ret; } @@ -649,29 +651,30 @@ static int ulpi_open(struct tegra_usb_phy *phy) { int err; - phy->clk = devm_clk_get(phy->dev, "ulpi-link"); + phy->clk = devm_clk_get(phy->u_phy.dev, "ulpi-link"); if (IS_ERR(phy->clk)) { pr_err("%s: can't get ulpi clock\n", __func__); return PTR_ERR(phy->clk); } - err = devm_gpio_request(phy->dev, phy->reset_gpio, "ulpi_phy_reset_b"); + err = devm_gpio_request(phy->u_phy.dev, phy->reset_gpio, + "ulpi_phy_reset_b"); if (err < 0) { - dev_err(phy->dev, "request failed for gpio: %d\n", + dev_err(phy->u_phy.dev, "request failed for gpio: %d\n", phy->reset_gpio); return err; } err = gpio_direction_output(phy->reset_gpio, 0); if (err < 0) { - dev_err(phy->dev, "gpio %d direction not set to output\n", + dev_err(phy->u_phy.dev, "gpio %d direction not set to output\n", phy->reset_gpio); return err; } phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0); if (!phy->ulpi) { - dev_err(phy->dev, "otg_ulpi_create returned NULL\n"); + dev_err(phy->u_phy.dev, "otg_ulpi_create returned NULL\n"); err = -ENOMEM; return err; } @@ -686,7 +689,7 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) int i; int err; - phy->pll_u = devm_clk_get(phy->dev, "pll_u"); + phy->pll_u = devm_clk_get(phy->u_phy.dev, "pll_u"); if (IS_ERR(phy->pll_u)) { pr_err("Can't get pll_u clock\n"); return PTR_ERR(phy->pll_u); @@ -712,7 +715,7 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) if (!IS_ERR(phy->vbus)) { err = regulator_enable(phy->vbus); if (err) { - dev_err(phy->dev, + dev_err(phy->u_phy.dev, "failed to enable usb vbus regulator: %d\n", err); goto fail; @@ -920,7 +923,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->vbus = ERR_PTR(-ENODEV); } - tegra_phy->dev = &pdev->dev; + tegra_phy->u_phy.dev = &pdev->dev; err = tegra_usb_phy_init(tegra_phy); if (err < 0) return err; @@ -953,7 +956,7 @@ static int tegra_usb_phy_match(struct device *dev, void *data) struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev); struct device_node *dn = data; - return (tegra_phy->dev->of_node == dn) ? 1 : 0; + return (tegra_phy->u_phy.dev->of_node == dn) ? 1 : 0; } struct usb_phy *tegra_usb_get_phy(struct device_node *dn) diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 2b5fa947980a..c2bc7106aaa8 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -60,7 +60,6 @@ struct tegra_usb_phy { void *config; struct usb_phy *ulpi; struct usb_phy u_phy; - struct device *dev; bool is_legacy_phy; bool is_ulpi_phy; int reset_gpio; From de3f233703080bfbbd5861d27660db7a2e476238 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:02 +0300 Subject: [PATCH 053/101] usb: host: tegra: Remove leftover code ehci-tegra calls devm_usb_get_phy, which will never succeed since the Tegra PHY does not register itself with the PHY subsystem. It is also completely redundant since the code has already located a PHY via an internal API. Call otg_set_host unconditionally to simplify the code since it should be safe to do so. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/host/ehci-tegra.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 14c1f35a4b10..06e8febdcc2c 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -58,7 +58,6 @@ static int (*orig_hub_control)(struct usb_hcd *hcd, struct tegra_ehci_hcd { struct tegra_usb_phy *phy; struct clk *clk; - struct usb_phy *transceiver; int port_resuming; bool needs_double_reset; enum tegra_usb_phy_port_speed port_speed; @@ -436,26 +435,18 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto cleanup_phy; } - if (pdata->operating_mode == TEGRA_USB_OTG) { - tegra->transceiver = - devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, &hcd->self); - } else { - tegra->transceiver = ERR_PTR(-ENODEV); - } + otg_set_host(u_phy->otg, &hcd->self); err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) { dev_err(&pdev->dev, "Failed to add USB HCD\n"); - goto cleanup_transceiver; + goto cleanup_otg_set_host; } return err; -cleanup_transceiver: - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, NULL); +cleanup_otg_set_host: + otg_set_host(u_phy->otg, NULL); cleanup_phy: usb_phy_shutdown(hcd->phy); cleanup_clk_en: @@ -473,8 +464,7 @@ static int tegra_ehci_remove(struct platform_device *pdev) struct tegra_ehci_hcd *tegra = (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; - if (!IS_ERR(tegra->transceiver)) - otg_set_host(tegra->transceiver->otg, NULL); + otg_set_host(hcd->phy->otg, NULL); usb_phy_shutdown(hcd->phy); usb_remove_hcd(hcd); From d506427945089ced99cfbc5f53dd5adc5d34a5cd Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:03 +0300 Subject: [PATCH 054/101] usb: tegra: host: Remove references to plat data Platform data is not used in tegra-ehci anymore, so remove all references to it. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/host/ehci-tegra.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 06e8febdcc2c..a208cea4e4c7 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -327,18 +326,11 @@ static int tegra_ehci_probe(struct platform_device *pdev) struct usb_hcd *hcd; struct ehci_hcd *ehci; struct tegra_ehci_hcd *tegra; - struct tegra_ehci_platform_data *pdata; int err = 0; int irq; struct device_node *np_phy; struct usb_phy *u_phy; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Platform data missing\n"); - return -EINVAL; - } - /* Right now device-tree probed devices don't get dma_mask set. * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. From 5fed6828318119656e243c4f0a11955cefc8eebd Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:04 +0300 Subject: [PATCH 055/101] ARM: tegra: Remove USB platform data USB-related platform data is not used anymore in the Tegra USB drivers, so remove all of it. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Acked-by: Stephen Warren Signed-off-by: Felipe Balbi --- arch/arm/mach-tegra/tegra.c | 38 +------------------------ include/linux/platform_data/tegra_usb.h | 32 --------------------- include/linux/usb/tegra_usb_phy.h | 5 ---- 3 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 include/linux/platform_data/tegra_usb.h diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 0d1e4128d460..fc97cfd52769 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -46,40 +45,6 @@ #include "fuse.h" #include "iomap.h" -static struct tegra_ehci_platform_data tegra_ehci1_pdata = { - .operating_mode = TEGRA_USB_OTG, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { - .reset_gpio = -1, - .clk = "cdev2", -}; - -static struct tegra_ehci_platform_data tegra_ehci2_pdata = { - .phy_config = &tegra_ehci2_ulpi_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct tegra_ehci_platform_data tegra_ehci3_pdata = { - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0", - &tegra_ehci1_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1", - &tegra_ehci2_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2", - &tegra_ehci3_pdata), - {} -}; - static void __init tegra_dt_init(void) { struct soc_device_attribute *soc_dev_attr; @@ -112,8 +77,7 @@ static void __init tegra_dt_init(void) * devices */ out: - of_platform_populate(NULL, of_default_bus_match_table, - tegra20_auxdata_lookup, parent); + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); } static void __init trimslice_init(void) diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h deleted file mode 100644 index 66c673fef408..000000000000 --- a/include/linux/platform_data/tegra_usb.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _TEGRA_USB_H_ -#define _TEGRA_USB_H_ - -enum tegra_usb_operating_modes { - TEGRA_USB_DEVICE, - TEGRA_USB_HOST, - TEGRA_USB_OTG, -}; - -struct tegra_ehci_platform_data { - enum tegra_usb_operating_modes operating_mode; - /* power down the phy on bus suspend */ - int power_down_on_bus_suspend; - void *phy_config; - int vbus_gpio; -}; - -#endif /* _TEGRA_USB_H_ */ diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index c2bc7106aaa8..847415313ad2 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -28,11 +28,6 @@ struct tegra_utmip_config { u8 xcvr_lsrslew; }; -struct tegra_ulpi_config { - int reset_gpio; - const char *clk; -}; - enum tegra_usb_phy_port_speed { TEGRA_USB_PHY_PORT_SPEED_FULL = 0, TEGRA_USB_PHY_PORT_SPEED_LOW, From 0ee5b4ab79b6be1400f3fa47142e927ddc33a5bd Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:05 +0300 Subject: [PATCH 056/101] usb: phy: tegra: Register as an USB PHY. Register the Tegra PHY device instances with the PHY subsystem so that the Tegra EHCI driver can locate a PHY via the standard APIs. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 311fe03f16e1..441c306c050f 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -932,6 +932,22 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend; dev_set_drvdata(&pdev->dev, tegra_phy); + + err = usb_add_phy_dev(&tegra_phy->u_phy); + if (err < 0) { + tegra_usb_phy_close(&tegra_phy->u_phy); + return err; + } + + return 0; +} + +static int tegra_usb_phy_remove(struct platform_device *pdev) +{ + struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev); + + usb_remove_phy(&tegra_phy->u_phy); + return 0; } @@ -943,6 +959,7 @@ MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table); static struct platform_driver tegra_usb_phy_driver = { .probe = tegra_usb_phy_probe, + .remove = tegra_usb_phy_remove, .driver = { .name = "tegra-phy", .owner = THIS_MODULE, From 7db71a9a6707284f3d9075fff2ad674f6a51c359 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:06 +0300 Subject: [PATCH 057/101] usb: host: tegra: Locate a PHY via standard API Use devm_get_phy_by_phandle to get a PHY device instead of the custom Tegra functions. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/host/ehci-tegra.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index a208cea4e4c7..db8031fd5c13 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -328,7 +328,6 @@ static int tegra_ehci_probe(struct platform_device *pdev) struct tegra_ehci_hcd *tegra; int err = 0; int irq; - struct device_node *np_phy; struct usb_phy *u_phy; /* Right now device-tree probed devices don't get dma_mask set. @@ -367,13 +366,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) udelay(1); tegra_periph_reset_deassert(tegra->clk); - np_phy = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0); - if (!np_phy) { - err = -ENODEV; - goto cleanup_clk_en; - } - - u_phy = tegra_usb_get_phy(np_phy); + u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); if (IS_ERR(u_phy)) { err = PTR_ERR(u_phy); goto cleanup_clk_en; From 3b102e8bc0e49d417c7d376af857537080335dbf Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:07 +0300 Subject: [PATCH 058/101] usb: phy: tegra: Remove custom PHY locating APIs The Tegra EHCI driver is no longer using these custom functions, so they can be removed. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 24 ------------------------ include/linux/usb/tegra_usb_phy.h | 2 -- 2 files changed, 26 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 441c306c050f..fb5bc8cea680 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -968,29 +968,5 @@ static struct platform_driver tegra_usb_phy_driver = { }; module_platform_driver(tegra_usb_phy_driver); -static int tegra_usb_phy_match(struct device *dev, void *data) -{ - struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev); - struct device_node *dn = data; - - return (tegra_phy->u_phy.dev->of_node == dn) ? 1 : 0; -} - -struct usb_phy *tegra_usb_get_phy(struct device_node *dn) -{ - struct device *dev; - struct tegra_usb_phy *tegra_phy; - - dev = driver_find_device(&tegra_usb_phy_driver.driver, NULL, dn, - tegra_usb_phy_match); - if (!dev) - return ERR_PTR(-EPROBE_DEFER); - - tegra_phy = dev_get_drvdata(dev); - - return &tegra_phy->u_phy; -} -EXPORT_SYMBOL_GPL(tegra_usb_get_phy); - MODULE_DESCRIPTION("Tegra USB PHY driver"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 847415313ad2..a095c98184d0 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -60,8 +60,6 @@ struct tegra_usb_phy { int reset_gpio; }; -struct usb_phy *tegra_usb_get_phy(struct device_node *dn); - void tegra_usb_phy_preresume(struct usb_phy *phy); void tegra_usb_phy_postresume(struct usb_phy *phy); From 9fdb07f72088ab5fc7bd6fd6f070fac53d636bd9 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:08 +0300 Subject: [PATCH 059/101] usb: phy: tegra: Use DT helpers for phy_type Use the new of_usb_get_phy_mode helper function for parsing phy_type from the device tree. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index fb5bc8cea680..fb469f1e8d10 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -860,6 +861,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) struct resource *res; struct tegra_usb_phy *tegra_phy = NULL; struct device_node *np = pdev->dev.of_node; + enum usb_phy_interface phy_type; int err; tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL); @@ -884,12 +886,12 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->is_legacy_phy = of_property_read_bool(np, "nvidia,has-legacy-mode"); - err = of_property_match_string(np, "phy_type", "ulpi"); - if (err < 0) { + phy_type = of_usb_get_phy_mode(np); + if (phy_type == USBPHY_INTERFACE_MODE_UTMI) { err = utmi_phy_probe(tegra_phy, pdev); if (err < 0) return err; - } else { + } else if (phy_type == USBPHY_INTERFACE_MODE_ULPI) { tegra_phy->is_ulpi_phy = true; tegra_phy->reset_gpio = @@ -899,8 +901,10 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->reset_gpio); return tegra_phy->reset_gpio; } - tegra_phy->config = NULL; + } else { + dev_err(&pdev->dev, "phy_type is invalid or unsupported\n"); + return -EINVAL; } err = of_property_match_string(np, "dr_mode", "otg"); From 6558d7edbe069df1220b525362d4aa854a65a8bc Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:09 +0300 Subject: [PATCH 060/101] usb: phy: tegra: Use DT helpers for dr_mode Use the new of_usb_get_dr_mode helper function for parsing dr_mode from the device tree. Also replace the usage of the custom tegra_usb_phy_mode enum with the standard enum. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 24 ++++++++++++------------ include/linux/usb/tegra_usb_phy.h | 8 +------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index fb469f1e8d10..01c30ff8874e 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -377,7 +377,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); writel(val, base + UTMIP_PLL_CFG1); - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { + if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl(base + USB_SUSP_CTRL); val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); writel(val, base + USB_SUSP_CTRL); @@ -412,7 +412,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) if (phy->is_legacy_phy) { val = readl(base + UTMIP_SPARE_CFG0); - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) + if (phy->mode == USB_DR_MODE_PERIPHERAL) val &= ~FUSE_SETUP_SEL; else val |= FUSE_SETUP_SEL; @@ -453,7 +453,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) utmi_phy_clk_disable(phy); - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { + if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl(base + USB_SUSP_CTRL); val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); @@ -907,15 +907,15 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return -EINVAL; } - err = of_property_match_string(np, "dr_mode", "otg"); - if (err < 0) { - err = of_property_match_string(np, "dr_mode", "peripheral"); - if (err < 0) - tegra_phy->mode = TEGRA_USB_PHY_MODE_HOST; - else - tegra_phy->mode = TEGRA_USB_PHY_MODE_DEVICE; - } else - tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG; + if (of_find_property(np, "dr_mode", NULL)) + tegra_phy->mode = of_usb_get_dr_mode(np); + else + tegra_phy->mode = USB_DR_MODE_HOST; + + if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) { + dev_err(&pdev->dev, "dr_mode is invalid\n"); + return -EINVAL; + } /* On some boards, the VBUS regulator doesn't need to be controlled */ if (of_find_property(np, "vbus-supply", NULL)) { diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index a095c98184d0..d3db274610a1 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -34,12 +34,6 @@ enum tegra_usb_phy_port_speed { TEGRA_USB_PHY_PORT_SPEED_HIGH, }; -enum tegra_usb_phy_mode { - TEGRA_USB_PHY_MODE_DEVICE, - TEGRA_USB_PHY_MODE_HOST, - TEGRA_USB_PHY_MODE_OTG, -}; - struct tegra_xtal_freq; struct tegra_usb_phy { @@ -51,7 +45,7 @@ struct tegra_usb_phy { struct clk *pll_u; struct clk *pad_clk; struct regulator *vbus; - enum tegra_usb_phy_mode mode; + enum usb_dr_mode mode; void *config; struct usb_phy *ulpi; struct usb_phy u_phy; From fa7b4ca50f03b6e71665ccef66ca000311353fc8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 26 Jul 2013 11:11:37 +0200 Subject: [PATCH 061/101] usb: musb: dsps: rename ti81xx_driver_data to am33xx_driver_data The ti81xx platform is not fully supported right now. This patch renames the date structure to a am33xx prefix which is actually used. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 55f5ff9351d6..aba2dc58938d 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -720,7 +720,7 @@ static int dsps_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); -static const struct dsps_musb_wrapper ti81xx_driver_data = { +static const struct dsps_musb_wrapper am33xx_driver_data = { .revision = 0x00, .control = 0x14, .status = 0x18, @@ -753,7 +753,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = { static const struct of_device_id musb_dsps_of_match[] = { { .compatible = "ti,musb-am33xx", - .data = (void *) &ti81xx_driver_data, }, + .data = (void *) &am33xx_driver_data, }, { }, }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); From 9be73bae70ac5b0149daa243eeae2bdacd970574 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 26 Jul 2013 11:11:38 +0200 Subject: [PATCH 062/101] usb: musb: dsps: remove EOI access The EOI register is not present in the AM335x memory space according to the TRM and thus removed. Should any platform using the EOI register get merged then it may be used again if the register address is not zero. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index aba2dc58938d..23f511f7df6d 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -73,7 +73,6 @@ struct dsps_musb_wrapper { u16 revision; u16 control; u16 status; - u16 eoi; u16 epintr_set; u16 epintr_clear; u16 epintr_status; @@ -203,7 +202,6 @@ static void dsps_musb_disable(struct musb *musb) dsps_writel(reg_base, wrp->epintr_clear, wrp->txep_bitmap | wrp->rxep_bitmap); dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); - dsps_writel(reg_base, wrp->eoi, 0); } static void otg_timer(unsigned long _musb) @@ -317,7 +315,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) /* Get usb core interrupts */ usbintr = dsps_readl(reg_base, wrp->coreintr_status); if (!usbintr && !epintr) - goto eoi; + goto out; musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; if (usbintr) @@ -385,16 +383,11 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) if (musb->int_tx || musb->int_rx || musb->int_usb) ret |= musb_interrupt(musb); - eoi: - /* EOI needs to be written for the IRQ to be re-asserted. */ - if (ret == IRQ_HANDLED || epintr || usbintr) - dsps_writel(reg_base, wrp->eoi, 1); - /* Poll for ID change */ if (musb->xceiv->state == OTG_STATE_B_IDLE) mod_timer(&glue->timer[pdev->id], jiffies + wrp->poll_seconds * HZ); - +out: spin_unlock_irqrestore(&musb->lock, flags); return ret; @@ -443,9 +436,6 @@ static int dsps_musb_init(struct musb *musb) val &= ~(1 << wrp->otg_disable); dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); - /* clear level interrupt */ - dsps_writel(reg_base, wrp->eoi, 0); - return 0; err0: usb_put_phy(musb->xceiv); @@ -724,7 +714,6 @@ static const struct dsps_musb_wrapper am33xx_driver_data = { .revision = 0x00, .control = 0x14, .status = 0x18, - .eoi = 0x24, .epintr_set = 0x38, .epintr_clear = 0x40, .epintr_status = 0x30, From a554aea67aaadb7f3396b2a8f940ab0b915b2a5e Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 22:24:09 +0300 Subject: [PATCH 063/101] usb: phy: tegra: Use switch instead of if-else Use switch() instead of if-else when checking for the PHY type. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 01c30ff8874e..49fa2da56c4b 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -887,11 +887,14 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) of_property_read_bool(np, "nvidia,has-legacy-mode"); phy_type = of_usb_get_phy_mode(np); - if (phy_type == USBPHY_INTERFACE_MODE_UTMI) { + switch (phy_type) { + case USBPHY_INTERFACE_MODE_UTMI: err = utmi_phy_probe(tegra_phy, pdev); if (err < 0) return err; - } else if (phy_type == USBPHY_INTERFACE_MODE_ULPI) { + break; + + case USBPHY_INTERFACE_MODE_ULPI: tegra_phy->is_ulpi_phy = true; tegra_phy->reset_gpio = @@ -902,7 +905,9 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return tegra_phy->reset_gpio; } tegra_phy->config = NULL; - } else { + break; + + default: dev_err(&pdev->dev, "phy_type is invalid or unsupported\n"); return -EINVAL; } From 2e112345c22bcdf5d246db40f0587d7d11f1dc61 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 29 Jul 2013 10:27:02 +0300 Subject: [PATCH 064/101] usb: dwc3: core: modify IO memory resource after deferred probe completes When deferred probe happens driver will try to ioremap multiple times and will fail. Memory resource.start variable is a global variable, modifications in this field will be accumulated on every probe. Fix this by moving the above operations after driver hold all required PHY's. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index dfbc1f0fc0e3..da0a4b8b33ed 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -384,21 +384,6 @@ static int dwc3_probe(struct platform_device *pdev) dev_err(dev, "missing memory resource\n"); return -ENODEV; } - dwc->xhci_resources[0].start = res->start; - dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + - DWC3_XHCI_REGS_END; - dwc->xhci_resources[0].flags = res->flags; - dwc->xhci_resources[0].name = res->name; - - res->start += DWC3_GLOBALS_REGS_START; - - /* - * Request memory region but exclude xHCI regs, - * since it will be requested by the xhci-plat driver. - */ - regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) - return PTR_ERR(regs); if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); @@ -452,6 +437,22 @@ static int dwc3_probe(struct platform_device *pdev) return -EPROBE_DEFER; } + dwc->xhci_resources[0].start = res->start; + dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + + DWC3_XHCI_REGS_END; + dwc->xhci_resources[0].flags = res->flags; + dwc->xhci_resources[0].name = res->name; + + res->start += DWC3_GLOBALS_REGS_START; + + /* + * Request memory region but exclude xHCI regs, + * since it will be requested by the xhci-plat driver. + */ + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); From 9cf7b244187bba5964d4bf7438946baa2a974466 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jul 2013 09:09:15 +0300 Subject: [PATCH 065/101] usb: of: fix build breakage caused by recent patches commit 052a11d (usb: phy: make PHY driver selection possible by controller drivers) changed the rules on how drivers/usb/phy/of.c would be compiled and failed to update include/linux/usb/of.h accordingly. Because of that, we can fall into situations where of_usb_get_phy_mode() is redefined. In order to fix the error, we update the IS_ENABLED() check in include/linux/usb/of.h to reflect the condition where of.c is built. Reported-by: Stephen Rothwell Signed-off-by: Felipe Balbi --- include/linux/usb/of.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index 5a7cb9ebf0ef..8c38aa26b3bb 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -27,7 +27,7 @@ of_usb_get_maximum_speed(struct device_node *np) } #endif -#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_PHY) +#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT) enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np); #else static inline enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np) From b27f274d358b2bf51fa052c196090f8acd1f35d6 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Tue, 30 Jul 2013 09:47:57 +0300 Subject: [PATCH 066/101] usb: tegra: Fix typo in tegra20-usb-phy documentation The device tree binding documentation for tegra20-usb-phy used to claim that the vbus-supply property is required for host phys and optional for otg phys. This should be the other way around. Signed-off-by: Mikko Perttunen Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt index 59c48542abb9..4c8ade8b340b 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -48,5 +48,5 @@ Optional properties: peripheral means it is device controller otg means it can operate as either ("on the go") -VBUS control (required for dr_mode == host, optional for dr_mode == otg): +VBUS control (required for dr_mode == otg, optional for dr_mode == host): - vbus-supply: regulator for VBUS From e01ee9f509a927158f670408b41127d4166db1c7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 30 Jul 2013 17:00:51 +0900 Subject: [PATCH 067/101] usb: gadget: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/at91_udc.c | 4 ++-- drivers/usb/gadget/atmel_usba_udc.c | 2 +- drivers/usb/gadget/bcm63xx_udc.c | 2 +- drivers/usb/gadget/fsl_mxc_udc.c | 4 ++-- drivers/usb/gadget/fsl_udc_core.c | 6 +++--- drivers/usb/gadget/hid.c | 2 +- drivers/usb/gadget/m66592-udc.c | 4 ++-- drivers/usb/gadget/mv_u3d_core.c | 12 ++++++------ drivers/usb/gadget/mv_udc_core.c | 4 ++-- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa25x_udc.c | 2 +- drivers/usb/gadget/pxa27x_udc.c | 2 +- drivers/usb/gadget/r8a66597-udc.c | 2 +- drivers/usb/gadget/s3c-hsotg.c | 4 ++-- drivers/usb/gadget/s3c-hsudc.c | 4 ++-- drivers/usb/gadget/s3c2410_udc.c | 2 +- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index d9a6add0c852..d237429dd93a 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1697,7 +1697,7 @@ static int at91udc_probe(struct platform_device *pdev) int retval; struct resource *res; - if (!dev->platform_data && !pdev->dev.of_node) { + if (!dev_get_platdata(dev) && !pdev->dev.of_node) { /* small (so we copy it) but critical! */ DBG("missing platform_data\n"); return -ENODEV; @@ -1728,7 +1728,7 @@ static int at91udc_probe(struct platform_device *pdev) if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) at91udc_of_init(udc, pdev->dev.of_node); else - memcpy(&udc->board, dev->platform_data, + memcpy(&udc->board, dev_get_platdata(dev), sizeof(struct at91_udc_data)); udc->pdev = pdev; udc->enabled = 0; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index f018017e3a77..40d23384b716 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1931,7 +1931,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, static struct usba_ep * usba_udc_pdata(struct platform_device *pdev, struct usba_udc *udc) { - struct usba_platform_data *pdata = pdev->dev.platform_data; + struct usba_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usba_ep *eps; int i; diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index fd24cb4540a4..c58fcf1ebe41 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -2313,7 +2313,7 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc) static int bcm63xx_udc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct bcm63xx_usbd_platform_data *pd = dev->platform_data; + struct bcm63xx_usbd_platform_data *pd = dev_get_platdata(dev); struct bcm63xx_udc *udc; struct resource *res; int rc = -ENOMEM, i, irq; diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index d3bd7b095ba3..9b140fc4d3bc 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c @@ -33,7 +33,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) unsigned long freq; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); mxc_ipg_clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(mxc_ipg_clk)) { @@ -80,7 +80,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) int fsl_udc_clk_finalize(struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); int ret = 0; /* workaround ENGcm09152 for i.MX35 */ diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index a766a4ca1cb7..36ac7cfba91d 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2248,7 +2248,7 @@ static int __init struct_udc_setup(struct fsl_udc *udc, struct fsl_usb2_platform_data *pdata; size_t size; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); udc->phy_mode = pdata->phy_mode; udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); @@ -2343,7 +2343,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) return -ENOMEM; } - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); udc_controller->pdata = pdata; spin_lock_init(&udc_controller->lock); udc_controller->stopped = 1; @@ -2524,7 +2524,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) static int __exit fsl_udc_remove(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); DECLARE_COMPLETION(done); diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c index c36260ea8bf2..778613eb37af 100644 --- a/drivers/usb/gadget/hid.c +++ b/drivers/usb/gadget/hid.c @@ -185,7 +185,7 @@ static int __exit hid_unbind(struct usb_composite_dev *cdev) static int __init hidg_plat_driver_probe(struct platform_device *pdev) { - struct hidg_func_descriptor *func = pdev->dev.platform_data; + struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev); struct hidg_func_node *entry; if (!func) { diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 46ba9838c3a0..d5f050d30edf 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1584,7 +1584,7 @@ static int __init m66592_probe(struct platform_device *pdev) goto clean_up; } - if (pdev->dev.platform_data == NULL) { + if (dev_get_platdata(&pdev->dev) == NULL) { dev_err(&pdev->dev, "no platform data\n"); ret = -ENODEV; goto clean_up; @@ -1598,7 +1598,7 @@ static int __init m66592_probe(struct platform_device *pdev) goto clean_up; } - m66592->pdata = pdev->dev.platform_data; + m66592->pdata = dev_get_platdata(&pdev->dev); m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK; spin_lock_init(&m66592->lock); diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index ec6a2d290398..bbb6e98c4384 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -1109,7 +1109,7 @@ static int mv_u3d_controller_reset(struct mv_u3d *u3d) static int mv_u3d_enable(struct mv_u3d *u3d) { - struct mv_usb_platform_data *pdata = u3d->dev->platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); int retval; if (u3d->active) @@ -1138,7 +1138,7 @@ static int mv_u3d_enable(struct mv_u3d *u3d) static void mv_u3d_disable(struct mv_u3d *u3d) { - struct mv_usb_platform_data *pdata = u3d->dev->platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); if (u3d->clock_gating && u3d->active) { dev_dbg(u3d->dev, "disable u3d\n"); if (pdata->phy_deinit) @@ -1246,7 +1246,7 @@ static int mv_u3d_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget); - struct mv_usb_platform_data *pdata = u3d->dev->platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); unsigned long flags; if (u3d->driver) @@ -1277,7 +1277,7 @@ static int mv_u3d_stop(struct usb_gadget *g, struct usb_gadget_driver *driver) { struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget); - struct mv_usb_platform_data *pdata = u3d->dev->platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev); unsigned long flags; u3d->vbus_valid_detect = 0; @@ -1794,12 +1794,12 @@ static int mv_u3d_remove(struct platform_device *dev) static int mv_u3d_probe(struct platform_device *dev) { struct mv_u3d *u3d = NULL; - struct mv_usb_platform_data *pdata = dev->dev.platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(&dev->dev); int retval = 0; struct resource *r; size_t size; - if (!dev->dev.platform_data) { + if (!dev_get_platdata(&dev->dev)) { dev_err(&dev->dev, "missing platform_data\n"); retval = -ENODEV; goto err_pdata; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index c2a57023e467..104cdbea635a 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2100,7 +2100,7 @@ static int mv_udc_remove(struct platform_device *pdev) static int mv_udc_probe(struct platform_device *pdev) { - struct mv_usb_platform_data *pdata = pdev->dev.platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mv_udc *udc; int retval = 0; struct resource *r; @@ -2118,7 +2118,7 @@ static int mv_udc_probe(struct platform_device *pdev) } udc->done = &release_done; - udc->pdata = pdev->dev.platform_data; + udc->pdata = dev_get_platdata(&pdev->dev); spin_lock_init(&udc->lock); udc->dev = pdev; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index b8ed74a823cb..83957cc225d9 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2734,7 +2734,7 @@ static int omap_udc_probe(struct platform_device *pdev) int hmc; struct usb_phy *xceiv = NULL; const char *type = NULL; - struct omap_usb_config *config = pdev->dev.platform_data; + struct omap_usb_config *config = dev_get_platdata(&pdev->dev); struct clk *dc_clk = NULL; struct clk *hhc_clk = NULL; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 95c531d5aa4f..cc9207473dbc 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -2117,7 +2117,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) /* other non-static parts of init */ dev->dev = &pdev->dev; - dev->mach = pdev->dev.platform_data; + dev->mach = dev_get_platdata(&pdev->dev); dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 41cea9566ac8..3c97da7760da 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -2422,7 +2422,7 @@ static int pxa_udc_probe(struct platform_device *pdev) return udc->irq; udc->dev = &pdev->dev; - udc->mach = pdev->dev.platform_data; + udc->mach = dev_get_platdata(&pdev->dev); udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); gpio = udc->mach->gpio_pullup; diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index c6af649f3240..68be48d33404 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1910,7 +1910,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) spin_lock_init(&r8a66597->lock); platform_set_drvdata(pdev, r8a66597); - r8a66597->pdata = pdev->dev.platform_data; + r8a66597->pdata = dev_get_platdata(&pdev->dev); r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; r8a66597->gadget.ops = &r8a66597_gadget_ops; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 616ed51f8585..d69b36a99dbc 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -3451,7 +3451,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) static int s3c_hsotg_probe(struct platform_device *pdev) { - struct s3c_hsotg_plat *plat = pdev->dev.platform_data; + struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev); struct usb_phy *phy; struct device *dev = &pdev->dev; struct s3c_hsotg_ep *eps; @@ -3470,7 +3470,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); if (IS_ERR(phy)) { /* Fallback for pdata */ - plat = pdev->dev.platform_data; + plat = dev_get_platdata(&pdev->dev); if (!plat) { dev_err(&pdev->dev, "no platform data or transceiver defined\n"); return -EPROBE_DEFER; diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index b1f0771fbd3d..1a1a41498db2 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1262,7 +1262,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *res; struct s3c_hsudc *hsudc; - struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data; + struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev); int ret, i; hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) + @@ -1275,7 +1275,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); hsudc->dev = dev; - hsudc->pd = pdev->dev.platform_data; + hsudc->pd = dev_get_platdata(&pdev->dev); hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 09c4f70c93c4..c72d810e6b36 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1809,7 +1809,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) } spin_lock_init(&udc->lock); - udc_info = pdev->dev.platform_data; + udc_info = dev_get_platdata(&pdev->dev); rsrc_start = S3C2410_PA_USBDEV; rsrc_len = S3C24XX_SZ_USBDEV; From 19f9e188deb4bbcd5fc588f39dc63bdfa9103827 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 30 Jul 2013 17:02:13 +0900 Subject: [PATCH 068/101] usb: phy: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsl-usb.c | 6 +++--- drivers/usb/phy/phy-gpio-vbus-usb.c | 10 +++++----- drivers/usb/phy/phy-msm-usb.c | 4 ++-- drivers/usb/phy/phy-mv-u3d-usb.c | 2 +- drivers/usb/phy/phy-mv-usb.c | 2 +- drivers/usb/phy/phy-nop.c | 3 ++- drivers/usb/phy/phy-omap-control.c | 3 ++- drivers/usb/phy/phy-rcar-usb.c | 4 ++-- drivers/usb/phy/phy-samsung-usb2.c | 2 +- drivers/usb/phy/phy-samsung-usb3.c | 2 +- drivers/usb/phy/phy-twl4030-usb.c | 2 +- drivers/usb/phy/phy-twl6030-usb.c | 2 +- 12 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index e771bafb9f1d..e965cf65d696 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -834,7 +834,7 @@ int usb_otg_start(struct platform_device *pdev) int status; struct resource *res; u32 temp; - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); p_otg = container_of(otg_trans, struct fsl_otg, phy); fsm = &p_otg->fsm; @@ -1105,7 +1105,7 @@ static int fsl_otg_probe(struct platform_device *pdev) { int ret; - if (!pdev->dev.platform_data) + if (!dev_get_platdata(&pdev->dev)) return -ENODEV; /* configure the OTG */ @@ -1137,7 +1137,7 @@ static int fsl_otg_probe(struct platform_device *pdev) static int fsl_otg_remove(struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); usb_remove_phy(&fsl_otg_dev->phy); free_irq(fsl_otg_dev->irq, fsl_otg_dev); diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 8443335c2ea0..b2f29c9aebbf 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -101,7 +101,7 @@ static void gpio_vbus_work(struct work_struct *work) { struct gpio_vbus_data *gpio_vbus = container_of(work, struct gpio_vbus_data, work.work); - struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data; + struct gpio_vbus_mach_info *pdata = dev_get_platdata(gpio_vbus->dev); int gpio, status, vbus; if (!gpio_vbus->phy.otg->gadget) @@ -155,7 +155,7 @@ static void gpio_vbus_work(struct work_struct *work) static irqreturn_t gpio_vbus_irq(int irq, void *data) { struct platform_device *pdev = data; - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; + struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); struct usb_otg *otg = gpio_vbus->phy.otg; @@ -182,7 +182,7 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg, gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy); pdev = to_platform_device(gpio_vbus->dev); - pdata = gpio_vbus->dev->platform_data; + pdata = dev_get_platdata(gpio_vbus->dev); gpio = pdata->gpio_pullup; if (!gadget) { @@ -243,7 +243,7 @@ static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend) static int __init gpio_vbus_probe(struct platform_device *pdev) { - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; + struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); struct gpio_vbus_data *gpio_vbus; struct resource *res; int err, gpio, irq; @@ -352,7 +352,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) static int __exit gpio_vbus_remove(struct platform_device *pdev) { struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; + struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); int gpio = pdata->gpio_vbus; device_init_wakeup(&pdev->dev, 0); diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index d08f33435e96..e9d4cd960ecd 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1419,7 +1419,7 @@ static int __init msm_otg_probe(struct platform_device *pdev) struct usb_phy *phy; dev_info(&pdev->dev, "msm_otg probe\n"); - if (!pdev->dev.platform_data) { + if (!dev_get_platdata(&pdev->dev)) { dev_err(&pdev->dev, "No platform data given. Bailing out\n"); return -ENODEV; } @@ -1436,7 +1436,7 @@ static int __init msm_otg_probe(struct platform_device *pdev) return -ENOMEM; } - motg->pdata = pdev->dev.platform_data; + motg->pdata = dev_get_platdata(&pdev->dev); phy = &motg->phy; phy->dev = &pdev->dev; diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c index 1568ea63e338..6688023021d3 100644 --- a/drivers/usb/phy/phy-mv-u3d-usb.c +++ b/drivers/usb/phy/phy-mv-u3d-usb.c @@ -271,7 +271,7 @@ static int mv_u3d_phy_probe(struct platform_device *pdev) void __iomem *phy_base; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "%s: no platform data defined\n", __func__); return -EINVAL; diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 4a6b03c73876..03d16ff24c02 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -673,7 +673,7 @@ int mv_otg_remove(struct platform_device *pdev) static int mv_otg_probe(struct platform_device *pdev) { - struct mv_usb_platform_data *pdata = pdev->dev.platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mv_otg *mvotg; struct usb_otg *otg; struct resource *r; diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-nop.c index 55445e5d72e5..f52b7f89eef1 100644 --- a/drivers/usb/phy/phy-nop.c +++ b/drivers/usb/phy/phy-nop.c @@ -142,7 +142,8 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) static int nop_usb_xceiv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data; + struct nop_usb_xceiv_platform_data *pdata = + dev_get_platdata(&pdev->dev); struct nop_usb_xceiv *nop; enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/usb/phy/phy-omap-control.c index 1419ceda9759..a4dda8e12562 100644 --- a/drivers/usb/phy/phy-omap-control.c +++ b/drivers/usb/phy/phy-omap-control.c @@ -197,7 +197,8 @@ static int omap_control_usb_probe(struct platform_device *pdev) { struct resource *res; struct device_node *np = pdev->dev.of_node; - struct omap_control_usb_platform_data *pdata = pdev->dev.platform_data; + struct omap_control_usb_platform_data *pdata = + dev_get_platdata(&pdev->dev); control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb), GFP_KERNEL); diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c index deb7f97f37c7..33265a5b2cdf 100644 --- a/drivers/usb/phy/phy-rcar-usb.c +++ b/drivers/usb/phy/phy-rcar-usb.c @@ -83,7 +83,7 @@ static int rcar_usb_phy_init(struct usb_phy *phy) { struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy); struct device *dev = phy->dev; - struct rcar_phy_platform_data *pdata = dev->platform_data; + struct rcar_phy_platform_data *pdata = dev_get_platdata(dev); void __iomem *reg0 = priv->reg0; void __iomem *reg1 = priv->reg1; static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT }; @@ -184,7 +184,7 @@ static int rcar_usb_phy_probe(struct platform_device *pdev) void __iomem *reg0, *reg1 = NULL; int ret; - if (!pdev->dev.platform_data) { + if (!dev_get_platdata(&pdev->dev)) { dev_err(dev, "No platform data\n"); return -EINVAL; } diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c index 758b86d0fcb3..ff70e4b19b97 100644 --- a/drivers/usb/phy/phy-samsung-usb2.c +++ b/drivers/usb/phy/phy-samsung-usb2.c @@ -359,7 +359,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev) { struct samsung_usbphy *sphy; struct usb_otg *otg; - struct samsung_usbphy_data *pdata = pdev->dev.platform_data; + struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev); const struct samsung_usbphy_drvdata *drv_data; struct device *dev = &pdev->dev; struct resource *phy_mem; diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c index 300e0cf5e31f..c6eb22213de6 100644 --- a/drivers/usb/phy/phy-samsung-usb3.c +++ b/drivers/usb/phy/phy-samsung-usb3.c @@ -231,7 +231,7 @@ static void samsung_usb3phy_shutdown(struct usb_phy *phy) static int samsung_usb3phy_probe(struct platform_device *pdev) { struct samsung_usbphy *sphy; - struct samsung_usbphy_data *pdata = pdev->dev.platform_data; + struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct resource *phy_mem; void __iomem *phy_base; diff --git a/drivers/usb/phy/phy-twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c index 8f78d2d40722..90730c8762b8 100644 --- a/drivers/usb/phy/phy-twl4030-usb.c +++ b/drivers/usb/phy/phy-twl4030-usb.c @@ -648,7 +648,7 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host) static int twl4030_usb_probe(struct platform_device *pdev) { - struct twl4030_usb_data *pdata = pdev->dev.platform_data; + struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev); struct twl4030_usb *twl; int status, err; struct usb_otg *otg; diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 1753bd367e0a..16dbc9382678 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -324,7 +324,7 @@ static int twl6030_usb_probe(struct platform_device *pdev) int status, err; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - struct twl4030_usb_data *pdata = dev->platform_data; + struct twl4030_usb_data *pdata = dev_get_platdata(dev); twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL); if (!twl) From c1a7d67c1901347bdb3d06536cd69d018fbf2c4b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 30 Jul 2013 17:03:12 +0900 Subject: [PATCH 069/101] usb: musb: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/musb/am35x.c | 14 +++++++------- drivers/usb/musb/blackfin.c | 2 +- drivers/usb/musb/da8xx.c | 2 +- drivers/usb/musb/davinci.c | 2 +- drivers/usb/musb/musb_core.c | 2 +- drivers/usb/musb/musb_dsps.c | 2 +- drivers/usb/musb/omap2430.c | 8 ++++---- drivers/usb/musb/tusb6010.c | 2 +- drivers/usb/musb/ux500.c | 2 +- drivers/usb/musb/ux500_dma.c | 2 +- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 2231850c0625..baebc39a571b 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -218,7 +218,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci) struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; struct usb_otg *otg = musb->xceiv->otg; unsigned long flags; @@ -335,7 +335,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci) static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode) { struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; int retval = 0; @@ -350,7 +350,7 @@ static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode) static int am35x_musb_init(struct musb *musb) { struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; void __iomem *reg_base = musb->ctrl_base; u32 rev; @@ -394,7 +394,7 @@ static int am35x_musb_init(struct musb *musb) static int am35x_musb_exit(struct musb *musb) { struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; del_timer_sync(&otg_workaround); @@ -456,7 +456,7 @@ static u64 am35x_dmamask = DMA_BIT_MASK(32); static int am35x_probe(struct platform_device *pdev) { - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct am35x_glue *glue; @@ -577,7 +577,7 @@ static int am35x_remove(struct platform_device *pdev) static int am35x_suspend(struct device *dev) { struct am35x_glue *glue = dev_get_drvdata(dev); - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; /* Shutdown the on-chip PHY and its PLL. */ @@ -593,7 +593,7 @@ static int am35x_suspend(struct device *dev) static int am35x_resume(struct device *dev) { struct am35x_glue *glue = dev_get_drvdata(dev); - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; int ret; diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 6ba8439bd5a6..3e63379ec469 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -451,7 +451,7 @@ static u64 bfin_dmamask = DMA_BIT_MASK(32); static int bfin_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct bfin_glue *glue; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 0da6f648a9fe..7a46521c0800 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -477,7 +477,7 @@ static u64 da8xx_dmamask = DMA_BIT_MASK(32); static int da8xx_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct da8xx_glue *glue; diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index f8aeaf2e2cd1..12ab66d26d8f 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -510,7 +510,7 @@ static u64 davinci_dmamask = DMA_BIT_MASK(32); static int davinci_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct davinci_glue *glue; struct clk *clk; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 80ffd7ee55df..b9d741614f8c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1783,7 +1783,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) { int status; struct musb *musb; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); /* The driver might handle more features than the board; OK. * Fail when the board needs a feature that's not enabled. diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 23f511f7df6d..4816b2f972d0 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -478,7 +478,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) { struct device *dev = glue->dev; struct platform_device *pdev = to_platform_device(dev); - struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct device_node *np = pdev->dev.of_node; struct musb_hdrc_config *config; struct platform_device *musb; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 6708a3b78ad8..ebb46eca1791 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -255,7 +255,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) { struct musb *musb = glue_to_musb(glue); struct device *dev = musb->controller; - struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct omap_musb_board_data *data = pdata->board_data; struct usb_otg *otg = musb->xceiv->otg; @@ -341,7 +341,7 @@ static int omap2430_musb_init(struct musb *musb) int status = 0; struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct omap_musb_board_data *data = plat->board_data; /* We require some kind of external transceiver, hooked @@ -412,7 +412,7 @@ static void omap2430_musb_enable(struct musb *musb) unsigned long timeout = jiffies + msecs_to_jiffies(1000); struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct omap_musb_board_data *data = pdata->board_data; switch (glue->status) { @@ -482,7 +482,7 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32); static int omap2430_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct omap_musb_board_data *data; struct platform_device *musb; struct omap2430_glue *glue; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 2c06a8969a9f..2196ee6e79fe 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1157,7 +1157,7 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32); static int tusb_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct tusb6010_glue *glue; diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index fce71b605936..59256b12f746 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -227,7 +227,7 @@ ux500_of_probe(struct platform_device *pdev, struct device_node *np) static int ux500_probe(struct platform_device *pdev) { struct resource musb_resources[2]; - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *np = pdev->dev.of_node; struct platform_device *musb; struct ux500_glue *glue; diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 1ce214e5b7ad..e51dd9b88e71 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -286,7 +286,7 @@ static int ux500_dma_controller_start(struct ux500_dma_controller *controller) struct ux500_dma_channel *ux500_channel = NULL; struct musb *musb = controller->private_data; struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; + struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); struct ux500_musb_board_data *data; struct dma_channel *dma_channel = NULL; char **chan_names; From f074245960e8fec9948eb8022322e43670ace4e5 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 30 Jul 2013 17:06:20 +0900 Subject: [PATCH 070/101] usb: renesas: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index cfd205036aba..3b39757c13bc 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -416,7 +416,7 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) */ static int usbhs_probe(struct platform_device *pdev) { - struct renesas_usbhs_platform_info *info = pdev->dev.platform_data; + struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev); struct renesas_usbhs_driver_callback *dfunc; struct usbhs_priv *priv; struct resource *res, *irq_res; @@ -558,7 +558,7 @@ static int usbhs_probe(struct platform_device *pdev) static int usbhs_remove(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - struct renesas_usbhs_platform_info *info = pdev->dev.platform_data; + struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev); struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback; dev_dbg(&pdev->dev, "usb remove\n"); From 941ea3616c747545d0278fc432fb7919b6d0d8f0 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 31 Jul 2013 09:21:25 +0300 Subject: [PATCH 071/101] usb: dwc3: use dev_get_platdata() Use the wrapper function for retrieving the platform_data instead of accessing dev->platform_data directly. While at that also make change 'node' initialization to use the dev pointer. Inspired-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index da0a4b8b33ed..3ff6f0ad01df 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -350,11 +350,11 @@ static void dwc3_core_exit(struct dwc3 *dwc) static int dwc3_probe(struct platform_device *pdev) { - struct dwc3_platform_data *pdata = pdev->dev.platform_data; - struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct dwc3_platform_data *pdata = dev_get_platdata(dev); + struct device_node *node = dev->of_node; struct resource *res; struct dwc3 *dwc; - struct device *dev = &pdev->dev; int ret = -ENOMEM; From fb74d282d29dbb39ef20211a9cf2883f9f593bdd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 2 Aug 2013 17:13:17 +0900 Subject: [PATCH 072/101] usb: dwc3: pci: add CONFIG_PM_SLEEP to suspend/resume functions Add CONFIG_PM_SLEEP to suspend/resume functions to fix the following build warning when CONFIG_PM_SLEEP is not selected. This is because sleep PM callbacks defined by SET_SYSTEM_SLEEP_PM_OPS are only used when the CONFIG_PM_SLEEP is enabled. Unnecessary CONFIG_PM ifdefs are removed. drivers/usb/dwc3/dwc3-pci.c:215:12: warning: 'dwc3_pci_suspend' defined but not used [-Wunused-function] drivers/usb/dwc3/dwc3-pci.c:224:12: warning: 'dwc3_pci_resume' defined but not used [-Wunused-function] Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 5d746e5d6a0a..105535abcc4a 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -191,7 +191,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int dwc3_pci_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); @@ -216,23 +216,19 @@ static int dwc3_pci_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) }; -#define DEV_PM_OPS (&dwc3_pci_dev_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM */ - static struct pci_driver dwc3_pci_driver = { .name = "dwc3-pci", .id_table = dwc3_pci_id_table, .probe = dwc3_pci_probe, .remove = dwc3_pci_remove, .driver = { - .pm = DEV_PM_OPS, + .pm = &dwc3_pci_dev_pm_ops, }, }; From 027ca0d2fe779faf19c7c3414f840fdc851af41d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 2 Aug 2013 17:16:33 +0900 Subject: [PATCH 073/101] usb: gadget: goku_udc: use NULL instead of 0 'req' is a pointer; thus, use NULL instead of 0 to fix the following sparse warning: drivers/usb/gadget/goku_udc.c:775:13: warning: Using plain integer as NULL pointer Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/goku_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 52dd6cc6c0aa..c64deb9e3d62 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -772,7 +772,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } /* else pio or dma irq handler advances the queue. */ - if (likely(req != 0)) + if (likely(req != NULL)) list_add_tail(&req->queue, &ep->queue); if (likely(!list_empty(&ep->queue)) From 93487aa1639d2151820f3988f62005d0a00e9269 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 2 Aug 2013 17:17:05 +0900 Subject: [PATCH 074/101] usb: gadget: fusb300_udc: Staticize fusb300_rdcxf() fusb300_rdcxf() used only in this file. Fix the following sparse warning: drivers/usb/gadget/fusb300_udc.c:560:6: warning: symbol 'fusb300_rdcxf' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fusb300_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index c83f3e165325..f1dd6daabe21 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -557,7 +557,7 @@ static void fusb300_set_cxdone(struct fusb300 *fusb300) } /* read data from cx fifo */ -void fusb300_rdcxf(struct fusb300 *fusb300, +static void fusb300_rdcxf(struct fusb300 *fusb300, u8 *buffer, u32 length) { int i = 0; From 30ce1987160e64f58d92359ee11999e1218a45b9 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Fri, 2 Aug 2013 10:37:27 +0200 Subject: [PATCH 075/101] usb: gadget: at91_udc: add missing clk_put on fclk and iclk This patch adds missing clk_put on fclk and iclk in case the probe function fails after these clocks have been retrieved. Signed-off-by: Boris BREZILLON Signed-off-by: Felipe Balbi --- drivers/usb/gadget/at91_udc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index d237429dd93a..94d1d3cacce8 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1851,6 +1851,10 @@ static int at91udc_probe(struct platform_device *pdev) fail2: free_irq(udc->udp_irq, udc); fail1: + if (!IS_ERR(udc->fclk)) + clk_put(udc->fclk); + if (!IS_ERR(udc->iclk)) + clk_put(udc->iclk); iounmap(udc->udp_baseaddr); fail0a: if (cpu_is_at91rm9200()) From c0aefc75ce2512bc308a89ca3cb7bece63c1128f Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Fri, 2 Aug 2013 10:37:34 +0200 Subject: [PATCH 076/101] usb: gadget: at91_udc: add usb_clk for transition to common clk framework The AT91 PMC (Power Management Controller) provides an USB clock used by USB Full Speed host (ohci) and USB Full Speed device (udc). The usb drivers (ohci and udc) must configure this clock to 48Mhz. This configuration was formely done in mach-at91/clock.c, but this implementation will be removed when moving to common clk framework. This patch adds support for usb clock retrieval and configuration, and is backward compatible with the current at91 clk implementation (if usb clk is not found, it does not configure/enable it). Signed-off-by: Boris BREZILLON Signed-off-by: Felipe Balbi --- drivers/usb/gadget/at91_udc.c | 17 +++++++++++++++-- drivers/usb/gadget/at91_udc.h | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 94d1d3cacce8..4cc4fd6d1473 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -870,6 +870,11 @@ static void clk_on(struct at91_udc *udc) if (udc->clocked) return; udc->clocked = 1; + + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + clk_set_rate(udc->uclk, 48000000); + clk_prepare_enable(udc->uclk); + } clk_prepare_enable(udc->iclk); clk_prepare_enable(udc->fclk); } @@ -882,6 +887,8 @@ static void clk_off(struct at91_udc *udc) udc->gadget.speed = USB_SPEED_UNKNOWN; clk_disable_unprepare(udc->fclk); clk_disable_unprepare(udc->iclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_disable_unprepare(udc->uclk); } /* @@ -1774,10 +1781,12 @@ static int at91udc_probe(struct platform_device *pdev) /* get interface and function clocks */ udc->iclk = clk_get(dev, "udc_clk"); udc->fclk = clk_get(dev, "udpck"); - if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { + if (IS_ENABLED(CONFIG_COMMON_CLK)) + udc->uclk = clk_get(dev, "usb_clk"); + if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk) || + (IS_ENABLED(CONFIG_COMMON_CLK) && IS_ERR(udc->uclk))) { DBG("clocks missing\n"); retval = -ENODEV; - /* NOTE: we "know" here that refcounts on these are NOPs */ goto fail1; } @@ -1851,6 +1860,8 @@ static int at91udc_probe(struct platform_device *pdev) fail2: free_irq(udc->udp_irq, udc); fail1: + if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk)) + clk_put(udc->uclk); if (!IS_ERR(udc->fclk)) clk_put(udc->fclk); if (!IS_ERR(udc->iclk)) @@ -1898,6 +1909,8 @@ static int __exit at91udc_remove(struct platform_device *pdev) clk_put(udc->iclk); clk_put(udc->fclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_put(udc->uclk); return 0; } diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index e647d1c2ada4..017524663381 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -126,7 +126,7 @@ struct at91_udc { unsigned active_suspend:1; u8 addr; struct at91_udc_data board; - struct clk *iclk, *fclk; + struct clk *iclk, *fclk, *uclk; struct platform_device *pdev; struct proc_dir_entry *pde; void __iomem *udp_baseaddr; From ffcba5a510af99e9d443b7e577a9cb0515c919e1 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Thu, 1 Aug 2013 23:50:47 +0400 Subject: [PATCH 077/101] usb: gadget: amd5536udc: unconditionally use GFP_ATOMIC in udc_queue() As far as prep_dma() is called with spinlock held, we have to pass GFP_ATOMIC regardless of gfp argument. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Felipe Balbi --- drivers/usb/gadget/amd5536udc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index f52dcfe8f545..a9a4346c83aa 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1122,7 +1122,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) goto finished; } if (ep->dma) { - retval = prep_dma(ep, req, gfp); + retval = prep_dma(ep, req, GFP_ATOMIC); if (retval != 0) goto finished; /* write desc pointer to enable DMA */ @@ -1190,7 +1190,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) * for PPB modes, because of chain creation reasons */ if (ep->in) { - retval = prep_dma(ep, req, gfp); + retval = prep_dma(ep, req, GFP_ATOMIC); if (retval != 0) goto finished; } From 136c489b1cdcaad8f3da31298b839b5861d9de6d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 5 Aug 2013 12:11:05 +0900 Subject: [PATCH 078/101] usb: gadget: f_mass_storage: use NULL instead of 0 The local variables such as 'filename', 'vendor_name', and 'product_name' are pointers; thus, use NULL instead of 0 to fix the following sparse warnings drivers/usb/gadget/f_mass_storage.c:3046:27: warning: Using plain integer as NULL pointer drivers/usb/gadget/f_mass_storage.c:3050:28: warning: Using plain integer as NULL pointer drivers/usb/gadget/f_mass_storage.c:3051:29: warning: Using plain integer as NULL pointer Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 56f1fd1cba25..4d4e96a5d2e9 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -3043,12 +3043,12 @@ fsg_config_from_params(struct fsg_config *cfg, lun->filename = params->file_count > i && params->file[i][0] ? params->file[i] - : 0; + : NULL; } /* Let MSF use defaults */ - cfg->vendor_name = 0; - cfg->product_name = 0; + cfg->vendor_name = NULL; + cfg->product_name = NULL; cfg->ops = NULL; cfg->private_data = NULL; From bf19647d8f19e89bdf94eef387cfc3825bb48d7f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 5 Aug 2013 12:12:42 +0900 Subject: [PATCH 079/101] usb: gadget: rndis: Staticize rndis_init()/rndis_exit() rndis_init() and rndis_exit() are used only in this file. Fix the following sparse warnings: drivers/usb/gadget/rndis.c:1145:5: warning: symbol 'rndis_init' was not declared. Should it be static? drivers/usb/gadget/rndis.c:1179:6: warning: symbol 'rndis_exit' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/rndis.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 3e3ea7203030..9575085ded81 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1142,7 +1142,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ -int rndis_init(void) +static int rndis_init(void) { u8 i; @@ -1176,7 +1176,7 @@ int rndis_init(void) } module_init(rndis_init); -void rndis_exit(void) +static void rndis_exit(void) { #ifdef CONFIG_USB_GADGET_DEBUG_FILES u8 i; From 2419831c375d466fcf41dfe02799e5750c25f765 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 5 Aug 2013 12:14:17 +0900 Subject: [PATCH 080/101] usb: gadget: u_uac1: add __user annotation Added __user annotation to fix the following sparse warning. drivers/usb/gadget/u_uac1.c:194:52: warning: incorrect type in argument 2 (different address spaces) drivers/usb/gadget/u_uac1.c:194:52: expected void const [noderef] *buf drivers/usb/gadget/u_uac1.c:194:52: got void *buf Acked-by: Jassi Brar Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/u_uac1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/u_uac1.c b/drivers/usb/gadget/u_uac1.c index c7d460f43390..7a55fea43430 100644 --- a/drivers/usb/gadget/u_uac1.c +++ b/drivers/usb/gadget/u_uac1.c @@ -191,7 +191,7 @@ static size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) frames = bytes_to_frames(runtime, count); old_fs = get_fs(); set_fs(KERNEL_DS); - result = snd_pcm_lib_write(snd->substream, buf, frames); + result = snd_pcm_lib_write(snd->substream, (void __user *)buf, frames); if (result != frames) { ERROR(card, "Playback error: %d\n", (int)result); set_fs(old_fs); From cf1dea73c72ded6e1e1f61598a69b663d4c163ed Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 5 Aug 2013 12:15:27 +0900 Subject: [PATCH 081/101] usb: gadget: f_uac1: Staticize local functions control_selector_init() is used only in this file. audio_bind_config() is used only in audio.c file to which f_uac1.c is included. Thus, these functions are staticized to fix the following warnings. drivers/usb/gadget/f_uac1.c:698:12: warning: symbol 'control_selector_init' was not declared. Should it be static? drivers/usb/gadget/f_uac1.c:722:12: warning: symbol 'audio_bind_config' was not declared. Should it be static? Acked-by: Jassi Brar Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_uac1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c index fa8ea4ea00c1..2b4c82d84bfc 100644 --- a/drivers/usb/gadget/f_uac1.c +++ b/drivers/usb/gadget/f_uac1.c @@ -695,7 +695,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd) } /* Todo: add more control selecotor dynamically */ -int __init control_selector_init(struct f_audio *audio) +static int __init control_selector_init(struct f_audio *audio) { INIT_LIST_HEAD(&audio->cs); list_add(&feature_unit.list, &audio->cs); @@ -719,7 +719,7 @@ int __init control_selector_init(struct f_audio *audio) * * Returns zero on success, else negative errno. */ -int __init audio_bind_config(struct usb_configuration *c) +static int __init audio_bind_config(struct usb_configuration *c) { struct f_audio *audio; int status; From 1e0f20bea2b08775eb832e8f95d320cddd65737b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 5 Aug 2013 14:17:11 +0900 Subject: [PATCH 082/101] usb: phy: mv-u3d: Staticize mv_u3d_phy_shutdown() mv_u3d_phy_shutdown() is used only in this file. Fix the following sparse warning: drivers/usb/phy/phy-mv-u3d-usb.c:85:6: warning: symbol 'mv_u3d_phy_shutdown' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-mv-u3d-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c index 6688023021d3..d317903022bf 100644 --- a/drivers/usb/phy/phy-mv-u3d-usb.c +++ b/drivers/usb/phy/phy-mv-u3d-usb.c @@ -82,7 +82,7 @@ static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value) writel_relaxed(value, data); } -void mv_u3d_phy_shutdown(struct usb_phy *phy) +static void mv_u3d_phy_shutdown(struct usb_phy *phy) { struct mv_u3d_phy *mv_u3d_phy; void __iomem *base; From d07f4a8200cfc7ff2ba23ef87dd6267a4d70fb10 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 5 Aug 2013 14:17:53 +0900 Subject: [PATCH 083/101] usb: phy: mv-usb: remove incorrect __exit_p annotation When platform_driver_probe() is not used, bind/unbind via sysfs is enabled. Thus, __exit_p annotation should be removed from remove(). Also, mv_otg_remove() is staticized, because this function is used only in this file. Fix the following sparse warning: drivers/usb/phy/phy-mv-usb.c:656:5: warning: symbol 'mv_otg_remove' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-mv-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 03d16ff24c02..98f6ac6a78ea 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -653,7 +653,7 @@ static struct attribute_group inputs_attr_group = { .attrs = inputs_attrs, }; -int mv_otg_remove(struct platform_device *pdev) +static int mv_otg_remove(struct platform_device *pdev) { struct mv_otg *mvotg = platform_get_drvdata(pdev); @@ -893,7 +893,7 @@ static int mv_otg_resume(struct platform_device *pdev) static struct platform_driver mv_otg_driver = { .probe = mv_otg_probe, - .remove = __exit_p(mv_otg_remove), + .remove = mv_otg_remove, .driver = { .owner = THIS_MODULE, .name = driver_name, From 3fa4d7344be0afebd80382ffeea6b1787cccf971 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 26 Jul 2013 12:16:42 +0200 Subject: [PATCH 084/101] usb: phy: rename nop_usb_xceiv => usb_phy_gen_xceiv The "nop" driver isn't a do-nothing-stub but supports a couple functions like clock on/off or is able to use a voltage regulator. This patch simply renames the driver to "generic" since it is easy possible to extend it by a simple function istead of writing a complete driver. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- arch/arm/mach-omap2/board-omap3beagle.c | 4 +- arch/arm/mach-omap2/board-omap3evm.c | 4 +- arch/arm/mach-omap2/board-omap3pandora.c | 2 +- arch/arm/mach-omap2/usb-host.c | 10 ++--- drivers/usb/dwc3/dwc3-exynos.c | 8 ++-- drivers/usb/dwc3/dwc3-pci.c | 8 ++-- drivers/usb/musb/am35x.c | 2 +- drivers/usb/musb/blackfin.c | 2 +- drivers/usb/musb/da8xx.c | 2 +- drivers/usb/musb/davinci.c | 2 +- drivers/usb/musb/musb_dsps.c | 2 +- drivers/usb/musb/tusb6010.c | 2 +- drivers/usb/phy/Makefile | 2 +- drivers/usb/phy/{phy-nop.c => phy-generic.c} | 44 +++++++++---------- .../{nop-usb-xceiv.h => usb_phy_gen_xceiv.h} | 4 +- 15 files changed, 49 insertions(+), 49 deletions(-) rename drivers/usb/phy/{phy-nop.c => phy-generic.c} (83%) rename include/linux/usb/{nop-usb-xceiv.h => usb_phy_gen_xceiv.h} (81%) diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 04c116555412..1c6ae5f5bae7 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -279,7 +279,7 @@ static struct regulator_consumer_supply beagle_vsim_supply[] = { static struct gpio_led gpio_leds[]; /* PHY's VCC regulator might be added later, so flag that we need it */ -static struct nop_usb_xceiv_platform_data hsusb2_phy_data = { +static struct usb_phy_gen_xceiv_platform_data hsusb2_phy_data = { .needs_vcc = true, }; diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 8c026269baca..52bdddd41e0e 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -468,7 +468,7 @@ struct wl12xx_platform_data omap3evm_wlan_data __initdata = { static struct regulator_consumer_supply omap3evm_vaux2_supplies[] = { REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"), /* OMAP ISP */ REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"), /* OMAP ISP */ - REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */ + REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */ REGULATOR_SUPPLY("vaux2", NULL), }; diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index b1547a0edfcd..d2b455e70486 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -352,7 +352,7 @@ static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = { }; static struct regulator_consumer_supply pandora_usb_phy_supply[] = { - REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */ + REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */ }; /* ads7846 on SPI and 2 nub controllers on I2C */ diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 2eb19d4d0aa1..e83a6a4b184a 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include "soc.h" #include "omap_device.h" @@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = { /* .init_data filled later */ }; -static const char *nop_name = "nop_usb_xceiv"; /* NOP PHY driver */ +static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */ static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */ /** @@ -460,9 +460,9 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) pdevinfo.name = nop_name; pdevinfo.id = phy->port; pdevinfo.data = phy->platform_data; - pdevinfo.size_data = sizeof(struct nop_usb_xceiv_platform_data); - - scnprintf(phy_id, MAX_STR, "nop_usb_xceiv.%d", + pdevinfo.size_data = + sizeof(struct usb_phy_gen_xceiv_platform_data); + scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d", phy->port); pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 8ce9d7fd6cfc..a179c5a54b39 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -34,13 +34,13 @@ struct dwc3_exynos { static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) { - struct nop_usb_xceiv_platform_data pdata; + struct usb_phy_gen_xceiv_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; @@ -51,7 +51,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) if (ret) goto err1; - pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); if (!pdev) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index ed07ec04a962..87ea3d503fc5 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -43,7 +43,7 @@ #include #include -#include +#include /* FIXME define these in */ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 @@ -58,13 +58,13 @@ struct dwc3_pci { static int dwc3_pci_register_phys(struct dwc3_pci *glue) { - struct nop_usb_xceiv_platform_data pdata; + struct usb_phy_gen_xceiv_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("nop_usb_xceiv", 0); + pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); if (!pdev) return -ENOMEM; @@ -75,7 +75,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue) if (ret) goto err1; - pdev = platform_device_alloc("nop_usb_xceiv", 1); + pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); if (!pdev) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 2231850c0625..5733a209ab95 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include "musb_core.h" diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 6ba8439bd5a6..195e96674fff 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 0da6f648a9fe..ccc6b63bc380 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index f8aeaf2e2cd1..91f300e93cf4 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 5233804d66b1..55fe3c292cd2 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 2c06a8969a9f..20f182c6184a 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "musb_core.h" diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 070eca3af18b..24c5816409fd 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -14,7 +14,7 @@ phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o -obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o +obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-generic.c similarity index 83% rename from drivers/usb/phy/phy-nop.c rename to drivers/usb/phy/phy-generic.c index 55445e5d72e5..f379b7ded037 100644 --- a/drivers/usb/phy/phy-nop.c +++ b/drivers/usb/phy/phy-generic.c @@ -30,13 +30,13 @@ #include #include #include -#include +#include #include #include #include #include -struct nop_usb_xceiv { +struct usb_phy_gen_xceiv { struct usb_phy phy; struct device *dev; struct clk *clk; @@ -50,9 +50,9 @@ void usb_nop_xceiv_register(void) { if (pd) return; - pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0); + pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); if (!pd) { - printk(KERN_ERR "Unable to register usb nop transceiver\n"); + pr_err("Unable to register generic usb transceiver\n"); return; } } @@ -72,7 +72,7 @@ static int nop_set_suspend(struct usb_phy *x, int suspend) static int nop_init(struct usb_phy *phy) { - struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); + struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); if (!IS_ERR(nop->vcc)) { if (regulator_enable(nop->vcc)) @@ -93,7 +93,7 @@ static int nop_init(struct usb_phy *phy) static void nop_shutdown(struct usb_phy *phy) { - struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); + struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); if (!IS_ERR(nop->reset)) { /* Assert RESET */ @@ -139,11 +139,11 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } -static int nop_usb_xceiv_probe(struct platform_device *pdev) +static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data; - struct nop_usb_xceiv *nop; + struct usb_phy_gen_xceiv_platform_data *pdata = pdev->dev.platform_data; + struct usb_phy_gen_xceiv *nop; enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; u32 clk_rate = 0; @@ -245,9 +245,9 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev) return err; } -static int nop_usb_xceiv_remove(struct platform_device *pdev) +static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) { - struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); + struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); if (!IS_ERR(nop->clk)) clk_unprepare(nop->clk); @@ -264,29 +264,29 @@ static const struct of_device_id nop_xceiv_dt_ids[] = { MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); -static struct platform_driver nop_usb_xceiv_driver = { - .probe = nop_usb_xceiv_probe, - .remove = nop_usb_xceiv_remove, +static struct platform_driver usb_phy_gen_xceiv_driver = { + .probe = usb_phy_gen_xceiv_probe, + .remove = usb_phy_gen_xceiv_remove, .driver = { - .name = "nop_usb_xceiv", + .name = "usb_phy_gen_xceiv", .owner = THIS_MODULE, .of_match_table = nop_xceiv_dt_ids, }, }; -static int __init nop_usb_xceiv_init(void) +static int __init usb_phy_gen_xceiv_init(void) { - return platform_driver_register(&nop_usb_xceiv_driver); + return platform_driver_register(&usb_phy_gen_xceiv_driver); } -subsys_initcall(nop_usb_xceiv_init); +subsys_initcall(usb_phy_gen_xceiv_init); -static void __exit nop_usb_xceiv_exit(void) +static void __exit usb_phy_gen_xceiv_exit(void) { - platform_driver_unregister(&nop_usb_xceiv_driver); + platform_driver_unregister(&usb_phy_gen_xceiv_driver); } -module_exit(nop_usb_xceiv_exit); +module_exit(usb_phy_gen_xceiv_exit); -MODULE_ALIAS("platform:nop_usb_xceiv"); +MODULE_ALIAS("platform:usb_phy_gen_xceiv"); MODULE_AUTHOR("Texas Instruments Inc"); MODULE_DESCRIPTION("NOP USB Transceiver driver"); MODULE_LICENSE("GPL"); diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h similarity index 81% rename from include/linux/usb/nop-usb-xceiv.h rename to include/linux/usb/usb_phy_gen_xceiv.h index 148d35171aac..f9a7e7bc925b 100644 --- a/include/linux/usb/nop-usb-xceiv.h +++ b/include/linux/usb/usb_phy_gen_xceiv.h @@ -3,7 +3,7 @@ #include -struct nop_usb_xceiv_platform_data { +struct usb_phy_gen_xceiv_platform_data { enum usb_phy_type type; unsigned long clk_rate; @@ -12,7 +12,7 @@ struct nop_usb_xceiv_platform_data { unsigned int needs_reset:1; }; -#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_NOP_USB_XCEIV) /* sometimes transceivers are accessed only through e.g. ULPI */ extern void usb_nop_xceiv_register(void); extern void usb_nop_xceiv_unregister(void); From 53b6fc28ea8e9857b6141afb92f3683eab9568ba Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 30 Jul 2013 17:20:06 +0200 Subject: [PATCH 085/101] usb: phy: phy-generic: export init functions This patch exports the mostly generic functions so they can be used from other phy driver instead of duplicating the code. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-generic.c | 160 +++++++++++++++++++--------------- drivers/usb/phy/phy-generic.h | 20 +++++ 2 files changed, 108 insertions(+), 72 deletions(-) create mode 100644 drivers/usb/phy/phy-generic.h diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 406f8e43f852..efe59f3f7fda 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -36,13 +36,7 @@ #include #include -struct usb_phy_gen_xceiv { - struct usb_phy phy; - struct device *dev; - struct clk *clk; - struct regulator *vcc; - struct regulator *reset; -}; +#include "phy-generic.h" static struct platform_device *pd; @@ -70,7 +64,7 @@ static int nop_set_suspend(struct usb_phy *x, int suspend) return 0; } -static int nop_init(struct usb_phy *phy) +int usb_gen_phy_init(struct usb_phy *phy) { struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); @@ -90,8 +84,9 @@ static int nop_init(struct usb_phy *phy) return 0; } +EXPORT_SYMBOL_GPL(usb_gen_phy_init); -static void nop_shutdown(struct usb_phy *phy) +void usb_gen_phy_shutdown(struct usb_phy *phy) { struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); @@ -109,6 +104,7 @@ static void nop_shutdown(struct usb_phy *phy) dev_err(phy->dev, "Failed to disable power\n"); } } +EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown); static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { @@ -139,6 +135,78 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, + enum usb_phy_type type, u32 clk_rate, bool needs_vcc, + bool needs_reset) +{ + int err; + + nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), + GFP_KERNEL); + if (!nop->phy.otg) + return -ENOMEM; + + nop->clk = devm_clk_get(dev, "main_clk"); + if (IS_ERR(nop->clk)) { + dev_dbg(dev, "Can't get phy clock: %ld\n", + PTR_ERR(nop->clk)); + } + + if (!IS_ERR(nop->clk) && clk_rate) { + err = clk_set_rate(nop->clk, clk_rate); + if (err) { + dev_err(dev, "Error setting clock rate\n"); + return err; + } + } + + if (!IS_ERR(nop->clk)) { + err = clk_prepare(nop->clk); + if (err) { + dev_err(dev, "Error preparing clock\n"); + return err; + } + } + + nop->vcc = devm_regulator_get(dev, "vcc"); + if (IS_ERR(nop->vcc)) { + dev_dbg(dev, "Error getting vcc regulator: %ld\n", + PTR_ERR(nop->vcc)); + if (needs_vcc) + return -EPROBE_DEFER; + } + + nop->reset = devm_regulator_get(dev, "reset"); + if (IS_ERR(nop->reset)) { + dev_dbg(dev, "Error getting reset regulator: %ld\n", + PTR_ERR(nop->reset)); + if (needs_reset) + return -EPROBE_DEFER; + } + + nop->dev = dev; + nop->phy.dev = nop->dev; + nop->phy.label = "nop-xceiv"; + nop->phy.set_suspend = nop_set_suspend; + nop->phy.state = OTG_STATE_UNDEFINED; + nop->phy.type = type; + + nop->phy.otg->phy = &nop->phy; + nop->phy.otg->set_host = nop_set_host; + nop->phy.otg->set_peripheral = nop_set_peripheral; + + ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); + return 0; +} +EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); + +void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop) +{ + if (!IS_ERR(nop->clk)) + clk_unprepare(nop->clk); +} +EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy); + static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -151,15 +219,6 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) bool needs_vcc = false; bool needs_reset = false; - nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL); - if (!nop) - return -ENOMEM; - - nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg), - GFP_KERNEL); - if (!nop->phy.otg) - return -ENOMEM; - if (dev->of_node) { struct device_node *node = dev->of_node; @@ -176,56 +235,18 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) needs_reset = pdata->needs_reset; } - nop->clk = devm_clk_get(&pdev->dev, "main_clk"); - if (IS_ERR(nop->clk)) { - dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n", - PTR_ERR(nop->clk)); - } + nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); + if (!nop) + return -ENOMEM; - if (!IS_ERR(nop->clk) && clk_rate) { - err = clk_set_rate(nop->clk, clk_rate); - if (err) { - dev_err(&pdev->dev, "Error setting clock rate\n"); - return err; - } - } - if (!IS_ERR(nop->clk)) { - err = clk_prepare(nop->clk); - if (err) { - dev_err(&pdev->dev, "Error preparing clock\n"); - return err; - } - } + err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc, + needs_reset); + if (err) + return err; - nop->vcc = devm_regulator_get(&pdev->dev, "vcc"); - if (IS_ERR(nop->vcc)) { - dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n", - PTR_ERR(nop->vcc)); - if (needs_vcc) - return -EPROBE_DEFER; - } - - nop->reset = devm_regulator_get(&pdev->dev, "reset"); - if (IS_ERR(nop->reset)) { - dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n", - PTR_ERR(nop->reset)); - if (needs_reset) - return -EPROBE_DEFER; - } - - nop->dev = &pdev->dev; - nop->phy.dev = nop->dev; - nop->phy.label = "nop-xceiv"; - nop->phy.set_suspend = nop_set_suspend; - nop->phy.init = nop_init; - nop->phy.shutdown = nop_shutdown; - nop->phy.state = OTG_STATE_UNDEFINED; - nop->phy.type = type; - - nop->phy.otg->phy = &nop->phy; - nop->phy.otg->set_host = nop_set_host; - nop->phy.otg->set_peripheral = nop_set_peripheral; + nop->phy.init = usb_gen_phy_init; + nop->phy.shutdown = usb_gen_phy_shutdown; err = usb_add_phy_dev(&nop->phy); if (err) { @@ -236,13 +257,10 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nop); - ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); - return 0; err_add: - if (!IS_ERR(nop->clk)) - clk_unprepare(nop->clk); + usb_phy_gen_cleanup_phy(nop); return err; } @@ -250,9 +268,7 @@ static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) { struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); - if (!IS_ERR(nop->clk)) - clk_unprepare(nop->clk); - + usb_phy_gen_cleanup_phy(nop); usb_remove_phy(&nop->phy); return 0; diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h new file mode 100644 index 000000000000..61687d5a965b --- /dev/null +++ b/drivers/usb/phy/phy-generic.h @@ -0,0 +1,20 @@ +#ifndef _PHY_GENERIC_H_ +#define _PHY_GENERIC_H_ + +struct usb_phy_gen_xceiv { + struct usb_phy phy; + struct device *dev; + struct clk *clk; + struct regulator *vcc; + struct regulator *reset; +}; + +int usb_gen_phy_init(struct usb_phy *phy); +void usb_gen_phy_shutdown(struct usb_phy *phy); + +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, + enum usb_phy_type type, u32 clk_rate, bool needs_vcc, + bool needs_reset); +void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop); + +#endif From 3bb869c8b3f1a11f1854cd74ebdeb60753614cf8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 30 Jul 2013 21:43:45 +0200 Subject: [PATCH 086/101] usb: phy: Add AM335x PHY driver This driver is a redo of my earlier attempt. It uses parts of the generic PHY driver and uses the new control driver for the register the phy needs to power on/off the phy. It also enables easy access for the wakeup register which is not yet implemented. The difference between the omap attempt is: - no static holding variable - one global visible function which exports a struct with callbacks to access the "control" registers. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/phy/Kconfig | 12 +++ drivers/usb/phy/Makefile | 2 + drivers/usb/phy/am35x-phy-control.h | 21 +++++ drivers/usb/phy/phy-am335x-control.c | 136 +++++++++++++++++++++++++++ drivers/usb/phy/phy-am335x.c | 99 +++++++++++++++++++ 5 files changed, 270 insertions(+) create mode 100644 drivers/usb/phy/am35x-phy-control.h create mode 100644 drivers/usb/phy/phy-am335x-control.c create mode 100644 drivers/usb/phy/phy-am335x.c diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index f5ea339ec155..f41c3e12c6a7 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -86,6 +86,18 @@ config OMAP_USB3 This driver interacts with the "OMAP Control USB Driver" to power on/off the PHY. +config AM335X_CONTROL_USB + tristate + +config AM335X_PHY_USB + tristate "AM335x USB PHY Driver" + select USB_PHY + select AM335X_CONTROL_USB + select NOP_USB_XCEIV + help + This driver provides PHY support for that phy which part for the + AM335x SoC. + config SAMSUNG_USBPHY tristate help diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 24c5816409fd..dae321de3b2e 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o +obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o +obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o diff --git a/drivers/usb/phy/am35x-phy-control.h b/drivers/usb/phy/am35x-phy-control.h new file mode 100644 index 000000000000..b96594d1962c --- /dev/null +++ b/drivers/usb/phy/am35x-phy-control.h @@ -0,0 +1,21 @@ +#ifndef _AM335x_PHY_CONTROL_H_ +#define _AM335x_PHY_CONTROL_H_ + +struct phy_control { + void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); + void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); +}; + +static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on) +{ + phy_ctrl->phy_power(phy_ctrl, id, on); +} + +static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on) +{ + phy_ctrl->phy_wkup(phy_ctrl, id, on); +} + +struct phy_control *am335x_get_phy_control(struct device *dev); + +#endif diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c new file mode 100644 index 000000000000..35494f1c33b6 --- /dev/null +++ b/drivers/usb/phy/phy-am335x-control.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +struct phy_control { + void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); + void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); +}; + +struct am335x_control_usb { + struct device *dev; + void __iomem *phy_reg; + void __iomem *wkup; + spinlock_t lock; + struct phy_control phy_ctrl; +}; + +#define AM335X_USB0_CTRL 0x0 +#define AM335X_USB1_CTRL 0x8 +#define AM335x_USB_WKUP 0x0 + +#define USBPHY_CM_PWRDN (1 << 0) +#define USBPHY_OTG_PWRDN (1 << 1) +#define USBPHY_OTGVDET_EN (1 << 19) +#define USBPHY_OTGSESSEND_EN (1 << 20) + +static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) +{ + struct am335x_control_usb *usb_ctrl; + u32 val; + u32 reg; + + usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl); + + switch (id) { + case 0: + reg = AM335X_USB0_CTRL; + break; + case 1: + reg = AM335X_USB1_CTRL; + break; + default: + __WARN(); + return; + } + + val = readl(usb_ctrl->phy_reg + reg); + if (on) { + val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); + val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; + } else { + val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; + } + + writel(val, usb_ctrl->phy_reg + reg); +} + +static const struct phy_control ctrl_am335x = { + .phy_power = am335x_phy_power, +}; + +static const struct of_device_id omap_control_usb_id_table[] = { + { .compatible = "ti,am335x-usb-ctrl-module", .data = &ctrl_am335x }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); + +static struct platform_driver am335x_control_driver; +static int match(struct device *dev, void *data) +{ + struct device_node *node = (struct device_node *)data; + return dev->of_node == node && + dev->driver == &am335x_control_driver.driver; +} + +struct phy_control *am335x_get_phy_control(struct device *dev) +{ + struct device_node *node; + struct am335x_control_usb *ctrl_usb; + + node = of_parse_phandle(dev->of_node, "ti,ctrl_mod", 0); + if (!node) + return NULL; + + dev = bus_find_device(&platform_bus_type, NULL, node, match); + ctrl_usb = dev_get_drvdata(dev); + if (!ctrl_usb) + return NULL; + return &ctrl_usb->phy_ctrl; +} +EXPORT_SYMBOL_GPL(am335x_get_phy_control); + +static int am335x_control_usb_probe(struct platform_device *pdev) +{ + struct resource *res; + struct am335x_control_usb *ctrl_usb; + const struct of_device_id *of_id; + const struct phy_control *phy_ctrl; + + of_id = of_match_node(omap_control_usb_id_table, pdev->dev.of_node); + if (!of_id) + return -EINVAL; + + phy_ctrl = of_id->data; + + ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL); + if (!ctrl_usb) { + dev_err(&pdev->dev, "unable to alloc memory for control usb\n"); + return -ENOMEM; + } + + ctrl_usb->dev = &pdev->dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); + ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ctrl_usb->phy_reg)) + return PTR_ERR(ctrl_usb->phy_reg); + spin_lock_init(&ctrl_usb->lock); + ctrl_usb->phy_ctrl = *phy_ctrl; + + dev_set_drvdata(ctrl_usb->dev, ctrl_usb); + return 0; +} + +static struct platform_driver am335x_control_driver = { + .probe = am335x_control_usb_probe, + .driver = { + .name = "am335x-control-usb", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(omap_control_usb_id_table), + }, +}; + +module_platform_driver(am335x_control_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c new file mode 100644 index 000000000000..c4d614d1f173 --- /dev/null +++ b/drivers/usb/phy/phy-am335x.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "am35x-phy-control.h" +#include "phy-generic.h" + +struct am335x_phy { + struct usb_phy_gen_xceiv usb_phy_gen; + struct phy_control *phy_ctrl; + int id; +}; + +static int am335x_init(struct usb_phy *phy) +{ + struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); + + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); + return 0; +} + +static void am335x_shutdown(struct usb_phy *phy) +{ + struct am335x_phy *am_phy = dev_get_drvdata(phy->dev); + + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); +} + +static int am335x_phy_probe(struct platform_device *pdev) +{ + struct am335x_phy *am_phy; + struct device *dev = &pdev->dev; + int ret; + + am_phy = devm_kzalloc(dev, sizeof(*am_phy), GFP_KERNEL); + if (!am_phy) + return -ENOMEM; + + am_phy->phy_ctrl = am335x_get_phy_control(dev); + if (!am_phy->phy_ctrl) + return -EPROBE_DEFER; + am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy"); + if (am_phy->id < 0) { + dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id); + return am_phy->id; + } + + ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, + USB_PHY_TYPE_USB2, 0, false, false); + if (ret) + return ret; + + ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy); + if (ret) + goto err_add; + am_phy->usb_phy_gen.phy.init = am335x_init; + am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown; + + platform_set_drvdata(pdev, am_phy); + return 0; + +err_add: + usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen); + return ret; +} + +static int am335x_phy_remove(struct platform_device *pdev) +{ + struct am335x_phy *am_phy = platform_get_drvdata(pdev); + + usb_remove_phy(&am_phy->usb_phy_gen.phy); + return 0; +} + +static const struct of_device_id am335x_phy_ids[] = { + { .compatible = "ti,am335x-usb-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, am335x_phy_ids); + +static struct platform_driver am335x_phy_driver = { + .probe = am335x_phy_probe, + .remove = am335x_phy_remove, + .driver = { + .name = "am335x-phy-driver", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(am335x_phy_ids), + }, +}; + +module_platform_driver(am335x_phy_driver); +MODULE_LICENSE("GPL v2"); From e96bdc3dafe471375e2e780e319e3ead2d9ad4a7 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 5 Jul 2013 12:33:33 +0200 Subject: [PATCH 087/101] usb: musb: dsps: remove the hardcoded phy pieces dsps uses a nop driver which is added in dsps itself and does the PHY on/off calls within dsps. Since those calls are now moved the nop driver itself, we can now request the phy proper phy and remove those calls. Currently only the first musb interface is used so we only add one phy node for now. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 97 +----------------------------------- 1 file changed, 1 insertion(+), 96 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e7a2cd1c6630..74333321cb62 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -120,49 +120,8 @@ struct dsps_glue { const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ struct timer_list timer[2]; /* otg_workaround timer */ unsigned long last_timer[2]; /* last timer data for each instance */ - u32 __iomem *usb_ctrl[2]; }; -#define DSPS_AM33XX_CONTROL_MODULE_PHYS_0 0x44e10620 -#define DSPS_AM33XX_CONTROL_MODULE_PHYS_1 0x44e10628 - -static const resource_size_t dsps_control_module_phys[] = { - DSPS_AM33XX_CONTROL_MODULE_PHYS_0, - DSPS_AM33XX_CONTROL_MODULE_PHYS_1, -}; - -#define USBPHY_CM_PWRDN (1 << 0) -#define USBPHY_OTG_PWRDN (1 << 1) -#define USBPHY_OTGVDET_EN (1 << 19) -#define USBPHY_OTGSESSEND_EN (1 << 20) - -/** - * musb_dsps_phy_control - phy on/off - * @glue: struct dsps_glue * - * @id: musb instance - * @on: flag for phy to be switched on or off - * - * This is to enable the PHY using usb_ctrl register in system control - * module space. - * - * XXX: This function will be removed once we have a seperate driver for - * control module - */ -static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on) -{ - u32 usbphycfg; - - usbphycfg = readl(glue->usb_ctrl[id]); - - if (on) { - usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); - usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; - } else { - usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; - } - - writel(usbphycfg, glue->usb_ctrl[id]); -} /** * dsps_musb_enable - enable interrupts */ @@ -407,8 +366,7 @@ static int dsps_musb_init(struct musb *musb) musb->mregs += wrp->musb_core_offset; /* NOP driver needs change if supporting dual instance */ - usb_nop_xceiv_register(); - musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); + musb->xceiv = devm_usb_get_phy_by_phandle(glue->dev, "phys", 0); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -426,9 +384,6 @@ static int dsps_musb_init(struct musb *musb) /* Reset the musb */ dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); - /* Start the on-chip PHY and its PLL. */ - musb_dsps_phy_control(glue, pdev->id, 1); - musb->isr = dsps_interrupt; /* reset the otgdisable bit, needed for host mode to work */ @@ -438,8 +393,6 @@ static int dsps_musb_init(struct musb *musb) return 0; err0: - usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); return status; } @@ -451,14 +404,7 @@ static int dsps_musb_exit(struct musb *musb) del_timer_sync(&glue->timer[pdev->id]); - /* Shutdown the on-chip PHY and its PLL. */ - musb_dsps_phy_control(glue, pdev->id, 0); usb_phy_shutdown(musb->xceiv); - - /* NOP driver needs change if supporting dual instance */ - usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); - return 0; } @@ -487,16 +433,6 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) char res_name[11]; int ret; - resources[0].start = dsps_control_module_phys[id]; - resources[0].end = resources[0].start + SZ_4 - 1; - resources[0].flags = IORESOURCE_MEM; - - glue->usb_ctrl[id] = devm_ioremap_resource(&pdev->dev, resources); - if (IS_ERR(glue->usb_ctrl[id])) { - ret = PTR_ERR(glue->usb_ctrl[id]); - goto err0; - } - /* first resource is for usbss, so start index from 1 */ res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1); if (!res) { @@ -680,36 +616,6 @@ static int dsps_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int dsps_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); - const struct dsps_musb_wrapper *wrp = glue->wrp; - int i; - - for (i = 0; i < wrp->instances; i++) - musb_dsps_phy_control(glue, i, 0); - - return 0; -} - -static int dsps_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); - const struct dsps_musb_wrapper *wrp = glue->wrp; - int i; - - for (i = 0; i < wrp->instances; i++) - musb_dsps_phy_control(glue, i, 1); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); - static const struct dsps_musb_wrapper am33xx_driver_data = { .revision = 0x00, .control = 0x14, @@ -752,7 +658,6 @@ static struct platform_driver dsps_usbss_driver = { .remove = dsps_remove, .driver = { .name = "musb-dsps", - .pm = &dsps_pm_ops, .of_match_table = of_match_ptr(musb_dsps_of_match), }, }; From 97238b35d5bbb5d5312d83c30a429824b777619f Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 5 Jul 2013 14:51:33 +0200 Subject: [PATCH 088/101] usb: musb: dsps: use proper child nodes This moves the two instances from the big node into two child nodes. The glue layer ontop does almost nothing. There is one devices containing the control module for USB (2) phy, (2) usb and later the dma engine. The usb device is the "glue device" which contains the musb device as a child. This is what we do ever since. The new file musb_am335x is just here to prob the new bus and populate child devices. There are a lot of changes to the dsps file as a result of the changes: - musb_core_offset This is gone. The device tree provides memory ressources information for the device there is no need to "fix" things - instances This is gone as well. If we have two instances then we have have two child enabled nodes in the device tree. For instance the SoC in beagle bone has two USB instances but only one has been wired up so there is no need to load and init the second instance since it won't be used. - dsps_glue is now per glue device In the past there was one of this structs but with an array of two and each instance accessed its variable depending on the platform device id. - no unneeded copy of structs I do not know why struct dsps_musb_wrapper is copied but it is not necessary. The same goes for musb_hdrc_platform_data which allocated on demand and then again by platform_device_add_data(). One copy is enough. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- arch/arm/boot/dts/am335x-bone.dts | 16 ++ arch/arm/boot/dts/am335x-evm.dts | 24 +++ arch/arm/boot/dts/am335x-evmsk.dts | 16 ++ arch/arm/boot/dts/am33xx.dtsi | 97 +++++++++-- drivers/usb/musb/Kconfig | 4 + drivers/usb/musb/Makefile | 3 + drivers/usb/musb/musb_am335x.c | 55 +++++++ drivers/usb/musb/musb_dsps.c | 255 +++++++++++------------------ 8 files changed, 299 insertions(+), 171 deletions(-) create mode 100644 drivers/usb/musb/musb_am335x.c diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts index 444b4ede0d60..a8907b57c75c 100644 --- a/arch/arm/boot/dts/am335x-bone.dts +++ b/arch/arm/boot/dts/am335x-bone.dts @@ -120,6 +120,22 @@ uart0: serial@44e09000 { status = "okay"; }; + musb: usb@47400000 { + status = "okay"; + + control@44e10000 { + status = "okay"; + }; + + phy@47401300 { + status = "okay"; + }; + + usb@47401000 { + status = "okay"; + }; + }; + i2c0: i2c@44e0b000 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index 3aee1a43782d..b2987e03b19f 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -171,6 +171,30 @@ tps: tps@2d { }; }; + musb: usb@47400000 { + status = "okay"; + + control@44e10000 { + status = "okay"; + }; + + phy@47401300 { + status = "okay"; + }; + + phy@47401b00 { + status = "okay"; + }; + + usb@47401000 { + status = "okay"; + }; + + usb@47401800 { + status = "okay"; + }; + }; + i2c1: i2c@4802a000 { pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins>; diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 0c8ad173d2b0..e92446c6846e 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -207,6 +207,22 @@ lis331dlh: lis331dlh@18 { }; }; + musb: usb@47400000 { + status = "okay"; + + control@44e10000 { + status = "okay"; + }; + + phy@47401300 { + status = "okay"; + }; + + usb@47401000 { + status = "okay"; + }; + }; + epwmss2: epwmss@48304000 { status = "okay"; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 38b446ba1ce1..e1e773cd2556 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -26,6 +26,10 @@ aliases { serial5 = &uart5; d_can0 = &dcan0; d_can1 = &dcan1; + usb0 = &usb0; + usb1 = &usb1; + phy0 = &usb0_phy; + phy1 = &usb1_phy; }; cpus { @@ -333,21 +337,86 @@ spi1: spi@481a0000 { status = "disabled"; }; - usb@47400000 { - compatible = "ti,musb-am33xx"; - reg = <0x47400000 0x1000 /* usbss */ - 0x47401000 0x800 /* musb instance 0 */ - 0x47401800 0x800>; /* musb instance 1 */ - interrupts = <17 /* usbss */ - 18 /* musb instance 0 */ - 19>; /* musb instance 1 */ - multipoint = <1>; - num-eps = <16>; - ram-bits = <12>; - port0-mode = <3>; - port1-mode = <3>; - power = <250>; + usb: usb@47400000 { + compatible = "ti,am33xx-usb"; + reg = <0x47400000 0x1000>; + ranges; + #address-cells = <1>; + #size-cells = <1>; ti,hwmods = "usb_otg_hs"; + status = "disabled"; + + ctrl_mod: control@44e10000 { + compatible = "ti,am335x-usb-ctrl-module"; + reg = <0x44e10620 0x10 + 0x44e10648 0x4>; + reg-names = "phy_ctrl", "wakeup"; + status = "disabled"; + }; + + usb0_phy: phy@47401300 { + compatible = "ti,am335x-usb-phy"; + reg = <0x47401300 0x100>; + reg-names = "phy"; + status = "disabled"; + ti,ctrl_mod = <&ctrl_mod>; + }; + + usb0: usb@47401000 { + compatible = "ti,musb-am33xx"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x47401000 0x200>; + reg-names = "control"; + status = "disabled"; + + musb0: usb@47401400 { + compatible = "mg,musbmhdrc"; + reg = <0x47401400 0x400>; + reg-names = "mc"; + interrupts = <18>; + interrupt-names = "mc"; + multipoint = <1>; + num-eps = <16>; + ram-bits = <12>; + port-mode = <3>; + power = <250>; + phys = <&usb0_phy>; + }; + }; + + usb1_phy: phy@47401b00 { + compatible = "ti,am335x-usb-phy"; + reg = <0x47401b00 0x100>; + reg-names = "phy"; + status = "disabled"; + ti,ctrl_mod = <&ctrl_mod>; + }; + + usb1: usb@47401800 { + compatible = "ti,musb-am33xx"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x47401800 0x200>; + reg-names = "control"; + status = "disabled"; + + musb1: usb@47401c00 { + compatible = "mg,musbmhdrc"; + reg = <0x47401c00 0x400>; + reg-names = "mc"; + interrupts = <19>; + interrupt-names = "mc"; + multipoint = <1>; + num-eps = <16>; + ram-bits = <12>; + port-mode = <3>; + power = <250>; + phys = <&usb1_phy>; + }; + }; }; epwmss0: epwmss@48300000 { diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 797e3fd45510..b7257ae038fd 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -83,6 +83,7 @@ config USB_MUSB_AM35X config USB_MUSB_DSPS tristate "TI DSPS platforms" + select USB_MUSB_AM335X_CHILD config USB_MUSB_BLACKFIN tristate "Blackfin" @@ -93,6 +94,9 @@ config USB_MUSB_UX500 endchoice +config USB_MUSB_AM335X_CHILD + tristate + choice prompt 'MUSB DMA mode' default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 2b82ed7c85ca..52f552c1ba2b 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -20,6 +20,9 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o obj-$(CONFIG_USB_MUSB_UX500) += ux500.o + +obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o + # the kconfig must guarantee that only one of the # possible I/O schemes will be enabled at a time ... # PIO only, or DMA (several potential schemes). diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c new file mode 100644 index 000000000000..41ac5b5b57ce --- /dev/null +++ b/drivers/usb/musb/musb_am335x.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +static int am335x_child_probe(struct platform_device *pdev) +{ + int ret; + + pm_runtime_enable(&pdev->dev); + + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (ret) + goto err; + + return 0; +err: + pm_runtime_disable(&pdev->dev); + return ret; +} + +static int of_remove_populated_child(struct device *dev, void *d) +{ + struct platform_device *pdev = to_platform_device(dev); + + of_device_unregister(pdev); + return 0; +} + +static int am335x_child_remove(struct platform_device *pdev) +{ + device_for_each_child(&pdev->dev, NULL, of_remove_populated_child); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static const struct of_device_id am335x_child_of_match[] = { + { .compatible = "ti,am33xx-usb" }, + { }, +}; +MODULE_DEVICE_TABLE(of, am335x_child_of_match); + +static struct platform_driver am335x_child_driver = { + .probe = am335x_child_probe, + .remove = am335x_child_remove, + .driver = { + .name = "am335x-usb-childs", + .of_match_table = of_match_ptr(am335x_child_of_match), + }, +}; + +module_platform_driver(am335x_child_driver); +MODULE_DESCRIPTION("AM33xx child devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 74333321cb62..4ffbaace7913 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "musb_core.h" @@ -105,10 +106,7 @@ struct dsps_musb_wrapper { /* bit positions for mode */ unsigned iddig:5; /* miscellaneous stuff */ - u32 musb_core_offset; u8 poll_seconds; - /* number of musb instances */ - u8 instances; }; /** @@ -116,10 +114,10 @@ struct dsps_musb_wrapper { */ struct dsps_glue { struct device *dev; - struct platform_device *musb[2]; /* child musb pdev */ + struct platform_device *musb; /* child musb pdev */ const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ - struct timer_list timer[2]; /* otg_workaround timer */ - unsigned long last_timer[2]; /* last timer data for each instance */ + struct timer_list timer; /* otg_workaround timer */ + unsigned long last_timer; /* last timer data for each instance */ }; /** @@ -168,7 +166,6 @@ static void otg_timer(unsigned long _musb) struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; u8 devctl; @@ -205,7 +202,7 @@ static void otg_timer(unsigned long _musb) case OTG_STATE_B_IDLE: devctl = dsps_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) - mod_timer(&glue->timer[pdev->id], + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); else musb->xceiv->state = OTG_STATE_A_IDLE; @@ -219,7 +216,6 @@ static void otg_timer(unsigned long _musb) static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); if (timeout == 0) @@ -230,23 +226,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", usb_otg_state_string(musb->xceiv->state)); - del_timer(&glue->timer[pdev->id]); - glue->last_timer[pdev->id] = jiffies; + del_timer(&glue->timer); + glue->last_timer = jiffies; return; } - if (time_after(glue->last_timer[pdev->id], timeout) && - timer_pending(&glue->timer[pdev->id])) { + if (time_after(glue->last_timer, timeout) && + timer_pending(&glue->timer)) { dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n"); return; } - glue->last_timer[pdev->id] = timeout; + glue->last_timer = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", usb_otg_state_string(musb->xceiv->state), jiffies_to_msecs(timeout - jiffies)); - mod_timer(&glue->timer[pdev->id], timeout); + mod_timer(&glue->timer, timeout); } static irqreturn_t dsps_interrupt(int irq, void *hci) @@ -254,7 +250,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; unsigned long flags; @@ -314,7 +309,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; - mod_timer(&glue->timer[pdev->id], + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { @@ -322,7 +317,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - del_timer(&glue->timer[pdev->id]); + del_timer(&glue->timer); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); @@ -344,8 +339,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) /* Poll for ID change */ if (musb->xceiv->state == OTG_STATE_B_IDLE) - mod_timer(&glue->timer[pdev->id], - jiffies + wrp->poll_seconds * HZ); + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); out: spin_unlock_irqrestore(&musb->lock, flags); @@ -355,31 +349,34 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) static int dsps_musb_init(struct musb *musb) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); + struct platform_device *parent = to_platform_device(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; - void __iomem *reg_base = musb->ctrl_base; + void __iomem *reg_base; + struct resource *r; u32 rev, val; - int status; - /* mentor core register starts at offset of 0x400 from musb base */ - musb->mregs += wrp->musb_core_offset; + r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); + if (!r) + return -EINVAL; + + reg_base = devm_ioremap_resource(dev, r); + if (!musb->ctrl_base) + return -EINVAL; + musb->ctrl_base = reg_base; /* NOP driver needs change if supporting dual instance */ - musb->xceiv = devm_usb_get_phy_by_phandle(glue->dev, "phys", 0); - if (IS_ERR_OR_NULL(musb->xceiv)) - return -EPROBE_DEFER; + musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0); + if (IS_ERR(musb->xceiv)) + return PTR_ERR(musb->xceiv); /* Returns zero if e.g. not clocked */ rev = dsps_readl(reg_base, wrp->revision); - if (!rev) { - status = -ENODEV; - goto err0; - } + if (!rev) + return -ENODEV; usb_phy_init(musb->xceiv); - - setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb); + setup_timer(&glue->timer, otg_timer, (unsigned long) musb); /* Reset the musb */ dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); @@ -392,17 +389,14 @@ static int dsps_musb_init(struct musb *musb) dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); return 0; -err0: - return status; } static int dsps_musb_exit(struct musb *musb) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); struct dsps_glue *glue = dev_get_drvdata(dev->parent); - del_timer_sync(&glue->timer[pdev->id]); + del_timer_sync(&glue->timer); usb_phy_shutdown(musb->xceiv); return 0; @@ -420,106 +414,98 @@ static struct musb_platform_ops dsps_ops = { static u64 musb_dmamask = DMA_BIT_MASK(32); -static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) +static int get_int_prop(struct device_node *dn, const char *s) { - struct device *dev = glue->dev; - struct platform_device *pdev = to_platform_device(dev); - struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); - struct device_node *np = pdev->dev.of_node; - struct musb_hdrc_config *config; - struct platform_device *musb; - struct resource *res; + int ret; + u32 val; + + ret = of_property_read_u32(dn, s, &val); + if (ret) + return 0; + return val; +} + +static int dsps_create_musb_pdev(struct dsps_glue *glue, + struct platform_device *parent) +{ + struct musb_hdrc_platform_data pdata; struct resource resources[2]; - char res_name[11]; + struct device *dev = &parent->dev; + struct musb_hdrc_config *config; + struct platform_device *musb; + struct device_node *dn = parent->dev.of_node; + struct device_node *child_node; int ret; - /* first resource is for usbss, so start index from 1 */ - res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1); - if (!res) { - dev_err(dev, "failed to get memory for instance %d\n", id); - ret = -ENODEV; - goto err0; - } - res->parent = NULL; - resources[0] = *res; + child_node = of_get_child_by_name(dn, "usb"); + if (!child_node) + return -EINVAL; - /* first resource is for usbss, so start index from 1 */ - res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1); - if (!res) { - dev_err(dev, "failed to get irq for instance %d\n", id); - ret = -ENODEV; - goto err0; + memset(resources, 0, sizeof(resources)); + ret = of_address_to_resource(child_node, 0, &resources[0]); + if (ret) { + dev_err(dev, "failed to get memory.\n"); + return ret; + } + + ret = of_irq_to_resource(child_node, 0, &resources[1]); + if (ret == 0) { + dev_err(dev, "failed to get irq.\n"); + ret = -EINVAL; + return ret; } - res->parent = NULL; - resources[1] = *res; - resources[1].name = "mc"; /* allocate the child platform device */ musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); if (!musb) { dev_err(dev, "failed to allocate musb device\n"); - ret = -ENOMEM; - goto err0; + return -ENOMEM; } musb->dev.parent = dev; musb->dev.dma_mask = &musb_dmamask; musb->dev.coherent_dma_mask = musb_dmamask; + musb->dev.of_node = of_node_get(child_node); - glue->musb[id] = musb; + glue->musb = musb; - ret = platform_device_add_resources(musb, resources, 2); + ret = platform_device_add_resources(musb, resources, + ARRAY_SIZE(resources)); if (ret) { dev_err(dev, "failed to add resources\n"); - goto err2; + goto err; } - if (np) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, - "failed to allocate musb platform data\n"); - ret = -ENOMEM; - goto err2; - } - - config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); - if (!config) { - dev_err(&pdev->dev, - "failed to allocate musb hdrc config\n"); - ret = -ENOMEM; - goto err2; - } - - of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); - of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); - snprintf(res_name, sizeof(res_name), "port%d-mode", id); - of_property_read_u32(np, res_name, (u32 *)&pdata->mode); - of_property_read_u32(np, "power", (u32 *)&pdata->power); - config->multipoint = of_property_read_bool(np, "multipoint"); - - pdata->config = config; + config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL); + if (!config) { + dev_err(dev, "failed to allocate musb hdrc config\n"); + ret = -ENOMEM; + goto err; } + pdata.config = config; + pdata.platform_ops = &dsps_ops; - pdata->platform_ops = &dsps_ops; + config->num_eps = get_int_prop(child_node, "num-eps"); + config->ram_bits = get_int_prop(child_node, "ram-bits"); + pdata.mode = get_int_prop(child_node, "port-mode"); + pdata.power = get_int_prop(child_node, "power"); + config->multipoint = of_property_read_bool(child_node, "multipoint"); - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); + ret = platform_device_add_data(musb, &pdata, sizeof(pdata)); if (ret) { dev_err(dev, "failed to add platform_data\n"); - goto err2; + goto err; } ret = platform_device_add(musb); if (ret) { dev_err(dev, "failed to register musb device\n"); - goto err2; + goto err; } - return 0; -err2: +err: platform_device_put(musb); -err0: return ret; } @@ -528,14 +514,12 @@ static int dsps_probe(struct platform_device *pdev) const struct of_device_id *match; const struct dsps_musb_wrapper *wrp; struct dsps_glue *glue; - struct resource *iomem; - int ret, i; + int ret; match = of_match_node(musb_dsps_of_match, pdev->dev.of_node); if (!match) { dev_err(&pdev->dev, "fail to get matching of_match struct\n"); - ret = -EINVAL; - goto err0; + return -EINVAL; } wrp = match->data; @@ -543,29 +527,13 @@ static int dsps_probe(struct platform_device *pdev) glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&pdev->dev, "unable to allocate glue memory\n"); - ret = -ENOMEM; - goto err0; - } - - /* get memory resource */ - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem) { - dev_err(&pdev->dev, "failed to get usbss mem resourse\n"); - ret = -ENODEV; - goto err1; + return -ENOMEM; } glue->dev = &pdev->dev; + glue->wrp = wrp; - glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL); - if (!glue->wrp) { - dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n"); - ret = -ENOMEM; - goto err1; - } platform_set_drvdata(pdev, glue); - - /* enable the usbss clocks */ pm_runtime_enable(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev); @@ -574,17 +542,9 @@ static int dsps_probe(struct platform_device *pdev) goto err2; } - /* create the child platform device for all instances of musb */ - for (i = 0; i < wrp->instances ; i++) { - ret = dsps_create_musb_pdev(glue, i); - if (ret != 0) { - dev_err(&pdev->dev, "failed to create child pdev\n"); - /* release resources of previously created instances */ - for (i--; i >= 0 ; i--) - platform_device_unregister(glue->musb[i]); - goto err3; - } - } + ret = dsps_create_musb_pdev(glue, pdev); + if (ret) + goto err3; return 0; @@ -592,26 +552,19 @@ static int dsps_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); err2: pm_runtime_disable(&pdev->dev); - kfree(glue->wrp); -err1: kfree(glue); -err0: return ret; } + static int dsps_remove(struct platform_device *pdev) { struct dsps_glue *glue = platform_get_drvdata(pdev); - const struct dsps_musb_wrapper *wrp = glue->wrp; - int i; - /* delete the child platform device */ - for (i = 0; i < wrp->instances ; i++) - platform_device_unregister(glue->musb[i]); + platform_device_unregister(glue->musb); /* disable usbss clocks */ pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - kfree(glue->wrp); kfree(glue); return 0; } @@ -641,9 +594,7 @@ static const struct dsps_musb_wrapper am33xx_driver_data = { .rxep_shift = 16, .rxep_mask = 0xfffe, .rxep_bitmap = (0xfffe << 16), - .musb_core_offset = 0x400, .poll_seconds = 2, - .instances = 1, }; static const struct of_device_id musb_dsps_of_match[] = { @@ -667,14 +618,4 @@ MODULE_AUTHOR("Ravi B "); MODULE_AUTHOR("Ajay Kumar Gupta "); MODULE_LICENSE("GPL v2"); -static int __init dsps_init(void) -{ - return platform_driver_register(&dsps_usbss_driver); -} -subsys_initcall(dsps_init); - -static void __exit dsps_exit(void) -{ - platform_driver_unregister(&dsps_usbss_driver); -} -module_exit(dsps_exit); +module_platform_driver(dsps_usbss_driver); From 9b3452d1fa3c017d3664ff9e6a601daa6e0576eb Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 20 Jun 2013 12:13:04 +0200 Subject: [PATCH 089/101] usb: musb dma: add cppi41 dma driver This driver is currently used by musb' cppi41 couter part. I may merge both dma engine user of musb at some point but not just yet. The driver seems to work in RX/TX mode in host mode, tested on mass storage. I increaed the size of the TX / RX transfers and waited for the core code to cancel a transfers and it seems to recover. v2..3: - use mall transfers on RX side and check data toggle. - use rndis mode on tx side so we haveon interrupt for 4096 transfers. - remove custom "transferred" hack and use dmaengine_tx_status() to compute the total amount of data that has been transferred. - cancel transfers and reclaim descriptors v1..v2: - RX path added - dma mode 0 & 1 is working - device tree nodes re-created. Cc: Vinod Koul Cc: Dan Williams Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- arch/arm/boot/dts/am335x-evm.dts | 4 + arch/arm/boot/dts/am33xx.dtsi | 61 ++ drivers/dma/Kconfig | 8 + drivers/dma/Makefile | 1 + drivers/dma/cppi41.c | 1048 ++++++++++++++++++++++++++++++ drivers/usb/musb/Kconfig | 4 + drivers/usb/musb/Makefile | 1 + drivers/usb/musb/musb_cppi41.c | 552 ++++++++++++++++ drivers/usb/musb/musb_dma.h | 2 +- 9 files changed, 1680 insertions(+), 1 deletion(-) create mode 100644 drivers/dma/cppi41.c create mode 100644 drivers/usb/musb/musb_cppi41.c diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index b2987e03b19f..c26c16cace3c 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -193,6 +193,10 @@ usb@47401000 { usb@47401800 { status = "okay"; }; + + dma@07402000 { + status = "okay"; + }; }; i2c1: i2c@4802a000 { diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index e1e773cd2556..24d63095ab83 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -383,6 +383,29 @@ musb0: usb@47401400 { port-mode = <3>; power = <250>; phys = <&usb0_phy>; + + dmas = <&cppi41dma 0 0 &cppi41dma 1 0 + &cppi41dma 2 0 &cppi41dma 3 0 + &cppi41dma 4 0 &cppi41dma 5 0 + &cppi41dma 6 0 &cppi41dma 7 0 + &cppi41dma 8 0 &cppi41dma 9 0 + &cppi41dma 10 0 &cppi41dma 11 0 + &cppi41dma 12 0 &cppi41dma 13 0 + &cppi41dma 14 0 &cppi41dma 0 1 + &cppi41dma 1 1 &cppi41dma 2 1 + &cppi41dma 3 1 &cppi41dma 4 1 + &cppi41dma 5 1 &cppi41dma 6 1 + &cppi41dma 7 1 &cppi41dma 8 1 + &cppi41dma 9 1 &cppi41dma 10 1 + &cppi41dma 11 1 &cppi41dma 12 1 + &cppi41dma 13 1 &cppi41dma 14 1>; + dma-names = + "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7", + "rx8", "rx9", "rx10", "rx11", "rx12", "rx13", + "rx14", "rx15", + "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7", + "tx8", "tx9", "tx10", "tx11", "tx12", "tx13", + "tx14", "tx15"; }; }; @@ -415,8 +438,46 @@ musb1: usb@47401c00 { port-mode = <3>; power = <250>; phys = <&usb1_phy>; + + dmas = <&cppi41dma 15 0 &cppi41dma 16 0 + &cppi41dma 17 0 &cppi41dma 18 0 + &cppi41dma 19 0 &cppi41dma 20 0 + &cppi41dma 21 0 &cppi41dma 22 0 + &cppi41dma 23 0 &cppi41dma 24 0 + &cppi41dma 25 0 &cppi41dma 26 0 + &cppi41dma 27 0 &cppi41dma 28 0 + &cppi41dma 29 0 &cppi41dma 15 1 + &cppi41dma 16 1 &cppi41dma 17 1 + &cppi41dma 18 1 &cppi41dma 19 1 + &cppi41dma 20 1 &cppi41dma 21 1 + &cppi41dma 22 1 &cppi41dma 23 1 + &cppi41dma 24 1 &cppi41dma 25 1 + &cppi41dma 26 1 &cppi41dma 27 1 + &cppi41dma 28 1 &cppi41dma 29 1>; + dma-names = + "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7", + "rx8", "rx9", "rx10", "rx11", "rx12", "rx13", + "rx14", "rx15", + "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7", + "tx8", "tx9", "tx10", "tx11", "tx12", "tx13", + "tx14", "tx15"; }; }; + + cppi41dma: dma@07402000 { + compatible = "ti,am3359-cppi41"; + reg = <0x47400000 0x1000 + 0x47402000 0x1000 + 0x47403000 0x1000 + 0x47404000 0x4000>; + reg-names = "glue controller scheduler queuemgr"; + interrupts = <17>; + interrupt-names = "glue"; + #dma-cells = <2>; + #dma-channels = <30>; + #dma-requests = <256>; + status = "disabled"; + }; }; epwmss0: epwmss@48300000 { diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 6825957c97fb..77bc480117b7 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -287,6 +287,14 @@ config DMA_OMAP select DMA_ENGINE select DMA_VIRTUAL_CHANNELS +config TI_CPPI41 + tristate "AM33xx CPPI41 DMA support" + depends on ARCH_OMAP + select DMA_ENGINE + help + The Communications Port Programming Interface (CPPI) 4.1 DMA engine + is currently used by the USB driver on AM335x platforms. + config MMP_PDMA bool "MMP PDMA support" depends on (ARCH_MMP || ARCH_PXA) diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 5e0f2ef85614..6d62ec30c4bc 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -39,3 +39,4 @@ obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o obj-$(CONFIG_DMA_OMAP) += omap-dma.o obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o +obj-$(CONFIG_TI_CPPI41) += cppi41.o diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c new file mode 100644 index 000000000000..5dcebca37760 --- /dev/null +++ b/drivers/dma/cppi41.c @@ -0,0 +1,1048 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dmaengine.h" + +#define DESC_TYPE 27 +#define DESC_TYPE_HOST 0x10 +#define DESC_TYPE_TEARD 0x13 + +#define TD_DESC_IS_RX (1 << 16) +#define TD_DESC_DMA_NUM 10 + +#define DESC_LENGTH_BITS_NUM 21 + +#define DESC_TYPE_USB (5 << 26) +#define DESC_PD_COMPLETE (1 << 31) + +/* DMA engine */ +#define DMA_TDFDQ 4 +#define DMA_TXGCR(x) (0x800 + (x) * 0x20) +#define DMA_RXGCR(x) (0x808 + (x) * 0x20) +#define RXHPCRA0 4 + +#define GCR_CHAN_ENABLE (1 << 31) +#define GCR_TEARDOWN (1 << 30) +#define GCR_STARV_RETRY (1 << 24) +#define GCR_DESC_TYPE_HOST (1 << 14) + +/* DMA scheduler */ +#define DMA_SCHED_CTRL 0 +#define DMA_SCHED_CTRL_EN (1 << 31) +#define DMA_SCHED_WORD(x) ((x) * 4 + 0x800) + +#define SCHED_ENTRY0_CHAN(x) ((x) << 0) +#define SCHED_ENTRY0_IS_RX (1 << 7) + +#define SCHED_ENTRY1_CHAN(x) ((x) << 8) +#define SCHED_ENTRY1_IS_RX (1 << 15) + +#define SCHED_ENTRY2_CHAN(x) ((x) << 16) +#define SCHED_ENTRY2_IS_RX (1 << 23) + +#define SCHED_ENTRY3_CHAN(x) ((x) << 24) +#define SCHED_ENTRY3_IS_RX (1 << 31) + +/* Queue manager */ +/* 4 KiB of memory for descriptors, 2 for each endpoint */ +#define ALLOC_DECS_NUM 128 +#define DESCS_AREAS 1 +#define TOTAL_DESCS_NUM (ALLOC_DECS_NUM * DESCS_AREAS) +#define QMGR_SCRATCH_SIZE (TOTAL_DESCS_NUM * 4) + +#define QMGR_LRAM0_BASE 0x80 +#define QMGR_LRAM_SIZE 0x84 +#define QMGR_LRAM1_BASE 0x88 +#define QMGR_MEMBASE(x) (0x1000 + (x) * 0x10) +#define QMGR_MEMCTRL(x) (0x1004 + (x) * 0x10) +#define QMGR_MEMCTRL_IDX_SH 16 +#define QMGR_MEMCTRL_DESC_SH 8 + +#define QMGR_NUM_PEND 5 +#define QMGR_PEND(x) (0x90 + (x) * 4) + +#define QMGR_PENDING_SLOT_Q(x) (x / 32) +#define QMGR_PENDING_BIT_Q(x) (x % 32) + +#define QMGR_QUEUE_A(n) (0x2000 + (n) * 0x10) +#define QMGR_QUEUE_B(n) (0x2004 + (n) * 0x10) +#define QMGR_QUEUE_C(n) (0x2008 + (n) * 0x10) +#define QMGR_QUEUE_D(n) (0x200c + (n) * 0x10) + +/* Glue layer specific */ +/* USBSS / USB AM335x */ +#define USBSS_IRQ_STATUS 0x28 +#define USBSS_IRQ_ENABLER 0x2c +#define USBSS_IRQ_CLEARR 0x30 + +#define USBSS_IRQ_PD_COMP (1 << 2) + +struct cppi41_channel { + struct dma_chan chan; + struct dma_async_tx_descriptor txd; + struct cppi41_dd *cdd; + struct cppi41_desc *desc; + dma_addr_t desc_phys; + void __iomem *gcr_reg; + int is_tx; + u32 residue; + + unsigned int q_num; + unsigned int q_comp_num; + unsigned int port_num; + + unsigned td_retry; + unsigned td_queued:1; + unsigned td_seen:1; + unsigned td_desc_seen:1; +}; + +struct cppi41_desc { + u32 pd0; + u32 pd1; + u32 pd2; + u32 pd3; + u32 pd4; + u32 pd5; + u32 pd6; + u32 pd7; +} __aligned(32); + +struct chan_queues { + u16 submit; + u16 complete; +}; + +struct cppi41_dd { + struct dma_device ddev; + + void *qmgr_scratch; + dma_addr_t scratch_phys; + + struct cppi41_desc *cd; + dma_addr_t descs_phys; + u32 first_td_desc; + struct cppi41_channel *chan_busy[ALLOC_DECS_NUM]; + + void __iomem *usbss_mem; + void __iomem *ctrl_mem; + void __iomem *sched_mem; + void __iomem *qmgr_mem; + unsigned int irq; + const struct chan_queues *queues_rx; + const struct chan_queues *queues_tx; + struct chan_queues td_queue; +}; + +#define FIST_COMPLETION_QUEUE 93 +static struct chan_queues usb_queues_tx[] = { + /* USB0 ENDP 1 */ + [ 0] = { .submit = 32, .complete = 93}, + [ 1] = { .submit = 34, .complete = 94}, + [ 2] = { .submit = 36, .complete = 95}, + [ 3] = { .submit = 38, .complete = 96}, + [ 4] = { .submit = 40, .complete = 97}, + [ 5] = { .submit = 42, .complete = 98}, + [ 6] = { .submit = 44, .complete = 99}, + [ 7] = { .submit = 46, .complete = 100}, + [ 8] = { .submit = 48, .complete = 101}, + [ 9] = { .submit = 50, .complete = 102}, + [10] = { .submit = 52, .complete = 103}, + [11] = { .submit = 54, .complete = 104}, + [12] = { .submit = 56, .complete = 105}, + [13] = { .submit = 58, .complete = 106}, + [14] = { .submit = 60, .complete = 107}, + + /* USB1 ENDP1 */ + [15] = { .submit = 62, .complete = 125}, + [16] = { .submit = 64, .complete = 126}, + [17] = { .submit = 66, .complete = 127}, + [18] = { .submit = 68, .complete = 128}, + [19] = { .submit = 70, .complete = 129}, + [20] = { .submit = 72, .complete = 130}, + [21] = { .submit = 74, .complete = 131}, + [22] = { .submit = 76, .complete = 132}, + [23] = { .submit = 78, .complete = 133}, + [24] = { .submit = 80, .complete = 134}, + [25] = { .submit = 82, .complete = 135}, + [26] = { .submit = 84, .complete = 136}, + [27] = { .submit = 86, .complete = 137}, + [28] = { .submit = 88, .complete = 138}, + [29] = { .submit = 90, .complete = 139}, +}; + +static const struct chan_queues usb_queues_rx[] = { + /* USB0 ENDP 1 */ + [ 0] = { .submit = 1, .complete = 109}, + [ 1] = { .submit = 2, .complete = 110}, + [ 2] = { .submit = 3, .complete = 111}, + [ 3] = { .submit = 4, .complete = 112}, + [ 4] = { .submit = 5, .complete = 113}, + [ 5] = { .submit = 6, .complete = 114}, + [ 6] = { .submit = 7, .complete = 115}, + [ 7] = { .submit = 8, .complete = 116}, + [ 8] = { .submit = 9, .complete = 117}, + [ 9] = { .submit = 10, .complete = 118}, + [10] = { .submit = 11, .complete = 119}, + [11] = { .submit = 12, .complete = 120}, + [12] = { .submit = 13, .complete = 121}, + [13] = { .submit = 14, .complete = 122}, + [14] = { .submit = 15, .complete = 123}, + + /* USB1 ENDP 1 */ + [15] = { .submit = 16, .complete = 141}, + [16] = { .submit = 17, .complete = 142}, + [17] = { .submit = 18, .complete = 143}, + [18] = { .submit = 19, .complete = 144}, + [19] = { .submit = 20, .complete = 145}, + [20] = { .submit = 21, .complete = 146}, + [21] = { .submit = 22, .complete = 147}, + [22] = { .submit = 23, .complete = 148}, + [23] = { .submit = 24, .complete = 149}, + [24] = { .submit = 25, .complete = 150}, + [25] = { .submit = 26, .complete = 151}, + [26] = { .submit = 27, .complete = 152}, + [27] = { .submit = 28, .complete = 153}, + [28] = { .submit = 29, .complete = 154}, + [29] = { .submit = 30, .complete = 155}, +}; + +struct cppi_glue_infos { + irqreturn_t (*isr)(int irq, void *data); + const struct chan_queues *queues_rx; + const struct chan_queues *queues_tx; + struct chan_queues td_queue; +}; + +static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c) +{ + return container_of(c, struct cppi41_channel, chan); +} + +static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc) +{ + struct cppi41_channel *c; + u32 descs_size; + u32 desc_num; + + descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM; + + if (!((desc >= cdd->descs_phys) && + (desc < (cdd->descs_phys + descs_size)))) { + return NULL; + } + + desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc); + BUG_ON(desc_num > ALLOC_DECS_NUM); + c = cdd->chan_busy[desc_num]; + cdd->chan_busy[desc_num] = NULL; + return c; +} + +static void cppi_writel(u32 val, void *__iomem *mem) +{ + __raw_writel(val, mem); +} + +static u32 cppi_readl(void *__iomem *mem) +{ + return __raw_readl(mem); +} + +static u32 pd_trans_len(u32 val) +{ + return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1); +} + +static irqreturn_t cppi41_irq(int irq, void *data) +{ + struct cppi41_dd *cdd = data; + struct cppi41_channel *c; + u32 status; + int i; + + status = cppi_readl(cdd->usbss_mem + USBSS_IRQ_STATUS); + if (!(status & USBSS_IRQ_PD_COMP)) + return IRQ_NONE; + cppi_writel(status, cdd->usbss_mem + USBSS_IRQ_STATUS); + + for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND; + i++) { + u32 val; + u32 q_num; + + val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i)); + if (i == QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE) && val) { + u32 mask; + /* set corresponding bit for completetion Q 93 */ + mask = 1 << QMGR_PENDING_BIT_Q(FIST_COMPLETION_QUEUE); + /* not set all bits for queues less than Q 93 */ + mask--; + /* now invert and keep only Q 93+ set */ + val &= ~mask; + } + + if (val) + __iormb(); + + while (val) { + u32 desc; + + q_num = __fls(val); + val &= ~(1 << q_num); + q_num += 32 * i; + desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(q_num)); + desc &= ~0x1f; + c = desc_to_chan(cdd, desc); + if (WARN_ON(!c)) { + pr_err("%s() q %d desc %08x\n", __func__, + q_num, desc); + continue; + } + c->residue = pd_trans_len(c->desc->pd6) - + pd_trans_len(c->desc->pd0); + + dma_cookie_complete(&c->txd); + c->txd.callback(c->txd.callback_param); + } + } + return IRQ_HANDLED; +} + +static dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx) +{ + dma_cookie_t cookie; + + cookie = dma_cookie_assign(tx); + + return cookie; +} + +static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + + dma_cookie_init(chan); + dma_async_tx_descriptor_init(&c->txd, chan); + c->txd.tx_submit = cppi41_tx_submit; + + if (!c->is_tx) + cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0); + + return 0; +} + +static void cppi41_dma_free_chan_resources(struct dma_chan *chan) +{ +} + +static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + enum dma_status ret; + + /* lock */ + ret = dma_cookie_status(chan, cookie, txstate); + if (txstate && ret == DMA_SUCCESS) + txstate->residue = c->residue; + /* unlock */ + + return ret; +} + +static void push_desc_queue(struct cppi41_channel *c) +{ + struct cppi41_dd *cdd = c->cdd; + u32 desc_num; + u32 desc_phys; + u32 reg; + + desc_phys = lower_32_bits(c->desc_phys); + desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); + WARN_ON(cdd->chan_busy[desc_num]); + cdd->chan_busy[desc_num] = c; + + reg = (sizeof(struct cppi41_desc) - 24) / 4; + reg |= desc_phys; + cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num)); +} + +static void cppi41_dma_issue_pending(struct dma_chan *chan) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + u32 reg; + + c->residue = 0; + + reg = GCR_CHAN_ENABLE; + if (!c->is_tx) { + reg |= GCR_STARV_RETRY; + reg |= GCR_DESC_TYPE_HOST; + reg |= c->q_comp_num; + } + + cppi_writel(reg, c->gcr_reg); + + /* + * We don't use writel() but __raw_writel() so we have to make sure + * that the DMA descriptor in coherent memory made to the main memory + * before starting the dma engine. + */ + __iowmb(); + push_desc_queue(c); +} + +static u32 get_host_pd0(u32 length) +{ + u32 reg; + + reg = DESC_TYPE_HOST << DESC_TYPE; + reg |= length; + + return reg; +} + +static u32 get_host_pd1(struct cppi41_channel *c) +{ + u32 reg; + + reg = 0; + + return reg; +} + +static u32 get_host_pd2(struct cppi41_channel *c) +{ + u32 reg; + + reg = DESC_TYPE_USB; + reg |= c->q_comp_num; + + return reg; +} + +static u32 get_host_pd3(u32 length) +{ + u32 reg; + + /* PD3 = packet size */ + reg = length; + + return reg; +} + +static u32 get_host_pd6(u32 length) +{ + u32 reg; + + /* PD6 buffer size */ + reg = DESC_PD_COMPLETE; + reg |= length; + + return reg; +} + +static u32 get_host_pd4_or_7(u32 addr) +{ + u32 reg; + + reg = addr; + + return reg; +} + +static u32 get_host_pd5(void) +{ + u32 reg; + + reg = 0; + + return reg; +} + +static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len, + enum dma_transfer_direction dir, unsigned long tx_flags, void *context) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + struct cppi41_desc *d; + struct scatterlist *sg; + unsigned int i; + unsigned int num; + + num = 0; + d = c->desc; + for_each_sg(sgl, sg, sg_len, i) { + u32 addr; + u32 len; + + /* We need to use more than one desc once musb supports sg */ + BUG_ON(num > 0); + addr = lower_32_bits(sg_dma_address(sg)); + len = sg_dma_len(sg); + + d->pd0 = get_host_pd0(len); + d->pd1 = get_host_pd1(c); + d->pd2 = get_host_pd2(c); + d->pd3 = get_host_pd3(len); + d->pd4 = get_host_pd4_or_7(addr); + d->pd5 = get_host_pd5(); + d->pd6 = get_host_pd6(len); + d->pd7 = get_host_pd4_or_7(addr); + + d++; + } + + return &c->txd; +} + +static int cpp41_cfg_chan(struct cppi41_channel *c, + struct dma_slave_config *cfg) +{ + return 0; +} + +static void cppi41_compute_td_desc(struct cppi41_desc *d) +{ + d->pd0 = DESC_TYPE_TEARD << DESC_TYPE; +} + +static u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num) +{ + u32 desc; + + desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(queue_num)); + desc &= ~0x1f; + return desc; +} + +static int cppi41_tear_down_chan(struct cppi41_channel *c) +{ + struct cppi41_dd *cdd = c->cdd; + struct cppi41_desc *td; + u32 reg; + u32 desc_phys; + u32 td_desc_phys; + + td = cdd->cd; + td += cdd->first_td_desc; + + td_desc_phys = cdd->descs_phys; + td_desc_phys += cdd->first_td_desc * sizeof(struct cppi41_desc); + + if (!c->td_queued) { + cppi41_compute_td_desc(td); + __iowmb(); + + reg = (sizeof(struct cppi41_desc) - 24) / 4; + reg |= td_desc_phys; + cppi_writel(reg, cdd->qmgr_mem + + QMGR_QUEUE_D(cdd->td_queue.submit)); + + reg = GCR_CHAN_ENABLE; + if (!c->is_tx) { + reg |= GCR_STARV_RETRY; + reg |= GCR_DESC_TYPE_HOST; + reg |= c->q_comp_num; + } + reg |= GCR_TEARDOWN; + cppi_writel(reg, c->gcr_reg); + c->td_queued = 1; + c->td_retry = 100; + } + + if (!c->td_seen) { + unsigned td_comp_queue; + + if (c->is_tx) + td_comp_queue = cdd->td_queue.complete; + else + td_comp_queue = c->q_comp_num; + + desc_phys = cppi41_pop_desc(cdd, td_comp_queue); + if (desc_phys) { + __iormb(); + + if (desc_phys == td_desc_phys) { + u32 pd0; + pd0 = td->pd0; + WARN_ON((pd0 >> DESC_TYPE) != DESC_TYPE_TEARD); + WARN_ON(!c->is_tx && !(pd0 & TD_DESC_IS_RX)); + WARN_ON((pd0 & 0x1f) != c->port_num); + } else { + __WARN(); + } + c->td_seen = 1; + } + } + if (!c->td_desc_seen) { + desc_phys = cppi41_pop_desc(cdd, c->q_comp_num); + if (desc_phys) { + __iormb(); + WARN_ON(c->desc_phys != desc_phys); + c->td_desc_seen = 1; + } + } + c->td_retry--; + /* + * If the TX descriptor / channel is in use, the caller needs to poke + * his TD bit multiple times. After that he hardware releases the + * transfer descriptor followed by TD descriptor. Waiting seems not to + * cause any difference. + * RX seems to be thrown out right away. However once the TearDown + * descriptor gets through we are done. If we have seens the transfer + * descriptor before the TD we fetch it from enqueue, it has to be + * there waiting for us. + */ + if (!c->td_seen && c->td_retry) + return -EAGAIN; + + WARN_ON(!c->td_retry); + if (!c->td_desc_seen) { + desc_phys = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num)); + WARN_ON(!desc_phys); + } + + c->td_queued = 0; + c->td_seen = 0; + c->td_desc_seen = 0; + cppi_writel(0, c->gcr_reg); + return 0; +} + +static int cppi41_stop_chan(struct dma_chan *chan) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + struct cppi41_dd *cdd = c->cdd; + u32 desc_num; + u32 desc_phys; + int ret; + + ret = cppi41_tear_down_chan(c); + if (ret) + return ret; + + desc_phys = lower_32_bits(c->desc_phys); + desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); + WARN_ON(!cdd->chan_busy[desc_num]); + cdd->chan_busy[desc_num] = NULL; + + return 0; +} + +static int cppi41_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + struct cppi41_channel *c = to_cpp41_chan(chan); + int ret; + + switch (cmd) { + case DMA_SLAVE_CONFIG: + ret = cpp41_cfg_chan(c, (struct dma_slave_config *) arg); + break; + + case DMA_TERMINATE_ALL: + ret = cppi41_stop_chan(chan); + break; + + default: + ret = -ENXIO; + break; + } + return ret; +} + +static void cleanup_chans(struct cppi41_dd *cdd) +{ + while (!list_empty(&cdd->ddev.channels)) { + struct cppi41_channel *cchan; + + cchan = list_first_entry(&cdd->ddev.channels, + struct cppi41_channel, chan.device_node); + list_del(&cchan->chan.device_node); + kfree(cchan); + } +} + +static int cppi41_add_chans(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + struct cppi41_channel *cchan; + int i; + int ret; + u32 n_chans; + + ret = of_property_read_u32(pdev->dev.of_node, "#dma-channels", + &n_chans); + if (ret) + return ret; + /* + * The channels can only be used as TX or as RX. So we add twice + * that much dma channels because USB can only do RX or TX. + */ + n_chans *= 2; + + for (i = 0; i < n_chans; i++) { + cchan = kzalloc(sizeof(*cchan), GFP_KERNEL); + if (!cchan) + goto err; + + cchan->cdd = cdd; + if (i & 1) { + cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1); + cchan->is_tx = 1; + } else { + cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1); + cchan->is_tx = 0; + } + cchan->port_num = i >> 1; + cchan->desc = &cdd->cd[i]; + cchan->desc_phys = cdd->descs_phys; + cchan->desc_phys += i * sizeof(struct cppi41_desc); + cchan->chan.device = &cdd->ddev; + list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels); + } + cdd->first_td_desc = n_chans; + + return 0; +err: + cleanup_chans(cdd); + return -ENOMEM; +} + +static void purge_descs(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + unsigned int mem_decs; + int i; + + mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc); + + for (i = 0; i < DESCS_AREAS; i++) { + + cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i)); + cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i)); + + dma_free_coherent(&pdev->dev, mem_decs, cdd->cd, + cdd->descs_phys); + } +} + +static void disable_sched(struct cppi41_dd *cdd) +{ + cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); +} + +static void deinit_cpii41(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + disable_sched(cdd); + + purge_descs(pdev, cdd); + + cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE); + cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE); + dma_free_coherent(&pdev->dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch, + cdd->scratch_phys); +} + +static int init_descs(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + unsigned int desc_size; + unsigned int mem_decs; + int i; + u32 reg; + u32 idx; + + BUILD_BUG_ON(sizeof(struct cppi41_desc) & + (sizeof(struct cppi41_desc) - 1)); + BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32); + BUILD_BUG_ON(ALLOC_DECS_NUM < 32); + + desc_size = sizeof(struct cppi41_desc); + mem_decs = ALLOC_DECS_NUM * desc_size; + + idx = 0; + for (i = 0; i < DESCS_AREAS; i++) { + + reg = idx << QMGR_MEMCTRL_IDX_SH; + reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH; + reg |= ilog2(ALLOC_DECS_NUM) - 5; + + BUILD_BUG_ON(DESCS_AREAS != 1); + cdd->cd = dma_alloc_coherent(&pdev->dev, mem_decs, + &cdd->descs_phys, GFP_KERNEL); + if (!cdd->cd) + return -ENOMEM; + + cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i)); + cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i)); + + idx += ALLOC_DECS_NUM; + } + return 0; +} + +static void init_sched(struct cppi41_dd *cdd) +{ + unsigned ch; + unsigned word; + u32 reg; + + word = 0; + cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); + for (ch = 0; ch < 15 * 2; ch += 2) { + + reg = SCHED_ENTRY0_CHAN(ch); + reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX; + + reg |= SCHED_ENTRY2_CHAN(ch + 1); + reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX; + cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word)); + word++; + } + reg = 15 * 2 * 2 - 1; + reg |= DMA_SCHED_CTRL_EN; + cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL); +} + +static int init_cppi41(struct platform_device *pdev, struct cppi41_dd *cdd) +{ + int ret; + + BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1)); + cdd->qmgr_scratch = dma_alloc_coherent(&pdev->dev, QMGR_SCRATCH_SIZE, + &cdd->scratch_phys, GFP_KERNEL); + if (!cdd->qmgr_scratch) + return -ENOMEM; + + cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE); + cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE); + cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); + + ret = init_descs(pdev, cdd); + if (ret) + goto err_td; + + cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ); + init_sched(cdd); + return 0; +err_td: + deinit_cpii41(pdev, cdd); + return ret; +} + +static struct platform_driver cpp41_dma_driver; +/* + * The param format is: + * X Y + * X: Port + * Y: 0 = RX else TX + */ +#define INFO_PORT 0 +#define INFO_IS_TX 1 + +static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param) +{ + struct cppi41_channel *cchan; + struct cppi41_dd *cdd; + const struct chan_queues *queues; + u32 *num = param; + + if (chan->device->dev->driver != &cpp41_dma_driver.driver) + return false; + + cchan = to_cpp41_chan(chan); + + if (cchan->port_num != num[INFO_PORT]) + return false; + + if (cchan->is_tx && !num[INFO_IS_TX]) + return false; + cdd = cchan->cdd; + if (cchan->is_tx) + queues = cdd->queues_tx; + else + queues = cdd->queues_rx; + + BUILD_BUG_ON(ARRAY_SIZE(usb_queues_rx) != ARRAY_SIZE(usb_queues_tx)); + if (WARN_ON(cchan->port_num > ARRAY_SIZE(usb_queues_rx))) + return false; + + cchan->q_num = queues[cchan->port_num].submit; + cchan->q_comp_num = queues[cchan->port_num].complete; + return true; +} + +static struct of_dma_filter_info cpp41_dma_info = { + .filter_fn = cpp41_dma_filter_fn, +}; + +static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + int count = dma_spec->args_count; + struct of_dma_filter_info *info = ofdma->of_dma_data; + + if (!info || !info->filter_fn) + return NULL; + + if (count != 2) + return NULL; + + return dma_request_channel(info->dma_cap, info->filter_fn, + &dma_spec->args[0]); +} + +static const struct cppi_glue_infos usb_infos = { + .isr = cppi41_irq, + .queues_rx = usb_queues_rx, + .queues_tx = usb_queues_tx, + .td_queue = { .submit = 31, .complete = 0 }, +}; + +static const struct of_device_id cppi41_dma_ids[] = { + { .compatible = "ti,am3359-cppi41", .data = &usb_infos}, + {}, +}; +MODULE_DEVICE_TABLE(of, cppi41_dma_ids); + +static const struct cppi_glue_infos *get_glue_info(struct platform_device *pdev) +{ + const struct of_device_id *of_id; + + of_id = of_match_node(cppi41_dma_ids, pdev->dev.of_node); + if (!of_id) + return NULL; + return of_id->data; +} + +static int cppi41_dma_probe(struct platform_device *pdev) +{ + struct cppi41_dd *cdd; + const struct cppi_glue_infos *glue_info; + int irq; + int ret; + + glue_info = get_glue_info(pdev); + if (!glue_info) + return -EINVAL; + + cdd = kzalloc(sizeof(*cdd), GFP_KERNEL); + if (!cdd) + return -ENOMEM; + + dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask); + cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources; + cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources; + cdd->ddev.device_tx_status = cppi41_dma_tx_status; + cdd->ddev.device_issue_pending = cppi41_dma_issue_pending; + cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg; + cdd->ddev.device_control = cppi41_dma_control; + cdd->ddev.dev = &pdev->dev; + INIT_LIST_HEAD(&cdd->ddev.channels); + cpp41_dma_info.dma_cap = cdd->ddev.cap_mask; + + cdd->usbss_mem = of_iomap(pdev->dev.of_node, 0); + cdd->ctrl_mem = of_iomap(pdev->dev.of_node, 1); + cdd->sched_mem = of_iomap(pdev->dev.of_node, 2); + cdd->qmgr_mem = of_iomap(pdev->dev.of_node, 3); + + if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem || + !cdd->qmgr_mem) { + ret = -ENXIO; + goto err_remap; + } + + cdd->queues_rx = glue_info->queues_rx; + cdd->queues_tx = glue_info->queues_tx; + cdd->td_queue = glue_info->td_queue; + + ret = init_cppi41(pdev, cdd); + if (ret) + goto err_init_cppi; + + ret = cppi41_add_chans(pdev, cdd); + if (ret) + goto err_chans; + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!irq) + goto err_irq; + + cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER); + + ret = request_irq(irq, glue_info->isr, IRQF_SHARED, + dev_name(&pdev->dev), cdd); + if (ret) + goto err_irq; + cdd->irq = irq; + + ret = dma_async_device_register(&cdd->ddev); + if (ret) + goto err_dma_reg; + + ret = of_dma_controller_register(pdev->dev.of_node, + cppi41_dma_xlate, &cpp41_dma_info); + if (ret) + goto err_of; + + platform_set_drvdata(pdev, cdd); + return 0; +err_of: + dma_async_device_unregister(&cdd->ddev); +err_dma_reg: + free_irq(irq, cdd); +err_irq: + cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); + cleanup_chans(cdd); +err_chans: + deinit_cpii41(pdev, cdd); +err_init_cppi: + iounmap(cdd->usbss_mem); + iounmap(cdd->ctrl_mem); + iounmap(cdd->sched_mem); + iounmap(cdd->qmgr_mem); +err_remap: + kfree(cdd); + return ret; +} + +static int cppi41_dma_remove(struct platform_device *pdev) +{ + struct cppi41_dd *cdd = platform_get_drvdata(pdev); + + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&cdd->ddev); + + cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); + free_irq(cdd->irq, cdd); + cleanup_chans(cdd); + deinit_cpii41(pdev, cdd); + iounmap(cdd->usbss_mem); + iounmap(cdd->ctrl_mem); + iounmap(cdd->sched_mem); + iounmap(cdd->qmgr_mem); + kfree(cdd); + return 0; +} + +static struct platform_driver cpp41_dma_driver = { + .probe = cppi41_dma_probe, + .remove = cppi41_dma_remove, + .driver = { + .name = "cppi41-dma-engine", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(cppi41_dma_ids), + }, +}; + +module_platform_driver(cpp41_dma_driver); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sebastian Andrzej Siewior "); diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index b7257ae038fd..04658d7666e9 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -129,6 +129,10 @@ config USB_TI_CPPI_DMA help Enable DMA transfers when TI CPPI DMA is available. +config USB_TI_CPPI41_DMA + bool 'TI CPPI 4.1 (AM335x)' + depends on ARCH_OMAP + config USB_TUSB_OMAP_DMA bool 'TUSB 6010' depends on USB_MUSB_TUSB6010 diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 52f552c1ba2b..c5ea5c6dc169 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -32,3 +32,4 @@ musb_hdrc-$(CONFIG_USB_INVENTRA_DMA) += musbhsdma.o musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA) += cppi_dma.o musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA) += tusb6010_omap.o musb_hdrc-$(CONFIG_USB_UX500_DMA) += ux500_dma.o +musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA) += musb_cppi41.o diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c new file mode 100644 index 000000000000..a74259ea0306 --- /dev/null +++ b/drivers/usb/musb/musb_cppi41.c @@ -0,0 +1,552 @@ +#include +#include +#include +#include +#include +#include + +#include "musb_core.h" + +#define RNDIS_REG(x) (0x80 + ((x - 1) * 4)) + +#define EP_MODE_AUTOREG_NONE 0 +#define EP_MODE_AUTOREG_ALL_NEOP 1 +#define EP_MODE_AUTOREG_ALWAYS 3 + +#define EP_MODE_DMA_TRANSPARENT 0 +#define EP_MODE_DMA_RNDIS 1 +#define EP_MODE_DMA_GEN_RNDIS 3 + +#define USB_CTRL_TX_MODE 0x70 +#define USB_CTRL_RX_MODE 0x74 +#define USB_CTRL_AUTOREQ 0xd0 +#define USB_TDOWN 0xd8 + +struct cppi41_dma_channel { + struct dma_channel channel; + struct cppi41_dma_controller *controller; + struct musb_hw_ep *hw_ep; + struct dma_chan *dc; + dma_cookie_t cookie; + u8 port_num; + u8 is_tx; + u8 is_allocated; + u8 usb_toggle; + + dma_addr_t buf_addr; + u32 total_len; + u32 prog_len; + u32 transferred; + u32 packet_sz; +}; + +#define MUSB_DMA_NUM_CHANNELS 15 + +struct cppi41_dma_controller { + struct dma_controller controller; + struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS]; + struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS]; + struct musb *musb; + u32 rx_mode; + u32 tx_mode; + u32 auto_req; +}; + +static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel) +{ + u16 csr; + u8 toggle; + + if (cppi41_channel->is_tx) + return; + if (!is_host_active(cppi41_channel->controller->musb)) + return; + + csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); + toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; + + cppi41_channel->usb_toggle = toggle; +} + +static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) +{ + u16 csr; + u8 toggle; + + if (cppi41_channel->is_tx) + return; + if (!is_host_active(cppi41_channel->controller->musb)) + return; + + csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); + toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0; + + /* + * AM335x Advisory 1.0.13: Due to internal synchronisation error the + * data toggle may reset from DATA1 to DATA0 during receiving data from + * more than one endpoint. + */ + if (!toggle && toggle == cppi41_channel->usb_toggle) { + csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE; + musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr); + dev_dbg(cppi41_channel->controller->musb->controller, + "Restoring DATA1 toggle.\n"); + } + + cppi41_channel->usb_toggle = toggle; +} + +static void cppi41_dma_callback(void *private_data) +{ + struct dma_channel *channel = private_data; + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + struct musb *musb = hw_ep->musb; + unsigned long flags; + struct dma_tx_state txstate; + u32 transferred; + + spin_lock_irqsave(&musb->lock, flags); + + dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, + &txstate); + transferred = cppi41_channel->prog_len - txstate.residue; + cppi41_channel->transferred += transferred; + + dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", + hw_ep->epnum, cppi41_channel->transferred, + cppi41_channel->total_len); + + update_rx_toggle(cppi41_channel); + + if (cppi41_channel->transferred == cppi41_channel->total_len || + transferred < cppi41_channel->packet_sz) { + + /* done, complete */ + cppi41_channel->channel.actual_len = + cppi41_channel->transferred; + cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; + musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx); + } else { + /* next iteration, reload */ + struct dma_chan *dc = cppi41_channel->dc; + struct dma_async_tx_descriptor *dma_desc; + enum dma_transfer_direction direction; + u16 csr; + u32 remain_bytes; + void __iomem *epio = cppi41_channel->hw_ep->regs; + + cppi41_channel->buf_addr += cppi41_channel->packet_sz; + + remain_bytes = cppi41_channel->total_len; + remain_bytes -= cppi41_channel->transferred; + remain_bytes = min(remain_bytes, cppi41_channel->packet_sz); + cppi41_channel->prog_len = remain_bytes; + + direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV + : DMA_DEV_TO_MEM; + dma_desc = dmaengine_prep_slave_single(dc, + cppi41_channel->buf_addr, + remain_bytes, + direction, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (WARN_ON(!dma_desc)) + return; + + dma_desc->callback = cppi41_dma_callback; + dma_desc->callback_param = channel; + cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); + dma_async_issue_pending(dc); + + if (!cppi41_channel->is_tx) { + csr = musb_readw(epio, MUSB_RXCSR); + csr |= MUSB_RXCSR_H_REQPKT; + musb_writew(epio, MUSB_RXCSR, csr); + } + } + spin_unlock_irqrestore(&musb->lock, flags); +} + +static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old) +{ + unsigned shift; + + shift = (ep - 1) * 2; + old &= ~(3 << shift); + old |= mode << shift; + return old; +} + +static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, + unsigned mode) +{ + struct cppi41_dma_controller *controller = cppi41_channel->controller; + u32 port; + u32 new_mode; + u32 old_mode; + + if (cppi41_channel->is_tx) + old_mode = controller->tx_mode; + else + old_mode = controller->rx_mode; + port = cppi41_channel->port_num; + new_mode = update_ep_mode(port, mode, old_mode); + + if (new_mode == old_mode) + return; + if (cppi41_channel->is_tx) { + controller->tx_mode = new_mode; + musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE, + new_mode); + } else { + controller->rx_mode = new_mode; + musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE, + new_mode); + } +} + +static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel, + unsigned mode) +{ + struct cppi41_dma_controller *controller = cppi41_channel->controller; + u32 port; + u32 new_mode; + u32 old_mode; + + old_mode = controller->auto_req; + port = cppi41_channel->port_num; + new_mode = update_ep_mode(port, mode, old_mode); + + if (new_mode == old_mode) + return; + controller->auto_req = new_mode; + musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode); +} + +static bool cppi41_configure_channel(struct dma_channel *channel, + u16 packet_sz, u8 mode, + dma_addr_t dma_addr, u32 len) +{ + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct dma_chan *dc = cppi41_channel->dc; + struct dma_async_tx_descriptor *dma_desc; + enum dma_transfer_direction direction; + struct musb *musb = cppi41_channel->controller->musb; + unsigned use_gen_rndis = 0; + + dev_dbg(musb->controller, + "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n", + cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num), + packet_sz, mode, (unsigned long long) dma_addr, + len, cppi41_channel->is_tx); + + cppi41_channel->buf_addr = dma_addr; + cppi41_channel->total_len = len; + cppi41_channel->transferred = 0; + cppi41_channel->packet_sz = packet_sz; + + /* + * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more + * than max packet size at a time. + */ + if (cppi41_channel->is_tx) + use_gen_rndis = 1; + + if (use_gen_rndis) { + /* RNDIS mode */ + if (len > packet_sz) { + musb_writel(musb->ctrl_base, + RNDIS_REG(cppi41_channel->port_num), len); + /* gen rndis */ + cppi41_set_dma_mode(cppi41_channel, + EP_MODE_DMA_GEN_RNDIS); + + /* auto req */ + cppi41_set_autoreq_mode(cppi41_channel, + EP_MODE_AUTOREG_ALL_NEOP); + } else { + musb_writel(musb->ctrl_base, + RNDIS_REG(cppi41_channel->port_num), 0); + cppi41_set_dma_mode(cppi41_channel, + EP_MODE_DMA_TRANSPARENT); + cppi41_set_autoreq_mode(cppi41_channel, + EP_MODE_AUTOREG_NONE); + } + } else { + /* fallback mode */ + cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT); + cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE); + len = min_t(u32, packet_sz, len); + } + cppi41_channel->prog_len = len; + direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!dma_desc) + return false; + + dma_desc->callback = cppi41_dma_callback; + dma_desc->callback_param = channel; + cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); + + save_rx_toggle(cppi41_channel); + dma_async_issue_pending(dc); + return true; +} + +static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c, + struct musb_hw_ep *hw_ep, u8 is_tx) +{ + struct cppi41_dma_controller *controller = container_of(c, + struct cppi41_dma_controller, controller); + struct cppi41_dma_channel *cppi41_channel = NULL; + u8 ch_num = hw_ep->epnum - 1; + + if (ch_num >= MUSB_DMA_NUM_CHANNELS) + return NULL; + + if (is_tx) + cppi41_channel = &controller->tx_channel[ch_num]; + else + cppi41_channel = &controller->rx_channel[ch_num]; + + if (!cppi41_channel->dc) + return NULL; + + if (cppi41_channel->is_allocated) + return NULL; + + cppi41_channel->hw_ep = hw_ep; + cppi41_channel->is_allocated = 1; + + return &cppi41_channel->channel; +} + +static void cppi41_dma_channel_release(struct dma_channel *channel) +{ + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + + if (cppi41_channel->is_allocated) { + cppi41_channel->is_allocated = 0; + channel->status = MUSB_DMA_STATUS_FREE; + channel->actual_len = 0; + } +} + +static int cppi41_dma_channel_program(struct dma_channel *channel, + u16 packet_sz, u8 mode, + dma_addr_t dma_addr, u32 len) +{ + int ret; + + BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || + channel->status == MUSB_DMA_STATUS_BUSY); + + channel->status = MUSB_DMA_STATUS_BUSY; + channel->actual_len = 0; + ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len); + if (!ret) + channel->status = MUSB_DMA_STATUS_FREE; + + return ret; +} + +static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, + void *buf, u32 length) +{ + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct cppi41_dma_controller *controller = cppi41_channel->controller; + struct musb *musb = controller->musb; + + if (is_host_active(musb)) { + WARN_ON(1); + return 1; + } + return 0; +} + +static int cppi41_dma_channel_abort(struct dma_channel *channel) +{ + struct cppi41_dma_channel *cppi41_channel = channel->private_data; + struct cppi41_dma_controller *controller = cppi41_channel->controller; + struct musb *musb = controller->musb; + void __iomem *epio = cppi41_channel->hw_ep->regs; + int tdbit; + int ret; + unsigned is_tx; + u16 csr; + + is_tx = cppi41_channel->is_tx; + dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n", + cppi41_channel->port_num, is_tx); + + if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) + return 0; + + if (is_tx) { + csr = musb_readw(epio, MUSB_TXCSR); + csr &= ~MUSB_TXCSR_DMAENAB; + musb_writew(epio, MUSB_TXCSR, csr); + } else { + csr = musb_readw(epio, MUSB_RXCSR); + csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB); + musb_writew(epio, MUSB_RXCSR, csr); + + csr = musb_readw(epio, MUSB_RXCSR); + if (csr & MUSB_RXCSR_RXPKTRDY) { + csr |= MUSB_RXCSR_FLUSHFIFO; + musb_writew(epio, MUSB_RXCSR, csr); + musb_writew(epio, MUSB_RXCSR, csr); + } + } + + tdbit = 1 << cppi41_channel->port_num; + if (is_tx) + tdbit <<= 16; + + do { + musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); + ret = dmaengine_terminate_all(cppi41_channel->dc); + } while (ret == -EAGAIN); + + musb_writel(musb->ctrl_base, USB_TDOWN, tdbit); + + if (is_tx) { + csr = musb_readw(epio, MUSB_TXCSR); + if (csr & MUSB_TXCSR_TXPKTRDY) { + csr |= MUSB_TXCSR_FLUSHFIFO; + musb_writew(epio, MUSB_TXCSR, csr); + } + } + + cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE; + return 0; +} + +static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl) +{ + struct dma_chan *dc; + int i; + + for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) { + dc = ctrl->tx_channel[i].dc; + if (dc) + dma_release_channel(dc); + dc = ctrl->rx_channel[i].dc; + if (dc) + dma_release_channel(dc); + } +} + +static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller) +{ + cppi41_release_all_dma_chans(controller); +} + +static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) +{ + struct musb *musb = controller->musb; + struct device *dev = musb->controller; + struct device_node *np = dev->of_node; + struct cppi41_dma_channel *cppi41_channel; + int count; + int i; + int ret; + + count = of_property_count_strings(np, "dma-names"); + if (count < 0) + return count; + + for (i = 0; i < count; i++) { + struct dma_chan *dc; + struct dma_channel *musb_dma; + const char *str; + unsigned is_tx; + unsigned int port; + + ret = of_property_read_string_index(np, "dma-names", i, &str); + if (ret) + goto err; + if (!strncmp(str, "tx", 2)) + is_tx = 1; + else if (!strncmp(str, "rx", 2)) + is_tx = 0; + else { + dev_err(dev, "Wrong dmatype %s\n", str); + goto err; + } + ret = kstrtouint(str + 2, 0, &port); + if (ret) + goto err; + + if (port > MUSB_DMA_NUM_CHANNELS || !port) + goto err; + if (is_tx) + cppi41_channel = &controller->tx_channel[port - 1]; + else + cppi41_channel = &controller->rx_channel[port - 1]; + + cppi41_channel->controller = controller; + cppi41_channel->port_num = port; + cppi41_channel->is_tx = is_tx; + + musb_dma = &cppi41_channel->channel; + musb_dma->private_data = cppi41_channel; + musb_dma->status = MUSB_DMA_STATUS_FREE; + musb_dma->max_len = SZ_4M; + + dc = dma_request_slave_channel(dev, str); + if (!dc) { + dev_err(dev, "Falied to request %s.\n", str); + goto err; + } + cppi41_channel->dc = dc; + } + return 0; +err: + cppi41_release_all_dma_chans(controller); + return -EINVAL; +} + +void dma_controller_destroy(struct dma_controller *c) +{ + struct cppi41_dma_controller *controller = container_of(c, + struct cppi41_dma_controller, controller); + + cppi41_dma_controller_stop(controller); + kfree(controller); +} + +struct dma_controller *dma_controller_create(struct musb *musb, + void __iomem *base) +{ + struct cppi41_dma_controller *controller; + int ret; + + if (!musb->controller->of_node) { + dev_err(musb->controller, "Need DT for the DMA engine.\n"); + return NULL; + } + + controller = kzalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) + goto kzalloc_fail; + + controller->musb = musb; + + controller->controller.channel_alloc = cppi41_dma_channel_allocate; + controller->controller.channel_release = cppi41_dma_channel_release; + controller->controller.channel_program = cppi41_dma_channel_program; + controller->controller.channel_abort = cppi41_dma_channel_abort; + controller->controller.is_compatible = cppi41_is_compatible; + + ret = cppi41_dma_controller_start(controller); + if (ret) + goto plat_get_fail; + return &controller->controller; + +plat_get_fail: + kfree(controller); +kzalloc_fail: + return NULL; +} diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index c8e67fde2156..1345a4ff041a 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -68,7 +68,7 @@ struct musb_hw_ep; #define is_dma_capable() (1) #endif -#ifdef CONFIG_USB_TI_CPPI_DMA +#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA) #define is_cppi_enabled() 1 #else #define is_cppi_enabled() 0 From ebe864a6cb8e087ede047fa1fa6b6d06fcb9a9e4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 29 Apr 2013 22:18:01 +0200 Subject: [PATCH 090/101] usb: gadget: uvc: Fix error handling in uvc_queue_buffer() The conversion to videobuf2 failed to check the return value of vb2_qbuf(). Fix it. Cc: stable@vger.kernel.org Reported-by: Michael Grzeschik Signed-off-by: Laurent Pinchart Tested-By: Michael Grzeschik Signed-off-by: Felipe Balbi --- drivers/usb/gadget/uvc_queue.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index e6170478ea9f..0bb5d50075de 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -193,12 +193,16 @@ static int uvc_queue_buffer(struct uvc_video_queue *queue, mutex_lock(&queue->mutex); ret = vb2_qbuf(&queue->queue, buf); + if (ret < 0) + goto done; + spin_lock_irqsave(&queue->irqlock, flags); ret = (queue->flags & UVC_QUEUE_PAUSED) != 0; queue->flags &= ~UVC_QUEUE_PAUSED; spin_unlock_irqrestore(&queue->irqlock, flags); - mutex_unlock(&queue->mutex); +done: + mutex_unlock(&queue->mutex); return ret; } From 23381db7cedc26f87a37746ccf7c658d977e467e Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 9 Aug 2013 10:40:32 -0500 Subject: [PATCH 091/101] usb: dwc3: core: clarify usb-phy array binding The binding spec wasn't clear that the order of the phandles in the usb-phy array has meaning. Clarify this point in the binding that it should be . Signed-off-by: Kumar Gala Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 3a64e20f6c32..e807635f9e1c 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -6,7 +6,9 @@ Required properties: - compatible: must be "snps,dwc3" - reg : Address and length of the register set for the device - interrupts: Interrupts used by the dwc3 controller. - - usb-phy : array of phandle for the PHY device + - usb-phy : array of phandle for the PHY device. The first element + in the array is expected to be a handle to the USB2/HS PHY and + the second element is expected to be a handle to the USB3/SS PHY Optional properties: - tx-fifo-resize: determines if the FIFO *has* to be reallocated. From 2cdcec4fedd6a5ee77bd551e6be7505f2230cd43 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 12 Aug 2013 16:06:49 +0300 Subject: [PATCH 092/101] usb: host: add has_tdi_phy_lpm capability bit The has_hostpc capability bit indicates that the host controller has the HOSTPC register extensions, but at the same time enables clock disabling power saving features with the PHY Low Power Clock Disable (PHCD) bit. However, some host controllers have the HOSTPC extensions but don't support the low-power feature, so the PHCD bit must not be set on those controllers. Add a separate capability bit for the low-power feature instead, and change all existing users of has_hostpc to use this new capability bit. The idea for this commit is taken from an old 2012 commit that never got merged ("disociate chipidea PHY low power suspend control from hostpc") Inspired-by: Matthieu CASTET Signed-off-by: Tuomas Tynkkynen Acked-by: Alan Stern Tested-by: Stephen Warren Reviewed-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/chipidea/host.c | 1 + drivers/usb/host/ehci-hub.c | 14 +++++++------- drivers/usb/host/ehci.h | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 40d0fda4f66c..9b3aaf132bc3 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -63,6 +63,7 @@ static int host_start(struct ci_hdrc *ci) ehci = hcd_to_ehci(hcd); ehci->caps = ci->hw_bank.cap; ehci->has_hostpc = ci->hw_bank.lpm; + ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; ret = usb_add_hcd(hcd, 0, 0); if (ret) diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 6dce37555c4f..6280bd269e12 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -183,7 +183,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, spin_lock_irq(&ehci->lock); /* clear phy low-power mode before changing wakeup flags */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -217,7 +217,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, } /* enter phy low-power mode again */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -309,7 +309,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } } - if (changed && ehci->has_hostpc) { + if (changed && ehci->has_tdi_phy_lpm) { spin_unlock_irq(&ehci->lock); msleep(5); /* 5 ms for HCD to enter low-power mode */ spin_lock_irq(&ehci->lock); @@ -435,7 +435,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) goto shutdown; /* clear phy low-power mode before resume */ - if (ehci->bus_suspended && ehci->has_hostpc) { + if (ehci->bus_suspended && ehci->has_tdi_phy_lpm) { i = HCS_N_PORTS(ehci->hcs_params); while (i--) { if (test_bit(i, &ehci->bus_suspended)) { @@ -788,7 +788,7 @@ static int ehci_hub_control ( goto error; /* clear phy low-power mode before resume */ - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { temp1 = ehci_readl(ehci, hostpc_reg); ehci_writel(ehci, temp1 & ~HOSTPC_PHCD, hostpc_reg); @@ -1032,12 +1032,12 @@ static int ehci_hub_control ( /* After above check the port must be connected. * Set appropriate bit thus could put phy into low power - * mode if we have hostpc feature + * mode if we have tdi_phy_lpm feature */ temp &= ~PORT_WKCONN_E; temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); - if (ehci->has_hostpc) { + if (ehci->has_tdi_phy_lpm) { spin_unlock_irqrestore(&ehci->lock, flags); msleep(5);/* 5ms for HCD enter low pwr mode */ spin_lock_irqsave(&ehci->lock, flags); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 64f9a08e959c..d034d94a7fea 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -210,6 +210,7 @@ struct ehci_hcd { /* one per controller */ #define OHCI_HCCTRL_LEN 0x4 __hc32 *ohci_hcctrl_reg; unsigned has_hostpc:1; + unsigned has_tdi_phy_lpm:1; unsigned has_ppcd:1; /* support per-port change bits */ u8 sbrn; /* packed release number */ From f5833a0bde5d7795b19f8a881278e5506ab5764b Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 12 Aug 2013 16:06:50 +0300 Subject: [PATCH 093/101] usb: phy: tegra: Fix wrong PHY parameters Some of the PHY parameters are not set according to the TRMs: - UTMIP_FS_PREABMLE_J should be set, not cleared - UTMIP_XCVR_LSBIAS_SEL should be cleared, not set - UTMIP_PD_CHRG should be set in host mode and cleared in device mode - UTMIP_XCVR_SETUP is a two-part field; the upper bits were not set properly Signed-off-by: Tuomas Tynkkynen Tested-by: Stephen Warren Reviewed-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 49fa2da56c4b..ebbf85fdfc7f 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -86,11 +86,13 @@ #define UTMIP_XCVR_CFG0 0x808 #define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) +#define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22) #define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) #define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) #define UTMIP_FORCE_PD_POWERDOWN (1 << 14) #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) +#define UTMIP_XCVR_LSBIAS_SEL (1 << 21) #define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) #define UTMIP_BIAS_CFG0 0x80c @@ -342,7 +344,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) } val = readl(base + UTMIP_TX_CFG0); - val &= ~UTMIP_FS_PREABMLE_J; + val |= UTMIP_FS_PREABMLE_J; writel(val, base + UTMIP_TX_CFG0); val = readl(base + UTMIP_HSRX_CFG0); @@ -381,16 +383,26 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val = readl(base + USB_SUSP_CTRL); val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); writel(val, base + USB_SUSP_CTRL); + + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val &= ~UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); + } else { + val = readl(base + UTMIP_BAT_CHRG_CFG0); + val |= UTMIP_PD_CHRG; + writel(val, base + UTMIP_BAT_CHRG_CFG0); } utmip_pad_power_on(phy); val = readl(base + UTMIP_XCVR_CFG0); val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | - UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) | + UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL | + UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) | UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0)); val |= UTMIP_XCVR_SETUP(config->xcvr_setup); + val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup); val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); writel(val, base + UTMIP_XCVR_CFG0); @@ -401,10 +413,6 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj); writel(val, base + UTMIP_XCVR_CFG1); - val = readl(base + UTMIP_BAT_CHRG_CFG0); - val &= ~UTMIP_PD_CHRG; - writel(val, base + UTMIP_BAT_CHRG_CFG0); - val = readl(base + UTMIP_BIAS_CFG1); val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); val |= UTMIP_BIAS_PDTRK_COUNT(0x5); From 3e635202ce40e4d7ff3fafc18db70c5d28cc6622 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 12 Aug 2013 16:06:51 +0300 Subject: [PATCH 094/101] usb: phy: tegra: Tegra30 support The Tegra30 USB PHY is a bit different than the Tegra20 PHY: - The EHCI controller supports the HOSTPC register extension, and some of the fields that the PHY needs to modify (PHCD and PTS) have moved to the new HOSTPC register. - Some of the UTMI PLL configuration registers have moved from the USB register space to the Clock-And-Reset controller space. In Tegra30 the clock driver is responsible for configuring the UTMI PLL. - The USBMODE register must be explicitly written to enter host mode. - Certain PHY parameters need to be programmed for optimal signal quality. Support for this will be added in the next patch. The new tegra_phy_soc_config structure is added to describe the differences between the SoCs. Signed-off-by: Tuomas Tynkkynen Tested-by: Stephen Warren Reviewed-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 119 +++++++++++++++++++++++------- include/linux/usb/tegra_usb_phy.h | 19 +++++ 2 files changed, 111 insertions(+), 27 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index ebbf85fdfc7f..1ad184af7601 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -39,11 +40,16 @@ #define ULPI_VIEWPORT 0x170 -/* PORTSC registers */ +/* PORTSC PTS/PHCD bits, Tegra20 only */ #define TEGRA_USB_PORTSC1 0x184 #define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) #define TEGRA_USB_PORTSC1_PHCD (1 << 23) +/* HOSTPC1 PTS/PHCD bits, Tegra30 and above */ +#define TEGRA_USB_HOSTPC1_DEVLC 0x1b4 +#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) +#define TEGRA_USB_HOSTPC1_DEVLC_PHCD (1 << 22) + /* Bits of PORTSC1, which will get cleared by writing 1 into them */ #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) @@ -141,6 +147,12 @@ #define UTMIP_BIAS_CFG1 0x83c #define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) +/* For Tegra30 and above only, the address is different in Tegra20 */ +#define USB_USBMODE 0x1f8 +#define USB_USBMODE_MASK (3 << 0) +#define USB_USBMODE_HOST (3 << 0) +#define USB_USBMODE_DEVICE (2 << 0) + static DEFINE_SPINLOCK(utmip_pad_lock); static int utmip_pad_count; @@ -193,10 +205,17 @@ static void set_pts(struct tegra_usb_phy *phy, u8 pts_val) void __iomem *base = phy->regs; unsigned long val; - val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; - val &= ~TEGRA_USB_PORTSC1_PTS(3); - val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3); - writel(val, base + TEGRA_USB_PORTSC1); + if (phy->soc_config->has_hostpc) { + val = readl(base + TEGRA_USB_HOSTPC1_DEVLC); + val &= ~TEGRA_USB_HOSTPC1_DEVLC_PTS(~0); + val |= TEGRA_USB_HOSTPC1_DEVLC_PTS(pts_val); + writel(val, base + TEGRA_USB_HOSTPC1_DEVLC); + } else { + val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; + val &= ~TEGRA_USB_PORTSC1_PTS(~0); + val |= TEGRA_USB_PORTSC1_PTS(pts_val); + writel(val, base + TEGRA_USB_PORTSC1); + } } static void set_phcd(struct tegra_usb_phy *phy, bool enable) @@ -204,12 +223,21 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable) void __iomem *base = phy->regs; unsigned long val; - val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; - if (enable) - val |= TEGRA_USB_PORTSC1_PHCD; - else - val &= ~TEGRA_USB_PORTSC1_PHCD; - writel(val, base + TEGRA_USB_PORTSC1); + if (phy->soc_config->has_hostpc) { + val = readl(base + TEGRA_USB_HOSTPC1_DEVLC); + if (enable) + val |= TEGRA_USB_HOSTPC1_DEVLC_PHCD; + else + val &= ~TEGRA_USB_HOSTPC1_DEVLC_PHCD; + writel(val, base + TEGRA_USB_HOSTPC1_DEVLC); + } else { + val = readl(base + TEGRA_USB_PORTSC1) & ~PORT_RWC_BITS; + if (enable) + val |= TEGRA_USB_PORTSC1_PHCD; + else + val &= ~TEGRA_USB_PORTSC1_PHCD; + writel(val, base + TEGRA_USB_PORTSC1); + } } static int utmip_pad_open(struct tegra_usb_phy *phy) @@ -367,17 +395,21 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; writel(val, base + UTMIP_MISC_CFG0); - val = readl(base + UTMIP_MISC_CFG1); - val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0)); - val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) | - UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count); - writel(val, base + UTMIP_MISC_CFG1); + if (!phy->soc_config->utmi_pll_config_in_car_module) { + val = readl(base + UTMIP_MISC_CFG1); + val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | + UTMIP_PLLU_STABLE_COUNT(~0)); + val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) | + UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count); + writel(val, base + UTMIP_MISC_CFG1); - val = readl(base + UTMIP_PLL_CFG1); - val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); - val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) | - UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); - writel(val, base + UTMIP_PLL_CFG1); + val = readl(base + UTMIP_PLL_CFG1); + val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | + UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); + val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) | + UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); + writel(val, base + UTMIP_PLL_CFG1); + } if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl(base + USB_SUSP_CTRL); @@ -448,6 +480,16 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) utmi_phy_clk_enable(phy); + if (phy->soc_config->requires_usbmode_setup) { + val = readl(base + USB_USBMODE); + val &= ~USB_USBMODE_MASK; + if (phy->mode == USB_DR_MODE_HOST) + val |= USB_USBMODE_HOST; + else + val |= USB_USBMODE_DEVICE; + writel(val, base + USB_USBMODE); + } + if (!phy->is_legacy_phy) set_pts(phy, 0); @@ -864,8 +906,30 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, return 0; } +static const struct tegra_phy_soc_config tegra20_soc_config = { + .utmi_pll_config_in_car_module = false, + .has_hostpc = false, + .requires_usbmode_setup = false, + .requires_extra_tuning_parameters = false, +}; + +static const struct tegra_phy_soc_config tegra30_soc_config = { + .utmi_pll_config_in_car_module = true, + .has_hostpc = true, + .requires_usbmode_setup = true, + .requires_extra_tuning_parameters = true, +}; + +static struct of_device_id tegra_usb_phy_id_table[] = { + { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config }, + { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table); + static int tegra_usb_phy_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct resource *res; struct tegra_usb_phy *tegra_phy = NULL; struct device_node *np = pdev->dev.of_node; @@ -878,6 +942,13 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return -ENOMEM; } + match = of_match_device(tegra_usb_phy_id_table, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + tegra_phy->soc_config = match->data; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Failed to get I/O memory\n"); @@ -968,12 +1039,6 @@ static int tegra_usb_phy_remove(struct platform_device *pdev) return 0; } -static struct of_device_id tegra_usb_phy_id_table[] = { - { .compatible = "nvidia,tegra20-usb-phy", }, - { }, -}; -MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table); - static struct platform_driver tegra_usb_phy_driver = { .probe = tegra_usb_phy_probe, .remove = tegra_usb_phy_remove, diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d3db274610a1..d3a63c354db9 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -18,6 +18,24 @@ #include #include +/* + * utmi_pll_config_in_car_module: true if the UTMI PLL configuration registers + * should be set up by clk-tegra, false if by the PHY code + * has_hostpc: true if the USB controller has the HOSTPC extension, which + * changes the location of the PHCD and PTS fields + * requires_usbmode_setup: true if the USBMODE register needs to be set to + * enter host mode + * requires_extra_tuning_parameters: true if xcvr_hsslew, hssquelch_level + * and hsdiscon_level should be set for adequate signal quality + */ + +struct tegra_phy_soc_config { + bool utmi_pll_config_in_car_module; + bool has_hostpc; + bool requires_usbmode_setup; + bool requires_extra_tuning_parameters; +}; + struct tegra_utmip_config { u8 hssync_start_delay; u8 elastic_limit; @@ -47,6 +65,7 @@ struct tegra_usb_phy { struct regulator *vbus; enum usb_dr_mode mode; void *config; + const struct tegra_phy_soc_config *soc_config; struct usb_phy *ulpi; struct usb_phy u_phy; bool is_legacy_phy; From 91e66700029d71d2938e1341172331c58b6bd8b3 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 12 Aug 2013 16:06:52 +0300 Subject: [PATCH 095/101] Documentation: New DT parameters for tegra30-usb-phy Document the new device tree parameters for Tegra30 USB PHY. Signed-off-by: Tuomas Tynkkynen Tested-by: Stephen Warren Reviewed-by: Stephen Warren Signed-off-by: Felipe Balbi --- .../bindings/usb/nvidia,tegra20-usb-phy.txt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt index 4c8ade8b340b..ba797d3e6326 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -3,7 +3,7 @@ Tegra SOC USB PHY The device node for Tegra SOC USB PHY: Required properties : - - compatible : Should be "nvidia,tegra20-usb-phy". + - compatible : Should be "nvidia,tegra-usb-phy". - reg : Defines the following set of registers, in the order listed: - The PHY's own register set. Always present. @@ -24,17 +24,26 @@ Required properties : Required properties for phy_type == ulpi: - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. -Required PHY timing params for utmi phy: +Required PHY timing params for utmi phy, for all chips: - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before start of sync launches RxActive - nvidia,elastic-limit : Variable FIFO Depth of elastic input store - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait before declare IDLE. - nvidia,term-range-adj : Range adjusment on terminations - - nvidia,xcvr-setup : HS driver output control + - Either one of the following for HS driver output control: + - nvidia,xcvr-setup : integer, uses the provided value. + - nvidia,xcvr-setup-use-fuses : boolean, indicates that the value is read + from the on-chip fuses + If both are provided, nvidia,xcvr-setup-use-fuses takes precedence. - nvidia,xcvr-lsfslew : LS falling slew rate control. - nvidia,xcvr-lsrslew : LS rising slew rate control. +Required PHY timing params for utmi phy, only on Tegra30 and above: + - nvidia,xcvr-hsslew : HS slew rate control. + - nvidia,hssquelch-level : HS squelch detector level. + - nvidia,hsdiscon-level : HS disconnect detector level. + Optional properties: - nvidia,has-legacy-mode : boolean indicates whether this controller can operate in legacy mode (as APX 2500 / 2600). In legacy mode some From e497a24d8e18af510879b2ae059ee20a4a58eae8 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 12 Aug 2013 16:06:53 +0300 Subject: [PATCH 096/101] usb: phy: tegra: Program new PHY parameters The Tegra30 TRM recommends configuration of certain PHY parameters for optimal quality. Program the following registers based on device tree parameters: - UTMIP_XCVR_HSSLEW: HS slew rate control. - UTMIP_HSSQUELCH_LEVEL: HS squelch detector level - UTMIP_HSDISCON_LEVEL: HS disconnect detector level. These registers exist in Tegra20, but programming them hasn't been necessary, so these parameters won't be set on Tegra20 to keep the device trees backward compatible. Additionally, the UTMIP_XCVR_SETUP parameter can be set from fuses instead of a software-programmed value, as the optimal value can vary between invidual boards. The boolean property nvidia,xcvr-setup-use-fuses can be used to enable this behaviour. Signed-off-by: Tuomas Tynkkynen Tested-by: Stephen Warren Reviewed-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 81 ++++++++++++++++++++++++------- include/linux/usb/tegra_usb_phy.h | 4 ++ 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 1ad184af7601..3bfb3d1957c1 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -99,11 +99,15 @@ #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) #define UTMIP_XCVR_LSBIAS_SEL (1 << 21) -#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) +#define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4) +#define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25) #define UTMIP_BIAS_CFG0 0x80c #define UTMIP_OTGPD (1 << 11) #define UTMIP_BIASPD (1 << 10) +#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) +#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) +#define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24) #define UTMIP_HSRX_CFG0 0x810 #define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) @@ -255,6 +259,7 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy) { unsigned long val, flags; void __iomem *base = phy->pad_regs; + struct tegra_utmip_config *config = phy->config; clk_prepare_enable(phy->pad_clk); @@ -263,6 +268,16 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy) if (utmip_pad_count++ == 0) { val = readl(base + UTMIP_BIAS_CFG0); val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); + + if (phy->soc_config->requires_extra_tuning_parameters) { + val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | + UTMIP_HSDISCON_LEVEL(~0) | + UTMIP_HSDISCON_LEVEL_MSB(~0)); + + val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level); + val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level); + val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level); + } writel(val, base + UTMIP_BIAS_CFG0); } @@ -431,12 +446,20 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL | UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) | - UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) | - UTMIP_XCVR_HSSLEW_MSB(~0)); - val |= UTMIP_XCVR_SETUP(config->xcvr_setup); - val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup); + UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0)); + + if (!config->xcvr_setup_use_fuses) { + val |= UTMIP_XCVR_SETUP(config->xcvr_setup); + val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup); + } val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); + + if (phy->soc_config->requires_extra_tuning_parameters) { + val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0)); + val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew); + val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew); + } writel(val, base + UTMIP_XCVR_CFG0); val = readl(base + UTMIP_XCVR_CFG1); @@ -450,14 +473,14 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val |= UTMIP_BIAS_PDTRK_COUNT(0x5); writel(val, base + UTMIP_BIAS_CFG1); - if (phy->is_legacy_phy) { - val = readl(base + UTMIP_SPARE_CFG0); - if (phy->mode == USB_DR_MODE_PERIPHERAL) - val &= ~FUSE_SETUP_SEL; - else - val |= FUSE_SETUP_SEL; - writel(val, base + UTMIP_SPARE_CFG0); - } else { + val = readl(base + UTMIP_SPARE_CFG0); + if (config->xcvr_setup_use_fuses) + val |= FUSE_SETUP_SEL; + else + val &= ~FUSE_SETUP_SEL; + writel(val, base + UTMIP_SPARE_CFG0); + + if (!phy->is_legacy_phy) { val = readl(base + USB_SUSP_CTRL); val |= UTMIP_PHY_ENABLE; writel(val, base + USB_SUSP_CTRL); @@ -888,11 +911,6 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, if (err < 0) return err; - err = read_utmi_param(pdev, "nvidia,xcvr-setup", - &config->xcvr_setup); - if (err < 0) - return err; - err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew", &config->xcvr_lsfslew); if (err < 0) @@ -903,6 +921,33 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, if (err < 0) return err; + if (tegra_phy->soc_config->requires_extra_tuning_parameters) { + err = read_utmi_param(pdev, "nvidia,xcvr-hsslew", + &config->xcvr_hsslew); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,hssquelch-level", + &config->hssquelch_level); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,hsdiscon-level", + &config->hsdiscon_level); + if (err < 0) + return err; + } + + config->xcvr_setup_use_fuses = of_property_read_bool( + pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses"); + + if (!config->xcvr_setup_use_fuses) { + err = read_utmi_param(pdev, "nvidia,xcvr-setup", + &config->xcvr_setup); + if (err < 0) + return err; + } + return 0; } diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d3a63c354db9..1de16c324ec8 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -41,9 +41,13 @@ struct tegra_utmip_config { u8 elastic_limit; u8 idle_wait_delay; u8 term_range_adj; + bool xcvr_setup_use_fuses; u8 xcvr_setup; u8 xcvr_lsfslew; u8 xcvr_lsrslew; + u8 xcvr_hsslew; + u8 hssquelch_level; + u8 hsdiscon_level; }; enum tegra_usb_phy_port_speed { From 327d8b424578254f0c1e71f83960bf8934063529 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 12 Aug 2013 16:06:54 +0300 Subject: [PATCH 097/101] usb: host: tegra: Tegra30 support The Tegra30 EHCI controller is mostly compatible with the Tegra20 controller, except Tegra30 includes the HOSTPC register extension. The has_hostpc capability bit must be set in the ehci_hcd structure if the controller has such extensions. The new tegra_ehci_soc_config structure is added to describe the differences between the SoCs. Signed-off-by: Tuomas Tynkkynen Tested-by: Stephen Warren Reviewed-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/host/ehci-tegra.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index db8031fd5c13..78fa76da3324 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,10 @@ static struct hc_driver __read_mostly tegra_ehci_hc_driver; +struct tegra_ehci_soc_config { + bool has_hostpc; +}; + static int (*orig_hub_control)(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); @@ -320,8 +325,24 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) free_dma_aligned_buffer(urb); } +static const struct tegra_ehci_soc_config tegra30_soc_config = { + .has_hostpc = true, +}; + +static const struct tegra_ehci_soc_config tegra20_soc_config = { + .has_hostpc = false, +}; + +static struct of_device_id tegra_ehci_of_match[] = { + { .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config }, + { .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config }, + { }, +}; + static int tegra_ehci_probe(struct platform_device *pdev) { + const struct of_device_id *match; + const struct tegra_ehci_soc_config *soc_config; struct resource *res; struct usb_hcd *hcd; struct ehci_hcd *ehci; @@ -330,6 +351,13 @@ static int tegra_ehci_probe(struct platform_device *pdev) int irq; struct usb_phy *u_phy; + match = of_match_device(tegra_ehci_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + soc_config = match->data; + /* Right now device-tree probed devices don't get dma_mask set. * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. @@ -391,6 +419,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto cleanup_clk_en; } ehci->caps = hcd->regs + 0x100; + ehci->has_hostpc = soc_config->has_hostpc; err = usb_phy_init(hcd->phy); if (err) { @@ -468,11 +497,6 @@ static void tegra_ehci_hcd_shutdown(struct platform_device *pdev) hcd->driver->shutdown(hcd); } -static struct of_device_id tegra_ehci_of_match[] = { - { .compatible = "nvidia,tegra20-ehci", }, - { }, -}; - static struct platform_driver tegra_ehci_driver = { .probe = tegra_ehci_probe, .remove = tegra_ehci_remove, From eff196ad4e6b10499d4c4e4a0bd4a7c8afb8455f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 12 Aug 2013 14:01:14 -0500 Subject: [PATCH 098/101] usb: musb: dsps: make it depend on OF_IRQ musb_dsps.c utilizes a symbol which is only available when CONFIG_OF_IRQ is set, so make it depend on that. Signed-off-by: Felipe Balbi --- drivers/usb/musb/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 04658d7666e9..c64ee09a7c0e 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -84,6 +84,7 @@ config USB_MUSB_AM35X config USB_MUSB_DSPS tristate "TI DSPS platforms" select USB_MUSB_AM335X_CHILD + depends on OF_IRQ config USB_MUSB_BLACKFIN tristate "Blackfin" From fc525751457e93783b1c85a0612735a598c8497f Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 13 Aug 2013 19:38:23 +0200 Subject: [PATCH 099/101] usb: musb: Use is_cppi_enabled() and tusb_dma_omap() instead of the ifdef This patch makes use of the two function is_cppi_enabled() and tusb_dma_omap() instead of the ifdef for the proper DMA implementation setup code. It basically shifts the code right by one indention level and adds a few line breaks once the chars are crossed. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 82 +++++++++++++++++----------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 96632f9e3eeb..4376f51f5ef1 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -357,47 +357,49 @@ static void txstate(struct musb *musb, struct musb_request *req) } } -#elif defined(CONFIG_USB_TI_CPPI_DMA) - /* program endpoint CSR first, then setup DMA */ - csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); - csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | - MUSB_TXCSR_MODE; - musb_writew(epio, MUSB_TXCSR, - (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) - | csr); - - /* ensure writebuffer is empty */ - csr = musb_readw(epio, MUSB_TXCSR); - - /* NOTE host side sets DMAENAB later than this; both are - * OK since the transfer dma glue (between CPPI and Mentor - * fifos) just tells CPPI it could start. Data only moves - * to the USB TX fifo when both fifos are ready. - */ - - /* "mode" is irrelevant here; handle terminating ZLPs like - * PIO does, since the hardware RNDIS mode seems unreliable - * except for the last-packet-is-already-short case. - */ - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - 0, - request->dma + request->actual, - request_size); - if (!use_dma) { - c->channel_release(musb_ep->dma); - musb_ep->dma = NULL; - csr &= ~MUSB_TXCSR_DMAENAB; - musb_writew(epio, MUSB_TXCSR, csr); - /* invariant: prequest->buf is non-null */ - } -#elif defined(CONFIG_USB_TUSB_OMAP_DMA) - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - request->zero, - request->dma + request->actual, - request_size); #endif + if (is_cppi_enabled()) { + /* program endpoint CSR first, then setup DMA */ + csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); + csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | + MUSB_TXCSR_MODE; + musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS & + ~MUSB_TXCSR_P_UNDERRUN) | csr); + + /* ensure writebuffer is empty */ + csr = musb_readw(epio, MUSB_TXCSR); + + /* + * NOTE host side sets DMAENAB later than this; both are + * OK since the transfer dma glue (between CPPI and + * Mentor fifos) just tells CPPI it could start. Data + * only moves to the USB TX fifo when both fifos are + * ready. + */ + /* + * "mode" is irrelevant here; handle terminating ZLPs + * like PIO does, since the hardware RNDIS mode seems + * unreliable except for the + * last-packet-is-already-short case. + */ + use_dma = use_dma && c->channel_program( + musb_ep->dma, musb_ep->packet_sz, + 0, + request->dma + request->actual, + request_size); + if (!use_dma) { + c->channel_release(musb_ep->dma); + musb_ep->dma = NULL; + csr &= ~MUSB_TXCSR_DMAENAB; + musb_writew(epio, MUSB_TXCSR, csr); + /* invariant: prequest->buf is non-null */ + } + } else if (tusb_dma_omap()) + use_dma = use_dma && c->channel_program( + musb_ep->dma, musb_ep->packet_sz, + request->zero, + request->dma + request->actual, + request_size); } #endif From 13266fea59f6f55e98d61e66707d784b9e947c84 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 13 Aug 2013 19:38:24 +0200 Subject: [PATCH 100/101] usb: musb: cppi41: Enable in device-TX mode Since the musb-gadget code now calls the dma engine properly it is possible to enable it for the TX path in device mode. AM335x Advisory 1.0.13 says that we may lose the toggle bit on multiple RX transfers. There is a workaround in host mode but none in device mode and therefore RX transfers are disabled. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_cppi41.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index a74259ea0306..e64701d15401 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -362,6 +362,9 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, WARN_ON(1); return 1; } + if (cppi41_channel->is_tx) + return 1; + /* AM335x Advisory 1.0.13. No workaround for device RX mode */ return 0; } From 8b841cb217fac676498de3dfe8fabe38b39cba4e Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 13 Aug 2013 10:57:08 +0200 Subject: [PATCH 101/101] usb: phy: am335x: include linux/err.h Stephen Rothwell reported that this driver does not compile on PowerPC due to this missing include. One could argue why this driver is enabled on PowerPC in the first place but it sure isn't wrong to include headers for used function instead of to rely that they sneak in. Reported-by: Stephen Rothwell Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x-control.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index 35494f1c33b6..759754521426 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -1,5 +1,6 @@ #include #include +#include #include #include