18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * dwc3-pci.c - PCI Specific glue layer
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Authors: Felipe Balbi <balbi@ti.com>,
88c2ecf20Sopenharmony_ci *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/pci.h>
158c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
178c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
188c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
198c2ecf20Sopenharmony_ci#include <linux/gpio/machine.h>
208c2ecf20Sopenharmony_ci#include <linux/acpi.h>
218c2ecf20Sopenharmony_ci#include <linux/delay.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BYT			0x0f37
248c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_MRFLD		0x119e
258c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BSW			0x22b7
268c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_SPTLP		0x9d30
278c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_SPTH		0xa130
288c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BXT			0x0aaa
298c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BXT_M		0x1aaa
308c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_APL			0x5aaa
318c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_KBP			0xa2b0
328c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_CMLLP		0x02ee
338c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_CMLH		0x06ee
348c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_GLK			0x31aa
358c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_CNPLP		0x9dee
368c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_CNPH		0xa36e
378c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_CNPV		0xa3b0
388c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_ICLLP		0x34ee
398c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_EHLLP		0x4b7e
408c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_TGPLP		0xa0ee
418c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_TGPH		0x43ee
428c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_JSP			0x4dee
438c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_ADLS		0x7ae1
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define PCI_INTEL_BXT_DSM_GUID		"732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
468c2ecf20Sopenharmony_ci#define PCI_INTEL_BXT_FUNC_PMU_PWR	4
478c2ecf20Sopenharmony_ci#define PCI_INTEL_BXT_STATE_D0		0
488c2ecf20Sopenharmony_ci#define PCI_INTEL_BXT_STATE_D3		3
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define GP_RWBAR			1
518c2ecf20Sopenharmony_ci#define GP_RWREG1			0xa0
528c2ecf20Sopenharmony_ci#define GP_RWREG1_ULPI_REFCLK_DISABLE	(1 << 17)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/**
558c2ecf20Sopenharmony_ci * struct dwc3_pci - Driver private structure
568c2ecf20Sopenharmony_ci * @dwc3: child dwc3 platform_device
578c2ecf20Sopenharmony_ci * @pci: our link to PCI bus
588c2ecf20Sopenharmony_ci * @guid: _DSM GUID
598c2ecf20Sopenharmony_ci * @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
608c2ecf20Sopenharmony_ci * @wakeup_work: work for asynchronous resume
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_cistruct dwc3_pci {
638c2ecf20Sopenharmony_ci	struct platform_device *dwc3;
648c2ecf20Sopenharmony_ci	struct pci_dev *pci;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	guid_t guid;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	unsigned int has_dsm_for_pm:1;
698c2ecf20Sopenharmony_ci	struct work_struct wakeup_work;
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params reset_gpios = { 0, 0, false };
738c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params cs_gpios = { 1, 0, false };
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
768c2ecf20Sopenharmony_ci	{ "reset-gpios", &reset_gpios, 1 },
778c2ecf20Sopenharmony_ci	{ "cs-gpios", &cs_gpios, 1 },
788c2ecf20Sopenharmony_ci	{ },
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic struct gpiod_lookup_table platform_bytcr_gpios = {
828c2ecf20Sopenharmony_ci	.dev_id		= "0000:00:16.0",
838c2ecf20Sopenharmony_ci	.table		= {
848c2ecf20Sopenharmony_ci		GPIO_LOOKUP("INT33FC:00", 54, "cs", GPIO_ACTIVE_HIGH),
858c2ecf20Sopenharmony_ci		GPIO_LOOKUP("INT33FC:02", 14, "reset", GPIO_ACTIVE_HIGH),
868c2ecf20Sopenharmony_ci		{}
878c2ecf20Sopenharmony_ci	},
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int dwc3_byt_enable_ulpi_refclock(struct pci_dev *pci)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	void __iomem	*reg;
938c2ecf20Sopenharmony_ci	u32		value;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	reg = pcim_iomap(pci, GP_RWBAR, 0);
968c2ecf20Sopenharmony_ci	if (!reg)
978c2ecf20Sopenharmony_ci		return -ENOMEM;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	value = readl(reg + GP_RWREG1);
1008c2ecf20Sopenharmony_ci	if (!(value & GP_RWREG1_ULPI_REFCLK_DISABLE))
1018c2ecf20Sopenharmony_ci		goto unmap; /* ULPI refclk already enabled */
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	value &= ~GP_RWREG1_ULPI_REFCLK_DISABLE;
1048c2ecf20Sopenharmony_ci	writel(value, reg + GP_RWREG1);
1058c2ecf20Sopenharmony_ci	/* This comes from the Intel Android x86 tree w/o any explanation */
1068c2ecf20Sopenharmony_ci	msleep(100);
1078c2ecf20Sopenharmony_ciunmap:
1088c2ecf20Sopenharmony_ci	pcim_iounmap(pci, reg);
1098c2ecf20Sopenharmony_ci	return 0;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic const struct property_entry dwc3_pci_intel_properties[] = {
1138c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
1148c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
1158c2ecf20Sopenharmony_ci	{}
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic const struct property_entry dwc3_pci_mrfld_properties[] = {
1198c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_STRING("dr_mode", "otg"),
1208c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
1218c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
1228c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
1238c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,usb2-gadget-lpm-disable"),
1248c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
1258c2ecf20Sopenharmony_ci	{}
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic const struct property_entry dwc3_pci_amd_properties[] = {
1298c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
1308c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
1318c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
1328c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
1338c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
1348c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
1358c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
1368c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
1378c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
1388c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
1398c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
1408c2ecf20Sopenharmony_ci	/* FIXME these quirks should be removed when AMD NL tapes out */
1418c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
1428c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
1438c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
1448c2ecf20Sopenharmony_ci	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
1458c2ecf20Sopenharmony_ci	{}
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int dwc3_pci_quirks(struct dwc3_pci *dwc)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct pci_dev			*pdev = dwc->pci;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1538c2ecf20Sopenharmony_ci		if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
1548c2ecf20Sopenharmony_ci		    pdev->device == PCI_DEVICE_ID_INTEL_BXT_M ||
1558c2ecf20Sopenharmony_ci		    pdev->device == PCI_DEVICE_ID_INTEL_EHLLP) {
1568c2ecf20Sopenharmony_ci			guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
1578c2ecf20Sopenharmony_ci			dwc->has_dsm_for_pm = true;
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
1618c2ecf20Sopenharmony_ci			struct gpio_desc *gpio;
1628c2ecf20Sopenharmony_ci			int ret;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci			/* On BYT the FW does not always enable the refclock */
1658c2ecf20Sopenharmony_ci			ret = dwc3_byt_enable_ulpi_refclock(pdev);
1668c2ecf20Sopenharmony_ci			if (ret)
1678c2ecf20Sopenharmony_ci				return ret;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci			ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
1708c2ecf20Sopenharmony_ci					acpi_dwc3_byt_gpios);
1718c2ecf20Sopenharmony_ci			if (ret)
1728c2ecf20Sopenharmony_ci				dev_dbg(&pdev->dev, "failed to add mapping table\n");
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci			/*
1758c2ecf20Sopenharmony_ci			 * A lot of BYT devices lack ACPI resource entries for
1768c2ecf20Sopenharmony_ci			 * the GPIOs. If the ACPI entry for the GPIO controller
1778c2ecf20Sopenharmony_ci			 * is present add a fallback mapping to the reference
1788c2ecf20Sopenharmony_ci			 * design GPIOs which all boards seem to use.
1798c2ecf20Sopenharmony_ci			 */
1808c2ecf20Sopenharmony_ci			if (acpi_dev_present("INT33FC", NULL, -1))
1818c2ecf20Sopenharmony_ci				gpiod_add_lookup_table(&platform_bytcr_gpios);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci			/*
1848c2ecf20Sopenharmony_ci			 * These GPIOs will turn on the USB2 PHY. Note that we have to
1858c2ecf20Sopenharmony_ci			 * put the gpio descriptors again here because the phy driver
1868c2ecf20Sopenharmony_ci			 * might want to grab them, too.
1878c2ecf20Sopenharmony_ci			 */
1888c2ecf20Sopenharmony_ci			gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
1898c2ecf20Sopenharmony_ci			if (IS_ERR(gpio))
1908c2ecf20Sopenharmony_ci				return PTR_ERR(gpio);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci			gpiod_set_value_cansleep(gpio, 1);
1938c2ecf20Sopenharmony_ci			gpiod_put(gpio);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci			gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
1968c2ecf20Sopenharmony_ci			if (IS_ERR(gpio))
1978c2ecf20Sopenharmony_ci				return PTR_ERR(gpio);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci			if (gpio) {
2008c2ecf20Sopenharmony_ci				gpiod_set_value_cansleep(gpio, 1);
2018c2ecf20Sopenharmony_ci				gpiod_put(gpio);
2028c2ecf20Sopenharmony_ci				usleep_range(10000, 11000);
2038c2ecf20Sopenharmony_ci			}
2048c2ecf20Sopenharmony_ci		}
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	return 0;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
2118c2ecf20Sopenharmony_cistatic void dwc3_pci_resume_work(struct work_struct *work)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct dwc3_pci *dwc = container_of(work, struct dwc3_pci, wakeup_work);
2148c2ecf20Sopenharmony_ci	struct platform_device *dwc3 = dwc->dwc3;
2158c2ecf20Sopenharmony_ci	int ret;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(&dwc3->dev);
2188c2ecf20Sopenharmony_ci	if (ret < 0) {
2198c2ecf20Sopenharmony_ci		pm_runtime_put_sync_autosuspend(&dwc3->dev);
2208c2ecf20Sopenharmony_ci		return;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(&dwc3->dev);
2248c2ecf20Sopenharmony_ci	pm_runtime_put_sync_autosuspend(&dwc3->dev);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci#endif
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct property_entry *p = (struct property_entry *)id->driver_data;
2318c2ecf20Sopenharmony_ci	struct dwc3_pci		*dwc;
2328c2ecf20Sopenharmony_ci	struct resource		res[2];
2338c2ecf20Sopenharmony_ci	int			ret;
2348c2ecf20Sopenharmony_ci	struct device		*dev = &pci->dev;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	ret = pcim_enable_device(pci);
2378c2ecf20Sopenharmony_ci	if (ret) {
2388c2ecf20Sopenharmony_ci		dev_err(dev, "failed to enable pci device\n");
2398c2ecf20Sopenharmony_ci		return -ENODEV;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	pci_set_master(pci);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
2458c2ecf20Sopenharmony_ci	if (!dwc)
2468c2ecf20Sopenharmony_ci		return -ENOMEM;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	dwc->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
2498c2ecf20Sopenharmony_ci	if (!dwc->dwc3)
2508c2ecf20Sopenharmony_ci		return -ENOMEM;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	res[0].start	= pci_resource_start(pci, 0);
2558c2ecf20Sopenharmony_ci	res[0].end	= pci_resource_end(pci, 0);
2568c2ecf20Sopenharmony_ci	res[0].name	= "dwc_usb3";
2578c2ecf20Sopenharmony_ci	res[0].flags	= IORESOURCE_MEM;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	res[1].start	= pci->irq;
2608c2ecf20Sopenharmony_ci	res[1].name	= "dwc_usb3";
2618c2ecf20Sopenharmony_ci	res[1].flags	= IORESOURCE_IRQ;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
2648c2ecf20Sopenharmony_ci	if (ret) {
2658c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't add resources to dwc3 device\n");
2668c2ecf20Sopenharmony_ci		goto err;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	dwc->pci = pci;
2708c2ecf20Sopenharmony_ci	dwc->dwc3->dev.parent = dev;
2718c2ecf20Sopenharmony_ci	ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	ret = platform_device_add_properties(dwc->dwc3, p);
2748c2ecf20Sopenharmony_ci	if (ret < 0)
2758c2ecf20Sopenharmony_ci		goto err;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	ret = dwc3_pci_quirks(dwc);
2788c2ecf20Sopenharmony_ci	if (ret)
2798c2ecf20Sopenharmony_ci		goto err;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	ret = platform_device_add(dwc->dwc3);
2828c2ecf20Sopenharmony_ci	if (ret) {
2838c2ecf20Sopenharmony_ci		dev_err(dev, "failed to register dwc3 device\n");
2848c2ecf20Sopenharmony_ci		goto err;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	device_init_wakeup(dev, true);
2888c2ecf20Sopenharmony_ci	pci_set_drvdata(pci, dwc);
2898c2ecf20Sopenharmony_ci	pm_runtime_put(dev);
2908c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
2918c2ecf20Sopenharmony_ci	INIT_WORK(&dwc->wakeup_work, dwc3_pci_resume_work);
2928c2ecf20Sopenharmony_ci#endif
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	return 0;
2958c2ecf20Sopenharmony_cierr:
2968c2ecf20Sopenharmony_ci	platform_device_put(dwc->dwc3);
2978c2ecf20Sopenharmony_ci	return ret;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic void dwc3_pci_remove(struct pci_dev *pci)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct dwc3_pci		*dwc = pci_get_drvdata(pci);
3038c2ecf20Sopenharmony_ci	struct pci_dev		*pdev = dwc->pci;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (pdev->device == PCI_DEVICE_ID_INTEL_BYT)
3068c2ecf20Sopenharmony_ci		gpiod_remove_lookup_table(&platform_bytcr_gpios);
3078c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
3088c2ecf20Sopenharmony_ci	cancel_work_sync(&dwc->wakeup_work);
3098c2ecf20Sopenharmony_ci#endif
3108c2ecf20Sopenharmony_ci	device_init_wakeup(&pci->dev, false);
3118c2ecf20Sopenharmony_ci	pm_runtime_get(&pci->dev);
3128c2ecf20Sopenharmony_ci	platform_device_unregister(dwc->dwc3);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic const struct pci_device_id dwc3_pci_id_table[] = {
3168c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
3178c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties },
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
3208c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
3238c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_mrfld_properties, },
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP),
3268c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH),
3298c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
3328c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
3358c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
3388c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
3418c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
3448c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
3478c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK),
3508c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP),
3538c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH),
3568c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV),
3598c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
3628c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
3658c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
3688c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH),
3718c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP),
3748c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS),
3778c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_intel_properties, },
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
3808c2ecf20Sopenharmony_ci	  (kernel_ulong_t) &dwc3_pci_amd_properties, },
3818c2ecf20Sopenharmony_ci	{  }	/* Terminating Entry */
3828c2ecf20Sopenharmony_ci};
3838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci#if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
3868c2ecf20Sopenharmony_cistatic int dwc3_pci_dsm(struct dwc3_pci *dwc, int param)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	union acpi_object *obj;
3898c2ecf20Sopenharmony_ci	union acpi_object tmp;
3908c2ecf20Sopenharmony_ci	union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (!dwc->has_dsm_for_pm)
3938c2ecf20Sopenharmony_ci		return 0;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	tmp.type = ACPI_TYPE_INTEGER;
3968c2ecf20Sopenharmony_ci	tmp.integer.value = param;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	obj = acpi_evaluate_dsm(ACPI_HANDLE(&dwc->pci->dev), &dwc->guid,
3998c2ecf20Sopenharmony_ci			1, PCI_INTEL_BXT_FUNC_PMU_PWR, &argv4);
4008c2ecf20Sopenharmony_ci	if (!obj) {
4018c2ecf20Sopenharmony_ci		dev_err(&dwc->pci->dev, "failed to evaluate _DSM\n");
4028c2ecf20Sopenharmony_ci		return -EIO;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	ACPI_FREE(obj);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	return 0;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci#endif /* CONFIG_PM || CONFIG_PM_SLEEP */
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
4128c2ecf20Sopenharmony_cistatic int dwc3_pci_runtime_suspend(struct device *dev)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct dwc3_pci		*dwc = dev_get_drvdata(dev);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (device_can_wakeup(dev))
4178c2ecf20Sopenharmony_ci		return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D3);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return -EBUSY;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int dwc3_pci_runtime_resume(struct device *dev)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct dwc3_pci		*dwc = dev_get_drvdata(dev);
4258c2ecf20Sopenharmony_ci	int			ret;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
4288c2ecf20Sopenharmony_ci	if (ret)
4298c2ecf20Sopenharmony_ci		return ret;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	queue_work(pm_wq, &dwc->wakeup_work);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
4388c2ecf20Sopenharmony_cistatic int dwc3_pci_suspend(struct device *dev)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	struct dwc3_pci		*dwc = dev_get_drvdata(dev);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D3);
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic int dwc3_pci_resume(struct device *dev)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct dwc3_pci		*dwc = dev_get_drvdata(dev);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
4548c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
4558c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_runtime_resume,
4568c2ecf20Sopenharmony_ci		NULL)
4578c2ecf20Sopenharmony_ci};
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic struct pci_driver dwc3_pci_driver = {
4608c2ecf20Sopenharmony_ci	.name		= "dwc3-pci",
4618c2ecf20Sopenharmony_ci	.id_table	= dwc3_pci_id_table,
4628c2ecf20Sopenharmony_ci	.probe		= dwc3_pci_probe,
4638c2ecf20Sopenharmony_ci	.remove		= dwc3_pci_remove,
4648c2ecf20Sopenharmony_ci	.driver		= {
4658c2ecf20Sopenharmony_ci		.pm	= &dwc3_pci_dev_pm_ops,
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci};
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ciMODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
4708c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
4718c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cimodule_pci_driver(dwc3_pci_driver);
474