ARM: cpu topology: Add debugfs interface for cpu_power
[cmplus.git] / arch / arm / mach-omap2 / board-tuna-wifi.c
blob8e3076ffd02536b7dc532b72af415ea655497917
1 /*
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>
19 #include <asm/gpio.h>
20 #include <asm/io.h>
21 #include <asm/setup.h>
22 #include <linux/if.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>
29 #include <plat/mmc.h>
31 #include <linux/random.h>
32 #include <linux/jiffies.h>
34 #include <mach/id.h>
35 #include "hsmmc.h"
36 #include "control.h"
37 #include "mux.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 {
61 void *mem_ptr;
62 unsigned long size;
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))
77 return NULL;
78 if (wifi_mem_array[section].size < size)
79 return NULL;
80 return wifi_mem_array[section].mem_ptr;
82 #endif
84 int __init tuna_init_wifi_mem(void)
86 #ifdef CONFIG_DHD_USE_STATIC_BUF
87 int i;
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);
92 else
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,
97 GFP_KERNEL);
98 if (wifi_mem_array[i].mem_ptr == NULL)
99 return -ENOMEM;
101 #endif
102 return 0;
105 static struct resource tuna_wifi_resources[] = {
106 [0] = {
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,
114 #if 0
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 = {
119 .cccr = {
120 .sdio_vsn = 2,
121 .multi_block = 1,
122 .low_speed = 0,
123 .wide_bus = 0,
124 .high_power = 1,
125 .high_speed = 1,
128 #endif
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),
137 void *dev_id)
139 if (wifi_status_cb)
140 return -EAGAIN;
141 wifi_status_cb = callback;
142 wifi_status_cb_devid = dev_id;
143 return 0;
146 static unsigned int tuna_wifi_status(struct device *dev)
148 return tuna_wifi_cd;
151 struct mmc_platform_data tuna_wifi_data = {
152 .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21,
153 .built_in = 1,
154 .status = tuna_wifi_status,
155 .card_present = 0,
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);
162 tuna_wifi_cd = val;
163 if (wifi_status_cb) {
164 wifi_status_cb(val, wifi_status_cb_devid);
165 } else
166 pr_warning("%s: Nobody to notify\n", __func__);
167 return 0;
170 static int tuna_wifi_power_state;
172 struct fixed_voltage_data {
173 struct regulator_desc desc;
174 struct regulator_dev *dev;
175 int microvolts;
176 int gpio;
177 unsigned startup_delay;
178 bool enable_high;
179 bool is_enabled;
182 static struct regulator_consumer_supply tuna_vmmc5_supply = {
183 .supply = "vmmc",
184 .dev_name = "omap_hsmmc.4",
187 static struct regulator_init_data tuna_vmmc5 = {
188 .constraints = {
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 */
200 .enable_high = 1,
201 .enabled_at_boot = 0,
202 .init_data = &tuna_vmmc5,
205 static struct platform_device omap_vwlan_device = {
206 .name = "reg-fixed-voltage",
207 .id = 1,
208 .dev = {
209 .platform_data = &tuna_vwlan,
213 static int tuna_wifi_power(int on)
215 int ret = 0;
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);
228 if (ret)
229 pr_err("%s: regulator_enable failed: %d\n", __func__,
230 ret);
232 msleep(300);
233 gpio_set_value(GPIO_WLAN_PMENA, on);
234 msleep(200);
236 if (clk32kaudio_reg && !on && tuna_wifi_power_state) {
237 ret = regulator_disable(clk32kaudio_reg);
238 if (ret)
239 pr_err("%s: regulator_disable failed: %d\n", __func__,
240 ret);
242 tuna_wifi_power_state = on;
243 return ret;
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;
252 return 0;
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;
261 char *token;
262 int i = 0;
264 if (!str)
265 return 0;
266 pr_debug("wlan MAC = %s\n", str);
267 if (strlen(str) >= sizeof(macstr))
268 return 0;
269 strcpy(macstr, str);
271 while ((token = strsep(&macptr, ":")) != NULL) {
272 unsigned long val;
273 int res;
275 if (i >= IFHWADDRLEN)
276 break;
277 res = strict_strtoul(token, 0x10, &val);
278 if (res < 0)
279 return 0;
280 tuna_mac_addr[i++] = (u8)val;
283 return 1;
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();
291 uint rand_mac;
292 struct omap_die_id oid;
294 if (type != TUNA_TYPE_TORO)
295 return -EINVAL;
297 if (!buf)
298 return -EFAULT;
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);
308 return 0;
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 */
325 {"AT", "EU", 5},
326 {"BE", "EU", 5},
327 {"BG", "EU", 5},
328 {"CY", "EU", 5},
329 {"CZ", "EU", 5},
330 {"DK", "EU", 5},
331 {"EE", "EU", 5},
332 {"FI", "EU", 5},
333 {"FR", "EU", 5},
334 {"DE", "EU", 5},
335 {"GR", "EU", 5},
336 {"HU", "EU", 5},
337 {"IE", "EU", 5},
338 {"IT", "EU", 5},
339 {"LV", "EU", 5},
340 {"LI", "EU", 5},
341 {"LT", "EU", 5},
342 {"LU", "EU", 5},
343 {"MT", "EU", 5},
344 {"NL", "EU", 5},
345 {"PL", "EU", 5},
346 {"PT", "EU", 5},
347 {"RO", "EU", 5},
348 {"SK", "EU", 5},
349 {"SI", "EU", 5},
350 {"ES", "EU", 5},
351 {"SE", "EU", 5},
352 {"GB", "EU", 5}, /* input ISO "GB" to : EU regrev 05 */
353 {"IL", "IL", 0},
354 {"CH", "CH", 0},
355 {"TR", "TR", 0},
356 {"NO", "NO", 0},
357 {"KR", "KR", 25},
358 {"AU", "XY", 3},
359 {"CN", "CN", 0},
360 {"TW", "XY", 3},
361 {"AR", "XY", 3},
362 {"MX", "XY", 3},
363 {"JP", "EU", 0},
364 {"BR", "KR", 25}
367 static void *tuna_wifi_get_country_code(char *ccode)
369 int size = ARRAY_SIZE(tuna_wifi_translate_custom_table);
370 int i;
372 if (!ccode)
373 return NULL;
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,
387 #else
388 .mem_prealloc = NULL,
389 #endif
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",
396 .id = 1,
397 .num_resources = ARRAY_SIZE(tuna_wifi_resources),
398 .resource = tuna_wifi_resources,
399 .dev = {
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__);
435 tuna_wlan_gpio();
436 tuna_init_wifi_mem();
437 platform_device_register(&omap_vwlan_device);
438 return platform_device_register(&tuna_wifi_device);