172246da4SFelipe Balbi /** 272246da4SFelipe Balbi * dwc3-pci.c - PCI Specific glue layer 372246da4SFelipe Balbi * 472246da4SFelipe Balbi * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com 572246da4SFelipe Balbi * 672246da4SFelipe Balbi * Authors: Felipe Balbi <balbi@ti.com>, 772246da4SFelipe Balbi * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 872246da4SFelipe Balbi * 95945f789SFelipe Balbi * This program is free software: you can redistribute it and/or modify 105945f789SFelipe Balbi * it under the terms of the GNU General Public License version 2 of 115945f789SFelipe Balbi * the License as published by the Free Software Foundation. 1272246da4SFelipe Balbi * 135945f789SFelipe Balbi * This program is distributed in the hope that it will be useful, 145945f789SFelipe Balbi * but WITHOUT ANY WARRANTY; without even the implied warranty of 155945f789SFelipe Balbi * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 165945f789SFelipe Balbi * GNU General Public License for more details. 1772246da4SFelipe Balbi */ 1872246da4SFelipe Balbi 1972246da4SFelipe Balbi #include <linux/kernel.h> 2046a57283SStephen Rothwell #include <linux/module.h> 2172246da4SFelipe Balbi #include <linux/slab.h> 2272246da4SFelipe Balbi #include <linux/pci.h> 2372246da4SFelipe Balbi #include <linux/platform_device.h> 2472246da4SFelipe Balbi 25e3ec3eb7SFelipe Balbi #include <linux/usb/otg.h> 26d7078df6SFelipe Balbi #include <linux/usb/usb_phy_generic.h> 27e3ec3eb7SFelipe Balbi 28*8f317b47SHuang Rui #include "platform_data.h" 29*8f317b47SHuang Rui 3072246da4SFelipe Balbi /* FIXME define these in <linux/pci_ids.h> */ 3172246da4SFelipe Balbi #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 3272246da4SFelipe Balbi #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd 33b62cd96dSHeikki Krogerus #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 3485601f8cSDavid Cohen #define PCI_DEVICE_ID_INTEL_MRFLD 0x119e 357d643664SAlan Cox #define PCI_DEVICE_ID_INTEL_BSW 0x22B7 3672246da4SFelipe Balbi 3772246da4SFelipe Balbi struct dwc3_pci { 3872246da4SFelipe Balbi struct device *dev; 3972246da4SFelipe Balbi struct platform_device *dwc3; 40e3ec3eb7SFelipe Balbi struct platform_device *usb2_phy; 41e3ec3eb7SFelipe Balbi struct platform_device *usb3_phy; 4272246da4SFelipe Balbi }; 4372246da4SFelipe Balbi 4441ac7b3aSBill Pemberton static int dwc3_pci_register_phys(struct dwc3_pci *glue) 45e3ec3eb7SFelipe Balbi { 464525beebSFelipe Balbi struct usb_phy_generic_platform_data pdata; 47e3ec3eb7SFelipe Balbi struct platform_device *pdev; 48e3ec3eb7SFelipe Balbi int ret; 49e3ec3eb7SFelipe Balbi 50e3ec3eb7SFelipe Balbi memset(&pdata, 0x00, sizeof(pdata)); 51e3ec3eb7SFelipe Balbi 524525beebSFelipe Balbi pdev = platform_device_alloc("usb_phy_generic", 0); 53e3ec3eb7SFelipe Balbi if (!pdev) 54e3ec3eb7SFelipe Balbi return -ENOMEM; 55e3ec3eb7SFelipe Balbi 56e3ec3eb7SFelipe Balbi glue->usb2_phy = pdev; 57e3ec3eb7SFelipe Balbi pdata.type = USB_PHY_TYPE_USB2; 5813518673SHeikki Krogerus pdata.gpio_reset = -1; 59e3ec3eb7SFelipe Balbi 60e3ec3eb7SFelipe Balbi ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata)); 61e3ec3eb7SFelipe Balbi if (ret) 62e3ec3eb7SFelipe Balbi goto err1; 63e3ec3eb7SFelipe Balbi 644525beebSFelipe Balbi pdev = platform_device_alloc("usb_phy_generic", 1); 65e3ec3eb7SFelipe Balbi if (!pdev) { 66e3ec3eb7SFelipe Balbi ret = -ENOMEM; 67e3ec3eb7SFelipe Balbi goto err1; 68e3ec3eb7SFelipe Balbi } 69e3ec3eb7SFelipe Balbi 70e3ec3eb7SFelipe Balbi glue->usb3_phy = pdev; 71e3ec3eb7SFelipe Balbi pdata.type = USB_PHY_TYPE_USB3; 72e3ec3eb7SFelipe Balbi 73e3ec3eb7SFelipe Balbi ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata)); 74e3ec3eb7SFelipe Balbi if (ret) 75e3ec3eb7SFelipe Balbi goto err2; 76e3ec3eb7SFelipe Balbi 77e3ec3eb7SFelipe Balbi ret = platform_device_add(glue->usb2_phy); 78e3ec3eb7SFelipe Balbi if (ret) 79e3ec3eb7SFelipe Balbi goto err2; 80e3ec3eb7SFelipe Balbi 81e3ec3eb7SFelipe Balbi ret = platform_device_add(glue->usb3_phy); 82e3ec3eb7SFelipe Balbi if (ret) 83e3ec3eb7SFelipe Balbi goto err3; 84e3ec3eb7SFelipe Balbi 85e3ec3eb7SFelipe Balbi return 0; 86e3ec3eb7SFelipe Balbi 87e3ec3eb7SFelipe Balbi err3: 88e3ec3eb7SFelipe Balbi platform_device_del(glue->usb2_phy); 89e3ec3eb7SFelipe Balbi 90e3ec3eb7SFelipe Balbi err2: 91e3ec3eb7SFelipe Balbi platform_device_put(glue->usb3_phy); 92e3ec3eb7SFelipe Balbi 93e3ec3eb7SFelipe Balbi err1: 94e3ec3eb7SFelipe Balbi platform_device_put(glue->usb2_phy); 95e3ec3eb7SFelipe Balbi 96e3ec3eb7SFelipe Balbi return ret; 97e3ec3eb7SFelipe Balbi } 98e3ec3eb7SFelipe Balbi 9941ac7b3aSBill Pemberton static int dwc3_pci_probe(struct pci_dev *pci, 10072246da4SFelipe Balbi const struct pci_device_id *id) 10172246da4SFelipe Balbi { 10272246da4SFelipe Balbi struct resource res[2]; 10372246da4SFelipe Balbi struct platform_device *dwc3; 10472246da4SFelipe Balbi struct dwc3_pci *glue; 105b09e99eeSAndy Shevchenko int ret; 106802ca850SChanho Park struct device *dev = &pci->dev; 107*8f317b47SHuang Rui struct dwc3_platform_data dwc3_pdata; 108*8f317b47SHuang Rui 109*8f317b47SHuang Rui memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata)); 11072246da4SFelipe Balbi 111802ca850SChanho Park glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); 112734d5a53SJingoo Han if (!glue) 113802ca850SChanho Park return -ENOMEM; 11472246da4SFelipe Balbi 115802ca850SChanho Park glue->dev = dev; 11672246da4SFelipe Balbi 117f1c7e710SAndy Shevchenko ret = pcim_enable_device(pci); 11872246da4SFelipe Balbi if (ret) { 119802ca850SChanho Park dev_err(dev, "failed to enable pci device\n"); 120802ca850SChanho Park return -ENODEV; 12172246da4SFelipe Balbi } 12272246da4SFelipe Balbi 12372246da4SFelipe Balbi pci_set_master(pci); 12472246da4SFelipe Balbi 125e3ec3eb7SFelipe Balbi ret = dwc3_pci_register_phys(glue); 126e3ec3eb7SFelipe Balbi if (ret) { 127e3ec3eb7SFelipe Balbi dev_err(dev, "couldn't register PHYs\n"); 128e3ec3eb7SFelipe Balbi return ret; 129e3ec3eb7SFelipe Balbi } 130e3ec3eb7SFelipe Balbi 131124dafdeSSebastian Andrzej Siewior dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 13272246da4SFelipe Balbi if (!dwc3) { 133802ca850SChanho Park dev_err(dev, "couldn't allocate dwc3 device\n"); 134f1c7e710SAndy Shevchenko return -ENOMEM; 13572246da4SFelipe Balbi } 13672246da4SFelipe Balbi 13772246da4SFelipe Balbi memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); 13872246da4SFelipe Balbi 13972246da4SFelipe Balbi res[0].start = pci_resource_start(pci, 0); 14072246da4SFelipe Balbi res[0].end = pci_resource_end(pci, 0); 14172246da4SFelipe Balbi res[0].name = "dwc_usb3"; 14272246da4SFelipe Balbi res[0].flags = IORESOURCE_MEM; 14372246da4SFelipe Balbi 14472246da4SFelipe Balbi res[1].start = pci->irq; 14572246da4SFelipe Balbi res[1].name = "dwc_usb3"; 14672246da4SFelipe Balbi res[1].flags = IORESOURCE_IRQ; 14772246da4SFelipe Balbi 14872246da4SFelipe Balbi ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); 14972246da4SFelipe Balbi if (ret) { 150802ca850SChanho Park dev_err(dev, "couldn't add resources to dwc3 device\n"); 151f1c7e710SAndy Shevchenko return ret; 15272246da4SFelipe Balbi } 15372246da4SFelipe Balbi 15472246da4SFelipe Balbi pci_set_drvdata(pci, glue); 15572246da4SFelipe Balbi 156*8f317b47SHuang Rui ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata)); 157*8f317b47SHuang Rui if (ret) 158*8f317b47SHuang Rui goto err3; 159*8f317b47SHuang Rui 160802ca850SChanho Park dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); 16172246da4SFelipe Balbi 162802ca850SChanho Park dwc3->dev.dma_mask = dev->dma_mask; 163802ca850SChanho Park dwc3->dev.dma_parms = dev->dma_parms; 164802ca850SChanho Park dwc3->dev.parent = dev; 16572246da4SFelipe Balbi glue->dwc3 = dwc3; 16672246da4SFelipe Balbi 16772246da4SFelipe Balbi ret = platform_device_add(dwc3); 16872246da4SFelipe Balbi if (ret) { 169802ca850SChanho Park dev_err(dev, "failed to register dwc3 device\n"); 170802ca850SChanho Park goto err3; 17172246da4SFelipe Balbi } 17272246da4SFelipe Balbi 17372246da4SFelipe Balbi return 0; 17472246da4SFelipe Balbi 175802ca850SChanho Park err3: 17672246da4SFelipe Balbi platform_device_put(dwc3); 17772246da4SFelipe Balbi return ret; 17872246da4SFelipe Balbi } 17972246da4SFelipe Balbi 180fb4e98abSBill Pemberton static void dwc3_pci_remove(struct pci_dev *pci) 18172246da4SFelipe Balbi { 18272246da4SFelipe Balbi struct dwc3_pci *glue = pci_get_drvdata(pci); 18372246da4SFelipe Balbi 184f28c42c5SPeter Chen platform_device_unregister(glue->dwc3); 185e3ec3eb7SFelipe Balbi platform_device_unregister(glue->usb2_phy); 186e3ec3eb7SFelipe Balbi platform_device_unregister(glue->usb3_phy); 18772246da4SFelipe Balbi } 18872246da4SFelipe Balbi 189782df20cSJingoo Han static const struct pci_device_id dwc3_pci_id_table[] = { 19072246da4SFelipe Balbi { 19172246da4SFelipe Balbi PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 19272246da4SFelipe Balbi PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), 19372246da4SFelipe Balbi }, 1947d643664SAlan Cox { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, 195b62cd96dSHeikki Krogerus { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, 19685601f8cSDavid Cohen { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, 19772246da4SFelipe Balbi { } /* Terminating Entry */ 19872246da4SFelipe Balbi }; 19972246da4SFelipe Balbi MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); 20072246da4SFelipe Balbi 201fb74d282SJingoo Han #ifdef CONFIG_PM_SLEEP 20268907a77SFelipe Balbi static int dwc3_pci_suspend(struct device *dev) 20368907a77SFelipe Balbi { 20468907a77SFelipe Balbi struct pci_dev *pci = to_pci_dev(dev); 20568907a77SFelipe Balbi 20668907a77SFelipe Balbi pci_disable_device(pci); 20768907a77SFelipe Balbi 20868907a77SFelipe Balbi return 0; 20968907a77SFelipe Balbi } 21068907a77SFelipe Balbi 21168907a77SFelipe Balbi static int dwc3_pci_resume(struct device *dev) 21268907a77SFelipe Balbi { 21368907a77SFelipe Balbi struct pci_dev *pci = to_pci_dev(dev); 21468907a77SFelipe Balbi int ret; 21568907a77SFelipe Balbi 21668907a77SFelipe Balbi ret = pci_enable_device(pci); 21768907a77SFelipe Balbi if (ret) { 21868907a77SFelipe Balbi dev_err(dev, "can't re-enable device --> %d\n", ret); 21968907a77SFelipe Balbi return ret; 22068907a77SFelipe Balbi } 22168907a77SFelipe Balbi 22268907a77SFelipe Balbi pci_set_master(pci); 22368907a77SFelipe Balbi 22468907a77SFelipe Balbi return 0; 22568907a77SFelipe Balbi } 226fb74d282SJingoo Han #endif /* CONFIG_PM_SLEEP */ 22768907a77SFelipe Balbi 22868907a77SFelipe Balbi static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { 22968907a77SFelipe Balbi SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) 23068907a77SFelipe Balbi }; 23168907a77SFelipe Balbi 23272246da4SFelipe Balbi static struct pci_driver dwc3_pci_driver = { 2330949e99bSFelipe Balbi .name = "dwc3-pci", 23472246da4SFelipe Balbi .id_table = dwc3_pci_id_table, 23572246da4SFelipe Balbi .probe = dwc3_pci_probe, 2367690417dSBill Pemberton .remove = dwc3_pci_remove, 23768907a77SFelipe Balbi .driver = { 238fb74d282SJingoo Han .pm = &dwc3_pci_dev_pm_ops, 23968907a77SFelipe Balbi }, 24072246da4SFelipe Balbi }; 24172246da4SFelipe Balbi 24272246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 2435945f789SFelipe Balbi MODULE_LICENSE("GPL v2"); 24472246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); 24572246da4SFelipe Balbi 24695656336SGreg Kroah-Hartman module_pci_driver(dwc3_pci_driver); 247