1/* 2* Customer code to add GPIO control during WLAN start/stop 3* Copyright (C) 1999-2012, Broadcom Corporation 4* 5* Unless you and Broadcom execute a separate written software license 6* agreement governing use of this software, this software is licensed to you 7* under the terms of the GNU General Public License version 2 (the "GPL"), 8* available at http://www.broadcom.com/licenses/GPLv2.php, with the 9* following added to such license: 10* 11* As a special exception, the copyright holders of this software give you 12* permission to link this software with independent modules, and to copy and 13* distribute the resulting executable under terms of your choice, provided that 14* you also meet, for each linked independent module, the terms and conditions of 15* the license of that module. An independent module is a module which is not 16* derived from this software. The special exception does not apply to any 17* modifications of the software. 18* 19* Notwithstanding the above, under no circumstances may you combine this 20* software in any way with any other Broadcom software provided under a license 21* other than the GPL, without Broadcom's express prior written consent. 22* 23* $Id: dhd_custom_gpio.c 345514 2012-07-18 07:47:36Z $ 24*/ 25 26#include <typedefs.h> 27#include <linuxver.h> 28#include <osl.h> 29#include <bcmutils.h> 30 31#include <dngl_stats.h> 32#include <dhd.h> 33 34#include <wlioctl.h> 35#include <wl_iw.h> 36 37#define WL_ERROR(x) printf x 38#define WL_TRACE(x) 39 40#ifdef CUSTOMER_HW 41extern void bcm_wlan_power_off(int); 42extern void bcm_wlan_power_on(int); 43#endif /* CUSTOMER_HW */ 44#if defined(CUSTOMER_HW2) 45#ifdef CONFIG_WIFI_CONTROL_FUNC 46int wifi_set_power(int on, unsigned long msec); 47int wifi_get_irq_number(unsigned long *irq_flags_ptr); 48int wifi_get_mac_addr(unsigned char *buf); 49void *wifi_get_country_code(char *ccode); 50#else 51int wifi_set_power(int on, unsigned long msec) { return -1; } 52int wifi_get_irq_number(unsigned long *irq_flags_ptr) { return -1; } 53int wifi_get_mac_addr(unsigned char *buf) { return -1; } 54void *wifi_get_country_code(char *ccode) { return NULL; } 55#endif /* CONFIG_WIFI_CONTROL_FUNC */ 56#endif /* CUSTOMER_HW2 */ 57 58#if defined(OOB_INTR_ONLY) 59 60#if defined(BCMLXSDMMC) 61extern int sdioh_mmc_irq(int irq); 62#endif /* (BCMLXSDMMC) */ 63 64#ifdef CUSTOMER_HW3 65#include <mach/gpio.h> 66#endif 67 68/* Customer specific Host GPIO defintion */ 69static int dhd_oob_gpio_num = -1; 70 71module_param(dhd_oob_gpio_num, int, 0644); 72MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); 73 74/* This function will return: 75 * 1) return : Host gpio interrupt number per customer platform 76 * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge 77 * 78 * NOTE : 79 * Customer should check his platform definitions 80 * and his Host Interrupt spec 81 * to figure out the proper setting for his platform. 82 * Broadcom provides just reference settings as example. 83 * 84 */ 85int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) 86{ 87 int host_oob_irq = 0; 88 89#if defined(CUSTOMER_HW2) 90 host_oob_irq = wifi_get_irq_number(irq_flags_ptr); 91 92#else 93#if defined(CUSTOM_OOB_GPIO_NUM) 94 if (dhd_oob_gpio_num < 0) { 95 dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; 96 } 97#endif /* CUSTOMER_OOB_GPIO_NUM */ 98 99 if (dhd_oob_gpio_num < 0) { 100 WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", 101 __FUNCTION__)); 102 return (dhd_oob_gpio_num); 103 } 104 105 WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", 106 __FUNCTION__, dhd_oob_gpio_num)); 107 108#if defined CUSTOMER_HW 109 host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num); 110#elif defined CUSTOMER_HW3 111 gpio_request(dhd_oob_gpio_num, "oob irq"); 112 host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); 113 gpio_direction_input(dhd_oob_gpio_num); 114#endif /* CUSTOMER_HW */ 115#endif /* CUSTOMER_HW2 */ 116 117 return (host_oob_irq); 118} 119#endif /* defined(OOB_INTR_ONLY) */ 120 121/* Customer function to control hw specific wlan gpios */ 122void 123dhd_customer_gpio_wlan_ctrl(int onoff) 124{ 125 switch (onoff) { 126 case WLAN_RESET_OFF: 127 WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n", 128 __FUNCTION__)); 129#ifdef CUSTOMER_HW 130 bcm_wlan_power_off(2); 131#endif /* CUSTOMER_HW */ 132#if defined(CUSTOMER_HW2) 133 wifi_set_power(0, 0); 134#endif 135 WL_ERROR(("=========== WLAN placed in RESET ========\n")); 136 break; 137 138 case WLAN_RESET_ON: 139 WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n", 140 __FUNCTION__)); 141#ifdef CUSTOMER_HW 142 bcm_wlan_power_on(2); 143#endif /* CUSTOMER_HW */ 144#if defined(CUSTOMER_HW2) 145 wifi_set_power(1, 0); 146#endif 147 WL_ERROR(("=========== WLAN going back to live ========\n")); 148 break; 149 150 case WLAN_POWER_OFF: 151 WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n", 152 __FUNCTION__)); 153#ifdef CUSTOMER_HW 154 bcm_wlan_power_off(1); 155#endif /* CUSTOMER_HW */ 156 break; 157 158 case WLAN_POWER_ON: 159 WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n", 160 __FUNCTION__)); 161#ifdef CUSTOMER_HW 162 bcm_wlan_power_on(1); 163 /* Lets customer power to get stable */ 164 OSL_DELAY(200); 165#endif /* CUSTOMER_HW */ 166 break; 167 } 168} 169 170#ifdef GET_CUSTOM_MAC_ENABLE 171/* Function to get custom MAC address */ 172int 173dhd_custom_get_mac_address(unsigned char *buf) 174{ 175 int ret = 0; 176 177 WL_TRACE(("%s Enter\n", __FUNCTION__)); 178 if (!buf) 179 return -EINVAL; 180 181 /* Customer access to MAC address stored outside of DHD driver */ 182#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) 183 ret = wifi_get_mac_addr(buf); 184#endif 185 186#ifdef EXAMPLE_GET_MAC 187 /* EXAMPLE code */ 188 { 189 struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; 190 bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); 191 } 192#endif /* EXAMPLE_GET_MAC */ 193 194 return ret; 195} 196#endif /* GET_CUSTOM_MAC_ENABLE */ 197 198/* Customized Locale table : OPTIONAL feature */ 199const struct cntry_locales_custom translate_custom_table[] = { 200/* Table should be filled out based on custom platform regulatory requirement */ 201#ifdef EXAMPLE_TABLE 202 {"", "XY", 4}, /* Universal if Country code is unknown or empty */ 203 {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ 204 {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ 205 {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ 206 {"AT", "EU", 5}, 207 {"BE", "EU", 5}, 208 {"BG", "EU", 5}, 209 {"CY", "EU", 5}, 210 {"CZ", "EU", 5}, 211 {"DK", "EU", 5}, 212 {"EE", "EU", 5}, 213 {"FI", "EU", 5}, 214 {"FR", "EU", 5}, 215 {"DE", "EU", 5}, 216 {"GR", "EU", 5}, 217 {"HU", "EU", 5}, 218 {"IE", "EU", 5}, 219 {"IT", "EU", 5}, 220 {"LV", "EU", 5}, 221 {"LI", "EU", 5}, 222 {"LT", "EU", 5}, 223 {"LU", "EU", 5}, 224 {"MT", "EU", 5}, 225 {"NL", "EU", 5}, 226 {"PL", "EU", 5}, 227 {"PT", "EU", 5}, 228 {"RO", "EU", 5}, 229 {"SK", "EU", 5}, 230 {"SI", "EU", 5}, 231 {"ES", "EU", 5}, 232 {"SE", "EU", 5}, 233 {"GB", "EU", 5}, 234 {"KR", "XY", 3}, 235 {"AU", "XY", 3}, 236 {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ 237 {"TW", "XY", 3}, 238 {"AR", "XY", 3}, 239 {"MX", "XY", 3}, 240 {"IL", "IL", 0}, 241 {"CH", "CH", 0}, 242 {"TR", "TR", 0}, 243 {"NO", "NO", 0}, 244#endif /* EXMAPLE_TABLE */ 245}; 246 247 248/* Customized Locale convertor 249* input : ISO 3166-1 country abbreviation 250* output: customized cspec 251*/ 252void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) 253{ 254#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) 255 256 struct cntry_locales_custom *cloc_ptr; 257 258 if (!cspec) 259 return; 260 261 cloc_ptr = wifi_get_country_code(country_iso_code); 262 if (cloc_ptr) { 263 strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); 264 cspec->rev = cloc_ptr->custom_locale_rev; 265 } 266 return; 267#else 268 int size, i; 269 270 size = ARRAYSIZE(translate_custom_table); 271 272 if (cspec == 0) 273 return; 274 275 if (size == 0) 276 return; 277 278 for (i = 0; i < size; i++) { 279 if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { 280 memcpy(cspec->ccode, 281 translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); 282 cspec->rev = translate_custom_table[i].custom_locale_rev; 283 return; 284 } 285 } 286#ifdef EXAMPLE_TABLE 287 /* if no country code matched return first universal code from translate_custom_table */ 288 memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); 289 cspec->rev = translate_custom_table[0].custom_locale_rev; 290#endif /* EXMAPLE_TABLE */ 291 return; 292#endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) */ 293} 294