xref: /openbmc/linux/drivers/usb/dwc3/dwc3-pci.c (revision ff6defa6)
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