Ejemplo n.º 1
0
/*
 * U-Boot USB interface
 */
int usb_lowlevel_init(int index, void **controller)
{
	/*
	 * We need doubleword-aligned buffers for DMA transfers
	 */
	allocated_buffer = (uint8_t *)malloc(DWC_OTG_HCD_STATUS_BUF_SIZE + DWC_OTG_HCD_DATA_BUF_SIZE + 8);
	uint32_t addr = (uint32_t)allocated_buffer;
	aligned_buffer = (uint8_t *) ((addr + 7) & ~7);
	status_buffer = (uint8_t *)((uint32_t)aligned_buffer + DWC_OTG_HCD_DATA_BUF_SIZE);
	int i, j;
	hprt0_data_t hprt0 = {.d32 = 0 };

	root_hub_devnum = 0;
	memset(&g_core_if, 0, sizeof(g_core_if));
	dwc_otg_cil_init(&g_core_if, (uint32_t *)CONFIG_SYS_USB_ADDRESS);

	if ((g_core_if.snpsid & 0xFFFFF000) !=
		0x4F542000) {
		printf("SNPSID is invalid (not DWC OTG device): %08x\n", g_core_if.snpsid);
		return -1;
	}

	dwc_otg_core_init(&g_core_if);
	dwc_otg_core_host_init(&g_core_if);

	hprt0.d32 = dwc_otg_read_hprt0(&g_core_if);
	hprt0.b.prtrst = 1;
	dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
	mdelay(50);
	hprt0.b.prtrst = 0;
	dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
	
	for (i = 0; i < MAX_DEVICE; i++) {
		for (j = 0; j < MAX_ENDPOINT; j++) {
			control_data_toggle[i][j] = DWC_OTG_HC_PID_DATA1;
			bulk_data_toggle[i][j] = DWC_OTG_HC_PID_DATA0;
		}
	}

	return 0;
}

int usb_lowlevel_stop(int index)
{
	free(allocated_buffer);

	return 0;
}
Ejemplo n.º 2
0
/**
 * Store the value in the register at the offset in the reg_offset
 * attribute.
 * 
 */
static ssize_t regvalue_store( struct device *_dev,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
			       struct device_attribute *attr,
#endif
			       const char *buf, 
			       size_t count ) 
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#else
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#endif
	volatile uint32_t * addr;
	uint32_t val = simple_strtoul(buf, NULL, 16);
	//dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
	if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
		/* Calculate the address */
		addr = (uint32_t*)(otg_dev->reg_offset + 
				   (uint8_t*)otg_dev->base);
		//dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); 
		dwc_write_reg32( addr, val );
	}
	else {
		dev_err(_dev, "Invalid Register Offset (0x%08x)\n", 
			otg_dev->reg_offset);
	}
	return count;
}
Ejemplo n.º 3
0
/**
 * Set the Bus Power status
 */
static ssize_t buspower_store( struct device *_dev,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
			       struct device_attribute *attr,
#endif
			       const char *buf, 
			       size_t count ) 
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#else
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#endif
	uint32_t on = simple_strtoul(buf, NULL, 16);
	uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0;
	hprt0_data_t mem;

	mem.d32 = dwc_read_reg32(addr);
	mem.b.prtpwr = on;

	//dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32);
	dwc_write_reg32(addr, mem.d32);

	return count;
}
Ejemplo n.º 4
0
/**
 * Displays the time required to write the GNPTXFSIZ register many times (the
 * output shows the number of times the register is written).
 */
static ssize_t wr_reg_test_show( struct device *_dev,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
				 struct device_attribute *attr,
#endif
				 char *buf) 
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#else
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#endif
	uint32_t reg_val;
	int i;
	int time;
	int start_jiffies;

	printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
	       HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
	reg_val = dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz);
	start_jiffies = jiffies;
	for (i = 0; i < RW_REG_COUNT; i++) {
		dwc_write_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz, reg_val);
	}
	time = jiffies - start_jiffies;
   	return sprintf( buf, "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
			RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
}
Ejemplo n.º 5
0
/**
 * This function writes a packet into the Tx FIFO associated with the
 * EP.  For non-periodic EPs the non-periodic Tx FIFO is written.  For
 * periodic EPs the periodic Tx FIFO associated with the EP is written
 * with all packets for the next micro-frame.
 *
 * @param _core_if Programming view of DWC_otg controller.
 * @param _ep The EP to write packet for.
 * @param _dma Indicates if DMA is being used.
 */
void dwc_otg_ep_write_packet( dwc_ep_t *_ep)
{
	/**
	 * The buffer is padded to DWORD on a per packet basis in
	 * slave/dma mode if the MPS is not DWORD aligned.  The last
	 * packet, if short, is also padded to a multiple of DWORD.
	 *
	 * ep->xfer_buff always starts DWORD aligned in memory and is a 
	 * multiple of DWORD in length
	 *
	 * ep->xfer_len can be any number of bytes
	 *
	 * ep->xfer_count is a multiple of ep->maxpacket until the last 
	 *  packet
	 *
	 * FIFO access is DWORD */

	uint32_t i;
	uint32_t byte_count;
	uint32_t dword_count;
	uint32_t fifo;
        uint8_t *data_buff = _ep->xfer_buff;
        uint32_t temp_data ;

	//DBG("dwc_otg_ep_write_packet() : %d\n",_ep->xfer_len);
        if (_ep->xfer_count >= _ep->xfer_len) {
                //DWC_WARN("%s() No data for EP%d!!!\n", "dwc_otg_ep_write_packet", _ep->num);
                return;                
        }

	/* Find the byte length of the packet either short packet or MPS */
	if ((_ep->xfer_len - _ep->xfer_count) < _ep->maxpacket) {
		byte_count = _ep->xfer_len - _ep->xfer_count;
	}
	else {
		byte_count = _ep->maxpacket;
	}

	/* Find the DWORD length, padded by extra bytes as neccessary if MPS
	 * is not a multiple of DWORD */
	dword_count =  (byte_count + 3) / 4;


       //fifo = _core_if->data_fifo[_ep->num];
     fifo = DWC_REG_DATA_FIFO(_ep->num);


	for (i=0; i<dword_count; i++) {
		temp_data =get_unaligned(data_buff);
		dwc_write_reg32( fifo, temp_data );
		data_buff += 4;
	}


	_ep->xfer_count += byte_count;
        _ep->xfer_buff += byte_count;

	flush_cpu_cache();

}
Ejemplo n.º 6
0
/**
 * Set the Bus Suspend status
 */
static ssize_t bussuspend_store(struct device *_dev,
				struct device_attribute *attr, const char *buf,
				size_t count)
{
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
	uint32_t in;
	uint32_t *addr; 
	hprt0_data_t mem;

	if(strncmp(buf, "1", sizeof("1")-1) == 0)
		in = 1;
	else if(strncmp(buf, "0", sizeof("0")-1) == 0)
		in = 0;
	else
		in = simple_strtoul(buf, NULL, 16);
	
	addr = (uint32_t *) otg_dev->core_if->host_if->hprt0;

	mem.d32 = dwc_read_reg32(addr);
	mem.b.prtsusp = in;
	dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t) addr,
		mem.d32);
	dwc_write_reg32(addr, mem.d32);
	return count;
}
/** This function will log a debug message
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t *core_if)
{
	gintsts_data_t gintsts;
	DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
		 dwc_otg_mode(core_if) ? "Host" : "Device");

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.modemismatch = 1;
	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}
/**
 * Set the HNP Request bit
 */
static ssize_t hnp_store( struct device *_dev, struct device_attribute *attr, const char *buf,
			  size_t count )
{
        dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
	uint32_t in = simple_strtoul(buf, NULL, 16);
	uint32_t *addr = (uint32_t *)&(otg_dev->core_if->core_global_regs->gotgctl);
	gotgctl_data_t mem;
	mem.d32 = dwc_read_reg32(addr);
	mem.b.hnpreq = in;
	dev_dbg(_dev, "Storing Address=%p Data=0x%08x\n", addr, mem.d32);
	dwc_write_reg32(addr, mem.d32);
	return count;
}
Ejemplo n.º 9
0
/**
 * This function configures EP0 to receive SETUP packets.
 *
 * @todo NGS: Update the comments from the HW FS.
 *
 *  -# Program the following fields in the endpoint specific registers
 *  for Control OUT EP 0, in order to receive a setup packet
 * 	- DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
 * 	  setup packets)
 *	- DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
 *	  to back setup packets)
 *      - In DMA mode, DOEPDMA0 Register with a memory address to
 *        store any setup packets received
 *
 */
static void ep0_out_start(void)
{
	deptsiz0_data_t doeptsize0 = { 0};
	depctl_data_t doepctl = { 0 };

	doeptsize0.b.supcnt = 3;
	doeptsize0.b.pktcnt = 1;
	doeptsize0.b.xfersize = 8*3;

	DBG("ep0_out_start()\n");
	dwc_write_reg32( DWC_REG_OUT_EP_TSIZE(0),doeptsize0.d32 );


	// EP enable
	doepctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(0));
	doepctl.b.epena = 1;

	doepctl.d32 = 0x80008000;
	dwc_write_reg32(DWC_REG_OUT_EP_REG(0),doepctl.d32);

	flush_cpu_cache();
}
Ejemplo n.º 10
0
/**
 * Set the Bus Suspend status
 */
static ssize_t bussuspend_store( struct device *_dev,
								struct device_attribute *attr, 
								const char *buf, size_t count ) 
{
        dwc_otg_device_t *otg_dev = _dev->platform_data;
	uint32_t in = simple_strtoul(buf, NULL, 16);
	uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0;
	hprt0_data_t mem;
	mem.d32 = dwc_read_reg32(addr);
	mem.b.prtsusp = in;
	dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32);
	dwc_write_reg32(addr, mem.d32);
	return count;
}
/**
 * Set the Bus Power status
 */
