
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@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@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) = {