2 * Broadcom B43 wireless driver
4 * SDIO over Sonics Silicon Backplane bus glue for b43.
6 * Copyright (C) 2009 Albert Herranz
7 * Copyright (C) 2009 Michael Buesch <m@bues.ch>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
15 #include <linux/kernel.h>
16 #include <linux/mmc/card.h>
17 #include <linux/mmc/sdio_func.h>
18 #include <linux/mmc/sdio_ids.h>
19 #include <linux/slab.h>
20 #include <linux/ssb/ssb.h>
26 #define HNBU_CHIPID 0x01 /* vendor & device id */
28 #define B43_SDIO_BLOCK_SIZE 64 /* rx fifo max size in bytes */
31 static const struct b43_sdio_quirk
{
35 } b43_sdio_quirks
[] = {
36 { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32
, },
41 static unsigned int b43_sdio_get_quirks(u16 vendor
, u16 device
)
43 const struct b43_sdio_quirk
*q
;
45 for (q
= b43_sdio_quirks
; q
->quirks
; q
++) {
46 if (vendor
== q
->vendor
&& device
== q
->device
)
53 static void b43_sdio_interrupt_dispatcher(struct sdio_func
*func
)
55 struct b43_sdio
*sdio
= sdio_get_drvdata(func
);
56 struct b43_wldev
*dev
= sdio
->irq_handler_opaque
;
58 if (unlikely(b43_status(dev
) < B43_STAT_STARTED
))
61 sdio_release_host(func
);
62 sdio
->irq_handler(dev
);
63 sdio_claim_host(func
);
66 int b43_sdio_request_irq(struct b43_wldev
*dev
,
67 void (*handler
)(struct b43_wldev
*dev
))
69 struct ssb_bus
*bus
= dev
->dev
->sdev
->bus
;
70 struct sdio_func
*func
= bus
->host_sdio
;
71 struct b43_sdio
*sdio
= sdio_get_drvdata(func
);
74 sdio
->irq_handler_opaque
= dev
;
75 sdio
->irq_handler
= handler
;
76 sdio_claim_host(func
);
77 err
= sdio_claim_irq(func
, b43_sdio_interrupt_dispatcher
);
78 sdio_release_host(func
);
83 void b43_sdio_free_irq(struct b43_wldev
*dev
)
85 struct ssb_bus
*bus
= dev
->dev
->sdev
->bus
;
86 struct sdio_func
*func
= bus
->host_sdio
;
87 struct b43_sdio
*sdio
= sdio_get_drvdata(func
);
89 sdio_claim_host(func
);
90 sdio_release_irq(func
);
91 sdio_release_host(func
);
92 sdio
->irq_handler_opaque
= NULL
;
93 sdio
->irq_handler
= NULL
;
96 static int __devinit
b43_sdio_probe(struct sdio_func
*func
,
97 const struct sdio_device_id
*id
)
99 struct b43_sdio
*sdio
;
100 struct sdio_func_tuple
*tuple
;
101 u16 vendor
= 0, device
= 0;
104 /* Look for the card chip identifier. */
105 tuple
= func
->tuples
;
107 switch (tuple
->code
) {
109 switch (tuple
->data
[0]) {
111 if (tuple
->size
!= 5)
113 vendor
= tuple
->data
[1] | (tuple
->data
[2]<<8);
114 device
= tuple
->data
[3] | (tuple
->data
[4]<<8);
115 dev_info(&func
->dev
, "Chip ID %04x:%04x\n",
127 if (!vendor
|| !device
) {
132 sdio_claim_host(func
);
133 error
= sdio_set_block_size(func
, B43_SDIO_BLOCK_SIZE
);
135 dev_err(&func
->dev
, "failed to set block size to %u bytes,"
136 " error %d\n", B43_SDIO_BLOCK_SIZE
, error
);
137 goto err_release_host
;
139 error
= sdio_enable_func(func
);
141 dev_err(&func
->dev
, "failed to enable func, error %d\n", error
);
142 goto err_release_host
;
144 sdio_release_host(func
);
146 sdio
= kzalloc(sizeof(*sdio
), GFP_KERNEL
);
149 dev_err(&func
->dev
, "failed to allocate ssb bus\n");
150 goto err_disable_func
;
152 error
= ssb_bus_sdiobus_register(&sdio
->ssb
, func
,
153 b43_sdio_get_quirks(vendor
, device
));
155 dev_err(&func
->dev
, "failed to register ssb sdio bus,"
156 " error %d\n", error
);
159 sdio_set_drvdata(func
, sdio
);
166 sdio_claim_host(func
);
167 sdio_disable_func(func
);
169 sdio_release_host(func
);
174 static void __devexit
b43_sdio_remove(struct sdio_func
*func
)
176 struct b43_sdio
*sdio
= sdio_get_drvdata(func
);
178 ssb_bus_unregister(&sdio
->ssb
);
179 sdio_claim_host(func
);
180 sdio_disable_func(func
);
181 sdio_release_host(func
);
183 sdio_set_drvdata(func
, NULL
);
186 static const struct sdio_device_id b43_sdio_ids
[] = {
187 { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
188 { SDIO_DEVICE(0x0092, 0x0004) }, /* C-guys, Inc. EW-CG1102GC */
192 static struct sdio_driver b43_sdio_driver
= {
194 .id_table
= b43_sdio_ids
,
195 .probe
= b43_sdio_probe
,
196 .remove
= b43_sdio_remove
,
199 int b43_sdio_init(void)
201 return sdio_register_driver(&b43_sdio_driver
);
204 void b43_sdio_exit(void)
206 sdio_unregister_driver(&b43_sdio_driver
);