static ssize_t buspower_store( struct device *_dev, struct device_attribute *attr, const char *buf,
                               size_t count )
{
        dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
	uint32_t on = simple_strtoul(buf, NULL, 16);
	uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0;
	hprt0_data_t mem;

	mem.d32 = dwc_read_reg32(addr);
	mem.b.prtpwr = on;

	//dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32);
	dwc_write_reg32(addr, mem.d32);

	return count;
}
Ejemplo n.º 12
0
int dwc_common_irq()
{
	gotgint_data_t gotgint;
	
	gotgint.d32 = dwc_read_reg32(DWC_REG_GOTGINT);
	if(gotgint.d32 == 0)
		return 0;
//	if(gotgint.b.sesreqsucstschng)
//	{
//		DBG("Session Request Success Status Change\n");
//	}
	dwc_write_reg32(DWC_REG_GOTGINT,gotgint.d32); // clear intr


	return 0;
}
Ejemplo n.º 13
0
/**
 * Store the value in the register at the offset in the reg_offset
 * attribute.
 *
 */
static ssize_t regvalue_store(struct device *_dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
	uint32_t __iomem *addr;
	uint32_t val = simple_strtoul(buf, NULL, 16);

	if (otg_dev->reg_offset != 0xffffffff && 0 != otg_dev->base) {
		/* Calculate the address */
		addr = (uint32_t __iomem *)(otg_dev->base +
						otg_dev->reg_offset);
		dwc_write_reg32(addr, val);
	} else {
		dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
			otg_dev->reg_offset);
	}
	return count;
}
Ejemplo n.º 14
0
int dwc_pcd_irq()
{
	gintsts_data_t  gintr_status;
	gintsts_data_t  gintr_msk;

	gintr_msk.d32 = dwc_read_reg32(DWC_REG_GINTMSK);
	gintr_status.d32 = dwc_read_reg32(DWC_REG_GINTSTS);
	if((gintr_status.d32 & gintr_msk.d32)== 0)
		return 0;
	
	//DBG("irq gintmsk:  0x%08x\n",gintr_msk.d32);
	//DBG("irq gintrsts: 0x%08x\n",gintr_status.d32);

	gintr_status.d32 = gintr_status.d32 & gintr_msk.d32;
	//DBG("irq gintmsk & gintrsts = 0x%08x\n",gintr_status.d32);

	if (gintr_status.b.rxstsqlvl) {
	    dwc_otg_pcd_handle_rx_status_q_level_intr();
	}
	if (gintr_status.b.nptxfempty) {
	    dwc_otg_pcd_handle_np_tx_fifo_empty_intr( );
	}

	if (gintr_status.b.usbreset) {
	   dwc_otg_pcd_handle_usb_reset_intr( );
	}
	if (gintr_status.b.enumdone) {
	    dwc_otg_pcd_handle_enum_done_intr();
	}
	if (gintr_status.b.epmismatch) {
	    //dwc_otg_pcd_handle_ep_mismatch_intr( core_if );
	}
	if (gintr_status.b.inepint) {
	    dwc_otg_pcd_handle_in_ep_intr();
	}
	if (gintr_status.b.outepintr) {
	    dwc_otg_pcd_handle_out_ep_intr( );
	}

	dwc_write_reg32(DWC_REG_GINTSTS,gintr_status.d32);
	flush_cpu_cache();
	return 0;
}
/**
 * Displays the time required to write the GNPTXFSIZ register many times (the
 * output shows the number of times the register is written).
 */
static ssize_t wr_reg_test_show( struct device *_dev, struct device_attribute *attr, char *buf)
{
	int i;
	int time;
	int start_jiffies;
        dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
	uint32_t reg_val;

	printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
	       HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
	reg_val = dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz);
	start_jiffies = jiffies;
	for (i = 0; i < RW_REG_COUNT; i++) {
		dwc_write_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz, reg_val);
	}
	time = jiffies - start_jiffies;
   	return sprintf( buf, "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
			RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
}
Ejemplo n.º 16
0
int dwc_common_irq(void)
{
	int ret = 0;
	gotgint_data_t gotgint;

	gotgint.d32 = dwc_read_reg32(DWC_REG_GOTGINT);
	if (gotgint.d32 == 0)
		return 0;
	if (gotgint.b.sesreqsucstschng) {
		ERR("Session Request Success Status Change\n");
	}
	if (gotgint.b.sesenddet) {
		ERR("Session End Detected, Line Disconected\n");
                cb_4_dis_connect_intr();
	}

	dwc_write_reg32(DWC_REG_GOTGINT,gotgint.d32); // clear intr

	return ret;
}
/**
 * Store the value in the register at the offset in the reg_offset
 * attribute.
 *
 */
static ssize_t regvalue_store( struct device *_dev, struct device_attribute *attr, const char *buf,
                               size_t count )
{
        dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
	volatile uint32_t * addr;
	uint32_t val = simple_strtoul(buf, NULL, 16);
	//dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
	if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
		/* Calculate the address */
		addr = (uint32_t*)(otg_dev->reg_offset +
				   (uint8_t*)otg_dev->base);
		//dev_dbg(_dev, "@0x%08x\n", (unsigned)addr);
		dwc_write_reg32( addr, val );
	}
	else {
		dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
			otg_dev->reg_offset);
	}
	return count;
}
Ejemplo n.º 18
0
/**
 * Set the HNP Request bit
 */
static ssize_t hnp_store( struct device *_dev,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
			  struct device_attribute *attr,
#endif
			  const char *buf, 
			  size_t count ) 
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#else
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#endif
	uint32_t in = simple_strtoul(buf, NULL, 16);
	uint32_t *addr = (uint32_t *)&(otg_dev->core_if->core_global_regs->gotgctl);
	gotgctl_data_t mem;
	mem.d32 = dwc_read_reg32(addr);
	mem.b.hnpreq = in;
	dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32);
	dwc_write_reg32(addr, mem.d32);
	return count;
}
Ejemplo n.º 19
0
static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
				 void *buffer, int transfer_len,
				 struct devrequest *cmd)
{
	int leni = transfer_len;
	int len = 0;
	int stat = 0;
	__u16 bmRType_bReq;
	__u16 wValue;
	__u16 wLength;
	unsigned char data[32];
	hprt0_data_t hprt0 = {.d32 = 0 };

	if (usb_pipeint(pipe)) {
		printf("Root-Hub submit IRQ: NOT implemented");
		return 0;
	}

	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
	wValue	      = cpu_to_le16 (cmd->value);
	wLength	      = cpu_to_le16 (cmd->length);

	switch (bmRType_bReq) {
	case RH_GET_STATUS:
		*(__u16 *)buffer = cpu_to_le16(1);
		len = 2;
		break;
	case RH_GET_STATUS | RH_INTERFACE:
		*(__u16 *)buffer = cpu_to_le16(0);
		len = 2;
		break;
	case RH_GET_STATUS | RH_ENDPOINT:
		*(__u16 *)buffer = cpu_to_le16(0);
		len = 2;
		break;
	case RH_GET_STATUS | RH_CLASS:
		*(__u32 *)buffer = cpu_to_le32(0);
		len = 4;
		break;
	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
		{
			uint32_t port_status = 0;
			uint32_t port_change = 0;
			hprt0.d32 = dwc_read_reg32(g_core_if.host_if->hprt0);
			if (hprt0.b.prtconnsts)
				port_status |= USB_PORT_STAT_CONNECTION;
			if (hprt0.b.prtena)
				port_status |= USB_PORT_STAT_ENABLE;
			if (hprt0.b.prtsusp)
				port_status |= USB_PORT_STAT_SUSPEND;
			if (hprt0.b.prtovrcurract)
				port_status |= USB_PORT_STAT_OVERCURRENT;
			if (hprt0.b.prtrst)
				port_status |= USB_PORT_STAT_RESET;
			if (hprt0.b.prtpwr)
				port_status |= USB_PORT_STAT_POWER;

			port_status |= USB_PORT_STAT_HIGH_SPEED;

			if (hprt0.b.prtenchng)
				port_change |= USB_PORT_STAT_C_ENABLE;
			if (hprt0.b.prtconndet)
				port_change |= USB_PORT_STAT_C_CONNECTION;
			if (hprt0.b.prtovrcurrchng)
				port_change |= USB_PORT_STAT_C_OVERCURRENT;

			*(__u32 *)buffer = cpu_to_le32(port_status |
						(port_change << 16));
			len = 4;
		}
		break;
	case RH_CLEAR_FEATURE | RH_ENDPOINT:
	case RH_CLEAR_FEATURE | RH_CLASS:
		break;

	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
		switch (wValue) {
		case RH_C_PORT_CONNECTION:
			hprt0.d32 = dwc_read_reg32(g_core_if.host_if->hprt0);
			hprt0.b.prtconndet = 1;
			dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
			break;
		}
		break;

	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
		switch (wValue) {
		case (RH_PORT_SUSPEND):
			break;

		case (RH_PORT_RESET):
			hprt0.d32 = dwc_otg_read_hprt0(&g_core_if);
			hprt0.b.prtrst = 1;
			dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
			mdelay(50);
			hprt0.b.prtrst = 0;
			dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);

			break;

		case (RH_PORT_POWER):
			hprt0.d32 = dwc_otg_read_hprt0(&g_core_if);
			hprt0.b.prtpwr = 1;
			dwc_write_reg32(g_core_if.host_if->hprt0, hprt0.d32);
			break;

		case (RH_PORT_ENABLE):
			break;
		}
		break;
	case RH_SET_ADDRESS:
		root_hub_devnum = wValue;
		break;
	case RH_GET_DESCRIPTOR:
		switch ((wValue & 0xff00) >> 8) {
		case (0x01): /* device descriptor */
			len = min_t(unsigned int,
				  leni,
				  min_t(unsigned int,
				      sizeof(root_hub_dev_des),
				      wLength));
			memcpy(buffer, root_hub_dev_des, len);
			break;
		case (0x02): /* configuration descriptor */
			len = min_t(unsigned int,
				  leni,
				  min_t(unsigned int,
				      sizeof(root_hub_config_des),
				      wLength));
			memcpy(buffer, root_hub_config_des, len);
			break;
		case (0x03): /* string descriptors */
			if (wValue == 0x0300) {
				len = min_t(unsigned int,
					  leni,
					  min_t(unsigned int,
					      sizeof(root_hub_str_index0),
					      wLength));
				memcpy(buffer, root_hub_str_index0, len);
			}
			if (wValue == 0x0301) {
				len = min_t(unsigned int,
					  leni,
					  min_t(unsigned int,
					      sizeof(root_hub_str_index1),
					      wLength));
				memcpy(buffer, root_hub_str_index1, len);
			}
			break;
		default:
			stat = USB_ST_STALLED;
		}
		break;

