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 2872246da4SFelipe Balbi /* FIXME define these in <linux/pci_ids.h> */ 2972246da4SFelipe Balbi #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 3072246da4SFelipe Balbi #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd 31b62cd96dSHeikki Krogerus #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 3285601f8cSDavid Cohen #define PCI_DEVICE_ID_INTEL_MRFLD 0x119e 3372246da4SFelipe Balbi 3472246da4SFelipe Balbi struct dwc3_pci { 3572246da4SFelipe Balbi struct device *dev; 3672246da4SFelipe Balbi struct platform_device *dwc3; 37e3ec3eb7SFelipe Balbi struct platform_device *usb2_phy; 38e3ec3eb7SFelipe Balbi struct platform_device *usb3_phy; 3972246da4SFelipe Balbi }; 4072246da4SFelipe Balbi 4141ac7b3aSBill Pemberton static int dwc3_pci_register_phys(struct dwc3_pci *glue) 42e3ec3eb7SFelipe Balbi { 434525beebSFelipe Balbi struct usb_phy_generic_platform_data pdata; 44e3ec3eb7SFelipe Balbi struct platform_device *pdev; 45e3ec3eb7SFelipe Balbi int ret; 46e3ec3eb7SFelipe Balbi 47e3ec3eb7SFelipe Balbi memset(&pdata, 0x00, sizeof(pdata)); 48e3ec3eb7SFelipe Balbi 494525beebSFelipe Balbi pdev = platform_device_alloc("usb_phy_generic", 0); 50e3ec3eb7SFelipe Balbi if (!pdev) 51e3ec3eb7SFelipe Balbi return -ENOMEM; 52e3ec3eb7SFelipe Balbi 53e3ec3eb7SFelipe Balbi glue->usb2_phy = pdev; 54e3ec3eb7SFelipe Balbi pdata.type = USB_PHY_TYPE_USB2; 5513518673SHeikki Krogerus pdata.gpio_reset = -1; 56e3ec3eb7SFelipe Balbi 57e3ec3eb7SFelipe Balbi ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata)); 58e3ec3eb7SFelipe Balbi if (ret) 59e3ec3eb7SFelipe Balbi goto err1; 60e3ec3eb7SFelipe Balbi 614525beebSFelipe Balbi pdev = platform_device_alloc("usb_phy_generic", 1); 62e3ec3eb7SFelipe Balbi if (!pdev) { 63e3ec3eb7SFelipe Balbi ret = -ENOMEM; 64e3ec3eb7SFelipe Balbi goto err1; 65e3ec3eb7SFelipe Balbi } 66e3ec3eb7SFelipe Balbi 67e3ec3eb7SFelipe Balbi glue->usb3_phy = pdev; 68e3ec3eb7SFelipe Balbi pdata.type = USB_PHY_TYPE_USB3; 69e3ec3eb7SFelipe Balbi 70e3ec3eb7SFelipe Balbi ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata)); 71e3ec3eb7SFelipe Balbi if (ret) 72e3ec3eb7SFelipe Balbi goto err2; 73e3ec3eb7SFelipe Balbi 74e3ec3eb7SFelipe Balbi ret = platform_device_add(glue->usb2_phy); 75e3ec3eb7SFelipe Balbi if (ret) 76e3ec3eb7SFelipe Balbi goto err2; 77e3ec3eb7SFelipe Balbi 78e3ec3eb7SFelipe Balbi ret = platform_device_add(glue->usb3_phy); 79e3ec3eb7SFelipe Balbi if (ret) 80e3ec3eb7SFelipe Balbi goto err3; 81e3ec3eb7SFelipe Balbi 82e3ec3eb7SFelipe Balbi return 0; 83e3ec3eb7SFelipe Balbi 84e3ec3eb7SFelipe Balbi err3: 85e3ec3eb7SFelipe Balbi platform_device_del(glue->usb2_phy); 86e3ec3eb7SFelipe Balbi 87e3ec3eb7SFelipe Balbi err2: 88e3ec3eb7SFelipe Balbi platform_device_put(glue->usb3_phy); 89e3ec3eb7SFelipe Balbi 90e3ec3eb7SFelipe Balbi err1: 91e3ec3eb7SFelipe Balbi platform_device_put(glue->usb2_phy); 92e3ec3eb7SFelipe Balbi 93e3ec3eb7SFelipe Balbi return ret; 94e3ec3eb7SFelipe Balbi } 95e3ec3eb7SFelipe Balbi 9641ac7b3aSBill Pemberton static int dwc3_pci_probe(struct pci_dev *pci, 9772246da4SFelipe Balbi const struct pci_device_id *id) 9872246da4SFelipe Balbi { 9972246da4SFelipe Balbi struct resource res[2]; 10072246da4SFelipe Balbi struct platform_device *dwc3; 10172246da4SFelipe Balbi struct dwc3_pci *glue; 102b09e99eeSAndy Shevchenko int ret; 103802ca850SChanho Park struct device *dev = &pci->dev; 10472246da4SFelipe Balbi 105802ca850SChanho Park glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); 10672246da4SFelipe Balbi if (!glue) { 107802ca850SChanho Park dev_err(dev, "not enough memory\n"); 108802ca850SChanho Park return -ENOMEM; 10972246da4SFelipe Balbi } 11072246da4SFelipe Balbi 111802ca850SChanho Park glue->dev = dev; 11272246da4SFelipe Balbi 113*f1c7e710SAndy Shevchenko ret = pcim_enable_device(pci); 11472246da4SFelipe Balbi if (ret) { 115802ca850SChanho Park dev_err(dev, "failed to enable pci device\n"); 116802ca850SChanho Park return -ENODEV; 11772246da4SFelipe Balbi } 11872246da4SFelipe Balbi 11972246da4SFelipe Balbi pci_set_master(pci); 12072246da4SFelipe Balbi 121e3ec3eb7SFelipe Balbi ret = dwc3_pci_register_phys(glue); 122e3ec3eb7SFelipe Balbi if (ret) { 123e3ec3eb7SFelipe Balbi dev_err(dev, "couldn't register PHYs\n"); 124e3ec3eb7SFelipe Balbi return ret; 125e3ec3eb7SFelipe Balbi } 126e3ec3eb7SFelipe Balbi 127124dafdeSSebastian Andrzej Siewior dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 12872246da4SFelipe Balbi if (!dwc3) { 129802ca850SChanho Park dev_err(dev, "couldn't allocate dwc3 device\n"); 130*f1c7e710SAndy Shevchenko return -ENOMEM; 13172246da4SFelipe Balbi } 13272246da4SFelipe Balbi 13372246da4SFelipe Balbi memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); 13472246da4SFelipe Balbi 13572246da4SFelipe Balbi res[0].start = pci_resource_start(pci, 0); 13672246da4SFelipe Balbi res[0].end = pci_resource_end(pci, 0); 13772246da4SFelipe Balbi res[0].name = "dwc_usb3"; 13872246da4SFelipe Balbi res[0].flags = IORESOURCE_MEM; 13972246da4SFelipe Balbi 14072246da4SFelipe Balbi res[1].start = pci->irq; 14172246da4SFelipe Balbi res[1].name = "dwc_usb3"; 14272246da4SFelipe Balbi res[1].flags = IORESOURCE_IRQ; 14372246da4SFelipe Balbi 14472246da4SFelipe Balbi ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); 14572246da4SFelipe Balbi if (ret) { 146802ca850SChanho Park dev_err(dev, "couldn't add resources to dwc3 device\n"); 147*f1c7e710SAndy Shevchenko return ret; 14872246da4SFelipe Balbi } 14972246da4SFelipe Balbi 15072246da4SFelipe Balbi pci_set_drvdata(pci, glue); 15172246da4SFelipe Balbi 152802ca850SChanho Park dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); 15372246da4SFelipe Balbi 154802ca850SChanho Park dwc3->dev.dma_mask = dev->dma_mask; 155802ca850SChanho Park dwc3->dev.dma_parms = dev->dma_parms; 156802ca850SChanho Park dwc3->dev.parent = dev; 15772246da4SFelipe Balbi glue->dwc3 = dwc3; 15872246da4SFelipe Balbi 15972246da4SFelipe Balbi ret = platform_device_add(dwc3); 16072246da4SFelipe Balbi if (ret) { 161802ca850SChanho Park dev_err(dev, "failed to register dwc3 device\n"); 162802ca850SChanho Park goto err3; 16372246da4SFelipe Balbi } 16472246da4SFelipe Balbi 16572246da4SFelipe Balbi return 0; 16672246da4SFelipe Balbi 167802ca850SChanho Park err3: 16872246da4SFelipe Balbi platform_device_put(dwc3); 16972246da4SFelipe Balbi return ret; 17072246da4SFelipe Balbi } 17172246da4SFelipe Balbi 172fb4e98abSBill Pemberton static void dwc3_pci_remove(struct pci_dev *pci) 17372246da4SFelipe Balbi { 17472246da4SFelipe Balbi struct dwc3_pci *glue = pci_get_drvdata(pci); 17572246da4SFelipe Balbi 176f28c42c5SPeter Chen platform_device_unregister(glue->dwc3); 177e3ec3eb7SFelipe Balbi platform_device_unregister(glue->usb2_phy); 178e3ec3eb7SFelipe Balbi platform_device_unregister(glue->usb3_phy); 17972246da4SFelipe Balbi } 18072246da4SFelipe Balbi 181782df20cSJingoo Han static const struct pci_device_id dwc3_pci_id_table[] = { 18272246da4SFelipe Balbi { 18372246da4SFelipe Balbi PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 18472246da4SFelipe Balbi PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), 18572246da4SFelipe Balbi }, 186b62cd96dSHeikki Krogerus { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, 18785601f8cSDavid Cohen { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, 18872246da4SFelipe Balbi { } /* Terminating Entry */ 18972246da4SFelipe Balbi }; 19072246da4SFelipe Balbi MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); 19172246da4SFelipe Balbi 192fb74d282SJingoo Han #ifdef CONFIG_PM_SLEEP 19368907a77SFelipe Balbi static int dwc3_pci_suspend(struct device *dev) 19468907a77SFelipe Balbi { 19568907a77SFelipe Balbi struct pci_dev *pci = to_pci_dev(dev); 19668907a77SFelipe Balbi 19768907a77SFelipe Balbi pci_disable_device(pci); 19868907a77SFelipe Balbi 19968907a77SFelipe Balbi return 0; 20068907a77SFelipe Balbi } 20168907a77SFelipe Balbi 20268907a77SFelipe Balbi static int dwc3_pci_resume(struct device *dev) 20368907a77SFelipe Balbi { 20468907a77SFelipe Balbi struct pci_dev *pci = to_pci_dev(dev); 20568907a77SFelipe Balbi int ret; 20668907a77SFelipe Balbi 20768907a77SFelipe Balbi ret = pci_enable_device(pci); 20868907a77SFelipe Balbi if (ret) { 20968907a77SFelipe Balbi dev_err(dev, "can't re-enable device --> %d\n", ret); 21068907a77SFelipe Balbi return ret; 21168907a77SFelipe Balbi } 21268907a77SFelipe Balbi 21368907a77SFelipe Balbi pci_set_master(pci); 21468907a77SFelipe Balbi 21568907a77SFelipe Balbi return 0; 21668907a77SFelipe Balbi } 217fb74d282SJingoo Han #endif /* CONFIG_PM_SLEEP */ 21868907a77SFelipe Balbi 21968907a77SFelipe Balbi static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { 22068907a77SFelipe Balbi SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) 22168907a77SFelipe Balbi }; 22268907a77SFelipe Balbi 22372246da4SFelipe Balbi static struct pci_driver dwc3_pci_driver = { 2240949e99bSFelipe Balbi .name = "dwc3-pci", 22572246da4SFelipe Balbi .id_table = dwc3_pci_id_table, 22672246da4SFelipe Balbi .probe = dwc3_pci_probe, 2277690417dSBill Pemberton .remove = dwc3_pci_remove, 22868907a77SFelipe Balbi .driver = { 229fb74d282SJingoo Han .pm = &dwc3_pci_dev_pm_ops, 23068907a77SFelipe Balbi }, 23172246da4SFelipe Balbi }; 23272246da4SFelipe Balbi 23372246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 2345945f789SFelipe Balbi MODULE_LICENSE("GPL v2"); 23572246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); 23672246da4SFelipe Balbi 23795656336SGreg Kroah-Hartman module_pci_driver(dwc3_pci_driver); 238