GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / usb / cdns3 / cdnsp-pci.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Cadence PCI Glue driver.
4  *
5  * Copyright (C) 2019 Cadence.
6  *
7  * Author: Pawel Laszczak <pawell@cadence.com>
8  *
9  */
10
11 #include <linux/platform_device.h>
12 #include <linux/dma-mapping.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/pci.h>
17
18 #include "core.h"
19 #include "gadget-export.h"
20
21 #define PCI_BAR_HOST            0
22 #define PCI_BAR_OTG             0
23 #define PCI_BAR_DEV             2
24
25 #define PCI_DEV_FN_HOST_DEVICE  0
26 #define PCI_DEV_FN_OTG          1
27
28 #define PCI_DRIVER_NAME         "cdns-pci-usbssp"
29 #define PLAT_DRIVER_NAME        "cdns-usbssp"
30
31 #define CDNS_VENDOR_ID          0x17cd
32 #define CDNS_DEVICE_ID          0x0200
33 #define CDNS_DRD_ID             0x0100
34 #define CDNS_DRD_IF             (PCI_CLASS_SERIAL_USB << 8 | 0x80)
35
36 static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
37 {
38         /*
39          * Gets the second function.
40          * Platform has two function. The fist keeps resources for
41          * Host/Device while the secon keeps resources for DRD/OTG.
42          */
43         if (pdev->device == CDNS_DEVICE_ID)
44                 return  pci_get_device(pdev->vendor, CDNS_DRD_ID, NULL);
45         else if (pdev->device == CDNS_DRD_ID)
46                 return pci_get_device(pdev->vendor, CDNS_DEVICE_ID, NULL);
47
48         return NULL;
49 }
50
51 static int cdnsp_pci_probe(struct pci_dev *pdev,
52                            const struct pci_device_id *id)
53 {
54         struct device *dev = &pdev->dev;
55         struct pci_dev *func;
56         struct resource *res;
57         struct cdns *cdnsp;
58         int ret;
59
60         /*
61          * For GADGET/HOST PCI (devfn) function number is 0,
62          * for OTG PCI (devfn) function number is 1.
63          */
64         if (!id || (pdev->devfn != PCI_DEV_FN_HOST_DEVICE &&
65                     pdev->devfn != PCI_DEV_FN_OTG))
66                 return -EINVAL;
67
68         func = cdnsp_get_second_fun(pdev);
69         if (!func)
70                 return -EINVAL;
71
72         if (func->class == PCI_CLASS_SERIAL_USB_XHCI ||
73             pdev->class == PCI_CLASS_SERIAL_USB_XHCI) {
74                 ret = -EINVAL;
75                 goto put_pci;
76         }
77
78         ret = pcim_enable_device(pdev);
79         if (ret) {
80                 dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", ret);
81                 goto put_pci;
82         }
83
84         pci_set_master(pdev);
85         if (pci_is_enabled(func)) {
86                 cdnsp = pci_get_drvdata(func);
87         } else {
88                 cdnsp = kzalloc(sizeof(*cdnsp), GFP_KERNEL);
89                 if (!cdnsp) {
90                         ret = -ENOMEM;
91                         goto disable_pci;
92                 }
93         }
94
95         /* For GADGET device function number is 0. */
96         if (pdev->devfn == 0) {
97                 resource_size_t rsrc_start, rsrc_len;
98
99                 /* Function 0: host(BAR_0) + device(BAR_1).*/
100                 dev_dbg(dev, "Initialize resources\n");
101                 rsrc_start = pci_resource_start(pdev, PCI_BAR_DEV);
102                 rsrc_len = pci_resource_len(pdev, PCI_BAR_DEV);
103                 res = devm_request_mem_region(dev, rsrc_start, rsrc_len, "dev");
104                 if (!res) {
105                         dev_dbg(dev, "controller already in use\n");
106                         ret = -EBUSY;
107                         goto free_cdnsp;
108                 }
109
110                 cdnsp->dev_regs = devm_ioremap(dev, rsrc_start, rsrc_len);
111                 if (!cdnsp->dev_regs) {
112                         dev_dbg(dev, "error mapping memory\n");
113                         ret = -EFAULT;
114                         goto free_cdnsp;
115                 }
116
117                 cdnsp->dev_irq = pdev->irq;
118                 dev_dbg(dev, "USBSS-DEV physical base addr: %pa\n",
119                         &rsrc_start);
120
121                 res = &cdnsp->xhci_res[0];
122                 res->start = pci_resource_start(pdev, PCI_BAR_HOST);
123                 res->end = pci_resource_end(pdev, PCI_BAR_HOST);
124                 res->name = "xhci";
125                 res->flags = IORESOURCE_MEM;
126                 dev_dbg(dev, "USBSS-XHCI physical base addr: %pa\n",
127                         &res->start);
128
129                 /* Interrupt for XHCI, */
130                 res = &cdnsp->xhci_res[1];
131                 res->start = pdev->irq;
132                 res->name = "host";
133                 res->flags = IORESOURCE_IRQ;
134         } else {
135                 res = &cdnsp->otg_res;
136                 res->start = pci_resource_start(pdev, PCI_BAR_OTG);
137                 res->end =   pci_resource_end(pdev, PCI_BAR_OTG);
138                 res->name = "otg";
139                 res->flags = IORESOURCE_MEM;
140                 dev_dbg(dev, "CDNSP-DRD physical base addr: %pa\n",
141                         &res->start);
142
143                 /* Interrupt for OTG/DRD. */
144                 cdnsp->otg_irq = pdev->irq;
145         }
146
147         if (pci_is_enabled(func)) {
148                 cdnsp->dev = dev;
149                 cdnsp->gadget_init = cdnsp_gadget_init;
150
151                 ret = cdns_init(cdnsp);
152                 if (ret)
153                         goto free_cdnsp;
154         }
155
156         pci_set_drvdata(pdev, cdnsp);
157
158         device_wakeup_enable(&pdev->dev);
159         if (pci_dev_run_wake(pdev))
160                 pm_runtime_put_noidle(&pdev->dev);
161
162         return 0;
163
164 free_cdnsp:
165         if (!pci_is_enabled(func))
166                 kfree(cdnsp);
167
168 disable_pci:
169         pci_disable_device(pdev);
170
171 put_pci:
172         pci_dev_put(func);
173
174         return ret;
175 }
176
177 static void cdnsp_pci_remove(struct pci_dev *pdev)
178 {
179         struct cdns *cdnsp;
180         struct pci_dev *func;
181
182         func = cdnsp_get_second_fun(pdev);
183         cdnsp = (struct cdns *)pci_get_drvdata(pdev);
184
185         if (pci_dev_run_wake(pdev))
186                 pm_runtime_get_noresume(&pdev->dev);
187
188         if (pci_is_enabled(func)) {
189                 cdns_remove(cdnsp);
190         } else {
191                 kfree(cdnsp);
192         }
193
194         pci_dev_put(func);
195 }
196
197 static int __maybe_unused cdnsp_pci_suspend(struct device *dev)
198 {
199         struct cdns *cdns = dev_get_drvdata(dev);
200
201         return cdns_suspend(cdns);
202 }
203
204 static int __maybe_unused cdnsp_pci_resume(struct device *dev)
205 {
206         struct cdns *cdns = dev_get_drvdata(dev);
207         unsigned long flags;
208         int ret;
209
210         spin_lock_irqsave(&cdns->lock, flags);
211         ret = cdns_resume(cdns);
212         spin_unlock_irqrestore(&cdns->lock, flags);
213         cdns_set_active(cdns, 1);
214
215         return ret;
216 }
217
218 static const struct dev_pm_ops cdnsp_pci_pm_ops = {
219         SET_SYSTEM_SLEEP_PM_OPS(cdnsp_pci_suspend, cdnsp_pci_resume)
220 };
221
222 static const struct pci_device_id cdnsp_pci_ids[] = {
223         { PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
224           PCI_CLASS_SERIAL_USB_DEVICE, PCI_ANY_ID },
225         { PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
226           CDNS_DRD_IF, PCI_ANY_ID },
227         { PCI_VENDOR_ID_CDNS, CDNS_DRD_ID, PCI_ANY_ID, PCI_ANY_ID,
228           CDNS_DRD_IF, PCI_ANY_ID },
229         { 0, }
230 };
231
232 static struct pci_driver cdnsp_pci_driver = {
233         .name = "cdnsp-pci",
234         .id_table = &cdnsp_pci_ids[0],
235         .probe = cdnsp_pci_probe,
236         .remove = cdnsp_pci_remove,
237         .driver = {
238                 .pm = &cdnsp_pci_pm_ops,
239         }
240 };
241
242 module_pci_driver(cdnsp_pci_driver);
243 MODULE_DEVICE_TABLE(pci, cdnsp_pci_ids);
244
245 MODULE_ALIAS("pci:cdnsp");
246 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
247 MODULE_LICENSE("GPL v2");
248 MODULE_DESCRIPTION("Cadence CDNSP PCI driver");