diff options
Diffstat (limited to 'drivers/bcma/main.c')
-rw-r--r-- | drivers/bcma/main.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c new file mode 100644 index 000000000000..be52344ed19d --- /dev/null +++ b/drivers/bcma/main.c | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * Broadcom specific AMBA | ||
3 | * Bus subsystem | ||
4 | * | ||
5 | * Licensed under the GNU/GPL. See COPYING for details. | ||
6 | */ | ||
7 | |||
8 | #include "bcma_private.h" | ||
9 | #include <linux/bcma/bcma.h> | ||
10 | |||
11 | MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); | ||
12 | MODULE_LICENSE("GPL"); | ||
13 | |||
14 | static int bcma_bus_match(struct device *dev, struct device_driver *drv); | ||
15 | static int bcma_device_probe(struct device *dev); | ||
16 | static int bcma_device_remove(struct device *dev); | ||
17 | |||
18 | static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
19 | { | ||
20 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | ||
21 | return sprintf(buf, "0x%03X\n", core->id.manuf); | ||
22 | } | ||
23 | static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
24 | { | ||
25 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | ||
26 | return sprintf(buf, "0x%03X\n", core->id.id); | ||
27 | } | ||
28 | static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
29 | { | ||
30 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | ||
31 | return sprintf(buf, "0x%02X\n", core->id.rev); | ||
32 | } | ||
33 | static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
34 | { | ||
35 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | ||
36 | return sprintf(buf, "0x%X\n", core->id.class); | ||
37 | } | ||
38 | static struct device_attribute bcma_device_attrs[] = { | ||
39 | __ATTR_RO(manuf), | ||
40 | __ATTR_RO(id), | ||
41 | __ATTR_RO(rev), | ||
42 | __ATTR_RO(class), | ||
43 | __ATTR_NULL, | ||
44 | }; | ||
45 | |||
46 | static struct bus_type bcma_bus_type = { | ||
47 | .name = "bcma", | ||
48 | .match = bcma_bus_match, | ||
49 | .probe = bcma_device_probe, | ||
50 | .remove = bcma_device_remove, | ||
51 | .dev_attrs = bcma_device_attrs, | ||
52 | }; | ||
53 | |||
54 | static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) | ||
55 | { | ||
56 | struct bcma_device *core; | ||
57 | |||
58 | list_for_each_entry(core, &bus->cores, list) { | ||
59 | if (core->id.id == coreid) | ||
60 | return core; | ||
61 | } | ||
62 | return NULL; | ||
63 | } | ||
64 | |||
65 | static void bcma_release_core_dev(struct device *dev) | ||
66 | { | ||
67 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | ||
68 | kfree(core); | ||
69 | } | ||
70 | |||
71 | static int bcma_register_cores(struct bcma_bus *bus) | ||
72 | { | ||
73 | struct bcma_device *core; | ||
74 | int err, dev_id = 0; | ||
75 | |||
76 | list_for_each_entry(core, &bus->cores, list) { | ||
77 | /* We support that cores ourself */ | ||
78 | switch (core->id.id) { | ||
79 | case BCMA_CORE_CHIPCOMMON: | ||
80 | case BCMA_CORE_PCI: | ||
81 | case BCMA_CORE_PCIE: | ||
82 | continue; | ||
83 | } | ||
84 | |||
85 | core->dev.release = bcma_release_core_dev; | ||
86 | core->dev.bus = &bcma_bus_type; | ||
87 | dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id); | ||
88 | |||
89 | switch (bus->hosttype) { | ||
90 | case BCMA_HOSTTYPE_PCI: | ||
91 | core->dev.parent = &bus->host_pci->dev; | ||
92 | break; | ||
93 | case BCMA_HOSTTYPE_NONE: | ||
94 | case BCMA_HOSTTYPE_SDIO: | ||
95 | break; | ||
96 | } | ||
97 | |||
98 | err = device_register(&core->dev); | ||
99 | if (err) { | ||
100 | pr_err("Could not register dev for core 0x%03X\n", | ||
101 | core->id.id); | ||
102 | continue; | ||
103 | } | ||
104 | core->dev_registered = true; | ||
105 | dev_id++; | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static void bcma_unregister_cores(struct bcma_bus *bus) | ||
112 | { | ||
113 | struct bcma_device *core; | ||
114 | |||
115 | list_for_each_entry(core, &bus->cores, list) { | ||
116 | if (core->dev_registered) | ||
117 | device_unregister(&core->dev); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | int bcma_bus_register(struct bcma_bus *bus) | ||
122 | { | ||
123 | int err; | ||
124 | struct bcma_device *core; | ||
125 | |||
126 | /* Scan for devices (cores) */ | ||
127 | err = bcma_bus_scan(bus); | ||
128 | if (err) { | ||
129 | pr_err("Failed to scan: %d\n", err); | ||
130 | return -1; | ||
131 | } | ||
132 | |||
133 | /* Init CC core */ | ||
134 | core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); | ||
135 | if (core) { | ||
136 | bus->drv_cc.core = core; | ||
137 | bcma_core_chipcommon_init(&bus->drv_cc); | ||
138 | } | ||
139 | |||
140 | /* Init PCIE core */ | ||
141 | core = bcma_find_core(bus, BCMA_CORE_PCIE); | ||
142 | if (core) { | ||
143 | bus->drv_pci.core = core; | ||
144 | bcma_core_pci_init(&bus->drv_pci); | ||
145 | } | ||
146 | |||
147 | /* Register found cores */ | ||
148 | bcma_register_cores(bus); | ||
149 | |||
150 | pr_info("Bus registered\n"); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | EXPORT_SYMBOL_GPL(bcma_bus_register); | ||
155 | |||
156 | void bcma_bus_unregister(struct bcma_bus *bus) | ||
157 | { | ||
158 | bcma_unregister_cores(bus); | ||
159 | } | ||
160 | EXPORT_SYMBOL_GPL(bcma_bus_unregister); | ||
161 | |||
162 | int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) | ||
163 | { | ||
164 | drv->drv.name = drv->name; | ||
165 | drv->drv.bus = &bcma_bus_type; | ||
166 | drv->drv.owner = owner; | ||
167 | |||
168 | return driver_register(&drv->drv); | ||
169 | } | ||
170 | EXPORT_SYMBOL_GPL(__bcma_driver_register); | ||
171 | |||
172 | void bcma_driver_unregister(struct bcma_driver *drv) | ||
173 | { | ||
174 | driver_unregister(&drv->drv); | ||
175 | } | ||
176 | EXPORT_SYMBOL_GPL(bcma_driver_unregister); | ||
177 | |||
178 | static int bcma_bus_match(struct device *dev, struct device_driver *drv) | ||
179 | { | ||
180 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | ||
181 | struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); | ||
182 | const struct bcma_device_id *cid = &core->id; | ||
183 | const struct bcma_device_id *did; | ||
184 | |||
185 | for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) { | ||
186 | if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) && | ||
187 | (did->id == cid->id || did->id == BCMA_ANY_ID) && | ||
188 | (did->rev == cid->rev || did->rev == BCMA_ANY_REV) && | ||
189 | (did->class == cid->class || did->class == BCMA_ANY_CLASS)) | ||
190 | return 1; | ||
191 | } | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int bcma_device_probe(struct device *dev) | ||
196 | { | ||
197 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | ||
198 | struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, | ||
199 | drv); | ||
200 | int err = 0; | ||
201 | |||
202 | if (adrv->probe) | ||
203 | err = adrv->probe(core); | ||
204 | |||
205 | return err; | ||
206 | } | ||
207 | |||
208 | static int bcma_device_remove(struct device *dev) | ||
209 | { | ||
210 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | ||
211 | struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, | ||
212 | drv); | ||
213 | |||
214 | if (adrv->remove) | ||
215 | adrv->remove(core); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int __init bcma_modinit(void) | ||
221 | { | ||
222 | int err; | ||
223 | |||
224 | err = bus_register(&bcma_bus_type); | ||
225 | if (err) | ||
226 | return err; | ||
227 | |||
228 | #ifdef CONFIG_BCMA_HOST_PCI | ||
229 | err = bcma_host_pci_init(); | ||
230 | if (err) { | ||
231 | pr_err("PCI host initialization failed\n"); | ||
232 | err = 0; | ||
233 | } | ||
234 | #endif | ||
235 | |||
236 | return err; | ||
237 | } | ||
238 | fs_initcall(bcma_modinit); | ||
239 | |||
240 | static void __exit bcma_modexit(void) | ||
241 | { | ||
242 | #ifdef CONFIG_BCMA_HOST_PCI | ||
243 | bcma_host_pci_exit(); | ||
244 | #endif | ||
245 | bus_unregister(&bcma_bus_type); | ||
246 | } | ||
247 | module_exit(bcma_modexit) | ||