www.pudn.com > Linux2410_device.rar > omap.c


/*
 * linux/drivers/usb/device/bi/omap.c
 * TI OMAP1510/1610 USB bus interface driver
 *
 * Author: MontaVista Software, Inc.
 *	   source@mvista.com
 *
 * 2003 (c) MontaVista Software, Inc. This file is licensed under
 * the terms of the GNU General Public License version 2. This program
 * is licensed "as is" without any warranty of any kind, whether express
 * or implied.
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "../usbd.h"
#include "../usbd-export.h"
#include "../usbd-build.h"
#include "../usbd-module.h"
#include "../usbd-func.h"
#include "../usbd-bus.h"
#include "../usbd-inline.h"
#include "usbd-bi.h"

#include "omap.h"

#ifdef CONFIG_OMAP_H2
#include 

#define ISP1301_I2C_ADDR 0x2D

#define ISP1301_I2C_MODE_CONTROL_1 0x4
#define ISP1301_I2C_MODE_CONTROL_2 0x12
#define ISP1301_I2C_OTG_CONTROL_1 0x6
#define ISP1301_I2C_OTG_CONTROL_2 0x10
#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
#define ISP1301_I2C_INTERRUPT_LATCH 0xA
#define ISP1301_I2C_INTERRUPT_FALLING 0xC
#define ISP1301_I2C_INTERRUPT_RISING 0xE
#define ISP1301_I2C_REG_CLEAR_ADDR 1

#define OMAP1610_SET_FUNC_MUX_CTRL(mode,reg,bit) outl((inl(reg)&~(0x7<comm, "dpm_usbd_connect");

	for (;;) {
		down(&usbd_connect_lock);
		if (connect_thread_terminating == 1)
			break;

		down(&usbd_i2c_lock);
		if ((usbd_do_connect) && (!usbd_connected)) {
			/*enable pull-up resistor on D+ */
			i2c_write(0x9, ISP1301_I2C_OTG_CONTROL_1);
			i2c_write(~0x9,
				  ISP1301_I2C_OTG_CONTROL_1 |
				  ISP1301_I2C_REG_CLEAR_ADDR);
			usbd_connected = 1;
		}
		usbd_do_connect = 0;
		up(&usbd_i2c_lock);
	}

	complete_and_exit(&connect_thread_exit, 0);
	return 0;
}

static int
i2c_configure(void)
{
	char filename[20];
	int tmp;
	if (initstate_i2c)
		return 0;
	/*find the I2C driver we need */
	for (tmp = 0; tmp < I2C_ADAP_MAX; tmp++) {
#ifdef CONFIG_DEVFS_FS
		sprintf(filename, "/dev/i2c/%d", tmp);
#else
		sprintf(filename, "/dev/i2c-%d", tmp);
#endif

		if (!IS_ERR(i2c_file = filp_open(filename, O_RDWR, 0))) {
			/*found some driver */
			omap_i2c_client =
			    (struct i2c_client *) i2c_file->private_data;
			if (strlen(omap_i2c_client->adapter->name) >= 12) {
				if (!memcmp
				    (omap_i2c_client->adapter->name,
				     "OMAP1610 I2C", 12))
					break;	/*we found our driver! */
			}
			filp_close(i2c_file, NULL);
		}
	}

	if (tmp == I2C_ADAP_MAX) {	/*no matching I2C driver found */
		printk(KERN_ERR UDC_NAME ": cannot find OMAP1610 I2C driver\n");
		return -ENODEV;
	}

	initstate_i2c = 1;
	return 0;
}

static void
i2c_close(void)
{
	if (initstate_i2c)
		filp_close(i2c_file, NULL);
	initstate_i2c = 0;
}

#if 0
static int
i2c_read(u8 subaddr)
{
	u8 buf = 0;
	if (!i2c_configure()) {
		omap_i2c_client->addr = ISP1301_I2C_ADDR;

		i2c_master_send(omap_i2c_client, &subaddr, 1);
		i2c_master_recv(omap_i2c_client, &buf, 1);
	}

	return buf;
}
#endif

static int
i2c_write(u8 buf, u8 subaddr)
{
	char tmpbuf[2];
	if (!i2c_configure()) {
		omap_i2c_client->addr = ISP1301_I2C_ADDR;

		tmpbuf[0] = subaddr;	/*register number */
		tmpbuf[1] = buf;	/*register data */
		i2c_master_send(omap_i2c_client, &tmpbuf[0], 2);
	}

	return 0;
}

static void
isp1301_configure(void)
{
	i2c_write(6, ISP1301_I2C_MODE_CONTROL_1);
	i2c_write(~6, ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
	i2c_write(4, ISP1301_I2C_MODE_CONTROL_2);
	i2c_write(~4, ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR);
	i2c_write(0xFF,
		  ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR);
	i2c_write(0xFF,
		  ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR);
	i2c_write(0xFF,
		  ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR);
}
#endif

#if 0
static void
__dump_ep(struct usb_endpoint_instance *endpoint)
{
	int n;
	printk("ep [addr:%x st:%d sent:%d last:%d tx:%p]\n",
	       endpoint->endpoint_address, endpoint->state, endpoint->sent,
	       endpoint->last, endpoint->tx_urb);
	printk("TX urb contents:\n");
	for (n = 0; n < endpoint->tx_urb->actual_length; n++) {
		printk(" %.2x", endpoint->tx_urb->buffer[n]);
		if (n && (n % 16 == 0))
			printk("\n");
	}
	printk("\n");
}
#endif

/* ************************************************************************** */
/* IO
 */

/*
 * omap_prepare_endpoint_for_rx
 *
 * This function implements TRM Figure 14-11.
 *
 * The endpoint to prepare for transfer is specified as a physical endpoint
 * number.  For OUT (rx) endpoints 1 through 15, the corresponding endpoint 
 * configuration register is checked to see if the endpoint is ISO or not.
 * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled.  
 * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30.
 */
static void
omap_prepare_endpoint_for_rx(int ep)
{
	int ep_addr = PHYS_EP_TO_EP_ADDR(ep);
	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
	unsigned long flags;

	if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
	    && (ep_num >= 1) && (ep_num <= 15)) {
		if ((inw(UDC_EP_RX(ep_num)) &
		     (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso))
		    == UDC_EPn_RX_Valid) {
			/* rx endpoint is valid, non-ISO, so enable its FIFO */
			local_irq_save(flags);

			outw(ep_num, UDC_EP_NUM);
			outw(UDC_Set_FIFO_En, UDC_CTRL);

			local_irq_restore(flags);
		}
	}
}

/* omap_configure_endpoints
 *
 * This function implements TRM Figure 14-10.
 */
