All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Bondar <bond@simicon.com>
To: linux-leds@vger.kernel.org
Cc: Jacek Anaszewski <j.anaszewski@samsung.com>,
	Richard Purdie <rpurdie@rpsys.net>
Subject: [PATCH] Add LED driven by multiple gpio.
Date: Mon, 25 Apr 2016 11:14:38 +0300	[thread overview]
Message-ID: <1461572078.2269.2.camel@dlinux> (raw)

[-- Attachment #1: Type: text/plain, Size: 458 bytes --]

Hello, on our board we have one LED with 2 gpio connected to it:
 - when gpio0 is on and gpio1 on - LED is orange.
 - when gpio0 is on and gpio1 off - LED is green.
 - when gpio0 is off and gpio1 on - LED is red.
 - when gpio0 is off and gpio1 off - LED is off.
We want use led_trigger (nand-disk) on this LED.
Below patch which we use for get one LED on 2 gpios.
Can be this in mainline, or may be exist other - better way?

-- 
Dmitry Bondar, 
simicon.com

[-- Attachment #2: 0000-cover-letter.patch --]
[-- Type: text/x-patch, Size: 1190 bytes --]

>From 27f61d2bf3264f1434c0e568c5adb82fafc591b1 Mon Sep 17 00:00:00 2001
From: Dmitry Bondar <bond@simicon.ru>
Date: Fri, 22 Apr 2016 18:33:44 +0300
Subject: [PATCH 0/2] Add LED driven by multiple gpio

Hello, on our board we have one LED with 2 gpio connected to it:
 - when gpio0 is on and gpio1 on - LED is orange.
 - when gpio0 is on and gpio1 off - LED is green.
 - when gpio0 is off and gpio1 on - LED is red.
 - when gpio0 is off and gpio1 off - LED is off.
We want use led_trigger (nand-disk) on this LED.
Below patch which we use for get one LED on 2 gpios.
Can be this in mainline, or may be exist other - better way?


Dmitry Bondar (2):
  add multiple gpio led(mgpio-led) description to device tree
  add multiple gpio led(mgpio-led) driver

 .../devicetree/bindings/leds/leds-mgpio.txt        |   31 ++++
 drivers/leds/Kconfig                               |    8 +
 drivers/leds/Makefile                              |    1 +
 drivers/leds/leds-mgpio.c                          |  191 ++++++++++++++++++++
 4 files changed, 231 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-mgpio.txt
 create mode 100644 drivers/leds/leds-mgpio.c

-- 
1.7.10.4


[-- Attachment #3: 0001-add-multiple-gpio-led-mgpio-led-description-to-devic.patch --]
[-- Type: text/x-patch, Size: 1795 bytes --]

>From 359cf82ccd8ca100b4330596843af17fbaa85a9e Mon Sep 17 00:00:00 2001
From: Dmitry Bondar <bond@simicon.ru>
Date: Fri, 22 Apr 2016 17:46:33 +0300
Subject: [PATCH 1/2] Add LED driven by multiple gpio
 led(mgpio-led) description to
 device tree

---
 .../devicetree/bindings/leds/leds-mgpio.txt        |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-mgpio.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-mgpio.txt b/Documentation/devicetree/bindings/leds/leds-mgpio.txt
new file mode 100644
index 0000000..135d810
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-mgpio.txt
@@ -0,0 +1,31 @@
+LED connected to multiple GPIO lines
+For example red/green/orange led with to 2 gpio connectd to it.
+
+Required properties:
+- compatible : should be "mgpio-led".
+- gpios :  Should specify the LED's GPIOs, see "gpios property" in
+  Documentation/devicetree/bindings/gpio/gpio.txt.  Active low LEDs should be
+  indicated using flags in the GPIO specifier.
+- color_names: list of colors
+- color_vals: list of gpio values for each color
+  in example below for red led gpio 23 must be 0 and gpio 8 must be 1
+
+Optional properties:
+- label :
+  see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger :
+  see Documentation/devicetree/bindings/leds/common.txt
+- default-color
+  string from color-names
+Examples:
+
+led_uplink{
+        compatible = "simicon,mgpio-led";
+        label = "uplink";
+        gpios = <&portb 23 GPIO_ACTIVE_HIGH>, <&portb 8 GPIO_ACTIVE_HIGH>;
+        color_vals =  <1 1>, <0 1>, <1 0>;
+        color_names = "orange", "red", "green";
+        default-color = "green";
+        linux,default-trigger = "heartbeat";
+};
+
-- 
1.7.10.4


[-- Attachment #4: 0002-add-multiple-gpio-led-mgpio-led-driver.patch --]
[-- Type: text/x-patch, Size: 6660 bytes --]

>From 27f61d2bf3264f1434c0e568c5adb82fafc591b1 Mon Sep 17 00:00:00 2001
From: Dmitry Bondar <bond@simicon.ru>
Date: Fri, 22 Apr 2016 17:50:04 +0300
Subject: [PATCH 2/2] Add LED driven by multiple gpio
 led(mgpio-led) driver

---
 drivers/leds/Kconfig      |    8 ++
 drivers/leds/Makefile     |    1 +
 drivers/leds/leds-mgpio.c |  191 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 200 insertions(+)
 create mode 100644 drivers/leds/leds-mgpio.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2251478..33ce940 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -616,6 +616,14 @@ config LEDS_VERSATILE
 	  This option enabled support for the LEDs on the ARM Versatile
 	  and RealView boards. Say Y to enabled these.
 
+config LEDS_MGPIO
+	tristate "LED driven by multiple gpio"
+	depends on LEDS_CLASS
+	depends on GPIOLIB || COMPILE_TEST
+	help
+	  This option enables support for the LEDs connected to
+	  multiple GPIO outputs.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index cb2013d..e6189e2 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_LEDS_KTD2692)		+= leds-ktd2692.o
 obj-$(CONFIG_LEDS_POWERNV)		+= leds-powernv.o
 obj-$(CONFIG_LEDS_SEAD3)		+= leds-sead3.o
 obj-$(CONFIG_LEDS_IS31FL32XX)		+= leds-is31fl32xx.o
+obj-$(CONFIG_LEDS_MGPIO)		+= leds-mgpio.c
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
diff --git a/drivers/leds/leds-mgpio.c b/drivers/leds/leds-mgpio.c
new file mode 100644
index 0000000..9055af0
--- /dev/null
+++ b/drivers/leds/leds-mgpio.c
@@ -0,0 +1,191 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/leds.h>
+#include <linux/of.h>
+#include <linux/device.h>
+
+struct ledmgpio_state {
+	struct device_node *of_node;
+	struct gpio_descs *gpios;
+	struct led_classdev led;
+	int *color_vals; /*color to gpios values*/
+
+	int color; /*current color*/
+};
+
+static ssize_t show_dev_attr_color(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct ledmgpio_state *s =
+			container_of(cdev, struct ledmgpio_state, led);
+	const char *string;
+	int ret;
+
+	ret = of_property_read_string_index(s->of_node, "color_names", s->color,
+			&string);
+	if (ret != 0)
+		return -EINVAL;
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", string);
+	return strlen(buf);
+}
+
+ssize_t store_dev_attr_color(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct ledmgpio_state *s =
+			container_of(cdev, struct ledmgpio_state, led);
+	int len, idx;
+	char color_name[64];
+
+	if (count < 1)
+		return -EINVAL;
+
+	strncpy(color_name, buf, sizeof(color_name));
+	color_name[sizeof(color_name) - 1] = '\0';
+	len = strlen(color_name);
+	if (len && color_name[len - 1] == '\n')
+		color_name[len - 1] = '\0';
+
+	idx = of_property_match_string(s->of_node, "color_names", color_name);
+	if (idx < 0)
+		return -EINVAL;
+	s->color = idx;
+	return count;
+}
+
+static DEVICE_ATTR(color, S_IRUGO | S_IWUSR,
+		show_dev_attr_color, store_dev_attr_color);
+
+static void ledmgpio_led_set(struct led_classdev *cdev,
+		enum led_brightness brightness)
+{
+	struct ledmgpio_state *s =
+			container_of(cdev, struct ledmgpio_state, led);
+	int values[s->gpios->ndescs];
+	unsigned int i;
+
+	if (brightness == LED_OFF) {
+		for (i = 0; i < s->gpios->ndescs; i++)
+			values[i] = 0;
+	} else {
+		for (i = 0; i < s->gpios->ndescs; i++) {
+			int idx  = s->color * s->gpios->ndescs + i;
+
+			values[i] = s->color_vals[idx];
+		}
+	}
+	gpiod_set_array_cansleep(s->gpios->ndescs, s->gpios->desc, values);
+}
+
+int read_recode_table(struct device *dev, struct ledmgpio_state *s)
+{
+	int ncolors;
+	int ret;
+	int color, g;
+
+	ncolors = of_property_count_strings(dev->of_node, "color_names");
+	if (ncolors <= 0)
+		return -1;
+	s->color_vals = devm_kcalloc(dev, ncolors * s->gpios->ndescs,
+			sizeof(int), GFP_KERNEL);
+	if (!s->color_vals)
+		return -1;
+	for (color = 0; color < ncolors; color++) {
+		for (g = 0; g < s->gpios->ndescs; g++) {
+			u32 val;
+			int idx  = color * s->gpios->ndescs + g;
+
+			ret = of_property_read_u32_index(dev->of_node,
+					"color_vals", idx, &val);
+			if (ret != 0)
+				return -1;
+			s->color_vals[idx] = val;
+		}
+	}
+	return 0;
+}
+
+static int ledmgpio_probe(struct platform_device *pdev)
+{
+	struct ledmgpio_state *s;
+	const char *string;
+	int ret;
+
+	s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+	s->of_node = pdev->dev.of_node;
+
+	s->gpios = devm_gpiod_get_array(&pdev->dev, NULL, GPIOD_OUT_LOW);
+	if (IS_ERR(s->gpios))
+		return PTR_ERR(s->gpios);
+
+	s->led.name = pdev->dev.of_node->name;
+	ret = of_property_read_string(pdev->dev.of_node, "label", &string);
+	if (ret == 0)
+		s->led.name = string;
+	s->led.default_trigger = "none";
+	ret = of_property_read_string(pdev->dev.of_node,
+			"linux,default-trigger", &string);
+	if (ret == 0)
+		s->led.default_trigger = string;
+	s->led.brightness_set = ledmgpio_led_set;
+	s->color = 0;
+	ret = of_property_read_string(pdev->dev.of_node, "default-color",
+			&string);
+	if (ret == 0) {
+		int idx = of_property_match_string(s->of_node, "color_names",
+				string);
+		if (idx < 0)
+			return -EINVAL;
+		s->color = idx;
+	}
+
+	ret = read_recode_table(&pdev->dev, s);
+	if (ret != 0)
+		return ret;
+
+	ret = led_classdev_register(&pdev->dev, &s->led);
+	if (ret != 0)
+		return ret;
+	ret = device_create_file(s->led.dev, &dev_attr_color);
+	if (ret)
+		return ret;
+	pdev->dev.platform_data = s;
+	return 0;
+}
+
+static int ledmgpio_remove(struct platform_device *pdev)
+{
+	struct ledmgpio_state *s = dev_get_platdata(&pdev->dev);
+
+	device_remove_file(s->led.dev, &dev_attr_color);
+	led_classdev_unregister(&s->led);
+	devm_gpiod_put_array(&pdev->dev, s->gpios);
+	return 0;
+}
+
+static const struct of_device_id ledmgpio_of_match[] = {
+	{ .compatible = "mgpio-led", },
+	{}
+};
+
+static struct platform_driver ledmgpio_platform_driver = {
+	.probe = ledmgpio_probe,
+	.remove = ledmgpio_remove,
+	.driver = {
+		.name = "led-mgpio",
+		.of_match_table = ledmgpio_of_match,
+	},
+};
+
+module_platform_driver(ledmgpio_platform_driver);
+MODULE_AUTHOR("Dmitry Bondar <bond@simicon.com>");
+MODULE_DESCRIPTION("multipe GPIO LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:led-mgpio");
-- 
1.7.10.4


             reply	other threads:[~2016-04-25  8:29 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-25  8:14 Dmitry Bondar [this message]
2016-04-25  9:23 ` [PATCH] Add LED driven by multiple gpio Jacek Anaszewski
2016-04-27  6:56   ` Jacek Anaszewski
2016-04-26 20:26 ` David Rivshin (Allworx)
2016-04-29 12:42   ` Jacek Anaszewski
2016-04-29 12:58     ` Pavel Machek
2016-04-29 13:07       ` Jacek Anaszewski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1461572078.2269.2.camel@dlinux \
    --to=bond@simicon.com \
    --cc=j.anaszewski@samsung.com \
    --cc=linux-leds@vger.kernel.org \
    --cc=rpurdie@rpsys.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.