int dwc_peripheral_start(void *data, bool enable)
{
	struct gadget_wrapper *d;
	d = gadget_wrapper;

	pr_info("usb: %s d->vbus=%d, enable=%d\n", __func__, d->vbus, enable);

	mutex_lock(&udc_lock);
	d->vbus = enable;
	if ( !d->softconnect )
	{
		printk("usb: %s , d->softconnect is %d / udc don't start now \r\n",__func__, d->softconnect );
		mutex_unlock(&udc_lock);
		return 0;
	}

	if(enable) {
		wake_lock(&usb_wake_lock);
		udc_enable();
		dwc_otg_core_init(GET_CORE_IF(d->pcd));
		dwc_otg_enable_global_interrupts(GET_CORE_IF(d->pcd));
		dwc_otg_core_dev_init(GET_CORE_IF(d->pcd));
		d->udc_startup = 1;
	} else {
		dwc_otg_disable_global_interrupts(GET_CORE_IF(d->pcd));
		dwc_otg_clear_all_int(GET_CORE_IF(d->pcd));
		dwc_otg_pcd_stop(d->pcd);
		udc_disable();
		d->udc_startup = 0;
		wake_unlock(&usb_wake_lock);
	}
	mutex_unlock(&udc_lock);
	return 0;
}
static void __udc_shutdown(void)
{
	struct gadget_wrapper *d;

	d = gadget_wrapper;

	pr_info("USB:shutdown udc\n");
	if (d->udc_startup) {
		dwc_otg_disable_global_interrupts(GET_CORE_IF(d->pcd));
		dwc_otg_clear_all_int(GET_CORE_IF(d->pcd));
		dwc_otg_pcd_stop(d->pcd);
		udc_disable();
		d->udc_startup = 0;
		wake_unlock(&usb_wake_lock);
	}
}
/*
 * This function is called when an lm_device is bound to a
 * dwc_otg_driver. It creates the driver components required to
 * control the device (CIL, HCD, and PCD) and it initializes the
 * device. The driver components are stored in a dwc_otg_device
 * structure. A reference to the dwc_otg_device is saved in the
 * lm_device. This allows the driver to access the dwc_otg_device
 * structure on subsequent calls to driver methods for this device.
 *
 */
int usb_driver_init(uint32_t base_addr)
{
	int retval = 0;

	__DWC_WARN("dwc_otg_driver_init\n");

	dwc_otg_device = &static_data->dwc_otg_device_inst;

	DWC_MEMSET(dwc_otg_device, 0, sizeof(*dwc_otg_device));

	/*
	 * Initialize driver data to point to the global DWC_otg
	 * Device structure.
	 */
	__DWC_ERROR("dwc_otg_device addr = 0x%p\n", dwc_otg_device);

	dwc_otg_device->core_if = dwc_otg_cil_init(base_addr);
	if (!dwc_otg_device->core_if) {
		__DWC_ERROR("CIL initialization failed!\n");
		retval = -DWC_E_NO_MEMORY;
		goto fail;
	}

#ifdef USB_DEBUG
	/*
	 * Attempt to ensure this device is really a DWC_otg Controller.
	 * Read and verify the SNPSID register contents. The value should be
	 * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3",
	 * as in "OTG version 2.XX" or "OTG version 3.XX".
	 */

	if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) !=
	     0x4F542000)
	    && ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) !=
		0x4F543000)) {
		__DWC_WARN("Bad value for SNPSID: 0x%x\n",
			   dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
		retval = -DWC_E_INVALID;
		goto fail;
	}
#endif /* USB_DEBUG */

	/*
	 * Disable the global interrupt until all the interrupt
	 * handlers are installed.
	 */
	__DWC_WARN("USB INIT: Disabling global IRQ\n");
	dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);

	/*
	 * Initialize the DWC_otg core.
	 */
	__DWC_WARN("USB INIT: Initializing OTG core\n");
	dwc_otg_core_init(dwc_otg_device->core_if);

	/*
	 * Initialize the PCD
	 */
	__DWC_WARN("USB INIT: Initializing PCD\n");
	retval = pcd_init(dwc_otg_device);
	if (retval != 0) {
		__DWC_ERROR("pcd_init failed\n");
		dwc_otg_device->pcd = NULL;
		goto fail;
	}

	__DWC_WARN("USB INIT: Enabling global IRQ\n");
	dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);

	__DWC_WARN("DWC core initialized! \n");
	return 0;

