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