	case RH_GET_DESCRIPTOR | RH_CLASS:
	{
		__u32 temp = 0x00000001;

		data[0] = 9;		/* min length; */
		data[1] = 0x29;
		data[2] = temp & RH_A_NDP;
		data[3] = 0;
		if (temp & RH_A_PSM)
			data[3] |= 0x1;
		if (temp & RH_A_NOCP)
			data[3] |= 0x10;
		else if (temp & RH_A_OCPM)
			data[3] |= 0x8;

		/* corresponds to data[4-7] */
		data[5] = (temp & RH_A_POTPGT) >> 24;
		data[7] = temp & RH_B_DR;
		if (data[2] < 7) {
			data[8] = 0xff;
		} else {
			data[0] += 2;
			data[8] = (temp & RH_B_DR) >> 8;
			data[10] = data[9] = 0xff;
		}

		len = min_t(unsigned int, leni,
			    min_t(unsigned int, data[0], wLength));
		memcpy(buffer, data, len);
		break;
	}

	case RH_GET_CONFIGURATION:
		*(__u8 *) buffer = 0x01;
		len = 1;
		break;
	case RH_SET_CONFIGURATION:
		break;
	default:
		printf("unsupported root hub command\n");
		stat = USB_ST_STALLED;
	}
Ejemplo n.º 20
0
int dwc_pcd_irq(void)
{
	gintsts_data_t  gintr_status;
	gintsts_data_t  gintr_msk;

	gintr_msk.d32 = dwc_read_reg32(DWC_REG_GINTMSK);
	gintr_status.d32 = dwc_read_reg32(DWC_REG_GINTSTS);

	if ((gintr_status.d32 & gintr_msk.d32)== 0)
		return 0;

	DBG("irq gintmsk:  0x%08x\n",gintr_msk.d32);
	DBG("irq gintrsts: 0x%08x\n",gintr_status.d32);

	gintr_status.d32 = gintr_status.d32 & gintr_msk.d32;
	DBG("irq gintmsk & gintrsts = 0x%08x\n",gintr_status.d32);

    if (gintr_status.b.sofintr)
	{
        if (_sofintr_not_occur) {
			DWN_MSG("sof\n");
			_sofintr_not_occur = 0;
		}
	}

	if (gintr_status.b.rxstsqlvl) {
		dwc_otg_pcd_handle_rx_status_q_level_intr();
		pcd_out_completed(&this_pcd[0]);
	}
	if (gintr_status.b.nptxfempty) {
		dwc_otg_pcd_handle_np_tx_fifo_empty_intr( );
	}

	if (gintr_status.b.usbreset) {
	   dwc_otg_pcd_handle_usb_reset_intr( );
	}
	if (gintr_status.b.enumdone) {
	    dwc_otg_pcd_handle_enum_done_intr();
	}
	if (gintr_status.b.epmismatch) {
	    //dwc_otg_pcd_handle_ep_mismatch_intr( core_if );
	}
	if (gintr_status.b.inepint) {
	    dwc_otg_pcd_handle_in_ep_intr();
	}
	if (gintr_status.b.outepintr) {
	    dwc_otg_pcd_handle_out_ep_intr( );
	}

#if 0
    if (gintr_status.b.otgintr)
    {
        gotgint_data_t gotgint;

        gotgint.d32 = dwc_read_reg32(DWC_REG_GOTGINT);
        if (gotgint.b.sesenddet)
        {
            printf("dis-connect-intr\n");
            cb_4_dis_connect_intr();
        }
    }
#endif//#if 0

    dwc_write_reg32(DWC_REG_GINTSTS,gintr_status.d32);
    flush_cpu_cache();
	return 0;
}
Ejemplo n.º 21
0
/**
 * This function handles the Rx Status Queue Level Interrupt, which
 * indicates that there is a least one packet in the Rx FIFO.  The
 * packets are moved from the FIFO to memory, where they will be
 * processed when the Endpoint Interrupt Register indicates Transfer
 * Complete or SETUP Phase Done.
 *
 * Repeat the following until the Rx Status Queue is empty:
 *   -#	Read the Receive Status Pop Register (GRXSTSP) to get Packet
 *     	info
 *   -#	If Receive FIFO is empty then skip to step Clear the interrupt
 *     	and exit
 *   -#	If SETUP Packet call dwc_otg_read_setup_packet to copy the
 *   	SETUP data to the buffer
 *   -#	If OUT Data Packet call dwc_otg_read_packet to copy the data
 *     	to the destination buffer
 */
int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(void)
{
    gintmsk_data_t gintmask = { 0 };
    device_grxsts_data_t status;
    gintsts_data_t gintsts;
    dwc_ep_t *ep;


    DBG("dwc_otg_pcd_handle_rx_status_q_level_intr()\n");
    /* Disable the Rx Status Queue Level interrupt */
    gintmask.b.rxstsqlvl= 1;
    dwc_modify_reg32( DWC_REG_GINTMSK, gintmask.d32, 0);

    /* Get the Status from the top of the FIFO */
    status.d32 = dwc_read_reg32( DWC_REG_GRXSTSP);

    //DBG("rx status: ep%d, pktsts: %d\n",status.b.epnum,status.b.pktsts);

    /* Get pointer to EP structure */
    ep = &g_dwc_eps[status.b.epnum];

    switch (status.b.pktsts)
    {
        case DWC_DSTS_GOUT_NAK:
            DBG( "Global OUT NAK\n");
            break;

        case DWC_STS_DATA_UPDT:
            DBG( "OUT Data Packet\n");
            {
                if (status.b.bcnt && ep->xfer_buff)
                {
                    /** @todo NGS Check for buffer overflow? */
                    dwc_otg_read_packet( ep->xfer_buff,status.b.bcnt);
                    ep->xfer_count += status.b.bcnt;
                    ep->xfer_buff += status.b.bcnt;

                    if (!status.b.epnum)
                    {
                        /*const char* p = ep->xfer_buff - status.b.bcnt;*/
                        this_pcd[0].cmdtype.out_complete = 1;
                        /*
                         *if(!strcmp("power", p) || !strcmp("low_power", p)){
                         *    printf("%s, bcnt %d, cnt %d, %d\n", p, status.b.bcnt, ep->xfer_count, this_pcd.cmdtype.in_complete);
                         *}
                         */
                    }
                }
            }
            break;

        case DWC_STS_XFER_COMP:
            DBG("OUT Complete\n");
            break;

        case DWC_DSTS_SETUP_COMP:
            DBG("SETUP Complete\n");
            break;

        case DWC_DSTS_SETUP_UPDT:
            DBG("SETUP update\n");
            {
                static int _is_first_setup_out_in_cmd = 1;

                dwc_otg_read_setup_packet( this_pcd[0].setup_pkt.d32);
                this_pcd[0].request_enable = 1;
                ep->xfer_count += status.b.bcnt;

                DBG("set %d, %d\n", status.b.bcnt, ep->xfer_count);
                if (_is_first_setup_out_in_cmd) //first tplcmd/bulkcmd that in sequence 'setup + out + in'
                {
                    struct usb_ctrlrequest request = this_pcd[0].setup_pkt.req;
                    if ( USB_TYPE_VENDOR == (request.bRequestType & USB_TYPE_MASK) )
                    {
                        unsigned bRequest = request.bRequest;

                        if ((AM_REQ_WR_LARGE_MEM == bRequest) || (AM_REQ_RD_LARGE_MEM == bRequest)
                                ||(AM_REQ_TPL_CMD == bRequest) || (AM_REQ_TPL_STAT == bRequest)
                                || (AM_REQ_DOWNLOAD == bRequest) || (AM_REQ_BULKCMD == bRequest))
                        {
                            __udelay(20);//delay for first command that consisted of consecutive 'ep0 out', i.e. 'setup + out + in'
                            _is_first_setup_out_in_cmd = 0;
                        }
                    }
                }
            }
        break;

        default:
            //DBG( "Invalid Packet Status (0x%0x)\n", status.b.pktsts);
            break;

    }

    /* Enable the Rx Status Queue Level interrupt */
    dwc_modify_reg32( DWC_REG_GINTMSK, 0, gintmask.d32);
    /* Clear interrupt */
    gintsts.d32 = 0;
    gintsts.b.rxstsqlvl = 1;
    dwc_write_reg32 ( DWC_REG_GINTSTS, gintsts.d32);

    return 1;
}
Ejemplo n.º 22
0
/**
 * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
 * The active request is checked for the next packet to be loaded into
 * the non-periodic Tx FIFO.
 */
int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(void)
{
        gnptxsts_data_t txstatus = {0};
        gintsts_data_t gintsts;

        int epnum = 0;
        dwc_ep_t *ep = 0;
        uint32_t len = 0;
        int dwords;
	 depctl_data_t depctl;

	DBG("dwc_otg_pcd_handle_np_tx_fifo_empty_intr()\n");
        /* Get the epnum from the IN Token Learning Queue. */
	for (epnum=0; epnum < NUM_EP; epnum++)
	{

		ep = &g_dwc_eps[epnum];


		/* IN endpoint ? */
		if (epnum && !ep->is_in ) {
			continue;
	        }
		depctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(epnum));
	       if (depctl.b.epena != 1)
			continue;

		 if (ep->type == DWC_OTG_EP_TYPE_INTR && ep->xfer_len == 0)
			continue;

		 flush_cpu_cache();

	        len = ep->xfer_len - ep->xfer_count;
	        if (len > ep->maxpacket) {
	                len = ep->maxpacket;
	        }
	        dwords = (len + 3)/4;

		 //DBG("nptx: write data to fifo, ep%d , size %d\n",epnum,len);
	        /* While there is space in the queue and space in the FIFO and
	         * More data to tranfer, Write packets to the Tx FIFO */
	        txstatus.d32 = dwc_read_reg32( DWC_REG_GNPTXSTS );
	        while  (txstatus.b.nptxqspcavail > 0 &&
	                txstatus.b.nptxfspcavail > dwords &&
	                ep->xfer_count < ep->xfer_len) {

			   flush_cpu_cache();

			   /* Write the FIFO */
	                dwc_otg_ep_write_packet( ep );

	                len = ep->xfer_len - ep->xfer_count;
	                if (len > ep->maxpacket) {
	                        len = ep->maxpacket;
	                }
	                dwords = (len + 3)/4;
			   flush_cpu_cache();
			   //txstatus.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS);
#if 1
			   /*
				  TODO:  Remove these code.
				  Because, if code break from "while"(Line427), an incomplete-in-trans will occour.
				  Then the tansfer will break.
			   */
			   int retry = 50000;	//retry times
			   while (retry--)
			   {
			       txstatus.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS);
				if(txstatus.b.nptxqspcavail > 0  || //txstatus.b.nptxfspcavail <= dwords ||
					ep->xfer_count >= ep->xfer_len)
					break;
				else
				{
					flush_cpu_cache();
				}

			   }
			   if (retry <= 0)
			   {
				//DWC_ERROR("TxFIFO FULL: Can't trans data to HOST !\n");
			   }

			   /* END todo */
#endif
	        }

	}

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.nptxfempty = 1;
	dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32);

        return 1;
}
void w_conn_id_status_change(void *p)
{
	dwc_otg_core_if_t *core_if = p;
	uint32_t count = 0;
	gotgctl_data_t gotgctl = {.d32 = 0 };

	gotgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);

	/* B-Device connector (Device Mode) */
	if (gotgctl.b.conidsts) {
		/* Wait for switch to device mode. */
		while (!dwc_otg_is_device_mode(core_if)) {
			DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
				   (dwc_otg_is_host_mode(core_if) ? "Host" :
				    "Peripheral"));
			dwc_mdelay(100);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
			   "Connection id status change timed out");