static void
omap_configure_endpoints(struct usb_device_instance *device)
{
	int ep;
	struct usb_bus_instance *bus;
	struct usb_endpoint_instance *endpoint;
	struct usb_bus_driver *driver;
	unsigned short ep_ptr;
	unsigned short ep_size;
	unsigned short ep_isoc;
	unsigned short ep_doublebuffer;
	int ep_addr;
	int packet_size;
	int buffer_size;
	int attributes;

	bus = device->bus;
	driver = bus->driver;

	/* There is a dedicated 2048 byte buffer for USB packets that may be 
	 * arbitrarily partitioned among the endpoints on 8-byte boundaries.  
	 * The first 8 bytes are reserved for receiving setup packets on
	 * endpoint 0.
	 */
	ep_ptr = 8;		/* reserve the first 8 bytes for the setup fifo */

	for (ep = 0; ep < driver->max_endpoints; ep++) {
		endpoint = bus->endpoint_array + ep;
		ep_addr = PHYS_EP_TO_EP_ADDR(ep);
		if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
			/* IN endpoint */
			packet_size = endpoint->tx_packetSize;
			attributes = endpoint->tx_attributes;
		} else {
			/* OUT endpoint */
			packet_size = endpoint->rcv_packetSize;
			attributes = endpoint->rcv_attributes;
		}

		switch (packet_size) {
		case 0:
			ep_size = 0;
			break;
		case 8:
			ep_size = 0;
			break;
		case 16:
			ep_size = 1;
			break;
		case 32:
			ep_size = 2;
			break;
		case 64:
			ep_size = 3;
			break;
		case 128:
			ep_size = 4;
			break;
		case 256:
			ep_size = 5;
			break;
		case 512:
			ep_size = 6;
			break;
		default:
			UDCDBG("ep 0x%02x has bad packet size %d",
			       ep_addr, packet_size);
			packet_size = 0;
			ep_size = 0;
			break;
		}

		switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {
		case USB_ENDPOINT_XFER_CONTROL:
		case USB_ENDPOINT_XFER_BULK:
		case USB_ENDPOINT_XFER_INT:
		default:
			/* A non-isochronous endpoint may optionally be
			 * double-buffered. For now we disable 
			 * double-buffering.
			 */
			ep_doublebuffer = 0;
			ep_isoc = 0;
			if (packet_size > 64)
				packet_size = 0;
			if (!ep || !ep_doublebuffer)
				buffer_size = packet_size;
			else
				buffer_size = packet_size * 2;
			break;
		case USB_ENDPOINT_XFER_ISOC:
			/* Isochronous endpoints are always double-
			 * buffered, but the double-buffering bit 
			 * in the endpoint configuration register 
			 * becomes the msb of the endpoint size so we
			 * set the double-buffering flag to zero.
			 */
			ep_doublebuffer = 0;
			ep_isoc = 1;
			buffer_size = packet_size * 2;
			break;
		}

		/* check to see if our packet buffer RAM is exhausted */
		if ((ep_ptr + buffer_size) > 2048) {
			UDCDBG("out of packet RAM for ep 0x%02x buf size %d",
			       ep_addr, buffer_size);
			buffer_size = packet_size = 0;
		}

		/* force a default configuration for endpoint 0 since it is 
		 * always enabled
		 */
		if (!ep && ((packet_size < 8) || (packet_size > 64))) {
			buffer_size = packet_size = 64;
			ep_size = 3;
		}

		if (!ep) {
			/* configure endpoint 0 */
			outw((ep_size << 12) | (ep_ptr >> 3), UDC_EP0);
			UDCDBG("ep 0 buffer offset 0x%03x packet size 0x%03x",
			       ep_ptr, packet_size);
		} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
			/* IN endpoint */
			if (packet_size) {
				outw((1 << 15) | (ep_doublebuffer << 14) |
				     (ep_size << 12) | (ep_isoc << 11) |
				     (ep_ptr >> 3),
				     UDC_EP_TX(ep_addr &
					       USB_ENDPOINT_NUMBER_MASK));
				UDCDBG("IN ep %d buffer offset 0x%03x"
				       " packet size 0x%03x",
				       ep_addr & USB_ENDPOINT_NUMBER_MASK,
				       ep_ptr, packet_size);
			} else {
				outw(0,
				     UDC_EP_TX(ep_addr &
					       USB_ENDPOINT_NUMBER_MASK));
			}
		} else {
			/* OUT endpoint */
			if (packet_size) {
				outw((1 << 15) | (ep_doublebuffer << 14) |
				     (ep_size << 12) | (ep_isoc << 11) |
				     (ep_ptr >> 3),
				     UDC_EP_RX(ep_addr &
					       USB_ENDPOINT_NUMBER_MASK));
				UDCDBG("OUT ep %d buffer offset 0x%03x"
				       " packet size 0x%03x",
				       ep_addr & USB_ENDPOINT_NUMBER_MASK,
				       ep_ptr, packet_size);
			} else {
				outw(0,
				     UDC_EP_RX(ep_addr &
					       USB_ENDPOINT_NUMBER_MASK));
			}
		}
		ep_ptr += buffer_size;
	}
}

/* omap_deconfigure_device
 *
 * This function balances omap_configure_device.
 */
