void musbfs_check_mpu_violation(u32 addr, int wr_vio)
{
    void __iomem *mregs = (void *)USB_BASE;

    printk(KERN_CRIT "MUSB checks EMI MPU violation.\n");
    printk(KERN_CRIT "addr = 0x%x, %s violation.\n", addr, wr_vio? "Write": "Read");
    printk(KERN_CRIT "POWER = 0x%x,DEVCTL= 0x%x.\n", musbfsh_readb(mregs, MUSBFSH_POWER),musbfsh_readb(USB11_BASE,MUSBFSH_DEVCTL));
    printk(KERN_CRIT "DMA_CNTLch0 0x%04x,DMA_ADDRch0 0x%08x,DMA_COUNTch0 0x%08x \n",musbfsh_readw(mregs, 0x204),musbfsh_readl(mregs,0x208),musbfsh_readl(mregs,0x20C));
    printk(KERN_CRIT "DMA_CNTLch1 0x%04x,DMA_ADDRch1 0x%08x,DMA_COUNTch1 0x%08x \n",musbfsh_readw(mregs, 0x214),musbfsh_readl(mregs,0x218),musbfsh_readl(mregs,0x21C));
    printk(KERN_CRIT "DMA_CNTLch2 0x%04x,DMA_ADDRch2 0x%08x,DMA_COUNTch2 0x%08x \n",musbfsh_readw(mregs, 0x224),musbfsh_readl(mregs,0x228),musbfsh_readl(mregs,0x22C));
    printk(KERN_CRIT "DMA_CNTLch3 0x%04x,DMA_ADDRch3 0x%08x,DMA_COUNTch3 0x%08x \n",musbfsh_readw(mregs, 0x234),musbfsh_readl(mregs,0x238),musbfsh_readl(mregs,0x23C));
    printk(KERN_CRIT "DMA_CNTLch4 0x%04x,DMA_ADDRch4 0x%08x,DMA_COUNTch4 0x%08x \n",musbfsh_readw(mregs, 0x244),musbfsh_readl(mregs,0x248),musbfsh_readl(mregs,0x24C));
    printk(KERN_CRIT "DMA_CNTLch5 0x%04x,DMA_ADDRch5 0x%08x,DMA_COUNTch5 0x%08x \n",musbfsh_readw(mregs, 0x254),musbfsh_readl(mregs,0x258),musbfsh_readl(mregs,0x25C));
    printk(KERN_CRIT "DMA_CNTLch6 0x%04x,DMA_ADDRch6 0x%08x,DMA_COUNTch6 0x%08x \n",musbfsh_readw(mregs, 0x264),musbfsh_readl(mregs,0x268),musbfsh_readl(mregs,0x26C));
    printk(KERN_CRIT "DMA_CNTLch7 0x%04x,DMA_ADDRch7 0x%08x,DMA_COUNTch7 0x%08x \n",musbfsh_readw(mregs, 0x274),musbfsh_readl(mregs,0x278),musbfsh_readl(mregs,0x27C));        
}
static ssize_t store_start(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)
{
	char *pvalue = NULL;
	unsigned int value = 0;
	size_t count = 0;
	u8 devctl = musbfsh_readb((unsigned char __iomem*)USB11_BASE, MUSBFSH_DEVCTL);
	value = simple_strtoul(buf,&pvalue,10);
	count = pvalue - buf;
	
	if (*pvalue && isspace(*pvalue))
		count++;
		
	if(count == size)
	{
		if(value) {			
		WARNING("[IC-USB]start session\n");
		devctl |= MUSBFSH_DEVCTL_SESSION; // wx? why not wait until device connected
		musbfsh_writeb((unsigned char __iomem*)USB11_BASE, MUSBFSH_DEVCTL, devctl);
		WARNING("[IC-USB]power on VSIM\n");
		hwPowerOn(MT65XX_POWER_LDO_VSIM, VOL_3000, "USB11-SIM");
		}
	}
	return size;
}
irqreturn_t musbfsh_dma_controller_irq(int irq, void *private_data)
{
	struct musbfsh_dma_controller *controller = private_data;
	struct musbfsh *musbfsh = controller->private_data;
	struct musbfsh_dma_channel *musbfsh_channel;
	struct dma_channel *channel;

	void __iomem *mbase = controller->base;

	irqreturn_t retval = IRQ_NONE;

	// unsigned long flags;

	u8 bchannel;
	u8 int_hsdma;

	u32 addr, count;
	u16 csr;
	
	INFO("++\n");
	// spin_lock_irqsave(&musbfsh->lock, flags); // removed due to now this function is called inside generic_interrupt

	int_hsdma = musbfsh->int_dma;

	if (!int_hsdma) {//should not to run here!
		WARNING("spurious DMA irq\n");

		for (bchannel = 0; bchannel < MUSBFSH_HSDMA_CHANNELS; bchannel++) {
			musbfsh_channel = (struct musbfsh_dma_channel *)
					&(controller->channel[bchannel]);
			channel = &musbfsh_channel->channel;
			if (channel->status == MUSBFSH_DMA_STATUS_BUSY) {
				count = musbfsh_read_hsdma_count(mbase, bchannel);

				if (count == 0)//all of the data have been transferred, should notify the CPU to process. 
					int_hsdma |= (1 << bchannel);
			}
		}

		INFO("int_hsdma = 0x%x\n", int_hsdma);

		if (!int_hsdma)
			goto done;
	}

	for (bchannel = 0; bchannel < MUSBFSH_HSDMA_CHANNELS; bchannel++) {
		if (int_hsdma & (1 << bchannel)) {
			musbfsh_channel = (struct musbfsh_dma_channel *)
					&(controller->channel[bchannel]);
			channel = &musbfsh_channel->channel;

			csr = musbfsh_readw(mbase,
					MUSBFSH_HSDMA_CHANNEL_OFFSET(bchannel,
							MUSBFSH_HSDMA_CONTROL));

			if (csr & (1 << MUSBFSH_HSDMA_BUSERROR_SHIFT)) {
				musbfsh_channel->channel.status =
					MUSBFSH_DMA_STATUS_BUS_ABORT;
			} else {
				u8 devctl;

				addr = musbfsh_read_hsdma_addr(mbase,
						bchannel);//the register of address will increase with the data transfer.
				channel->actual_len = addr
					- musbfsh_channel->start_addr;

				INFO("ch %p, 0x%x -> 0x%x (%zu / %d) %s\n",
					channel, musbfsh_channel->start_addr,
					addr, channel->actual_len,
					musbfsh_channel->len,
					(channel->actual_len
						< musbfsh_channel->len) ?
					"=> reconfig 0" : "=> complete");

				devctl = musbfsh_readb(mbase, MUSBFSH_DEVCTL);

				channel->status = MUSBFSH_DMA_STATUS_FREE;

				/* completed */
				if ((devctl & MUSBFSH_DEVCTL_HM)
					&& (musbfsh_channel->transmit)//Tx
					&& ((channel->desired_mode == 0)
					    || (channel->actual_len &//indicate it is a short packet
					    (musbfsh_channel->max_packet_sz - 1)))
				    ) {
					u8  epnum  = musbfsh_channel->epnum;
					int offset = MUSBFSH_EP_OFFSET(epnum,
								    MUSBFSH_TXCSR);
					u16 txcsr;

					/*
					 * The programming guide says that we
					 * must clear DMAENAB before DMAMODE.
					 */
					musbfsh_ep_select(mbase, epnum);
					txcsr = musbfsh_readw(mbase, offset);
					txcsr &= ~(MUSBFSH_TXCSR_DMAENAB
							| MUSBFSH_TXCSR_AUTOSET);
					musbfsh_writew(mbase, offset, txcsr);
					/* Send out the packet */
					txcsr &= ~MUSBFSH_TXCSR_DMAMODE;
					txcsr |=  MUSBFSH_TXCSR_TXPKTRDY;//the packet has been in the fifo,only need to set TxPktRdy
					musbfsh_writew(mbase, offset, txcsr);
				}
					musbfsh_dma_completion(musbfsh, musbfsh_channel->epnum,
						    musbfsh_channel->transmit);
				}
			}
		}

	retval = IRQ_HANDLED;
done:
	// spin_unlock_irqrestore(&musbfsh->lock, flags);
	return retval;
}
static void musbfsh_port_suspend(struct musbfsh *musbfsh, bool do_suspend)
{
	u8 power;
	u8 intrusbe;
	u8 intrusb;
	void __iomem *mbase = musbfsh->mregs;
	int retries = 0;


	/* MYDBG("cpuid:%d\n", smp_processor_id()); */

	/* NOTE:  this doesn't necessarily put PHY into low power mode,
	 * turning off its clock; that's a function of PHY integration and
	 * MUSBFSH_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
	 * SE0 changing to connect (J) or wakeup (K) states.
	 */
	if (do_suspend) {

#ifdef CONFIG_MTK_DT_USB_SUPPORT
		if (musbfsh_skip_port_suspend) {
			MYDBG("\n");
			musbfsh->port1_status |= USB_PORT_STAT_SUSPEND;
			return;
		}
#endif

		/* clean MUSBFSH_INTR_SOF in MUSBFSH_INTRUSBE */
		intrusbe = musbfsh_readb(mbase, MUSBFSH_INTRUSBE);
		intrusbe &= ~MUSBFSH_INTR_SOF;
		musbfsh_writeb(mbase, MUSBFSH_INTRUSBE, intrusbe);
		mb(); /* flush POWER and PHY setting immediately */
		/* clean MUSBFSH_INTR_SOF in MUSBFSH_INTRUSB */
		intrusb = musbfsh_readb(mbase, MUSBFSH_INTRUSB);
		intrusb |= MUSBFSH_INTR_SOF;
		musbfsh_writeb(mbase, MUSBFSH_INTRUSB, intrusb);
		mb(); /* flush POWER and PHY setting immediately */
		retries = 10000;
		intrusb = musbfsh_readb(mbase, MUSBFSH_INTRUSB);
		while (!(intrusb & MUSBFSH_INTR_SOF)) {
			intrusb = musbfsh_readb(mbase, MUSBFSH_INTRUSB);
			if (retries-- < 1) {
				MYDBG("\n");
				break;
			}
		}

		/* delay 10 us */
		udelay(10);

		/* set MUSBFSH_POWER_SUSPENDM in MUSBFSH_POWER_SUSPENDM */
		power = musbfsh_readb(mbase, MUSBFSH_POWER);
#ifdef CONFIG_MTK_DT_USB_SUPPORT
#if defined(CONFIG_PM_RUNTIME) &&  defined(USB11_REMOTE_IRQ_NON_AUTO_MASK)
		disable_remote_wake_up();
#endif
#endif

#ifdef MTK_USB_RUNTIME_SUPPORT
		/*
		 * mask remote wake up IRQ between port suspend and bus suspend.
		 * hub.c will call set_port_feature first then
		 * usb_set_device_state, so if EINT comes between them,
		 * resume flow may see device state without USB_STATE_SUSPENDED
		 * and do nothing.
		 * So we postpone remote wake up IRQ until the suspend flow
		 * is all done (when bus_suspend is called). Since suspend flow
		 * may be interrupted (root hub is suspended, but not host
		 * controller), so we also unmaks EINT when resume is done.
		 */
		mt_eint_mask(CUST_EINT_MT6280_USB_WAKEUP_NUM);
#endif

		retries = 10000;

#ifdef CONFIG_MTK_ICUSB_SUPPORT
		if (skip_port_pm_attr.value) {
			MYDBG("skip hw operation for port suspend\n");
		} else {
			power &= ~MUSBFSH_POWER_RESUME;
			power |= MUSBFSH_POWER_SUSPENDM;
			musbfsh_writeb(mbase, MUSBFSH_POWER, power);

			/* Needed for OPT A tests */
			power = musbfsh_readb(mbase, MUSBFSH_POWER);
			while (power & MUSBFSH_POWER_SUSPENDM) {
				power = musbfsh_readb(mbase, MUSBFSH_POWER);
				if (retries-- < 1)
					break;
			}
		}
#else
		power &= ~MUSBFSH_POWER_RESUME;
		power |= MUSBFSH_POWER_SUSPENDM;
		musbfsh_writeb(mbase, MUSBFSH_POWER, power);

		/* Needed for OPT A tests */
		power = musbfsh_readb(mbase, MUSBFSH_POWER);
		while (power & MUSBFSH_POWER_SUSPENDM) {
			power = musbfsh_readb(mbase, MUSBFSH_POWER);
			if (retries-- < 1) {
				MYDBG("\n");
				break;
			}
		}
#endif
		mb(); /* flush POWER and PHY setting immediately */
		WARNING("Root port suspended, power 0x%02x\n", power);

#ifdef CONFIG_MTK_DT_USB_SUPPORT
#if defined(CONFIG_PM_RUNTIME)
		disable_usb11_clk();
#endif
#endif
		musbfsh->port1_status |= USB_PORT_STAT_SUSPEND;
	} else {

#ifdef CONFIG_MTK_DT_USB_SUPPORT
		if (musbfsh_skip_port_resume) {
			MYDBG("\n");
			request_wakeup_md_timeout(0, 0);
			musbfsh->port1_status |= MUSBFSH_PORT_STAT_RESUME;
			musbfsh->rh_timer = jiffies + msecs_to_jiffies(20);
			return;
		}
#if defined(CONFIG_PM_RUNTIME)
		enable_usb11_clk();
#endif
#endif

		power = musbfsh_readb(mbase, MUSBFSH_POWER);
		if (!(power & MUSBFSH_POWER_SUSPENDM)) {
			WARNING("Root port resuming abort, power 0x%02x\n",
				power);
			if (power & MUSBFSH_POWER_RESUME)
				goto finish;
			else
				return;
		}
#ifdef CONFIG_MTK_DT_USB_SUPPORT
		request_wakeup_md_timeout(0, 0);
#endif

#ifdef MTK_USB_RUNTIME_SUPPORT
		/* ERR("EINT to wake up MD for resume\n"); */
		/* request_wakeup_md_timeout(0, 0); //wx, wakeup MD first */
#endif

#ifdef CONFIG_MTK_ICUSB_SUPPORT
		if (skip_port_pm_attr.value) {
			MYDBG("skip hw operation for port resume\n");
		} else {
			power &= ~MUSBFSH_POWER_SUSPENDM;
			power |= MUSBFSH_POWER_RESUME;
			musbfsh_writeb(mbase, MUSBFSH_POWER, power);
		}
#else
		power &= ~MUSBFSH_POWER_SUSPENDM;
		power |= MUSBFSH_POWER_RESUME;
		musbfsh_writeb(mbase, MUSBFSH_POWER, power);
#endif
		mb();  /* flush POWER and PHY setting immediately */
		WARNING("Root port resuming, power 0x%02x\n", power);
finish:
		/* later, GetPortStatus will stop RESUME signaling */
		musbfsh->port1_status |= MUSBFSH_PORT_STAT_RESUME;
		musbfsh->rh_timer = jiffies + msecs_to_jiffies(20);
	}
}
int musbfsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
			u16 wIndex, char *buf, u16 wLength)
{
	struct musbfsh *musbfsh = hcd_to_musbfsh(hcd);
	u32 temp;
	int retval = 0;
	unsigned long flags;

	INFO("%s++, typeReq=0x%x, wValue=0x%x, wIndex=0x%x\r\n",
	     __func__, typeReq, wValue, wIndex);
	spin_lock_irqsave(&musbfsh->lock, flags);

	if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) {
		spin_unlock_irqrestore(&musbfsh->lock, flags);
		return -ESHUTDOWN;
	}

	/* hub features:  always zero, setting is a NOP
	 * port features: reported, sometimes updated when host is active
	 * no indicators
	 */
	switch (typeReq) {
	case ClearHubFeature:
	case SetHubFeature:
		switch (wValue) {
		case C_HUB_OVER_CURRENT:
		case C_HUB_LOCAL_POWER:
			break;
		default:
			goto error;
		}
		break;
	case ClearPortFeature:
		/* wIndex indicate the port number, here it is should be 1 */
		if ((wIndex & 0xff) != 1)
			goto error;

		switch (wValue) {
		case USB_PORT_FEAT_ENABLE:
			break;
		case USB_PORT_FEAT_SUSPEND:
			/* here is clearing the suspend */
			musbfsh_port_suspend(musbfsh, false);
			break;
		case USB_PORT_FEAT_POWER:
#ifndef MTK_ALPS_BOX_SUPPORT
			/* only power off the vbus */
			musbfsh_set_vbus(musbfsh, 0);
#else
			/* only power off the vbus */
			musbfsh_platform_set_vbus(musbfsh, 0);
#endif
			break;
		case USB_PORT_FEAT_C_CONNECTION:
		case USB_PORT_FEAT_C_ENABLE:
		case USB_PORT_FEAT_C_OVER_CURRENT:
		case USB_PORT_FEAT_C_RESET:
		case USB_PORT_FEAT_C_SUSPEND:
			break;
		default:
			goto error;
		}
		INFO("clear feature %d\n", wValue);
		musbfsh->port1_status &= ~(1 << wValue);
		break;
	case GetHubDescriptor:
		{
			struct usb_hub_descriptor *desc = (void *)buf;

			desc->bDescLength = 9;
			desc->bDescriptorType = 0x29;
			desc->bNbrPorts = 1;

			/* 0x0001: per-port power switching */
			/* 0x0010: no overcurrent reporting */
			desc->wHubCharacteristics =
				cpu_to_le16(0x0001 | 0x0010);
			/* msec/2 */
			desc->bPwrOn2PwrGood = 5;
			desc->bHubContrCurrent = 0;

			/* workaround bogus struct definition */
			desc->u.hs.DeviceRemovable[0] = 0x02;	/* port 1 */
			desc->u.hs.DeviceRemovable[1] = 0xff;
		}
		break;
	case GetHubStatus:
		temp = 0;
		*(__le32 *)buf = cpu_to_le32(temp);
		break;
	case GetPortStatus:
		if (wIndex != 1)
			goto error;

		/* finish RESET signaling? */
		/* if FALSE: stop the reset because the timeout of reset. */
		if ((musbfsh->port1_status & USB_PORT_STAT_RESET)
		    && time_after_eq(jiffies, musbfsh->rh_timer))
			musbfsh_port_reset(musbfsh, false);

		/* finish RESUME signaling? */
		if ((musbfsh->port1_status & MUSBFSH_PORT_STAT_RESUME)
		    && time_after_eq(jiffies, musbfsh->rh_timer)) {
			u8 pwr;
#ifdef CONFIG_MTK_DT_USB_SUPPORT
			if (!musbfsh_skip_port_resume) {
				pwr = musbfsh_readb(musbfsh->mregs,
						      MUSBFSH_POWER);
				pwr &= ~MUSBFSH_POWER_RESUME;
				WARNING("Root port resume stopped\n");
				WARNING("power 0x%02x\n", pwr);
				musbfsh_writeb(musbfsh->mregs, MUSBFSH_POWER,
					       pwr);
#if defined(CONFIG_PM_RUNTIME) && defined(USB11_REMOTE_IRQ_NON_AUTO_MASK)
				enable_remote_wake_up();
#endif
			} else {
				MYDBG("\n");
			}
#else

			pwr = musbfsh_readb(musbfsh->mregs, MUSBFSH_POWER);
			pwr &= ~MUSBFSH_POWER_RESUME;
			WARNING("Root port resume stopped, power 0x%02x\n",
				pwr);
			musbfsh_writeb(musbfsh->mregs, MUSBFSH_POWER, pwr);
#endif

#ifdef MTK_USB_RUNTIME_SUPPORT
			/* mt_eint_unmask(CUST_EINT_MT6280_USB_WAKEUP_NUM); */
#endif

			/*
			 * ISSUE: DaVinci (RTL 1.300) disconnects after
			 * resume of high speed peripherals (but not full
			 * speed ones).
			 */

			musbfsh->is_active = 1;
			musbfsh->port1_status &= ~(USB_PORT_STAT_SUSPEND
						   | MUSBFSH_PORT_STAT_RESUME);
			musbfsh->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
			usb_hcd_poll_rh_status(musbfsh_to_hcd(musbfsh));
		}

		put_unaligned(cpu_to_le32(musbfsh->port1_status &
					  ~MUSBFSH_PORT_STAT_RESUME),
					  (__le32 *)buf);

		/* port change status is more interesting */
		WARNING("port status %08x,devctl=0x%x\n", musbfsh->port1_status,
			musbfsh_readb(musbfsh->mregs, MUSBFSH_DEVCTL));
		break;
	case SetPortFeature:
		if ((wIndex & 0xff) != 1)
			goto error;

		switch (wValue) {
		case USB_PORT_FEAT_POWER:
			/* NOTE: this controller has a strange state machine
			 * that involves "requesting sessions" according to
			 * magic side effects from incompletely-described
			 * rules about startup...
			 *
			 * This call is what really starts the host mode; be
			 * very careful about side effects if you reorder any
			 * initialization logic, e.g. for OTG, or change any
			 * logic relating to VBUS power-up.
			 */
			INFO("musbfsh_start is called in hub control\r\n");
#ifdef CONFIG_MTK_ICUSB_SUPPORT
			if (skip_mac_init_attr.value)
				MYDBG("");
			else
				musbfsh_start(musbfsh);
#else
			musbfsh_start(musbfsh);
#endif
			break;
		case USB_PORT_FEAT_RESET:
			/* enable the reset, but not finish */
			musbfsh_port_reset(musbfsh, true);
			break;
		case USB_PORT_FEAT_SUSPEND:
			musbfsh_port_suspend(musbfsh, true);
			break;
		case USB_PORT_FEAT_TEST:
#if 0
			if (unlikely(is_host_active(musbfsh)))
				goto error;

			wIndex >>= 8;
			switch (wIndex) {
			case 1:
				pr_debug("TEST_J\n");
				temp = MUSBFSH_TEST_J;
				break;
			case 2:
				pr_debug("TEST_K\n");
				temp = MUSBFSH_TEST_K;
				break;
			case 3:
				pr_debug("TEST_SE0_NAK\n");
				temp = MUSBFSH_TEST_SE0_NAK;
				break;
			case 4:
				pr_debug("TEST_PACKET\n");
				temp = MUSBFSH_TEST_PACKET;
				musbfsh_load_testpacket(musbfsh);
				break;
			case 5:
				pr_debug("TEST_FORCE_ENABLE\n");
				temp = MUSBFSH_TEST_FORCE_HOST |
				       MUSBFSH_TEST_FORCE_FS;

				musbfsh_writeb(musbfsh->mregs, MUSBFSH_DEVCTL,
					       MUSBFSH_DEVCTL_SESSION);
				break;
			case 6:
				pr_debug("TEST_FIFO_ACCESS\n");
				temp = MUSBFSH_TEST_FIFO_ACCESS;
				break;
			default:
				goto error;
			}
			musbfsh_writeb(musbfsh->mregs, MUSBFSH_TESTMODE, temp);
#endif
			break;
		default:
			goto error;
		}
		INFO("set feature %d\n", wValue);
		musbfsh->port1_status |= 1 << wValue;
		break;

	default:
error:
		/* "protocol stall" on error */
		retval = -EPIPE;
	}
	spin_unlock_irqrestore(&musbfsh->lock, flags);
	return retval;
}
static void musbfsh_port_reset(struct musbfsh *musbfsh, bool do_reset)
{
	u8 power;
	void __iomem *mbase = musbfsh->mregs;

	/* NOTE:  caller guarantees it will turn off the reset when
	 * the appropriate amount of time has passed
	 */
	power = musbfsh_readb(mbase, MUSBFSH_POWER);
	WARNING("reset=%d power=0x%x\n", do_reset, power);
	if (do_reset) {
		if (power & MUSBFSH_POWER_SUSPENDM) {
			WARNING("reset a suspended device\n");
#ifdef CONFIG_MTK_DT_USB_SUPPORT
			request_wakeup_md_timeout(0, 0);
#endif

#ifdef MTK_USB_RUNTIME_SUPPORT
			/* ERR("EINT to wake up MD for reset\n"); */
			/* wx, we may have to reset a suspended MD */
			/* request_wakeup_md_timeout(0, 0); */
#endif
			musbfsh_writeb(mbase,
				       MUSBFSH_POWER, power |
				       MUSBFSH_POWER_RESUME);
			mdelay(20);
			musbfsh_writeb(mbase, MUSBFSH_POWER,
				       power & ~MUSBFSH_POWER_RESUME);
		}

		/*
		 * If RESUME is set, we must make sure it stays minimum 20 ms.
		 * Then we must clear RESUME and wait a bit to let musb start
		 * generating SOFs. If we don't do this, OPT HS A 6.8 tests
		 * fail with "Error! Did not receive an SOF before suspend
		 * detected".
		 */
		if (power & MUSBFSH_POWER_RESUME) {
			WARNING("reset a resuming device\n");
			while (time_before(jiffies, musbfsh->rh_timer))
				mdelay(1);
			/* stop the resume signal */
			musbfsh_writeb(mbase, MUSBFSH_POWER,
				       power & ~MUSBFSH_POWER_RESUME);
			mdelay(1);
		}

		musbfsh->ignore_disconnect = true;
		power &= 0xf0;
		musbfsh_writeb(mbase, MUSBFSH_POWER,
			       power | MUSBFSH_POWER_RESET);
		mb();  /* flush POWER and PHY setting immediately */
		musbfsh->port1_status |= USB_PORT_STAT_RESET;
		musbfsh->port1_status &= ~USB_PORT_STAT_ENABLE;
		musbfsh->rh_timer = jiffies + msecs_to_jiffies(50);
	} else {
		INFO("Root port reset stopped\n");

#ifdef CONFIG_MTK_ICUSB_SUPPORT

		if (resistor_control_attr.value) {
			/* improve signal quality, from Dingjun */
#if 0
			/* FS_DISC_DISABLE */
			u32 TM1;

			TM1 = musbfsh_readl(mbase, 0x604);
			musbfsh_writel(mbase, 0x604, TM1 | 0x4);
			MYDBG("set FS_DISC_DISABLE\n");
#endif

			/* original flow from SS5 */
			USB11PHY_SET8(U1PHTCR2,
				      force_usb11_dm_rpd | force_usb11_dp_rpd);

			/*
			 * disconnect host port's pull down resistors
			 * on D+ and D-
			 */
			USB11PHY_CLR8(U1PHTCR2,
				      RG_USB11_DM_RPD | RG_USB11_DP_RPD);

			/*
			 * Tell MAC there still is a device attached,
			 * ohterwise we will get disconnect interrupt
			 */
			USB11PHY_SET8(U1PHTCR2,
				      force_usb11_dp_rpu | RG_USB11_DP_RPU);

			/* force */
			USB11PHY_SET8(0x6a, 0x20 | 0x10);
			/* RG */
			/*
			 * disconnect host port's pull down resistors
			 * on D+ and D-
			 */
			USB11PHY_CLR8(0x68, 0x80 | 0x40);

			/*
			 * Tell MAC there still is a device attached,
			 * ohterwise we will get disconnect interrupt.
			 */
			/* USB11PHY_SET8(U1PHTCR2,
			 *		 force_usb11_dp_rpu |
			 *		 RG_USB11_DP_RPU);
			 */

			MYDBG("USB1.1 PHY special config for IC-USB\n");
		} else {
			MYDBG("");
		}
#endif
		musbfsh_writeb(mbase,
			       MUSBFSH_POWER, power & ~MUSBFSH_POWER_RESET);


#ifdef CONFIG_MTK_ICUSB_SUPPORT
		if (resistor_control_attr.value)
			USB11PHY_CLR8(0x6a, 0x20 | 0x10);
		else
			MYDBG("");
#endif
		mb(); /* flush POWER and PHY setting immediately */
		musbfsh->ignore_disconnect = false;

		power = musbfsh_readb(mbase, MUSBFSH_POWER);
		if (power & MUSBFSH_POWER_HSMODE) {
			INFO("high-speed device connected\n");
			musbfsh->port1_status |= USB_PORT_STAT_HIGH_SPEED;
		}
#if 0				/* IC_USB from SS5 */
#ifdef IC_USB
		USB11PHY_SET8(U1PHTCR2,
			      force_usb11_dm_rpd | force_usb11_dp_rpd);

		/* disconnect host port's pull down resistors on D+ and D- */
		USB11PHY_CLR8(U1PHTCR2, RG_USB11_DM_RPD | RG_USB11_DP_RPD);

		/*
		 * tell MAC there still is a device attached,
		 * ohterwise we will get disconnect interrupt
		 */
		USB11PHY_SET8(U1PHTCR2, force_usb11_dp_rpu | RG_USB11_DP_RPU);
		WARNING("USB1.1 PHY special config for IC-USB 0x%X=%x\n",
			U1PHTCR2, USB11PHY_READ8(U1PHTCR2));
#endif
#endif
		musbfsh->port1_status &= ~USB_PORT_STAT_RESET;
		musbfsh->port1_status |=
			USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET << 16) |
			(USB_PORT_STAT_C_ENABLE << 16);

		/* call back func to notify the hub thread the state of hub! */
		usb_hcd_poll_rh_status(musbfsh_to_hcd(musbfsh));

		musbfsh->vbuserr_retry = VBUSERR_RETRY_COUNT;
	}
}
예제 #7
0
static void musbfsh_port_suspend(struct musbfsh *musbfsh, bool do_suspend)
{
	u8		power;
	u8		intrusbe;
	u8		intrusb;
	void __iomem	*mbase = musbfsh->mregs;
	int retries = 0;

	/* NOTE:  this doesn't necessarily put PHY into low power mode,
	 * turning off its clock; that's a function of PHY integration and
	 * MUSBFSH_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
	 * SE0 changing to connect (J) or wakeup (K) states.
	 */
	if (do_suspend) {
		/* clean MUSBFSH_INTR_SOF in MUSBFSH_INTRUSBE */
		intrusbe = musbfsh_readb(mbase, MUSBFSH_INTRUSBE);
		intrusbe &= ~MUSBFSH_INTR_SOF;
		musbfsh_writeb(mbase, MUSBFSH_INTRUSBE, intrusbe);
		mb();
		/* clean MUSBFSH_INTR_SOF in MUSBFSH_INTRUSB */
		intrusb = musbfsh_readb(mbase, MUSBFSH_INTRUSB);
		intrusb |= MUSBFSH_INTR_SOF;
		musbfsh_writeb(mbase, MUSBFSH_INTRUSB, intrusb);
		mb();
		retries = 10000;
		intrusb = musbfsh_readb(mbase, MUSBFSH_INTRUSB);
		while (!(intrusb & MUSBFSH_INTR_SOF)) {
			intrusb = musbfsh_readb(mbase, MUSBFSH_INTRUSB);
			if (retries-- < 1)
				break;
		}

		/* delay 10 us */
		udelay(10);

		/* set MUSBFSH_POWER_SUSPENDM in MUSBFSH_POWER_SUSPENDM */
		power = musbfsh_readb(mbase, MUSBFSH_POWER);

#ifdef MTK_USB_RUNTIME_SUPPORT
		/* mask remote wake up IRQ between port suspend and bus suspend.
		    hub.c will call set_port_feature first then usb_set_device_state, so if EINT comes between them, resume flow may see
		    device state without USB_STATE_SUSPENDED and do nothing.
		    So we postpone remote wake up IRQ untill the suspend flow is all done (when bus_suspend is called). Since suspend flow
		    may be interrupted (root hub is suspended, but not host controller), so we also unmaks EINT when resume is done.
		*/
		mt_eint_mask(CUST_EINT_MT6280_USB_WAKEUP_NUM);
#endif

		retries = 10000;

		power &= ~MUSBFSH_POWER_RESUME;
		power |= MUSBFSH_POWER_SUSPENDM;
		musbfsh_writeb(mbase, MUSBFSH_POWER, power);

		/* Needed for OPT A tests */
		power = musbfsh_readb(mbase, MUSBFSH_POWER);
		while (power & MUSBFSH_POWER_SUSPENDM) {
			power = musbfsh_readb(mbase, MUSBFSH_POWER);
			if (retries-- < 1)
				break;
		}
		mb();
		WARNING( "Root port suspended, power 0x%02x\n", power);

		musbfsh->port1_status |= USB_PORT_STAT_SUSPEND;
	} else {
		power = musbfsh_readb(mbase, MUSBFSH_POWER);
		if(!(power & MUSBFSH_POWER_SUSPENDM)) {
			WARNING("Root port resuming abort, power 0x%02x\n", power);
			if(power & MUSBFSH_POWER_RESUME)
				goto finish;
			else
				return;
		}

#ifdef MTK_USB_RUNTIME_SUPPORT
		//ERR("EINT to wake up MD for resume\n");
		//request_wakeup_md_timeout(0, 0); //wx, wakeup MD first
#endif
		power &= ~MUSBFSH_POWER_SUSPENDM;
		power |= MUSBFSH_POWER_RESUME;
		musbfsh_writeb(mbase, MUSBFSH_POWER, power);
		mb();
		WARNING("Root port resuming, power 0x%02x\n", power);
finish:
		/* later, GetPortStatus will stop RESUME signaling */
		musbfsh->port1_status |= MUSBFSH_PORT_STAT_RESUME;
		musbfsh->rh_timer = jiffies + msecs_to_jiffies(20);
	}
}
예제 #8
0
static void musbfsh_port_reset(struct musbfsh *musbfsh, bool do_reset)
{
	u8		power;
	void __iomem	*mbase = musbfsh->mregs;

	/* NOTE:  caller guarantees it will turn off the reset when
	 * the appropriate amount of time has passed
	 */
	power = musbfsh_readb(mbase, MUSBFSH_POWER);
	WARNING("reset=%d power=0x%x\n", do_reset, power);
	if (do_reset) {
		if(power & MUSBFSH_POWER_SUSPENDM) {
			WARNING("reset a suspended device\n");

#ifdef MTK_USB_RUNTIME_SUPPORT
			//ERR("EINT to wake up MD for reset\n");
			//request_wakeup_md_timeout(0, 0); //wx, we may have to reset a suspended MD
#endif
			musbfsh_writeb(mbase, MUSBFSH_POWER,
				power | MUSBFSH_POWER_RESUME);
			mdelay(20);
			musbfsh_writeb(mbase, MUSBFSH_POWER,
				power & ~MUSBFSH_POWER_RESUME);
		}

		/*
		 * If RESUME is set, we must make sure it stays minimum 20 ms.
		 * Then we must clear RESUME and wait a bit to let musb start
		 * generating SOFs. If we don't do this, OPT HS A 6.8 tests
		 * fail with "Error! Did not receive an SOF before suspend
		 * detected".
		 */
		if (power &  MUSBFSH_POWER_RESUME) {
			WARNING("reset a resuming device\n");
			while (time_before(jiffies, musbfsh->rh_timer))
				mdelay(1);
			musbfsh_writeb(mbase, MUSBFSH_POWER,//stop the resume signal
				power & ~MUSBFSH_POWER_RESUME);
			mdelay(1);
		}

		musbfsh->ignore_disconnect = true;
		power &= 0xf0;
		musbfsh_writeb(mbase, MUSBFSH_POWER,
				power | MUSBFSH_POWER_RESET);
		mb();
		musbfsh->port1_status |= USB_PORT_STAT_RESET;
		musbfsh->port1_status &= ~USB_PORT_STAT_ENABLE;
		musbfsh->rh_timer = jiffies + msecs_to_jiffies(50);
	} else {
		INFO( "Root port reset stopped\n");
		musbfsh_writeb(mbase, MUSBFSH_POWER,
				power & ~MUSBFSH_POWER_RESET);
		mb();
		musbfsh->ignore_disconnect = false;

		power = musbfsh_readb(mbase, MUSBFSH_POWER);
		if (power & MUSBFSH_POWER_HSMODE) {
			INFO( "high-speed device connected\n");
			musbfsh->port1_status |= USB_PORT_STAT_HIGH_SPEED;
		}
#ifdef IC_USB
		USB11PHY_SET8(U1PHTCR2, force_usb11_dm_rpd | force_usb11_dp_rpd);
		USB11PHY_CLR8(U1PHTCR2, RG_USB11_DM_RPD | RG_USB11_DP_RPD);  // disconnect host port's pull down resistors on D+ and D-
		USB11PHY_SET8(U1PHTCR2, force_usb11_dp_rpu | RG_USB11_DP_RPU); // tell MAC there still is a device attached, ohterwise we will get disconnect interrupt
		WARNING("USB1.1 PHY special config for IC-USB 0x%X=%x\n", U1PHTCR2, USB11PHY_READ8(U1PHTCR2));
#endif
		musbfsh->port1_status &= ~USB_PORT_STAT_RESET;
		musbfsh->port1_status |= USB_PORT_STAT_ENABLE
					| (USB_PORT_STAT_C_RESET << 16)
					| (USB_PORT_STAT_C_ENABLE << 16);
		usb_hcd_poll_rh_status(musbfsh_to_hcd(musbfsh));//call back func to notify the hub thread the state of hub!

		musbfsh->vbuserr_retry = VBUSERR_RETRY_COUNT;
	}
}