[U-Boot] [PATCH v2 0/9] dm: led: Expand the LED interface and add a command

The LED interface for driver model is a little primitive. This series expands it to match the legacy interface and adds a command to match.
Changes in v2: - Add new patch with blank line in the Kconfig file - Drop the explicit assignment to LEDST_TOGGLE - Control this feature via a new CONFIG_LED_BLINK option
Simon Glass (9): sandbox: Add some test LEDs dm: led: Add a missing blank line in the Kconfig file dm: led: Rename struct led_uclass_plat dm: led: Adjust the LED uclass dm: led: Add support for getting the state of an LED dm: led: Support toggling LEDs dm: led: Add support for blinking LEDs led: Mark existing driver as legacy dm: led: Add a new 'led' command
arch/sandbox/dts/sandbox.dts | 14 +++ cmd/Kconfig | 9 ++ cmd/Makefile | 3 +- cmd/led.c | 262 +++++++++++++++++----------------------- cmd/legacy_led.c | 187 ++++++++++++++++++++++++++++ configs/sandbox_defconfig | 1 + configs/sandbox_noblk_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + drivers/led/Kconfig | 10 ++ drivers/led/led-uclass.c | 32 ++++- drivers/led/led_gpio.c | 39 +++++- include/led.h | 75 ++++++++++-- test/dm/led.c | 56 ++++++++- 13 files changed, 517 insertions(+), 173 deletions(-) create mode 100644 cmd/legacy_led.c

