diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 3 | ||||
-rw-r--r-- | drivers/usb/host/ehci-ppc4xx.c | 48 | ||||
-rw-r--r-- | drivers/usb/musb/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/musb/blackfin_usb.c | 143 | ||||
-rw-r--r-- | drivers/usb/musb/blackfin_usb.h | 99 | ||||
-rw-r--r-- | drivers/usb/musb/da8xx.c | 139 | ||||
-rw-r--r-- | drivers/usb/musb/da8xx.h | 103 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 18 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 18 | ||||
-rw-r--r-- | drivers/usb/musb/musb_hcd.c | 451 | ||||
-rw-r--r-- | drivers/usb/musb/musb_hcd.h | 59 | ||||
-rw-r--r-- | drivers/usb/musb/omap3.c | 3 |
13 files changed, 1079 insertions, 8 deletions
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 940d4a8..255679a 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -36,6 +36,7 @@ COBJS-$(CONFIG_USB_SL811HS) += sl811-hcd.o # echi COBJS-$(CONFIG_USB_EHCI) += ehci-hcd.o COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o +COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o COBJS-$(CONFIG_USB_EHCI_KIRKWOOD) += ehci-kirkwood.o COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ba85991..9ebeb4f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -708,6 +708,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, * root */ wait_ms(50); + /* terminate the reset */ + ehci_writel(status_reg, reg & ~EHCI_PS_PR); + wait_ms(2); portreset |= 1 << le16_to_cpu(req->index); } break; diff --git a/drivers/usb/host/ehci-ppc4xx.c b/drivers/usb/host/ehci-ppc4xx.c new file mode 100644 index 0000000..946a0a0 --- /dev/null +++ b/drivers/usb/host/ehci-ppc4xx.c @@ -0,0 +1,48 @@ +/* + * (C) Copyright 2010, Chris Zhang <chris@seamicro.com> + * + * Author: Chris Zhang <chris@seamicro.com> + * This code is based on ehci freescale driver + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <usb.h> + +#include "ehci.h" +#include "ehci-core.h" + +/* + * Create the appropriate control structures to manage + * a new EHCI host controller. + */ +int ehci_hcd_init(void) +{ + hccr = (struct ehci_hccr *)(CONFIG_SYS_PPC4XX_USB_ADDR); + hcor = (struct ehci_hcor *)((uint32_t) hccr + + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + usb_dev_init(); + return 0; +} + +/* + * Destroy the appropriate control structures corresponding + * the the EHCI host controller. + */ +int ehci_hcd_stop(void) +{ + return 0; +} diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index f2ccd9f..397f5fe 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -27,8 +27,10 @@ LIB := $(obj)libusb_musb.a COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o COBJS-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o +COBJS-$(CONFIG_USB_BLACKFIN) += blackfin_usb.o COBJS-$(CONFIG_USB_DAVINCI) += davinci.o COBJS-$(CONFIG_USB_OMAP3) += omap3.o +COBJS-$(CONFIG_USB_DA8XX) += da8xx.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/usb/musb/blackfin_usb.c b/drivers/usb/musb/blackfin_usb.c new file mode 100644 index 0000000..38aceb2 --- /dev/null +++ b/drivers/usb/musb/blackfin_usb.c @@ -0,0 +1,143 @@ +/* + * Blackfin MUSB HCD (Host Controller Driver) for u-boot + * + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <common.h> + +#include <usb.h> + +#include <asm/blackfin.h> +#include <asm/mach-common/bits/usb.h> + +#include "musb_core.h" + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { + .regs = (struct musb_regs *)USB_FADDR, + .timeout = 0x3FFFFFF, + .musb_speed = 0, +}; + +/* + * This function read or write data to endpoint fifo + * Blackfin use DMA polling method to avoid buffer alignment issues + * + * ep - Endpoint number + * length - Number of bytes to write to FIFO + * fifo_data - Pointer to data buffer to be read/write + * is_write - Flag for read or write + */ +void rw_fifo(u8 ep, u32 length, void *fifo_data, int is_write) +{ + struct bfin_musb_dma_regs *regs; + u32 val = (u32)fifo_data; + + blackfin_dcache_flush_invalidate_range(fifo_data, fifo_data + length); + + regs = (void *)USB_DMA_INTERRUPT; + regs += ep; + + /* Setup DMA address register */ + bfin_write16(®s->addr_low, val); + SSYNC(); + + bfin_write16(®s->addr_high, val >> 16); + SSYNC(); + + /* Setup DMA count register */ + bfin_write16(®s->count_low, length); + bfin_write16(®s->count_high, 0); + SSYNC(); + + /* Enable the DMA */ + val = (ep << 4) | DMA_ENA | INT_ENA; + if (is_write) + val |= DIRECTION; + bfin_write16(®s->control, val); + SSYNC(); + + /* Wait for compelete */ + while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << ep))) + continue; + + /* acknowledge dma interrupt */ + bfin_write_USB_DMA_INTERRUPT(1 << ep); + SSYNC(); + + /* Reset DMA */ + bfin_write16(®s->control, 0); + SSYNC(); +} + +void write_fifo(u8 ep, u32 length, void *fifo_data) +{ + rw_fifo(ep, length, fifo_data, 1); +} + +void read_fifo(u8 ep, u32 length, void *fifo_data) +{ + rw_fifo(ep, length, fifo_data, 0); +} + + +/* + * CPU and board-specific MUSB initializations. Aliased function + * signals caller to move on. + */ +static void __def_musb_init(void) +{ +} +void board_musb_init(void) __attribute__((weak, alias("__def_musb_init"))); + +int musb_platform_init(void) +{ + /* board specific initialization */ + board_musb_init(); + + if (ANOMALY_05000346) { + bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); + SSYNC(); + } + + if (ANOMALY_05000347) { + bfin_write_USB_APHY_CNTRL(0x0); + SSYNC(); + } + + /* 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(); + + return 0; +} + +/* + * This function performs Blackfin platform specific deinitialization for usb. +*/ +void musb_platform_deinit(void) +{ +} diff --git a/drivers/usb/musb/blackfin_usb.h b/drivers/usb/musb/blackfin_usb.h new file mode 100644 index 0000000..ab26ca2 --- /dev/null +++ b/drivers/usb/musb/blackfin_usb.h @@ -0,0 +1,99 @@ +/* + * Blackfin MUSB HCD (Host Controller Driver) for u-boot + * + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __BLACKFIN_USB_H__ +#define __BLACKFIN_USB_H__ + +#include <linux/types.h> + +/* Every register is 32bit aligned, but only 16bits in size */ +#define ureg(name) u16 name; u16 __pad_##name; + +#define musb_regs musb_regs +struct musb_regs { + /* common registers */ + ureg(faddr) + ureg(power) + ureg(intrtx) + ureg(intrrx) + ureg(intrtxe) + ureg(intrrxe) + ureg(intrusb) + ureg(intrusbe) + ureg(frame) + ureg(index) + ureg(testmode) + ureg(globintr) + ureg(global_ctl) + u32 reserved0[3]; + /* indexed registers */ + ureg(txmaxp) + ureg(txcsr) + ureg(rxmaxp) + ureg(rxcsr) + ureg(rxcount) + ureg(txtype) + ureg(txinterval) + ureg(rxtype) + ureg(rxinterval) + u32 reserved1; + ureg(txcount) + u32 reserved2[5]; + /* fifo */ + u16 fifox[32]; + /* OTG, dynamic FIFO, version & vendor registers */ + u32 reserved3[16]; + ureg(devctl) + ureg(vbus_irq) + ureg(vbus_mask) + u32 reserved4[15]; + ureg(linkinfo) + ureg(vplen) + ureg(hseof1) + ureg(fseof1) + ureg(lseof1) + u32 reserved5[41]; + /* target address registers */ + struct musb_tar_regs { + ureg(txmaxp) + ureg(txcsr) + ureg(rxmaxp) + ureg(rxcsr) + ureg(rxcount) + ureg(txtype) + ureg(txinternal) + ureg(rxtype) + ureg(rxinternal) + u32 reserved6; + ureg(txcount) + u32 reserved7[5]; + } tar[8]; +} __attribute__((packed)); + +struct bfin_musb_dma_regs { + ureg(interrupt); + ureg(control); + ureg(addr_low); + ureg(addr_high); + ureg(count_low); + ureg(count_high); + ureg(pad); +}; + +#undef ureg + +/* EP5-EP7 are the only ones with 1024 byte FIFOs which BULK really needs */ +#define MUSB_BULK_EP 5 + +/* Blackfin FIFO's are static */ +#define MUSB_NO_DYNAMIC_FIFO + +/* No HUB support :( */ +#define MUSB_NO_MULTIPOINT + +#endif diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c new file mode 100644 index 0000000..40bfe44 --- /dev/null +++ b/drivers/usb/musb/da8xx.c @@ -0,0 +1,139 @@ +/* + * da8xx.c - TI's DA8xx platform specific usb wrapper functions. + * + * Author: Ajay Kumar Gupta <ajay.gupta@ti.com> + * + * Based on drivers/usb/musb/davinci.c + * + * Copyright (C) 2009 Texas Instruments Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <common.h> + +#include "da8xx.h" + +/* MUSB platform configuration */ +struct musb_config musb_cfg = { + (struct musb_regs *)DA8XX_USB_OTG_CORE_BASE, + DA8XX_USB_OTG_TIMEOUT, + 0 +}; + +/* + * This function enables VBUS by driving the GPIO Bank4 Pin 15 high. + */ +static void enable_vbus(void) +{ + u32 value; + + /* configure GPIO bank4 pin 15 in output direction */ + value = readl(&davinci_gpio_bank45->dir); + writel((value & (~DA8XX_USB_VBUS_GPIO)), &davinci_gpio_bank45->dir); + + /* set GPIO bank4 pin 15 high to drive VBUS */ + value = readl(&davinci_gpio_bank45->set_data); + writel((value | DA8XX_USB_VBUS_GPIO), &davinci_gpio_bank45->set_data); +} + +/* + * Enable the usb0 phy. This initialization procedure is explained in + * the DA8xx USB user guide document. + */ +static u8 phy_on(void) +{ + u32 timeout; + u32 cfgchip2; + + cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2); + + cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | + CFGCHIP2_OTGMODE | CFGCHIP2_REFFREQ); + cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN | CFGCHIP2_PHY_PLLON | + CFGCHIP2_REFFREQ_24MHZ; + + writel(cfgchip2, &davinci_syscfg_regs->cfgchip2); + + /* wait until the usb phy pll locks */ + timeout = musb_cfg.timeout; + while (timeout--) + if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD) + return 1; + + /* USB phy was not turned on */ + return 0; +} + +/* + * Disable the usb phy + */ +static void phy_off(void) +{ + u32 cfgchip2; + + /* + * Power down the on-chip PHY. + */ + cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2); + cfgchip2 &= ~CFGCHIP2_PHY_PLLON; + cfgchip2 |= CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN; + writel(cfgchip2, &davinci_syscfg_regs->cfgchip2); +} + +/* + * This function performs DA8xx platform specific initialization for usb0. + */ +int musb_platform_init(void) +{ + u32 revision; + + /* enable psc for usb2.0 */ + lpsc_on(33); + + /* enable usb vbus */ + enable_vbus(); + + /* reset the controller */ + writel(0x1, &da8xx_usb_regs->control); + udelay(5000); + + /* start the on-chip usb phy and its pll */ + if (phy_on() == 0) + return -1; + + /* Returns zero if e.g. not clocked */ + revision = readl(&da8xx_usb_regs->revision); + if (revision == 0) + return -1; + + /* Disable all interrupts */ + writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK | + DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_set); + return 0; +} + +/* + * This function performs DA8xx platform specific deinitialization for usb0. + */ +void musb_platform_deinit(void) +{ + /* Turn of the phy */ + phy_off(); + + /* flush any interrupts */ + writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK | + DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr); + writel(0, &da8xx_usb_regs->eoi); +} diff --git a/drivers/usb/musb/da8xx.h b/drivers/usb/musb/da8xx.h new file mode 100644 index 0000000..93234f0 --- /dev/null +++ b/drivers/usb/musb/da8xx.h @@ -0,0 +1,103 @@ +/* + * da8xx.h -- TI's DA8xx platform specific usb wrapper definitions. + * + * Author: Ajay Kumar Gupta <ajay.gupta@ti.com> + * + * Based on drivers/usb/musb/davinci.h + * + * Copyright (C) 2009 Texas Instruments Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __DA8XX_MUSB_H__ +#define __DA8XX_MUSB_H__ + +#include <asm/arch/hardware.h> +#include <asm/arch/gpio_defs.h> +#include "musb_core.h" + +/* Base address of da8xx usb0 wrapper */ +#define DA8XX_USB_OTG_BASE 0x01E00000 + +/* Base address of da8xx musb core */ +#define DA8XX_USB_OTG_CORE_BASE (DA8XX_USB_OTG_BASE + 0x400) + +/* Timeout for DA8xx usb module */ +#define DA8XX_USB_OTG_TIMEOUT 0x3FFFFFF + +/* + * DA8xx platform USB wrapper register overlay. + */ +struct da8xx_usb_regs { + dv_reg revision; + dv_reg control; + dv_reg status; + dv_reg emulation; + dv_reg mode; + dv_reg autoreq; + dv_reg srpfixtime; + dv_reg teardown; + dv_reg intsrc; + dv_reg intsrc_set; + dv_reg intsrc_clr; + dv_reg intmsk; + dv_reg intmsk_set; + dv_reg intmsk_clr; + dv_reg intsrcmsk; + dv_reg eoi; + dv_reg intvector; + dv_reg grndis_size[4]; +}; + +#define da8xx_usb_regs ((struct da8xx_usb_regs *)DA8XX_USB_OTG_BASE) + +/* DA8XX interrupt bits definitions */ +#define DA8XX_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */ +#define DA8XX_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */ +#define DA8XX_USB_TXINT_SHIFT 0 +#define DA8XX_USB_RXINT_SHIFT 8 + +#define DA8XX_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */ +#define DA8XX_USB_TXINT_MASK \ + (DA8XX_USB_TX_ENDPTS_MASK << DA8XX_USB_TXINT_SHIFT) +#define DA8XX_USB_RXINT_MASK \ + (DA8XX_USB_RX_ENDPTS_MASK << DA8XX_USB_RXINT_SHIFT) + +/* DA8xx CFGCHIP2 (USB 2.0 PHY Control) register bits */ +#define CFGCHIP2_PHYCLKGD (1 << 17) +#define CFGCHIP2_VBUSSENSE (1 << 16) +#define CFGCHIP2_RESET (1 << 15) +#define CFGCHIP2_OTGMODE (3 << 13) +#define CFGCHIP2_NO_OVERRIDE (0 << 13) +#define CFGCHIP2_FORCE_HOST (1 << 13) +#define CFGCHIP2_FORCE_DEVICE (2 << 13) +#define CFGCHIP2_FORCE_HOST_VBUS_LOW (3 << 13) +#define CFGCHIP2_USB1PHYCLKMUX (1 << 12) +#define CFGCHIP2_USB2PHYCLKMUX (1 << 11) +#define CFGCHIP2_PHYPWRDN (1 << 10) +#define CFGCHIP2_OTGPWRDN (1 << 9) +#define CFGCHIP2_DATPOL (1 << 8) +#define CFGCHIP2_USB1SUSPENDM (1 << 7) +#define CFGCHIP2_PHY_PLLON (1 << 6) /* override PLL suspend */ +#define CFGCHIP2_SESENDEN (1 << 5) /* Vsess_end comparator */ +#define CFGCHIP2_VBDTCTEN (1 << 4) /* Vbus comparator */ +#define CFGCHIP2_REFFREQ (0xf << 0) +#define CFGCHIP2_REFFREQ_12MHZ (1 << 0) +#define CFGCHIP2_REFFREQ_24MHZ (2 << 0) +#define CFGCHIP2_REFFREQ_48MHZ (3 << 0) + +#define DA8XX_USB_VBUS_GPIO (1 << 15) +#endif /* __DA8XX_MUSB_H__ */ + diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 22f3dba..7766069 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -50,6 +50,16 @@ void musb_start(void) #endif } +#ifdef MUSB_NO_DYNAMIC_FIFO +# define config_fifo(dir, idx, addr) +#else +# define config_fifo(dir, idx, addr) \ + do { \ + writeb(idx, &musbr->dir##fifosz); \ + writew(fifoaddr >> 3, &musbr->dir##fifoadd); \ + } while (0) +#endif + /* * This function configures the endpoint configuration. The musb hcd or musb * device implementation can use this function to configure the endpoints @@ -74,8 +84,7 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt) writeb(epinfo->epnum, &musbr->index); if (epinfo->epdir) { /* Configure fifo size and fifo base address */ - writeb(idx, &musbr->txfifosz); - writew(fifoaddr >> 3, &musbr->txfifoadd); + config_fifo(tx, idx, fifoaddr); csr = readw(&musbr->txcsr); #if defined(CONFIG_MUSB_HCD) @@ -88,8 +97,7 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt) &musbr->txcsr); } else { /* Configure fifo size and fifo base address */ - writeb(idx, &musbr->rxfifosz); - writew(fifoaddr >> 3, &musbr->rxfifoadd); + config_fifo(rx, idx, fifoaddr); csr = readw(&musbr->rxcsr); #if defined(CONFIG_MUSB_HCD) @@ -113,6 +121,7 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt) * length - number of bytes to write to FIFO * fifo_data - Pointer to data buffer that contains the data to write */ +__attribute__((weak)) void write_fifo(u8 ep, u32 length, void *fifo_data) { u8 *data = (u8 *)fifo_data; @@ -132,6 +141,7 @@ void write_fifo(u8 ep, u32 length, void *fifo_data) * length - number of bytes to read from FIFO * fifo_data - pointer to data buffer into which data is read */ +__attribute__((weak)) void read_fifo(u8 ep, u32 length, void *fifo_data) { u8 *data = (u8 *)fifo_data; diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 15c7f49..f0f0301 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -38,6 +38,10 @@ #include <usb_defs.h> #include <asm/io.h> +#ifdef CONFIG_USB_BLACKFIN +# include "blackfin_usb.h" +#endif + #define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */ /* EP0 */ @@ -71,6 +75,7 @@ struct musb_epN_regs { }; /* Mentor USB core register overlay structure */ +#ifndef musb_regs struct musb_regs { /* common registers */ u8 faddr; @@ -137,7 +142,8 @@ struct musb_regs { struct musb_epN_regs epN; } ep[16]; -} __attribute__((aligned(32))); +} __attribute__((packed, aligned(32))); +#endif /* * MUSB Register bits @@ -347,4 +353,14 @@ extern void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt); extern void write_fifo(u8 ep, u32 length, void *fifo_data); extern void read_fifo(u8 ep, u32 length, void *fifo_data); +#if defined(CONFIG_USB_BLACKFIN) +/* Every USB register is accessed as a 16-bit even if the value itself + * is only 8-bits in size. Fun stuff. + */ +# undef readb +# define readb(addr) (u8)bfin_read16(addr) +# undef writeb +# define writeb(b, addr) bfin_write16(addr, b) +#endif + #endif /* __MUSB_HDRC_DEFS_H__ */ diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 555d2dc..dd2aa7f 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -35,6 +35,106 @@ static struct musb_epinfo epinfo[3] = { {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */ }; +/* --- Virtual Root Hub ---------------------------------------------------- */ +#ifdef MUSB_NO_MULTIPOINT +static int rh_devnum; +static u32 port_status; + +/* Device descriptor */ +static u8 root_hub_dev_des[] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, /* __u16 bcdUSB; v1.1 */ + 0x02, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x01, /* __u8 iProduct; */ + 0x00, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static u8 root_hub_config_des[] = { + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ + 0x02, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static unsigned char root_hub_str_index0[] = { + 0x04, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 0x09, /* __u8 lang ID */ + 0x04, /* __u8 lang ID */ +}; + +static unsigned char root_hub_str_index1[] = { + 0x1c, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 'M', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'U', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'S', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'B', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'R', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 't', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'u', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'b', /* __u8 Unicode */ + 0, /* __u8 Unicode */ +}; +#endif + /* * This function writes the data toggle value. */ @@ -402,14 +502,335 @@ static void config_hub_port(struct usb_device *dev, u8 ep) if (dev->parent->children[chid] == dev) break; +#ifndef MUSB_NO_MULTIPOINT /* configure the hub address and the port address */ writeb(hub, &musbr->tar[ep].txhubaddr); writeb((chid + 1), &musbr->tar[ep].txhubport); writeb(hub, &musbr->tar[ep].rxhubaddr); writeb((chid + 1), &musbr->tar[ep].rxhubport); +#endif +} + +#ifdef MUSB_NO_MULTIPOINT + +static void musb_port_reset(int do_reset) +{ + u8 power = readb(&musbr->power); + + if (do_reset) { + power &= 0xf0; + writeb(power | MUSB_POWER_RESET, &musbr->power); + port_status |= USB_PORT_STAT_RESET; + port_status &= ~USB_PORT_STAT_ENABLE; + udelay(30000); + } else { + writeb(power & ~MUSB_POWER_RESET, &musbr->power); + + power = readb(&musbr->power); + if (power & MUSB_POWER_HSMODE) + port_status |= USB_PORT_STAT_HIGH_SPEED; + + port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16)); + port_status |= USB_PORT_STAT_ENABLE + | (USB_PORT_STAT_C_RESET << 16) + | (USB_PORT_STAT_C_ENABLE << 16); + } } /* + * root hub control + */ +static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, + struct devrequest *cmd) +{ + int leni = transfer_len; + int len = 0; + int stat = 0; + u32 datab[4]; + u8 *data_buf = (u8 *) datab; + u16 bmRType_bReq; + u16 wValue; + u16 wIndex; + u16 wLength; + u16 int_usb; + + if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { + debug("Root-Hub submit IRQ: NOT implemented\n"); + return 0; + } + + bmRType_bReq = cmd->requesttype | (cmd->request << 8); + wValue = swap_16(cmd->value); + wIndex = swap_16(cmd->index); + wLength = swap_16(cmd->length); + + debug("--- HUB ----------------------------------------\n"); + debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n", + bmRType_bReq, wValue, wIndex, wLength); + debug("------------------------------------------------\n"); + + switch (bmRType_bReq) { + case RH_GET_STATUS: + debug("RH_GET_STATUS\n"); + + *(__u16 *) data_buf = swap_16(1); + len = 2; + break; + + case RH_GET_STATUS | RH_INTERFACE: + debug("RH_GET_STATUS | RH_INTERFACE\n"); + + *(__u16 *) data_buf = swap_16(0); + len = 2; + break; + + case RH_GET_STATUS | RH_ENDPOINT: + debug("RH_GET_STATUS | RH_ENDPOINT\n"); + + *(__u16 *) data_buf = swap_16(0); + len = 2; + break; + + case RH_GET_STATUS | RH_CLASS: + debug("RH_GET_STATUS | RH_CLASS\n"); + + *(__u32 *) data_buf = swap_32(0); + len = 4; + break; + + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n"); + + int_usb = readw(&musbr->intrusb); + if (int_usb & MUSB_INTR_CONNECT) { + port_status |= USB_PORT_STAT_CONNECTION + | (USB_PORT_STAT_C_CONNECTION << 16); + port_status |= USB_PORT_STAT_HIGH_SPEED + | USB_PORT_STAT_ENABLE; + } + + if (port_status & USB_PORT_STAT_RESET) + musb_port_reset(0); + + *(__u32 *) data_buf = swap_32(port_status); + len = 4; + break; + + case RH_CLEAR_FEATURE | RH_ENDPOINT: + debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n"); + + switch (wValue) { + case RH_ENDPOINT_STALL: + debug("C_HUB_ENDPOINT_STALL\n"); + len = 0; + break; + } + port_status &= ~(1 << wValue); + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + debug("RH_CLEAR_FEATURE | RH_CLASS\n"); + + switch (wValue) { + case RH_C_HUB_LOCAL_POWER: + debug("C_HUB_LOCAL_POWER\n"); + len = 0; + break; + + case RH_C_HUB_OVER_CURRENT: + debug("C_HUB_OVER_CURRENT\n"); + len = 0; + break; + } + port_status &= ~(1 << wValue); + break; + + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n"); + + switch (wValue) { + case RH_PORT_ENABLE: + len = 0; + break; + + case RH_PORT_SUSPEND: + len = 0; + break; + + case RH_PORT_POWER: + len = 0; + break; + + case RH_C_PORT_CONNECTION: + len = 0; + break; + + case RH_C_PORT_ENABLE: + len = 0; + break; + + case RH_C_PORT_SUSPEND: + len = 0; + break; + + case RH_C_PORT_OVER_CURRENT: + len = 0; + break; + + case RH_C_PORT_RESET: + len = 0; + break; + + default: + debug("invalid wValue\n"); + stat = USB_ST_STALLED; + } + + port_status &= ~(1 << wValue); + break; + + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n"); + + switch (wValue) { + case RH_PORT_SUSPEND: + len = 0; + break; + + case RH_PORT_RESET: + musb_port_reset(1); + len = 0; + break; + + case RH_PORT_POWER: + len = 0; + break; + + case RH_PORT_ENABLE: + len = 0; + break; + + default: + debug("invalid wValue\n"); + stat = USB_ST_STALLED; + } + + port_status |= 1 << wValue; + break; + + case RH_SET_ADDRESS: + debug("RH_SET_ADDRESS\n"); + + rh_devnum = wValue; + len = 0; + break; + + case RH_GET_DESCRIPTOR: + debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength); + + switch (wValue) { + case (USB_DT_DEVICE << 8): /* device descriptor */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_dev_des), + wLength)); + data_buf = root_hub_dev_des; + break; + + case (USB_DT_CONFIG << 8): /* configuration descriptor */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_config_des), + wLength)); + data_buf = root_hub_config_des; + break; + + case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_str_index0), + wLength)); + data_buf = root_hub_str_index0; + break; + + case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_str_index1), + wLength)); + data_buf = root_hub_str_index1; + break; + + default: + debug("invalid wValue\n"); + stat = USB_ST_STALLED; + } + + break; + + case RH_GET_DESCRIPTOR | RH_CLASS: + debug("RH_GET_DESCRIPTOR | RH_CLASS\n"); + + data_buf[0] = 0x09; /* min length; */ + data_buf[1] = 0x29; + data_buf[2] = 0x1; /* 1 port */ + data_buf[3] = 0x01; /* per-port power switching */ + data_buf[3] |= 0x10; /* no overcurrent reporting */ + + /* Corresponds to data_buf[4-7] */ + data_buf[4] = 0; + data_buf[5] = 5; + data_buf[6] = 0; + data_buf[7] = 0x02; + data_buf[8] = 0xff; + + len = min_t(unsigned int, leni, + min_t(unsigned int, data_buf[0], wLength)); + break; + + case RH_GET_CONFIGURATION: + debug("RH_GET_CONFIGURATION\n"); + + *(__u8 *) data_buf = 0x01; + len = 1; + break; + + case RH_SET_CONFIGURATION: + debug("RH_SET_CONFIGURATION\n"); + + len = 0; + break; + + default: + debug("*** *** *** unsupported root hub command *** *** ***\n"); + stat = USB_ST_STALLED; + } + + len = min_t(int, len, leni); + if (buffer != data_buf) + memcpy(buffer, data_buf, len); + + dev->act_len = len; + dev->status = stat; + debug("dev act_len %d, status %d\n", dev->act_len, dev->status); + + return stat; +} + +static void musb_rh_init(void) +{ + rh_devnum = 0; + port_status = 0; +} + +#else + +static void musb_rh_init(void) {} + +#endif + +/* * do a control transfer */ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, @@ -419,13 +840,21 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, u16 csr; u8 devspeed; +#ifdef MUSB_NO_MULTIPOINT + /* Control message is for the HUB? */ + if (devnum == rh_devnum) + return musb_submit_rh_msg(dev, pipe, buffer, len, setup); +#endif + /* select control endpoint */ writeb(MUSB_CONTROL_EP, &musbr->index); csr = readw(&musbr->txcsr); +#ifndef MUSB_NO_MULTIPOINT /* target addr and (for multipoint) hub addr/port */ writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr); writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr); +#endif /* configure the hub address and the port number as required */ devspeed = get_dev_speed(dev); @@ -435,10 +864,12 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, writeb(devspeed << 6, &musbr->txtype); } else { writeb(musb_cfg.musb_speed << 6, &musbr->txtype); +#ifndef MUSB_NO_MULTIPOINT writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr); writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport); writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr); writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport); +#endif } /* Control transfer setup phase */ @@ -497,7 +928,9 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, { int dir_out = usb_pipeout(pipe); int ep = usb_pipeendpoint(pipe); +#ifndef MUSB_NO_MULTIPOINT int devnum = usb_pipedevice(pipe); +#endif u8 type; u16 csr; u32 txlen = 0; @@ -507,11 +940,13 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, /* select bulk endpoint */ writeb(MUSB_BULK_EP, &musbr->index); +#ifndef MUSB_NO_MULTIPOINT /* write the address of the device */ if (dir_out) writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr); else writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr); +#endif /* configure the hub address and the port number as required */ devspeed = get_dev_speed(dev); @@ -524,6 +959,7 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, */ config_hub_port(dev, MUSB_BULK_EP); } else { +#ifndef MUSB_NO_MULTIPOINT if (dir_out) { writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr); writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport); @@ -531,6 +967,7 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr); writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport); } +#endif devspeed = musb_cfg.musb_speed; } @@ -590,7 +1027,8 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, (len-txlen) : dev->epmaxpacketin[ep]; /* Set the ReqPkt bit */ - writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); + csr = readw(&musbr->rxcsr); + writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); /* Wait until the RxPktRdy bit is set */ if (!wait_until_rxep_ready(dev, MUSB_BULK_EP)) { @@ -634,6 +1072,8 @@ int usb_lowlevel_init(void) u8 power; u32 timeout; + musb_rh_init(); + if (musb_platform_init() == -1) return -1; @@ -696,7 +1136,9 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, { int dir_out = usb_pipeout(pipe); int ep = usb_pipeendpoint(pipe); +#ifndef MUSB_NO_MULTIPOINT int devnum = usb_pipedevice(pipe); +#endif u8 type; u16 csr; u32 txlen = 0; @@ -706,11 +1148,13 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, /* select interrupt endpoint */ writeb(MUSB_INTR_EP, &musbr->index); +#ifndef MUSB_NO_MULTIPOINT /* write the address of the device */ if (dir_out) writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr); else writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr); +#endif /* configure the hub address and the port number as required */ devspeed = get_dev_speed(dev); @@ -723,6 +1167,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, */ config_hub_port(dev, MUSB_INTR_EP); } else { +#ifndef MUSB_NO_MULTIPOINT if (dir_out) { writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr); writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport); @@ -730,6 +1175,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr); writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport); } +#endif devspeed = musb_cfg.musb_speed; } @@ -755,7 +1201,8 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, (len-txlen) : dev->epmaxpacketin[ep]; /* Set the ReqPkt bit */ - writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); + csr = readw(&musbr->rxcsr); + writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); /* Wait until the RxPktRdy bit is set */ if (!wait_until_rxep_ready(dev, MUSB_INTR_EP)) { diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h index 17e9091..dde7d37 100644 --- a/drivers/usb/musb/musb_hcd.h +++ b/drivers/usb/musb/musb_hcd.h @@ -38,7 +38,9 @@ extern unsigned char new[]; #define MUSB_CONTROL_EP 0 /* This defines the endpoint number used for bulk transfer */ -#define MUSB_BULK_EP 1 +#ifndef MUSB_BULK_EP +# define MUSB_BULK_EP 1 +#endif /* This defines the endpoint number used for interrupt transfer */ #define MUSB_INTR_EP 2 @@ -48,6 +50,61 @@ extern unsigned char new[]; ((readb(&musbr->power) & MUSB_POWER_HSMODE) \ >> MUSB_POWER_HSMODE_SHIFT) +#define min_t(type, x, y) \ + ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) + +/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ + +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 + +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + /* extern functions */ extern int musb_platform_init(void); extern void musb_platform_deinit(void); diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c index ea98c3c..3bfd0a0 100644 --- a/drivers/usb/musb/omap3.c +++ b/drivers/usb/musb/omap3.c @@ -123,7 +123,10 @@ int musb_platform_init(void) } ret = platform_needs_initialization; + +#ifdef CONFIG_TWL4030_USB end: +#endif return ret; } |