fail:
	__DWC_ERROR("ERROR! unable to init USB driver\n");
	return retval;
}
Exemple #4
0
static int __devinit dwc_otg_driver_probe(struct platform_device *ofdev)
{
	int retval;
	struct dwc_otg_device *dwc_dev;
	struct device *dev = &ofdev->dev;
	struct resource res;
	ulong gusbcfg_addr;
	u32 usbcfg = 0;
	struct resource *nres = 0;
#ifdef CONFIG_OF
	u32 prop;
	u32 prop_array[15];
#endif

	dwc_dev = kzalloc(sizeof(*dwc_dev), GFP_KERNEL);
	if (!dwc_dev) {
		dev_err(dev, "kmalloc of dwc_otg_device failed\n");
		retval = -ENOMEM;
		goto fail_dwc_dev;
	}

	/* Retrieve the memory and IRQ resources. */
	dwc_dev->irq = platform_get_irq(ofdev, 0);
	if (dwc_dev->irq == NO_IRQ) {
		dev_err(dev, "no device irq\n");
		retval = -ENODEV;
		goto fail_of_irq;
	}

	nres = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
	res = *nres;
	if(nres == 0) {
		dev_err(dev, "%s: Can't get USB-OTG register address\n",
			__func__);
		retval = -ENOMEM;
		goto fail_of_irq;
	}

	dwc_dev->phys_addr = res.start;
	dwc_dev->base_len = res.end - res.start + 1;
	if (!request_mem_region(dwc_dev->phys_addr,
				dwc_dev->base_len, dwc_driver_name)) {
		dev_err(dev, "request_mem_region failed\n");
		retval = -EBUSY;
		goto fail_of_irq;
	}

	/* Map the DWC_otg Core memory into virtual address space. */
	dwc_dev->base = ioremap(platform_get_resource(ofdev, IORESOURCE_MEM, 0)->start, SZ_256K);
	if (!dwc_dev->base) {
		dev_err(dev, "ioremap() failed\n");
		retval = -ENOMEM;
		goto fail_ioremap;
	}
	dev_dbg(dev, "mapped base=0x%08x\n", (__force u32)dwc_dev->base);

	/*
	 * Initialize driver data to point to the global DWC_otg
	 * Device structure.
	 */
	dev_set_drvdata(dev, dwc_dev);//driver

	dwc_dev->core_if =
	    dwc_otg_cil_init(dwc_dev->base, &dwc_otg_module_params);
	if (!dwc_dev->core_if) {
		dev_err(dev, "CIL initialization failed!\n");
		retval = -ENOMEM;
		goto fail_cil_init;
	}

	/*
	* Set the wqfunc of this core_if as "not set"
	*/
	dwc_dev->core_if->wqfunc_setup_done = 0;

	/*
	 * Validate parameter values after dwc_otg_cil_init.
	 */
	if (check_parameters(dwc_dev->core_if)) {
		retval = -EINVAL;
		goto fail_check_param;
	}

#ifdef CONFIG_OF
	if(!of_property_read_u32(ofdev->dev.of_node,
		"dma-mask", (u32*)&dwc_otg_dma_mask)) {
		dev->dma_mask = &dwc_otg_dma_mask;
	}
	else {
		dev->dma_mask = NULL;
	}

	if(!of_property_read_u32(ofdev->dev.of_node,
		"ulpi-ddr", &prop)) {
		dwc_otg_module_params.phy_ulpi_ddr = prop;
	}

	if(!of_property_read_u32(ofdev->dev.of_node,
		"host-rx-fifo-size", &prop)) {
		dwc_otg_module_params.host_rx_fifo_size = prop;
	}
	if(!of_property_read_u32(ofdev->dev.of_node,
		"dev-rx-fifo-size", &prop)) {
		dwc_otg_module_params.dev_rx_fifo_size = prop;
	}
	if(!of_property_read_u32(ofdev->dev.of_node,
		"host-nperio-tx-fifo-size", &prop)) {
		dwc_otg_module_params.host_nperio_tx_fifo_size = prop;
	}
	if(!of_property_read_u32(ofdev->dev.of_node,
		"dev-nperio-tx-fifo-size", &prop)) {
		dwc_otg_module_params.dev_nperio_tx_fifo_size = prop;
	}
	if(!of_property_read_u32(ofdev->dev.of_node,
		"host-perio-tx-fifo-size", &prop)) {
		dwc_otg_module_params.host_perio_tx_fifo_size = prop;
	}
	if(!of_property_read_u32_array(ofdev->dev.of_node,
		"dev-perio-tx-fifo-size", prop_array, MAX_PERIO_FIFOS)) {
		int i;
		for(i=0; i<MAX_PERIO_FIFOS; i++)
			dwc_otg_module_params.dev_tx_fifo_size[i]
				= prop_array[i];
	}
	if(!of_property_read_u32_array(ofdev->dev.of_node,
		"dev-tx-fifo-size", prop_array, MAX_TX_FIFOS)) {
		int i;
		for(i=0; i<MAX_TX_FIFOS; i++)
			dwc_otg_module_params.dev_perio_tx_fifo_size[i]
				= prop_array[i];
	}
#endif

	usb_nop_xceiv_register();
	dwc_dev->core_if->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
	if (!dwc_dev->core_if->xceiv) {
		retval = -ENODEV;
		goto fail_xceiv;
	}
	dwc_set_feature(dwc_dev->core_if);

	/* Initialize the DWC_otg core. */
	dwc_otg_core_init(dwc_dev->core_if);

	/*
	 * Disable the global interrupt until all the interrupt
	 * handlers are installed.
	 */
	spin_lock(&dwc_dev->lock);
	dwc_otg_disable_global_interrupts(dwc_dev->core_if);
	spin_unlock(&dwc_dev->lock);

	/*
	 * Install the interrupt handler for the common interrupts before
	 * enabling common interrupts in core_init below.
	 */
	retval = request_irq(dwc_dev->irq, dwc_otg_common_irq,
			     IRQF_SHARED, "dwc_otg", dwc_dev);
	if (retval) {
		dev_err(dev, "request of irq%d failed retval: %d\n",
			dwc_dev->irq, retval);
		retval = -EBUSY;
		goto fail_req_irq;
	} else {
		dwc_dev->common_irq_installed = 1;
	}

	if (!dwc_has_feature(dwc_dev->core_if, DWC_HOST_ONLY)) {
	//if (dwc_has_feature(dwc_dev->core_if, DWC_DEVICE_ONLY)) {
		/* Initialize the PCD */
		retval = dwc_otg_pcd_init(dev);
		if (retval) {
			dev_err(dev, "dwc_otg_pcd_init failed\n");
			dwc_dev->pcd = NULL;
			goto fail_req_irq;
		}
	}

	gusbcfg_addr = (ulong) (dwc_dev->core_if->core_global_regs)
		+ DWC_GUSBCFG;
	if (!dwc_has_feature(dwc_dev->core_if, DWC_DEVICE_ONLY)) {
	//if (dwc_has_feature(dwc_dev->core_if, DWC_HOST_ONLY)) {
		/* Initialize the HCD and force_host_mode */
		usbcfg = dwc_reg_read(gusbcfg_addr, 0);
		usbcfg |= DWC_USBCFG_FRC_HST_MODE;
		dwc_reg_write(gusbcfg_addr, 0, usbcfg);

		retval = dwc_otg_hcd_init(dev, dwc_dev);
		if (retval) {
			dev_err(dev, "dwc_otg_hcd_init failed\n");
			dwc_dev->hcd = NULL;
			goto fail_hcd;
		}
		/* configure chargepump interrupt */
		dwc_dev->hcd->cp_irq = platform_get_irq_byname(ofdev, "chargepumpirq");
		if(dwc_dev->hcd->cp_irq != -ENXIO) {
			retval = request_irq(dwc_dev->hcd->cp_irq,
					     dwc_otg_externalchgpump_irq,
					     IRQF_SHARED,
					     "dwc_otg_ext_chg_pump", dwc_dev);
			if (retval) {
				dev_err(dev,
					"request of irq failed retval: %d\n",
					retval);
				retval = -EBUSY;
				goto fail_hcd;
			} else {
				dev_dbg(dev, "%s: ExtChgPump Detection "
					"IRQ registered\n", dwc_driver_name);
			}
		}
	}
	/*
	 * Enable the global interrupt after all the interrupt
	 * handlers are installed.
	 */
	dwc_otg_enable_global_interrupts(dwc_dev->core_if);

#if 0
	usbcfg = dwc_reg_read(gusbcfg_addr, 0);
	usbcfg &= ~DWC_USBCFG_FRC_HST_MODE;
	dwc_reg_write(gusbcfg_addr, 0, usbcfg);
#endif

	return 0;
fail_hcd:
	free_irq(dwc_dev->irq, dwc_dev);
	if (!dwc_has_feature(dwc_dev->core_if, DWC_HOST_ONLY)) {
		if (dwc_dev->pcd)
			dwc_otg_pcd_remove(dev);
	}
fail_req_irq:
	usb_put_phy(dwc_dev->core_if->xceiv);
fail_xceiv:
	usb_nop_xceiv_unregister();
fail_check_param:
	dwc_otg_cil_remove(dwc_dev->core_if);
fail_cil_init:
	dev_set_drvdata(dev, NULL);
	iounmap(dwc_dev->base);
fail_ioremap:
	release_mem_region(dwc_dev->phys_addr, dwc_dev->base_len);
fail_of_irq:
	kfree(dwc_dev);
fail_dwc_dev:
	return retval;
}
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) {
		dwc_otg_disable_global_interrupts(core_if);
		/* 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); */
			dwc_msleep(10);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
				"Connection id status change timed out");
		core_if->op_state = B_PERIPHERAL;
		dwc_otg_core_init(core_if);
		cil_pcd_start(core_if);
		dwc_otg_enable_global_interrupts(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); */
			dwc_msleep(10);
			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"));

