xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/dhd_custom_exynos.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Platform Dependent file for Samsung Exynos
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 #include <linux/device.h>
26 #include <linux/gpio.h>
27 #include <linux/of_gpio.h>
28 #include <linux/delay.h>
29 #include <linux/interrupt.h>
30 #include <linux/irq.h>
31 #include <linux/slab.h>
32 #include <linux/workqueue.h>
33 #include <linux/poll.h>
34 #include <linux/miscdevice.h>
35 #include <linux/sched.h>
36 #include <linux/module.h>
37 #include <linux/fs.h>
38 #include <linux/list.h>
39 #include <linux/io.h>
40 #include <linux/workqueue.h>
41 #include <linux/unistd.h>
42 #include <linux/bug.h>
43 #include <linux/skbuff.h>
44 #include <linux/init.h>
45 #include <linux/platform_device.h>
46 #if defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \
47     defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830) || \
48     defined(CONFIG_SOC_EXYNOS2100) || defined(CONFIG_SOC_EXYNOS1000)
49 #include <linux/exynos-pci-ctrl.h>
50 #endif /* CONFIG_SOC_EXYNOS8895 || CONFIG_SOC_EXYNOS9810 ||
51 	* CONFIG_SOC_EXYNOS9820 || CONFIG_SOC_EXYNOS9830 ||
52 	* CONFIG_SOC_EXYNOS2100 || CONFIG_SOC_EXYNOS1000
53 	*/
54 
55 #if defined(CONFIG_64BIT)
56 #include <asm-generic/gpio.h>
57 #endif /* CONFIG_64BIT */
58 
59 #ifdef BCMDHD_MODULAR
60 #if IS_ENABLED(CONFIG_SEC_SYSFS)
61 #include <linux/sec_sysfs.h>
62 #endif /* CONFIG_SEC_SYSFS */
63 #if IS_ENABLED(CONFIG_DRV_SAMSUNG)
64 #include <linux/sec_class.h>
65 #endif /* CONFIG_SEC_SYSFS */
66 #else
67 #if defined(CONFIG_SEC_SYSFS)
68 #include <linux/sec_sysfs.h>
69 #elif defined(CONFIG_DRV_SAMSUNG)
70 #include <linux/sec_class.h>
71 #endif /* CONFIG_SEC_SYSFS */
72 #endif /* BCMDHD_MODULAR */
73 #include <linux/wlan_plat.h>
74 
75 #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
76 #define PINCTL_DELAY 150
77 #endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */
78 
79 #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
80 extern void dhd_exit_wlan_mem(void);
81 extern int dhd_init_wlan_mem(void);
82 extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
83 #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
84 
85 #define WIFI_TURNON_DELAY	200
86 static int wlan_pwr_on = -1;
87 
88 #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
89 static int wlan_host_wake_irq = 0;
90 static unsigned int wlan_host_wake_up = -1;
91 #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
92 
93 #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
94 extern struct device *mmc_dev_for_wlan;
95 #endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */
96 
97 #ifdef CONFIG_BCMDHD_PCIE
98 extern int pcie_ch_num;
99 extern void exynos_pcie_pm_resume(int);
100 extern void exynos_pcie_pm_suspend(int);
101 #endif /* CONFIG_BCMDHD_PCIE */
102 
103 #if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110)
104 extern struct mmc_host *wlan_mmc;
105 extern void mmc_ctrl_power(struct mmc_host *host, bool onoff);
106 #endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */
107 
108 static int
dhd_wlan_power(int onoff)109 dhd_wlan_power(int onoff)
110 {
111 #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
112 	struct pinctrl *pinctrl = NULL;
113 #endif /* CONFIG_MACH_A7LTE || ONFIG_NOBLESSE */
114 
115 	printk(KERN_INFO"%s Enter: power %s\n", __FUNCTION__, onoff ? "on" : "off");
116 
117 #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
118 	if (onoff) {
119 		pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_on");
120 		if (IS_ERR(pinctrl))
121 			printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__);
122 		msleep(PINCTL_DELAY);
123 	}
124 #endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */
125 
126 	if (gpio_direction_output(wlan_pwr_on, onoff)) {
127 		printk(KERN_ERR "%s failed to control WLAN_REG_ON to %s\n",
128 			__FUNCTION__, onoff ? "HIGH" : "LOW");
129 		return -EIO;
130 	}
131 
132 #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
133 	if (!onoff) {
134 		pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_off");
135 		if (IS_ERR(pinctrl))
136 			printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__);
137 	}
138 #endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */
139 
140 #if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110)
141 	if (wlan_mmc)
142 		mmc_ctrl_power(wlan_mmc, onoff);
143 #endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */
144 	return 0;
145 }
146 
147 static int
dhd_wlan_reset(int onoff)148 dhd_wlan_reset(int onoff)
149 {
150 	return 0;
151 }
152 
153 #ifndef CONFIG_BCMDHD_PCIE
154 extern void (*notify_func_callback)(void *dev_id, int state);
155 extern void *mmc_host_dev;
156 #endif /* !CONFIG_BCMDHD_PCIE */
157 
158 static int
dhd_wlan_set_carddetect(int val)159 dhd_wlan_set_carddetect(int val)
160 {
161 #ifndef CONFIG_BCMDHD_PCIE
162 	pr_err("%s: notify_func=%p, mmc_host_dev=%p, val=%d\n",
163 		__FUNCTION__, notify_func_callback, mmc_host_dev, val);
164 
165 	if (notify_func_callback) {
166 		notify_func_callback(mmc_host_dev, val);
167 	} else {
168 		pr_warning("%s: Nobody to notify\n", __FUNCTION__);
169 	}
170 #else
171 	if (val) {
172 		exynos_pcie_pm_resume(pcie_ch_num);
173 	} else {
174 		exynos_pcie_pm_suspend(pcie_ch_num);
175 	}
176 #endif /* CONFIG_BCMDHD_PCIE */
177 
178 	return 0;
179 }
180 
181 int __init
dhd_wlan_init_gpio(void)182 dhd_wlan_init_gpio(void)
183 {
184 	const char *wlan_node = "samsung,brcm-wlan";
185 	struct device_node *root_node = NULL;
186 	struct device *wlan_dev;
187 
188 	wlan_dev = sec_device_create(NULL, "wlan");
189 
190 	root_node = of_find_compatible_node(NULL, NULL, wlan_node);
191 	if (!root_node) {
192 		WARN(1, "failed to get device node of bcm4354\n");
193 		return -ENODEV;
194 	}
195 
196 	/* ========== WLAN_PWR_EN ============ */
197 	wlan_pwr_on = of_get_gpio(root_node, 0);
198 	if (!gpio_is_valid(wlan_pwr_on)) {
199 		WARN(1, "Invalied gpio pin : %d\n", wlan_pwr_on);
200 		return -ENODEV;
201 	}
202 
203 	if (gpio_request(wlan_pwr_on, "WLAN_REG_ON")) {
204 		WARN(1, "fail to request gpio(WLAN_REG_ON)\n");
205 		return -ENODEV;
206 	}
207 #ifdef CONFIG_BCMDHD_PCIE
208 	gpio_direction_output(wlan_pwr_on, 1);
209 	msleep(WIFI_TURNON_DELAY);
210 #else
211 	gpio_direction_output(wlan_pwr_on, 0);
212 #endif /* CONFIG_BCMDHD_PCIE */
213 	gpio_export(wlan_pwr_on, 1);
214 	if (wlan_dev)
215 		gpio_export_link(wlan_dev, "WLAN_REG_ON", wlan_pwr_on);
216 
217 #ifdef CONFIG_BCMDHD_PCIE
218 	exynos_pcie_pm_resume(pcie_ch_num);
219 #endif /* CONFIG_BCMDHD_PCIE */
220 
221 #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
222 	/* ========== WLAN_HOST_WAKE ============ */
223 	wlan_host_wake_up = of_get_gpio(root_node, 1);
224 	if (!gpio_is_valid(wlan_host_wake_up)) {
225 		WARN(1, "Invalied gpio pin : %d\n", wlan_host_wake_up);
226 		return -ENODEV;
227 	}
228 
229 	if (gpio_request(wlan_host_wake_up, "WLAN_HOST_WAKE")) {
230 		WARN(1, "fail to request gpio(WLAN_HOST_WAKE)\n");
231 		return -ENODEV;
232 	}
233 	gpio_direction_input(wlan_host_wake_up);
234 	gpio_export(wlan_host_wake_up, 1);
235 	if (wlan_dev)
236 		gpio_export_link(wlan_dev, "WLAN_HOST_WAKE", wlan_host_wake_up);
237 
238 	wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up);
239 #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
240 
241 	return 0;
242 }
243 
244 #if defined(CONFIG_BCMDHD_OOB_HOST_WAKE) && defined(CONFIG_BCMDHD_GET_OOB_STATE)
245 int
dhd_get_wlan_oob_gpio(void)246 dhd_get_wlan_oob_gpio(void)
247 {
248 	return gpio_is_valid(wlan_host_wake_up) ?
249 		gpio_get_value(wlan_host_wake_up) : -1;
250 }
251 EXPORT_SYMBOL(dhd_get_wlan_oob_gpio);
252 #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE && CONFIG_BCMDHD_GET_OOB_STATE */
253 
254 struct resource dhd_wlan_resources = {
255 	.name	= "bcmdhd_wlan_irq",
256 	.start	= 0,
257 	.end	= 0,
258 	.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE |
259 #ifdef CONFIG_BCMDHD_PCIE
260 	IORESOURCE_IRQ_HIGHEDGE,
261 #else
262 	IORESOURCE_IRQ_HIGHLEVEL,
263 #endif /* CONFIG_BCMDHD_PCIE */
264 };
265 EXPORT_SYMBOL(dhd_wlan_resources);
266 
267 struct wifi_platform_data dhd_wlan_control = {
268 	.set_power	= dhd_wlan_power,
269 	.set_reset	= dhd_wlan_reset,
270 	.set_carddetect	= dhd_wlan_set_carddetect,
271 #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
272 	.mem_prealloc	= dhd_wlan_mem_prealloc,
273 #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
274 };
275 EXPORT_SYMBOL(dhd_wlan_control);
276 
277 int __init
dhd_wlan_init(void)278 dhd_wlan_init(void)
279 {
280 	int ret;
281 
282 	printk(KERN_INFO "%s: START.......\n", __FUNCTION__);
283 	ret = dhd_wlan_init_gpio();
284 	if (ret < 0) {
285 		printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n",
286 			__FUNCTION__, ret);
287 		goto fail;
288 	}
289 
290 #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
291 	dhd_wlan_resources.start = wlan_host_wake_irq;
292 	dhd_wlan_resources.end = wlan_host_wake_irq;
293 #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
294 
295 #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
296 	ret = dhd_init_wlan_mem();
297 	if (ret < 0) {
298 		printk(KERN_ERR "%s: failed to alloc reserved memory,"
299 			" ret=%d\n", __FUNCTION__, ret);
300 	}
301 #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
302 
303 fail:
304 	return ret;
305 }
306 
307 int
dhd_wlan_deinit(void)308 dhd_wlan_deinit(void)
309 {
310 #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
311 	gpio_free(wlan_host_wake_up);
312 #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
313 	gpio_free(wlan_pwr_on);
314 
315 #ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
316 	dhd_exit_wlan_mem();
317 #endif /*  CONFIG_BROADCOM_WIFI_RESERVED_MEM */
318 	return 0;
319 }
320 
321 #ifndef BCMDHD_MODULAR
322 #if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS8890) || \
323 	defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \
324 	defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830)
325 #if defined(CONFIG_DEFERRED_INITCALLS)
326 deferred_module_init(dhd_wlan_init);
327 #else
328 late_initcall(dhd_wlan_init);
329 #endif /* CONFIG_DEFERRED_INITCALLS */
330 #else
331 device_initcall(dhd_wlan_init);
332 #endif /* CONFIG Exynos PCIE Platforms */
333 #endif /* !BCMDHD_MODULAR */
334