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 #define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30 37 #define PCI_DEVICE_ID_INTEL_SPTH 0xa130 38 39 struct dwc3_pci { 40 struct device *dev; 41 struct platform_device *dwc3; 42 struct platform_device *usb2_phy; 43 struct platform_device *usb3_phy; 44 }; 45 46 static int dwc3_pci_register_phys(struct dwc3_pci *glue) 47 { 48 struct usb_phy_generic_platform_data pdata; 49 struct platform_device *pdev; 50 int ret; 51 52 memset(&pdata, 0x00, sizeof(pdata)); 53 54 pdev = platform_device_alloc("usb_phy_generic", 0); 55 if (!pdev) 56 return -ENOMEM; 57 58 glue->usb2_phy = pdev; 59 pdata.type = USB_PHY_TYPE_USB2; 60 pdata.gpio_reset = -1; 61 62 ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata)); 63 if (ret) 64 goto err1; 65 66 pdev = platform_device_alloc("usb_phy_generic", 1); 67 if (!pdev) { 68 ret = -ENOMEM; 69 goto err1; 70 } 71 72 glue->usb3_phy = pdev; 73 pdata.type = USB_PHY_TYPE_USB3; 74 75 ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata)); 76 if (ret) 77 goto err2; 78 79 ret = platform_device_add(glue->usb2_phy); 80 if (ret) 81 goto err2; 82 83 ret = platform_device_add(glue->usb3_phy); 84 if (ret) 85 goto err3; 86 87 return 0; 88 89 err3: 90 platform_device_del(glue->usb2_phy); 91 92 err2: 93 platform_device_put(glue->usb3_phy); 94 95 err1: 96 platform_device_put(glue->usb2_phy); 97 98 return ret; 99 } 100 101 static int dwc3_pci_probe(struct pci_dev *pci, 102 const struct pci_device_id *id) 103 { 104 struct resource res[2]; 105 struct platform_device *dwc3; 106 struct dwc3_pci *glue; 107 int ret; 108 struct device *dev = &pci->dev; 109 struct dwc3_platform_data dwc3_pdata; 110 111 memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata)); 112 113 glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); 114 if (!glue) 115 return -ENOMEM; 116 117 glue->dev = dev; 118 119 ret = pcim_enable_device(pci); 120 if (ret) { 121 dev_err(dev, "failed to enable pci device\n"); 122 return -ENODEV; 123 } 124 125 pci_set_master(pci); 126 127 ret = dwc3_pci_register_phys(glue); 128 if (ret) { 129 dev_err(dev, "couldn't register PHYs\n"); 130 return ret; 131 } 132 133 dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 134 if (!dwc3) { 135 dev_err(dev, "couldn't allocate dwc3 device\n"); 136 return -ENOMEM; 137 } 138 139 memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); 140 141 res[0].start = pci_resource_start(pci, 0); 142 res[0].end = pci_resource_end(pci, 0); 143 res[0].name = "dwc_usb3"; 144 res[0].flags = IORESOURCE_MEM; 145 146 res[1].start = pci->irq; 147 res[1].name = "dwc_usb3"; 148 res[1].flags = IORESOURCE_IRQ; 149 150 if (pci->vendor == PCI_VENDOR_ID_AMD && 151 pci->device == PCI_DEVICE_ID_AMD_NL_USB) { 152 dwc3_pdata.has_lpm_erratum = true; 153 dwc3_pdata.lpm_nyet_threshold = 0xf; 154 155 dwc3_pdata.u2exit_lfps_quirk = true; 156 dwc3_pdata.u2ss_inp3_quirk = true; 157 dwc3_pdata.req_p1p2p3_quirk = true; 158 dwc3_pdata.del_p1p2p3_quirk = true; 159 dwc3_pdata.del_phy_power_chg_quirk = true; 160 dwc3_pdata.lfps_filter_quirk = true; 161 dwc3_pdata.rx_detect_poll_quirk = true; 162 163 dwc3_pdata.tx_de_emphasis_quirk = true; 164 dwc3_pdata.tx_de_emphasis = 1; 165 166 /* 167 * FIXME these quirks should be removed when AMD NL 168 * taps out 169 */ 170 dwc3_pdata.disable_scramble_quirk = true; 171 dwc3_pdata.dis_u3_susphy_quirk = true; 172 dwc3_pdata.dis_u2_susphy_quirk = true; 173 } 174 175 ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); 176 if (ret) { 177 dev_err(dev, "couldn't add resources to dwc3 device\n"); 178 return ret; 179 } 180 181 pci_set_drvdata(pci, glue); 182 183 ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata)); 184 if (ret) 185 goto err3; 186 187 dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); 188 189 dwc3->dev.dma_mask = dev->dma_mask; 190 dwc3->dev.dma_parms = dev->dma_parms; 191 dwc3->dev.parent = dev; 192 glue->dwc3 = dwc3; 193 194 ret = platform_device_add(dwc3); 195 if (ret) { 196 dev_err(dev, "failed to register dwc3 device\n"); 197 goto err3; 198 } 199 200 return 0; 201 202 err3: 203 platform_device_put(dwc3); 204 return ret; 205 } 206 207 static void dwc3_pci_remove(struct pci_dev *pci) 208 { 209 struct dwc3_pci *glue = pci_get_drvdata(pci); 210 211 platform_device_unregister(glue->dwc3); 212 platform_device_unregister(glue->usb2_phy); 213 platform_device_unregister(glue->usb3_phy); 214 } 215 216 static const struct pci_device_id dwc3_pci_id_table[] = { 217 { 218 PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 219 PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), 220 }, 221 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, 222 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, 223 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, 224 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, 225 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, 226 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, 227 { } /* Terminating Entry */ 228 }; 229 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); 230 231 #ifdef CONFIG_PM_SLEEP 232 static int dwc3_pci_suspend(struct device *dev) 233 { 234 struct pci_dev *pci = to_pci_dev(dev); 235 236 pci_disable_device(pci); 237 238 return 0; 239 } 240 241 static int dwc3_pci_resume(struct device *dev) 242 { 243 struct pci_dev *pci = to_pci_dev(dev); 244 int ret; 245 246 ret = pci_enable_device(pci); 247 if (ret) { 248 dev_err(dev, "can't re-enable device --> %d\n", ret); 249 return ret; 250 } 251 252 pci_set_master(pci); 253 254 return 0; 255 } 256 #endif /* CONFIG_PM_SLEEP */ 257 258 static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { 259 SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) 260 }; 261 262 static struct pci_driver dwc3_pci_driver = { 263 .name = "dwc3-pci", 264 .id_table = dwc3_pci_id_table, 265 .probe = dwc3_pci_probe, 266 .remove = dwc3_pci_remove, 267 .driver = { 268 .pm = &dwc3_pci_dev_pm_ops, 269 }, 270 }; 271 272 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 273 MODULE_LICENSE("GPL v2"); 274 MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); 275 276 module_pci_driver(dwc3_pci_driver); 277