#include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM #define WLAN_STATIC_SCAN_BUF0 5 #define WLAN_STATIC_SCAN_BUF1 6 #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(65536, GFP_KERNEL); if (!wlan_static_scan_buf0) goto err_mem_alloc; wlan_static_scan_buf1 = kmalloc(65536, 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); #if defined(CONFIG_MACH_U1_NA_SPR) || defined(CONFIG_MACH_U1_NA_USCC) mmc_force_presence_change(&s3c_device_hsmmc2); #else mmc_force_presence_change(&s3c_device_hsmmc3); #endif 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), #ifdef CONFIG_MACH_Q1_BD .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |IORESOURCE_IRQ_SHAREABLE, #else .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, #endif }, }; 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); }