From 5ac76bad2277ed40f2a2112ffab0f156e3b599fb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 23 Jun 2015 15:38:46 -0600 Subject: 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 --- drivers/led/Kconfig | 9 +++++ drivers/led/Makefile | 1 + drivers/led/led_gpio.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 drivers/led/led_gpio.c (limited to 'drivers') diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index e4d9a84b1d..de5feea8dd 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 b39b20581b..990129e08d 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 0000000000..a4cd618787 --- /dev/null +++ b/drivers/led/led_gpio.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +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, +}; -- cgit v1.2.1