• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Platform Dependent file for Hikey
3  *
4  * Copyright (C) 1999-2019, 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
16  * of the license of that module.  An independent module is a module which is
17  * not derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  * <<Broadcom-WL-IPTag/Open:>>
25  *
26  * $Id$
27  *
28  */
29 
30 #include <linux/kernel.h>
31 #include <linux/init.h>
32 #include <linux/platform_device.h>
33 #include <linux/delay.h>
34 #include <linux/err.h>
35 #include <linux/gpio.h>
36 #include <linux/skbuff.h>
37 #include <linux/wlan_plat.h>
38 #include <linux/fcntl.h>
39 #include <linux/fs.h>
40 #include <linux/of_gpio.h>
41 
42 #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
43 extern int dhd_init_wlan_mem(void);
44 extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
45 #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
46 
47 #define WIFI_TURNON_DELAY 200
48 #define WLAN_REG_ON_GPIO 491
49 #define WLAN_HOST_WAKE_GPIO 493
50 
51 static int wlan_reg_on = -1;
52 #define DHD_DT_COMPAT_ENTRY "android,bcmdhd_wlan"
53 #define WIFI_WL_REG_ON_PROPNAME "wl_reg_on"
54 
55 static int wlan_host_wake_up = -1;
56 static int wlan_host_wake_irq = 0;
57 #define WIFI_WLAN_HOST_WAKE_PROPNAME "wl_host_wake"
58 
dhd_wifi_init_gpio(void)59 int dhd_wifi_init_gpio(void)
60 {
61     int gpio_reg_on_val;
62     /* ========== WLAN_PWR_EN ============ */
63     char *wlan_node = DHD_DT_COMPAT_ENTRY;
64     struct device_node *root_node = NULL;
65 
66     root_node = of_find_compatible_node(NULL, NULL, wlan_node);
67     if (root_node) {
68         wlan_reg_on = of_get_named_gpio(root_node, WIFI_WL_REG_ON_PROPNAME, 0);
69         wlan_host_wake_up =
70             of_get_named_gpio(root_node, WIFI_WLAN_HOST_WAKE_PROPNAME, 0);
71     } else {
72         printk(KERN_ERR
73                "failed to get device node of BRCM WLAN, use default GPIOs\n");
74         wlan_reg_on = WLAN_REG_ON_GPIO;
75         wlan_host_wake_up = WLAN_HOST_WAKE_GPIO;
76     }
77 
78     /* ========== WLAN_PWR_EN ============ */
79     printk(KERN_INFO "%s: gpio_wlan_power : %d\n", __FUNCTION__, wlan_reg_on);
80 
81     /*
82      * For reg_on, gpio_request will fail if the gpio is configured to
83      * output-high in the dts using gpio-hog, so do not return error for
84      * failure.
85      */
86     if (gpio_request_one(wlan_reg_on, GPIOF_OUT_INIT_HIGH, "WL_REG_ON")) {
87         printk(KERN_ERR "%s: Failed to request gpio %d for WL_REG_ON, "
88                         "might have configured in the dts\n",
89                __FUNCTION__, wlan_reg_on);
90     } else {
91         printk(KERN_ERR "%s: gpio_request WL_REG_ON done - WLAN_EN: GPIO %d\n",
92                __FUNCTION__, wlan_reg_on);
93     }
94 
95     gpio_reg_on_val = gpio_get_value(wlan_reg_on);
96     printk(KERN_INFO "%s: Initial WL_REG_ON: [%d]\n", __FUNCTION__,
97            gpio_get_value(wlan_reg_on));
98 
99     if (gpio_reg_on_val == 0) {
100         printk(KERN_INFO "%s: WL_REG_ON is LOW, drive it HIGH\n", __FUNCTION__);
101         if (gpio_direction_output(wlan_reg_on, 1)) {
102             printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n",
103                    __FUNCTION__);
104             return -EIO;
105         }
106     }
107 
108     printk(KERN_ERR "%s: WL_REG_ON is pulled up\n", __FUNCTION__);
109 
110     /* Wait for WIFI_TURNON_DELAY due to power stability */
111     msleep(WIFI_TURNON_DELAY);
112 
113     /* ========== WLAN_HOST_WAKE ============ */
114     printk(KERN_INFO "%s: gpio_wlan_host_wake : %d\n", __FUNCTION__,
115            wlan_host_wake_up);
116 
117     if (gpio_request_one(wlan_host_wake_up, GPIOF_IN, "WLAN_HOST_WAKE")) {
118         printk(KERN_ERR "%s: Failed to request gpio %d for WLAN_HOST_WAKE\n",
119                __FUNCTION__, wlan_host_wake_up);
120         return -ENODEV;
121     } else {
122         printk(KERN_ERR "%s: gpio_request WLAN_HOST_WAKE done"
123                         " - WLAN_HOST_WAKE: GPIO %d\n",
124                __FUNCTION__, wlan_host_wake_up);
125     }
126 
127     if (gpio_direction_input(wlan_host_wake_up)) {
128         printk(KERN_ERR "%s: Failed to set WL_HOST_WAKE gpio direction\n",
129                __FUNCTION__);
130     }
131 
132     wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up);
133 
134     return 0;
135 }
136 
137 extern void kirin_pcie_power_on_atu_fixup(void) __attribute__((weak));
138 extern int kirin_pcie_lp_ctrl(u32 enable) __attribute__((weak));
139 
140 #ifndef BOARD_HIKEY_MODULAR
dhd_wlan_power(int onoff)141 int dhd_wlan_power(int onoff)
142 {
143     printk(KERN_INFO "------------------------------------------------");
144     printk(KERN_INFO "------------------------------------------------\n");
145     printk(KERN_INFO "%s Enter: power %s\n", __func__, onoff ? "on" : "off");
146 
147     if (onoff) {
148         if (gpio_direction_output(wlan_reg_on, 1)) {
149             printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n",
150                    __FUNCTION__);
151             return -EIO;
152         }
153         if (gpio_get_value(wlan_reg_on)) {
154             printk(KERN_INFO "WL_REG_ON on-step-2 : [%d]\n",
155                    gpio_get_value(wlan_reg_on));
156         } else {
157             printk("[%s] gpio value is 0. We need reinit.\n", __func__);
158             if (gpio_direction_output(wlan_reg_on, 1)) {
159                 printk(KERN_ERR "%s: WL_REG_ON is "
160                                 "failed to pull up\n",
161                        __func__);
162             }
163         }
164 
165         /* Wait for WIFI_TURNON_DELAY due to power stability */
166         msleep(WIFI_TURNON_DELAY);
167 
168         /*
169          * Call Kiric RC ATU fixup else si_attach will fail due to
170          * improper BAR0/1 address translations
171          */
172         if (kirin_pcie_power_on_atu_fixup) {
173             kirin_pcie_power_on_atu_fixup();
174         } else {
175             printk(KERN_ERR "[%s] kirin_pcie_power_on_atu_fixup is NULL. "
176                             "REG_ON may not work\n",
177                    __func__);
178         }
179         /* Enable ASPM after powering ON */
180         if (kirin_pcie_lp_ctrl) {
181             kirin_pcie_lp_ctrl(onoff);
182         } else {
183             printk(KERN_ERR "[%s] kirin_pcie_lp_ctrl is NULL. "
184                             "ASPM may not work\n",
185                    __func__);
186         }
187     } else {
188         /* Disable ASPM before powering off */
189         if (kirin_pcie_lp_ctrl) {
190             kirin_pcie_lp_ctrl(onoff);
191         } else {
192             printk(KERN_ERR "[%s] kirin_pcie_lp_ctrl is NULL. "
193                             "ASPM may not work\n",
194                    __func__);
195         }
196         if (gpio_direction_output(wlan_reg_on, 0)) {
197             printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n",
198                    __FUNCTION__);
199             return -EIO;
200         }
201         if (gpio_get_value(wlan_reg_on)) {
202             printk(KERN_INFO "WL_REG_ON on-step-2 : [%d]\n",
203                    gpio_get_value(wlan_reg_on));
204         }
205     }
206     return 0;
207 }
208 EXPORT_SYMBOL(dhd_wlan_power);
209 #endif /* BOARD_HIKEY_MODULAR */
210 
dhd_wlan_reset(int onoff)211 static int dhd_wlan_reset(int onoff)
212 {
213     return 0;
214 }
215 
dhd_wlan_set_carddetect(int val)216 static int dhd_wlan_set_carddetect(int val)
217 {
218     return 0;
219 }
220 
221 #ifdef BCMSDIO
dhd_wlan_get_wake_irq(void)222 static int dhd_wlan_get_wake_irq(void)
223 {
224     return gpio_to_irq(wlan_host_wake_up);
225 }
226 #endif /* BCMSDIO */
227 
228 #if defined(CONFIG_BCMDHD_OOB_HOST_WAKE) && defined(CONFIG_BCMDHD_GET_OOB_STATE)
dhd_get_wlan_oob_gpio(void)229 int dhd_get_wlan_oob_gpio(void)
230 {
231     return gpio_is_valid(wlan_host_wake_up) ? gpio_get_value(wlan_host_wake_up)
232                                             : -1;
233 }
234 EXPORT_SYMBOL(dhd_get_wlan_oob_gpio);
235 #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE && CONFIG_BCMDHD_GET_OOB_STATE */
236 
237 struct resource dhd_wlan_resources = {
238     .name = "bcmdhd_wlan_irq",
239     .start = 0, /* Dummy */
240     .end = 0,   /* Dummy */
241     .flags =
242         IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE | IORESOURCE_IRQ_HIGHEDGE,
243 };
244 EXPORT_SYMBOL(dhd_wlan_resources);
245 
246 struct wifi_platform_data dhd_wlan_control = {
247 #ifndef BOARD_HIKEY_MODULAR
248     .set_power = dhd_wlan_power,
249 #endif /* BOARD_HIKEY_MODULAR */
250     .set_reset = dhd_wlan_reset,
251     .set_carddetect = dhd_wlan_set_carddetect,
252 #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
253     .mem_prealloc = dhd_wlan_mem_prealloc,
254 #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
255 #ifdef BCMSDIO
256     .get_wake_irq = dhd_wlan_get_wake_irq,
257 #endif // endif
258 };
259 EXPORT_SYMBOL(dhd_wlan_control);
260 
dhd_wlan_init(void)261 int dhd_wlan_init(void)
262 {
263     int ret;
264 
265     printk(KERN_INFO "%s: START.......\n", __FUNCTION__);
266     ret = dhd_wifi_init_gpio();
267     if (ret < 0) {
268         printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n", __FUNCTION__,
269                ret);
270         goto fail;
271     }
272 
273     dhd_wlan_resources.start = wlan_host_wake_irq;
274     dhd_wlan_resources.end = wlan_host_wake_irq;
275 
276 #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
277     ret = dhd_init_wlan_mem();
278     if (ret < 0) {
279         printk(KERN_ERR "%s: failed to alloc reserved memory,"
280                         " ret=%d\n",
281                __FUNCTION__, ret);
282     }
283 #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
284 
285 fail:
286     printk(KERN_INFO "%s: FINISH.......\n", __FUNCTION__);
287     return ret;
288 }
289 
dhd_wlan_deinit(void)290 int dhd_wlan_deinit(void)
291 {
292     gpio_free(wlan_host_wake_up);
293     gpio_free(wlan_reg_on);
294     return 0;
295 }
296 #ifndef BOARD_HIKEY_MODULAR
297 /* Required only for Built-in DHD */
298 device_initcall(dhd_wlan_init);
299 #endif /* BOARD_HIKEY_MODULAR */
300