diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-07 15:37:24 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-07 15:37:24 -0800 |
commit | 7c7758f99d39d529a64d4f60d22129bbf2f16d74 (patch) | |
tree | 8847b5e56812fe4c4c812cfffc78e391a91f4ebe /drivers/usb/musb | |
parent | 67acd8b4b7a3f1b183ae358e1dfdb8a80e170736 (diff) | |
parent | 8a70da82edc50aa7a4b54864babf2d72538ba1bb (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (123 commits)
wimax/i2400m: add CREDITS and MAINTAINERS entries
wimax: export linux/wimax.h and linux/wimax/i2400m.h with headers_install
i2400m: Makefile and Kconfig
i2400m/SDIO: TX and RX path backends
i2400m/SDIO: firmware upload backend
i2400m/SDIO: probe/disconnect, dev init/shutdown and reset backends
i2400m/SDIO: header for the SDIO subdriver
i2400m/USB: TX and RX path backends
i2400m/USB: firmware upload backend
i2400m/USB: probe/disconnect, dev init/shutdown and reset backends
i2400m/USB: header for the USB bus driver
i2400m: debugfs controls
i2400m: various functions for device management
i2400m: RX and TX data/control paths
i2400m: firmware loading and bootrom initialization
i2400m: linkage to the networking stack
i2400m: Generic probe/disconnect, reset and message passing
i2400m: host/device procotol and core driver definitions
i2400m: documentation and instructions for usage
wimax: Makefile, Kconfig and docbook linkage for the stack
...
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/Kconfig | 12 | ||||
-rw-r--r-- | drivers/usb/musb/Makefile | 8 | ||||
-rw-r--r-- | drivers/usb/musb/blackfin.c | 320 | ||||
-rw-r--r-- | drivers/usb/musb/blackfin.h | 52 | ||||
-rw-r--r-- | drivers/usb/musb/davinci.c | 18 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 84 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 73 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 2 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.c | 45 | ||||
-rw-r--r-- | drivers/usb/musb/musb_io.h | 26 | ||||
-rw-r--r-- | drivers/usb/musb/musb_regs.h | 397 | ||||
-rw-r--r-- | drivers/usb/musb/musbhsdma.c | 84 | ||||
-rw-r--r-- | drivers/usb/musb/musbhsdma.h | 149 | ||||
-rw-r--r-- | drivers/usb/musb/omap2430.c | 15 | ||||
-rw-r--r-- | drivers/usb/musb/tusb6010.c | 7 |
15 files changed, 1043 insertions, 249 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 4b9542bbb35..5af7379cd9a 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -11,7 +11,7 @@ config USB_MUSB_HDRC depends on (USB || USB_GADGET) && HAVE_CLK depends on !SUPERH select TWL4030_USB if MACH_OMAP_3430SDP - tristate 'Inventra Highspeed Dual Role Controller (TI, ...)' + tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' help Say Y here if your system has a dual role high speed USB controller based on the Mentor Graphics silicon IP. Then @@ -22,6 +22,9 @@ config USB_MUSB_HDRC Texas Instruments parts using this IP include DaVinci 644x, OMAP 243x, OMAP 343x, and TUSB 6010. + Analog Devices parts using this IP include Blackfin BF54x, + BF525 and BF527. + If you do not know what this is, please say N. To compile this driver as a module, choose M here; the @@ -33,6 +36,8 @@ config USB_MUSB_SOC default y if ARCH_DAVINCI default y if ARCH_OMAP2430 default y if ARCH_OMAP34XX + default y if (BF54x && !BF544) + default y if (BF52x && !BF522 && !BF523) comment "DaVinci 644x USB support" depends on USB_MUSB_HDRC && ARCH_DAVINCI @@ -43,6 +48,9 @@ comment "OMAP 243x high speed USB support" comment "OMAP 343x high speed USB support" depends on USB_MUSB_HDRC && ARCH_OMAP34XX +comment "Blackfin high speed USB Support" + depends on USB_MUSB_HDRC && (BF54x && !BF544) || (BF52x && !BF522 && !BF523) + config USB_TUSB6010 boolean "TUSB 6010 support" depends on USB_MUSB_HDRC && !USB_MUSB_SOC @@ -142,7 +150,7 @@ config MUSB_PIO_ONLY config USB_INVENTRA_DMA bool depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY - default ARCH_OMAP2430 || ARCH_OMAP34XX + default ARCH_OMAP2430 || ARCH_OMAP34XX || BLACKFIN help Enable DMA transfers using Mentor's engine. diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index b6af0d687a7..85710ccc188 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -22,6 +22,14 @@ ifeq ($(CONFIG_ARCH_OMAP3430),y) musb_hdrc-objs += omap2430.o endif +ifeq ($(CONFIG_BF54x),y) + musb_hdrc-objs += blackfin.o +endif + +ifeq ($(CONFIG_BF52x),y) + musb_hdrc-objs += blackfin.o +endif + ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y) musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o endif diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c new file mode 100644 index 00000000000..78613485209 --- /dev/null +++ b/drivers/usb/musb/blackfin.c @@ -0,0 +1,320 @@ +/* + * MUSB OTG controller driver for Blackfin Processors + * + * Copyright 2006-2008 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#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/clk.h> +#include <linux/gpio.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> + +#include "musb_core.h" +#include "blackfin.h" + +/* + * 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; + void __iomem *epio = hw_ep->regs; + + prefetch((u8 *)src); + + musb_writew(epio, MUSB_TXCOUNT, len); + + DBG(4, "TX ep%d fifo %p count %d buf %p, epio %p\n", + hw_ep->epnum, fifo, len, src, epio); + + dump_fifo_data(src, len); + + if (unlikely((unsigned long)src & 0x01)) + outsw_8((unsigned long)fifo, src, + len & 0x01 ? (len >> 1) + 1 : len >> 1); + else + outsw((unsigned long)fifo, src, + len & 0x01 ? (len >> 1) + 1 : len >> 1); +} + +/* + * 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; + u8 epnum = hw_ep->epnum; + u16 dma_reg = 0; + + DBG(4, "%cX ep%d fifo %p count %d buf %p\n", + 'R', hw_ep->epnum, fifo, len, dst); + +#ifdef CONFIG_BF52x + invalidate_dcache_range((unsigned int)dst, + (unsigned int)(dst + len)); + + /* Setup DMA address register */ + dma_reg = (u16) ((u32) dst & 0xFFFF); + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg); + SSYNC(); + + dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF); + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg); + SSYNC(); + + /* Setup DMA count register */ + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len); + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0); + SSYNC(); + + /* Enable the DMA */ + dma_reg = (epnum << 4) | DMA_ENA | INT_ENA; + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg); + SSYNC(); + + /* Wait for compelete */ + while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum))) + cpu_relax(); + + /* acknowledge dma interrupt */ + bfin_write_USB_DMA_INTERRUPT(1 << epnum); + SSYNC(); + + /* Reset DMA */ + bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0); + SSYNC(); +#else + if (unlikely((unsigned long)dst & 0x01)) + insw_8((unsigned long)fifo, dst, + len & 0x01 ? (len >> 1) + 1 : len >> 1); + else + insw((unsigned long)fifo, dst, + len & 0x01 ? (len >> 1) + 1 : len >> 1); +#endif + + dump_fifo_data(dst, len); +} + +static irqreturn_t blackfin_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) { + musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); + musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); + musb_writew(musb->mregs, MUSB_INTRRX, 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... fall in BF54x too. + */ + if (retval != IRQ_HANDLED) + DBG(5, "spurious?\n"); + + return IRQ_HANDLED; +} + +static void musb_conn_timer_handler(unsigned long _musb) +{ + struct musb *musb = (void *)_musb; + unsigned long flags; + u16 val; + + spin_lock_irqsave(&musb->lock, flags); + switch (musb->xceiv.state) { + case OTG_STATE_A_IDLE: + case OTG_STATE_A_WAIT_BCON: + /* Start a new session */ + val = musb_readw(musb->mregs, MUSB_DEVCTL); + val |= MUSB_DEVCTL_SESSION; + musb_writew(musb->mregs, MUSB_DEVCTL, val); + + val = musb_readw(musb->mregs, MUSB_DEVCTL); + if (!(val & MUSB_DEVCTL_BDEVICE)) { + gpio_set_value(musb->config->gpio_vrsel, 1); + musb->xceiv.state = OTG_STATE_A_WAIT_BCON; + } else { + gpio_set_value(musb->config->gpio_vrsel, 0); + + /* Ignore VBUSERROR and SUSPEND IRQ */ + val = musb_readb(musb->mregs, MUSB_INTRUSBE); + val &= ~MUSB_INTR_VBUSERROR; + musb_writeb(musb->mregs, MUSB_INTRUSBE, val); + + val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; + musb_writeb(musb->mregs, MUSB_INTRUSB, val); + + val = MUSB_POWER_HSENAB; + musb_writeb(musb->mregs, MUSB_POWER, val); + } + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); + break; + + default: + DBG(1, "%s state not handled\n", otg_state_string(musb)); + break; + } + spin_unlock_irqrestore(&musb->lock, flags); + + DBG(4, "state is %s\n", otg_state_string(musb)); +} + +void musb_platform_enable(struct musb *musb) +{ + if (is_host_enabled(musb)) { + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); + musb->a_wait_bcon = TIMER_DELAY; + } +} + +void musb_platform_disable(struct musb *musb) +{ +} + +static void bfin_vbus_power(struct musb *musb, int is_on, int sleeping) +{ +} + +static void bfin_set_vbus(struct musb *musb, int is_on) +{ + if (is_on) + gpio_set_value(musb->config->gpio_vrsel, 1); + else + gpio_set_value(musb->config->gpio_vrsel, 0); + + DBG(1, "VBUS %s, devctl %02x " + /* otg %3x conf %08x prcm %08x */ "\n", + otg_state_string(musb), + musb_readb(musb->mregs, MUSB_DEVCTL)); +} + +static int bfin_set_power(struct otg_transceiver *x, unsigned mA) +{ + return 0; +} + +void musb_platform_try_idle(struct musb *musb, unsigned long timeout) +{ + if (is_host_enabled(musb)) + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); +} + +int musb_platform_get_vbus_status(struct musb *musb) +{ + return 0; +} + +void musb_platform_set_mode(struct musb *musb, u8 musb_mode) +{ +} + +int __init musb_platform_init(struct musb *musb) +{ + + /* + * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE + * and OTG HOST modes, while rev 1.1 and greater require PE7 to + * be low for DEVICE mode and high for HOST mode. We set it high + * here because we are in host mode + */ + + if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) { + printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n", + musb->config->gpio_vrsel); + return -ENODEV; + } + gpio_direction_output(musb->config->gpio_vrsel, 0); + + if (ANOMALY_05000346) { + bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); + SSYNC(); + } + + if (ANOMALY_05000347) { + bfin_write_USB_APHY_CNTRL(0x0); + SSYNC(); + } + + /* TODO + * Set SIC-IVG register + */ + + /* Configure PLL oscillator register */ + bfin_write_USB_PLLOSC_CTRL(0x30a8); + SSYNC(); + + bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1); + SSYNC(); + + bfin_write_USB_EP_NI0_RXMAXP(64); + SSYNC(); + + bfin_write_USB_EP_NI0_TXMAXP(64); + SSYNC(); + + /* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/ + bfin_write_USB_GLOBINTR(0x7); + SSYNC(); + + bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA | + EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA | + EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA | + EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA | + EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA); + SSYNC(); + + if (is_host_enabled(musb)) { + musb->board_set_vbus = bfin_set_vbus; + setup_timer(&musb_conn_timer, + musb_conn_timer_handler, (unsigned long) musb); + } + if (is_peripheral_enabled(musb)) + musb->xceiv.set_power = bfin_set_power; + + musb->isr = blackfin_interrupt; + + return 0; +} + +int musb_platform_suspend(struct musb *musb) +{ + return 0; +} + +int musb_platform_resume(struct musb *musb) +{ + return 0; +} + + +int musb_platform_exit(struct musb *musb) +{ + + bfin_vbus_power(musb, 0 /*off*/, 1); + gpio_free(musb->config->gpio_vrsel); + musb_platform_suspend(musb); + + return 0; +} diff --git a/drivers/usb/musb/blackfin.h b/drivers/usb/musb/blackfin.h new file mode 100644 index 00000000000..a240c1e53d1 --- /dev/null +++ b/drivers/usb/musb/blackfin.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 by Analog Devices, Inc. + * + * The Inventra Controller Driver for Linux 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. + */ + +#ifndef __MUSB_BLACKFIN_H__ +#define __MUSB_BLACKFIN_H__ + +/* + * Blackfin specific definitions + */ + +#undef DUMP_FIFO_DATA +#ifdef DUMP_FIFO_DATA +static void dump_fifo_data(u8 *buf, u16 len) +{ + u8 *tmp = buf; + int i; + + for (i = 0; i < len; i++) { + if (!(i % 16) && i) + pr_debug("\n"); + pr_debug("%02x ", *tmp++); + } + pr_debug("\n"); +} +#else +#define dump_fifo_data(buf, len) do {} while (0) +#endif + +#ifdef CONFIG_BF52x + +#define USB_DMA_BASE USB_DMA_INTERRUPT +#define USB_DMAx_CTRL 0x04 +#define USB_DMAx_ADDR_LOW 0x08 +#define USB_DMAx_ADDR_HIGH 0x0C +#define USB_DMAx_COUNT_LOW 0x10 +#define USB_DMAx_COUNT_HIGH 0x14 + +#define USB_DMA_REG(ep, reg) (USB_DMA_BASE + 0x20 * ep + reg) +#endif + +/* Almost 1 second */ +#define TIMER_DELAY (1 * HZ) + +static struct timer_list musb_conn_timer; + +#endif /* __MUSB_BLACKFIN_H__ */ diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index dfb3bcbe00f..0d566dc5ce0 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -32,9 +32,9 @@ #include <linux/io.h> #include <linux/gpio.h> -#include <asm/arch/hardware.h> -#include <asm/arch/memory.h> -#include <asm/arch/gpio.h> +#include <mach/arch/hardware.h> +#include <mach/arch/memory.h> +#include <mach/arch/gpio.h> #include <asm/mach-types.h> #include "musb_core.h" @@ -364,6 +364,18 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) return IRQ_HANDLED; } +int musb_platform_set_mode(struct musb *musb, u8 mode) +{ + /* EVM can't do this (right?) */ + return -EIO; +} + +int musb_platform_set_mode(struct musb *musb, u8 mode) +{ + /* EVM can't do this (right?) */ + return -EIO; +} + int __init musb_platform_init(struct musb *musb) { void __iomem *tibase = musb->ctrl_base; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 5280dba9b1f..6c7faacfb53 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -148,7 +148,8 @@ static inline struct musb *dev_to_musb(struct device *dev) /*-------------------------------------------------------------------------*/ -#ifndef CONFIG_USB_TUSB6010 +#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN) + /* * Load an endpoint's FIFO */ @@ -1124,25 +1125,25 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, #endif switch (cfg->style) { case FIFO_TX: - musb_writeb(mbase, MUSB_TXFIFOSZ, c_size); - musb_writew(mbase, MUSB_TXFIFOADD, c_off); + musb_write_txfifosz(mbase, c_size); + musb_write_txfifoadd(mbase, 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); + musb_write_rxfifosz(mbase, c_size); + musb_write_rxfifoadd(mbase, 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); + musb_write_txfifosz(mbase, c_size); + musb_write_txfifoadd(mbase, 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); + musb_write_rxfifosz(mbase, c_size); + musb_write_rxfifoadd(mbase, c_off); hw_ep->tx_double_buffered = hw_ep->rx_double_buffered; hw_ep->max_packet_sz_tx = maxpacket; @@ -1212,7 +1213,7 @@ static int __init ep_config_from_table(struct musb *musb) if (epn >= musb->config->num_eps) { pr_debug("%s: invalid ep %d\n", musb_driver_name, epn); - continue; + return -EINVAL; } offset = fifo_setup(musb, hw_ep + epn, cfg++, offset); if (offset < 0) { @@ -1246,9 +1247,10 @@ static int __init ep_config_from_table(struct musb *musb) */ static int __init ep_config_from_hw(struct musb *musb) { - u8 epnum = 0, reg; + u8 epnum = 0; struct musb_hw_ep *hw_ep; void *mbase = musb->mregs; + int ret = 0; DBG(2, "<== static silicon ep config\n"); @@ -1258,26 +1260,9 @@ static int __init ep_config_from_hw(struct musb *musb) 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 */ + ret = musb_read_fifosize(musb, hw_ep, epnum); + if (ret < 0) 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 */ @@ -1326,7 +1311,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) /* log core options (read using indexed model) */ musb_ep_select(mbase, 0); - reg = musb_readb(mbase, 0x10 + MUSB_CONFIGDATA); + reg = musb_read_configdata(mbase); strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8"); if (reg & MUSB_CONFIGDATA_DYNFIFO) @@ -1391,7 +1376,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) } /* log release info */ - hwvers = musb_readw(mbase, MUSB_HWVERS); + hwvers = musb_read_hwvers(mbase); rev_major = (hwvers >> 10) & 0x1f; rev_minor = hwvers & 0x3ff; snprintf(aRevision, 32, "%d.%d%s", rev_major, @@ -1400,8 +1385,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) 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; + musb_configure_ep0(musb); /* discover endpoint configuration */ musb->nr_endpoints = 1; @@ -1445,7 +1429,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) 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->target_regs = musb_read_target_reg_base(i, mbase); hw_ep->rx_reinit = 1; hw_ep->tx_reinit = 1; #endif @@ -1671,17 +1655,20 @@ musb_mode_store(struct device *dev, struct device_attribute *attr, { struct musb *musb = dev_to_musb(dev); unsigned long flags; + int status; 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); + if (sysfs_streq(buf, "host")) + status = musb_platform_set_mode(musb, MUSB_HOST); + else if (sysfs_streq(buf, "peripheral")) + status = musb_platform_set_mode(musb, MUSB_PERIPHERAL); + else if (sysfs_streq(buf, "otg")) + status = musb_platform_set_mode(musb, MUSB_OTG); + else + status = -EINVAL; spin_unlock_irqrestore(&musb->lock, flags); - return n; + return (status == 0) ? n : status; } static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store); @@ -1781,7 +1768,7 @@ allocate_instance(struct device *dev, #ifdef CONFIG_USB_MUSB_HDRC_HCD struct usb_hcd *hcd; - hcd = usb_create_hcd(&musb_hc_driver, dev, dev->bus_id); + hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev)); if (!hcd) return NULL; /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ @@ -1810,7 +1797,6 @@ allocate_instance(struct device *dev, for (epnum = 0, ep = musb->endpoints; epnum < musb->config->num_eps; epnum++, ep++) { - ep->musb = musb; ep->epnum = epnum; } @@ -1838,7 +1824,7 @@ static void musb_free(struct musb *musb) musb_gadget_cleanup(musb); #endif - if (musb->nIrq >= 0) { + if (musb->nIrq >= 0 && musb->irq_wake) { disable_irq_wake(musb->nIrq); free_irq(musb->nIrq, musb); } @@ -1984,15 +1970,19 @@ bad_config: INIT_WORK(&musb->irq_work, musb_irq_work); /* attach to the IRQ */ - if (request_irq(nIrq, musb->isr, 0, dev->bus_id, musb)) { + if (request_irq(nIrq, musb->isr, 0, dev_name(dev), 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) + if (enable_irq_wake(nIrq) == 0) { + musb->irq_wake = 1; device_init_wakeup(dev, 1); + } else { + musb->irq_wake = 0; + } pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n", musb_driver_name, diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 82227251931..630946a2d9f 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -191,7 +191,7 @@ enum musb_g_ep0_state { */ #if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \ - || defined(CONFIG_ARCH_OMAP3430) + || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN) /* REVISIT indexed access seemed to * misbehave (on DaVinci) for at least peripheral IN ... */ @@ -359,6 +359,7 @@ struct musb { struct otg_transceiver xceiv; int nIrq; + unsigned irq_wake:1; struct musb_hw_ep endpoints[MUSB_C_NUM_EPS]; #define control_ep endpoints @@ -447,6 +448,70 @@ static inline struct musb *gadget_to_musb(struct usb_gadget *g) } #endif +#ifdef CONFIG_BLACKFIN +static inline int musb_read_fifosize(struct musb *musb, + struct musb_hw_ep *hw_ep, u8 epnum) +{ + musb->nr_endpoints++; + musb->epmask |= (1 << epnum); + + if (epnum < 5) { + hw_ep->max_packet_sz_tx = 128; + hw_ep->max_packet_sz_rx = 128; + } else { + hw_ep->max_packet_sz_tx = 1024; + hw_ep->max_packet_sz_rx = 1024; + } + hw_ep->is_shared_fifo = false; + + return 0; +} + +static inline void musb_configure_ep0(struct musb *musb) +{ + musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE; + musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE; + musb->endpoints[0].is_shared_fifo = true; +} + +#else + +static inline int musb_read_fifosize(struct musb *musb, + struct musb_hw_ep *hw_ep, u8 epnum) +{ + u8 reg = 0; + + /* read from core using indexed model */ + reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE); + /* 0's returned when no more endpoints */ + if (!reg) + return -ENODEV; + + 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; + return 0; + } else { + hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4); + hw_ep->is_shared_fifo = false; + } + + return 0; +} + +static inline void musb_configure_ep0(struct musb *musb) +{ + musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE; + musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE; +} +#endif /* CONFIG_BLACKFIN */ + /***************************** Glue it together *****************************/ @@ -467,16 +532,16 @@ extern void musb_platform_disable(struct musb *musb); extern void musb_hnp_stop(struct musb *musb); -extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode); +extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode); -#if defined(CONFIG_USB_TUSB6010) || \ +#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \ defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout); #else #define musb_platform_try_idle(x, y) do {} while (0) #endif -#ifdef CONFIG_USB_TUSB6010 +#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) extern int musb_platform_get_vbus_status(struct musb *musb); #else #define musb_platform_get_vbus_status(x) 0 diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index d6a802c224f..6197daeab8f 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1633,7 +1633,7 @@ int __init musb_gadget_setup(struct musb *musb) musb->g.speed = USB_SPEED_UNKNOWN; /* this "gadget" abstracts/virtualizes the controller */ - strcpy(musb->g.dev.bus_id, "gadget"); + dev_set_name(&musb->g.dev, "gadget"); musb->g.dev.parent = musb->controller; musb->g.dev.dma_mask = musb->controller->dma_mask; musb->g.dev.release = musb_gadget_release; diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index cc64462d4c4..99fa6123487 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -112,18 +112,21 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) { void __iomem *epio = ep->regs; u16 csr; + u16 lastcsr = 0; int retries = 1000; csr = musb_readw(epio, MUSB_TXCSR); while (csr & MUSB_TXCSR_FIFONOTEMPTY) { - DBG(5, "Host TX FIFONOTEMPTY csr: %02x\n", csr); + if (csr != lastcsr) + DBG(3, "Host TX FIFONOTEMPTY csr: %02x\n", csr); + lastcsr = csr; csr |= MUSB_TXCSR_FLUSHFIFO; musb_writew(epio, MUSB_TXCSR, csr); csr = musb_readw(epio, MUSB_TXCSR); - if (retries-- < 1) { - ERR("Could not flush host TX fifo: csr: %04x\n", csr); + if (WARN(retries-- < 1, + "Could not flush host TX%d fifo: csr: %04x\n", + ep->epnum, csr)) return; - } mdelay(1); } } @@ -268,7 +271,7 @@ __musb_giveback(struct musb *musb, struct urb *urb, int status) __releases(musb->lock) __acquires(musb->lock) { - DBG(({ int level; switch (urb->status) { + DBG(({ int level; switch (status) { case 0: level = 4; break; @@ -283,8 +286,8 @@ __acquires(musb->lock) level = 2; break; }; level; }), - "complete %p (%d), dev%d ep%d%s, %d/%d\n", - urb, urb->status, + "complete %p %pF (%d), dev%d ep%d%s, %d/%d\n", + urb, urb->complete, status, usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe), usb_pipein(urb->pipe) ? "in" : "out", @@ -593,12 +596,10 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) /* target addr and (for multipoint) hub addr/port */ if (musb->is_multipoint) { - musb_writeb(ep->target_regs, MUSB_RXFUNCADDR, - qh->addr_reg); - musb_writeb(ep->target_regs, MUSB_RXHUBADDR, - qh->h_addr_reg); - musb_writeb(ep->target_regs, MUSB_RXHUBPORT, - qh->h_port_reg); + musb_write_rxfunaddr(ep->target_regs, qh->addr_reg); + musb_write_rxhubaddr(ep->target_regs, qh->h_addr_reg); + musb_write_rxhubport(ep->target_regs, qh->h_port_reg); + } else musb_writeb(musb->mregs, MUSB_FADDR, qh->addr_reg); @@ -712,15 +713,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum, /* target addr and (for multipoint) hub addr/port */ if (musb->is_multipoint) { - musb_writeb(mbase, - MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR), - qh->addr_reg); - musb_writeb(mbase, - MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR), - qh->h_addr_reg); - musb_writeb(mbase, - MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT), - qh->h_port_reg); + musb_write_txfunaddr(mbase, epnum, qh->addr_reg); + musb_write_txhubaddr(mbase, epnum, qh->h_addr_reg); + musb_write_txhubport(mbase, epnum, qh->h_port_reg); /* FIXME if !epnum, do the same for RX ... */ } else musb_writeb(mbase, MUSB_FADDR, qh->addr_reg); @@ -988,8 +983,10 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) if (fifo_count) { fifo_dest = (u8 *) (urb->transfer_buffer + urb->actual_length); - DBG(3, "Sending %d bytes to %p\n", - fifo_count, fifo_dest); + DBG(3, "Sending %d byte%s to ep0 fifo %p\n", + fifo_count, + (fifo_count == 1) ? "" : "s", + fifo_dest); musb_write_fifo(hw_ep, fifo_count, fifo_dest); urb->actual_length += fifo_count; diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index 223f0a51409..b06e9ef00cf 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -39,7 +39,7 @@ #if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \ && !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \ - && !defined(CONFIG_PPC64) + && !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) 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) @@ -56,6 +56,8 @@ static inline void writesb(const void __iomem *addr, const void *buf, int len) #endif +#ifndef CONFIG_BLACKFIN + /* NOTE: these offsets are all in bytes */ static inline u16 musb_readw(const void __iomem *addr, unsigned offset) @@ -114,4 +116,26 @@ static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) #endif /* CONFIG_USB_TUSB6010 */ +#else + +static inline u8 musb_readb(const void __iomem *addr, unsigned offset) + { return (u8) (bfin_read16(addr + offset)); } + +static inline u16 musb_readw(const void __iomem *addr, unsigned offset) + { return bfin_read16(addr + offset); } + +static inline u32 musb_readl(const void __iomem *addr, unsigned offset) + { return (u32 |