#if 0
	DWC_SPINUNLOCK(core_if->lock);

	/*
	 * Need to schedule a work, as there are possible DELAY function calls
	 * Release lock before scheduling workq as it holds spinlock during scheduling
	 */

	DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
					   core_if, "connection id status change");
	DWC_SPINLOCK(core_if->lock);
#endif

	/* 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
	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");

	if (dwc_otg_is_device_mode(core_if)) {
		DWC_PRINTF("SRP: Device mode\n");
	} else {
		hprt0_data_t hprt0;
		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);

		/* Start the Connection timer. So a message can be displayed
		 * if connect does not occur within 10 seconds. */
		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 };

	printk(KERN_INFO "[USB]%s\n", __func__);

	if (!core_if) {
		printk(KERN_ERR "%s: core_if NULL!\n", __func__);
		return;
	}

#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;
}

/**
 * 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_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);

	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);

			DWC_SPINUNLOCK(core_if->lock);
			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
			}
			DWC_SPINLOCK(core_if->lock);
		} 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) {
			pcgcctl_data_t pcgcctl = {.d32 = 0 };

			/* Restart the Phy Clock */
			pcgcctl.b.stoppclk = 1;
			DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
			DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
		} else {
			/** Change to L0 state*/
			core_if->lx_state = DWC_OTG_L0;
		}
	}
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);
	}
}
/**
 * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
 */
