cpufreq: intel_pstate: Fix fast-switch fallback path
[linux-2.6-microblaze.git] / drivers / usb / dwc3 / host.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * host.c - DesignWare USB3 DRD Controller Host Glue
4  *
5  * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com
6  *
7  * Authors: Felipe Balbi <balbi@ti.com>,
8  */
9
10 #include <linux/acpi.h>
11 #include <linux/platform_device.h>
12
13 #include "core.h"
14
15 static int dwc3_host_get_irq(struct dwc3 *dwc)
16 {
17         struct platform_device  *dwc3_pdev = to_platform_device(dwc->dev);
18         int irq;
19
20         irq = platform_get_irq_byname_optional(dwc3_pdev, "host");
21         if (irq > 0)
22                 goto out;
23
24         if (irq == -EPROBE_DEFER)
25                 goto out;
26
27         irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
28         if (irq > 0)
29                 goto out;
30
31         if (irq == -EPROBE_DEFER)
32                 goto out;
33
34         irq = platform_get_irq(dwc3_pdev, 0);
35         if (irq > 0)
36                 goto out;
37
38         if (!irq)
39                 irq = -EINVAL;
40
41 out:
42         return irq;
43 }
44
45 int dwc3_host_init(struct dwc3 *dwc)
46 {
47         struct property_entry   props[4];
48         struct platform_device  *xhci;
49         int                     ret, irq;
50         struct resource         *res;
51         struct platform_device  *dwc3_pdev = to_platform_device(dwc->dev);
52         int                     prop_idx = 0;
53
54         irq = dwc3_host_get_irq(dwc);
55         if (irq < 0)
56                 return irq;
57
58         res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, "host");
59         if (!res)
60                 res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ,
61                                 "dwc_usb3");
62         if (!res)
63                 res = platform_get_resource(dwc3_pdev, IORESOURCE_IRQ, 0);
64         if (!res)
65                 return -ENOMEM;
66
67         dwc->xhci_resources[1].start = irq;
68         dwc->xhci_resources[1].end = irq;
69         dwc->xhci_resources[1].flags = res->flags;
70         dwc->xhci_resources[1].name = res->name;
71
72         xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
73         if (!xhci) {
74                 dev_err(dwc->dev, "couldn't allocate xHCI device\n");
75                 return -ENOMEM;
76         }
77
78         xhci->dev.parent        = dwc->dev;
79         ACPI_COMPANION_SET(&xhci->dev, ACPI_COMPANION(dwc->dev));
80
81         dwc->xhci = xhci;
82
83         ret = platform_device_add_resources(xhci, dwc->xhci_resources,
84                                                 DWC3_XHCI_RESOURCES_NUM);
85         if (ret) {
86                 dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
87                 goto err;
88         }
89
90         memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
91
92         if (dwc->usb3_lpm_capable)
93                 props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb3-lpm-capable");
94
95         if (dwc->usb2_lpm_disable)
96                 props[prop_idx++] = PROPERTY_ENTRY_BOOL("usb2-lpm-disable");
97
98         /**
99          * WORKAROUND: dwc3 revisions <=3.00a have a limitation
100          * where Port Disable command doesn't work.
101          *
102          * The suggested workaround is that we avoid Port Disable
103          * completely.
104          *
105          * This following flag tells XHCI to do just that.
106          */
107         if (DWC3_VER_IS_WITHIN(DWC3, ANY, 300A))
108                 props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped");
109
110         if (prop_idx) {
111                 ret = platform_device_add_properties(xhci, props);
112                 if (ret) {
113                         dev_err(dwc->dev, "failed to add properties to xHCI\n");
114                         goto err;
115                 }
116         }
117
118         ret = platform_device_add(xhci);
119         if (ret) {
120                 dev_err(dwc->dev, "failed to register xHCI device\n");
121                 goto err;
122         }
123
124         return 0;
125 err:
126         platform_device_put(xhci);
127         return ret;
128 }
129
130 void dwc3_host_exit(struct dwc3 *dwc)
131 {
132         platform_device_unregister(dwc->xhci);
133 }