upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / bcm4330.c
1 /*
2  *  bcm4330.c
3  *  Machine specific driver for WLAN/BT module (bcm4329,bcm4330,etc)
4  *  Most of functional blocks are implemented in dhd.ko module driver
5  *  provided by Broadcom.
6  *
7  *  Copyright (C) 2010 Samsung Electronics
8  *  Jaehoon Chung <jh80.chung@samsung.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14
15 #include <linux/slab.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/platform_device.h>
19 #include <linux/regulator/consumer.h>
20 #include <linux/mutex.h>
21 #include <linux/err.h>
22 #include <linux/delay.h>
23 #include <linux/rfkill.h>
24 #include <linux/io.h>
25 #include <linux/interrupt.h>
26 #include <linux/firmware.h>
27
28 #include <mach/gpio.h>
29 #include <mach/regs-gpio.h>
30
31 #include <plat/gpio-cfg.h>
32 #include <plat/sdhci.h>
33
34 #include "bcm4330.h"
35
36 #define BT_FW_NAME              "BCM4330.hcd"
37 #define BT_FW_LOAD_SUCCESS      1
38 #define BT_FW_LOAD_FAIL         0
39
40 #define to_dev(obj) container_of(obj, struct device, kobj)
41
42 #define WLAN_STATIC_BUF // this feature for using static buffer on wifi driver /Kernel/drivers/net/wireless/bcm4330
43
44 #if defined (WLAN_STATIC_BUF)
45 #include <linux/skbuff.h>
46 #endif /* WLAN_STATIC_BUF */
47
48 struct bcm4330_data {
49         struct bcm4330_platform_data    *pdata;
50         struct rfkill                   *bt_rfk;
51         struct rfkill                   *wlan_rfk;
52         bool                            bt_in_use;
53         bool                            wlan_in_use;
54
55         unsigned char                   *fw_data;
56         unsigned int                    fw_size;
57         int                             fw_state;
58
59         struct regulator                *regulator_bt;
60         struct regulator                *regulator_wlan;
61 };
62
63 struct bcm4330_data *bcm4330_bd;
64
65 /* The device name consist of chip name and revision informatin. */
66 #define BCM4330_NAME_SIZE       15
67 char bcm4330_name[][BCM4330_NAME_SIZE] = {
68         [TYPE_BCM4330_B1]       = {"bcm4330-b1"}, /* BCM4330's rev : "b1" */
69         [TYPE_BCM4330_B0]       = {"bcm4330-b0"}, /* BCM4330's rev : "b0" */
70 };
71
72 static void bcm4330_bt_enable(void *data)
73 {
74         struct bcm4330_data *bd = data;
75         struct bcm4330_platform_data *pdata = bd->pdata;
76         int ret;
77
78         if (bd->bt_in_use)
79                 return;
80
81         if (bd->regulator_bt)
82                 ret = regulator_enable(bd->regulator_bt);
83         if (ret) {
84                 printk(KERN_INFO "Failed to enable regulator_bt\n");
85                 return;
86         }
87
88         gpio_set_value(pdata->bt_en, 1);
89
90         /* 100msec delay is required but regulator handle this one */
91         gpio_set_value(pdata->bt_wake, 1);
92         gpio_set_value(pdata->bt_nrst, 1);
93
94         /* FIXME: BCM4330 has a error that is happened
95            when enable/disable repeatedly. Temporarily,
96            I extened delay time (100ms->150ms) */
97         msleep(150);
98
99         bd->bt_in_use = true;
100 }
101
102 static void bcm4330_bt_disable(void *data)
103 {
104         struct bcm4330_data *bd = data;
105         struct bcm4330_platform_data *pdata = bd->pdata;
106         int ret;
107
108         if (!bd->bt_in_use)
109                 return;
110
111         if (bd->regulator_bt)
112                 ret = regulator_disable(bd->regulator_bt);
113         if (ret) {
114                 printk(KERN_INFO "Failed to disable regulator_bt\n");
115                 return;
116         }
117
118         gpio_set_value(pdata->bt_wake, 0);
119         gpio_set_value(pdata->bt_nrst, 0);
120
121         gpio_set_value(pdata->bt_en, 0);
122
123         bd->bt_in_use = false;
124 }
125
126 static void bcm4330_wlan_enable(void *data)
127 {
128         struct bcm4330_data *bd = data;
129         struct bcm4330_platform_data *pdata = bd->pdata;
130         int ret;
131
132         if (bd->wlan_in_use)
133                 return;
134
135         if (bd->regulator_wlan)
136                 ret = regulator_enable(bd->regulator_wlan);
137         if (ret) {
138                 printk(KERN_INFO "Failed to enable regulator_wlan\n");
139                 return;
140         }
141
142         gpio_set_value(pdata->wlan_en, 1);
143
144         msleep(100);
145
146         /* 100msec delay is required but regulator handle this one */
147
148         /* FIXME why BT_RST_N is required 100ms high at WLAN on? */
149         if (!bd->bt_in_use) {
150                 gpio_set_value(pdata->bt_wake, 1);
151                 gpio_set_value(pdata->bt_nrst, 1);
152                 msleep(100);
153                 gpio_set_value(pdata->bt_wake, 0);
154                 gpio_set_value(pdata->bt_nrst, 0);
155         }
156
157         bd->wlan_in_use = true;
158 }
159
160 static void bcm4330_wlan_disable(void *data)
161 {
162         struct bcm4330_data *bd = data;
163         struct bcm4330_platform_data *pdata = bd->pdata;
164         int ret;
165
166         if (!bd->wlan_in_use)
167                 return;
168
169         if (bd->regulator_wlan)
170                 ret = regulator_disable(bd->regulator_wlan);
171         if (ret) {
172                 printk(KERN_INFO "Failed to disable regulator_wlan\n");
173                 return;
174         }
175
176         gpio_set_value(pdata->wlan_en, 0);
177
178         bd->wlan_in_use = false;
179 }
180
181 static int bcm4330_set_bt_block(void *data, bool blocked)
182 {
183         if (!blocked) {
184                 /* RFKILL_STATE_UNBLOCKED */
185                 printk(KERN_INFO "%s : Enable BCM4330 BT chip\n", __func__);
186                 bcm4330_bt_enable(data);
187         } else {
188                 /* RFKILL_STATE_SOFT_BLOCKED */
189                 printk(KERN_INFO "%s : Disable BCM4330 BT chip\n", __func__);
190                 bcm4330_bt_disable(data);
191         }
192
193         return 0;
194 }
195
196 static int bcm4330_set_wlan_block(void *data, bool blocked)
197 {
198         if (!blocked) {
199                 /* RFKILL_STATE_UNBLOCKED */
200                 printk(KERN_INFO "%s : Enable BCM4330 WLAN chip\n", __func__);
201                 bcm4330_wlan_enable(data);
202                 wlan_set_power(1);
203         } else {
204                 /* RFKILL_STATE_SOFT_BLOCKED */
205                 printk(KERN_INFO "%s : Disable BCM4330 WLAN chip\n", __func__);
206                 bcm4330_wlan_disable(data);
207                 wlan_set_power(0);
208         }
209
210         return 0;
211 }
212
213 static const struct rfkill_ops bcm4330_rfkill_bt_ops = {
214         .set_block = bcm4330_set_bt_block,
215 };
216
217 static const struct rfkill_ops bcm4330_rfkill_wlan_ops = {
218         .set_block = bcm4330_set_wlan_block,
219 };
220
221 int wlan_set_power(int flag)
222 {
223         struct bcm4330_data *bd = bcm4330_bd;
224         struct bcm4330_platform_data *pdata = bd->pdata;
225
226         if (flag) {
227                 printk("%s[%d] Power ON\n",__func__,__LINE__);
228                 gpio_set_value(pdata->wlan_en, 1);
229                 msleep(200);
230         } else {
231                 printk("%s[%d] Power OFF\n",__func__,__LINE__);
232                 gpio_set_value(pdata->wlan_en, 0);
233         }
234
235         if (pdata->wlan_host_enable)
236                 pdata->wlan_host_enable(flag);
237         else {
238                 printk(KERN_ERR "%s: Didn't find SDIO card Host\n",__func__);
239
240                 printk(KERN_DEBUG "%s[%d] Power OFF\n",__func__,__LINE__);
241                 gpio_set_value(pdata->wlan_en, 0);
242                 return -EINVAL;
243         }
244
245         return 0;
246 }
247 EXPORT_SYMBOL(wlan_set_power);
248
249 static void bcm4330_host_wake(struct work_struct *work)
250 {
251         printk(KERN_DEBUG "BT/WLAN_HOST_WAKE irq is occured!");
252 }
253 static DECLARE_WORK(bcm4330_host_wake_work, bcm4330_host_wake);
254
255 static irqreturn_t bcm4330_host_wake_handler(int irq, void *dev_id)
256 {
257         /* FIXME: The overhead of scheduling is occurred
258          *        during data transmission through bluetooth,
259          *        because bt_host_wake is frequently coming. */
260         /* schedule_work(&bcm4330_host_wake_work); */
261         return IRQ_HANDLED;
262 }
263
264 static void bcm4330_firmware_handler(const struct firmware *fw,
265                                           void *context)
266 {
267         if (fw != NULL) {
268                 bcm4330_bd->fw_size = fw->size;
269                 bcm4330_bd->fw_data = kzalloc(fw->size, GFP_KERNEL);
270                 if (!bcm4330_bd->fw_data) {
271                         bcm4330_bd->fw_state = BT_FW_LOAD_FAIL;
272
273                         printk(KERN_INFO "Failed to allocate memory for Bluetooth \
274                                         firmware \n");
275                 } else {
276                         memcpy(bcm4330_bd->fw_data, fw->data, fw->size);
277                         bcm4330_bd->fw_state = BT_FW_LOAD_SUCCESS;
278
279                         printk(KERN_INFO "BT F/W loaded successfully (size: %d)\n", fw->size);
280                 }
281         } else {
282                 bcm4330_bd->fw_state = BT_FW_LOAD_FAIL;
283
284                 printk(KERN_INFO "failed to load BT F/W, BT will not working\n");
285         }
286 }
287
288 static DEFINE_MUTEX(fw_lock);
289 static ssize_t bcm4330_firmware_read(struct file *filp, struct kobject *kobj,
290                                   struct bin_attribute *bin_attr,
291                                   char *buffer, loff_t offset, size_t count)
292 {
293         char *fw_data = bcm4330_bd->fw_data;
294         int fw_size = bcm4330_bd->fw_size;
295         int ret_count;
296
297         mutex_lock(&fw_lock);
298
299         if (offset > fw_size) {
300                 ret_count = 0;
301                 goto out;
302         }
303         if (count > fw_size - offset)
304                 count = fw_size - offset;
305
306         ret_count = count;
307
308         while (count) {
309                 void *page_data;
310                 int page_nr = offset >> PAGE_SHIFT;
311                 int page_ofs = offset & (PAGE_SIZE-1);
312                 int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
313
314                 page_data = fw_data + (4096 * page_nr);
315
316                 memcpy(buffer, page_data, page_cnt);
317
318                 buffer += page_cnt;
319                 offset += page_cnt;
320                 count -= page_cnt;
321         }
322 out:
323         mutex_unlock(&fw_lock);
324         return ret_count;
325 }
326
327 static ssize_t bcm4330_firmware_write(struct file *filp, struct kobject *kobj,
328                                    struct bin_attribute *bin_attr,
329                                    char *buffer, loff_t offset, size_t count)
330 {
331         printk(KERN_INFO "Permission denied! Only read firmware of bcm4330\n");
332         return 0;
333 }
334
335 static struct bin_attribute bcm4330_firmware_attr = {
336         .attr = { .name = "firmware", .mode = 0644 },
337         .size = 0,
338         .read = bcm4330_firmware_read,
339         .write = bcm4330_firmware_write,
340 };
341
342 #if defined (WLAN_STATIC_BUF)
343 static int init_wifi_mem(void);
344 #endif /* WLAN_STATIC_BUF */
345
346 static int __devinit bcm4330_probe(struct platform_device *pdev)
347 {
348         struct bcm4330_platform_data *pdata;
349         struct bcm4330_data *bd;
350         int gpio, i, ret, irq, type;
351         char *name = NULL;
352
353         /*
354          * WLAN_BT_EN   ____|```````````````````````````
355          * WLAN_nRST    ______100ms__|``````````````````
356          * BT_nRST      ______100ms__|``````````````````
357          */
358
359         pdata = pdev->dev.platform_data;
360         if (!pdata) {
361                 dev_err(&pdev->dev, "No BCM4330 platform data.\n");
362                 return -EINVAL;
363         }
364
365 #if defined (WLAN_STATIC_BUF)
366         ret = init_wifi_mem();
367         if (ret < 0) {
368                 printk(KERN_ERR
369                         "%s : Failed to init wifi memory\n", __func__);
370                 goto wlan_mem_failed;
371         }
372 #endif /* WLAN_STATIC_BUF */
373
374         bd = kzalloc(sizeof(struct bcm4330_data), GFP_KERNEL);
375         if (!bd)
376                 return -ENOMEM;
377
378         bd->pdata = pdata;
379         bcm4330_bd = bd;
380
381         /* WLAN */
382
383         /* WLAN_EN */
384         gpio = pdata->wlan_en;
385         gpio_request(gpio, "WLAN_EN");
386         gpio_direction_output(gpio, 0);
387         s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
388
389         /* WLAN_HOST_WAKE */
390         gpio = pdata->wlan_host_wake;
391         gpio_request(gpio, "WLAN_HOST_WAKE");
392         s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
393
394         /* BT */
395         /* BT_EN */
396         gpio = pdata->bt_en;
397         gpio_request(gpio, "BT_EN");
398         gpio_direction_output(gpio, 0);
399         s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
400
401         /* BT_nRST */
402         gpio = pdata->bt_nrst;
403         gpio_request(gpio, "BT_nRST");
404         gpio_direction_output(gpio, 1);
405         s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
406
407         /* BT_WAKE */
408         gpio = pdata->bt_wake;
409         gpio_request(gpio, "BT_WAKE");
410         gpio_direction_output(gpio, 0);
411
412         /* BT_HOST_WAKE */
413         gpio = pdata->bt_host_wake;
414         gpio_request(gpio, "BT_HOST_nWAKE");
415         s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
416
417         /* - Register irq handler of BT_HOST_WAKE interrupt */
418         irq = gpio_to_irq(gpio);
419         ret = request_irq(irq, bcm4330_host_wake_handler,
420                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
421                         "BT_HOST_WAKE", NULL);
422         if (ret < 0) {
423                 printk(KERN_ERR
424                         "%s : Failed to register handler of BT_HOST_WAKE\n",
425                         __func__);
426                 goto bt_irq_failed;
427         }
428
429         /* WLAN_HOST_WAKE - Interrupt */
430         gpio = pdata->wlan_host_wake;
431         s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0x0));
432         gpio_request(gpio, "WLAN_HOST_nWAKE");
433         gpio_direction_input(gpio);
434         /*      Initialize and free gpio once, 
435          *      unless will float until DHD module get loaded.*/
436         gpio_free(gpio);
437
438 #if 0
439         /* - Register irq handler of WLAN_HOST_WAKE interrupt */
440         irq = gpio_to_irq(gpio);
441         ret = request_irq(irq, bcm4330_host_wake_handler,
442                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
443                         "WLAN_HOST_WAKE", NULL);
444         if (ret < 0) {
445                 printk(KERN_ERR
446                         "%s : Failed to register handler of WLAN_HOST_WAKE\n",
447                         __func__);
448                 goto wlan_irq_failed;
449         }
450 #endif
451         /* BT_UART pin configuration - UART0 */
452         for (i = 0; i < 4; i++)
453                 if (gpio_is_valid(pdata->bt_uart[i])) {
454                         s3c_gpio_cfgpin(pdata->bt_uart[i], S3C_GPIO_SFN(2));
455                 }
456
457         /* Check BCM4330 chip type */
458         type = platform_get_device_id(pdev)->driver_data;
459         for (i = 0 ; i < TYPE_BCM4330_NUM ; i++) {
460                 if(type == i) {
461                         name = bcm4330_name[i];
462                         break;
463                 }
464         }
465         printk("%s module is ready to start\n", name);
466
467         /* Register BCM4330 to RFKILL class */
468         bd->wlan_rfk = rfkill_alloc(name, &pdev->dev, RFKILL_TYPE_WLAN,
469                                 &bcm4330_rfkill_wlan_ops, bd);
470         if (!bd->wlan_rfk) {
471                 ret = -ENOMEM;
472                 goto wlan_rfk_failed;
473         }
474
475         /*
476          * described by the comment in rfkill.h
477          * true : turn off
478          * false : turn on
479          */
480         rfkill_init_sw_state(bd->wlan_rfk, true);
481
482         ret = rfkill_register(bd->wlan_rfk);
483         if (ret)
484                 goto wlan_rfk_register_failed;
485
486         bd->bt_rfk = rfkill_alloc(name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
487                                 &bcm4330_rfkill_bt_ops, bd);
488         if (!bd->bt_rfk) {
489                 ret = -ENOMEM;
490                 goto bt_rfk_faild;
491         }
492
493         rfkill_init_sw_state(bd->bt_rfk, true);
494
495         ret = rfkill_register(bd->bt_rfk);
496         if (ret)
497                 goto bt_rfk_register_failed;
498
499         /* Get Clock of BT/WiFi */
500         bd->regulator_bt = regulator_get(NULL, "bt_clk");
501         if (bd->regulator_bt == NULL || IS_ERR(bd->regulator_bt)) {
502                 printk(KERN_INFO
503                 "Failed to get the regulator : BT_WIFI_CLK32k(BT)\n");
504                 goto wifi_regulator_failed;
505         }
506
507         bd->regulator_wlan = regulator_get(NULL, "wifi_clk");
508         if (bd->regulator_wlan == NULL || IS_ERR(bd->regulator_wlan)) {
509                 printk(KERN_INFO
510                 "Failed to get the regulator : BT_WIFI_CLK32k(WiFi)\n");
511                 goto bt_regulator_failed;
512         }
513
514         /* Load firmware */
515         ret = request_firmware_nowait(THIS_MODULE,
516                         FW_ACTION_NOHOTPLUG,
517                         BT_FW_NAME,
518                         &pdev->dev,
519                         GFP_KERNEL,
520                         pdev,
521                         bcm4330_firmware_handler);
522         if (ret < 0) {
523                 printk(KERN_INFO "Failed to request firmware of Bluetooth : \
524                                 err=%d\n", ret);
525                 goto bt_rfk_register_failed;
526         }
527
528         /* Create sysfs for firmware of bluetooth, so the user can get firmware
529          * image through sysfs node in user-space. */
530         ret = device_create_bin_file(&pdev->dev, &bcm4330_firmware_attr);
531         if (ret) {
532                 dev_err(&pdev->dev, "Failed to create sysfs of Bluetooth : \
533                                 err=%d\n", ret);
534                 goto bt_sysfs_create_failed;
535         }
536
537         platform_set_drvdata(pdev, bd);
538
539         return 0;
540
541 bt_sysfs_create_failed:
542         device_remove_bin_file(&pdev->dev, &bcm4330_firmware_attr);
543 wifi_regulator_failed:
544         regulator_put(bd->regulator_wlan);
545 bt_regulator_failed:
546         regulator_put(bd->regulator_bt);
547 bt_rfk_register_failed:
548         rfkill_destroy(bd->bt_rfk);
549 bt_rfk_faild:
550         rfkill_unregister(bd->wlan_rfk);
551 wlan_rfk_register_failed:
552         rfkill_destroy(bd->wlan_rfk);
553 wlan_rfk_failed:
554 wlan_irq_failed:
555 bt_irq_failed:
556         gpio_free(pdata->bt_host_wake);
557         gpio_free(pdata->bt_wake);
558         gpio_free(pdata->bt_nrst);
559         gpio_free(pdata->bt_en);
560         gpio_free(pdata->wlan_host_wake);
561         gpio_free(pdata->wlan_en);
562         kfree(bd);
563 #if defined (WLAN_STATIC_BUF)
564 wlan_mem_failed:
565 #endif /* WLAN_STATIC_BUF */
566         return ret;
567 }
568
569 static int __devexit bcm4330_remove(struct platform_device *pdev)
570 {
571         struct bcm4330_data *bd = platform_get_drvdata(pdev);
572         struct bcm4330_platform_data *pdata = bd->pdata;
573
574         rfkill_unregister(bd->bt_rfk);
575         rfkill_destroy(bd->bt_rfk);
576         rfkill_unregister(bd->wlan_rfk);
577         rfkill_destroy(bd->wlan_rfk);
578         gpio_free(pdata->bt_host_wake);
579         gpio_free(pdata->bt_wake);
580         gpio_free(pdata->bt_nrst);
581         gpio_free(pdata->bt_en);
582         gpio_free(pdata->wlan_host_wake);
583         gpio_free(pdata->wlan_en);
584         kfree(bd);
585
586         platform_set_drvdata(pdev, NULL);
587
588         return 0;
589 }
590
591 #ifdef CONFIG_PM
592 static int bcm4330_suspend(struct platform_device *pdev, pm_message_t state)
593 {
594         struct bcm4330_data *bd = platform_get_drvdata(pdev);
595         struct bcm4330_platform_data *pdata = bd->pdata;
596
597         if (bd->wlan_in_use)
598                 s5p_gpio_set_pdn_config(pdata->wlan_en, S3C_GPIO_PDNCFG_OUTPUT1);
599         else
600                 s5p_gpio_set_pdn_config(pdata->wlan_en, S3C_GPIO_PDNCFG_OUTPUT0);
601
602         if (bd->bt_in_use) {
603                 s5p_gpio_set_pdn_config(pdata->bt_en, S3C_GPIO_PDNCFG_OUTPUT1);
604                 s5p_gpio_set_pdn_config(pdata->bt_nrst, S3C_GPIO_PDNCFG_OUTPUT1);
605                 s5p_gpio_set_pdn_config(pdata->bt_wake, S3C_GPIO_PDNCFG_OUTPUT0);
606         } else {
607                 s5p_gpio_set_pdn_config(pdata->bt_en, S3C_GPIO_PDNCFG_OUTPUT0);
608                 s5p_gpio_set_pdn_config(pdata->bt_nrst, S3C_GPIO_PDNCFG_OUTPUT0);
609                 s5p_gpio_set_pdn_config(pdata->bt_wake, S3C_GPIO_PDNCFG_OUTPUT0);
610         }
611
612         return 0;
613 }
614
615 static int bcm4330_resume(struct platform_device *pdev)
616 {
617         return 0;
618 }
619 #else
620 #define bcm4330_suspend         NULL
621 #define bcm4330_resume          NULL
622 #endif
623
624 #if defined (WLAN_STATIC_BUF)
625
626 #define PREALLOC_WLAN_SEC_NUM           4
627 #define PREALLOC_WLAN_BUF_NUM           160
628 #define PREALLOC_WLAN_SECTION_HEADER    24
629
630
631 #define WLAN_SECTION_SIZE_0     (PREALLOC_WLAN_BUF_NUM * 128)
632 #define WLAN_SECTION_SIZE_1     (PREALLOC_WLAN_BUF_NUM * 128)
633 #define WLAN_SECTION_SIZE_2     (PREALLOC_WLAN_BUF_NUM * 512)
634 #define WLAN_SECTION_SIZE_3     (PREALLOC_WLAN_BUF_NUM * 1024)
635
636 #define WLAN_SKB_BUF_NUM        17
637
638 static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
639
640 #endif /* WLAN_STATIC_BUF */
641
642 #if defined (WLAN_STATIC_BUF)
643
644 struct wifi_mem_prealloc {
645         void *mem_ptr;
646         unsigned long size;
647 };
648
649 static struct wifi_mem_prealloc wifi_mem_array[PREALLOC_WLAN_SEC_NUM] = {
650         {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)},
651         {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)},
652         {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)},
653         {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)}
654 };
655
656 void *wlan_mem_prealloc(int section, unsigned long size)
657 {
658         if (section == PREALLOC_WLAN_SEC_NUM)
659                 return wlan_static_skb;
660
661         if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM))
662                 return NULL;
663
664         if (wifi_mem_array[section].size < size)
665                 return NULL;
666
667         return wifi_mem_array[section].mem_ptr;
668 }
669 EXPORT_SYMBOL(wlan_mem_prealloc);
670
671 #define DHD_SKB_HDRSIZE                 336
672 #define DHD_SKB_1PAGE_BUFSIZE   ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE)
673 #define DHD_SKB_2PAGE_BUFSIZE   ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE)
674 #define DHD_SKB_4PAGE_BUFSIZE   ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE)
675
676 static int init_wifi_mem(void)
677 {
678         int i;
679         int j;
680
681         for (i = 0; i < 8; i++) {
682                 wlan_static_skb[i] = alloc_skb(DHD_SKB_1PAGE_BUFSIZE, GFP_KERNEL);
683                 if (!wlan_static_skb[i])
684                         goto err_skb_alloc;
685         }
686         
687         for (; i < 16; i++) {
688                 wlan_static_skb[i] = alloc_skb(DHD_SKB_2PAGE_BUFSIZE, GFP_KERNEL);
689                 if (!wlan_static_skb[i])
690                         goto err_skb_alloc;
691         }
692         
693         wlan_static_skb[i] = alloc_skb(DHD_SKB_4PAGE_BUFSIZE, GFP_KERNEL);
694         if (!wlan_static_skb[i])
695                 goto err_skb_alloc;
696
697         for (i = 0 ; i < PREALLOC_WLAN_SEC_NUM ; i++) {
698                 wifi_mem_array[i].mem_ptr =
699                                 kmalloc(wifi_mem_array[i].size, GFP_KERNEL);
700
701                 if (!wifi_mem_array[i].mem_ptr)
702                         goto err_mem_alloc;
703         }
704         return 0;
705
706  err_mem_alloc:
707         pr_err("Failed to mem_alloc for WLAN\n");
708         for (j = 0 ; j < i ; j++)
709                 kfree(wifi_mem_array[j].mem_ptr);
710
711         i = WLAN_SKB_BUF_NUM;
712
713  err_skb_alloc:
714         pr_err("Failed to skb_alloc for WLAN\n");
715         for (j = 0 ; j < i ; j++)
716                 dev_kfree_skb(wlan_static_skb[j]);
717
718         return -ENOMEM;
719 }
720
721 #endif  /* WLAN_STATIC_BUF */
722
723 static struct platform_device_id bcm4330_ids[] = {
724         {
725                 .name           = "bcm4330-b1",
726                 .driver_data    = TYPE_BCM4330_B1,
727         }, {
728                 .name           = "bcm4330-b0",
729                 .driver_data    = TYPE_BCM4330_B0,
730         },
731 };
732 MODULE_DEVICE_TABLE(platform, bcm4330_ids);
733
734 static struct platform_driver bcm4330_driver = {
735         .probe                  = bcm4330_probe,
736         .remove                 = __devexit_p(bcm4330_remove),
737         .suspend                = bcm4330_suspend,
738         .resume                 = bcm4330_resume,
739         .driver = {
740                 .name           = "bcm4330",
741         },
742         .id_table               = bcm4330_ids,
743 };
744
745 static int __init bcm4330_init(void)
746 {
747         return platform_driver_register(&bcm4330_driver);
748 }
749
750 static void __exit bcm4330_exit(void)
751 {
752         platform_driver_unregister(&bcm4330_driver);
753 }
754
755 module_init(bcm4330_init);
756 module_exit(bcm4330_exit);
757
758 MODULE_AUTHOR("Jaehoon Chung <jh80.chung@samsung.com>");
759 MODULE_DESCRIPTION("BCM4330 (WLAN/BT) module driver");
760 MODULE_LICENSE("GPL");