brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · 02b0cfd Raw
204 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Broadcom B43 wireless driver4 *5 * SDIO over Sonics Silicon Backplane bus glue for b43.6 *7 * Copyright (C) 2009 Albert Herranz8 * Copyright (C) 2009 Michael Buesch <m@bues.ch>9 */10 11#include <linux/kernel.h>12#include <linux/mmc/card.h>13#include <linux/mmc/sdio_func.h>14#include <linux/mmc/sdio_ids.h>15#include <linux/slab.h>16#include <linux/ssb/ssb.h>17 18#include "sdio.h"19#include "b43.h"20 21 22#define HNBU_CHIPID		0x01	/* vendor & device id */23 24#define B43_SDIO_BLOCK_SIZE	64	/* rx fifo max size in bytes */25 26 27static const struct b43_sdio_quirk {28	u16 vendor;29	u16 device;30	unsigned int quirks;31} b43_sdio_quirks[] = {32	{ 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, },33	{ },34};35 36 37static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device)38{39	const struct b43_sdio_quirk *q;40 41	for (q = b43_sdio_quirks; q->quirks; q++) {42		if (vendor == q->vendor && device == q->device)43			return q->quirks;44	}45 46	return 0;47}48 49static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)50{51	struct b43_sdio *sdio = sdio_get_drvdata(func);52	struct b43_wldev *dev = sdio->irq_handler_opaque;53 54	if (unlikely(b43_status(dev) < B43_STAT_STARTED))55		return;56 57	sdio_release_host(func);58	sdio->irq_handler(dev);59	sdio_claim_host(func);60}61 62int b43_sdio_request_irq(struct b43_wldev *dev,63			 void (*handler)(struct b43_wldev *dev))64{65	struct ssb_bus *bus = dev->dev->sdev->bus;66	struct sdio_func *func = bus->host_sdio;67	struct b43_sdio *sdio = sdio_get_drvdata(func);68	int err;69 70	sdio->irq_handler_opaque = dev;71	sdio->irq_handler = handler;72	sdio_claim_host(func);73	err = sdio_claim_irq(func, b43_sdio_interrupt_dispatcher);74	sdio_release_host(func);75 76	return err;77}78 79void b43_sdio_free_irq(struct b43_wldev *dev)80{81	struct ssb_bus *bus = dev->dev->sdev->bus;82	struct sdio_func *func = bus->host_sdio;83	struct b43_sdio *sdio = sdio_get_drvdata(func);84 85	sdio_claim_host(func);86	sdio_release_irq(func);87	sdio_release_host(func);88	sdio->irq_handler_opaque = NULL;89	sdio->irq_handler = NULL;90}91 92static int b43_sdio_probe(struct sdio_func *func,93				    const struct sdio_device_id *id)94{95	struct b43_sdio *sdio;96	struct sdio_func_tuple *tuple;97	u16 vendor = 0, device = 0;98	int error;99 100	/* Look for the card chip identifier. */101	tuple = func->tuples;102	while (tuple) {103		switch (tuple->code) {104		case 0x80:105			switch (tuple->data[0]) {106			case HNBU_CHIPID:107				if (tuple->size != 5)108					break;109				vendor = tuple->data[1] | (tuple->data[2]<<8);110				device = tuple->data[3] | (tuple->data[4]<<8);111				dev_info(&func->dev, "Chip ID %04x:%04x\n",112					 vendor, device);113				break;114			default:115				break;116			}117			break;118		default:119			break;120		}121		tuple = tuple->next;122	}123	if (!vendor || !device) {124		error = -ENODEV;125		goto out;126	}127 128	sdio_claim_host(func);129	error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE);130	if (error) {131		dev_err(&func->dev, "failed to set block size to %u bytes,"132			" error %d\n", B43_SDIO_BLOCK_SIZE, error);133		goto err_release_host;134	}135	error = sdio_enable_func(func);136	if (error) {137		dev_err(&func->dev, "failed to enable func, error %d\n", error);138		goto err_release_host;139	}140	sdio_release_host(func);141 142	sdio = kzalloc(sizeof(*sdio), GFP_KERNEL);143	if (!sdio) {144		error = -ENOMEM;145		dev_err(&func->dev, "failed to allocate ssb bus\n");146		goto err_disable_func;147	}148	error = ssb_bus_sdiobus_register(&sdio->ssb, func,149					 b43_sdio_get_quirks(vendor, device));150	if (error) {151		dev_err(&func->dev, "failed to register ssb sdio bus,"152			" error %d\n", error);153		goto err_free_ssb;154	}155	sdio_set_drvdata(func, sdio);156 157	return 0;158 159err_free_ssb:160	kfree(sdio);161err_disable_func:162	sdio_claim_host(func);163	sdio_disable_func(func);164err_release_host:165	sdio_release_host(func);166out:167	return error;168}169 170static void b43_sdio_remove(struct sdio_func *func)171{172	struct b43_sdio *sdio = sdio_get_drvdata(func);173 174	ssb_bus_unregister(&sdio->ssb);175	sdio_claim_host(func);176	sdio_disable_func(func);177	sdio_release_host(func);178	kfree(sdio);179	sdio_set_drvdata(func, NULL);180}181 182static const struct sdio_device_id b43_sdio_ids[] = {183	{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_NINTENDO_WII) },184	{ SDIO_DEVICE(SDIO_VENDOR_ID_CGUYS, SDIO_DEVICE_ID_CGUYS_EW_CG1102GC) },185	{ },186};187 188static struct sdio_driver b43_sdio_driver = {189	.name		= "b43-sdio",190	.id_table	= b43_sdio_ids,191	.probe		= b43_sdio_probe,192	.remove		= b43_sdio_remove,193};194 195int b43_sdio_init(void)196{197	return sdio_register_driver(&b43_sdio_driver);198}199 200void b43_sdio_exit(void)201{202	sdio_unregister_driver(&b43_sdio_driver);203}204