* [PATCH 0/9] musb_hdrc: Unify naming and rename common files @ 2007-08-20 9:10 Tony Lindgren 2007-08-20 9:10 ` [PATCH 1/9] musb_hdrc: Search and replace USB_INVENTRA_FIFO with USB_MUSB_DISABLE_DMA Tony Lindgren 2007-08-21 7:23 ` [PATCH 0/9] musb_hdrc: Unify naming and rename common files Tony Lindgren 0 siblings, 2 replies; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Hi all, Attached patch series replaces Inventra naming with musb, and renames the core musb files to start with musb_. Renaming the files unifies the file names, and groups them by type. This all should make it easier for people to locate the right piece of code within the driver. After applying the patch series, the musb directory has following files: $ ls cppi_dma.c musb_core.c musb_host.c omap2430.h cppi_dma.h musb_core.h musb_host.h tusb6010.c davinci.c musb_debug.h musb_host_virthub.c tusb6010.h davinci.h musb_dma.h musbhsdma.c tusb6010_omap.c Kconfig musb_gadget.c musb_procfs.c Makefile musb_gadget_ep0.c musb_regs.h musb_arch.h musb_gadget.h omap2430.c Tested on tusb. Regards, Tony ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/9] musb_hdrc: Search and replace USB_INVENTRA_FIFO with USB_MUSB_DISABLE_DMA 2007-08-20 9:10 [PATCH 0/9] musb_hdrc: Unify naming and rename common files Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 2007-08-20 9:10 ` [PATCH 2/9] musb_hdrc: Search and replace USB_INVENTRA_HCD_LOGGING with USB_MUSB_LOGLEVEL Tony Lindgren 2007-08-21 7:23 ` [PATCH 0/9] musb_hdrc: Unify naming and rename common files Tony Lindgren 1 sibling, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Search and replace USB_INVENTRA_FIFO with USB_MUSB_DISABLE_DMA Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/Kconfig | 8 ++++---- drivers/usb/musb/Makefile | 2 +- drivers/usb/musb/dma.h | 2 +- drivers/usb/musb/musb_gadget.c | 2 +- drivers/usb/musb/musb_procfs.c | 2 +- drivers/usb/musb/plat_uds.c | 12 ++++++------ 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index a9bcd7e..8e5430a 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -129,7 +129,7 @@ config USB_MUSB_HDRC_HCD default y -config USB_INVENTRA_FIFO +config USB_MUSB_DISABLE_DMA bool 'Disable DMA (always use PIO)' depends on USB_MUSB_HDRC default y if USB_TUSB6010 @@ -144,21 +144,21 @@ config USB_INVENTRA_FIFO config USB_INVENTRA_DMA bool - depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO + depends on USB_MUSB_HDRC && !USB_MUSB_DISABLE_DMA default ARCH_OMAP2430 || ARCH_OMAP343X help Enable DMA transfers using Mentor's engine. config USB_TI_CPPI_DMA bool - depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO + depends on USB_MUSB_HDRC && !USB_MUSB_DISABLE_DMA default ARCH_DAVINCI help Enable DMA transfers when TI CPPI DMA is available. config USB_TUSB_OMAP_DMA bool - depends on USB_MUSB_HDRC && !USB_INVENTRA_FIFO + depends on USB_MUSB_HDRC && !USB_MUSB_DISABLE_DMA depends on USB_TUSB6010 depends on ARCH_OMAP default y diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 535ba40..fbff415 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -31,7 +31,7 @@ endif # PIO (INVENTRA_FIFO), or DMA (several potential schemes). # though PIO is always there to back up DMA, and for ep0 -ifneq ($(CONFIG_USB_INVENTRA_FIFO),y) +ifneq ($(CONFIG_USB_MUSB_DISABLE_DMA),y) ifeq ($(CONFIG_USB_INVENTRA_DMA),y) musb_hdrc-objs += musbhsdma.o diff --git a/drivers/usb/musb/dma.h b/drivers/usb/musb/dma.h index 701d312..deef0c2 100644 --- a/drivers/usb/musb/dma.h +++ b/drivers/usb/musb/dma.h @@ -62,7 +62,7 @@ struct musb_hw_ep; #define DMA_ADDR_INVALID (~(dma_addr_t)0) -#ifndef CONFIG_USB_INVENTRA_FIFO +#ifndef CONFIG_USB_MUSB_DISABLE_DMA #define is_dma_capable() (1) #else #define is_dma_capable() (0) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 88757ce..5a4227e 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -291,7 +291,7 @@ static void txstate(struct musb *musb, struct musb_request *req) epnum, musb_ep->packet_sz, fifo_count, csr); -#ifndef CONFIG_USB_INVENTRA_FIFO +#ifndef CONFIG_USB_MUSB_DISABLE_DMA if (is_dma_capable() && musb_ep->dma) { struct dma_controller *c = musb->dma_controller; diff --git a/drivers/usb/musb/musb_procfs.c b/drivers/usb/musb/musb_procfs.c index 1bc5c79..3144f34 100644 --- a/drivers/usb/musb/musb_procfs.c +++ b/drivers/usb/musb/musb_procfs.c @@ -508,7 +508,7 @@ static int dump_header_stats(struct musb *musb, char *buffer) code = sprintf(buffer, "Options: " -#ifdef CONFIG_USB_INVENTRA_FIFO +#ifdef CONFIG_USB_MUSB_DISABLE_DMA "pio" #elif defined(CONFIG_USB_TI_CPPI_DMA) "cppi-dma" diff --git a/drivers/usb/musb/plat_uds.c b/drivers/usb/musb/plat_uds.c index dacf930..e544339 100644 --- a/drivers/usb/musb/plat_uds.c +++ b/drivers/usb/musb/plat_uds.c @@ -1536,7 +1536,7 @@ irqreturn_t musb_interrupt(struct musb *musb) } -#ifndef CONFIG_USB_INVENTRA_FIFO +#ifndef CONFIG_USB_MUSB_DISABLE_DMA static int __initdata use_dma = 1; /* "modprobe ... use_dma=0" etc */ @@ -1918,7 +1918,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) goto fail2; } -#ifndef CONFIG_USB_INVENTRA_FIFO +#ifndef CONFIG_USB_MUSB_DISABLE_DMA if (use_dma && dev->dma_mask) { struct dma_controller *c; @@ -2047,7 +2047,7 @@ fail2: * bridge to a platform device; this driver then suffices. */ -#ifndef CONFIG_USB_INVENTRA_FIFO +#ifndef CONFIG_USB_MUSB_DISABLE_DMA static u64 *orig_dma_mask; #endif @@ -2068,7 +2068,7 @@ static int __init musb_probe(struct platform_device *pdev) return -ENOMEM; } -#ifndef CONFIG_USB_INVENTRA_FIFO +#ifndef CONFIG_USB_MUSB_DISABLE_DMA /* clobbered by use_dma=n */ orig_dma_mask = dev->dma_mask; #endif @@ -2094,7 +2094,7 @@ static int __devexit musb_remove(struct platform_device *pdev) musb_free(musb); iounmap(ctrl_base); device_init_wakeup(&pdev->dev, 0); -#ifndef CONFIG_USB_INVENTRA_FIFO +#ifndef CONFIG_USB_MUSB_DISABLE_DMA pdev->dev.dma_mask = orig_dma_mask; #endif return 0; @@ -2180,7 +2180,7 @@ static int __init musb_init(void) #endif pr_info("%s: version " MUSB_VERSION ", " -#ifdef CONFIG_USB_INVENTRA_FIFO +#ifdef CONFIG_USB_MUSB_DISABLE_DMA "pio" #elif defined(CONFIG_USB_TI_CPPI_DMA) "cppi-dma" -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/9] musb_hdrc: Search and replace USB_INVENTRA_HCD_LOGGING with USB_MUSB_LOGLEVEL 2007-08-20 9:10 ` [PATCH 1/9] musb_hdrc: Search and replace USB_INVENTRA_FIFO with USB_MUSB_DISABLE_DMA Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 2007-08-20 9:10 ` [PATCH 3/9] musb_hdrc: Rename plat_uds.c to musb_core.c, plat_arc.h to musb_arch.h Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Search and replace USB_INVENTRA_HCD_LOGGING with USB_MUSB_LOGLEVEL Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/Kconfig | 2 +- drivers/usb/musb/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 8e5430a..ed800a0 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -165,7 +165,7 @@ config USB_TUSB_OMAP_DMA help Enable DMA transfers on TUSB 6010 when OMAP DMA is available. -config USB_INVENTRA_HCD_LOGGING +config USB_MUSB_LOGLEVEL depends on USB_MUSB_HDRC int 'Logging Level (0 - none / 3 - annoying / ... )' default 0 diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index fbff415..93c3f40 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -60,7 +60,7 @@ endif # Debugging -MUSB_DEBUG:=$(CONFIG_USB_INVENTRA_HCD_LOGGING) +MUSB_DEBUG:=$(CONFIG_USB_MUSB_LOGLEVEL) ifeq ("$(strip $(MUSB_DEBUG))","") ifdef CONFIG_USB_DEBUG -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/9] musb_hdrc: Rename plat_uds.c to musb_core.c, plat_arc.h to musb_arch.h 2007-08-20 9:10 ` [PATCH 2/9] musb_hdrc: Search and replace USB_INVENTRA_HCD_LOGGING with USB_MUSB_LOGLEVEL Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 2007-08-20 9:10 ` [PATCH 4/9] musb_hdrc: Rename musbhdrc.h to musb_regs.h Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Rename plat_uds.c to musb_core.c, plat_arc.h to musb_arch.h Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/Makefile | 2 +- drivers/usb/musb/musb_arch.h | 115 +++ drivers/usb/musb/musb_core.c | 2216 ++++++++++++++++++++++++++++++++++++++++++ drivers/usb/musb/musbdefs.h | 2 +- drivers/usb/musb/plat_arc.h | 115 --- drivers/usb/musb/plat_uds.c | 2216 ------------------------------------------ 6 files changed, 2333 insertions(+), 2333 deletions(-) create mode 100644 drivers/usb/musb/musb_arch.h create mode 100644 drivers/usb/musb/musb_core.c delete mode 100644 drivers/usb/musb/plat_arc.h delete mode 100644 drivers/usb/musb/plat_uds.c diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 93c3f40..537faed 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -2,7 +2,7 @@ # for USB OTG silicon based on Mentor Graphics INVENTRA designs # -musb_hdrc-objs := plat_uds.o +musb_hdrc-objs := musb_core.o obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o diff --git a/drivers/usb/musb/musb_arch.h b/drivers/usb/musb/musb_arch.h new file mode 100644 index 0000000..5decdbe --- /dev/null +++ b/drivers/usb/musb/musb_arch.h @@ -0,0 +1,115 @@ +/* + * MUSB OTG driver Linux-specific architecture defines + * + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. + * + */ + +#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__ +#define __MUSB_LINUX_PLATFORM_ARCH_H__ + +#include <asm/io.h> + +#ifndef CONFIG_ARM +static inline void readsl(const void __iomem *addr, void *buf, int len) + { insl((unsigned long)addr, buf, len); } +static inline void readsw(const void __iomem *addr, void *buf, int len) + { insw((unsigned long)addr, buf, len); } +static inline void readsb(const void __iomem *addr, void *buf, int len) + { insb((unsigned long)addr, buf, len); } + +static inline void writesl(const void __iomem *addr, const void *buf, int len) + { outsl((unsigned long)addr, buf, len); } +static inline void writesw(const void __iomem *addr, const void *buf, int len) + { outsw((unsigned long)addr, buf, len); } +static inline void writesb(const void __iomem *addr, const void *buf, int len) + { outsb((unsigned long)addr, buf, len); } + +#endif + +/* NOTE: these offsets are all in bytes */ + +static inline u16 musb_readw(const void __iomem *addr, unsigned offset) + { return __raw_readw(addr + offset); } + +static inline u32 musb_readl(const void __iomem *addr, unsigned offset) + { return __raw_readl(addr + offset); } + + +static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data) + { __raw_writew(data, addr + offset); } + +static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) + { __raw_writel(data, addr + offset); } + + +#ifdef CONFIG_USB_TUSB6010 + +/* + * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. + */ +static inline u8 musb_readb(const void __iomem *addr, unsigned offset) +{ + u16 tmp; + u8 val; + + tmp = __raw_readw(addr + (offset & ~1)); + if (offset & 1) + val = (tmp >> 8); + else + val = tmp & 0xff; + + return val; +} + +static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) +{ + u16 tmp; + + tmp = __raw_readw(addr + (offset & ~1)); + if (offset & 1) + tmp = (data << 8) | (tmp & 0xff); + else + tmp = (tmp & 0xff00) | data; + + __raw_writew(tmp, addr + (offset & ~1)); +} + +#else + +static inline u8 musb_readb(const void __iomem *addr, unsigned offset) + { return __raw_readb(addr + offset); } + +static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) + { __raw_writeb(data, addr + offset); } + +#endif /* CONFIG_USB_TUSB6010 */ + +#endif diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c new file mode 100644 index 0000000..e544339 --- /dev/null +++ b/drivers/usb/musb/musb_core.c @@ -0,0 +1,2216 @@ +/* + * MUSB OTG driver core code + * + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. + * + */ + +/* + * Inventra (Multipoint) Dual-Role Controller Driver for Linux. + * + * This consists of a Host Controller Driver (HCD) and a peripheral + * controller driver implementing the "Gadget" API; OTG support is + * in the works. These are normal Linux-USB controller drivers which + * use IRQs and have no dedicated thread. + * + * This version of the driver has only been used with products from + * Texas Instruments. Those products integrate the Inventra logic + * with other DMA, IRQ, and bus modules, as well as other logic that + * needs to be reflected in this driver. + * + * + * NOTE: the original Mentor code here was pretty much a collection + * of mechanisms that don't seem to have been fully integrated/working + * for *any* Linux kernel version. This version aims at Linux 2.6.now, + * Key open issues include: + * + * - Lack of host-side transaction scheduling, for all transfer types. + * The hardware doesn't do it; instead, software must. + * + * This is not an issue for OTG devices that don't support external + * hubs, but for more "normal" USB hosts it's a user issue that the + * "multipoint" support doesn't scale in the expected ways. That + * includes DaVinci EVM in a common non-OTG mode. + * + * * Control and bulk use dedicated endpoints, and there's as + * yet no mechanism to either (a) reclaim the hardware when + * peripherals are NAKing, which gets complicated with bulk + * endpoints, or (b) use more than a single bulk endpoint in + * each direction. + * + * RESULT: one device may be perceived as blocking another one. + * + * * Interrupt and isochronous will dynamically allocate endpoint + * hardware, but (a) there's no record keeping for bandwidth; + * (b) in the common case that few endpoints are available, there + * is no mechanism to reuse endpoints to talk to multiple devices. + * + * RESULT: At one extreme, bandwidth can be overcommitted in + * some hardware configurations, no faults will be reported. + * At the other extreme, the bandwidth capabilities which do + * exist tend to be severely undercommitted. You can't yet hook + * up both a keyboard and a mouse to an external USB hub. + */ + +/* + * This gets many kinds of configuration information: + * - Kconfig for everything user-configurable + * - <asm/arch/hdrc_cnf.h> for SOC or family details + * - platform_device for addressing, irq, and platform_data + * - platform_data is mostly for board-specific informarion + * + * Most of the conditional compilation will (someday) vanish. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/kobject.h> +#include <linux/platform_device.h> + +#include <asm/io.h> + +#ifdef CONFIG_ARM +#include <asm/arch/hardware.h> +#include <asm/arch/memory.h> +#include <asm/mach-types.h> +#endif + +#include "musbdefs.h" + + +#ifdef CONFIG_ARCH_DAVINCI +#include "davinci.h" +#endif + + + +#if MUSB_DEBUG > 0 +unsigned debug = MUSB_DEBUG; +module_param(debug, uint, 0); +MODULE_PARM_DESC(debug, "initial debug message level"); + +#define MUSB_VERSION_SUFFIX "/dbg" +#else + +const char *otg_state_string(struct musb *musb) +{ + static char buf[8]; + + snprintf(buf, sizeof buf, "otg-%d", musb->xceiv.state); + return buf; +} +#endif + +#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia" +#define DRIVER_DESC "Inventra Dual-Role USB Controller Driver" + +#define MUSB_VERSION_BASE "2.2a/db-0.5.2" + +#ifndef MUSB_VERSION_SUFFIX +#define MUSB_VERSION_SUFFIX "" +#endif +#define MUSB_VERSION MUSB_VERSION_BASE MUSB_VERSION_SUFFIX + +#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION + +const char musb_driver_name[] = "musb_hdrc"; + +MODULE_DESCRIPTION(DRIVER_INFO); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); + + +/*-------------------------------------------------------------------------*/ + +static inline struct musb *dev_to_musb(struct device *dev) +{ +#ifdef CONFIG_USB_MUSB_HDRC_HCD + /* usbcore insists dev->driver_data is a "struct hcd *" */ + return hcd_to_musb(dev_get_drvdata(dev)); +#else + return dev_get_drvdata(dev); +#endif +} + +/*-------------------------------------------------------------------------*/ + +#ifndef CONFIG_USB_TUSB6010 +/* + * Load an endpoint's FIFO + */ +void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) +{ + void __iomem *fifo = hw_ep->fifo; + + prefetch((u8 *)src); + + DBG(4, "%cX ep%d fifo %p count %d buf %p\n", + 'T', hw_ep->epnum, fifo, len, src); + + /* we can't assume unaligned reads work */ + if (likely((0x01 & (unsigned long) src) == 0)) { + u16 index = 0; + + /* best case is 32bit-aligned source address */ + if ((0x02 & (unsigned long) src) == 0) { + if (len >= 4) { + writesl(fifo, src + index, len >> 2); + index += len & ~0x03; + } + if (len & 0x02) { + musb_writew(fifo, 0, *(u16*)&src[index]); + index += 2; + } + } else { + if (len >= 2) { + writesw(fifo, src + index, len >> 1); + index += len & ~0x01; + } + } + if (len & 0x01) + musb_writeb(fifo, 0, src[index]); + } else { + /* byte aligned */ + writesb(fifo, src, len); + } +} + +/* + * Unload an endpoint's FIFO + */ +void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) +{ + void __iomem *fifo = hw_ep->fifo; + + DBG(4, "%cX ep%d fifo %p count %d buf %p\n", + 'R', hw_ep->epnum, fifo, len, dst); + + /* we can't assume unaligned writes work */ + if (likely((0x01 & (unsigned long) dst) == 0)) { + u16 index = 0; + + /* best case is 32bit-aligned destination address */ + if ((0x02 & (unsigned long) dst) == 0) { + if (len >= 4) { + readsl(fifo, dst, len >> 2); + index = len & ~0x03; + } + if (len & 0x02) { + *(u16*)&dst[index] = musb_readw(fifo, 0); + index += 2; + } + } else { + if (len >= 2) { + readsw(fifo, dst, len >> 1); + index = len & ~0x01; + } + } + if (len & 0x01) + dst[index] = musb_readb(fifo, 0); + } else { + /* byte aligned */ + readsb(fifo, dst, len); + } +} + +#endif /* normal PIO */ + + +/*-------------------------------------------------------------------------*/ + +/* for high speed test mode; see USB 2.0 spec 7.1.20 */ +static const u8 musb_test_packet[53] = { + /* implicit SYNC then DATA0 to start */ + + /* JKJKJKJK x9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* JJKKJJKK x8 */ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + /* JJJJKKKK x8 */ + 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + /* JJJJJJJKKKKKKK x8 */ + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* JJJJJJJK x8 */ + 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, + /* JKKKKKKK x10, JK */ + 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e + + /* implicit CRC16 then EOP to end */ +}; + +void musb_load_testpacket(struct musb *musb) +{ + void __iomem *regs = musb->endpoints[0].regs; + + musb_ep_select(musb->mregs, 0); + musb_write_fifo(musb->control_ep, + sizeof(musb_test_packet), musb_test_packet); + musb_writew(regs, MUSB_CSR0, MUSB_CSR0_TXPKTRDY); +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_MUSB_OTG + +/* + * See also USB_OTG_1-3.pdf 6.6.5 Timers + * REVISIT: Are the other timers done in the hardware? + */ +#define TB_ASE0_BRST 100 /* Min 3.125 ms */ + +/* + * Handles OTG hnp timeouts, such as b_ase0_brst + */ +void musb_otg_timer_func(unsigned long data) +{ + struct musb *musb = (struct musb *)data; + unsigned long flags; + + spin_lock_irqsave(&musb->lock, flags); + if (musb->xceiv.state == OTG_STATE_B_WAIT_ACON) { + DBG(1, "HNP: B_WAIT_ACON timeout, going back to B_PERIPHERAL\n"); + musb_g_disconnect(musb); + musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->is_active = 0; + } + spin_unlock_irqrestore(&musb->lock, flags); +} + +static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0); + +/* + * Stops the B-device HNP state. Caller must take care of locking. + */ +void musb_hnp_stop(struct musb *musb) +{ + struct usb_hcd *hcd = musb_to_hcd(musb); + void __iomem *mbase = musb->mregs; + u8 reg; + + switch (musb->xceiv.state) { + case OTG_STATE_A_PERIPHERAL: + case OTG_STATE_A_WAIT_VFALL: + DBG(1, "HNP: Switching back to A-host\n"); + musb_g_disconnect(musb); + musb_root_disconnect(musb); + musb->xceiv.state = OTG_STATE_A_IDLE; + musb->is_active = 0; + break; + case OTG_STATE_B_HOST: + DBG(1, "HNP: Disabling HR\n"); + hcd->self.is_b_host = 0; + musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + reg = musb_readb(mbase, MUSB_POWER); + reg |= MUSB_POWER_SUSPENDM; + musb_writeb(mbase, MUSB_POWER, reg); + /* REVISIT: Start SESSION_REQUEST here? */ + break; + default: + DBG(1, "HNP: Stopping in unknown state %s\n", + otg_state_string(musb)); + } +} + +#endif + +/* + * Interrupt Service Routine to record USB "global" interrupts. + * Since these do not happen often and signify things of + * paramount importance, it seems OK to check them individually; + * the order of the tests is specified in the manual + * + * @param musb instance pointer + * @param int_usb register contents + * @param devctl + * @param power + */ + +#define STAGE0_MASK (MUSB_INTR_RESUME | MUSB_INTR_SESSREQ \ + | MUSB_INTR_VBUSERROR | MUSB_INTR_CONNECT \ + | MUSB_INTR_RESET ) + +static irqreturn_t musb_stage0_irq(struct musb * musb, u8 int_usb, + u8 devctl, u8 power) +{ + irqreturn_t handled = IRQ_NONE; +#ifdef CONFIG_USB_MUSB_HDRC_HCD + void __iomem *mbase = musb->mregs; +#endif + + DBG(3, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl, + int_usb); + + /* in host mode, the peripheral may issue remote wakeup. + * in peripheral mode, the host may resume the link. + * spurious RESUME irqs happen too, paired with SUSPEND. + */ + if (int_usb & MUSB_INTR_RESUME) { + handled = IRQ_HANDLED; + DBG(3, "RESUME (%s)\n", otg_state_string(musb)); + + if (devctl & MUSB_DEVCTL_HM) { +#ifdef CONFIG_USB_MUSB_HDRC_HCD + switch (musb->xceiv.state) { + case OTG_STATE_A_SUSPEND: + /* remote wakeup? later, GetPortStatus + * will stop RESUME signaling + */ + + if (power & MUSB_POWER_SUSPENDM) { + /* spurious */ + musb->int_usb &= ~MUSB_INTR_SUSPEND; + DBG(2, "Spurious SUSPENDM\n"); + break; + } + + power &= ~MUSB_POWER_SUSPENDM; + musb_writeb(mbase, MUSB_POWER, + power | MUSB_POWER_RESUME); + + musb->port1_status |= + (USB_PORT_STAT_C_SUSPEND << 16) + | MUSB_PORT_STAT_RESUME; + musb->rh_timer = jiffies + + msecs_to_jiffies(20); + + musb->xceiv.state = OTG_STATE_A_HOST; + musb->is_active = 1; + usb_hcd_resume_root_hub(musb_to_hcd(musb)); + break; + case OTG_STATE_B_WAIT_ACON: + musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->is_active = 1; + MUSB_DEV_MODE(musb); + break; + default: + WARN("bogus %s RESUME (%s)\n", + "host", + otg_state_string(musb)); + } +#endif + } else { + switch (musb->xceiv.state) { +#ifdef CONFIG_USB_MUSB_HDRC_HCD + case OTG_STATE_A_SUSPEND: + /* possibly DISCONNECT is upcoming */ + musb->xceiv.state = OTG_STATE_A_HOST; + usb_hcd_resume_root_hub(musb_to_hcd(musb)); + break; +#endif +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + case OTG_STATE_B_WAIT_ACON: + case OTG_STATE_B_PERIPHERAL: + /* disconnect while suspended? we may + * not get a disconnect irq... + */ + if ((devctl & MUSB_DEVCTL_VBUS) + != (3 << MUSB_DEVCTL_VBUS_SHIFT)) { + musb->int_usb |= MUSB_INTR_DISCONNECT; + musb->int_usb &= ~MUSB_INTR_SUSPEND; + break; + } + musb_g_resume(musb); + break; + case OTG_STATE_B_IDLE: + musb->int_usb &= ~MUSB_INTR_SUSPEND; + break; +#endif + default: + WARN("bogus %s RESUME (%s)\n", + "peripheral", + otg_state_string(musb)); + } + } + } + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + /* see manual for the order of the tests */ + if (int_usb & MUSB_INTR_SESSREQ) { + DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(musb)); + + /* IRQ arrives from ID pin sense or (later, if VBUS power + * is removed) SRP. responses are time critical: + * - turn on VBUS (with silicon-specific mechanism) + * - go through A_WAIT_VRISE + * - ... to A_WAIT_BCON. + * a_wait_vrise_tmout triggers VBUS_ERROR transitions + */ + musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); + musb->ep0_stage = MUSB_EP0_START; + musb->xceiv.state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + musb_set_vbus(musb, 1); + + handled = IRQ_HANDLED; + } + + if (int_usb & MUSB_INTR_VBUSERROR) { + int ignore = 0; + + /* During connection as an A-Device, we may see a short + * current spikes causing voltage drop, because of cable + * and peripheral capacitance combined with vbus draw. + * (So: less common with truly self-powered devices, where + * vbus doesn't act like a power supply.) + * + * Such spikes are short; usually less than ~500 usec, max + * of ~2 msec. That is, they're not sustained overcurrent + * errors, though they're reported using VBUSERROR irqs. + * + * Workarounds: (a) hardware: use self powered devices. + * (b) software: ignore non-repeated VBUS errors. + * + * REVISIT: do delays from lots of DEBUG_KERNEL checks + * make trouble here, keeping VBUS < 4.4V ? + */ + switch (musb->xceiv.state) { + case OTG_STATE_A_HOST: + /* recovery is dicey once we've gotten past the + * initial stages of enumeration, but if VBUS + * stayed ok at the other end of the link, and + * another reset is due (at least for high speed, + * to redo the chirp etc), it might work OK... + */ + case OTG_STATE_A_WAIT_BCON: + case OTG_STATE_A_WAIT_VRISE: + if (musb->vbuserr_retry) { + musb->vbuserr_retry--; + ignore = 1; + devctl |= MUSB_DEVCTL_SESSION; + musb_writeb(mbase, MUSB_DEVCTL, devctl); + } else { + musb->port1_status |= + (1 << USB_PORT_FEAT_OVER_CURRENT) + | (1 << USB_PORT_FEAT_C_OVER_CURRENT); + } + break; + default: + break; + } + + DBG(1, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", + otg_state_string(musb), + devctl, + ({ char *s; + switch (devctl & MUSB_DEVCTL_VBUS) { + case 0 << MUSB_DEVCTL_VBUS_SHIFT: + s = "<SessEnd"; break; + case 1 << MUSB_DEVCTL_VBUS_SHIFT: + s = "<AValid"; break; + case 2 << MUSB_DEVCTL_VBUS_SHIFT: + s = "<VBusValid"; break; + //case 3 << MUSB_DEVCTL_VBUS_SHIFT: + default: + s = "VALID"; break; + }; s; }), + VBUSERR_RETRY_COUNT - musb->vbuserr_retry, + musb->port1_status); + + /* go through A_WAIT_VFALL then start a new session */ + if (!ignore) + musb_set_vbus(musb, 0); + handled = IRQ_HANDLED; + } + + if (int_usb & MUSB_INTR_CONNECT) { + struct usb_hcd *hcd = musb_to_hcd(musb); + + handled = IRQ_HANDLED; + musb->is_active = 1; + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + + musb->ep0_stage = MUSB_EP0_START; + +#ifdef CONFIG_USB_MUSB_OTG + /* flush endpoints when transitioning from Device Mode */ + if (is_peripheral_active(musb)) { + // REVISIT HNP; just force disconnect + } + musb_writew(mbase, MUSB_INTRTXE, musb->epmask); + musb_writew(mbase, MUSB_INTRRXE, musb->epmask & 0xfffe); + musb_writeb(mbase, MUSB_INTRUSBE, 0xf7); +#endif + musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED + |USB_PORT_STAT_HIGH_SPEED + |USB_PORT_STAT_ENABLE + ); + musb->port1_status |= USB_PORT_STAT_CONNECTION + |(USB_PORT_STAT_C_CONNECTION << 16); + + /* high vs full speed is just a guess until after reset */ + if (devctl & MUSB_DEVCTL_LSDEV) + musb->port1_status |= USB_PORT_STAT_LOW_SPEED; + + if (hcd->status_urb) + usb_hcd_poll_rh_status(hcd); + else + usb_hcd_resume_root_hub(hcd); + + MUSB_HST_MODE(musb); + + /* indicate new connection to OTG machine */ + switch (musb->xceiv.state) { + case OTG_STATE_B_WAIT_ACON: + DBG(1, "HNP: Waiting to switch to b_host state\n"); + musb->xceiv.state = OTG_STATE_B_HOST; + hcd->self.is_b_host = 1; + break; + default: + if ((devctl & MUSB_DEVCTL_VBUS) + == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { + musb->xceiv.state = OTG_STATE_A_HOST; + hcd->self.is_b_host = 0; + } + break; + } + DBG(1, "CONNECT (%s) devctl %02x\n", + otg_state_string(musb), devctl); + } +#endif /* CONFIG_USB_MUSB_HDRC_HCD */ + + /* mentor saves a bit: bus reset and babble share the same irq. + * only host sees babble; only peripheral sees bus reset. + */ + if (int_usb & MUSB_INTR_RESET) { +#ifdef CONFIG_USB_MUSB_HDRC_HCD + if (devctl & MUSB_DEVCTL_HM) { + /* + * Looks like non-HS BABBLE can be ignored, but + * HS BABBLE is an error condition. For HS the solution + * is to avoid babble in the first place and fix whatever + * causes BABBLE. When HS BABBLE happens we can only stop + * the session. + */ + if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV)) + DBG(1, "BABBLE devctl: %02x\n", devctl); + else { + ERR("Stopping host session because of babble\n"); + musb_writeb(mbase, MUSB_DEVCTL, 0); + } + } else +#endif /* CONFIG_USB_MUSB_HDRC_HCD */ + { + DBG(1, "BUS RESET\n"); + + musb_g_reset(musb); + schedule_work(&musb->irq_work); + } + + handled = IRQ_HANDLED; + } + + return handled; +} + +/* + * Interrupt Service Routine to record USB "global" interrupts. + * Since these do not happen often and signify things of + * paramount importance, it seems OK to check them individually; + * the order of the tests is specified in the manual + * + * @param musb instance pointer + * @param int_usb register contents + * @param devctl + * @param power + */ +static irqreturn_t musb_stage2_irq(struct musb * musb, u8 int_usb, + u8 devctl, u8 power) +{ + irqreturn_t handled = IRQ_NONE; + +#if 0 +/* REVISIT ... this would be for multiplexing periodic endpoints, or + * supporting transfer phasing to prevent exceeding ISO bandwidth + * limits of a given frame or microframe. + * + * It's not needed for peripheral side, which dedicates endpoints; + * though it _might_ use SOF irqs for other purposes. + * + * And it's not currently needed for host side, which also dedicates + * endpoints, relies on TX/RX interval registers, and isn't claimed + * to support ISO transfers yet. + */ + if (int_usb & MUSB_INTR_SOF) { + void __iomem *mbase = musb->mregs; + struct musb_hw_ep *ep; + u8 epnum; + u16 frame; + + DBG(6, "START_OF_FRAME\n"); + handled = IRQ_HANDLED; + + /* start any periodic Tx transfers waiting for current frame */ + frame = musb_readw(mbase, MUSB_FRAME); + ep = musb->endpoints; + for (epnum = 1; (epnum < musb->nr_endpoints) + && (musb->epmask >= (1 << epnum)); + epnum++, ep++) { + // FIXME handle framecounter wraps (12 bits) + // eliminate duplicated StartUrb logic + if (ep->dwWaitFrame >= frame) { + ep->dwWaitFrame = 0; + printk("SOF --> periodic TX%s on %d\n", + ep->tx_channel ? " DMA" : "", + epnum); + if (!ep->tx_channel) + musb_h_tx_start(musb, epnum); + else + cppi_hostdma_start(musb, epnum); + } + } /* end of for loop */ + } +#endif + + if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) { + DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n", + otg_state_string(musb), + MUSB_MODE(musb), devctl); + handled = IRQ_HANDLED; + + switch (musb->xceiv.state) { +#ifdef CONFIG_USB_MUSB_HDRC_HCD + case OTG_STATE_A_HOST: + case OTG_STATE_A_SUSPEND: + musb_root_disconnect(musb); + if (musb->a_wait_bcon != 0) + musb_platform_try_idle(musb, jiffies + + msecs_to_jiffies(musb->a_wait_bcon)); + break; +#endif /* HOST */ +#ifdef CONFIG_USB_MUSB_OTG + case OTG_STATE_B_HOST: + musb_hnp_stop(musb); + break; + /* FALLTHROUGH */ + case OTG_STATE_A_PERIPHERAL: + musb_root_disconnect(musb); + /* FALLTHROUGH */ + case OTG_STATE_B_WAIT_ACON: +#endif /* OTG */ +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_IDLE: + musb_g_disconnect(musb); + break; +#endif /* GADGET */ + default: + WARN("unhandled DISCONNECT transition (%s)\n", + otg_state_string(musb)); + break; + } + + schedule_work(&musb->irq_work); + } + + if (int_usb & MUSB_INTR_SUSPEND) { + DBG(1, "SUSPEND (%s) devctl %02x power %02x\n", + otg_state_string(musb), devctl, power); + handled = IRQ_HANDLED; + + switch (musb->xceiv.state) { +#ifdef CONFIG_USB_MUSB_OTG + case OTG_STATE_A_PERIPHERAL: + musb_hnp_stop(musb); + break; +#endif + case OTG_STATE_B_PERIPHERAL: + musb_g_suspend(musb); + musb->is_active = is_otg_enabled(musb) + && musb->xceiv.gadget->b_hnp_enable; + if (musb->is_active) { + musb->xceiv.state = OTG_STATE_B_WAIT_ACON; +#ifdef CONFIG_USB_MUSB_OTG + DBG(1, "HNP: Setting timer for b_ase0_brst\n"); + musb_otg_timer.data = (unsigned long)musb; + mod_timer(&musb_otg_timer, jiffies + + msecs_to_jiffies(TB_ASE0_BRST)); +#endif + } + break; + case OTG_STATE_A_WAIT_BCON: + if (musb->a_wait_bcon != 0) + musb_platform_try_idle(musb, jiffies + + msecs_to_jiffies(musb->a_wait_bcon)); + break; + case OTG_STATE_A_HOST: + musb->xceiv.state = OTG_STATE_A_SUSPEND; + musb->is_active = is_otg_enabled(musb) + && musb->xceiv.host->b_hnp_enable; + break; + case OTG_STATE_B_HOST: + /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ + DBG(1, "REVISIT: SUSPEND as B_HOST\n"); + break; + default: + /* "should not happen" */ + musb->is_active = 0; + break; + } + } + + + return handled; +} + +/*-------------------------------------------------------------------------*/ + +/* +* Program the HDRC to start (enable interrupts, dma, etc.). +*/ +void musb_start(struct musb *musb) +{ + void __iomem *regs = musb->mregs; + u8 devctl = musb_readb(regs, MUSB_DEVCTL); + + DBG(2, "<== devctl %02x\n", devctl); + + /* Set INT enable registers, enable interrupts */ + musb_writew(regs, MUSB_INTRTXE, musb->epmask); + musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe); + musb_writeb(regs, MUSB_INTRUSBE, 0xf7); + + musb_writeb(regs, MUSB_TESTMODE, 0); + + /* put into basic highspeed mode and start session */ + musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE + | MUSB_POWER_SOFTCONN + | MUSB_POWER_HSENAB + /* ENSUSPEND wedges tusb */ + // | MUSB_POWER_ENSUSPEND + ); + + musb->is_active = 0; + devctl = musb_readb(regs, MUSB_DEVCTL); + devctl &= ~MUSB_DEVCTL_SESSION; + + if (is_otg_enabled(musb)) { + /* session started after: + * (a) ID-grounded irq, host mode; + * (b) vbus present/connect IRQ, peripheral mode; + * (c) peripheral initiates, using SRP + */ + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) + musb->is_active = 1; + else + devctl |= MUSB_DEVCTL_SESSION; + + } else if (is_host_enabled(musb)) { + /* assume ID pin is hard-wired to ground */ + devctl |= MUSB_DEVCTL_SESSION; + + } else /* peripheral is enabled */ { + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) + musb->is_active = 1; + } + musb_platform_enable(musb); + musb_writeb(regs, MUSB_DEVCTL, devctl); +} + + +static void musb_generic_disable(struct musb *musb) +{ + void __iomem *mbase = musb->mregs; + u16 temp; + + /* disable interrupts */ + musb_writeb(mbase, MUSB_INTRUSBE, 0); + musb_writew(mbase, MUSB_INTRTXE, 0); + musb_writew(mbase, MUSB_INTRRXE, 0); + + /* off */ + musb_writeb(mbase, MUSB_DEVCTL, 0); + + /* flush pending interrupts */ + temp = musb_readb(mbase, MUSB_INTRUSB); + temp = musb_readw(mbase, MUSB_INTRTX); + temp = musb_readw(mbase, MUSB_INTRRX); + +} + +/* + * Make the HDRC stop (disable interrupts, etc.); + * reversible by musb_start + * called on gadget driver unregister + * with controller locked, irqs blocked + * acts as a NOP unless some role activated the hardware + */ +void musb_stop(struct musb *musb) +{ + /* stop IRQs, timers, ... */ + musb_platform_disable(musb); + musb_generic_disable(musb); + DBG(3, "HDRC disabled\n"); + + /* FIXME + * - mark host and/or peripheral drivers unusable/inactive + * - disable DMA (and enable it in HdrcStart) + * - make sure we can musb_start() after musb_stop(); with + * OTG mode, gadget driver module rmmod/modprobe cycles that + * - ... + */ + musb_platform_try_idle(musb, 0); +} + +static void musb_shutdown(struct platform_device *pdev) +{ + struct musb *musb = dev_to_musb(&pdev->dev); + unsigned long flags; + + spin_lock_irqsave(&musb->lock, flags); + musb_platform_disable(musb); + musb_generic_disable(musb); + if (musb->clock) { + clk_put(musb->clock); + musb->clock = NULL; + } + spin_unlock_irqrestore(&musb->lock, flags); + + /* FIXME power down */ +} + + +/*-------------------------------------------------------------------------*/ + +/* + * The silicon either has hard-wired endpoint configurations, or else + * "dynamic fifo" sizing. The driver has support for both, though at this + * writing only the dynamic sizing is very well tested. We use normal + * idioms to so both modes are compile-tested, but dead code elimination + * leaves only the relevant one in the object file. + * + * We don't currently use dynamic fifo setup capability to do anything + * more than selecting one of a bunch of predefined configurations. + */ +#ifdef MUSB_C_DYNFIFO_DEF +#define can_dynfifo() 1 +#else +#define can_dynfifo() 0 +#endif + +#ifdef CONFIG_USB_TUSB6010 +static ushort __initdata fifo_mode = 4; +#else +static ushort __initdata fifo_mode = 2; +#endif + +/* "modprobe ... fifo_mode=1" etc */ +module_param(fifo_mode, ushort, 0); +MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration"); + + +#define DYN_FIFO_SIZE (1<<(MUSB_C_RAM_BITS+2)) + +enum fifo_style { FIFO_RXTX, FIFO_TX, FIFO_RX } __attribute__ ((packed)); +enum buf_mode { BUF_SINGLE, BUF_DOUBLE } __attribute__ ((packed)); + +struct fifo_cfg { + u8 hw_ep_num; + enum fifo_style style; + enum buf_mode mode; + u16 maxpacket; +}; + +/* + * tables defining fifo_mode values. define more if you like. + * for host side, make sure both halves of ep1 are set up. + */ + +/* mode 0 - fits in 2KB */ +static struct fifo_cfg __initdata mode_0_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, }, +{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, +{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, +}; + +/* mode 1 - fits in 4KB */ +static struct fifo_cfg __initdata mode_1_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, +{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, +}; + +/* mode 2 - fits in 4KB */ +static struct fifo_cfg __initdata mode_2_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, +{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, +}; + +/* mode 3 - fits in 4KB */ +static struct fifo_cfg __initdata mode_3_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, +{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, +{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, +}; + +/* mode 4 - fits in 16KB */ +static struct fifo_cfg __initdata mode_4_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, }, +{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, }, +}; + + +/* + * configure a fifo; for non-shared endpoints, this may be called + * once for a tx fifo and once for an rx fifo. + * + * returns negative errno or offset for next fifo. + */ +static int __init +fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, + const struct fifo_cfg *cfg, u16 offset) +{ + void __iomem *mbase = musb->mregs; + int size = 0; + u16 maxpacket = cfg->maxpacket; + u16 c_off = offset >> 3; + u8 c_size; + + /* expect hw_ep has already been zero-initialized */ + + size = ffs(max(maxpacket, (u16) 8)) - 1; + maxpacket = 1 << size; + + c_size = size - 3; + if (cfg->mode == BUF_DOUBLE) { + if ((offset + (maxpacket << 1)) > DYN_FIFO_SIZE) + return -EMSGSIZE; + c_size |= MUSB_FIFOSZ_DPB; + } else { + if ((offset + maxpacket) > DYN_FIFO_SIZE) + return -EMSGSIZE; + } + + /* configure the FIFO */ + musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum); + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + /* EP0 reserved endpoint for control, bidirectional; + * EP1 reserved for bulk, two unidirection halves. + */ + if (hw_ep->epnum == 1) + musb->bulk_ep = hw_ep; + /* REVISIT error check: be sure ep0 can both rx and tx ... */ +#endif + switch (cfg->style) { + case FIFO_TX: + musb_writeb(mbase, MUSB_TXFIFOSZ, c_size); + musb_writew(mbase, MUSB_TXFIFOADD, c_off); + hw_ep->tx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); + hw_ep->max_packet_sz_tx = maxpacket; + break; + case FIFO_RX: + musb_writeb(mbase, MUSB_RXFIFOSZ, c_size); + musb_writew(mbase, MUSB_RXFIFOADD, c_off); + hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); + hw_ep->max_packet_sz_rx = maxpacket; + break; + case FIFO_RXTX: + musb_writeb(mbase, MUSB_TXFIFOSZ, c_size); + musb_writew(mbase, MUSB_TXFIFOADD, c_off); + hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); + hw_ep->max_packet_sz_rx = maxpacket; + + musb_writeb(mbase, MUSB_RXFIFOSZ, c_size); + musb_writew(mbase, MUSB_RXFIFOADD, c_off); + hw_ep->tx_double_buffered = hw_ep->rx_double_buffered; + hw_ep->max_packet_sz_tx = maxpacket; + + hw_ep->is_shared_fifo = TRUE; + break; + } + + /* NOTE rx and tx endpoint irqs aren't managed separately, + * which happens to be ok + */ + musb->epmask |= (1 << hw_ep->epnum); + + return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0)); +} + +static struct fifo_cfg __initdata ep0_cfg = { + .style = FIFO_RXTX, .maxpacket = 64, +}; + +static int __init ep_config_from_table(struct musb *musb) +{ + const struct fifo_cfg *cfg; + unsigned i, n; + int offset; + struct musb_hw_ep *hw_ep = musb->endpoints; + + switch (fifo_mode) { + default: + fifo_mode = 0; + /* FALLTHROUGH */ + case 0: + cfg = mode_0_cfg; + n = ARRAY_SIZE(mode_0_cfg); + break; + case 1: + cfg = mode_1_cfg; + n = ARRAY_SIZE(mode_1_cfg); + break; + case 2: + cfg = mode_2_cfg; + n = ARRAY_SIZE(mode_2_cfg); + break; + case 3: + cfg = mode_3_cfg; + n = ARRAY_SIZE(mode_3_cfg); + break; + case 4: + cfg = mode_4_cfg; + n = ARRAY_SIZE(mode_4_cfg); + break; + } + + printk(KERN_DEBUG "%s: setup fifo_mode %d\n", + musb_driver_name, fifo_mode); + + + offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0); + // assert(offset > 0) + + /* NOTE: for RTL versions >= 1.400 EPINFO and RAMINFO would + * be better than static MUSB_C_NUM_EPS and DYN_FIFO_SIZE... + */ + + for (i = 0; i < n; i++) { + u8 epn = cfg->hw_ep_num; + + if (epn >= MUSB_C_NUM_EPS) { + pr_debug( "%s: invalid ep %d\n", + musb_driver_name, epn); + continue; + } + offset = fifo_setup(musb, hw_ep + epn, cfg++, offset); + if (offset < 0) { + pr_debug( "%s: mem overrun, ep %d\n", + musb_driver_name, epn); + return -EINVAL; + } + epn++; + musb->nr_endpoints = max(epn, musb->nr_endpoints); + } + + printk(KERN_DEBUG "%s: %d/%d max ep, %d/%d memory\n", + musb_driver_name, + n + 1, MUSB_C_NUM_EPS * 2 - 1, + offset, DYN_FIFO_SIZE); + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + if (!musb->bulk_ep) { + pr_debug( "%s: missing bulk\n", musb_driver_name); + return -EINVAL; + } +#endif + + return 0; +} + + +/* + * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false + * @param musb the controller + */ +static int __init ep_config_from_hw(struct musb *musb) +{ + u8 epnum = 0, reg; + struct musb_hw_ep *hw_ep; + void *mbase = musb->mregs; + + DBG(2, "<== static silicon ep config\n"); + + /* FIXME pick up ep0 maxpacket size */ + + for (epnum = 1; epnum < MUSB_C_NUM_EPS; epnum++) { + musb_ep_select(mbase, epnum); + hw_ep = musb->endpoints + epnum; + + /* read from core using indexed model */ + reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE); + if (!reg) { + /* 0's returned when no more endpoints */ + break; + } + musb->nr_endpoints++; + musb->epmask |= (1 << epnum); + + hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f); + + /* shared TX/RX FIFO? */ + if ((reg & 0xf0) == 0xf0) { + hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx; + hw_ep->is_shared_fifo = TRUE; + continue; + } else { + hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4); + hw_ep->is_shared_fifo = FALSE; + } + + /* FIXME set up hw_ep->{rx,tx}_double_buffered */ + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + /* pick an RX/TX endpoint for bulk */ + if (hw_ep->max_packet_sz_tx < 512 + || hw_ep->max_packet_sz_rx < 512) + continue; + + /* REVISIT: this algorithm is lazy, we should at least + * try to pick a double buffered endpoint. + */ + if (musb->bulk_ep) + continue; + musb->bulk_ep = hw_ep; +#endif + } + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + if (!musb->bulk_ep) { + pr_debug( "%s: missing bulk\n", musb_driver_name); + return -EINVAL; + } +#endif + + return 0; +} + +enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, }; + +/* Initialize MUSB (M)HDRC part of the USB hardware subsystem; + * configure endpoints, or take their config from silicon + */ +static int __init musb_core_init(u16 musb_type, struct musb *musb) +{ +#ifdef MUSB_AHB_ID + u32 data; +#endif + u8 reg; + char *type; + u16 hwvers, rev_major, rev_minor; + char aInfo[78], aRevision[32], aDate[12]; + void __iomem *mbase = musb->mregs; + int status = 0; + int i; + + /* log core options (read using indexed model) */ + musb_ep_select(mbase, 0); + reg = musb_readb(mbase, 0x10 + MUSB_CONFIGDATA); + + strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8"); + if (reg & MUSB_CONFIGDATA_DYNFIFO) { + strcat(aInfo, ", dyn FIFOs"); + } + if (reg & MUSB_CONFIGDATA_MPRXE) { + strcat(aInfo, ", bulk combine"); +#ifdef C_MP_RX + musb->bulk_combine = TRUE; +#else + strcat(aInfo, " (X)"); /* no driver support */ +#endif + } + if (reg & MUSB_CONFIGDATA_MPTXE) { + strcat(aInfo, ", bulk split"); +#ifdef C_MP_TX + musb->bulk_split = TRUE; +#else + strcat(aInfo, " (X)"); /* no driver support */ +#endif + } + if (reg & MUSB_CONFIGDATA_HBRXE) { + strcat(aInfo, ", HB-ISO Rx"); + strcat(aInfo, " (X)"); /* no driver support */ + } + if (reg & MUSB_CONFIGDATA_HBTXE) { + strcat(aInfo, ", HB-ISO Tx"); + strcat(aInfo, " (X)"); /* no driver support */ + } + if (reg & MUSB_CONFIGDATA_SOFTCONE) { + strcat(aInfo, ", SoftConn"); + } + + printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n", + musb_driver_name, reg, aInfo); + +#ifdef MUSB_AHB_ID + data = musb_readl(mbase, 0x404); + sprintf(aDate, "%04d-%02x-%02x", (data & 0xffff), + (data >> 16) & 0xff, (data >> 24) & 0xff); + /* FIXME ID2 and ID3 are unused */ + data = musb_readl(mbase, 0x408); + printk("ID2=%lx\n", (long unsigned)data); + data = musb_readl(mbase, 0x40c); + printk("ID3=%lx\n", (long unsigned)data); + reg = musb_readb(mbase, 0x400); + musb_type = ('M' == reg) ? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC; +#else + aDate[0] = 0; +#endif + if (MUSB_CONTROLLER_MHDRC == musb_type) { + musb->is_multipoint = 1; + type = "M"; + } else { + musb->is_multipoint = 0; + type = ""; +#ifdef CONFIG_USB_MUSB_HDRC_HCD +#ifndef CONFIG_USB_OTG_BLACKLIST_HUB + printk(KERN_ERR + "%s: kernel must blacklist external hubs\n", + musb_driver_name); +#endif +#endif + } + + /* log release info */ + hwvers = musb_readw(mbase, MUSB_HWVERS); + rev_major = (hwvers >> 10) & 0x1f; + rev_minor = hwvers & 0x3ff; + snprintf(aRevision, 32, "%d.%d%s", rev_major, + rev_minor, (hwvers & 0x8000) ? "RC" : ""); + printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n", + musb_driver_name, type, aRevision, aDate); + + /* configure ep0 */ + musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE; + musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE; + + /* discover endpoint configuration */ + musb->nr_endpoints = 1; + musb->epmask = 1; + + if (reg & MUSB_CONFIGDATA_DYNFIFO) { + if (can_dynfifo()) + status = ep_config_from_table(musb); + else { + ERR("reconfigure software for Dynamic FIFOs\n"); + status = -ENODEV; + } + } else { + if (!can_dynfifo()) + status = ep_config_from_hw(musb); + else { + ERR("reconfigure software for static FIFOs\n"); + return -ENODEV; + } + } + + if (status < 0) + return status; + + /* finish init, and print endpoint config */ + for (i = 0; i < musb->nr_endpoints; i++) { + struct musb_hw_ep *hw_ep = musb->endpoints + i; + + hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase; +#ifdef CONFIG_USB_TUSB6010 + hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i); + hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i); + hw_ep->fifo_sync_va = + musb->sync_va + 0x400 + MUSB_FIFO_OFFSET(i); + + if (i == 0) + hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF; + else + hw_ep->conf = mbase + 0x400 + (((i - 1) & 0xf) << 2); +#endif + + hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase; +#ifdef CONFIG_USB_MUSB_HDRC_HCD + hw_ep->target_regs = MUSB_BUSCTL_OFFSET(i, 0) + mbase; + hw_ep->rx_reinit = 1; + hw_ep->tx_reinit = 1; +#endif + + if (hw_ep->max_packet_sz_tx) { + printk(KERN_DEBUG + "%s: hw_ep %d%s, %smax %d\n", + musb_driver_name, i, + hw_ep->is_shared_fifo ? "shared" : "tx", + hw_ep->tx_double_buffered + ? "doublebuffer, " : "", + hw_ep->max_packet_sz_tx); + } + if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) { + printk(KERN_DEBUG + "%s: hw_ep %d%s, %smax %d\n", + musb_driver_name, i, + "rx", + hw_ep->rx_double_buffered + ? "doublebuffer, " : "", + hw_ep->max_packet_sz_rx); + } + if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx)) + DBG(1, "hw_ep %d not configured\n", i); + } + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) + +static irqreturn_t generic_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + /* REVISIT we sometimes get spurious IRQs on g_ep0 + * not clear why... + */ + if (retval != IRQ_HANDLED) + DBG(5, "spurious?\n"); + + return IRQ_HANDLED; +} + +#else +#define generic_interrupt NULL +#endif + +/* + * handle all the irqs defined by the HDRC core. for now we expect: other + * irq sources (phy, dma, etc) will be handled first, musb->int_* values + * will be assigned, and the irq will already have been acked. + * + * called in irq context with spinlock held, irqs blocked + */ +irqreturn_t musb_interrupt(struct musb *musb) +{ + irqreturn_t retval = IRQ_NONE; + u8 devctl, power; + int ep_num; + u32 reg; + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + power = musb_readb(musb->mregs, MUSB_POWER); + + DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n", + (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", + musb->int_usb, musb->int_tx, musb->int_rx); + + /* the core can interrupt us for multiple reasons; docs have + * a generic interrupt flowchart to follow + */ + if (musb->int_usb & STAGE0_MASK) + retval |= musb_stage0_irq(musb, musb->int_usb, + devctl, power); + + /* "stage 1" is handling endpoint irqs */ + + /* handle endpoint 0 first */ + if (musb->int_tx & 1) { + if (devctl & MUSB_DEVCTL_HM) + retval |= musb_h_ep0_irq(musb); + else + retval |= musb_g_ep0_irq(musb); + } + + /* RX on endpoints 1-15 */ + reg = musb->int_rx >> 1; + ep_num = 1; + while (reg) { + if (reg & 1) { + // musb_ep_select(musb->mregs, ep_num); + /* REVISIT just retval = ep->rx_irq(...) */ + retval = IRQ_HANDLED; + if (devctl & MUSB_DEVCTL_HM) { + if (is_host_capable()) + musb_host_rx(musb, ep_num); + } else { + if (is_peripheral_capable()) + musb_g_rx(musb, ep_num); + } + } + + reg >>= 1; + ep_num++; + } + + /* TX on endpoints 1-15 */ + reg = musb->int_tx >> 1; + ep_num = 1; + while (reg) { + if (reg & 1) { + // musb_ep_select(musb->mregs, ep_num); + /* REVISIT just retval |= ep->tx_irq(...) */ + retval = IRQ_HANDLED; + if (devctl & MUSB_DEVCTL_HM) { + if (is_host_capable()) + musb_host_tx(musb, ep_num); + } else { + if (is_peripheral_capable()) + musb_g_tx(musb, ep_num); + } + } + reg >>= 1; + ep_num++; + } + + /* finish handling "global" interrupts after handling fifos */ + if (musb->int_usb) + retval |= musb_stage2_irq(musb, + musb->int_usb, devctl, power); + + return retval; +} + + +#ifndef CONFIG_USB_MUSB_DISABLE_DMA +static int __initdata use_dma = 1; + +/* "modprobe ... use_dma=0" etc */ +module_param(use_dma, bool, 0); +MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); + +void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) +{ + u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + /* called with controller lock already held */ + + if (!epnum) { +#ifndef CONFIG_USB_TUSB_OMAP_DMA + if (!is_cppi_enabled()) { + /* endpoint 0 */ + if (devctl & MUSB_DEVCTL_HM) + musb_h_ep0_irq(musb); + else + musb_g_ep0_irq(musb); + } +#endif + } else { + /* endpoints 1..15 */ + if (transmit) { + if (devctl & MUSB_DEVCTL_HM) { + if (is_host_capable()) + musb_host_tx(musb, epnum); + } else { + if (is_peripheral_capable()) + musb_g_tx(musb, epnum); + } + } else { + /* receive */ + if (devctl & MUSB_DEVCTL_HM) { + if (is_host_capable()) + musb_host_rx(musb, epnum); + } else { + if (is_peripheral_capable()) + musb_g_rx(musb, epnum); + } + } + } +} + +#else +#define use_dma 0 +#endif + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_SYSFS + +static ssize_t +musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct musb *musb = dev_to_musb(dev); + unsigned long flags; + int ret = -EINVAL; + + spin_lock_irqsave(&musb->lock, flags); + ret = sprintf(buf, "%s\n", otg_state_string(musb)); + spin_unlock_irqrestore(&musb->lock, flags); + + return ret; +} + +static ssize_t +musb_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct musb *musb = dev_to_musb(dev); + unsigned long flags; + + spin_lock_irqsave(&musb->lock, flags); + if (!strncmp(buf, "host", 4)) + musb_platform_set_mode(musb, MUSB_HOST); + if (!strncmp(buf, "peripheral", 10)) + musb_platform_set_mode(musb, MUSB_PERIPHERAL); + if (!strncmp(buf, "otg", 3)) + musb_platform_set_mode(musb, MUSB_OTG); + spin_unlock_irqrestore(&musb->lock, flags); + + return n; +} +static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store); + +static ssize_t +musb_cable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct musb *musb = dev_to_musb(dev); + char *v1= "", *v2 = "?"; + unsigned long flags; + int vbus; + + spin_lock_irqsave(&musb->lock, flags); +#if defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_USB_MUSB_OTG) + /* REVISIT: connect-A != connect-B ... */ + vbus = musb_platform_get_vbus_status(musb); + if (vbus) + v2 = "connected"; + else + v2 = "disconnected"; +#else + /* NOTE: board-specific issues, like too-big capacitors keeping + * VBUS high for a long time after power has been removed, can + * cause temporary false indications of a connection. + */ + vbus = musb_readb(musb->mregs, MUSB_DEVCTL); + if (vbus & 0x10) { + /* REVISIT retest on real OTG hardware */ + switch (musb->board_mode) { + case MUSB_HOST: + v2 = "A"; + break; + case MUSB_PERIPHERAL: + v2 = "B"; + break; + case MUSB_OTG: + v1 = "Mini-"; + v2 = (vbus & MUSB_DEVCTL_BDEVICE) ? "B" : "A"; + break; + } + } else /* VBUS level below A-Valid */ + v2 = "disconnected"; +#endif + musb_platform_try_idle(musb, 0); + spin_unlock_irqrestore(&musb->lock, flags); + + return sprintf(buf, "%s%s\n", v1, v2); +} +static DEVICE_ATTR(cable, S_IRUGO, musb_cable_show, NULL); + +static ssize_t +musb_vbus_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct musb *musb = dev_to_musb(dev); + unsigned long flags; + unsigned long val; + + spin_lock_irqsave(&musb->lock, flags); + if (sscanf(buf, "%lu", &val) < 1) { + printk(KERN_ERR "Invalid VBUS timeout ms value\n"); + return -EINVAL; + } + musb->a_wait_bcon = val; + if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON) + musb->is_active = 0; + musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val)); + spin_unlock_irqrestore(&musb->lock, flags); + + return n; +} + +static ssize_t +musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct musb *musb = dev_to_musb(dev); + unsigned long flags; + unsigned long val; + + spin_lock_irqsave(&musb->lock, flags); + val = musb->a_wait_bcon; + spin_unlock_irqrestore(&musb->lock, flags); + + return sprintf(buf, "%lu\n", val); +} +static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store); + +static ssize_t +musb_srp_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct musb *musb=dev_to_musb(dev); + unsigned short srp; + + if (sscanf(buf, "%hu", &srp) != 1 + || (srp != 1)) { + printk (KERN_ERR "SRP: Value must be 1\n"); + return -EINVAL; + } + + if (srp == 1) + musb_g_wakeup(musb); + + return n; +} +static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); +#endif + +/* Only used to provide cable state change events */ +static void musb_irq_work(struct work_struct *data) +{ + struct musb *musb = container_of(data, struct musb, irq_work); + + sysfs_notify(&musb->controller->kobj, NULL, "cable"); +} + +/* -------------------------------------------------------------------------- + * Init support + */ + +static struct musb *__init +allocate_instance(struct device *dev, void __iomem *mbase) +{ + struct musb *musb; + struct musb_hw_ep *ep; + int epnum; +#ifdef CONFIG_USB_MUSB_HDRC_HCD + struct usb_hcd *hcd; + + hcd = usb_create_hcd(&musb_hc_driver, dev, dev->bus_id); + if (!hcd) + return NULL; + /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ + + musb = hcd_to_musb(hcd); + INIT_LIST_HEAD(&musb->control); + INIT_LIST_HEAD(&musb->in_bulk); + INIT_LIST_HEAD(&musb->out_bulk); + + hcd->uses_new_polling = 1; + + musb->vbuserr_retry = VBUSERR_RETRY_COUNT; +#else + musb = kzalloc(sizeof *musb, GFP_KERNEL); + if (!musb) + return NULL; + dev_set_drvdata(dev, musb); + +#endif + + musb->mregs = mbase; + musb->ctrl_base = mbase; + musb->nIrq = -ENODEV; + for (epnum = 0, ep = musb->endpoints; + epnum < MUSB_C_NUM_EPS; + epnum++, ep++) { + + ep->musb = musb; + ep->epnum = epnum; + } + + musb->controller = dev; + return musb; +} + +static void musb_free(struct musb *musb) +{ + /* this has multiple entry modes. it handles fault cleanup after + * probe(), where things may be partially set up, as well as rmmod + * cleanup after everything's been de-activated. + */ + +#ifdef CONFIG_SYSFS + device_remove_file(musb->controller, &dev_attr_mode); + device_remove_file(musb->controller, &dev_attr_cable); + device_remove_file(musb->controller, &dev_attr_vbus); +#ifdef CONFIG_USB_MUSB_OTG + device_remove_file(musb->controller, &dev_attr_srp); +#endif +#endif + +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + musb_gadget_cleanup(musb); +#endif + + if (musb->nIrq >= 0) { + 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->private_data); + dma_controller_destroy(c); + } + + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + musb_platform_exit(musb); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + + if (musb->clock) { + clk_disable(musb->clock); + clk_put(musb->clock); + } + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + usb_put_hcd(musb_to_hcd(musb)); +#else + kfree(musb); +#endif +} + +/* + * Perform generic per-controller initialization. + * + * @pDevice: the controller (already clocked, etc) + * @nIrq: irq + * @mregs: virtual address of controller registers, + * not yet corrected for platform-specific offsets + */ +static int __init +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; + + /* The driver might handle more features than the board; OK. + * Fail when the board needs a feature that's not enabled. + */ + if (!plat) { + dev_dbg(dev, "no platform_data?\n"); + return -ENODEV; + } + switch (plat->mode) { + case MUSB_HOST: +#ifdef CONFIG_USB_MUSB_HDRC_HCD + break; +#else + goto bad_config; +#endif + case MUSB_PERIPHERAL: +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + break; +#else + goto bad_config; +#endif + case MUSB_OTG: +#ifdef CONFIG_USB_MUSB_OTG + break; +#else + bad_config: +#endif + default: + dev_err(dev, "incompatible Kconfig role setting\n"); + return -EINVAL; + } + + /* allocate */ + musb = allocate_instance(dev, ctrl); + if (!musb) + return -ENOMEM; + + spin_lock_init(&musb->lock); + musb->board_mode = plat->mode; + musb->board_set_power = plat->set_power; + musb->set_clock = plat->set_clock; + musb->min_power = plat->min_power; + + /* Clock usage is chip-specific ... functional clock (DaVinci, + * OMAP2430), or PHY ref (some TUSB6010 boards). All this core + * code does is make sure a clock handle is available; platform + * code manages it during start/stop and suspend/resume. + */ + if (plat->clock) { + musb->clock = clk_get(dev, plat->clock); + if (IS_ERR(musb->clock)) { + status = PTR_ERR(musb->clock); + musb->clock = NULL; + goto fail; + } + } + + /* assume vbus is off */ + + /* platform adjusts musb->mregs and musb->isr if needed, + * and activates clocks + */ + musb->isr = generic_interrupt; + status = musb_platform_init(musb); + + if (status < 0) + goto fail; + if (!musb->isr) { + status = -ENODEV; + goto fail2; + } + +#ifndef CONFIG_USB_MUSB_DISABLE_DMA + 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->private_data); + } +#endif + /* ideally this would be abstracted in platform setup */ + if (!is_dma_capable() || !musb->dma_controller) + dev->dma_mask = NULL; + + /* be sure interrupts are disabled before connecting ISR */ + musb_platform_disable(musb); + musb_generic_disable(musb); + + /* setup musb parts of the core (especially endpoints) */ + status = musb_core_init(plat->multipoint + ? MUSB_CONTROLLER_MHDRC + : MUSB_CONTROLLER_HDRC, musb); + if (status < 0) + goto fail2; + + /* attach to the IRQ */ + if (request_irq (nIrq, musb->isr, 0, dev->bus_id, musb)) { + dev_err(dev, "request_irq %d failed!\n", nIrq); + status = -ENODEV; + goto fail2; + } + musb->nIrq = nIrq; +// FIXME this handles wakeup irqs wrong + if (enable_irq_wake(nIrq) == 0) + device_init_wakeup(dev, 1); + + pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n", + musb_driver_name, + ({char *s; + switch (musb->board_mode) { + case MUSB_HOST: s = "Host"; break; + case MUSB_PERIPHERAL: s = "Peripheral"; break; + default: s = "OTG"; break; + }; s; }), + ctrl, + (is_dma_capable() && musb->dma_controller) + ? "DMA" : "PIO", + musb->nIrq); + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + /* host side needs more setup, except for no-host modes */ + if (musb->board_mode != MUSB_PERIPHERAL) { + struct usb_hcd *hcd = musb_to_hcd(musb); + + if (musb->board_mode == MUSB_OTG) + hcd->self.otg_port = 1; + musb->xceiv.host = &hcd->self; + hcd->power_budget = 2 * (plat->power ? : 250); + } +#endif /* CONFIG_USB_MUSB_HDRC_HCD */ + + /* For the host-only role, we can activate right away. + * (We expect the ID pin to be forcibly grounded!!) + * Otherwise, wait till the gadget driver hooks up. + */ + if (!is_otg_enabled(musb) && is_host_enabled(musb)) { + MUSB_HST_MODE(musb); + musb->xceiv.default_a = 1; + musb->xceiv.state = OTG_STATE_A_IDLE; + + status = usb_add_hcd(musb_to_hcd(musb), -1, 0); + + DBG(1, "%s mode, status %d, devctl %02x %c\n", + "HOST", status, + musb_readb(musb->mregs, MUSB_DEVCTL), + (musb_readb(musb->mregs, MUSB_DEVCTL) + & MUSB_DEVCTL_BDEVICE + ? 'B' : 'A')); + + } else /* peripheral is enabled */ { + MUSB_DEV_MODE(musb); + musb->xceiv.default_a = 0; + musb->xceiv.state = OTG_STATE_B_IDLE; + + status = musb_gadget_setup(musb); + + DBG(1, "%s mode, status %d, dev%02x\n", + is_otg_enabled(musb) ? "OTG" : "PERIPHERAL", + status, + musb_readb(musb->mregs, MUSB_DEVCTL)); + + } + + if (status == 0) + musb_debug_create("driver/musb_hdrc", musb); + else { +fail: + if (musb->clock) + clk_put(musb->clock); + device_init_wakeup(dev, 0); + musb_free(musb); + return status; + } + + INIT_WORK(&musb->irq_work, musb_irq_work); + +#ifdef CONFIG_SYSFS + status = device_create_file(dev, &dev_attr_mode); + status = device_create_file(dev, &dev_attr_cable); + status = device_create_file(dev, &dev_attr_vbus); +#ifdef CONFIG_USB_MUSB_OTG + status = device_create_file(dev, &dev_attr_srp); +#endif /* CONFIG_USB_MUSB_OTG */ + status = 0; +#endif + + return status; + +fail2: + musb_platform_exit(musb); + goto fail; +} + +/*-------------------------------------------------------------------------*/ + +/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just + * bridge to a platform device; this driver then suffices. + */ + +#ifndef CONFIG_USB_MUSB_DISABLE_DMA +static u64 *orig_dma_mask; +#endif + +static int __init musb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int irq = platform_get_irq(pdev, 0); + struct resource *iomem; + void __iomem *base; + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem || irq == 0) + return -ENODEV; + + base = ioremap(iomem->start, iomem->end - iomem->start + 1); + if (!base) { + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; + } + +#ifndef CONFIG_USB_MUSB_DISABLE_DMA + /* clobbered by use_dma=n */ + orig_dma_mask = dev->dma_mask; +#endif + return musb_init_controller(dev, irq, base); +} + +static int __devexit musb_remove(struct platform_device *pdev) +{ + struct musb *musb = dev_to_musb(&pdev->dev); + void __iomem *ctrl_base = musb->ctrl_base; + + /* this gets called on rmmod. + * - Host mode: host may still be active + * - Peripheral mode: peripheral is deactivated (or never-activated) + * - OTG mode: both roles are deactivated (or never-activated) + */ + musb_shutdown(pdev); + musb_debug_delete("driver/musb_hdrc", musb); +#ifdef CONFIG_USB_MUSB_HDRC_HCD + if (musb->board_mode == MUSB_HOST) + usb_remove_hcd(musb_to_hcd(musb)); +#endif + musb_free(musb); + iounmap(ctrl_base); + device_init_wakeup(&pdev->dev, 0); +#ifndef CONFIG_USB_MUSB_DISABLE_DMA + pdev->dev.dma_mask = orig_dma_mask; +#endif + return 0; +} + +#ifdef CONFIG_PM + +static int musb_suspend(struct platform_device *pdev, pm_message_t message) +{ + unsigned long flags; + struct musb *musb = dev_to_musb(&pdev->dev); + + if (!musb->clock) + return 0; + + spin_lock_irqsave(&musb->lock, flags); + + if (is_peripheral_active(musb)) { + /* FIXME force disconnect unless we know USB will wake + * the system up quickly enough to respond ... + */ + } else if (is_host_active(musb)) { + /* we know all the children are suspended; sometimes + * they will even be wakeup-enabled. + */ + } + + if (musb->set_clock) + musb->set_clock(musb->clock, 0); + else + clk_disable(musb->clock); + spin_unlock_irqrestore(&musb->lock, flags); + return 0; +} + +static int musb_resume(struct platform_device *pdev) +{ + unsigned long flags; + struct musb *musb = dev_to_musb(&pdev->dev); + + if (!musb->clock) + return 0; + + spin_lock_irqsave(&musb->lock, flags); + + if (musb->set_clock) + musb->set_clock(musb->clock, 1); + else + clk_enable(musb->clock); + + /* for static cmos like DaVinci, register values were preserved + * unless for some reason the whole soc powered down and we're + * not treating that as a whole-system restart (e.g. swsusp) + */ + spin_unlock_irqrestore(&musb->lock, flags); + return 0; +} + +#else +#define musb_suspend NULL +#define musb_resume NULL +#endif + +static struct platform_driver musb_driver = { + .driver = { + .name = (char *)musb_driver_name, + .bus = &platform_bus_type, + .owner = THIS_MODULE, + }, + .remove = __devexit_p(musb_remove), + .shutdown = musb_shutdown, + .suspend = musb_suspend, + .resume = musb_resume, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init musb_init(void) +{ +#ifdef CONFIG_USB_MUSB_HDRC_HCD + if (usb_disabled()) + return 0; +#endif + + pr_info("%s: version " MUSB_VERSION ", " +#ifdef CONFIG_USB_MUSB_DISABLE_DMA + "pio" +#elif defined(CONFIG_USB_TI_CPPI_DMA) + "cppi-dma" +#elif defined(CONFIG_USB_INVENTRA_DMA) + "musb-dma" +#elif defined(CONFIG_USB_TUSB_OMAP_DMA) + "tusb-omap-dma" +#else + "?dma?" +#endif + ", " +#ifdef CONFIG_USB_MUSB_OTG + "otg (peripheral+host)" +#elif defined(CONFIG_USB_GADGET_MUSB_HDRC) + "peripheral" +#elif defined(CONFIG_USB_MUSB_HDRC_HCD) + "host" +#endif + ", debug=%d\n", + musb_driver_name, debug); + return platform_driver_probe(&musb_driver, musb_probe); +} + +/* make us init after usbcore and before usb + * gadget and host-side drivers start to register + */ +subsys_initcall(musb_init); + +static void __exit musb_cleanup(void) +{ + platform_driver_unregister(&musb_driver); +} +module_exit(musb_cleanup); diff --git a/drivers/usb/musb/musbdefs.h b/drivers/usb/musb/musbdefs.h index ccc8d24..a9af51e 100644 --- a/drivers/usb/musb/musbdefs.h +++ b/drivers/usb/musb/musbdefs.h @@ -68,7 +68,7 @@ struct musb_ep; #include <asm/arch/hdrc_cnf.h> #endif -#include "plat_arc.h" +#include "musb_arch.h" #include "musbhdrc.h" #include "musb_gadget.h" diff --git a/drivers/usb/musb/plat_arc.h b/drivers/usb/musb/plat_arc.h deleted file mode 100644 index 5decdbe..0000000 --- a/drivers/usb/musb/plat_arc.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * MUSB OTG driver Linux-specific architecture defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. - * - */ - -#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__ -#define __MUSB_LINUX_PLATFORM_ARCH_H__ - -#include <asm/io.h> - -#ifndef CONFIG_ARM -static inline void readsl(const void __iomem *addr, void *buf, int len) - { insl((unsigned long)addr, buf, len); } -static inline void readsw(const void __iomem *addr, void *buf, int len) - { insw((unsigned long)addr, buf, len); } -static inline void readsb(const void __iomem *addr, void *buf, int len) - { insb((unsigned long)addr, buf, len); } - -static inline void writesl(const void __iomem *addr, const void *buf, int len) - { outsl((unsigned long)addr, buf, len); } -static inline void writesw(const void __iomem *addr, const void *buf, int len) - { outsw((unsigned long)addr, buf, len); } -static inline void writesb(const void __iomem *addr, const void *buf, int len) - { outsb((unsigned long)addr, buf, len); } - -#endif - -/* NOTE: these offsets are all in bytes */ - -static inline u16 musb_readw(const void __iomem *addr, unsigned offset) - { return __raw_readw(addr + offset); } - -static inline u32 musb_readl(const void __iomem *addr, unsigned offset) - { return __raw_readl(addr + offset); } - - -static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data) - { __raw_writew(data, addr + offset); } - -static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) - { __raw_writel(data, addr + offset); } - - -#ifdef CONFIG_USB_TUSB6010 - -/* - * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. - */ -static inline u8 musb_readb(const void __iomem *addr, unsigned offset) -{ - u16 tmp; - u8 val; - - tmp = __raw_readw(addr + (offset & ~1)); - if (offset & 1) - val = (tmp >> 8); - else - val = tmp & 0xff; - - return val; -} - -static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) -{ - u16 tmp; - - tmp = __raw_readw(addr + (offset & ~1)); - if (offset & 1) - tmp = (data << 8) | (tmp & 0xff); - else - tmp = (tmp & 0xff00) | data; - - __raw_writew(tmp, addr + (offset & ~1)); -} - -#else - -static inline u8 musb_readb(const void __iomem *addr, unsigned offset) - { return __raw_readb(addr + offset); } - -static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) - { __raw_writeb(data, addr + offset); } - -#endif /* CONFIG_USB_TUSB6010 */ - -#endif diff --git a/drivers/usb/musb/plat_uds.c b/drivers/usb/musb/plat_uds.c deleted file mode 100644 index e544339..0000000 --- a/drivers/usb/musb/plat_uds.c +++ /dev/null @@ -1,2216 +0,0 @@ -/* - * MUSB OTG driver core code - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. - * - */ - -/* - * Inventra (Multipoint) Dual-Role Controller Driver for Linux. - * - * This consists of a Host Controller Driver (HCD) and a peripheral - * controller driver implementing the "Gadget" API; OTG support is - * in the works. These are normal Linux-USB controller drivers which - * use IRQs and have no dedicated thread. - * - * This version of the driver has only been used with products from - * Texas Instruments. Those products integrate the Inventra logic - * with other DMA, IRQ, and bus modules, as well as other logic that - * needs to be reflected in this driver. - * - * - * NOTE: the original Mentor code here was pretty much a collection - * of mechanisms that don't seem to have been fully integrated/working - * for *any* Linux kernel version. This version aims at Linux 2.6.now, - * Key open issues include: - * - * - Lack of host-side transaction scheduling, for all transfer types. - * The hardware doesn't do it; instead, software must. - * - * This is not an issue for OTG devices that don't support external - * hubs, but for more "normal" USB hosts it's a user issue that the - * "multipoint" support doesn't scale in the expected ways. That - * includes DaVinci EVM in a common non-OTG mode. - * - * * Control and bulk use dedicated endpoints, and there's as - * yet no mechanism to either (a) reclaim the hardware when - * peripherals are NAKing, which gets complicated with bulk - * endpoints, or (b) use more than a single bulk endpoint in - * each direction. - * - * RESULT: one device may be perceived as blocking another one. - * - * * Interrupt and isochronous will dynamically allocate endpoint - * hardware, but (a) there's no record keeping for bandwidth; - * (b) in the common case that few endpoints are available, there - * is no mechanism to reuse endpoints to talk to multiple devices. - * - * RESULT: At one extreme, bandwidth can be overcommitted in - * some hardware configurations, no faults will be reported. - * At the other extreme, the bandwidth capabilities which do - * exist tend to be severely undercommitted. You can't yet hook - * up both a keyboard and a mouse to an external USB hub. - */ - -/* - * This gets many kinds of configuration information: - * - Kconfig for everything user-configurable - * - <asm/arch/hdrc_cnf.h> for SOC or family details - * - platform_device for addressing, irq, and platform_data - * - platform_data is mostly for board-specific informarion - * - * Most of the conditional compilation will (someday) vanish. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/kobject.h> -#include <linux/platform_device.h> - -#include <asm/io.h> - -#ifdef CONFIG_ARM -#include <asm/arch/hardware.h> -#include <asm/arch/memory.h> -#include <asm/mach-types.h> -#endif - -#include "musbdefs.h" - - -#ifdef CONFIG_ARCH_DAVINCI -#include "davinci.h" -#endif - - - -#if MUSB_DEBUG > 0 -unsigned debug = MUSB_DEBUG; -module_param(debug, uint, 0); -MODULE_PARM_DESC(debug, "initial debug message level"); - -#define MUSB_VERSION_SUFFIX "/dbg" -#else - -const char *otg_state_string(struct musb *musb) -{ - static char buf[8]; - - snprintf(buf, sizeof buf, "otg-%d", musb->xceiv.state); - return buf; -} -#endif - -#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia" -#define DRIVER_DESC "Inventra Dual-Role USB Controller Driver" - -#define MUSB_VERSION_BASE "2.2a/db-0.5.2" - -#ifndef MUSB_VERSION_SUFFIX -#define MUSB_VERSION_SUFFIX "" -#endif -#define MUSB_VERSION MUSB_VERSION_BASE MUSB_VERSION_SUFFIX - -#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION - -const char musb_driver_name[] = "musb_hdrc"; - -MODULE_DESCRIPTION(DRIVER_INFO); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); - - -/*-------------------------------------------------------------------------*/ - -static inline struct musb *dev_to_musb(struct device *dev) -{ -#ifdef CONFIG_USB_MUSB_HDRC_HCD - /* usbcore insists dev->driver_data is a "struct hcd *" */ - return hcd_to_musb(dev_get_drvdata(dev)); -#else - return dev_get_drvdata(dev); -#endif -} - -/*-------------------------------------------------------------------------*/ - -#ifndef CONFIG_USB_TUSB6010 -/* - * Load an endpoint's FIFO - */ -void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) -{ - void __iomem *fifo = hw_ep->fifo; - - prefetch((u8 *)src); - - DBG(4, "%cX ep%d fifo %p count %d buf %p\n", - 'T', hw_ep->epnum, fifo, len, src); - - /* we can't assume unaligned reads work */ - if (likely((0x01 & (unsigned long) src) == 0)) { - u16 index = 0; - - /* best case is 32bit-aligned source address */ - if ((0x02 & (unsigned long) src) == 0) { - if (len >= 4) { - writesl(fifo, src + index, len >> 2); - index += len & ~0x03; - } - if (len & 0x02) { - musb_writew(fifo, 0, *(u16*)&src[index]); - index += 2; - } - } else { - if (len >= 2) { - writesw(fifo, src + index, len >> 1); - index += len & ~0x01; - } - } - if (len & 0x01) - musb_writeb(fifo, 0, src[index]); - } else { - /* byte aligned */ - writesb(fifo, src, len); - } -} - -/* - * Unload an endpoint's FIFO - */ -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) -{ - void __iomem *fifo = hw_ep->fifo; - - DBG(4, "%cX ep%d fifo %p count %d buf %p\n", - 'R', hw_ep->epnum, fifo, len, dst); - - /* we can't assume unaligned writes work */ - if (likely((0x01 & (unsigned long) dst) == 0)) { - u16 index = 0; - - /* best case is 32bit-aligned destination address */ - if ((0x02 & (unsigned long) dst) == 0) { - if (len >= 4) { - readsl(fifo, dst, len >> 2); - index = len & ~0x03; - } - if (len & 0x02) { - *(u16*)&dst[index] = musb_readw(fifo, 0); - index += 2; - } - } else { - if (len >= 2) { - readsw(fifo, dst, len >> 1); - index = len & ~0x01; - } - } - if (len & 0x01) - dst[index] = musb_readb(fifo, 0); - } else { - /* byte aligned */ - readsb(fifo, dst, len); - } -} - -#endif /* normal PIO */ - - -/*-------------------------------------------------------------------------*/ - -/* for high speed test mode; see USB 2.0 spec 7.1.20 */ -static const u8 musb_test_packet[53] = { - /* implicit SYNC then DATA0 to start */ - - /* JKJKJKJK x9 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* JJKKJJKK x8 */ - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - /* JJJJKKKK x8 */ - 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, - /* JJJJJJJKKKKKKK x8 */ - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* JJJJJJJK x8 */ - 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, - /* JKKKKKKK x10, JK */ - 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e - - /* implicit CRC16 then EOP to end */ -}; - -void musb_load_testpacket(struct musb *musb) -{ - void __iomem *regs = musb->endpoints[0].regs; - - musb_ep_select(musb->mregs, 0); - musb_write_fifo(musb->control_ep, - sizeof(musb_test_packet), musb_test_packet); - musb_writew(regs, MUSB_CSR0, MUSB_CSR0_TXPKTRDY); -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_MUSB_OTG - -/* - * See also USB_OTG_1-3.pdf 6.6.5 Timers - * REVISIT: Are the other timers done in the hardware? - */ -#define TB_ASE0_BRST 100 /* Min 3.125 ms */ - -/* - * Handles OTG hnp timeouts, such as b_ase0_brst - */ -void musb_otg_timer_func(unsigned long data) -{ - struct musb *musb = (struct musb *)data; - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - if (musb->xceiv.state == OTG_STATE_B_WAIT_ACON) { - DBG(1, "HNP: B_WAIT_ACON timeout, going back to B_PERIPHERAL\n"); - musb_g_disconnect(musb); - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; - musb->is_active = 0; - } - spin_unlock_irqrestore(&musb->lock, flags); -} - -static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0); - -/* - * Stops the B-device HNP state. Caller must take care of locking. - */ -void musb_hnp_stop(struct musb *musb) -{ - struct usb_hcd *hcd = musb_to_hcd(musb); - void __iomem *mbase = musb->mregs; - u8 reg; - - switch (musb->xceiv.state) { - case OTG_STATE_A_PERIPHERAL: - case OTG_STATE_A_WAIT_VFALL: - DBG(1, "HNP: Switching back to A-host\n"); - musb_g_disconnect(musb); - musb_root_disconnect(musb); - musb->xceiv.state = OTG_STATE_A_IDLE; - musb->is_active = 0; - break; - case OTG_STATE_B_HOST: - DBG(1, "HNP: Disabling HR\n"); - hcd->self.is_b_host = 0; - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; - reg = musb_readb(mbase, MUSB_POWER); - reg |= MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, reg); - /* REVISIT: Start SESSION_REQUEST here? */ - break; - default: - DBG(1, "HNP: Stopping in unknown state %s\n", - otg_state_string(musb)); - } -} - -#endif - -/* - * Interrupt Service Routine to record USB "global" interrupts. - * Since these do not happen often and signify things of - * paramount importance, it seems OK to check them individually; - * the order of the tests is specified in the manual - * - * @param musb instance pointer - * @param int_usb register contents - * @param devctl - * @param power - */ - -#define STAGE0_MASK (MUSB_INTR_RESUME | MUSB_INTR_SESSREQ \ - | MUSB_INTR_VBUSERROR | MUSB_INTR_CONNECT \ - | MUSB_INTR_RESET ) - -static irqreturn_t musb_stage0_irq(struct musb * musb, u8 int_usb, - u8 devctl, u8 power) -{ - irqreturn_t handled = IRQ_NONE; -#ifdef CONFIG_USB_MUSB_HDRC_HCD - void __iomem *mbase = musb->mregs; -#endif - - DBG(3, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl, - int_usb); - - /* in host mode, the peripheral may issue remote wakeup. - * in peripheral mode, the host may resume the link. - * spurious RESUME irqs happen too, paired with SUSPEND. - */ - if (int_usb & MUSB_INTR_RESUME) { - handled = IRQ_HANDLED; - DBG(3, "RESUME (%s)\n", otg_state_string(musb)); - - if (devctl & MUSB_DEVCTL_HM) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD - switch (musb->xceiv.state) { - case OTG_STATE_A_SUSPEND: - /* remote wakeup? later, GetPortStatus - * will stop RESUME signaling - */ - - if (power & MUSB_POWER_SUSPENDM) { - /* spurious */ - musb->int_usb &= ~MUSB_INTR_SUSPEND; - DBG(2, "Spurious SUSPENDM\n"); - break; - } - - power &= ~MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, - power | MUSB_POWER_RESUME); - - musb->port1_status |= - (USB_PORT_STAT_C_SUSPEND << 16) - | MUSB_PORT_STAT_RESUME; - musb->rh_timer = jiffies - + msecs_to_jiffies(20); - - musb->xceiv.state = OTG_STATE_A_HOST; - musb->is_active = 1; - usb_hcd_resume_root_hub(musb_to_hcd(musb)); - break; - case OTG_STATE_B_WAIT_ACON: - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; - musb->is_active = 1; - MUSB_DEV_MODE(musb); - break; - default: - WARN("bogus %s RESUME (%s)\n", - "host", - otg_state_string(musb)); - } -#endif - } else { - switch (musb->xceiv.state) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD - case OTG_STATE_A_SUSPEND: - /* possibly DISCONNECT is upcoming */ - musb->xceiv.state = OTG_STATE_A_HOST; - usb_hcd_resume_root_hub(musb_to_hcd(musb)); - break; -#endif -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_PERIPHERAL: - /* disconnect while suspended? we may - * not get a disconnect irq... - */ - if ((devctl & MUSB_DEVCTL_VBUS) - != (3 << MUSB_DEVCTL_VBUS_SHIFT)) { - musb->int_usb |= MUSB_INTR_DISCONNECT; - musb->int_usb &= ~MUSB_INTR_SUSPEND; - break; - } - musb_g_resume(musb); - break; - case OTG_STATE_B_IDLE: - musb->int_usb &= ~MUSB_INTR_SUSPEND; - break; -#endif - default: - WARN("bogus %s RESUME (%s)\n", - "peripheral", - otg_state_string(musb)); - } - } - } - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - /* see manual for the order of the tests */ - if (int_usb & MUSB_INTR_SESSREQ) { - DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(musb)); - - /* IRQ arrives from ID pin sense or (later, if VBUS power - * is removed) SRP. responses are time critical: - * - turn on VBUS (with silicon-specific mechanism) - * - go through A_WAIT_VRISE - * - ... to A_WAIT_BCON. - * a_wait_vrise_tmout triggers VBUS_ERROR transitions - */ - musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - musb->ep0_stage = MUSB_EP0_START; - musb->xceiv.state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - musb_set_vbus(musb, 1); - - handled = IRQ_HANDLED; - } - - if (int_usb & MUSB_INTR_VBUSERROR) { - int ignore = 0; - - /* During connection as an A-Device, we may see a short - * current spikes causing voltage drop, because of cable - * and peripheral capacitance combined with vbus draw. - * (So: less common with truly self-powered devices, where - * vbus doesn't act like a power supply.) - * - * Such spikes are short; usually less than ~500 usec, max - * of ~2 msec. That is, they're not sustained overcurrent - * errors, though they're reported using VBUSERROR irqs. - * - * Workarounds: (a) hardware: use self powered devices. - * (b) software: ignore non-repeated VBUS errors. - * - * REVISIT: do delays from lots of DEBUG_KERNEL checks - * make trouble here, keeping VBUS < 4.4V ? - */ - switch (musb->xceiv.state) { - case OTG_STATE_A_HOST: - /* recovery is dicey once we've gotten past the - * initial stages of enumeration, but if VBUS - * stayed ok at the other end of the link, and - * another reset is due (at least for high speed, - * to redo the chirp etc), it might work OK... - */ - case OTG_STATE_A_WAIT_BCON: - case OTG_STATE_A_WAIT_VRISE: - if (musb->vbuserr_retry) { - musb->vbuserr_retry--; - ignore = 1; - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(mbase, MUSB_DEVCTL, devctl); - } else { - musb->port1_status |= - (1 << USB_PORT_FEAT_OVER_CURRENT) - | (1 << USB_PORT_FEAT_C_OVER_CURRENT); - } - break; - default: - break; - } - - DBG(1, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", - otg_state_string(musb), - devctl, - ({ char *s; - switch (devctl & MUSB_DEVCTL_VBUS) { - case 0 << MUSB_DEVCTL_VBUS_SHIFT: - s = "<SessEnd"; break; - case 1 << MUSB_DEVCTL_VBUS_SHIFT: - s = "<AValid"; break; - case 2 << MUSB_DEVCTL_VBUS_SHIFT: - s = "<VBusValid"; break; - //case 3 << MUSB_DEVCTL_VBUS_SHIFT: - default: - s = "VALID"; break; - }; s; }), - VBUSERR_RETRY_COUNT - musb->vbuserr_retry, - musb->port1_status); - - /* go through A_WAIT_VFALL then start a new session */ - if (!ignore) - musb_set_vbus(musb, 0); - handled = IRQ_HANDLED; - } - - if (int_usb & MUSB_INTR_CONNECT) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - handled = IRQ_HANDLED; - musb->is_active = 1; - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - - musb->ep0_stage = MUSB_EP0_START; - -#ifdef CONFIG_USB_MUSB_OTG - /* flush endpoints when transitioning from Device Mode */ - if (is_peripheral_active(musb)) { - // REVISIT HNP; just force disconnect - } - musb_writew(mbase, MUSB_INTRTXE, musb->epmask); - musb_writew(mbase, MUSB_INTRRXE, musb->epmask & 0xfffe); - musb_writeb(mbase, MUSB_INTRUSBE, 0xf7); -#endif - musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED - |USB_PORT_STAT_HIGH_SPEED - |USB_PORT_STAT_ENABLE - ); - musb->port1_status |= USB_PORT_STAT_CONNECTION - |(USB_PORT_STAT_C_CONNECTION << 16); - - /* high vs full speed is just a guess until after reset */ - if (devctl & MUSB_DEVCTL_LSDEV) - musb->port1_status |= USB_PORT_STAT_LOW_SPEED; - - if (hcd->status_urb) - usb_hcd_poll_rh_status(hcd); - else - usb_hcd_resume_root_hub(hcd); - - MUSB_HST_MODE(musb); - - /* indicate new connection to OTG machine */ - switch (musb->xceiv.state) { - case OTG_STATE_B_WAIT_ACON: - DBG(1, "HNP: Waiting to switch to b_host state\n"); - musb->xceiv.state = OTG_STATE_B_HOST; - hcd->self.is_b_host = 1; - break; - default: - if ((devctl & MUSB_DEVCTL_VBUS) - == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { - musb->xceiv.state = OTG_STATE_A_HOST; - hcd->self.is_b_host = 0; - } - break; - } - DBG(1, "CONNECT (%s) devctl %02x\n", - otg_state_string(musb), devctl); - } -#endif /* CONFIG_USB_MUSB_HDRC_HCD */ - - /* mentor saves a bit: bus reset and babble share the same irq. - * only host sees babble; only peripheral sees bus reset. - */ - if (int_usb & MUSB_INTR_RESET) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD - if (devctl & MUSB_DEVCTL_HM) { - /* - * Looks like non-HS BABBLE can be ignored, but - * HS BABBLE is an error condition. For HS the solution - * is to avoid babble in the first place and fix whatever - * causes BABBLE. When HS BABBLE happens we can only stop - * the session. - */ - if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV)) - DBG(1, "BABBLE devctl: %02x\n", devctl); - else { - ERR("Stopping host session because of babble\n"); - musb_writeb(mbase, MUSB_DEVCTL, 0); - } - } else -#endif /* CONFIG_USB_MUSB_HDRC_HCD */ - { - DBG(1, "BUS RESET\n"); - - musb_g_reset(musb); - schedule_work(&musb->irq_work); - } - - handled = IRQ_HANDLED; - } - - return handled; -} - -/* - * Interrupt Service Routine to record USB "global" interrupts. - * Since these do not happen often and signify things of - * paramount importance, it seems OK to check them individually; - * the order of the tests is specified in the manual - * - * @param musb instance pointer - * @param int_usb register contents - * @param devctl - * @param power - */ -static irqreturn_t musb_stage2_irq(struct musb * musb, u8 int_usb, - u8 devctl, u8 power) -{ - irqreturn_t handled = IRQ_NONE; - -#if 0 -/* REVISIT ... this would be for multiplexing periodic endpoints, or - * supporting transfer phasing to prevent exceeding ISO bandwidth - * limits of a given frame or microframe. - * - * It's not needed for peripheral side, which dedicates endpoints; - * though it _might_ use SOF irqs for other purposes. - * - * And it's not currently needed for host side, which also dedicates - * endpoints, relies on TX/RX interval registers, and isn't claimed - * to support ISO transfers yet. - */ - if (int_usb & MUSB_INTR_SOF) { - void __iomem *mbase = musb->mregs; - struct musb_hw_ep *ep; - u8 epnum; - u16 frame; - - DBG(6, "START_OF_FRAME\n"); - handled = IRQ_HANDLED; - - /* start any periodic Tx transfers waiting for current frame */ - frame = musb_readw(mbase, MUSB_FRAME); - ep = musb->endpoints; - for (epnum = 1; (epnum < musb->nr_endpoints) - && (musb->epmask >= (1 << epnum)); - epnum++, ep++) { - // FIXME handle framecounter wraps (12 bits) - // eliminate duplicated StartUrb logic - if (ep->dwWaitFrame >= frame) { - ep->dwWaitFrame = 0; - printk("SOF --> periodic TX%s on %d\n", - ep->tx_channel ? " DMA" : "", - epnum); - if (!ep->tx_channel) - musb_h_tx_start(musb, epnum); - else - cppi_hostdma_start(musb, epnum); - } - } /* end of for loop */ - } -#endif - - if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) { - DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n", - otg_state_string(musb), - MUSB_MODE(musb), devctl); - handled = IRQ_HANDLED; - - switch (musb->xceiv.state) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD - case OTG_STATE_A_HOST: - case OTG_STATE_A_SUSPEND: - musb_root_disconnect(musb); - if (musb->a_wait_bcon != 0) - musb_platform_try_idle(musb, jiffies - + msecs_to_jiffies(musb->a_wait_bcon)); - break; -#endif /* HOST */ -#ifdef CONFIG_USB_MUSB_OTG - case OTG_STATE_B_HOST: - musb_hnp_stop(musb); - break; - /* FALLTHROUGH */ - case OTG_STATE_A_PERIPHERAL: - musb_root_disconnect(musb); - /* FALLTHROUGH */ - case OTG_STATE_B_WAIT_ACON: -#endif /* OTG */ -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_IDLE: - musb_g_disconnect(musb); - break; -#endif /* GADGET */ - default: - WARN("unhandled DISCONNECT transition (%s)\n", - otg_state_string(musb)); - break; - } - - schedule_work(&musb->irq_work); - } - - if (int_usb & MUSB_INTR_SUSPEND) { - DBG(1, "SUSPEND (%s) devctl %02x power %02x\n", - otg_state_string(musb), devctl, power); - handled = IRQ_HANDLED; - - switch (musb->xceiv.state) { -#ifdef CONFIG_USB_MUSB_OTG - case OTG_STATE_A_PERIPHERAL: - musb_hnp_stop(musb); - break; -#endif - case OTG_STATE_B_PERIPHERAL: - musb_g_suspend(musb); - musb->is_active = is_otg_enabled(musb) - && musb->xceiv.gadget->b_hnp_enable; - if (musb->is_active) { - musb->xceiv.state = OTG_STATE_B_WAIT_ACON; -#ifdef CONFIG_USB_MUSB_OTG - DBG(1, "HNP: Setting timer for b_ase0_brst\n"); - musb_otg_timer.data = (unsigned long)musb; - mod_timer(&musb_otg_timer, jiffies - + msecs_to_jiffies(TB_ASE0_BRST)); -#endif - } - break; - case OTG_STATE_A_WAIT_BCON: - if (musb->a_wait_bcon != 0) - musb_platform_try_idle(musb, jiffies - + msecs_to_jiffies(musb->a_wait_bcon)); - break; - case OTG_STATE_A_HOST: - musb->xceiv.state = OTG_STATE_A_SUSPEND; - musb->is_active = is_otg_enabled(musb) - && musb->xceiv.host->b_hnp_enable; - break; - case OTG_STATE_B_HOST: - /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ - DBG(1, "REVISIT: SUSPEND as B_HOST\n"); - break; - default: - /* "should not happen" */ - musb->is_active = 0; - break; - } - } - - - return handled; -} - -/*-------------------------------------------------------------------------*/ - -/* -* Program the HDRC to start (enable interrupts, dma, etc.). -*/ -void musb_start(struct musb *musb) -{ - void __iomem *regs = musb->mregs; - u8 devctl = musb_readb(regs, MUSB_DEVCTL); - - DBG(2, "<== devctl %02x\n", devctl); - - /* Set INT enable registers, enable interrupts */ - musb_writew(regs, MUSB_INTRTXE, musb->epmask); - musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe); - musb_writeb(regs, MUSB_INTRUSBE, 0xf7); - - musb_writeb(regs, MUSB_TESTMODE, 0); - - /* put into basic highspeed mode and start session */ - musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE - | MUSB_POWER_SOFTCONN - | MUSB_POWER_HSENAB - /* ENSUSPEND wedges tusb */ - // | MUSB_POWER_ENSUSPEND - ); - - musb->is_active = 0; - devctl = musb_readb(regs, MUSB_DEVCTL); - devctl &= ~MUSB_DEVCTL_SESSION; - - if (is_otg_enabled(musb)) { - /* session started after: - * (a) ID-grounded irq, host mode; - * (b) vbus present/connect IRQ, peripheral mode; - * (c) peripheral initiates, using SRP - */ - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - else - devctl |= MUSB_DEVCTL_SESSION; - - } else if (is_host_enabled(musb)) { - /* assume ID pin is hard-wired to ground */ - devctl |= MUSB_DEVCTL_SESSION; - - } else /* peripheral is enabled */ { - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - } - musb_platform_enable(musb); - musb_writeb(regs, MUSB_DEVCTL, devctl); -} - - -static void musb_generic_disable(struct musb *musb) -{ - void __iomem *mbase = musb->mregs; - u16 temp; - - /* disable interrupts */ - musb_writeb(mbase, MUSB_INTRUSBE, 0); - musb_writew(mbase, MUSB_INTRTXE, 0); - musb_writew(mbase, MUSB_INTRRXE, 0); - - /* off */ - musb_writeb(mbase, MUSB_DEVCTL, 0); - - /* flush pending interrupts */ - temp = musb_readb(mbase, MUSB_INTRUSB); - temp = musb_readw(mbase, MUSB_INTRTX); - temp = musb_readw(mbase, MUSB_INTRRX); - -} - -/* - * Make the HDRC stop (disable interrupts, etc.); - * reversible by musb_start - * called on gadget driver unregister - * with controller locked, irqs blocked - * acts as a NOP unless some role activated the hardware - */ -void musb_stop(struct musb *musb) -{ - /* stop IRQs, timers, ... */ - musb_platform_disable(musb); - musb_generic_disable(musb); - DBG(3, "HDRC disabled\n"); - - /* FIXME - * - mark host and/or peripheral drivers unusable/inactive - * - disable DMA (and enable it in HdrcStart) - * - make sure we can musb_start() after musb_stop(); with - * OTG mode, gadget driver module rmmod/modprobe cycles that - * - ... - */ - musb_platform_try_idle(musb, 0); -} - -static void musb_shutdown(struct platform_device *pdev) -{ - struct musb *musb = dev_to_musb(&pdev->dev); - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - musb_platform_disable(musb); - musb_generic_disable(musb); - if (musb->clock) { - clk_put(musb->clock); - musb->clock = NULL; - } - spin_unlock_irqrestore(&musb->lock, flags); - - /* FIXME power down */ -} - - -/*-------------------------------------------------------------------------*/ - -/* - * The silicon either has hard-wired endpoint configurations, or else - * "dynamic fifo" sizing. The driver has support for both, though at this - * writing only the dynamic sizing is very well tested. We use normal - * idioms to so both modes are compile-tested, but dead code elimination - * leaves only the relevant one in the object file. - * - * We don't currently use dynamic fifo setup capability to do anything - * more than selecting one of a bunch of predefined configurations. - */ -#ifdef MUSB_C_DYNFIFO_DEF -#define can_dynfifo() 1 -#else -#define can_dynfifo() 0 -#endif - -#ifdef CONFIG_USB_TUSB6010 -static ushort __initdata fifo_mode = 4; -#else -static ushort __initdata fifo_mode = 2; -#endif - -/* "modprobe ... fifo_mode=1" etc */ -module_param(fifo_mode, ushort, 0); -MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration"); - - -#define DYN_FIFO_SIZE (1<<(MUSB_C_RAM_BITS+2)) - -enum fifo_style { FIFO_RXTX, FIFO_TX, FIFO_RX } __attribute__ ((packed)); -enum buf_mode { BUF_SINGLE, BUF_DOUBLE } __attribute__ ((packed)); - -struct fifo_cfg { - u8 hw_ep_num; - enum fifo_style style; - enum buf_mode mode; - u16 maxpacket; -}; - -/* - * tables defining fifo_mode values. define more if you like. - * for host side, make sure both halves of ep1 are set up. - */ - -/* mode 0 - fits in 2KB */ -static struct fifo_cfg __initdata mode_0_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, -}; - -/* mode 1 - fits in 4KB */ -static struct fifo_cfg __initdata mode_1_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, -}; - -/* mode 2 - fits in 4KB */ -static struct fifo_cfg __initdata mode_2_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, -}; - -/* mode 3 - fits in 4KB */ -static struct fifo_cfg __initdata mode_3_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, -}; - -/* mode 4 - fits in 16KB */ -static struct fifo_cfg __initdata mode_4_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, }, -{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, }, -}; - - -/* - * configure a fifo; for non-shared endpoints, this may be called - * once for a tx fifo and once for an rx fifo. - * - * returns negative errno or offset for next fifo. - */ -static int __init -fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, - const struct fifo_cfg *cfg, u16 offset) -{ - void __iomem *mbase = musb->mregs; - int size = 0; - u16 maxpacket = cfg->maxpacket; - u16 c_off = offset >> 3; - u8 c_size; - - /* expect hw_ep has already been zero-initialized */ - - size = ffs(max(maxpacket, (u16) 8)) - 1; - maxpacket = 1 << size; - - c_size = size - 3; - if (cfg->mode == BUF_DOUBLE) { - if ((offset + (maxpacket << 1)) > DYN_FIFO_SIZE) - return -EMSGSIZE; - c_size |= MUSB_FIFOSZ_DPB; - } else { - if ((offset + maxpacket) > DYN_FIFO_SIZE) - return -EMSGSIZE; - } - - /* configure the FIFO */ - musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum); - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - /* EP0 reserved endpoint for control, bidirectional; - * EP1 reserved for bulk, two unidirection halves. - */ - if (hw_ep->epnum == 1) - musb->bulk_ep = hw_ep; - /* REVISIT error check: be sure ep0 can both rx and tx ... */ -#endif - switch (cfg->style) { - case FIFO_TX: - musb_writeb(mbase, MUSB_TXFIFOSZ, c_size); - musb_writew(mbase, MUSB_TXFIFOADD, c_off); - hw_ep->tx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); - hw_ep->max_packet_sz_tx = maxpacket; - break; - case FIFO_RX: - musb_writeb(mbase, MUSB_RXFIFOSZ, c_size); - musb_writew(mbase, MUSB_RXFIFOADD, c_off); - hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); - hw_ep->max_packet_sz_rx = maxpacket; - break; - case FIFO_RXTX: - musb_writeb(mbase, MUSB_TXFIFOSZ, c_size); - musb_writew(mbase, MUSB_TXFIFOADD, c_off); - hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); - hw_ep->max_packet_sz_rx = maxpacket; - - musb_writeb(mbase, MUSB_RXFIFOSZ, c_size); - musb_writew(mbase, MUSB_RXFIFOADD, c_off); - hw_ep->tx_double_buffered = hw_ep->rx_double_buffered; - hw_ep->max_packet_sz_tx = maxpacket; - - hw_ep->is_shared_fifo = TRUE; - break; - } - - /* NOTE rx and tx endpoint irqs aren't managed separately, - * which happens to be ok - */ - musb->epmask |= (1 << hw_ep->epnum); - - return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0)); -} - -static struct fifo_cfg __initdata ep0_cfg = { - .style = FIFO_RXTX, .maxpacket = 64, -}; - -static int __init ep_config_from_table(struct musb *musb) -{ - const struct fifo_cfg *cfg; - unsigned i, n; - int offset; - struct musb_hw_ep *hw_ep = musb->endpoints; - - switch (fifo_mode) { - default: - fifo_mode = 0; - /* FALLTHROUGH */ - case 0: - cfg = mode_0_cfg; - n = ARRAY_SIZE(mode_0_cfg); - break; - case 1: - cfg = mode_1_cfg; - n = ARRAY_SIZE(mode_1_cfg); - break; - case 2: - cfg = mode_2_cfg; - n = ARRAY_SIZE(mode_2_cfg); - break; - case 3: - cfg = mode_3_cfg; - n = ARRAY_SIZE(mode_3_cfg); - break; - case 4: - cfg = mode_4_cfg; - n = ARRAY_SIZE(mode_4_cfg); - break; - } - - printk(KERN_DEBUG "%s: setup fifo_mode %d\n", - musb_driver_name, fifo_mode); - - - offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0); - // assert(offset > 0) - - /* NOTE: for RTL versions >= 1.400 EPINFO and RAMINFO would - * be better than static MUSB_C_NUM_EPS and DYN_FIFO_SIZE... - */ - - for (i = 0; i < n; i++) { - u8 epn = cfg->hw_ep_num; - - if (epn >= MUSB_C_NUM_EPS) { - pr_debug( "%s: invalid ep %d\n", - musb_driver_name, epn); - continue; - } - offset = fifo_setup(musb, hw_ep + epn, cfg++, offset); - if (offset < 0) { - pr_debug( "%s: mem overrun, ep %d\n", - musb_driver_name, epn); - return -EINVAL; - } - epn++; - musb->nr_endpoints = max(epn, musb->nr_endpoints); - } - - printk(KERN_DEBUG "%s: %d/%d max ep, %d/%d memory\n", - musb_driver_name, - n + 1, MUSB_C_NUM_EPS * 2 - 1, - offset, DYN_FIFO_SIZE); - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - if (!musb->bulk_ep) { - pr_debug( "%s: missing bulk\n", musb_driver_name); - return -EINVAL; - } -#endif - - return 0; -} - - -/* - * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false - * @param musb the controller - */ -static int __init ep_config_from_hw(struct musb *musb) -{ - u8 epnum = 0, reg; - struct musb_hw_ep *hw_ep; - void *mbase = musb->mregs; - - DBG(2, "<== static silicon ep config\n"); - - /* FIXME pick up ep0 maxpacket size */ - - for (epnum = 1; epnum < MUSB_C_NUM_EPS; epnum++) { - musb_ep_select(mbase, epnum); - hw_ep = musb->endpoints + epnum; - - /* read from core using indexed model */ - reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE); - if (!reg) { - /* 0's returned when no more endpoints */ - break; - } - musb->nr_endpoints++; - musb->epmask |= (1 << epnum); - - hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f); - - /* shared TX/RX FIFO? */ - if ((reg & 0xf0) == 0xf0) { - hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx; - hw_ep->is_shared_fifo = TRUE; - continue; - } else { - hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4); - hw_ep->is_shared_fifo = FALSE; - } - - /* FIXME set up hw_ep->{rx,tx}_double_buffered */ - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - /* pick an RX/TX endpoint for bulk */ - if (hw_ep->max_packet_sz_tx < 512 - || hw_ep->max_packet_sz_rx < 512) - continue; - - /* REVISIT: this algorithm is lazy, we should at least - * try to pick a double buffered endpoint. - */ - if (musb->bulk_ep) - continue; - musb->bulk_ep = hw_ep; -#endif - } - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - if (!musb->bulk_ep) { - pr_debug( "%s: missing bulk\n", musb_driver_name); - return -EINVAL; - } -#endif - - return 0; -} - -enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, }; - -/* Initialize MUSB (M)HDRC part of the USB hardware subsystem; - * configure endpoints, or take their config from silicon - */ -static int __init musb_core_init(u16 musb_type, struct musb *musb) -{ -#ifdef MUSB_AHB_ID - u32 data; -#endif - u8 reg; - char *type; - u16 hwvers, rev_major, rev_minor; - char aInfo[78], aRevision[32], aDate[12]; - void __iomem *mbase = musb->mregs; - int status = 0; - int i; - - /* log core options (read using indexed model) */ - musb_ep_select(mbase, 0); - reg = musb_readb(mbase, 0x10 + MUSB_CONFIGDATA); - - strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8"); - if (reg & MUSB_CONFIGDATA_DYNFIFO) { - strcat(aInfo, ", dyn FIFOs"); - } - if (reg & MUSB_CONFIGDATA_MPRXE) { - strcat(aInfo, ", bulk combine"); -#ifdef C_MP_RX - musb->bulk_combine = TRUE; -#else - strcat(aInfo, " (X)"); /* no driver support */ -#endif - } - if (reg & MUSB_CONFIGDATA_MPTXE) { - strcat(aInfo, ", bulk split"); -#ifdef C_MP_TX - musb->bulk_split = TRUE; -#else - strcat(aInfo, " (X)"); /* no driver support */ -#endif - } - if (reg & MUSB_CONFIGDATA_HBRXE) { - strcat(aInfo, ", HB-ISO Rx"); - strcat(aInfo, " (X)"); /* no driver support */ - } - if (reg & MUSB_CONFIGDATA_HBTXE) { - strcat(aInfo, ", HB-ISO Tx"); - strcat(aInfo, " (X)"); /* no driver support */ - } - if (reg & MUSB_CONFIGDATA_SOFTCONE) { - strcat(aInfo, ", SoftConn"); - } - - printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n", - musb_driver_name, reg, aInfo); - -#ifdef MUSB_AHB_ID - data = musb_readl(mbase, 0x404); - sprintf(aDate, "%04d-%02x-%02x", (data & 0xffff), - (data >> 16) & 0xff, (data >> 24) & 0xff); - /* FIXME ID2 and ID3 are unused */ - data = musb_readl(mbase, 0x408); - printk("ID2=%lx\n", (long unsigned)data); - data = musb_readl(mbase, 0x40c); - printk("ID3=%lx\n", (long unsigned)data); - reg = musb_readb(mbase, 0x400); - musb_type = ('M' == reg) ? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC; -#else - aDate[0] = 0; -#endif - if (MUSB_CONTROLLER_MHDRC == musb_type) { - musb->is_multipoint = 1; - type = "M"; - } else { - musb->is_multipoint = 0; - type = ""; -#ifdef CONFIG_USB_MUSB_HDRC_HCD -#ifndef CONFIG_USB_OTG_BLACKLIST_HUB - printk(KERN_ERR - "%s: kernel must blacklist external hubs\n", - musb_driver_name); -#endif -#endif - } - - /* log release info */ - hwvers = musb_readw(mbase, MUSB_HWVERS); - rev_major = (hwvers >> 10) & 0x1f; - rev_minor = hwvers & 0x3ff; - snprintf(aRevision, 32, "%d.%d%s", rev_major, - rev_minor, (hwvers & 0x8000) ? "RC" : ""); - printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n", - musb_driver_name, type, aRevision, aDate); - - /* configure ep0 */ - musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE; - musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE; - - /* discover endpoint configuration */ - musb->nr_endpoints = 1; - musb->epmask = 1; - - if (reg & MUSB_CONFIGDATA_DYNFIFO) { - if (can_dynfifo()) - status = ep_config_from_table(musb); - else { - ERR("reconfigure software for Dynamic FIFOs\n"); - status = -ENODEV; - } - } else { - if (!can_dynfifo()) - status = ep_config_from_hw(musb); - else { - ERR("reconfigure software for static FIFOs\n"); - return -ENODEV; - } - } - - if (status < 0) - return status; - - /* finish init, and print endpoint config */ - for (i = 0; i < musb->nr_endpoints; i++) { - struct musb_hw_ep *hw_ep = musb->endpoints + i; - - hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase; -#ifdef CONFIG_USB_TUSB6010 - hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i); - hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i); - hw_ep->fifo_sync_va = - musb->sync_va + 0x400 + MUSB_FIFO_OFFSET(i); - - if (i == 0) - hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF; - else - hw_ep->conf = mbase + 0x400 + (((i - 1) & 0xf) << 2); -#endif - - hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase; -#ifdef CONFIG_USB_MUSB_HDRC_HCD - hw_ep->target_regs = MUSB_BUSCTL_OFFSET(i, 0) + mbase; - hw_ep->rx_reinit = 1; - hw_ep->tx_reinit = 1; -#endif - - if (hw_ep->max_packet_sz_tx) { - printk(KERN_DEBUG - "%s: hw_ep %d%s, %smax %d\n", - musb_driver_name, i, - hw_ep->is_shared_fifo ? "shared" : "tx", - hw_ep->tx_double_buffered - ? "doublebuffer, " : "", - hw_ep->max_packet_sz_tx); - } - if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) { - printk(KERN_DEBUG - "%s: hw_ep %d%s, %smax %d\n", - musb_driver_name, i, - "rx", - hw_ep->rx_double_buffered - ? "doublebuffer, " : "", - hw_ep->max_packet_sz_rx); - } - if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx)) - DBG(1, "hw_ep %d not configured\n", i); - } - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) - -static irqreturn_t generic_interrupt(int irq, void *__hci) -{ - unsigned long flags; - irqreturn_t retval = IRQ_NONE; - struct musb *musb = __hci; - - spin_lock_irqsave(&musb->lock, flags); - - musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); - musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); - musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - - if (musb->int_usb || musb->int_tx || musb->int_rx) - retval = musb_interrupt(musb); - - spin_unlock_irqrestore(&musb->lock, flags); - - /* REVISIT we sometimes get spurious IRQs on g_ep0 - * not clear why... - */ - if (retval != IRQ_HANDLED) - DBG(5, "spurious?\n"); - - return IRQ_HANDLED; -} - -#else -#define generic_interrupt NULL -#endif - -/* - * handle all the irqs defined by the HDRC core. for now we expect: other - * irq sources (phy, dma, etc) will be handled first, musb->int_* values - * will be assigned, and the irq will already have been acked. - * - * called in irq context with spinlock held, irqs blocked - */ -irqreturn_t musb_interrupt(struct musb *musb) -{ - irqreturn_t retval = IRQ_NONE; - u8 devctl, power; - int ep_num; - u32 reg; - - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - power = musb_readb(musb->mregs, MUSB_POWER); - - DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n", - (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", - musb->int_usb, musb->int_tx, musb->int_rx); - - /* the core can interrupt us for multiple reasons; docs have - * a generic interrupt flowchart to follow - */ - if (musb->int_usb & STAGE0_MASK) - retval |= musb_stage0_irq(musb, musb->int_usb, - devctl, power); - - /* "stage 1" is handling endpoint irqs */ - - /* handle endpoint 0 first */ - if (musb->int_tx & 1) { - if (devctl & MUSB_DEVCTL_HM) - retval |= musb_h_ep0_irq(musb); - else - retval |= musb_g_ep0_irq(musb); - } - - /* RX on endpoints 1-15 */ - reg = musb->int_rx >> 1; - ep_num = 1; - while (reg) { - if (reg & 1) { - // musb_ep_select(musb->mregs, ep_num); - /* REVISIT just retval = ep->rx_irq(...) */ - retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, ep_num); - } - } - - reg >>= 1; - ep_num++; - } - - /* TX on endpoints 1-15 */ - reg = musb->int_tx >> 1; - ep_num = 1; - while (reg) { - if (reg & 1) { - // musb_ep_select(musb->mregs, ep_num); - /* REVISIT just retval |= ep->tx_irq(...) */ - retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, ep_num); - } - } - reg >>= 1; - ep_num++; - } - - /* finish handling "global" interrupts after handling fifos */ - if (musb->int_usb) - retval |= musb_stage2_irq(musb, - musb->int_usb, devctl, power); - - return retval; -} - - -#ifndef CONFIG_USB_MUSB_DISABLE_DMA -static int __initdata use_dma = 1; - -/* "modprobe ... use_dma=0" etc */ -module_param(use_dma, bool, 0); -MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); - -void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) -{ - u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - - /* called with controller lock already held */ - - if (!epnum) { -#ifndef CONFIG_USB_TUSB_OMAP_DMA - if (!is_cppi_enabled()) { - /* endpoint 0 */ - if (devctl & MUSB_DEVCTL_HM) - musb_h_ep0_irq(musb); - else - musb_g_ep0_irq(musb); - } -#endif - } else { - /* endpoints 1..15 */ - if (transmit) { - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, epnum); - } - } else { - /* receive */ - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, epnum); - } - } - } -} - -#else -#define use_dma 0 -#endif - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_SYSFS - -static ssize_t -musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&musb->lock, flags); - ret = sprintf(buf, "%s\n", otg_state_string(musb)); - spin_unlock_irqrestore(&musb->lock, flags); - - return ret; -} - -static ssize_t -musb_mode_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - if (!strncmp(buf, "host", 4)) - musb_platform_set_mode(musb, MUSB_HOST); - if (!strncmp(buf, "peripheral", 10)) - musb_platform_set_mode(musb, MUSB_PERIPHERAL); - if (!strncmp(buf, "otg", 3)) - musb_platform_set_mode(musb, MUSB_OTG); - spin_unlock_irqrestore(&musb->lock, flags); - - return n; -} -static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store); - -static ssize_t -musb_cable_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct musb *musb = dev_to_musb(dev); - char *v1= "", *v2 = "?"; - unsigned long flags; - int vbus; - - spin_lock_irqsave(&musb->lock, flags); -#if defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_USB_MUSB_OTG) - /* REVISIT: connect-A != connect-B ... */ - vbus = musb_platform_get_vbus_status(musb); - if (vbus) - v2 = "connected"; - else - v2 = "disconnected"; -#else - /* NOTE: board-specific issues, like too-big capacitors keeping - * VBUS high for a long time after power has been removed, can - * cause temporary false indications of a connection. - */ - vbus = musb_readb(musb->mregs, MUSB_DEVCTL); - if (vbus & 0x10) { - /* REVISIT retest on real OTG hardware */ - switch (musb->board_mode) { - case MUSB_HOST: - v2 = "A"; - break; - case MUSB_PERIPHERAL: - v2 = "B"; - break; - case MUSB_OTG: - v1 = "Mini-"; - v2 = (vbus & MUSB_DEVCTL_BDEVICE) ? "B" : "A"; - break; - } - } else /* VBUS level below A-Valid */ - v2 = "disconnected"; -#endif - musb_platform_try_idle(musb, 0); - spin_unlock_irqrestore(&musb->lock, flags); - - return sprintf(buf, "%s%s\n", v1, v2); -} -static DEVICE_ATTR(cable, S_IRUGO, musb_cable_show, NULL); - -static ssize_t -musb_vbus_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - unsigned long val; - - spin_lock_irqsave(&musb->lock, flags); - if (sscanf(buf, "%lu", &val) < 1) { - printk(KERN_ERR "Invalid VBUS timeout ms value\n"); - return -EINVAL; - } - musb->a_wait_bcon = val; - if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON) - musb->is_active = 0; - musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val)); - spin_unlock_irqrestore(&musb->lock, flags); - - return n; -} - -static ssize_t -musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - unsigned long val; - - spin_lock_irqsave(&musb->lock, flags); - val = musb->a_wait_bcon; - spin_unlock_irqrestore(&musb->lock, flags); - - return sprintf(buf, "%lu\n", val); -} -static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store); - -static ssize_t -musb_srp_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb=dev_to_musb(dev); - unsigned short srp; - - if (sscanf(buf, "%hu", &srp) != 1 - || (srp != 1)) { - printk (KERN_ERR "SRP: Value must be 1\n"); - return -EINVAL; - } - - if (srp == 1) - musb_g_wakeup(musb); - - return n; -} -static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); -#endif - -/* Only used to provide cable state change events */ -static void musb_irq_work(struct work_struct *data) -{ - struct musb *musb = container_of(data, struct musb, irq_work); - - sysfs_notify(&musb->controller->kobj, NULL, "cable"); -} - -/* -------------------------------------------------------------------------- - * Init support - */ - -static struct musb *__init -allocate_instance(struct device *dev, void __iomem *mbase) -{ - struct musb *musb; - struct musb_hw_ep *ep; - int epnum; -#ifdef CONFIG_USB_MUSB_HDRC_HCD - struct usb_hcd *hcd; - - hcd = usb_create_hcd(&musb_hc_driver, dev, dev->bus_id); - if (!hcd) - return NULL; - /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ - - musb = hcd_to_musb(hcd); - INIT_LIST_HEAD(&musb->control); - INIT_LIST_HEAD(&musb->in_bulk); - INIT_LIST_HEAD(&musb->out_bulk); - - hcd->uses_new_polling = 1; - - musb->vbuserr_retry = VBUSERR_RETRY_COUNT; -#else - musb = kzalloc(sizeof *musb, GFP_KERNEL); - if (!musb) - return NULL; - dev_set_drvdata(dev, musb); - -#endif - - musb->mregs = mbase; - musb->ctrl_base = mbase; - musb->nIrq = -ENODEV; - for (epnum = 0, ep = musb->endpoints; - epnum < MUSB_C_NUM_EPS; - epnum++, ep++) { - - ep->musb = musb; - ep->epnum = epnum; - } - - musb->controller = dev; - return musb; -} - -static void musb_free(struct musb *musb) -{ - /* this has multiple entry modes. it handles fault cleanup after - * probe(), where things may be partially set up, as well as rmmod - * cleanup after everything's been de-activated. - */ - -#ifdef CONFIG_SYSFS - device_remove_file(musb->controller, &dev_attr_mode); - device_remove_file(musb->controller, &dev_attr_cable); - device_remove_file(musb->controller, &dev_attr_vbus); -#ifdef CONFIG_USB_MUSB_OTG - device_remove_file(musb->controller, &dev_attr_srp); -#endif -#endif - -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - musb_gadget_cleanup(musb); -#endif - - if (musb->nIrq >= 0) { - 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->private_data); - dma_controller_destroy(c); - } - - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - musb_platform_exit(musb); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - - if (musb->clock) { - clk_disable(musb->clock); - clk_put(musb->clock); - } - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - usb_put_hcd(musb_to_hcd(musb)); -#else - kfree(musb); -#endif -} - -/* - * Perform generic per-controller initialization. - * - * @pDevice: the controller (already clocked, etc) - * @nIrq: irq - * @mregs: virtual address of controller registers, - * not yet corrected for platform-specific offsets - */ -static int __init -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; - - /* The driver might handle more features than the board; OK. - * Fail when the board needs a feature that's not enabled. - */ - if (!plat) { - dev_dbg(dev, "no platform_data?\n"); - return -ENODEV; - } - switch (plat->mode) { - case MUSB_HOST: -#ifdef CONFIG_USB_MUSB_HDRC_HCD - break; -#else - goto bad_config; -#endif - case MUSB_PERIPHERAL: -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - break; -#else - goto bad_config; -#endif - case MUSB_OTG: -#ifdef CONFIG_USB_MUSB_OTG - break; -#else - bad_config: -#endif - default: - dev_err(dev, "incompatible Kconfig role setting\n"); - return -EINVAL; - } - - /* allocate */ - musb = allocate_instance(dev, ctrl); - if (!musb) - return -ENOMEM; - - spin_lock_init(&musb->lock); - musb->board_mode = plat->mode; - musb->board_set_power = plat->set_power; - musb->set_clock = plat->set_clock; - musb->min_power = plat->min_power; - - /* Clock usage is chip-specific ... functional clock (DaVinci, - * OMAP2430), or PHY ref (some TUSB6010 boards). All this core - * code does is make sure a clock handle is available; platform - * code manages it during start/stop and suspend/resume. - */ - if (plat->clock) { - musb->clock = clk_get(dev, plat->clock); - if (IS_ERR(musb->clock)) { - status = PTR_ERR(musb->clock); - musb->clock = NULL; - goto fail; - } - } - - /* assume vbus is off */ - - /* platform adjusts musb->mregs and musb->isr if needed, - * and activates clocks - */ - musb->isr = generic_interrupt; - status = musb_platform_init(musb); - - if (status < 0) - goto fail; - if (!musb->isr) { - status = -ENODEV; - goto fail2; - } - -#ifndef CONFIG_USB_MUSB_DISABLE_DMA - 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->private_data); - } -#endif - /* ideally this would be abstracted in platform setup */ - if (!is_dma_capable() || !musb->dma_controller) - dev->dma_mask = NULL; - - /* be sure interrupts are disabled before connecting ISR */ - musb_platform_disable(musb); - musb_generic_disable(musb); - - /* setup musb parts of the core (especially endpoints) */ - status = musb_core_init(plat->multipoint - ? MUSB_CONTROLLER_MHDRC - : MUSB_CONTROLLER_HDRC, musb); - if (status < 0) - goto fail2; - - /* attach to the IRQ */ - if (request_irq (nIrq, musb->isr, 0, dev->bus_id, musb)) { - dev_err(dev, "request_irq %d failed!\n", nIrq); - status = -ENODEV; - goto fail2; - } - musb->nIrq = nIrq; -// FIXME this handles wakeup irqs wrong - if (enable_irq_wake(nIrq) == 0) - device_init_wakeup(dev, 1); - - pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n", - musb_driver_name, - ({char *s; - switch (musb->board_mode) { - case MUSB_HOST: s = "Host"; break; - case MUSB_PERIPHERAL: s = "Peripheral"; break; - default: s = "OTG"; break; - }; s; }), - ctrl, - (is_dma_capable() && musb->dma_controller) - ? "DMA" : "PIO", - musb->nIrq); - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - /* host side needs more setup, except for no-host modes */ - if (musb->board_mode != MUSB_PERIPHERAL) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - if (musb->board_mode == MUSB_OTG) - hcd->self.otg_port = 1; - musb->xceiv.host = &hcd->self; - hcd->power_budget = 2 * (plat->power ? : 250); - } -#endif /* CONFIG_USB_MUSB_HDRC_HCD */ - - /* For the host-only role, we can activate right away. - * (We expect the ID pin to be forcibly grounded!!) - * Otherwise, wait till the gadget driver hooks up. - */ - if (!is_otg_enabled(musb) && is_host_enabled(musb)) { - MUSB_HST_MODE(musb); - musb->xceiv.default_a = 1; - musb->xceiv.state = OTG_STATE_A_IDLE; - - status = usb_add_hcd(musb_to_hcd(musb), -1, 0); - - DBG(1, "%s mode, status %d, devctl %02x %c\n", - "HOST", status, - musb_readb(musb->mregs, MUSB_DEVCTL), - (musb_readb(musb->mregs, MUSB_DEVCTL) - & MUSB_DEVCTL_BDEVICE - ? 'B' : 'A')); - - } else /* peripheral is enabled */ { - MUSB_DEV_MODE(musb); - musb->xceiv.default_a = 0; - musb->xceiv.state = OTG_STATE_B_IDLE; - - status = musb_gadget_setup(musb); - - DBG(1, "%s mode, status %d, dev%02x\n", - is_otg_enabled(musb) ? "OTG" : "PERIPHERAL", - status, - musb_readb(musb->mregs, MUSB_DEVCTL)); - - } - - if (status == 0) - musb_debug_create("driver/musb_hdrc", musb); - else { -fail: - if (musb->clock) - clk_put(musb->clock); - device_init_wakeup(dev, 0); - musb_free(musb); - return status; - } - - INIT_WORK(&musb->irq_work, musb_irq_work); - -#ifdef CONFIG_SYSFS - status = device_create_file(dev, &dev_attr_mode); - status = device_create_file(dev, &dev_attr_cable); - status = device_create_file(dev, &dev_attr_vbus); -#ifdef CONFIG_USB_MUSB_OTG - status = device_create_file(dev, &dev_attr_srp); -#endif /* CONFIG_USB_MUSB_OTG */ - status = 0; -#endif - - return status; - -fail2: - musb_platform_exit(musb); - goto fail; -} - -/*-------------------------------------------------------------------------*/ - -/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just - * bridge to a platform device; this driver then suffices. - */ - -#ifndef CONFIG_USB_MUSB_DISABLE_DMA -static u64 *orig_dma_mask; -#endif - -static int __init musb_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int irq = platform_get_irq(pdev, 0); - struct resource *iomem; - void __iomem *base; - - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem || irq == 0) - return -ENODEV; - - base = ioremap(iomem->start, iomem->end - iomem->start + 1); - if (!base) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } - -#ifndef CONFIG_USB_MUSB_DISABLE_DMA - /* clobbered by use_dma=n */ - orig_dma_mask = dev->dma_mask; -#endif - return musb_init_controller(dev, irq, base); -} - -static int __devexit musb_remove(struct platform_device *pdev) -{ - struct musb *musb = dev_to_musb(&pdev->dev); - void __iomem *ctrl_base = musb->ctrl_base; - - /* this gets called on rmmod. - * - Host mode: host may still be active - * - Peripheral mode: peripheral is deactivated (or never-activated) - * - OTG mode: both roles are deactivated (or never-activated) - */ - musb_shutdown(pdev); - musb_debug_delete("driver/musb_hdrc", musb); -#ifdef CONFIG_USB_MUSB_HDRC_HCD - if (musb->board_mode == MUSB_HOST) - usb_remove_hcd(musb_to_hcd(musb)); -#endif - musb_free(musb); - iounmap(ctrl_base); - device_init_wakeup(&pdev->dev, 0); -#ifndef CONFIG_USB_MUSB_DISABLE_DMA - pdev->dev.dma_mask = orig_dma_mask; -#endif - return 0; -} - -#ifdef CONFIG_PM - -static int musb_suspend(struct platform_device *pdev, pm_message_t message) -{ - unsigned long flags; - struct musb *musb = dev_to_musb(&pdev->dev); - - if (!musb->clock) - return 0; - - spin_lock_irqsave(&musb->lock, flags); - - if (is_peripheral_active(musb)) { - /* FIXME force disconnect unless we know USB will wake - * the system up quickly enough to respond ... - */ - } else if (is_host_active(musb)) { - /* we know all the children are suspended; sometimes - * they will even be wakeup-enabled. - */ - } - - if (musb->set_clock) - musb->set_clock(musb->clock, 0); - else - clk_disable(musb->clock); - spin_unlock_irqrestore(&musb->lock, flags); - return 0; -} - -static int musb_resume(struct platform_device *pdev) -{ - unsigned long flags; - struct musb *musb = dev_to_musb(&pdev->dev); - - if (!musb->clock) - return 0; - - spin_lock_irqsave(&musb->lock, flags); - - if (musb->set_clock) - musb->set_clock(musb->clock, 1); - else - clk_enable(musb->clock); - - /* for static cmos like DaVinci, register values were preserved - * unless for some reason the whole soc powered down and we're - * not treating that as a whole-system restart (e.g. swsusp) - */ - spin_unlock_irqrestore(&musb->lock, flags); - return 0; -} - -#else -#define musb_suspend NULL -#define musb_resume NULL -#endif - -static struct platform_driver musb_driver = { - .driver = { - .name = (char *)musb_driver_name, - .bus = &platform_bus_type, - .owner = THIS_MODULE, - }, - .remove = __devexit_p(musb_remove), - .shutdown = musb_shutdown, - .suspend = musb_suspend, - .resume = musb_resume, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init musb_init(void) -{ -#ifdef CONFIG_USB_MUSB_HDRC_HCD - if (usb_disabled()) - return 0; -#endif - - pr_info("%s: version " MUSB_VERSION ", " -#ifdef CONFIG_USB_MUSB_DISABLE_DMA - "pio" -#elif defined(CONFIG_USB_TI_CPPI_DMA) - "cppi-dma" -#elif defined(CONFIG_USB_INVENTRA_DMA) - "musb-dma" -#elif defined(CONFIG_USB_TUSB_OMAP_DMA) - "tusb-omap-dma" -#else - "?dma?" -#endif - ", " -#ifdef CONFIG_USB_MUSB_OTG - "otg (peripheral+host)" -#elif defined(CONFIG_USB_GADGET_MUSB_HDRC) - "peripheral" -#elif defined(CONFIG_USB_MUSB_HDRC_HCD) - "host" -#endif - ", debug=%d\n", - musb_driver_name, debug); - return platform_driver_probe(&musb_driver, musb_probe); -} - -/* make us init after usbcore and before usb - * gadget and host-side drivers start to register - */ -subsys_initcall(musb_init); - -static void __exit musb_cleanup(void) -{ - platform_driver_unregister(&musb_driver); -} -module_exit(musb_cleanup); -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/9] musb_hdrc: Rename musbhdrc.h to musb_regs.h 2007-08-20 9:10 ` [PATCH 3/9] musb_hdrc: Rename plat_uds.c to musb_core.c, plat_arc.h to musb_arch.h Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 2007-08-20 9:10 ` [PATCH 5/9] musb_hdrc: Rename musbdefs.h to musb_core.h Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Rename musbhdrc.h to musb_regs.h Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/musb_regs.h | 300 ++++++++++++++++++++++++++++++++++++++++++ drivers/usb/musb/musbdefs.h | 2 +- drivers/usb/musb/musbhdrc.h | 300 ------------------------------------------ 3 files changed, 301 insertions(+), 301 deletions(-) create mode 100644 drivers/usb/musb/musb_regs.h delete mode 100644 drivers/usb/musb/musbhdrc.h diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h new file mode 100644 index 0000000..d1500a4 --- /dev/null +++ b/drivers/usb/musb/musb_regs.h @@ -0,0 +1,300 @@ +/* + * MUSB OTG driver register defines + * + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. + * + */ + +#ifndef __MUSB_REGS_H__ +#define __MUSB_REGS_H__ + +#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */ + +/* + * Common USB registers + */ + +#define MUSB_FADDR 0x00 /* 8-bit */ +#define MUSB_POWER 0x01 /* 8-bit */ + +#define MUSB_INTRTX 0x02 /* 16-bit */ +#define MUSB_INTRRX 0x04 +#define MUSB_INTRTXE 0x06 +#define MUSB_INTRRXE 0x08 +#define MUSB_INTRUSB 0x0A /* 8 bit */ +#define MUSB_INTRUSBE 0x0B /* 8 bit */ +#define MUSB_FRAME 0x0C +#define MUSB_INDEX 0x0E /* 8 bit */ +#define MUSB_TESTMODE 0x0F /* 8 bit */ + +/* Get offset for a given FIFO from musb->mregs */ +#ifdef CONFIG_USB_TUSB6010 +#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20)) +#else +#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4)) +#endif + +/* + * Additional Control Registers + */ + +#define MUSB_DEVCTL 0x60 /* 8 bit */ + +/* These are always controlled through the INDEX register */ +#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */ +#define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */ +#define MUSB_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */ +#define MUSB_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */ + +/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */ +#define MUSB_HWVERS 0x6C /* 8 bit */ + +#define MUSB_EPINFO 0x78 /* 8 bit */ +#define MUSB_RAMINFO 0x79 /* 8 bit */ +#define MUSB_LINKINFO 0x7a /* 8 bit */ +#define MUSB_VPLEN 0x7b /* 8 bit */ +#define MUSB_HS_EOF1 0x7c /* 8 bit */ +#define MUSB_FS_EOF1 0x7d /* 8 bit */ +#define MUSB_LS_EOF1 0x7e /* 8 bit */ + +/* Offsets to endpoint registers */ +#define MUSB_TXMAXP 0x00 +#define MUSB_TXCSR 0x02 +#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */ +#define MUSB_RXMAXP 0x04 +#define MUSB_RXCSR 0x06 +#define MUSB_RXCOUNT 0x08 +#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */ +#define MUSB_TXTYPE 0x0A +#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */ +#define MUSB_TXINTERVAL 0x0B +#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */ +#define MUSB_RXTYPE 0x0C +#define MUSB_RXINTERVAL 0x0D +#define MUSB_FIFOSIZE 0x0F +#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */ + +/* Offsets to endpoint registers in indexed model (using INDEX register) */ +#define MUSB_INDEXED_OFFSET(_epnum, _offset) \ + (0x10 + (_offset)) + +/* Offsets to endpoint registers in flat models */ +#define MUSB_FLAT_OFFSET(_epnum, _offset) \ + (0x100 + (0x10*(_epnum)) + (_offset)) + +#ifdef CONFIG_USB_TUSB6010 +/* TUSB6010 EP0 configuration register is special */ +#define MUSB_TUSB_OFFSET(_epnum, _offset) \ + (0x10 + _offset) +#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */ +#endif + +/* "bus control"/target registers, for host side multipoint (external hubs) */ +#define MUSB_TXFUNCADDR 0x00 +#define MUSB_TXHUBADDR 0x02 +#define MUSB_TXHUBPORT 0x03 + +#define MUSB_RXFUNCADDR 0x04 +#define MUSB_RXHUBADDR 0x06 +#define MUSB_RXHUBPORT 0x07 + +#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \ + (0x80 + (8*(_epnum)) + (_offset)) + +/* + * MUSB Register bits + */ + +/* POWER */ +#define MUSB_POWER_ISOUPDATE 0x80 +#define MUSB_POWER_SOFTCONN 0x40 +#define MUSB_POWER_HSENAB 0x20 +#define MUSB_POWER_HSMODE 0x10 +#define MUSB_POWER_RESET 0x08 +#define MUSB_POWER_RESUME 0x04 +#define MUSB_POWER_SUSPENDM 0x02 +#define MUSB_POWER_ENSUSPEND 0x01 + +/* INTRUSB */ +#define MUSB_INTR_SUSPEND 0x01 +#define MUSB_INTR_RESUME 0x02 +#define MUSB_INTR_RESET 0x04 +#define MUSB_INTR_BABBLE 0x04 +#define MUSB_INTR_SOF 0x08 +#define MUSB_INTR_CONNECT 0x10 +#define MUSB_INTR_DISCONNECT 0x20 +#define MUSB_INTR_SESSREQ 0x40 +#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */ + +/* DEVCTL */ +#define MUSB_DEVCTL_BDEVICE 0x80 +#define MUSB_DEVCTL_FSDEV 0x40 +#define MUSB_DEVCTL_LSDEV 0x20 +#define MUSB_DEVCTL_VBUS 0x18 +#define MUSB_DEVCTL_VBUS_SHIFT 3 +#define MUSB_DEVCTL_HM 0x04 +#define MUSB_DEVCTL_HR 0x02 +#define MUSB_DEVCTL_SESSION 0x01 + +/* TESTMODE */ +#define MUSB_TEST_FORCE_HOST 0x80 +#define MUSB_TEST_FIFO_ACCESS 0x40 +#define MUSB_TEST_FORCE_FS 0x20 +#define MUSB_TEST_FORCE_HS 0x10 +#define MUSB_TEST_PACKET 0x08 +#define MUSB_TEST_K 0x04 +#define MUSB_TEST_J 0x02 +#define MUSB_TEST_SE0_NAK 0x01 + +/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */ +#define MUSB_FIFOSZ_DPB 0x10 +/* Allocation size (8, 16, 32, ... 4096) */ +#define MUSB_FIFOSZ_SIZE 0x0f + +/* CSR0 */ +#define MUSB_CSR0_FLUSHFIFO 0x0100 +#define MUSB_CSR0_TXPKTRDY 0x0002 +#define MUSB_CSR0_RXPKTRDY 0x0001 + +/* CSR0 in Peripheral mode */ +#define MUSB_CSR0_P_SVDSETUPEND 0x0080 +#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040 +#define MUSB_CSR0_P_SENDSTALL 0x0020 +#define MUSB_CSR0_P_SETUPEND 0x0010 +#define MUSB_CSR0_P_DATAEND 0x0008 +#define MUSB_CSR0_P_SENTSTALL 0x0004 + +/* CSR0 in Host mode */ +#define MUSB_CSR0_H_DIS_PING 0x0800 +#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */ +#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */ +#define MUSB_CSR0_H_NAKTIMEOUT 0x0080 +#define MUSB_CSR0_H_STATUSPKT 0x0040 +#define MUSB_CSR0_H_REQPKT 0x0020 +#define MUSB_CSR0_H_ERROR 0x0010 +#define MUSB_CSR0_H_SETUPPKT 0x0008 +#define MUSB_CSR0_H_RXSTALL 0x0004 + +/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MUSB_CSR0_P_WZC_BITS \ + ( MUSB_CSR0_P_SENTSTALL ) +#define MUSB_CSR0_H_WZC_BITS \ + ( MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \ + | MUSB_CSR0_RXPKTRDY ) + +/* TxType/RxType */ +#define MUSB_TYPE_SPEED 0xc0 +#define MUSB_TYPE_SPEED_SHIFT 6 +#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */ +#define MUSB_TYPE_PROTO_SHIFT 4 +#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */ + +/* CONFIGDATA */ +#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */ +#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */ +#define MUSB_CONFIGDATA_BIGENDIAN 0x20 +#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ +#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ +#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */ +#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ +#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */ + +/* TXCSR in Peripheral and Host mode */ +#define MUSB_TXCSR_AUTOSET 0x8000 +#define MUSB_TXCSR_MODE 0x2000 +#define MUSB_TXCSR_DMAENAB 0x1000 +#define MUSB_TXCSR_FRCDATATOG 0x0800 +#define MUSB_TXCSR_DMAMODE 0x0400 +#define MUSB_TXCSR_CLRDATATOG 0x0040 +#define MUSB_TXCSR_FLUSHFIFO 0x0008 +#define MUSB_TXCSR_FIFONOTEMPTY 0x0002 +#define MUSB_TXCSR_TXPKTRDY 0x0001 + +/* TXCSR in Peripheral mode */ +#define MUSB_TXCSR_P_ISO 0x4000 +#define MUSB_TXCSR_P_INCOMPTX 0x0080 +#define MUSB_TXCSR_P_SENTSTALL 0x0020 +#define MUSB_TXCSR_P_SENDSTALL 0x0010 +#define MUSB_TXCSR_P_UNDERRUN 0x0004 + +/* TXCSR in Host mode */ +#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200 +#define MUSB_TXCSR_H_DATATOGGLE 0x0100 +#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080 +#define MUSB_TXCSR_H_RXSTALL 0x0020 +#define MUSB_TXCSR_H_ERROR 0x0004 + +/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MUSB_TXCSR_P_WZC_BITS \ + ( MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \ + | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY ) +#define MUSB_TXCSR_H_WZC_BITS \ + ( MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \ + | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY ) + +/* RXCSR in Peripheral and Host mode */ +#define MUSB_RXCSR_AUTOCLEAR 0x8000 +#define MUSB_RXCSR_DMAENAB 0x2000 +#define MUSB_RXCSR_DISNYET 0x1000 +#define MUSB_RXCSR_PID_ERR 0x1000 +#define MUSB_RXCSR_DMAMODE 0x0800 +#define MUSB_RXCSR_INCOMPRX 0x0100 +#define MUSB_RXCSR_CLRDATATOG 0x0080 +#define MUSB_RXCSR_FLUSHFIFO 0x0010 +#define MUSB_RXCSR_DATAERROR 0x0008 +#define MUSB_RXCSR_FIFOFULL 0x0002 +#define MUSB_RXCSR_RXPKTRDY 0x0001 + +/* RXCSR in Peripheral mode */ +#define MUSB_RXCSR_P_ISO 0x4000 +#define MUSB_RXCSR_P_SENTSTALL 0x0040 +#define MUSB_RXCSR_P_SENDSTALL 0x0020 +#define MUSB_RXCSR_P_OVERRUN 0x0004 + +/* RXCSR in Host mode */ +#define MUSB_RXCSR_H_AUTOREQ 0x4000 +#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400 +#define MUSB_RXCSR_H_DATATOGGLE 0x0200 +#define MUSB_RXCSR_H_RXSTALL 0x0040 +#define MUSB_RXCSR_H_REQPKT 0x0020 +#define MUSB_RXCSR_H_ERROR 0x0004 + +/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ +#define MUSB_RXCSR_P_WZC_BITS \ + ( MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \ + | MUSB_RXCSR_RXPKTRDY ) +#define MUSB_RXCSR_H_WZC_BITS \ + ( MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \ + | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY ) + +/* HUBADDR */ +#define MUSB_HUBADDR_MULTI_TT 0x80 + +#endif /* __MUSB_REGS_H__ */ diff --git a/drivers/usb/musb/musbdefs.h b/drivers/usb/musb/musbdefs.h index a9af51e..7dbc74a 100644 --- a/drivers/usb/musb/musbdefs.h +++ b/drivers/usb/musb/musbdefs.h @@ -69,7 +69,7 @@ struct musb_ep; #endif #include "musb_arch.h" -#include "musbhdrc.h" +#include "musb_regs.h" #include "musb_gadget.h" #include "../core/hcd.h" diff --git a/drivers/usb/musb/musbhdrc.h b/drivers/usb/musb/musbhdrc.h deleted file mode 100644 index 961e321..0000000 --- a/drivers/usb/musb/musbhdrc.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * MUSB OTG driver register defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. - * - */ - -#ifndef __MUSB_HDRC_DEFS_H__ -#define __MUSB_HDRC_DEFS_H__ - -#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */ - -/* - * Common USB registers - */ - -#define MUSB_FADDR 0x00 /* 8-bit */ -#define MUSB_POWER 0x01 /* 8-bit */ - -#define MUSB_INTRTX 0x02 /* 16-bit */ -#define MUSB_INTRRX 0x04 -#define MUSB_INTRTXE 0x06 -#define MUSB_INTRRXE 0x08 -#define MUSB_INTRUSB 0x0A /* 8 bit */ -#define MUSB_INTRUSBE 0x0B /* 8 bit */ -#define MUSB_FRAME 0x0C -#define MUSB_INDEX 0x0E /* 8 bit */ -#define MUSB_TESTMODE 0x0F /* 8 bit */ - -/* Get offset for a given FIFO from musb->mregs */ -#ifdef CONFIG_USB_TUSB6010 -#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20)) -#else -#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4)) -#endif - -/* - * Additional Control Registers - */ - -#define MUSB_DEVCTL 0x60 /* 8 bit */ - -/* These are always controlled through the INDEX register */ -#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */ -#define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */ -#define MUSB_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */ -#define MUSB_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */ - -/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */ -#define MUSB_HWVERS 0x6C /* 8 bit */ - -#define MUSB_EPINFO 0x78 /* 8 bit */ -#define MUSB_RAMINFO 0x79 /* 8 bit */ -#define MUSB_LINKINFO 0x7a /* 8 bit */ -#define MUSB_VPLEN 0x7b /* 8 bit */ -#define MUSB_HS_EOF1 0x7c /* 8 bit */ -#define MUSB_FS_EOF1 0x7d /* 8 bit */ -#define MUSB_LS_EOF1 0x7e /* 8 bit */ - -/* Offsets to endpoint registers */ -#define MUSB_TXMAXP 0x00 -#define MUSB_TXCSR 0x02 -#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */ -#define MUSB_RXMAXP 0x04 -#define MUSB_RXCSR 0x06 -#define MUSB_RXCOUNT 0x08 -#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */ -#define MUSB_TXTYPE 0x0A -#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */ -#define MUSB_TXINTERVAL 0x0B -#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */ -#define MUSB_RXTYPE 0x0C -#define MUSB_RXINTERVAL 0x0D -#define MUSB_FIFOSIZE 0x0F -#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */ - -/* Offsets to endpoint registers in indexed model (using INDEX register) */ -#define MUSB_INDEXED_OFFSET(_epnum, _offset) \ - (0x10 + (_offset)) - -/* Offsets to endpoint registers in flat models */ -#define MUSB_FLAT_OFFSET(_epnum, _offset) \ - (0x100 + (0x10*(_epnum)) + (_offset)) - -#ifdef CONFIG_USB_TUSB6010 -/* TUSB6010 EP0 configuration register is special */ -#define MUSB_TUSB_OFFSET(_epnum, _offset) \ - (0x10 + _offset) -#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */ -#endif - -/* "bus control"/target registers, for host side multipoint (external hubs) */ -#define MUSB_TXFUNCADDR 0x00 -#define MUSB_TXHUBADDR 0x02 -#define MUSB_TXHUBPORT 0x03 - -#define MUSB_RXFUNCADDR 0x04 -#define MUSB_RXHUBADDR 0x06 -#define MUSB_RXHUBPORT 0x07 - -#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \ - (0x80 + (8*(_epnum)) + (_offset)) - -/* - * MUSB Register bits - */ - -/* POWER */ -#define MUSB_POWER_ISOUPDATE 0x80 -#define MUSB_POWER_SOFTCONN 0x40 -#define MUSB_POWER_HSENAB 0x20 -#define MUSB_POWER_HSMODE 0x10 -#define MUSB_POWER_RESET 0x08 -#define MUSB_POWER_RESUME 0x04 -#define MUSB_POWER_SUSPENDM 0x02 -#define MUSB_POWER_ENSUSPEND 0x01 - -/* INTRUSB */ -#define MUSB_INTR_SUSPEND 0x01 -#define MUSB_INTR_RESUME 0x02 -#define MUSB_INTR_RESET 0x04 -#define MUSB_INTR_BABBLE 0x04 -#define MUSB_INTR_SOF 0x08 -#define MUSB_INTR_CONNECT 0x10 -#define MUSB_INTR_DISCONNECT 0x20 -#define MUSB_INTR_SESSREQ 0x40 -#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */ - -/* DEVCTL */ -#define MUSB_DEVCTL_BDEVICE 0x80 -#define MUSB_DEVCTL_FSDEV 0x40 -#define MUSB_DEVCTL_LSDEV 0x20 -#define MUSB_DEVCTL_VBUS 0x18 -#define MUSB_DEVCTL_VBUS_SHIFT 3 -#define MUSB_DEVCTL_HM 0x04 -#define MUSB_DEVCTL_HR 0x02 -#define MUSB_DEVCTL_SESSION 0x01 - -/* TESTMODE */ -#define MUSB_TEST_FORCE_HOST 0x80 -#define MUSB_TEST_FIFO_ACCESS 0x40 -#define MUSB_TEST_FORCE_FS 0x20 -#define MUSB_TEST_FORCE_HS 0x10 -#define MUSB_TEST_PACKET 0x08 -#define MUSB_TEST_K 0x04 -#define MUSB_TEST_J 0x02 -#define MUSB_TEST_SE0_NAK 0x01 - -/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */ -#define MUSB_FIFOSZ_DPB 0x10 -/* Allocation size (8, 16, 32, ... 4096) */ -#define MUSB_FIFOSZ_SIZE 0x0f - -/* CSR0 */ -#define MUSB_CSR0_FLUSHFIFO 0x0100 -#define MUSB_CSR0_TXPKTRDY 0x0002 -#define MUSB_CSR0_RXPKTRDY 0x0001 - -/* CSR0 in Peripheral mode */ -#define MUSB_CSR0_P_SVDSETUPEND 0x0080 -#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040 -#define MUSB_CSR0_P_SENDSTALL 0x0020 -#define MUSB_CSR0_P_SETUPEND 0x0010 -#define MUSB_CSR0_P_DATAEND 0x0008 -#define MUSB_CSR0_P_SENTSTALL 0x0004 - -/* CSR0 in Host mode */ -#define MUSB_CSR0_H_DIS_PING 0x0800 -#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */ -#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */ -#define MUSB_CSR0_H_NAKTIMEOUT 0x0080 -#define MUSB_CSR0_H_STATUSPKT 0x0040 -#define MUSB_CSR0_H_REQPKT 0x0020 -#define MUSB_CSR0_H_ERROR 0x0010 -#define MUSB_CSR0_H_SETUPPKT 0x0008 -#define MUSB_CSR0_H_RXSTALL 0x0004 - -/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_CSR0_P_WZC_BITS \ - ( MUSB_CSR0_P_SENTSTALL ) -#define MUSB_CSR0_H_WZC_BITS \ - ( MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \ - | MUSB_CSR0_RXPKTRDY ) - -/* TxType/RxType */ -#define MUSB_TYPE_SPEED 0xc0 -#define MUSB_TYPE_SPEED_SHIFT 6 -#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */ -#define MUSB_TYPE_PROTO_SHIFT 4 -#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */ - -/* CONFIGDATA */ -#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */ -#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */ -#define MUSB_CONFIGDATA_BIGENDIAN 0x20 -#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ -#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ -#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */ -#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ -#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */ - -/* TXCSR in Peripheral and Host mode */ -#define MUSB_TXCSR_AUTOSET 0x8000 -#define MUSB_TXCSR_MODE 0x2000 -#define MUSB_TXCSR_DMAENAB 0x1000 -#define MUSB_TXCSR_FRCDATATOG 0x0800 -#define MUSB_TXCSR_DMAMODE 0x0400 -#define MUSB_TXCSR_CLRDATATOG 0x0040 -#define MUSB_TXCSR_FLUSHFIFO 0x0008 -#define MUSB_TXCSR_FIFONOTEMPTY 0x0002 -#define MUSB_TXCSR_TXPKTRDY 0x0001 - -/* TXCSR in Peripheral mode */ -#define MUSB_TXCSR_P_ISO 0x4000 -#define MUSB_TXCSR_P_INCOMPTX 0x0080 -#define MUSB_TXCSR_P_SENTSTALL 0x0020 -#define MUSB_TXCSR_P_SENDSTALL 0x0010 -#define MUSB_TXCSR_P_UNDERRUN 0x0004 - -/* TXCSR in Host mode */ -#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200 -#define MUSB_TXCSR_H_DATATOGGLE 0x0100 -#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080 -#define MUSB_TXCSR_H_RXSTALL 0x0020 -#define MUSB_TXCSR_H_ERROR 0x0004 - -/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_TXCSR_P_WZC_BITS \ - ( MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \ - | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY ) -#define MUSB_TXCSR_H_WZC_BITS \ - ( MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \ - | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY ) - -/* RXCSR in Peripheral and Host mode */ -#define MUSB_RXCSR_AUTOCLEAR 0x8000 -#define MUSB_RXCSR_DMAENAB 0x2000 -#define MUSB_RXCSR_DISNYET 0x1000 -#define MUSB_RXCSR_PID_ERR 0x1000 -#define MUSB_RXCSR_DMAMODE 0x0800 -#define MUSB_RXCSR_INCOMPRX 0x0100 -#define MUSB_RXCSR_CLRDATATOG 0x0080 -#define MUSB_RXCSR_FLUSHFIFO 0x0010 -#define MUSB_RXCSR_DATAERROR 0x0008 -#define MUSB_RXCSR_FIFOFULL 0x0002 -#define MUSB_RXCSR_RXPKTRDY 0x0001 - -/* RXCSR in Peripheral mode */ -#define MUSB_RXCSR_P_ISO 0x4000 -#define MUSB_RXCSR_P_SENTSTALL 0x0040 -#define MUSB_RXCSR_P_SENDSTALL 0x0020 -#define MUSB_RXCSR_P_OVERRUN 0x0004 - -/* RXCSR in Host mode */ -#define MUSB_RXCSR_H_AUTOREQ 0x4000 -#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400 -#define MUSB_RXCSR_H_DATATOGGLE 0x0200 -#define MUSB_RXCSR_H_RXSTALL 0x0040 -#define MUSB_RXCSR_H_REQPKT 0x0020 -#define MUSB_RXCSR_H_ERROR 0x0004 - -/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_RXCSR_P_WZC_BITS \ - ( MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \ - | MUSB_RXCSR_RXPKTRDY ) -#define MUSB_RXCSR_H_WZC_BITS \ - ( MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \ - | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY ) - -/* HUBADDR */ -#define MUSB_HUBADDR_MULTI_TT 0x80 - -#endif /* __MUSB_HDRC_DEFS_H__ */ -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/9] musb_hdrc: Rename musbdefs.h to musb_core.h 2007-08-20 9:10 ` [PATCH 4/9] musb_hdrc: Rename musbhdrc.h to musb_regs.h Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 2007-08-20 9:10 ` [PATCH 6/9] musb_hdrc: Rename dma.h to musb_dma.h Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Rename musbdefs.h to musb_core.h Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/cppi_dma.c | 2 +- drivers/usb/musb/cppi_dma.h | 2 +- drivers/usb/musb/davinci.c | 2 +- drivers/usb/musb/g_ep0.c | 2 +- drivers/usb/musb/musb_core.c | 2 +- drivers/usb/musb/musb_core.h | 525 ++++++++++++++++++++++++++++++++++++++ drivers/usb/musb/musb_gadget.c | 2 +- drivers/usb/musb/musb_host.c | 2 +- drivers/usb/musb/musb_procfs.c | 2 +- drivers/usb/musb/musbdefs.h | 525 -------------------------------------- drivers/usb/musb/musbhsdma.c | 2 +- drivers/usb/musb/omap2430.c | 2 +- drivers/usb/musb/tusb6010.c | 2 +- drivers/usb/musb/tusb6010_omap.c | 2 +- drivers/usb/musb/virthub.c | 2 +- 15 files changed, 538 insertions(+), 538 deletions(-) create mode 100644 drivers/usb/musb/musb_core.h delete mode 100644 drivers/usb/musb/musbdefs.h diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 8ce3fd5..5403a4f 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -8,7 +8,7 @@ #include <linux/usb.h> -#include "musbdefs.h" +#include "musb_core.h" #include "cppi_dma.h" diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index da97a99..c121865 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -10,7 +10,7 @@ #include <linux/dmapool.h> #include "dma.h" -#include "musbdefs.h" +#include "musb_core.h" #include "davinci.h" diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 99ac042..85300dd 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -36,7 +36,7 @@ #include <asm/arch/gpio.h> #include <asm/mach-types.h> -#include "musbdefs.h" +#include "musb_core.h" #ifdef CONFIG_MACH_DAVINCI_EVM diff --git a/drivers/usb/musb/g_ep0.c b/drivers/usb/musb/g_ep0.c index e63e983..2395729 100644 --- a/drivers/usb/musb/g_ep0.c +++ b/drivers/usb/musb/g_ep0.c @@ -40,7 +40,7 @@ #include <linux/device.h> #include <linux/interrupt.h> -#include "musbdefs.h" +#include "musb_core.h" /* ep0 is always musb->endpoints[0].ep_in */ #define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0]) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index e544339..edb03a1 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -106,7 +106,7 @@ #include <asm/mach-types.h> #endif -#include "musbdefs.h" +#include "musb_core.h" #ifdef CONFIG_ARCH_DAVINCI diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h new file mode 100644 index 0000000..ed02839 --- /dev/null +++ b/drivers/usb/musb/musb_core.h @@ -0,0 +1,525 @@ +/* + * MUSB OTG driver defines + * + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. + * + */ + +#ifndef __MUSB_CORE_H__ +#define __MUSB_CORE_H__ + +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/usb/ch9.h> +#include <linux/usb_gadget.h> +#include <linux/usb.h> +#include <linux/usb/otg.h> +#include <linux/usb/musb.h> + +struct musb; +struct musb_hw_ep; +struct musb_ep; + + +#include "debug.h" +#include "dma.h" + +#ifdef CONFIG_USB_MUSB_SOC +/* + * Get core configuration from a header converted (by cfg_conv) + * from the Verilog config file generated by the core config utility + * + * For now we assume that header is provided along with other + * arch-specific files. Discrete chips will need a build tweak. + * So will using AHB IDs from silicon that provides them. + */ +#include <asm/arch/hdrc_cnf.h> +#endif + +#include "musb_arch.h" +#include "musb_regs.h" + +#include "musb_gadget.h" +#include "../core/hcd.h" +#include "musb_host.h" + + + +#ifdef CONFIG_USB_MUSB_OTG + +#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST) +#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL) +#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG) + +/* NOTE: otg and peripheral-only state machines start at B_IDLE. + * OTG or host-only go to A_IDLE when ID is sensed. + */ +#define is_peripheral_active(m) (!(m)->is_host) +#define is_host_active(m) ((m)->is_host) + +#else +#define is_peripheral_enabled(musb) is_peripheral_capable() +#define is_host_enabled(musb) is_host_capable() +#define is_otg_enabled(musb) 0 + +#define is_peripheral_active(musb) is_peripheral_capable() +#define is_host_active(musb) is_host_capable() +#endif + +#if defined(CONFIG_USB_MUSB_OTG) || defined(CONFIG_USB_MUSB_PERIPHERAL) +/* for some reason, the "select USB_GADGET_MUSB_HDRC" doesn't always + * override that choice selection (often USB_GADGET_DUMMY_HCD). + */ +#ifndef CONFIG_USB_GADGET_MUSB_HDRC +#error bogus Kconfig output ... select CONFIG_USB_GADGET_MUSB_HDRC +#endif +#endif /* need MUSB gadget selection */ + + +#ifdef CONFIG_PROC_FS +#include <linux/fs.h> +#define MUSB_CONFIG_PROC_FS +#endif + +/****************************** PERIPHERAL ROLE *****************************/ + +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + +#define is_peripheral_capable() (1) + +extern irqreturn_t musb_g_ep0_irq(struct musb *); +extern void musb_g_tx(struct musb *, u8); +extern void musb_g_rx(struct musb *, u8); +extern void musb_g_reset(struct musb *); +extern void musb_g_suspend(struct musb *); +extern void musb_g_resume(struct musb *); +extern void musb_g_wakeup(struct musb *); +extern void musb_g_disconnect(struct musb *); + +#else + +#define is_peripheral_capable() (0) + +static inline irqreturn_t musb_g_ep0_irq(struct musb *m) { return IRQ_NONE; } +static inline void musb_g_reset(struct musb *m) {} +static inline void musb_g_suspend(struct musb *m) {} +static inline void musb_g_resume(struct musb *m) {} +static inline void musb_g_wakeup(struct musb *m) {} +static inline void musb_g_disconnect(struct musb *m) {} + +#endif + +/****************************** HOST ROLE ***********************************/ + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + +#define is_host_capable() (1) + +extern irqreturn_t musb_h_ep0_irq(struct musb *); +extern void musb_host_tx(struct musb *, u8); +extern void musb_host_rx(struct musb *, u8); + +#else + +#define is_host_capable() (0) + +static inline irqreturn_t musb_h_ep0_irq(struct musb *m) { return IRQ_NONE; } +static inline void musb_host_tx(struct musb *m, u8 e) {} +static inline void musb_host_rx(struct musb *m, u8 e) {} + +#endif + + +/****************************** CONSTANTS ********************************/ + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef MUSB_C_NUM_EPS +#define MUSB_C_NUM_EPS ((u8)16) +#endif + +#ifndef MUSB_MAX_END0_PACKET +#define MUSB_MAX_END0_PACKET ((u16)MUSB_EP0_FIFOSIZE) +#endif + +/* host side ep0 states */ +enum musb_h_ep0_state { + MUSB_EP0_IDLE, + MUSB_EP0_START, /* expect ack of setup */ + MUSB_EP0_IN, /* expect IN DATA */ + MUSB_EP0_OUT, /* expect ack of OUT DATA */ + MUSB_EP0_STATUS, /* expect ack of STATUS */ +} __attribute__ ((packed)); + +/* peripheral side ep0 states */ +enum musb_g_ep0_state { + MUSB_EP0_STAGE_SETUP, /* idle, waiting for setup */ + MUSB_EP0_STAGE_TX, /* IN data */ + MUSB_EP0_STAGE_RX, /* OUT data */ + MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */ + MUSB_EP0_STAGE_STATUSOUT, /* (after IN data) */ + MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */ +} __attribute__ ((packed)); + +/* OTG protocol constants */ +#define OTG_TIME_A_WAIT_VRISE 100 /* msec (max) */ +#define OTG_TIME_A_WAIT_BCON 0 /* 0=infinite; min 1000 msec */ +#define OTG_TIME_A_IDLE_BDIS 200 /* msec (min) */ + +/*************************** REGISTER ACCESS ********************************/ + +/* Endpoint registers (other than dynfifo setup) can be accessed either + * directly with the "flat" model, or after setting up an index register. + */ + +#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) || \ + defined(CONFIG_ARCH_OMAP3430) +/* REVISIT indexed access seemed to + * misbehave (on DaVinci) for at least peripheral IN ... + */ +#define MUSB_FLAT_REG +#endif + +/* TUSB mapping: "flat" plus ep0 special cases */ +#if defined(CONFIG_USB_TUSB6010) +#define musb_ep_select(_mbase, _epnum) \ + musb_writeb((_mbase), MUSB_INDEX, (_epnum)) +#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET + +/* "flat" mapping: each endpoint has its own i/o address */ +#elif defined(MUSB_FLAT_REG) +#define musb_ep_select(_mbase, _epnum) (((void)(_mbase)),((void)(_epnum))) +#define MUSB_EP_OFFSET MUSB_FLAT_OFFSET + +/* "indexed" mapping: INDEX register controls register bank select */ +#else +#define musb_ep_select(_mbase, _epnum) \ + musb_writeb((_mbase), MUSB_INDEX, (_epnum)) +#define MUSB_EP_OFFSET MUSB_INDEXED_OFFSET +#endif + +/****************************** FUNCTIONS ********************************/ + +#define MUSB_HST_MODE(_musb)\ + { (_musb)->is_host=TRUE; } +#define MUSB_DEV_MODE(_musb) \ + { (_musb)->is_host=FALSE; } + +#define test_devctl_hst_mode(_x) \ + (musb_readb((_x)->mregs, MUSB_DEVCTL)&MUSB_DEVCTL_HM) + +#define MUSB_MODE(musb) ((musb)->is_host ? "Host" : "Peripheral") + +/******************************** TYPES *************************************/ + +/* + * struct musb_hw_ep - endpoint hardware (bidirectional) + * + * Ordered slightly for better cacheline locality. + */ +struct musb_hw_ep { + struct musb *musb; + void __iomem *fifo; + void __iomem *regs; + +#ifdef CONFIG_USB_TUSB6010 + void __iomem *conf; +#endif + + /* index in musb->endpoints[] */ + u8 epnum; + + /* hardware configuration, possibly dynamic */ + u8 is_shared_fifo; + u8 tx_double_buffered; + u8 rx_double_buffered; + u16 max_packet_sz_tx; + u16 max_packet_sz_rx; + + struct dma_channel *tx_channel; + struct dma_channel *rx_channel; + +#ifdef CONFIG_USB_TUSB6010 + /* TUSB has "asynchronous" and "synchronous" dma modes */ + dma_addr_t fifo_async; + dma_addr_t fifo_sync; + void __iomem *fifo_sync_va; +#endif + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + void __iomem *target_regs; + + /* currently scheduled peripheral endpoint */ + struct musb_qh *in_qh; + struct musb_qh *out_qh; + + u8 rx_reinit; + u8 tx_reinit; +#endif + +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + /* peripheral side */ + struct musb_ep ep_in; /* TX */ + struct musb_ep ep_out; /* RX */ +#endif +}; + +static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep) +{ +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + return next_request(&hw_ep->ep_in); +#else + return NULL; +#endif +} + +static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep) +{ +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + return next_request(&hw_ep->ep_out); +#else + return NULL; +#endif +} + +/* + * struct musb - Driver instance data. + */ +struct musb { + spinlock_t lock; + struct clk *clock; + irqreturn_t (*isr)(int, void *); + struct work_struct irq_work; + +#ifdef CONFIG_USB_MUSB_HDRC_HCD + +/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */ +#define MUSB_PORT_STAT_RESUME (1 << 31) + + u32 port1_status; + unsigned long rh_timer; + + enum musb_h_ep0_state ep0_stage; + + /* bulk traffic normally dedicates endpoint hardware, and each + * direction has its own ring of host side endpoints. + * we try to progress the transfer at the head of each endpoint's + * queue until it completes or NAKs too much; then we try the next + * endpoint. + */ + struct musb_hw_ep *bulk_ep; + + struct list_head control; /* of musb_qh */ + struct list_head in_bulk; /* of musb_qh */ + struct list_head out_bulk; /* of musb_qh */ + struct musb_qh *periodic[32]; /* tree of interrupt+iso */ +#endif + + /* called with IRQs blocked; ON/nonzero implies starting a session, + * and waiting at least a_wait_vrise_tmout. + */ + void (*board_set_vbus)(struct musb *, int is_on); + + struct dma_controller *dma_controller; + + struct device *controller; + void __iomem *ctrl_base; + void __iomem *mregs; + +#ifdef CONFIG_USB_TUSB6010 + dma_addr_t async; + dma_addr_t sync; + void __iomem *sync_va; +#endif + + /* passed down from chip/board specific irq handlers */ + u8 int_usb; + u16 int_rx; + u16 int_tx; + + struct otg_transceiver xceiv; + + int nIrq; + + struct musb_hw_ep endpoints[MUSB_C_NUM_EPS]; +#define control_ep endpoints + +#define VBUSERR_RETRY_COUNT 3 + u16 vbuserr_retry; + u16 epmask; + u8 nr_endpoints; + + u8 board_mode; /* enum musb_mode */ + int (*board_set_power)(int state); + + int (*set_clock)(struct clk *clk, int is_active); + + u8 min_power; /* vbus for periph, in mA/2 */ + + /* active means connected and not suspended */ + unsigned is_active:1; + + unsigned is_multipoint:1; + unsigned is_host:1; + unsigned ignore_disconnect:1; /* during bus resets */ + + int a_wait_bcon; /* VBUS timeout in msecs */ + unsigned long idle_timeout; /* Next timeout in jiffies */ + +#ifdef C_MP_TX + unsigned bulk_split:1; +#define can_bulk_split(musb,type) \ + (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split) +#else +#define can_bulk_split(musb,type) 0 +#endif + +#ifdef C_MP_RX + unsigned bulk_combine:1; + /* REVISIT allegedly doesn't work reliably */ +#if 0 +#define can_bulk_combine(musb,type) \ + (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine) +#else +#define can_bulk_combine(musb,type) 0 +#endif +#else +#define can_bulk_combine(musb,type) 0 +#endif + +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + /* is_suspended means USB B_PERIPHERAL suspend */ + unsigned is_suspended:1; + + /* may_wakeup means remote wakeup is enabled */ + unsigned may_wakeup:1; + + /* is_self_powered is reported in device status and the + * config descriptor. is_bus_powered means B_PERIPHERAL + * draws some VBUS current; both can be true. + */ + unsigned is_self_powered:1; + unsigned is_bus_powered:1; + + unsigned set_address:1; + unsigned test_mode:1; + unsigned softconnect:1; + + enum musb_g_ep0_state ep0_state; + u8 address; + u8 test_mode_nr; + u16 ackpend; /* ep0 */ + struct usb_gadget g; /* the gadget */ + struct usb_gadget_driver *gadget_driver; /* its driver */ +#endif + +#ifdef MUSB_CONFIG_PROC_FS + struct proc_dir_entry *proc_entry; +#endif +}; + +static inline void musb_set_vbus(struct musb *musb, int is_on) +{ + musb->board_set_vbus(musb, is_on); +} + +#ifdef CONFIG_USB_GADGET_MUSB_HDRC +static inline struct musb *gadget_to_musb(struct usb_gadget *g) +{ + return container_of(g, struct musb, g); +} +#endif + + +/***************************** Glue it together *****************************/ + +extern const char musb_driver_name[]; + +extern void musb_start(struct musb *musb); +extern void musb_stop(struct musb *musb); + +extern void musb_write_fifo(struct musb_hw_ep *ep, + u16 len, const u8 * src); +extern void musb_read_fifo(struct musb_hw_ep *ep, + u16 len, u8 * dst); + +extern void musb_load_testpacket(struct musb *); + +extern irqreturn_t musb_interrupt(struct musb *); + +extern void musb_platform_enable(struct musb *musb); +extern void musb_platform_disable(struct musb *musb); + +extern void musb_hnp_stop(struct musb *musb); + +#ifdef CONFIG_USB_TUSB6010 +extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout); +extern int musb_platform_get_vbus_status(struct musb *musb); +extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode); +#else +#define musb_platform_try_idle(x, y) do {} while (0) +#define musb_platform_get_vbus_status(x) 0 +#define musb_platform_set_mode(x, y) do {} while (0) +#endif + +extern int __init musb_platform_init(struct musb *musb); +extern int musb_platform_exit(struct musb *musb); + +/*-------------------------- ProcFS definitions ---------------------*/ + +struct proc_dir_entry; + +#if (MUSB_DEBUG > 0) && defined(MUSB_CONFIG_PROC_FS) +extern struct proc_dir_entry *musb_debug_create(char *name, + struct musb *data); +extern void musb_debug_delete(char *name, struct musb *data); + +#else +static inline struct proc_dir_entry *musb_debug_create(char *name, + struct musb *data) +{ + return NULL; +} +static inline void musb_debug_delete(char *name, struct musb *data) +{ +} +#endif + +#endif /* __MUSB_CORE_H__ */ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 5a4227e..1789ede 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -43,7 +43,7 @@ #include <linux/stat.h> #include <linux/dma-mapping.h> -#include "musbdefs.h" +#include "musb_core.h" /* MUSB PERIPHERAL status 3-mar: diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index e924853..e7935fb 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -41,7 +41,7 @@ #include <linux/init.h> #include <linux/list.h> -#include "musbdefs.h" +#include "musb_core.h" #include "musb_host.h" diff --git a/drivers/usb/musb/musb_procfs.c b/drivers/usb/musb/musb_procfs.c index 3144f34..fa36969 100644 --- a/drivers/usb/musb/musb_procfs.c +++ b/drivers/usb/musb/musb_procfs.c @@ -44,7 +44,7 @@ #include <asm/uaccess.h> /* FIXME remove procfs writes */ #include <asm/arch/hardware.h> -#include "musbdefs.h" +#include "musb_core.h" #include "davinci.h" diff --git a/drivers/usb/musb/musbdefs.h b/drivers/usb/musb/musbdefs.h deleted file mode 100644 index 7dbc74a..0000000 --- a/drivers/usb/musb/musbdefs.h +++ /dev/null @@ -1,525 +0,0 @@ -/* - * MUSB OTG driver defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. - * - */ - -#ifndef __MUSB_MUSBDEFS_H__ -#define __MUSB_MUSBDEFS_H__ - -#include <linux/slab.h> -#include <linux/list.h> -#include <linux/interrupt.h> -#include <linux/smp_lock.h> -#include <linux/errno.h> -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/usb/ch9.h> -#include <linux/usb_gadget.h> -#include <linux/usb.h> -#include <linux/usb/otg.h> -#include <linux/usb/musb.h> - -struct musb; -struct musb_hw_ep; -struct musb_ep; - - -#include "debug.h" -#include "dma.h" - -#ifdef CONFIG_USB_MUSB_SOC -/* - * Get core configuration from a header converted (by cfg_conv) - * from the Verilog config file generated by the core config utility - * - * For now we assume that header is provided along with other - * arch-specific files. Discrete chips will need a build tweak. - * So will using AHB IDs from silicon that provides them. - */ -#include <asm/arch/hdrc_cnf.h> -#endif - -#include "musb_arch.h" -#include "musb_regs.h" - -#include "musb_gadget.h" -#include "../core/hcd.h" -#include "musb_host.h" - - - -#ifdef CONFIG_USB_MUSB_OTG - -#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST) -#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL) -#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG) - -/* NOTE: otg and peripheral-only state machines start at B_IDLE. - * OTG or host-only go to A_IDLE when ID is sensed. - */ -#define is_peripheral_active(m) (!(m)->is_host) -#define is_host_active(m) ((m)->is_host) - -#else -#define is_peripheral_enabled(musb) is_peripheral_capable() -#define is_host_enabled(musb) is_host_capable() -#define is_otg_enabled(musb) 0 - -#define is_peripheral_active(musb) is_peripheral_capable() -#define is_host_active(musb) is_host_capable() -#endif - -#if defined(CONFIG_USB_MUSB_OTG) || defined(CONFIG_USB_MUSB_PERIPHERAL) -/* for some reason, the "select USB_GADGET_MUSB_HDRC" doesn't always - * override that choice selection (often USB_GADGET_DUMMY_HCD). - */ -#ifndef CONFIG_USB_GADGET_MUSB_HDRC -#error bogus Kconfig output ... select CONFIG_USB_GADGET_MUSB_HDRC -#endif -#endif /* need MUSB gadget selection */ - - -#ifdef CONFIG_PROC_FS -#include <linux/fs.h> -#define MUSB_CONFIG_PROC_FS -#endif - -/****************************** PERIPHERAL ROLE *****************************/ - -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - -#define is_peripheral_capable() (1) - -extern irqreturn_t musb_g_ep0_irq(struct musb *); -extern void musb_g_tx(struct musb *, u8); -extern void musb_g_rx(struct musb *, u8); -extern void musb_g_reset(struct musb *); -extern void musb_g_suspend(struct musb *); -extern void musb_g_resume(struct musb *); -extern void musb_g_wakeup(struct musb *); -extern void musb_g_disconnect(struct musb *); - -#else - -#define is_peripheral_capable() (0) - -static inline irqreturn_t musb_g_ep0_irq(struct musb *m) { return IRQ_NONE; } -static inline void musb_g_reset(struct musb *m) {} -static inline void musb_g_suspend(struct musb *m) {} -static inline void musb_g_resume(struct musb *m) {} -static inline void musb_g_wakeup(struct musb *m) {} -static inline void musb_g_disconnect(struct musb *m) {} - -#endif - -/****************************** HOST ROLE ***********************************/ - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - -#define is_host_capable() (1) - -extern irqreturn_t musb_h_ep0_irq(struct musb *); -extern void musb_host_tx(struct musb *, u8); -extern void musb_host_rx(struct musb *, u8); - -#else - -#define is_host_capable() (0) - -static inline irqreturn_t musb_h_ep0_irq(struct musb *m) { return IRQ_NONE; } -static inline void musb_host_tx(struct musb *m, u8 e) {} -static inline void musb_host_rx(struct musb *m, u8 e) {} - -#endif - - -/****************************** CONSTANTS ********************************/ - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef MUSB_C_NUM_EPS -#define MUSB_C_NUM_EPS ((u8)16) -#endif - -#ifndef MUSB_MAX_END0_PACKET -#define MUSB_MAX_END0_PACKET ((u16)MUSB_EP0_FIFOSIZE) -#endif - -/* host side ep0 states */ -enum musb_h_ep0_state { - MUSB_EP0_IDLE, - MUSB_EP0_START, /* expect ack of setup */ - MUSB_EP0_IN, /* expect IN DATA */ - MUSB_EP0_OUT, /* expect ack of OUT DATA */ - MUSB_EP0_STATUS, /* expect ack of STATUS */ -} __attribute__ ((packed)); - -/* peripheral side ep0 states */ -enum musb_g_ep0_state { - MUSB_EP0_STAGE_SETUP, /* idle, waiting for setup */ - MUSB_EP0_STAGE_TX, /* IN data */ - MUSB_EP0_STAGE_RX, /* OUT data */ - MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */ - MUSB_EP0_STAGE_STATUSOUT, /* (after IN data) */ - MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */ -} __attribute__ ((packed)); - -/* OTG protocol constants */ -#define OTG_TIME_A_WAIT_VRISE 100 /* msec (max) */ -#define OTG_TIME_A_WAIT_BCON 0 /* 0=infinite; min 1000 msec */ -#define OTG_TIME_A_IDLE_BDIS 200 /* msec (min) */ - -/*************************** REGISTER ACCESS ********************************/ - -/* Endpoint registers (other than dynfifo setup) can be accessed either - * directly with the "flat" model, or after setting up an index register. - */ - -#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) || \ - defined(CONFIG_ARCH_OMAP3430) -/* REVISIT indexed access seemed to - * misbehave (on DaVinci) for at least peripheral IN ... - */ -#define MUSB_FLAT_REG -#endif - -/* TUSB mapping: "flat" plus ep0 special cases */ -#if defined(CONFIG_USB_TUSB6010) -#define musb_ep_select(_mbase, _epnum) \ - musb_writeb((_mbase), MUSB_INDEX, (_epnum)) -#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET - -/* "flat" mapping: each endpoint has its own i/o address */ -#elif defined(MUSB_FLAT_REG) -#define musb_ep_select(_mbase, _epnum) (((void)(_mbase)),((void)(_epnum))) -#define MUSB_EP_OFFSET MUSB_FLAT_OFFSET - -/* "indexed" mapping: INDEX register controls register bank select */ -#else -#define musb_ep_select(_mbase, _epnum) \ - musb_writeb((_mbase), MUSB_INDEX, (_epnum)) -#define MUSB_EP_OFFSET MUSB_INDEXED_OFFSET -#endif - -/****************************** FUNCTIONS ********************************/ - -#define MUSB_HST_MODE(_musb)\ - { (_musb)->is_host=TRUE; } -#define MUSB_DEV_MODE(_musb) \ - { (_musb)->is_host=FALSE; } - -#define test_devctl_hst_mode(_x) \ - (musb_readb((_x)->mregs, MUSB_DEVCTL)&MUSB_DEVCTL_HM) - -#define MUSB_MODE(musb) ((musb)->is_host ? "Host" : "Peripheral") - -/******************************** TYPES *************************************/ - -/* - * struct musb_hw_ep - endpoint hardware (bidirectional) - * - * Ordered slightly for better cacheline locality. - */ -struct musb_hw_ep { - struct musb *musb; - void __iomem *fifo; - void __iomem *regs; - -#ifdef CONFIG_USB_TUSB6010 - void __iomem *conf; -#endif - - /* index in musb->endpoints[] */ - u8 epnum; - - /* hardware configuration, possibly dynamic */ - u8 is_shared_fifo; - u8 tx_double_buffered; - u8 rx_double_buffered; - u16 max_packet_sz_tx; - u16 max_packet_sz_rx; - - struct dma_channel *tx_channel; - struct dma_channel *rx_channel; - -#ifdef CONFIG_USB_TUSB6010 - /* TUSB has "asynchronous" and "synchronous" dma modes */ - dma_addr_t fifo_async; - dma_addr_t fifo_sync; - void __iomem *fifo_sync_va; -#endif - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - void __iomem *target_regs; - - /* currently scheduled peripheral endpoint */ - struct musb_qh *in_qh; - struct musb_qh *out_qh; - - u8 rx_reinit; - u8 tx_reinit; -#endif - -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - /* peripheral side */ - struct musb_ep ep_in; /* TX */ - struct musb_ep ep_out; /* RX */ -#endif -}; - -static inline struct usb_request *next_in_request(struct musb_hw_ep *hw_ep) -{ -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - return next_request(&hw_ep->ep_in); -#else - return NULL; -#endif -} - -static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep) -{ -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - return next_request(&hw_ep->ep_out); -#else - return NULL; -#endif -} - -/* - * struct musb - Driver instance data. - */ -struct musb { - spinlock_t lock; - struct clk *clock; - irqreturn_t (*isr)(int, void *); - struct work_struct irq_work; - -#ifdef CONFIG_USB_MUSB_HDRC_HCD - -/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */ -#define MUSB_PORT_STAT_RESUME (1 << 31) - - u32 port1_status; - unsigned long rh_timer; - - enum musb_h_ep0_state ep0_stage; - - /* bulk traffic normally dedicates endpoint hardware, and each - * direction has its own ring of host side endpoints. - * we try to progress the transfer at the head of each endpoint's - * queue until it completes or NAKs too much; then we try the next - * endpoint. - */ - struct musb_hw_ep *bulk_ep; - - struct list_head control; /* of musb_qh */ - struct list_head in_bulk; /* of musb_qh */ - struct list_head out_bulk; /* of musb_qh */ - struct musb_qh *periodic[32]; /* tree of interrupt+iso */ -#endif - - /* called with IRQs blocked; ON/nonzero implies starting a session, - * and waiting at least a_wait_vrise_tmout. - */ - void (*board_set_vbus)(struct musb *, int is_on); - - struct dma_controller *dma_controller; - - struct device *controller; - void __iomem *ctrl_base; - void __iomem *mregs; - -#ifdef CONFIG_USB_TUSB6010 - dma_addr_t async; - dma_addr_t sync; - void __iomem *sync_va; -#endif - - /* passed down from chip/board specific irq handlers */ - u8 int_usb; - u16 int_rx; - u16 int_tx; - - struct otg_transceiver xceiv; - - int nIrq; - - struct musb_hw_ep endpoints[MUSB_C_NUM_EPS]; -#define control_ep endpoints - -#define VBUSERR_RETRY_COUNT 3 - u16 vbuserr_retry; - u16 epmask; - u8 nr_endpoints; - - u8 board_mode; /* enum musb_mode */ - int (*board_set_power)(int state); - - int (*set_clock)(struct clk *clk, int is_active); - - u8 min_power; /* vbus for periph, in mA/2 */ - - /* active means connected and not suspended */ - unsigned is_active:1; - - unsigned is_multipoint:1; - unsigned is_host:1; - unsigned ignore_disconnect:1; /* during bus resets */ - - int a_wait_bcon; /* VBUS timeout in msecs */ - unsigned long idle_timeout; /* Next timeout in jiffies */ - -#ifdef C_MP_TX - unsigned bulk_split:1; -#define can_bulk_split(musb,type) \ - (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split) -#else -#define can_bulk_split(musb,type) 0 -#endif - -#ifdef C_MP_RX - unsigned bulk_combine:1; - /* REVISIT allegedly doesn't work reliably */ -#if 0 -#define can_bulk_combine(musb,type) \ - (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine) -#else -#define can_bulk_combine(musb,type) 0 -#endif -#else -#define can_bulk_combine(musb,type) 0 -#endif - -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - /* is_suspended means USB B_PERIPHERAL suspend */ - unsigned is_suspended:1; - - /* may_wakeup means remote wakeup is enabled */ - unsigned may_wakeup:1; - - /* is_self_powered is reported in device status and the - * config descriptor. is_bus_powered means B_PERIPHERAL - * draws some VBUS current; both can be true. - */ - unsigned is_self_powered:1; - unsigned is_bus_powered:1; - - unsigned set_address:1; - unsigned test_mode:1; - unsigned softconnect:1; - - enum musb_g_ep0_state ep0_state; - u8 address; - u8 test_mode_nr; - u16 ackpend; /* ep0 */ - struct usb_gadget g; /* the gadget */ - struct usb_gadget_driver *gadget_driver; /* its driver */ -#endif - -#ifdef MUSB_CONFIG_PROC_FS - struct proc_dir_entry *proc_entry; -#endif -}; - -static inline void musb_set_vbus(struct musb *musb, int is_on) -{ - musb->board_set_vbus(musb, is_on); -} - -#ifdef CONFIG_USB_GADGET_MUSB_HDRC -static inline struct musb *gadget_to_musb(struct usb_gadget *g) -{ - return container_of(g, struct musb, g); -} -#endif - - -/***************************** Glue it together *****************************/ - -extern const char musb_driver_name[]; - -extern void musb_start(struct musb *musb); -extern void musb_stop(struct musb *musb); - -extern void musb_write_fifo(struct musb_hw_ep *ep, - u16 len, const u8 * src); -extern void musb_read_fifo(struct musb_hw_ep *ep, - u16 len, u8 * dst); - -extern void musb_load_testpacket(struct musb *); - -extern irqreturn_t musb_interrupt(struct musb *); - -extern void musb_platform_enable(struct musb *musb); -extern void musb_platform_disable(struct musb *musb); - -extern void musb_hnp_stop(struct musb *musb); - -#ifdef CONFIG_USB_TUSB6010 -extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout); -extern int musb_platform_get_vbus_status(struct musb *musb); -extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode); -#else -#define musb_platform_try_idle(x, y) do {} while (0) -#define musb_platform_get_vbus_status(x) 0 -#define musb_platform_set_mode(x, y) do {} while (0) -#endif - -extern int __init musb_platform_init(struct musb *musb); -extern int musb_platform_exit(struct musb *musb); - -/*-------------------------- ProcFS definitions ---------------------*/ - -struct proc_dir_entry; - -#if (MUSB_DEBUG > 0) && defined(MUSB_CONFIG_PROC_FS) -extern struct proc_dir_entry *musb_debug_create(char *name, - struct musb *data); -extern void musb_debug_delete(char *name, struct musb *data); - -#else -static inline struct proc_dir_entry *musb_debug_create(char *name, - struct musb *data) -{ - return NULL; -} -static inline void musb_debug_delete(char *name, struct musb *data) -{ -} -#endif - -#endif /* __MUSB_MUSBDEFS_H__ */ diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 515b914..974fd7d 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -38,7 +38,7 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/platform_device.h> -#include "musbdefs.h" +#include "musb_core.h" #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) #include "omap2430.h" diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 3664ff8..660d202 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -33,7 +33,7 @@ #include <asm/arch/hardware.h> #include <asm/arch/mux.h> -#include "musbdefs.h" +#include "musb_core.h" #include "omap2430.h" #ifdef CONFIG_ARCH_OMAP3430 diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 4b5a4dc..537788e 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -23,7 +23,7 @@ #include <linux/irq.h> #include <linux/platform_device.h> -#include "musbdefs.h" +#include "musb_core.h" static void tusb_source_power(struct musb *musb, int is_on); diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index c71e123..c7fbfba 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -18,7 +18,7 @@ #include <asm/arch/dma.h> #include <asm/arch/mux.h> -#include "musbdefs.h" +#include "musb_core.h" /* * REVISIT: With TUSB2.0 only one dmareq line can be used at a time. diff --git a/drivers/usb/musb/virthub.c b/drivers/usb/musb/virthub.c index d9f3c28..9422881 100644 --- a/drivers/usb/musb/virthub.c +++ b/drivers/usb/musb/virthub.c @@ -43,7 +43,7 @@ #include <asm/unaligned.h> -#include "musbdefs.h" +#include "musb_core.h" static void musb_port_suspend(struct musb *musb, u8 bSuspend) -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/9] musb_hdrc: Rename dma.h to musb_dma.h 2007-08-20 9:10 ` [PATCH 5/9] musb_hdrc: Rename musbdefs.h to musb_core.h Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 2007-08-20 9:10 ` [PATCH 7/9] musb_hdrc: Rename g_ep0.c musb_gadget_ep0.c Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Rename dma.h to musb_dma.h Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/cppi_dma.h | 2 +- drivers/usb/musb/dma.h | 174 ------------------------------------------ drivers/usb/musb/musb_core.h | 2 +- drivers/usb/musb/musb_dma.h | 174 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 176 deletions(-) delete mode 100644 drivers/usb/musb/dma.h create mode 100644 drivers/usb/musb/musb_dma.h diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index c121865..1d72c1b 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -9,7 +9,7 @@ #include <linux/errno.h> #include <linux/dmapool.h> -#include "dma.h" +#include "musb_dma.h" #include "musb_core.h" #include "davinci.h" diff --git a/drivers/usb/musb/dma.h b/drivers/usb/musb/dma.h deleted file mode 100644 index deef0c2..0000000 --- a/drivers/usb/musb/dma.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * MUSB OTG driver DMA controller abstraction - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. - * - */ - -#ifndef __MUSB_DMA_H__ -#define __MUSB_DMA_H__ - -struct musb_hw_ep; - -/* - * DMA Controller Abstraction - * - * DMA Controllers are abstracted to allow use of a variety of different - * implementations of DMA, as allowed by the Inventra USB cores. On the - * host side, usbcore sets up the DMA mappings and flushes caches; on the - * peripheral side, the gadget controller driver does. Responsibilities - * of a DMA controller driver include: - * - * - Handling the details of moving multiple USB packets - * in cooperation with the Inventra USB core, including especially - * the correct RX side treatment of short packets and buffer-full - * states (both of which terminate transfers). - * - * - Knowing the correlation between dma channels and the - * Inventra core's local endpoint resources and data direction. - * - * - Maintaining a list of allocated/available channels. - * - * - Updating channel status on interrupts, - * whether shared with the Inventra core or separate. - */ - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#ifndef CONFIG_USB_MUSB_DISABLE_DMA -#define is_dma_capable() (1) -#else -#define is_dma_capable() (0) -#endif - -#ifdef CONFIG_USB_TI_CPPI_DMA -#define is_cppi_enabled() 1 -#else -#define is_cppi_enabled() 0 -#endif - -#ifdef CONFIG_USB_TUSB_OMAP_DMA -#define tusb_dma_omap() 1 -#else -#define tusb_dma_omap() 0 -#endif - -/* - * DMA channel status ... updated by the dma controller driver whenever that - * status changes, and protected by the overall controller spinlock. - */ -enum dma_channel_status { - /* unallocated */ - MUSB_DMA_STATUS_UNKNOWN, - /* allocated ... but not busy, no errors */ - MUSB_DMA_STATUS_FREE, - /* busy ... transactions are active */ - MUSB_DMA_STATUS_BUSY, - /* transaction(s) aborted due to ... dma or memory bus error */ - MUSB_DMA_STATUS_BUS_ABORT, - /* transaction(s) aborted due to ... core error or USB fault */ - MUSB_DMA_STATUS_CORE_ABORT -}; - -struct dma_controller; - -/** - * struct dma_channel - A DMA channel. - * @private_data: channel-private data - * @max_len: the maximum number of bytes the channel can move in one - * transaction (typically representing many USB maximum-sized packets) - * @actual_len: how many bytes have been transferred - * @status: current channel status (updated e.g. on interrupt) - * @desired_mode: TRUE if mode 1 is desired; FALSE if mode 0 is desired - * - * channels are associated with an endpoint for the duration of at least - * one usb transfer. - */ -struct dma_channel { - void *private_data; - // FIXME not void* private_data, but a dma_controller * - size_t max_len; - size_t actual_len; - enum dma_channel_status status; - u8 desired_mode; -}; - -/* - * dma_channel_status - return status of dma channel - * @c: the channel - * - * Returns the software's view of the channel status. If that status is BUSY - * then it's possible that the hardware has completed (or aborted) a transfer, - * so the driver needs to update that status. - */ -static inline enum dma_channel_status -dma_channel_status(struct dma_channel *c) -{ - return (is_dma_capable() && c) ? c->status : MUSB_DMA_STATUS_UNKNOWN; -} - -/** - * struct dma_controller - A DMA Controller. - * @private_data: controller-private data; - * @start: call this to start a DMA controller; - * return 0 on success, else negative errno - * @stop: call this to stop a DMA controller - * return 0 on success, else negative errno - * @channel_alloc: call this to allocate a DMA channel - * @channel_release: call this to release a DMA channel - * @channel_abort: call this to abort a pending DMA transaction, - * returning it to FREE (but allocated) state - * - * Controllers manage dma channels. - */ -struct dma_controller { - void *private_data; - 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 *); - int (*channel_program)(struct dma_channel *channel, - u16 maxpacket, u8 mode, - dma_addr_t dma_addr, - u32 length); - int (*channel_abort)(struct dma_channel *); -}; - -/* called after channel_program(), may indicate a fault */ -extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); - - -extern struct dma_controller *__init -dma_controller_create(struct musb *, void __iomem *); - -extern void dma_controller_destroy(struct dma_controller *); - -#endif /* __MUSB_DMA_H__ */ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index ed02839..56f8fbb 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -54,7 +54,7 @@ struct musb_ep; #include "debug.h" -#include "dma.h" +#include "musb_dma.h" #ifdef CONFIG_USB_MUSB_SOC /* diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h new file mode 100644 index 0000000..deef0c2 --- /dev/null +++ b/drivers/usb/musb/musb_dma.h @@ -0,0 +1,174 @@ +/* + * MUSB OTG driver DMA controller abstraction + * + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. + * + */ + +#ifndef __MUSB_DMA_H__ +#define __MUSB_DMA_H__ + +struct musb_hw_ep; + +/* + * DMA Controller Abstraction + * + * DMA Controllers are abstracted to allow use of a variety of different + * implementations of DMA, as allowed by the Inventra USB cores. On the + * host side, usbcore sets up the DMA mappings and flushes caches; on the + * peripheral side, the gadget controller driver does. Responsibilities + * of a DMA controller driver include: + * + * - Handling the details of moving multiple USB packets + * in cooperation with the Inventra USB core, including especially + * the correct RX side treatment of short packets and buffer-full + * states (both of which terminate transfers). + * + * - Knowing the correlation between dma channels and the + * Inventra core's local endpoint resources and data direction. + * + * - Maintaining a list of allocated/available channels. + * + * - Updating channel status on interrupts, + * whether shared with the Inventra core or separate. + */ + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +#ifndef CONFIG_USB_MUSB_DISABLE_DMA +#define is_dma_capable() (1) +#else +#define is_dma_capable() (0) +#endif + +#ifdef CONFIG_USB_TI_CPPI_DMA +#define is_cppi_enabled() 1 +#else +#define is_cppi_enabled() 0 +#endif + +#ifdef CONFIG_USB_TUSB_OMAP_DMA +#define tusb_dma_omap() 1 +#else +#define tusb_dma_omap() 0 +#endif + +/* + * DMA channel status ... updated by the dma controller driver whenever that + * status changes, and protected by the overall controller spinlock. + */ +enum dma_channel_status { + /* unallocated */ + MUSB_DMA_STATUS_UNKNOWN, + /* allocated ... but not busy, no errors */ + MUSB_DMA_STATUS_FREE, + /* busy ... transactions are active */ + MUSB_DMA_STATUS_BUSY, + /* transaction(s) aborted due to ... dma or memory bus error */ + MUSB_DMA_STATUS_BUS_ABORT, + /* transaction(s) aborted due to ... core error or USB fault */ + MUSB_DMA_STATUS_CORE_ABORT +}; + +struct dma_controller; + +/** + * struct dma_channel - A DMA channel. + * @private_data: channel-private data + * @max_len: the maximum number of bytes the channel can move in one + * transaction (typically representing many USB maximum-sized packets) + * @actual_len: how many bytes have been transferred + * @status: current channel status (updated e.g. on interrupt) + * @desired_mode: TRUE if mode 1 is desired; FALSE if mode 0 is desired + * + * channels are associated with an endpoint for the duration of at least + * one usb transfer. + */ +struct dma_channel { + void *private_data; + // FIXME not void* private_data, but a dma_controller * + size_t max_len; + size_t actual_len; + enum dma_channel_status status; + u8 desired_mode; +}; + +/* + * dma_channel_status - return status of dma channel + * @c: the channel + * + * Returns the software's view of the channel status. If that status is BUSY + * then it's possible that the hardware has completed (or aborted) a transfer, + * so the driver needs to update that status. + */ +static inline enum dma_channel_status +dma_channel_status(struct dma_channel *c) +{ + return (is_dma_capable() && c) ? c->status : MUSB_DMA_STATUS_UNKNOWN; +} + +/** + * struct dma_controller - A DMA Controller. + * @private_data: controller-private data; + * @start: call this to start a DMA controller; + * return 0 on success, else negative errno + * @stop: call this to stop a DMA controller + * return 0 on success, else negative errno + * @channel_alloc: call this to allocate a DMA channel + * @channel_release: call this to release a DMA channel + * @channel_abort: call this to abort a pending DMA transaction, + * returning it to FREE (but allocated) state + * + * Controllers manage dma channels. + */ +struct dma_controller { + void *private_data; + 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 *); + int (*channel_program)(struct dma_channel *channel, + u16 maxpacket, u8 mode, + dma_addr_t dma_addr, + u32 length); + int (*channel_abort)(struct dma_channel *); +}; + +/* called after channel_program(), may indicate a fault */ +extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); + + +extern struct dma_controller *__init +dma_controller_create(struct musb *, void __iomem *); + +extern void dma_controller_destroy(struct dma_controller *); + +#endif /* __MUSB_DMA_H__ */ -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 7/9] musb_hdrc: Rename g_ep0.c musb_gadget_ep0.c 2007-08-20 9:10 ` [PATCH 6/9] musb_hdrc: Rename dma.h to musb_dma.h Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 2007-08-20 9:10 ` [PATCH 8/9] musb_hdrc: Rename virthub.c musb_host_virthub.c Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Rename g_ep0.c musb_gadget_ep0.c Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/Makefile | 2 +- drivers/usb/musb/g_ep0.c | 963 ------------------------------------ drivers/usb/musb/musb_gadget_ep0.c | 963 ++++++++++++++++++++++++++++++++++++ 3 files changed, 964 insertions(+), 964 deletions(-) delete mode 100644 drivers/usb/musb/g_ep0.c create mode 100644 drivers/usb/musb/musb_gadget_ep0.c diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 537faed..e91bb2b 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -19,7 +19,7 @@ ifeq ($(CONFIG_ARCH_OMAP2430),y) endif ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y) - musb_hdrc-objs += g_ep0.o musb_gadget.o + musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o endif ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y) diff --git a/drivers/usb/musb/g_ep0.c b/drivers/usb/musb/g_ep0.c deleted file mode 100644 index 2395729..0000000 --- a/drivers/usb/musb/g_ep0.c +++ /dev/null @@ -1,963 +0,0 @@ -/* - * MUSB OTG driver ep0 handling - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. - * - */ - -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/timer.h> -#include <linux/spinlock.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/interrupt.h> - -#include "musb_core.h" - -/* ep0 is always musb->endpoints[0].ep_in */ -#define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0]) - -/* - * locking note: we use only the controller lock, for simpler correctness. - * It's always held with IRQs blocked. - * - * It protects the ep0 request queue as well as ep0_state, not just the - * controller and indexed registers. And that lock stays held unless it - * needs to be dropped to allow reentering this driver ... like upcalls to - * the gadget driver, or adjusting endpoint halt status. - */ - -static char *decode_ep0stage(u8 stage) -{ - switch(stage) { - case MUSB_EP0_STAGE_SETUP: return "idle"; - case MUSB_EP0_STAGE_TX: return "in"; - case MUSB_EP0_STAGE_RX: return "out"; - case MUSB_EP0_STAGE_ACKWAIT: return "wait"; - case MUSB_EP0_STAGE_STATUSIN: return "in/status"; - case MUSB_EP0_STAGE_STATUSOUT: return "out/status"; - default: return "?"; - } -} - -/* handle a standard GET_STATUS request - * Context: caller holds controller lock - */ -static int service_tx_status_request( - struct musb *musb, - const struct usb_ctrlrequest *ctrlrequest) -{ - void __iomem *mbase = musb->mregs; - int handled = 1; - u8 result[2], epnum = 0; - const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; - - result[1] = 0; - - switch (recip) { - case USB_RECIP_DEVICE: - result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED; - result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; -#ifdef CONFIG_USB_MUSB_OTG - if (musb->g.is_otg) { - result[0] |= musb->g.b_hnp_enable - << USB_DEVICE_B_HNP_ENABLE; - result[0] |= musb->g.a_alt_hnp_support - << USB_DEVICE_A_ALT_HNP_SUPPORT; - result[0] |= musb->g.a_hnp_support - << USB_DEVICE_A_HNP_SUPPORT; - } -#endif - break; - - case USB_RECIP_INTERFACE: - result[0] = 0; - break; - - case USB_RECIP_ENDPOINT: { - int is_in; - struct musb_ep *ep; - u16 tmp; - void __iomem *regs; - - epnum = (u8) ctrlrequest->wIndex; - if (!epnum) { - result[0] = 0; - break; - } - - is_in = epnum & USB_DIR_IN; - if (is_in) { - epnum &= 0x0f; - ep = &musb->endpoints[epnum].ep_in; - } else { - ep = &musb->endpoints[epnum].ep_out; - } - regs = musb->endpoints[epnum].regs; - - if (epnum >= MUSB_C_NUM_EPS || !ep->desc) { - handled = -EINVAL; - break; - } - - musb_ep_select(mbase, epnum); - if (is_in) - tmp = musb_readw(regs, MUSB_TXCSR) - & MUSB_TXCSR_P_SENDSTALL; - else - tmp = musb_readw(regs, MUSB_RXCSR) - & MUSB_RXCSR_P_SENDSTALL; - musb_ep_select(mbase, 0); - - result[0] = tmp ? 1 : 0; - } break; - - default: - /* class, vendor, etc ... delegate */ - handled = 0; - break; - } - - /* fill up the fifo; caller updates csr0 */ - if (handled > 0) { - u16 len = le16_to_cpu(ctrlrequest->wLength); - - if (len > 2) - len = 2; - musb_write_fifo(&musb->endpoints[0], len, result); - } - - return handled; -} - -/* - * handle a control-IN request, the end0 buffer contains the current request - * that is supposed to be a standard control request. Assumes the fifo to - * be at least 2 bytes long. - * - * @return 0 if the request was NOT HANDLED, - * < 0 when error - * > 0 when the request is processed - * - * Context: caller holds controller lock - */ -static int -service_in_request(struct musb *musb, - const struct usb_ctrlrequest *ctrlrequest) -{ - int handled = 0; /* not handled */ - - if ((ctrlrequest->bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD) { - switch (ctrlrequest->bRequest) { - case USB_REQ_GET_STATUS: - handled = service_tx_status_request(musb, - ctrlrequest); - break; - - /* case USB_REQ_SYNC_FRAME: */ - - default: - break; - } - } - return handled; -} - -/* - * Context: caller holds controller lock - */ -static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req) -{ - musb->ep0_state = MUSB_EP0_STAGE_SETUP; - musb_g_giveback(&musb->endpoints[0].ep_in, req, 0); -} - -/* - * Tries to start B-device HNP negotiation if enabled via sysfs - */ -static inline void musb_try_b_hnp_enable(struct musb *musb) -{ - void __iomem *mbase = musb->mregs; - u8 devctl; - - DBG(1, "HNP: Setting HR\n"); - devctl = musb_readb(mbase, MUSB_DEVCTL); - musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR); -} - -/* - * Handle all control requests with no DATA stage, including standard - * requests such as: - * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized - * always delegated to the gadget driver - * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE - * always handled here, except for class/vendor/... features - * - * Context: caller holds controller lock - */ -static int -service_zero_data_request(struct musb *musb, - struct usb_ctrlrequest *ctrlrequest) -__releases(musb->lock) -__acquires(musb->lock) -{ - int handled = -EINVAL; - void __iomem *mbase = musb->mregs; - const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; - - /* the gadget driver handles everything except what we MUST handle */ - if ((ctrlrequest->bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD) { - switch (ctrlrequest->bRequest) { - case USB_REQ_SET_ADDRESS: - /* change it after the status stage */ - musb->set_address = TRUE; - musb->address = (u8) (ctrlrequest->wValue & 0x7f); - handled = 1; - break; - - case USB_REQ_CLEAR_FEATURE: - switch (recip) { - case USB_RECIP_DEVICE: - if (ctrlrequest->wValue - != USB_DEVICE_REMOTE_WAKEUP) - break; - musb->may_wakeup = 0; - handled = 1; - break; - case USB_RECIP_INTERFACE: - break; - case USB_RECIP_ENDPOINT:{ - const u8 epnum = ctrlrequest->wIndex & 0x0f; - struct musb_ep *musb_ep; - - if (epnum == 0 - || epnum >= MUSB_C_NUM_EPS - || ctrlrequest->wValue - != USB_ENDPOINT_HALT) - break; - - if (ctrlrequest->wIndex & USB_DIR_IN) - musb_ep = &musb->endpoints[epnum].ep_in; - else - musb_ep = &musb->endpoints[epnum].ep_out; - if (!musb_ep->desc) - break; - - /* REVISIT do it directly, no locking games */ - spin_unlock(&musb->lock); - musb_gadget_set_halt(&musb_ep->end_point, 0); - spin_lock(&musb->lock); - - /* select ep0 again */ - musb_ep_select(mbase, 0); - handled = 1; - } break; - default: - /* class, vendor, etc ... delegate */ - handled = 0; - break; - } - break; - - case USB_REQ_SET_FEATURE: - switch (recip) { - case USB_RECIP_DEVICE: - handled = 1; - switch (ctrlrequest->wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - musb->may_wakeup = 1; - break; - case USB_DEVICE_TEST_MODE: - if (musb->g.speed != USB_SPEED_HIGH) - goto stall; - if (ctrlrequest->wIndex & 0xff) - goto stall; - - switch (ctrlrequest->wIndex >> 8) { - case 1: - pr_debug("TEST_J\n"); - /* TEST_J */ - musb->test_mode_nr = - MUSB_TEST_J; - break; - case 2: - /* TEST_K */ - pr_debug("TEST_K\n"); - musb->test_mode_nr = - MUSB_TEST_K; - break; - case 3: - /* TEST_SE0_NAK */ - pr_debug("TEST_SE0_NAK\n"); - musb->test_mode_nr = - MUSB_TEST_SE0_NAK; - break; - case 4: - /* TEST_PACKET */ - pr_debug("TEST_PACKET\n"); - musb->test_mode_nr = - MUSB_TEST_PACKET; - break; - default: - goto stall; - } - - /* enter test mode after irq */ - if (handled > 0) - musb->test_mode = TRUE; - break; -#ifdef CONFIG_USB_MUSB_OTG - case USB_DEVICE_B_HNP_ENABLE: - if (!musb->g.is_otg) - goto stall; - musb->g.b_hnp_enable = 1; - musb_try_b_hnp_enable(musb); - break; - case USB_DEVICE_A_HNP_SUPPORT: - if (!musb->g.is_otg) - goto stall; - musb->g.a_hnp_support = 1; - break; - case USB_DEVICE_A_ALT_HNP_SUPPORT: - if (!musb->g.is_otg) - goto stall; - musb->g.a_alt_hnp_support = 1; - break; -#endif -stall: - default: - handled = -EINVAL; - break; - } - break; - - case USB_RECIP_INTERFACE: - break; - - case USB_RECIP_ENDPOINT:{ - const u8 epnum = - ctrlrequest->wIndex & 0x0f; - struct musb_ep *musb_ep; - struct musb_hw_ep *ep; - void __iomem *regs; - int is_in; - u16 csr; - - if (epnum == 0 - || epnum >= MUSB_C_NUM_EPS - || ctrlrequest->wValue - != USB_ENDPOINT_HALT) - break; - - ep = musb->endpoints + epnum; - regs = ep->regs; - is_in = ctrlrequest->wIndex & USB_DIR_IN; - if (is_in) - musb_ep = &ep->ep_in; - else - musb_ep = &ep->ep_out; - if (!musb_ep->desc) - break; - - musb_ep_select(mbase, epnum); - if (is_in) { - csr = musb_readw(regs, - MUSB_TXCSR); - if (csr & MUSB_TXCSR_FIFONOTEMPTY) - csr |= MUSB_TXCSR_FLUSHFIFO; - csr |= MUSB_TXCSR_P_SENDSTALL - | MUSB_TXCSR_CLRDATATOG - | MUSB_TXCSR_P_WZC_BITS; - musb_writew(regs, MUSB_TXCSR, - csr); - } else { - csr = musb_readw(regs, - MUSB_RXCSR); - csr |= MUSB_RXCSR_P_SENDSTALL - | MUSB_RXCSR_FLUSHFIFO - | MUSB_RXCSR_CLRDATATOG - | MUSB_TXCSR_P_WZC_BITS; - musb_writew(regs, MUSB_RXCSR, - csr); - } - - /* select ep0 again */ - musb_ep_select(mbase, 0); - handled = 1; - } break; - - default: - /* class, vendor, etc ... delegate */ - handled = 0; - break; - } - break; - default: - /* delegate SET_CONFIGURATION, etc */ - handled = 0; - } - } else - handled = 0; - return handled; -} - -/* we have an ep0out data packet - * Context: caller holds controller lock - */ -static void ep0_rxstate(struct musb *this) -{ - void __iomem *regs = this->control_ep->regs; - struct usb_request *req; - u16 tmp; - - req = next_ep0_request(this); - - /* read packet and ack; or stall because of gadget driver bug: - * should have provided the rx buffer before setup() returned. - */ - if (req) { - void *buf = req->buf + req->actual; - unsigned len = req->length - req->actual; - - /* read the buffer */ - tmp = musb_readb(regs, MUSB_COUNT0); - if (tmp > len) { - req->status = -EOVERFLOW; - tmp = len; - } - musb_read_fifo(&this->endpoints[0], tmp, buf); - req->actual += tmp; - tmp = MUSB_CSR0_P_SVDRXPKTRDY; - if (tmp < 64 || req->actual == req->length) { - this->ep0_state = MUSB_EP0_STAGE_STATUSIN; - tmp |= MUSB_CSR0_P_DATAEND; - } else - req = NULL; - } else - tmp = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL; - musb_writew(regs, MUSB_CSR0, tmp); - - - /* NOTE: we "should" hold off reporting DATAEND and going to - * STATUSIN until after the completion handler decides whether - * to issue a stall instead, since this hardware can do that. - */ - if (req) - musb_g_ep0_giveback(this, req); -} - -/* - * transmitting to the host (IN), this code might be called from IRQ - * and from kernel thread. - * - * Context: caller holds controller lock - */ -static void ep0_txstate(struct musb *musb) -{ - void __iomem *regs = musb->control_ep->regs; - struct usb_request *request = next_ep0_request(musb); - u16 csr = MUSB_CSR0_TXPKTRDY; - u8 *fifo_src; - u8 fifo_count; - - if (!request) { - // WARN_ON(1); - DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0)); - return; - } - - /* load the data */ - fifo_src = (u8 *) request->buf + request->actual; - fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE, - request->length - request->actual); - musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src); - request->actual += fifo_count; - - /* update the flags */ - if (fifo_count < MUSB_MAX_END0_PACKET - || request->actual == request->length) { - musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT; - csr |= MUSB_CSR0_P_DATAEND; - } else - request = NULL; - - /* send it out, triggering a "txpktrdy cleared" irq */ - musb_writew(regs, MUSB_CSR0, csr); - - /* report completions as soon as the fifo's loaded; there's no - * win in waiting till this last packet gets acked. (other than - * very precise fault reporting, needed by USB TMC; possible with - * this hardware, but not usable from portable gadget drivers.) - */ - if (request) - musb_g_ep0_giveback(musb, request); -} - -/* - * Read a SETUP packet (struct usb_ctrlrequest) from the hardware. - * Fields are left in USB byte-order. - * - * Context: caller holds controller lock. - */ -static void -musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) -{ - struct usb_request *r; - void __iomem *regs = musb->control_ep->regs; - - musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req); - - /* NOTE: earlier 2.6 versions changed setup packets to host - * order, but now USB packets always stay in USB byte order. - */ - DBG(3, "SETUP req%02x.%02x v%04x i%04x l%d\n", - req->bRequestType, - req->bRequest, - le16_to_cpu(req->wValue), - le16_to_cpu(req->wIndex), - le16_to_cpu(req->wLength)); - - /* clean up any leftover transfers */ - r = next_ep0_request(musb); - if (r) - musb_g_ep0_giveback(musb, r); - - /* For zero-data requests we want to delay the STATUS stage to - * avoid SETUPEND errors. If we read data (OUT), delay accepting - * packets until there's a buffer to store them in. - * - * If we write data, the controller acts happier if we enable - * the TX FIFO right away, and give the controller a moment - * to switch modes... - */ - musb->set_address = FALSE; - musb->ackpend = MUSB_CSR0_P_SVDRXPKTRDY; - if (req->wLength == 0) { - if (req->bRequestType & USB_DIR_IN) - musb->ackpend |= MUSB_CSR0_TXPKTRDY; - musb->ep0_state = MUSB_EP0_STAGE_ACKWAIT; - } else if (req->bRequestType & USB_DIR_IN) { - musb->ep0_state = MUSB_EP0_STAGE_TX; - musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDRXPKTRDY); - while ((musb_readw(regs, MUSB_CSR0) - & MUSB_CSR0_RXPKTRDY) != 0) - cpu_relax(); - musb->ackpend = 0; - } else - musb->ep0_state = MUSB_EP0_STAGE_RX; -} - -static int -forward_to_driver(struct musb *musb, - const struct usb_ctrlrequest *ctrlrequest) -__releases(musb->lock) -__acquires(musb->lock) -{ - int retval; - if (!musb->gadget_driver) - return -EOPNOTSUPP; - spin_unlock(&musb->lock); - retval = musb->gadget_driver->setup(&musb->g, ctrlrequest); - spin_lock(&musb->lock); - return retval; -} - -/* - * Handle peripheral ep0 interrupt - * - * Context: irq handler; we won't re-enter the driver that way. - */ -irqreturn_t musb_g_ep0_irq(struct musb *musb) -{ - u16 csr; - u16 len; - void __iomem *mbase = musb->mregs; - void __iomem *regs = musb->endpoints[0].regs; - irqreturn_t retval = IRQ_NONE; - - musb_ep_select(mbase, 0); /* select ep0 */ - csr = musb_readw(regs, MUSB_CSR0); - len = musb_readb(regs, MUSB_COUNT0); - - DBG(4, "csr %04x, count %d, myaddr %d, ep0stage %s\n", - csr, len, - musb_readb(mbase, MUSB_FADDR), - decode_ep0stage(musb->ep0_state)); - - /* I sent a stall.. need to acknowledge it now.. */ - if (csr & MUSB_CSR0_P_SENTSTALL) { - musb_writew(regs, MUSB_CSR0, - csr & ~MUSB_CSR0_P_SENTSTALL); - retval = IRQ_HANDLED; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; - csr = musb_readw(regs, MUSB_CSR0); - } - - /* request ended "early" */ - if (csr & MUSB_CSR0_P_SETUPEND) { - musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND); - retval = IRQ_HANDLED; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; - csr = musb_readw(regs, MUSB_CSR0); - /* NOTE: request may need completion */ - } - - /* docs from Mentor only describe tx, rx, and idle/setup states. - * we need to handle nuances around status stages, and also the - * case where status and setup stages come back-to-back ... - */ - switch (musb->ep0_state) { - - case MUSB_EP0_STAGE_TX: - /* irq on clearing txpktrdy */ - if ((csr & MUSB_CSR0_TXPKTRDY) == 0) { - ep0_txstate(musb); - retval = IRQ_HANDLED; - } - break; - - case MUSB_EP0_STAGE_RX: - /* irq on set rxpktrdy */ - if (csr & MUSB_CSR0_RXPKTRDY) { - ep0_rxstate(musb); - retval = IRQ_HANDLED; - } - break; - - case MUSB_EP0_STAGE_STATUSIN: - /* end of sequence #2 (OUT/RX state) or #3 (no data) */ - - /* update address (if needed) only @ the end of the - * status phase per usb spec, which also guarantees - * we get 10 msec to receive this irq... until this - * is done we won't see the next packet. - */ - if (musb->set_address) { - musb->set_address = FALSE; - musb_writeb(mbase, MUSB_FADDR, musb->address); - } - - /* enter test mode if needed (exit by reset) */ - else if (musb->test_mode) { - DBG(1, "entering TESTMODE\n"); - - if (MUSB_TEST_PACKET == musb->test_mode_nr) - musb_load_testpacket(musb); - - musb_writeb(mbase, MUSB_TESTMODE, - musb->test_mode_nr); - } - /* FALLTHROUGH */ - - case MUSB_EP0_STAGE_STATUSOUT: - /* end of sequence #1: write to host (TX state) */ - { - struct usb_request *req; - - req = next_ep0_request(musb); - if (req) - musb_g_ep0_giveback(musb, req); - } - retval = IRQ_HANDLED; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; - /* FALLTHROUGH */ - - case MUSB_EP0_STAGE_SETUP: - if (csr & MUSB_CSR0_RXPKTRDY) { - struct usb_ctrlrequest setup; - int handled = 0; - - if (len != 8) { - ERR("SETUP packet len %d != 8 ?\n", len); - break; - } - musb_read_setup(musb, &setup); - retval = IRQ_HANDLED; - - /* sometimes the RESET won't be reported */ - if (unlikely(musb->g.speed == USB_SPEED_UNKNOWN)) { - u8 power; - - printk(KERN_NOTICE "%s: peripheral reset " - "irq lost!\n", - musb_driver_name); - power = musb_readb(mbase, MUSB_POWER); - musb->g.speed = (power & MUSB_POWER_HSMODE) - ? USB_SPEED_HIGH : USB_SPEED_FULL; - - } - - switch (musb->ep0_state) { - - /* sequence #3 (no data stage), includes requests - * we can't forward (notably SET_ADDRESS and the - * device/endpoint feature set/clear operations) - * plus SET_CONFIGURATION and others we must - */ - case MUSB_EP0_STAGE_ACKWAIT: - handled = service_zero_data_request( - musb, &setup); - - /* status stage might be immediate */ - if (handled > 0) { - musb->ackpend |= MUSB_CSR0_P_DATAEND; - musb->ep0_state = - MUSB_EP0_STAGE_STATUSIN; - } - break; - - /* sequence #1 (IN to host), includes GET_STATUS - * requests that we can't forward, GET_DESCRIPTOR - * and others that we must - */ - case MUSB_EP0_STAGE_TX: - handled = service_in_request(musb, &setup); - if (handled > 0) { - musb->ackpend = MUSB_CSR0_TXPKTRDY - | MUSB_CSR0_P_DATAEND; - musb->ep0_state = - MUSB_EP0_STAGE_STATUSOUT; - } - break; - - /* sequence #2 (OUT from host), always forward */ - default: /* MUSB_EP0_STAGE_RX */ - break; - } - - DBG(3, "handled %d, csr %04x, ep0stage %s\n", - handled, csr, - decode_ep0stage(musb->ep0_state)); - - /* unless we need to delegate this to the gadget - * driver, we know how to wrap this up: csr0 has - * not yet been written. - */ - if (handled < 0) - goto stall; - else if (handled > 0) - goto finish; - - handled = forward_to_driver(musb, &setup); - if (handled < 0) { - musb_ep_select(mbase, 0); -stall: - DBG(3, "stall (%d)\n", handled); - musb->ackpend |= MUSB_CSR0_P_SENDSTALL; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; -finish: - musb_writew(regs, MUSB_CSR0, - musb->ackpend); - musb->ackpend = 0; - } - } - break; - - case MUSB_EP0_STAGE_ACKWAIT: - /* This should not happen. But happens with tusb6010 with - * g_file_storage and high speed. Do nothing. - */ - retval = IRQ_HANDLED; - break; - - default: - /* "can't happen" */ - WARN_ON(1); - musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL); - musb->ep0_state = MUSB_EP0_STAGE_SETUP; - break; - } - - return retval; -} - - -static int -musb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) -{ - /* always enabled */ - return -EINVAL; -} - -static int musb_g_ep0_disable(struct usb_ep *e) -{ - /* always enabled */ - return -EINVAL; -} - -static int -musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags) -{ - struct musb_ep *ep; - struct musb_request *req; - struct musb *musb; - int status; - unsigned long lockflags; - void __iomem *regs; - - if (!e || !r) - return -EINVAL; - - ep = to_musb_ep(e); - musb = ep->musb; - regs = musb->control_ep->regs; - - req = to_musb_request(r); - req->musb = musb; - req->request.actual = 0; - req->request.status = -EINPROGRESS; - req->tx = ep->is_in; - - spin_lock_irqsave(&musb->lock, lockflags); - - if (!list_empty(&ep->req_list)) { - status = -EBUSY; - goto cleanup; - } - - switch (musb->ep0_state) { - case MUSB_EP0_STAGE_RX: /* control-OUT data */ - case MUSB_EP0_STAGE_TX: /* control-IN data */ - case MUSB_EP0_STAGE_ACKWAIT: /* zero-length data */ - status = 0; - break; - default: - DBG(1, "ep0 request queued in state %d\n", - musb->ep0_state); - status = -EINVAL; - goto cleanup; - } - - /* add request to the list */ - list_add_tail(&(req->request.list), &(ep->req_list)); - - DBG(3, "queue to %s (%s), length=%d\n", - ep->name, ep->is_in ? "IN/TX" : "OUT/RX", - req->request.length); - - musb_ep_select(musb->mregs, 0); - - /* sequence #1, IN ... start writing the data */ - if (musb->ep0_state == MUSB_EP0_STAGE_TX) - ep0_txstate(musb); - - /* sequence #3, no-data ... issue IN status */ - else if (musb->ep0_state == MUSB_EP0_STAGE_ACKWAIT) { - if (req->request.length) - status = -EINVAL; - else { - musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; - musb_writew(regs, MUSB_CSR0, - musb->ackpend | MUSB_CSR0_P_DATAEND); - musb->ackpend = 0; - musb_g_ep0_giveback(ep->musb, r); - } - - /* else for sequence #2 (OUT), caller provides a buffer - * before the next packet arrives. deferred responses - * (after SETUP is acked) are racey. - */ - } else if (musb->ackpend) { - musb_writew(regs, MUSB_CSR0, musb->ackpend); - musb->ackpend = 0; - } - -cleanup: - spin_unlock_irqrestore(&musb->lock, lockflags); - return status; -} - -static int -musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - /* we just won't support this */ - return -EINVAL; -} - -static int musb_g_ep0_halt(struct usb_ep *e, int value) -{ - struct musb_ep *ep; - struct musb *musb; - void __iomem *base, *regs; - unsigned long flags; - int status; - u16 csr; - - if (!e || !value) - return -EINVAL; - - ep = to_musb_ep(e); - musb = ep->musb; - base = musb->mregs; - regs = musb->control_ep->regs; - - spin_lock_irqsave(&musb->lock, flags); - - if (!list_empty(&ep->req_list)) { - status = -EBUSY; - goto cleanup; - } - - switch (musb->ep0_state) { - case MUSB_EP0_STAGE_TX: /* control-IN data */ - case MUSB_EP0_STAGE_ACKWAIT: /* STALL for zero-length data */ - case MUSB_EP0_STAGE_RX: /* control-OUT data */ - status = 0; - - musb_ep_select(base, 0); - csr = musb_readw(regs, MUSB_CSR0); - csr |= MUSB_CSR0_P_SENDSTALL; - musb_writew(regs, MUSB_CSR0, csr); - musb->ep0_state = MUSB_EP0_STAGE_SETUP; - break; - default: - DBG(1, "ep0 can't halt in state %d\n", musb->ep0_state); - status = -EINVAL; - } - -cleanup: - spin_unlock_irqrestore(&musb->lock, flags); - return status; -} - -const struct usb_ep_ops musb_g_ep0_ops = { - .enable = musb_g_ep0_enable, - .disable = musb_g_ep0_disable, - .alloc_request = musb_alloc_request, - .free_request = musb_free_request, - .queue = musb_g_ep0_queue, - .dequeue = musb_g_ep0_dequeue, - .set_halt = musb_g_ep0_halt, - .fifo_status = NULL, - .fifo_flush = NULL, -}; diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c new file mode 100644 index 0000000..2395729 --- /dev/null +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -0,0 +1,963 @@ +/* + * MUSB OTG driver ep0 handling + * + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. + * + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/interrupt.h> + +#include "musb_core.h" + +/* ep0 is always musb->endpoints[0].ep_in */ +#define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0]) + +/* + * locking note: we use only the controller lock, for simpler correctness. + * It's always held with IRQs blocked. + * + * It protects the ep0 request queue as well as ep0_state, not just the + * controller and indexed registers. And that lock stays held unless it + * needs to be dropped to allow reentering this driver ... like upcalls to + * the gadget driver, or adjusting endpoint halt status. + */ + +static char *decode_ep0stage(u8 stage) +{ + switch(stage) { + case MUSB_EP0_STAGE_SETUP: return "idle"; + case MUSB_EP0_STAGE_TX: return "in"; + case MUSB_EP0_STAGE_RX: return "out"; + case MUSB_EP0_STAGE_ACKWAIT: return "wait"; + case MUSB_EP0_STAGE_STATUSIN: return "in/status"; + case MUSB_EP0_STAGE_STATUSOUT: return "out/status"; + default: return "?"; + } +} + +/* handle a standard GET_STATUS request + * Context: caller holds controller lock + */ +static int service_tx_status_request( + struct musb *musb, + const struct usb_ctrlrequest *ctrlrequest) +{ + void __iomem *mbase = musb->mregs; + int handled = 1; + u8 result[2], epnum = 0; + const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; + + result[1] = 0; + + switch (recip) { + case USB_RECIP_DEVICE: + result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED; + result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; +#ifdef CONFIG_USB_MUSB_OTG + if (musb->g.is_otg) { + result[0] |= musb->g.b_hnp_enable + << USB_DEVICE_B_HNP_ENABLE; + result[0] |= musb->g.a_alt_hnp_support + << USB_DEVICE_A_ALT_HNP_SUPPORT; + result[0] |= musb->g.a_hnp_support + << USB_DEVICE_A_HNP_SUPPORT; + } +#endif + break; + + case USB_RECIP_INTERFACE: + result[0] = 0; + break; + + case USB_RECIP_ENDPOINT: { + int is_in; + struct musb_ep *ep; + u16 tmp; + void __iomem *regs; + + epnum = (u8) ctrlrequest->wIndex; + if (!epnum) { + result[0] = 0; + break; + } + + is_in = epnum & USB_DIR_IN; + if (is_in) { + epnum &= 0x0f; + ep = &musb->endpoints[epnum].ep_in; + } else { + ep = &musb->endpoints[epnum].ep_out; + } + regs = musb->endpoints[epnum].regs; + + if (epnum >= MUSB_C_NUM_EPS || !ep->desc) { + handled = -EINVAL; + break; + } + + musb_ep_select(mbase, epnum); + if (is_in) + tmp = musb_readw(regs, MUSB_TXCSR) + & MUSB_TXCSR_P_SENDSTALL; + else + tmp = musb_readw(regs, MUSB_RXCSR) + & MUSB_RXCSR_P_SENDSTALL; + musb_ep_select(mbase, 0); + + result[0] = tmp ? 1 : 0; + } break; + + default: + /* class, vendor, etc ... delegate */ + handled = 0; + break; + } + + /* fill up the fifo; caller updates csr0 */ + if (handled > 0) { + u16 len = le16_to_cpu(ctrlrequest->wLength); + + if (len > 2) + len = 2; + musb_write_fifo(&musb->endpoints[0], len, result); + } + + return handled; +} + +/* + * handle a control-IN request, the end0 buffer contains the current request + * that is supposed to be a standard control request. Assumes the fifo to + * be at least 2 bytes long. + * + * @return 0 if the request was NOT HANDLED, + * < 0 when error + * > 0 when the request is processed + * + * Context: caller holds controller lock + */ +static int +service_in_request(struct musb *musb, + const struct usb_ctrlrequest *ctrlrequest) +{ + int handled = 0; /* not handled */ + + if ((ctrlrequest->bRequestType & USB_TYPE_MASK) + == USB_TYPE_STANDARD) { + switch (ctrlrequest->bRequest) { + case USB_REQ_GET_STATUS: + handled = service_tx_status_request(musb, + ctrlrequest); + break; + + /* case USB_REQ_SYNC_FRAME: */ + + default: + break; + } + } + return handled; +} + +/* + * Context: caller holds controller lock + */ +static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req) +{ + musb->ep0_state = MUSB_EP0_STAGE_SETUP; + musb_g_giveback(&musb->endpoints[0].ep_in, req, 0); +} + +/* + * Tries to start B-device HNP negotiation if enabled via sysfs + */ +static inline void musb_try_b_hnp_enable(struct musb *musb) +{ + void __iomem *mbase = musb->mregs; + u8 devctl; + + DBG(1, "HNP: Setting HR\n"); + devctl = musb_readb(mbase, MUSB_DEVCTL); + musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR); +} + +/* + * Handle all control requests with no DATA stage, including standard + * requests such as: + * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized + * always delegated to the gadget driver + * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE + * always handled here, except for class/vendor/... features + * + * Context: caller holds controller lock + */ +static int +service_zero_data_request(struct musb *musb, + struct usb_ctrlrequest *ctrlrequest) +__releases(musb->lock) +__acquires(musb->lock) +{ + int handled = -EINVAL; + void __iomem *mbase = musb->mregs; + const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; + + /* the gadget driver handles everything except what we MUST handle */ + if ((ctrlrequest->bRequestType & USB_TYPE_MASK) + == USB_TYPE_STANDARD) { + switch (ctrlrequest->bRequest) { + case USB_REQ_SET_ADDRESS: + /* change it after the status stage */ + musb->set_address = TRUE; + musb->address = (u8) (ctrlrequest->wValue & 0x7f); + handled = 1; + break; + + case USB_REQ_CLEAR_FEATURE: + switch (recip) { + case USB_RECIP_DEVICE: + if (ctrlrequest->wValue + != USB_DEVICE_REMOTE_WAKEUP) + break; + musb->may_wakeup = 0; + handled = 1; + break; + case USB_RECIP_INTERFACE: + break; + case USB_RECIP_ENDPOINT:{ + const u8 epnum = ctrlrequest->wIndex & 0x0f; + struct musb_ep *musb_ep; + + if (epnum == 0 + || epnum >= MUSB_C_NUM_EPS + || ctrlrequest->wValue + != USB_ENDPOINT_HALT) + break; + + if (ctrlrequest->wIndex & USB_DIR_IN) + musb_ep = &musb->endpoints[epnum].ep_in; + else + musb_ep = &musb->endpoints[epnum].ep_out; + if (!musb_ep->desc) + break; + + /* REVISIT do it directly, no locking games */ + spin_unlock(&musb->lock); + musb_gadget_set_halt(&musb_ep->end_point, 0); + spin_lock(&musb->lock); + + /* select ep0 again */ + musb_ep_select(mbase, 0); + handled = 1; + } break; + default: + /* class, vendor, etc ... delegate */ + handled = 0; + break; + } + break; + + case USB_REQ_SET_FEATURE: + switch (recip) { + case USB_RECIP_DEVICE: + handled = 1; + switch (ctrlrequest->wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + musb->may_wakeup = 1; + break; + case USB_DEVICE_TEST_MODE: + if (musb->g.speed != USB_SPEED_HIGH) + goto stall; + if (ctrlrequest->wIndex & 0xff) + goto stall; + + switch (ctrlrequest->wIndex >> 8) { + case 1: + pr_debug("TEST_J\n"); + /* TEST_J */ + musb->test_mode_nr = + MUSB_TEST_J; + break; + case 2: + /* TEST_K */ + pr_debug("TEST_K\n"); + musb->test_mode_nr = + MUSB_TEST_K; + break; + case 3: + /* TEST_SE0_NAK */ + pr_debug("TEST_SE0_NAK\n"); + musb->test_mode_nr = + MUSB_TEST_SE0_NAK; + break; + case 4: + /* TEST_PACKET */ + pr_debug("TEST_PACKET\n"); + musb->test_mode_nr = + MUSB_TEST_PACKET; + break; + default: + goto stall; + } + + /* enter test mode after irq */ + if (handled > 0) + musb->test_mode = TRUE; + break; +#ifdef CONFIG_USB_MUSB_OTG + case USB_DEVICE_B_HNP_ENABLE: + if (!musb->g.is_otg) + goto stall; + musb->g.b_hnp_enable = 1; + musb_try_b_hnp_enable(musb); + break; + case USB_DEVICE_A_HNP_SUPPORT: + if (!musb->g.is_otg) + goto stall; + musb->g.a_hnp_support = 1; + break; + case USB_DEVICE_A_ALT_HNP_SUPPORT: + if (!musb->g.is_otg) + goto stall; + musb->g.a_alt_hnp_support = 1; + break; +#endif +stall: + default: + handled = -EINVAL; + break; + } + break; + + case USB_RECIP_INTERFACE: + break; + + case USB_RECIP_ENDPOINT:{ + const u8 epnum = + ctrlrequest->wIndex & 0x0f; + struct musb_ep *musb_ep; + struct musb_hw_ep *ep; + void __iomem *regs; + int is_in; + u16 csr; + + if (epnum == 0 + || epnum >= MUSB_C_NUM_EPS + || ctrlrequest->wValue + != USB_ENDPOINT_HALT) + break; + + ep = musb->endpoints + epnum; + regs = ep->regs; + is_in = ctrlrequest->wIndex & USB_DIR_IN; + if (is_in) + musb_ep = &ep->ep_in; + else + musb_ep = &ep->ep_out; + if (!musb_ep->desc) + break; + + musb_ep_select(mbase, epnum); + if (is_in) { + csr = musb_readw(regs, + MUSB_TXCSR); + if (csr & MUSB_TXCSR_FIFONOTEMPTY) + csr |= MUSB_TXCSR_FLUSHFIFO; + csr |= MUSB_TXCSR_P_SENDSTALL + | MUSB_TXCSR_CLRDATATOG + | MUSB_TXCSR_P_WZC_BITS; + musb_writew(regs, MUSB_TXCSR, + csr); + } else { + csr = musb_readw(regs, + MUSB_RXCSR); + csr |= MUSB_RXCSR_P_SENDSTALL + | MUSB_RXCSR_FLUSHFIFO + | MUSB_RXCSR_CLRDATATOG + | MUSB_TXCSR_P_WZC_BITS; + musb_writew(regs, MUSB_RXCSR, + csr); + } + + /* select ep0 again */ + musb_ep_select(mbase, 0); + handled = 1; + } break; + + default: + /* class, vendor, etc ... delegate */ + handled = 0; + break; + } + break; + default: + /* delegate SET_CONFIGURATION, etc */ + handled = 0; + } + } else + handled = 0; + return handled; +} + +/* we have an ep0out data packet + * Context: caller holds controller lock + */ +static void ep0_rxstate(struct musb *this) +{ + void __iomem *regs = this->control_ep->regs; + struct usb_request *req; + u16 tmp; + + req = next_ep0_request(this); + + /* read packet and ack; or stall because of gadget driver bug: + * should have provided the rx buffer before setup() returned. + */ + if (req) { + void *buf = req->buf + req->actual; + unsigned len = req->length - req->actual; + + /* read the buffer */ + tmp = musb_readb(regs, MUSB_COUNT0); + if (tmp > len) { + req->status = -EOVERFLOW; + tmp = len; + } + musb_read_fifo(&this->endpoints[0], tmp, buf); + req->actual += tmp; + tmp = MUSB_CSR0_P_SVDRXPKTRDY; + if (tmp < 64 || req->actual == req->length) { + this->ep0_state = MUSB_EP0_STAGE_STATUSIN; + tmp |= MUSB_CSR0_P_DATAEND; + } else + req = NULL; + } else + tmp = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL; + musb_writew(regs, MUSB_CSR0, tmp); + + + /* NOTE: we "should" hold off reporting DATAEND and going to + * STATUSIN until after the completion handler decides whether + * to issue a stall instead, since this hardware can do that. + */ + if (req) + musb_g_ep0_giveback(this, req); +} + +/* + * transmitting to the host (IN), this code might be called from IRQ + * and from kernel thread. + * + * Context: caller holds controller lock + */ +static void ep0_txstate(struct musb *musb) +{ + void __iomem *regs = musb->control_ep->regs; + struct usb_request *request = next_ep0_request(musb); + u16 csr = MUSB_CSR0_TXPKTRDY; + u8 *fifo_src; + u8 fifo_count; + + if (!request) { + // WARN_ON(1); + DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0)); + return; + } + + /* load the data */ + fifo_src = (u8 *) request->buf + request->actual; + fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE, + request->length - request->actual); + musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src); + request->actual += fifo_count; + + /* update the flags */ + if (fifo_count < MUSB_MAX_END0_PACKET + || request->actual == request->length) { + musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT; + csr |= MUSB_CSR0_P_DATAEND; + } else + request = NULL; + + /* send it out, triggering a "txpktrdy cleared" irq */ + musb_writew(regs, MUSB_CSR0, csr); + + /* report completions as soon as the fifo's loaded; there's no + * win in waiting till this last packet gets acked. (other than + * very precise fault reporting, needed by USB TMC; possible with + * this hardware, but not usable from portable gadget drivers.) + */ + if (request) + musb_g_ep0_giveback(musb, request); +} + +/* + * Read a SETUP packet (struct usb_ctrlrequest) from the hardware. + * Fields are left in USB byte-order. + * + * Context: caller holds controller lock. + */ +static void +musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) +{ + struct usb_request *r; + void __iomem *regs = musb->control_ep->regs; + + musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req); + + /* NOTE: earlier 2.6 versions changed setup packets to host + * order, but now USB packets always stay in USB byte order. + */ + DBG(3, "SETUP req%02x.%02x v%04x i%04x l%d\n", + req->bRequestType, + req->bRequest, + le16_to_cpu(req->wValue), + le16_to_cpu(req->wIndex), + le16_to_cpu(req->wLength)); + + /* clean up any leftover transfers */ + r = next_ep0_request(musb); + if (r) + musb_g_ep0_giveback(musb, r); + + /* For zero-data requests we want to delay the STATUS stage to + * avoid SETUPEND errors. If we read data (OUT), delay accepting + * packets until there's a buffer to store them in. + * + * If we write data, the controller acts happier if we enable + * the TX FIFO right away, and give the controller a moment + * to switch modes... + */ + musb->set_address = FALSE; + musb->ackpend = MUSB_CSR0_P_SVDRXPKTRDY; + if (req->wLength == 0) { + if (req->bRequestType & USB_DIR_IN) + musb->ackpend |= MUSB_CSR0_TXPKTRDY; + musb->ep0_state = MUSB_EP0_STAGE_ACKWAIT; + } else if (req->bRequestType & USB_DIR_IN) { + musb->ep0_state = MUSB_EP0_STAGE_TX; + musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDRXPKTRDY); + while ((musb_readw(regs, MUSB_CSR0) + & MUSB_CSR0_RXPKTRDY) != 0) + cpu_relax(); + musb->ackpend = 0; + } else + musb->ep0_state = MUSB_EP0_STAGE_RX; +} + +static int +forward_to_driver(struct musb *musb, + const struct usb_ctrlrequest *ctrlrequest) +__releases(musb->lock) +__acquires(musb->lock) +{ + int retval; + if (!musb->gadget_driver) + return -EOPNOTSUPP; + spin_unlock(&musb->lock); + retval = musb->gadget_driver->setup(&musb->g, ctrlrequest); + spin_lock(&musb->lock); + return retval; +} + +/* + * Handle peripheral ep0 interrupt + * + * Context: irq handler; we won't re-enter the driver that way. + */ +irqreturn_t musb_g_ep0_irq(struct musb *musb) +{ + u16 csr; + u16 len; + void __iomem *mbase = musb->mregs; + void __iomem *regs = musb->endpoints[0].regs; + irqreturn_t retval = IRQ_NONE; + + musb_ep_select(mbase, 0); /* select ep0 */ + csr = musb_readw(regs, MUSB_CSR0); + len = musb_readb(regs, MUSB_COUNT0); + + DBG(4, "csr %04x, count %d, myaddr %d, ep0stage %s\n", + csr, len, + musb_readb(mbase, MUSB_FADDR), + decode_ep0stage(musb->ep0_state)); + + /* I sent a stall.. need to acknowledge it now.. */ + if (csr & MUSB_CSR0_P_SENTSTALL) { + musb_writew(regs, MUSB_CSR0, + csr & ~MUSB_CSR0_P_SENTSTALL); + retval = IRQ_HANDLED; + musb->ep0_state = MUSB_EP0_STAGE_SETUP; + csr = musb_readw(regs, MUSB_CSR0); + } + + /* request ended "early" */ + if (csr & MUSB_CSR0_P_SETUPEND) { + musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND); + retval = IRQ_HANDLED; + musb->ep0_state = MUSB_EP0_STAGE_SETUP; + csr = musb_readw(regs, MUSB_CSR0); + /* NOTE: request may need completion */ + } + + /* docs from Mentor only describe tx, rx, and idle/setup states. + * we need to handle nuances around status stages, and also the + * case where status and setup stages come back-to-back ... + */ + switch (musb->ep0_state) { + + case MUSB_EP0_STAGE_TX: + /* irq on clearing txpktrdy */ + if ((csr & MUSB_CSR0_TXPKTRDY) == 0) { + ep0_txstate(musb); + retval = IRQ_HANDLED; + } + break; + + case MUSB_EP0_STAGE_RX: + /* irq on set rxpktrdy */ + if (csr & MUSB_CSR0_RXPKTRDY) { + ep0_rxstate(musb); + retval = IRQ_HANDLED; + } + break; + + case MUSB_EP0_STAGE_STATUSIN: + /* end of sequence #2 (OUT/RX state) or #3 (no data) */ + + /* update address (if needed) only @ the end of the + * status phase per usb spec, which also guarantees + * we get 10 msec to receive this irq... until this + * is done we won't see the next packet. + */ + if (musb->set_address) { + musb->set_address = FALSE; + musb_writeb(mbase, MUSB_FADDR, musb->address); + } + + /* enter test mode if needed (exit by reset) */ + else if (musb->test_mode) { + DBG(1, "entering TESTMODE\n"); + + if (MUSB_TEST_PACKET == musb->test_mode_nr) + musb_load_testpacket(musb); + + musb_writeb(mbase, MUSB_TESTMODE, + musb->test_mode_nr); + } + /* FALLTHROUGH */ + + case MUSB_EP0_STAGE_STATUSOUT: + /* end of sequence #1: write to host (TX state) */ + { + struct usb_request *req; + + req = next_ep0_request(musb); + if (req) + musb_g_ep0_giveback(musb, req); + } + retval = IRQ_HANDLED; + musb->ep0_state = MUSB_EP0_STAGE_SETUP; + /* FALLTHROUGH */ + + case MUSB_EP0_STAGE_SETUP: + if (csr & MUSB_CSR0_RXPKTRDY) { + struct usb_ctrlrequest setup; + int handled = 0; + + if (len != 8) { + ERR("SETUP packet len %d != 8 ?\n", len); + break; + } + musb_read_setup(musb, &setup); + retval = IRQ_HANDLED; + + /* sometimes the RESET won't be reported */ + if (unlikely(musb->g.speed == USB_SPEED_UNKNOWN)) { + u8 power; + + printk(KERN_NOTICE "%s: peripheral reset " + "irq lost!\n", + musb_driver_name); + power = musb_readb(mbase, MUSB_POWER); + musb->g.speed = (power & MUSB_POWER_HSMODE) + ? USB_SPEED_HIGH : USB_SPEED_FULL; + + } + + switch (musb->ep0_state) { + + /* sequence #3 (no data stage), includes requests + * we can't forward (notably SET_ADDRESS and the + * device/endpoint feature set/clear operations) + * plus SET_CONFIGURATION and others we must + */ + case MUSB_EP0_STAGE_ACKWAIT: + handled = service_zero_data_request( + musb, &setup); + + /* status stage might be immediate */ + if (handled > 0) { + musb->ackpend |= MUSB_CSR0_P_DATAEND; + musb->ep0_state = + MUSB_EP0_STAGE_STATUSIN; + } + break; + + /* sequence #1 (IN to host), includes GET_STATUS + * requests that we can't forward, GET_DESCRIPTOR + * and others that we must + */ + case MUSB_EP0_STAGE_TX: + handled = service_in_request(musb, &setup); + if (handled > 0) { + musb->ackpend = MUSB_CSR0_TXPKTRDY + | MUSB_CSR0_P_DATAEND; + musb->ep0_state = + MUSB_EP0_STAGE_STATUSOUT; + } + break; + + /* sequence #2 (OUT from host), always forward */ + default: /* MUSB_EP0_STAGE_RX */ + break; + } + + DBG(3, "handled %d, csr %04x, ep0stage %s\n", + handled, csr, + decode_ep0stage(musb->ep0_state)); + + /* unless we need to delegate this to the gadget + * driver, we know how to wrap this up: csr0 has + * not yet been written. + */ + if (handled < 0) + goto stall; + else if (handled > 0) + goto finish; + + handled = forward_to_driver(musb, &setup); + if (handled < 0) { + musb_ep_select(mbase, 0); +stall: + DBG(3, "stall (%d)\n", handled); + musb->ackpend |= MUSB_CSR0_P_SENDSTALL; + musb->ep0_state = MUSB_EP0_STAGE_SETUP; +finish: + musb_writew(regs, MUSB_CSR0, + musb->ackpend); + musb->ackpend = 0; + } + } + break; + + case MUSB_EP0_STAGE_ACKWAIT: + /* This should not happen. But happens with tusb6010 with + * g_file_storage and high speed. Do nothing. + */ + retval = IRQ_HANDLED; + break; + + default: + /* "can't happen" */ + WARN_ON(1); + musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL); + musb->ep0_state = MUSB_EP0_STAGE_SETUP; + break; + } + + return retval; +} + + +static int +musb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) +{ + /* always enabled */ + return -EINVAL; +} + +static int musb_g_ep0_disable(struct usb_ep *e) +{ + /* always enabled */ + return -EINVAL; +} + +static int +musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags) +{ + struct musb_ep *ep; + struct musb_request *req; + struct musb *musb; + int status; + unsigned long lockflags; + void __iomem *regs; + + if (!e || !r) + return -EINVAL; + + ep = to_musb_ep(e); + musb = ep->musb; + regs = musb->control_ep->regs; + + req = to_musb_request(r); + req->musb = musb; + req->request.actual = 0; + req->request.status = -EINPROGRESS; + req->tx = ep->is_in; + + spin_lock_irqsave(&musb->lock, lockflags); + + if (!list_empty(&ep->req_list)) { + status = -EBUSY; + goto cleanup; + } + + switch (musb->ep0_state) { + case MUSB_EP0_STAGE_RX: /* control-OUT data */ + case MUSB_EP0_STAGE_TX: /* control-IN data */ + case MUSB_EP0_STAGE_ACKWAIT: /* zero-length data */ + status = 0; + break; + default: + DBG(1, "ep0 request queued in state %d\n", + musb->ep0_state); + status = -EINVAL; + goto cleanup; + } + + /* add request to the list */ + list_add_tail(&(req->request.list), &(ep->req_list)); + + DBG(3, "queue to %s (%s), length=%d\n", + ep->name, ep->is_in ? "IN/TX" : "OUT/RX", + req->request.length); + + musb_ep_select(musb->mregs, 0); + + /* sequence #1, IN ... start writing the data */ + if (musb->ep0_state == MUSB_EP0_STAGE_TX) + ep0_txstate(musb); + + /* sequence #3, no-data ... issue IN status */ + else if (musb->ep0_state == MUSB_EP0_STAGE_ACKWAIT) { + if (req->request.length) + status = -EINVAL; + else { + musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; + musb_writew(regs, MUSB_CSR0, + musb->ackpend | MUSB_CSR0_P_DATAEND); + musb->ackpend = 0; + musb_g_ep0_giveback(ep->musb, r); + } + + /* else for sequence #2 (OUT), caller provides a buffer + * before the next packet arrives. deferred responses + * (after SETUP is acked) are racey. + */ + } else if (musb->ackpend) { + musb_writew(regs, MUSB_CSR0, musb->ackpend); + musb->ackpend = 0; + } + +cleanup: + spin_unlock_irqrestore(&musb->lock, lockflags); + return status; +} + +static int +musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + /* we just won't support this */ + return -EINVAL; +} + +static int musb_g_ep0_halt(struct usb_ep *e, int value) +{ + struct musb_ep *ep; + struct musb *musb; + void __iomem *base, *regs; + unsigned long flags; + int status; + u16 csr; + + if (!e || !value) + return -EINVAL; + + ep = to_musb_ep(e); + musb = ep->musb; + base = musb->mregs; + regs = musb->control_ep->regs; + + spin_lock_irqsave(&musb->lock, flags); + + if (!list_empty(&ep->req_list)) { + status = -EBUSY; + goto cleanup; + } + + switch (musb->ep0_state) { + case MUSB_EP0_STAGE_TX: /* control-IN data */ + case MUSB_EP0_STAGE_ACKWAIT: /* STALL for zero-length data */ + case MUSB_EP0_STAGE_RX: /* control-OUT data */ + status = 0; + + musb_ep_select(base, 0); + csr = musb_readw(regs, MUSB_CSR0); + csr |= MUSB_CSR0_P_SENDSTALL; + musb_writew(regs, MUSB_CSR0, csr); + musb->ep0_state = MUSB_EP0_STAGE_SETUP; + break; + default: + DBG(1, "ep0 can't halt in state %d\n", musb->ep0_state); + status = -EINVAL; + } + +cleanup: + spin_unlock_irqrestore(&musb->lock, flags); + return status; +} + +const struct usb_ep_ops musb_g_ep0_ops = { + .enable = musb_g_ep0_enable, + .disable = musb_g_ep0_disable, + .alloc_request = musb_alloc_request, + .free_request = musb_free_request, + .queue = musb_g_ep0_queue, + .dequeue = musb_g_ep0_dequeue, + .set_halt = musb_g_ep0_halt, + .fifo_status = NULL, + .fifo_flush = NULL, +}; -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 8/9] musb_hdrc: Rename virthub.c musb_host_virthub.c 2007-08-20 9:10 ` [PATCH 7/9] musb_hdrc: Rename g_ep0.c musb_gadget_ep0.c Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 2007-08-20 9:10 ` [PATCH 9/9] musb_hdrc: Rename debug.h to musb_debug.h Tony Lindgren 0 siblings, 1 reply; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Rename virthub.c musb_host_virthub.c Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/Makefile | 2 +- drivers/usb/musb/musb_host_virthub.c | 418 ++++++++++++++++++++++++++++++++++ drivers/usb/musb/virthub.c | 418 ---------------------------------- 3 files changed, 419 insertions(+), 419 deletions(-) create mode 100644 drivers/usb/musb/musb_host_virthub.c delete mode 100644 drivers/usb/musb/virthub.c diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index e91bb2b..4f0ae5a 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -23,7 +23,7 @@ ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y) endif ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y) - musb_hdrc-objs += virthub.o musb_host.o + musb_hdrc-objs += musb_host_virthub.o musb_host.o endif # the kconfig must guarantee that only one of the diff --git a/drivers/usb/musb/musb_host_virthub.c b/drivers/usb/musb/musb_host_virthub.c new file mode 100644 index 0000000..9422881 --- /dev/null +++ b/drivers/usb/musb/musb_host_virthub.c @@ -0,0 +1,418 @@ +/* + * MUSB OTG driver virtual hub support + * + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/timer.h> + +#include <asm/unaligned.h> + +#include "musb_core.h" + + +static void musb_port_suspend(struct musb *musb, u8 bSuspend) +{ + u8 power; + void __iomem *mbase = musb->mregs; + + if (!is_host_active(musb)) + return; + + /* NOTE: this doesn't necessarily put PHY into low power mode, + * turning off its clock; that's a function of PHY integration and + * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect + * SE0 changing to connect (J) or wakeup (K) states. + */ + power = musb_readb(mbase, MUSB_POWER); + if (bSuspend) { + int retries = 10000; + + power &= ~MUSB_POWER_RESUME; + power |= MUSB_POWER_SUSPENDM; + musb_writeb(mbase, MUSB_POWER, power); + + /* Needed for OPT A tests */ + power = musb_readb(mbase, MUSB_POWER); + while (power & MUSB_POWER_SUSPENDM) { + power = musb_readb(mbase, MUSB_POWER); + if (retries-- < 1) + break; + } + + DBG(3, "Root port suspended, power %02x\n", power); + + musb->port1_status |= USB_PORT_STAT_SUSPEND; + switch (musb->xceiv.state) { + case OTG_STATE_A_HOST: + musb->xceiv.state = OTG_STATE_A_SUSPEND; + musb->is_active = is_otg_enabled(musb) + && musb->xceiv.host->b_hnp_enable; + musb_platform_try_idle(musb, 0); + break; +#ifdef CONFIG_USB_MUSB_OTG + case OTG_STATE_B_HOST: + musb->xceiv.state = OTG_STATE_B_WAIT_ACON; + musb->is_active = is_otg_enabled(musb) + && musb->xceiv.host->b_hnp_enable; + musb_platform_try_idle(musb, 0); + break; +#endif + default: + DBG(1, "bogus rh suspend? %s\n", + otg_state_string(musb)); + } + } else if (power & MUSB_POWER_SUSPENDM) { + power &= ~MUSB_POWER_SUSPENDM; + power |= MUSB_POWER_RESUME; + musb_writeb(mbase, MUSB_POWER, power); + + DBG(3, "Root port resuming, power %02x\n", power); + + /* later, GetPortStatus will stop RESUME signaling */ + musb->port1_status |= MUSB_PORT_STAT_RESUME; + musb->rh_timer = jiffies + msecs_to_jiffies(20); + } +} + +static void musb_port_reset(struct musb *musb, u8 bReset) +{ + u8 power; + void __iomem *mbase = musb->mregs; + +#ifdef CONFIG_USB_MUSB_OTG + if (musb->xceiv.state == OTG_STATE_B_IDLE) { + DBG(2, "HNP: Returning from HNP, not resetting hub as b_idle\n"); + musb->port1_status &= ~USB_PORT_STAT_RESET; + return; + } +#endif + + if (!is_host_active(musb)) + return; + + /* NOTE: caller guarantees it will turn off the reset when + * the appropriate amount of time has passed + */ + power = musb_readb(mbase, MUSB_POWER); + if (bReset) { + + /* + * If RESUME is set, we must make sure it stays minimum 20 ms. + * Then we must clear RESUME and wait a bit to let musb start + * generating SOFs. If we don't do this, OPT HS A 6.8 tests + * fail with "Error! Did not receive an SOF before suspend + * detected". + */ + if (power & MUSB_POWER_RESUME) { + while (time_before(jiffies, musb->rh_timer)) + msleep(1); + musb_writeb(mbase, MUSB_POWER, + power & ~MUSB_POWER_RESUME); + msleep(1); + } + + musb->ignore_disconnect = TRUE; + power &= 0xf0; + musb_writeb(mbase, MUSB_POWER, + power | MUSB_POWER_RESET); + + musb->port1_status |= USB_PORT_STAT_RESET; + musb->port1_status &= ~USB_PORT_STAT_ENABLE; + musb->rh_timer = jiffies + msecs_to_jiffies(50); + } else { + DBG(4, "root port reset stopped\n"); + musb_writeb(mbase, MUSB_POWER, + power & ~MUSB_POWER_RESET); + + musb->ignore_disconnect = FALSE; + + power = musb_readb(mbase, MUSB_POWER); + if (power & MUSB_POWER_HSMODE) { + DBG(4, "high-speed device connected\n"); + musb->port1_status |= USB_PORT_STAT_HIGH_SPEED; + } + + musb->port1_status &= ~USB_PORT_STAT_RESET; + musb->port1_status |= USB_PORT_STAT_ENABLE + | (USB_PORT_STAT_C_RESET << 16) + | (USB_PORT_STAT_C_ENABLE << 16); + usb_hcd_poll_rh_status(musb_to_hcd(musb)); + + musb->vbuserr_retry = VBUSERR_RETRY_COUNT; + } +} + +void musb_root_disconnect(struct musb *musb) +{ + musb->port1_status = (1 << USB_PORT_FEAT_POWER) + | (1 << USB_PORT_FEAT_C_CONNECTION); + + usb_hcd_poll_rh_status(musb_to_hcd(musb)); + musb->is_active = 0; + + switch (musb->xceiv.state) { + case OTG_STATE_A_HOST: + case OTG_STATE_A_SUSPEND: + musb->xceiv.state = OTG_STATE_A_WAIT_BCON; + break; + case OTG_STATE_A_WAIT_VFALL: + musb->xceiv.state = OTG_STATE_B_IDLE; + break; + default: + DBG(1, "host disconnect (%s)\n", otg_state_string(musb)); + } +} + + +/*---------------------------------------------------------------------*/ + +int musb_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct musb *musb = hcd_to_musb(hcd); + int retval = 0; + + /* called in_irq() via usb_hcd_poll_rh_status() */ + if (musb->port1_status & 0xffff0000) { + *buf = 0x02; + retval = 1; + } + return retval; +} + +int musb_hub_control( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength) +{ + struct musb *musb = hcd_to_musb(hcd); + u32 temp; + int retval = 0; + unsigned long flags; + + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) + return -ESHUTDOWN; + + /* hub features: always zero, setting is a NOP + * port features: reported, sometimes updated when host is active + * no indicators + */ + spin_lock_irqsave(&musb->lock, flags); + switch (typeReq) { + case ClearHubFeature: + case SetHubFeature: + switch (wValue) { + case C_HUB_OVER_CURRENT: + case C_HUB_LOCAL_POWER: + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (wIndex != 1) + goto error; + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + break; + case USB_PORT_FEAT_SUSPEND: + musb_port_suspend(musb, FALSE); + break; + case USB_PORT_FEAT_POWER: + if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) + musb_set_vbus(musb, 0); + break; + case USB_PORT_FEAT_C_CONNECTION: + case USB_PORT_FEAT_C_ENABLE: + case USB_PORT_FEAT_C_OVER_CURRENT: + case USB_PORT_FEAT_C_RESET: + case USB_PORT_FEAT_C_SUSPEND: + break; + default: + goto error; + } + DBG(5, "clear feature %d\n", wValue); + musb->port1_status &= ~(1 << wValue); + break; + case GetHubDescriptor: + { + struct usb_hub_descriptor *desc = (void *)buf; + + desc->bDescLength = 9; + desc->bDescriptorType = 0x29; + desc->bNbrPorts = 1; + desc->wHubCharacteristics = __constant_cpu_to_le16( + 0x0001 /* per-port power switching */ + | 0x0010 /* no overcurrent reporting */ + ); + desc->bPwrOn2PwrGood = 5; /* msec/2 */ + desc->bHubContrCurrent = 0; + + /* workaround bogus struct definition */ + desc->DeviceRemovable[0] = 0x02; /* port 1 */ + desc->DeviceRemovable[1] = 0xff; + } + break; + case GetHubStatus: + temp = 0; + *(__le32 *) buf = cpu_to_le32 (temp); + break; + case GetPortStatus: + if (wIndex != 1) + goto error; + + /* finish RESET signaling? */ + if ((musb->port1_status & USB_PORT_STAT_RESET) + && time_after(jiffies, musb->rh_timer)) + musb_port_reset(musb, FALSE); + + /* finish RESUME signaling? */ + if ((musb->port1_status & MUSB_PORT_STAT_RESUME) + && time_after(jiffies, musb->rh_timer)) { + u8 power; + + power = musb_readb(musb->mregs, MUSB_POWER); + power &= ~MUSB_POWER_RESUME; + DBG(4, "root port resume stopped, power %02x\n", + power); + musb_writeb(musb->mregs, MUSB_POWER, power); + + /* ISSUE: DaVinci (RTL 1.300) disconnects after + * resume of high speed peripherals (but not full + * speed ones). + */ + + musb->is_active = 1; + musb->port1_status &= ~(USB_PORT_STAT_SUSPEND + | MUSB_PORT_STAT_RESUME); + musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; + usb_hcd_poll_rh_status(musb_to_hcd(musb)); + /* NOTE: it might really be A_WAIT_BCON ... */ + musb->xceiv.state = OTG_STATE_A_HOST; + } + + put_unaligned(cpu_to_le32(musb->port1_status & ~MUSB_PORT_STAT_RESUME), + (__le32 *) buf); + + /* port change status is more interesting */ + DBG(get_unaligned((u16*)(buf+2)) ? 2 : 5, "port status %08x\n", + musb->port1_status); + break; + case SetPortFeature: + if ((wIndex & 0xff) != 1) + goto error; + + switch (wValue) { + case USB_PORT_FEAT_POWER: + /* NOTE: this controller has a strange state machine + * that involves "requesting sessions" according to + * magic side effects from incompletely-described + * rules about startup... + * + * This call is what really starts the host mode; be + * very careful about side effects if you reorder any + * initialization logic, e.g. for OTG, or change any + * logic relating to VBUS power-up. + */ + if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) + musb_start(musb); + break; + case USB_PORT_FEAT_RESET: + musb_port_reset(musb, TRUE); + break; + case USB_PORT_FEAT_SUSPEND: + musb_port_suspend(musb, TRUE); + break; + case USB_PORT_FEAT_TEST: + if (unlikely(is_host_active(musb))) + goto error; + + wIndex >>= 8; + switch (wIndex) { + case 1: + pr_debug("TEST_J\n"); + temp = MUSB_TEST_J; + break; + case 2: + pr_debug("TEST_K\n"); + temp = MUSB_TEST_K; + break; + case 3: + pr_debug("TEST_SE0_NAK\n"); + temp = MUSB_TEST_SE0_NAK; + break; + case 4: + pr_debug("TEST_PACKET\n"); + temp = MUSB_TEST_PACKET; + musb_load_testpacket(musb); + break; + case 5: + pr_debug("TEST_FORCE_ENABLE\n"); + temp = MUSB_TEST_FORCE_HOST + | MUSB_TEST_FORCE_HS; + + musb_writeb(musb->mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); + break; + case 6: + pr_debug("TEST_FIFO_ACCESS\n"); + temp = MUSB_TEST_FIFO_ACCESS; + break; + default: + goto error; + } + musb_writeb(musb->mregs, MUSB_TESTMODE, temp); + break; + default: + goto error; + } + DBG(5, "set feature %d\n", wValue); + musb->port1_status |= 1 << wValue; + break; + + default: +error: + /* "protocol stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore(&musb->lock, flags); + return retval; +} diff --git a/drivers/usb/musb/virthub.c b/drivers/usb/musb/virthub.c deleted file mode 100644 index 9422881..0000000 --- a/drivers/usb/musb/virthub.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * MUSB OTG driver virtual hub support - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/time.h> -#include <linux/timer.h> - -#include <asm/unaligned.h> - -#include "musb_core.h" - - -static void musb_port_suspend(struct musb *musb, u8 bSuspend) -{ - u8 power; - void __iomem *mbase = musb->mregs; - - if (!is_host_active(musb)) - return; - - /* NOTE: this doesn't necessarily put PHY into low power mode, - * turning off its clock; that's a function of PHY integration and - * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect - * SE0 changing to connect (J) or wakeup (K) states. - */ - power = musb_readb(mbase, MUSB_POWER); - if (bSuspend) { - int retries = 10000; - - power &= ~MUSB_POWER_RESUME; - power |= MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, power); - - /* Needed for OPT A tests */ - power = musb_readb(mbase, MUSB_POWER); - while (power & MUSB_POWER_SUSPENDM) { - power = musb_readb(mbase, MUSB_POWER); - if (retries-- < 1) - break; - } - - DBG(3, "Root port suspended, power %02x\n", power); - - musb->port1_status |= USB_PORT_STAT_SUSPEND; - switch (musb->xceiv.state) { - case OTG_STATE_A_HOST: - musb->xceiv.state = OTG_STATE_A_SUSPEND; - musb->is_active = is_otg_enabled(musb) - && musb->xceiv.host->b_hnp_enable; - musb_platform_try_idle(musb, 0); - break; -#ifdef CONFIG_USB_MUSB_OTG - case OTG_STATE_B_HOST: - musb->xceiv.state = OTG_STATE_B_WAIT_ACON; - musb->is_active = is_otg_enabled(musb) - && musb->xceiv.host->b_hnp_enable; - musb_platform_try_idle(musb, 0); - break; -#endif - default: - DBG(1, "bogus rh suspend? %s\n", - otg_state_string(musb)); - } - } else if (power & MUSB_POWER_SUSPENDM) { - power &= ~MUSB_POWER_SUSPENDM; - power |= MUSB_POWER_RESUME; - musb_writeb(mbase, MUSB_POWER, power); - - DBG(3, "Root port resuming, power %02x\n", power); - - /* later, GetPortStatus will stop RESUME signaling */ - musb->port1_status |= MUSB_PORT_STAT_RESUME; - musb->rh_timer = jiffies + msecs_to_jiffies(20); - } -} - -static void musb_port_reset(struct musb *musb, u8 bReset) -{ - u8 power; - void __iomem *mbase = musb->mregs; - -#ifdef CONFIG_USB_MUSB_OTG - if (musb->xceiv.state == OTG_STATE_B_IDLE) { - DBG(2, "HNP: Returning from HNP, not resetting hub as b_idle\n"); - musb->port1_status &= ~USB_PORT_STAT_RESET; - return; - } -#endif - - if (!is_host_active(musb)) - return; - - /* NOTE: caller guarantees it will turn off the reset when - * the appropriate amount of time has passed - */ - power = musb_readb(mbase, MUSB_POWER); - if (bReset) { - - /* - * If RESUME is set, we must make sure it stays minimum 20 ms. - * Then we must clear RESUME and wait a bit to let musb start - * generating SOFs. If we don't do this, OPT HS A 6.8 tests - * fail with "Error! Did not receive an SOF before suspend - * detected". - */ - if (power & MUSB_POWER_RESUME) { - while (time_before(jiffies, musb->rh_timer)) - msleep(1); - musb_writeb(mbase, MUSB_POWER, - power & ~MUSB_POWER_RESUME); - msleep(1); - } - - musb->ignore_disconnect = TRUE; - power &= 0xf0; - musb_writeb(mbase, MUSB_POWER, - power | MUSB_POWER_RESET); - - musb->port1_status |= USB_PORT_STAT_RESET; - musb->port1_status &= ~USB_PORT_STAT_ENABLE; - musb->rh_timer = jiffies + msecs_to_jiffies(50); - } else { - DBG(4, "root port reset stopped\n"); - musb_writeb(mbase, MUSB_POWER, - power & ~MUSB_POWER_RESET); - - musb->ignore_disconnect = FALSE; - - power = musb_readb(mbase, MUSB_POWER); - if (power & MUSB_POWER_HSMODE) { - DBG(4, "high-speed device connected\n"); - musb->port1_status |= USB_PORT_STAT_HIGH_SPEED; - } - - musb->port1_status &= ~USB_PORT_STAT_RESET; - musb->port1_status |= USB_PORT_STAT_ENABLE - | (USB_PORT_STAT_C_RESET << 16) - | (USB_PORT_STAT_C_ENABLE << 16); - usb_hcd_poll_rh_status(musb_to_hcd(musb)); - - musb->vbuserr_retry = VBUSERR_RETRY_COUNT; - } -} - -void musb_root_disconnect(struct musb *musb) -{ - musb->port1_status = (1 << USB_PORT_FEAT_POWER) - | (1 << USB_PORT_FEAT_C_CONNECTION); - - usb_hcd_poll_rh_status(musb_to_hcd(musb)); - musb->is_active = 0; - - switch (musb->xceiv.state) { - case OTG_STATE_A_HOST: - case OTG_STATE_A_SUSPEND: - musb->xceiv.state = OTG_STATE_A_WAIT_BCON; - break; - case OTG_STATE_A_WAIT_VFALL: - musb->xceiv.state = OTG_STATE_B_IDLE; - break; - default: - DBG(1, "host disconnect (%s)\n", otg_state_string(musb)); - } -} - - -/*---------------------------------------------------------------------*/ - -int musb_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct musb *musb = hcd_to_musb(hcd); - int retval = 0; - - /* called in_irq() via usb_hcd_poll_rh_status() */ - if (musb->port1_status & 0xffff0000) { - *buf = 0x02; - retval = 1; - } - return retval; -} - -int musb_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength) -{ - struct musb *musb = hcd_to_musb(hcd); - u32 temp; - int retval = 0; - unsigned long flags; - - if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) - return -ESHUTDOWN; - - /* hub features: always zero, setting is a NOP - * port features: reported, sometimes updated when host is active - * no indicators - */ - spin_lock_irqsave(&musb->lock, flags); - switch (typeReq) { - case ClearHubFeature: - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case ClearPortFeature: - if (wIndex != 1) - goto error; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - break; - case USB_PORT_FEAT_SUSPEND: - musb_port_suspend(musb, FALSE); - break; - case USB_PORT_FEAT_POWER: - if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) - musb_set_vbus(musb, 0); - break; - case USB_PORT_FEAT_C_CONNECTION: - case USB_PORT_FEAT_C_ENABLE: - case USB_PORT_FEAT_C_OVER_CURRENT: - case USB_PORT_FEAT_C_RESET: - case USB_PORT_FEAT_C_SUSPEND: - break; - default: - goto error; - } - DBG(5, "clear feature %d\n", wValue); - musb->port1_status &= ~(1 << wValue); - break; - case GetHubDescriptor: - { - struct usb_hub_descriptor *desc = (void *)buf; - - desc->bDescLength = 9; - desc->bDescriptorType = 0x29; - desc->bNbrPorts = 1; - desc->wHubCharacteristics = __constant_cpu_to_le16( - 0x0001 /* per-port power switching */ - | 0x0010 /* no overcurrent reporting */ - ); - desc->bPwrOn2PwrGood = 5; /* msec/2 */ - desc->bHubContrCurrent = 0; - - /* workaround bogus struct definition */ - desc->DeviceRemovable[0] = 0x02; /* port 1 */ - desc->DeviceRemovable[1] = 0xff; - } - break; - case GetHubStatus: - temp = 0; - *(__le32 *) buf = cpu_to_le32 (temp); - break; - case GetPortStatus: - if (wIndex != 1) - goto error; - - /* finish RESET signaling? */ - if ((musb->port1_status & USB_PORT_STAT_RESET) - && time_after(jiffies, musb->rh_timer)) - musb_port_reset(musb, FALSE); - - /* finish RESUME signaling? */ - if ((musb->port1_status & MUSB_PORT_STAT_RESUME) - && time_after(jiffies, musb->rh_timer)) { - u8 power; - - power = musb_readb(musb->mregs, MUSB_POWER); - power &= ~MUSB_POWER_RESUME; - DBG(4, "root port resume stopped, power %02x\n", - power); - musb_writeb(musb->mregs, MUSB_POWER, power); - - /* ISSUE: DaVinci (RTL 1.300) disconnects after - * resume of high speed peripherals (but not full - * speed ones). - */ - - musb->is_active = 1; - musb->port1_status &= ~(USB_PORT_STAT_SUSPEND - | MUSB_PORT_STAT_RESUME); - musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; - usb_hcd_poll_rh_status(musb_to_hcd(musb)); - /* NOTE: it might really be A_WAIT_BCON ... */ - musb->xceiv.state = OTG_STATE_A_HOST; - } - - put_unaligned(cpu_to_le32(musb->port1_status & ~MUSB_PORT_STAT_RESUME), - (__le32 *) buf); - - /* port change status is more interesting */ - DBG(get_unaligned((u16*)(buf+2)) ? 2 : 5, "port status %08x\n", - musb->port1_status); - break; - case SetPortFeature: - if ((wIndex & 0xff) != 1) - goto error; - - switch (wValue) { - case USB_PORT_FEAT_POWER: - /* NOTE: this controller has a strange state machine - * that involves "requesting sessions" according to - * magic side effects from incompletely-described - * rules about startup... - * - * This call is what really starts the host mode; be - * very careful about side effects if you reorder any - * initialization logic, e.g. for OTG, or change any - * logic relating to VBUS power-up. - */ - if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) - musb_start(musb); - break; - case USB_PORT_FEAT_RESET: - musb_port_reset(musb, TRUE); - break; - case USB_PORT_FEAT_SUSPEND: - musb_port_suspend(musb, TRUE); - break; - case USB_PORT_FEAT_TEST: - if (unlikely(is_host_active(musb))) - goto error; - - wIndex >>= 8; - switch (wIndex) { - case 1: - pr_debug("TEST_J\n"); - temp = MUSB_TEST_J; - break; - case 2: - pr_debug("TEST_K\n"); - temp = MUSB_TEST_K; - break; - case 3: - pr_debug("TEST_SE0_NAK\n"); - temp = MUSB_TEST_SE0_NAK; - break; - case 4: - pr_debug("TEST_PACKET\n"); - temp = MUSB_TEST_PACKET; - musb_load_testpacket(musb); - break; - case 5: - pr_debug("TEST_FORCE_ENABLE\n"); - temp = MUSB_TEST_FORCE_HOST - | MUSB_TEST_FORCE_HS; - - musb_writeb(musb->mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - break; - case 6: - pr_debug("TEST_FIFO_ACCESS\n"); - temp = MUSB_TEST_FIFO_ACCESS; - break; - default: - goto error; - } - musb_writeb(musb->mregs, MUSB_TESTMODE, temp); - break; - default: - goto error; - } - DBG(5, "set feature %d\n", wValue); - musb->port1_status |= 1 << wValue; - break; - - default: -error: - /* "protocol stall" on error */ - retval = -EPIPE; - } - spin_unlock_irqrestore(&musb->lock, flags); - return retval; -} -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 9/9] musb_hdrc: Rename debug.h to musb_debug.h 2007-08-20 9:10 ` [PATCH 8/9] musb_hdrc: Rename virthub.c musb_host_virthub.c Tony Lindgren @ 2007-08-20 9:10 ` Tony Lindgren 0 siblings, 0 replies; 11+ messages in thread From: Tony Lindgren @ 2007-08-20 9:10 UTC (permalink / raw) To: linux-omap-open-source Rename debug.h to musb_debug.h Signed-off-by: Tony Lindgren <tony@atomide.com> --- drivers/usb/musb/debug.h | 66 ----------------------------------------- drivers/usb/musb/musb_core.h | 2 +- drivers/usb/musb/musb_debug.h | 66 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 67 deletions(-) delete mode 100644 drivers/usb/musb/debug.h create mode 100644 drivers/usb/musb/musb_debug.h diff --git a/drivers/usb/musb/debug.h b/drivers/usb/musb/debug.h deleted file mode 100644 index 5eff56e..0000000 --- a/drivers/usb/musb/debug.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * MUSB OTG driver debug defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. - * - */ - -#ifndef __MUSB_LINUX_DEBUG_H__ -#define __MUSB_LINUX_DEBUG_H__ - -#define yprintk(facility, format, args...) \ - do { printk(facility "%s %d: " format , \ - __FUNCTION__, __LINE__ , ## args); } while (0) -#define WARN(fmt, args...) yprintk(KERN_WARNING,fmt, ## args) -#define INFO(fmt,args...) yprintk(KERN_INFO,fmt, ## args) -#define ERR(fmt,args...) yprintk(KERN_ERR,fmt, ## args) - -#define xprintk(level, facility, format, args...) do { \ - if ( _dbg_level(level) ) { \ - printk(facility "%s %d: " format , \ - __FUNCTION__, __LINE__ , ## args); \ - } } while (0) - -#if MUSB_DEBUG > 0 -extern unsigned debug; -#else -#define debug 0 -#endif - -static inline int _dbg_level(unsigned l) -{ - return debug >= l; -} - -#define DBG(level,fmt,args...) xprintk(level,KERN_DEBUG,fmt, ## args) - -extern const char *otg_state_string(struct musb *); - -#endif // __MUSB_LINUX_DEBUG_H__ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 56f8fbb..29239a0 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -53,7 +53,7 @@ struct musb_hw_ep; struct musb_ep; -#include "debug.h" +#include "musb_debug.h" #include "musb_dma.h" #ifdef CONFIG_USB_MUSB_SOC diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h new file mode 100644 index 0000000..5eff56e --- /dev/null +++ b/drivers/usb/musb/musb_debug.h @@ -0,0 +1,66 @@ +/* + * MUSB OTG driver debug defines + * + * Copyright 2005 Mentor Graphics Corporation + * Copyright (C) 2005-2006 by Texas Instruments + * Copyright (C) 2006-2007 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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. + * + */ + +#ifndef __MUSB_LINUX_DEBUG_H__ +#define __MUSB_LINUX_DEBUG_H__ + +#define yprintk(facility, format, args...) \ + do { printk(facility "%s %d: " format , \ + __FUNCTION__, __LINE__ , ## args); } while (0) +#define WARN(fmt, args...) yprintk(KERN_WARNING,fmt, ## args) +#define INFO(fmt,args...) yprintk(KERN_INFO,fmt, ## args) +#define ERR(fmt,args...) yprintk(KERN_ERR,fmt, ## args) + +#define xprintk(level, facility, format, args...) do { \ + if ( _dbg_level(level) ) { \ + printk(facility "%s %d: " format , \ + __FUNCTION__, __LINE__ , ## args); \ + } } while (0) + +#if MUSB_DEBUG > 0 +extern unsigned debug; +#else +#define debug 0 +#endif + +static inline int _dbg_level(unsigned l) +{ + return debug >= l; +} + +#define DBG(level,fmt,args...) xprintk(level,KERN_DEBUG,fmt, ## args) + +extern const char *otg_state_string(struct musb *); + +#endif // __MUSB_LINUX_DEBUG_H__ -- 1.5.2.3 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 0/9] musb_hdrc: Unify naming and rename common files 2007-08-20 9:10 [PATCH 0/9] musb_hdrc: Unify naming and rename common files Tony Lindgren 2007-08-20 9:10 ` [PATCH 1/9] musb_hdrc: Search and replace USB_INVENTRA_FIFO with USB_MUSB_DISABLE_DMA Tony Lindgren @ 2007-08-21 7:23 ` Tony Lindgren 1 sibling, 0 replies; 11+ messages in thread From: Tony Lindgren @ 2007-08-21 7:23 UTC (permalink / raw) To: linux-omap-open-source * Tony Lindgren <tony@atomide.com> [070820 06:38]: > Hi all, > > Attached patch series replaces Inventra naming with > musb, and renames the core musb files to start with > musb_. > > Renaming the files unifies the file names, and groups > them by type. This all should make it easier for people > to locate the right piece of code within the driver. > > After applying the patch series, the musb directory > has following files: > > $ ls > cppi_dma.c musb_core.c musb_host.c omap2430.h > cppi_dma.h musb_core.h musb_host.h tusb6010.c > davinci.c musb_debug.h musb_host_virthub.c tusb6010.h > davinci.h musb_dma.h musbhsdma.c tusb6010_omap.c > Kconfig musb_gadget.c musb_procfs.c > Makefile musb_gadget_ep0.c musb_regs.h > musb_arch.h musb_gadget.h omap2430.c > > Tested on tusb. Pushing this series today refreshed based on following comments from David Brownell: - 1/9: Use MUSB_PIO_ONLY instead of USB_MUSB_DISABLE_DMA, fix Makefile comment - 3/9: Use musb_io.h instead of musb_arch.h - 8/9: Use musb_virthub.c instead of musb_host_virthub.c Regards, Tony ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2007-08-21 7:23 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-08-20 9:10 [PATCH 0/9] musb_hdrc: Unify naming and rename common files Tony Lindgren 2007-08-20 9:10 ` [PATCH 1/9] musb_hdrc: Search and replace USB_INVENTRA_FIFO with USB_MUSB_DISABLE_DMA Tony Lindgren 2007-08-20 9:10 ` [PATCH 2/9] musb_hdrc: Search and replace USB_INVENTRA_HCD_LOGGING with USB_MUSB_LOGLEVEL Tony Lindgren 2007-08-20 9:10 ` [PATCH 3/9] musb_hdrc: Rename plat_uds.c to musb_core.c, plat_arc.h to musb_arch.h Tony Lindgren 2007-08-20 9:10 ` [PATCH 4/9] musb_hdrc: Rename musbhdrc.h to musb_regs.h Tony Lindgren 2007-08-20 9:10 ` [PATCH 5/9] musb_hdrc: Rename musbdefs.h to musb_core.h Tony Lindgren 2007-08-20 9:10 ` [PATCH 6/9] musb_hdrc: Rename dma.h to musb_dma.h Tony Lindgren 2007-08-20 9:10 ` [PATCH 7/9] musb_hdrc: Rename g_ep0.c musb_gadget_ep0.c Tony Lindgren 2007-08-20 9:10 ` [PATCH 8/9] musb_hdrc: Rename virthub.c musb_host_virthub.c Tony Lindgren 2007-08-20 9:10 ` [PATCH 9/9] musb_hdrc: Rename debug.h to musb_debug.h Tony Lindgren 2007-08-21 7:23 ` [PATCH 0/9] musb_hdrc: Unify naming and rename common files Tony Lindgren
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox