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