前言:
wifi 状态灯在嵌入式项目中很常见,同过状态灯可以判断wifi是否正常工作,不同的led status,可以表示数据发,收等。在nxp项目中,用到的是bcm43455 wifi (博通ap6255),需要增加一个led灯来表示wifi是否正常工作。有以下方案:
方案一:bcm43xx ap硬件有先关的led-gpio,由硬件来完成
方案二:无led-gpio,需要nxp主控引出一个gpio与wifi状态tx、rx、radio状态建立trigger
方案三:wifi驱动力面增加phytx0、phyrx0 triger条件,注册对应的gpio
1. 方案分析
方案一:可以看到,wifi硬件tx、rx、radio无对应的gpio引出,硬件无法实现。
方案二:
通过以下配置,实现wifi_led,但是出现了问题,bcm-wifi用的cfg80211,在 err = wiphy_register(wiphy); 注册的时候,不会注册、生成phy0rx phy0tx triger 条件。如下,无 phy0rx phy0tx 的triger。在linux 内核调试了半天也没有看到wifi对应的triger条件,反而把网口的百兆、千兆triger打开了。当然使用网口的不行。方案二是一个大众的方案,标准,但是bcm43xx wifi驱动里不支持。所以实行方案三。
#dts配置gpio1_1
leds {
compatible = "gpio-leds";
status = "okay";
wlan_led {
label = "green-wlan";
gpios = <&gpio1 1 0>; /* wlan */
};
};
#系统配置实现:
#/etc/config/system
config led wlan-led ——配置项目的标签
option name wlan_led ——配置项目的名字
option sysfs green-wlan ——设备号
option trigger phy0rx phy0tx ——触发的设备类型
option dev wlan0_led ——对应的设备
option mode link tx rx ——要响应的设备活动事件
option default 0
cat trigger
none rc-feedback bluetooth-power kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock [mmc0] mmc1 mmc2 heartbeat cpu cpu0 cpu1 cpu2 cpu3 default-on
方案三:在wifi驱动增加led, 如下所示:
在调试过程中,通过
ieee80211_create_tpt_led_trigger(hw,IEEE80211_TPT_LEDTRIG_FL_RADIO,tpt_blink,ARRAY_SIZE(tpt_blink));注册triger条件,返回的null值,这个问题由于项目关系,没有看到底。自然triger没有生效,wifi的状态灯,是wifi驱动正常probe 后,gpio1_1 点亮。如果没有wifi芯片或者probe失败,不会点亮。
2. 驱动调试
1->wifi驱动增加led
diff --git a/drivers/net/wireless/broadcom/brcm80211/Kconfig b/drivers/net/wireless/broadcom/brcm80211/Kconfig
index 9d99eb42d917..a19649a481be 100644
--- a/drivers/net/wireless/broadcom/brcm80211/Kconfig
+++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig
@@ -27,6 +27,15 @@ config BRCMFMAC
interface support. If you choose to build a module, it'll be called
brcmfmac.ko.
+config BCMXX_LED
+ tristate "Broadcom WLAN LED driver"
+ depends on BRCMFMAC
+ ---help---
+ This module adds support for wireless adapters based on Broadcom
+ FullMAC chipsets. It has to work with at least one of the bus
+ interface support. If you choose to build a module, it'll be called
+ brcmfmac.ko.
+
config BRCMFMAC_PROTO_BCDC
bool
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
index 1f5a9b948abf..b3b2696a86ba 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
@@ -54,3 +54,4 @@ brcmfmac-$(CONFIG_BRCM_TRACING) += \
tracepoint.o
brcmfmac-$(CONFIG_OF) += \
of.o
+brcmfmac-$(CONFIG_BCMXX_LED) += led.o
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index d1cc95584128..ef479312e80d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -21,6 +21,9 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <net/cfg80211.h>
+#if IS_ENABLED(CONFIG_BCMXX_LED)
+#include <net/mac80211.h>
+#endif
#include <net/netlink.h>
#include <brcmu_utils.h>
@@ -7215,6 +7218,16 @@ static void brcmf_free_wiphy(struct wiphy *wiphy)
wiphy_free(wiphy);
}
+#if IS_ENABLED(CONFIG_BCMXX_LED)
+int led_blink = 1;
+module_param_named(blink, led_blink, int, 0444);
+MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+
+static const struct ieee80211_tpt_blink tpt_blink[] = {
+ { .throughput = 0 * 1024, .blink_time = 334 },
+};
+#endif
+
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct device *busdev,
bool p2pdev_forced)
@@ -7225,6 +7238,9 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct cfg80211_ops *ops;
struct brcmf_cfg80211_vif *vif;
struct brcmf_if *ifp;
+#if IS_ENABLED(CONFIG_BCMXX_LED)
+ struct ieee80211_hw *hw;
+#endif
s32 err = 0;
s32 io_type;
u16 *cap = NULL;
@@ -7302,6 +7318,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
*cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
}
+
err = wiphy_register(wiphy);
if (err < 0) {
brcmf_err("Could not register wiphy device (%d)\n", err);
@@ -7384,6 +7401,16 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
#endif
}
+#if IS_ENABLED(CONFIG_BCMXX_LED)
+ //printk("zyy bcmxx led..............");
+ hw = wiphy_to_ieee80211_hw(wiphy);
+
+ cfg->led_dev.name = wiphy_name(wiphy);
+ cfg->led_dev.default_trigger = ieee80211_create_tpt_led_trigger(hw,IEEE80211_TPT_LEDTRIG_FL_RADIO,tpt_blink,ARRAY_SIZE(tpt_blink));
+
+ if(hw) brcm_led_register(cfg);
+
+#endif
return cfg;
detach:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 00faae6e50ab..74e2f62d1267 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -23,6 +23,11 @@
#include "core.h"
#include "fwil_types.h"
#include "p2p.h"
+#if IS_ENABLED(CONFIG_BCMXX_LED)
+#include "led.h"
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#endif
#define BRCMF_SCAN_IE_LEN_MAX 2048
@@ -304,7 +309,13 @@ struct brcmf_cfg80211_wowl {
bool nd_data_completed;
bool nd_enabled;
};
-
+#if IS_ENABLED(CONFIG_BCMXX_LED)
+struct brcm_led {
+ char name[32];
+ unsigned gpio;
+ bool active_low;
+};
+#endif
/**
* struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
*
@@ -376,6 +387,14 @@ struct brcmf_cfg80211_info {
struct brcmf_pno_info *pno;
u8 ac_priority[MAX_8021D_PRIO];
u8 pm_state;
+
+#if IS_ENABLED(CONFIG_BCMXX_LED)
+ struct brcm_led radio_led;
+ struct led_classdev led_dev;
+ struct gpio_chip gpio;
+ struct work_struct led_work;
+ struct device_node *nd;
+#endif
};
/**
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/led.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/led.c
new file mode 100644
index 000000000000..e0f8c11a9c3f
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/led.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <net/mac80211.h>
+#include <linux/bcma/bcma_driver_chipcommon.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+
+#include "led.h"
+#include "cfg80211.h"
+
+
+void brcm_radio_led_ctrl(struct brcmf_cfg80211_info *wl, bool state)
+{
+ if (wl->radio_led.gpio == -1)
+ return;
+
+ if (wl->radio_led.active_low)
+ state = !state;
+
+ if (state)
+ gpio_set_value(wl->radio_led.gpio, 1);
+ else
+ gpio_set_value(wl->radio_led.gpio, 0);
+}
+
+
+
+void bcm_led_work(struct work_struct *work)
+{
+ struct brcmf_cfg80211_info *wl = container_of(work,struct brcmf_cfg80211_info,led_work);
+ brcm_radio_led_ctrl(wl, 0);
+}
+
+/* Callback from the LED subsystem. */
+static void brcm_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct brcmf_cfg80211_info *wl = container_of(led_dev,
+ struct brcmf_cfg80211_info, led_dev);
+ brcm_radio_led_ctrl(wl, 0);
+}
+
+void brcm_led_unregister(struct brcmf_cfg80211_info *wl)
+{
+ if (wl->led_dev.dev)
+ led_classdev_unregister(&wl->led_dev);
+ if (wl->radio_led.gpio != -1)
+ gpio_free(wl->radio_led.gpio);
+}
+
+int brcm_led_register(struct brcmf_cfg80211_info *wl)
+{
+ int i, err;
+ struct brcm_led *radio_led = &wl->radio_led;
+ //struct ssb_sprom *sprom = &wl->pub->bus_sprom;
+ unsigned gpio = -1;
+ bool active_low = false;
+ struct ieee80211_hw *hw;
+ char name[20 + 1];
+
+ //printk("wlan-gt810..................... \r\n");
+ wl->nd = of_find_node_by_path("/bcmxxled");
+ if(wl->nd == NULL)
+ {
+ printk("wlan-gt810 not find \r\n");
+ return -EINVAL;
+ }
+
+ radio_led->gpio = of_get_named_gpio(wl->nd,"wlan-gpio",0);
+ if(radio_led->gpio<0)
+ {
+ printk("can't get wlan-gpio\r\n");
+ return -EINVAL;
+ }
+
+
+ //u8 *leds[] = { &sprom->gpio0,&sprom->gpio1,&sprom->gpio2,&sprom->gpio3 };
+
+ /* none by default */
+ //radio_led->gpio = -1;
+ radio_led->active_low = false;
+/*
+ for (i = 0; i < BRCMS_LED_NO; i++) {
+ u8 led = *leds[i];
+ if ((led & BRCMS_LED_BEH_MASK) == BRCMS_LED_RADIO) {
+ gpio = bcma_gpio->base + i;
+ if (led & BRCMS_LED_AL_MASK)
+ active_low = true;
+ break;
+ }
+ }
+*/
+ /* request and configure LED gpio */
+ err = gpio_request_one(radio_led->gpio,GPIOF_OUT_INIT_HIGH,"radio on");
+ if (err) {
+ return err;
+ }
+ err = gpio_direction_output(radio_led->gpio, 1);
+ if (err) {
+ return err;
+ }
+
+ hw = wiphy_to_ieee80211_hw(wl->wiphy);
+ snprintf(name, sizeof(name),"b43-%s::tx", wiphy_name(hw->wiphy));
+
+ //wl->led_dev.name = "wlan-led";//wl->radio_led.name;
+ printk("...........default :%s\r\n",ieee80211_get_radio_led_name(hw));
+ wl->led_dev.default_trigger = ieee80211_get_radio_led_name(hw);
+ wl->led_dev.brightness_set = brcm_led_brightness_set;
+ err = led_classdev_register(wiphy_dev(wl->wiphy), &wl->led_dev);
+
+ if (err) {
+ return err;
+ }
+
+ INIT_WORK(&wl->led_work, bcm_led_work);
+
+ //radio_led->gpio = 1;
+ radio_led->active_low = active_low;
+
+ return 0;
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/led.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/led.h
new file mode 100644
index 000000000000..f56d4333cffb
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/led.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BRCM_LED_H_
+#define _BRCM_LED_H_
+#include "cfg80211.h"
+void brcm_radio_led_ctrl(struct brcmf_cfg80211_info *wl, bool state);
+void brcm_led_unregister(struct brcmf_cfg80211_info *wl);
+int brcm_led_register(struct brcmf_cfg80211_info *wl);
+#endif /* _BRCM_LED_H_ */
2->dts 配置
index cc1afbd..cd01ff5 100755
--- a/arch/arm64/boot/dts/freescale/fsl-imx8mm-evk.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-imx8mm-evk.dts
@@ -32,6 +32,10 @@
clock-frequency = <16000000>;
};
};
+
+ bcmxxled {
+ wlan-gpio = <&gpio1 1 0>;
+ };
leds {
compatible = "gpio-leds";
@@ -44,6 +48,32 @@
gpios = <&gpio3 16 0>;
default-state = "on";
};
+
+ user_led1 {
+ label = "green-sys";
+ gpios = <&gpio1 8 0>; /* sys */
+ linux,default-trigger = "heartbeat";
+ };
+
+ user_led2 {
+ label = "green-error";
+ gpios = <&gpio2 20 0>; /* error */
+ linux,default-trigger = "mmc2";
+ };
+#if 0
+ wlan_led {
+ label = "green-wlan";
+ gpios = <&gpio1 1 0>; /* wlan */
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+#endif
+ bt_led {
+ label = "green-bt";
+ gpios = <&gpio1 7 0>; /* bt */
+ linux,default-trigger = "hci0-power";
+ default-state = "off";
+ };
};
3->kconfig /Makefile 配置
diff --git a/drivers/net/wireless/broadcom/brcm80211/Kconfig b/drivers/net/wireless/broadcom/brcm80211/Kconfig
index 9d99eb42d917..a19649a481be 100644
--- a/drivers/net/wireless/broadcom/brcm80211/Kconfig
+++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig
@@ -27,6 +27,15 @@ config BRCMFMAC
interface support. If you choose to build a module, it'll be called
brcmfmac.ko.
+config BCMXX_LED
+ tristate "Broadcom WLAN LED driver"
+ depends on BRCMFMAC
+ ---help---
+ This module adds support for wireless adapters based on Broadcom
+ FullMAC chipsets. It has to work with at least one of the bus
+ interface support. If you choose to build a module, it'll be called
+ brcmfmac.ko.
+
config BRCMFMAC_PROTO_BCDC
bool
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
index 1f5a9b948abf..b3b2696a86ba 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
@@ -54,3 +54,4 @@ brcmfmac-$(CONFIG_BRCM_TRACING) += \
tracepoint.o
brcmfmac-$(CONFIG_OF) += \
of.o
+brcmfmac-$(CONFIG_BCMXX_LED) += led.o
4-> defconfig 配置
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
CONFIG_BRIDGE_LT9611=y
+CONFIG_BCMXX_LED=y
5->遗留问题
//创建trigger失败问题。
ieee80211_create_tpt_led_trigger(hw,IEEE80211_TPT_LEDTRIG_FL_RADIO,tpt_blink,ARRAY_SIZE(tpt_blink));