2 * Copyright (C) 2011 Google, Inc.
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/platform_device.h>
16 #include <linux/delay.h>
17 #include <linux/err.h>
18 #include <asm/mach-types.h>
21 #include <asm/setup.h>
23 #include <linux/skbuff.h>
24 #include <linux/wlan_plat.h>
25 #include <linux/pm_runtime.h>
26 #include <linux/regulator/machine.h>
27 #include <linux/regulator/driver.h>
28 #include <linux/regulator/fixed.h>
31 #include <linux/random.h>
32 #include <linux/jiffies.h>
38 #include "board-tuna.h"
40 #define GPIO_WLAN_PMENA 104
41 #define GPIO_WLAN_IRQ 2
43 #define ATAG_TUNA_MAC 0x57464d41
44 /* #define ATAG_TUNA_MAC_DEBUG */
46 #ifdef CONFIG_DHD_USE_STATIC_BUF
47 #define PREALLOC_WLAN_NUMBER_OF_SECTIONS 4
48 #define PREALLOC_WLAN_NUMBER_OF_BUFFERS 160
49 #define PREALLOC_WLAN_SECTION_HEADER 24
51 #define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
52 #define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
53 #define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 512)
54 #define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 1024)
56 #define WLAN_SKB_BUF_NUM 16
58 static struct sk_buff
*wlan_static_skb
[WLAN_SKB_BUF_NUM
];
60 typedef struct wifi_mem_prealloc_struct
{
63 } wifi_mem_prealloc_t
;
65 static wifi_mem_prealloc_t wifi_mem_array
[PREALLOC_WLAN_NUMBER_OF_SECTIONS
] = {
66 { NULL
, (WLAN_SECTION_SIZE_0
+ PREALLOC_WLAN_SECTION_HEADER
) },
67 { NULL
, (WLAN_SECTION_SIZE_1
+ PREALLOC_WLAN_SECTION_HEADER
) },
68 { NULL
, (WLAN_SECTION_SIZE_2
+ PREALLOC_WLAN_SECTION_HEADER
) },
69 { NULL
, (WLAN_SECTION_SIZE_3
+ PREALLOC_WLAN_SECTION_HEADER
) }
72 static void *tuna_wifi_mem_prealloc(int section
, unsigned long size
)
74 if (section
== PREALLOC_WLAN_NUMBER_OF_SECTIONS
)
75 return wlan_static_skb
;
76 if ((section
< 0) || (section
> PREALLOC_WLAN_NUMBER_OF_SECTIONS
))
78 if (wifi_mem_array
[section
].size
< size
)
80 return wifi_mem_array
[section
].mem_ptr
;
84 int __init
tuna_init_wifi_mem(void)
86 #ifdef CONFIG_DHD_USE_STATIC_BUF
89 for(i
=0;( i
< WLAN_SKB_BUF_NUM
);i
++) {
90 if (i
< (WLAN_SKB_BUF_NUM
/2))
91 wlan_static_skb
[i
] = dev_alloc_skb(4096);
93 wlan_static_skb
[i
] = dev_alloc_skb(8192);
95 for(i
=0;( i
< PREALLOC_WLAN_NUMBER_OF_SECTIONS
);i
++) {
96 wifi_mem_array
[i
].mem_ptr
= kmalloc(wifi_mem_array
[i
].size
,
98 if (wifi_mem_array
[i
].mem_ptr
== NULL
)
105 static struct resource tuna_wifi_resources
[] = {
107 .name
= "bcmdhd_wlan_irq",
108 .start
= OMAP_GPIO_IRQ(GPIO_WLAN_IRQ
),
109 .end
= OMAP_GPIO_IRQ(GPIO_WLAN_IRQ
),
110 .flags
= IORESOURCE_IRQ
| IORESOURCE_IRQ_HIGHLEVEL
| IORESOURCE_IRQ_SHAREABLE
,
115 /* BCM4329 returns wrong sdio_vsn(1) when we read cccr,
116 * we use predefined value (sdio_vsn=2) here to initial sdio driver well
118 static struct embedded_sdio_data tuna_wifi_emb_data
= {
130 static int tuna_wifi_cd
= 0; /* WIFI virtual 'card detect' status */
131 static void (*wifi_status_cb
)(int card_present
, void *dev_id
);
132 static void *wifi_status_cb_devid
;
133 static struct regulator
*clk32kaudio_reg
;
135 static int tuna_wifi_status_register(
136 void (*callback
)(int card_present
, void *dev_id
),
141 wifi_status_cb
= callback
;
142 wifi_status_cb_devid
= dev_id
;
146 static unsigned int tuna_wifi_status(struct device
*dev
)
151 struct mmc_platform_data tuna_wifi_data
= {
152 .ocr_mask
= MMC_VDD_165_195
| MMC_VDD_20_21
,
154 .status
= tuna_wifi_status
,
156 .register_status_notify
= tuna_wifi_status_register
,
159 static int tuna_wifi_set_carddetect(int val
)
161 pr_debug("%s: %d\n", __func__
, val
);
163 if (wifi_status_cb
) {
164 wifi_status_cb(val
, wifi_status_cb_devid
);
166 pr_warning("%s: Nobody to notify\n", __func__
);
170 static int tuna_wifi_power_state
;
172 struct fixed_voltage_data
{
173 struct regulator_desc desc
;
174 struct regulator_dev
*dev
;
177 unsigned startup_delay
;
182 static struct regulator_consumer_supply tuna_vmmc5_supply
= {
184 .dev_name
= "omap_hsmmc.4",
187 static struct regulator_init_data tuna_vmmc5
= {
189 .valid_ops_mask
= REGULATOR_CHANGE_STATUS
,
191 .num_consumer_supplies
= 1,
192 .consumer_supplies
= &tuna_vmmc5_supply
,
195 static struct fixed_voltage_config tuna_vwlan
= {
196 .supply_name
= "vwl1271",
197 .microvolts
= 2000000, /* 2.0V */
198 .gpio
= GPIO_WLAN_PMENA
,
199 .startup_delay
= 70000, /* 70msec */
201 .enabled_at_boot
= 0,
202 .init_data
= &tuna_vmmc5
,
205 static struct platform_device omap_vwlan_device
= {
206 .name
= "reg-fixed-voltage",
209 .platform_data
= &tuna_vwlan
,
213 static int tuna_wifi_power(int on
)
217 pr_debug("%s: %d\n", __func__
, on
);
218 if (!clk32kaudio_reg
) {
219 clk32kaudio_reg
= regulator_get(0, "clk32kaudio");
220 if (IS_ERR(clk32kaudio_reg
)) {
221 pr_err("%s: clk32kaudio reg not found!\n", __func__
);
222 clk32kaudio_reg
= NULL
;
226 if (clk32kaudio_reg
&& on
&& !tuna_wifi_power_state
) {
227 ret
= regulator_enable(clk32kaudio_reg
);
229 pr_err("%s: regulator_enable failed: %d\n", __func__
,
233 gpio_set_value(GPIO_WLAN_PMENA
, on
);
236 if (clk32kaudio_reg
&& !on
&& tuna_wifi_power_state
) {
237 ret
= regulator_disable(clk32kaudio_reg
);
239 pr_err("%s: regulator_disable failed: %d\n", __func__
,
242 tuna_wifi_power_state
= on
;
246 static int tuna_wifi_reset_state
;
248 static int tuna_wifi_reset(int on
)
250 pr_debug("%s: do nothing\n", __func__
);
251 tuna_wifi_reset_state
= on
;
255 static unsigned char tuna_mac_addr
[IFHWADDRLEN
] = { 0,0x90,0x4c,0,0,0 };
257 static int __init
tuna_mac_addr_setup(char *str
)
259 char macstr
[IFHWADDRLEN
*3];
260 char *macptr
= macstr
;
266 pr_debug("wlan MAC = %s\n", str
);
267 if (strlen(str
) >= sizeof(macstr
))
271 while ((token
= strsep(&macptr
, ":")) != NULL
) {
275 if (i
>= IFHWADDRLEN
)
277 res
= strict_strtoul(token
, 0x10, &val
);
280 tuna_mac_addr
[i
++] = (u8
)val
;
286 __setup("androidboot.macaddr=", tuna_mac_addr_setup
);
288 static int tuna_wifi_get_mac_addr(unsigned char *buf
)
290 int type
= omap4_tuna_get_type();
292 struct omap_die_id oid
;
294 if (type
!= TUNA_TYPE_TORO
)
300 if ((tuna_mac_addr
[4] == 0) && (tuna_mac_addr
[5] == 0)) {
301 omap_get_die_id(&oid
);
302 rand_mac
= (uint
)oid
.id_3
; // id_3 or id_1 ?
303 tuna_mac_addr
[3] = (unsigned char)rand_mac
;
304 tuna_mac_addr
[4] = (unsigned char)(rand_mac
>> 8);
305 tuna_mac_addr
[5] = (unsigned char)(rand_mac
>> 16);
307 memcpy(buf
, tuna_mac_addr
, IFHWADDRLEN
);
311 /* Customized Locale table : OPTIONAL feature */
312 #define WLC_CNTRY_BUF_SZ 4
313 typedef struct cntry_locales_custom
{
314 char iso_abbrev
[WLC_CNTRY_BUF_SZ
];
315 char custom_locale
[WLC_CNTRY_BUF_SZ
];
316 int custom_locale_rev
;
317 } cntry_locales_custom_t
;
319 static cntry_locales_custom_t tuna_wifi_translate_custom_table
[] = {
320 /* Table should be filled out based on custom platform regulatory requirement */
321 {"", "XY", 4}, /* universal */
322 {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */
323 {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */
324 {"EU", "EU", 5}, /* European union countries */
352 {"GB", "EU", 5}, /* input ISO "GB" to : EU regrev 05 */
367 static void *tuna_wifi_get_country_code(char *ccode
)
369 int size
= ARRAY_SIZE(tuna_wifi_translate_custom_table
);
375 for (i
= 0; i
< size
; i
++)
376 if (strcmp(ccode
, tuna_wifi_translate_custom_table
[i
].iso_abbrev
) == 0)
377 return &tuna_wifi_translate_custom_table
[i
];
378 return &tuna_wifi_translate_custom_table
[0];
381 static struct wifi_platform_data tuna_wifi_control
= {
382 .set_power
= tuna_wifi_power
,
383 .set_reset
= tuna_wifi_reset
,
384 .set_carddetect
= tuna_wifi_set_carddetect
,
385 #ifdef CONFIG_DHD_USE_STATIC_BUF
386 .mem_prealloc
= tuna_wifi_mem_prealloc
,
388 .mem_prealloc
= NULL
,
390 .get_mac_addr
= tuna_wifi_get_mac_addr
,
391 .get_country_code
= tuna_wifi_get_country_code
,
394 static struct platform_device tuna_wifi_device
= {
395 .name
= "bcmdhd_wlan",
397 .num_resources
= ARRAY_SIZE(tuna_wifi_resources
),
398 .resource
= tuna_wifi_resources
,
400 .platform_data
= &tuna_wifi_control
,
404 static void __init
tuna_wlan_gpio(void)
406 pr_debug("%s: start\n", __func__
);
408 /* WLAN SDIO: MMC5 CMD */
409 omap_mux_init_signal("sdmmc5_cmd", OMAP_PIN_INPUT_PULLUP
);
410 /* WLAN SDIO: MMC5 CLK */
411 omap_mux_init_signal("sdmmc5_clk", OMAP_PIN_INPUT_PULLUP
);
412 /* WLAN SDIO: MMC5 DAT[0-3] */
413 omap_mux_init_signal("sdmmc5_dat0", OMAP_PIN_INPUT_PULLUP
);
414 omap_mux_init_signal("sdmmc5_dat1", OMAP_PIN_INPUT_PULLUP
);
415 omap_mux_init_signal("sdmmc5_dat2", OMAP_PIN_INPUT_PULLUP
);
416 omap_mux_init_signal("sdmmc5_dat3", OMAP_PIN_INPUT_PULLUP
);
417 /* WLAN OOB - BCM4330 - GPIO 16 or GPIO 2 */
418 omap_mux_init_signal("sim_reset.gpio_wk2", OMAP_PIN_INPUT
);
419 omap_mux_init_signal("kpd_row1.safe_mode", 0);
420 /* WLAN PMENA - GPIO 104 */
421 omap_mux_init_signal("gpmc_ncs7.gpio_104", OMAP_PIN_OUTPUT
);
422 /* Enable power to gpio_wk0-gpio_wk2 */
423 omap4_ctrl_wk_pad_writel(0xb0000000,
424 OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_USIMIO
);
426 /* gpio_enable(GPIO_WLAN_IRQ); */
427 gpio_request(GPIO_WLAN_IRQ
, "wlan_irq");
428 gpio_direction_input(GPIO_WLAN_IRQ
);
431 int __init
tuna_wlan_init(void)
433 pr_debug("%s: start\n", __func__
);
436 tuna_init_wifi_mem();
437 platform_device_register(&omap_vwlan_device
);
438 return platform_device_register(&tuna_wifi_device
);