dwc3-pci.c 5.2 KB
Newer Older
1 2 3 4 5 6 7 8
/**
 * dwc3-pci.c - PCI Specific glue layer
 *
 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
 *
 * Authors: Felipe Balbi <balbi@ti.com>,
 *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
 *
F
Felipe Balbi 已提交
9 10 11
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2  of
 * the License as published by the Free Software Foundation.
12
 *
F
Felipe Balbi 已提交
13 14 15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
17 18 19
 */

#include <linux/kernel.h>
20
#include <linux/module.h>
21 22 23 24
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/platform_device.h>

25 26 27
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>

28 29 30 31 32 33 34
/* FIXME define these in <linux/pci_ids.h> */
#define PCI_VENDOR_ID_SYNOPSYS		0x16c3
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd

struct dwc3_pci {
	struct device		*dev;
	struct platform_device	*dwc3;
35 36
	struct platform_device	*usb2_phy;
	struct platform_device	*usb3_phy;
37 38
};

B
Bill Pemberton 已提交
39
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
{
	struct nop_usb_xceiv_platform_data pdata;
	struct platform_device	*pdev;
	int			ret;

	memset(&pdata, 0x00, sizeof(pdata));

	pdev = platform_device_alloc("nop_usb_xceiv", 0);
	if (!pdev)
		return -ENOMEM;

	glue->usb2_phy = pdev;
	pdata.type = USB_PHY_TYPE_USB2;

	ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
	if (ret)
		goto err1;

	pdev = platform_device_alloc("nop_usb_xceiv", 1);
	if (!pdev) {
		ret = -ENOMEM;
		goto err1;
	}

	glue->usb3_phy = pdev;
	pdata.type = USB_PHY_TYPE_USB3;

	ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
	if (ret)
		goto err2;

	ret = platform_device_add(glue->usb2_phy);
	if (ret)
		goto err2;

	ret = platform_device_add(glue->usb3_phy);
	if (ret)
		goto err3;

	return 0;

err3:
	platform_device_del(glue->usb2_phy);

err2:
	platform_device_put(glue->usb3_phy);

err1:
	platform_device_put(glue->usb2_phy);

	return ret;
}

B
Bill Pemberton 已提交
93
static int dwc3_pci_probe(struct pci_dev *pci,
94 95 96 97 98 99
		const struct pci_device_id *id)
{
	struct resource		res[2];
	struct platform_device	*dwc3;
	struct dwc3_pci		*glue;
	int			ret = -ENOMEM;
C
Chanho Park 已提交
100
	struct device		*dev = &pci->dev;
101

C
Chanho Park 已提交
102
	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
103
	if (!glue) {
C
Chanho Park 已提交
104 105
		dev_err(dev, "not enough memory\n");
		return -ENOMEM;
106 107
	}

108
	glue->dev = dev;
109 110 111

	ret = pci_enable_device(pci);
	if (ret) {
C
Chanho Park 已提交
112 113
		dev_err(dev, "failed to enable pci device\n");
		return -ENODEV;
114 115 116 117
	}

	pci_set_master(pci);

118 119 120 121 122 123
	ret = dwc3_pci_register_phys(glue);
	if (ret) {
		dev_err(dev, "couldn't register PHYs\n");
		return ret;
	}

124
	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
125
	if (!dwc3) {
C
Chanho Park 已提交
126
		dev_err(dev, "couldn't allocate dwc3 device\n");
127
		ret = -ENOMEM;
C
Chanho Park 已提交
128
		goto err1;
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
	}

	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));

	res[0].start	= pci_resource_start(pci, 0);
	res[0].end	= pci_resource_end(pci, 0);
	res[0].name	= "dwc_usb3";
	res[0].flags	= IORESOURCE_MEM;

	res[1].start	= pci->irq;
	res[1].name	= "dwc_usb3";
	res[1].flags	= IORESOURCE_IRQ;

	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
	if (ret) {
C
Chanho Park 已提交
144
		dev_err(dev, "couldn't add resources to dwc3 device\n");
145
		goto err1;
146 147 148 149
	}

	pci_set_drvdata(pci, glue);

C
Chanho Park 已提交
150
	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
151

C
Chanho Park 已提交
152 153 154
	dwc3->dev.dma_mask = dev->dma_mask;
	dwc3->dev.dma_parms = dev->dma_parms;
	dwc3->dev.parent = dev;
155
	glue->dwc3 = dwc3;
156 157 158

	ret = platform_device_add(dwc3);
	if (ret) {
C
Chanho Park 已提交
159 160
		dev_err(dev, "failed to register dwc3 device\n");
		goto err3;
161 162 163 164
	}

	return 0;

C
Chanho Park 已提交
165
err3:
166 167 168
	pci_set_drvdata(pci, NULL);
	platform_device_put(dwc3);
err1:
C
Chanho Park 已提交
169
	pci_disable_device(pci);
170 171 172 173

	return ret;
}

B
Bill Pemberton 已提交
174
static void dwc3_pci_remove(struct pci_dev *pci)
175 176 177
{
	struct dwc3_pci	*glue = pci_get_drvdata(pci);

178
	platform_device_unregister(glue->dwc3);
179 180
	platform_device_unregister(glue->usb2_phy);
	platform_device_unregister(glue->usb3_phy);
181 182 183 184 185 186 187 188 189 190 191 192 193
	pci_set_drvdata(pci, NULL);
	pci_disable_device(pci);
}

static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
	{
		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
	},
	{  }	/* Terminating Entry */
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
#ifdef CONFIG_PM
static int dwc3_pci_suspend(struct device *dev)
{
	struct pci_dev	*pci = to_pci_dev(dev);

	pci_disable_device(pci);

	return 0;
}

static int dwc3_pci_resume(struct device *dev)
{
	struct pci_dev	*pci = to_pci_dev(dev);
	int		ret;

	ret = pci_enable_device(pci);
	if (ret) {
		dev_err(dev, "can't re-enable device --> %d\n", ret);
		return ret;
	}

	pci_set_master(pci);

	return 0;
}

static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
};

#define DEV_PM_OPS	(&dwc3_pci_dev_pm_ops)
#else
#define DEV_PM_OPS	NULL
#endif /* CONFIG_PM */

229
static struct pci_driver dwc3_pci_driver = {
230
	.name		= "dwc3-pci",
231 232
	.id_table	= dwc3_pci_id_table,
	.probe		= dwc3_pci_probe,
B
Bill Pemberton 已提交
233
	.remove		= dwc3_pci_remove,
234 235 236
	.driver		= {
		.pm	= DEV_PM_OPS,
	},
237 238 239
};

MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
F
Felipe Balbi 已提交
240
MODULE_LICENSE("GPL v2");
241 242
MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");

G
Greg Kroah-Hartman 已提交
243
module_pci_driver(dwc3_pci_driver);