[PATCH] led: Add a 74273 led driver

Juergen Borleis jbe at pengutronix.de
Wed Jul 14 02:14:23 PDT 2021


From: Sascha Hauer <s.hauer at pengutronix.de>

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Juergen Borleis <jbe at pengutronix.de>
---
 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




More information about the barebox mailing list