From: Ragul Balaji <ragulbaby@gmail.com>
To: linux-wireless@vger.kernel.org
Cc: Arend van Spriel <arend.vanspriel@broadcom.com>,
Johannes Berg <johannes@sipsolutions.net>,
brcm80211@lists.linux.dev, Ragul Balaji <ragulbaby@gmail.com>,
Ho Jie Feng <hjf3108@gmail.com>,
linux-kernel@vger.kernel.org,
brcm80211-dev-list.pdl@broadcom.com
Subject: [RFC PATCH wireless-next 16/17] wifi: bcm4323x: add LED and WPS button support
Date: Mon, 26 Oct 2026 13:36:22 +0800 [thread overview]
Message-ID: <20261026053633.361454-17-ragulbaby@gmail.com> (raw)
In-Reply-To: <20261026053633.361454-1-ragulbaby@gmail.com>
Add the LED and WPS button to the device driver.
Currently the GPIOs are hardcoded to values in specific devices.
Signed-off-by: Ragul Balaji <ragulbaby@gmail.com>
Signed-off-by: Ho Jie Feng <hjf3108@gmail.com>
---
.../brcm80211/bcm4323x/bcm4323x_led.c | 221 ++++++++++++++++++
1 file changed, 221 insertions(+)
create mode 100644 drivers/net/wireless/broadcom/brcm80211/bcm4323x/bcm4323x_led.c
diff --git a/drivers/net/wireless/broadcom/brcm80211/bcm4323x/bcm4323x_led.c b/drivers/net/wireless/broadcom/brcm80211/bcm4323x/bcm4323x_led.c
new file mode 100644
index 000000000..8d2aa459a
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/bcm4323x/bcm4323x_led.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bits.h>
+#include <linux/input.h>
+#include <linux/led-class-multicolor.h>
+#include <linux/leds.h>
+#include <linux/usb/input.h>
+
+#include "bcm4323x.h"
+
+/* Power/Activity LED */
+#define BCM4323X_LED_GPIO 1
+#define BCM4323X_LED_BLINK_MS 500
+/* TODO: This is Belkin F9L1101 specific*/
+#define BCM4323X_WPS_GREEN_GPIO 2
+#define BCM4323X_WPS_RED_GPIO 3
+/* TODO: this is Belkin F9L1101 and WNA3100 specific */
+#define BCM4323X_WPS_BUTTON_GPIO 10
+#define BCM4323X_WPS_BUTTON_POLL_MS 200
+
+static const struct ieee80211_tpt_blink bcm4323x_tpt_blink[] = {
+ { .throughput = 0 * 1024, .blink_time = 334 },
+ { .throughput = 1 * 1024, .blink_time = 260 },
+ { .throughput = 5 * 1024, .blink_time = 220 },
+ { .throughput = 10 * 1024, .blink_time = 190 },
+ { .throughput = 20 * 1024, .blink_time = 170 },
+ { .throughput = 50 * 1024, .blink_time = 150 },
+ { .throughput = 70 * 1024, .blink_time = 130 },
+ { .throughput = 100 * 1024, .blink_time = 110 },
+ { .throughput = 200 * 1024, .blink_time = 80 },
+ { .throughput = 300 * 1024, .blink_time = 50 },
+};
+
+static int bcm4323x_led_blink(struct bcm4323x *dev, unsigned long on_ms, unsigned long off_ms)
+{
+ int ret = bcm4323x_rpc_send_u32(dev, BCM4323X_RPC_PROC_LED_BLINK, BCM4323X_LED_GPIO, on_ms,
+ off_ms);
+
+ return ret == -ENODEV ? 0 : ret;
+}
+
+static int bcm4323x_led_gpio_out(struct bcm4323x *dev, u32 mask, u32 value)
+{
+ int ret = bcm4323x_rpc_send_u32(dev, BCM4323X_RPC_PROC_GPIO_OUT, mask, value, 1);
+
+ return ret == -ENODEV ? 0 : ret;
+}
+
+static int bcm4323x_led_set(struct bcm4323x *dev, bool on)
+{
+ int ret;
+
+ ret = bcm4323x_led_blink(dev, 0, 0);
+ if (ret)
+ return ret;
+ return bcm4323x_led_gpio_out(dev, BIT(BCM4323X_LED_GPIO),
+ on ? BIT(BCM4323X_LED_GPIO) : 0);
+}
+
+static int bcm4323x_led_brightness_set(struct led_classdev *led, enum led_brightness brightness)
+{
+ return bcm4323x_led_set(container_of(led, struct bcm4323x, led), brightness);
+}
+
+static int bcm4323x_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct bcm4323x *dev = container_of(led, struct bcm4323x, led);
+
+ if (!*delay_on && !*delay_off)
+ *delay_on = *delay_off = BCM4323X_LED_BLINK_MS;
+ if (!*delay_on || !*delay_off)
+ return bcm4323x_led_set(dev, *delay_on);
+ return bcm4323x_led_blink(dev, *delay_on, *delay_off);
+}
+
+#if IS_REACHABLE(CONFIG_LEDS_CLASS_MULTICOLOR)
+static int bcm4323x_wps_led_brightness_set(struct led_classdev *led,
+ enum led_brightness brightness)
+{
+ struct led_classdev_mc *mc = lcdev_to_mccdev(led);
+ struct bcm4323x *dev = container_of(mc, struct bcm4323x, wps_led);
+ u32 value = 0;
+ unsigned int i;
+
+ led_mc_calc_color_components(mc, brightness);
+ for (i = 0; i < mc->num_colors; i++) {
+ if (mc->subled_info[i].brightness)
+ value |= BIT(mc->subled_info[i].channel);
+ }
+ return bcm4323x_led_gpio_out(dev, BIT(BCM4323X_WPS_GREEN_GPIO) | BIT(BCM4323X_WPS_RED_GPIO),
+ value);
+}
+
+/* F9L1101 v1 specific */
+static void bcm4323x_wps_led_register(struct bcm4323x *dev)
+{
+ struct led_classdev *led = &dev->wps_led.led_cdev;
+ int ret;
+
+ if (!dev->chip->has_wps_led)
+ return;
+ dev->wps_subleds[0] = (struct mc_subled) {
+ .color_index = LED_COLOR_ID_GREEN,
+ .intensity = 1,
+ .max_intensity = 1,
+ .channel = BCM4323X_WPS_GREEN_GPIO,
+ };
+ dev->wps_subleds[1] = (struct mc_subled) {
+ .color_index = LED_COLOR_ID_RED,
+ .intensity = 1,
+ .max_intensity = 1,
+ .channel = BCM4323X_WPS_RED_GPIO,
+ };
+ dev->wps_led.subled_info = dev->wps_subleds;
+ dev->wps_led.num_colors = ARRAY_SIZE(dev->wps_subleds);
+ snprintf(dev->wps_led_name, sizeof(dev->wps_led_name), "bcm4323x-%s:multicolor:wps",
+ wiphy_name(dev->hw->wiphy));
+ led->name = dev->wps_led_name;
+ led->max_brightness = 1;
+ led->brightness_set_blocking = bcm4323x_wps_led_brightness_set;
+ ret = bcm4323x_wps_led_brightness_set(led, LED_OFF);
+ if (!ret)
+ ret = led_classdev_multicolor_register(&dev->intf->dev, &dev->wps_led);
+ if (ret) {
+ led->dev = NULL;
+ wiphy_warn(dev->hw->wiphy, "cannot register the WPS LED: %d\n", ret);
+ }
+}
+
+static void bcm4323x_wps_led_unregister(struct bcm4323x *dev)
+{
+ if (dev->wps_led.led_cdev.dev)
+ led_classdev_multicolor_unregister(&dev->wps_led);
+}
+#else
+static void bcm4323x_wps_led_register(struct bcm4323x *dev) {}
+static void bcm4323x_wps_led_unregister(struct bcm4323x *dev) {}
+#endif
+
+static void bcm4323x_wps_button_poll(struct input_dev *input)
+{
+ struct bcm4323x *dev = input_get_drvdata(input);
+ __le32 value;
+
+ if (bcm4323x_rpc_call_u32(dev, BCM4323X_RPC_PROC_REG_READ, &value,
+ D11REGOFFS(psm_gpio_in), sizeof(u16)))
+ return;
+ input_report_key(input, KEY_WPS_BUTTON,
+ !(le32_to_cpu(value) & BIT(BCM4323X_WPS_BUTTON_GPIO)));
+ input_sync(input);
+}
+
+static void bcm4323x_wps_button_register(struct bcm4323x *dev)
+{
+ struct input_dev *input;
+ int ret;
+
+ if (!dev->chip->has_wps_button)
+ return;
+ input = input_allocate_device();
+ if (!input)
+ return;
+ input->name = "BCM4323x WPS button";
+ snprintf(dev->wps_button_phys, sizeof(dev->wps_button_phys), "ieee80211/%s/input0",
+ wiphy_name(dev->hw->wiphy));
+ input->phys = dev->wps_button_phys;
+ usb_to_input_id(dev->udev, &input->id);
+ input->dev.parent = &dev->hw->wiphy->dev;
+ input_set_capability(input, EV_KEY, KEY_WPS_BUTTON);
+ input_set_drvdata(input, dev);
+ ret = input_setup_polling(input, bcm4323x_wps_button_poll);
+ if (!ret) {
+ input_set_poll_interval(input, BCM4323X_WPS_BUTTON_POLL_MS);
+ ret = input_register_device(input);
+ }
+ if (ret) {
+ input_free_device(input);
+ wiphy_warn(dev->hw->wiphy, "cannot register the WPS button: %d\n", ret);
+ return;
+ }
+ dev->wps_button = input;
+}
+
+void bcm4323x_led_init(struct bcm4323x *dev)
+{
+ dev->led.default_trigger =
+ ieee80211_create_tpt_led_trigger(dev->hw, IEEE80211_TPT_LEDTRIG_FL_RADIO,
+ bcm4323x_tpt_blink,
+ ARRAY_SIZE(bcm4323x_tpt_blink));
+}
+
+void bcm4323x_led_register(struct bcm4323x *dev)
+{
+ struct wiphy *wiphy = dev->hw->wiphy;
+ int ret;
+
+ snprintf(dev->led_name, sizeof(dev->led_name), "bcm4323x-%s:radio", wiphy_name(wiphy));
+ dev->led.name = dev->led_name;
+ dev->led.max_brightness = 1;
+ dev->led.brightness_set_blocking = bcm4323x_led_brightness_set;
+ dev->led.blink_set = bcm4323x_led_blink_set;
+ ret = bcm4323x_led_set(dev, false);
+ if (!ret)
+ ret = led_classdev_register(&dev->intf->dev, &dev->led);
+ if (ret) {
+ dev->led.dev = NULL;
+ wiphy_warn(wiphy, "cannot register the LED: %d\n", ret);
+ }
+ bcm4323x_wps_led_register(dev);
+ bcm4323x_wps_button_register(dev);
+}
+
+void bcm4323x_led_unregister(struct bcm4323x *dev)
+{
+ if (dev->wps_button)
+ input_unregister_device(dev->wps_button);
+ bcm4323x_wps_led_unregister(dev);
+ if (dev->led.dev)
+ led_classdev_unregister(&dev->led);
+}
--
2.53.0
next prev parent reply other threads:[~2026-10-26 5:37 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 5:36 [RFC PATCH wireless-next 00/17] wifi: add a driver for Broadcom BCM4323x USB adapters Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 01/17] wifi: brcmsmac: make d11.h self-contained Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 02/17] wifi: brcm80211: move d11.h to the shared include directory Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 03/17] wifi: brcmsmac: look up OFDM rates in rate.c Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 04/17] wifi: brcmsmac: give the rate tables and helpers a brcmu_ prefix Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 05/17] wifi: brcmsmac: round short-GI L-SIG lengths up to whole symbols Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 06/17] wifi: brcmsmac: pass the band to the PLCP and frame timing helpers Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 07/17] wifi: brcmsmac: move the PLCP and frame timing helpers to rate.c Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 08/17] wifi: brcm80211: move the rate helpers of brcmsmac to brcmutil Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 09/17] wifi: brcm80211: move the USB bootloader definitions to a shared header Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 10/17] wifi: mac80211: export ieee80211_get_bssid() again Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 11/17] wifi: bcm4323x: add the shared definitions Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 12/17] wifi: bcm4323x: add the USB transport and firmware setup Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 13/17] wifi: bcm4323x: add the receive path Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 14/17] wifi: bcm4323x: add the transmit path Ragul Balaji
2026-10-26 5:36 ` [RFC PATCH wireless-next 15/17] wifi: bcm4323x: add the mac80211 operations Ragul Balaji
2026-10-26 5:36 ` Ragul Balaji [this message]
2026-10-26 5:36 ` [RFC PATCH wireless-next 17/17] wifi: bcm4323x: add Kconfig, Makefile and MAINTAINERS entry Ragul Balaji
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261026053633.361454-17-ragulbaby@gmail.com \
--to=ragulbaby@gmail.com \
--cc=arend.vanspriel@broadcom.com \
--cc=brcm80211-dev-list.pdl@broadcom.com \
--cc=brcm80211@lists.linux.dev \
--cc=hjf3108@gmail.com \
--cc=johannes@sipsolutions.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox