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