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