dhd: import wifi and bluetooth firmware
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.101.10.240.x / dhd_linux_platdev.c
CommitLineData
1b4a7c03
LJ
1/*
2 * Linux platform device for DHD WLAN adapter
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
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:
11 *
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.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Open:>>
22 *
23 * $Id$
24 */
25#include <typedefs.h>
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/platform_device.h>
30#include <bcmutils.h>
31#include <linux_osl.h>
32#include <dhd_dbg.h>
33#include <dngl_stats.h>
34#include <dhd.h>
35#include <dhd_bus.h>
36#include <dhd_linux.h>
37#include <wl_android.h>
38#if defined(CONFIG_WIFI_CONTROL_FUNC)
39#include <linux/wlan_plat.h>
40#endif
41#ifdef CONFIG_DTS
42#include<linux/regulator/consumer.h>
43#include<linux/of_gpio.h>
44#endif /* CONFIG_DTS */
45
46#if defined(CUSTOMER_HW)
47extern int dhd_wlan_init_plat_data(void);
48extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter);
49#endif /* CUSTOMER_HW */
50
51#define WIFI_PLAT_NAME "bcmdhd_wlan"
52#define WIFI_PLAT_NAME2 "bcm4329_wlan"
53#define WIFI_PLAT_EXT "bcmdhd_wifi_platform"
54
55#ifdef DHD_WIFI_SHUTDOWN
56extern void wifi_plat_dev_drv_shutdown(struct platform_device *pdev);
57#endif
58
59#ifdef CONFIG_DTS
60struct regulator *wifi_regulator = NULL;
61#endif /* CONFIG_DTS */
62
63bool cfg_multichip = FALSE;
64bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL;
65static int wifi_plat_dev_probe_ret = 0;
66static bool is_power_on = FALSE;
67/* XXX Some Qualcomm based CUSTOMER_HW4 platforms are using platform
68 * device structure even if the Kernel uses device tree structure.
69 * Therefore, the CONFIG_ARCH_MSM condition is temporarly remained
70 * to support in this case.
71 */
72#if !defined(CONFIG_DTS)
73#if defined(DHD_OF_SUPPORT)
74static bool dts_enabled = TRUE;
75extern struct resource dhd_wlan_resources;
76extern struct wifi_platform_data dhd_wlan_control;
77#else
78static bool dts_enabled = FALSE;
79#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
80#pragma GCC diagnostic push
81#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
82#endif
83struct resource dhd_wlan_resources = {0};
84struct wifi_platform_data dhd_wlan_control = {0};
85#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
86#pragma GCC diagnostic pop
87#endif
88#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */
89#endif /* !defind(CONFIG_DTS) */
90
91static int dhd_wifi_platform_load(void);
92
93extern void* wl_cfg80211_get_dhdp(struct net_device *dev);
94
95#ifdef BCMDHD_MODULAR
96extern int dhd_wlan_init(void);
97extern int dhd_wlan_deinit(void);
98#endif /* BCMDHD_MODULAR */
99
100#ifdef ENABLE_4335BT_WAR
101extern int bcm_bt_lock(int cookie);
102extern void bcm_bt_unlock(int cookie);
103static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
104#endif /* ENABLE_4335BT_WAR */
105
106#ifdef BCM4335_XTAL_WAR
107extern bool check_bcm4335_rev(void);
108#endif /* BCM4335_XTAL_WAR */
109
110wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type,
111 uint32 bus_num, uint32 slot_num, unsigned long status)
112{
113 int i;
114
115 if (dhd_wifi_platdata == NULL)
116 return NULL;
117
118 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
119 wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i];
120 if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) &&
121 (adapter->bus_num == -1 || adapter->bus_num == bus_num) &&
122 (adapter->slot_num == -1 || adapter->slot_num == slot_num)
123#if defined(ENABLE_INSMOD_NO_FW_LOAD)
124 && (wifi_chk_adapter_status(adapter, status))
125#endif
126 ) {
127 DHD_ERROR(("attach adapter info '%s'\n", adapter->name));
128 return adapter;
129 }
130 }
131 return NULL;
132}
133
134wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num)
135{
136 int i;
137
138 if (dhd_wifi_platdata == NULL)
139 return NULL;
140
141 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
142 wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i];
143 if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) &&
144 (adapter->bus_num == -1 || adapter->bus_num == bus_num) &&
145 (adapter->slot_num == -1 || adapter->slot_num == slot_num)) {
146 DHD_TRACE(("found adapter info '%s'\n", adapter->name));
147 return adapter;
148 }
149 }
150 return NULL;
151}
152
153void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size)
154{
155 void *alloc_ptr = NULL;
156 struct wifi_platform_data *plat_data;
157
158 if (!adapter || !adapter->wifi_plat_data)
159 return NULL;
160 plat_data = adapter->wifi_plat_data;
161 if (plat_data->mem_prealloc) {
162 alloc_ptr = plat_data->mem_prealloc(section, size);
163 if (alloc_ptr) {
164 DHD_INFO(("success alloc section %d\n", section));
165 if (size != 0L)
166 bzero(alloc_ptr, size);
167 return alloc_ptr;
168 }
169 } else
170 return NULL;
171
172 DHD_ERROR(("%s: failed to alloc static mem section %d\n", __FUNCTION__, section));
173 return NULL;
174}
175
176void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter)
177{
178 struct wifi_platform_data *plat_data;
179
180 if (!adapter || !adapter->wifi_plat_data)
181 return NULL;
182 plat_data = adapter->wifi_plat_data;
183 return plat_data->mem_prealloc;
184}
185
186int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr)
187{
188 if (adapter == NULL)
189 return -1;
190 if (irq_flags_ptr)
191 *irq_flags_ptr = adapter->intr_flags;
192 return adapter->irq_num;
193}
194
195int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec)
196{
197 int err = 0;
198#ifndef CONFIG_DTS
199 struct wifi_platform_data *plat_data;
200#endif
201#ifdef BT_OVER_SDIO
202 if (is_power_on == on) {
203 return -EINVAL;
204 }
205#endif /* BT_OVER_SDIO */
206 if (on) {
207 wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON);
208 } else {
209 wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON);
210 }
211#ifdef CONFIG_DTS
212 if (on) {
213 printf("======== PULL WL_REG_ON HIGH! ========\n");
214 err = regulator_enable(wifi_regulator);
215 is_power_on = TRUE;
216 }
217 else {
218 printf("======== PULL WL_REG_ON LOW! ========\n");
219 err = regulator_disable(wifi_regulator);
220 is_power_on = FALSE;
221 }
222 if (err < 0) {
223 DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__));
224 goto fail;
225 }
226#else
227 if (!adapter || !adapter->wifi_plat_data) {
228 err = -EINVAL;
229 goto fail;
230 }
231 plat_data = adapter->wifi_plat_data;
232
233 DHD_ERROR(("%s = %d, delay: %lu msec\n", __FUNCTION__, on, msec));
234 if (plat_data->set_power) {
235#ifdef ENABLE_4335BT_WAR
236 if (on) {
237 printk("WiFi: trying to acquire BT lock\n");
238 if (bcm_bt_lock(lock_cookie_wifi) != 0)
239 printk("** WiFi: timeout in acquiring bt lock**\n");
240 printk("%s: btlock acquired\n", __FUNCTION__);
241 }
242 else {
243 /* For a exceptional case, release btlock */
244 bcm_bt_unlock(lock_cookie_wifi);
245 }
246#endif /* ENABLE_4335BT_WAR */
247
248#ifdef BUS_POWER_RESTORE
249 err = plat_data->set_power(on, adapter);
250#else
251 err = plat_data->set_power(on);
252#endif
253 }
254
255 if (msec && !err)
256 OSL_SLEEP(msec);
257
258 if (on && !err)
259 is_power_on = TRUE;
260 else
261 is_power_on = FALSE;
262
263#endif /* CONFIG_DTS */
264
265 return err;
266fail:
267 if (on) {
268 wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON);
269 } else {
270 wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON);
271 }
272 return err;
273}
274
275int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present)
276{
277 int err = 0;
278 struct wifi_platform_data *plat_data;
279
280 if (!adapter || !adapter->wifi_plat_data)
281 return -EINVAL;
282 plat_data = adapter->wifi_plat_data;
283
284 DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present));
285 if (plat_data->set_carddetect) {
286 err = plat_data->set_carddetect(device_present);
287 }
288 return err;
289
290}
291
292int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf,
293 char *name)
294{
295 struct wifi_platform_data *plat_data;
296
297 DHD_ERROR(("%s\n", __FUNCTION__));
298 if (!buf || !adapter || !adapter->wifi_plat_data)
299 return -EINVAL;
300 plat_data = adapter->wifi_plat_data;
301 if (plat_data->get_mac_addr) {
302#ifdef CUSTOM_MULTI_MAC
303 return plat_data->get_mac_addr(buf, name);
304#else
305 return plat_data->get_mac_addr(buf);
306#endif
307 }
308 return -EOPNOTSUPP;
309}
310
311void *
312#ifdef CUSTOM_COUNTRY_CODE
313wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags)
314#else
315wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode)
316#endif /* CUSTOM_COUNTRY_CODE */
317{
318 /* get_country_code was added after 2.6.39 */
319#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
320 struct wifi_platform_data *plat_data;
321
322 if (!ccode || !adapter || !adapter->wifi_plat_data)
323 return NULL;
324 plat_data = adapter->wifi_plat_data;
325
326 DHD_TRACE(("%s\n", __FUNCTION__));
327 if (plat_data->get_country_code) {
328#ifdef CUSTOM_FORCE_NODFS_FLAG
329 return plat_data->get_country_code(ccode, flags);
330#else
331 return plat_data->get_country_code(ccode);
332#endif /* CUSTOM_COUNTRY_CODE */
333 }
334#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
335
336 return NULL;
337}
338
339#ifndef CUSTOMER_HW
340static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
341{
342 struct resource *resource;
343 wifi_adapter_info_t *adapter;
344#if defined(CONFIG_DTS) && defined(CUSTOMER_OOB)
345 int irq, gpio;
346#endif /* CONFIG_DTS */
347
348 /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan")
349 * is kept for backward compatibility and supports only 1 adapter
350 */
351 ASSERT(dhd_wifi_platdata != NULL);
352 ASSERT(dhd_wifi_platdata->num_adapters == 1);
353 adapter = &dhd_wifi_platdata->adapters[0];
354#if defined(CONFIG_WIFI_CONTROL_FUNC)
355 adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data);
356#else
357 adapter->wifi_plat_data = (void *)&dhd_wlan_control;
358#endif
359
360 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
361 if (resource == NULL)
362 resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq");
363 if (resource) {
364 adapter->irq_num = resource->start;
365 adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK;
366#ifdef DHD_ISR_NO_SUSPEND
367 adapter->intr_flags |= IRQF_NO_SUSPEND;
368#endif
369 }
370
371#ifdef CONFIG_DTS
372 wifi_regulator = regulator_get(&pdev->dev, "wlreg_on");
373 if (wifi_regulator == NULL) {
374 DHD_ERROR(("%s regulator is null\n", __FUNCTION__));
375 return -1;
376 }
377
378#if defined(CUSTOMER_OOB)
379 /* This is to get the irq for the OOB */
380 gpio = of_get_gpio(pdev->dev.of_node, 0);
381
382 if (gpio < 0) {
383 DHD_ERROR(("%s gpio information is incorrect\n", __FUNCTION__));
384 return -1;
385 }
386 irq = gpio_to_irq(gpio);
387 if (irq < 0) {
388 DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__));
389 return -1;
390 }
391 adapter->irq_num = irq;
392
393 /* need to change the flags according to our requirement */
394 adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |
395 IORESOURCE_IRQ_SHAREABLE;
396#endif
397#endif /* CONFIG_DTS */
398
399 wifi_plat_dev_probe_ret = dhd_wifi_platform_load();
400 return wifi_plat_dev_probe_ret;
401}
402
403static int wifi_plat_dev_drv_remove(struct platform_device *pdev)
404{
405 wifi_adapter_info_t *adapter;
406
407 /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan")
408 * is kept for backward compatibility and supports only 1 adapter
409 */
410 ASSERT(dhd_wifi_platdata != NULL);
411 ASSERT(dhd_wifi_platdata->num_adapters == 1);
412 adapter = &dhd_wifi_platdata->adapters[0];
413 if (is_power_on) {
414#ifdef BCMPCIE
415 wifi_platform_bus_enumerate(adapter, FALSE);
416 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
417#else
418 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
419 wifi_platform_bus_enumerate(adapter, FALSE);
420#endif /* BCMPCIE */
421 }
422
423#ifdef CONFIG_DTS
424 regulator_put(wifi_regulator);
425#endif /* CONFIG_DTS */
426 return 0;
427}
428
429static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state)
430{
431 DHD_TRACE(("##> %s\n", __FUNCTION__));
432#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \
433 defined(BCMSDIO)
434 bcmsdh_oob_intr_set(0);
435#endif /* (OOB_INTR_ONLY) */
436 return 0;
437}
438
439static int wifi_plat_dev_drv_resume(struct platform_device *pdev)
440{
441 DHD_TRACE(("##> %s\n", __FUNCTION__));
442#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \
443 defined(BCMSDIO)
444 if (dhd_os_check_if_up(wl_cfg80211_get_dhdp()))
445 bcmsdh_oob_intr_set(1);
446#endif /* (OOB_INTR_ONLY) */
447 return 0;
448}
449
450#ifdef CONFIG_DTS
451static const struct of_device_id wifi_device_dt_match[] = {
452 { .compatible = "android,bcmdhd_wlan", },
453 {},
454};
455#endif /* CONFIG_DTS */
456
457static struct platform_driver wifi_platform_dev_driver = {
458 .probe = wifi_plat_dev_drv_probe,
459 .remove = wifi_plat_dev_drv_remove,
460 .suspend = wifi_plat_dev_drv_suspend,
461 .resume = wifi_plat_dev_drv_resume,
462#ifdef DHD_WIFI_SHUTDOWN
463 .shutdown = wifi_plat_dev_drv_shutdown,
464#endif /* DHD_WIFI_SHUTDOWN */
465 .driver = {
466 .name = WIFI_PLAT_NAME,
467#ifdef CONFIG_DTS
468 .of_match_table = wifi_device_dt_match,
469#endif /* CONFIG_DTS */
470 }
471};
472
473static struct platform_driver wifi_platform_dev_driver_legacy = {
474 .probe = wifi_plat_dev_drv_probe,
475 .remove = wifi_plat_dev_drv_remove,
476 .suspend = wifi_plat_dev_drv_suspend,
477 .resume = wifi_plat_dev_drv_resume,
478#ifdef DHD_WIFI_SHUTDOWN
479 .shutdown = wifi_plat_dev_drv_shutdown,
480#endif /* DHD_WIFI_SHUTDOWN */
481 .driver = {
482 .name = WIFI_PLAT_NAME2,
483 }
484};
485
486static int wifi_platdev_match(struct device *dev, void *data)
487{
488 char *name = (char*)data;
489 const struct platform_device *pdev;
490 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
491 pdev = to_platform_device(dev);
492 GCC_DIAGNOSTIC_POP();
493
494 if (strcmp(pdev->name, name) == 0) {
495 DHD_ERROR(("found wifi platform device %s\n", name));
496 return TRUE;
497 }
498
499 return FALSE;
500}
501#endif
502
503static int wifi_ctrlfunc_register_drv(void)
504{
505 wifi_adapter_info_t *adapter;
506
507#ifndef CUSTOMER_HW
508 int err = 0;
509 struct device *dev1, *dev2;
510 dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match);
511 dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match);
512#endif
513
514#ifdef BCMDHD_MODULAR
515 dhd_wlan_init();
516#endif /* BCMDHD_MODULAR */
517
518#if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
519 if (!dts_enabled) {
520 if (dev1 == NULL && dev2 == NULL) {
521 DHD_ERROR(("no wifi platform data, skip\n"));
522 return -ENXIO;
523 }
524 }
525#endif /* !defined(CONFIG_DTS) */
526
527 /* multi-chip support not enabled, build one adapter information for
528 * DHD (either SDIO, USB or PCIe)
529 */
530 adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL);
531 if (adapter == NULL) {
532 DHD_ERROR(("%s:adapter alloc failed", __FUNCTION__));
533 return -ENOMEM;
534 }
535 adapter->name = "DHD generic adapter";
536 adapter->bus_type = -1;
537 adapter->bus_num = -1;
538 adapter->slot_num = -1;
539 adapter->irq_num = -1;
540 is_power_on = FALSE;
541 wifi_plat_dev_probe_ret = 0;
542 dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL);
543 dhd_wifi_platdata->num_adapters = 1;
544 dhd_wifi_platdata->adapters = adapter;
545 init_waitqueue_head(&adapter->status_event);
546
547#ifndef CUSTOMER_HW
548 if (dev1) {
549 err = platform_driver_register(&wifi_platform_dev_driver);
550 if (err) {
551 DHD_ERROR(("%s: failed to register wifi ctrl func driver\n",
552 __FUNCTION__));
553 return err;
554 }
555 }
556 if (dev2) {
557 err = platform_driver_register(&wifi_platform_dev_driver_legacy);
558 if (err) {
559 DHD_ERROR(("%s: failed to register wifi ctrl func legacy driver\n",
560 __FUNCTION__));
561 return err;
562 }
563 }
564#endif
565
566#if !defined(CONFIG_DTS)
567 if (dts_enabled) {
568 struct resource *resource;
569 adapter->wifi_plat_data = (void *)&dhd_wlan_control;
570 resource = &dhd_wlan_resources;
571#ifdef CUSTOMER_HW
572 wifi_plat_dev_probe_ret = dhd_wlan_init_plat_data();
573 if (wifi_plat_dev_probe_ret)
574 return wifi_plat_dev_probe_ret;
575#endif
576 adapter->irq_num = resource->start;
577 adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK;
578#ifdef DHD_ISR_NO_SUSPEND
579 adapter->intr_flags |= IRQF_NO_SUSPEND;
580#endif
581 wifi_plat_dev_probe_ret = dhd_wifi_platform_load();
582 }
583#endif /* !defined(CONFIG_DTS) */
584
585#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
586 wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver);
587#endif /* CONFIG_DTS */
588
589 /* return probe function's return value if registeration succeeded */
590 return wifi_plat_dev_probe_ret;
591}
592
593void wifi_ctrlfunc_unregister_drv(void)
594{
595#ifndef CONFIG_DTS
596 wifi_adapter_info_t *adapter;
597#endif
598
599#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
600 DHD_ERROR(("unregister wifi platform drivers\n"));
601 platform_driver_unregister(&wifi_platform_dev_driver);
602#else
603#ifndef CUSTOMER_HW
604 struct device *dev1, *dev2;
605 dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match);
606 dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match);
607 if (!dts_enabled)
608 if (dev1 == NULL && dev2 == NULL)
609 return;
610#endif
611 DHD_ERROR(("unregister wifi platform drivers\n"));
612#ifndef CUSTOMER_HW
613 if (dev1)
614 platform_driver_unregister(&wifi_platform_dev_driver);
615 if (dev2)
616 platform_driver_unregister(&wifi_platform_dev_driver_legacy);
617#endif
618 if (dts_enabled) {
619 adapter = &dhd_wifi_platdata->adapters[0];
620 if (is_power_on) {
621 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
622 }
623 wifi_platform_bus_enumerate(adapter, FALSE);
624 }
625#ifdef BCMDHD_MODULAR
626 dhd_wlan_deinit();
627#endif /* BCMDHD_MODULAR */
628#endif /* !defined(CONFIG_DTS) */
629
630#if defined(CUSTOMER_HW)
631 dhd_wlan_deinit_plat_data(adapter);
632#endif
633
634 kfree(dhd_wifi_platdata->adapters);
635 dhd_wifi_platdata->adapters = NULL;
636 dhd_wifi_platdata->num_adapters = 0;
637 kfree(dhd_wifi_platdata);
638 dhd_wifi_platdata = NULL;
639}
640
641#ifndef CUSTOMER_HW
642static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device *pdev)
643{
644 dhd_wifi_platdata = (bcmdhd_wifi_platdata_t *)(pdev->dev.platform_data);
645
646 return dhd_wifi_platform_load();
647}
648
649static int bcmdhd_wifi_plat_dev_drv_remove(struct platform_device *pdev)
650{
651 int i;
652 wifi_adapter_info_t *adapter;
653 ASSERT(dhd_wifi_platdata != NULL);
654
655 /* power down all adapters */
656 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
657 adapter = &dhd_wifi_platdata->adapters[i];
658 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
659 wifi_platform_bus_enumerate(adapter, FALSE);
660 }
661 return 0;
662}
663
664static struct platform_driver dhd_wifi_platform_dev_driver = {
665 .probe = bcmdhd_wifi_plat_dev_drv_probe,
666 .remove = bcmdhd_wifi_plat_dev_drv_remove,
667 .driver = {
668 .name = WIFI_PLAT_EXT,
669 }
670};
671#endif
672
673int dhd_wifi_platform_register_drv(void)
674{
675 int err = 0;
676#ifndef CUSTOMER_HW
677 struct device *dev;
678
679 /* register Broadcom wifi platform data driver if multi-chip is enabled,
680 * otherwise use Android style wifi platform data (aka wifi control function)
681 * if it exists
682 *
683 * to support multi-chip DHD, Broadcom wifi platform data device must
684 * be added in kernel early boot (e.g. board config file).
685 */
686 if (cfg_multichip) {
687 dev = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_EXT, wifi_platdev_match);
688 if (dev == NULL) {
689 DHD_ERROR(("bcmdhd wifi platform data device not found!!\n"));
690 return -ENXIO;
691 }
692 err = platform_driver_register(&dhd_wifi_platform_dev_driver);
693 } else
694#endif
695 {
696 err = wifi_ctrlfunc_register_drv();
697
698 /* no wifi ctrl func either, load bus directly and ignore this error */
699 if (err) {
700 if (err == -ENXIO) {
701 /* wifi ctrl function does not exist */
702 err = dhd_wifi_platform_load();
703 } else {
704 /* unregister driver due to initialization failure */
705 wifi_ctrlfunc_unregister_drv();
706 }
707 }
708 }
709
710 return err;
711}
712
713#ifdef BCMPCIE
714static int dhd_wifi_platform_load_pcie(void)
715{
716 int err = 0;
717 int i;
718 wifi_adapter_info_t *adapter;
719
720 BCM_REFERENCE(i);
721 BCM_REFERENCE(adapter);
722
723 if (dhd_wifi_platdata == NULL) {
724 /* XXX For x86 Bringup PC or BRIX */
725 err = dhd_bus_register();
726 } else {
727#ifdef DHD_SUPPORT_HDM
728 if (dhd_download_fw_on_driverload || hdm_trigger_init) {
729#else
730 if (dhd_download_fw_on_driverload) {
731#endif /* DHD_SUPPORT_HDM */
732 /* power up all adapters */
733 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
734 int retry = POWERUP_MAX_RETRY;
735 adapter = &dhd_wifi_platdata->adapters[i];
736
737 DHD_ERROR(("Power-up adapter '%s'\n", adapter->name));
738 DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n",
739 adapter->irq_num, adapter->intr_flags, adapter->fw_path,
740 adapter->nv_path));
741 DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n",
742 adapter->bus_type, adapter->bus_num, adapter->slot_num));
743
744 do {
745 err = wifi_platform_set_power(adapter,
746 TRUE, WIFI_TURNON_DELAY);
747 if (err) {
748 DHD_ERROR(("failed to power up %s,"
749 " %d retry left\n",
750 adapter->name, retry));
751 /* WL_REG_ON state unknown, Power off forcely */
752 wifi_platform_set_power(adapter,
753 FALSE, WIFI_TURNOFF_DELAY);
754 continue;
755 } else {
756 err = wifi_platform_bus_enumerate(adapter, TRUE);
757 if (err) {
758 DHD_ERROR(("failed to enumerate bus %s, "
759 "%d retry left\n",
760 adapter->name, retry));
761 wifi_platform_set_power(adapter, FALSE,
762 WIFI_TURNOFF_DELAY);
763 } else {
764 break;
765 }
766 }
767 } while (retry--);
768
769 if (retry < 0) {
770 DHD_ERROR(("failed to power up %s, max retry reached**\n",
771 adapter->name));
772 return -ENODEV;
773 }
774 }
775 }
776
777 err = dhd_bus_register();
778
779 if (err) {
780 DHD_ERROR(("%s: pcie_register_driver failed\n", __FUNCTION__));
781 if (dhd_download_fw_on_driverload) {
782 /* power down all adapters */
783 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
784 adapter = &dhd_wifi_platdata->adapters[i];
785 wifi_platform_bus_enumerate(adapter, FALSE);
786 wifi_platform_set_power(adapter,
787 FALSE, WIFI_TURNOFF_DELAY);
788 }
789 }
790 }
791 }
792
793 return err;
794}
795#else
796static int dhd_wifi_platform_load_pcie(void)
797{
798 return 0;
799}
800#endif /* BCMPCIE */
801
802void dhd_wifi_platform_unregister_drv(void)
803{
804#ifndef CUSTOMER_HW
805 if (cfg_multichip)
806 platform_driver_unregister(&dhd_wifi_platform_dev_driver);
807 else
808#endif
809 wifi_ctrlfunc_unregister_drv();
810}
811
812extern int dhd_watchdog_prio;
813extern int dhd_dpc_prio;
814extern uint dhd_deferred_tx;
815#if defined(BCMLXSDMMC) || defined(BCMDBUS)
816extern struct semaphore dhd_registration_sem;
817#endif
818
819#ifdef BCMSDIO
820static int dhd_wifi_platform_load_sdio(void)
821{
822 int i;
823 int err = 0;
824 wifi_adapter_info_t *adapter;
825
826 BCM_REFERENCE(i);
827 BCM_REFERENCE(adapter);
828 /* Sanity check on the module parameters
829 * - Both watchdog and DPC as tasklets are ok
830 * - If both watchdog and DPC are threads, TX must be deferred
831 */
832 if (!(dhd_watchdog_prio < 0 && dhd_dpc_prio < 0) &&
833 !(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx))
834 return -EINVAL;
835
836#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD)
837 sema_init(&dhd_registration_sem, 0);
838#endif
839
840 if (dhd_wifi_platdata == NULL) {
841 DHD_ERROR(("DHD wifi platform data is required for Android build\n"));
842 DHD_ERROR(("DHD registering bus directly\n"));
843 /* x86 bring-up PC needs no power-up operations */
844 err = dhd_bus_register();
845 return err;
846 }
847
848#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD)
849 /* power up all adapters */
850 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
851 bool chip_up = FALSE;
852 int retry = POWERUP_MAX_RETRY;
853 struct semaphore dhd_chipup_sem;
854
855 adapter = &dhd_wifi_platdata->adapters[i];
856
857 DHD_ERROR(("Power-up adapter '%s'\n", adapter->name));
858 DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n",
859 adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path));
860 DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n",
861 adapter->bus_type, adapter->bus_num, adapter->slot_num));
862
863 do {
864#ifndef CUSTOMER_HW_AMLOGIC
865 sema_init(&dhd_chipup_sem, 0);
866 err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem);
867 if (err) {
868 DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n",
869 __FUNCTION__, err));
870 return err;
871 }
872#endif
873 err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
874 if (err) {
875 DHD_ERROR(("%s: wifi pwr on error ! \n", __FUNCTION__));
876 dhd_bus_unreg_sdio_notify();
877 /* WL_REG_ON state unknown, Power off forcely */
878 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
879 continue;
880 } else {
881 wifi_platform_bus_enumerate(adapter, TRUE);
882 }
883#ifdef CUSTOMER_HW_AMLOGIC
884 sema_init(&dhd_chipup_sem, 0);
885 err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem);
886 if (err) {
887 DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n",
888 __FUNCTION__, err));
889 return err;
890 }
891#endif
892
893 if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) {
894 dhd_bus_unreg_sdio_notify();
895 chip_up = TRUE;
896 break;
897 }
898
899 DHD_ERROR(("failed to power up %s, %d retry left\n", adapter->name, retry));
900 dhd_bus_unreg_sdio_notify();
901 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
902 wifi_platform_bus_enumerate(adapter, FALSE);
903 } while (retry--);
904
905 if (!chip_up) {
906 DHD_ERROR(("failed to power up %s, max retry reached**\n", adapter->name));
907 return -ENODEV;
908 }
909
910 }
911
912 err = dhd_bus_register();
913
914 if (err) {
915 DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__));
916 goto fail;
917 }
918
919 /*
920 * Wait till MMC sdio_register_driver callback called and made driver attach.
921 * It's needed to make sync up exit from dhd insmod and
922 * Kernel MMC sdio device callback registration
923 */
924 err = down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT));
925 if (err) {
926 DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__));
927 dhd_bus_unregister();
928 goto fail;
929 }
930
931 return err;
932
933fail:
934 /* power down all adapters */
935 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
936 adapter = &dhd_wifi_platdata->adapters[i];
937 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
938 wifi_platform_bus_enumerate(adapter, FALSE);
939 }
940#else
941 /* x86 bring-up PC needs no power-up operations */
942 err = dhd_bus_register();
943#endif // endif
944
945 return err;
946}
947#else /* BCMSDIO */
948static int dhd_wifi_platform_load_sdio(void)
949{
950 return 0;
951}
952#endif /* BCMSDIO */
953
954#ifdef BCMDBUS
955static int dhd_wifi_platform_load_usb(void)
956{
957 int err = 0;
958#if !defined(DHD_PRELOAD)
959 wifi_adapter_info_t *adapter;
960 s32 timeout = -1;
961 int i;
962 enum wifi_adapter_status wait_status;
963#endif
964
965 err = dhd_bus_register();
966 if (err) {
967 DHD_ERROR(("%s: usb_register failed\n", __FUNCTION__));
968 goto exit;
969 }
970
971#if !defined(DHD_PRELOAD)
972 /* power up all adapters */
973 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
974 adapter = &dhd_wifi_platdata->adapters[i];
975 DHD_ERROR(("Power-up adapter '%s'\n", adapter->name));
976 DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n",
977 adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path));
978 DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n",
979 adapter->bus_type, adapter->bus_num, adapter->slot_num));
980 err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
981 if (err) {
982 DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name));
983 goto fail;
984 }
985 if (dhd_download_fw_on_driverload)
986 wait_status = WIFI_STATUS_ATTACH;
987 else
988 wait_status = WIFI_STATUS_DETTACH;
989 timeout = wait_event_interruptible_timeout(adapter->status_event,
990 wifi_get_adapter_status(adapter, wait_status),
991 msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT));
992 if (timeout <= 0) {
993 err = -1;
994 DHD_ERROR(("%s: usb_register_driver timeout\n", __FUNCTION__));
995 goto fail;
996 }
997 }
998#endif
999
1000exit:
1001 return err;
1002
1003#if !defined(DHD_PRELOAD)
1004fail:
1005 dhd_bus_unregister();
1006 /* power down all adapters */
1007 for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
1008 adapter = &dhd_wifi_platdata->adapters[i];
1009 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
1010 }
1011
1012 return err;
1013#endif
1014}
1015#else /* BCMDBUS */
1016static int dhd_wifi_platform_load_usb(void)
1017{
1018 return 0;
1019}
1020#endif /* BCMDBUS */
1021
1022static int dhd_wifi_platform_load()
1023{
1024 int err = 0;
1025 printf("%s: Enter\n", __FUNCTION__);
1026
1027 wl_android_init();
1028
1029 if ((err = dhd_wifi_platform_load_usb()))
1030 goto end;
1031 else if ((err = dhd_wifi_platform_load_sdio()))
1032 goto end;
1033 else
1034 err = dhd_wifi_platform_load_pcie();
1035
1036end:
1037 if (err)
1038 wl_android_exit();
1039#if !defined(MULTIPLE_SUPPLICANT)
1040 else
1041 wl_android_post_init();
1042#endif
1043
1044 return err;
1045}