1/* 2 * Broadcom B43 wireless driver 3 * 4 * SDIO over Sonics Silicon Backplane bus glue for b43. 5 * 6 * Copyright (C) 2009 Albert Herranz 7 * Copyright (C) 2009 Michael Buesch <m@bues.ch> 8 * 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. 13 */ 14 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> 21 22#include "sdio.h" 23#include "b43.h" 24 25 26#define HNBU_CHIPID 0x01 /* vendor & device id */ 27 28#define B43_SDIO_BLOCK_SIZE 64 /* rx fifo max size in bytes */ 29 30 31static const struct b43_sdio_quirk { 32 u16 vendor; 33 u16 device; 34 unsigned int quirks; 35} b43_sdio_quirks[] = { 36 { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, }, 37 { }, 38}; 39 40 41static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device) 42{ 43 const struct b43_sdio_quirk *q; 44 45 for (q = b43_sdio_quirks; q->quirks; q++) { 46 if (vendor == q->vendor && device == q->device) 47 return q->quirks; 48 } 49 50 return 0; 51} 52 53static void b43_sdio_interrupt_dispatcher(struct sdio_func *func) 54{ 55 struct b43_sdio *sdio = sdio_get_drvdata(func); 56 struct b43_wldev *dev = sdio->irq_handler_opaque; 57 58 if (unlikely(b43_status(dev) < B43_STAT_STARTED)) 59 return; 60 61 sdio_release_host(func); 62 sdio->irq_handler(dev); 63 sdio_claim_host(func); 64} 65 66int b43_sdio_request_irq(struct b43_wldev *dev, 67 void (*handler)(struct b43_wldev *dev)) 68{ 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); 72 int err; 73 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); 79 80 return err; 81} 82 83void b43_sdio_free_irq(struct b43_wldev *dev) 84{ 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); 88 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; 94} 95 96static int b43_sdio_probe(struct sdio_func *func, 97 const struct sdio_device_id *id) 98{ 99 struct b43_sdio *sdio; 100 struct sdio_func_tuple *tuple; 101 u16 vendor = 0, device = 0; 102 int error; 103 104 /* Look for the card chip identifier. */ 105 tuple = func->tuples; 106 while (tuple) { 107 switch (tuple->code) { 108 case 0x80: 109 switch (tuple->data[0]) { 110 case HNBU_CHIPID: 111 if (tuple->size != 5) 112 break; 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", 116 vendor, device); 117 break; 118 default: 119 break; 120 } 121 break; 122 default: 123 break; 124 } 125 tuple = tuple->next; 126 } 127 if (!vendor || !device) { 128 error = -ENODEV; 129 goto out; 130 } 131 132 sdio_claim_host(func); 133 error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE); 134 if (error) { 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; 138 } 139 error = sdio_enable_func(func); 140 if (error) { 141 dev_err(&func->dev, "failed to enable func, error %d\n", error); 142 goto err_release_host; 143 } 144 sdio_release_host(func); 145 146 sdio = kzalloc(sizeof(*sdio), GFP_KERNEL); 147 if (!sdio) { 148 error = -ENOMEM; 149 dev_err(&func->dev, "failed to allocate ssb bus\n"); 150 goto err_disable_func; 151 } 152 error = ssb_bus_sdiobus_register(&sdio->ssb, func, 153 b43_sdio_get_quirks(vendor, device)); 154 if (error) { 155 dev_err(&func->dev, "failed to register ssb sdio bus," 156 " error %d\n", error); 157 goto err_free_ssb; 158 } 159 sdio_set_drvdata(func, sdio); 160 161 return 0; 162 163err_free_ssb: 164 kfree(sdio); 165err_disable_func: 166 sdio_claim_host(func); 167 sdio_disable_func(func); 168err_release_host: 169 sdio_release_host(func); 170out: 171 return error; 172} 173 174static void b43_sdio_remove(struct sdio_func *func) 175{ 176 struct b43_sdio *sdio = sdio_get_drvdata(func); 177 178 ssb_bus_unregister(&sdio->ssb); 179 sdio_claim_host(func); 180 sdio_disable_func(func); 181 sdio_release_host(func); 182 kfree(sdio); 183 sdio_set_drvdata(func, NULL); 184} 185 186static 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 */ 189 { }, 190}; 191 192static struct sdio_driver b43_sdio_driver = { 193 .name = "b43-sdio", 194 .id_table = b43_sdio_ids, 195 .probe = b43_sdio_probe, 196 .remove = b43_sdio_remove, 197}; 198 199int b43_sdio_init(void) 200{ 201 return sdio_register_driver(&b43_sdio_driver); 202} 203 204void b43_sdio_exit(void) 205{ 206 sdio_unregister_driver(&b43_sdio_driver); 207} 208