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