blob: 8cd24766b03c48ecbbfa475f0fe4f723cc4d021e [file] [log] [blame]
/* linux/arch/arm/mach-msm/board-mahimahi-wifi.c
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <linux/skbuff.h>
#include <linux/wlan_plat.h>
#include "board-mahimahi.h"
int mahimahi_wifi_power(int on);
int mahimahi_wifi_reset(int on);
int mahimahi_wifi_set_carddetect(int on);
#define PREALLOC_WLAN_NUMBER_OF_SECTIONS 4
#define PREALLOC_WLAN_NUMBER_OF_BUFFERS 160
#define PREALLOC_WLAN_SECTION_HEADER 24
#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 512)
#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 1024)
#define WLAN_SKB_BUF_NUM 16
static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
typedef struct wifi_mem_prealloc_struct {
void *mem_ptr;
unsigned long size;
} wifi_mem_prealloc_t;
static wifi_mem_prealloc_t wifi_mem_array[PREALLOC_WLAN_NUMBER_OF_SECTIONS] = {
{ NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER) },
{ NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER) },
{ NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER) },
{ NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER) }
};
static void *mahimahi_wifi_mem_prealloc(int section, unsigned long size)
{
if (section == PREALLOC_WLAN_NUMBER_OF_SECTIONS)
return wlan_static_skb;
if ((section < 0) || (section > PREALLOC_WLAN_NUMBER_OF_SECTIONS))
return NULL;
if (wifi_mem_array[section].size < size)
return NULL;
return wifi_mem_array[section].mem_ptr;
}
int __init mahimahi_init_wifi_mem(void)
{
int i;
for(i=0;( i < WLAN_SKB_BUF_NUM );i++) {
if (i < (WLAN_SKB_BUF_NUM/2))
wlan_static_skb[i] = dev_alloc_skb(4096);
else
wlan_static_skb[i] = dev_alloc_skb(8192);
}
for(i=0;( i < PREALLOC_WLAN_NUMBER_OF_SECTIONS );i++) {
wifi_mem_array[i].mem_ptr = kmalloc(wifi_mem_array[i].size,
GFP_KERNEL);
if (wifi_mem_array[i].mem_ptr == NULL)
return -ENOMEM;
}
return 0;
}
static struct resource mahimahi_wifi_resources[] = {
[0] = {
.name = "bcm4329_wlan_irq",
.start = MSM_GPIO_TO_INT(MAHIMAHI_GPIO_WIFI_IRQ),
.end = MSM_GPIO_TO_INT(MAHIMAHI_GPIO_WIFI_IRQ),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE,
},
};
static struct wifi_platform_data mahimahi_wifi_control = {
.set_power = mahimahi_wifi_power,
.set_reset = mahimahi_wifi_reset,
.set_carddetect = mahimahi_wifi_set_carddetect,
.mem_prealloc = mahimahi_wifi_mem_prealloc,
};
static struct platform_device mahimahi_wifi_device = {
.name = "bcm4329_wlan",
.id = 1,
.num_resources = ARRAY_SIZE(mahimahi_wifi_resources),
.resource = mahimahi_wifi_resources,
.dev = {
.platform_data = &mahimahi_wifi_control,
},
};
extern unsigned char *get_wifi_nvs_ram(void);
extern int wifi_calibration_size_set(void);
static unsigned mahimahi_wifi_update_nvs(char *str, int add_flag)
{
#define NVS_LEN_OFFSET 0x0C
#define NVS_DATA_OFFSET 0x40
unsigned char *ptr;
unsigned len;
if (!str)
return -EINVAL;
ptr = get_wifi_nvs_ram();
/* Size in format LE assumed */
memcpy(&len, ptr + NVS_LEN_OFFSET, sizeof(len));
/* if the last byte in NVRAM is 0, trim it */
if (ptr[NVS_DATA_OFFSET + len - 1] == 0)
len -= 1;
if (add_flag) {
strcpy(ptr + NVS_DATA_OFFSET + len, str);
len += strlen(str);
} else {
if (strnstr(ptr + NVS_DATA_OFFSET, str, len))
len -= strlen(str);
}
memcpy(ptr + NVS_LEN_OFFSET, &len, sizeof(len));
wifi_calibration_size_set();
return 0;
}
static int __init mahimahi_wifi_init(void)
{
int ret;
if (!machine_is_mahimahi())
return 0;
printk("%s: start\n", __func__);
mahimahi_wifi_update_nvs("sd_oobonly=1\r\n", 0);
mahimahi_wifi_update_nvs("btc_params70=0x32\r\n", 1);
mahimahi_init_wifi_mem();
ret = platform_device_register(&mahimahi_wifi_device);
return ret;
}
late_initcall(mahimahi_wifi_init);