diff options
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/Kconfig | 6 | ||||
-rw-r--r-- | drivers/usb/musb/Makefile | 14 | ||||
-rw-r--r-- | drivers/usb/musb/blackfin.c | 96 | ||||
-rw-r--r-- | drivers/usb/musb/davinci.c | 2 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 147 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 10 | ||||
-rw-r--r-- | drivers/usb/musb/musb_debug.h | 13 | ||||
-rw-r--r-- | drivers/usb/musb/musb_debugfs.c | 294 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget_ep0.c | 25 | ||||
-rw-r--r-- | drivers/usb/musb/musb_regs.h | 10 | ||||
-rw-r--r-- | drivers/usb/musb/musb_virthub.c | 4 | ||||
-rw-r--r-- | drivers/usb/musb/musbhsdma.h | 16 | ||||
-rw-r--r-- | drivers/usb/musb/omap2430.c | 29 | ||||
-rw-r--r-- | drivers/usb/musb/tusb6010.c | 2 |
14 files changed, 567 insertions, 101 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 07fe490b44d8..cfd38edfcf9e 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -38,6 +38,7 @@ config USB_MUSB_SOC default y if ARCH_DAVINCI default y if ARCH_OMAP2430 default y if ARCH_OMAP3 + default y if ARCH_OMAP4 default y if (BF54x && !BF544) default y if (BF52x && !BF522 && !BF523) @@ -50,6 +51,9 @@ comment "OMAP 243x high speed USB support" comment "OMAP 343x high speed USB support" depends on USB_MUSB_HDRC && ARCH_OMAP3 +comment "OMAP 44xx high speed USB support" + depends on USB_MUSB_HDRC && ARCH_OMAP4 + comment "Blackfin high speed USB Support" depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523)) @@ -153,7 +157,7 @@ config MUSB_PIO_ONLY config USB_INVENTRA_DMA bool depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY - default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN + default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN || ARCH_OMAP4 help Enable DMA transfers using Mentor's engine. diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 3a485dabebbb..9705f716386e 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -22,6 +22,10 @@ ifeq ($(CONFIG_ARCH_OMAP3430),y) musb_hdrc-objs += omap2430.o endif +ifeq ($(CONFIG_ARCH_OMAP4),y) + musb_hdrc-objs += omap2430.o +endif + ifeq ($(CONFIG_BF54x),y) musb_hdrc-objs += blackfin.o endif @@ -38,6 +42,10 @@ ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y) musb_hdrc-objs += musb_virthub.o musb_host.o endif +ifeq ($(CONFIG_DEBUG_FS),y) + musb_hdrc-objs += musb_debugfs.o +endif + # the kconfig must guarantee that only one of the # possible I/O schemes will be enabled at a time ... # PIO only, or DMA (several potential schemes). @@ -64,12 +72,6 @@ endif ################################################################################ -# FIXME remove all these extra "-DMUSB_* things, stick to CONFIG_* - -ifeq ($(CONFIG_USB_INVENTRA_MUSB_HAS_AHB_ID),y) - EXTRA_CFLAGS += -DMUSB_AHB_ID -endif - # Debugging ifeq ($(CONFIG_USB_MUSB_DEBUG),y) diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index ec8d324237f6..b611420a8050 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -170,6 +170,13 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci) retval = musb_interrupt(musb); } + /* Start sampling ID pin, when plug is removed from MUSB */ + if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE + || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); + musb->a_wait_bcon = TIMER_DELAY; + } + spin_unlock_irqrestore(&musb->lock, flags); return retval; @@ -180,6 +187,7 @@ static void musb_conn_timer_handler(unsigned long _musb) struct musb *musb = (void *)_musb; unsigned long flags; u16 val; + static u8 toggle; spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { @@ -187,10 +195,44 @@ static void musb_conn_timer_handler(unsigned long _musb) 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_DEVCTL_SESSION; musb_writew(musb->mregs, MUSB_DEVCTL, val); + /* Check if musb is host or peripheral. */ + 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); + if (is_otg_enabled(musb)) + musb->xceiv->state = OTG_STATE_B_IDLE; + else + musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB); + } + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); + break; + case OTG_STATE_B_IDLE: + + if (!is_peripheral_enabled(musb)) + break; + /* Start a new session. It seems that MUSB needs taking + * some time to recognize the type of the plug inserted? + */ + 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; @@ -205,12 +247,27 @@ static void musb_conn_timer_handler(unsigned long _musb) 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); + /* Toggle the Soft Conn bit, so that we can response to + * the inserting of either A-plug or B-plug. + */ + if (toggle) { + val = musb_readb(musb->mregs, MUSB_POWER); + val &= ~MUSB_POWER_SOFTCONN; + musb_writeb(musb->mregs, MUSB_POWER, val); + toggle = 0; + } else { + val = musb_readb(musb->mregs, MUSB_POWER); + val |= MUSB_POWER_SOFTCONN; + musb_writeb(musb->mregs, MUSB_POWER, val); + toggle = 1; + } + /* The delay time is set to 1/4 second by default, + * shortening it, if accelerating A-plug detection + * is needed in OTG mode. + */ + mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY / 4); } - mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); break; - default: DBG(1, "%s state not handled\n", otg_state_string(musb)); break; @@ -222,7 +279,7 @@ static void musb_conn_timer_handler(unsigned long _musb) void musb_platform_enable(struct musb *musb) { - if (is_host_enabled(musb)) { + if (!is_otg_enabled(musb) && is_host_enabled(musb)) { mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); musb->a_wait_bcon = TIMER_DELAY; } @@ -232,16 +289,12 @@ 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); + int value = musb->config->gpio_vrsel_active; + if (!is_on) + value = !value; + gpio_set_value(musb->config->gpio_vrsel, value); DBG(1, "VBUS %s, devctl %02x " /* otg %3x conf %08x prcm %08x */ "\n", @@ -256,7 +309,7 @@ static int bfin_set_power(struct otg_transceiver *x, unsigned mA) void musb_platform_try_idle(struct musb *musb, unsigned long timeout) { - if (is_host_enabled(musb)) + if (!is_otg_enabled(musb) && is_host_enabled(musb)) mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); } @@ -270,7 +323,7 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode) return -EIO; } -int __init musb_platform_init(struct musb *musb) +int __init musb_platform_init(struct musb *musb, void *board_data) { /* @@ -339,23 +392,10 @@ int __init musb_platform_init(struct musb *musb) 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/davinci.c b/drivers/usb/musb/davinci.c index ce2e16fee0df..57624361c1de 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -376,7 +376,7 @@ int musb_platform_set_mode(struct musb *musb, u8 mode) return -EIO; } -int __init musb_platform_init(struct musb *musb) +int __init musb_platform_init(struct musb *musb, void *board_data) { void __iomem *tibase = musb->ctrl_base; u32 revision; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 705cc4ad8737..fad70bc83555 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -149,6 +149,87 @@ static inline struct musb *dev_to_musb(struct device *dev) /*-------------------------------------------------------------------------*/ +#ifndef CONFIG_BLACKFIN +static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) +{ + void __iomem *addr = otg->io_priv; + int i = 0; + u8 r; + u8 power; + + /* Make sure the transceiver is not in low power mode */ + power = musb_readb(addr, MUSB_POWER); + power &= ~MUSB_POWER_SUSPENDM; + musb_writeb(addr, MUSB_POWER, power); + + /* REVISIT: musbhdrc_ulpi_an.pdf recommends setting the + * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM. + */ + + musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); + musb_writeb(addr, MUSB_ULPI_REG_CONTROL, + MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR); + + while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) + & MUSB_ULPI_REG_CMPLT)) { + i++; + if (i == 10000) { + DBG(3, "ULPI read timed out\n"); + return -ETIMEDOUT; + } + + } + r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); + r &= ~MUSB_ULPI_REG_CMPLT; + musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); + + return musb_readb(addr, MUSB_ULPI_REG_DATA); +} + +static int musb_ulpi_write(struct otg_transceiver *otg, + u32 offset, u32 data) +{ + void __iomem *addr = otg->io_priv; + int i = 0; + u8 r = 0; + u8 power; + + /* Make sure the transceiver is not in low power mode */ + power = musb_readb(addr, MUSB_POWER); + power &= ~MUSB_POWER_SUSPENDM; + musb_writeb(addr, MUSB_POWER, power); + + musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); + musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data); + musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ); + + while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) + & MUSB_ULPI_REG_CMPLT)) { + i++; + if (i == 10000) { + DBG(3, "ULPI write timed out\n"); + return -ETIMEDOUT; + } + } + + r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); + r &= ~MUSB_ULPI_REG_CMPLT; + musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); + + return 0; +} +#else +#define musb_ulpi_read(a, b) NULL +#define musb_ulpi_write(a, b, c) NULL +#endif + +static struct otg_io_access_ops musb_ulpi_access = { + .read = musb_ulpi_read, + .write = musb_ulpi_write, +}; + +/*-------------------------------------------------------------------------*/ + #if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN) /* @@ -353,8 +434,7 @@ void musb_hnp_stop(struct musb *musb) * which cause occasional OPT A "Did not receive reset after connect" * errors. */ - musb->port1_status &= - ~(1 << USB_PORT_FEAT_C_CONNECTION); + musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16); } #endif @@ -530,8 +610,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb_writeb(mbase, MUSB_DEVCTL, devctl); } else { musb->port1_status |= - (1 << USB_PORT_FEAT_OVER_CURRENT) - | (1 << USB_PORT_FEAT_C_OVER_CURRENT); + USB_PORT_STAT_OVERCURRENT + | (USB_PORT_STAT_C_OVERCURRENT << 16); } break; default: @@ -986,7 +1066,8 @@ static void musb_shutdown(struct platform_device *pdev) * more than selecting one of a bunch of predefined configurations. */ #if defined(CONFIG_USB_TUSB6010) || \ - defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) + defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \ + || defined(CONFIG_ARCH_OMAP4) static ushort __initdata fifo_mode = 4; #else static ushort __initdata fifo_mode = 2; @@ -996,24 +1077,13 @@ static ushort __initdata fifo_mode = 2; module_param(fifo_mode, ushort, 0); MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration"); - -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[] = { +static struct musb_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, }, @@ -1022,7 +1092,7 @@ static struct fifo_cfg __initdata mode_0_cfg[] = { }; /* mode 1 - fits in 4KB */ -static struct fifo_cfg __initdata mode_1_cfg[] = { +static struct musb_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, }, @@ -1031,7 +1101,7 @@ static struct fifo_cfg __initdata mode_1_cfg[] = { }; /* mode 2 - fits in 4KB */ -static struct fifo_cfg __initdata mode_2_cfg[] = { +static struct musb_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, }, @@ -1041,7 +1111,7 @@ static struct fifo_cfg __initdata mode_2_cfg[] = { }; /* mode 3 - fits in 4KB */ -static struct fifo_cfg __initdata mode_3_cfg[] = { +static struct musb_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, }, @@ -1051,7 +1121,7 @@ static struct fifo_cfg __initdata mode_3_cfg[] = { }; /* mode 4 - fits in 16KB */ -static struct fifo_cfg __initdata mode_4_cfg[] = { +static struct musb_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, }, @@ -1082,7 +1152,7 @@ static struct fifo_cfg __initdata mode_4_cfg[] = { }; /* mode 5 - fits in 8KB */ -static struct fifo_cfg __initdata mode_5_cfg[] = { +static struct musb_fifo_cfg __initdata mode_5_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, }, @@ -1120,7 +1190,7 @@ static struct fifo_cfg __initdata mode_5_cfg[] = { */ static int __init fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, - const struct fifo_cfg *cfg, u16 offset) + const struct musb_fifo_cfg *cfg, u16 offset) { void __iomem *mbase = musb->mregs; int size = 0; @@ -1191,17 +1261,23 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0)); } -static struct fifo_cfg __initdata ep0_cfg = { +static struct musb_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; + const struct musb_fifo_cfg *cfg; unsigned i, n; int offset; struct musb_hw_ep *hw_ep = musb->endpoints; + if (musb->config->fifo_cfg) { + cfg = musb->config->fifo_cfg; + n = musb->config->fifo_cfg_size; + goto done; + } + switch (fifo_mode) { default: fifo_mode = 0; @@ -1236,6 +1312,7 @@ static int __init ep_config_from_table(struct musb *musb) musb_driver_name, fifo_mode); +done: offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0); /* assert(offset > 0) */ @@ -1461,7 +1538,8 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \ + defined(CONFIG_ARCH_OMAP4) static irqreturn_t generic_interrupt(int irq, void *__hci) { @@ -1948,7 +2026,7 @@ bad_config: * isp1504, non-OTG, etc) mostly hooking up through ULPI. */ musb->isr = generic_interrupt; - status = musb_platform_init(musb); + status = musb_platform_init(musb, plat->board_data); if (status < 0) goto fail2; @@ -1957,6 +2035,11 @@ bad_config: goto fail3; } + if (!musb->xceiv->io_ops) { + musb->xceiv->io_priv = musb->mregs; + musb->xceiv->io_ops = &musb_ulpi_access; + } + #ifndef CONFIG_MUSB_PIO_ONLY if (use_dma && dev->dma_mask) { struct dma_controller *c; @@ -2057,10 +2140,14 @@ bad_config: if (status < 0) goto fail3; + status = musb_init_debugfs(musb); + if (status < 0) + goto fail4; + #ifdef CONFIG_SYSFS status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group); if (status) - goto fail4; + goto fail5; #endif dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n", @@ -2077,6 +2164,9 @@ bad_config: return 0; +fail5: + musb_exit_debugfs(musb); + fail4: if (!is_otg_enabled(musb) && is_host_enabled(musb)) usb_remove_hcd(musb_to_hcd(musb)); @@ -2153,6 +2243,7 @@ static int __exit musb_remove(struct platform_device *pdev) * - Peripheral mode: peripheral is deactivated (or never-activated) * - OTG mode: both roles are deactivated (or never-activated) */ + musb_exit_debugfs(musb); musb_shutdown(pdev); #ifdef CONFIG_USB_MUSB_HDRC_HCD if (musb->board_mode == MUSB_HOST) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index ac17b004909b..b22d02dea7d3 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -69,7 +69,7 @@ struct musb_ep; #include "musb_regs.h" #include "musb_gadget.h" -#include "../core/hcd.h" +#include <linux/usb/hcd.h> #include "musb_host.h" @@ -213,7 +213,8 @@ enum musb_g_ep0_state { */ #if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \ - || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN) + || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN) \ + || defined(CONFIG_ARCH_OMAP4) /* REVISIT indexed access seemed to * misbehave (on DaVinci) for at least peripheral IN ... */ @@ -596,7 +597,8 @@ extern void musb_hnp_stop(struct musb *musb); extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode); #if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \ - defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) + defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ + defined(CONFIG_ARCH_OMAP4) extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout); #else #define musb_platform_try_idle(x, y) do {} while (0) @@ -608,7 +610,7 @@ extern int musb_platform_get_vbus_status(struct musb *musb); #define musb_platform_get_vbus_status(x) 0 #endif -extern int __init musb_platform_init(struct musb *musb); +extern int __init musb_platform_init(struct musb *musb, void *board_data); extern int musb_platform_exit(struct musb *musb); #endif /* __MUSB_CORE_H__ */ diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h index 9fc1db44c72c..d73afdbde3ee 100644 --- a/drivers/usb/musb/musb_debug.h +++ b/drivers/usb/musb/musb_debug.h @@ -59,4 +59,17 @@ static inline int _dbg_level(unsigned l) extern const char *otg_state_string(struct musb *); +#ifdef CONFIG_DEBUG_FS +extern int musb_init_debugfs(struct musb *musb); +extern void musb_exit_debugfs(struct musb *musb); +#else +static inline int musb_init_debugfs(struct musb *musb) +{ + return 0; +} +static inline void musb_exit_debugfs(struct musb *musb) +{ +} +#endif + #endif /* __MUSB_LINUX_DEBUG_H__ */ diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c new file mode 100644 index 000000000000..bba76af0c0c6 --- /dev/null +++ b/drivers/usb/musb/musb_debugfs.c @@ -0,0 +1,294 @@ +/* + * MUSB OTG driver debugfs support + * + * Copyright 2010 Nokia Corporation + * Contact: Felipe Balbi <felipe.balbi@nokia.com> + * + * 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/init.h> +#include <linux/list.h> +#include <linux/kobject.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#ifdef CONFIG_ARM +#include <mach/hardware.h> +#include <mach/memory.h> +#include <asm/mach-types.h> +#endif + +#include <asm/uaccess.h> + +#include "musb_core.h" +#include "musb_debug.h" + +#ifdef CONFIG_ARCH_DAVINCI +#include "davinci.h" +#endif + +struct musb_register_map { + char *name; + unsigned offset; + unsigned size; +}; + +static const struct musb_register_map musb_regmap[] = { + { "FAddr", 0x00, 8 }, + { "Power", 0x01, 8 }, + { "Frame", 0x0c, 16 }, + { "Index", 0x0e, 8 }, + { "Testmode", 0x0f, 8 }, + { "TxMaxPp", 0x10, 16 }, + { "TxCSRp", 0x12, 16 }, + { "RxMaxPp", 0x14, 16 }, + { "RxCSR", 0x16, 16 }, + { "RxCount", 0x18, 16 }, + { "ConfigData", 0x1f, 8 }, + { "DevCtl", 0x60, 8 }, + { "MISC", 0x61, 8 }, + { "TxFIFOsz", 0x62, 8 }, + { "RxFIFOsz", 0x63, 8 }, + { "TxFIFOadd", 0x64, 16 }, + { "RxFIFOadd", 0x66, 16 }, + { "VControl", 0x68, 32 }, + { "HWVers", 0x6C, 16 }, + { "EPInfo", 0x78, 8 }, + { "RAMInfo", 0x79, 8 }, + { "LinkInfo", 0x7A, 8 }, + { "VPLen", 0x7B, 8 }, + { "HS_EOF1", 0x7C, 8 }, + { "FS_EOF1", 0x7D, 8 }, + { "LS_EOF1", 0x7E, 8 }, + { "SOFT_RST", 0x7F, 8 }, + { "DMA_CNTLch0", 0x204, 16 }, + { "DMA_ADDRch0", 0x208, 16 }, + { "DMA_COUNTch0", 0x20C, 16 }, + { "DMA_CNTLch1", 0x214, 16 }, + { "DMA_ADDRch1", 0x218, 16 }, + { "DMA_COUNTch1", 0x21C, 16 }, + { "DMA_CNTLch2", 0x224, 16 }, + { "DMA_ADDRch2", 0x228, 16 }, + { "DMA_COUNTch2", 0x22C, 16 }, + { "DMA_CNTLch3", 0x234, 16 }, + { "DMA_ADDRch3", 0x238, 16 }, + { "DMA_COUNTch3", 0x23C, 16 }, + { "DMA_CNTLch4", 0x244, 16 }, + { "DMA_ADDRch4", 0x248, 16 }, + { "DMA_COUNTch4", 0x24C, 16 }, + { "DMA_CNTLch5", 0x254, 16 }, + { "DMA_ADDRch5", 0x258, 16 }, + { "DMA_COUNTch5", 0x25C, 16 }, + { "DMA_CNTLch6", 0x264, 16 }, + { "DMA_ADDRch6", 0x268, 16 }, + { "DMA_COUNTch6", 0x26C, 16 }, + { "DMA_CNTLch7", 0x274, 16 }, + { "DMA_ADDRch7", 0x278, 16 }, + { "DMA_COUNTch7", 0x27C, 16 }, + { } /* Terminating Entry */ +}; + +static struct dentry *musb_debugfs_root; + +static int musb_regdump_show(struct seq_file *s, void *unused) +{ + struct musb *musb = s->private; + unsigned i; + + seq_printf(s, "MUSB (M)HDRC Register Dump\n"); + + for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) { + switch (musb_regmap[i].size) { + case 8: + seq_printf(s, "%-12s: %02x\n", musb_regmap[i].name, + musb_readb(musb->mregs, musb_regmap[i].offset)); + break; + case 16: + seq_printf(s, "%-12s: %04x\n", musb_regmap[i].name, + musb_readw(musb->mregs, musb_regmap[i].offset)); + break; + case 32: + seq_printf(s, "%-12s: %08x\n", musb_regmap[i].name, + musb_readl(musb->mregs, musb_regmap[i].offset)); + break; + } + } + + return 0; +} + +static int musb_regdump_open(struct inode *inode, struct file *file) +{ + return single_open(file, musb_regdump_show, inode->i_private); +} + +static int musb_test_mode_show(struct seq_file *s, void *unused) +{ + struct musb *musb = s->private; + unsigned test; + + test = musb_readb(musb->mregs, MUSB_TESTMODE); + + if (test & MUSB_TEST_FORCE_HOST) + seq_printf(s, "force host\n"); + + if (test & MUSB_TEST_FIFO_ACCESS) + seq_printf(s, "fifo access\n"); + + if (test & MUSB_TEST_FORCE_FS) + seq_printf(s, "force full-speed\n"); + + if (test & MUSB_TEST_FORCE_HS) + seq_printf(s, "force high-speed\n"); + + if (test & MUSB_TEST_PACKET) + seq_printf(s, "test packet\n"); + + if (test & MUSB_TEST_K) + seq_printf(s, "test K\n"); + + if (test & MUSB_TEST_J) + seq_printf(s, "test J\n"); + + if (test & MUSB_TEST_SE0_NAK) + seq_printf(s, "test SE0 NAK\n"); + + return 0; +} + +static const struct file_operations musb_regdump_fops = { + .open = musb_regdump_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int musb_test_mode_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + + return single_open(file, musb_test_mode_show, inode->i_private); +} + +static ssize_t musb_test_mode_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct musb *musb = file->private_data; + u8 test = 0; + char buf[18]; + + memset(buf, 0x00, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "force host", 9)) + test = MUSB_TEST_FORCE_HOST; + + if (!strncmp(buf, "fifo access", 11)) + test = MUSB_TEST_FIFO_ACCESS; + + if (!strncmp(buf, "force full-speed", 15)) + test = MUSB_TEST_FORCE_FS; + + if (!strncmp(buf, "force high-speed", 15)) + test = MUSB_TEST_FORCE_HS; + + if (!strncmp(buf, "test packet", 10)) { + test = MUSB_TEST_PACKET; + musb_load_testpacket(musb); + } + + if (!strncmp(buf, "test K", 6)) + test = MUSB_TEST_K; + + if (!strncmp(buf, "test J", 6)) + test = MUSB_TEST_J; + + if (!strncmp(buf, "test SE0 NAK", 12)) + test = MUSB_TEST_SE0_NAK; + + musb_writeb(musb->mregs, MUSB_TESTMODE, test); + + return count; +} + +static const struct file_operations musb_test_mode_fops = { + .open = musb_test_mode_open, + .write = musb_test_mode_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int __init musb_init_debugfs(struct musb *musb) +{ + struct dentry *root; + struct dentry *file; + int ret; + + root = debugfs_create_dir("musb", NULL); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto err0; + } + + file = debugfs_create_file("regdump", S_IRUGO, root, musb, + &musb_regdump_fops); + if (IS_ERR(file)) { + ret = PTR_ERR(file); + goto err1; + } + + file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, + root, musb, &musb_test_mode_fops); + if (IS_ERR(file)) { + ret = PTR_ERR(file); + goto err1; + } + + musb_debugfs_root = root; + + return 0; + +err1: + debugfs_remove_recursive(root); + +err0: + return ret; +} + +void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb) +{ + debugfs_remove_recursive(musb_debugfs_root); +} diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 53d06451f820..21b9788d0243 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -351,6 +351,31 @@ __acquires(musb->lock) musb->test_mode_nr = MUSB_TEST_PACKET; break; + + case 0xc0: + /* TEST_FORCE_HS */ + pr_debug("TEST_FORCE_HS\n"); + musb->test_mode_nr = + MUSB_TEST_FORCE_HS; + break; + case 0xc1: + /* TEST_FORCE_FS */ + pr_debug("TEST_FORCE_FS\n"); + musb->test_mode_nr = + MUSB_TEST_FORCE_FS; + break; + case 0xc2: + /* TEST_FIFO_ACCESS */ + pr_debug("TEST_FIFO_ACCESS\n"); + musb->test_mode_nr = + MUSB_TEST_FIFO_ACCESS; + break; + case 0xc3: + /* TEST_FORCE_HOST */ + pr_debug("TEST_FORCE_HOST\n"); + musb->test_mode_nr = + MUSB_TEST_FORCE_HOST; + break; default: goto stall; } diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index fa55aacc385d..244267527a60 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -75,6 +75,10 @@ /* MUSB ULPI VBUSCONTROL */ #define MUSB_ULPI_USE_EXTVBUS 0x01 #define MUSB_ULPI_USE_EXTVBUSIND 0x02 +/* ULPI_REG_CONTROL */ +#define MUSB_ULPI_REG_REQ (1 << 0) +#define MUSB_ULPI_REG_CMPLT (1 << 1) +#define MUSB_ULPI_RDN_WR (1 << 2) /* TESTMODE */ #define MUSB_TEST_FORCE_HOST 0x80 @@ -251,6 +255,12 @@ /* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */ #define MUSB_HWVERS 0x6C /* 8 bit */ #define MUSB_ULPI_BUSCONTROL 0x70 /* 8 bit */ +#define MUSB_ULPI_INT_MASK 0x72 /* 8 bit */ +#define MUSB_ULPI_INT_SRC 0x73 /* 8 bit */ +#define MUSB_ULPI_REG_DATA 0x74 /* 8 bit */ +#define MUSB_ULPI_REG_ADDR 0x75 /* 8 bit */ +#define MUSB_ULPI_REG_CONTROL 0x76 /* 8 bit */ +#define MUSB_ULPI_RAW_DATA 0x77 /* 8 bit */ #define MUSB_EPINFO 0x78 /* 8 bit */ #define MUSB_RAMINFO 0x79 /* 8 bit */ diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 7775e1c0a215..92e85e027cfb 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -183,8 +183,8 @@ static void musb_port_reset(struct musb *musb, bool do_reset) void musb_root_disconnect(struct musb *musb) { - musb->port1_status = (1 << USB_PORT_FEAT_POWER) - | (1 << USB_PORT_FEAT_C_CONNECTION); + musb->port1_status = USB_PORT_STAT_POWER + | (USB_PORT_STAT_C_CONNECTION << 16); usb_hcd_poll_rh_status(musb_to_hcd(musb)); musb->is_active = 0; diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h index 613f95a058f7..f763d62f151c 100644 --- a/drivers/usb/musb/musbhsdma.h +++ b/drivers/usb/musb/musbhsdma.h @@ -102,26 +102,16 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase, static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel) { - u32 count = musb_readw(mbase, + return musb_readl(mbase, MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH)); - - count = count << 16; - - count |= musb_readw(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW)); - - return count; } static inline void musb_write_hsdma_count(void __iomem *mbase, u8 bchannel, u32 len) { - musb_writew(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW), - ((u16)((u32) len & 0xFFFF))); - musb_writew(mbase, + musb_writel(mbase, MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH), - ((u16)(((u32) len >> 16) & 0xFFFF))); + len); } #endif /* CONFIG_BLACKFIN */ diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 82592633502f..e06d65e36bf7 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -32,17 +32,11 @@ #include <linux/clk.h> #include <linux/io.h> -#include <asm/mach-types.h> -#include <mach/hardware.h> #include <plat/mux.h> #include "musb_core.h" #include "omap2430.h" -#ifdef CONFIG_ARCH_OMAP3430 -#define get_cpu_rev() 2 -#endif - static struct timer_list musb_idle_timer; @@ -145,10 +139,6 @@ void musb_platform_enable(struct musb *musb) void musb_platform_disable(struct musb *musb) { } -static void omap_vbus_power(struct musb *musb, int is_on, int sleeping) -{ -} - static void omap_set_vbus(struct musb *musb, int is_on) { u8 devctl; @@ -199,9 +189,10 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode) return 0; } -int __init musb_platform_init(struct musb *musb) +int __init musb_platform_init(struct musb *musb, void *board_data) { u32 l; + struct omap_musb_board_data *data = board_data; #if defined(CONFIG_ARCH_OMAP2430) omap_cfg_reg(AE5_2430_USB0HS_STP); @@ -235,7 +226,15 @@ int __init musb_platform_init(struct musb *musb) musb_writel(musb->mregs, OTG_SYSCONFIG, l); l = musb_readl(musb->mregs, OTG_INTERFSEL); - l |= ULPI_12PIN; + + if (data->interface_type == MUSB_INTERFACE_UTMI) { + /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */ + l &= ~ULPI_12PIN; /* Disable ULPI */ + l |= UTMI_8BIT; /* Enable UTMI */ + } else { + l |= ULPI_12PIN; + } + musb_writel(musb->mregs, OTG_INTERFSEL, l); pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, " @@ -246,8 +245,6 @@ int __init musb_platform_init(struct musb *musb) musb_readl(musb->mregs, OTG_INTERFSEL), musb_readl(musb->mregs, OTG_SIMENABLE)); - omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1); - if (is_host_enabled(musb)) musb->board_set_vbus = omap_set_vbus; @@ -272,7 +269,7 @@ void musb_platform_restore_context(struct musb *musb, } #endif -int musb_platform_suspend(struct musb *musb) +static int musb_platform_suspend(struct musb *musb) { u32 l; @@ -327,8 +324,6 @@ static int musb_platform_resume(struct musb *musb) int musb_platform_exit(struct musb *musb) { - omap_vbus_power(musb, 0 /*off*/, 1); - musb_platform_suspend(musb); return 0; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 60d3938cafcf..05c077f8f9ac 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1104,7 +1104,7 @@ err: return -ENODEV; } -int __init musb_platform_init(struct musb *musb) +int __init musb_platform_init(struct musb *musb, void *board_data) { struct platform_device *pdev; struct resource *mem; |