]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/commitdiff
Kernel: Add support for wifi and bluetooth on imx6 wandboards.
authorStefan Schantl <stefan.schantl@ipfire.org>
Thu, 19 Dec 2013 20:34:09 +0000 (21:34 +0100)
committerStefan Schantl <stefan.schantl@ipfire.org>
Thu, 19 Dec 2013 20:36:37 +0000 (21:36 +0100)
lfs/linux
src/patches/kernel/wandboard/dts/0004-ARM-dts-wandboard-add-binding-for-wand-rfkill-driver.patch [new file with mode: 0644]
src/patches/kernel/wandboard/imx/0004-ARM-i.MX6-Wandboard-add-wifi-bt-rfkill-driver.patch [new file with mode: 0644]

index 6f75ab1c1e6cd8668c3ec675324a9bda35bcced9..6d5aea47c842c1133a59a267d5f8caec30f44695 100644 (file)
--- a/lfs/linux
+++ b/lfs/linux
@@ -170,10 +170,12 @@ ifeq "$(KCFG)" "-multi"
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/dts/0001-imx6qdl-wandboard-dts-backport.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/dts/0002-ARM-dts-imx6qdl-wandboard-add-gpio-lines-to-wandboar.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/dts/0003-ARM-dts-imx6qdl-wandboard-Add-support-for-i2c1.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/dts/0004-ARM-dts-wandboard-add-binding-for-wand-rfkill-driver.patch
 
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/imx/0001-i2c-imx-retry-on-NAK.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/imx/0002-i.MX6-Wandboard-add-CKO1-clock-output.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/imx/0003-thermal-add-imx-thermal-driver-support.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/imx/0004-ARM-i.MX6-Wandboard-add-wifi-bt-rfkill-driver.patch
 
        # Patchset for Compulab Utilite.
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/utilite/linux-3.10-compulab-utilite-support.patch
diff --git a/src/patches/kernel/wandboard/dts/0004-ARM-dts-wandboard-add-binding-for-wand-rfkill-driver.patch b/src/patches/kernel/wandboard/dts/0004-ARM-dts-wandboard-add-binding-for-wand-rfkill-driver.patch
new file mode 100644 (file)
index 0000000..54bb388
--- /dev/null
@@ -0,0 +1,52 @@
+From 1305ac7e9308dcd59c3acc205bc95097cad87ed5 Mon Sep 17 00:00:00 2001
+From: Vladimir Ermakov <vooon341@gmail.com>
+Date: Fri, 16 Aug 2013 06:52:26 +0400
+Subject: [PATCH 5/5] ARM: dts: wandboard: add binding for wand-rfkill driver
+
+Required gpios pincontrol selected in hog. Add binding only.
+Disabled non-removable, because after unblocking need to redetect SDIO device.
+
+Signed-off-by: Vladimir Ermakov <vooon341@gmail.com>
+---
+ arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+index 737805b..c1ef3bd 100644
+--- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
++++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+@@ -50,6 +50,22 @@
+               spdif-controller = <&spdif>;
+               spdif-out;
+       };
++
++      rfkill {
++              compatible = "wand,imx6qdl-wandboard-rfkill";
++              pinctrl-names = "default";
++              pinctrl-0 = <>;
++
++              bluetooth-on = <&gpio3 13 0>;
++              bluetooth-wake = <&gpio3 14 0>;
++              bluetooth-host-wake = <&gpio3 15 0>;
++
++              wifi-ref-on = <&gpio2 29 0>;
++              wifi-rst-n = <&gpio5 2 0>;
++              wifi-reg-on = <&gpio1 26 0>;
++              wifi-host-wake = <&gpio1 29 0>;
++              wifi-wake = <&gpio1 30 0>;
++      };
+ };
+ &audmux {
+@@ -175,7 +191,7 @@
+ &usdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_usdhc2_2>;
+-      non-removable;
++      //non-removable;
+       status = "okay";
+ };
+-- 
+1.8.4.rc3
+
diff --git a/src/patches/kernel/wandboard/imx/0004-ARM-i.MX6-Wandboard-add-wifi-bt-rfkill-driver.patch b/src/patches/kernel/wandboard/imx/0004-ARM-i.MX6-Wandboard-add-wifi-bt-rfkill-driver.patch
new file mode 100644 (file)
index 0000000..993b1d7
--- /dev/null
@@ -0,0 +1,341 @@
+From adf0f7b7d7c0083dd936fe46423b89e974f8df12 Mon Sep 17 00:00:00 2001
+From: Vladimir Ermakov <vooon341@gmail.com>
+Date: Wed, 10 Jul 2013 03:06:54 +0400
+Subject: [PATCH] ARM i.MX6 Wandboard add wifi+bt rfkill driver
+
+BRCM WiFi module requires initialization for control gpio;
+Additional provides rfkill funcs.
+
+v2: fix wrong probe func in driver struct
+v3: add imx6qdl compatible
+
+Signed-off-by: Vladimir Ermakov <vooon341@gmail.com>
+---
+ arch/arm/mach-imx/devices/Kconfig       |   6 +
+ arch/arm/mach-imx/devices/Makefile      |   1 +
+ arch/arm/mach-imx/devices/wand-rfkill.c | 290 ++++++++++++++++++++++++++++++++
+ 3 files changed, 297 insertions(+)
+ create mode 100644 arch/arm/mach-imx/devices/wand-rfkill.c
+
+diff --git a/arch/arm/mach-imx/devices/Kconfig b/arch/arm/mach-imx/devices/Kconfig
+index 68c74fb..a0adf75 100644
+--- a/arch/arm/mach-imx/devices/Kconfig
++++ b/arch/arm/mach-imx/devices/Kconfig
+@@ -85,3 +85,9 @@ config IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+ config IMX_HAVE_PLATFORM_SPI_IMX
+       bool
++
++config WAND_RFKILL
++      tristate "Wandboard RF Kill support"
++      depends on SOC_IMX6Q
++      default m
++      select RFKILL
+diff --git a/arch/arm/mach-imx/devices/Makefile b/arch/arm/mach-imx/devices/Makefile
+index 67416fb..b2aded5 100644
+--- a/arch/arm/mach-imx/devices/Makefile
++++ b/arch/arm/mach-imx/devices/Makefile
+@@ -30,3 +30,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o
+ obj-$(CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX) += platform-sdhci-esdhc-imx.o
+ obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) +=  platform-spi_imx.o
+ obj-$(CONFIG_IMX_HAVE_PLATFORM_MX2_EMMA) += platform-mx2-emma.o
++obj-$(CONFIG_WAND_RFKILL) += wand-rfkill.o
+diff --git a/arch/arm/mach-imx/devices/wand-rfkill.c b/arch/arm/mach-imx/devices/wand-rfkill.c
+new file mode 100644
+index 0000000..da7ef9f
+--- /dev/null
++++ b/arch/arm/mach-imx/devices/wand-rfkill.c
+@@ -0,0 +1,290 @@
++/*
++ * arch/arm/mach-imx/devices/wand-rfkill.c
++ *
++ * Copyright (C) 2013 Vladimir Ermakov <vooon341@gmail.com>
++ *
++ * based on net/rfkill/rfkill-gpio.c
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/of.h>
++#include <linux/of_gpio.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/platform_device.h>
++#include <linux/rfkill.h>
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++
++
++struct wand_rfkill_data {
++      struct rfkill *rfkill_dev;
++      int shutdown_gpio;
++      const char *shutdown_name;
++};
++
++static int wand_rfkill_set_block(void *data, bool blocked)
++{
++      struct wand_rfkill_data *rfkill = data;
++
++      pr_debug("wandboard-rfkill: set block %d\n", blocked);
++
++      if (blocked) {
++              if (gpio_is_valid(rfkill->shutdown_gpio))
++                      gpio_direction_output(rfkill->shutdown_gpio, 0);
++      } else {
++              if (gpio_is_valid(rfkill->shutdown_gpio))
++                      gpio_direction_output(rfkill->shutdown_gpio, 1);
++      }
++
++      return 0;
++}
++
++static const struct rfkill_ops wand_rfkill_ops = {
++      .set_block = wand_rfkill_set_block,
++};
++
++static int wand_rfkill_wifi_probe(struct device *dev,
++              struct device_node *np,
++              struct wand_rfkill_data *rfkill)
++{
++      int ret;
++      int wl_ref_on, wl_rst_n, wl_reg_on, wl_wake, wl_host_wake;
++
++      wl_ref_on = of_get_named_gpio(np, "wifi-ref-on", 0);
++      wl_rst_n = of_get_named_gpio(np, "wifi-rst-n", 0);
++      wl_reg_on = of_get_named_gpio(np, "wifi-reg-on", 0);
++      wl_wake = of_get_named_gpio(np, "wifi-wake", 0);
++      wl_host_wake = of_get_named_gpio(np, "wifi-host-wake", 0);
++
++      if (!gpio_is_valid(wl_rst_n) || !gpio_is_valid(wl_ref_on) ||
++                      !gpio_is_valid(wl_reg_on) || !gpio_is_valid(wl_wake) ||
++                      !gpio_is_valid(wl_host_wake)) {
++
++              dev_err(dev, "incorrect wifi gpios (%d %d %d %d %d)\n",
++                              wl_rst_n, wl_ref_on, wl_reg_on, wl_wake, wl_host_wake);
++              return -EINVAL;
++      }
++
++      dev_info(dev, "initialize wifi chip\n");
++
++      gpio_request(wl_rst_n, "wl_rst_n");
++      gpio_direction_output(wl_rst_n, 0);
++      msleep(11);
++      gpio_set_value(wl_rst_n, 1);
++
++      gpio_request(wl_ref_on, "wl_ref_on");
++      gpio_direction_output(wl_ref_on, 1);
++
++      gpio_request(wl_reg_on, "wl_reg_on");
++      gpio_direction_output(wl_reg_on, 1);
++
++      gpio_request(wl_wake, "wl_wake");
++      gpio_direction_output(wl_wake, 1);
++
++      gpio_request(wl_host_wake, "wl_host_wake");
++      gpio_direction_input(wl_host_wake);
++
++      rfkill->shutdown_name = "wifi_shutdown";
++      rfkill->shutdown_gpio = wl_wake;
++
++      rfkill->rfkill_dev = rfkill_alloc("wifi-rfkill", dev, RFKILL_TYPE_WLAN,
++                      &wand_rfkill_ops, rfkill);
++      if (!rfkill->rfkill_dev) {
++              ret = -ENOMEM;
++              goto wifi_fail_free_gpio;
++      }
++
++      ret = rfkill_register(rfkill->rfkill_dev);
++      if (ret < 0)
++              goto wifi_fail_unregister;
++
++      dev_info(dev, "wifi-rfkill registered.\n");
++
++      return 0;
++
++wifi_fail_unregister:
++      rfkill_destroy(rfkill->rfkill_dev);
++wifi_fail_free_gpio:
++      if (gpio_is_valid(wl_rst_n))     gpio_free(wl_rst_n);
++      if (gpio_is_valid(wl_ref_on))    gpio_free(wl_ref_on);
++      if (gpio_is_valid(wl_reg_on))    gpio_free(wl_reg_on);
++      if (gpio_is_valid(wl_wake))      gpio_free(wl_wake);
++      if (gpio_is_valid(wl_host_wake)) gpio_free(wl_host_wake);
++
++      return ret;
++}
++
++static int wand_rfkill_bt_probe(struct device *dev,
++              struct device_node *np,
++              struct wand_rfkill_data *rfkill)
++{
++      int ret;
++      int bt_on, bt_wake, bt_host_wake;
++
++      bt_on = of_get_named_gpio(np, "bluetooth-on", 0);
++      bt_wake = of_get_named_gpio(np, "bluetooth-wake", 0);
++      bt_host_wake = of_get_named_gpio(np, "bluetooth-host-wake", 0);
++
++      if (!gpio_is_valid(bt_on) || !gpio_is_valid(bt_wake) ||
++                      !gpio_is_valid(bt_host_wake)) {
++
++              dev_err(dev, "incorrect bt gpios (%d %d %d)\n",
++                              bt_on, bt_wake, bt_host_wake);
++              return -EINVAL;
++      }
++
++      dev_info(dev, "initialize bluetooth chip\n");
++
++      gpio_request(bt_on, "bt_on");
++      gpio_direction_output(bt_on, 0);
++      msleep(11);
++      gpio_set_value(bt_on, 1);
++
++      gpio_request(bt_wake, "bt_wake");
++      gpio_direction_output(bt_wake, 1);
++
++      gpio_request(bt_host_wake, "bt_host_wake");
++      gpio_direction_input(bt_host_wake);
++
++      rfkill->shutdown_name = "bluetooth_shutdown";
++      rfkill->shutdown_gpio = bt_wake;
++
++      rfkill->rfkill_dev = rfkill_alloc("bluetooth-rfkill", dev, RFKILL_TYPE_BLUETOOTH,
++                      &wand_rfkill_ops, rfkill);
++      if (!rfkill->rfkill_dev) {
++              ret = -ENOMEM;
++              goto bt_fail_free_gpio;
++      }
++
++      ret = rfkill_register(rfkill->rfkill_dev);
++      if (ret < 0)
++              goto bt_fail_unregister;
++
++      dev_info(dev, "bluetooth-rfkill registered.\n");
++
++      return 0;
++
++bt_fail_unregister:
++      rfkill_destroy(rfkill->rfkill_dev);
++bt_fail_free_gpio:
++      if (gpio_is_valid(bt_on))        gpio_free(bt_on);
++      if (gpio_is_valid(bt_wake))      gpio_free(bt_wake);
++      if (gpio_is_valid(bt_host_wake)) gpio_free(bt_host_wake);
++
++      return ret;
++}
++
++static int wand_rfkill_probe(struct platform_device *pdev)
++{
++      struct wand_rfkill_data *rfkill;
++      struct pinctrl *pinctrl;
++      int ret;
++
++      dev_info(&pdev->dev, "Wandboard rfkill initialization\n");
++
++      if (!pdev->dev.of_node) {
++              dev_err(&pdev->dev, "no device tree node\n");
++              return -ENODEV;
++      }
++
++      rfkill = kzalloc(sizeof(*rfkill) * 2, GFP_KERNEL);
++      if (!rfkill)
++              return -ENOMEM;
++
++      pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++      if (IS_ERR(pinctrl)) {
++              int ret = PTR_ERR(pinctrl);
++              dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
++              return ret;
++      }
++
++      /* setup WiFi */
++      ret = wand_rfkill_wifi_probe(&pdev->dev, pdev->dev.of_node, &rfkill[0]);
++      if (ret < 0)
++              goto fail_free_rfkill;
++
++      /* setup bluetooth */
++      ret = wand_rfkill_bt_probe(&pdev->dev, pdev->dev.of_node, &rfkill[1]);
++      if (ret < 0)
++              goto fail_unregister_wifi;
++
++      platform_set_drvdata(pdev, rfkill);
++
++      return 0;
++
++fail_unregister_wifi:
++      if (rfkill[1].rfkill_dev) {
++              rfkill_unregister(rfkill[1].rfkill_dev);
++              rfkill_destroy(rfkill[1].rfkill_dev);
++      }
++
++      /* TODO free gpio */
++
++fail_free_rfkill:
++      kfree(rfkill);
++
++      return ret;
++}
++
++static int wand_rfkill_remove(struct platform_device *pdev)
++{
++      struct wand_rfkill_data *rfkill = platform_get_drvdata(pdev);
++
++      dev_info(&pdev->dev, "Module unloading\n");
++
++      if (!rfkill)
++              return 0;
++
++      /* WiFi */
++      if (gpio_is_valid(rfkill[0].shutdown_gpio))
++              gpio_free(rfkill[0].shutdown_gpio);
++
++      rfkill_unregister(rfkill[0].rfkill_dev);
++      rfkill_destroy(rfkill[0].rfkill_dev);
++
++      /* Bt */
++      if (gpio_is_valid(rfkill[1].shutdown_gpio))
++              gpio_free(rfkill[1].shutdown_gpio);
++
++      rfkill_unregister(rfkill[1].rfkill_dev);
++      rfkill_destroy(rfkill[1].rfkill_dev);
++
++      kfree(rfkill);
++
++      return 0;
++}
++
++static struct of_device_id wand_rfkill_match[] = {
++      { .compatible = "wand,imx6q-wandboard-rfkill", },
++      { .compatible = "wand,imx6dl-wandboard-rfkill", },
++      { .compatible = "wand,imx6qdl-wandboard-rfkill", },
++      {}
++};
++
++static struct platform_driver wand_rfkill_driver = {
++      .driver = {
++              .name = "wandboard-rfkill",
++              .owner = THIS_MODULE,
++              .of_match_table = of_match_ptr(wand_rfkill_match),
++      },
++      .probe = wand_rfkill_probe,
++      .remove = wand_rfkill_remove
++};
++
++module_platform_driver(wand_rfkill_driver);
++
++MODULE_AUTHOR("Vladimir Ermakov <vooon341@gmail.com>");
++MODULE_DESCRIPTION("Wandboard rfkill driver");
++MODULE_LICENSE("GPL v2");
+-- 
+1.8.4.rc3
+