#ifdef CONFIG_USB_OTG_UTILS
		if (core_if->xceiver->otg->set_vbus)
			core_if->xceiver->otg->set_vbus(core_if->xceiver->otg, false);
#endif
		core_if->op_state = B_PERIPHERAL;
		dwc_otg_core_init(core_if);
		dwc_otg_enable_global_interrupts(core_if);
		cil_pcd_start(core_if);
	} else {
		/* A-Device connector (Host Mode) */
		while (!dwc_otg_is_host_mode(core_if)) {
			DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
				   (dwc_otg_is_host_mode(core_if) ? "Host" :
				    "Peripheral"));
			dwc_mdelay(100);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
			   "Connection id status change timed out");
		core_if->op_state = A_HOST;
		/*
		 * Initialize the Core for Host mode.
		 */
		dwc_otg_core_init(core_if);
		dwc_otg_enable_global_interrupts(core_if);
		cil_hcd_start(core_if);
	}
}

/**
 * This function handles the Connector ID Status Change Interrupt.  It
 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
 * is a Device to Host Mode transition or a Host Mode to Device
 * Transition.
 *
 * This only occurs when the cable is connected/removed from the PHY
 * connector.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *core_if)
{

	/*
	 * Need to disable SOF interrupt immediately. If switching from device
	 * to host, the PCD interrupt handler won't handle the interrupt if
	 * host mode is already set. The HCD interrupt handler won't get
	 * called if the HCD state is HALT. This means that the interrupt does
	 * not get handled and Linux complains loudly.
	 */
	gintmsk_data_t gintmsk = {.d32 = 0 };
	gintsts_data_t gintsts = {.d32 = 0 };

	gintmsk.b.sofintr = 1;
	dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);

	DWC_DEBUGPL(DBG_CIL,
		    " ++Connector ID Status Change Interrupt++  (%s)\n",
		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));

	/*
	 * Need to schedule a work, as there are possible DELAY function calls
	 */
	DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
			   core_if, "connection id status change");

	/* Set flag and clear interrupt */
	gintsts.b.conidstschng = 1;
	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);

	return 1;
}

/**
 * This interrupt indicates that a device is initiating the Session
 * Request Protocol to request the host to turn on bus power so a new
 * session can begin. The handler responds by turning on bus power. If
 * the DWC_otg controller is in low power mode, the handler brings the
 * controller out of low power mode before turning on bus power.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t *core_if)
{
	hprt0_data_t hprt0;
	gintsts_data_t gintsts;

#ifndef DWC_HOST_ONLY
	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");

	if (dwc_otg_is_device_mode(core_if)) {
		DWC_PRINTF("SRP: Device mode\n");
	} else {
		DWC_PRINTF("SRP: Host mode\n");
		/* Turn on the port power bit. */
		hprt0.d32 = dwc_otg_read_hprt0(core_if);
		hprt0.b.prtpwr = 1;
		dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);

#ifdef CONFIG_USB_OTG
		if (core_if->core_params->otg_supp_enable) {
			/* Schedule a work item to init the core */
			DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_init_core,
					   core_if, "SRP detected");
		} else
#endif
		{
			/* Start the Connection timer. So a message can be displayed
			 * if connect does not occur within connection wait timeout */
			cil_hcd_session_start(core_if);
		}
	}
#endif

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.sessreqintr = 1;
	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);

	return 1;
}

void w_wakeup_detected(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;
	/*
	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
	 * so that OPT tests pass with all PHYs).
	 */
	hprt0_data_t hprt0 = {.d32 = 0 };
#if 0
	pcgcctl_data_t pcgcctl = {.d32 = 0 };
	/* Restart the Phy Clock */
	pcgcctl.b.stoppclk = 1;
	dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
	dwc_udelay(10);
#endif /*0 */
	hprt0.d32 = dwc_otg_read_hprt0(core_if);
	DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
/*      dwc_mdelay(70); */
	hprt0.b.prtres = 0;	/* Resume */
	dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
	DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
		    dwc_read_reg32(core_if->host_if->hprt0));

	cil_hcd_resume(core_if);

	/** Change to L0 state*/
	core_if->lx_state = DWC_OTG_L0;
}

void w_a_periph_done(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;

	if (core_if->op_state == A_PERIPHERAL) {
		/* Clear the a_peripheral flag, back to a_host. */
		cil_pcd_stop(core_if);
		cil_hcd_start(core_if);
		core_if->op_state = A_HOST;
	}
}

void w_peri_suspend_powersaving(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;

	if (core_if) {
		/* Clear DWC Core interrupts before PHY suspend,
		   this is because to prevent DWC core Hangs while 
		   accessing some registers with PHY suspended if at
		   all we get some core interrupts when phy in suspend*/

		/* Clear any pending OTG Interrupts */
		dwc_write_reg32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);

		/* Clear any pending interrupts */
		dwc_write_reg32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);

		dwc_otg_disable_global_interrupts(core_if);		

		/* Suspend trasceiver */
		usb_phy_set_suspend(core_if->xceiver, 1);
	}
}
Ejemplo n.º 24
0
/**
 * This interrupt indicates that an OUT EP has a pending Interrupt.
 * The sequence for handling the OUT EP interrupt is shown below:
 * -#	Read the Device All Endpoint Interrupt register
 * -#	Repeat the following for each OUT EP interrupt bit set (from
 *   	LSB to MSB).
 * -#	Read the Device Endpoint Interrupt (DOEPINTn) register
 * -#	If "Transfer Complete" call the request complete function
 * -#	If "Endpoint Disabled" complete the EP disable procedure.
 * -#	If "AHB Error Interrupt" log error
 * -#	If "Setup Phase Done" process Setup Packet (See Standard USB
 *   	Command Processing)
 */
static int32_t dwc_otg_pcd_handle_out_ep_intr(void)
{
#define CLEAR_OUT_EP_INTR(__epnum,__intr) \
do { \
        doepint_data_t doepint = { 0 }; \
	doepint.b.__intr = 1; \
	dwc_write_reg32(DWC_REG_OUT_EP_INTR(__epnum), \
			doepint.d32); \
} while (0)

        uint32_t ep_intr;
        doepint_data_t doepint = { 0 };
        uint32_t epnum = 0;
//	 uint32_t epnum_trans = 0;
        gintsts_data_t gintsts;

        DBG( "dwc_otg_pcd_handle_out_ep_intr()\n" );

	/* Read in the device interrupt bits */
        ep_intr = (dwc_read_reg32(DWC_REG_DAINT) &
                dwc_read_reg32( DWC_REG_DAINTMSK));
        ep_intr =( (ep_intr & 0xffff0000) >> 16);

	/* Clear the OUTEPINT in GINTSTS */
	gintsts.d32 = 0;
	gintsts.b.outepintr = 1;
	dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32);
	dwc_write_reg32(DWC_REG_DAINT, 0xFFFF0000 );

        while ( ep_intr ) {
            if (ep_intr&0x1) {
                    doepint.d32 = (dwc_read_reg32( DWC_REG_OUT_EP_INTR(epnum)) &
						dwc_read_reg32(DWC_REG_DOEPMSK));

                    /* Transfer complete */
			if ( doepint.b.xfercompl ) {
				DBG("EP%d OUT Xfer Complete\n", epnum);

				/* Clear the bit in DOEPINTn for this interrupt */
				CLEAR_OUT_EP_INTR(epnum,xfercompl);

				if (epnum == 0) {
					handle_ep0( 0 );
				} else {
					complete_ep( epnum,0 );
				}
                    }
                    /* Endpoint disable  */
                    if ( doepint.b.epdisabled ) {
                            DBG("EP%d OUT disabled\n", epnum);
				/* Clear the bit in DOEPINTn for this interrupt */
				CLEAR_OUT_EP_INTR(epnum,epdisabled);
                    }
                    /* AHB Error */
                    if ( doepint.b.ahberr ) {
                            DBG("EP%d OUT AHB Error\n", epnum);
				CLEAR_OUT_EP_INTR(epnum,ahberr);
                    }
                    /* Setup Phase Done (contorl EPs) */
                    if ( doepint.b.setup ) {
                            handle_ep0( 0 );
				CLEAR_OUT_EP_INTR(epnum,setup);
                    }
            }
		epnum++;
		ep_intr >>=1;
        }

        return 1;

#undef CLEAR_OUT_EP_INTR
}
Ejemplo n.º 25
0
/**
 * Read the device status register and set the device speed in the
 * data structure.
 * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
 */
