]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/kernel/wandboard/imx/0004-ARM-i.MX6-Wandboard-add-wifi-bt-rfkill-driver.patch
snort: Update urls for rules download (2.9.7.0) in 'ids.cgi'
[ipfire-2.x.git] / src / patches / kernel / wandboard / imx / 0004-ARM-i.MX6-Wandboard-add-wifi-bt-rfkill-driver.patch
CommitLineData
0c41633e
SS
1From adf0f7b7d7c0083dd936fe46423b89e974f8df12 Mon Sep 17 00:00:00 2001
2From: Vladimir Ermakov <vooon341@gmail.com>
3Date: Wed, 10 Jul 2013 03:06:54 +0400
4Subject: [PATCH] ARM i.MX6 Wandboard add wifi+bt rfkill driver
5
6BRCM WiFi module requires initialization for control gpio;
7Additional provides rfkill funcs.
8
9v2: fix wrong probe func in driver struct
10v3: add imx6qdl compatible
11
12Signed-off-by: Vladimir Ermakov <vooon341@gmail.com>
13---
14 arch/arm/mach-imx/devices/Kconfig | 6 +
15 arch/arm/mach-imx/devices/Makefile | 1 +
16 arch/arm/mach-imx/devices/wand-rfkill.c | 290 ++++++++++++++++++++++++++++++++
17 3 files changed, 297 insertions(+)
18 create mode 100644 arch/arm/mach-imx/devices/wand-rfkill.c
19
20diff --git a/arch/arm/mach-imx/devices/Kconfig b/arch/arm/mach-imx/devices/Kconfig
21index 68c74fb..a0adf75 100644
22--- a/arch/arm/mach-imx/devices/Kconfig
23+++ b/arch/arm/mach-imx/devices/Kconfig
24@@ -85,3 +85,9 @@ config IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
25
26 config IMX_HAVE_PLATFORM_SPI_IMX
27 bool
28+
29+config WAND_RFKILL
30+ tristate "Wandboard RF Kill support"
31+ depends on SOC_IMX6Q
32+ default m
33+ select RFKILL
34diff --git a/arch/arm/mach-imx/devices/Makefile b/arch/arm/mach-imx/devices/Makefile
35index 67416fb..b2aded5 100644
36--- a/arch/arm/mach-imx/devices/Makefile
37+++ b/arch/arm/mach-imx/devices/Makefile
38@@ -30,3 +30,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o
39 obj-$(CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX) += platform-sdhci-esdhc-imx.o
40 obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) += platform-spi_imx.o
41 obj-$(CONFIG_IMX_HAVE_PLATFORM_MX2_EMMA) += platform-mx2-emma.o
42+obj-$(CONFIG_WAND_RFKILL) += wand-rfkill.o
43diff --git a/arch/arm/mach-imx/devices/wand-rfkill.c b/arch/arm/mach-imx/devices/wand-rfkill.c
44new file mode 100644
45index 0000000..da7ef9f
46--- /dev/null
47+++ b/arch/arm/mach-imx/devices/wand-rfkill.c
48@@ -0,0 +1,290 @@
49+/*
50+ * arch/arm/mach-imx/devices/wand-rfkill.c
51+ *
52+ * Copyright (C) 2013 Vladimir Ermakov <vooon341@gmail.com>
53+ *
54+ * based on net/rfkill/rfkill-gpio.c
55+ *
56+ * This software is licensed under the terms of the GNU General Public
57+ * License version 2, as published by the Free Software Foundation, and
58+ * may be copied, distributed, and modified under those terms.
59+ *
60+ * This program is distributed in the hope that it will be useful,
61+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
62+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63+ * GNU General Public License for more details.
64+ *
65+ */
66+
67+#include <linux/of.h>
68+#include <linux/of_gpio.h>
69+#include <linux/of_device.h>
70+#include <linux/pinctrl/consumer.h>
71+#include <linux/platform_device.h>
72+#include <linux/rfkill.h>
73+#include <linux/delay.h>
74+#include <linux/kernel.h>
75+#include <linux/module.h>
76+#include <linux/slab.h>
77+
78+
79+struct wand_rfkill_data {
80+ struct rfkill *rfkill_dev;
81+ int shutdown_gpio;
82+ const char *shutdown_name;
83+};
84+
85+static int wand_rfkill_set_block(void *data, bool blocked)
86+{
87+ struct wand_rfkill_data *rfkill = data;
88+
89+ pr_debug("wandboard-rfkill: set block %d\n", blocked);
90+
91+ if (blocked) {
92+ if (gpio_is_valid(rfkill->shutdown_gpio))
93+ gpio_direction_output(rfkill->shutdown_gpio, 0);
94+ } else {
95+ if (gpio_is_valid(rfkill->shutdown_gpio))
96+ gpio_direction_output(rfkill->shutdown_gpio, 1);
97+ }
98+
99+ return 0;
100+}
101+
102+static const struct rfkill_ops wand_rfkill_ops = {
103+ .set_block = wand_rfkill_set_block,
104+};
105+
106+static int wand_rfkill_wifi_probe(struct device *dev,
107+ struct device_node *np,
108+ struct wand_rfkill_data *rfkill)
109+{
110+ int ret;
111+ int wl_ref_on, wl_rst_n, wl_reg_on, wl_wake, wl_host_wake;
112+
113+ wl_ref_on = of_get_named_gpio(np, "wifi-ref-on", 0);
114+ wl_rst_n = of_get_named_gpio(np, "wifi-rst-n", 0);
115+ wl_reg_on = of_get_named_gpio(np, "wifi-reg-on", 0);
116+ wl_wake = of_get_named_gpio(np, "wifi-wake", 0);
117+ wl_host_wake = of_get_named_gpio(np, "wifi-host-wake", 0);
118+
119+ if (!gpio_is_valid(wl_rst_n) || !gpio_is_valid(wl_ref_on) ||
120+ !gpio_is_valid(wl_reg_on) || !gpio_is_valid(wl_wake) ||
121+ !gpio_is_valid(wl_host_wake)) {
122+
123+ dev_err(dev, "incorrect wifi gpios (%d %d %d %d %d)\n",
124+ wl_rst_n, wl_ref_on, wl_reg_on, wl_wake, wl_host_wake);
125+ return -EINVAL;
126+ }
127+
128+ dev_info(dev, "initialize wifi chip\n");
129+
130+ gpio_request(wl_rst_n, "wl_rst_n");
131+ gpio_direction_output(wl_rst_n, 0);
132+ msleep(11);
133+ gpio_set_value(wl_rst_n, 1);
134+
135+ gpio_request(wl_ref_on, "wl_ref_on");
136+ gpio_direction_output(wl_ref_on, 1);
137+
138+ gpio_request(wl_reg_on, "wl_reg_on");
139+ gpio_direction_output(wl_reg_on, 1);
140+
141+ gpio_request(wl_wake, "wl_wake");
142+ gpio_direction_output(wl_wake, 1);
143+
144+ gpio_request(wl_host_wake, "wl_host_wake");
145+ gpio_direction_input(wl_host_wake);
146+
147+ rfkill->shutdown_name = "wifi_shutdown";
148+ rfkill->shutdown_gpio = wl_wake;
149+
150+ rfkill->rfkill_dev = rfkill_alloc("wifi-rfkill", dev, RFKILL_TYPE_WLAN,
151+ &wand_rfkill_ops, rfkill);
152+ if (!rfkill->rfkill_dev) {
153+ ret = -ENOMEM;
154+ goto wifi_fail_free_gpio;
155+ }
156+
157+ ret = rfkill_register(rfkill->rfkill_dev);
158+ if (ret < 0)
159+ goto wifi_fail_unregister;
160+
161+ dev_info(dev, "wifi-rfkill registered.\n");
162+
163+ return 0;
164+
165+wifi_fail_unregister:
166+ rfkill_destroy(rfkill->rfkill_dev);
167+wifi_fail_free_gpio:
168+ if (gpio_is_valid(wl_rst_n)) gpio_free(wl_rst_n);
169+ if (gpio_is_valid(wl_ref_on)) gpio_free(wl_ref_on);
170+ if (gpio_is_valid(wl_reg_on)) gpio_free(wl_reg_on);
171+ if (gpio_is_valid(wl_wake)) gpio_free(wl_wake);
172+ if (gpio_is_valid(wl_host_wake)) gpio_free(wl_host_wake);
173+
174+ return ret;
175+}
176+
177+static int wand_rfkill_bt_probe(struct device *dev,
178+ struct device_node *np,
179+ struct wand_rfkill_data *rfkill)
180+{
181+ int ret;
182+ int bt_on, bt_wake, bt_host_wake;
183+
184+ bt_on = of_get_named_gpio(np, "bluetooth-on", 0);
185+ bt_wake = of_get_named_gpio(np, "bluetooth-wake", 0);
186+ bt_host_wake = of_get_named_gpio(np, "bluetooth-host-wake", 0);
187+
188+ if (!gpio_is_valid(bt_on) || !gpio_is_valid(bt_wake) ||
189+ !gpio_is_valid(bt_host_wake)) {
190+
191+ dev_err(dev, "incorrect bt gpios (%d %d %d)\n",
192+ bt_on, bt_wake, bt_host_wake);
193+ return -EINVAL;
194+ }
195+
196+ dev_info(dev, "initialize bluetooth chip\n");
197+
198+ gpio_request(bt_on, "bt_on");
199+ gpio_direction_output(bt_on, 0);
200+ msleep(11);
201+ gpio_set_value(bt_on, 1);
202+
203+ gpio_request(bt_wake, "bt_wake");
204+ gpio_direction_output(bt_wake, 1);
205+
206+ gpio_request(bt_host_wake, "bt_host_wake");
207+ gpio_direction_input(bt_host_wake);
208+
209+ rfkill->shutdown_name = "bluetooth_shutdown";
210+ rfkill->shutdown_gpio = bt_wake;
211+
212+ rfkill->rfkill_dev = rfkill_alloc("bluetooth-rfkill", dev, RFKILL_TYPE_BLUETOOTH,
213+ &wand_rfkill_ops, rfkill);
214+ if (!rfkill->rfkill_dev) {
215+ ret = -ENOMEM;
216+ goto bt_fail_free_gpio;
217+ }
218+
219+ ret = rfkill_register(rfkill->rfkill_dev);
220+ if (ret < 0)
221+ goto bt_fail_unregister;
222+
223+ dev_info(dev, "bluetooth-rfkill registered.\n");
224+
225+ return 0;
226+
227+bt_fail_unregister:
228+ rfkill_destroy(rfkill->rfkill_dev);
229+bt_fail_free_gpio:
230+ if (gpio_is_valid(bt_on)) gpio_free(bt_on);
231+ if (gpio_is_valid(bt_wake)) gpio_free(bt_wake);
232+ if (gpio_is_valid(bt_host_wake)) gpio_free(bt_host_wake);
233+
234+ return ret;
235+}
236+
237+static int wand_rfkill_probe(struct platform_device *pdev)
238+{
239+ struct wand_rfkill_data *rfkill;
240+ struct pinctrl *pinctrl;
241+ int ret;
242+
243+ dev_info(&pdev->dev, "Wandboard rfkill initialization\n");
244+
245+ if (!pdev->dev.of_node) {
246+ dev_err(&pdev->dev, "no device tree node\n");
247+ return -ENODEV;
248+ }
249+
250+ rfkill = kzalloc(sizeof(*rfkill) * 2, GFP_KERNEL);
251+ if (!rfkill)
252+ return -ENOMEM;
253+
254+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
255+ if (IS_ERR(pinctrl)) {
256+ int ret = PTR_ERR(pinctrl);
257+ dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
258+ return ret;
259+ }
260+
261+ /* setup WiFi */
262+ ret = wand_rfkill_wifi_probe(&pdev->dev, pdev->dev.of_node, &rfkill[0]);
263+ if (ret < 0)
264+ goto fail_free_rfkill;
265+
266+ /* setup bluetooth */
267+ ret = wand_rfkill_bt_probe(&pdev->dev, pdev->dev.of_node, &rfkill[1]);
268+ if (ret < 0)
269+ goto fail_unregister_wifi;
270+
271+ platform_set_drvdata(pdev, rfkill);
272+
273+ return 0;
274+
275+fail_unregister_wifi:
276+ if (rfkill[1].rfkill_dev) {
277+ rfkill_unregister(rfkill[1].rfkill_dev);
278+ rfkill_destroy(rfkill[1].rfkill_dev);
279+ }
280+
281+ /* TODO free gpio */
282+
283+fail_free_rfkill:
284+ kfree(rfkill);
285+
286+ return ret;
287+}
288+
289+static int wand_rfkill_remove(struct platform_device *pdev)
290+{
291+ struct wand_rfkill_data *rfkill = platform_get_drvdata(pdev);
292+
293+ dev_info(&pdev->dev, "Module unloading\n");
294+
295+ if (!rfkill)
296+ return 0;
297+
298+ /* WiFi */
299+ if (gpio_is_valid(rfkill[0].shutdown_gpio))
300+ gpio_free(rfkill[0].shutdown_gpio);
301+
302+ rfkill_unregister(rfkill[0].rfkill_dev);
303+ rfkill_destroy(rfkill[0].rfkill_dev);
304+
305+ /* Bt */
306+ if (gpio_is_valid(rfkill[1].shutdown_gpio))
307+ gpio_free(rfkill[1].shutdown_gpio);
308+
309+ rfkill_unregister(rfkill[1].rfkill_dev);
310+ rfkill_destroy(rfkill[1].rfkill_dev);
311+
312+ kfree(rfkill);
313+
314+ return 0;
315+}
316+
317+static struct of_device_id wand_rfkill_match[] = {
318+ { .compatible = "wand,imx6q-wandboard-rfkill", },
319+ { .compatible = "wand,imx6dl-wandboard-rfkill", },
320+ { .compatible = "wand,imx6qdl-wandboard-rfkill", },
321+ {}
322+};
323+
324+static struct platform_driver wand_rfkill_driver = {
325+ .driver = {
326+ .name = "wandboard-rfkill",
327+ .owner = THIS_MODULE,
328+ .of_match_table = of_match_ptr(wand_rfkill_match),
329+ },
330+ .probe = wand_rfkill_probe,
331+ .remove = wand_rfkill_remove
332+};
333+
334+module_platform_driver(wand_rfkill_driver);
335+
336+MODULE_AUTHOR("Vladimir Ermakov <vooon341@gmail.com>");
337+MODULE_DESCRIPTION("Wandboard rfkill driver");
338+MODULE_LICENSE("GPL v2");
339--
3401.8.4.rc3
341