[package] broadcom-wl: remove an erroneous BUG() call in the glue driver
[openwrt.git] / package / broadcom-wl / src / glue / wl_glue.c
1 /*
2  * wl_glue.c: Broadcom WL support module providing a unified SSB/BCMA handling.
3  * Copyright (C) 2011 Jo-Philipp Wich <jow@openwrt.org>
4  */
5
6 #include "wl_glue.h"
7
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11
12 #ifdef CONFIG_BCM47XX
13 #include <bcm47xx.h>
14 #endif
15
16 #ifdef CONFIG_SSB
17 #include <linux/ssb/ssb.h>
18 #endif
19
20 #ifdef CONFIG_BCMA
21 #include <linux/bcma/bcma.h>
22 #endif
23
24 MODULE_AUTHOR("Jo-Philipp Wich (jow@openwrt.org)");
25 MODULE_DESCRIPTION("Broadcom WL SSB/BCMA compatibility layer");
26 MODULE_LICENSE("GPL");
27
28 static wl_glue_attach_cb_t attach_cb = NULL;
29 static wl_glue_remove_cb_t remove_cb = NULL;
30 static enum wl_glue_bus_type active_bus_type = WL_GLUE_BUS_TYPE_UNSPEC;
31 static int wl_glue_attached = 0;
32
33
34 #ifdef CONFIG_SSB
35 static int wl_glue_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
36 {
37         void *mmio;
38         void *wldev;
39
40         if (!attach_cb)
41         {
42                 pr_err("No attach callback registered\n");
43                 return -ENOSYS;
44         }
45
46         if (dev->bus->bustype != SSB_BUSTYPE_SSB)
47         {
48                 pr_err("Attaching to SSB behind PCI is not supported. Please remove the b43 ssb bridge\n");
49                 return -EINVAL;
50         }
51
52         mmio = (void *) 0x18000000 + dev->core_index * 0x1000;
53         wldev = attach_cb(id->vendor, id->coreid, (ulong)mmio, dev, dev->irq);
54
55         if (!wldev)
56         {
57                 pr_err("The attach callback failed, SSB probe aborted\n");
58                 return -ENODEV;
59         }
60
61         ssb_set_drvdata(dev, wldev);
62         return 0;
63 }
64
65 static void wl_glue_ssb_remove(struct ssb_device *dev)
66 {
67         void *wldev = ssb_get_drvdata(dev);
68
69         if (remove_cb)
70                 remove_cb(wldev);
71
72         ssb_set_drvdata(dev, NULL);
73 }
74
75 static const struct ssb_device_id wl_glue_ssb_tbl[] = {
76         SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, SSB_ANY_REV),
77         SSB_DEVTABLE_END
78 };
79
80 static struct ssb_driver wl_glue_ssb_driver = {
81         .name     = KBUILD_MODNAME,
82         .id_table = wl_glue_ssb_tbl,
83         .probe    = wl_glue_ssb_probe,
84         .remove   = wl_glue_ssb_remove,
85 };
86 #endif /* CONFIG_SSB */
87
88 #ifdef CONFIG_BCMA
89 static int wl_glue_bcma_probe(struct bcma_device *dev)
90 {
91         void *mmio;
92         void *wldev;
93
94         if (!attach_cb)
95         {
96                 pr_err("No attach callback registered\n");
97                 return -ENOSYS;
98         }
99
100         if (dev->bus->hosttype != BCMA_HOSTTYPE_SOC)
101         {
102                 pr_err("Unsupported BCMA bus type %d\n", dev->bus->hosttype);
103                 return -EINVAL;
104         }
105
106         /*
107          * NB:
108          * 0x18000000 = BCMA_ADDR_BASE
109          * 0x1000     = BCMA_CORE_SIZE
110          */
111
112         mmio = (void *) 0x18000000 + dev->core_index * 0x1000;
113         wldev = attach_cb(dev->id.manuf, dev->id.id, (ulong)mmio, dev, dev->irq);
114
115         if (!wldev)
116         {
117                 pr_err("The attach callback failed, BCMA probe aborted\n");
118                 return -ENODEV;
119         }
120
121         bcma_set_drvdata(dev, wldev);
122         return 0;
123 }
124
125 static void wl_glue_bcma_remove(struct bcma_device *dev)
126 {
127         void *wldev = bcma_get_drvdata(dev);
128
129         if (remove_cb)
130                 remove_cb(wldev);
131
132         bcma_set_drvdata(dev, NULL);
133 }
134
135 static const struct bcma_device_id wl_glue_bcma_tbl[] = {
136         BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, BCMA_ANY_REV, BCMA_ANY_CLASS),
137         BCMA_CORETABLE_END
138 };
139
140 static struct bcma_driver wl_glue_bcma_driver = {
141         .name     = KBUILD_MODNAME,
142         .id_table = wl_glue_bcma_tbl,
143         .probe    = wl_glue_bcma_probe,
144         .remove   = wl_glue_bcma_remove,
145 };
146 #endif /* CONFIG_BCMA */
147
148
149 void wl_glue_set_attach_callback(wl_glue_attach_cb_t cb)
150 {
151         attach_cb = cb;
152 }
153 EXPORT_SYMBOL(wl_glue_set_attach_callback);
154
155 void wl_glue_set_remove_callback(wl_glue_remove_cb_t cb)
156 {
157         remove_cb = cb;
158 }
159 EXPORT_SYMBOL(wl_glue_set_remove_callback);
160
161 int wl_glue_register(void)
162 {
163         int err;
164
165         switch(active_bus_type)
166         {
167 #ifdef CONFIG_SSB
168         case WL_GLUE_BUS_TYPE_SSB:
169                 err = ssb_driver_register(&wl_glue_ssb_driver);
170                 break;
171 #endif /* CONFIG_SSB */
172
173 #ifdef CONFIG_BCMA
174         case WL_GLUE_BUS_TYPE_BCMA:
175                 err = bcma_driver_register(&wl_glue_bcma_driver);
176                 break;
177 #endif /* CONFIG_BCMA */
178
179         default:
180                 pr_err("Not attaching through glue driver due to unsupported bus\n");
181                 err = -ENOSYS;
182                 break;
183         }
184
185         if (!err)
186         {
187                 pr_info("SSB/BCMA glue driver successfully attached\n");
188                 wl_glue_attached = 1;
189         }
190
191         return err;
192 }
193 EXPORT_SYMBOL(wl_glue_register);
194
195 int wl_glue_unregister(void)
196 {
197         int err;
198
199         if (!wl_glue_attached)
200                 return -ENOSYS;
201
202         switch (active_bus_type)
203         {
204 #ifdef CONFIG_SSB
205         case WL_GLUE_BUS_TYPE_SSB:
206                 ssb_driver_unregister(&wl_glue_ssb_driver);
207                 err = 0;
208                 break;
209 #endif /* CONFIG_SSB */
210
211 #ifdef CONFIG_BCMA
212         case WL_GLUE_BUS_TYPE_BCMA:
213                 bcma_driver_unregister(&wl_glue_bcma_driver);
214                 err = 0;
215                 break;
216 #endif /* CONFIG_BCMA */
217
218         default:
219                 pr_err("Not removing glue driver due to unsupported bus\n");
220                 err = -ENOSYS;
221                 break;
222         }
223
224         if (!err)
225         {
226                 pr_info("SSB/BCMA glue driver successfully detached\n");
227                 wl_glue_attached = 0;
228         }
229
230         return err;
231 }
232 EXPORT_SYMBOL(wl_glue_unregister);
233
234 struct device * wl_glue_get_dmadev(void *dev)
235 {
236         struct device *dma_dev;
237
238         switch (active_bus_type)
239         {
240 #ifdef CONFIG_SSB
241         case WL_GLUE_BUS_TYPE_SSB:
242                 dma_dev = ((struct ssb_device *)dev)->dma_dev;
243                 break;
244 #endif /* CONFIG_SSB */
245
246 #ifdef CONFIG_BCMA
247         case WL_GLUE_BUS_TYPE_BCMA:
248                 dma_dev = ((struct bcma_device *)dev)->dma_dev;
249                 break;
250 #endif /* CONFIG_BCMA */
251
252         default:
253                 BUG();
254                 dma_dev = NULL;
255                 break;
256         }
257
258         return dma_dev;
259 }
260 EXPORT_SYMBOL(wl_glue_get_dmadev);
261
262
263 static int __init wl_glue_init(void)
264 {
265 #ifdef CONFIG_BCM47XX
266         /*
267          * BCM47xx currently supports either SSB or BCMA bus,
268          * determine the used one from the info set by the
269          * platform setup code.
270          */
271         switch (bcm47xx_bus_type)
272         {
273 #ifdef CONFIG_SSB
274         case BCM47XX_BUS_TYPE_SSB:
275                 active_bus_type = WL_GLUE_BUS_TYPE_SSB;
276                 break;
277 #endif /* CONFIG_SSB */
278
279 #ifdef CONFIG_BCMA
280         case BCM47XX_BUS_TYPE_BCMA:
281                 active_bus_type = WL_GLUE_BUS_TYPE_BCMA;
282                 break;
283 #endif /* CONFIG_BCMA */
284         }
285 #endif /* CONFIG_BCM47XX */
286
287 #ifdef CONFIG_BCM63XX
288 #ifdef CONFIG_SSB
289         /*
290          * BCM63xx currently only uses SSB, so assume that.
291          */
292         active_bus_type = WL_GLUE_BUS_TYPE_SSB;
293 #endif /* CONFIG_SSB */
294 #endif /* CONFIG_BCM63XX */
295
296         /* do not fail here, let wl_glue_register() return -ENOSYS later */
297         if (active_bus_type == WL_GLUE_BUS_TYPE_UNSPEC)
298                 pr_err("Unable to determine used system bus type\n");
299
300         return 0;
301 }
302
303 static void __exit wl_glue_exit(void)
304 {
305         if (wl_glue_attached)
306         {
307                 if (wl_glue_unregister())
308                         pr_err("Failed to unregister glue driver\n");
309
310                 wl_glue_attached = 0;
311         }
312
313         return;
314 }
315
316 module_init(wl_glue_init);
317 module_exit(wl_glue_exit);