xref: /linux/drivers/usb/dwc3/dwc3-pci.c (revision 124dafde8f8174caf5cef1c3eaba001657d66f4f)
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  *
972246da4SFelipe Balbi  * Redistribution and use in source and binary forms, with or without
1072246da4SFelipe Balbi  * modification, are permitted provided that the following conditions
1172246da4SFelipe Balbi  * are met:
1272246da4SFelipe Balbi  * 1. Redistributions of source code must retain the above copyright
1372246da4SFelipe Balbi  *    notice, this list of conditions, and the following disclaimer,
1472246da4SFelipe Balbi  *    without modification.
1572246da4SFelipe Balbi  * 2. Redistributions in binary form must reproduce the above copyright
1672246da4SFelipe Balbi  *    notice, this list of conditions and the following disclaimer in the
1772246da4SFelipe Balbi  *    documentation and/or other materials provided with the distribution.
1872246da4SFelipe Balbi  * 3. The names of the above-listed copyright holders may not be used
1972246da4SFelipe Balbi  *    to endorse or promote products derived from this software without
2072246da4SFelipe Balbi  *    specific prior written permission.
2172246da4SFelipe Balbi  *
2272246da4SFelipe Balbi  * ALTERNATIVELY, this software may be distributed under the terms of the
2372246da4SFelipe Balbi  * GNU General Public License ("GPL") version 2, as published by the Free
2472246da4SFelipe Balbi  * Software Foundation.
2572246da4SFelipe Balbi  *
2672246da4SFelipe Balbi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
2772246da4SFelipe Balbi  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2872246da4SFelipe Balbi  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2972246da4SFelipe Balbi  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
3072246da4SFelipe Balbi  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
3172246da4SFelipe Balbi  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3272246da4SFelipe Balbi  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3372246da4SFelipe Balbi  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3472246da4SFelipe Balbi  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3572246da4SFelipe Balbi  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3672246da4SFelipe Balbi  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3772246da4SFelipe Balbi  */
3872246da4SFelipe Balbi 
3972246da4SFelipe Balbi #include <linux/kernel.h>
4046a57283SStephen Rothwell #include <linux/module.h>
4172246da4SFelipe Balbi #include <linux/slab.h>
4272246da4SFelipe Balbi #include <linux/pci.h>
4372246da4SFelipe Balbi #include <linux/platform_device.h>
4472246da4SFelipe Balbi 
45e3ec3eb7SFelipe Balbi #include <linux/usb/otg.h>
46e3ec3eb7SFelipe Balbi #include <linux/usb/nop-usb-xceiv.h>
47e3ec3eb7SFelipe Balbi 
488300dd23SFelipe Balbi #include "core.h"
498300dd23SFelipe Balbi 
5072246da4SFelipe Balbi /* FIXME define these in <linux/pci_ids.h> */
5172246da4SFelipe Balbi #define PCI_VENDOR_ID_SYNOPSYS		0x16c3
5272246da4SFelipe Balbi #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd
5372246da4SFelipe Balbi 
5472246da4SFelipe Balbi struct dwc3_pci {
5572246da4SFelipe Balbi 	struct device		*dev;
5672246da4SFelipe Balbi 	struct platform_device	*dwc3;
57e3ec3eb7SFelipe Balbi 	struct platform_device	*usb2_phy;
58e3ec3eb7SFelipe Balbi 	struct platform_device	*usb3_phy;
5972246da4SFelipe Balbi };
6072246da4SFelipe Balbi 
61e3ec3eb7SFelipe Balbi static int __devinit dwc3_pci_register_phys(struct dwc3_pci *glue)
62e3ec3eb7SFelipe Balbi {
63e3ec3eb7SFelipe Balbi 	struct nop_usb_xceiv_platform_data pdata;
64e3ec3eb7SFelipe Balbi 	struct platform_device	*pdev;
65e3ec3eb7SFelipe Balbi 	int			ret;
66e3ec3eb7SFelipe Balbi 
67e3ec3eb7SFelipe Balbi 	memset(&pdata, 0x00, sizeof(pdata));
68e3ec3eb7SFelipe Balbi 
69e3ec3eb7SFelipe Balbi 	pdev = platform_device_alloc("nop_usb_xceiv", 0);
70e3ec3eb7SFelipe Balbi 	if (!pdev)
71e3ec3eb7SFelipe Balbi 		return -ENOMEM;
72e3ec3eb7SFelipe Balbi 
73e3ec3eb7SFelipe Balbi 	glue->usb2_phy = pdev;
74e3ec3eb7SFelipe Balbi 	pdata.type = USB_PHY_TYPE_USB2;
75e3ec3eb7SFelipe Balbi 
76e3ec3eb7SFelipe Balbi 	ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
77e3ec3eb7SFelipe Balbi 	if (ret)
78e3ec3eb7SFelipe Balbi 		goto err1;
79e3ec3eb7SFelipe Balbi 
80e3ec3eb7SFelipe Balbi 	pdev = platform_device_alloc("nop_usb_xceiv", 1);
81e3ec3eb7SFelipe Balbi 	if (!pdev) {
82e3ec3eb7SFelipe Balbi 		ret = -ENOMEM;
83e3ec3eb7SFelipe Balbi 		goto err1;
84e3ec3eb7SFelipe Balbi 	}
85e3ec3eb7SFelipe Balbi 
86e3ec3eb7SFelipe Balbi 	glue->usb3_phy = pdev;
87e3ec3eb7SFelipe Balbi 	pdata.type = USB_PHY_TYPE_USB3;
88e3ec3eb7SFelipe Balbi 
89e3ec3eb7SFelipe Balbi 	ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
90e3ec3eb7SFelipe Balbi 	if (ret)
91e3ec3eb7SFelipe Balbi 		goto err2;
92e3ec3eb7SFelipe Balbi 
93e3ec3eb7SFelipe Balbi 	ret = platform_device_add(glue->usb2_phy);
94e3ec3eb7SFelipe Balbi 	if (ret)
95e3ec3eb7SFelipe Balbi 		goto err2;
96e3ec3eb7SFelipe Balbi 
97e3ec3eb7SFelipe Balbi 	ret = platform_device_add(glue->usb3_phy);
98e3ec3eb7SFelipe Balbi 	if (ret)
99e3ec3eb7SFelipe Balbi 		goto err3;
100e3ec3eb7SFelipe Balbi 
101e3ec3eb7SFelipe Balbi 	return 0;
102e3ec3eb7SFelipe Balbi 
103e3ec3eb7SFelipe Balbi err3:
104e3ec3eb7SFelipe Balbi 	platform_device_del(glue->usb2_phy);
105e3ec3eb7SFelipe Balbi 
106e3ec3eb7SFelipe Balbi err2:
107e3ec3eb7SFelipe Balbi 	platform_device_put(glue->usb3_phy);
108e3ec3eb7SFelipe Balbi 
109e3ec3eb7SFelipe Balbi err1:
110e3ec3eb7SFelipe Balbi 	platform_device_put(glue->usb2_phy);
111e3ec3eb7SFelipe Balbi 
112e3ec3eb7SFelipe Balbi 	return ret;
113e3ec3eb7SFelipe Balbi }
114e3ec3eb7SFelipe Balbi 
11572246da4SFelipe Balbi static int __devinit dwc3_pci_probe(struct pci_dev *pci,
11672246da4SFelipe Balbi 		const struct pci_device_id *id)
11772246da4SFelipe Balbi {
11872246da4SFelipe Balbi 	struct resource		res[2];
11972246da4SFelipe Balbi 	struct platform_device	*dwc3;
12072246da4SFelipe Balbi 	struct dwc3_pci		*glue;
12172246da4SFelipe Balbi 	int			ret = -ENOMEM;
122802ca850SChanho Park 	struct device		*dev = &pci->dev;
12372246da4SFelipe Balbi 
124802ca850SChanho Park 	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
12572246da4SFelipe Balbi 	if (!glue) {
126802ca850SChanho Park 		dev_err(dev, "not enough memory\n");
127802ca850SChanho Park 		return -ENOMEM;
12872246da4SFelipe Balbi 	}
12972246da4SFelipe Balbi 
130802ca850SChanho Park 	glue->dev = dev;
13172246da4SFelipe Balbi 
13272246da4SFelipe Balbi 	ret = pci_enable_device(pci);
13372246da4SFelipe Balbi 	if (ret) {
134802ca850SChanho Park 		dev_err(dev, "failed to enable pci device\n");
135802ca850SChanho Park 		return -ENODEV;
13672246da4SFelipe Balbi 	}
13772246da4SFelipe Balbi 
13872246da4SFelipe Balbi 	pci_set_power_state(pci, PCI_D0);
13972246da4SFelipe Balbi 	pci_set_master(pci);
14072246da4SFelipe Balbi 
141e3ec3eb7SFelipe Balbi 	ret = dwc3_pci_register_phys(glue);
142e3ec3eb7SFelipe Balbi 	if (ret) {
143e3ec3eb7SFelipe Balbi 		dev_err(dev, "couldn't register PHYs\n");
144e3ec3eb7SFelipe Balbi 		return ret;
145e3ec3eb7SFelipe Balbi 	}
146e3ec3eb7SFelipe Balbi 
147*124dafdeSSebastian Andrzej Siewior 	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
14872246da4SFelipe Balbi 	if (!dwc3) {
149802ca850SChanho Park 		dev_err(dev, "couldn't allocate dwc3 device\n");
15028f1a0d9SFelipe Balbi 		ret = -ENOMEM;
151802ca850SChanho Park 		goto err1;
15272246da4SFelipe Balbi 	}
15372246da4SFelipe Balbi 
15472246da4SFelipe Balbi 	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
15572246da4SFelipe Balbi 
15672246da4SFelipe Balbi 	res[0].start	= pci_resource_start(pci, 0);
15772246da4SFelipe Balbi 	res[0].end	= pci_resource_end(pci, 0);
15872246da4SFelipe Balbi 	res[0].name	= "dwc_usb3";
15972246da4SFelipe Balbi 	res[0].flags	= IORESOURCE_MEM;
16072246da4SFelipe Balbi 
16172246da4SFelipe Balbi 	res[1].start	= pci->irq;
16272246da4SFelipe Balbi 	res[1].name	= "dwc_usb3";
16372246da4SFelipe Balbi 	res[1].flags	= IORESOURCE_IRQ;
16472246da4SFelipe Balbi 
16572246da4SFelipe Balbi 	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
16672246da4SFelipe Balbi 	if (ret) {
167802ca850SChanho Park 		dev_err(dev, "couldn't add resources to dwc3 device\n");
168*124dafdeSSebastian Andrzej Siewior 		goto err1;
16972246da4SFelipe Balbi 	}
17072246da4SFelipe Balbi 
17172246da4SFelipe Balbi 	pci_set_drvdata(pci, glue);
17272246da4SFelipe Balbi 
173802ca850SChanho Park 	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
17472246da4SFelipe Balbi 
175802ca850SChanho Park 	dwc3->dev.dma_mask = dev->dma_mask;
176802ca850SChanho Park 	dwc3->dev.dma_parms = dev->dma_parms;
177802ca850SChanho Park 	dwc3->dev.parent = dev;
17872246da4SFelipe Balbi 	glue->dwc3 = dwc3;
17972246da4SFelipe Balbi 
18072246da4SFelipe Balbi 	ret = platform_device_add(dwc3);
18172246da4SFelipe Balbi 	if (ret) {
182802ca850SChanho Park 		dev_err(dev, "failed to register dwc3 device\n");
183802ca850SChanho Park 		goto err3;
18472246da4SFelipe Balbi 	}
18572246da4SFelipe Balbi 
18672246da4SFelipe Balbi 	return 0;
18772246da4SFelipe Balbi 
188802ca850SChanho Park err3:
18972246da4SFelipe Balbi 	pci_set_drvdata(pci, NULL);
19072246da4SFelipe Balbi 	platform_device_put(dwc3);
191802ca850SChanho Park err1:
19272246da4SFelipe Balbi 	pci_disable_device(pci);
19372246da4SFelipe Balbi 
19472246da4SFelipe Balbi 	return ret;
19572246da4SFelipe Balbi }
19672246da4SFelipe Balbi 
19772246da4SFelipe Balbi static void __devexit dwc3_pci_remove(struct pci_dev *pci)
19872246da4SFelipe Balbi {
19972246da4SFelipe Balbi 	struct dwc3_pci	*glue = pci_get_drvdata(pci);
20072246da4SFelipe Balbi 
201e3ec3eb7SFelipe Balbi 	platform_device_unregister(glue->usb2_phy);
202e3ec3eb7SFelipe Balbi 	platform_device_unregister(glue->usb3_phy);
20372246da4SFelipe Balbi 	platform_device_unregister(glue->dwc3);
20472246da4SFelipe Balbi 	pci_set_drvdata(pci, NULL);
20572246da4SFelipe Balbi 	pci_disable_device(pci);
20672246da4SFelipe Balbi }
20772246da4SFelipe Balbi 
20872246da4SFelipe Balbi static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
20972246da4SFelipe Balbi 	{
21072246da4SFelipe Balbi 		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
21172246da4SFelipe Balbi 				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
21272246da4SFelipe Balbi 	},
21372246da4SFelipe Balbi 	{  }	/* Terminating Entry */
21472246da4SFelipe Balbi };
21572246da4SFelipe Balbi MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
21672246da4SFelipe Balbi 
21772246da4SFelipe Balbi static struct pci_driver dwc3_pci_driver = {
2180949e99bSFelipe Balbi 	.name		= "dwc3-pci",
21972246da4SFelipe Balbi 	.id_table	= dwc3_pci_id_table,
22072246da4SFelipe Balbi 	.probe		= dwc3_pci_probe,
22172246da4SFelipe Balbi 	.remove		= __devexit_p(dwc3_pci_remove),
22272246da4SFelipe Balbi };
22372246da4SFelipe Balbi 
22472246da4SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
22572246da4SFelipe Balbi MODULE_LICENSE("Dual BSD/GPL");
22672246da4SFelipe Balbi MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
22772246da4SFelipe Balbi 
22895656336SGreg Kroah-Hartman module_pci_driver(dwc3_pci_driver);
229