Linux wireless drivers development
 help / color / mirror / Atom feed
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


  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