int32_t dwc_otg_pcd_handle_enum_done_intr(void)
{
	gintsts_data_t gintsts;
	gusbcfg_data_t gusbcfg;
	/*dsts_data_t dsts;*/
	depctl_data_t diepctl;
	depctl_data_t doepctl;
	dctl_data_t dctl ={0};

	DBG("SPEED ENUM\n");

	/* Read the Device Status and Endpoint 0 Control registers */
	/*dsts.d32 = dwc_read_reg32(DWC_REG_DSTS);*/
	diepctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(0) );
	doepctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(0));

	/* Set the MPS of the IN EP based on the enumeration speed */
	diepctl.b.mps = DWC_DEP0CTL_MPS_64;
	dwc_write_reg32(DWC_REG_IN_EP_REG(0) , diepctl.d32);

	/* Enable OUT EP for receive */
	doepctl.b.epena = 1;
	dwc_write_reg32(DWC_REG_OUT_EP_REG(0), doepctl.d32);

	dctl.b.cgnpinnak = 1;
	dwc_modify_reg32(DWC_REG_DCTL, dctl.d32, dctl.d32);

        if (this_pcd[0].ep0state == EP0_DISCONNECT) {
				this_pcd[0].ep0state = EP0_IDLE;
		} else if (this_pcd[0].ep0state == EP0_STALL) {
				this_pcd[0].ep0state = EP0_IDLE;
        }

    this_pcd[0].ep0state = EP0_IDLE;


	/* Set USB turnaround time based on device speed and PHY interface. */
	gusbcfg.d32 = dwc_read_reg32(DWC_REG_GUSBCFG);
#if 0
	if (_pcd->gadget.speed == USB_SPEED_HIGH) {
		if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
			/* ULPI interface */
			gusbcfg.b.usbtrdtim = 9;
		}
		if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
			/* UTMI+ interface */
			if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16) {
				gusbcfg.b.usbtrdtim = 5;
			} else {
				gusbcfg.b.usbtrdtim = 9;
			}
		}
		if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
			/* UTMI+  OR  ULPI interface */
			if (gusbcfg.b.ulpi_utmi_sel == 1) {
				/* ULPI interface */
				gusbcfg.b.usbtrdtim = 9;
			} else {
				/* UTMI+ interface */
				if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16) {
					gusbcfg.b.usbtrdtim = 5;
				} else {
					gusbcfg.b.usbtrdtim = 9;
				}
			}
		}
	} else {
		/* Full or low speed */
		gusbcfg.b.usbtrdtim = 9;
	}
#else
	/* Full or low speed */
	gusbcfg.b.usbtrdtim = 5;
#endif
	dwc_write_reg32(DWC_REG_GUSBCFG, gusbcfg.d32);

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.enumdone = 1;
	dwc_write_reg32(DWC_REG_GINTSTS,gintsts.d32 );
	return 1;
}
/**
 * This function handles the OTG Interrupts. It reads the OTG
 * Interrupt Register (GOTGINT) to determine what interrupt has
 * occurred.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *core_if)
{
	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
	gotgint_data_t gotgint;
	gotgctl_data_t gotgctl;
	gintmsk_data_t gintmsk;
	gpwrdn_data_t gpwrdn;

	gotgint.d32 = dwc_read_reg32(&global_regs->gotgint);
	gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
		    op_state_str(core_if));

	if (gotgint.b.sesenddet) {
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
			    "Session End Detected++ (%s)\n",
			    op_state_str(core_if));
		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);

		if (core_if->op_state == B_HOST) {
			cil_pcd_start(core_if);
			core_if->op_state = B_PERIPHERAL;
		} else {
			/* If not B_HOST and Device HNP still set. HNP
			 * Did not succeed!*/
			if (gotgctl.b.devhnpen) {
				DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
				__DWC_ERROR
				    ("Device Not Connected/Responding!\n");
			}

			/* If Session End Detected the B-Cable has
			 * been disconnected. */
			/* Reset PCD and Gadget driver to a
			 * clean state. */
			core_if->lx_state = DWC_OTG_L0;
			cil_pcd_stop(core_if);

			if (core_if->adp_enable) {
				if (core_if->power_down == 2) {
					gpwrdn.d32 = 0;
					gpwrdn.b.pwrdnswtch = 1;
					dwc_modify_reg32(&core_if->
							 core_global_regs->
							 gpwrdn, gpwrdn.d32, 0);
				}

				gpwrdn.d32 = 0;
				gpwrdn.b.pmuactv = 1;
				dwc_modify_reg32(&core_if->core_global_regs->
						 gpwrdn, 0, gpwrdn.d32);

				dwc_otg_adp_sense_start(core_if);
			}
		}

		gotgctl.d32 = 0;
		gotgctl.b.devhnpen = 1;
		dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
	}
	if (gotgint.b.sesreqsucstschng) {
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
			    "Session Reqeust Success Status Change++\n");
		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
		if (gotgctl.b.sesreqscs) {
			if ((core_if->core_params->phy_type ==
			     DWC_PHY_TYPE_PARAM_FS)
			    && (core_if->core_params->i2c_enable)) {
				core_if->srp_success = 1;
			} else {
				cil_pcd_resume(core_if);
				/* Clear Session Request */
				gotgctl.d32 = 0;
				gotgctl.b.sesreq = 1;
				dwc_modify_reg32(&global_regs->gotgctl,
						 gotgctl.d32, 0);
			}
		}
	}
	if (gotgint.b.hstnegsucstschng) {
		/* Print statements during the HNP interrupt handling
		 * can cause it to fail.*/
		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
		if (gotgctl.b.hstnegscs) {
			if (dwc_otg_is_host_mode(core_if)) {
				core_if->op_state = B_HOST;
				/*
				 * Need to disable SOF interrupt immediately.
				 * When switching from device to host, the PCD
				 * interrupt handler won't handle the
				 * interrupt if host mode is already set. The
				 * HCD interrupt handler won't get called if
				 * the HCD state is HALT. This means that the
				 * interrupt does not get handled and Linux
				 * complains loudly.
				 */
				gintmsk.d32 = 0;
				gintmsk.b.sofintr = 1;
				dwc_modify_reg32(&global_regs->gintmsk,
						 gintmsk.d32, 0);
				cil_pcd_stop(core_if);
				/*
				 * Initialize the Core for Host mode.
				 */
				cil_hcd_start(core_if);
				core_if->op_state = B_HOST;
			}
		} else {
			gotgctl.d32 = 0;
			gotgctl.b.hnpreq = 1;
			gotgctl.b.devhnpen = 1;
			dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
			DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
			__DWC_ERROR("Device Not Connected/Responding\n");
			/* Stop and re-start PCD to move back to B_PERIPHERAL state */
			cil_pcd_stop(core_if);
			cil_pcd_start(core_if);
			core_if->op_state = B_PERIPHERAL;
		}
	}
	if (gotgint.b.hstnegdet) {
		/* The disconnect interrupt is set at the same time as
		 * Host Negotiation Detected.  During the mode
		 * switch all interrupts are cleared so the disconnect
		 * interrupt handler will not get executed.
		 */
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
			    "Host Negotiation Detected++ (%s)\n",
			    (dwc_otg_is_host_mode(core_if) ? "Host" :
			     "Device"));
		if (dwc_otg_is_device_mode(core_if)) {
			DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
				    core_if->op_state);
			cil_hcd_disconnect(core_if);
			cil_pcd_start(core_if);
			core_if->op_state = A_PERIPHERAL;
		} else {
			/*
			 * Need to disable SOF interrupt immediately. When
			 * switching from device to host, the PCD interrupt
			 * handler won't handle the interrupt if host mode is
			 * already set. The HCD interrupt handler won't get
			 * called if the HCD state is HALT. This means that
			 * the interrupt does not get handled and Linux
			 * complains loudly.
			 */
			gintmsk.d32 = 0;
			gintmsk.b.sofintr = 1;
			dwc_modify_reg32(&global_regs->gintmsk, gintmsk.d32, 0);
			cil_pcd_stop(core_if);
			cil_hcd_start(core_if);
			core_if->op_state = A_HOST;
		}
	}
	if (gotgint.b.adevtoutchng)
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
			    "A-Device Timeout Change++\n");

	if (gotgint.b.debdone)
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");

	/* Clear GOTGINT */
	dwc_write_reg32(&core_if->core_global_regs->gotgint, gotgint.d32);

	return 1;
}
/**
 * This interrupt indicates that the DWC_otg controller has detected a
 * resume or remote wakeup sequence. If the DWC_otg controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume
 * signaling. The handler schedules a time to stop resume signaling.
 */
int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t *core_if)
{
	gintsts_data_t gintsts;

	DWC_DEBUGPL(DBG_ANY,
		    "++Resume and Remote Wakeup Detected Interrupt++\n");

	DWC_DEBUGPL(DBG_PCD,
			"%s lxstate = %d\n", __func__, core_if->lx_state);

#ifdef CONFIG_USB_OTG_UTILS
	if (core_if->xceiver->set_suspend &&
	    (core_if->lx_state == DWC_OTG_L2) &&
	    !core_if->core_params->otg_supp_enable) {

#ifdef CONFIG_USB_DELAYED_SUSPEND_POWER_SAVING
		/* We can see a reset before suspend processing
		 * gets scheduled. Cancel it since we don't want to
		 * suspend after seeing reset
		 */
		DWC_TIMER_CANCEL(core_if->suspend_power_saving_timer);
#else
		/* REVISIT when we use the external wake interrupt */
		usb_phy_set_suspend(core_if->xceiver, 0);
#endif

	}
#endif

	if (dwc_otg_is_device_mode(core_if)) {
		dctl_data_t dctl = {.d32 = 0 };
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
			    dwc_read_reg32(&core_if->dev_if->dev_global_regs->
					   dsts));
		if (core_if->lx_state == DWC_OTG_L2) {
#ifdef PARTIAL_POWER_DOWN
			if (core_if->hwcfg4.b.power_optimiz) {
				pcgcctl_data_t power = {.d32 = 0 };

				power.d32 = dwc_read_reg32(core_if->pcgcctl);
				DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
					    power.d32);

				power.b.stoppclk = 0;
				dwc_write_reg32(core_if->pcgcctl, power.d32);

				power.b.pwrclmp = 0;
				dwc_write_reg32(core_if->pcgcctl, power.d32);

				power.b.rstpdwnmodule = 0;
				dwc_write_reg32(core_if->pcgcctl, power.d32);
			}
#endif
			/* Clear the Remote Wakeup Signaling */
			dctl.b.rmtwkupsig = 1;
			dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
					 dctl, dctl.d32, 0);

			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
							       p);
			}
		} else {
			glpmcfg_data_t lpmcfg;
			lpmcfg.d32 =
			    dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
			lpmcfg.b.hird_thres &= (~(1 << 4));
			dwc_write_reg32(&core_if->core_global_regs->glpmcfg,
					lpmcfg.d32);
		}
		/** Change to L0 state*/
		core_if->lx_state = DWC_OTG_L0;
	} else {
		if (core_if->lx_state != DWC_OTG_L1) {
Ejemplo n.º 28
0
/**
 * Set the register offset for the next Register Access          Read/Write
 */
static ssize_t regoffset_store(struct device *_dev,
			       struct device_attribute *attr,
			       const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)

	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t offset = simple_strtoul(buf, NULL, 16);

#if defined(PCI_INTERFACE)
	if (offset < 0x00040000) {
#else
	if (offset < SZ_256K) {
#endif
		otg_dev->reg_offset = offset;
	} else {
		dev_err(_dev, "invalid offset\n");
	}

	return count;
}

DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);

/**
 * Show the value of the register at the offset in the reg_offset
 * attribute.
 */
static ssize_t regvalue_show(struct device *_dev,
			     struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t val;
	volatile uint32_t *addr;

	if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
		/* Calculate the address */
		addr = (uint32_t *)(otg_dev->reg_offset +
				    (uint8_t *)otg_dev->base);
		val = dwc_read_reg32(addr);
		return snprintf(buf,
				sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
				"Reg@0x%06x = 0x%08x\n", otg_dev->reg_offset,
				val);
	} else {
		dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->reg_offset);
		return sprintf(buf, "invalid offset\n");
	}
}

