diff options
Diffstat (limited to 'arch/arm/mach-exynos/board-p10-wlan.c')
-rw-r--r-- | arch/arm/mach-exynos/board-p10-wlan.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/board-p10-wlan.c b/arch/arm/mach-exynos/board-p10-wlan.c new file mode 100644 index 0000000..de4b352 --- /dev/null +++ b/arch/arm/mach-exynos/board-p10-wlan.c @@ -0,0 +1,333 @@ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/skbuff.h> +#include <linux/wlan_plat.h> + +#include <plat/devs.h> +#include <plat/sdhci.h> +#include <plat/gpio-cfg.h> +#include <mach/regs-gpio.h> +#include <mach/gpio.h> + +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + +#define WLAN_STATIC_SCAN_BUF0 5 +#define WLAN_STATIC_SCAN_BUF1 6 +#define WLAN_SCAN_BUF_SIZE (64 * 1024) +#define PREALLOC_WLAN_SEC_NUM 4 +#define PREALLOC_WLAN_BUF_NUM 160 +#define PREALLOC_WLAN_SECTION_HEADER 24 + +#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128) +#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512) +#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) + +#define DHD_SKB_HDRSIZE 336 +#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) +#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) +#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) + +#define WLAN_SKB_BUF_NUM 17 + +static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; + +struct wlan_mem_prealloc { + void *mem_ptr; + unsigned long size; +}; + +static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = { + {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)} +}; + +void *wlan_static_scan_buf0; +void *wlan_static_scan_buf1; + +static void *brcm_wlan_mem_prealloc(int section, unsigned long size) +{ + if (section == PREALLOC_WLAN_SEC_NUM) + return wlan_static_skb; + + if (section == WLAN_STATIC_SCAN_BUF0) + return wlan_static_scan_buf0; + + if (section == WLAN_STATIC_SCAN_BUF1) + return wlan_static_scan_buf1; + + if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) + return NULL; + + if (wlan_mem_array[section].size < size) + return NULL; + + return wlan_mem_array[section].mem_ptr; +} + +static int brcm_init_wlan_mem(void) +{ + int i; + int j; + + for (i = 0; i < 8; i++) { + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE); + if (!wlan_static_skb[i]) + goto err_skb_alloc; + } + + for (; i < 16; i++) { + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE); + if (!wlan_static_skb[i]) + goto err_skb_alloc; + } + + wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE); + if (!wlan_static_skb[i]) + goto err_skb_alloc; + + for (i = 0 ; i < PREALLOC_WLAN_SEC_NUM ; i++) { + wlan_mem_array[i].mem_ptr = + kmalloc(wlan_mem_array[i].size, GFP_KERNEL); + + if (!wlan_mem_array[i].mem_ptr) + goto err_mem_alloc; + } + + wlan_static_scan_buf0 = kmalloc (WLAN_SCAN_BUF_SIZE, GFP_KERNEL); + if (!wlan_static_scan_buf0) + goto err_mem_alloc; + + wlan_static_scan_buf1 = kmalloc (WLAN_SCAN_BUF_SIZE, GFP_KERNEL); + if (!wlan_static_scan_buf1) + goto err_mem_alloc; + + printk(KERN_INFO"%s: WIFI MEM Allocated\n", __func__); + return 0; + + err_mem_alloc: + pr_err("Failed to mem_alloc for WLAN\n"); + for (j = 0 ; j < i ; j++) + kfree(wlan_mem_array[j].mem_ptr); + + i = WLAN_SKB_BUF_NUM; + + err_skb_alloc: + pr_err("Failed to skb_alloc for WLAN\n"); + for (j = 0 ; j < i ; j++) + dev_kfree_skb(wlan_static_skb[j]); + + return -ENOMEM; +} +#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ + +static unsigned int wlan_on_gpio_table[][4] = { + {GPIO_WLAN_EN , GPIO_WLAN_EN_AF, GPIO_LEVEL_HIGH, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_HOST_WAKE, GPIO_WLAN_HOST_WAKE_AF, + GPIO_LEVEL_NONE, S3C_GPIO_PULL_DOWN}, +}; + +static unsigned int wlan_off_gpio_table[][4] = { + {GPIO_WLAN_EN , GPIO_WLAN_EN_AF, GPIO_LEVEL_LOW, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_HOST_WAKE, 0 , GPIO_LEVEL_NONE, S3C_GPIO_PULL_DOWN}, +}; + +static unsigned int wlan_sdio_on_table[][4] = { + {GPIO_WLAN_SDIO_CLK, GPIO_WLAN_SDIO_CLK_AF, + GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_CMD, GPIO_WLAN_SDIO_CMD_AF, + GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_D0, GPIO_WLAN_SDIO_D0_AF, + GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_D1, GPIO_WLAN_SDIO_D1_AF, + GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_D2, GPIO_WLAN_SDIO_D2_AF, + GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_D3, GPIO_WLAN_SDIO_D3_AF, + GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, +}; + +static unsigned int wlan_sdio_off_table[][4] = { + {GPIO_WLAN_SDIO_CLK, 1, GPIO_LEVEL_LOW, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_CMD, 0, GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_D0, 0, GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_D1, 0, GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_D2, 0, GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, + {GPIO_WLAN_SDIO_D3, 0, GPIO_LEVEL_NONE, S3C_GPIO_PULL_NONE}, +}; + +static void s3c_config_gpio_alive_table +(int array_size, unsigned int +(*gpio_table)[4]) +{ + u32 i, gpio; + printk(KERN_INFO"gpio_table = [%d] \r\n" , array_size); + for (i = 0; i < array_size; i++) { + gpio = gpio_table[i][0]; + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(gpio_table[i][1])); + s3c_gpio_setpull(gpio, gpio_table[i][3]); + if (gpio_table[i][2] != GPIO_LEVEL_NONE) + gpio_set_value(gpio, gpio_table[i][2]); + } +} + +static int brcm_wlan_power(int onoff) +{ + printk(KERN_INFO"------------------------------------------------"); + printk(KERN_INFO"------------------------------------------------\n"); + printk(KERN_INFO"%s Enter: power %s\n", __func__, onoff ? "on" : "off"); + if (onoff) { + s3c_config_gpio_alive_table + (ARRAY_SIZE(wlan_on_gpio_table), wlan_on_gpio_table); + udelay(200); + gpio_set_value(GPIO_WLAN_EN, GPIO_LEVEL_HIGH); + printk(KERN_DEBUG"WLAN: GPIO_WLAN_EN = %d\n", + gpio_get_value(GPIO_WLAN_EN)); + } else { + gpio_set_value(GPIO_WLAN_EN, GPIO_LEVEL_LOW); + s3c_config_gpio_alive_table + (ARRAY_SIZE(wlan_off_gpio_table), wlan_off_gpio_table); + printk(KERN_DEBUG"WLAN: GPIO_WLAN_EN = %d\n", + gpio_get_value(GPIO_WLAN_EN)); + } + + return 0; +} + +static int brcm_wlan_reset(int onoff) +{ + gpio_set_value(GPIO_WLAN_EN, + onoff ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW); + return 0; +} + +static int brcm_wlan_set_carddetect(int onoff) +{ + if (onoff) { + s3c_config_gpio_alive_table( +ARRAY_SIZE(wlan_sdio_on_table), wlan_sdio_on_table); + } else { + s3c_config_gpio_alive_table( +ARRAY_SIZE(wlan_sdio_off_table), wlan_sdio_off_table); } + + udelay(200); + + mmc_force_presence_change(&s3c_device_hsmmc3); + msleep(500); /* wait for carddetect */ + return 0; +} + +/* Customized Locale table : OPTIONAL feature */ +#define WLC_CNTRY_BUF_SZ 4 +struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; + char custom_locale[WLC_CNTRY_BUF_SZ]; + int custom_locale_rev; +}; + +static struct cntry_locales_custom brcm_wlan_translate_custom_table[] = { + /* Table should be filled out based + on custom platform regulatory requirement */ + {"", "XY", 4}, /* universal */ + {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ + {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ + {"EU", "EU", 5}, /* European union countries */ + {"AT", "EU", 5}, + {"BE", "EU", 5}, + {"BG", "EU", 5}, + {"CY", "EU", 5}, + {"CZ", "EU", 5}, + {"DK", "EU", 5}, + {"EE", "EU", 5}, + {"FI", "EU", 5}, + {"FR", "EU", 5}, + {"DE", "EU", 5}, + {"GR", "EU", 5}, + {"HU", "EU", 5}, + {"IE", "EU", 5}, + {"IT", "EU", 5}, + {"LV", "EU", 5}, + {"LI", "EU", 5}, + {"LT", "EU", 5}, + {"LU", "EU", 5}, + {"MT", "EU", 5}, + {"NL", "EU", 5}, + {"PL", "EU", 5}, + {"PT", "EU", 5}, + {"RO", "EU", 5}, + {"SK", "EU", 5}, + {"SI", "EU", 5}, + {"ES", "EU", 5}, + {"SE", "EU", 5}, + {"GB", "EU", 5}, /* input ISO "GB" to : EU regrev 05 */ + {"IL", "IL", 0}, + {"CH", "CH", 0}, + {"TR", "TR", 0}, + {"NO", "NO", 0}, + {"KR", "XY", 3}, + {"AU", "XY", 3}, + {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ + {"TW", "XY", 3}, + {"AR", "XY", 3}, + {"MX", "XY", 3} +}; + +static void *brcm_wlan_get_country_code(char *ccode) +{ + int size = ARRAY_SIZE(brcm_wlan_translate_custom_table); + int i; + + if (!ccode) + return NULL; + + for (i = 0; i < size; i++) + if (strcmp(ccode, + brcm_wlan_translate_custom_table[i].iso_abbrev) == 0) + return &brcm_wlan_translate_custom_table[i]; + return &brcm_wlan_translate_custom_table[0]; +} + +static struct resource brcm_wlan_resources[] = { + [0] = { + .name = "bcmdhd_wlan_irq", + .start = IRQ_EINT(21), + .end = IRQ_EINT(21), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE, + }, +}; + +static struct wifi_platform_data brcm_wlan_control = { + .set_power = brcm_wlan_power, + .set_reset = brcm_wlan_reset, + .set_carddetect = brcm_wlan_set_carddetect, +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + .mem_prealloc = brcm_wlan_mem_prealloc, +#endif + .get_country_code = brcm_wlan_get_country_code, +}; + +static struct platform_device brcm_device_wlan = { + .name = "bcmdhd_wlan", + .id = 1, + .num_resources = ARRAY_SIZE(brcm_wlan_resources), + .resource = brcm_wlan_resources, + .dev = { + .platform_data = &brcm_wlan_control, + }, +}; + +int __init brcm_wlan_init(void) +{ + printk(KERN_INFO"%s: start\n", __func__); + +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + brcm_init_wlan_mem(); +#endif + + return platform_device_register(&brcm_device_wlan); +} |