1 /** 2 * dwc3-pci.c - PCI Specific glue layer 3 * 4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com 5 * 6 * Authors: Felipe Balbi <balbi@ti.com>, 7 * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 8 * 9 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 of 11 * the License as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/slab.h> 22 #include <linux/pci.h> 23 #include <linux/platform_device.h> 24 25 #include <linux/usb/otg.h> 26 #include <linux/usb/usb_phy_generic.h> 27 28 #include "platform_data.h" 29 30 /* FIXME define these in <linux/pci_ids.h> */ 31 #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 32 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd 33 #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 34 #define PCI_DEVICE_ID_INTEL_MRFLD 0x119e 35 #define PCI_DEVICE_ID_INTEL_BSW 0x22B7 36 37 struct dwc3_pci { 38 struct device *dev; 39 struct platform_device *dwc3; 40 struct platform_device *usb2_phy; 41 struct platform_device *usb3_phy; 42 }; 43 44 static int dwc3_pci_register_phys(struct dwc3_pci *glue) 45 { 46 struct usb_phy_generic_platform_data pdata; 47 struct platform_device *pdev; 48 int ret; 49 50 memset(&pdata, 0x00, sizeof(pdata)); 51 52 pdev = platform_device_alloc("usb_phy_generic", 0); 53 if (!pdev) 54 return -ENOMEM; 55 56 glue->usb2_phy = pdev; 57 pdata.type = USB_PHY_TYPE_USB2; 58 pdata.gpio_reset = -1; 59 60 ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata)); 61 if (ret) 62 goto err1; 63 64 pdev = platform_device_alloc("usb_phy_generic", 1); 65 if (!pdev) { 66 ret = -ENOMEM; 67 goto err1; 68 } 69 70 glue->usb3_phy = pdev; 71 pdata.type = USB_PHY_TYPE_USB3; 72 73 ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata)); 74 if (ret) 75 goto err2; 76 77 ret = platform_device_add(glue->usb2_phy); 78 if (ret) 79 goto err2; 80 81 ret = platform_device_add(glue->usb3_phy); 82 if (ret) 83 goto err3; 84 85 return 0; 86 87 err3: 88 platform_device_del(glue->usb2_phy); 89 90 err2: 91 platform_device_put(glue->usb3_phy); 92 93 err1: 94 platform_device_put(glue->usb2_phy); 95 96 return ret; 97 } 98 99 static int dwc3_pci_probe(struct pci_dev *pci, 100 const struct pci_device_id *id) 101 { 102 struct resource res[2]; 103 struct platform_device *dwc3; 104 struct dwc3_pci *glue; 105 int ret; 106 struct device *dev = &pci->dev; 107 struct dwc3_platform_data dwc3_pdata; 108 109 memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata)); 110 111 glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); 112 if (!glue) 113 return -ENOMEM; 114 115 glue->dev = dev; 116 117 ret = pcim_enable_device(pci); 118 if (ret) { 119 dev_err(dev, "failed to enable pci device\n"); 120 return -ENODEV; 121 } 122 123 pci_set_master(pci); 124 125 ret = dwc3_pci_register_phys(glue); 126 if (ret) { 127 dev_err(dev, "couldn't register PHYs\n"); 128 return ret; 129 } 130 131 dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 132 if (!dwc3) { 133 dev_err(dev, "couldn't allocate dwc3 device\n"); 134 return -ENOMEM; 135 } 136 137 memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); 138 139 res[0].start = pci_resource_start(pci, 0); 140 res[0].end = pci_resource_end(pci, 0); 141 res[0].name = "dwc_usb3"; 142 res[0].flags = IORESOURCE_MEM; 143 144 res[1].start = pci->irq; 145 res[1].name = "dwc_usb3"; 146 res[1].flags = IORESOURCE_IRQ; 147 148 if (pci->vendor == PCI_VENDOR_ID_AMD && 149 pci->device == PCI_DEVICE_ID_AMD_NL_USB) { 150 dwc3_pdata.has_lpm_erratum = true; 151 dwc3_pdata.lpm_nyet_threshold = 0xf; 152 153 dwc3_pdata.u2exit_lfps_quirk = true; 154 dwc3_pdata.u2ss_inp3_quirk = true; 155 dwc3_pdata.req_p1p2p3_quirk = true; 156 dwc3_pdata.del_p1p2p3_quirk = true; 157 dwc3_pdata.del_phy_power_chg_quirk = true; 158 dwc3_pdata.lfps_filter_quirk = true; 159 dwc3_pdata.rx_detect_poll_quirk = true; 160 161 dwc3_pdata.tx_de_emphasis_quirk = true; 162 dwc3_pdata.tx_de_emphasis = 1; 163 164 /* 165 * FIXME these quirks should be removed when AMD NL 166 * taps out 167 */ 168 dwc3_pdata.disable_scramble_quirk = true; 169 dwc3_pdata.dis_u3_susphy_quirk = true; 170 dwc3_pdata.dis_u2_susphy_quirk = true; 171 } 172 173 ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); 174 if (ret) { 175 dev_err(dev, "couldn't add resources to dwc3 device\n"); 176 return ret; 177 } 178 179 pci_set_drvdata(pci, glue); 180 181 ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata)); 182 if (ret) 183 goto err3; 184 185 dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); 186 187 dwc3->dev.dma_mask = dev->dma_mask; 188 dwc3->dev.dma_parms = dev->dma_parms; 189 dwc3->dev.parent = dev; 190 glue->dwc3 = dwc3; 191 192 ret = platform_device_add(dwc3); 193 if (ret) { 194 dev_err(dev, "failed to register dwc3 device\n"); 195 goto err3; 196 } 197 198 return 0; 199 200 err3: 201 platform_device_put(dwc3); 202 return ret; 203 } 204 205 static void dwc3_pci_remove(struct pci_dev *pci) 206 { 207 struct dwc3_pci *glue = pci_get_drvdata(pci); 208 209 platform_device_unregister(glue->dwc3); 210 platform_device_unregister(glue->usb2_phy); 211 platform_device_unregister(glue->usb3_phy); 212 } 213 214 static const struct pci_device_id dwc3_pci_id_table[] = { 215 { 216 PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 217 PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), 218 }, 219 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, 220 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, 221 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, 222 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, 223 { } /* Terminating Entry */ 224 }; 225 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); 226 227 #ifdef CONFIG_PM_SLEEP 228 static int dwc3_pci_suspend(struct device *dev) 229 { 230 struct pci_dev *pci = to_pci_dev(dev); 231 232 pci_disable_device(pci); 233 234 return 0; 235 } 236 237 static int dwc3_pci_resume(struct device *dev) 238 { 239 struct pci_dev *pci = to_pci_dev(dev); 240 int ret; 241 242 ret = pci_enable_device(pci); 243 if (ret) { 244 dev_err(dev, "can't re-enable device --> %d\n", ret); 245 return ret; 246 } 247 248 pci_set_master(pci); 249 250 return 0; 251 } 252 #endif /* CONFIG_PM_SLEEP */ 253 254 static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { 255 SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) 256 }; 257 258 static struct pci_driver dwc3_pci_driver = { 259 .name = "dwc3-pci", 260 .id_table = dwc3_pci_id_table, 261 .probe = dwc3_pci_probe, 262 .remove = dwc3_pci_remove, 263 .driver = { 264 .pm = &dwc3_pci_dev_pm_ops, 265 }, 266 }; 267 268 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 269 MODULE_LICENSE("GPL v2"); 270 MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); 271 272 module_pci_driver(dwc3_pci_driver); 273