int dwc3_intel_byt_resume(struct dwc_otg2 *otg)
{
	struct pci_dev *pci_dev;

	if (!otg)
		return 0;

	pci_dev = to_pci_dev(otg->dev);

	/* From synopsys spec 12.2.11.
	 * Software cannot access memory-mapped I/O space
	 * for 10ms.
	 */
	mdelay(10);

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

	return 0;
}
예제 #2
0
int dwc3_intel_platform_init(struct dwc_otg2 *otg)
{
	int retval;
	struct intel_dwc_otg_pdata *data;

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

	/* Init a_bus_drop callback */
	otg->usb2_phy.a_bus_drop = dwc_a_bus_drop;
	otg->usb2_phy.vbus_state = VBUS_ENABLED;
	/* Get usb2 phy type */
	otg->usb2_phy.intf = data->usb2_phy_type;

	/* Turn off VUSBPHY if it haven't used by USB2 PHY.
	 * Otherwise, it will consume ~2.6mA(on VSYS) on MOFD.
	 */
	if (!data->using_vusbphy) {
		retval = control_usb_phy_power(PMIC_VLDOCNT, false);
		if (retval)
			otg_err(otg, "Fail to turn off VUSBPHY\n");
	} else if (!is_utmi_phy(otg)) {
		/* If the current USB2 PHY low power controlled by VUSBPHY. Then
		 * we need to de-assert USBRST pin to make USB2 PHY always stay
		 * in active state.
		 */
		retval = control_usb_phy_power(PMIC_USBPHYCTRL, true);
		if (retval)
			otg_err(otg, "Fail to de-assert USBRST#\n");
	} else {
		/* If we are using utmi phy, and through VUSBPHY to do power
		 * control. Then we need to assert USBRST# for external ULPI phy
		 * to ask it under inactive state saving power.
		 */
		retval = control_usb_phy_power(PMIC_USBPHYCTRL, false);
		if (retval)
			otg_err(otg, "Fail to de-assert USBRST#\n");
	}

	/* 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;
	}

	otg_dbg(otg, "\n");
	otg_write(otg, OEVTEN, 0);
	otg_write(otg, OCTL, 0);

	dwc3_switch_mode(otg, GCTL_PRT_CAP_DIR_OTG);

	return 0;
}
int dwc3_intel_byt_suspend(struct dwc_otg2 *otg)
{
	struct pci_dev *pci_dev;
	pci_power_t state = PCI_D3hot;

	if (!otg)
		return 0;

	pci_dev = to_pci_dev(otg->dev);

	set_sus_phy(otg, 1);

	if (pci_save_state(pci_dev)) {
		otg_err(otg, "pci_save_state failed!\n");
		return -EIO;
	}

	pci_disable_device(pci_dev);
	pci_set_power_state(pci_dev, state);

	return 0;
}
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;
}
예제 #5
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;
}
예제 #6
0
int dwc3_intel_suspend(struct dwc_otg2 *otg)
{
	int ret;
	struct usb_phy *phy;
	struct pci_dev *pci_dev;
	struct usb_hcd *hcd = NULL;
	pci_power_t state = PCI_D3cold;

	if (!otg)
		return 0;

	hcd = container_of(otg->otg.host, struct usb_hcd, self);

	pci_dev = to_pci_dev(otg->dev);

	if (otg->state == DWC_STATE_A_HOST &&
			otg->suspend_host) {
		/* Check if USB2 ULPI PHY is hang via access its internal
		 * registers. If hang, then do hard reset before enter
		 * hibernation mode. Otherwise, the USB2 PHY can't enter
		 * suspended state which will blocking U2PMU can't get ready
		 * then can't enter D0i3hot forever in SCU FW.
		 */
		if (!is_utmi_phy(otg)) {
			phy = usb_get_phy(USB_PHY_TYPE_USB2);
			if (!phy)
				return -ENODEV;
			if (usb_phy_io_read(phy, ULPI_VENDOR_ID_LOW) < 0) {
				enable_usb_phy(otg, 0);
				enable_usb_phy(otg, 1);
			}
			usb_put_phy(phy);
		}

		ret = otg->suspend_host(hcd);
		if (ret) {
			otg_err(otg, "dwc3-host enter suspend faield: %d\n", ret);
			return ret;
		}
	}

	if (otg->state == DWC_STATE_B_PERIPHERAL ||
			otg->state == DWC_STATE_A_HOST)
		state = PCI_D3hot;

	set_sus_phy(otg, 1);

	if (pci_save_state(pci_dev)) {
		otg_err(otg, "pci_save_state failed!\n");
		return -EIO;
	}

	pci_disable_device(pci_dev);
	if ((state == PCI_D3cold) && is_utmi_phy(otg)) {
		/* Important!!  Whenever the VUSBPHY rail is disabled, SW
		 * must assert USBRST# to isolate the SOC’s DP/DM pins from the
		 * outside world.  There is a risk of damage to the SOC if a
		 * peripheral were to bias DP/DM to 3.3V when the SOC is
		 * unpowered. */
		ret = intel_scu_ipc_update_register(PMIC_USBPHYCTRL,
				0x0, USBPHYRSTB);
		if (ret)
			otg_err(otg, "%s: ipc update failed\n", __func__);
	}
	pci_set_power_state(pci_dev, state);
	return 0;
}