Add some LEDs to the standard sandbox device tree.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
arch/sandbox/dts/sandbox.dts | 14 ++++++++++++++ cmd/{led.c => legacy_led.c} | 0 2 files changed, 14 insertions(+) rename cmd/{led.c => legacy_led.c} (100%)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 20614646f7..40f423da25 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -123,6 +123,20 @@ yres = <768>; };
+ leds { + compatible = "gpio-leds"; + + iracibble { + gpios = <&gpio_a 1 0>; + label = "sandbox:red"; + }; + + martinet { + gpios = <&gpio_a 2 0>; + label = "sandbox:green"; + }; + }; + pci: pci-controller { compatible = "sandbox,pci"; device_type = "pci"; diff --git a/cmd/led.c b/cmd/legacy_led.c similarity index 100% rename from cmd/led.c rename to cmd/legacy_led.c

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
Add some LEDs to the standard sandbox device tree.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
arch/sandbox/dts/sandbox.dts | 14 ++++++++++++++ cmd/{led.c => legacy_led.c} | 0 2 files changed, 14 insertions(+) rename cmd/{led.c => legacy_led.c} (100%)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 20614646f7..40f423da25 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -123,6 +123,20 @@ yres = <768>; };
leds {
compatible = "gpio-leds";
iracibble {
gpios = <&gpio_a 1 0>;
label = "sandbox:red";
};
martinet {
gpios = <&gpio_a 2 0>;
label = "sandbox:green";
};
};
pci: pci-controller { compatible = "sandbox,pci"; device_type = "pci";
diff --git a/cmd/led.c b/cmd/legacy_led.c similarity index 100% rename from cmd/led.c rename to cmd/legacy_led.c -- 2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:51, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
Add some LEDs to the standard sandbox device tree.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
arch/sandbox/dts/sandbox.dts | 14 ++++++++++++++ cmd/{led.c => legacy_led.c} | 0 2 files changed, 14 insertions(+) rename cmd/{led.c => legacy_led.c} (100%)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 20614646f7..40f423da25 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -123,6 +123,20 @@ yres = <768>; };
leds {
compatible = "gpio-leds";
iracibble {
gpios = <&gpio_a 1 0>;
label = "sandbox:red";
};
martinet {
gpios = <&gpio_a 2 0>;
label = "sandbox:green";
};
};
pci: pci-controller { compatible = "sandbox,pci"; device_type = "pci";
diff --git a/cmd/led.c b/cmd/legacy_led.c similarity index 100% rename from cmd/led.c rename to cmd/legacy_led.c -- 2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com
Applied to u-boot-dm.

There should be a blank line between each option. Add one before LED_GPIO.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Add new patch with blank line in the Kconfig file
drivers/led/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 609b1fa3fe..0ef45bc06a 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -17,6 +17,7 @@ config SPL_LED If this is acceptable and you have a need to use LEDs in SPL, enable this option. You will need to enable device tree in SPL for this to work. + config LED_GPIO bool "LED support for GPIO-connected LEDs" depends on LED && DM_GPIO

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
There should be a blank line between each option. Add one before LED_GPIO.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch with blank line in the Kconfig file
drivers/led/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 609b1fa3fe..0ef45bc06a 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -17,6 +17,7 @@ config SPL_LED If this is acceptable and you have a need to use LEDs in SPL, enable this option. You will need to enable device tree in SPL for this to work.
config LED_GPIO bool "LED support for GPIO-connected LEDs" depends on LED && DM_GPIO -- 2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:51, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
There should be a blank line between each option. Add one before LED_GPIO.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch with blank line in the Kconfig file
drivers/led/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 609b1fa3fe..0ef45bc06a 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -17,6 +17,7 @@ config SPL_LED If this is acceptable and you have a need to use LEDs in SPL, enable this option. You will need to enable device tree in SPL for this to work.
config LED_GPIO bool "LED support for GPIO-connected LEDs" depends on LED && DM_GPIO -- 2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

These structures are normally named with 'uc' instead of 'uclass'. Change this one for consistency.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
drivers/led/led-uclass.c | 4 ++-- drivers/led/led_gpio.c | 4 ++-- include/led.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index 784ac870e2..ca4f98c0b3 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -22,7 +22,7 @@ int led_get_by_label(const char *label, struct udevice **devp) if (ret) return ret; uclass_foreach_dev(dev, uc) { - struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev); + struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev);
/* Ignore the top-level LED node */ if (uc_plat->label && !strcmp(label, uc_plat->label)) @@ -45,5 +45,5 @@ int led_set_on(struct udevice *dev, int on) UCLASS_DRIVER(led) = { .id = UCLASS_LED, .name = "led", - .per_device_platdata_auto_alloc_size = sizeof(struct led_uclass_plat), + .per_device_platdata_auto_alloc_size = sizeof(struct led_uc_plat), }; diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index 5b119903f5..97b5da35cd 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -30,7 +30,7 @@ static int gpio_led_set_on(struct udevice *dev, int on)
static int led_gpio_probe(struct udevice *dev) { - struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev); + struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); struct led_gpio_priv *priv = dev_get_priv(dev);
/* Ignore the top-level LED node */ @@ -65,7 +65,7 @@ static int led_gpio_bind(struct udevice *parent) for (node = fdt_first_subnode(blob, dev_of_offset(parent)); node > 0; node = fdt_next_subnode(blob, node)) { - struct led_uclass_plat *uc_plat; + struct led_uc_plat *uc_plat; const char *label;
label = fdt_getprop(blob, node, "label", NULL); diff --git a/include/led.h b/include/led.h index b929d0ca3c..a856b3d9ff 100644 --- a/include/led.h +++ b/include/led.h @@ -9,11 +9,11 @@ #define __LED_H
/** - * struct led_uclass_plat - Platform data the uclass stores about each device + * struct led_uc_plat - Platform data the uclass stores about each device * * @label: LED label */ -struct led_uclass_plat { +struct led_uc_plat { const char *label; };

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
These structures are normally named with 'uc' instead of 'uclass'. Change this one for consistency.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
drivers/led/led-uclass.c | 4 ++-- drivers/led/led_gpio.c | 4 ++-- include/led.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index 784ac870e2..ca4f98c0b3 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -22,7 +22,7 @@ int led_get_by_label(const char *label, struct udevice **devp) if (ret) return ret; uclass_foreach_dev(dev, uc) {
struct led_uclass_plat *uc_plat =
dev_get_uclass_platdata(dev);
struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); /* Ignore the top-level LED node */ if (uc_plat->label && !strcmp(label, uc_plat->label))
@@ -45,5 +45,5 @@ int led_set_on(struct udevice *dev, int on) UCLASS_DRIVER(led) = { .id = UCLASS_LED, .name = "led",
.per_device_platdata_auto_alloc_size = sizeof(struct
led_uclass_plat),
.per_device_platdata_auto_alloc_size = sizeof(struct led_uc_plat),
}; diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index 5b119903f5..97b5da35cd 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -30,7 +30,7 @@ static int gpio_led_set_on(struct udevice *dev, int on)
static int led_gpio_probe(struct udevice *dev) {
struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev);
struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); struct led_gpio_priv *priv = dev_get_priv(dev); /* Ignore the top-level LED node */
@@ -65,7 +65,7 @@ static int led_gpio_bind(struct udevice *parent) for (node = fdt_first_subnode(blob, dev_of_offset(parent)); node > 0; node = fdt_next_subnode(blob, node)) {
struct led_uclass_plat *uc_plat;
struct led_uc_plat *uc_plat; const char *label; label = fdt_getprop(blob, node, "label", NULL);
diff --git a/include/led.h b/include/led.h index b929d0ca3c..a856b3d9ff 100644 --- a/include/led.h +++ b/include/led.h @@ -9,11 +9,11 @@ #define __LED_H
/**
- struct led_uclass_plat - Platform data the uclass stores about each
device
*/
- struct led_uc_plat - Platform data the uclass stores about each device
- @label: LED label
-struct led_uclass_plat { +struct led_uc_plat { const char *label; };
-- 2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:51, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
These structures are normally named with 'uc' instead of 'uclass'. Change this one for consistency.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
drivers/led/led-uclass.c | 4 ++-- drivers/led/led_gpio.c | 4 ++-- include/led.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-)
Reviewed-by: Ziping Chen techping.chan@gmail.com
Applied to u-boot-dm

At present this is very simple, supporting only on and off. We want to also support toggling and blinking. As a first step, change the name of the main method and use an enum to indicate the state.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
drivers/led/led-uclass.c | 6 +++--- drivers/led/led_gpio.c | 6 +++--- include/led.h | 19 +++++++++++++------ test/dm/led.c | 5 +++-- 4 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index ca4f98c0b3..b30346913b 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -32,14 +32,14 @@ int led_get_by_label(const char *label, struct udevice **devp) return -ENODEV; }
-int led_set_on(struct udevice *dev, int on) +int led_set_state(struct udevice *dev, enum led_state_t state) { struct led_ops *ops = led_get_ops(dev);
- if (!ops->set_on) + if (!ops->set_state) return -ENOSYS;
- return ops->set_on(dev, on); + return ops->set_state(dev, state); }
UCLASS_DRIVER(led) = { diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index 97b5da35cd..af8133d3c7 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -18,14 +18,14 @@ struct led_gpio_priv { struct gpio_desc gpio; };
-static int gpio_led_set_on(struct udevice *dev, int on) +static int gpio_led_set_state(struct udevice *dev, enum led_state_t state) { struct led_gpio_priv *priv = dev_get_priv(dev);
if (!dm_gpio_is_valid(&priv->gpio)) return -EREMOTEIO;
- return dm_gpio_set_value(&priv->gpio, on); + return dm_gpio_set_value(&priv->gpio, state); }
static int led_gpio_probe(struct udevice *dev) @@ -87,7 +87,7 @@ static int led_gpio_bind(struct udevice *parent) }
static const struct led_ops gpio_led_ops = { - .set_on = gpio_led_set_on, + .set_state = gpio_led_set_state, };
static const struct udevice_id led_gpio_ids[] = { diff --git a/include/led.h b/include/led.h index a856b3d9ff..8af87ea8ea 100644 --- a/include/led.h +++ b/include/led.h @@ -17,15 +17,22 @@ struct led_uc_plat { const char *label; };
+enum led_state_t { + LEDST_OFF = 0, + LEDST_ON = 1, + + LEDST_COUNT, +}; + struct led_ops { /** - * set_on() - set the state of an LED + * set_state() - set the state of an LED * * @dev: LED device to change - * @on: 1 to turn the LED on, 0 to turn it off + * @state: LED state to set * @return 0 if OK, -ve on error */ - int (*set_on)(struct udevice *dev, int on); + int (*set_state)(struct udevice *dev, enum led_state_t state); };
#define led_get_ops(dev) ((struct led_ops *)(dev)->driver->ops) @@ -40,12 +47,12 @@ struct led_ops { int led_get_by_label(const char *label, struct udevice **devp);
/** - * led_set_on() - set the state of an LED + * led_set_state() - set the state of an LED * * @dev: LED device to change - * @on: 1 to turn the LED on, 0 to turn it off + * @state: LED state to set * @return 0 if OK, -ve on error */ -int led_set_on(struct udevice *dev, int on); +int led_set_state(struct udevice *dev, enum led_state_t state);
#endif diff --git a/test/dm/led.c b/test/dm/led.c index 8ee075cf1c..ebb9b46584 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -41,9 +41,10 @@ static int dm_test_led_gpio(struct unit_test_state *uts) 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)); - led_set_on(dev, 1); + ut_assertok(led_set_state(dev, LEDST_ON)); ut_asserteq(1, sandbox_gpio_get_value(gpio, offset)); - led_set_on(dev, 0); + + ut_assertok(led_set_state(dev, LEDST_OFF)); ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
return 0;

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
At present this is very simple, supporting only on and off. We want to also support toggling and blinking. As a first step, change the name of the main method and use an enum to indicate the state.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
drivers/led/led-uclass.c | 6 +++--- drivers/led/led_gpio.c | 6 +++--- include/led.h | 19 +++++++++++++------ test/dm/led.c | 5 +++-- 4 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index ca4f98c0b3..b30346913b 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -32,14 +32,14 @@ int led_get_by_label(const char *label, struct udevice **devp) return -ENODEV; }
-int led_set_on(struct udevice *dev, int on) +int led_set_state(struct udevice *dev, enum led_state_t state) { struct led_ops *ops = led_get_ops(dev);
if (!ops->set_on)
if (!ops->set_state) return -ENOSYS;
return ops->set_on(dev, on);
return ops->set_state(dev, state);
}
UCLASS_DRIVER(led) = { diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index 97b5da35cd..af8133d3c7 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -18,14 +18,14 @@ struct led_gpio_priv { struct gpio_desc gpio; };
-static int gpio_led_set_on(struct udevice *dev, int on) +static int gpio_led_set_state(struct udevice *dev, enum led_state_t state) { struct led_gpio_priv *priv = dev_get_priv(dev);
if (!dm_gpio_is_valid(&priv->gpio)) return -EREMOTEIO;
return dm_gpio_set_value(&priv->gpio, on);
return dm_gpio_set_value(&priv->gpio, state);
}
static int led_gpio_probe(struct udevice *dev) @@ -87,7 +87,7 @@ static int led_gpio_bind(struct udevice *parent) }
static const struct led_ops gpio_led_ops = {
.set_on = gpio_led_set_on,
.set_state = gpio_led_set_state,
};
static const struct udevice_id led_gpio_ids[] = { diff --git a/include/led.h b/include/led.h index a856b3d9ff..8af87ea8ea 100644 --- a/include/led.h +++ b/include/led.h @@ -17,15 +17,22 @@ struct led_uc_plat { const char *label; };
+enum led_state_t {
LEDST_OFF = 0,
LEDST_ON = 1,
LEDST_COUNT,
+};
struct led_ops { /**
* set_on() - set the state of an LED
* set_state() - set the state of an LED * * @dev: LED device to change
* @on: 1 to turn the LED on, 0 to turn it off
* @state: LED state to set * @return 0 if OK, -ve on error */
int (*set_on)(struct udevice *dev, int on);
int (*set_state)(struct udevice *dev, enum led_state_t state);
};
#define led_get_ops(dev) ((struct led_ops *)(dev)->driver->ops) @@ -40,12 +47,12 @@ struct led_ops { int led_get_by_label(const char *label, struct udevice **devp);
/**
- led_set_on() - set the state of an LED
- led_set_state() - set the state of an LED
- @dev: LED device to change
- @on: 1 to turn the LED on, 0 to turn it off
*/
- @state: LED state to set
- @return 0 if OK, -ve on error
-int led_set_on(struct udevice *dev, int on); +int led_set_state(struct udevice *dev, enum led_state_t state);
#endif diff --git a/test/dm/led.c b/test/dm/led.c index 8ee075cf1c..ebb9b46584 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -41,9 +41,10 @@ static int dm_test_led_gpio(struct unit_test_state *uts) 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));
led_set_on(dev, 1);
ut_assertok(led_set_state(dev, LEDST_ON)); ut_asserteq(1, sandbox_gpio_get_value(gpio, offset));
led_set_on(dev, 0);
ut_assertok(led_set_state(dev, LEDST_OFF)); ut_asserteq(0, sandbox_gpio_get_value(gpio, offset)); return 0;
-- 2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:52, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
At present this is very simple, supporting only on and off. We want to also support toggling and blinking. As a first step, change the name of the main method and use an enum to indicate the state.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
drivers/led/led-uclass.c | 6 +++--- drivers/led/led_gpio.c | 6 +++--- include/led.h | 19 +++++++++++++------ test/dm/led.c | 5 +++-- 4 files changed, 22 insertions(+), 14 deletions(-)
Reviewed-by: Ziping Chen techping.chan@gmail.com
Applied to u-boot-dm

It is useful to be able to read the LED as well as write it. Add this to the uclass and update the GPIO driver.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
drivers/led/led-uclass.c | 10 ++++++++++ drivers/led/led_gpio.c | 22 ++++++++++++++++++++++ include/led.h | 16 ++++++++++++++++ test/dm/led.c | 2 ++ 4 files changed, 50 insertions(+)
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index b30346913b..ea5fbabadf 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -42,6 +42,16 @@ int led_set_state(struct udevice *dev, enum led_state_t state) return ops->set_state(dev, state); }
+enum led_state_t led_get_state(struct udevice *dev) +{ + struct led_ops *ops = led_get_ops(dev); + + if (!ops->get_state) + return -ENOSYS; + + return ops->get_state(dev); +} + UCLASS_DRIVER(led) = { .id = UCLASS_LED, .name = "led", diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index af8133d3c7..789d15600f 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -24,10 +24,31 @@ static int gpio_led_set_state(struct udevice *dev, enum led_state_t state)
if (!dm_gpio_is_valid(&priv->gpio)) return -EREMOTEIO; + switch (state) { + case LEDST_OFF: + case LEDST_ON: + break; + default: + return -ENOSYS; + }
return dm_gpio_set_value(&priv->gpio, state); }
+static enum led_state_t gpio_led_get_state(struct udevice *dev) +{ + struct led_gpio_priv *priv = dev_get_priv(dev); + int ret; + + if (!dm_gpio_is_valid(&priv->gpio)) + return -EREMOTEIO; + ret = dm_gpio_get_value(&priv->gpio); + if (ret < 0) + return ret; + + return ret ? LEDST_ON : LEDST_OFF; +} + static int led_gpio_probe(struct udevice *dev) { struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); @@ -88,6 +109,7 @@ 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, };
static const struct udevice_id led_gpio_ids[] = { diff --git a/include/led.h b/include/led.h index 8af87ea8ea..bbab4d14c9 100644 --- a/include/led.h +++ b/include/led.h @@ -33,6 +33,14 @@ struct led_ops { * @return 0 if OK, -ve on error */ int (*set_state)(struct udevice *dev, enum led_state_t state); + + /** + * led_get_state() - get the state of an LED + * + * @dev: LED device to change + * @return LED state led_state_t, or -ve on error + */ + enum led_state_t (*get_state)(struct udevice *dev); };
#define led_get_ops(dev) ((struct led_ops *)(dev)->driver->ops) @@ -55,4 +63,12 @@ int led_get_by_label(const char *label, struct udevice **devp); */ int led_set_state(struct udevice *dev, enum led_state_t state);
+/** + * led_get_state() - get the state of an LED + * + * @dev: LED device to change + * @return LED state led_state_t, or -ve on error + */ +enum led_state_t led_get_state(struct udevice *dev); + #endif diff --git a/test/dm/led.c b/test/dm/led.c index ebb9b46584..68aa39bd4d 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -43,9 +43,11 @@ static int dm_test_led_gpio(struct unit_test_state *uts) ut_asserteq(0, sandbox_gpio_get_value(gpio, offset)); ut_assertok(led_set_state(dev, LEDST_ON)); ut_asserteq(1, sandbox_gpio_get_value(gpio, offset)); + ut_asserteq(LEDST_ON, led_get_state(dev));
ut_assertok(led_set_state(dev, LEDST_OFF)); ut_asserteq(0, sandbox_gpio_get_value(gpio, offset)); + ut_asserteq(LEDST_OFF, led_get_state(dev));
return 0; }

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
It is useful to be able to read the LED as well as write it. Add this to the uclass and update the GPIO driver.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
drivers/led/led-uclass.c | 10 ++++++++++ drivers/led/led_gpio.c | 22 ++++++++++++++++++++++ include/led.h | 16 ++++++++++++++++ test/dm/led.c | 2 ++ 4 files changed, 50 insertions(+)
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index b30346913b..ea5fbabadf 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -42,6 +42,16 @@ int led_set_state(struct udevice *dev, enum led_state_t state) return ops->set_state(dev, state); }
+enum led_state_t led_get_state(struct udevice *dev) +{
struct led_ops *ops = led_get_ops(dev);
if (!ops->get_state)
return -ENOSYS;
return ops->get_state(dev);
+}
UCLASS_DRIVER(led) = { .id = UCLASS_LED, .name = "led", diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index af8133d3c7..789d15600f 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -24,10 +24,31 @@ static int gpio_led_set_state(struct udevice *dev, enum led_state_t state)
if (!dm_gpio_is_valid(&priv->gpio)) return -EREMOTEIO;
switch (state) {
case LEDST_OFF:
case LEDST_ON:
break;
default:
return -ENOSYS;
} return dm_gpio_set_value(&priv->gpio, state);
}
+static enum led_state_t gpio_led_get_state(struct udevice *dev) +{
struct led_gpio_priv *priv = dev_get_priv(dev);
int ret;
if (!dm_gpio_is_valid(&priv->gpio))
return -EREMOTEIO;
ret = dm_gpio_get_value(&priv->gpio);
if (ret < 0)
return ret;
return ret ? LEDST_ON : LEDST_OFF;
+}
static int led_gpio_probe(struct udevice *dev) { struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); @@ -88,6 +109,7 @@ 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,
};
static const struct udevice_id led_gpio_ids[] = { diff --git a/include/led.h b/include/led.h index 8af87ea8ea..bbab4d14c9 100644 --- a/include/led.h +++ b/include/led.h @@ -33,6 +33,14 @@ struct led_ops { * @return 0 if OK, -ve on error */ int (*set_state)(struct udevice *dev, enum led_state_t state);
/**
* led_get_state() - get the state of an LED
*
* @dev: LED device to change
* @return LED state led_state_t, or -ve on error
*/
enum led_state_t (*get_state)(struct udevice *dev);
};
#define led_get_ops(dev) ((struct led_ops *)(dev)->driver->ops) @@ -55,4 +63,12 @@ int led_get_by_label(const char *label, struct udevice **devp); */ int led_set_state(struct udevice *dev, enum led_state_t state);
+/**
- led_get_state() - get the state of an LED
- @dev: LED device to change
- @return LED state led_state_t, or -ve on error
- */
+enum led_state_t led_get_state(struct udevice *dev);
#endif diff --git a/test/dm/led.c b/test/dm/led.c index ebb9b46584..68aa39bd4d 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -43,9 +43,11 @@ static int dm_test_led_gpio(struct unit_test_state *uts) ut_asserteq(0, sandbox_gpio_get_value(gpio, offset)); ut_assertok(led_set_state(dev, LEDST_ON)); ut_asserteq(1, sandbox_gpio_get_value(gpio, offset));
ut_asserteq(LEDST_ON, led_get_state(dev)); ut_assertok(led_set_state(dev, LEDST_OFF)); ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
ut_asserteq(LEDST_OFF, led_get_state(dev)); return 0;
}
2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:52, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
It is useful to be able to read the LED as well as write it. Add this to the uclass and update the GPIO driver.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
drivers/led/led-uclass.c | 10 ++++++++++ drivers/led/led_gpio.c | 22 ++++++++++++++++++++++ include/led.h | 16 ++++++++++++++++ test/dm/led.c | 2 ++ 4 files changed, 50 insertions(+)
Reviewed-by: Ziping Chen techping.chan@gmail.com
Applied to u-boot-dm

