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