Hello Jürgen, On 14.07.21 11:14, Juergen Borleis wrote: > 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" I talked this over with Sascha before: https://lore.barebox.org/barebox/0f039d89-2b64-ae91-a0c3-30c10c461c34@xxxxxxxxxxxxxx/ The 74273 is rather an output-only GPIO controller, so a LED driver isn't the correct abstraction. I implemented a GPIO driver for this before (see above link), but Sascha's opinion is that this should at least have an upstream binding first. Cheers, Ahmad > > 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); > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox