[RAMEN9610-20413][9610] wlbt: SCSC Driver version 10.6.1.0
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / drivers / misc / samsung / scsc / pcie_mif_module.c
1 #include <linux/module.h>
2 #include <linux/interrupt.h>
3 #include <linux/pci.h>
4 #include <linux/slab.h>
5 #include <scsc/scsc_logring.h>
6 #include "pcie_mif_module.h"
7 #include "pcie_mif.h"
8
9 /* Implements */
10 #include "scsc_mif_abs.h"
11
12 struct mif_abs_node {
13 struct list_head list;
14 struct scsc_mif_abs *mif_abs;
15 };
16
17 struct mif_driver_node {
18 struct list_head list;
19 struct scsc_mif_abs_driver *driver; /* list of drivers (in practice just the core_module) */
20 };
21
22 struct mif_mmap_node {
23 struct list_head list;
24 struct scsc_mif_mmap_driver *driver; /* list of drivers (in practive just the core_module) */
25 };
26
27 static struct pcie_mif_module {
28 struct list_head mif_abs_list;
29 struct list_head mif_driver_list;
30 struct list_head mif_mmap_list;
31 } mif_module = {
32 .mif_abs_list = LIST_HEAD_INIT(mif_module.mif_abs_list),
33 .mif_driver_list = LIST_HEAD_INIT(mif_module.mif_driver_list),
34 .mif_mmap_list = LIST_HEAD_INIT(mif_module.mif_mmap_list),
35 };
36
37
38 static const struct pci_device_id pcie_mif_module_tbl[] = {
39 { PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_SAMSUNG_SCSC) },
40 { /*End: all zeroes */ }
41 };
42
43 MODULE_DEVICE_TABLE(pci, pcie_mif_module_tbl);
44
45 static void pcie_mif_module_probe_registered_clients(struct scsc_mif_abs *mif_abs)
46 {
47 struct mif_driver_node *mif_driver_node, *next;
48 struct device *dev;
49 bool driver_registered = false;
50
51 /* Traverse Linked List for each mif_driver node */
52 list_for_each_entry_safe(mif_driver_node, next, &mif_module.mif_driver_list, list) {
53 SCSC_TAG_INFO(PCIE_MIF, "node %p\n", mif_driver_node);
54
55 dev = pcie_mif_get_dev(mif_abs);
56 mif_driver_node->driver->probe(mif_driver_node->driver, mif_abs);
57 driver_registered = true;
58 }
59 if (driver_registered == false)
60 SCSC_TAG_INFO(PCIE_MIF, "No mif drivers registered\n");
61 }
62
63 static int pcie_mif_module_probe(struct pci_dev *pdev, const struct pci_device_id *id)
64 {
65 struct mif_abs_node *mif_node;
66 struct scsc_mif_abs *mif_abs;
67
68 mif_node = kzalloc(sizeof(*mif_node), GFP_KERNEL);
69 if (!mif_node)
70 return -ENODEV;
71
72 mif_abs = pcie_mif_create(pdev, id);
73 if (!mif_abs) {
74 SCSC_TAG_INFO(PCIE_MIF, "Error creating PCIe interface\n");
75 kfree(mif_node);
76 return -ENODEV;
77 }
78 /* Add node */
79 mif_node->mif_abs = mif_abs;
80 SCSC_TAG_INFO(PCIE_MIF, "mif_node A %p\n", mif_node);
81 list_add_tail(&mif_node->list, &mif_module.mif_abs_list);
82
83 pcie_mif_module_probe_registered_clients(mif_abs);
84
85 return 0;
86 }
87
88 static void pcie_mif_module_remove(struct pci_dev *pdev)
89 {
90 struct mif_abs_node *mif_node, *next;
91 bool match = false;
92
93 /* Remove node */
94 list_for_each_entry_safe(mif_node, next, &mif_module.mif_abs_list, list) {
95 if (pcie_mif_get_pci_dev(mif_node->mif_abs) == pdev) {
96 match = true;
97 SCSC_TAG_INFO(PCIE_MIF, "Match, destroy pcie_mif\n");
98 pcie_mif_destroy_pcie(pdev, mif_node->mif_abs);
99 list_del(&mif_node->list);
100 kfree(mif_node);
101 }
102 }
103 if (match == false)
104 SCSC_TAG_INFO(PCIE_MIF, "FATAL, no match for given scsc_mif_abs\n");
105 }
106
107 static struct pci_driver scsc_pcie = {
108 .name = DRV_NAME,
109 .id_table = pcie_mif_module_tbl,
110 .probe = pcie_mif_module_probe,
111 .remove = pcie_mif_module_remove,
112 };
113
114 void scsc_mif_abs_register(struct scsc_mif_abs_driver *driver)
115 {
116 struct mif_driver_node *mif_driver_node;
117 struct mif_abs_node *mif_node;
118 struct device *dev;
119
120 /* Add node in driver linked list */
121 mif_driver_node = kzalloc(sizeof(*mif_driver_node), GFP_KERNEL);
122 if (!mif_driver_node)
123 return;
124
125 mif_driver_node->driver = driver;
126 list_add_tail(&mif_driver_node->list, &mif_module.mif_driver_list);
127
128 /* Traverse Linked List for each mif_abs node */
129 list_for_each_entry(mif_node, &mif_module.mif_abs_list, list) {
130 dev = pcie_mif_get_dev(mif_node->mif_abs);
131 driver->probe(driver, mif_node->mif_abs);
132 }
133 }
134 EXPORT_SYMBOL(scsc_mif_abs_register);
135
136 void scsc_mif_abs_unregister(struct scsc_mif_abs_driver *driver)
137 {
138 struct mif_driver_node *mif_driver_node, *next;
139
140 /* Traverse Linked List for each mif_driver node */
141 list_for_each_entry_safe(mif_driver_node, next, &mif_module.mif_driver_list, list) {
142 if (mif_driver_node->driver == driver) {
143 list_del(&mif_driver_node->list);
144 kfree(mif_driver_node);
145 }
146 }
147 }
148 EXPORT_SYMBOL(scsc_mif_abs_unregister);
149
150 /* Register a mmap - debug driver - for this specific transport*/
151 void scsc_mif_mmap_register(struct scsc_mif_mmap_driver *mmap_driver)
152 {
153 struct mif_mmap_node *mif_mmap_node;
154 struct mif_abs_node *mif_node;
155
156 /* Add node in driver linked list */
157 mif_mmap_node = kzalloc(sizeof(*mif_mmap_node), GFP_KERNEL);
158 if (!mif_mmap_node)
159 return;
160
161 mif_mmap_node->driver = mmap_driver;
162 list_add_tail(&mif_mmap_node->list, &mif_module.mif_mmap_list);
163
164 /* Traverse Linked List for each mif_abs node */
165 list_for_each_entry(mif_node, &mif_module.mif_abs_list, list) {
166 mmap_driver->probe(mmap_driver, mif_node->mif_abs);
167 }
168 }
169 EXPORT_SYMBOL(scsc_mif_mmap_register);
170
171 /* Unregister a mmap - debug driver - for this specific transport*/
172 void scsc_mif_mmap_unregister(struct scsc_mif_mmap_driver *mmap_driver)
173 {
174 struct mif_mmap_node *mif_mmap_node, *next;
175
176 /* Traverse Linked List for each mif_mmap_driver node */
177 list_for_each_entry_safe(mif_mmap_node, next, &mif_module.mif_mmap_list, list) {
178 if (mif_mmap_node->driver == mmap_driver) {
179 list_del(&mif_mmap_node->list);
180 kfree(mif_mmap_node);
181 }
182 }
183 }
184 EXPORT_SYMBOL(scsc_mif_mmap_unregister);
185
186 module_pci_driver(scsc_pcie);
187
188 MODULE_DESCRIPTION("SLSI PCIe mx140 MIF abstraction");
189 MODULE_AUTHOR("SLSI");
190 MODULE_LICENSE("GPL");