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
next 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).