Add support for toggling an LED into the uclass interface. This can be efficiently implemented by the driver.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Drop the explicit assignment to LEDST_TOGGLE
drivers/led/led_gpio.c | 7 +++++++ include/led.h | 1 + test/dm/led.c | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+)
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index 789d15600f..4106ecb679 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -21,6 +21,7 @@ struct led_gpio_priv { 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;
if (!dm_gpio_is_valid(&priv->gpio)) return -EREMOTEIO; @@ -28,6 +29,12 @@ static int gpio_led_set_state(struct udevice *dev, enum led_state_t state) case LEDST_OFF: case LEDST_ON: break; + case LEDST_TOGGLE: + ret = dm_gpio_get_value(&priv->gpio); + if (ret < 0) + return ret; + state = !ret; + break; default: return -ENOSYS; } diff --git a/include/led.h b/include/led.h index bbab4d14c9..8c107e28e7 100644 --- a/include/led.h +++ b/include/led.h @@ -20,6 +20,7 @@ struct led_uc_plat { enum led_state_t { LEDST_OFF = 0, LEDST_ON = 1, + LEDST_TOGGLE,
LEDST_COUNT, }; diff --git a/test/dm/led.c b/test/dm/led.c index 68aa39bd4d..2cc24127e2 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -53,6 +53,31 @@ static int dm_test_led_gpio(struct unit_test_state *uts) } DM_TEST(dm_test_led_gpio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/* Test that we can toggle LEDs */ +static int dm_test_led_toggle(struct unit_test_state *uts) +{ + const int offset = 1; + struct udevice *dev, *gpio; + + /* + * Check that we can manipulate an LED. LED 1 is connected to GPIO + * bank gpio_a, offset 1. + */ + 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_assertok(led_set_state(dev, LEDST_TOGGLE)); + ut_asserteq(1, sandbox_gpio_get_value(gpio, offset)); + ut_asserteq(LEDST_ON, led_get_state(dev)); + + ut_assertok(led_set_state(dev, LEDST_TOGGLE)); + ut_asserteq(0, sandbox_gpio_get_value(gpio, offset)); + ut_asserteq(LEDST_OFF, led_get_state(dev)); + + return 0; +} +DM_TEST(dm_test_led_toggle, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + /* Test obtaining an LED by label */ static int dm_test_led_label(struct unit_test_state *uts) {

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
Add support for toggling an LED into the uclass interface. This can be efficiently implemented by the driver.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Drop the explicit assignment to LEDST_TOGGLE
drivers/led/led_gpio.c | 7 +++++++ include/led.h | 1 + test/dm/led.c | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+)
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index 789d15600f..4106ecb679 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -21,6 +21,7 @@ struct led_gpio_priv { 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; if (!dm_gpio_is_valid(&priv->gpio)) return -EREMOTEIO;
@@ -28,6 +29,12 @@ static int gpio_led_set_state(struct udevice *dev, enum led_state_t state) case LEDST_OFF: case LEDST_ON: break;
case LEDST_TOGGLE:
ret = dm_gpio_get_value(&priv->gpio);
if (ret < 0)
return ret;
state = !ret;
break; default: return -ENOSYS; }
diff --git a/include/led.h b/include/led.h index bbab4d14c9..8c107e28e7 100644 --- a/include/led.h +++ b/include/led.h @@ -20,6 +20,7 @@ struct led_uc_plat { enum led_state_t { LEDST_OFF = 0, LEDST_ON = 1,
LEDST_TOGGLE, LEDST_COUNT,
}; diff --git a/test/dm/led.c b/test/dm/led.c index 68aa39bd4d..2cc24127e2 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -53,6 +53,31 @@ static int dm_test_led_gpio(struct unit_test_state *uts) } DM_TEST(dm_test_led_gpio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/* Test that we can toggle LEDs */ +static int dm_test_led_toggle(struct unit_test_state *uts) +{
const int offset = 1;
struct udevice *dev, *gpio;
/*
* Check that we can manipulate an LED. LED 1 is connected to GPIO
* bank gpio_a, offset 1.
*/
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_assertok(led_set_state(dev, LEDST_TOGGLE));
ut_asserteq(1, sandbox_gpio_get_value(gpio, offset));
ut_asserteq(LEDST_ON, led_get_state(dev));
ut_assertok(led_set_state(dev, LEDST_TOGGLE));
ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
ut_asserteq(LEDST_OFF, led_get_state(dev));
return 0;
+} +DM_TEST(dm_test_led_toggle, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Test obtaining an LED by label */ static int dm_test_led_label(struct unit_test_state *uts) { -- 2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:52, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
Add support for toggling an LED into the uclass interface. This can be efficiently implemented by the driver.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Drop the explicit assignment to LEDST_TOGGLE
drivers/led/led_gpio.c | 7 +++++++ include/led.h | 1 + test/dm/led.c | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+)
Reviewed-by: Ziping Chen techping.chan@gmail.com
Applied to u-boot-dm

Allow LEDs to be blinked if the driver supports it. Enable this for sandbox so that the tests run.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Control this feature via a new CONFIG_LED_BLINK option
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

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
Allow LEDs to be blinked if the driver supports it. Enable this for sandbox so that the tests run.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Control this feature via a new CONFIG_LED_BLINK option
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.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:52, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
Allow LEDs to be blinked if the driver supports it. Enable this for sandbox so that the tests run.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Control this feature via a new CONFIG_LED_BLINK option
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(+)
Reviewed-by: Ziping Chen techping.chan@gmail.com
Applied to u-boot-dm

The existing 'led' command does not support driver model. Rename it to indicate that it is legacy code.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
cmd/Makefile | 2 +- cmd/legacy_led.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/cmd/Makefile b/cmd/Makefile index ef1406b3f8..19d450e0fb 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_CMD_ITEST) += itest.o obj-$(CONFIG_CMD_JFFS2) += jffs2.o obj-$(CONFIG_CMD_CRAMFS) += cramfs.o obj-$(CONFIG_CMD_LDRINFO) += ldrinfo.o -obj-$(CONFIG_LED_STATUS_CMD) += led.o +obj-$(CONFIG_LED_STATUS_CMD) += legacy_led.o obj-$(CONFIG_CMD_LICENSE) += license.o obj-y += load.o obj-$(CONFIG_LOGBUFFER) += log.o diff --git a/cmd/legacy_led.c b/cmd/legacy_led.c index 951a5e242f..1ec2e43e50 100644 --- a/cmd/legacy_led.c +++ b/cmd/legacy_led.c @@ -86,7 +86,7 @@ void __weak __led_blink(led_id_t mask, int freq) { }
-int do_led (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_legacy_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int i, match = 0; enum led_cmd cmd; @@ -148,7 +148,7 @@ int do_led (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) }
U_BOOT_CMD( - led, 4, 1, do_led, + led, 4, 1, do_legacy_led, "[" #ifdef CONFIG_LED_STATUS_BOARD_SPECIFIC #ifdef CONFIG_LED_STATUS0

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
The existing 'led' command does not support driver model. Rename it to indicate that it is legacy code.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
cmd/Makefile | 2 +- cmd/legacy_led.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/cmd/Makefile b/cmd/Makefile index ef1406b3f8..19d450e0fb 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_CMD_ITEST) += itest.o obj-$(CONFIG_CMD_JFFS2) += jffs2.o obj-$(CONFIG_CMD_CRAMFS) += cramfs.o obj-$(CONFIG_CMD_LDRINFO) += ldrinfo.o -obj-$(CONFIG_LED_STATUS_CMD) += led.o +obj-$(CONFIG_LED_STATUS_CMD) += legacy_led.o obj-$(CONFIG_CMD_LICENSE) += license.o obj-y += load.o obj-$(CONFIG_LOGBUFFER) += log.o diff --git a/cmd/legacy_led.c b/cmd/legacy_led.c index 951a5e242f..1ec2e43e50 100644 --- a/cmd/legacy_led.c +++ b/cmd/legacy_led.c @@ -86,7 +86,7 @@ void __weak __led_blink(led_id_t mask, int freq) { }
-int do_led (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_legacy_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int i, match = 0; enum led_cmd cmd; @@ -148,7 +148,7 @@ int do_led (cmd_tbl_t *cmdtp, int flag, int argc, char
- const argv[])
}
U_BOOT_CMD(
led, 4, 1, do_led,
led, 4, 1, do_legacy_led, "["
#ifdef CONFIG_LED_STATUS_BOARD_SPECIFIC
#ifdef CONFIG_LED_STATUS0
2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:53, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
The existing 'led' command does not support driver model. Rename it to indicate that it is legacy code.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
cmd/Makefile | 2 +- cmd/legacy_led.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
Reviewed-by: Ziping Chen techping.chan@gmail.com
Applied to u-boot-dm

When driver model is used for LEDs, provide a command to allow LED access.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: None
cmd/Kconfig | 9 ++++ cmd/Makefile | 1 + cmd/led.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 cmd/led.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 661ae7a98c..13dc46a174 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -667,6 +667,15 @@ config CMD_CACHE help Enable the "icache" and "dcache" commands
+config CMD_LED + bool "led" + default y if LED + help + Enable the 'led' command which allows for control of LEDs supported + by the board. The LEDs can be listed with 'led list' and controlled + with led on/off/togle/blink. Any LED drivers can be controlled with + this command, e.g. led_gpio. + config CMD_TIME bool "time" help diff --git a/cmd/Makefile b/cmd/Makefile index 19d450e0fb..3cb0cfde7b 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_CMD_JFFS2) += jffs2.o obj-$(CONFIG_CMD_CRAMFS) += cramfs.o obj-$(CONFIG_CMD_LDRINFO) += ldrinfo.o obj-$(CONFIG_LED_STATUS_CMD) += legacy_led.o +obj-$(CONFIG_CMD_LED) += led.o obj-$(CONFIG_CMD_LICENSE) += license.o obj-y += load.o obj-$(CONFIG_LOGBUFFER) += log.o diff --git a/cmd/led.c b/cmd/led.c new file mode 100644 index 0000000000..84173f86f2 --- /dev/null +++ b/cmd/led.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2017 Google, Inc + * Written by Simon Glass sjg@chromium.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <dm.h> +#include <led.h> +#include <dm/uclass-internal.h> + +#define LED_TOGGLE LEDST_COUNT + +static const char *const state_label[] = { + [LEDST_OFF] = "off", + [LEDST_ON] = "on", + [LEDST_TOGGLE] = "toggle", +#ifdef CONFIG_LED_BLINK + [LEDST_BLINK] = "blink", +#endif +}; + +enum led_state_t get_led_cmd(char *var) +{ + int i; + + for (i = 0; i < LEDST_COUNT; i++) { + if (!strncmp(var, state_label[i], strlen(var))) + return i; + } + + return -1; +} + +static int show_led_state(struct udevice *dev) +{ + int ret; + + ret = led_get_state(dev); + if (ret >= LEDST_COUNT) + ret = -EINVAL; + if (ret >= 0) + printf("%s\n", state_label[ret]); + + return ret; +} + +static int list_leds(void) +{ + struct udevice *dev; + int ret; + + for (uclass_find_first_device(UCLASS_LED, &dev); + dev; + uclass_find_next_device(&dev)) { + struct led_uc_plat *plat = dev_get_uclass_platdata(dev); + + if (!plat->label) + continue; + printf("%-15s ", plat->label); + if (device_active(dev)) { + ret = show_led_state(dev); + if (ret < 0) + printf("Error %d\n", ret); + } else { + printf("<inactive>\n"); + } + } + + return 0; +} + +int do_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + enum led_state_t cmd; + const char *led_label; + struct udevice *dev; +#ifdef CONFIG_LED_BLINK + int freq_ms = 0; +#endif + int ret; + + /* Validate arguments */ + if (argc < 2) + return CMD_RET_USAGE; + led_label = argv[1]; + if (*led_label == 'l') + return list_leds(); + + cmd = argc > 2 ? get_led_cmd(argv[2]) : LEDST_COUNT; + if (cmd < 0) + return CMD_RET_USAGE; +#ifdef CONFIG_LED_BLINK + if (cmd == LEDST_BLINK) { + if (argc < 4) + return CMD_RET_USAGE; + freq_ms = simple_strtoul(argv[3], NULL, 10); + } +#endif + ret = led_get_by_label(led_label, &dev); + if (ret) { + printf("LED '%s' not found (err=%d)\n", led_label, ret); + return CMD_RET_FAILURE; + } + switch (cmd) { + case LEDST_OFF: + case LEDST_ON: + case LEDST_TOGGLE: + ret = led_set_state(dev, cmd); + break; +#ifdef CONFIG_LED_BLINK + case LEDST_BLINK: + ret = led_set_period(dev, freq_ms); + if (!ret) + ret = led_set_state(dev, LEDST_BLINK); + break; +#endif + case LEDST_COUNT: + printf("LED '%s': ", led_label); + ret = show_led_state(dev); + break; + } + if (ret < 0) { + printf("LED '%s' operation failed (err=%d)\n", led_label, ret); + return CMD_RET_FAILURE; + } + + return 0; +} + +#ifdef CONFIG_LED_BLINK +#define BLINK "|blink [blink-freq in ms]" +#else +#define BLINK "" +#endif + +U_BOOT_CMD( + led, 4, 1, do_led, + "manage LEDs", + "<led_label> on|off|toggle" BLINK "\tChange LED state\n" + "led [<led_label>\tGet LED state\n" + "led list\t\tshow a list of LEDs" +);

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
When driver model is used for LEDs, provide a command to allow LED access.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
cmd/Kconfig | 9 ++++ cmd/Makefile | 1 + cmd/led.c | 145 ++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 cmd/led.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 661ae7a98c..13dc46a174 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -667,6 +667,15 @@ config CMD_CACHE help Enable the "icache" and "dcache" commands
+config CMD_LED
bool "led"
default y if LED
help
Enable the 'led' command which allows for control of LEDs
supported
by the board. The LEDs can be listed with 'led list' and
controlled
with led on/off/togle/blink. Any LED drivers can be controlled
with
this command, e.g. led_gpio.
config CMD_TIME bool "time" help diff --git a/cmd/Makefile b/cmd/Makefile index 19d450e0fb..3cb0cfde7b 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_CMD_JFFS2) += jffs2.o obj-$(CONFIG_CMD_CRAMFS) += cramfs.o obj-$(CONFIG_CMD_LDRINFO) += ldrinfo.o obj-$(CONFIG_LED_STATUS_CMD) += legacy_led.o +obj-$(CONFIG_CMD_LED) += led.o obj-$(CONFIG_CMD_LICENSE) += license.o obj-y += load.o obj-$(CONFIG_LOGBUFFER) += log.o diff --git a/cmd/led.c b/cmd/led.c new file mode 100644 index 0000000000..84173f86f2 --- /dev/null +++ b/cmd/led.c @@ -0,0 +1,145 @@ +/*
- Copyright (c) 2017 Google, Inc
- Written by Simon Glass sjg@chromium.org
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <command.h> +#include <dm.h> +#include <led.h> +#include <dm/uclass-internal.h>
+#define LED_TOGGLE LEDST_COUNT
+static const char *const state_label[] = {
[LEDST_OFF] = "off",
[LEDST_ON] = "on",
[LEDST_TOGGLE] = "toggle",
+#ifdef CONFIG_LED_BLINK
[LEDST_BLINK] = "blink",
+#endif +};
+enum led_state_t get_led_cmd(char *var) +{
int i;
for (i = 0; i < LEDST_COUNT; i++) {
if (!strncmp(var, state_label[i], strlen(var)))
return i;
}
return -1;
+}
+static int show_led_state(struct udevice *dev) +{
int ret;
ret = led_get_state(dev);
if (ret >= LEDST_COUNT)
ret = -EINVAL;
if (ret >= 0)
printf("%s\n", state_label[ret]);
return ret;
+}
+static int list_leds(void) +{
struct udevice *dev;
int ret;
for (uclass_find_first_device(UCLASS_LED, &dev);
dev;
uclass_find_next_device(&dev)) {
struct led_uc_plat *plat = dev_get_uclass_platdata(dev);
if (!plat->label)
continue;
printf("%-15s ", plat->label);
if (device_active(dev)) {
ret = show_led_state(dev);
if (ret < 0)
printf("Error %d\n", ret);
} else {
printf("<inactive>\n");
}
}
return 0;
+}
+int do_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{
enum led_state_t cmd;
const char *led_label;
struct udevice *dev;
+#ifdef CONFIG_LED_BLINK
int freq_ms = 0;
+#endif
int ret;
/* Validate arguments */
if (argc < 2)
return CMD_RET_USAGE;
led_label = argv[1];
if (*led_label == 'l')
return list_leds();
cmd = argc > 2 ? get_led_cmd(argv[2]) : LEDST_COUNT;
if (cmd < 0)
return CMD_RET_USAGE;
+#ifdef CONFIG_LED_BLINK
if (cmd == LEDST_BLINK) {
if (argc < 4)
return CMD_RET_USAGE;
freq_ms = simple_strtoul(argv[3], NULL, 10);
}
+#endif
ret = led_get_by_label(led_label, &dev);
if (ret) {
printf("LED '%s' not found (err=%d)\n", led_label, ret);
return CMD_RET_FAILURE;
}
switch (cmd) {
case LEDST_OFF:
case LEDST_ON:
case LEDST_TOGGLE:
ret = led_set_state(dev, cmd);
break;
+#ifdef CONFIG_LED_BLINK
case LEDST_BLINK:
ret = led_set_period(dev, freq_ms);
if (!ret)
ret = led_set_state(dev, LEDST_BLINK);
break;
+#endif
case LEDST_COUNT:
printf("LED '%s': ", led_label);
ret = show_led_state(dev);
break;
}
if (ret < 0) {
printf("LED '%s' operation failed (err=%d)\n", led_label,
ret);
return CMD_RET_FAILURE;
}
return 0;
+}
+#ifdef CONFIG_LED_BLINK +#define BLINK "|blink [blink-freq in ms]" +#else +#define BLINK "" +#endif
+U_BOOT_CMD(
led, 4, 1, do_led,
"manage LEDs",
"<led_label> on|off|toggle" BLINK "\tChange LED state\n"
"led [<led_label>\tGet LED state\n"
"led list\t\tshow a list of LEDs"
+);
2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com

On 12 April 2017 at 02:53, Ziping Chen techping.chan@gmail.com wrote:
2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
When driver model is used for LEDs, provide a command to allow LED access.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None
cmd/Kconfig | 9 ++++ cmd/Makefile | 1 + cmd/led.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 cmd/led.c
Reviewed-by: Ziping Chen techping.chan@gmail.com
Applied to u-boot-dm

2017-04-11 1:34 GMT+08:00 Simon Glass sjg@chromium.org:
The LED interface for driver model is a little primitive. This series expands it to match the legacy interface and adds a command to match.
Changes in v2:
- Add new patch with blank line in the Kconfig file
- Drop the explicit assignment to LEDST_TOGGLE
- Control this feature via a new CONFIG_LED_BLINK option
Simon Glass (9): sandbox: Add some test LEDs dm: led: Add a missing blank line in the Kconfig file dm: led: Rename struct led_uclass_plat dm: led: Adjust the LED uclass dm: led: Add support for getting the state of an LED dm: led: Support toggling LEDs dm: led: Add support for blinking LEDs led: Mark existing driver as legacy dm: led: Add a new 'led' command
arch/sandbox/dts/sandbox.dts | 14 +++ cmd/Kconfig | 9 ++ cmd/Makefile | 3 +- cmd/led.c | 262 +++++++++++++++++-------------
cmd/legacy_led.c | 187 ++++++++++++++++++++++++++++ configs/sandbox_defconfig | 1 + configs/sandbox_noblk_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + drivers/led/Kconfig | 10 ++ drivers/led/led-uclass.c | 32 ++++- drivers/led/led_gpio.c | 39 +++++- include/led.h | 75 ++++++++++-- test/dm/led.c | 56 ++++++++- 13 files changed, 517 insertions(+), 173 deletions(-) create mode 100644 cmd/legacy_led.c
-- 2.12.2.715.g7642488e1d-goog
Reviewed-by: Ziping Chen techping.chan@gmail.com
participants (2)
-
Simon Glass
-
Ziping Chen