Commit | Line | Data |
---|---|---|
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 | |
69 | extern int dhd_init_wlan_mem(void); | |
70 | extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); | |
71 | #endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ | |
72 | ||
73 | #define WIFI_TURNON_DELAY 200 | |
74 | static int wlan_pwr_on = -1; | |
75 | ||
76 | #ifdef CONFIG_BCMDHD_OOB_HOST_WAKE | |
77 | static int wlan_host_wake_irq = 0; | |
78 | EXPORT_SYMBOL(wlan_host_wake_irq); | |
79 | static unsigned int wlan_host_wake_up = -1; | |
80 | #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ | |
81 | ||
82 | #if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE) | |
83 | extern 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 */ | |
92 | extern void exynos_pcie_pm_resume(int); | |
93 | extern void exynos_pcie_pm_suspend(int); | |
94 | #endif /* CONFIG_BCMDHD_PCIE */ | |
95 | ||
96 | #if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110) | |
97 | extern struct mmc_host *wlan_mmc; | |
98 | extern void mmc_ctrl_power(struct mmc_host *host, bool onoff); | |
99 | #endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */ | |
100 | ||
101 | static int | |
102 | dhd_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 | ||
140 | static int | |
141 | dhd_wlan_reset(int onoff) | |
142 | { | |
143 | return 0; | |
144 | } | |
145 | ||
146 | #ifndef CONFIG_BCMDHD_PCIE | |
147 | extern void (*notify_func_callback)(void *dev_id, int state); | |
148 | extern void *mmc_host_dev; | |
149 | #endif /* !CONFIG_BCMDHD_PCIE */ | |
150 | ||
151 | static int | |
152 | dhd_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 | ||
174 | int __init | |
175 | dhd_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) | |
238 | int | |
239 | dhd_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 | } | |
244 | EXPORT_SYMBOL(dhd_get_wlan_oob_gpio); | |
245 | #endif /* CONFIG_BCMDHD_OOB_HOST_WAKE && CONFIG_BCMDHD_GET_OOB_STATE */ | |
246 | ||
247 | struct 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 | }; | |
258 | EXPORT_SYMBOL(dhd_wlan_resources); | |
259 | ||
260 | struct 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 | }; | |
268 | EXPORT_SYMBOL(dhd_wlan_control); | |
269 | ||
270 | int __init | |
271 | dhd_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 | ||
296 | fail: | |
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) | |
304 | deferred_module_init(dhd_wlan_init); | |
305 | #else | |
306 | late_initcall(dhd_wlan_init); | |
307 | #endif /* CONFIG_DEFERRED_INITCALLS */ | |
308 | #else | |
309 | device_initcall(dhd_wlan_init); | |
310 | #endif /* CONFIG Exynos PCIE Platforms */ |