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> 263fa4d734SSebastian Andrzej Siewior #include <linux/usb/usb_phy_gen_xceiv.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 31*b62cd96dSHeikki Krogerus #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 3272246da4SFelipe Balbi 3372246da4SFelipe Balbi struct dwc3_pci { 3472246da4SFelipe Balbi struct device *dev; 3572246da4SFelipe Balbi struct platform_device *dwc3; 36e3ec3eb7SFelipe Balbi struct platform_device *usb2_phy; 37e3ec3eb7SFelipe Balbi struct platform_device *usb3_phy; 3872246da4SFelipe Balbi }; 3972246da4SFelipe Balbi 4041ac7b3aSBill Pemberton static int dwc3_pci_register_phys(struct dwc3_pci *glue) 41e3ec3eb7SFelipe Balbi { 423fa4d734SSebastian Andrzej Siewior struct usb_phy_gen_xceiv_platform_data pdata; 43e3ec3eb7SFelipe Balbi struct platform_device *pdev; 44e3ec3eb7SFelipe Balbi int ret; 45e3ec3eb7SFelipe Balbi 46e3ec3eb7SFelipe Balbi memset(&pdata, 0x00, sizeof(pdata)); 47e3ec3eb7SFelipe Balbi 483fa4d734SSebastian Andrzej Siewior pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); 49e3ec3eb7SFelipe Balbi if (!pdev) 50e3ec3eb7SFelipe Balbi return -ENOMEM; 51e3ec3eb7SFelipe Balbi 52e3ec3eb7SFelipe Balbi glue->usb2_phy = pdev; 53e3ec3eb7SFelipe Balbi pdata.type = USB_PHY_TYPE_USB2; 54e3ec3eb7SFelipe Balbi 55e3ec3eb7SFelipe Balbi ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata)); 56e3ec3eb7SFelipe Balbi if (ret) 57e3ec3eb7SFelipe Balbi goto err1; 58e3ec3eb7SFelipe Balbi 593fa4d734SSebastian Andrzej Siewior pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); 60e3ec3eb7SFelipe Balbi if (!pdev) { 61e3ec3eb7SFelipe Balbi ret = -ENOMEM; 62e3ec3eb7SFelipe Balbi goto err1; 63e3ec3eb7SFelipe Balbi } 64e3ec3eb7SFelipe Balbi 65e3ec3eb7SFelipe Balbi glue->usb3_phy = pdev; 66e3ec3eb7SFelipe Balbi pdata.type = USB_PHY_TYPE_USB3; 67e3ec3eb7SFelipe Balbi 68e3ec3eb7SFelipe Balbi ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata)); 69e3ec3eb7SFelipe Balbi if (ret) 70e3ec3eb7SFelipe Balbi goto err2; 71e3ec3eb7SFelipe Balbi 72e3ec3eb7SFelipe Balbi ret = platform_device_add(glue->usb2_phy); 73e3ec3eb7SFelipe Balbi if (ret) 74e3ec3eb7SFelipe Balbi goto err2; 75e3ec3eb7SFelipe Balbi 76e3ec3eb7SFelipe Balbi ret = platform_device_add(glue->usb3_phy); 77e3ec3eb7SFelipe Balbi if (ret) 78e3ec3eb7SFelipe Balbi goto err3; 79e3ec3eb7SFelipe Balbi 80e3ec3eb7SFelipe Balbi return 0; 81e3ec3eb7SFelipe Balbi 82e3ec3eb7SFelipe Balbi err3: 83e3ec3eb7SFelipe Balbi platform_device_del(glue->usb2_phy); 84e3ec3eb7SFelipe Balbi 85e3ec3eb7SFelipe Balbi err2: 86e3ec3eb7SFelipe Balbi platform_device_put(glue->usb3_phy); 87e3ec3eb7SFelipe Balbi 88e3ec3eb7SFelipe Balbi err1: 89e3ec3eb7SFelipe Balbi platform_device_put(glue->usb2_phy); 90e3ec3eb7SFelipe Balbi 91e3ec3eb7SFelipe Balbi return ret; 92e3ec3eb7SFelipe Balbi } 93e3ec3eb7SFelipe Balbi 9441ac7b3aSBill Pemberton static int dwc3_pci_probe(struct pci_dev *pci, 9572246da4SFelipe Balbi const struct pci_device_id *id) 9672246da4SFelipe Balbi { 9772246da4SFelipe Balbi struct resource res[2]; 9872246da4SFelipe Balbi struct platform_device *dwc3; 9972246da4SFelipe Balbi struct dwc3_pci *glue; 10072246da4SFelipe Balbi int ret = -ENOMEM; 101802ca850SChanho Park struct device *dev = &pci->dev; 10272246da4SFelipe Balbi 103802ca850SChanho Park glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); 10472246da4SFelipe Balbi if (!glue) { 105802ca850SChanho Park dev_err(dev, "not enough memory\n"); 106802ca850SChanho Park return -ENOMEM; 10772246da4SFelipe Balbi } 10872246da4SFelipe Balbi 109802ca850SChanho Park glue->dev = dev; 11072246da4SFelipe Balbi 11172246da4SFelipe Balbi ret = pci_enable_device(pci); 11272246da4SFelipe Balbi if (ret) { 113802ca850SChanho Park dev_err(dev, "failed to enable pci device\n"); 114802ca850SChanho Park return -ENODEV; 11572246da4SFelipe Balbi } 11672246da4SFelipe Balbi 11772246da4SFelipe Balbi pci_set_master(pci); 11872246da4SFelipe Balbi 119e3ec3eb7SFelipe Balbi ret = dwc3_pci_register_phys(glue); 120e3ec3eb7SFelipe Balbi if (ret) { 121e3ec3eb7SFelipe Balbi dev_err(dev, "couldn't register PHYs\n"); 122e3ec3eb7SFelipe Balbi return ret; 123e3ec3eb7SFelipe Balbi } 124e3ec3eb7SFelipe Balbi 125124dafdeSSebastian Andrzej Siewior dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 12672246da4SFelipe Balbi if (!dwc3) { 127802ca850SChanho Park dev_err(dev, "couldn't allocate dwc3 device\n"); 12828f1a0d9SFelipe Balbi ret = -ENOMEM; 129802ca850SChanho Park goto err1; 13072246da4SFelipe Balbi } 13172246da4SFelipe Balbi 13272246da4SFelipe Balbi memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); 13372246da4SFelipe Balbi 13472246da4SFelipe Balbi res[0].start = pci_resource_start(pci, 0); 13572246da4SFelipe Balbi res[0].end = pci_resource_end(pci, 0); 13672246da4SFelipe Balbi res[0].name = "dwc_usb3"; 13772246da4SFelipe Balbi res[0].flags = IORESOURCE_MEM; 13872246da4SFelipe Balbi 13972246da4SFelipe Balbi res[1].start = pci->irq; 14072246da4SFelipe Balbi res[1].name = "dwc_usb3"; 14172246da4SFelipe Balbi res[1].flags = IORESOURCE_IRQ; 14272246da4SFelipe Balbi 14372246da4SFelipe Balbi ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); 14472246da4SFelipe Balbi if (ret) { 145802ca850SChanho Park dev_err(dev, "couldn't add resources to dwc3 device\n"); 146124dafdeSSebastian Andrzej Siewior goto err1; 14772246da4SFelipe Balbi } 14872246da4SFelipe Balbi 14972246da4SFelipe Balbi pci_set_drvdata(pci, glue); 15072246da4SFelipe Balbi 151802ca850SChanho Park dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); 15272246da4SFelipe Balbi 153802ca850SChanho Park dwc3->dev.dma_mask = dev->dma_mask; 154802ca850SChanho Park dwc3->dev.dma_parms = dev->dma_parms; 155802ca850SChanho Park dwc3->dev.parent = dev; 15672246da4SFelipe Balbi glue->dwc3 = dwc3; 15772246da4SFelipe Balbi 15872246da4SFelipe Balbi ret = platform_device_add(dwc3); 15972246da4SFelipe Balbi if (ret) { 160802ca850SChanho Park dev_err(dev, "failed to register dwc3 device\n"); 161802ca850SChanho Park goto err3; 16272246da4SFelipe Balbi } 16372246da4SFelipe Balbi 16472246da4SFelipe Balbi return 0; 16572246da4SFelipe Balbi 166802ca850SChanho Park err3: 16772246da4SFelipe Balbi pci_set_drvdata(pci, NULL); 16872246da4SFelipe Balbi platform_device_put(dwc3); 169802ca850SChanho Park err1: 17072246da4SFelipe Balbi pci_disable_device(pci); 17172246da4SFelipe Balbi 17272246da4SFelipe Balbi return ret; 17372246da4SFelipe Balbi } 17472246da4SFelipe Balbi 175fb4e98abSBill Pemberton static void dwc3_pci_remove(struct pci_dev *pci) 17672246da4SFelipe Balbi { 17772246da4SFelipe Balbi struct dwc3_pci *glue = pci_get_drvdata(pci); 17872246da4SFelipe Balbi 179f28c42c5SPeter Chen platform_device_unregister(glue->dwc3); 180e3ec3eb7SFelipe Balbi platform_device_unregister(glue->usb2_phy); 181e3ec3eb7SFelipe Balbi platform_device_unregister(glue->usb3_phy); 18272246da4SFelipe Balbi pci_set_drvdata(pci, NULL); 18372246da4SFelipe Balbi pci_disable_device(pci); 18472246da4SFelipe Balbi } 18572246da4SFelipe Balbi 18672246da4SFelipe Balbi static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { 18772246da4SFelipe Balbi { 18872246da4SFelipe Balbi PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 18972246da4SFelipe Balbi PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), 19072246da4SFelipe Balbi }, 191*b62cd96dSHeikki Krogerus { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, 19272246da4SFelipe Balbi { } /* Terminating Entry */ 19372246da4SFelipe Balbi }; 19472246da4SFelipe Balbi MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); 19572246da4SFelipe Balbi 196fb74d282SJingoo Han #ifdef CONFIG_PM_SLEEP 19768907a77SFelipe Balbi static int dwc3_pci_suspend(struct device *dev) 19868907a77SFelipe Balbi { 19968907a77SFelipe Balbi struct pci_dev *pci = to_pci_dev(dev); 20068907a77SFelipe Balbi 20168907a77SFelipe Balbi pci_disable_device(pci); 20268907a77SFelipe Balbi 20368907a77SFelipe Balbi return 0; 20468907a77SFelipe Balbi } 20568907a77SFelipe Balbi 20668907a77SFelipe Balbi static int dwc3_pci_resume(struct device *dev) 20768907a77SFelipe Balbi { 20868907a77SFelipe Balbi struct pci_dev *pci = to_pci_dev(dev); 20968907a77SFelipe Balbi int ret; 21068907a77SFelipe Balbi 21168907a77SFelipe Balbi ret = pci_enable_device(pci); 21268907a77SFelipe Balbi if (ret) { 21368907a77SFelipe Balbi dev_err(dev, "can't re-enable device --> %d\n", ret); 21468907a77SFelipe Balbi return ret; 21568907a77SFelipe Balbi } 21668907a77SFelipe Balbi 21768907a77SFelipe Balbi pci_set_master(pci); 21868907a77SFelipe Balbi 21968907a77SFelipe Balbi return 0; 22068907a77SFelipe Balbi } 221fb74d282SJingoo Han #endif /* CONFIG_PM_SLEEP */ 22268907a77SFelipe Balbi 22368907a77SFelipe Balbi static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { 22468907a77SFelipe Balbi SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) 22568907a77SFelipe Balbi }; 22668907a77SFelipe Balbi 22772246da4SFelipe Balbi static struct pci_driver dwc3_pci_driver = { 2280949e99bSFelipe Balbi .name = "dwc3-pci", 22972246da4SFelipe Balbi .id_table = dwc3_pci_id_table, 23072246da4SFelipe Balbi .probe = dwc3_pci_probe, 2317690417dSBill Pemberton .remove = dwc3_pci_remove, 23268907a77SFelipe Balbi .driver = { 233fb74d282SJingoo Han .pm = &dwc3_pci_dev_pm_ops, 23468907a77SFelipe Balbi }, 23572246da4SFelipe Balbi }; 23672246da4SFelipe Balbi 23772246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 2385945f789SFelipe Balbi MODULE_LICENSE("GPL v2"); 23972246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); 24072246da4SFelipe Balbi 24195656336SGreg Kroah-Hartman module_pci_driver(dwc3_pci_driver); 242