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 <mb@bu3sch.de>
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/ssb/ssb.h>
25 #define HNBU_CHIPID 0x01 /* vendor & device id */
27 #define B43_SDIO_BLOCK_SIZE 64 /* rx fifo max size in bytes */
30 static const struct b43_sdio_quirk
{
34 } b43_sdio_quirks
[] = {
35 { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32
, },
40 static unsigned int b43_sdio_get_quirks(u16 vendor
, u16 device
)
42 const struct b43_sdio_quirk
*q
;
44 for (q
= b43_sdio_quirks
; q
->quirks
; q
++) {
45 if (vendor
== q
->vendor
&& device
== q
->device
)
52 static void b43_sdio_interrupt_dispatcher(struct sdio_func
*func
)
54 struct b43_sdio
*sdio
= sdio_get_drvdata(func
);
55 struct b43_wldev
*dev
= sdio
->irq_handler_opaque
;
57 if (unlikely(b43_status(dev
) < B43_STAT_STARTED
))
60 sdio_release_host(func
);
61 sdio
->irq_handler(dev
);
62 sdio_claim_host(func
);
65 int b43_sdio_request_irq(struct b43_wldev
*dev
,
66 void (*handler
)(struct b43_wldev
*dev
))
68 struct ssb_bus
*bus
= dev
->dev
->bus
;
69 struct sdio_func
*func
= bus
->host_sdio
;
70 struct b43_sdio
*sdio
= sdio_get_drvdata(func
);
73 sdio
->irq_handler_opaque
= dev
;
74 sdio
->irq_handler
= handler
;
75 sdio_claim_host(func
);
76 err
= sdio_claim_irq(func
, b43_sdio_interrupt_dispatcher
);
77 sdio_release_host(func
);
82 void b43_sdio_free_irq(struct b43_wldev
*dev
)
84 struct ssb_bus
*bus
= dev
->dev
->bus
;
85 struct sdio_func
*func
= bus
->host_sdio
;
86 struct b43_sdio
*sdio
= sdio_get_drvdata(func
);
88 sdio_claim_host(func
);
89 sdio_release_irq(func
);
90 sdio_release_host(func
);
91 sdio
->irq_handler_opaque
= NULL
;
92 sdio
->irq_handler
= NULL
;
95 static int b43_sdio_probe(struct sdio_func
*func
,
96 const struct sdio_device_id
*id
)
98 struct b43_sdio
*sdio
;
99 struct sdio_func_tuple
*tuple
;
100 u16 vendor
= 0, device
= 0;
103 /* Look for the card chip identifier. */
104 tuple
= func
->tuples
;
106 switch (tuple
->code
) {
108 switch (tuple
->data
[0]) {
110 if (tuple
->size
!= 5)
112 vendor
= tuple
->data
[1] | (tuple
->data
[2]<<8);
113 device
= tuple
->data
[3] | (tuple
->data
[4]<<8);
114 dev_info(&func
->dev
, "Chip ID %04x:%04x\n",
126 if (!vendor
|| !device
) {
131 sdio_claim_host(func
);
132 error
= sdio_set_block_size(func
, B43_SDIO_BLOCK_SIZE
);
134 dev_err(&func
->dev
, "failed to set block size to %u bytes,"
135 " error %d\n", B43_SDIO_BLOCK_SIZE
, error
);
136 goto err_release_host
;
138 error
= sdio_enable_func(func
);
140 dev_err(&func
->dev
, "failed to enable func, error %d\n", error
);
141 goto err_release_host
;
143 sdio_release_host(func
);
145 sdio
= kzalloc(sizeof(*sdio
), GFP_KERNEL
);
148 dev_err(&func
->dev
, "failed to allocate ssb bus\n");
149 goto err_disable_func
;
151 error
= ssb_bus_sdiobus_register(&sdio
->ssb
, func
,
152 b43_sdio_get_quirks(vendor
, device
));
154 dev_err(&func
->dev
, "failed to register ssb sdio bus,"
155 " error %d\n", error
);
158 sdio_set_drvdata(func
, sdio
);
165 sdio_disable_func(func
);
167 sdio_release_host(func
);
172 static void b43_sdio_remove(struct sdio_func
*func
)
174 struct b43_sdio
*sdio
= sdio_get_drvdata(func
);
176 ssb_bus_unregister(&sdio
->ssb
);
177 sdio_disable_func(func
);
179 sdio_set_drvdata(func
, NULL
);
182 static const struct sdio_device_id b43_sdio_ids
[] = {
183 { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
187 static struct sdio_driver b43_sdio_driver
= {
189 .id_table
= b43_sdio_ids
,
190 .probe
= b43_sdio_probe
,
191 .remove
= b43_sdio_remove
,
194 int b43_sdio_init(void)
196 return sdio_register_driver(&b43_sdio_driver
);
199 void b43_sdio_exit(void)
201 sdio_unregister_driver(&b43_sdio_driver
);