alistair23-linux/drivers/staging/wilc1000/linux_wlan_sdio.c
Johnny Kim c5c77ba18e staging: wilc1000: Add SDIO/SPI 802.11 driver
This driver is for the wilc1000 which is a single chip IEEE 802.11
b/g/n device.
The driver works together with cfg80211, which is the kernel side of
configuration management for wireless devices because the wilc1000
chipset is fullmac where the MLME is managed in hardware.

The driver worked from kernel version 2.6.38 and being now ported
to several others since then.
A TODO file is included as well in this commit.

Signed-off-by: Johnny Kim <johnny.kim@atmel.com>
Signed-off-by: Rachel Kim <rachel.kim@atmel.com>
Signed-off-by: Dean Lee <dean.lee@atmel.com>
Signed-off-by: Chris Park <chris.park@atmel.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-05-24 13:36:53 -07:00

250 lines
4.8 KiB
C

#include "wilc_wfi_netdevice.h"
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/host.h>
#if defined (NM73131_0_BOARD)
#define SDIO_MODALIAS "wilc_sdio"
#else
#define SDIO_MODALIAS "wilc1000_sdio"
#endif
#if defined (NM73131_0_BOARD)
#define MAX_SPEED 50000000
#elif defined(CUSTOMER_PLATFORM)
/* TODO : User have to stable bus clock as user's environment. */
#ifdef MAX_BUS_SPEED
#define MAX_SPEED MAX_BUS_SPEED
#else
#define MAX_SPEED 50000000
#endif
#else
#define MAX_SPEED (6 * 1000000) /* Max 50M */
#endif
struct sdio_func *local_sdio_func;
extern linux_wlan_t *g_linux_wlan;
extern int wilc_netdev_init(void);
extern int sdio_clear_int(void);
extern void wilc_handle_isr(void);
static unsigned int sdio_default_speed;
#define SDIO_VENDOR_ID_WILC 0x0296
#define SDIO_DEVICE_ID_WILC 0x5347
static const struct sdio_device_id wilc_sdio_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) },
};
static void wilc_sdio_interrupt(struct sdio_func *func)
{
#ifndef WILC_SDIO_IRQ_GPIO
sdio_release_host(func);
wilc_handle_isr();
sdio_claim_host(func);
#endif
}
int linux_sdio_cmd52(sdio_cmd52_t *cmd)
{
struct sdio_func *func = g_linux_wlan->wilc_sdio_func;
int ret;
u8 data;
sdio_claim_host(func);
func->num = cmd->function;
if (cmd->read_write) { /* write */
if (cmd->raw) {
sdio_writeb(func, cmd->data, cmd->address, &ret);
data = sdio_readb(func, cmd->address, &ret);
cmd->data = data;
} else {
sdio_writeb(func, cmd->data, cmd->address, &ret);
}
} else { /* read */
data = sdio_readb(func, cmd->address, &ret);
cmd->data = data;
}
sdio_release_host(func);
if (ret < 0) {
PRINT_ER("wilc_sdio_cmd52..failed, err(%d)\n", ret);
return 0;
}
return 1;
}
int linux_sdio_cmd53(sdio_cmd53_t *cmd)
{
struct sdio_func *func = g_linux_wlan->wilc_sdio_func;
int size, ret;
sdio_claim_host(func);
func->num = cmd->function;
func->cur_blksize = cmd->block_size;
if (cmd->block_mode)
size = cmd->count * cmd->block_size;
else
size = cmd->count;
if (cmd->read_write) { /* write */
ret = sdio_memcpy_toio(func, cmd->address, (void *)cmd->buffer, size);
} else { /* read */
ret = sdio_memcpy_fromio(func, (void *)cmd->buffer, cmd->address, size);
}
sdio_release_host(func);
if (ret < 0) {
PRINT_ER("wilc_sdio_cmd53..failed, err(%d)\n", ret);
return 0;
}
return 1;
}
volatile int probe; /* COMPLEMENT_BOOT */
static int linux_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
{
PRINT_D(INIT_DBG, "probe function\n");
#ifdef COMPLEMENT_BOOT
if (local_sdio_func != NULL) {
local_sdio_func = func;
probe = 1;
PRINT_D(INIT_DBG, "local_sdio_func isn't NULL\n");
return 0;
}
#endif
PRINT_D(INIT_DBG, "Initializing netdev\n");
local_sdio_func = func;
if (wilc_netdev_init()) {
PRINT_ER("Couldn't initialize netdev\n");
return -1;
}
printk("Driver Initializing success\n");
return 0;
}
static void linux_sdio_remove(struct sdio_func *func)
{
/**
* TODO
**/
}
struct sdio_driver wilc_bus = {
.name = SDIO_MODALIAS,
.id_table = wilc_sdio_ids,
.probe = linux_sdio_probe,
.remove = linux_sdio_remove,
};
int enable_sdio_interrupt(void)
{
int ret = 0;
#ifndef WILC_SDIO_IRQ_GPIO
sdio_claim_host(local_sdio_func);
ret = sdio_claim_irq(local_sdio_func, wilc_sdio_interrupt);
sdio_release_host(local_sdio_func);
if (ret < 0) {
PRINT_ER("can't claim sdio_irq, err(%d)\n", ret);
ret = -EIO;
}
#endif
return ret;
}
void disable_sdio_interrupt(void)
{
#ifndef WILC_SDIO_IRQ_GPIO
int ret;
PRINT_D(INIT_DBG, "disable_sdio_interrupt IN\n");
sdio_claim_host(local_sdio_func);
ret = sdio_release_irq(local_sdio_func);
if (ret < 0) {
PRINT_ER("can't release sdio_irq, err(%d)\n", ret);
}
sdio_release_host(local_sdio_func);
PRINT_D(INIT_DBG, "disable_sdio_interrupt OUT\n");
#endif
}
static int linux_sdio_set_speed(int speed)
{
struct mmc_ios ios;
sdio_claim_host(local_sdio_func);
memcpy((void *)&ios, (void *)&local_sdio_func->card->host->ios, sizeof(struct mmc_ios));
local_sdio_func->card->host->ios.clock = speed;
ios.clock = speed;
local_sdio_func->card->host->ops->set_ios(local_sdio_func->card->host, &ios);
sdio_release_host(local_sdio_func);
PRINT_INFO(INIT_DBG, "@@@@@@@@@@@@ change SDIO speed to %d @@@@@@@@@\n", speed);
return 1;
}
static int linux_sdio_get_speed(void)
{
return local_sdio_func->card->host->ios.clock;
}
int linux_sdio_init(void *pv)
{
/**
* TODO :
**/
sdio_default_speed = linux_sdio_get_speed();
return 1;
}
void linux_sdio_deinit(void *pv)
{
/**
* TODO :
**/
sdio_unregister_driver(&wilc_bus);
}
int linux_sdio_set_max_speed(void)
{
return linux_sdio_set_speed(MAX_SPEED);
}
int linux_sdio_set_default_speed(void)
{
return linux_sdio_set_speed(sdio_default_speed);
}