dhd: import wifi and bluetooth firmware
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.101.10.240.x / dhd_gpio.c
1
2 #include <osl.h>
3 #include <dhd_linux.h>
4 #include <linux/gpio.h>
5
6 #if defined(BUS_POWER_RESTORE) && defined(BCMSDIO)
7 #include <linux/mmc/core.h>
8 #include <linux/mmc/card.h>
9 #include <linux/mmc/host.h>
10 #include <linux/mmc/sdio_func.h>
11 #endif /* defined(BUS_POWER_RESTORE) && defined(BCMSDIO) */
12
13 #ifdef CONFIG_DHD_USE_STATIC_BUF
14 extern void *bcmdhd_mem_prealloc(int section, unsigned long size);
15 #endif /* CONFIG_DHD_USE_STATIC_BUF */
16
17 static int gpio_wl_reg_on = -1; // WL_REG_ON is input pin of WLAN module
18 #ifdef CUSTOMER_OOB
19 static int gpio_wl_host_wake = -1; // WL_HOST_WAKE is output pin of WLAN module
20 #endif
21
22 #ifdef CUSTOMER_HW_AMLOGIC
23 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
24 #include <linux/amlogic/aml_gpio_consumer.h>
25 extern int wifi_irq_trigger_level(void);
26 extern u8 *wifi_get_mac(void);
27 extern u8 *wifi_get_ap_mac(void);
28 #endif
29 extern void sdio_reinit(void);
30 extern void set_usb_bt_power(int is_power);
31 extern void extern_wifi_set_enable(int is_on);
32 extern void pci_remove_reinit(unsigned int vid, unsigned int pid, int delBus);
33 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
34 extern int wifi_irq_num(void);
35 #endif
36 #endif
37
38 static int
39 dhd_wlan_set_power(int on
40 #ifdef BUS_POWER_RESTORE
41 , wifi_adapter_info_t *adapter
42 #endif /* BUS_POWER_RESTORE */
43 )
44 {
45 int err = 0;
46
47 if (on) {
48 printf("======== PULL WL_REG_ON(%d) HIGH! ========\n", gpio_wl_reg_on);
49 if (gpio_wl_reg_on >= 0) {
50 err = gpio_direction_output(gpio_wl_reg_on, 1);
51 if (err) {
52 printf("%s: WL_REG_ON didn't output high\n", __FUNCTION__);
53 return -EIO;
54 }
55 }
56 #ifdef CUSTOMER_HW_AMLOGIC
57 #ifdef BCMSDIO
58 extern_wifi_set_enable(0);
59 mdelay(200);
60 extern_wifi_set_enable(1);
61 mdelay(200);
62 // sdio_reinit();
63 #endif
64 #ifdef BCMDBUS
65 set_usb_bt_power(0);
66 mdelay(200);
67 set_usb_bt_power(1);
68 mdelay(200);
69 #endif
70 #endif
71 #if defined(BUS_POWER_RESTORE)
72 #if defined(BCMSDIO) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
73 if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) {
74 mdelay(100);
75 printf("======== mmc_power_restore_host! ========\n");
76 mmc_power_restore_host(adapter->sdio_func->card->host);
77 }
78 #elif defined(BCMPCIE)
79 if (adapter->pci_dev) {
80 mdelay(100);
81 printf("======== pci_set_power_state PCI_D0! ========\n");
82 pci_set_power_state(adapter->pci_dev, PCI_D0);
83 if (adapter->pci_saved_state)
84 pci_load_and_free_saved_state(adapter->pci_dev, &adapter->pci_saved_state);
85 pci_restore_state(adapter->pci_dev);
86 err = pci_enable_device(adapter->pci_dev);
87 if (err < 0)
88 printf("%s: PCI enable device failed", __FUNCTION__);
89 pci_set_master(adapter->pci_dev);
90 }
91 #endif /* BCMPCIE */
92 #endif /* BUS_POWER_RESTORE */
93 /* Lets customer power to get stable */
94 mdelay(100);
95 } else {
96 #if defined(BUS_POWER_RESTORE)
97 #if defined(BCMSDIO) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
98 if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) {
99 printf("======== mmc_power_save_host! ========\n");
100 mmc_power_save_host(adapter->sdio_func->card->host);
101 }
102 #elif defined(BCMPCIE)
103 if (adapter->pci_dev) {
104 printf("======== pci_set_power_state PCI_D3hot! ========\n");
105 pci_save_state(adapter->pci_dev);
106 adapter->pci_saved_state = pci_store_saved_state(adapter->pci_dev);
107 if (pci_is_enabled(adapter->pci_dev))
108 pci_disable_device(adapter->pci_dev);
109 pci_set_power_state(adapter->pci_dev, PCI_D3hot);
110 }
111 #endif /* BCMPCIE */
112 #endif /* BUS_POWER_RESTORE */
113 printf("======== PULL WL_REG_ON(%d) LOW! ========\n", gpio_wl_reg_on);
114 if (gpio_wl_reg_on >= 0) {
115 err = gpio_direction_output(gpio_wl_reg_on, 0);
116 if (err) {
117 printf("%s: WL_REG_ON didn't output low\n", __FUNCTION__);
118 return -EIO;
119 }
120 }
121 #ifdef CUSTOMER_HW_AMLOGIC
122 #ifdef BCMSIDO
123 extern_wifi_set_enable(0);
124 mdelay(200);
125 #endif
126 #ifdef BCMDBUS
127 set_usb_bt_power(0);
128 mdelay(200);
129 #endif
130 #endif
131 }
132
133 return err;
134 }
135
136 static int dhd_wlan_set_reset(int onoff)
137 {
138 return 0;
139 }
140
141 static int dhd_wlan_set_carddetect(int present)
142 {
143 int err = 0;
144
145 #if !defined(BUS_POWER_RESTORE)
146 if (present) {
147 #if defined(BCMSDIO)
148 printf("======== Card detection to detect SDIO card! ========\n");
149 #ifdef CUSTOMER_HW_PLATFORM
150 err = sdhci_force_presence_change(&sdmmc_channel, 1);
151 #endif /* CUSTOMER_HW_PLATFORM */
152 #ifdef CUSTOMER_HW_AMLOGIC
153 sdio_reinit();
154 #endif
155 #elif defined(BCMPCIE)
156 printf("======== Card detection to detect PCIE card! ========\n");
157 #endif
158 } else {
159 #if defined(BCMSDIO)
160 printf("======== Card detection to remove SDIO card! ========\n");
161 #ifdef CUSTOMER_HW_PLATFORM
162 err = sdhci_force_presence_change(&sdmmc_channel, 0);
163 #endif /* CUSTOMER_HW_PLATFORM */
164 #ifdef CUSTOMER_HW_AMLOGIC
165 extern_wifi_set_enable(0);
166 mdelay(200);
167 #endif
168 #elif defined(BCMPCIE)
169 printf("======== Card detection to remove PCIE card! ========\n");
170 #ifdef CUSTOMER_HW_AMLOGIC
171 extern_wifi_set_enable(0);
172 mdelay(200);
173 #endif
174 #endif
175 }
176 #endif /* BUS_POWER_RESTORE */
177
178 return err;
179 }
180
181 static int dhd_wlan_get_mac_addr(unsigned char *buf
182 #ifdef CUSTOM_MULTI_MAC
183 , char *name
184 #endif
185 )
186 {
187 int err = 0;
188
189 #ifdef CUSTOM_MULTI_MAC
190 if (!strcmp("wlan1", name)) {
191 #ifdef CUSTOMER_HW_AMLOGIC
192 #ifdef CUSTOM_AP_MAC
193 bcopy((char *)wifi_get_ap_mac(), buf, sizeof(struct ether_addr));
194 if (buf[0] == 0xff) {
195 printf("custom wifi ap mac is not set\n");
196 err = -1;
197 } else
198 printf("custom wifi ap mac-addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
199 buf[0], buf[1], buf[2],
200 buf[3], buf[4], buf[5]);
201 #else
202 err = -1;
203 #endif
204 #endif
205 } else
206 #endif /* CUSTOM_MULTI_MAC */
207 {
208 #ifdef CUSTOMER_HW_AMLOGIC
209 bcopy((char *)wifi_get_mac(), buf, sizeof(struct ether_addr));
210 if (buf[0] == 0xff) {
211 printf("custom wifi mac is not set\n");
212 err = -1;
213 } else
214 printf("custom wifi mac-addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
215 buf[0], buf[1], buf[2],
216 buf[3], buf[4], buf[5]);
217 #endif
218 }
219
220 #ifdef EXAMPLE_GET_MAC_VER2
221 /* EXAMPLE code */
222 {
223 char macpad[56]= {
224 0x00,0xaa,0x9c,0x84,0xc7,0xbc,0x9b,0xf6,
225 0x02,0x33,0xa9,0x4d,0x5c,0xb4,0x0a,0x5d,
226 0xa8,0xef,0xb0,0xcf,0x8e,0xbf,0x24,0x8a,
227 0x87,0x0f,0x6f,0x0d,0xeb,0x83,0x6a,0x70,
228 0x4a,0xeb,0xf6,0xe6,0x3c,0xe7,0x5f,0xfc,
229 0x0e,0xa7,0xb3,0x0f,0x00,0xe4,0x4a,0xaf,
230 0x87,0x08,0x16,0x6d,0x3a,0xe3,0xc7,0x80};
231 bcopy(macpad, buf+6, sizeof(macpad));
232 }
233 #endif /* EXAMPLE_GET_MAC_VER2 */
234
235 printf("======== %s err=%d ========\n", __FUNCTION__, err);
236
237 return err;
238 }
239
240 static struct cntry_locales_custom brcm_wlan_translate_custom_table[] = {
241 /* Table should be filled out based on custom platform regulatory requirement */
242 #ifdef EXAMPLE_TABLE
243 {"", "XT", 49}, /* Universal if Country code is unknown or empty */
244 {"US", "US", 0},
245 #endif /* EXMAPLE_TABLE */
246 };
247
248 #ifdef CUSTOM_FORCE_NODFS_FLAG
249 struct cntry_locales_custom brcm_wlan_translate_nodfs_table[] = {
250 #ifdef EXAMPLE_TABLE
251 {"", "XT", 50}, /* Universal if Country code is unknown or empty */
252 {"US", "US", 0},
253 #endif /* EXMAPLE_TABLE */
254 };
255 #endif
256
257 static void *dhd_wlan_get_country_code(char *ccode
258 #ifdef CUSTOM_FORCE_NODFS_FLAG
259 , u32 flags
260 #endif
261 )
262 {
263 struct cntry_locales_custom *locales;
264 int size;
265 int i;
266
267 if (!ccode)
268 return NULL;
269
270 #ifdef CUSTOM_FORCE_NODFS_FLAG
271 if (flags & WLAN_PLAT_NODFS_FLAG) {
272 locales = brcm_wlan_translate_nodfs_table;
273 size = ARRAY_SIZE(brcm_wlan_translate_nodfs_table);
274 } else {
275 #endif
276 locales = brcm_wlan_translate_custom_table;
277 size = ARRAY_SIZE(brcm_wlan_translate_custom_table);
278 #ifdef CUSTOM_FORCE_NODFS_FLAG
279 }
280 #endif
281
282 for (i = 0; i < size; i++)
283 if (strcmp(ccode, locales[i].iso_abbrev) == 0)
284 return &locales[i];
285 return NULL;
286 }
287
288 struct resource dhd_wlan_resources[] = {
289 [0] = {
290 .name = "bcmdhd_wlan_irq",
291 .start = 0, /* Dummy */
292 .end = 0, /* Dummy */
293 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE
294 | IORESOURCE_IRQ_HIGHLEVEL, /* Dummy */
295 },
296 };
297
298 struct wifi_platform_data dhd_wlan_control = {
299 .set_power = dhd_wlan_set_power,
300 .set_reset = dhd_wlan_set_reset,
301 .set_carddetect = dhd_wlan_set_carddetect,
302 .get_mac_addr = dhd_wlan_get_mac_addr,
303 #ifdef CONFIG_DHD_USE_STATIC_BUF
304 .mem_prealloc = bcmdhd_mem_prealloc,
305 #endif /* CONFIG_DHD_USE_STATIC_BUF */
306 .get_country_code = dhd_wlan_get_country_code,
307 };
308
309 int dhd_wlan_init_gpio(void)
310 {
311 int err = 0;
312 #ifdef CUSTOMER_OOB
313 int host_oob_irq = -1;
314 uint host_oob_irq_flags = 0;
315 #endif
316
317 /* Please check your schematic and fill right GPIO number which connected to
318 * WL_REG_ON and WL_HOST_WAKE.
319 */
320 gpio_wl_reg_on = -1;
321 #ifdef CUSTOMER_OOB
322 gpio_wl_host_wake = -1;
323 #endif
324
325 #ifdef CUSTOMER_HW_AMLOGIC
326 #if defined(BCMPCIE)
327 printf("======== Card detection to detect PCIE card! ========\n");
328 //pci_remove_reinit(0x14e4, 0x449d, 1);
329 #endif
330 #endif
331
332 if (gpio_wl_reg_on >= 0) {
333 err = gpio_request(gpio_wl_reg_on, "WL_REG_ON");
334 if (err < 0) {
335 printf("%s: gpio_request(%d) for WL_REG_ON failed\n",
336 __FUNCTION__, gpio_wl_reg_on);
337 gpio_wl_reg_on = -1;
338 }
339 }
340
341 #ifdef CUSTOMER_OOB
342 if (gpio_wl_host_wake >= 0) {
343 err = gpio_request(gpio_wl_host_wake, "bcmdhd");
344 if (err < 0) {
345 printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n",
346 __FUNCTION__, gpio_wl_host_wake);
347 return -1;
348 }
349 err = gpio_direction_input(gpio_wl_host_wake);
350 if (err < 0) {
351 printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n",
352 __FUNCTION__, gpio_wl_host_wake);
353 gpio_free(gpio_wl_host_wake);
354 return -1;
355 }
356 host_oob_irq = gpio_to_irq(gpio_wl_host_wake);
357 if (host_oob_irq < 0) {
358 printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n",
359 __FUNCTION__, gpio_wl_host_wake);
360 gpio_free(gpio_wl_host_wake);
361 return -1;
362 }
363 }
364 #ifdef CUSTOMER_HW_AMLOGIC
365 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
366 host_oob_irq = INT_GPIO_4;
367 #else
368 host_oob_irq = wifi_irq_num();
369 #endif
370 #endif
371
372 #ifdef HW_OOB
373 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
374 if (wifi_irq_trigger_level() == GPIO_IRQ_LOW)
375 host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE;
376 else
377 host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
378 #else
379 #ifdef HW_OOB_LOW_LEVEL
380 host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE;
381 #else
382 host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
383 #endif
384 #endif
385 #else
386 host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_SHAREABLE;
387 #endif
388
389 dhd_wlan_resources[0].start = dhd_wlan_resources[0].end = host_oob_irq;
390 dhd_wlan_resources[0].flags = host_oob_irq_flags;
391 printf("%s: WL_HOST_WAKE=%d, oob_irq=%d, oob_irq_flags=0x%x\n", __FUNCTION__,
392 gpio_wl_host_wake, host_oob_irq, host_oob_irq_flags);
393 #endif /* CUSTOMER_OOB */
394 printf("%s: WL_REG_ON=%d\n", __FUNCTION__, gpio_wl_reg_on);
395
396 return 0;
397 }
398
399 static void dhd_wlan_deinit_gpio(void)
400 {
401 if (gpio_wl_reg_on >= 0) {
402 printf("%s: gpio_free(WL_REG_ON %d)\n", __FUNCTION__, gpio_wl_reg_on);
403 gpio_free(gpio_wl_reg_on);
404 gpio_wl_reg_on = -1;
405 }
406 #ifdef CUSTOMER_OOB
407 if (gpio_wl_host_wake >= 0) {
408 printf("%s: gpio_free(WL_HOST_WAKE %d)\n", __FUNCTION__, gpio_wl_host_wake);
409 gpio_free(gpio_wl_host_wake);
410 gpio_wl_host_wake = -1;
411 }
412 #endif /* CUSTOMER_OOB */
413 }
414
415 int dhd_wlan_init_plat_data(void)
416 {
417 int err = 0;
418
419 printf("======== %s ========\n", __FUNCTION__);
420 err = dhd_wlan_init_gpio();
421 return err;
422 }
423
424 void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter)
425 {
426 printf("======== %s ========\n", __FUNCTION__);
427 dhd_wlan_deinit_gpio();
428 }
429