diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_custom_exynos.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_custom_exynos.c | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_exynos.c b/drivers/net/wireless/bcmdhd/dhd_custom_exynos.c new file mode 100644 index 0000000..43d705c --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_custom_exynos.c @@ -0,0 +1,345 @@ +/* + * Platform Dependent file for Samsung Exynos + * + * Copyright (C) 1999-2014, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_custom_exynos.c 459213 2014-03-01 06:26:09Z $ + */ +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/poll.h> +#include <linux/miscdevice.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/list.h> +#include <linux/io.h> +#include <linux/workqueue.h> +#include <linux/unistd.h> +#include <linux/bug.h> +#include <linux/skbuff.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/wlan_plat.h> + +#include <mach/gpio.h> +#include <mach/irqs.h> +#include <linux/sec_sysfs.h> + +#include <plat/gpio-cfg.h> + +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + +#define WLAN_STATIC_SCAN_BUF0 5 +#define WLAN_STATIC_SCAN_BUF1 6 +#define WLAN_STATIC_DHD_INFO_BUF 7 +#define WLAN_SCAN_BUF_SIZE (64 * 1024) +#define WLAN_DHD_INFO_BUF_SIZE (16 * 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; +void *wlan_static_dhd_info_buf; + +static void *dhd_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 == WLAN_STATIC_DHD_INFO_BUF) { + if (size > WLAN_DHD_INFO_BUF_SIZE) { + pr_err("request DHD_INFO size(%lu) is bigger than" + " static size(%d).\n", size, + WLAN_DHD_INFO_BUF_SIZE); + return NULL; + } + return wlan_static_dhd_info_buf; + } + + 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 dhd_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; + + wlan_static_dhd_info_buf = kmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL); + if (!wlan_static_dhd_info_buf) + goto err_mem_alloc; + + pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__); + return 0; + +err_mem_alloc: + pr_err("Failed to mem_alloc for WLAN\n"); + if (wlan_static_scan_buf0) + kfree(wlan_static_scan_buf0); + if (wlan_static_scan_buf1) + kfree(wlan_static_scan_buf1); + if (wlan_static_dhd_info_buf) + kfree(wlan_static_dhd_info_buf); + + 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 struct device *wlan_dev; +static int wlan_pwr_on = -1; +static int wlan_host_wake_irq = 0; + +static int dhd_wlan_power(int onoff) +{ + printk(KERN_INFO"------------------------------------------------"); + printk(KERN_INFO"------------------------------------------------\n"); + printk(KERN_INFO"%s Enter: power %s\n", __FUNCTION__, onoff ? "on" : "off"); + + if (gpio_direction_output(wlan_pwr_on, onoff)) { + printk(KERN_ERR "%s failed to control WLAN_REG_ON to %s\n", + __FUNCTION__, onoff ? "HIGH" : "LOW"); + return -EIO; + } + + return 0; +} + +static int dhd_wlan_reset(int onoff) +{ + return 0; +} + +extern void (*notify_func_callback)(void *dev_id, int state); +extern void *mmc_host_dev; + +static int dhd_wlan_set_carddetect(int val) +{ + pr_err("%s: notify_func=%p, mmc_host_dev=%p, val=%d\n", + __FUNCTION__, notify_func_callback, mmc_host_dev, val); + + if (notify_func_callback) + notify_func_callback(mmc_host_dev, val); + else + pr_warning("%s: Nobody to notify\n", __FUNCTION__); + + return 0; +} + +int __init dhd_wlan_init_gpio(void) +{ + const char *wlan_node = "samsung,brcm-wlan"; + unsigned int wlan_host_wake_up = -1; + struct device_node *root_node = NULL; + + wlan_dev = sec_device_create(NULL, "wlan"); + BUG_ON(!wlan_dev); + + root_node = of_find_compatible_node(NULL, NULL, wlan_node); + if (!root_node) { + WARN(1, "failed to get device node of bcm4354\n"); + return -ENODEV; + } + + /* ========== WLAN_PWR_EN ============ */ + wlan_pwr_on = of_get_gpio(root_node, 0); + if (!gpio_is_valid(wlan_pwr_on)) { + WARN(1, "Invalied gpio pin : %d\n", wlan_pwr_on); + return -ENODEV; + } + + if (gpio_request(wlan_pwr_on, "WLAN_REG_ON")) { + WARN(1, "fail to request gpio(WLAN_REG_ON)\n"); + return -ENODEV; + } + gpio_direction_output(wlan_pwr_on, 0); + gpio_export(wlan_pwr_on, 1); + gpio_export_link(wlan_dev, "WLAN_REG_ON", wlan_pwr_on); + + /* ========== WLAN_HOST_WAKE ============ */ + wlan_host_wake_up = of_get_gpio(root_node, 1); + if (!gpio_is_valid(wlan_host_wake_up)) { + WARN(1, "Invalied gpio pin : %d\n", wlan_host_wake_up); + return -ENODEV; + } + + if (gpio_request(wlan_host_wake_up, "WLAN_HOST_WAKE")) { + WARN(1, "fail to request gpio(WLAN_HOST_WAKE)\n"); + return -ENODEV; + } + gpio_direction_input(wlan_host_wake_up); + gpio_export(wlan_host_wake_up, 1); + gpio_export_link(wlan_dev, "WLAN_HOST_WAKE", wlan_host_wake_up); + + wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up); + + return 0; +} + +void interrupt_set_cpucore(int set) +{ + printk(KERN_INFO "%s: set: %d\n", __FUNCTION__, set); + if (set) + { +#if defined(CONFIG_MACH_UNIVERSAL5422) + irq_set_affinity(EXYNOS5_IRQ_HSMMC1, cpumask_of(DPC_CPUCORE)); + irq_set_affinity(EXYNOS_IRQ_EINT16_31, cpumask_of(DPC_CPUCORE)); +#elif defined(CONFIG_MACH_UNIVERSAL5430) + irq_set_affinity(IRQ_SPI(226), cpumask_of(DPC_CPUCORE)); + irq_set_affinity(IRQ_SPI(2), cpumask_of(DPC_CPUCORE)); +#endif + } else { +#if defined(CONFIG_MACH_UNIVERSAL5422) + irq_set_affinity(EXYNOS5_IRQ_HSMMC1, cpumask_of(PRIMARY_CPUCORE)); + irq_set_affinity(EXYNOS_IRQ_EINT16_31, cpumask_of(PRIMARY_CPUCORE)); +#elif defined(CONFIG_MACH_UNIVERSAL5430) + irq_set_affinity(IRQ_SPI(226), cpumask_of(PRIMARY_CPUCORE)); + irq_set_affinity(IRQ_SPI(2), cpumask_of(PRIMARY_CPUCORE)); +#endif + } +} + +struct resource dhd_wlan_resources = { + .name = "bcmdhd_wlan_irq", + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | + IORESOURCE_IRQ_SHAREABLE, +}; + +struct wifi_platform_data dhd_wlan_control = { + .set_power = dhd_wlan_power, + .set_reset = dhd_wlan_reset, + .set_carddetect = dhd_wlan_set_carddetect, +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + .mem_prealloc = dhd_wlan_mem_prealloc, +#endif +}; + +int __init dhd_wlan_init(void) +{ + int ret; + + printk(KERN_INFO "%s: start\n", __FUNCTION__); + ret = dhd_wlan_init_gpio(); + if (ret < 0) { + printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n", + __FUNCTION__, ret); + return ret; + } + + dhd_wlan_resources.start = wlan_host_wake_irq; + dhd_wlan_resources.end = wlan_host_wake_irq; + +#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM + dhd_init_wlan_mem(); +#endif + + return ret; +} + +device_initcall(dhd_wlan_init); |