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);
	}
}
Example #2
0
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;
	}
}