/**
 * Store the value in the register at the offset in the reg_offset
 * attribute.
 *
 */
static ssize_t regvalue_store(struct device *_dev,
			      struct device_attribute *attr,
			      const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)

	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	volatile uint32_t *addr;
	uint32_t val = simple_strtoul(buf, NULL, 16);
	/* dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val); */
	if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
		/* Calculate the address */
		addr = (uint32_t *)(otg_dev->reg_offset +
				    (uint8_t *)otg_dev->base);
		dwc_write_reg32(addr, val);
	} else {
		dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
			otg_dev->reg_offset);
	}
	return count;
}

DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);

/*
 * Attributes
 */
DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");

/* DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); */
/* DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); */
DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");

DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
			     &(otg_dev->core_if->core_global_regs->gusbcfg),
			     "GUSBCFG");
DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
			     &(otg_dev->core_if->core_global_regs->grxfsiz),
			     "GRXFSIZ");
DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
			     &(otg_dev->core_if->core_global_regs->gnptxfsiz),
			     "GNPTXFSIZ");
DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
			     &(otg_dev->core_if->core_global_regs->gpvndctl),
			     "GPVNDCTL");
DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
			     &(otg_dev->core_if->core_global_regs->ggpio),
			     "GGPIO");
DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
			     "GUID");
DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
			     &(otg_dev->core_if->core_global_regs->gsnpsid),
			     "GSNPSID");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");

DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
			     &(otg_dev->core_if->core_global_regs->hptxfsiz),
			     "HPTXFSIZ");
DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");

/**
 * @todo Add code to initiate the HNP.
 */
/**
 * Show the HNP status bit
 */
static ssize_t hnp_show(struct device *_dev,
			struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	return sprintf(buf, "HstNegScs = 0x%x\n",
		       dwc_otg_get_hnpstatus(otg_dev->core_if));
}

/**
 * Set the HNP Request bit
 */
static ssize_t hnp_store(struct device *_dev,
			 struct device_attribute *attr,
			 const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	uint32_t in = simple_strtoul(buf, NULL, 16);
	dwc_otg_set_hnpreq(otg_dev->core_if, in);
	return count;
}

DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);

/**
 * @todo Add code to initiate the SRP.
 */
/**
 * Show the SRP status bit
 */
static ssize_t srp_show(struct device *_dev,
			struct device_attribute *attr, char *buf)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	return sprintf(buf, "SesReqScs = 0x%x\n",
		       dwc_otg_get_srpstatus(otg_dev->core_if));
#else
	return sprintf(buf, "Host Only Mode!\n");
#endif
}

/**
 * Set the SRP Request bit
 */
static ssize_t srp_store(struct device *_dev,
			 struct device_attribute *attr,
			 const char *buf, size_t count)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	if (NULL != otg_dev->pcd)
		dwc_otg_pcd_initiate_srp(otg_dev->pcd);
#endif
	return count;
}

DEVICE_ATTR(srp, 0644, srp_show, srp_store);

/**
 * @todo Need to do more for power on/off?
 */
/**
 * Show the Bus Power status
 */
static ssize_t buspower_show(struct device *_dev,
			     struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	return sprintf(buf, "Bus Power = 0x%x\n",
		       dwc_otg_get_prtpower(otg_dev->core_if));
}

/**
 * Set the Bus Power status
 */
static ssize_t buspower_store(struct device *_dev,
			      struct device_attribute *attr,
			      const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	uint32_t on = simple_strtoul(buf, NULL, 16);
	dwc_otg_set_prtpower(otg_dev->core_if, on);
	return count;
}

DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);

/**
 * @todo Need to do more for suspend?
 */
/**
 * Show the Bus Suspend status
 */
static ssize_t bussuspend_show(struct device *_dev,
			       struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	return sprintf(buf, "Bus Suspend = 0x%x\n",
		       dwc_otg_get_prtsuspend(otg_dev->core_if));
}

/**
 * Set the Bus Suspend status
 */
static ssize_t bussuspend_store(struct device *_dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t in = simple_strtoul(buf, NULL, 16);
	dwc_otg_set_prtsuspend(otg_dev->core_if, in);
	return count;
}

DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);

/**
 * Show the status of Remote Wakeup.
 */
static ssize_t remote_wakeup_show(struct device *_dev,
				  struct device_attribute *attr, char *buf)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	return sprintf(buf,
		       "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
		       dwc_otg_get_remotewakesig(otg_dev->core_if),
		       dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
		       dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
#else
	return sprintf(buf, "Host Only Mode!\n");
#endif /* DWC_HOST_ONLY */
}

/**
 * Initiate a remote wakeup of the host.  The Device control register
 * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
 * flag is set.
 *
 */
static ssize_t remote_wakeup_store(struct device *_dev,
				   struct device_attribute *attr,
				   const char *buf, size_t count)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t val = simple_strtoul(buf, NULL, 16);

	if (val & 1)
		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
	else
		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
#endif /* DWC_HOST_ONLY */
	return count;
}

DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
	    remote_wakeup_store);

/**
 * Show the whether core is hibernated or not.
 */
static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
				     struct device_attribute *attr, char *buf)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	if (dwc_otg_get_core_state(otg_dev->core_if))
		DWC_PRINTF("Core is in hibernation\n");
	else
		DWC_PRINTF("Core is not in hibernation\n");
#endif /* DWC_HOST_ONLY */
	return 0;
}

/**
 * Initiate a remote wakeup of the device to exit from hibernation.
 */
static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
				      struct device_attribute *attr,
				      const char *buf, size_t count)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
#endif
	return count;
}

DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
	    rem_wakeup_pwrdn_store);

static ssize_t disconnect_us(struct device *_dev,
			     struct device_attribute *attr,
			     const char *buf, size_t count)
{

#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	uint32_t val = simple_strtoul(buf, NULL, 16);
	DWC_PRINTF("The Passed value is %04x\n", val);

	dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);

#endif /* DWC_HOST_ONLY */
	return count;
}

DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);

/**
 * Dump global registers and either host or device registers (depending on the
 * current mode of the core).
 */
static ssize_t regdump_show(struct device *_dev,
			    struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

#ifdef CONFIG_KONA_USB_CONTROL
	/* We want to be able to do this with and without
	 * USB-PMU-xceiver interface so use direct API
	 */
	bcm_hsotgctrl_en_clock(true);
	dwc_otg_dump_global_registers(otg_dev->core_if);
	if (dwc_otg_is_host_mode(otg_dev->core_if))
		dwc_otg_dump_host_registers(otg_dev->core_if);
	else
		dwc_otg_dump_dev_registers(otg_dev->core_if);

	bcm_hsotgctrl_en_clock(false);
#else
	dwc_otg_dump_global_registers(otg_dev->core_if);
	if (dwc_otg_is_host_mode(otg_dev->core_if))
		dwc_otg_dump_host_registers(otg_dev->core_if);
	else
		dwc_otg_dump_dev_registers(otg_dev->core_if);
#endif

	return sprintf(buf, "Register Dump\n");
}

DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);

/**
 * Dump global registers and either host or device registers (depending on the
 * current mode of the core).
 */
static ssize_t spramdump_show(struct device *_dev,
			      struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	dwc_otg_dump_spram(otg_dev->core_if);

	return sprintf(buf, "SPRAM Dump\n");
}

DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);

/**
 * Dump the current hcd state.
 */
static ssize_t hcddump_show(struct device *_dev,
			    struct device_attribute *attr, char *buf)
{
#ifndef DWC_DEVICE_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	dwc_otg_hcd_dump_state(otg_dev->hcd);
#endif /* DWC_DEVICE_ONLY */
	return sprintf(buf, "HCD Dump\n");
}

DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);

/**
 * Dump the average frame remaining at SOF. This can be used to
 * determine average interrupt latency. Frame remaining is also shown for
 * start transfer and two additional sample points.
 */
static ssize_t hcd_frrem_show(struct device *_dev,
			      struct device_attribute *attr, char *buf)
{
#ifndef DWC_DEVICE_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	dwc_otg_hcd_dump_frrem(otg_dev->hcd);
#endif /* DWC_DEVICE_ONLY */
	return sprintf(buf, "HCD Dump Frame Remaining\n");
}

DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);

/**
 * Displays the time required to read the GNPTXFSIZ register many times (the
 * output shows the number of times the register is read).
 */
