dwc3-pci.c 6.4 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
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
24 25
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
26

27 28
#include "platform_data.h"

J
John Youn 已提交
29 30 31 32 33 34 35 36
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3		0xabcd
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI	0xabce
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31	0xabcf
#define PCI_DEVICE_ID_INTEL_BYT			0x0f37
#define PCI_DEVICE_ID_INTEL_MRFLD		0x119e
#define PCI_DEVICE_ID_INTEL_BSW			0x22b7
#define PCI_DEVICE_ID_INTEL_SPTLP		0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH		0xa130
37
#define PCI_DEVICE_ID_INTEL_BXT			0x0aaa
38
#define PCI_DEVICE_ID_INTEL_BXT_M		0x1aaa
39
#define PCI_DEVICE_ID_INTEL_APL			0x5aaa
40

41 42 43 44 45 46 47 48 49
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
static const struct acpi_gpio_params cs_gpios = { 1, 0, false };

static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
	{ "reset-gpios", &reset_gpios, 1 },
	{ "cs-gpios", &cs_gpios, 1 },
	{ },
};

H
Heikki Krogerus 已提交
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
static int dwc3_pci_quirks(struct pci_dev *pdev)
{
	if (pdev->vendor == PCI_VENDOR_ID_AMD &&
	    pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
		struct dwc3_platform_data pdata;

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

		pdata.has_lpm_erratum = true;
		pdata.lpm_nyet_threshold = 0xf;

		pdata.u2exit_lfps_quirk = true;
		pdata.u2ss_inp3_quirk = true;
		pdata.req_p1p2p3_quirk = true;
		pdata.del_p1p2p3_quirk = true;
		pdata.del_phy_power_chg_quirk = true;
		pdata.lfps_filter_quirk = true;
		pdata.rx_detect_poll_quirk = true;

		pdata.tx_de_emphasis_quirk = true;
		pdata.tx_de_emphasis = 1;

		/*
		 * FIXME these quirks should be removed when AMD NL
		 * taps out
		 */
		pdata.disable_scramble_quirk = true;
		pdata.dis_u3_susphy_quirk = true;
		pdata.dis_u2_susphy_quirk = true;

		return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
						sizeof(pdata));
	}

84 85 86 87 88 89 90
	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
	    pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
		struct gpio_desc *gpio;

		acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
					  acpi_dwc3_byt_gpios);

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
		/*
		 * These GPIOs will turn on the USB2 PHY. Note that we have to
		 * put the gpio descriptors again here because the phy driver
		 * might want to grab them, too.
		 */
		gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
		if (IS_ERR(gpio))
			return PTR_ERR(gpio);

		gpiod_set_value_cansleep(gpio, 1);
		gpiod_put(gpio);

		gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
		if (IS_ERR(gpio))
			return PTR_ERR(gpio);
106

107
		if (gpio) {
108 109 110 111 112 113
			gpiod_set_value_cansleep(gpio, 1);
			gpiod_put(gpio);
			usleep_range(10000, 11000);
		}
	}

114 115 116 117 118 119 120 121 122 123
	if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS &&
	    (pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
	     pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
	     pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {

		struct dwc3_platform_data pdata;

		memset(&pdata, 0, sizeof(pdata));
		pdata.usb3_lpm_capable = true;
		pdata.has_lpm_erratum = true;
124
		pdata.dis_enblslpm_quirk = true;
125 126 127 128 129

		return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
						sizeof(pdata));
	}

H
Heikki Krogerus 已提交
130 131
	return 0;
}
132

B
Bill Pemberton 已提交
133
static int dwc3_pci_probe(struct pci_dev *pci,
134 135 136 137
		const struct pci_device_id *id)
{
	struct resource		res[2];
	struct platform_device	*dwc3;
138
	int			ret;
C
Chanho Park 已提交
139
	struct device		*dev = &pci->dev;
140

141
	ret = pcim_enable_device(pci);
142
	if (ret) {
C
Chanho Park 已提交
143 144
		dev_err(dev, "failed to enable pci device\n");
		return -ENODEV;
145 146 147 148
	}

	pci_set_master(pci);

149
	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
150
	if (!dwc3) {
C
Chanho Park 已提交
151
		dev_err(dev, "couldn't allocate dwc3 device\n");
152
		return -ENOMEM;
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
	}

	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 已提交
168
		dev_err(dev, "couldn't add resources to dwc3 device\n");
169
		return ret;
170 171
	}

H
Heikki Krogerus 已提交
172 173
	pci_set_drvdata(pci, dwc3);
	ret = dwc3_pci_quirks(pci);
174
	if (ret)
H
Heikki Krogerus 已提交
175
		goto err;
176

C
Chanho Park 已提交
177
	dwc3->dev.parent = dev;
178
	ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev));
179 180 181

	ret = platform_device_add(dwc3);
	if (ret) {
C
Chanho Park 已提交
182
		dev_err(dev, "failed to register dwc3 device\n");
H
Heikki Krogerus 已提交
183
		goto err;
184 185 186
	}

	return 0;
H
Heikki Krogerus 已提交
187
err:
188 189 190 191
	platform_device_put(dwc3);
	return ret;
}

B
Bill Pemberton 已提交
192
static void dwc3_pci_remove(struct pci_dev *pci)
193
{
194
	acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pci->dev));
H
Heikki Krogerus 已提交
195
	platform_device_unregister(pci_get_drvdata(pci));
196 197
}

198
static const struct pci_device_id dwc3_pci_id_table[] = {
199 200 201 202
	{
		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
	},
203 204 205 206
	{
		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
	},
207 208 209 210
	{
		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
	},
211
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
212
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
213
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
214 215
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
216
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
217
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
218
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
219
	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
220 221 222 223 224
	{  }	/* Terminating Entry */
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);

static struct pci_driver dwc3_pci_driver = {
225
	.name		= "dwc3-pci",
226 227
	.id_table	= dwc3_pci_id_table,
	.probe		= dwc3_pci_probe,
B
Bill Pemberton 已提交
228
	.remove		= dwc3_pci_remove,
229 230 231
};

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

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