static void
omap_deconfigure_device(void)
{
	int epnum;

	UDCDBG("clear Cfg_Lock");
	outw(inw(UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1);
	UDCREG(UDC_SYSCON1);

	/* deconfigure all endpoints */
	for (epnum = 1; epnum <= 15; epnum++) {
		outw(0, UDC_EP_RX(epnum));
		outw(0, UDC_EP_TX(epnum));
	}
}

/* omap_configure_device
 *
 * This function implements TRM Figure 14-9.
 */
static void
omap_configure_device(struct usb_device_instance *device)
{
	omap_configure_endpoints(device);

	/* Figure 14-9 indicates we should enable interrupts here, but we have
	 * other routines (udc_all_interrupts, udc_suspended_interrupts) to
	 * do that.
	 */

	UDCDBG("set Cfg_Lock");
	outw(inw(UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1);
	UDCREG(UDC_SYSCON1);
}

/* omap_write_noniso_tx_fifo
 *
 * This function implements TRM Figure 14-30.
 *
 * If the endpoint has an active tx_urb, then the next packet of data from the
 * URB is written to the tx FIFO.  The total amount of data in the urb is given 
 * by urb->actual_length.  The maximum amount of data that can be sent in any
 * one packet is given by endpoint->tx_packetSize.  The number of data bytes
 * from this URB that have already been transmitted is given by endpoint->sent.
 * endpoint->last is updated by this routine with the number of data bytes 
 * transmitted in this packet.
 *
 * In accordance with Figure 14-30, the EP_NUM register must already have been
 * written with the value to select the appropriate tx FIFO before this routine 
 * is called.
 */
static void
omap_write_noniso_tx_fifo(struct usb_endpoint_instance *endpoint)
{
	struct urb *urb = endpoint->tx_urb;

	if (urb) {
		int last;

		if ((last = MIN(urb->actual_length - endpoint->sent,
				endpoint->tx_packetSize))) {
			unsigned char *cp = urb->buffer + endpoint->sent;

			outsw(UDC_DATA, cp, last >> 1);
			if (last & 1)
				outb(*(cp + last - 1), UDC_DATA);
		}
		endpoint->last = last;
	}
}

/* omap_read_noniso_rx_fifo
 *
 * This function implements TRM Figure 14-28.
 *
 * If the endpoint has an active rcv_urb, then the next packet of data is read 
 * from the rcv FIFO and written to rcv_urb->buffer at offset 
 * rcv_urb->actual_length to append the packet data to the data from any 
 * previous packets for this transfer.  We assume that there is sufficient room
 * left in the buffer to hold an entire packet of data.
 *
 * The return value is the number of bytes read from the FIFO for this packet.
 *
 * In accordance with Figure 14-28, the EP_NUM register must already have been
 * written with the value to select the appropriate rcv FIFO before this routine
 * is called.
 */
static int
omap_read_noniso_rx_fifo(struct usb_endpoint_instance *endpoint)
{
	struct urb *urb = endpoint->rcv_urb;
	int len = 0;

	if (urb) {
		len = inw(UDC_RXFSTAT);
		if (len) {
			unsigned char *cp = urb->buffer + urb->actual_length;
			insw(UDC_DATA, cp, len >> 1);
			if (len & 1)
				*(cp + len - 1) = inb(UDC_DATA);
		}
	}
	return len;
}

/* omap_prepare_for_control_write_status
 *
 * This function implements TRM Figure 14-17.
 *
 * We have to deal here with non-autodecoded control writes that haven't already
 * been dealt with by ep0_recv_setup.  The non-autodecoded standard control 
 * write requests are:  set/clear endpoint feature, set configuration, set
 * interface, and set descriptor.  ep0_recv_setup handles set/clear requests for 
 * ENDPOINT_HALT by halting the endpoint for a set request and resetting the 
 * endpoint for a clear request.  ep0_recv_setup returns an error for 
 * SET_DESCRIPTOR requests which causes them to be terminated with a stall by
 * the setup handler.  A SET_INTERFACE request is handled by ep0_recv_setup by 
 * generating a DEVICE_SET_INTERFACE event.  This leaves only the 
 * SET_CONFIGURATION event for us to deal with here.
 *
 */
static void
omap_prepare_for_control_write_status(struct urb *urb)
{
	struct usb_device_request *request = &urb->device_request;;

	/* check for a SET_CONFIGURATION request */
	if (request->bRequest == USB_REQ_SET_CONFIGURATION) {
		int configuration = le16_to_cpu(request->wValue) & 0xff;
		unsigned short devstat = inw(UDC_DEVSTAT);

		if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) {
			/* device is currently in ADDRESSED state */
			if (configuration) {
				/* Assume the specified non-zero configuration
				 * value is valid and switch to the CONFIGURED 
				 * state.
				 */
				outw(UDC_Dev_Cfg, UDC_SYSCON2);
			}
		} else if ((devstat & UDC_CFG) == UDC_CFG) {
			/* device is currently in CONFIGURED state */
			if (!configuration) {
				/* Switch to ADDRESSED state. */
				outw(UDC_Clr_Cfg, UDC_SYSCON2);
			}
		}
	}

	/* select EP0 tx FIFO */
	outw(UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
	/* clear endpoint (no data bytes in status stage) */
	outw(UDC_Clr_EP, UDC_CTRL);
	/* enable the EP0 tx FIFO */
	outw(UDC_Set_FIFO_En, UDC_CTRL);
	/* deselect the endpoint */
	outw(UDC_EP_Dir, UDC_EP_NUM);
}

/* udc_state_transition_up
 * udc_state_transition_down
 *
 * Helper functions to implement device state changes.  The device states and
 * the events that transition between them are:
 *
 *				STATE_ATTACHED
 *				||	/\
 *				\/	||
 *	DEVICE_HUB_CONFIGURED			DEVICE_HUB_RESET
 *				||	/\
 *				\/	||
 *				STATE_POWERED
 *				||	/\
 *				\/	||
 *	DEVICE_RESET				DEVICE_POWER_INTERRUPTION
 *				||	/\
 *				\/	||
 *				STATE_DEFAULT
 *				||	/\
 *				\/	||
 *	DEVICE_ADDRESS_ASSIGNED			DEVICE_RESET
 *				||	/\
 *				\/	||
 *				STATE_ADDRESSED
 *				||	/\
 *				\/	||
 *	DEVICE_CONFIGURED			DEVICE_DE_CONFIGURED
 *				||	/\
 *				\/	||
 *				STATE_CONFIGURED
 *
 * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED
 * to STATE_CONFIGURED) from the specified initial state to the specified final
 * state, passing through each intermediate state on the way.  If the initial
 * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
 * no state transitions will take place.
 *
 * udc_state_transition_down transitions down (in the direction from 
 * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the 
 * specified final state, passing through each intermediate state on the way.  
 * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final 
 * state, then no state transitions will take place.
 *
 * These functions must only be called with interrupts disabled.
 */
static void
udc_state_transition_up(usb_device_state_t initial, usb_device_state_t final)
{
	if (initial < final) {
		switch (initial) {
		case STATE_ATTACHED:
			usbd_device_event_irq(udc_device,
					      DEVICE_HUB_CONFIGURED, 0);
			if (final == STATE_POWERED)
				break;
		case STATE_POWERED:
			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
			if (final == STATE_DEFAULT)
				break;
		case STATE_DEFAULT:
			usbd_device_event_irq(udc_device,
					      DEVICE_ADDRESS_ASSIGNED, 0);
			if (final == STATE_ADDRESSED)
				break;
		case STATE_ADDRESSED:
			usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
		case STATE_CONFIGURED:
			break;
		default:
			break;
		}
	}
}

static void
udc_state_transition_down(usb_device_state_t initial, usb_device_state_t final)
{
	if (initial > final) {
		switch (initial) {
		case STATE_CONFIGURED:
			usbd_device_event_irq(udc_device,
					      DEVICE_DE_CONFIGURED, 0);
			if (final == STATE_ADDRESSED)
				break;
		case STATE_ADDRESSED:
			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
			if (final == STATE_DEFAULT)
				break;
		case STATE_DEFAULT:
			usbd_device_event_irq(udc_device,
					      DEVICE_POWER_INTERRUPTION, 0);
			if (final == STATE_POWERED)
				break;
		case STATE_POWERED:
			usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
		case STATE_ATTACHED:
			break;
		default:
			break;
		}
	}
}

/* Handle all device state changes.
 * This function implements TRM Figure 14-21.
 */
static void
omap_udc_state_changed(void)
{
	u16 bits;
	u16 devstat = inw(UDC_DEVSTAT);

	UDCDBG("state changed, devstat %x, old %x", devstat, udc_devstat);

	bits = devstat ^ udc_devstat;
	if (bits) {
		if (bits & UDC_ATT) {
			if (devstat & UDC_ATT) {
				UDCDBG("device attached and powered");
				udc_state_transition_up(udc_device->
							device_state,
							STATE_POWERED);
			} else {
				UDCDBG("device detached or unpowered");
				udc_state_transition_down(udc_device->
							  device_state,
							  STATE_ATTACHED);
			}
		}
		if (bits & UDC_USB_Reset) {
			if (devstat & UDC_USB_Reset) {
				UDCDBG("device reset in progess");
				udc_state_transition_down(udc_device->
							  device_state,
							  STATE_POWERED);
			} else {
				UDCDBG("device reset completed");
			}
		}
		if (bits & UDC_DEF) {
			if (devstat & UDC_DEF) {
				UDCDBG("device entering default state");
				udc_state_transition_up(udc_device->
							device_state,
							STATE_DEFAULT);
			} else {
				UDCDBG("device leaving default state");
				udc_state_transition_down(udc_device->
							  device_state,
							  STATE_POWERED);
			}
		}
		if (bits & UDC_SUS) {
			if (devstat & UDC_SUS) {
				UDCDBG("entering suspended state");
				usbd_device_event_irq(udc_device,
						      DEVICE_BUS_INACTIVE, 0);
			} else {
				UDCDBG("leaving suspended state");
				usbd_device_event_irq(udc_device,
						      DEVICE_BUS_ACTIVITY, 0);
			}
		}
		if (bits & UDC_R_WK_OK) {
			UDCDBG("remote wakeup %s", (devstat & UDC_R_WK_OK)
			       ? "enabled" : "disabled");
		}
		if (bits & UDC_ADD) {
			if (devstat & UDC_ADD) {
				UDCDBG("default -> addressed");
				udc_state_transition_up(udc_device->
							device_state,
							STATE_ADDRESSED);
			} else {
				UDCDBG("addressed -> default");
				udc_state_transition_down(udc_device->
							  device_state,
							  STATE_DEFAULT);
			}
		}
		if (bits & UDC_CFG) {
			if (devstat & UDC_CFG) {
				UDCDBG("device configured");
				/* The ep0_recv_setup function generates the
				 * DEVICE_CONFIGURED event when a
				 * USB_REQ_SET_CONFIGURATION setup packet is
				 * received, so we should already be in the
				 * state STATE_CONFIGURED.
				 */
				udc_state_transition_up(udc_device->
							device_state,
							STATE_CONFIGURED);
			} else {
				UDCDBG("device deconfigured");
				udc_state_transition_down(udc_device->
							  device_state,
							  STATE_ADDRESSED);
			}
		}
	}

	/* Clear interrupt source */
	outw(UDC_DS_Chg, UDC_IRQ_SRC);

	/* Save current DEVSTAT */
	udc_devstat = devstat;
}

/* Handle SETUP USB interrupt.
 * This function implements TRM Figure 14-14.
 */
static void
omap_udc_setup(struct usb_endpoint_instance *endpoint)
{
	UDCDBG("-> Entering device setup");

	do {
		const int setup_pktsize = 8;
		unsigned char *datap =
		    (unsigned char *) &ep0_urb->device_request;

		/* Gain access to EP 0 setup FIFO */
		outw(UDC_Setup_Sel, UDC_EP_NUM);

		/* Read control request data */
		insb(UDC_DATA, datap, setup_pktsize);

		UDCDBG("EP0 setup read [%x %x %x %x %x %x %x %x]",
		       *(datap + 0), *(datap + 1), *(datap + 2), *(datap + 3),
		       *(datap + 4), *(datap + 5), *(datap + 6), *(datap + 7));

		/* Reset EP0 setup FIFO */
		outw(0, UDC_EP_NUM);
	} while (inw(UDC_IRQ_SRC) & UDC_Setup);

	/* Try to process setup packet */
	if (usbd_recv_setup(ep0_urb)) {
		/* Not a setup packet, stall next EP0 transaction */
		udc_stall_ep(0);
		UDCDBG("can't parse setup packet, still waiting for setup");
		return;
	}

	/* Check direction */
	if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
	    == USB_REQ_HOST2DEVICE) {
		UDCDBG("control write on EP0");
		if (le16_to_cpu(ep0_urb->device_request.wLength)) {
			/* We don't support control write data stages.
			 * The only standard control write request with a data
			 * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't
			 * support that so we just stall those requests.  A 
			 * function driver might support a non-standard 
			 * write request with a data stage, but it isn't 
			 * obvious what we would do with the data if we read it 
			 * so we'll just stall it.  It seems like the API isn't 
			 * quite right here.
			 */
#if 0
			/* Here is what we would do if we did support control 
			 * write data stages.
			 */
			ep0_urb->actual_length = 0;
			outw(0, UDC_EP_NUM);
			/* enable the EP0 rx FIFO */
			outw(UDC_Set_FIFO_En, UDC_CTRL);
#else
			/* Stall this request */
			UDCDBG("Stalling unsupported EP0 control write data "
			       "stage.");
			udc_stall_ep(0);
#endif
		} else {
			omap_prepare_for_control_write_status(ep0_urb);
		}
	} else {
		UDCDBG("control read on EP0");
		/* The ep0_recv_setup function has already placed our response
		 * packet data in ep0_urb->buffer and the packet length in 
		 * ep0_urb->actual_length.
		 */
		endpoint->tx_urb = ep0_urb;
		endpoint->sent = 0;
		/* select the EP0 tx FIFO */
		outw(UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
		/* Write packet data to the FIFO.  omap_write_noniso_tx_fifo
		 * will update endpoint->last with the number of bytes written 
		 * to the FIFO.
		 */
		omap_write_noniso_tx_fifo(endpoint);
		/* enable the FIFO to start the packet transmission */
		outw(UDC_Set_FIFO_En, UDC_CTRL);
		/* deselect the EP0 tx FIFO */
		outw(UDC_EP_Dir, UDC_EP_NUM);
	}

	UDCDBG("<- Leaving device setup");
}

/* Handle endpoint 0 RX interrupt
 * This routine implements TRM Figure 14-16.
 */
static void
omap_udc_ep0_rx(struct usb_endpoint_instance *endpoint)
{
	unsigned short status;

	UDCDBG("RX on EP0");
	/* select EP0 rx FIFO */
	outw(UDC_EP_Sel, UDC_EP_NUM);

	status = inw(UDC_STAT_FLG);

	if (status & UDC_ACK) {
		/* Check direction */
		if ((ep0_urb->device_request.bmRequestType
		     & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
			/* This rx interrupt must be for a control write data
			 * stage packet.
			 *
			 * We don't support control write data stages.
			 * We should never end up here.
			 */

			/* clear the EP0 rx FIFO */
			outw(UDC_Clr_EP, UDC_CTRL);

			/* deselect the EP0 rx FIFO */
			outw(0, UDC_EP_NUM);

			UDCDBG("Stalling unexpected EP0 control write "
			       "data stage packet");
			udc_stall_ep(0);
		} else {
			/* This rx interrupt must be for a control read status 
			 * stage packet.
			 */
			UDCDBG("ACK on EP0 control read status stage packet");
			/* deselect EP0 rx FIFO */
			outw(0, UDC_EP_NUM);
		}
	} else if (status & UDC_STALL) {
		UDCDBG("EP0 stall during RX");
		/* deselect EP0 rx FIFO */
		outw(0, UDC_EP_NUM);
	} else {
		/* deselect EP0 rx FIFO */
		outw(0, UDC_EP_NUM);
	}
}

/* Handle endpoint 0 TX interrupt
 * This routine implements TRM Figure 14-18.
 */
static void
omap_udc_ep0_tx(struct usb_endpoint_instance *endpoint)
{
	unsigned short status;
	struct usb_device_request *request = &ep0_urb->device_request;

	UDCDBG("TX on EP0");
	/* select EP0 TX FIFO */
	outw(UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);

	status = inw(UDC_STAT_FLG);
	if (status & UDC_ACK) {
		/* Check direction */
		if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)
		    == USB_REQ_HOST2DEVICE) {
			/* This tx interrupt must be for a control write status 
			 * stage packet.
			 */
			UDCDBG("ACK on EP0 control write status stage packet");
			/* deselect EP0 TX FIFO */
			outw(UDC_EP_Dir, UDC_EP_NUM);
		} else {
			/* This tx interrupt must be for a control read data 
			 * stage packet.
			 */
			int wLength = le16_to_cpu(request->wLength);

			/* Update our count of bytes sent so far in this
			 * transfer.
			 */
			endpoint->sent += endpoint->last;

			/* We are finished with this transfer if we have sent 
			 * all of the bytes in our tx urb (urb->actual_length)
			 * unless we need a zero-length terminating packet.  We 
			 * need a zero-length terminating packet if we returned 
			 * fewer bytes than were requested (wLength) by the host,
			 * and the number of bytes we returned is an exact
			 * multiple of the packet size endpoint->tx_packetSize.
			 */
			if ((endpoint->sent == ep0_urb->actual_length)
			    && ((ep0_urb->actual_length == wLength)
				|| (endpoint->last != endpoint->tx_packetSize))) {
				/* Done with control read data stage. */
				UDCDBG("control read data stage complete");
				/* deselect EP0 TX FIFO */
				outw(UDC_EP_Dir, UDC_EP_NUM);
				/* select EP0 RX FIFO to prepare for control
				 * read status stage.
				 */
				outw(UDC_EP_Sel, UDC_EP_NUM);
				/* clear the EP0 RX FIFO */
				outw(UDC_Clr_EP, UDC_CTRL);
				/* enable the EP0 RX FIFO */
				outw(UDC_Set_FIFO_En, UDC_CTRL);
				/* deselect the EP0 RX FIFO */
				outw(0, UDC_EP_NUM);
			} else {
				/* We still have another packet of data to send 
				 * in this control read data stage or else we 
				 * need a zero-length terminating packet.
				 */
				UDCDBG("ACK control read data stage packet");
				omap_write_noniso_tx_fifo(endpoint);
				/* enable the EP0 tx FIFO to start transmission */
				outw(UDC_Set_FIFO_En, UDC_CTRL);
				/* deselect EP0 TX FIFO */
				outw(UDC_EP_Dir, UDC_EP_NUM);
			}
		}
	} else if (status & UDC_STALL) {
		UDCDBG("EP0 stall during TX");
		/* deselect EP0 TX FIFO */
		outw(UDC_EP_Dir, UDC_EP_NUM);
	} else {
		/* deselect EP0 TX FIFO */
		outw(UDC_EP_Dir, UDC_EP_NUM);
	}
}

/* Handle RX transaction on non-ISO endpoint.
 * This function implements TRM Figure 14-27.
 * The ep argument is a physical endpoint number for a non-ISO OUT endpoint
 * in the range 1 to 15.
 */
static void
omap_udc_epn_rx(int ep)
{
	unsigned short status;

	/* Check endpoint status */
	status = inw(UDC_STAT_FLG);

	if (status & UDC_ACK) {
		int nbytes;
		struct usb_endpoint_instance *endpoint =
		    udc_device->bus->endpoint_array + ep;

		nbytes = omap_read_noniso_rx_fifo(endpoint);

		usbd_rcv_complete_irq(endpoint, nbytes, 0);

		/* enable rx FIFO to prepare for next packet */
		outw(UDC_Set_FIFO_En, UDC_CTRL);
	} else if (status & UDC_STALL) {
		UDCDBG("STALL on RX endpoint %d", ep);
	} else if (status & UDC_NAK) {
		UDCDBG("NAK on RX ep %d", ep);
	} else
		printk(KERN_WARNING "omap-bi: RX on ep %d with status %x",
		       ep, status);
}

/* Handle TX transaction on non-ISO endpoint.
 * This function implements TRM Figure 14-29.
 * The ep argument is a physical endpoint number for a non-ISO IN endpoint
 * in the range 16 to 30.
 */
static void
omap_udc_epn_tx(int ep)
{
	unsigned short status;

	/* Check endpoint status */
	status = inw(UDC_STAT_FLG);

	if (status & UDC_ACK) {
		struct usb_endpoint_instance *endpoint =
		    udc_device->bus->endpoint_array + ep;

		/* We need to transmit a terminating zero-length packet now if 
		 * we have sent all of the data in this URB and the transfer 
		 * size was an exact multiple of the packet size.
		 */
		if (endpoint->tx_urb
		    && (endpoint->last == endpoint->tx_packetSize)
		    && (endpoint->tx_urb->actual_length - endpoint->sent
			- endpoint->last == 0)) {
			/* Prepare to transmit a zero-length packet. */
			endpoint->sent += endpoint->last;
			/* write 0 bytes of data to FIFO */
			omap_write_noniso_tx_fifo(endpoint);
			/* enable tx FIFO to start transmission */
			outw(UDC_Set_FIFO_En, UDC_CTRL);
		} else {
			/* retire the data that was just sent */
			usbd_tx_complete_irq(endpoint, 0);
			/* Check to see if we have more data ready to transmit
			 * now.
			 */
			if (endpoint->tx_urb) {
				/* write data to FIFO */
				omap_write_noniso_tx_fifo(endpoint);
				/* enable tx FIFO to start transmission */
				outw(UDC_Set_FIFO_En, UDC_CTRL);
			}
		}
	} else if (status & UDC_STALL) {
		UDCDBG("STALL on TX endpoint %d", ep);
	} else if (status & UDC_NAK) {
		UDCDBG("NAK on TX endpoint %d", ep);
	} else
		printk(KERN_WARNING "omap-bi: TX on ep %d with status %x",
		       ep, status);
}

#if 0
static void
omap_udc_eot(void)
{
	UDCDBG("eot NYI");
}

static void
omap_udc_rx_dma(void)
{
	UDCDBG("rx dma NYI");
}

static void
omap_udc_tx_dma(void)
{
	UDCDBG("tx dma NYI");
}
#endif

/* Handle general USB interrupts and dispatch according to type.
 * This function implements TRM Figure 14-13.
 */
static void
omap_udc_irq(int irq, void *dev_id, struct pt_regs *regs)
{
	u16 irq_src = inw(UDC_IRQ_SRC);
	int valid_irq = 0;

	UDCDBG("< IRQ #%d start >- %d %x %x",
	       udc_interrupts, irq, irq_src, inw(UDC_IRQ_EN));

	if (irq_src & UDC_DS_Chg) {
		/* Device status changed */
		omap_udc_state_changed();
		valid_irq++;
	}
	if (irq_src & UDC_EP0_RX) {
		/* Endpoint 0 receive */
		outw(UDC_EP0_RX, UDC_IRQ_SRC);	/* ack interrupt */
		omap_udc_ep0_rx(udc_device->bus->endpoint_array + 0);
		valid_irq++;
	}
	if (irq_src & UDC_EP0_TX) {
		/* Endpoint 0 transmit */
		outw(UDC_EP0_TX, UDC_IRQ_SRC);	/* ack interrupt */
		omap_udc_ep0_tx(udc_device->bus->endpoint_array + 0);
		valid_irq++;
	}
	if (irq_src & UDC_Setup) {
		/* Device setup */
		omap_udc_setup(udc_device->bus->endpoint_array + 0);
		valid_irq++;
	}
#if 0
	if (irq_src & UDC_RXn_EOT) {
		/* End of RX DMA transfer */
		omap_udc_eot();
		valid_irq++;
	}
	if (irq_src & UDC_RXn_Cnt) {
		/* RX DMA count (FIXME: ???) */
		omap_udc_rx_dma();
		valid_irq++;
	}
	if (irq_src & UDC_TXn_Done) {
		/* TX DMA finished */
		omap_udc_tx_dma();
		valid_irq++;
	}
#endif
	if (!valid_irq)
		printk(KERN_ERR UDC_NAME ": unknown interrupt, IRQ_SRC %.4x\n",
		       irq_src);
	UDCDBG("< IRQ #%d end >", udc_interrupts);
	udc_interrupts++;
}

/* This function implements TRM Figure 14-26. */
static void
omap_udc_noniso_irq(int irq, void *dev_id, struct pt_regs *regs)
{
	unsigned short epnum;
	unsigned short irq_src = inw(UDC_IRQ_SRC);
	int ep;
	int valid_irq = 0;

	UDCDBG("non-ISO IRQ, IRQ_EN %x", inw(UDC_IRQ_EN));

	if (irq_src & UDC_EPn_RX) {	/* Endpoint N OUT transaction */
		/* Determine the endpoint number for this interrupt */
		epnum = (inw(UDC_EPN_STAT) & 0x0f00) >> 8;
		UDCDBG("RX on ep %d", epnum);

		/* acknowledge interrupt */
		outw(UDC_EPn_RX, UDC_IRQ_SRC);

		if (epnum) {
			/* convert epnum to physical ep */
			ep = EP_ADDR_TO_PHYS_EP(USB_DIR_OUT | epnum);

			/* select the endpoint FIFO */
			outw(UDC_EP_Sel | epnum, UDC_EP_NUM);

			omap_udc_epn_rx(ep);

			/* deselect the endpoint FIFO */
			outw(epnum, UDC_EP_NUM);
		}
		valid_irq++;
	}
	if (irq_src & UDC_EPn_TX) {	/* Endpoint N IN transaction */
		/* Determine the endpoint number for this interrupt */
		epnum = inw(UDC_EPN_STAT) & 0x000f;
		UDCDBG("TX on ep %d", epnum);

		/* acknowledge interrupt */
		outw(UDC_EPn_TX, UDC_IRQ_SRC);

		if (epnum) {
			/* convert epnum to physical ep */
			ep = EP_ADDR_TO_PHYS_EP(USB_DIR_IN | epnum);

			/* select the endpoint FIFO */
			outw(UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);

			omap_udc_epn_tx(ep);

			/* deselect the endpoint FIFO */
			outw(UDC_EP_Dir | epnum, UDC_EP_NUM);
		}
		valid_irq++;
	}
	if (!valid_irq)
		printk(KERN_WARNING UDC_NAME
		       ": unknown non-ISO interrupt, IRQ_SRC %.4x\n", irq_src);
}

/* Handle SOF USB interrupts */
static void
omap_udc_sof_irq(int irq, void *dev_id, struct pt_regs *regs)
{
	/* For now, nothing except clear interrupt */
	outw(UDC_SOF_Flg, UDC_IRQ_SRC);
}

/* ************************************************************************** */

/* ************************************************************************** */
/*
 * Start of public functions.
 */

/* Called by the bus interface driver to start packet transmission. */
void
udc_start_in_irq(struct usb_endpoint_instance *endpoint)
{
	unsigned short epnum =
	    endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;

	UDCDBG("Starting transmit on ep %d", epnum);

	if (endpoint->tx_urb) {
		/* select the endpoint FIFO */
		outw(UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);

		/* write data to FIFO */
		omap_write_noniso_tx_fifo(endpoint);

		/* enable tx FIFO to start transmission */
		outw(UDC_Set_FIFO_En, UDC_CTRL);

		/* deselect the endpoint FIFO */
		outw(UDC_EP_Dir | epnum, UDC_EP_NUM);
	}
}

/* Start to initialize h/w stuff */
int
udc_init(void)
{
	u16 udc_rev;
	static int banner_printed = 0;

	udc_device = NULL;

	UDCDBG("starting");

#ifdef CONFIG_ARCH_OMAP1610
#ifdef CONFIG_OMAP_H2
/*set up pinout*/
/*USB pin group 1 configuration*/
	OMAP1610_SET_FUNC_MUX_CTRL(1, FUNC_MUX_CTRL_9, 24);	/*USB1.TXD W14 */
	open_drain(4, PULL_DWN_CTRL_2);
	OMAP1610_SET_FUNC_MUX_CTRL(2, FUNC_MUX_CTRL_9, 3);	/*USB1.TXEN W16 */
	open_drain(29, PULL_DWN_CTRL_1);
	//OMAP1610_SET_FUNC_MUX_CTRL(2, FUNC_MUX_CTRL_A, 3);    /*USB1.VP AA17 */
	//open_drain(7, PULL_DWN_CTRL_2);
	OMAP1610_SET_FUNC_MUX_CTRL(4, FUNC_MUX_CTRL_9, 0);	/*USB1.SEO W13 */
	open_drain(28, PULL_DWN_CTRL_1);
	OMAP1610_SET_FUNC_MUX_CTRL(1, FUNC_MUX_CTRL_A, 9);	/*USB1.RCV V15 */
	open_drain(9, PULL_DWN_CTRL_2);
	//OMAP1610_SET_FUNC_MUX_CTRL(2,FUNC_MUX_CTRL_8,27); /*USB1.SUSP J20*/ /*not used on OMAP1610 INNOVATOR*/
	//open_drain(27,PULL_DWN_CTRL_1);
	//OMAP1610_SET_FUNC_MUX_CTRL(2, FUNC_MUX_CTRL_A, 6);    /*USB1.VM P14 */
	//open_drain(8, PULL_DWN_CTRL_2);
	OMAP1610_SET_FUNC_MUX_CTRL(5, FUNC_MUX_CTRL_A, 12);	/*USB1.SPEED R13 *//*used on OMAP1610 H2, not INNOVATOR */
	open_drain(10, PULL_DWN_CTRL_2);

	OMAP1610_CONFIRM_MUX_SETUP();

	//USB_TRANSCEIVER_CTRL.7 = 1 (CONF_USB1_UNI_R) //unidirectional vs bidirectional, set to 1 if trx mode 0
	outl((inl(USB_TRANSCEIVER_CTRL) & ~(1 << 7)), USB_TRANSCEIVER_CTRL);
#else
	//USB_TRANSCEIVER_CTRL.7 = x (CONF_USB1_UNI_R) //unidirectional vs bidirectional, set to 1 if trx mode 0
	//USB_TRANSCEIVER_CTRL.8 = x (CONF_USB2_UNI_R) //unidirectional vs bidirectional, set to 1 if trx mode 0
	//all other bits = 0 (enable integrated transceiver, DP, DM, pull-downs on both)
	outl((inl(USB_TRANSCEIVER_CTRL) & ((1 << 7) | (1 << 8))),
	     USB_TRANSCEIVER_CTRL);
#endif

	/*set up USB Host without OTG function.
	   OTG registers still must be configured */

	//RESET_CONTROL.0 = 1 (CONF_OCP_RESET_R) //page oct03.448
	//RESET_CONTROL.2 = 1 (CONF_ARMIO_RESET_R)
	outl(inl(RESET_CONTROL) | 5, RESET_CONTROL);

	//ARM_RSTCT2.0 = 1(PER_EN)
	outl(inl(ARM_RSTCT2) | 1, ARM_RSTCT2);

	//CLOCK_CTRL_REG.5 = 0 (DIS_USB_PVCI_CLK)
	//CLOCK_CTRL_REG.4 = 1 (USB_MCLK_EN)
	outl((inl(CLOCK_CTRL_REG) & ~(1 << 5)), CLOCK_CTRL_REG);
	outl((inl(CLOCK_CTRL_REG) | (1 << 4)), CLOCK_CTRL_REG);

	//SOFT_REQ_REG.8 = 1 (SOFT_USB_OTG_DPLL_REQ)
	//SOFT_REQ_REG.4 = 1 (USB_REQ_EN) //USB Client HW DPLL req
	//SOFT_REQ_REG.3 = 1 (SOFT_USB_REQ)
	//SOFT_REQ_REG.0 = 1 (SOFT_DPLL_REQ) //ULPD_PLL clock req
	outl((inl(SOFT_REQ_REG) | (1 << 0) | (1 << 3) | (1 << 4) | (1 << 8)),
	     SOFT_REQ_REG);

	//SOFT_DISABLE_REQ_REG.3 = 0 (DIS_PERIPH_REQ)
	outl((inl(SOFT_DISABLE_REQ_REG) & ~(1 << 3)), SOFT_DISABLE_REQ_REG);

	//MOD_CONF_CTRL_0.17 = 0 (CONF_MOD_USB_W2FC_VBUS_MODE_R) //VBUS Detection via AA2/via FUNC_MUX_CTRL_0(19-18)
	outl((inl(MOD_CONF_CTRL_0) & ~(1 << 17)), MOD_CONF_CTRL_0);

	//? OTG_SYSCON_1.1 = 1 (SOFT_RST)
	//? OTG_SYSCON_1.2 == 1 ? (RESET_DONE)

	//OTG_SYSCON_1.15 = 0 (OTG_IDLE_EN)
	//OTG_SYSCON_1.13 = 0 (DEV_IDLE_EN) //user choice
	//OTG_SYSCON_1.1 = 0 (SOFT_RST)
#ifdef CONFIG_OMAP_H2
	//OTG_SYSCON_1.26-24 = 0 (USB2_TRXMODE) //user choice
	//OTG_SYSCON_1.22-20 = 2 (USB1_TRXMODE) //user choice
	//OTG_SYSCON_1.18-16 = 0 (USB0_TRXMODE) //user choice
	outl((2 << 20), OTG_SYSCON_1);
#else
	//OTG_SYSCON_1.26-24 = x (USB2_TRXMODE) //user choice
	//OTG_SYSCON_1.22-20 = x (USB1_TRXMODE) //user choice
	//OTG_SYSCON_1.18-16 = 3 (USB0_TRXMODE) //user choice
	outl((inl(OTG_SYSCON_1) & ((7 << 20) | (7 << 24))), OTG_SYSCON_1);
	outl((inl(OTG_SYSCON_1) | (3 << 16)), OTG_SYSCON_1);
#endif
	//OTG_CTRL.18 = 0 (BSESSVLD) //1 = host attached (VBUS present)
	outl(0, OTG_CTRL);

	//OTG_SYSCON_2.31 = 0 (OTG_EN)
	//OTG_SYSCON_2.30 = 1 (USBx_SYNCHRO)
	//OTG_SYSCON_2.29 = 0 (OTG_MST16)
	//OTG_SYSCON_2.28 = 0 (SRP_GPDATA)
	//OTG_SYSCON_2.27 = 0 (SRP_GPDVBUS)
	//OTG_SYSCON_2.26-24 = 0 (SRP_GPUVBUS)
	//OTG_SYSCON_2.22-20 = 0 (A_WAIT_RISE)
	//OTG_SYSCON_2.18-16 = 4 (B_ASE0_BRST)
	//OTG_SYSCON_2.14 = 0 (SRP_DPW)
	//OTG_SYSCON_2.13 = 0 (SRP_DATA)
	//OTG_SYSCON_2.12 = 0 (SRP_VBUS)
	//OTG_SYSCON_2.10 = 0 (OTG_PADEN)
	//OTG_SYSCON_2.9 = 0 (HMC_PADEN)
	//OTG_SYSCON_2.7 = 0 (HMC_TTLSPEED) //user choice
	//OTG_SYSCON_2.6 = 0 (HMC_TTLATTACH) //user choice
#ifdef CONFIG_OMAP_H2
	//OTG_SYSCON_2.8 = 0 (UHOST_EN) //user choice
	//OTG_SYSCON_2.5-0 = 3 (HMC_MODE) //user choice
	outl((1 << 30) | (4 << 16) | 3, OTG_SYSCON_2);
#else
	//OTG_SYSCON_2.8 = x (UHOST_EN) //user choice
	//OTG_SYSCON_2.5-0 = 4 (HMC_MODE) //user choice
	outl((inl(OTG_SYSCON_2) & ((1 << 30) | (4 << 16) | (1 << 8) | 4)),
	     OTG_SYSCON_2);
	outl((inl(OTG_SYSCON_2) | (1 << 30) | (4 << 16) | 4), OTG_SYSCON_2);
#endif
	//OTG_IRQ_EN = 0
	outl(0, OTG_IRQ_EN);
	//OTG_SYSCON_1.15 = 1 (OTG_IDLE_EN) //to reduce power consumption
	//outl(inl(OTG_SYSCON_1)|(1<<15),OTG_SYSCON_1); //if enabled, usbserial looses some incoming data
#else				/*old OMAP1510 configuration */
	/* Check peripheral reset. Must be 1 to make sure
	   MPU TIPB peripheral reset is inactive */
	UDCREG(ARM_RSTCT2);

	/* Set and check clock control.
	 * We might ought to be using the clock control API to do 
	 * this instead of fiddling with the clock registers directly 
	 * here.
	 */
	outw((1 << 4) | (1 << 5), CLOCK_CTRL);
	UDCREG(CLOCK_CTRL);

	/* Set and check APLL */
	outw(0x0008, APLL_CTRL);
	UDCREG(APLL_CTRL);

	/* Set and check DPLL */
	outw(0x2210, DPLL_CTRL);
	UDCREG(DPLL_CTRL);

	/* Set and check SOFT */
	outw((1 << 4) | (1 << 3) | 1, SOFT_REQ);
	/* Short delay to wait for DPLL */
	mdelay(1);
#endif

	/* Print banner with device revision */
	udc_rev = inw(UDC_REV) & 0xff;
	if (!banner_printed) {
		banner_printed = 1;
		printk(KERN_INFO
		       "TI OMAP1510/1610 USB function module rev %d.%d\n",
		       udc_rev >> 4, udc_rev);
	}

	/* The VBUS_MODE bit selects whether VBUS detection is done via
	 * software (1) or hardware (0).  When software detection is
	 * selected, VBUS_CTRL selects whether USB is not connected (0)
	 * or connected (1).
	 */
	outl(inl(FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
	outl(inl(FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
	UDCREGL(FUNC_MUX_CTRL_0);

	/* We'll assume that our firmware has properly initialized our 
	 * I/O pin multiplexing configuration so we don't need to fuss
	 * with it here.  Keeping this sort of thing out of the driver 
	 * makes it more likely that the driver will work without 
	 * modification on OMAP boards that might have the USB function 
	 * module pinned out differently than the Innovator.
	 */
#if 0
	/* FUNC_MUX_CTRL_D bits 5:3 select whether OMAP pin W4 is the 
	 * USB.PUEN signal (000) or the USB.CLK0 signal (001).  Pin W4
	 * is used for the USB.PUEN signal on the Innovator.
	 */
	outl(inl(FUNC_MUX_CTRL_D) & ~(7 << 3), FUNC_MUX_CTRL_D);
#endif
	UDCREGL(FUNC_MUX_CTRL_D);

	/*
	 * At this point, device is ready for configuration...
	 */
	UDCDBG("disable USB interrupts");
	outw(0, UDC_IRQ_EN);
	UDCREG(UDC_IRQ_EN);

	UDCDBG("disable USB DMA");
	outw(0, UDC_DMA_IRQ_EN);
	UDCREG(UDC_DMA_IRQ_EN);

	UDCDBG("initialize SYSCON1");
	outw(UDC_SYSCON1_INIT, UDC_SYSCON1);
	UDCREG(UDC_SYSCON1);

	return 0;
}

/* Stall endpoint */
void
udc_stall_ep(unsigned int ep)
{
	int ep_addr = PHYS_EP_TO_EP_ADDR(ep);
	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
	unsigned long flags;

	UDCDBG("stall ep %d", ep);

	/* REVISIT?
	 * The OMAP TRM section 14.2.4.2 says we must check that the FIFO
	 * is empty before halting the endpoint.  The current implementation 
	 * doesn't check that the FIFO is empty.
	 */

	local_irq_save(flags);

	if (!ep_num) {
		outw(UDC_Stall_Cmd, UDC_SYSCON2);
	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
		if (inw(UDC_EP_RX(ep_num)) & UDC_EPn_RX_Valid) {
			/* we have a valid rx endpoint, so halt it */
			outw(ep_num, UDC_EP_NUM);
			outw(UDC_Set_Halt, UDC_CTRL);
		}
	} else {
		if (inw(UDC_EP_TX(ep_num)) & UDC_EPn_TX_Valid) {
			/* we have a valid tx endpoint, so halt it */
			outw(ep_num | UDC_EP_Dir, UDC_EP_NUM);
			outw(UDC_Set_Halt, UDC_CTRL);
		}
	}

	local_irq_restore(flags);
}

/* Reset endpoint */
void
udc_reset_ep(unsigned int ep)
{
	int ep_addr = PHYS_EP_TO_EP_ADDR(ep);
	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
	unsigned long flags;

	UDCDBG("reset ep %d", ep);

	local_irq_save(flags);

	if (!ep_num) {
		/* control endpoint 0 can't be reset */
	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
		UDCDBG("UDC_EP_RX(%d) = 0x%04x", ep_num,
		       inw(UDC_EP_RX(ep_num)));
		if (inw(UDC_EP_RX(ep_num)) & UDC_EPn_RX_Valid) {
			/* we have a valid rx endpoint, so reset it */
			outw(ep_num | UDC_EP_Sel, UDC_EP_NUM);
			outw(UDC_Reset_EP, UDC_CTRL);
			outw(ep_num, UDC_EP_NUM);
			UDCDBG("OUT endpoint %d reset", ep_num);
		}
	} else {
		UDCDBG("UDC_EP_TX(%d) = 0x%04x", ep_num,
		       inw(UDC_EP_TX(ep_num)));
		/* Resetting of tx endpoints seems to be causing the USB function 
		 * module to fail, which causes problems when the driver is 
		 * uninstalled.  We'll skip resetting tx endpoints for now until 
		 * we figure out what the problem is.
		 */
#if 0
		if (inw(UDC_EP_TX(ep_num)) & UDC_EPn_TX_Valid) {
			/* we have a valid tx endpoint, so reset it */
			outw(ep_num | UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
			outw(UDC_Reset_EP, UDC_CTRL);
			outw(ep_num | UDC_EP_Dir, UDC_EP_NUM);
			UDCDBG("IN endpoint %d reset", ep_num);
		}
#endif
	}

	local_irq_restore(flags);
}

/**
 * udc_endpoint_halted - is endpoint halted
 * @ep:
 *
 * Return non-zero if endpoint is halted
 */
int
udc_endpoint_halted(unsigned int ep)
{
	return 0;
}

/**
 * udc_set_address - set the USB address for this device
 * @address:
 *
 * Called from control endpoint function after it decodes a set address setup packet.
 */
void
udc_set_address(unsigned char address)
{
	UDCDBG("setting address %x", address);
	usb_address = address;
}

#if 1
/**
 * udc_serial_init - set a serial number if available
 */
int __init
udc_serial_init(struct usb_bus_instance *bus)
{
	return -EINVAL;
}
#endif

/* ************************************************************************** */

/*
 * udc_max_endpoints - max physical endpoints 
 *
 * Return number of physical endpoints.
 */
int
udc_max_endpoints(void)
{
	return UDC_MAX_ENDPOINTS;
}

/**
 * udc_check_ep - check logical endpoint
  *
 * Return physical endpoint number to use for this logical endpoint or zero if not valid.
 */
int
udc_check_ep(int logical_endpoint, int packetsize)
{
	if ((logical_endpoint == 0x80) ||
	    ((logical_endpoint & 0x8f) != logical_endpoint)) {
		return 0;
	}

	switch (packetsize) {
	case 8:
	case 16:
	case 32:
	case 64:
	case 128:
	case 256:
	case 512:
		break;
	default:
		return 0;
	}

	return EP_ADDR_TO_PHYS_EP(logical_endpoint);
}

/*
 * udc_setup_ep - setup endpoint
 *
 * Associate a physical endpoint with endpoint_instance
 */
void
udc_setup_ep(struct usb_device_instance *device,
	     unsigned int ep, struct usb_endpoint_instance *endpoint)
{
	/* This routine gets called by bi_modinit for endpoint 0 and from
	 * bi_config for all of the other endpoints.  bi_config gets called 
	 * during the DEVICE_CREATE, DEVICE_CONFIGURED, and 
	 * DEVICE_SET_INTERFACE events.  We need to reconfigure the OMAP packet 
	 * RAM after bi_config scans the selected device configuration and 
	 * initializes the endpoint structures, but before this routine enables
	 * the OUT endpoint FIFOs.  Since bi_config calls this routine in a 
	 * loop for endpoints 1 through UDC_MAX_ENDPOINTS, we reconfigure our 
	 * packet RAM here when ep==1.
	 * I really hate to do this here, but it seems like the API exported
	 * by the USB bus interface controller driver to the usbd-bi module 
	 * isn't quite right so there is no good place to do this.
	 */
	if (ep == 1) {
		omap_deconfigure_device();
		omap_configure_device(device);
	}

	UDCDBG("setting up physical endpoint %d", ep);

	if (endpoint && (ep < UDC_MAX_ENDPOINTS)) {
		int ep_addr = PHYS_EP_TO_EP_ADDR(ep);

		if (!ep) {
			/* nothing to do for endpoint 0 */
		} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
			/* nothing to do for IN (tx) endpoints */
		} else {	/* OUT (rx) endpoint */
			if (endpoint->rcv_packetSize) {
				/* Why are we pre-allocating 5 urbs?  Because 
				 * most of the other existing USB controller 
				 * drivers pre-allocate 5 urbs.  We must 
				 * allocate enough urbs so that we never run 
				 * out of urbs in our endpoint->rdy queue 
				 * because the function driver hasn't had a 
				 * chance to process an urb from the 
				 * endpoint->rcv queue and recycle it back to 
				 * the rdy queue.
				 */
				usbd_fill_rcv(device, endpoint, 5);
				endpoint->rcv_urb =
				    first_urb_detached(&endpoint->rdy);
				omap_prepare_endpoint_for_rx(ep);
			}
		}
	}
}

/**
 * udc_disable_ep - disable endpoint
 * @ep:
 *
 * Disable specified endpoint
 */
void
udc_disable_ep(unsigned int ep)
{
	int ep_addr = PHYS_EP_TO_EP_ADDR(ep);
	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
	struct usb_endpoint_instance *endpoint =
	    udc_device->bus->endpoint_array + ep;

	UDCDBG("disable ep %d", ep);

	if (!ep_num) {
		/* nothing to do for endpoint 0 */ ;
	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
		if (endpoint->tx_packetSize) {
			/* we have a valid tx endpoint */
			usbd_flush_tx(endpoint);
		}
	} else {
		if (endpoint->rcv_packetSize) {
			/* we have a valid rx endpoint */
			usbd_flush_rcv(endpoint);
		}
	}
}

/* ************************************************************************** */

/**
 * udc_connected - is the USB cable connected
 *
 * Return non-zero if cable is connected.
 */
int
udc_connected(void)
{
	return ((inw(UDC_DEVSTAT) & UDC_ATT) == UDC_ATT);
}

/* Turn on the USB connection by enabling the pullup resistor */
void
udc_connect(void)
{
	UDCDBG("connect, enable Pullup");
	outw(inw(UDC_SYSCON1) | UDC_Pullup_En, UDC_SYSCON1);
	UDCREG(UDC_SYSCON1);
#ifdef CONFIG_OMAP_H2
	usbd_do_connect = 1;
	up(&usbd_connect_lock);
#endif
}

/* Turn off the USB connection by disabling the pullup resistor */
void
udc_disconnect(void)
{
	UDCDBG("disconnect, disable Pullup");
	outw(inw(UDC_SYSCON1) & ~UDC_Pullup_En, UDC_SYSCON1);
	UDCREG(UDC_SYSCON1);
#ifdef CONFIG_OMAP_H2
	down(&usbd_i2c_lock);
	usbd_do_connect = 0;
	if (usbd_connected) {
		/*disable pull-up resistor on D+ */
		i2c_write(0xC, ISP1301_I2C_OTG_CONTROL_1);
		i2c_write(~0xC,
			  ISP1301_I2C_OTG_CONTROL_1 |
			  ISP1301_I2C_REG_CLEAR_ADDR);
		usbd_connected = 0;
	}
	up(&usbd_i2c_lock);
#endif
}

/* ************************************************************************** */

/**
 * udc_enable_interrupts - enable interrupts
 *
 * Switch on UDC interrupts.
 *
 */
void
udc_all_interrupts(struct usb_device_instance *device)
{
	UDCDBG("enabling all endpoint interrupts");
	outw( /* UDC_Sof_IE | */ UDC_EPn_RX_IE | UDC_EPn_TX_IE | UDC_DS_Chg_IE
	     | UDC_EP0_IE, UDC_IRQ_EN);
}

/**
 * udc_suspended_interrupts - enable suspended interrupts
 *
 * Switch on only UDC resume interrupt.
 *
 */
void
udc_suspended_interrupts(struct usb_device_instance *device)
{
	UDCDBG("enabling resume interrupt (DS_Chg)");
	outw(UDC_DS_Chg_IE, UDC_IRQ_EN);
}

/*
 * udc_disable_interrupts - disable interrupts
 * switch off interrupts
 */
void
udc_disable_interrupts(struct usb_device_instance *device)
{
	UDCDBG("disabling all interrupts");
	outw(0, UDC_IRQ_EN);
}

/* ************************************************************************** */

/**
 * udc_ep0_packetsize - return ep0 packetsize
 */
int
udc_ep0_packetsize(void)
{
	return EP0_PACKETSIZE;
}

/* Switch on the UDC */
void
udc_enable(struct usb_device_instance *device)
{
	UDCDBG("enable device %p, status %d", device, device->status);

	/* initialize driver state variables */
	udc_devstat = 0;

	/* Save the device structure pointer */
	udc_device = device;

	/* Setup ep0 urb */
	if (!ep0_urb) {
		if (!(ep0_urb = usbd_alloc_urb(device,
					       device->function_instance_array,
					       0, 512))) {
			printk(KERN_ERR "udc_enable: usbd_alloc_urb failed\n");
		}
	} else {
		printk(KERN_ERR "udc_enable: ep0_urb already allocated\n");
	}

	UDCDBG("Check clock status");
	UDCREG(STATUS_REQ);

	/* The VBUS_MODE bit selects whether VBUS detection is done via
	 * software (1) or hardware (0).  When software detection is
	 * selected, VBUS_CTRL selects whether USB is not connected (0)
	 * or connected (1).
	 */
	outl(inl(FUNC_MUX_CTRL_0) | UDC_VBUS_CTRL | UDC_VBUS_MODE,
	     FUNC_MUX_CTRL_0);
	UDCREGL(FUNC_MUX_CTRL_0);
#ifdef CONFIG_ARCH_OMAP1610
	//OTG_CTRL.18 = 1 (BSESSVLD) //1 = host attached (VBUS present)
	outl((1 << 18), OTG_CTRL);
#endif

	omap_configure_device(device);
}

/* Switch off the UDC */
void
udc_disable(void)
{
	UDCDBG("disable UDC");

	omap_deconfigure_device();

#ifdef CONFIG_ARCH_OMAP1610
	//OTG_CTRL.18 = 0 (BSESSVLD) //1 = host attached (VBUS present)
	outl(0, OTG_CTRL);
#endif
	/* The VBUS_MODE bit selects whether VBUS detection is done via
	 * software (1) or hardware (0).  When software detection is
	 * selected, VBUS_CTRL selects whether USB is not connected (0)
	 * or connected (1).
	 */
	outl(inl(FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
	outl(inl(FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
	UDCREGL(FUNC_MUX_CTRL_0);

	/* Free ep0 URB */
	if (ep0_urb) {
		usbd_dealloc_urb(ep0_urb);
		ep0_urb = NULL;
	}

	/* Reset device pointer.
	 * We ought to do this here to balance the initialization of udc_device 
	 * in udc_enable, but some of our other exported functions get called 
	 * by the bus interface driver after udc_disable, so we have to hang on
	 * to the device pointer to avoid a null pointer dereference. */
	/* udc_device = NULL; */
}

/**
 * udc_startup - allow udc code to do any additional startup
 */
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(device, DEVICE_INIT, 0);

	/* The DEVICE_CREATE event puts the USB device in the state 
	 * STATE_ATTACHED.
	 */
	usbd_device_event(device, DEVICE_CREATE, 0);

	/* Some USB controller driver implementations signal 
	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
	 * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
	 * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
	 * The OMAP USB client controller has the capability to detect when the
	 * USB cable is connected to a powered USB bus via the ATT bit in the 
	 * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and 
	 * DEVICE_RESET events until later.
	 */
}

/* ************************************************************************** */

/* Return name of this UDC */
char *
udc_name(void)
{
	return UDC_NAME;
}

/* Request all UDC interrups */
int
udc_request_udc_irq(void)
{
	UDCDBG("installing interrupt handlers");

	/* Request general USB interrupt */
	if (request_irq(UDC_IRQ, omap_udc_irq, SA_INTERRUPT |
			SA_SAMPLE_RANDOM, UDC_NAME " Bus Interface", NULL)) {
		printk(KERN_ERR UDC_NAME
		       ": couldn't register USB interrupt handler\n");
		goto request_irq_failed;
	}

	/* Request non-ISO endpoint-specific interrupt */
	if (request_irq(UDC_NONISO_IRQ, omap_udc_noniso_irq, SA_INTERRUPT |
			SA_SAMPLE_RANDOM, UDC_NAME " non-ISO endpoints",
			NULL)) {
		printk(KERN_ERR UDC_NAME
		       ": couldn't register USB non-ISO interrupt handler\n");
		goto request_noniso_irq_failed;
	}

	/* Request Start-of-Frame interrupt for ISO transactions */
	if (request_irq(UDC_SOF_IRQ, omap_udc_sof_irq, SA_INTERRUPT |
			SA_SAMPLE_RANDOM, UDC_NAME " SOF ISO", NULL)) {
		printk(KERN_ERR UDC_NAME
		       ": couldn't register USB SOF ISO interrupt handler\n");
		goto request_sof_irq_failed;
	}
	return 0;

      request_sof_irq_failed:
	free_irq(UDC_NONISO_IRQ, NULL);
      request_noniso_irq_failed:
	free_irq(UDC_IRQ, NULL);
      request_irq_failed:
	return -EINVAL;
}

/* Release all UDC interrupts */
void
udc_release_udc_irq(void)
{
	UDCDBG("release all interrupts");
	free_irq(UDC_IRQ, NULL);
	free_irq(UDC_NONISO_IRQ, NULL);
	free_irq(UDC_SOF_IRQ, NULL);
}

/* Request UDC IO region */
int
udc_request_io(void)
{
#ifdef CONFIG_OMAP_H2
	int tmp = (int) request_region(OTG_BASE, OTG_IOSIZE, "OMAP H2 USBD BI");
	if (!tmp) {
		printk(KERN_ERR UDC_NAME ": OTG is already in use\n");
		udc_release_io();
		return -ENODEV;
	}
	initstate_region = 1;
	tmp = i2c_configure();
	if (tmp < 0) {
		udc_release_io();
		return tmp;
	}
	/*init thread */
	connect_thread_terminating = 0;
	tmp =
	    kernel_thread(&usbd_connect_thread, NULL,
			  CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
	if (tmp < 0) {
		printk(KERN_ERR UDC_NAME ": could not start thread\n");
		udc_release_io();
		return tmp;
	}
	initstate_thread = 1;
	isp1301_configure();
#endif
	return 0;
}

/* Release UDC IO region */
void
udc_release_io(void)
{
#ifdef CONFIG_OMAP_H2
	//OTG_CTRL.18 = 0 (BSESSVLD) //1 = host attached (VBUS present)
	outl(0, OTG_CTRL);

	if (initstate_thread) {
		connect_thread_terminating = 1;
		up(&usbd_connect_lock);
		wait_for_completion(&connect_thread_exit);
	}
	i2c_close();
	if (initstate_region) {
		release_region(OTG_BASE, OTG_IOSIZE);
		initstate_region = 0;
	}
#endif
}

/* Request UDC cable interrupt */
int
udc_request_cable_irq(void)
{
	/* Cable events are handled via the Ds_Chg ISR, so we don't need to 
	 * install a separate handler here.
	 */
	return 0;
}

/* Release UDC cable interrupt */
void
udc_release_cable_irq(void)
{
}

/* Dump all UDC registers */
void
udc_regs(void)
{
	UDCDBG("** ALL UDC registers **");
	UDCREG(UDC_REV);
	UDCREG(UDC_EP_NUM);
	UDCREG(UDC_SYSCON1);
	UDCREG(UDC_DEVSTAT);
	UDCREG(UDC_SOF);
	UDCREG(UDC_IRQ_EN);
	UDCREG(UDC_DMA_IRQ_EN);
	UDCREG(UDC_IRQ_SRC);
	UDCREG(UDC_EPN_STAT);
	UDCREG(UDC_DMAN_STAT);
}