[PATCH 1/9] led: led_gpio: add support for SW Blink

Christian Marangi ansuelsmth at gmail.com
Mon Jun 24 23:46:11 CEST 2024


Add support for GPIO-connected LEDs to make use of Cyclic API to
simulate Blink by software.

A new Kconfig is introduced to enable this, CONFIG_LED_GPIO_SW_BLINK.

Signed-off-by: Christian Marangi <ansuelsmth at gmail.com>
---
 drivers/led/Kconfig    |  9 +++++++
 drivers/led/led_gpio.c | 56 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig
index 9837960198d..13d6eb40cea 100644
--- a/drivers/led/Kconfig
+++ b/drivers/led/Kconfig
@@ -91,6 +91,15 @@ config LED_GPIO
 	  The GPIO driver must used driver model. LEDs are configured using
 	  the device tree.
 
+config LED_GPIO_SW_BLINK
+	bool "LED support for GPIO software blink"
+	depends on LED_GPIO
+	select CYCLIC
+	select LED_BLINK
+	help
+	  Enable support for GPIO-connected LEDs to make use of Cyclic API
+	  to simulate LED blink by software.
+
 config SPL_LED_GPIO
 	bool "LED support for GPIO-connected LEDs in SPL"
         depends on SPL_LED && SPL_DM_GPIO
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c
index ce22fb49f2a..20a6c149e4a 100644
--- a/drivers/led/led_gpio.c
+++ b/drivers/led/led_gpio.c
@@ -4,6 +4,7 @@
  * Written by Simon Glass <sjg at chromium.org>
  */
 
+#include <cyclic.h>
 #include <dm.h>
 #include <errno.h>
 #include <led.h>
@@ -13,13 +14,60 @@
 
 struct led_gpio_priv {
 	struct gpio_desc gpio;
+#ifdef CONFIG_LED_GPIO_SW_BLINK
+	bool sw_blink;
+	struct cyclic_info cyclic;
+#endif
 };
 
+#ifdef CONFIG_LED_GPIO_SW_BLINK
+static void gpio_led_toggle(struct cyclic_info *ctx)
+{
+	struct led_gpio_priv *priv = container_of(ctx, struct led_gpio_priv, cyclic);
+	struct gpio_desc *gpio = &priv->gpio;
+	int state;
+
+	state = dm_gpio_get_value(gpio);
+	if (state < 0) {
+		printf("Error getting value for GPIO %d\n",
+		       gpio->offset);
+		return;
+	}
+
+	dm_gpio_set_value(gpio, !state);
+}
+
+static int gpio_led_set_period(struct udevice *dev, int period_ms)
+{
+	struct led_gpio_priv *priv = dev_get_priv(dev);
+	char cyclic_name[16];
+
+	if (priv->sw_blink)
+		cyclic_unregister(&priv->cyclic);
+
+	snprintf(cyclic_name, sizeof(cyclic_name),
+		 "gpio_cyclic%u", priv->gpio.offset);
+	cyclic_register(&priv->cyclic, gpio_led_toggle,
+			period_ms * 500, cyclic_name);
+
+	/* Init the LED on */
+	dm_gpio_set_value(&priv->gpio, LEDST_ON);
+
+	priv->sw_blink = true;
+	return 0;
+}
+#endif
+
 static int gpio_led_set_state(struct udevice *dev, enum led_state_t state)
 {
 	struct led_gpio_priv *priv = dev_get_priv(dev);
 	int ret;
 
+#ifdef CONFIG_LED_GPIO_SW_BLINK
+	if (priv->sw_blink)
+		cyclic_unregister(&priv->cyclic);
+#endif
+
 	if (!dm_gpio_is_valid(&priv->gpio))
 		return -EREMOTEIO;
 	switch (state) {
@@ -50,6 +98,11 @@ static enum led_state_t gpio_led_get_state(struct udevice *dev)
 	if (ret < 0)
 		return ret;
 
+#ifdef CONFIG_LED_GPIO_SW_BLINK
+	if (priv->sw_blink)
+		return LEDST_BLINK;
+#endif
+
 	return ret ? LEDST_ON : LEDST_OFF;
 }
 
@@ -84,6 +137,9 @@ static int led_gpio_bind(struct udevice *parent)
 static const struct led_ops gpio_led_ops = {
 	.set_state	= gpio_led_set_state,
 	.get_state	= gpio_led_get_state,
+#ifdef CONFIG_LED_GPIO_SW_BLINK
+	.set_period	= gpio_led_set_period,
+#endif
 };
 
 U_BOOT_DRIVER(led_gpio) = {
-- 
2.45.1



More information about the U-Boot mailing list