1 // SPDX-License-Identifier: GPL-2.0
3 * Cadence USBSS PCI Glue driver
5 * Copyright (C) 2018-2019 Cadence.
7 * Author: Pawel Laszczak <pawell@cadence.com>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/pci.h>
13 #include <linux/platform_device.h>
14 #include <linux/dma-mapping.h>
15 #include <linux/slab.h>
18 struct platform_device
*plat_dev
;
19 struct resource dev_res
[6];
23 #define RES_IRQ_HOST_ID 0
24 #define RES_IRQ_PERIPHERAL_ID 1
25 #define RES_IRQ_OTG_ID 2
30 #define PCI_BAR_HOST 0
34 #define PCI_DEV_FN_HOST_DEVICE 0
35 #define PCI_DEV_FN_OTG 1
37 #define PCI_DRIVER_NAME "cdns3-pci-usbss"
38 #define PLAT_DRIVER_NAME "cdns-usb3"
40 #define CDNS_VENDOR_ID 0x17cd
41 #define CDNS_DEVICE_ID 0x0100
43 static struct pci_dev
*cdns3_get_second_fun(struct pci_dev
*pdev
)
48 * Gets the second function.
49 * It's little tricky, but this platform has two function.
50 * The fist keeps resources for Host/Device while the second
51 * keeps resources for DRD/OTG.
53 func
= pci_get_device(pdev
->vendor
, pdev
->device
, NULL
);
57 if (func
->devfn
== pdev
->devfn
) {
58 func
= pci_get_device(pdev
->vendor
, pdev
->device
, func
);
66 static int cdns3_pci_probe(struct pci_dev
*pdev
,
67 const struct pci_device_id
*id
)
69 struct platform_device_info plat_info
;
70 struct cdns3_wrap
*wrap
;
76 * for GADGET/HOST PCI (devfn) function number is 0,
77 * for OTG PCI (devfn) function number is 1
79 if (!id
|| (pdev
->devfn
!= PCI_DEV_FN_HOST_DEVICE
&&
80 pdev
->devfn
!= PCI_DEV_FN_OTG
))
83 func
= cdns3_get_second_fun(pdev
);
87 err
= pcim_enable_device(pdev
);
89 dev_err(&pdev
->dev
, "Enabling PCI device has failed %d\n", err
);
95 if (pci_is_enabled(func
)) {
96 wrap
= pci_get_drvdata(func
);
98 wrap
= kzalloc(sizeof(*wrap
), GFP_KERNEL
);
100 pci_disable_device(pdev
);
107 if (pdev
->devfn
== PCI_DEV_FN_HOST_DEVICE
) {
108 /* function 0: host(BAR_0) + device(BAR_1).*/
109 dev_dbg(&pdev
->dev
, "Initialize Device resources\n");
110 res
[RES_DEV_ID
].start
= pci_resource_start(pdev
, PCI_BAR_DEV
);
111 res
[RES_DEV_ID
].end
= pci_resource_end(pdev
, PCI_BAR_DEV
);
112 res
[RES_DEV_ID
].name
= "dev";
113 res
[RES_DEV_ID
].flags
= IORESOURCE_MEM
;
114 dev_dbg(&pdev
->dev
, "USBSS-DEV physical base addr: %pa\n",
115 &res
[RES_DEV_ID
].start
);
117 res
[RES_HOST_ID
].start
= pci_resource_start(pdev
, PCI_BAR_HOST
);
118 res
[RES_HOST_ID
].end
= pci_resource_end(pdev
, PCI_BAR_HOST
);
119 res
[RES_HOST_ID
].name
= "xhci";
120 res
[RES_HOST_ID
].flags
= IORESOURCE_MEM
;
121 dev_dbg(&pdev
->dev
, "USBSS-XHCI physical base addr: %pa\n",
122 &res
[RES_HOST_ID
].start
);
124 /* Interrupt for XHCI */
125 wrap
->dev_res
[RES_IRQ_HOST_ID
].start
= pdev
->irq
;
126 wrap
->dev_res
[RES_IRQ_HOST_ID
].name
= "host";
127 wrap
->dev_res
[RES_IRQ_HOST_ID
].flags
= IORESOURCE_IRQ
;
129 /* Interrupt device. It's the same as for HOST. */
130 wrap
->dev_res
[RES_IRQ_PERIPHERAL_ID
].start
= pdev
->irq
;
131 wrap
->dev_res
[RES_IRQ_PERIPHERAL_ID
].name
= "peripheral";
132 wrap
->dev_res
[RES_IRQ_PERIPHERAL_ID
].flags
= IORESOURCE_IRQ
;
134 res
[RES_DRD_ID
].start
= pci_resource_start(pdev
, PCI_BAR_OTG
);
135 res
[RES_DRD_ID
].end
= pci_resource_end(pdev
, PCI_BAR_OTG
);
136 res
[RES_DRD_ID
].name
= "otg";
137 res
[RES_DRD_ID
].flags
= IORESOURCE_MEM
;
138 dev_dbg(&pdev
->dev
, "USBSS-DRD physical base addr: %pa\n",
139 &res
[RES_DRD_ID
].start
);
141 /* Interrupt for OTG/DRD. */
142 wrap
->dev_res
[RES_IRQ_OTG_ID
].start
= pdev
->irq
;
143 wrap
->dev_res
[RES_IRQ_OTG_ID
].name
= "otg";
144 wrap
->dev_res
[RES_IRQ_OTG_ID
].flags
= IORESOURCE_IRQ
;
147 if (pci_is_enabled(func
)) {
148 /* set up platform device info */
149 memset(&plat_info
, 0, sizeof(plat_info
));
150 plat_info
.parent
= &pdev
->dev
;
151 plat_info
.fwnode
= pdev
->dev
.fwnode
;
152 plat_info
.name
= PLAT_DRIVER_NAME
;
153 plat_info
.id
= pdev
->devfn
;
154 wrap
->devfn
= pdev
->devfn
;
155 plat_info
.res
= wrap
->dev_res
;
156 plat_info
.num_res
= ARRAY_SIZE(wrap
->dev_res
);
157 plat_info
.dma_mask
= pdev
->dma_mask
;
158 /* register platform device */
159 wrap
->plat_dev
= platform_device_register_full(&plat_info
);
160 if (IS_ERR(wrap
->plat_dev
)) {
161 pci_disable_device(pdev
);
162 err
= PTR_ERR(wrap
->plat_dev
);
168 pci_set_drvdata(pdev
, wrap
);
172 static void cdns3_pci_remove(struct pci_dev
*pdev
)
174 struct cdns3_wrap
*wrap
;
175 struct pci_dev
*func
;
177 func
= cdns3_get_second_fun(pdev
);
179 wrap
= (struct cdns3_wrap
*)pci_get_drvdata(pdev
);
180 if (wrap
->devfn
== pdev
->devfn
)
181 platform_device_unregister(wrap
->plat_dev
);
183 if (!pci_is_enabled(func
))
187 static const struct pci_device_id cdns3_pci_ids
[] = {
188 { PCI_DEVICE(CDNS_VENDOR_ID
, CDNS_DEVICE_ID
), },
192 static struct pci_driver cdns3_pci_driver
= {
193 .name
= PCI_DRIVER_NAME
,
194 .id_table
= cdns3_pci_ids
,
195 .probe
= cdns3_pci_probe
,
196 .remove
= cdns3_pci_remove
,
199 module_pci_driver(cdns3_pci_driver
);
200 MODULE_DEVICE_TABLE(pci
, cdns3_pci_ids
);
202 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
203 MODULE_LICENSE("GPL v2");
204 MODULE_DESCRIPTION("Cadence USBSS PCI wrapper");