diff options
author | Simon Glass <sjg@chromium.org> | 2015-06-23 15:38:46 -0600 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2015-07-21 17:39:24 -0600 |
commit | 5ac76bad2277ed40f2a2112ffab0f156e3b599fb (patch) | |
tree | 83369bd34bf572f1df277e04e8772e8829a917b6 /drivers/led | |
parent | 5917112c9e9f7a60062c604b3224bd5713c41f46 (diff) |
dm: led: Add a driver for GPIO-controlled LEDs
Add a simple driver which allows use of LEDs attached to GPIOs. The linux
device tree binding is used.
Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/led')
-rw-r--r-- | drivers/led/Kconfig | 9 | ||||
-rw-r--r-- | drivers/led/Makefile | 1 | ||||
-rw-r--r-- | drivers/led/led_gpio.c | 101 |
3 files changed, 111 insertions, 0 deletions
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index e4d9a84b1da..de5feea8dd3 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -15,3 +15,12 @@ config SPL_LED_SUPPORT 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 + help + Enable support for LEDs which are connected to GPIO lines. These + GPIOs may be on the SoC or some other device which provides GPIOs. + The GPIO driver must used driver model. LEDs are configured using + the device tree. diff --git a/drivers/led/Makefile b/drivers/led/Makefile index b39b20581b6..990129e08d3 100644 --- a/drivers/led/Makefile +++ b/drivers/led/Makefile @@ -6,3 +6,4 @@ # obj-$(CONFIG_LED) += led-uclass.o +obj-$(CONFIG_LED_GPIO) += led_gpio.o diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c new file mode 100644 index 00000000000..a4cd6187874 --- /dev/null +++ b/drivers/led/led_gpio.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <led.h> +#include <asm/gpio.h> +#include <dm/lists.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct led_gpio_priv { + struct gpio_desc gpio; +}; + +static int gpio_led_set_on(struct udevice *dev, int on) +{ + 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); +} + +static int led_gpio_probe(struct udevice *dev) +{ + struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev); + struct led_gpio_priv *priv = dev_get_priv(dev); + + /* Ignore the top-level LED node */ + if (!uc_plat->label) + return 0; + return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); +} + +static int led_gpio_remove(struct udevice *dev) +{ + struct led_gpio_priv *priv = dev_get_priv(dev); + + if (dm_gpio_is_valid(&priv->gpio)) + dm_gpio_free(dev, &priv->gpio); + + return 0; +} + +static int led_gpio_bind(struct udevice *parent) +{ + const void *blob = gd->fdt_blob; + struct udevice *dev; + int node; + int ret; + + for (node = fdt_first_subnode(blob, parent->of_offset); + node > 0; + node = fdt_next_subnode(blob, node)) { + struct led_uclass_plat *uc_plat; + const char *label; + + label = fdt_getprop(blob, node, "label", NULL); + if (!label) { + debug("%s: node %s has no label\n", __func__, + fdt_get_name(blob, node, NULL)); + return -EINVAL; + } + ret = device_bind_driver_to_node(parent, "gpio_led", + fdt_get_name(blob, node, NULL), + node, &dev); + if (ret) + return ret; + uc_plat = dev_get_uclass_platdata(dev); + uc_plat->label = label; + } + + return 0; +} + +static const struct led_ops gpio_led_ops = { + .set_on = gpio_led_set_on, +}; + +static const struct udevice_id led_gpio_ids[] = { + { .compatible = "gpio-leds" }, + { } +}; + +U_BOOT_DRIVER(led_gpio) = { + .name = "gpio_led", + .id = UCLASS_LED, + .of_match = led_gpio_ids, + .ops = &gpio_led_ops, + .priv_auto_alloc_size = sizeof(struct led_gpio_priv), + .bind = led_gpio_bind, + .probe = led_gpio_probe, + .remove = led_gpio_remove, +}; |