static void adp_vbuson_timeout(void *ptr)
{
	gpwrdn_data_t gpwrdn;
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
	hprt0_data_t hprt0 = {.d32 = 0 };
	pcgcctl_data_t pcgcctl = {.d32 = 0 };
	DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
	if (core_if) {
		core_if->adp.vbuson_timer_started = 0;
		/* Turn off vbus */
		hprt0.b.prtpwr = 1;
		DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
		gpwrdn.d32 = 0;

		/* Power off the core */
		if (core_if->power_down == 2) {
			/* Enable Wakeup Logic */
            /* gpwrdn.b.wkupactiv = 1; */
			gpwrdn.b.pmuactv = 0;
			gpwrdn.b.pwrdnrstn = 1;
			gpwrdn.b.pwrdnclmp = 1;
			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
					 gpwrdn.d32);

			/* Suspend the Phy Clock */
			pcgcctl.b.stoppclk = 1;
			DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);

			/* Switch on VDD */
            /* gpwrdn.b.wkupactiv = 1;*/
			gpwrdn.b.pmuactv = 1;
			gpwrdn.b.pwrdnrstn = 1;
			gpwrdn.b.pwrdnclmp = 1;
			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
					 gpwrdn.d32);
		} else {
			/* Enable Power Down Logic */
			gpwrdn.b.pmuintsel = 1;
			gpwrdn.b.pmuactv = 1;
			DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
		}

		/* Power off the core */
		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);
		}

		/* Unmask SRP detected interrupt from Power Down Logic */
		gpwrdn.d32 = 0;
		gpwrdn.b.srp_det_msk = 1;
		DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);

		dwc_otg_adp_probe_start(core_if);
		dwc_otg_dump_global_registers(core_if);
		dwc_otg_dump_host_registers(core_if);
	}

}

/**
 * Start the ADP Initial Probe timer to detect if Port Connected interrupt is 
 * not asserted within 1.1 seconds.
 *
 * @param core_if the pointer to core_if strucure.
 */
