1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | /* |
3 | * xhci-plat.c - xHCI host controller driver platform Bus Glue. |
4 | * |
5 | * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com |
6 | * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
7 | * |
8 | * A lot of code borrowed from the Linux xHCI driver. |
9 | */ |
10 | |
11 | #include <linux/clk.h> |
12 | #include <linux/dma-mapping.h> |
13 | #include <linux/module.h> |
14 | #include <linux/pci.h> |
15 | #include <linux/of.h> |
16 | #include <linux/of_device.h> |
17 | #include <linux/platform_device.h> |
18 | #include <linux/usb/phy.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/acpi.h> |
21 | #include <linux/usb/of.h> |
22 | #include <linux/reset.h> |
23 | |
24 | #include "xhci.h" |
25 | #include "xhci-plat.h" |
26 | #include "xhci-mvebu.h" |
27 | |
28 | static struct hc_driver __read_mostly xhci_plat_hc_driver; |
29 | |
30 | static int xhci_plat_setup(struct usb_hcd *hcd); |
31 | static int xhci_plat_start(struct usb_hcd *hcd); |
32 | |
33 | static const struct xhci_driver_overrides xhci_plat_overrides __initconst = { |
34 | .extra_priv_size = sizeof(struct xhci_plat_priv), |
35 | .reset = xhci_plat_setup, |
36 | .start = xhci_plat_start, |
37 | }; |
38 | |
39 | static void xhci_priv_plat_start(struct usb_hcd *hcd) |
40 | { |
41 | struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
42 | |
43 | if (priv->plat_start) |
44 | priv->plat_start(hcd); |
45 | } |
46 | |
47 | static int xhci_priv_init_quirk(struct usb_hcd *hcd) |
48 | { |
49 | struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
50 | |
51 | if (!priv->init_quirk) |
52 | return 0; |
53 | |
54 | return priv->init_quirk(hcd); |
55 | } |
56 | |
57 | static int xhci_priv_suspend_quirk(struct usb_hcd *hcd) |
58 | { |
59 | struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
60 | |
61 | if (!priv->suspend_quirk) |
62 | return 0; |
63 | |
64 | return priv->suspend_quirk(hcd); |
65 | } |
66 | |
67 | static int xhci_priv_resume_quirk(struct usb_hcd *hcd) |
68 | { |
69 | struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
70 | |
71 | if (!priv->resume_quirk) |
72 | return 0; |
73 | |
74 | return priv->resume_quirk(hcd); |
75 | } |
76 | |
77 | static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) |
78 | { |
79 | struct xhci_plat_priv *priv = xhci_to_priv(xhci); |
80 | |
81 | xhci->quirks |= priv->quirks; |
82 | } |
83 | |
84 | /* called during probe() after chip reset completes */ |
85 | static int xhci_plat_setup(struct usb_hcd *hcd) |
86 | { |
87 | int ret; |
88 | |
89 | |
90 | ret = xhci_priv_init_quirk(hcd); |
91 | if (ret) |
92 | return ret; |
93 | |
94 | return xhci_gen_setup(hcd, get_quirks: xhci_plat_quirks); |
95 | } |
96 | |
97 | static int xhci_plat_start(struct usb_hcd *hcd) |
98 | { |
99 | xhci_priv_plat_start(hcd); |
100 | return xhci_run(hcd); |
101 | } |
102 | |
103 | #ifdef CONFIG_OF |
104 | static const struct xhci_plat_priv xhci_plat_marvell_armada = { |
105 | .init_quirk = xhci_mvebu_mbus_init_quirk, |
106 | }; |
107 | |
108 | static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { |
109 | .quirks = XHCI_RESET_ON_RESUME, |
110 | }; |
111 | |
112 | static const struct xhci_plat_priv xhci_plat_brcm = { |
113 | .quirks = XHCI_RESET_ON_RESUME | XHCI_SUSPEND_RESUME_CLKS, |
114 | }; |
115 | |
116 | static const struct of_device_id usb_xhci_of_match[] = { |
117 | { |
118 | .compatible = "generic-xhci", |
119 | }, { |
120 | .compatible = "xhci-platform", |
121 | }, { |
122 | .compatible = "marvell,armada-375-xhci", |
123 | .data = &xhci_plat_marvell_armada, |
124 | }, { |
125 | .compatible = "marvell,armada-380-xhci", |
126 | .data = &xhci_plat_marvell_armada, |
127 | }, { |
128 | .compatible = "marvell,armada3700-xhci", |
129 | .data = &xhci_plat_marvell_armada3700, |
130 | }, { |
131 | .compatible = "brcm,xhci-brcm-v2", |
132 | .data = &xhci_plat_brcm, |
133 | }, { |
134 | .compatible = "brcm,bcm2711-xhci", |
135 | .data = &xhci_plat_brcm, |
136 | }, { |
137 | .compatible = "brcm,bcm7445-xhci", |
138 | .data = &xhci_plat_brcm, |
139 | }, |
140 | {}, |
141 | }; |
142 | MODULE_DEVICE_TABLE(of, usb_xhci_of_match); |
143 | #endif |
144 | |
145 | int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const struct xhci_plat_priv *priv_match) |
146 | { |
147 | const struct hc_driver *driver; |
148 | struct device *tmpdev; |
149 | struct xhci_hcd *xhci; |
150 | struct resource *res; |
151 | struct usb_hcd *hcd, *usb3_hcd; |
152 | int ret; |
153 | int irq; |
154 | struct xhci_plat_priv *priv = NULL; |
155 | bool of_match; |
156 | |
157 | if (usb_disabled()) |
158 | return -ENODEV; |
159 | |
160 | driver = &xhci_plat_hc_driver; |
161 | |
162 | irq = platform_get_irq(pdev, 0); |
163 | if (irq < 0) |
164 | return irq; |
165 | |
166 | if (!sysdev) |
167 | sysdev = &pdev->dev; |
168 | |
169 | ret = dma_set_mask_and_coherent(dev: sysdev, DMA_BIT_MASK(64)); |
170 | if (ret) |
171 | return ret; |
172 | |
173 | pm_runtime_set_active(dev: &pdev->dev); |
174 | pm_runtime_enable(dev: &pdev->dev); |
175 | pm_runtime_get_noresume(dev: &pdev->dev); |
176 | |
177 | hcd = __usb_create_hcd(driver, sysdev, dev: &pdev->dev, |
178 | bus_name: dev_name(dev: &pdev->dev), NULL); |
179 | if (!hcd) { |
180 | ret = -ENOMEM; |
181 | goto disable_runtime; |
182 | } |
183 | |
184 | hcd->regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
185 | if (IS_ERR(ptr: hcd->regs)) { |
186 | ret = PTR_ERR(ptr: hcd->regs); |
187 | goto put_hcd; |
188 | } |
189 | |
190 | hcd->rsrc_start = res->start; |
191 | hcd->rsrc_len = resource_size(res); |
192 | |
193 | xhci = hcd_to_xhci(hcd); |
194 | |
195 | xhci->allow_single_roothub = 1; |
196 | |
197 | /* |
198 | * Not all platforms have clks so it is not an error if the |
199 | * clock do not exist. |
200 | */ |
201 | xhci->reg_clk = devm_clk_get_optional(dev: &pdev->dev, id: "reg"); |
202 | if (IS_ERR(ptr: xhci->reg_clk)) { |
203 | ret = PTR_ERR(ptr: xhci->reg_clk); |
204 | goto put_hcd; |
205 | } |
206 | |
207 | xhci->clk = devm_clk_get_optional(dev: &pdev->dev, NULL); |
208 | if (IS_ERR(ptr: xhci->clk)) { |
209 | ret = PTR_ERR(ptr: xhci->clk); |
210 | goto put_hcd; |
211 | } |
212 | |
213 | xhci->reset = devm_reset_control_array_get_optional_shared(dev: &pdev->dev); |
214 | if (IS_ERR(ptr: xhci->reset)) { |
215 | ret = PTR_ERR(ptr: xhci->reset); |
216 | goto put_hcd; |
217 | } |
218 | |
219 | ret = reset_control_deassert(rstc: xhci->reset); |
220 | if (ret) |
221 | goto put_hcd; |
222 | |
223 | ret = clk_prepare_enable(clk: xhci->reg_clk); |
224 | if (ret) |
225 | goto err_reset; |
226 | |
227 | ret = clk_prepare_enable(clk: xhci->clk); |
228 | if (ret) |
229 | goto disable_reg_clk; |
230 | |
231 | if (priv_match) { |
232 | priv = hcd_to_xhci_priv(hcd); |
233 | /* Just copy data for now */ |
234 | *priv = *priv_match; |
235 | } |
236 | |
237 | device_set_wakeup_capable(dev: &pdev->dev, capable: true); |
238 | |
239 | xhci->main_hcd = hcd; |
240 | |
241 | /* imod_interval is the interrupt moderation value in nanoseconds. */ |
242 | xhci->imod_interval = 40000; |
243 | |
244 | /* Iterate over all parent nodes for finding quirks */ |
245 | for (tmpdev = &pdev->dev; tmpdev; tmpdev = tmpdev->parent) { |
246 | |
247 | if (device_property_read_bool(dev: tmpdev, propname: "usb2-lpm-disable")) |
248 | xhci->quirks |= XHCI_HW_LPM_DISABLE; |
249 | |
250 | if (device_property_read_bool(dev: tmpdev, propname: "usb3-lpm-capable")) |
251 | xhci->quirks |= XHCI_LPM_SUPPORT; |
252 | |
253 | if (device_property_read_bool(dev: tmpdev, propname: "quirk-broken-port-ped")) |
254 | xhci->quirks |= XHCI_BROKEN_PORT_PED; |
255 | |
256 | if (device_property_read_bool(dev: tmpdev, propname: "xhci-sg-trb-cache-size-quirk")) |
257 | xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK; |
258 | |
259 | if (device_property_read_bool(dev: tmpdev, propname: "write-64-hi-lo-quirk")) |
260 | xhci->quirks |= XHCI_WRITE_64_HI_LO; |
261 | |
262 | if (device_property_read_bool(dev: tmpdev, propname: "xhci-missing-cas-quirk")) |
263 | xhci->quirks |= XHCI_MISSING_CAS; |
264 | |
265 | if (device_property_read_bool(dev: tmpdev, propname: "xhci-skip-phy-init-quirk")) |
266 | xhci->quirks |= XHCI_SKIP_PHY_INIT; |
267 | |
268 | device_property_read_u32(dev: tmpdev, propname: "imod-interval-ns", |
269 | val: &xhci->imod_interval); |
270 | device_property_read_u16(dev: tmpdev, propname: "num-hc-interrupters", |
271 | val: &xhci->max_interrupters); |
272 | } |
273 | |
274 | /* |
275 | * Drivers such as dwc3 manages PHYs themself (and rely on driver name |
276 | * matching for the xhci platform device). |
277 | */ |
278 | of_match = of_match_device(matches: pdev->dev.driver->of_match_table, dev: &pdev->dev); |
279 | if (of_match) { |
280 | hcd->usb_phy = devm_usb_get_phy_by_phandle(dev: sysdev, phandle: "usb-phy", index: 0); |
281 | if (IS_ERR(ptr: hcd->usb_phy)) { |
282 | ret = PTR_ERR(ptr: hcd->usb_phy); |
283 | if (ret == -EPROBE_DEFER) |
284 | goto disable_clk; |
285 | hcd->usb_phy = NULL; |
286 | } else { |
287 | ret = usb_phy_init(x: hcd->usb_phy); |
288 | if (ret) |
289 | goto disable_clk; |
290 | } |
291 | } |
292 | |
293 | hcd->tpl_support = of_usb_host_tpl_support(np: sysdev->of_node); |
294 | |
295 | if ((priv && (priv->quirks & XHCI_SKIP_PHY_INIT)) || |
296 | (xhci->quirks & XHCI_SKIP_PHY_INIT)) |
297 | hcd->skip_phy_initialization = 1; |
298 | |
299 | if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK)) |
300 | xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK; |
301 | |
302 | ret = usb_add_hcd(hcd, irqnum: irq, IRQF_SHARED); |
303 | if (ret) |
304 | goto disable_usb_phy; |
305 | |
306 | if (!xhci_has_one_roothub(xhci)) { |
307 | xhci->shared_hcd = __usb_create_hcd(driver, sysdev, dev: &pdev->dev, |
308 | bus_name: dev_name(dev: &pdev->dev), primary_hcd: hcd); |
309 | if (!xhci->shared_hcd) { |
310 | ret = -ENOMEM; |
311 | goto dealloc_usb2_hcd; |
312 | } |
313 | |
314 | if (of_match) { |
315 | xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(dev: sysdev, |
316 | phandle: "usb-phy", index: 1); |
317 | if (IS_ERR(ptr: xhci->shared_hcd->usb_phy)) { |
318 | xhci->shared_hcd->usb_phy = NULL; |
319 | } else { |
320 | ret = usb_phy_init(x: xhci->shared_hcd->usb_phy); |
321 | if (ret) |
322 | dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n", |
323 | __func__, ret); |
324 | } |
325 | } |
326 | |
327 | xhci->shared_hcd->tpl_support = hcd->tpl_support; |
328 | } |
329 | |
330 | usb3_hcd = xhci_get_usb3_hcd(xhci); |
331 | if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4) |
332 | usb3_hcd->can_do_streams = 1; |
333 | |
334 | if (xhci->shared_hcd) { |
335 | xhci->shared_hcd->rsrc_start = hcd->rsrc_start; |
336 | xhci->shared_hcd->rsrc_len = hcd->rsrc_len; |
337 | ret = usb_add_hcd(hcd: xhci->shared_hcd, irqnum: irq, IRQF_SHARED); |
338 | if (ret) |
339 | goto put_usb3_hcd; |
340 | } |
341 | |
342 | device_enable_async_suspend(dev: &pdev->dev); |
343 | pm_runtime_put_noidle(dev: &pdev->dev); |
344 | |
345 | /* |
346 | * Prevent runtime pm from being on as default, users should enable |
347 | * runtime pm using power/control in sysfs. |
348 | */ |
349 | pm_runtime_forbid(dev: &pdev->dev); |
350 | |
351 | return 0; |
352 | |
353 | |
354 | put_usb3_hcd: |
355 | usb_put_hcd(hcd: xhci->shared_hcd); |
356 | |
357 | dealloc_usb2_hcd: |
358 | usb_remove_hcd(hcd); |
359 | |
360 | disable_usb_phy: |
361 | usb_phy_shutdown(x: hcd->usb_phy); |
362 | |
363 | disable_clk: |
364 | clk_disable_unprepare(clk: xhci->clk); |
365 | |
366 | disable_reg_clk: |
367 | clk_disable_unprepare(clk: xhci->reg_clk); |
368 | |
369 | err_reset: |
370 | reset_control_assert(rstc: xhci->reset); |
371 | |
372 | put_hcd: |
373 | usb_put_hcd(hcd); |
374 | |
375 | disable_runtime: |
376 | pm_runtime_put_noidle(dev: &pdev->dev); |
377 | pm_runtime_disable(dev: &pdev->dev); |
378 | |
379 | return ret; |
380 | } |
381 | EXPORT_SYMBOL_GPL(xhci_plat_probe); |
382 | |
383 | static int xhci_generic_plat_probe(struct platform_device *pdev) |
384 | { |
385 | const struct xhci_plat_priv *priv_match; |
386 | struct device *sysdev; |
387 | int ret; |
388 | |
389 | /* |
390 | * sysdev must point to a device that is known to the system firmware |
391 | * or PCI hardware. We handle these three cases here: |
392 | * 1. xhci_plat comes from firmware |
393 | * 2. xhci_plat is child of a device from firmware (dwc3-plat) |
394 | * 3. xhci_plat is grandchild of a pci device (dwc3-pci) |
395 | */ |
396 | for (sysdev = &pdev->dev; sysdev; sysdev = sysdev->parent) { |
397 | if (is_of_node(fwnode: sysdev->fwnode) || |
398 | is_acpi_device_node(fwnode: sysdev->fwnode)) |
399 | break; |
400 | else if (dev_is_pci(sysdev)) |
401 | break; |
402 | } |
403 | |
404 | if (!sysdev) |
405 | sysdev = &pdev->dev; |
406 | |
407 | if (WARN_ON(!sysdev->dma_mask)) { |
408 | /* Platform did not initialize dma_mask */ |
409 | ret = dma_coerce_mask_and_coherent(dev: sysdev, DMA_BIT_MASK(64)); |
410 | if (ret) |
411 | return ret; |
412 | } |
413 | |
414 | if (pdev->dev.of_node) |
415 | priv_match = of_device_get_match_data(dev: &pdev->dev); |
416 | else |
417 | priv_match = dev_get_platdata(dev: &pdev->dev); |
418 | |
419 | return xhci_plat_probe(pdev, sysdev, priv_match); |
420 | } |
421 | |
422 | void xhci_plat_remove(struct platform_device *dev) |
423 | { |
424 | struct usb_hcd *hcd = platform_get_drvdata(pdev: dev); |
425 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
426 | struct clk *clk = xhci->clk; |
427 | struct clk *reg_clk = xhci->reg_clk; |
428 | struct usb_hcd *shared_hcd = xhci->shared_hcd; |
429 | |
430 | xhci->xhc_state |= XHCI_STATE_REMOVING; |
431 | pm_runtime_get_sync(dev: &dev->dev); |
432 | |
433 | if (shared_hcd) { |
434 | usb_remove_hcd(hcd: shared_hcd); |
435 | xhci->shared_hcd = NULL; |
436 | } |
437 | |
438 | usb_phy_shutdown(x: hcd->usb_phy); |
439 | |
440 | usb_remove_hcd(hcd); |
441 | |
442 | if (shared_hcd) |
443 | usb_put_hcd(hcd: shared_hcd); |
444 | |
445 | clk_disable_unprepare(clk); |
446 | clk_disable_unprepare(clk: reg_clk); |
447 | reset_control_assert(rstc: xhci->reset); |
448 | usb_put_hcd(hcd); |
449 | |
450 | pm_runtime_disable(dev: &dev->dev); |
451 | pm_runtime_put_noidle(dev: &dev->dev); |
452 | pm_runtime_set_suspended(dev: &dev->dev); |
453 | } |
454 | EXPORT_SYMBOL_GPL(xhci_plat_remove); |
455 | |
456 | static int xhci_plat_suspend(struct device *dev) |
457 | { |
458 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
459 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
460 | int ret; |
461 | |
462 | if (pm_runtime_suspended(dev)) |
463 | pm_runtime_resume(dev); |
464 | |
465 | ret = xhci_priv_suspend_quirk(hcd); |
466 | if (ret) |
467 | return ret; |
468 | /* |
469 | * xhci_suspend() needs `do_wakeup` to know whether host is allowed |
470 | * to do wakeup during suspend. |
471 | */ |
472 | ret = xhci_suspend(xhci, do_wakeup: device_may_wakeup(dev)); |
473 | if (ret) |
474 | return ret; |
475 | |
476 | if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { |
477 | clk_disable_unprepare(clk: xhci->clk); |
478 | clk_disable_unprepare(clk: xhci->reg_clk); |
479 | } |
480 | |
481 | return 0; |
482 | } |
483 | |
484 | static int xhci_plat_resume_common(struct device *dev, bool power_lost) |
485 | { |
486 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
487 | struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
488 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
489 | int ret; |
490 | |
491 | if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { |
492 | ret = clk_prepare_enable(clk: xhci->clk); |
493 | if (ret) |
494 | return ret; |
495 | |
496 | ret = clk_prepare_enable(clk: xhci->reg_clk); |
497 | if (ret) { |
498 | clk_disable_unprepare(clk: xhci->clk); |
499 | return ret; |
500 | } |
501 | } |
502 | |
503 | ret = xhci_priv_resume_quirk(hcd); |
504 | if (ret) |
505 | goto disable_clks; |
506 | |
507 | ret = xhci_resume(xhci, power_lost: power_lost || priv->power_lost, is_auto_resume: false); |
508 | if (ret) |
509 | goto disable_clks; |
510 | |
511 | pm_runtime_disable(dev); |
512 | pm_runtime_set_active(dev); |
513 | pm_runtime_enable(dev); |
514 | |
515 | return 0; |
516 | |
517 | disable_clks: |
518 | if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { |
519 | clk_disable_unprepare(clk: xhci->clk); |
520 | clk_disable_unprepare(clk: xhci->reg_clk); |
521 | } |
522 | |
523 | return ret; |
524 | } |
525 | |
526 | static int xhci_plat_resume(struct device *dev) |
527 | { |
528 | return xhci_plat_resume_common(dev, power_lost: false); |
529 | } |
530 | |
531 | static int xhci_plat_restore(struct device *dev) |
532 | { |
533 | return xhci_plat_resume_common(dev, power_lost: true); |
534 | } |
535 | |
536 | static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev) |
537 | { |
538 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
539 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
540 | int ret; |
541 | |
542 | ret = xhci_priv_suspend_quirk(hcd); |
543 | if (ret) |
544 | return ret; |
545 | |
546 | return xhci_suspend(xhci, do_wakeup: true); |
547 | } |
548 | |
549 | static int __maybe_unused xhci_plat_runtime_resume(struct device *dev) |
550 | { |
551 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
552 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
553 | |
554 | return xhci_resume(xhci, power_lost: false, is_auto_resume: true); |
555 | } |
556 | |
557 | const struct dev_pm_ops xhci_plat_pm_ops = { |
558 | .suspend = pm_sleep_ptr(xhci_plat_suspend), |
559 | .resume = pm_sleep_ptr(xhci_plat_resume), |
560 | .freeze = pm_sleep_ptr(xhci_plat_suspend), |
561 | .thaw = pm_sleep_ptr(xhci_plat_resume), |
562 | .poweroff = pm_sleep_ptr(xhci_plat_suspend), |
563 | .restore = pm_sleep_ptr(xhci_plat_restore), |
564 | |
565 | SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, |
566 | xhci_plat_runtime_resume, |
567 | NULL) |
568 | }; |
569 | EXPORT_SYMBOL_GPL(xhci_plat_pm_ops); |
570 | |
571 | #ifdef CONFIG_ACPI |
572 | static const struct acpi_device_id usb_xhci_acpi_match[] = { |
573 | /* XHCI-compliant USB Controller */ |
574 | { "PNP0D10", }, |
575 | { "PNP0D15", }, |
576 | { } |
577 | }; |
578 | MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); |
579 | #endif |
580 | |
581 | static struct platform_driver usb_generic_xhci_driver = { |
582 | .probe = xhci_generic_plat_probe, |
583 | .remove = xhci_plat_remove, |
584 | .shutdown = usb_hcd_platform_shutdown, |
585 | .driver = { |
586 | .name = "xhci-hcd", |
587 | .pm = &xhci_plat_pm_ops, |
588 | .of_match_table = of_match_ptr(usb_xhci_of_match), |
589 | .acpi_match_table = ACPI_PTR(usb_xhci_acpi_match), |
590 | }, |
591 | }; |
592 | MODULE_ALIAS("platform:xhci-hcd"); |
593 | |
594 | static int __init xhci_plat_init(void) |
595 | { |
596 | xhci_init_driver(drv: &xhci_plat_hc_driver, over: &xhci_plat_overrides); |
597 | return platform_driver_register(&usb_generic_xhci_driver); |
598 | } |
599 | module_init(xhci_plat_init); |
600 | |
601 | static void __exit xhci_plat_exit(void) |
602 | { |
603 | platform_driver_unregister(&usb_generic_xhci_driver); |
604 | } |
605 | module_exit(xhci_plat_exit); |
606 | |
607 | MODULE_DESCRIPTION("xHCI Platform Host Controller Driver"); |
608 | MODULE_LICENSE("GPL"); |
609 |
Definitions
- xhci_plat_hc_driver
- xhci_plat_overrides
- xhci_priv_plat_start
- xhci_priv_init_quirk
- xhci_priv_suspend_quirk
- xhci_priv_resume_quirk
- xhci_plat_quirks
- xhci_plat_setup
- xhci_plat_start
- xhci_plat_marvell_armada
- xhci_plat_marvell_armada3700
- xhci_plat_brcm
- usb_xhci_of_match
- xhci_plat_probe
- xhci_generic_plat_probe
- xhci_plat_remove
- xhci_plat_suspend
- xhci_plat_resume_common
- xhci_plat_resume
- xhci_plat_restore
- xhci_plat_runtime_suspend
- xhci_plat_runtime_resume
- xhci_plat_pm_ops
- usb_xhci_acpi_match
- usb_generic_xhci_driver
- xhci_plat_init
Improve your Profiling and Debugging skills
Find out more