From: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> Signed-off-by: Juergen Borleis <jbe@xxxxxxxxxxxxxx> --- drivers/led/Kconfig | 2 + drivers/led/Makefile | 1 + drivers/led/led-74273-gpio.c | 176 +++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 drivers/led/led-74273-gpio.c diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 2a5920a..876aa31 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -39,5 +39,7 @@ config LED_PCA955X LED driver chips accessed via the I2C bus. Supported devices include PCA9550, PCA9551, PCA9552, and PCA9553. +config LED_74273_GPIO + bool "Support for LEDs connected through a 74273" endif diff --git a/drivers/led/Makefile b/drivers/led/Makefile index 35693a7..5732f27 100644 --- a/drivers/led/Makefile +++ b/drivers/led/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_LED) += core.o obj-$(CONFIG_LED_GPIO) += led-gpio.o obj-$(CONFIG_LED_PWM) += led-pwm.o +obj-$(CONFIG_LED_74273_GPIO) += led-74273-gpio.o obj-$(CONFIG_LED_TRIGGERS) += led-triggers.o obj-$(CONFIG_LED_PCA955X) += led-pca955x.o diff --git a/drivers/led/led-74273-gpio.c b/drivers/led/led-74273-gpio.c new file mode 100644 index 0000000..1d62e32 --- /dev/null +++ b/drivers/led/led-74273-gpio.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2017 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <common.h> +#include <init.h> +#include <led.h> +#include <malloc.h> +#include <gpio.h> +#include <of_gpio.h> + +struct sn74273; + +struct sn74273_led { + struct led led; + struct sn74273 *sn74273; + int port; + int pin; +}; + +struct sn74273 { + struct sn74273_led *leds; + int *clk_gpios; + int *data_gpios; + u8 *shadow; + int n_ports; + int n_pins; + int n_leds; +}; + +static void sn74273_led_set(struct led *led, unsigned int brightness) +{ + struct sn74273_led *sled = container_of(led, struct sn74273_led, led); + struct sn74273 *sn74273 = sled->sn74273; + int i, j; + u8 val; + + val = sn74273->shadow[sled->port]; + if (brightness) + val |= 1 << sled->pin; + else + val &= ~(1 << sled->pin); + sn74273->shadow[sled->port] = val; + + for (i = 0; i < sn74273->n_ports; i++) { + for (j = 0; j < sn74273->n_pins; j++) { + gpio_set_active(sn74273->data_gpios[j], + sn74273->shadow[i] & (1 << j)); + } + + gpio_set_active(sn74273->clk_gpios[i], 1); + gpio_set_active(sn74273->clk_gpios[i], 0); + } +} + +static int sn74273_led_probe(struct device_d *dev) +{ + struct device_node *np = dev->device_node; + struct sn74273 *sn74273; + int i, ret; + enum of_gpio_flags flags; + + sn74273 = xzalloc(sizeof(*sn74273)); + + sn74273->n_ports = of_gpio_named_count(np, "clk-gpios"); + if (sn74273->n_ports < 0) { + dev_err(dev, "invalid or missing clk-gpios"); + ret = -EINVAL; + goto err_gpio; + } + + sn74273->n_pins = of_gpio_named_count(np, "data-gpios"); + if (sn74273->n_pins < 0) { + dev_err(dev, "invalid or missing data-gpios"); + ret = -EINVAL; + goto err_gpio; + } + + sn74273->n_leds = sn74273->n_ports * sn74273->n_pins; + + sn74273->clk_gpios = xzalloc(sizeof(int) * sn74273->n_ports); + sn74273->data_gpios = xzalloc(sizeof(int) * sn74273->n_pins); + + for (i = 0; i < sn74273->n_ports; i++) { + sn74273->clk_gpios[i] = of_get_named_gpio_flags(np, "clk-gpios", + i, &flags); + ret = gpio_request_one(sn74273->clk_gpios[i], + flags & OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0, + dev_name(dev)); + if (ret) { + dev_err(dev, "Cannot request gpio %d: %s\n", sn74273->clk_gpios[i], + strerror(-ret)); + goto err_gpio; + } + + gpio_direction_output(sn74273->clk_gpios[i], 0); + } + + for (i = 0; i < sn74273->n_pins; i++) { + sn74273->data_gpios[i] = of_get_named_gpio_flags(np, "data-gpios", + i, &flags); + ret = gpio_request_one(sn74273->data_gpios[i], + flags & OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0, + dev_name(dev)); + if (ret) { + dev_err(dev, "Cannot request gpio %d: %s\n", sn74273->data_gpios[i], + strerror(-ret)); + goto err_gpio; + } + + gpio_direction_output(sn74273->data_gpios[i], 0); + } + + sn74273->shadow = xzalloc(sizeof(u8) * sn74273->n_ports); + sn74273->leds = xzalloc(sizeof(*sn74273->leds) * sn74273->n_leds); + + for (i = 0; i < sn74273->n_leds; i++) { + struct sn74273_led *led = &sn74273->leds[i]; + const char *name; + + led->port = i / sn74273->n_pins; + led->pin = i % sn74273->n_pins; + + ret = of_property_read_string_index(np, "labels", i, &name); + if (ret) + led->led.name = basprintf("%s-%d", dev_name(dev), i); + else + led->led.name = xstrdup(name); + + led->led.set = sn74273_led_set; + led->led.max_value = 1; + led->sn74273 = sn74273; + + ret = led_register(&led->led); + if (ret) { + dev_err(dev, "Failed to register led %d\n", i); + goto err_register; + } + } + + return 0; + +err_register: + for (i = i - 1; i >= 0; i--) { + struct sn74273_led *led = &sn74273->leds[i]; + + led_unregister(&led->led); + } + +err_gpio: + return ret; +} + +static const struct of_device_id of_sn74273_gpio_leds_match[] = { + { + .compatible = "74273-gpio-leds", + }, { + }, +}; + +static struct driver_d sn74273_led_driver = { + .name = "74273-gpio-leds", + .of_compatible = of_sn74273_gpio_leds_match, + .probe = sn74273_led_probe, +}; + +device_platform_driver(sn74273_led_driver); -- 2.20.1 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox