int dwc3_intel_b_idle(struct dwc_otg2 *otg)
{
	u32 gctl, tmp;

	/* Disable hibernation mode by default */
	gctl = otg_read(otg, GCTL);
	gctl &= ~GCTL_GBL_HIBERNATION_EN;
	otg_write(otg, GCTL, gctl);

	/* Reset ADP related registers */
	otg_write(otg, ADPCFG, 0);
	otg_write(otg, ADPCTL, 0);
	otg_write(otg, ADPEVTEN, 0);
	tmp = otg_read(otg, ADPEVT);
	otg_write(otg, ADPEVT, tmp);

	otg_write(otg, OCFG, 0);
	otg_write(otg, OEVTEN, 0);
	tmp = otg_read(otg, OEVT);
	otg_write(otg, OEVT, tmp);

	/* Force config to otg mode as default. */
	dwc3_switch_mode(otg, GCTL_PRT_CAP_DIR_OTG);

	if (!is_hybridvp(otg)) {
		dwc_otg_charger_hwdet(false);
		enable_usb_phy(otg, false);
	}

	mdelay(100);

	return 0;
}
int dwc3_intel_byt_b_idle(struct dwc_otg2 *otg)
{
	u32 gctl, tmp;

	enable_usb_phy(otg, false);
	dwc_otg_charger_hwdet(false);

	/* Disable hibernation mode by default */
	gctl = otg_read(otg, GCTL);
	gctl &= ~GCTL_GBL_HIBERNATION_EN;
	otg_write(otg, GCTL, gctl);

	/* Reset ADP related registers */
	otg_write(otg, ADPCFG, 0);
	otg_write(otg, ADPCTL, 0);
	otg_write(otg, ADPEVTEN, 0);
	tmp = otg_read(otg, ADPEVT);
	otg_write(otg, ADPEVT, tmp);

	otg_write(otg, OCFG, 0);
	otg_write(otg, OEVTEN, 0);
	tmp = otg_read(otg, OEVT);
	otg_write(otg, OEVT, tmp);
	otg_write(otg, OCTL, OCTL_PERI_MODE);

	/* Force config to device mode as default */
	gctl = otg_read(otg, GCTL);
	gctl &= ~GCTL_PRT_CAP_DIR;
	gctl |= GCTL_PRT_CAP_DIR_DEV << GCTL_PRT_CAP_DIR_SHIFT;
	otg_write(otg, GCTL, gctl);

	mdelay(100);

	return 0;
}
/* Disable auto-resume feature for USB2 PHY. This is one
 * silicon workaround. It will cause fabric timeout error
 * for LS case after resume from hibernation */
