Merge tag 'mvebu-fixes-3.19' of git://git.infradead.org/linux-mvebu into fixes
[cascardo/linux.git] / drivers / usb / dwc3 / dwc3-pci.c
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);