diff options
| -rw-r--r-- | drivers/serial/usbtty.h | 2 | ||||
| -rw-r--r-- | drivers/usb/musb/Makefile | 2 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_core.c | 8 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_core.h | 40 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_debug.h | 205 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_udc.c | 963 | ||||
| -rw-r--r-- | drivers/usb/musb/omap3.c | 129 | ||||
| -rw-r--r-- | drivers/usb/musb/omap3.h | 48 | ||||
| -rw-r--r-- | include/usb.h | 3 | ||||
| -rw-r--r-- | include/usb/musb_udc.h | 54 | 
10 files changed, 1451 insertions, 3 deletions
| diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h index f746d6317..6b6c4a162 100644 --- a/drivers/serial/usbtty.h +++ b/drivers/serial/usbtty.h @@ -29,6 +29,8 @@  #include <usb/mpc8xx_udc.h>  #elif defined(CONFIG_OMAP1510)  #include <usb/omap1510_udc.h> +#elif defined(CONFIG_MUSB_UDC) +#include <usb/musb_udc.h>  #elif defined(CONFIG_PXA27X)  #include <usb/pxa27x_udc.h>  #endif diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 09e0a5f32..f2ccd9fe0 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -26,7 +26,9 @@ include $(TOPDIR)/config.mk  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_DAVINCI) += davinci.o +COBJS-$(CONFIG_USB_OMAP3) += omap3.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ec57fc811..22f3dba0c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -32,7 +32,9 @@ struct musb_regs *musbr;   */  void musb_start(void)  { +#if defined(CONFIG_MUSB_HCD)  	u8 devctl; +#endif  	/* disable all interrupts */  	writew(0, &musbr->intrtxe); @@ -74,9 +76,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)  			/* Configure fifo size and fifo base address */  			writeb(idx, &musbr->txfifosz);  			writew(fifoaddr >> 3, &musbr->txfifoadd); + +			csr = readw(&musbr->txcsr);  #if defined(CONFIG_MUSB_HCD)  			/* clear the data toggle bit */ -			csr = readw(&musbr->txcsr);  			writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);  #endif  			/* Flush fifo if required */ @@ -87,9 +90,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)  			/* Configure fifo size and fifo base address */  			writeb(idx, &musbr->rxfifosz);  			writew(fifoaddr >> 3, &musbr->rxfifoadd); + +			csr = readw(&musbr->rxcsr);  #if defined(CONFIG_MUSB_HCD)  			/* clear the data toggle bit */ -			csr = readw(&musbr->rxcsr);  			writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);  #endif  			/* Flush fifo if required */ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index f9da3f0b2..15c7f49a3 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -40,6 +40,36 @@  #define MUSB_EP0_FIFOSIZE	64	/* This is non-configurable */ +/* EP0 */ +struct musb_ep0_regs { +	u16	reserved4; +	u16	csr0; +	u16	reserved5; +	u16	reserved6; +	u16	count0; +	u8	host_type0; +	u8	host_naklimit0; +	u8	reserved7; +	u8	reserved8; +	u8	reserved9; +	u8	configdata; +}; + +/* EP 1-15 */ +struct musb_epN_regs { +	u16	txmaxp; +	u16	txcsr; +	u16	rxmaxp; +	u16	rxcsr; +	u16	rxcount; +	u8	txtype; +	u8	txinterval; +	u8	rxtype; +	u8	rxinterval; +	u8	reserved0; +	u8	fifosize; +}; +  /* Mentor USB core register overlay structure */  struct musb_regs {  	/* common registers */ @@ -97,6 +127,16 @@ struct musb_regs {  		u8	rxhubaddr;  		u8	rxhubport;  	} tar[16]; +	/* +	 * end point registers +	 * ep0 elements are valid when array index is 0 +	 * otherwise epN is valid +	 */ +	union musb_ep_regs { +		struct musb_ep0_regs ep0; +		struct musb_epN_regs epN; +	} ep[16]; +  } __attribute__((aligned(32)));  /* diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h new file mode 100644 index 000000000..62380ffc6 --- /dev/null +++ b/drivers/usb/musb/musb_debug.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * 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 + */ + +/* Define MUSB_DEBUG before including this file to get debug macros */ +#ifdef MUSB_DEBUG + +#define MUSB_FLAGS_PRINT(v, x, y)		\ +  if (((v) & MUSB_##x##_##y))			\ +		serial_printf("\t\t"#y"\n") + +static inline void musb_print_pwr(u8 b) +{ +	serial_printf("\tpower   0x%2.2x\n", b); +	MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE); +	MUSB_FLAGS_PRINT(b, POWER, SOFTCONN); +	MUSB_FLAGS_PRINT(b, POWER, HSENAB); +	MUSB_FLAGS_PRINT(b, POWER, HSMODE); +	MUSB_FLAGS_PRINT(b, POWER, RESET); +	MUSB_FLAGS_PRINT(b, POWER, RESUME); +	MUSB_FLAGS_PRINT(b, POWER, SUSPENDM); +	MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND); +} + +static inline void musb_print_csr0(u16 w) +{ +	serial_printf("\tcsr0    0x%4.4x\n", w); +	MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO); +	MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND); +	MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY); +	MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL); +	MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND); +	MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND); +	MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL); +	MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY); +	MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY); +} + +static inline void musb_print_intrusb(u8 b) +{ +	serial_printf("\tintrusb 0x%2.2x\n", b); +	MUSB_FLAGS_PRINT(b, INTR, VBUSERROR); +	MUSB_FLAGS_PRINT(b, INTR, SESSREQ); +	MUSB_FLAGS_PRINT(b, INTR, DISCONNECT); +	MUSB_FLAGS_PRINT(b, INTR, CONNECT); +	MUSB_FLAGS_PRINT(b, INTR, SOF); +	MUSB_FLAGS_PRINT(b, INTR, RESUME); +	MUSB_FLAGS_PRINT(b, INTR, SUSPEND); + +	if (b & MUSB_INTR_BABBLE) +		serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n"); + +} + +static inline void musb_print_intrtx(u16 w) +{ +	serial_printf("\tintrtx 0x%4.4x\n", w); +} + +static inline void musb_print_intrrx(u16 w) +{ +	serial_printf("\tintrx 0x%4.4x\n", w); +} + +static inline void musb_print_devctl(u8 b) +{ +	serial_printf("\tdevctl  0x%2.2x\n", b); +	if (b & MUSB_DEVCTL_BDEVICE) +		serial_printf("\t\tB device\n"); +	else +		serial_printf("\t\tA device\n"); +	if (b & MUSB_DEVCTL_FSDEV) +		serial_printf("\t\tFast Device -(host mode)\n"); +	if (b & MUSB_DEVCTL_LSDEV) +		serial_printf("\t\tSlow Device -(host mode)\n"); +	if (b & MUSB_DEVCTL_HM) +		serial_printf("\t\tHost mode\n"); +	else +		serial_printf("\t\tPeripherial mode\n"); +	if (b & MUSB_DEVCTL_HR) +		serial_printf("\t\tHost request started(B device)\n"); +	else +		serial_printf("\t\tHost request finished(B device)\n"); +	if (b & MUSB_DEVCTL_BDEVICE) { +		if (b & MUSB_DEVCTL_SESSION) +			serial_printf("\t\tStart of session(B device)\n"); +		else +			serial_printf("\t\tEnd of session(B device)\n"); +	} else { +		if (b & MUSB_DEVCTL_SESSION) +			serial_printf("\t\tStart of session(A device)\n"); +		else +			serial_printf("\t\tEnd of session(A device)\n"); +	} +} + +static inline void musb_print_config(u8 b) +{ +	serial_printf("\tconfig 0x%2.2x\n", b); +	if (b & MUSB_CONFIGDATA_MPRXE) +		serial_printf("\t\tAuto combine rx bulk packets\n"); +	if (b & MUSB_CONFIGDATA_MPTXE) +		serial_printf("\t\tAuto split tx bulk packets\n"); +	if (b & MUSB_CONFIGDATA_BIGENDIAN) +		serial_printf("\t\tBig Endian ordering\n"); +	else +		serial_printf("\t\tLittle Endian ordering\n"); +	if (b & MUSB_CONFIGDATA_HBRXE) +		serial_printf("\t\tHigh speed rx iso endpoint\n"); +	if (b & MUSB_CONFIGDATA_HBTXE) +		serial_printf("\t\tHigh speed tx iso endpoint\n"); +	if (b & MUSB_CONFIGDATA_DYNFIFO) +		serial_printf("\t\tDynamic fifo sizing\n"); +	if (b & MUSB_CONFIGDATA_SOFTCONE) +		serial_printf("\t\tSoft Connect\n"); +	if (b & MUSB_CONFIGDATA_UTMIDW) +		serial_printf("\t\t16 bit data width\n"); +	else +		serial_printf("\t\t8 bit data width\n"); +} + +static inline void musb_print_rxmaxp(u16 w) +{ +	serial_printf("\trxmaxp  0x%4.4x\n", w); +} + +static inline void musb_print_rxcsr(u16 w) +{ +	serial_printf("\trxcsr   0x%4.4x\n", w); +	MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR); +	MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB); +	MUSB_FLAGS_PRINT(w, RXCSR, DISNYET); +	MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR); +	MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE); +	MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG); +	MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO); +	MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR); +	MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL); +	MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY); +	MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL); +	MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL); +	MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN); + +	if (w & MUSB_RXCSR_P_ISO) +		serial_printf("\t\tiso mode\n"); +	else +		serial_printf("\t\tbulk mode\n"); + +} + +static inline void musb_print_txmaxp(u16 w) +{ +	serial_printf("\ttxmaxp  0x%4.4x\n", w); +} + +static inline void musb_print_txcsr(u16 w) +{ +	serial_printf("\ttxcsr   0x%4.4x\n", w); +	MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY); +	MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY); +	MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO); +	MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG); +	MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN); +	MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL); +	MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL); + +	if (w & MUSB_TXCSR_MODE) +		serial_printf("\t\tTX mode\n"); +	else +		serial_printf("\t\tRX mode\n"); +} + +#else + +/* stubs */ + +#define musb_print_pwr(b) +#define musb_print_csr0(w) +#define musb_print_intrusb(b) +#define musb_print_intrtx(w) +#define musb_print_intrrx(w) +#define musb_print_devctl(b) +#define musb_print_config(b) +#define musb_print_rxmaxp(w) +#define musb_print_rxcsr(w) +#define musb_print_txmaxp(w) +#define musb_print_txcsr(w) + +#endif /* MUSB_DEBUG */ diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c new file mode 100644 index 000000000..fc43cf4f0 --- /dev/null +++ b/drivers/usb/musb/musb_udc.c @@ -0,0 +1,963 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * This file is a rewrite of the usb device part of + * repository git.omapzoom.org/repo/u-boot.git, branch master, + * file cpu/omap3/fastboot.c + * + * This is the unique part of its copyright : + * + * ------------------------------------------------------------------------- + * + * (C) Copyright 2008 - 2009 + * Windriver, <www.windriver.com> + * Tom Rix <Tom.Rix@windriver.com> + * + * ------------------------------------------------------------------------- + * + * The details of connecting the device to the uboot usb device subsystem + * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git, + * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c + * + * This is the unique part of its copyright : + * + * ------------------------------------------------------------------------- + * + * (C) Copyright 2008 Texas Instruments Incorporated. + * + * Based on + * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c) + * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c) + * + * Author: Diego Dompe (diego.dompe@ridgerun.com) + *         Atin Malaviya (atin.malaviya@gmail.com) + * + * ------------------------------------------------------------------------- + * + * 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/musb_udc.h> +#include "../gadget/ep0.h" +#include "musb_core.h" +#if defined(CONFIG_USB_OMAP3) +#include "omap3.h" +#elif defined(CONFIG_USB_DAVINCI) +#include "davinci.h" +#endif + +/* Define MUSB_DEBUG for debugging */ +/* #define MUSB_DEBUG */ +#include "musb_debug.h" + +#define MAX_ENDPOINT 15 + +#define GET_ENDPOINT(dev,ep)						\ +(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep) + +#define SET_EP0_STATE(s)						\ +do {									\ +	if ((0 <= (s)) && (SET_ADDRESS >= (s))) {			\ +		if ((s) != ep0_state) {					\ +			if ((debug_setup) && (debug_level > 1))		\ +				serial_printf("INFO : Changing state "  \ +					      "from %s to %s in %s at " \ +					      "line %d\n",		\ +					      ep0_state_strings[ep0_state],\ +					      ep0_state_strings[s],	\ +					      __PRETTY_FUNCTION__,	\ +					      __LINE__);		\ +			ep0_state = s;					\ +		}							\ +	} else {							\ +		if (debug_level > 0)					\ +			serial_printf("Error at %s %d with setting "	\ +				      "state %d is invalid\n",		\ +				      __PRETTY_FUNCTION__, __LINE__, s); \ +	}								\ +} while (0) + +/* static implies these initialized to 0 or NULL */ +static int debug_setup; +static int debug_level; +static struct musb_epinfo epinfo[MAX_ENDPOINT * 2]; +static enum ep0_state_enum { +	IDLE = 0, +	TX, +	RX, +	SET_ADDRESS +} ep0_state = IDLE; +static char *ep0_state_strings[4] = { +	"IDLE", +	"TX", +	"RX", +	"SET_ADDRESS", +}; + +static struct urb *ep0_urb; +struct usb_endpoint_instance *ep0_endpoint; +static struct usb_device_instance *udc_device; +static int enabled; + +#ifdef MUSB_DEBUG +static void musb_db_regs(void) +{ +	u8 b; +	u16 w; + +	b = readb(&musbr->faddr); +	serial_printf("\tfaddr   0x%2.2x\n", b); + +	b = readb(&musbr->power); +	musb_print_pwr(b); + +	w = readw(&musbr->ep[0].ep0.csr0); +	musb_print_csr0(w); + +	b = readb(&musbr->devctl); +	musb_print_devctl(b); + +	b = readb(&musbr->ep[0].ep0.configdata); +	musb_print_config(b); + +	w = readw(&musbr->frame); +	serial_printf("\tframe   0x%4.4x\n", w); + +	b = readb(&musbr->index); +	serial_printf("\tindex   0x%2.2x\n", b); + +	w = readw(&musbr->ep[1].epN.rxmaxp); +	musb_print_rxmaxp(w); + +	w = readw(&musbr->ep[1].epN.rxcsr); +	musb_print_rxcsr(w); + +	w = readw(&musbr->ep[1].epN.txmaxp); +	musb_print_txmaxp(w); + +	w = readw(&musbr->ep[1].epN.txcsr); +	musb_print_txcsr(w); +} +#else +#define musb_db_regs() +#endif /* DEBUG_MUSB */ + +static void musb_peri_softconnect(void) +{ +	u8 power, devctl; +	u8 intrusb; +	u16 intrrx, intrtx; + +	/* Power off MUSB */ +	power = readb(&musbr->power); +	power &= ~MUSB_POWER_SOFTCONN; +	writeb(power, &musbr->power); + +	/* Read intr to clear */ +	intrusb = readb(&musbr->intrusb); +	intrrx = readw(&musbr->intrrx); +	intrtx = readw(&musbr->intrtx); + +	udelay(1000 * 1000); /* 1 sec */ + +	/* Power on MUSB */ +	power = readb(&musbr->power); +	power |= MUSB_POWER_SOFTCONN; +	/* +	 * The usb device interface is usb 1.1 +	 * Disable 2.0 high speed by clearring the hsenable bit. +	 */ +	power &= ~MUSB_POWER_HSENAB; +	writeb(power, &musbr->power); + +	/* Check if device is in b-peripheral mode */ +	devctl = readb(&musbr->devctl); +	if (!(devctl & MUSB_DEVCTL_BDEVICE) || +	    (devctl & MUSB_DEVCTL_HM)) { +		serial_printf("ERROR : Unsupport USB mode\n"); +		serial_printf("Check that mini-B USB cable is attached " +			      "to the device\n"); +	} + +	if (debug_setup && (debug_level > 1)) +		musb_db_regs(); +} + +static void musb_peri_reset(void) +{ +	if ((debug_setup) && (debug_level > 1)) +		serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__); + +	if (ep0_endpoint) +		ep0_endpoint->endpoint_address = 0xff; + +	/* Sync sw and hw addresses */ +	writeb(udc_device->address, &musbr->faddr); + +	SET_EP0_STATE(IDLE); +} + +static void musb_peri_resume(void) +{ +	/* noop */ +} + +static void musb_peri_ep0_stall(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= MUSB_CSR0_P_SENDSTALL; +	writew(csr0, &musbr->ep[0].ep0.csr0); +	if ((debug_setup) && (debug_level > 1)) +		serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__); +} + +static void musb_peri_ep0_ack_req(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= MUSB_CSR0_P_SVDRXPKTRDY; +	writew(csr0, &musbr->ep[0].ep0.csr0); +} + +static void musb_ep0_tx_ready(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= MUSB_CSR0_TXPKTRDY; +	writew(csr0, &musbr->ep[0].ep0.csr0); +} + +static void musb_ep0_tx_ready_and_last(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND); +	writew(csr0, &musbr->ep[0].ep0.csr0); +} + +static void musb_peri_ep0_last(void) +{ +	u16 csr0; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	csr0 |= MUSB_CSR0_P_DATAEND; +	writew(csr0, &musbr->ep[0].ep0.csr0); +} + +static void musb_peri_ep0_set_address(void) +{ +	u8 faddr; +	writeb(udc_device->address, &musbr->faddr); + +	/* Verify */ +	faddr = readb(&musbr->faddr); +	if (udc_device->address == faddr) { +		SET_EP0_STATE(IDLE); +		usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); +		if ((debug_setup) && (debug_level > 1)) +			serial_printf("INFO : %s Address set to %d\n", +				      __PRETTY_FUNCTION__, udc_device->address); +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s Address missmatch " +				      "sw %d vs hw %d\n", +				      __PRETTY_FUNCTION__, +				      udc_device->address, faddr); +	} +} + +static void musb_peri_rx_ack(unsigned int ep) +{ +	u16 peri_rxcsr; + +	peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr); +	peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY; +	writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr); +} + +static void musb_peri_tx_ready(unsigned int ep) +{ +	u16 peri_txcsr; + +	peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); +	peri_txcsr |= MUSB_TXCSR_TXPKTRDY; +	writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); +} + +static void musb_peri_ep0_zero_data_request(int err) +{ +	musb_peri_ep0_ack_req(); + +	if (err) { +		musb_peri_ep0_stall(); +		SET_EP0_STATE(IDLE); +	} else { + +		musb_peri_ep0_last(); + +		/* USBD state */ +		switch (ep0_urb->device_request.bRequest) { +		case USB_REQ_SET_ADDRESS: +			if ((debug_setup) && (debug_level > 1)) +				serial_printf("INFO : %s received set " +					      "address\n", __PRETTY_FUNCTION__); +			break; + +		case USB_REQ_SET_CONFIGURATION: +			if ((debug_setup) && (debug_level > 1)) +				serial_printf("INFO : %s Configured\n", +					      __PRETTY_FUNCTION__); +			usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); +			break; +		} + +		/* EP0 state */ +		if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) { +			SET_EP0_STATE(SET_ADDRESS); +		} else { +			SET_EP0_STATE(IDLE); +		} +	} +} + +static void musb_peri_ep0_rx_data_request(void) +{ +	/* +	 * This is the completion of the data OUT / RX +	 * +	 * Host is sending data to ep0 that is not +	 * part of setup.  This comes from the cdc_recv_setup +	 * op that is device specific. +	 * +	 */ +	musb_peri_ep0_ack_req(); + +	ep0_endpoint->rcv_urb = ep0_urb; +	ep0_urb->actual_length = 0; +	SET_EP0_STATE(RX); +} + +static void musb_peri_ep0_tx_data_request(int err) +{ +	if (err) { +		musb_peri_ep0_stall(); +		SET_EP0_STATE(IDLE); +	} else { +		musb_peri_ep0_ack_req(); + +		ep0_endpoint->tx_urb = ep0_urb; +		ep0_endpoint->sent = 0; +		SET_EP0_STATE(TX); +	} +} + +static void musb_peri_ep0_idle(void) +{ +	u16 count0; +	int err; +	u16 csr0; + +	/* +	 * Verify addresses +	 * A lot of confusion can be caused if the address +	 * in software, udc layer, does not agree with the +	 * hardware.  Since the setting of the hardware address +	 * must be set after the set address request, the +	 * usb state machine is out of sync for a few frame. +	 * It is a good idea to run this check when changes +	 * are made to the state machine. +	 */ +	if ((debug_level > 0) && +	    (ep0_state != SET_ADDRESS)) { +		u8 faddr; + +		faddr = readb(&musbr->faddr); +		if (udc_device->address != faddr) { +			serial_printf("ERROR : %s addresses do not" +				      "match sw %d vs hw %d\n", +				      __PRETTY_FUNCTION__, +				      udc_device->address, faddr); +			udelay(1000 * 1000); +			hang(); +		} +	} + +	csr0 = readw(&musbr->ep[0].ep0.csr0); + +	if (!(MUSB_CSR0_RXPKTRDY & csr0)) +		goto end; + +	count0 = readw(&musbr->ep[0].ep0.count0); +	if (count0 == 0) +		goto end; + +	if (count0 != 8) { +		if ((debug_setup) && (debug_level > 1)) +			serial_printf("WARN : %s SETUP incorrect size %d\n", +				      __PRETTY_FUNCTION__, count0); +		musb_peri_ep0_stall(); +		goto end; +	} + +	read_fifo(0, count0, &ep0_urb->device_request); + +	if (debug_level > 2) +		print_usb_device_request(&ep0_urb->device_request); + +	if (ep0_urb->device_request.wLength == 0) { +		err = ep0_recv_setup(ep0_urb); + +		/* Zero data request */ +		musb_peri_ep0_zero_data_request(err); +	} else { +		/* Is data coming or going ? */ +		u8 reqType = ep0_urb->device_request.bmRequestType; + +		if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) { +			err = ep0_recv_setup(ep0_urb); +			/* Device to host */ +			musb_peri_ep0_tx_data_request(err); +		} else { +			/* +			 * Host to device +			 * +			 * The RX routine will call ep0_recv_setup +			 * when the data packet has arrived. +			 */ +			musb_peri_ep0_rx_data_request(); +		} +	} + +end: +	return; +} + +static void musb_peri_ep0_rx(void) +{ +	/* +	 * This is the completion of the data OUT / RX +	 * +	 * Host is sending data to ep0 that is not +	 * part of setup.  This comes from the cdc_recv_setup +	 * op that is device specific. +	 * +	 * Pass the data back to driver ep0_recv_setup which +	 * should give the cdc_recv_setup the chance to handle +	 * the rx +	 */ +	u16 csr0; +	u16 count0; + +	if (debug_level > 3) { +		if (0 != ep0_urb->actual_length) { +			serial_printf("%s finished ? %d of %d\n", +				      __PRETTY_FUNCTION__, +				      ep0_urb->actual_length, +				      ep0_urb->device_request.wLength); +		} +	} + +	if (ep0_urb->device_request.wLength == ep0_urb->actual_length) { +		musb_peri_ep0_last(); +		SET_EP0_STATE(IDLE); +		ep0_recv_setup(ep0_urb); +		return; +	} + +	csr0 = readw(&musbr->ep[0].ep0.csr0); +	if (!(MUSB_CSR0_RXPKTRDY & csr0)) +		return; + +	count0 = readw(&musbr->ep[0].ep0.count0); + +	if (count0) { +		struct usb_endpoint_instance *endpoint; +		u32 length; +		u8 *data; + +		endpoint = ep0_endpoint; +		if (endpoint && endpoint->rcv_urb) { +			struct urb *urb = endpoint->rcv_urb; +			unsigned int remaining_space = urb->buffer_length - +				urb->actual_length; + +			if (remaining_space) { +				int urb_bad = 0; /* urb is good */ + +				if (count0 > remaining_space) +					length = remaining_space; +				else +					length = count0; + +				data = (u8 *) urb->buffer_data; +				data += urb->actual_length; + +				/* The common musb fifo reader */ +				read_fifo(0, length, data); + +				musb_peri_ep0_ack_req(); + +				/* +				 * urb's actual_length is updated in +				 * usbd_rcv_complete +				 */ +				usbd_rcv_complete(endpoint, length, urb_bad); + +			} else { +				if (debug_level > 0) +					serial_printf("ERROR : %s no space in " +						      "rcv buffer\n", +						      __PRETTY_FUNCTION__); +			} +		} else { +			if (debug_level > 0) +				serial_printf("ERROR : %s problem with " +					      "endpoint\n", +					      __PRETTY_FUNCTION__); +		} +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s with nothing to do\n", +				      __PRETTY_FUNCTION__); +	} +} + +static void musb_peri_ep0_tx(void) +{ +	u16 csr0; +	int transfer_size = 0; +	unsigned int p, pm; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); + +	/* Check for pending tx */ +	if (csr0 & MUSB_CSR0_TXPKTRDY) +		goto end; + +	/* Check if this is the last packet sent */ +	if (ep0_endpoint->sent >= ep0_urb->actual_length) { +		SET_EP0_STATE(IDLE); +		goto end; +	} + +	transfer_size = ep0_urb->actual_length - ep0_endpoint->sent; +	/* Is the transfer size negative ? */ +	if (transfer_size <= 0) { +		if (debug_level > 0) +			serial_printf("ERROR : %s problem with the" +				      " transfer size %d\n", +				      __PRETTY_FUNCTION__, +				      transfer_size); +		SET_EP0_STATE(IDLE); +		goto end; +	} + +	/* Truncate large transfers to the fifo size */ +	if (transfer_size > ep0_endpoint->tx_packetSize) +		transfer_size = ep0_endpoint->tx_packetSize; + +	write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]); +	ep0_endpoint->sent += transfer_size; + +	/* Done or more to send ? */ +	if (ep0_endpoint->sent >= ep0_urb->actual_length) +		musb_ep0_tx_ready_and_last(); +	else +		musb_ep0_tx_ready(); + +	/* Wait a bit */ +	pm = 10; +	for (p = 0; p < pm; p++) { +		csr0 = readw(&musbr->ep[0].ep0.csr0); +		if (!(csr0 & MUSB_CSR0_TXPKTRDY)) +			break; + +		/* Double the delay. */ +		udelay(1 << pm); +	} + +	if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm)) +		SET_EP0_STATE(IDLE); + +end: +	return; +} + +static void musb_peri_ep0(void) +{ +	u16 csr0; + +	if (SET_ADDRESS == ep0_state) +		return; + +	csr0 = readw(&musbr->ep[0].ep0.csr0); + +	/* Error conditions */ +	if (MUSB_CSR0_P_SENTSTALL & csr0) { +		csr0 &= ~MUSB_CSR0_P_SENTSTALL; +		writew(csr0, &musbr->ep[0].ep0.csr0); +		SET_EP0_STATE(IDLE); +	} +	if (MUSB_CSR0_P_SETUPEND & csr0) { +		csr0 |= MUSB_CSR0_P_SVDSETUPEND; +		writew(csr0, &musbr->ep[0].ep0.csr0); +		SET_EP0_STATE(IDLE); +		if ((debug_setup) && (debug_level > 1)) +			serial_printf("WARN: %s SETUPEND\n", +				      __PRETTY_FUNCTION__); +	} + +	/* Normal states */ +	if (IDLE == ep0_state) +		musb_peri_ep0_idle(); + +	if (TX == ep0_state) +		musb_peri_ep0_tx(); + +	if (RX == ep0_state) +		musb_peri_ep0_rx(); +} + +static void musb_peri_rx_ep(unsigned int ep) +{ +	u16 peri_rxcount = readw(&musbr->ep[ep].epN.rxcount); + +	if (peri_rxcount) { +		struct usb_endpoint_instance *endpoint; +		u32 length; +		u8 *data; + +		endpoint = GET_ENDPOINT(udc_device, ep); +		if (endpoint && endpoint->rcv_urb) { +			struct urb *urb = endpoint->rcv_urb; +			unsigned int remaining_space = urb->buffer_length - +				urb->actual_length; + +			if (remaining_space) { +				int urb_bad = 0; /* urb is good */ + +				if (peri_rxcount > remaining_space) +					length = remaining_space; +				else +					length = peri_rxcount; + +				data = (u8 *) urb->buffer_data; +				data += urb->actual_length; + +				/* The common musb fifo reader */ +				read_fifo(ep, length, data); + +				musb_peri_rx_ack(ep); + +				/* +				 * urb's actual_length is updated in +				 * usbd_rcv_complete +				 */ +				usbd_rcv_complete(endpoint, length, urb_bad); + +			} else { +				if (debug_level > 0) +					serial_printf("ERROR : %s %d no space " +						      "in rcv buffer\n", +						      __PRETTY_FUNCTION__, ep); +			} +		} else { +			if (debug_level > 0) +				serial_printf("ERROR : %s %d problem with " +					      "endpoint\n", +					      __PRETTY_FUNCTION__, ep); +		} + +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s %d with nothing to do\n", +				      __PRETTY_FUNCTION__, ep); +	} +} + +static void musb_peri_rx(u16 intr) +{ +	unsigned int ep; + +	/* Check for EP0 */ +	if (0x01 & intr) +		musb_peri_ep0(); + +	for (ep = 1; ep < 16; ep++) { +		if ((1 << ep) & intr) +			musb_peri_rx_ep(ep); +	} +} + +static void musb_peri_tx(u16 intr) +{ +	/* Check for EP0 */ +	if (0x01 & intr) +		musb_peri_ep0_tx(); + +	/* +	 * Use this in the future when handling epN tx +	 * +	 * u8 ep; +	 * +	 * for (ep = 1; ep < 16; ep++) { +	 *	if ((1 << ep) & intr) { +	 *		/ * handle tx for this endpoint * / +	 *	} +	 * } +	 */ +} + +void udc_irq(void) +{ +	/* This is a high freq called function */ +	if (enabled) { +		u8 intrusb; + +		intrusb = readb(&musbr->intrusb); + +		/* +		 * See drivers/usb/gadget/mpc8xx_udc.c for +		 * state diagram going from detached through +		 * configuration. +		 */ +		if (MUSB_INTR_RESUME & intrusb) { +			usbd_device_event_irq(udc_device, +					      DEVICE_BUS_ACTIVITY, 0); +			musb_peri_resume(); +		} + +		musb_peri_ep0(); + +		if (MUSB_INTR_RESET & intrusb) { +			usbd_device_event_irq(udc_device, DEVICE_RESET, 0); +			musb_peri_reset(); +		} + +		if (MUSB_INTR_DISCONNECT & intrusb) { +			/* cable unplugged from hub/host */ +			usbd_device_event_irq(udc_device, DEVICE_RESET, 0); +			musb_peri_reset(); +			usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); +		} + +		if (MUSB_INTR_SOF & intrusb) { +			usbd_device_event_irq(udc_device, +					      DEVICE_BUS_ACTIVITY, 0); +			musb_peri_resume(); +		} + +		if (MUSB_INTR_SUSPEND & intrusb) { +			usbd_device_event_irq(udc_device, +					      DEVICE_BUS_INACTIVE, 0); +		} + +		if (ep0_state != SET_ADDRESS) { +			u16 intrrx, intrtx; + +			intrrx = readw(&musbr->intrrx); +			intrtx = readw(&musbr->intrtx); + +			if (intrrx) +				musb_peri_rx(intrrx); + +			if (intrtx) +				musb_peri_tx(intrtx); +		} else { +			if (MUSB_INTR_SOF & intrusb) { +				u8 faddr; +				faddr = readb(&musbr->faddr); +				/* +				 * Setting of the address can fail. +				 * Normally it succeeds the second time. +				 */ +				if (udc_device->address != faddr) +					musb_peri_ep0_set_address(); +			} +		} +	} +} + +void udc_set_nak(int ep_num) +{ +	/* noop */ +} + +void udc_unset_nak(int ep_num) +{ +	/* noop */ +} + +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) +{ +	int ret = 0; + +	/* Transmit only if the hardware is available */ +	if (endpoint->tx_urb && endpoint->state == 0) { +		unsigned int ep = endpoint->endpoint_address & +			USB_ENDPOINT_NUMBER_MASK; + +		u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); + +		/* Error conditions */ +		if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) { +			peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN; +			writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); +		} + +		if (debug_level > 1) +			musb_print_txcsr(peri_txcsr); + +		/* Check if a packet is waiting to be sent */ +		if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) { +			u32 length; +			u8 *data; +			struct urb *urb = endpoint->tx_urb; +			unsigned int remaining_packet = urb->actual_length - +				endpoint->sent; + +			if (endpoint->tx_packetSize < remaining_packet) +				length = endpoint->tx_packetSize; +			else +				length = remaining_packet; + +			data = (u8 *) urb->buffer; +			data += endpoint->sent; + +			/* common musb fifo function */ +			write_fifo(ep, length, data); + +			musb_peri_tx_ready(ep); + +			endpoint->last = length; +			/* usbd_tx_complete will take care of updating 'sent' */ +			usbd_tx_complete(endpoint); +		} +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s Problem with urb %p " +				      "or ep state %d\n", +				      __PRETTY_FUNCTION__, +				      endpoint->tx_urb, endpoint->state); +	} + +	return ret; +} + +void udc_setup_ep(struct usb_device_instance *device, unsigned int id, +		  struct usb_endpoint_instance *endpoint) +{ +	if (0 == id) { +		/* EP0 */ +		ep0_endpoint = endpoint; +		ep0_endpoint->endpoint_address = 0xff; +		ep0_urb = usbd_alloc_urb(device, endpoint); +	} else if (MAX_ENDPOINT >= id) { +		int ep_addr; + +		/* Check the direction */ +		ep_addr = endpoint->endpoint_address; +		if (USB_DIR_IN == (ep_addr & USB_ENDPOINT_DIR_MASK)) { +			/* IN */ +			epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize; +		} else { +			/* OUT */ +			epinfo[id * 2].epsize = endpoint->rcv_packetSize; +		} + +		musb_configure_ep(&epinfo[0], +				  sizeof(epinfo) / sizeof(struct musb_epinfo)); +	} else { +		if (debug_level > 0) +			serial_printf("ERROR : %s endpoint request %d " +				      "exceeds maximum %d\n", +				      __PRETTY_FUNCTION__, id, MAX_ENDPOINT); +	} +} + +void udc_connect(void) +{ +	/* noop */ +} + +void udc_disconnect(void) +{ +	/* noop */ +} + +void udc_enable(struct usb_device_instance *device) +{ +	/* Save the device structure pointer */ +	udc_device = device; + +	enabled = 1; +} + +void udc_disable(void) +{ +	enabled = 0; +} + +void udc_startup_events(struct usb_device_instance *device) +{ +	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ +	usbd_device_event_irq(device, DEVICE_INIT, 0); + +	/* +	 * The DEVICE_CREATE event puts the USB device in the state +	 * STATE_ATTACHED. +	 */ +	usbd_device_event_irq(device, DEVICE_CREATE, 0); + +	/* Resets the address to 0 */ +	usbd_device_event_irq(device, DEVICE_RESET, 0); + +	udc_enable(device); +} + +int udc_init(void) +{ +	int ret; +	int ep_loop; + +	ret = musb_platform_init(); +	if (ret < 0) +		goto end; + +	/* Configure all the endpoint FIFO's and start usb controller */ +	musbr = musb_cfg.regs; + +	/* Initialize the endpoints */ +	for (ep_loop = 0; ep_loop < MAX_ENDPOINT * 2; ep_loop++) { +		epinfo[ep_loop].epnum = (ep_loop / 2) + 1; +		epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */ +		epinfo[ep_loop].epsize = 0; +	} + +	musb_peri_softconnect(); + +	ret = 0; +end: + +	return ret; +} diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c new file mode 100644 index 000000000..3e502e7d8 --- /dev/null +++ b/drivers/usb/musb/omap3.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * This is file is based on + * repository git.gitorious.org/u-boot-omap3/mainline.git, + * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c + * + * This is the unique part of its copyright : + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2009 Texas Instruments + * + * ------------------------------------------------------------------------ + * + * 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 <twl4030.h> +#include "omap3.h" + +static int platform_needs_initialization = 1; + +struct musb_config musb_cfg = { +	(struct	musb_regs *)MENTOR_USB0_BASE, +	OMAP3_USB_TIMEOUT, +	0 +}; + +/* + * OMAP3 USB OTG registers. + */ +struct omap3_otg_regs { +	u32	revision; +	u32	sysconfig; +	u32	sysstatus; +	u32	interfsel; +	u32	simenable; +	u32	forcestdby; +}; + +static struct omap3_otg_regs *otg; + +#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE		0x2000 +#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE		0x1000 +#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE		0x0010 +#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE		0x0008 +#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP		0x0004 +#define OMAP3_OTG_SYSCONFIG_SOFTRESET			0x0002 +#define OMAP3_OTG_SYSCONFIG_AUTOIDLE			0x0001 + +#define OMAP3_OTG_SYSSTATUS_RESETDONE			0x0001 + +#define OMAP3_OTG_INTERFSEL_OMAP			0x0001 + +#define OMAP3_OTG_FORCESTDBY_STANDBY			0x0001 + + +#ifdef DEBUG_MUSB_OMAP3 +static void musb_db_otg_regs(void) +{ +	u32 l; +	l = readl(&otg->revision); +	serial_printf("OTG_REVISION 0x%x\n", l); +	l = readl(&otg->sysconfig); +	serial_printf("OTG_SYSCONFIG 0x%x\n", l); +	l = readl(&otg->sysstatus); +	serial_printf("OTG_SYSSTATUS 0x%x\n", l); +	l = readl(&otg->interfsel); +	serial_printf("OTG_INTERFSEL 0x%x\n", l); +	l = readl(&otg->forcestdby); +	serial_printf("OTG_FORCESTDBY 0x%x\n", l); +} +#endif + +int musb_platform_init(void) +{ +	int ret = -1; + +	if (platform_needs_initialization) { +		u32 stdby; + +		if (twl4030_usb_ulpi_init()) { +			serial_printf("ERROR: %s Could not initialize PHY\n", +				__PRETTY_FUNCTION__); +			goto end; +		} + +		otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE; + +		/* Set OTG to always be on */ +		writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE | +		       OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig); + +		/* Set the interface */ +		writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel); + +		/* Clear force standby */ +		stdby = readl(&otg->forcestdby); +		stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY; +		writel(stdby, &otg->forcestdby); + +		platform_needs_initialization = 0; +	} + +	ret = platform_needs_initialization; +end: +	return ret; + +} + +void musb_platform_deinit(void) +{ +	/* noop */ +} diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h new file mode 100644 index 000000000..20fc9d294 --- /dev/null +++ b/drivers/usb/musb/omap3.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * This file is based on the file drivers/usb/musb/davinci.h + * + * This is the unique part of its copyright: + * + * -------------------------------------------------------------------- + * + * Copyright (c) 2008 Texas Instruments + * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments + * + * -------------------------------------------------------------------- + * + * 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 + */ +#ifndef _MUSB_OMAP3_H_ +#define _MUSB_OMAP3_H_ + +#include "musb_core.h" + +/* Base address of MUSB registers */ +#define MENTOR_USB0_BASE (OMAP34XX_CORE_L4_IO_BASE + 0xAB000) + +/* Base address of OTG registers */ +#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400) + +/* Timeout for USB module */ +#define OMAP3_USB_TIMEOUT 0x3FFFFFF + +int musb_platform_init(void); + +#endif /* _MUSB_OMAP3_H */ + diff --git a/include/usb.h b/include/usb.h index 4148d67e1..1cc3e4229 100644 --- a/include/usb.h +++ b/include/usb.h @@ -131,7 +131,8 @@ struct usb_device {  #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \  	defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \  	defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \ -	defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) +	defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \ +	defined(CONFIG_USB_OMAP3)  int usb_lowlevel_init(void);  int usb_lowlevel_stop(void); diff --git a/include/usb/musb_udc.h b/include/usb/musb_udc.h new file mode 100644 index 000000000..ef37dbbcc --- /dev/null +++ b/include/usb/musb_udc.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * 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 + */ +#ifndef __MUSB_UDC_H__ +#define __MUSB_UDC_H__ + +#include <usbdevice.h> + +/* UDC level routines */ +void udc_irq(void); +void udc_set_nak(int ep_num); +void udc_unset_nak(int ep_num); +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); +void udc_setup_ep(struct usb_device_instance *device, unsigned int id, +		  struct usb_endpoint_instance *endpoint); +void udc_connect(void); +void udc_disconnect(void); +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); +void udc_startup_events(struct usb_device_instance *device); +int udc_init(void); + +/* usbtty */ +#ifdef CONFIG_USB_TTY + +#define EP0_MAX_PACKET_SIZE	64 /* MUSB_EP0_FIFOSIZE */ +#define UDC_INT_ENDPOINT	1 +#define UDC_INT_PACKET_SIZE	64 +#define UDC_OUT_ENDPOINT	2 +#define UDC_OUT_PACKET_SIZE	64 +#define UDC_IN_ENDPOINT		3 +#define UDC_IN_PACKET_SIZE	64 +#define UDC_BULK_PACKET_SIZE	64 + +#endif /* CONFIG_USB_TTY */ + +#endif /* __MUSB_UDC_H__ */ + |