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