Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0+ |
efed421a AP |
2 | /* |
3 | * bdc_pci.c - BRCM BDC USB3.0 device controller PCI interface file. | |
4 | * | |
5 | * Copyright (C) 2014 Broadcom Corporation | |
6 | * | |
7 | * Author: Ashwini Pahuja | |
8 | * | |
9 | * Based on drivers under drivers/usb/ | |
efed421a AP |
10 | */ |
11 | ||
12 | #include <linux/kernel.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/slab.h> | |
15 | #include <linux/pci.h> | |
16 | #include <linux/pci_ids.h> | |
17 | #include <linux/platform_device.h> | |
18 | ||
19 | #include "bdc.h" | |
20 | ||
21 | #define BDC_PCI_PID 0x1570 | |
22 | ||
23 | struct bdc_pci { | |
24 | struct device *dev; | |
25 | struct platform_device *bdc; | |
26 | }; | |
27 | ||
28 | static int bdc_setup_msi(struct pci_dev *pci) | |
29 | { | |
30 | int ret; | |
31 | ||
32 | ret = pci_enable_msi(pci); | |
33 | if (ret) { | |
34 | pr_err("failed to allocate MSI entry\n"); | |
35 | return ret; | |
36 | } | |
37 | ||
38 | return ret; | |
39 | } | |
40 | ||
41 | static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) | |
42 | { | |
43 | struct resource res[2]; | |
44 | struct platform_device *bdc; | |
45 | struct bdc_pci *glue; | |
46 | int ret = -ENOMEM; | |
47 | ||
48 | glue = devm_kzalloc(&pci->dev, sizeof(*glue), GFP_KERNEL); | |
49 | if (!glue) | |
50 | return -ENOMEM; | |
51 | ||
52 | glue->dev = &pci->dev; | |
53 | ret = pci_enable_device(pci); | |
54 | if (ret) { | |
55 | dev_err(&pci->dev, "failed to enable pci device\n"); | |
56 | return -ENODEV; | |
57 | } | |
58 | pci_set_master(pci); | |
59 | ||
60 | bdc = platform_device_alloc(BRCM_BDC_NAME, PLATFORM_DEVID_AUTO); | |
61 | if (!bdc) | |
62 | return -ENOMEM; | |
63 | ||
64 | memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); | |
65 | bdc_setup_msi(pci); | |
66 | ||
67 | res[0].start = pci_resource_start(pci, 0); | |
68 | res[0].end = pci_resource_end(pci, 0); | |
69 | res[0].name = BRCM_BDC_NAME; | |
70 | res[0].flags = IORESOURCE_MEM; | |
71 | ||
72 | res[1].start = pci->irq; | |
73 | res[1].name = BRCM_BDC_NAME; | |
74 | res[1].flags = IORESOURCE_IRQ; | |
75 | ||
76 | ret = platform_device_add_resources(bdc, res, ARRAY_SIZE(res)); | |
77 | if (ret) { | |
78 | dev_err(&pci->dev, | |
79 | "couldn't add resources to bdc device\n"); | |
8874ae5f | 80 | platform_device_put(bdc); |
efed421a AP |
81 | return ret; |
82 | } | |
83 | ||
84 | pci_set_drvdata(pci, glue); | |
85 | ||
86 | dma_set_coherent_mask(&bdc->dev, pci->dev.coherent_dma_mask); | |
87 | ||
88 | bdc->dev.dma_mask = pci->dev.dma_mask; | |
89 | bdc->dev.dma_parms = pci->dev.dma_parms; | |
90 | bdc->dev.parent = &pci->dev; | |
91 | glue->bdc = bdc; | |
92 | ||
93 | ret = platform_device_add(bdc); | |
94 | if (ret) { | |
95 | dev_err(&pci->dev, "failed to register bdc device\n"); | |
96 | platform_device_put(bdc); | |
97 | return ret; | |
98 | } | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
103 | static void bdc_pci_remove(struct pci_dev *pci) | |
104 | { | |
105 | struct bdc_pci *glue = pci_get_drvdata(pci); | |
106 | ||
107 | platform_device_unregister(glue->bdc); | |
108 | pci_disable_msi(pci); | |
109 | } | |
110 | ||
111 | static struct pci_device_id bdc_pci_id_table[] = { | |
112 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, BDC_PCI_PID), }, | |
113 | {} /* Terminating Entry */ | |
114 | }; | |
115 | ||
116 | MODULE_DEVICE_TABLE(pci, bdc_pci_id_table); | |
117 | ||
118 | static struct pci_driver bdc_pci_driver = { | |
119 | .name = "bdc-pci", | |
120 | .id_table = bdc_pci_id_table, | |
121 | .probe = bdc_pci_probe, | |
122 | .remove = bdc_pci_remove, | |
123 | }; | |
124 | ||
125 | MODULE_AUTHOR("Ashwini Pahuja <ashwini.linux@gmail.com>"); | |
126 | MODULE_LICENSE("GPL"); | |
127 | MODULE_DESCRIPTION("BRCM BDC USB3 PCI Glue layer"); | |
128 | module_pci_driver(bdc_pci_driver); |