The kernel driver is directly pulled from TurrisOS.
https://gitlab.labs.nic.cz/turris/turris-build/commit/60f75b6b

I have added the associated extension of the device tree.

Signed-off-by: Klaus Kudielka <[email protected]>
---
 .../mvebu/patches-4.14/490-omnia-leds.patch   | 568 ++++++++++++++++++
 1 file changed, 568 insertions(+)
 create mode 100644 target/linux/mvebu/patches-4.14/490-omnia-leds.patch

diff --git a/target/linux/mvebu/patches-4.14/490-omnia-leds.patch 
b/target/linux/mvebu/patches-4.14/490-omnia-leds.patch
new file mode 100644
index 0000000000..e819eb247f
--- /dev/null
+++ b/target/linux/mvebu/patches-4.14/490-omnia-leds.patch
@@ -0,0 +1,568 @@
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -632,6 +632,13 @@ config LEDS_IS31FL32XX
+ 
+ comment "LED driver for blink(1) USB RGB LED is under Special HID drivers 
(HID_THINGM)"
+ 
++config LEDS_OMNIA
++       tristate "LED support for the Turris Omnia board"
++       depends on LEDS_CLASS
++       help
++         Say Y here to include support for the LED driver on Turris Omnia
++         board.
++
+ config LEDS_BLINKM
+       tristate "LED support for the BlinkM I2C RGB LED"
+       depends on LEDS_CLASS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -73,6 +73,7 @@ obj-$(CONFIG_LEDS_PM8058)            += leds-pm805
+ obj-$(CONFIG_LEDS_MLXCPLD)            += leds-mlxcpld.o
+ obj-$(CONFIG_LEDS_NIC78BX)            += leds-nic78bx.o
+ obj-$(CONFIG_LEDS_MT6323)             += leds-mt6323.o
++obj-$(CONFIG_LEDS_OMNIA)              += leds-omnia.o
+ 
+ # LED SPI Drivers
+ obj-$(CONFIG_LEDS_DAC124S085)         += leds-dac124s085.o
+--- /dev/null
++++ b/drivers/leds/leds-omnia.c
+@@ -0,0 +1,457 @@
++/*
++ * Copyright 2016 CZ.NIC, z.s.p.o.
++ *
++ * Author: Tomas Hlavacek <[email protected]>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/leds.h>
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/workqueue.h>
++
++#define MAX_LEDS 13
++#define ALL_LEDS_INDEX 12
++
++#define LED_AUTONOMOUS_ADDR 3
++#define LED_ONOFF_ADDR 4
++#define LED_COLOR_ADDR 5
++#define GLOB_BRIGHTNESS_READ 8
++#define GLOB_BRIGHTNESS_WRITE 7
++
++
++
++struct omnia_platform_data {
++        struct led_platform_data leds;
++};
++
++static const struct i2c_device_id omnia_id[] = {
++      { "omnia", 0 },
++      { }
++};
++MODULE_DEVICE_TABLE(i2c, omnia_id);
++
++struct omnia_led_mcu {
++      struct mutex mutex;
++      struct i2c_client *client;
++      struct omnia_led *leds;
++};
++
++struct omnia_led {
++      struct omnia_led_mcu *chip;
++      struct led_classdev led_cdev;
++      int led_num; /* 0 .. 11 + 12=ALL */
++      char name[32];
++      u8 autonomous;
++      u8 r;
++      u8 g;
++      u8 b;
++      struct work_struct work;
++      enum led_brightness new_brightness;
++};
++
++static int omnia_led_brightness_set(struct omnia_led *led,
++                              enum led_brightness brightness)
++{
++      int ret;
++
++      mutex_lock(&led->chip->mutex);
++
++      ret = i2c_smbus_write_byte_data(led->chip->client, LED_ONOFF_ADDR,
++                      (led->led_num | ((brightness != LED_OFF)<<4)));
++
++      mutex_unlock(&led->chip->mutex);
++      return ret;
++}
++
++static int omnia_led_autonomous_set(struct omnia_led *led, int autonomous)
++{
++      int ret, i;
++
++      mutex_lock(&led->chip->mutex);
++
++      if (led->autonomous == (autonomous != 0)) {
++              mutex_unlock(&led->chip->mutex);
++              return 0;
++      }
++
++      led->autonomous = (autonomous != 0);
++
++      if (led->led_num == ALL_LEDS_INDEX) {
++              for (i=0; i<(MAX_LEDS-1); i++)
++                      led->chip->leds[i].autonomous = led->autonomous;
++      }
++
++      ret = i2c_smbus_write_byte_data(led->chip->client, LED_AUTONOMOUS_ADDR,
++                      (u8)(led->led_num | ((!led->autonomous) << 4)));
++
++      mutex_unlock(&led->chip->mutex);
++      return ret;
++}
++
++static int omnia_glob_brightness_set(struct omnia_led_mcu *chip,
++                                      int glob_brightness)
++{
++      int ret;
++
++      mutex_lock(&chip->mutex);
++
++      ret = i2c_smbus_write_byte_data(chip->client, GLOB_BRIGHTNESS_WRITE,
++                                              (u8)glob_brightness);
++
++      mutex_unlock(&chip->mutex);
++      return ret;
++}
++
++static int omnia_glob_brightness_get(struct omnia_led_mcu *chip)
++{
++      int ret;
++
++      mutex_lock(&chip->mutex);
++
++      ret = i2c_smbus_read_byte_data(chip->client, GLOB_BRIGHTNESS_READ);
++
++      mutex_unlock(&chip->mutex);
++      return ret;
++}
++
++static int omnia_led_color_set(struct omnia_led *led, u8 r, u8 g, u8 b)
++{
++      int ret, i;
++      u8 buf[5];
++
++      buf[0] = LED_COLOR_ADDR;
++      buf[1] = led->led_num;
++      buf[2] = r;
++      buf[3] = g;
++      buf[4] = b;
++
++      mutex_lock(&led->chip->mutex);
++
++      ret = i2c_master_send(led->chip->client, buf, 5);
++
++      if (led->led_num == ALL_LEDS_INDEX) {
++              for (i=0; i<(MAX_LEDS-1); i++) {
++                      led->chip->leds[i].r = led->r;
++                      led->chip->leds[i].g = led->g;
++                      led->chip->leds[i].b = led->b;
++              }
++      }
++
++      mutex_unlock(&led->chip->mutex);
++      return -(ret<=0);
++}
++
++static void omnia_led_set_async(struct led_classdev *led_cdev,
++        enum led_brightness value)
++{
++      struct omnia_led *led =
++              container_of(led_cdev, struct omnia_led, led_cdev);
++
++      led->new_brightness = value;
++
++      schedule_work(&led->work);
++}
++
++static void omnia_led_work(struct work_struct *work)
++{
++        struct omnia_led *led;
++        led = container_of(work, struct omnia_led, work);
++
++        omnia_led_brightness_set(led, led->new_brightness);
++}
++
++static struct omnia_platform_data *
++omnia_dt_init(struct i2c_client *client)
++{
++      struct device_node *np = client->dev.of_node, *child;
++      struct omnia_platform_data *pdata;
++      struct led_info *leds;
++      int count;
++
++      count = of_get_child_count(np);
++      if (!count || count > MAX_LEDS)
++              return ERR_PTR(-ENODEV);
++
++      leds = devm_kzalloc(&client->dev,
++                      sizeof(struct led_info) * MAX_LEDS, GFP_KERNEL);
++      if (!leds)
++              return ERR_PTR(-ENOMEM);
++
++      for_each_child_of_node(np, child) {
++              u32 reg;
++              int res;
++
++              res = of_property_read_u32(child, "reg", &reg);
++              if ((res != 0) || (reg >= MAX_LEDS))
++                      continue;
++              leds[reg].name =
++                      of_get_property(child, "label", NULL) ? : child->name;
++              leds[reg].default_trigger =
++                      of_get_property(child, "linux,default-trigger", NULL);
++      }
++      pdata = devm_kzalloc(&client->dev,
++                           sizeof(struct omnia_platform_data), GFP_KERNEL);
++      if (!pdata)
++              return ERR_PTR(-ENOMEM);
++
++      pdata->leds.leds = leds;
++      pdata->leds.num_leds = MAX_LEDS;
++
++      return pdata;
++}
++
++static ssize_t global_brightness_show(struct device *d,
++                struct device_attribute *attr, char *buf)
++{
++      struct i2c_client *client = to_i2c_client(d);
++      struct omnia_led_mcu *chip = i2c_get_clientdata(client);
++
++      return scnprintf(buf, PAGE_SIZE, "%d\n",
++                              omnia_glob_brightness_get(chip));
++}
++
++static ssize_t global_brightness_store(struct device *d,
++                struct device_attribute *attr, const char *buf, size_t count)
++{
++      struct i2c_client *client = to_i2c_client(d);
++        struct omnia_led_mcu *chip = i2c_get_clientdata(client);
++      int ret;
++      int global_brightness;
++
++      if ((sscanf(buf, "%i", &global_brightness)) != 1)
++              return -EINVAL;
++
++      ret = omnia_glob_brightness_set(chip, global_brightness);
++      if (ret < 0)
++              return ret;
++
++      return count;
++}
++static DEVICE_ATTR_RW(global_brightness);
++
++static ssize_t autonomous_show(struct device *d,
++                struct device_attribute *attr, char *buf)
++{
++      struct led_classdev *led_cdev = dev_get_drvdata(d);
++      struct omnia_led *led =
++                      container_of(led_cdev, struct omnia_led, led_cdev);
++
++      return scnprintf(buf, PAGE_SIZE, "%d\n", led->autonomous);
++}
++
++static ssize_t autonomous_store(struct device *d,
++                struct device_attribute *attr, const char *buf, size_t count)
++{
++      int ret, autonomous;
++      struct led_classdev *led_cdev = dev_get_drvdata(d);
++      struct omnia_led *led =
++                      container_of(led_cdev, struct omnia_led, led_cdev);
++
++      if ((sscanf(buf, "%i", &autonomous)) != 1)
++              return -EINVAL;
++
++      ret = omnia_led_autonomous_set(led, autonomous);
++      if (ret < 0)
++              return ret;
++
++      led->autonomous = autonomous;
++      return count;
++}
++static DEVICE_ATTR_RW(autonomous);
++
++static ssize_t color_show(struct device *d,
++                struct device_attribute *attr, char *buf)
++{
++      struct led_classdev *led_cdev = dev_get_drvdata(d);
++      struct omnia_led *led =
++                      container_of(led_cdev, struct omnia_led, led_cdev);
++
++      return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", led->r, led->g, led->b);
++}
++
++static ssize_t color_store(struct device *d,
++                struct device_attribute *attr, const char *buf, size_t count)
++{
++      int ret, r, g, b;
++      struct led_classdev *led_cdev = dev_get_drvdata(d);
++      struct omnia_led *led =
++                      container_of(led_cdev, struct omnia_led, led_cdev);
++
++      if ((sscanf(buf, "%i %i %i", &r, &g, &b)) != 3)
++              return -EINVAL;
++
++      ret = omnia_led_color_set(led, r, g, b);
++      if (ret < 0)
++              return ret;
++
++      led->r = r;
++      led->g = g;
++      led->b = b;
++      return count;
++}
++static DEVICE_ATTR_RW(color);
++
++
++static const struct of_device_id of_omnia_match[] = {
++      { .compatible = "turris-leds,omnia", },
++      {},
++};
++MODULE_DEVICE_TABLE(of, of_omnia_match);
++
++static int omnia_probe(struct i2c_client *client,
++                                      const struct i2c_device_id *id)
++{
++      struct omnia_led_mcu *chip;
++      struct omnia_led *leds;
++      struct omnia_platform_data *pdata;
++      int i, err;
++
++      pdata = dev_get_platdata(&client->dev);
++
++      if (!pdata) {
++              pdata = omnia_dt_init(client);
++              if (IS_ERR(pdata)) {
++                      dev_warn(&client->dev, "could not parse 
configuration\n");
++                      pdata = NULL;
++              }
++      }
++
++      chip = devm_kzalloc(&client->dev, sizeof(*chip),
++                              GFP_KERNEL);
++      if (!chip)
++              return -ENOMEM;
++      leds = devm_kzalloc(&client->dev, MAX_LEDS * sizeof(*leds),
++                              GFP_KERNEL);
++      if (!leds)
++              return -ENOMEM;
++
++      i2c_set_clientdata(client, chip);
++
++      mutex_init(&chip->mutex);
++      chip->client = client;
++      chip->leds = leds;
++
++      for (i = 0; i < MAX_LEDS; i++) {
++              leds[i].led_num = i;
++              leds[i].chip = chip;
++              INIT_WORK(&leds[i].work, omnia_led_work);
++
++              /* Platform data can specify LED names and default triggers */
++              if (pdata && i < pdata->leds.num_leds) {
++                      if (pdata->leds.leds[i].name)
++                              snprintf(leds[i].name,
++                                       sizeof(leds[i].name), "omnia-led:%s",
++                                       pdata->leds.leds[i].name);
++                      if (pdata->leds.leds[i].default_trigger)
++                              leds[i].led_cdev.default_trigger =
++                                      pdata->leds.leds[i].default_trigger;
++              }
++              if (!pdata || i >= pdata->leds.num_leds ||
++                                              !pdata->leds.leds[i].name)
++                      snprintf(leds[i].name, sizeof(leds[i].name),
++                               "omnia-led:%d", i);
++
++              leds[i].led_cdev.name = leds[i].name;
++              leds[i].led_cdev.brightness_set = omnia_led_set_async;
++
++              err = led_classdev_register(&client->dev, &leds[i].led_cdev);
++              if (err < 0)
++                      goto exit;
++
++              err = device_create_file(leds[i].led_cdev.dev,
++                                              &dev_attr_autonomous);
++              if (err < 0) {
++                      dev_err(leds[i].led_cdev.dev,
++                              "failed to create attribute autonomous\n");
++                      goto exit;
++              }
++
++              err = device_create_file(leds[i].led_cdev.dev,
++                                              &dev_attr_color);
++              if (err < 0) {
++                      dev_err(leds[i].led_cdev.dev,
++                              "failed to create attribute color\n");
++                      goto exit;
++              }
++
++              /* Set AUTO for all LEDs by default */
++              leds[i].autonomous = 0;
++              omnia_led_autonomous_set(&leds[i], 1);
++
++              /* Set brightness to LED_OFF by default */
++              omnia_led_brightness_set(&leds[i], LED_OFF);
++
++              /* MCU default color is white */
++              leds[i].r = 255;
++              leds[i].g = 255;
++              leds[i].b = 255;
++      }
++
++      err = device_create_file(&client->dev, &dev_attr_global_brightness);
++      if (err < 0) {
++              dev_err(&client->dev,
++                      "failed to create attribute global_brightness\n");
++              goto exit;
++      }
++
++      return 0;
++
++exit:
++      device_remove_file(&client->dev, &dev_attr_global_brightness);
++      while (i--) {
++              device_remove_file(chip->leds[i].led_cdev.dev,
++                      &dev_attr_color);
++              device_remove_file(chip->leds[i].led_cdev.dev,
++                      &dev_attr_autonomous);
++
++              led_classdev_unregister(&leds[i].led_cdev);
++      }
++
++      return err;
++}
++
++static int omnia_remove(struct i2c_client *client)
++{
++      struct omnia_led_mcu *chip = i2c_get_clientdata(client);
++      int i;
++
++      device_remove_file(&client->dev, &dev_attr_global_brightness);
++
++      for (i = 0; i < MAX_LEDS; i++) {
++              device_remove_file(chip->leds[i].led_cdev.dev,
++                      &dev_attr_color);
++              device_remove_file(chip->leds[i].led_cdev.dev,
++                      &dev_attr_autonomous);
++
++              led_classdev_unregister(&chip->leds[i].led_cdev);
++      }
++
++      return 0;
++}
++
++static struct i2c_driver omnia_driver = {
++      .driver = {
++              .name   = "leds-omnia",
++              .of_match_table = of_match_ptr(of_omnia_match),
++      },
++      .probe  = omnia_probe,
++      .remove = omnia_remove,
++      .id_table = omnia_id,
++};
++
++module_i2c_driver(omnia_driver);
++
++MODULE_AUTHOR("Tomas Hlavacek <[email protected]>");
++MODULE_DESCRIPTION("Turris Omnia LED driver");
++MODULE_LICENSE("GPL v2");
++
+--- a/arch/arm/boot/dts/armada-385-turris-omnia.dts
++++ b/arch/arm/boot/dts/armada-385-turris-omnia.dts
+@@ -168,7 +168,78 @@
+                       reg = <0>;
+ 
+                       /* STM32F0 command interface at address 0x2a */
+-                      /* leds device (in STM32F0) at address 0x2b */
++
++                      leds@2b {
++                              compatible = "turris-leds,omnia";
++                              reg = <0x2b>;
++                              #address-cells = <1>;
++                              #size-cells = <0>;
++
++                              led0 {
++                                      label = "user2";
++                                      reg = <0x0>;
++                              };
++
++                              led1 {
++                                      label = "user1";
++                                      reg = <0x1>;
++                              };
++
++                              led2 {
++                                      label = "pci3";
++                                      reg = <0x2>;
++                              };
++
++                              led3 {
++                                      label = "pci2";
++                                      reg = <0x3>;
++                              };
++
++                              led4 {
++                                      label = "pci1";
++                                      reg = <0x4>;
++                              };
++
++                              led5 {
++                                      label = "wan";
++                                      reg = <0x5>;
++                              };
++
++                              led6 {
++                                      label = "lan4";
++                                      reg = <0x6>;
++                              };
++
++                              led7 {
++                                      label = "lan3";
++                                      reg = <0x7>;
++                              };
++
++                              led8 {
++                                      label = "lan2";
++                                      reg = <0x8>;
++                              };
++
++                              led9 {
++                                      label = "lan1";
++                                      reg = <0x9>;
++                              };
++
++                              led10 {
++                                      label = "lan0";
++                                      reg = <0xa>;
++                              };
++
++                              led11 {
++                                      label = "power";
++                                      reg = <0xb>;
++                              };
++
++                              led12 {
++                                      label = "all";
++                                      reg = <0xc>;
++                              };
++                      };
+ 
+                       eeprom@54 {
+                               compatible = "atmel,24c64";
-- 
2.17.1


_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to