>From 27f61d2bf3264f1434c0e568c5adb82fafc591b1 Mon Sep 17 00:00:00 2001 From: Dmitry Bondar 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 +#include +#include +#include +#include +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("multipe GPIO LED driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:led-mgpio"); -- 1.7.10.4