From 53378dac8dc33e3fd5f07d60bd7a5f8258ac7a20 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Apr 2017 11:34:57 -0600 Subject: [PATCH] dm: led: Add support for blinking LEDs Allow LEDs to be blinked if the driver supports it. Enable this for sandbox so that the tests run. Signed-off-by: Simon Glass Reviewed-by: Ziping Chen --- configs/sandbox_defconfig | 1 + configs/sandbox_noblk_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + drivers/led/Kconfig | 9 +++++++++ drivers/led/led-uclass.c | 12 +++++++++++ include/led.h | 35 +++++++++++++++++++++++++++++++++ test/dm/led.c | 24 ++++++++++++++++++++++ 7 files changed, 83 insertions(+) diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 7f3f5ac809..9814ea3b81 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -83,6 +83,7 @@ CONFIG_I2C_ARB_GPIO_CHALLENGE=y CONFIG_CROS_EC_KEYB=y CONFIG_I8042_KEYB=y CONFIG_LED=y +CONFIG_LED_BLINK=y CONFIG_LED_GPIO=y CONFIG_DM_MAILBOX=y CONFIG_SANDBOX_MBOX=y diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig index 3f8e70d523..bba744332c 100644 --- a/configs/sandbox_noblk_defconfig +++ b/configs/sandbox_noblk_defconfig @@ -92,6 +92,7 @@ CONFIG_I2C_ARB_GPIO_CHALLENGE=y CONFIG_CROS_EC_KEYB=y CONFIG_I8042_KEYB=y CONFIG_LED=y +CONFIG_LED_BLINK=y CONFIG_LED_GPIO=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index ade67143b1..6fe21254fd 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -94,6 +94,7 @@ CONFIG_I2C_ARB_GPIO_CHALLENGE=y CONFIG_CROS_EC_KEYB=y CONFIG_I8042_KEYB=y CONFIG_LED=y +CONFIG_LED_BLINK=y CONFIG_LED_GPIO=y CONFIG_DM_MAILBOX=y CONFIG_SANDBOX_MBOX=y diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 0ef45bc06a..309372ab56 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -9,6 +9,15 @@ config LED can provide access to board-specific LEDs. Use of the device tree for configuration is encouraged. +config LED_BLINK + bool "Support LED blinking" + depends on LED + help + Some drivers can support automatic blinking of LEDs with a given + period, without needing timers or extra code to handle the timing. + This option enables support for this which adds slightly to the + code size. + config SPL_LED bool "Enable LED support in SPL" depends on SPL && SPL_DM diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index ea5fbabadf..78ab76050d 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -52,6 +52,18 @@ enum led_state_t led_get_state(struct udevice *dev) return ops->get_state(dev); } +#ifdef CONFIG_LED_BLINK +int led_set_period(struct udevice *dev, int period_ms) +{ + struct led_ops *ops = led_get_ops(dev); + + if (!ops->set_period) + return -ENOSYS; + + return ops->set_period(dev, period_ms); +} +#endif + UCLASS_DRIVER(led) = { .id = UCLASS_LED, .name = "led", diff --git a/include/led.h b/include/led.h index 8c107e28e7..c67af22591 100644 --- a/include/led.h +++ b/include/led.h @@ -17,10 +17,22 @@ struct led_uc_plat { const char *label; }; +/** + * struct led_uc_priv - Private data the uclass stores about each device + * + * @period_ms: Flash period in milliseconds + */ +struct led_uc_priv { + int period_ms; +}; + enum led_state_t { LEDST_OFF = 0, LEDST_ON = 1, LEDST_TOGGLE, +#ifdef CONFIG_LED_BLINK + LEDST_BLINK, +#endif LEDST_COUNT, }; @@ -42,6 +54,20 @@ struct led_ops { * @return LED state led_state_t, or -ve on error */ enum led_state_t (*get_state)(struct udevice *dev); + +#ifdef CONFIG_LED_BLINK + /** + * led_set_period() - set the blink period of an LED + * + * Thie records the period if supported, or returns -ENOSYS if not. + * To start the LED blinking, use set_state(). + * + * @dev: LED device to change + * @period_ms: LED blink period in milliseconds + * @return 0 if OK, -ve on error + */ + int (*set_period)(struct udevice *dev, int period_ms); +#endif }; #define led_get_ops(dev) ((struct led_ops *)(dev)->driver->ops) @@ -72,4 +98,13 @@ int led_set_state(struct udevice *dev, enum led_state_t state); */ enum led_state_t led_get_state(struct udevice *dev); +/** + * led_set_period() - set the blink period of an LED + * + * @dev: LED device to change + * @period_ms: LED blink period in milliseconds + * @return 0 if OK, -ve on error + */ +int led_set_period(struct udevice *dev, int period_ms); + #endif diff --git a/test/dm/led.c b/test/dm/led.c index 2cc24127e2..fde700be38 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -98,3 +98,27 @@ static int dm_test_led_label(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_led_label, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test LED blinking */ +#ifdef CONFIG_LED_BLINK +static int dm_test_led_blink(struct unit_test_state *uts) +{ + const int offset = 1; + struct udevice *dev, *gpio; + + /* + * Check that we get an error when trying to blink an LED, since it is + * not supported by the GPIO LED driver. + */ + ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev)); + ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio)); + ut_asserteq(0, sandbox_gpio_get_value(gpio, offset)); + ut_asserteq(-ENOSYS, led_set_state(dev, LEDST_BLINK)); + ut_asserteq(0, sandbox_gpio_get_value(gpio, offset)); + ut_asserteq(LEDST_OFF, led_get_state(dev)); + ut_asserteq(-ENOSYS, led_set_period(dev, 100)); + + return 0; +} +DM_TEST(dm_test_led_blink, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +#endif -- 2.39.5