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 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 { 433fa4d734SSebastian Andrzej Siewior struct usb_phy_gen_xceiv_platform_data pdata; 44e3ec3eb7SFelipe Balbi struct platform_device *pdev; 45e3ec3eb7SFelipe Balbi int ret; 46e3ec3eb7SFelipe Balbi 47e3ec3eb7SFelipe Balbi memset(&pdata, 0x00, sizeof(pdata)); 48e3ec3eb7SFelipe Balbi 493fa4d734SSebastian Andrzej Siewior pdev = platform_device_alloc("usb_phy_gen_xceiv", 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; 55e3ec3eb7SFelipe Balbi 56e3ec3eb7SFelipe Balbi ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata)); 57e3ec3eb7SFelipe Balbi if (ret) 58e3ec3eb7SFelipe Balbi goto err1; 59e3ec3eb7SFelipe Balbi 603fa4d734SSebastian Andrzej Siewior pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); 61e3ec3eb7SFelipe Balbi if (!pdev) { 62e3ec3eb7SFelipe Balbi ret = -ENOMEM; 63e3ec3eb7SFelipe Balbi goto err1; 64e3ec3eb7SFelipe Balbi } 65e3ec3eb7SFelipe Balbi 66e3ec3eb7SFelipe Balbi glue->usb3_phy = pdev; 67e3ec3eb7SFelipe Balbi pdata.type = USB_PHY_TYPE_USB3; 68e3ec3eb7SFelipe Balbi 69e3ec3eb7SFelipe Balbi ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata)); 70e3ec3eb7SFelipe Balbi if (ret) 71e3ec3eb7SFelipe Balbi goto err2; 72e3ec3eb7SFelipe Balbi 73e3ec3eb7SFelipe Balbi ret = platform_device_add(glue->usb2_phy); 74e3ec3eb7SFelipe Balbi if (ret) 75e3ec3eb7SFelipe Balbi goto err2; 76e3ec3eb7SFelipe Balbi 77e3ec3eb7SFelipe Balbi ret = platform_device_add(glue->usb3_phy); 78e3ec3eb7SFelipe Balbi if (ret) 79e3ec3eb7SFelipe Balbi goto err3; 80e3ec3eb7SFelipe Balbi 81e3ec3eb7SFelipe Balbi return 0; 82e3ec3eb7SFelipe Balbi 83e3ec3eb7SFelipe Balbi err3: 84e3ec3eb7SFelipe Balbi platform_device_del(glue->usb2_phy); 85e3ec3eb7SFelipe Balbi 86e3ec3eb7SFelipe Balbi err2: 87e3ec3eb7SFelipe Balbi platform_device_put(glue->usb3_phy); 88e3ec3eb7SFelipe Balbi 89e3ec3eb7SFelipe Balbi err1: 90e3ec3eb7SFelipe Balbi platform_device_put(glue->usb2_phy); 91e3ec3eb7SFelipe Balbi 92e3ec3eb7SFelipe Balbi return ret; 93e3ec3eb7SFelipe Balbi } 94e3ec3eb7SFelipe Balbi 9541ac7b3aSBill Pemberton static int dwc3_pci_probe(struct pci_dev *pci, 9672246da4SFelipe Balbi const struct pci_device_id *id) 9772246da4SFelipe Balbi { 9872246da4SFelipe Balbi struct resource res[2]; 9972246da4SFelipe Balbi struct platform_device *dwc3; 10072246da4SFelipe Balbi struct dwc3_pci *glue; 10172246da4SFelipe Balbi int ret = -ENOMEM; 102802ca850SChanho Park struct device *dev = &pci->dev; 10372246da4SFelipe Balbi 104802ca850SChanho Park glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); 10572246da4SFelipe Balbi if (!glue) { 106802ca850SChanho Park dev_err(dev, "not enough memory\n"); 107802ca850SChanho Park return -ENOMEM; 10872246da4SFelipe Balbi } 10972246da4SFelipe Balbi 110802ca850SChanho Park glue->dev = dev; 11172246da4SFelipe Balbi 11272246da4SFelipe Balbi ret = pci_enable_device(pci); 11372246da4SFelipe Balbi if (ret) { 114802ca850SChanho Park dev_err(dev, "failed to enable pci device\n"); 115802ca850SChanho Park return -ENODEV; 11672246da4SFelipe Balbi } 11772246da4SFelipe Balbi 11872246da4SFelipe Balbi pci_set_master(pci); 11972246da4SFelipe Balbi 120e3ec3eb7SFelipe Balbi ret = dwc3_pci_register_phys(glue); 121e3ec3eb7SFelipe Balbi if (ret) { 122e3ec3eb7SFelipe Balbi dev_err(dev, "couldn't register PHYs\n"); 123e3ec3eb7SFelipe Balbi return ret; 124e3ec3eb7SFelipe Balbi } 125e3ec3eb7SFelipe Balbi 126124dafdeSSebastian Andrzej Siewior dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 12772246da4SFelipe Balbi if (!dwc3) { 128802ca850SChanho Park dev_err(dev, "couldn't allocate dwc3 device\n"); 12928f1a0d9SFelipe Balbi ret = -ENOMEM; 130802ca850SChanho Park goto err1; 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"); 147124dafdeSSebastian Andrzej Siewior goto err1; 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); 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_disable_device(pci); 18372246da4SFelipe Balbi } 18472246da4SFelipe Balbi 185*782df20cSJingoo Han static const struct pci_device_id dwc3_pci_id_table[] = { 18672246da4SFelipe Balbi { 18772246da4SFelipe Balbi PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 18872246da4SFelipe Balbi PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), 18972246da4SFelipe Balbi }, 190b62cd96dSHeikki Krogerus { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, 19185601f8cSDavid Cohen { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, 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