From: Stefan Schantl Date: Thu, 19 Dec 2013 20:34:09 +0000 (+0100) Subject: Kernel: Add support for wifi and bluetooth on imx6 wandboards. X-Git-Tag: v2.15-beta1~101^2~1^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0c41633ee1379d6646f04f53ab015992892132b2;p=people%2Fms%2Fipfire-2.x.git Kernel: Add support for wifi and bluetooth on imx6 wandboards. --- diff --git a/lfs/linux b/lfs/linux index 6f75ab1c1e..6d5aea47c8 100644 --- 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 index 0000000000..54bb388d43 --- /dev/null +++ b/src/patches/kernel/wandboard/dts/0004-ARM-dts-wandboard-add-binding-for-wand-rfkill-driver.patch @@ -0,0 +1,52 @@ +From 1305ac7e9308dcd59c3acc205bc95097cad87ed5 Mon Sep 17 00:00:00 2001 +From: Vladimir Ermakov +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 +--- + 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 index 0000000000..993b1d7d5b --- /dev/null +++ b/src/patches/kernel/wandboard/imx/0004-ARM-i.MX6-Wandboard-add-wifi-bt-rfkill-driver.patch @@ -0,0 +1,341 @@ +From adf0f7b7d7c0083dd936fe46423b89e974f8df12 Mon Sep 17 00:00:00 2001 +From: Vladimir Ermakov +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 +--- + 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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++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 "); ++MODULE_DESCRIPTION("Wandboard rfkill driver"); ++MODULE_LICENSE("GPL v2"); +-- +1.8.4.rc3 +