#define RW_REG_COUNT 10000000
#define MSEC_PER_JIFFIE (1000/HZ)
static ssize_t rd_reg_test_show(struct device *_dev,
				struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	int i;
	int time;
	int start_jiffies;

	pr_info("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
		HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
	start_jiffies = jiffies;
	for (i = 0; i < RW_REG_COUNT; i++)
		dwc_otg_get_gnptxfsiz(otg_dev->core_if);

	time = jiffies - start_jiffies;
	return sprintf(buf,
		       "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
}

DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);

/**
 * Displays the time required to write the GNPTXFSIZ register many times (the
 * output shows the number of times the register is written).
 */
static ssize_t wr_reg_test_show(struct device *_dev,
				struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t reg_val;
	int i;
	int time;
	int start_jiffies;

	pr_info("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
		HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
	reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
	start_jiffies = jiffies;
	for (i = 0; i < RW_REG_COUNT; i++)
		dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);

	time = jiffies - start_jiffies;
	return sprintf(buf,
		       "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
}

DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);

#ifdef CONFIG_USB_DWC_OTG_LPM

/**
* Show the lpm_response attribute.
*/
static ssize_t lpmresp_show(struct device *_dev,
			    struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
		return sprintf(buf, "** LPM is DISABLED **\n");

	if (!dwc_otg_is_device_mode(otg_dev->core_if))
		return sprintf(buf, "** Current mode is not device mode\n");

	return sprintf(buf, "lpm_response = %d\n",
		       dwc_otg_get_lpmresponse(otg_dev->core_if));
}

/**
* Store the lpm_response attribute.
*/
static ssize_t lpmresp_store(struct device *_dev,
			     struct device_attribute *attr,
			     const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t val = simple_strtoul(buf, NULL, 16);

	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
		return 0;

	if (!dwc_otg_is_device_mode(otg_dev->core_if))
		return 0;

	dwc_otg_set_lpmresponse(otg_dev->core_if, val);
	return count;
}

DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);

/**
* Show the sleep_status attribute.
*/
static ssize_t sleepstatus_show(struct device *_dev,
				struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	return sprintf(buf, "Sleep Status = %d\n",
		       dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
}

/**
 * Store the sleep_status attribure.
 */
static ssize_t sleepstatus_store(struct device *_dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	dwc_otg_core_if_t *core_if = otg_dev->core_if;

	if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
		if (dwc_otg_is_host_mode(core_if)) {

			DWC_PRINTF("Host initiated resume\n");
			dwc_otg_set_prtresume(otg_dev->core_if, 1);
		}
	}

	return count;
}

DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
	    sleepstatus_store);

#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */

/**
 * Show the value of Host mode Connection Timeout.
 */
static ssize_t h_conn_wait_tmout_show(struct device *_dev,
				      struct device_attribute *attr, char *buf)
{
#ifndef DWC_DEVICE_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	return sprintf(buf, "Connection wait timeout in ms = %d\n",
		       otg_dev->hcd->conn_wait_timeout);
#else
	return sprintf(buf, "Device Only Mode!\n");
#endif /* #ifndef DWC_DEVICE_ONLY */
}

/**
 * Set the value of host mode connection timeout
 *
 */
static ssize_t h_conn_wait_tmout_store(struct device *_dev,
				       struct device_attribute *attr,
				       const char *buf, size_t count)
{
#ifndef DWC_DEVICE_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	otg_dev->hcd->conn_wait_timeout = simple_strtoul(buf, NULL, 10);
#endif
	return count;
}

DEVICE_ATTR(h_conn_wait_tmout, S_IRUGO | S_IWUSR, h_conn_wait_tmout_show,
	    h_conn_wait_tmout_store);

/**@}*/

/**
 * Create the device files
 */
void dwc_otg_attr_create(
#ifdef LM_INTERFACE
				struct lm_device *dev
#elif defined(PCI_INTERFACE)
				struct pci_dev *dev
#else
				struct platform_device *dev
#endif
    )
{
	int error;

	error = device_create_file(&dev->dev, &dev_attr_regoffset);
	error = device_create_file(&dev->dev, &dev_attr_regvalue);
	error = device_create_file(&dev->dev, &dev_attr_mode);
	error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
	error = device_create_file(&dev->dev, &dev_attr_srpcapable);
	error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
	error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
	error = device_create_file(&dev->dev, &dev_attr_hnp);
	error = device_create_file(&dev->dev, &dev_attr_srp);
	error = device_create_file(&dev->dev, &dev_attr_buspower);
	error = device_create_file(&dev->dev, &dev_attr_bussuspend);
	error = device_create_file(&dev->dev, &dev_attr_busconnected);
	error = device_create_file(&dev->dev, &dev_attr_gotgctl);
	error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
	error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
	error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
	error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
	error = device_create_file(&dev->dev, &dev_attr_ggpio);
	error = device_create_file(&dev->dev, &dev_attr_guid);
	error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
	error = device_create_file(&dev->dev, &dev_attr_devspeed);
	error = device_create_file(&dev->dev, &dev_attr_enumspeed);
	error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
	error = device_create_file(&dev->dev, &dev_attr_hprt0);
	error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
	error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
	error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
	error = device_create_file(&dev->dev, &dev_attr_regdump);
	error = device_create_file(&dev->dev, &dev_attr_spramdump);
	error = device_create_file(&dev->dev, &dev_attr_hcddump);
	error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
	error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
	error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
#ifdef CONFIG_USB_DWC_OTG_LPM
	error = device_create_file(&dev->dev, &dev_attr_lpm_response);
	error = device_create_file(&dev->dev, &dev_attr_sleep_status);
#endif
	error = device_create_file(&dev->dev, &dev_attr_h_conn_wait_tmout);
}

/**
 * Remove the device files
 */
void dwc_otg_attr_remove(
#ifdef LM_INTERFACE
				struct lm_device *dev
#elif defined(PCI_INTERFACE)
				struct pci_dev *dev
#else
				struct platform_device *dev
#endif
    )
{
	device_remove_file(&dev->dev, &dev_attr_regoffset);
	device_remove_file(&dev->dev, &dev_attr_regvalue);
	device_remove_file(&dev->dev, &dev_attr_mode);
	device_remove_file(&dev->dev, &dev_attr_hnpcapable);
	device_remove_file(&dev->dev, &dev_attr_srpcapable);
	device_remove_file(&dev->dev, &dev_attr_hsic_connect);
	device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
	device_remove_file(&dev->dev, &dev_attr_hnp);
	device_remove_file(&dev->dev, &dev_attr_srp);
	device_remove_file(&dev->dev, &dev_attr_buspower);
	device_remove_file(&dev->dev, &dev_attr_bussuspend);
	device_remove_file(&dev->dev, &dev_attr_busconnected);
	device_remove_file(&dev->dev, &dev_attr_gotgctl);
	device_remove_file(&dev->dev, &dev_attr_gusbcfg);
	device_remove_file(&dev->dev, &dev_attr_grxfsiz);
	device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
	device_remove_file(&dev->dev, &dev_attr_gpvndctl);
	device_remove_file(&dev->dev, &dev_attr_ggpio);
	device_remove_file(&dev->dev, &dev_attr_guid);
	device_remove_file(&dev->dev, &dev_attr_gsnpsid);
	device_remove_file(&dev->dev, &dev_attr_devspeed);
	device_remove_file(&dev->dev, &dev_attr_enumspeed);
	device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
	device_remove_file(&dev->dev, &dev_attr_hprt0);
	device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
	device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
	device_remove_file(&dev->dev, &dev_attr_disconnect_us);
	device_remove_file(&dev->dev, &dev_attr_regdump);
	device_remove_file(&dev->dev, &dev_attr_spramdump);
	device_remove_file(&dev->dev, &dev_attr_hcddump);
	device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
	device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
	device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
#ifdef CONFIG_USB_DWC_OTG_LPM
	device_remove_file(&dev->dev, &dev_attr_lpm_response);
	device_remove_file(&dev->dev, &dev_attr_sleep_status);
#endif
	device_remove_file(&dev->dev, &dev_attr_h_conn_wait_tmout);
}
Ejemplo n.º 29
0
/**
 * This interrupt indicates that an IN EP has a pending Interrupt.
 * The sequence for handling the IN EP interrupt is shown below:
 * -#	Read the Device All Endpoint Interrupt register
 * -#	Repeat the following for each IN EP interrupt bit set (from
 *   	LSB to MSB).
 * -#	Read the Device Endpoint Interrupt (DIEPINTn) register
 * -#	If "Transfer Complete" call the request complete function
 * -#	If "Endpoint Disabled" complete the EP disable procedure.
 * -#	If "AHB Error Interrupt" log error
 * -#	If "Time-out Handshake" log error
 * -#	If "IN Token Received when TxFIFO Empty" write packet to Tx
 *   	FIFO.
 * -#	If "IN Token EP Mismatch" (disable, this is handled by EP
 *   	Mismatch Interrupt)
 */
static int32_t dwc_otg_pcd_handle_in_ep_intr(void)
{
#define CLEAR_IN_EP_INTR(__epnum,__intr) \
do { \
        diepint_data_t diepint = { 0 }; \
	diepint.b.__intr = 1; \
	dwc_write_reg32(DWC_REG_IN_EP_INTR(__epnum), \
			diepint.d32); \
} while (0)

        diepint_data_t diepint = { 0 };
//        depctl_data_t diepctl = { 0 };
        uint32_t ep_intr;
        uint32_t epnum = 0;
        gintmsk_data_t intr_mask = {0};
        gintsts_data_t gintsts;

	 DBG( "dwc_otg_pcd_handle_in_ep_intr()\n" );

	/* Read in the device interrupt bits */
        ep_intr = (dwc_read_reg32(DWC_REG_DAINT) &
                dwc_read_reg32( DWC_REG_DAINTMSK));
        ep_intr =( (ep_intr & 0xffff) );


	/* Clear the INEPINT in GINTSTS */
	/* Clear all the interrupt bits for all IN endpoints in DAINT */
	gintsts.d32 = 0;
	gintsts.b.inepint = 1;
	dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32);
	dwc_write_reg32(DWC_REG_DAINT, 0xFFFF );
	flush_cpu_cache();

	/* Service the Device IN interrupts for each endpoint */
        while ( ep_intr ) {
                if (ep_intr&0x1) {

                        diepint.d32 = (dwc_read_reg32( DWC_REG_IN_EP_INTR(epnum)) &
									dwc_read_reg32(DWC_REG_DAINTMSK));
                        /* Transfer complete */
                        if ( diepint.b.xfercompl ) {


                                /* Disable the NP Tx FIFO Empty
                                 * Interrrupt */
                                intr_mask.b.nptxfempty = 1;
                                dwc_modify_reg32( DWC_REG_GINTMSK, intr_mask.d32, 0);

                                /* Clear the bit in DIEPINTn for this interrupt */
                                CLEAR_IN_EP_INTR(epnum,xfercompl);

                                /* Complete the transfer */
					if (epnum == 0) {
						handle_ep0( 0 );
					} else {
						complete_ep( epnum,1 );
					}
                        }
                        /* Endpoint disable  */
                        if ( diepint.b.epdisabled ) {
                                handle_in_ep_disable_intr( epnum );

                                /* Clear the bit in DIEPINTn for this interrupt */
                                CLEAR_IN_EP_INTR(epnum,epdisabled);
                        }
                        /* AHB Error */
                        if ( diepint.b.ahberr ) {
				/* Clear the bit in DIEPINTn for this interrupt */
				CLEAR_IN_EP_INTR(epnum,ahberr);
                        }
                        /* TimeOUT Handshake (non-ISOC IN EPs) */
                        if ( diepint.b.timeout ) {
                                handle_in_ep_timeout_intr( epnum );

				CLEAR_IN_EP_INTR(epnum,timeout);
                        }
                        /** IN Token received with TxF Empty */
                        if (diepint.b.intktxfemp) {
                                DWN_MSG("diepint.b.intktxfemp\n");
#if 0
                                if (!ep->stopped && epnum != 0) {
                                        diepmsk_data_t diepmsk = { 0};
                                        diepmsk.b.intktxfemp = 1;
                                        dwc_modify_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32, 0 );
                                        start_next_request(ep);
                                }
#endif
				CLEAR_IN_EP_INTR(epnum,intktxfemp);
                        }
                        /** IN Token Received with EP mismatch */
                        if (diepint.b.intknepmis) {
                                DWN_MSG("intknepmis ep%d\n", epnum);
                                CLEAR_IN_EP_INTR(epnum,intknepmis);
                        }
                        /** IN Endpoint NAK Effective */
                        if (diepint.b.inepnakeff) {
				CLEAR_IN_EP_INTR(epnum,inepnakeff);
                        }
                }
                epnum++;
                ep_intr >>=1;
        }

        return 1;

