static int intel_mid_ehci_driver_register(struct pci_driver *host_driver)
{
	struct usb_phy			*otg;
	struct intel_mid_otg_xceiv	*iotg;

	otg = usb_get_transceiver();
	if (otg == NULL || host_driver == NULL)
		return -EINVAL;

	iotg = otg_to_mid_xceiv(otg);
	iotg->start_host = ehci_mid_start_host;
	iotg->stop_host = ehci_mid_stop_host;
	iotg->runtime_suspend_host = ehci_mid_runtime_suspend_host;
	iotg->runtime_resume_host = ehci_mid_runtime_resume_host;

	iotg->suspend_host = ehci_mid_suspend_host;
	iotg->suspend_noirq_host = ehci_mid_suspend_noirq_host;
	iotg->resume_host = ehci_mid_resume_host;
	iotg->resume_noirq_host = ehci_mid_resume_noirq_host;

#ifdef CONFIG_USB_SUSPEND
	wake_lock_init(&iotg->wake_lock, WAKE_LOCK_SUSPEND, "ehci_wake_lock");
#endif

	/* notify host driver is registered */
	atomic_notifier_call_chain(&iotg->iotg_notifier,
				MID_OTG_NOTIFY_HOSTADD, iotg);

	usb_put_transceiver(otg);

	return 0;
}
static void intel_mid_ehci_driver_unregister(struct pci_driver *host_driver)
{
	struct usb_phy			*otg;
	struct intel_mid_otg_xceiv	*iotg;

	otg = usb_get_transceiver();
	if (otg == NULL)
		return ;

	iotg = otg_to_mid_xceiv(otg);
	iotg->start_host = NULL;
	iotg->stop_host = NULL;
	iotg->runtime_suspend_host = NULL;
	iotg->runtime_resume_host = NULL;

#ifdef CONFIG_USB_SUSPEND
	wake_lock_destroy(&iotg->wake_lock);
#endif

	/* notify host driver is unregistered */
	atomic_notifier_call_chain(&iotg->iotg_notifier,
				MID_OTG_NOTIFY_HOSTREMOVE, iotg);

	usb_put_transceiver(otg);
}
static int intel_mid_ehci_driver_register(struct pci_driver *host_driver)
{
	struct usb_phy			*otg;
	struct intel_mid_otg_xceiv	*iotg;

	otg = usb_get_phy(USB_PHY_TYPE_USB2);
	if (otg == NULL || host_driver == NULL)
		return -EINVAL;

	iotg = otg_to_mid_xceiv(otg);
	iotg->start_host = ehci_mid_start_host;
	iotg->stop_host = ehci_mid_stop_host;
	iotg->runtime_suspend_host = ehci_mid_runtime_suspend_host;
	iotg->runtime_resume_host = ehci_mid_runtime_resume_host;

	iotg->suspend_host = ehci_mid_suspend_host;
	iotg->suspend_noirq_host = ehci_mid_suspend_noirq_host;
	iotg->resume_host = ehci_mid_resume_host;
	iotg->resume_noirq_host = ehci_mid_resume_noirq_host;

	/* notify host driver is registered */
	atomic_notifier_call_chain(&iotg->iotg_notifier,
				MID_OTG_NOTIFY_HOSTADD, iotg);

	usb_put_phy(otg);

	return 0;
}
/* the root hub will call this callback when device added/removed */
static void otg_notify(struct usb_device *udev, unsigned action)
{
	struct usb_phy *otg;
	struct intel_mid_otg_xceiv *iotg;

	/* Ignore root hub add/remove event */
	if (!udev->parent) {
		pr_debug("%s Ignore root hub otg_notify\n", __func__);
		return;
	}

	/* Ignore USB devices on external hub */
	if (udev->parent && udev->parent->parent)
		return;

	otg = usb_get_transceiver();
	if (otg == NULL) {
		printk(KERN_ERR "%s Failed to get otg transceiver\n", __func__);
		return;
	}
	iotg = otg_to_mid_xceiv(otg);

	switch (action) {
	case USB_DEVICE_ADD:
		pr_debug("Notify OTG HNP add device\n");
		atomic_notifier_call_chain(&iotg->iotg_notifier,
					MID_OTG_NOTIFY_CONNECT, iotg);
		break;
	case USB_DEVICE_REMOVE:
		pr_debug("Notify OTG HNP delete device\n");
		atomic_notifier_call_chain(&iotg->iotg_notifier,
					MID_OTG_NOTIFY_DISCONN, iotg);
		break;
	case USB_OTG_TESTDEV:
		pr_debug("Notify OTG test device\n");
		atomic_notifier_call_chain(&iotg->iotg_notifier,
					MID_OTG_NOTIFY_TEST, iotg);
		break;
	case USB_OTG_TESTDEV_VBUSOFF:
		pr_debug("Notify OTG test device, Vbusoff mode\n");
		atomic_notifier_call_chain(&iotg->iotg_notifier,
					MID_OTG_NOTIFY_TEST_VBUS_OFF, iotg);
		break;
	default:
		usb_put_transceiver(otg);
		return ;
	}
	usb_put_transceiver(otg);
	return;
}
static int usb_otg_resume(struct usb_hcd *hcd)
{
	struct usb_phy *otg;
	struct intel_mid_otg_xceiv *iotg;

	otg = usb_get_transceiver();
	if (otg == NULL) {
		printk(KERN_ERR "%s Failed to get otg transceiver\n", __func__);
		return -EINVAL;
	}
	iotg = otg_to_mid_xceiv(otg);
	dev_dbg(otg->dev, "%s OTG HNP update resume\n", __func__);

	atomic_notifier_call_chain(&iotg->iotg_notifier,
				MID_OTG_NOTIFY_HRESUME, iotg);
	usb_put_transceiver(otg);
	return 0;
}
static int usb_otg_suspend(struct usb_hcd *hcd)
{
	struct usb_phy *otg;
	struct intel_mid_otg_xceiv *iotg;

	otg = usb_get_transceiver();
	if (otg == NULL) {
		printk(KERN_ERR	"%s Failed to get otg transceiver\n", __func__);
		return -EINVAL;
	}
	iotg = otg_to_mid_xceiv(otg);
	printk(KERN_INFO "%s OTG HNP update suspend\n", __func__);

	atomic_notifier_call_chain(&iotg->iotg_notifier,
				MID_OTG_NOTIFY_HSUSPEND, iotg);
	usb_put_transceiver(otg);
	return 0;
}
static int usb_otg_suspend(struct usb_hcd *hcd)
{
	struct usb_phy			*otg;
	struct intel_mid_otg_xceiv	*iotg;

	otg = usb_get_phy(USB_PHY_TYPE_USB2);
	if (otg == NULL) {
		pr_err("%s: failed to get otg transceiver\n", __func__);
		return -EINVAL;
	}
	iotg = otg_to_mid_xceiv(otg);
	pr_info("%s: OTG HNP update suspend\n", __func__);

	atomic_notifier_call_chain(&iotg->iotg_notifier,
				MID_OTG_NOTIFY_HSUSPEND, iotg);
	usb_put_phy(otg);
	return 0;
}
static void intel_mid_ehci_driver_unregister(struct pci_driver *host_driver)
{
	struct usb_phy			*otg;
	struct intel_mid_otg_xceiv	*iotg;

	otg = usb_get_phy(USB_PHY_TYPE_USB2);
	if (otg == NULL)
		return;

	iotg = otg_to_mid_xceiv(otg);
	iotg->start_host = NULL;
	iotg->stop_host = NULL;
	iotg->runtime_suspend_host = NULL;
	iotg->runtime_resume_host = NULL;

	/* notify host driver is unregistered */
	atomic_notifier_call_chain(&iotg->iotg_notifier,
				MID_OTG_NOTIFY_HOSTREMOVE, iotg);

	usb_put_phy(otg);
}
static int ehci_mid_probe(struct pci_dev *pdev,
				const struct pci_device_id *id)
{
	struct hc_driver *driver;
	struct usb_phy *otg;
	struct intel_mid_otg_xceiv *iotg;
	struct intel_mid_otg_pdata *otg_pdata;
	struct usb_hcd *hcd;
	struct ehci_hcd *ehci;
	int irq;
	int retval;

	pr_debug("initializing Intel MID USB OTG Host Controller\n");

	/* we need not call pci_enable_dev since otg transceiver already take
	 * the control of this device and this probe actaully gets called by
	 * otg transceiver driver with HNP protocol.
	 */
	irq = pdev->irq;

	if (!id)
		return -EINVAL;
	driver = (struct hc_driver *)id->driver_data;
	if (!driver)
		return -EINVAL;

	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
	if (!hcd) {
		retval = -ENOMEM;
		goto err1;
	}

	ehci = hcd_to_ehci(hcd);
	/* this will be called in ehci_bus_suspend and ehci_bus_resume */
	ehci->otg_suspend = usb_otg_suspend;
	ehci->otg_resume = usb_otg_resume;
	/* this will be called by root hub code */
	hcd->otg_notify = otg_notify;
	otg = usb_get_transceiver();
	if (otg == NULL) {
		printk(KERN_ERR "%s Failed to get otg transceiver\n", __func__);
		retval = -EINVAL;
		goto err1;
	}

	iotg = otg_to_mid_xceiv(otg);
	hcd->regs = iotg->base;

	hcd->rsrc_start = pci_resource_start(pdev, 0);
	hcd->rsrc_len = pci_resource_len(pdev, 0);

	if (hcd->regs == NULL) {
		dev_dbg(&pdev->dev, "error mapping memory\n");
		retval = -EFAULT;
		goto err2;
	}

	otg_pdata = pdev->dev.platform_data;
	if (otg_pdata == NULL) {
		dev_err(&pdev->dev, "Failed to get OTG platform data.\n");
		retval = -ENODEV;
		goto err2;
	}
	hcd->power_budget = otg_pdata->power_budget;

	/* Mandatorily set the controller as remote-wakeup enabled */
	device_set_wakeup_enable(&pdev->dev, true);

	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
	if (retval != 0)
		goto err2;
	retval = otg_set_host(otg->otg, &hcd->self);
	if (!otg->otg->default_a)
		hcd->self.is_b_host = 1;
	usb_put_transceiver(otg);
	return retval;

err2:
	usb_put_hcd(hcd);
err1:
	dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
	return retval;
}