From: Sascha Hauer <[email protected]>

Signed-off-by: Sascha Hauer <[email protected]>
Signed-off-by: Juergen Borleis <[email protected]>
---
 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
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to