void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
{
	core_if->adp.vbuson_timer_started = 1;
	if (core_if->adp.vbuson_timer)
	{
		DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
		/* 1.1 secs + 60ms necessary for cil_hcd_start*/
		DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
	} else {
		DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
	}
}

#if 0
/**
 * Masks all DWC OTG core interrupts
 *
 */
static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
{
	int i;
	gahbcfg_data_t ahbcfg = {.d32 = 0 };

	/* Mask Host Interrupts */

	/* Clear and disable HCINTs */
	for (i = 0; i < core_if->core_params->host_channels; i++) {
		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);

	}

	/* Clear and disable HAINT */
	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);

	/* Mask Device Interrupts */
	if (!core_if->multiproc_int_enable) {
		/* Clear and disable IN Endpoint interrupts */
		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
					diepint, 0xFFFFFFFF);
		}

		/* Clear and disable OUT Endpoint interrupts */
		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
		for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
					doepint, 0xFFFFFFFF);
		}

		/* Clear and disable DAINT */
		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
				0xFFFFFFFF);
		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
	} else {
		for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
					diepeachintmsk[i], 0);
			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
					diepint, 0xFFFFFFFF);
		}

		for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
					doepeachintmsk[i], 0);
			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
					doepint, 0xFFFFFFFF);
		}

		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
				0);
		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
				0xFFFFFFFF);

	}

	/* Disable interrupts */
	ahbcfg.b.glblintrmsk = 1;
	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);

	/* Disable all interrupts. */
	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);

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

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

/**
 * Unmask Port Connection Detected interrupt
 *
 */
static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
{
	gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };

	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
}
#endif

/**
 * Starts the ADP Probing
 *
 * @param core_if the pointer to core_if structure.
 */
uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
{

	adpctl_data_t adpctl = {.d32 = 0};
	gpwrdn_data_t gpwrdn;
#if 0
	adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
								.b.adp_sns_int = 1, b.adp_tmout_int};
#endif
	dwc_otg_disable_global_interrupts(core_if);
	DWC_PRINTF("ADP Probe Start\n");
	core_if->adp.probe_enabled = 1;

	adpctl.b.adpres = 1;
	dwc_otg_adp_write_reg(core_if, adpctl.d32);

	while (adpctl.b.adpres) {
		adpctl.d32 = dwc_otg_adp_read_reg(core_if);
	}

	adpctl.d32 = 0;
	gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);

	/* In Host mode unmask SRP detected interrupt */
	gpwrdn.d32 = 0;
	gpwrdn.b.sts_chngint_msk = 1;
	if (!gpwrdn.b.idsts) {
		gpwrdn.b.srp_det_msk = 1;
	}
	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);

	adpctl.b.adp_tmout_int_msk = 1;
	adpctl.b.adp_prb_int_msk = 1;
	adpctl.b.prb_dschg = 1;
	adpctl.b.prb_delta = 1;
	adpctl.b.prb_per = 1;
	adpctl.b.adpen = 1;
	adpctl.b.enaprb = 1;

	dwc_otg_adp_write_reg(core_if, adpctl.d32);
	DWC_PRINTF("ADP Probe Finish\n");
	return 0;
}

/**
 * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted 
 * within 3 seconds.
 *
 * @param core_if the pointer to core_if strucure.
 */
void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
{
	core_if->adp.sense_timer_started = 1;
	DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
}

/**
 * Starts the ADP Sense
 *
 * @param core_if the pointer to core_if strucure.
 */
uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
{
	adpctl_data_t adpctl;

	DWC_PRINTF("ADP Sense Start\n");

	/* Unmask ADP sense interrupt and mask all other from the core */
	adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
	adpctl.b.adp_sns_int_msk = 1;
	dwc_otg_adp_write_reg(core_if, adpctl.d32);
	dwc_otg_disable_global_interrupts(core_if); // vahrama 

	/* Set ADP reset bit*/
	adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
	adpctl.b.adpres = 1;
	dwc_otg_adp_write_reg(core_if, adpctl.d32);

	while (adpctl.b.adpres) {
		adpctl.d32 = dwc_otg_adp_read_reg(core_if);
	}

	adpctl.b.adpres = 0;
	adpctl.b.adpen = 1;
	adpctl.b.enasns = 1;
	dwc_otg_adp_write_reg(core_if, adpctl.d32);

	dwc_otg_adp_sense_timer_start(core_if);

	return 0;
}