linux/drivers/usb/host/xhci-ext-caps.c
<<
>>
Prefs
   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
   8#include <linux/platform_device.h>
   9#include "xhci.h"
  10
  11#define USB_SW_DRV_NAME         "intel_xhci_usb_sw"
  12#define USB_SW_RESOURCE_SIZE    0x400
  13
  14static void xhci_intel_unregister_pdev(void *arg)
  15{
  16        platform_device_unregister(arg);
  17}
  18
  19static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd *xhci, u32 cap_offset)
  20{
  21        struct usb_hcd *hcd = xhci_to_hcd(xhci);
  22        struct device *dev = hcd->self.controller;
  23        struct platform_device *pdev;
  24        struct resource res = { 0, };
  25        int ret;
  26
  27        pdev = platform_device_alloc(USB_SW_DRV_NAME, PLATFORM_DEVID_NONE);
  28        if (!pdev) {
  29                xhci_err(xhci, "couldn't allocate %s platform device\n",
  30                         USB_SW_DRV_NAME);
  31                return -ENOMEM;
  32        }
  33
  34        res.start = hcd->rsrc_start + cap_offset;
  35        res.end   = res.start + USB_SW_RESOURCE_SIZE - 1;
  36        res.name  = USB_SW_DRV_NAME;
  37        res.flags = IORESOURCE_MEM;
  38
  39        ret = platform_device_add_resources(pdev, &res, 1);
  40        if (ret) {
  41                dev_err(dev, "couldn't add resources to intel_xhci_usb_sw pdev\n");
  42                platform_device_put(pdev);
  43                return ret;
  44        }
  45
  46        pdev->dev.parent = dev;
  47
  48        ret = platform_device_add(pdev);
  49        if (ret) {
  50                dev_err(dev, "couldn't register intel_xhci_usb_sw pdev\n");
  51                platform_device_put(pdev);
  52                return ret;
  53        }
  54
  55        ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev);
  56        if (ret) {
  57                dev_err(dev, "couldn't add unregister action for intel_xhci_usb_sw pdev\n");
  58                return ret;
  59        }
  60
  61        return 0;
  62}
  63
  64int xhci_ext_cap_init(struct xhci_hcd *xhci)
  65{
  66        void __iomem *base = &xhci->cap_regs->hc_capbase;
  67        u32 offset, val;
  68        int ret;
  69
  70        offset = xhci_find_next_ext_cap(base, 0, 0);
  71
  72        while (offset) {
  73                val = readl(base + offset);
  74
  75                switch (XHCI_EXT_CAPS_ID(val)) {
  76                case XHCI_EXT_CAPS_VENDOR_INTEL:
  77                        if (xhci->quirks & XHCI_INTEL_USB_ROLE_SW) {
  78                                ret = xhci_create_intel_xhci_sw_pdev(xhci,
  79                                                                     offset);
  80                                if (ret)
  81                                        return ret;
  82                        }
  83                        break;
  84                }
  85                offset = xhci_find_next_ext_cap(base, offset, 0);
  86        }
  87
  88        return 0;
  89}
  90EXPORT_SYMBOL_GPL(xhci_ext_cap_init);
  91