static void disable_phy_auto_resume(struct dwc_otg2 *otg)
{
	u32 data = 0;

	data = otg_read(otg, GUSB2PHYCFG0);
	data &= ~GUSB2PHYCFG_ULPI_AUTO_RESUME;
	otg_write(otg, GUSB2PHYCFG0, data);
}
void dwc3_switch_mode(struct dwc_otg2 *otg, u32 mode)
{
	u32 reg;

	reg = otg_read(otg, GCTL);
	reg &= ~(GCTL_PRT_CAP_DIR_OTG << GCTL_PRT_CAP_DIR_SHIFT);
	reg |= mode << GCTL_PRT_CAP_DIR_SHIFT;
	otg_write(otg, GCTL, reg);
}
static void set_sus_phy(struct dwc_otg2 *otg, int bit)
{
	u32 data = 0;

	data = otg_read(otg, GUSB2PHYCFG0);
	if (bit)
		data |= GUSB2PHYCFG_SUS_PHY;
	else
		data &= ~GUSB2PHYCFG_SUS_PHY;

	otg_write(otg, GUSB2PHYCFG0, data);

	data = otg_read(otg, GUSB3PIPECTL0);
	if (bit)
		data |= GUSB3PIPECTL_SUS_EN;
	else
		data &= ~GUSB3PIPECTL_SUS_EN;
	otg_write(otg, GUSB3PIPECTL0, data);
}
static int ulpi_read(struct usb_phy *phy, u32 reg)
{
	struct dwc_otg2 *otg = container_of(phy, struct dwc_otg2, usb2_phy);
	u32 val32 = 0, count = 10000;
	u8 val, tmp;

	if (phy->intf != USB2_PHY_ULPI)
		return -ENODEV;

	reg &= 0xFF;

	while (count) {
		if (otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_VSTSBSY)
			udelay(1);
		else
			break;

		count--;
	}

	if (!count) {
		otg_err(otg, "USB2 PHY always busy!!\n");
		return -EBUSY;
	}

	count = 10000;
	/* Determine if use extend registers access */
	if (reg & EXTEND_ULPI_REGISTER_ACCESS_MASK) {
		otg_dbg(otg, "Access extend registers 0x%x\n", reg);
		val32 = GUSB2PHYACC0_NEWREGREQ
			| GUSB2PHYACC0_REGADDR(ULPI_ACCESS_EXTENDED)
			| GUSB2PHYACC0_VCTRL(reg);
	} else {
		otg_dbg(otg, "Access normal registers 0x%x\n", reg);
		val32 = GUSB2PHYACC0_NEWREGREQ | GUSB2PHYACC0_REGADDR(reg)
			| GUSB2PHYACC0_VCTRL(0x00);
	}
	otg_write(otg, GUSB2PHYACC0, val32);

	while (count) {
		if (otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_VSTSDONE) {
			val = otg_read(otg, GUSB2PHYACC0) &
				  GUSB2PHYACC0_REGDATA_MASK;
			otg_dbg(otg, "%s - reg 0x%x data 0x%x\n",
					__func__, reg, val);
			goto cleanup;
		}

		udelay(1);
		count--;
	}

	otg_err(otg, "%s read PHY data failed.\n", __func__);

	return -ETIMEDOUT;

cleanup:
	/* Clear GUSB2PHYACC0[16:21] before return.
	 * Otherwise, it will cause PHY can't in workable
	 * state. This is one dwc3 controller silicon bug. */
	tmp = otg_read(otg, GUSB2PHYACC0);
	otg_write(otg, GUSB2PHYACC0, tmp &
			~GUSB2PHYACC0_REGADDR(0x3F));
	return val;
}
int dwc3_intel_byt_platform_init(struct dwc_otg2 *otg)
{
	struct intel_dwc_otg_pdata *data;
	u32 gctl;
	int id_value;
	int retval;

	data = (struct intel_dwc_otg_pdata *)otg->otg_data;

	if (data)
		INIT_DELAYED_WORK(&data->suspend_discon_work,
			dwc_otg_suspend_discon_work);

	if (data && data->gpio_cs && data->gpio_reset) {
		retval = gpio_request(data->gpio_cs, "phy_cs");
		if (retval < 0) {
			otg_err(otg, "failed to request CS pin %d\n",
					data->gpio_cs);
			return retval;
		}

		retval = gpio_request(data->gpio_reset, "phy_reset");
		if (retval < 0) {
			otg_err(otg, "failed to request RESET pin %d\n",
					data->gpio_reset);
			return retval;
		}
	}

	if (data && data->gpio_id) {
		dev_info(otg->dev,  "USB ID detection - Enabled - GPIO\n");

		/* Set ID default value to 1 Floating */
		data->id = 1;

		retval = gpio_request(data->gpio_id, "gpio_id");
		if (retval < 0) {
			otg_err(otg, "failed to request ID pin %d\n",
					data->gpio_id);
			return retval;
		}

		retval = gpio_direction_input(data->gpio_id);
		if (retval < 0) {
			otg_err(otg, "failed to request ID pin %d\n",
					data->gpio_id);
			return retval;
		}

		retval = request_threaded_irq(gpio_to_irq(data->gpio_id),
				NULL, dwc3_gpio_id_irq,
				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
				IRQF_ONESHOT, "dwc-gpio-id", otg->dev);

		if (retval < 0) {
			otg_err(otg, "failed to request interrupt gpio ID\n");
			return retval;
		}

		otg_dbg(otg, "GPIO ID request/Interrupt reuqest Done\n");

		id_value = dwc3_check_gpio_id(otg);
		if ((id_value == 0 || id_value == 1) &&
					(data->id != id_value)) {
			data->id = id_value;
			dev_info(otg->dev, "ID notification (id = %d)\n",
						data->id);

			atomic_notifier_call_chain(&otg->usb2_phy.notifier,
					USB_EVENT_ID, &id_value);
		} else
			otg_dbg(otg, "Get incorrect ID value %d\n", id_value);
	}

	/* Don't let phy go to suspend mode, which
	 * will cause FS/LS devices enum failed in host mode.
	 */
	set_sus_phy(otg, 0);

	retval = device_create_file(otg->dev, &dev_attr_otg_id);
	if (retval < 0) {
		otg_dbg(otg,
			"Can't register sysfs attribute: %d\n", retval);
		return -ENOMEM;
	}

	retval = device_create_file(otg->dev, &dev_attr_vbus_evt);
	if (retval < 0) {
		otg_dbg(otg,
			"Can't register sysfs attribute: %d\n", retval);
		return -ENOMEM;
	}

	otg_dbg(otg, "\n");
	otg_write(otg, OEVTEN, 0);
	otg_write(otg, OCTL, 0);
	gctl = otg_read(otg, GCTL);
	gctl |= GCTL_PRT_CAP_DIR_OTG << GCTL_PRT_CAP_DIR_SHIFT;
	otg_write(otg, GCTL, gctl);

	return 0;
}
int dwc3_intel_resume(struct dwc_otg2 *otg)
{
	struct pci_dev *pci_dev;
	struct usb_hcd *hcd = NULL;
	u32 data;
	int ret;

	if (!otg)
		return 0;

	hcd = container_of(otg->otg.host, struct usb_hcd, self);
	/* After resume from D0i3cold. The UTMI PHY D+ drive issue
	 * reproduced due to all setting be reseted. So switch to OTG
	 * mode avoid D+ drive too early.
	 */
	if ((otg->state == DWC_STATE_B_IDLE ||
		otg->state == DWC_STATE_CHARGING ||
		otg->state == DWC_STATE_WAIT_VBUS_FALL ||
		otg->state == DWC_STATE_WAIT_VBUS_RAISE) &&
			is_utmi_phy(otg)) {
		/* Reconnect DP/DM between Pmic and SOC for support host
		 * and device mode. */
		ret = intel_scu_ipc_update_register(PMIC_USBPHYCTRL,
				USBPHYRSTB, USBPHYRSTB);
		if (ret)
			otg_err(otg, "%s: ipc update failed\n", __func__);

		otg_write(otg, OEVTEN, 0);
		otg_write(otg, OCTL, 0);
		dwc3_switch_mode(otg, GCTL_PRT_CAP_DIR_OTG);
	}

	/* This is one SCU WA. SCU should set GUSB2PHYCFG0
	 * bit 4 for ULPI setting. But SCU haven't do that.
	 * So do WA first until SCU fix.
	 */
	data = otg_read(otg, GUSB2PHYCFG0);
	if (is_utmi_phy(otg))
		data &= ~(1 << 4);
	else
		data |= (1 << 4);
	otg_write(otg, GUSB2PHYCFG0, data);

	pci_dev = to_pci_dev(otg->dev);

	/* From synopsys spec 12.2.11.
	 * Software cannot access memory-mapped I/O space
	 * for 10ms. Delay 5 ms here should be enough. Too
	 * long a delay causes hibernation exit failure.
	 */
	mdelay(5);

	pci_restore_state(pci_dev);
	if (pci_enable_device(pci_dev) < 0) {
		otg_err(otg, "pci_enable_device failed.\n");
		return -EIO;
	}

	set_sus_phy(otg, 0);

	/* Delay 1ms waiting PHY clock debounce.
	 * Without this debounce, will met fabric error randomly.
	 **/
	mdelay(1);

	if (otg->state == DWC_STATE_A_HOST &&
			otg->resume_host)
		otg->resume_host(hcd);


	return 0;
}