]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - drivers/usb/dwc3/dwc3-pci.c
usb: dwc3: pci: Add GPIO lookup table on platforms without ACPI GPIO resources
[thirdparty/kernel/stable.git] / drivers / usb / dwc3 / dwc3-pci.c
CommitLineData
5fd54ace 1// SPDX-License-Identifier: GPL-2.0
72246da4
FB
2/**
3 * dwc3-pci.c - PCI Specific glue layer
4 *
5 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
72246da4
FB
6 *
7 * Authors: Felipe Balbi <balbi@ti.com>,
8 * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
72246da4
FB
9 */
10
11#include <linux/kernel.h>
46a57283 12#include <linux/module.h>
72246da4
FB
13#include <linux/slab.h>
14#include <linux/pci.h>
8eed00b2 15#include <linux/workqueue.h>
e9af9229 16#include <linux/pm_runtime.h>
72246da4 17#include <linux/platform_device.h>
a89d977c 18#include <linux/gpio/consumer.h>
5741022c 19#include <linux/gpio/machine.h>
a89d977c 20#include <linux/acpi.h>
cf48305d 21#include <linux/delay.h>
8f317b47 22
9a5a0783
JY
23#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
24#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
25#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
26#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
27#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
b4c580a4 28#define PCI_DEVICE_ID_INTEL_BXT 0x0aaa
1ffb4d5c 29#define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa
b4c580a4 30#define PCI_DEVICE_ID_INTEL_APL 0x5aaa
4491ed50 31#define PCI_DEVICE_ID_INTEL_KBP 0xa2b0
8f8983a5 32#define PCI_DEVICE_ID_INTEL_GLK 0x31aa
68217959
HK
33#define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee
34#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
00908693 35#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee
72246da4 36
94116f81 37#define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
9cecca75
FB
38#define PCI_INTEL_BXT_FUNC_PMU_PWR 4
39#define PCI_INTEL_BXT_STATE_D0 0
40#define PCI_INTEL_BXT_STATE_D3 3
41
0f817ae6
FB
42/**
43 * struct dwc3_pci - Driver private structure
44 * @dwc3: child dwc3 platform_device
45 * @pci: our link to PCI bus
94116f81 46 * @guid: _DSM GUID
9cecca75 47 * @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
0f817ae6
FB
48 */
49struct dwc3_pci {
50 struct platform_device *dwc3;
51 struct pci_dev *pci;
9cecca75 52
94116f81 53 guid_t guid;
9cecca75
FB
54
55 unsigned int has_dsm_for_pm:1;
8eed00b2 56 struct work_struct wakeup_work;
0f817ae6
FB
57};
58
a89d977c
HK
59static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
60static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
61
62static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
63 { "reset-gpios", &reset_gpios, 1 },
64 { "cs-gpios", &cs_gpios, 1 },
65 { },
66};
67
5741022c
HG
68static struct gpiod_lookup_table platform_bytcr_gpios = {
69 .dev_id = "0000:00:16.0",
70 .table = {
71 GPIO_LOOKUP("INT33FC:00", 54, "reset", GPIO_ACTIVE_HIGH),
72 GPIO_LOOKUP("INT33FC:02", 14, "cs", GPIO_ACTIVE_HIGH),
73 {}
74 },
75};
76
0f817ae6 77static int dwc3_pci_quirks(struct dwc3_pci *dwc)
2cd9ddf7 78{
0f817ae6
FB
79 struct platform_device *dwc3 = dwc->dwc3;
80 struct pci_dev *pdev = dwc->pci;
81
2cd9ddf7
HK
82 if (pdev->vendor == PCI_VENDOR_ID_AMD &&
83 pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
cf48305d
HK
84 struct property_entry properties[] = {
85 PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
86 PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
87 PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
88 PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
89 PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
90 PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
91 PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
92 PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
93 PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
94 PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
95 PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
96 /*
97 * FIXME these quirks should be removed when AMD NL
98 * tapes out
99 */
100 PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
101 PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
102 PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
0eae2fde 103 PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
cf48305d
HK
104 { },
105 };
106
107 return platform_device_add_properties(dwc3, properties);
2cd9ddf7
HK
108 }
109
e6fe66fe
FB
110 if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
111 int ret;
112
113 struct property_entry properties[] = {
51c1685d 114 PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
0eae2fde 115 PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
e6fe66fe
FB
116 { }
117 };
118
119 ret = platform_device_add_properties(dwc3, properties);
120 if (ret < 0)
121 return ret;
122
9cecca75
FB
123 if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
124 pdev->device == PCI_DEVICE_ID_INTEL_BXT_M) {
94116f81 125 guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
9cecca75
FB
126 dwc->has_dsm_for_pm = true;
127 }
128
e6fe66fe
FB
129 if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
130 struct gpio_desc *gpio;
131
4a56e413 132 ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
e6fe66fe 133 acpi_dwc3_byt_gpios);
4a56e413
AS
134 if (ret)
135 dev_dbg(&pdev->dev, "failed to add mapping table\n");
e6fe66fe 136
5741022c
HG
137 /*
138 * A lot of BYT devices lack ACPI resource entries for
139 * the GPIOs, add a fallback mapping to the reference
140 * design GPIOs which all boards seem to use.
141 */
142 gpiod_add_lookup_table(&platform_bytcr_gpios);
143
e6fe66fe
FB
144 /*
145 * These GPIOs will turn on the USB2 PHY. Note that we have to
146 * put the gpio descriptors again here because the phy driver
147 * might want to grab them, too.
148 */
149 gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
150 if (IS_ERR(gpio))
151 return PTR_ERR(gpio);
152
a89d977c
HK
153 gpiod_set_value_cansleep(gpio, 1);
154 gpiod_put(gpio);
e6fe66fe
FB
155
156 gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
157 if (IS_ERR(gpio))
158 return PTR_ERR(gpio);
159
160 if (gpio) {
161 gpiod_set_value_cansleep(gpio, 1);
162 gpiod_put(gpio);
163 usleep_range(10000, 11000);
164 }
a89d977c
HK
165 }
166 }
167
2cd9ddf7
HK
168 return 0;
169}
72246da4 170
8eed00b2
MG
171#ifdef CONFIG_PM
172static void dwc3_pci_resume_work(struct work_struct *work)
173{
174 struct dwc3_pci *dwc = container_of(work, struct dwc3_pci, wakeup_work);
175 struct platform_device *dwc3 = dwc->dwc3;
176 int ret;
177
178 ret = pm_runtime_get_sync(&dwc3->dev);
179 if (ret)
180 return;
181
182 pm_runtime_mark_last_busy(&dwc3->dev);
183 pm_runtime_put_sync_autosuspend(&dwc3->dev);
184}
185#endif
186
41ac7b3a 187static int dwc3_pci_probe(struct pci_dev *pci,
72246da4
FB
188 const struct pci_device_id *id)
189{
0f817ae6 190 struct dwc3_pci *dwc;
72246da4 191 struct resource res[2];
b09e99ee 192 int ret;
802ca850 193 struct device *dev = &pci->dev;
72246da4 194
f1c7e710 195 ret = pcim_enable_device(pci);
72246da4 196 if (ret) {
802ca850
CP
197 dev_err(dev, "failed to enable pci device\n");
198 return -ENODEV;
72246da4
FB
199 }
200
72246da4
FB
201 pci_set_master(pci);
202
0f817ae6
FB
203 dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
204 if (!dwc)
205 return -ENOMEM;
206
207 dwc->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
208 if (!dwc->dwc3)
f1c7e710 209 return -ENOMEM;
72246da4
FB
210
211 memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
212
213 res[0].start = pci_resource_start(pci, 0);
214 res[0].end = pci_resource_end(pci, 0);
215 res[0].name = "dwc_usb3";
216 res[0].flags = IORESOURCE_MEM;
217
218 res[1].start = pci->irq;
219 res[1].name = "dwc_usb3";
220 res[1].flags = IORESOURCE_IRQ;
221
0f817ae6 222 ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
72246da4 223 if (ret) {
802ca850 224 dev_err(dev, "couldn't add resources to dwc3 device\n");
cabdf83d 225 goto err;
72246da4
FB
226 }
227
0f817ae6
FB
228 dwc->pci = pci;
229 dwc->dwc3->dev.parent = dev;
230 ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
72246da4 231
0f817ae6 232 ret = dwc3_pci_quirks(dwc);
474799f0
HK
233 if (ret)
234 goto err;
235
0f817ae6 236 ret = platform_device_add(dwc->dwc3);
72246da4 237 if (ret) {
802ca850 238 dev_err(dev, "failed to register dwc3 device\n");
2cd9ddf7 239 goto err;
72246da4
FB
240 }
241
e9af9229 242 device_init_wakeup(dev, true);
0f817ae6 243 pci_set_drvdata(pci, dwc);
e9af9229 244 pm_runtime_put(dev);
8eed00b2
MG
245#ifdef CONFIG_PM
246 INIT_WORK(&dwc->wakeup_work, dwc3_pci_resume_work);
247#endif
e9af9229 248
72246da4 249 return 0;
2cd9ddf7 250err:
0f817ae6 251 platform_device_put(dwc->dwc3);
72246da4
FB
252 return ret;
253}
254
fb4e98ab 255static void dwc3_pci_remove(struct pci_dev *pci)
72246da4 256{
0f817ae6
FB
257 struct dwc3_pci *dwc = pci_get_drvdata(pci);
258
5741022c 259 gpiod_remove_lookup_table(&platform_bytcr_gpios);
8eed00b2
MG
260#ifdef CONFIG_PM
261 cancel_work_sync(&dwc->wakeup_work);
262#endif
e9af9229
FB
263 device_init_wakeup(&pci->dev, false);
264 pm_runtime_get(&pci->dev);
0f817ae6 265 platform_device_unregister(dwc->dwc3);
72246da4
FB
266}
267
782df20c 268static const struct pci_device_id dwc3_pci_id_table[] = {
7d643664 269 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
b62cd96d 270 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
85601f8c 271 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
84a2b61b
HK
272 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
273 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
b4c580a4 274 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
1ffb4d5c 275 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
b4c580a4 276 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
4491ed50 277 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
8f8983a5 278 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
68217959
HK
279 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), },
280 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), },
00908693 281 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), },
9755449d 282 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
72246da4
FB
283 { } /* Terminating Entry */
284};
285MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
286
36daf3aa
FB
287#if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
288static int dwc3_pci_dsm(struct dwc3_pci *dwc, int param)
289{
290 union acpi_object *obj;
291 union acpi_object tmp;
292 union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
293
294 if (!dwc->has_dsm_for_pm)
295 return 0;
296
297 tmp.type = ACPI_TYPE_INTEGER;
298 tmp.integer.value = param;
299
94116f81 300 obj = acpi_evaluate_dsm(ACPI_HANDLE(&dwc->pci->dev), &dwc->guid,
36daf3aa
FB
301 1, PCI_INTEL_BXT_FUNC_PMU_PWR, &argv4);
302 if (!obj) {
303 dev_err(&dwc->pci->dev, "failed to evaluate _DSM\n");
304 return -EIO;
305 }
306
307 ACPI_FREE(obj);
308
309 return 0;
310}
311#endif /* CONFIG_PM || CONFIG_PM_SLEEP */
312
e9af9229
FB
313#ifdef CONFIG_PM
314static int dwc3_pci_runtime_suspend(struct device *dev)
315{
9cecca75
FB
316 struct dwc3_pci *dwc = dev_get_drvdata(dev);
317
de3ef1eb 318 if (device_can_wakeup(dev))
9cecca75 319 return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D3);
e9af9229
FB
320
321 return -EBUSY;
322}
323
f6c274e1
FB
324static int dwc3_pci_runtime_resume(struct device *dev)
325{
0f817ae6 326 struct dwc3_pci *dwc = dev_get_drvdata(dev);
9cecca75
FB
327 int ret;
328
329 ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
330 if (ret)
331 return ret;
f6c274e1 332
8eed00b2
MG
333 queue_work(pm_wq, &dwc->wakeup_work);
334
335 return 0;
f6c274e1 336}
696118c0 337#endif /* CONFIG_PM */
f6c274e1 338
696118c0 339#ifdef CONFIG_PM_SLEEP
9cecca75 340static int dwc3_pci_suspend(struct device *dev)
e9af9229 341{
9cecca75
FB
342 struct dwc3_pci *dwc = dev_get_drvdata(dev);
343
344 return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D3);
345}
346
347static int dwc3_pci_resume(struct device *dev)
348{
349 struct dwc3_pci *dwc = dev_get_drvdata(dev);
350
351 return dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
e9af9229 352}
696118c0 353#endif /* CONFIG_PM_SLEEP */
e9af9229 354
95aa932c 355static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
9cecca75 356 SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
f6c274e1 357 SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_runtime_resume,
e9af9229
FB
358 NULL)
359};
360
72246da4 361static struct pci_driver dwc3_pci_driver = {
0949e99b 362 .name = "dwc3-pci",
72246da4
FB
363 .id_table = dwc3_pci_id_table,
364 .probe = dwc3_pci_probe,
7690417d 365 .remove = dwc3_pci_remove,
e9af9229
FB
366 .driver = {
367 .pm = &dwc3_pci_dev_pm_ops,
368 }
72246da4
FB
369};
370
371MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
5945f789 372MODULE_LICENSE("GPL v2");
72246da4
FB
373MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
374
95656336 375module_pci_driver(dwc3_pci_driver);