1 /* linux/arch/arm/mach-msm/board-stingray-wifi.c
3 #include <linux/kernel.h>
4 #include <linux/init.h>
5 #include <linux/platform_device.h>
6 #include <linux/delay.h>
8 #include <asm/mach-types.h>
11 #include <asm/setup.h>
13 #include <linux/skbuff.h>
14 #include <linux/wlan_plat.h>
15 #include <mach/sdhci.h>
17 #include <linux/random.h>
18 #include <linux/jiffies.h>
20 #include "board-stingray.h"
21 #include "gpio-names.h"
23 #define STINGRAY_WLAN_IRQ TEGRA_GPIO_PU5
24 #define STINGRAY_WLAN_RST TEGRA_GPIO_PU2
26 #define ATAG_STINGRAY_MAC 0x57464d41
27 #define ATAG_STINGRAY_MAC_DEBUG
29 #define PREALLOC_WLAN_NUMBER_OF_SECTIONS 4
30 #define PREALLOC_WLAN_NUMBER_OF_BUFFERS 160
31 #define PREALLOC_WLAN_SECTION_HEADER 24
33 #define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
34 #define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
35 #define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 512)
36 #define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 1024)
38 #define WLAN_SKB_BUF_NUM 16
40 static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
42 typedef struct wifi_mem_prealloc_struct {
45 } wifi_mem_prealloc_t;
47 static wifi_mem_prealloc_t wifi_mem_array[PREALLOC_WLAN_NUMBER_OF_SECTIONS] = {
48 { NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER) },
49 { NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER) },
50 { NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER) },
51 { NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER) }
54 static void *stingray_wifi_mem_prealloc(int section, unsigned long size)
56 if (section == PREALLOC_WLAN_NUMBER_OF_SECTIONS)
57 return wlan_static_skb;
58 if ((section < 0) || (section > PREALLOC_WLAN_NUMBER_OF_SECTIONS))
60 if (wifi_mem_array[section].size < size)
62 return wifi_mem_array[section].mem_ptr;
65 int __init stingray_init_wifi_mem(void)
69 for(i=0;( i < WLAN_SKB_BUF_NUM );i++) {
70 if (i < (WLAN_SKB_BUF_NUM/2))
71 wlan_static_skb[i] = dev_alloc_skb(4096);
73 wlan_static_skb[i] = dev_alloc_skb(8192);
75 for(i=0;( i < PREALLOC_WLAN_NUMBER_OF_SECTIONS );i++) {
76 wifi_mem_array[i].mem_ptr = kmalloc(wifi_mem_array[i].size,
78 if (wifi_mem_array[i].mem_ptr == NULL)
84 static struct resource stingray_wifi_resources[] = {
86 .name = "bcm4329_wlan_irq",
87 .start = TEGRA_GPIO_TO_IRQ(STINGRAY_WLAN_IRQ),
88 .end = TEGRA_GPIO_TO_IRQ(STINGRAY_WLAN_IRQ),
89 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE,
93 /* BCM4329 returns wrong sdio_vsn(1) when we read cccr,
94 * we use predefined value (sdio_vsn=2) here to initial sdio driver well
96 static struct embedded_sdio_data stingray_wifi_emb_data = {
107 static int stingray_wifi_cd = 0; /* WIFI virtual 'card detect' status */
108 static void (*wifi_status_cb)(int card_present, void *dev_id);
109 static void *wifi_status_cb_devid;
111 static int stingray_wifi_status_register(
112 void (*callback)(int card_present, void *dev_id),
117 wifi_status_cb = callback;
118 wifi_status_cb_devid = dev_id;
122 static unsigned int stingray_wifi_status(struct device *dev)
124 return stingray_wifi_cd;
127 struct tegra_sdhci_platform_data stingray_wifi_data = {
131 .ocr_mask = MMC_VDD_165_195,
133 .status = stingray_wifi_status,
134 .register_status_notify = stingray_wifi_status_register,
135 .embedded_sdio = &stingray_wifi_emb_data,
142 static int stingray_wifi_set_carddetect(int val)
144 pr_debug("%s: %d\n", __func__, val);
145 stingray_wifi_cd = val;
146 if (wifi_status_cb) {
147 wifi_status_cb(val, wifi_status_cb_devid);
149 pr_warning("%s: Nobody to notify\n", __func__);
153 static int stingray_wifi_power_state;
155 static int stingray_wifi_power(int on)
157 pr_debug("%s: %d\n", __func__, on);
160 change_power_brcm_4329(on);
162 gpio_set_value(STINGRAY_WLAN_RST, on);
165 stingray_wifi_power_state = on;
169 static int stingray_wifi_reset_state;
171 static int stingray_wifi_reset(int on)
173 pr_debug("%s: do nothing\n", __func__);
174 stingray_wifi_reset_state = on;
178 static unsigned char stingray_mac_addr[IFHWADDRLEN] = { 0,0x90,0x4c,0,0,0 };
180 static int __init parse_tag_wlan_mac(const struct tag *tag)
182 unsigned char *dptr = (unsigned char *)(&tag->u);
184 #ifdef ATAG_STINGRAY_MAC_DEBUG
188 size = min((tag->hdr.size - 2) * sizeof(__u32), (unsigned)IFHWADDRLEN);
189 #ifdef ATAG_STINGRAY_MAC_DEBUG
190 printk("WiFi MAC Addr [%d] = 0x%x\n", tag->hdr.size, tag->hdr.tag);
191 for(i=0;(i < size);i++) {
192 printk(" %02x", dptr[i]);
196 memcpy(stingray_mac_addr, dptr, size);
200 __tagtable(ATAG_STINGRAY_MAC, parse_tag_wlan_mac);
202 static int stingray_wifi_get_mac_addr(unsigned char *buf)
209 if ((stingray_mac_addr[4] == 0) && (stingray_mac_addr[5] == 0)) {
210 srandom32((uint)jiffies);
211 rand_mac = random32();
212 stingray_mac_addr[3] = (unsigned char)rand_mac;
213 stingray_mac_addr[4] = (unsigned char)(rand_mac >> 8);
214 stingray_mac_addr[5] = (unsigned char)(rand_mac >> 16);
216 memcpy(buf, stingray_mac_addr, IFHWADDRLEN);
220 /* Customized Locale table : OPTIONAL feature */
221 #define WLC_CNTRY_BUF_SZ 4
222 typedef struct cntry_locales_custom {
223 char iso_abbrev[WLC_CNTRY_BUF_SZ];
224 char custom_locale[WLC_CNTRY_BUF_SZ];
225 int custom_locale_rev;
226 } cntry_locales_custom_t;
228 static cntry_locales_custom_t stingray_wifi_translate_custom_table[] = {
229 /* Table should be filled out based on custom platform regulatory requirement */
230 {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */
231 {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */
232 {"EU", "EU", 5}, /* input ISO "EU" to : EU regrev 05 */
236 {"UK", "EU", 5}, /* input ISO "UK" to : EU regrev 05 */
239 {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */
244 static void *stingray_wifi_get_country_code(char *ccode)
246 int size = ARRAY_SIZE(stingray_wifi_translate_custom_table);
252 for (i = 0; i < size; i++)
253 if (strcmp(ccode, stingray_wifi_translate_custom_table[i].iso_abbrev) == 0)
254 return &stingray_wifi_translate_custom_table[i];
258 static struct wifi_platform_data stingray_wifi_control = {
259 .set_power = stingray_wifi_power,
260 .set_reset = stingray_wifi_reset,
261 .set_carddetect = stingray_wifi_set_carddetect,
262 .mem_prealloc = stingray_wifi_mem_prealloc,
263 .get_mac_addr = stingray_wifi_get_mac_addr,
264 .get_country_code = stingray_wifi_get_country_code,
267 static struct platform_device stingray_wifi_device = {
268 .name = "bcm4329_wlan",
270 .num_resources = ARRAY_SIZE(stingray_wifi_resources),
271 .resource = stingray_wifi_resources,
273 .platform_data = &stingray_wifi_control,
277 static void __init stingray_wlan_gpio(void)
279 tegra_gpio_enable(STINGRAY_WLAN_RST);
280 gpio_request(STINGRAY_WLAN_RST, "wlan_rst");
281 gpio_direction_output(STINGRAY_WLAN_RST, 0);
283 tegra_gpio_enable(STINGRAY_WLAN_IRQ);
284 gpio_request(STINGRAY_WLAN_IRQ, "wlan_irq");
285 gpio_direction_input(STINGRAY_WLAN_IRQ);
288 int __init stingray_wlan_init(void)
290 pr_debug("%s: start\n", __func__);
291 stingray_wlan_gpio();
292 stingray_init_wifi_mem();
293 return platform_device_register(&stingray_wifi_device);