2 * Linux platform device for DHD WLAN adapter
4 * Copyright (C) 1999-2015, Broadcom Corporation
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
24 * $Id: dhd_linux_platdev.c 401742 2013-05-13 15:03:21Z $
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/platform_device.h>
32 #include <linux_osl.h>
34 #include <dngl_stats.h>
37 #include <dhd_linux.h>
38 #include <wl_android.h>
39 #if defined(CONFIG_WIFI_CONTROL_FUNC)
40 #include <linux/wlan_plat.h>
46 #include<linux/regulator/consumer.h>
47 #include<linux/of_gpio.h>
48 #endif /* CONFIG_DTS */
50 #if defined(CUSTOMER_HW)
51 extern int bcm_wlan_set_plat_data(void);
52 #endif /* CUSTOMER_HW */
54 #define WIFI_PLAT_NAME "bcmdhd_wlan"
55 #define WIFI_PLAT_NAME2 "bcm4329_wlan"
56 #define WIFI_PLAT_EXT "bcmdhd_wifi_platform"
59 struct regulator
*wifi_regulator
= NULL
;
60 #endif /* CONFIG_DTS */
62 bool cfg_multichip
= FALSE
;
63 bcmdhd_wifi_platdata_t
*dhd_wifi_platdata
= NULL
;
64 static int wifi_plat_dev_probe_ret
= 0;
65 static bool is_power_on
= FALSE
;
66 #if !defined(CONFIG_DTS)
67 #if defined(DHD_OF_SUPPORT)
68 static bool dts_enabled
= TRUE
;
69 extern struct wifi_platform_data dhd_wlan_control
;
70 struct resource dhd_wlan_resources
= {0};
72 static bool dts_enabled
= FALSE
;
73 struct resource dhd_wlan_resources
= {0};
75 struct wifi_platform_data dhd_wlan_control
= {0};
77 #endif /* !defind(DHD_OF_SUPPORT) */
78 #endif /* !defind(CONFIG_DTS) */
80 static int dhd_wifi_platform_load(void);
82 extern void* wl_cfg80211_get_dhdp(void);
84 #ifdef ENABLE_4335BT_WAR
85 extern int bcm_bt_lock(int cookie
);
86 extern void bcm_bt_unlock(int cookie
);
87 static int lock_cookie_wifi
= 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
88 #endif /* ENABLE_4335BT_WAR */
90 wifi_adapter_info_t
* dhd_wifi_platform_get_adapter(uint32 bus_type
, uint32 bus_num
, uint32 slot_num
)
94 if (dhd_wifi_platdata
== NULL
)
97 for (i
= 0; i
< dhd_wifi_platdata
->num_adapters
; i
++) {
98 wifi_adapter_info_t
*adapter
= &dhd_wifi_platdata
->adapters
[i
];
99 if ((adapter
->bus_type
== -1 || adapter
->bus_type
== bus_type
) &&
100 (adapter
->bus_num
== -1 || adapter
->bus_num
== bus_num
) &&
101 (adapter
->slot_num
== -1 || adapter
->slot_num
== slot_num
)) {
102 DHD_TRACE(("found adapter info '%s'\n", adapter
->name
));
109 void* wifi_platform_prealloc(wifi_adapter_info_t
*adapter
, int section
, unsigned long size
)
111 void *alloc_ptr
= NULL
;
112 struct wifi_platform_data
*plat_data
;
114 if (!adapter
|| !adapter
->wifi_plat_data
)
116 plat_data
= adapter
->wifi_plat_data
;
117 if (plat_data
->mem_prealloc
) {
118 alloc_ptr
= plat_data
->mem_prealloc(section
, size
);
120 DHD_INFO(("success alloc section %d\n", section
));
122 bzero(alloc_ptr
, size
);
128 DHD_ERROR(("%s: failed to alloc static mem section %d\n", __FUNCTION__
, section
));
132 void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t
*adapter
)
134 struct wifi_platform_data
*plat_data
;
136 if (!adapter
|| !adapter
->wifi_plat_data
)
138 plat_data
= adapter
->wifi_plat_data
;
139 return plat_data
->mem_prealloc
;
142 int wifi_platform_get_irq_number(wifi_adapter_info_t
*adapter
, unsigned long *irq_flags_ptr
)
147 *irq_flags_ptr
= adapter
->intr_flags
;
148 return adapter
->irq_num
;
151 int wifi_platform_set_power(wifi_adapter_info_t
*adapter
, bool on
, unsigned long msec
)
156 err
= regulator_enable(wifi_regulator
);
160 err
= regulator_disable(wifi_regulator
);
164 DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__
));
166 struct wifi_platform_data
*plat_data
;
168 if (!adapter
|| !adapter
->wifi_plat_data
)
170 plat_data
= adapter
->wifi_plat_data
;
172 DHD_ERROR(("%s = %d\n", __FUNCTION__
, on
));
173 if (plat_data
->set_power
) {
174 #ifdef ENABLE_4335BT_WAR
176 printk("WiFi: trying to acquire BT lock\n");
177 if (bcm_bt_lock(lock_cookie_wifi
) != 0)
178 printk("** WiFi: timeout in acquiring bt lock**\n");
179 printk("%s: btlock acquired\n", __FUNCTION__
);
182 /* For a exceptional case, release btlock */
183 bcm_bt_unlock(lock_cookie_wifi
);
185 #endif /* ENABLE_4335BT_WAR */
187 err
= plat_data
->set_power(on
);
198 #endif /* CONFIG_DTS */
203 int wifi_platform_bus_enumerate(wifi_adapter_info_t
*adapter
, bool device_present
)
206 struct wifi_platform_data
*plat_data
;
208 if (!adapter
|| !adapter
->wifi_plat_data
)
210 plat_data
= adapter
->wifi_plat_data
;
212 DHD_ERROR(("%s device present %d\n", __FUNCTION__
, device_present
));
213 if (plat_data
->set_carddetect
) {
214 err
= plat_data
->set_carddetect(device_present
);
220 int wifi_platform_get_mac_addr(wifi_adapter_info_t
*adapter
, unsigned char *buf
)
222 struct wifi_platform_data
*plat_data
;
224 DHD_ERROR(("%s\n", __FUNCTION__
));
225 if (!buf
|| !adapter
|| !adapter
->wifi_plat_data
)
227 plat_data
= adapter
->wifi_plat_data
;
228 if (plat_data
->get_mac_addr
) {
229 return plat_data
->get_mac_addr(buf
);
234 void *wifi_platform_get_country_code(wifi_adapter_info_t
*adapter
, char *ccode
)
236 /* get_country_code was added after 2.6.39 */
237 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
238 struct wifi_platform_data
*plat_data
;
240 if (!ccode
|| !adapter
|| !adapter
->wifi_plat_data
)
242 plat_data
= adapter
->wifi_plat_data
;
244 DHD_TRACE(("%s\n", __FUNCTION__
));
245 if (plat_data
->get_country_code
) {
246 return plat_data
->get_country_code(ccode
);
248 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
254 static int wifi_plat_dev_drv_probe(struct platform_device
*pdev
)
256 struct resource
*resource
;
257 wifi_adapter_info_t
*adapter
;
260 #endif /* CONFIG_DTS */
262 /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan")
263 * is kept for backward compatibility and supports only 1 adapter
265 ASSERT(dhd_wifi_platdata
!= NULL
);
266 ASSERT(dhd_wifi_platdata
->num_adapters
== 1);
267 adapter
= &dhd_wifi_platdata
->adapters
[0];
268 adapter
->wifi_plat_data
= (struct wifi_platform_data
*)(pdev
->dev
.platform_data
);
270 resource
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
, "bcmdhd_wlan_irq");
271 if (resource
== NULL
)
272 resource
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
, "bcm4329_wlan_irq");
274 adapter
->irq_num
= resource
->start
;
275 adapter
->intr_flags
= resource
->flags
& IRQF_TRIGGER_MASK
;
279 wifi_regulator
= regulator_get(&pdev
->dev
, "wlreg_on");
280 if (wifi_regulator
== NULL
) {
281 DHD_ERROR(("%s regulator is null\n", __FUNCTION__
));
285 /* This is to get the irq for the OOB */
286 gpio
= of_get_gpio(pdev
->dev
.of_node
, 0);
289 DHD_ERROR(("%s gpio information is incorrect\n", __FUNCTION__
));
292 irq
= gpio_to_irq(gpio
);
294 DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__
));
297 adapter
->irq_num
= irq
;
299 /* need to change the flags according to our requirement */
300 adapter
->intr_flags
= IORESOURCE_IRQ
| IORESOURCE_IRQ_HIGHLEVEL
|
301 IORESOURCE_IRQ_SHAREABLE
;
302 #endif /* CONFIG_DTS */
304 printk("probe++++++++++++++++");
305 wifi_plat_dev_probe_ret
= dhd_wifi_platform_load();
306 return wifi_plat_dev_probe_ret
;
309 static int wifi_plat_dev_drv_remove(struct platform_device
*pdev
)
311 wifi_adapter_info_t
*adapter
;
313 /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan")
314 * is kept for backward compatibility and supports only 1 adapter
316 ASSERT(dhd_wifi_platdata
!= NULL
);
317 ASSERT(dhd_wifi_platdata
->num_adapters
== 1);
318 adapter
= &dhd_wifi_platdata
->adapters
[0];
321 wifi_platform_bus_enumerate(adapter
, FALSE
);
322 wifi_platform_set_power(adapter
, FALSE
, WIFI_TURNOFF_DELAY
);
324 wifi_platform_set_power(adapter
, FALSE
, WIFI_TURNOFF_DELAY
);
325 wifi_platform_bus_enumerate(adapter
, FALSE
);
330 regulator_put(wifi_regulator
);
331 #endif /* CONFIG_DTS */
335 static int wifi_plat_dev_drv_suspend(struct platform_device
*pdev
, pm_message_t state
)
337 DHD_TRACE(("##> %s\n", __FUNCTION__
));
338 printk("++++++++++++++++++++++++++AP6269 suspend\n");
339 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 0
340 bcmsdh_oob_intr_set(0);
341 #endif /* (OOB_INTR_ONLY) */
345 static int wifi_plat_dev_drv_resume(struct platform_device
*pdev
)
347 DHD_TRACE(("##> %s\n", __FUNCTION__
));
348 printk("++++++++++++++++++++++++++AP6269 resume\n");
349 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 0
350 if (dhd_os_check_if_up(wl_cfg80211_get_dhdp()))
351 bcmsdh_oob_intr_set(1);
352 #endif /* (OOB_INTR_ONLY) */
357 static const struct of_device_id wifi_device_dt_match
[] = {
358 { .compatible
= "android,bcmdhd_wlan", },
361 #endif /* CONFIG_DTS */
363 static struct platform_driver wifi_platform_dev_driver
= {
364 .probe
= wifi_plat_dev_drv_probe
,
365 .remove
= wifi_plat_dev_drv_remove
,
366 .suspend
= wifi_plat_dev_drv_suspend
,
367 .resume
= wifi_plat_dev_drv_resume
,
369 .name
= WIFI_PLAT_NAME
,
371 .of_match_table
= wifi_device_dt_match
,
372 #endif /* CONFIG_DTS */
376 static struct platform_driver wifi_platform_dev_driver_legacy
= {
377 .probe
= wifi_plat_dev_drv_probe
,
378 .remove
= wifi_plat_dev_drv_remove
,
379 .suspend
= wifi_plat_dev_drv_suspend
,
380 .resume
= wifi_plat_dev_drv_resume
,
382 .name
= WIFI_PLAT_NAME2
,
386 static int wifi_platdev_match(struct device
*dev
, void *data
)
388 char *name
= (char*)data
;
389 struct platform_device
*pdev
= to_platform_device(dev
);
391 if (strcmp(pdev
->name
, name
) == 0) {
392 DHD_ERROR(("found wifi platform device %s\n", name
));
400 static int wifi_ctrlfunc_register_drv(void)
402 wifi_adapter_info_t
*adapter
;
406 struct device
*dev1
, *dev2
;
407 dev1
= bus_find_device(&platform_bus_type
, NULL
, WIFI_PLAT_NAME
, wifi_platdev_match
);
408 dev2
= bus_find_device(&platform_bus_type
, NULL
, WIFI_PLAT_NAME2
, wifi_platdev_match
);
411 #if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
413 if (dev1
== NULL
&& dev2
== NULL
) {
414 DHD_ERROR(("no wifi platform data, skip\n"));
418 #endif /* !defined(CONFIG_DTS) */
420 /* multi-chip support not enabled, build one adapter information for
421 * DHD (either SDIO, USB or PCIe)
423 adapter
= kzalloc(sizeof(wifi_adapter_info_t
), GFP_KERNEL
);
424 if (adapter
== NULL
) {
425 DHD_ERROR(("%s:adapter alloc failed", __FUNCTION__
));
428 adapter
->name
= "DHD generic adapter";
429 adapter
->bus_type
= -1;
430 adapter
->bus_num
= -1;
431 adapter
->slot_num
= -1;
432 adapter
->irq_num
= -1;
434 wifi_plat_dev_probe_ret
= 0;
435 dhd_wifi_platdata
= kzalloc(sizeof(bcmdhd_wifi_platdata_t
), GFP_KERNEL
);
436 dhd_wifi_platdata
->num_adapters
= 1;
437 dhd_wifi_platdata
->adapters
= adapter
;
441 err
= platform_driver_register(&wifi_platform_dev_driver
);
443 DHD_ERROR(("%s: failed to register wifi ctrl func driver\n",
449 err
= platform_driver_register(&wifi_platform_dev_driver_legacy
);
451 DHD_ERROR(("%s: failed to register wifi ctrl func legacy driver\n",
458 #if !defined(CONFIG_DTS)
461 adapter
->wifi_plat_data
= (void *)&dhd_wlan_control
;
462 bcm_wlan_set_plat_data();
464 struct resource
*resource
;
465 resource
= &dhd_wlan_resources
;
466 adapter
->irq_num
= resource
->start
;
467 adapter
->intr_flags
= resource
->flags
& IRQF_TRIGGER_MASK
;
469 wifi_plat_dev_probe_ret
= dhd_wifi_platform_load();
471 #endif /* !defined(CONFIG_DTS) */
474 #if defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
475 wifi_plat_dev_probe_ret
= platform_driver_register(&wifi_platform_dev_driver
);
476 #endif /* CONFIG_DTS */
478 /* return probe function's return value if registeration succeeded */
479 return wifi_plat_dev_probe_ret
;
482 void wifi_ctrlfunc_unregister_drv(void)
485 #if defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
486 DHD_ERROR(("unregister wifi platform drivers\n"));
487 platform_driver_unregister(&wifi_platform_dev_driver
);
490 struct device
*dev1
, *dev2
;
491 dev1
= bus_find_device(&platform_bus_type
, NULL
, WIFI_PLAT_NAME
, wifi_platdev_match
);
492 dev2
= bus_find_device(&platform_bus_type
, NULL
, WIFI_PLAT_NAME2
, wifi_platdev_match
);
494 if (dev1
== NULL
&& dev2
== NULL
)
497 DHD_ERROR(("unregister wifi platform drivers\n"));
500 platform_driver_unregister(&wifi_platform_dev_driver
);
502 platform_driver_unregister(&wifi_platform_dev_driver_legacy
);
505 wifi_adapter_info_t
*adapter
;
506 adapter
= &dhd_wifi_platdata
->adapters
[0];
508 wifi_platform_set_power(adapter
, FALSE
, WIFI_TURNOFF_DELAY
);
509 wifi_platform_bus_enumerate(adapter
, FALSE
);
512 #endif /* !defined(CONFIG_DTS) */
514 kfree(dhd_wifi_platdata
->adapters
);
515 dhd_wifi_platdata
->adapters
= NULL
;
516 dhd_wifi_platdata
->num_adapters
= 0;
517 kfree(dhd_wifi_platdata
);
518 dhd_wifi_platdata
= NULL
;
522 static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device
*pdev
)
524 dhd_wifi_platdata
= (bcmdhd_wifi_platdata_t
*)(pdev
->dev
.platform_data
);
526 return dhd_wifi_platform_load();
529 static int bcmdhd_wifi_plat_dev_drv_remove(struct platform_device
*pdev
)
532 wifi_adapter_info_t
*adapter
;
533 ASSERT(dhd_wifi_platdata
!= NULL
);
535 /* power down all adapters */
536 for (i
= 0; i
< dhd_wifi_platdata
->num_adapters
; i
++) {
537 adapter
= &dhd_wifi_platdata
->adapters
[i
];
538 wifi_platform_set_power(adapter
, FALSE
, WIFI_TURNOFF_DELAY
);
539 wifi_platform_bus_enumerate(adapter
, FALSE
);
544 static struct platform_driver dhd_wifi_platform_dev_driver
= {
545 .probe
= bcmdhd_wifi_plat_dev_drv_probe
,
546 .remove
= bcmdhd_wifi_plat_dev_drv_remove
,
547 .suspend
= wifi_plat_dev_drv_suspend
,
548 .resume
= wifi_plat_dev_drv_resume
,
550 .name
= WIFI_PLAT_EXT
,
555 int dhd_wifi_platform_register_drv(void)
561 /* register Broadcom wifi platform data driver if multi-chip is enabled,
562 * otherwise use Android style wifi platform data (aka wifi control function)
565 * to support multi-chip DHD, Broadcom wifi platform data device must
566 * be added in kernel early boot (e.g. board config file).
569 dev
= bus_find_device(&platform_bus_type
, NULL
, WIFI_PLAT_EXT
, wifi_platdev_match
);
571 DHD_ERROR(("bcmdhd wifi platform data device not found!!\n"));
574 err
= platform_driver_register(&dhd_wifi_platform_dev_driver
);
578 err
= wifi_ctrlfunc_register_drv();
580 /* no wifi ctrl func either, load bus directly and ignore this error */
583 /* wifi ctrl function does not exist */
584 err
= dhd_wifi_platform_load();
586 /* unregister driver due to initialization failure */
587 wifi_ctrlfunc_unregister_drv();
596 static int dhd_wifi_platform_load_pcie(void)
600 wifi_adapter_info_t
*adapter
;
603 BCM_REFERENCE(adapter
);
605 if (dhd_wifi_platdata
== NULL
) {
606 err
= dhd_bus_register();
608 if (dhd_download_fw_on_driverload
) {
609 /* power up all adapters */
610 for (i
= 0; i
< dhd_wifi_platdata
->num_adapters
; i
++) {
611 int retry
= POWERUP_MAX_RETRY
;
612 adapter
= &dhd_wifi_platdata
->adapters
[i
];
614 DHD_ERROR(("Power-up adapter '%s'\n", adapter
->name
));
615 DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n",
616 adapter
->irq_num
, adapter
->intr_flags
, adapter
->fw_path
,
618 DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n",
619 adapter
->bus_type
, adapter
->bus_num
, adapter
->slot_num
));
622 err
= wifi_platform_set_power(adapter
,
623 TRUE
, WIFI_TURNON_DELAY
);
625 DHD_ERROR(("failed to power up %s,"
627 adapter
->name
, retry
));
628 /* WL_REG_ON state unknown, Power off forcely */
629 wifi_platform_set_power(adapter
,
630 FALSE
, WIFI_TURNOFF_DELAY
);
633 err
= wifi_platform_bus_enumerate(adapter
, TRUE
);
635 DHD_ERROR(("failed to enumerate bus %s, "
637 adapter
->name
, retry
));
638 wifi_platform_set_power(adapter
, FALSE
,
647 DHD_ERROR(("failed to power up %s, max retry reached**\n",
654 err
= dhd_bus_register();
657 DHD_ERROR(("%s: pcie_register_driver failed\n", __FUNCTION__
));
658 if (dhd_download_fw_on_driverload
) {
659 /* power down all adapters */
660 for (i
= 0; i
< dhd_wifi_platdata
->num_adapters
; i
++) {
661 adapter
= &dhd_wifi_platdata
->adapters
[i
];
662 wifi_platform_bus_enumerate(adapter
, FALSE
);
663 wifi_platform_set_power(adapter
,
664 FALSE
, WIFI_TURNOFF_DELAY
);
673 static int dhd_wifi_platform_load_pcie(void)
680 void dhd_wifi_platform_unregister_drv(void)
684 platform_driver_unregister(&dhd_wifi_platform_dev_driver
);
687 wifi_ctrlfunc_unregister_drv();
690 extern int dhd_watchdog_prio
;
691 extern int dhd_dpc_prio
;
692 extern uint dhd_deferred_tx
;
693 #if defined(OEM_ANDROID) && defined(BCMLXSDMMC)
694 extern struct semaphore dhd_registration_sem
;
695 #endif /* defined(OEM_ANDROID) && defined(BCMLXSDMMC) */
697 static int dhd_wifi_platform_load_sdio(void)
703 /* User-specified vid/pid */
706 module_param(dhd_vid
, int, 0);
707 module_param(dhd_pid
, int, 0);
708 void *dhd_dbus_probe_cb(void *arg
, const char *desc
, uint32 bustype
, uint32 hdrlen
);
709 void dhd_dbus_disconnect_cb(void *arg
);
711 static int dhd_wifi_platform_load_usb(void)
715 if (dhd_vid
< 0 || dhd_vid
> 0xffff) {
716 DHD_ERROR(("%s: invalid dhd_vid 0x%x\n", __FUNCTION__
, dhd_vid
));
719 if (dhd_pid
< 0 || dhd_pid
> 0xffff) {
720 DHD_ERROR(("%s: invalid dhd_pid 0x%x\n", __FUNCTION__
, dhd_pid
));
724 err
= dbus_register(dhd_vid
, dhd_pid
, dhd_dbus_probe_cb
, dhd_dbus_disconnect_cb
,
727 /* Device not detected */
728 if (err
== DBUS_ERR_NODEVICE
)
734 static int dhd_wifi_platform_load_usb(void)
740 static int dhd_wifi_platform_load()
743 printf("%s: Enter\n", __FUNCTION__
);
745 #if defined(OEM_ANDROID)
747 #endif /* OEM_ANDROID */
749 if ((err
= dhd_wifi_platform_load_usb()))
751 else if ((err
= dhd_wifi_platform_load_sdio()))
754 err
= dhd_wifi_platform_load_pcie();
757 #if defined(OEM_ANDROID)
760 #if !defined(MULTIPLE_SUPPLICANT)
762 wl_android_post_init();
764 #endif /* OEM_ANDROID */