Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
 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);