Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Broadcom B43 wireless driver
0004  *
0005  * SDIO over Sonics Silicon Backplane bus glue for b43.
0006  *
0007  * Copyright (C) 2009 Albert Herranz
0008  * Copyright (C) 2009 Michael Buesch <m@bues.ch>
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/mmc/card.h>
0013 #include <linux/mmc/sdio_func.h>
0014 #include <linux/mmc/sdio_ids.h>
0015 #include <linux/slab.h>
0016 #include <linux/ssb/ssb.h>
0017 
0018 #include "sdio.h"
0019 #include "b43.h"
0020 
0021 
0022 #define HNBU_CHIPID     0x01    /* vendor & device id */
0023 
0024 #define B43_SDIO_BLOCK_SIZE 64  /* rx fifo max size in bytes */
0025 
0026 
0027 static const struct b43_sdio_quirk {
0028     u16 vendor;
0029     u16 device;
0030     unsigned int quirks;
0031 } b43_sdio_quirks[] = {
0032     { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, },
0033     { },
0034 };
0035 
0036 
0037 static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device)
0038 {
0039     const struct b43_sdio_quirk *q;
0040 
0041     for (q = b43_sdio_quirks; q->quirks; q++) {
0042         if (vendor == q->vendor && device == q->device)
0043             return q->quirks;
0044     }
0045 
0046     return 0;
0047 }
0048 
0049 static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)
0050 {
0051     struct b43_sdio *sdio = sdio_get_drvdata(func);
0052     struct b43_wldev *dev = sdio->irq_handler_opaque;
0053 
0054     if (unlikely(b43_status(dev) < B43_STAT_STARTED))
0055         return;
0056 
0057     sdio_release_host(func);
0058     sdio->irq_handler(dev);
0059     sdio_claim_host(func);
0060 }
0061 
0062 int b43_sdio_request_irq(struct b43_wldev *dev,
0063              void (*handler)(struct b43_wldev *dev))
0064 {
0065     struct ssb_bus *bus = dev->dev->sdev->bus;
0066     struct sdio_func *func = bus->host_sdio;
0067     struct b43_sdio *sdio = sdio_get_drvdata(func);
0068     int err;
0069 
0070     sdio->irq_handler_opaque = dev;
0071     sdio->irq_handler = handler;
0072     sdio_claim_host(func);
0073     err = sdio_claim_irq(func, b43_sdio_interrupt_dispatcher);
0074     sdio_release_host(func);
0075 
0076     return err;
0077 }
0078 
0079 void b43_sdio_free_irq(struct b43_wldev *dev)
0080 {
0081     struct ssb_bus *bus = dev->dev->sdev->bus;
0082     struct sdio_func *func = bus->host_sdio;
0083     struct b43_sdio *sdio = sdio_get_drvdata(func);
0084 
0085     sdio_claim_host(func);
0086     sdio_release_irq(func);
0087     sdio_release_host(func);
0088     sdio->irq_handler_opaque = NULL;
0089     sdio->irq_handler = NULL;
0090 }
0091 
0092 static int b43_sdio_probe(struct sdio_func *func,
0093                     const struct sdio_device_id *id)
0094 {
0095     struct b43_sdio *sdio;
0096     struct sdio_func_tuple *tuple;
0097     u16 vendor = 0, device = 0;
0098     int error;
0099 
0100     /* Look for the card chip identifier. */
0101     tuple = func->tuples;
0102     while (tuple) {
0103         switch (tuple->code) {
0104         case 0x80:
0105             switch (tuple->data[0]) {
0106             case HNBU_CHIPID:
0107                 if (tuple->size != 5)
0108                     break;
0109                 vendor = tuple->data[1] | (tuple->data[2]<<8);
0110                 device = tuple->data[3] | (tuple->data[4]<<8);
0111                 dev_info(&func->dev, "Chip ID %04x:%04x\n",
0112                      vendor, device);
0113                 break;
0114             default:
0115                 break;
0116             }
0117             break;
0118         default:
0119             break;
0120         }
0121         tuple = tuple->next;
0122     }
0123     if (!vendor || !device) {
0124         error = -ENODEV;
0125         goto out;
0126     }
0127 
0128     sdio_claim_host(func);
0129     error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE);
0130     if (error) {
0131         dev_err(&func->dev, "failed to set block size to %u bytes,"
0132             " error %d\n", B43_SDIO_BLOCK_SIZE, error);
0133         goto err_release_host;
0134     }
0135     error = sdio_enable_func(func);
0136     if (error) {
0137         dev_err(&func->dev, "failed to enable func, error %d\n", error);
0138         goto err_release_host;
0139     }
0140     sdio_release_host(func);
0141 
0142     sdio = kzalloc(sizeof(*sdio), GFP_KERNEL);
0143     if (!sdio) {
0144         error = -ENOMEM;
0145         dev_err(&func->dev, "failed to allocate ssb bus\n");
0146         goto err_disable_func;
0147     }
0148     error = ssb_bus_sdiobus_register(&sdio->ssb, func,
0149                      b43_sdio_get_quirks(vendor, device));
0150     if (error) {
0151         dev_err(&func->dev, "failed to register ssb sdio bus,"
0152             " error %d\n", error);
0153         goto err_free_ssb;
0154     }
0155     sdio_set_drvdata(func, sdio);
0156 
0157     return 0;
0158 
0159 err_free_ssb:
0160     kfree(sdio);
0161 err_disable_func:
0162     sdio_claim_host(func);
0163     sdio_disable_func(func);
0164 err_release_host:
0165     sdio_release_host(func);
0166 out:
0167     return error;
0168 }
0169 
0170 static void b43_sdio_remove(struct sdio_func *func)
0171 {
0172     struct b43_sdio *sdio = sdio_get_drvdata(func);
0173 
0174     ssb_bus_unregister(&sdio->ssb);
0175     sdio_claim_host(func);
0176     sdio_disable_func(func);
0177     sdio_release_host(func);
0178     kfree(sdio);
0179     sdio_set_drvdata(func, NULL);
0180 }
0181 
0182 static const struct sdio_device_id b43_sdio_ids[] = {
0183     { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_NINTENDO_WII) },
0184     { SDIO_DEVICE(SDIO_VENDOR_ID_CGUYS, SDIO_DEVICE_ID_CGUYS_EW_CG1102GC) },
0185     { },
0186 };
0187 
0188 static struct sdio_driver b43_sdio_driver = {
0189     .name       = "b43-sdio",
0190     .id_table   = b43_sdio_ids,
0191     .probe      = b43_sdio_probe,
0192     .remove     = b43_sdio_remove,
0193 };
0194 
0195 int b43_sdio_init(void)
0196 {
0197     return sdio_register_driver(&b43_sdio_driver);
0198 }
0199 
0200 void b43_sdio_exit(void)
0201 {
0202     sdio_unregister_driver(&b43_sdio_driver);
0203 }