xref: /linux/drivers/usb/dwc3/dwc3-pci.c (revision 84a2b61b6eb94036093531cdabc448dddfbae45a)
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>
26d7078df6SFelipe Balbi #include <linux/usb/usb_phy_generic.h>
27e3ec3eb7SFelipe Balbi 
288f317b47SHuang Rui #include "platform_data.h"
298f317b47SHuang Rui 
3072246da4SFelipe Balbi /* FIXME define these in <linux/pci_ids.h> */
3172246da4SFelipe Balbi #define PCI_VENDOR_ID_SYNOPSYS		0x16c3
3272246da4SFelipe Balbi #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd
33b62cd96dSHeikki Krogerus #define PCI_DEVICE_ID_INTEL_BYT		0x0f37
3485601f8cSDavid Cohen #define PCI_DEVICE_ID_INTEL_MRFLD	0x119e
357d643664SAlan Cox #define PCI_DEVICE_ID_INTEL_BSW		0x22B7
36*84a2b61bSHeikki Krogerus #define PCI_DEVICE_ID_INTEL_SPTLP	0x9d30
37*84a2b61bSHeikki Krogerus #define PCI_DEVICE_ID_INTEL_SPTH	0xa130
3872246da4SFelipe Balbi 
3972246da4SFelipe Balbi struct dwc3_pci {
4072246da4SFelipe Balbi 	struct device		*dev;
4172246da4SFelipe Balbi 	struct platform_device	*dwc3;
42e3ec3eb7SFelipe Balbi 	struct platform_device	*usb2_phy;
43e3ec3eb7SFelipe Balbi 	struct platform_device	*usb3_phy;
4472246da4SFelipe Balbi };
4572246da4SFelipe Balbi 
4641ac7b3aSBill Pemberton static int dwc3_pci_register_phys(struct dwc3_pci *glue)
47e3ec3eb7SFelipe Balbi {
484525beebSFelipe Balbi 	struct usb_phy_generic_platform_data pdata;
49e3ec3eb7SFelipe Balbi 	struct platform_device	*pdev;
50e3ec3eb7SFelipe Balbi 	int			ret;
51e3ec3eb7SFelipe Balbi 
52e3ec3eb7SFelipe Balbi 	memset(&pdata, 0x00, sizeof(pdata));
53e3ec3eb7SFelipe Balbi 
544525beebSFelipe Balbi 	pdev = platform_device_alloc("usb_phy_generic", 0);
55e3ec3eb7SFelipe Balbi 	if (!pdev)
56e3ec3eb7SFelipe Balbi 		return -ENOMEM;
57e3ec3eb7SFelipe Balbi 
58e3ec3eb7SFelipe Balbi 	glue->usb2_phy = pdev;
59e3ec3eb7SFelipe Balbi 	pdata.type = USB_PHY_TYPE_USB2;
6013518673SHeikki Krogerus 	pdata.gpio_reset = -1;
61e3ec3eb7SFelipe Balbi 
62e3ec3eb7SFelipe Balbi 	ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
63e3ec3eb7SFelipe Balbi 	if (ret)
64e3ec3eb7SFelipe Balbi 		goto err1;
65e3ec3eb7SFelipe Balbi 
664525beebSFelipe Balbi 	pdev = platform_device_alloc("usb_phy_generic", 1);
67e3ec3eb7SFelipe Balbi 	if (!pdev) {
68e3ec3eb7SFelipe Balbi 		ret = -ENOMEM;
69e3ec3eb7SFelipe Balbi 		goto err1;
70e3ec3eb7SFelipe Balbi 	}
71e3ec3eb7SFelipe Balbi 
72e3ec3eb7SFelipe Balbi 	glue->usb3_phy = pdev;
73e3ec3eb7SFelipe Balbi 	pdata.type = USB_PHY_TYPE_USB3;
74e3ec3eb7SFelipe Balbi 
75e3ec3eb7SFelipe Balbi 	ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
76e3ec3eb7SFelipe Balbi 	if (ret)
77e3ec3eb7SFelipe Balbi 		goto err2;
78e3ec3eb7SFelipe Balbi 
79e3ec3eb7SFelipe Balbi 	ret = platform_device_add(glue->usb2_phy);
80e3ec3eb7SFelipe Balbi 	if (ret)
81e3ec3eb7SFelipe Balbi 		goto err2;
82e3ec3eb7SFelipe Balbi 
83e3ec3eb7SFelipe Balbi 	ret = platform_device_add(glue->usb3_phy);
84e3ec3eb7SFelipe Balbi 	if (ret)
85e3ec3eb7SFelipe Balbi 		goto err3;
86e3ec3eb7SFelipe Balbi 
87e3ec3eb7SFelipe Balbi 	return 0;
88e3ec3eb7SFelipe Balbi 
89e3ec3eb7SFelipe Balbi err3:
90e3ec3eb7SFelipe Balbi 	platform_device_del(glue->usb2_phy);
91e3ec3eb7SFelipe Balbi 
92e3ec3eb7SFelipe Balbi err2:
93e3ec3eb7SFelipe Balbi 	platform_device_put(glue->usb3_phy);
94e3ec3eb7SFelipe Balbi 
95e3ec3eb7SFelipe Balbi err1:
96e3ec3eb7SFelipe Balbi 	platform_device_put(glue->usb2_phy);
97e3ec3eb7SFelipe Balbi 
98e3ec3eb7SFelipe Balbi 	return ret;
99e3ec3eb7SFelipe Balbi }
100e3ec3eb7SFelipe Balbi 
10141ac7b3aSBill Pemberton static int dwc3_pci_probe(struct pci_dev *pci,
10272246da4SFelipe Balbi 		const struct pci_device_id *id)
10372246da4SFelipe Balbi {
10472246da4SFelipe Balbi 	struct resource		res[2];
10572246da4SFelipe Balbi 	struct platform_device	*dwc3;
10672246da4SFelipe Balbi 	struct dwc3_pci		*glue;
107b09e99eeSAndy Shevchenko 	int			ret;
108802ca850SChanho Park 	struct device		*dev = &pci->dev;
1098f317b47SHuang Rui 	struct dwc3_platform_data dwc3_pdata;
1108f317b47SHuang Rui 
1118f317b47SHuang Rui 	memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
11272246da4SFelipe Balbi 
113802ca850SChanho Park 	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
114734d5a53SJingoo Han 	if (!glue)
115802ca850SChanho Park 		return -ENOMEM;
11672246da4SFelipe Balbi 
117802ca850SChanho Park 	glue->dev = dev;
11872246da4SFelipe Balbi 
119f1c7e710SAndy Shevchenko 	ret = pcim_enable_device(pci);
12072246da4SFelipe Balbi 	if (ret) {
121802ca850SChanho Park 		dev_err(dev, "failed to enable pci device\n");
122802ca850SChanho Park 		return -ENODEV;
12372246da4SFelipe Balbi 	}
12472246da4SFelipe Balbi 
12572246da4SFelipe Balbi 	pci_set_master(pci);
12672246da4SFelipe Balbi 
127e3ec3eb7SFelipe Balbi 	ret = dwc3_pci_register_phys(glue);
128e3ec3eb7SFelipe Balbi 	if (ret) {
129e3ec3eb7SFelipe Balbi 		dev_err(dev, "couldn't register PHYs\n");
130e3ec3eb7SFelipe Balbi 		return ret;
131e3ec3eb7SFelipe Balbi 	}
132e3ec3eb7SFelipe Balbi 
133124dafdeSSebastian Andrzej Siewior 	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
13472246da4SFelipe Balbi 	if (!dwc3) {
135802ca850SChanho Park 		dev_err(dev, "couldn't allocate dwc3 device\n");
136f1c7e710SAndy Shevchenko 		return -ENOMEM;
13772246da4SFelipe Balbi 	}
13872246da4SFelipe Balbi 
13972246da4SFelipe Balbi 	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
14072246da4SFelipe Balbi 
14172246da4SFelipe Balbi 	res[0].start	= pci_resource_start(pci, 0);
14272246da4SFelipe Balbi 	res[0].end	= pci_resource_end(pci, 0);
14372246da4SFelipe Balbi 	res[0].name	= "dwc_usb3";
14472246da4SFelipe Balbi 	res[0].flags	= IORESOURCE_MEM;
14572246da4SFelipe Balbi 
14672246da4SFelipe Balbi 	res[1].start	= pci->irq;
14772246da4SFelipe Balbi 	res[1].name	= "dwc_usb3";
14872246da4SFelipe Balbi 	res[1].flags	= IORESOURCE_IRQ;
14972246da4SFelipe Balbi 
1509755449dSHuang Rui 	if (pci->vendor == PCI_VENDOR_ID_AMD &&
1519755449dSHuang Rui 			pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
1529755449dSHuang Rui 		dwc3_pdata.has_lpm_erratum = true;
1539755449dSHuang Rui 		dwc3_pdata.lpm_nyet_threshold = 0xf;
1549755449dSHuang Rui 
1559755449dSHuang Rui 		dwc3_pdata.u2exit_lfps_quirk = true;
1569755449dSHuang Rui 		dwc3_pdata.u2ss_inp3_quirk = true;
1579755449dSHuang Rui 		dwc3_pdata.req_p1p2p3_quirk = true;
1589755449dSHuang Rui 		dwc3_pdata.del_p1p2p3_quirk = true;
1599755449dSHuang Rui 		dwc3_pdata.del_phy_power_chg_quirk = true;
1609755449dSHuang Rui 		dwc3_pdata.lfps_filter_quirk = true;
1619755449dSHuang Rui 		dwc3_pdata.rx_detect_poll_quirk = true;
1629755449dSHuang Rui 
1639755449dSHuang Rui 		dwc3_pdata.tx_de_emphasis_quirk = true;
1649755449dSHuang Rui 		dwc3_pdata.tx_de_emphasis = 1;
1659755449dSHuang Rui 
1669755449dSHuang Rui 		/*
1679755449dSHuang Rui 		 * FIXME these quirks should be removed when AMD NL
1689755449dSHuang Rui 		 * taps out
1699755449dSHuang Rui 		 */
1709755449dSHuang Rui 		dwc3_pdata.disable_scramble_quirk = true;
1719755449dSHuang Rui 		dwc3_pdata.dis_u3_susphy_quirk = true;
1729755449dSHuang Rui 		dwc3_pdata.dis_u2_susphy_quirk = true;
1739755449dSHuang Rui 	}
1749755449dSHuang Rui 
17572246da4SFelipe Balbi 	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
17672246da4SFelipe Balbi 	if (ret) {
177802ca850SChanho Park 		dev_err(dev, "couldn't add resources to dwc3 device\n");
178f1c7e710SAndy Shevchenko 		return ret;
17972246da4SFelipe Balbi 	}
18072246da4SFelipe Balbi 
18172246da4SFelipe Balbi 	pci_set_drvdata(pci, glue);
18272246da4SFelipe Balbi 
1838f317b47SHuang Rui 	ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
1848f317b47SHuang Rui 	if (ret)
1858f317b47SHuang Rui 		goto err3;
1868f317b47SHuang Rui 
187802ca850SChanho Park 	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
18872246da4SFelipe Balbi 
189802ca850SChanho Park 	dwc3->dev.dma_mask = dev->dma_mask;
190802ca850SChanho Park 	dwc3->dev.dma_parms = dev->dma_parms;
191802ca850SChanho Park 	dwc3->dev.parent = dev;
19272246da4SFelipe Balbi 	glue->dwc3 = dwc3;
19372246da4SFelipe Balbi 
19472246da4SFelipe Balbi 	ret = platform_device_add(dwc3);
19572246da4SFelipe Balbi 	if (ret) {
196802ca850SChanho Park 		dev_err(dev, "failed to register dwc3 device\n");
197802ca850SChanho Park 		goto err3;
19872246da4SFelipe Balbi 	}
19972246da4SFelipe Balbi 
20072246da4SFelipe Balbi 	return 0;
20172246da4SFelipe Balbi 
202802ca850SChanho Park err3:
20372246da4SFelipe Balbi 	platform_device_put(dwc3);
20472246da4SFelipe Balbi 	return ret;
20572246da4SFelipe Balbi }
20672246da4SFelipe Balbi 
207fb4e98abSBill Pemberton static void dwc3_pci_remove(struct pci_dev *pci)
20872246da4SFelipe Balbi {
20972246da4SFelipe Balbi 	struct dwc3_pci	*glue = pci_get_drvdata(pci);
21072246da4SFelipe Balbi 
211f28c42c5SPeter Chen 	platform_device_unregister(glue->dwc3);
212e3ec3eb7SFelipe Balbi 	platform_device_unregister(glue->usb2_phy);
213e3ec3eb7SFelipe Balbi 	platform_device_unregister(glue->usb3_phy);
21472246da4SFelipe Balbi }
21572246da4SFelipe Balbi 
216782df20cSJingoo Han static const struct pci_device_id dwc3_pci_id_table[] = {
21772246da4SFelipe Balbi 	{
21872246da4SFelipe Balbi 		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
21972246da4SFelipe Balbi 				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
22072246da4SFelipe Balbi 	},
2217d643664SAlan Cox 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
222b62cd96dSHeikki Krogerus 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
22385601f8cSDavid Cohen 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
224*84a2b61bSHeikki Krogerus 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
225*84a2b61bSHeikki Krogerus 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
2269755449dSHuang Rui 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
22772246da4SFelipe Balbi 	{  }	/* Terminating Entry */
22872246da4SFelipe Balbi };
22972246da4SFelipe Balbi MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
23072246da4SFelipe Balbi 
231fb74d282SJingoo Han #ifdef CONFIG_PM_SLEEP
23268907a77SFelipe Balbi static int dwc3_pci_suspend(struct device *dev)
23368907a77SFelipe Balbi {
23468907a77SFelipe Balbi 	struct pci_dev	*pci = to_pci_dev(dev);
23568907a77SFelipe Balbi 
23668907a77SFelipe Balbi 	pci_disable_device(pci);
23768907a77SFelipe Balbi 
23868907a77SFelipe Balbi 	return 0;
23968907a77SFelipe Balbi }
24068907a77SFelipe Balbi 
24168907a77SFelipe Balbi static int dwc3_pci_resume(struct device *dev)
24268907a77SFelipe Balbi {
24368907a77SFelipe Balbi 	struct pci_dev	*pci = to_pci_dev(dev);
24468907a77SFelipe Balbi 	int		ret;
24568907a77SFelipe Balbi 
24668907a77SFelipe Balbi 	ret = pci_enable_device(pci);
24768907a77SFelipe Balbi 	if (ret) {
24868907a77SFelipe Balbi 		dev_err(dev, "can't re-enable device --> %d\n", ret);
24968907a77SFelipe Balbi 		return ret;
25068907a77SFelipe Balbi 	}
25168907a77SFelipe Balbi 
25268907a77SFelipe Balbi 	pci_set_master(pci);
25368907a77SFelipe Balbi 
25468907a77SFelipe Balbi 	return 0;
25568907a77SFelipe Balbi }
256fb74d282SJingoo Han #endif /* CONFIG_PM_SLEEP */
25768907a77SFelipe Balbi 
25868907a77SFelipe Balbi static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
25968907a77SFelipe Balbi 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
26068907a77SFelipe Balbi };
26168907a77SFelipe Balbi 
26272246da4SFelipe Balbi static struct pci_driver dwc3_pci_driver = {
2630949e99bSFelipe Balbi 	.name		= "dwc3-pci",
26472246da4SFelipe Balbi 	.id_table	= dwc3_pci_id_table,
26572246da4SFelipe Balbi 	.probe		= dwc3_pci_probe,
2667690417dSBill Pemberton 	.remove		= dwc3_pci_remove,
26768907a77SFelipe Balbi 	.driver		= {
268fb74d282SJingoo Han 		.pm	= &dwc3_pci_dev_pm_ops,
26968907a77SFelipe Balbi 	},
27072246da4SFelipe Balbi };
27172246da4SFelipe Balbi 
27272246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
2735945f789SFelipe Balbi MODULE_LICENSE("GPL v2");
27472246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
27572246da4SFelipe Balbi 
27695656336SGreg Kroah-Hartman module_pci_driver(dwc3_pci_driver);
277