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); } }
static ssize_t emd_cfifo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { cfifo_instance_t *cfifo_instance=(cfifo_instance_t *)file->private_data; int ret = 0, part; int data_be_write, size, value; unsigned read, write, length; char *tx_buffer; if(count == 0) { EMD_MSG_INF("cfifo","emd_cfifo_write: count=0\n"); return 0; } mutex_lock(&cfifo_instance->emd_cfifo_mutex); data_be_write = (int)count; #if 0 EMD_MSG_INF("cfifo","emd_cfifo%d_write: write_request=%d write=%d read=%d\n", cfifo_instance->idx, data_be_write, *(cfifo_instance->shared_mem.tx_control.write), *(cfifo_instance->shared_mem.tx_control.read)); #endif size = 0; /* Check free space */ read = (int)(*(cfifo_instance->shared_mem.tx_control.read)); write = (int)(*(cfifo_instance->shared_mem.tx_control.write)); length = (int)(*(cfifo_instance->shared_mem.tx_control.length)); tx_buffer = cfifo_instance->shared_mem.tx_control.buffer; do { size = emd_cfifo_writeable(cfifo_instance); if (size == 0) { if (file->f_flags & O_NONBLOCK) { ret=-EAGAIN; goto out; } else { // Block write value = wait_event_interruptible(cfifo_instance->write_waitq, emd_cfifo_writeable(cfifo_instance)); if(value == -ERESTARTSYS) { EMD_MSG_INF("cfifo","(W)Interrupted syscall.signal_pend=0x%llx\n", *(long long *)current->pending.signal.sig); ret = -EINTR; goto out; } } } else break; }while(size==0); // Calculate write size if(data_be_write >= size) data_be_write = size; if( (write+data_be_write) >= length) { // Write twice // 1st write part = length - write; ret = copy_from_user(&tx_buffer[write],buf,part); if (ret) { EMD_MSG_INF("cfifo","write: copy from user fail:tx_buffer=0x%08x,write=%d, buf=%08x, part=%d ret=%d line=%d\n",\ (unsigned int)tx_buffer,write,(unsigned int)buf,part,ret,__LINE__); ret=-EFAULT; goto out; } // 2nd write ret = copy_from_user(tx_buffer,&buf[part],data_be_write - part); if (ret) { EMD_MSG_INF("cfifo","write: copy from user fail:tx_buffer=0x%08x,buf=%08x,part=%d,data_be_write-part=%d ret=%d line=%d\n",\ (unsigned int)tx_buffer,(unsigned int)buf,part,data_be_write - part,ret,__LINE__); ret=-EFAULT; goto out; } } else { // Write once is OK ret = copy_from_user(&tx_buffer[write],buf,data_be_write); if (ret) { EMD_MSG_INF("cfifo","write: copy from user fail:tx_buffer=0x%08x,write=%d,buf=%08x,data_be_write=%d ret=%d line=%d\n",\ (unsigned int)tx_buffer,write,(unsigned int)buf,data_be_write,ret,__LINE__); ret=-EFAULT; goto out; } } // Update read pointer write += data_be_write; if(write >= length) write -= length; *(cfifo_instance->shared_mem.tx_control.write) = write; ret = data_be_write; out: mutex_unlock(&cfifo_instance->emd_cfifo_mutex); if(emd_cfifo_readable(cfifo_instance->other_side)) { wake_up_interruptible(&cfifo_instance->other_side->read_waitq); wake_up_interruptible_poll(&cfifo_instance->other_side->poll_waitq_r,POLLIN); wake_lock_timeout(&cfifo_instance->other_side->wake_lock, HZ / 2); if(cfifo_instance->idx == 1) { //muxd write, so wake up md to read request_wakeup_md_timeout(1, 1); } } EMD_MSG_INF("cfifo","emd_cfifo%d_write: ret=%d\n",cfifo_instance->idx,ret); return ret; }
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; } }