aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/u1-wlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos/u1-wlan.c')
-rw-r--r--arch/arm/mach-exynos/u1-wlan.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/u1-wlan.c b/arch/arm/mach-exynos/u1-wlan.c
new file mode 100644
index 0000000..c570fc8
--- /dev/null
+++ b/arch/arm/mach-exynos/u1-wlan.c
@@ -0,0 +1,329 @@
+#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 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);
+
+ 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),
+#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);
+}