xhci-ext-caps.c 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * XHCI extended capability handling
  4. *
  5. * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
  6. */
  7. #include <linux/platform_device.h>
  8. #include "xhci.h"
  9. #define USB_SW_DRV_NAME "intel_xhci_usb_sw"
  10. #define USB_SW_RESOURCE_SIZE 0x400
  11. static void xhci_intel_unregister_pdev(void *arg)
  12. {
  13. platform_device_unregister(arg);
  14. }
  15. static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd *xhci, u32 cap_offset)
  16. {
  17. struct usb_hcd *hcd = xhci_to_hcd(xhci);
  18. struct device *dev = hcd->self.controller;
  19. struct platform_device *pdev;
  20. struct resource res = { 0, };
  21. int ret;
  22. pdev = platform_device_alloc(USB_SW_DRV_NAME, PLATFORM_DEVID_NONE);
  23. if (!pdev) {
  24. xhci_err(xhci, "couldn't allocate %s platform device\n",
  25. USB_SW_DRV_NAME);
  26. return -ENOMEM;
  27. }
  28. res.start = hcd->rsrc_start + cap_offset;
  29. res.end = res.start + USB_SW_RESOURCE_SIZE - 1;
  30. res.name = USB_SW_DRV_NAME;
  31. res.flags = IORESOURCE_MEM;
  32. ret = platform_device_add_resources(pdev, &res, 1);
  33. if (ret) {
  34. dev_err(dev, "couldn't add resources to intel_xhci_usb_sw pdev\n");
  35. platform_device_put(pdev);
  36. return ret;
  37. }
  38. pdev->dev.parent = dev;
  39. ret = platform_device_add(pdev);
  40. if (ret) {
  41. dev_err(dev, "couldn't register intel_xhci_usb_sw pdev\n");
  42. platform_device_put(pdev);
  43. return ret;
  44. }
  45. ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev);
  46. if (ret) {
  47. dev_err(dev, "couldn't add unregister action for intel_xhci_usb_sw pdev\n");
  48. return ret;
  49. }
  50. return 0;
  51. }
  52. int xhci_ext_cap_init(struct xhci_hcd *xhci)
  53. {
  54. void __iomem *base = &xhci->cap_regs->hc_capbase;
  55. u32 offset, val;
  56. int ret;
  57. offset = xhci_find_next_ext_cap(base, 0, 0);
  58. while (offset) {
  59. val = readl(base + offset);
  60. switch (XHCI_EXT_CAPS_ID(val)) {
  61. case XHCI_EXT_CAPS_VENDOR_INTEL:
  62. if (xhci->quirks & XHCI_INTEL_USB_ROLE_SW) {
  63. ret = xhci_create_intel_xhci_sw_pdev(xhci,
  64. offset);
  65. if (ret)
  66. return ret;
  67. }
  68. break;
  69. }
  70. offset = xhci_find_next_ext_cap(base, offset, 0);
  71. }
  72. return 0;
  73. }
  74. EXPORT_SYMBOL_GPL(xhci_ext_cap_init);