#undef CLEAR_IN_EP_INTR
}
Ejemplo n.º 30
0
/**
 * This function handles the Connector ID Status Change Interrupt.  It
 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
 * is a Device to Host Mode transition or a Host Mode to Device
 * Transition.  
 *
 * This only occurs when the cable is connected/removed from the PHY
 * connector.
 *
 * @param _core_if Programming view of DWC_otg controller.
 */ 
int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *
						      _core_if) 
{
	uint32_t count = 0;
	gintsts_data_t gintsts = {.d32 = 0};
	gintmsk_data_t gintmsk = {.d32 = 0};
	gotgctl_data_t gotgctl = {.d32 = 0};
	
	/*
	 * Need to disable SOF interrupt immediately. If switching from device
	 * to host, the PCD interrupt handler won't handle the interrupt if
	 * host mode is already set. The HCD interrupt handler won't get
	 * called if the HCD state is HALT. This means that the interrupt does
	 * not get handled and Linux complains loudly.
	 */ 
	gintmsk.b.sofintr = 1;
	dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
	DWC_DEBUGPL(DBG_CIL,
		      " ++Connector ID Status Change Interrupt++  (%s)\n",
		      (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"));
	gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
	
	/* B-Device connector (Device Mode) */ 
	if (gotgctl.b.conidsts) {
		
		/* Wait for switch to device mode. */ 
		while (!dwc_otg_is_device_mode(_core_if)) {
			DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n", 
				   (dwc_otg_is_host_mode(_core_if) ? "Host" :
				    "Peripheral"));
			MDELAY(100);
			if (++count > 10000)
				*(uint32_t *) NULL = 0;
		}
		_core_if->op_state = B_PERIPHERAL;
		dwc_otg_core_init(_core_if);
		dwc_otg_enable_global_interrupts(_core_if);
		pcd_start(_core_if);
	} else {
		
		/* A-Device connector (Host Mode) */ 
		while (!dwc_otg_is_host_mode(_core_if)) {
			DWC_PRINT("Waiting for Host Mode, Mode=%s\n", 
				   (dwc_otg_is_host_mode(_core_if) ? "Host" :
				    "Peripheral"));
			MDELAY(100);
			if (++count > 10000)
				*(uint32_t *) NULL = 0;
		}
		_core_if->op_state = A_HOST;
		
		/*
		 * Initialize the Core for Host mode.
		 */ 
		dwc_otg_core_init(_core_if);
		dwc_otg_enable_global_interrupts(_core_if);
		hcd_start(_core_if);
	}
	
	/* Set flag and clear interrupt */ 
	gintsts.b.conidstschng = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that a device is initiating the Session
 * Request Protocol to request the host to turn on bus power so a new
 * session can begin. The handler responds by turning on bus power. If
 * the DWC_otg controller is in low power mode, the handler brings the
 * controller out of low power mode before turning on bus power. 
 *
 * @param _core_if Programming view of DWC_otg controller.
 */ 
int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	
#ifndef DWC_HOST_ONLY
	hprt0_data_t hprt0;
	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		DWC_PRINT("SRP: Device mode\n");
	} else {
		DWC_PRINT("SRP: Host mode\n");
		
		/* Turn on the port power bit. */ 
		hprt0.d32 = dwc_otg_read_hprt0(_core_if);
		hprt0.b.prtpwr = 1;
		dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32);
		
		/* Start the Connection timer. So a message can be displayed
		 * if connect does not occur within 10 seconds. */ 
		hcd_session_start(_core_if);
	}
	
#endif	/*  */
	    
	/* Clear interrupt */ 
	gintsts.d32 = 0;
	gintsts.b.sessreqintr = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that the DWC_otg controller has detected a
 * resume or remote wakeup sequence. If the DWC_otg controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume
 * signaling. The handler schedules a time to stop resume signaling.
 */ 
int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	DWC_DEBUGPL(DBG_ANY,"++Resume and Remote Wakeup Detected Interrupt++\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		dctl_data_t dctl = {.d32 = 0};
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
				dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts));
		
#ifdef PARTIAL_POWER_DOWN
		if (_core_if->hwcfg4.b.power_optimiz) {
			pcgcctl_data_t power = {.d32 = 0};
			power.d32 = dwc_read_reg32(_core_if->pcgcctl);
			DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", power.d32);
			power.b.stoppclk = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.pwrclmp = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.rstpdwnmodule = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
		}
		
#endif	/*  */
		/* Clear the Remote Wakeup Signalling */ 
		dctl.b.rmtwkupsig = 1;
		dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dctl,
				  dctl.d32, 0);
		if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup) {
			_core_if->pcd_cb->resume_wakeup(_core_if->pcd_cb->p);
		}
	} else {
		
		/*
		 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
		 * so that OPT tests pass with all PHYs).
		 */ 
		hprt0_data_t hprt0 = {.d32 = 0};
		pcgcctl_data_t pcgcctl = {.d32 = 0};
		
		/* Restart the Phy Clock */ 
		pcgcctl.b.stoppclk = 1;
		dwc_modify_reg32(_core_if->pcgcctl, pcgcctl.d32, 0);
		UDELAY(10);
		
		/* Now wait for 70 ms. */ 
		hprt0.d32 = dwc_otg_read_hprt0(_core_if);
		DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
		MDELAY(70);
		hprt0.b.prtres = 0;	/* Resume */
		dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32);
		DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
			     dwc_read_reg32(_core_if->host_if->hprt0));
	}
	
	/* Clear interrupt */ 
	gintsts.d32 = 0;
	gintsts.b.wkupintr = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that a device has been disconnected from
 * the root port. 
 */ 
int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	printk(KERN_ERR "  Disconnect Detected Interrupt++ (%s) %s\n", 
		 (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"),
		 op_state_str(_core_if));
	DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
		     (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"),
		     op_state_str(_core_if));
	
/** @todo Consolidate this if statement. */ 
#ifndef DWC_HOST_ONLY
	if (_core_if->op_state == B_HOST) {
		
		/* If in device mode Disconnect and stop the HCD, then
		 * start the PCD. */ 
		hcd_disconnect(_core_if);
		pcd_start(_core_if);
		_core_if->op_state = B_PERIPHERAL;
	} else if (dwc_otg_is_device_mode(_core_if)) {
		gotgctl_data_t gotgctl = {.d32 = 0};
		gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
		if (gotgctl.b.hstsethnpen == 1) {
			/* Do nothing, if HNP in process the OTG
			 * interrupt "Host Negotiation Detected"
			 * interrupt will do the mode switch.
			 */ 
		} else if (gotgctl.b.devhnpen == 0) {
			/* If in device mode Disconnect and stop the HCD, then
			 * start the PCD. */ 
			hcd_disconnect(_core_if);
			pcd_start(_core_if);
			_core_if->op_state = B_PERIPHERAL;
		} else {
			DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
		}
	} else {
		if (_core_if->op_state == A_HOST) {
			/* A-Cable still connected but device disconnected. */ 
			hcd_disconnect(_core_if);
		}
	}
	
#endif	/*  */
	gintsts.d32 = 0;
	gintsts.b.disconnect = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/**
 * This interrupt indicates that SUSPEND state has been detected on
 * the USB.
 * 
 * For HNP the USB Suspend interrupt signals the change from
 * "a_peripheral" to "a_host".
 *
 * When power management is enabled the core will be put in low power
 * mode.
 */ 
int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * _core_if) 
{
	dsts_data_t dsts;
	gintsts_data_t gintsts;
	DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		
		/* Check the Device status register to determine if the Suspend
		 * state is active. */ 
		dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts);
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
		DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d " 
			     "HWCFG4.power Optimize=%d\n", dsts.b.suspsts,
			     _core_if->hwcfg4.b.power_optimiz);
		
#ifdef PARTIAL_POWER_DOWN
/** @todo Add a module parameter for power management. */ 
		if (dsts.b.suspsts && _core_if->hwcfg4.b.power_optimiz) {
			pcgcctl_data_t power = {.d32 = 0};
			DWC_DEBUGPL(DBG_CIL, "suspend\n");
			power.b.pwrclmp = 1;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.rstpdwnmodule = 1;
			dwc_modify_reg32(_core_if->pcgcctl, 0, power.d32);
			power.b.stoppclk = 1;
			dwc_modify_reg32(_core_if->pcgcctl, 0, power.d32);
		} else {
			DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
		}
		
#endif	/*  */
		/* PCD callback for suspend. */ 
		pcd_suspend(_core_if);
	} else {
		if (_core_if->op_state == A_PERIPHERAL) {