aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel <pavel@ucw.cz>2018-10-28 13:14:47 +0100
committerPavel <pavel@ucw.cz>2019-01-07 11:21:58 +0100
commit347e0cd3da949ba484e93eb65cfafe3d1dcce4e6 (patch)
tree23d2d0200708d9e4ade8f5ea412699315ea655a4
parent5e607f898a6861f0f84fbb6471ff153a027c63d5 (diff)
downloadlinux-k-347e0cd3da949ba484e93eb65cfafe3d1dcce4e6.tar.gz
leds: RGB support
-rw-r--r--drivers/leds/Kconfig12
-rw-r--r--drivers/leds/led-class.c79
-rw-r--r--drivers/leds/led-rgb-core.c64
-rw-r--r--include/linux/leds.h27
4 files changed, 181 insertions, 1 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index a72f97fca57b48..d000972e89267c 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -19,6 +19,14 @@ config LEDS_CLASS
This option enables the led sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
+config LEDS_CLASS_RGB
+ bool "LED RGB Class Support"
+ depends on LEDS_CLASS
+ help
+ This option enables support for RGB LED devices.
+ Sysfs attribute brightness is interpreted as a HSV color value.
+ For details see Documentation/leds/leds-class.txt.
+
config LEDS_CLASS_FLASH
tristate "LED Flash Class Support"
depends on LEDS_CLASS
@@ -38,6 +46,10 @@ config LEDS_BRIGHTNESS_HW_CHANGED
See Documentation/ABI/testing/sysfs-class-led for details.
+if LEDS_CLASS_RGB
+comment "RGB LED drivers"
+endif # LEDS_CLASS_RGB
+
comment "LED drivers"
config LEDS_88PM860X
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 3c7e3487b373b1..68aa9239dc9b3a 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -65,6 +65,83 @@ unlock:
}
static DEVICE_ATTR_RW(brightness);
+static ssize_t saturation_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ /* no lock needed for this */
+ led_update_brightness(led_cdev);
+
+ return sprintf(buf, "%u\n", led_cdev->saturation);
+}
+
+static ssize_t saturation_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ unsigned long state;
+ ssize_t ret;
+
+ mutex_lock(&led_cdev->led_access);
+
+ if (led_sysfs_is_disabled(led_cdev)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = kstrtoul(buf, 10, &state);
+ if (ret)
+ goto unlock;
+
+ led_cdev->saturation = state;
+
+ ret = size;
+unlock:
+ mutex_unlock(&led_cdev->led_access);
+ return ret;
+}
+static DEVICE_ATTR_RW(saturation);
+
+static ssize_t hue_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ /* no lock needed for this */
+ led_update_brightness(led_cdev);
+
+ return sprintf(buf, "%u\n", led_cdev->hue);
+}
+
+static ssize_t hue_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ unsigned long state;
+ ssize_t ret;
+
+ mutex_lock(&led_cdev->led_access);
+
+ if (led_sysfs_is_disabled(led_cdev)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = kstrtoul(buf, 10, &state);
+ if (ret)
+ goto unlock;
+
+ led_cdev->hue = state;
+
+ ret = size;
+unlock:
+ mutex_unlock(&led_cdev->led_access);
+ return ret;
+}
+static DEVICE_ATTR_RW(hue);
+
+
static ssize_t max_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -88,6 +165,8 @@ static const struct attribute_group led_trigger_group = {
static struct attribute *led_class_attrs[] = {
&dev_attr_brightness.attr,
&dev_attr_max_brightness.attr,
+ &dev_attr_hue.attr,
+ &dev_attr_saturation.attr,
NULL,
};
diff --git a/drivers/leds/led-rgb-core.c b/drivers/leds/led-rgb-core.c
new file mode 100644
index 00000000000000..373303297374df
--- /dev/null
+++ b/drivers/leds/led-rgb-core.c
@@ -0,0 +1,64 @@
+/*
+ * LED RGB Class Support
+ *
+ * Author: Heiner Kallweit <hkallweit1@gmail.com>
+ *
+ * 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/leds.h>
+#include "leds.h"
+
+struct led_rgb led_hsv_to_rgb(struct led_hsv hsv)
+{
+ unsigned int h = hsv.hue >> 24;
+ unsigned int s = hsv.saturation >> 24;
+ unsigned int v = hsv.value >> 24;
+ unsigned int f, p, q, t, r, g, b;
+ struct led_rgb res;
+
+ if (!v) {
+ res.red = 0;
+ res.green = 0;
+ res.blue = 0;
+ return res;
+ }
+ if (!s) {
+ res.red = v << 24;
+ res.green = v << 24;
+ res.blue = v << 24;
+ return res;
+ }
+
+ f = DIV_ROUND_CLOSEST((h % 42) * 255, 42);
+ p = v - DIV_ROUND_CLOSEST(s * v, 255);
+ q = v - DIV_ROUND_CLOSEST(f * s * v, 255 * 255);
+ t = v - DIV_ROUND_CLOSEST((255 - f) * s * v, 255 * 255);
+
+ switch (h / 42) {
+ case 0:
+ r = v; g = t; b = p; break;
+ case 1:
+ r = q; g = v; b = p; break;
+ case 2:
+ r = p; g = v; b = t; break;
+ case 3:
+ r = p; g = q; b = v; break;
+ case 4:
+ r = t; g = p; b = v; break;
+ case 5:
+ r = v; g = p; b = q; break;
+ }
+
+ printk("hsv_to: h %5d, s %5d, v %5d -> %5d, %5d, %5d\n",
+ h*390, s*390, v*390, r*390, g*390, b*390);
+
+ res.red = r << 24;
+ res.green = g << 24;
+ res.blue = b << 24;
+ return res;
+}
+EXPORT_SYMBOL_GPL(led_hsv_to_rgb);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 5263f87e1d2c72..cd673d3bca90b5 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -38,6 +38,8 @@ struct led_classdev {
const char *name;
enum led_brightness brightness;
enum led_brightness max_brightness;
+ int hue;
+ int saturation;
int flags;
/* Lower 16 bits reflect status */
@@ -52,6 +54,7 @@ struct led_classdev {
#define LED_BRIGHT_HW_CHANGED BIT(21)
#define LED_RETAIN_AT_SHUTDOWN BIT(22)
#define LED_INIT_DEFAULT_TRIGGER BIT(23)
+#define LED_DEV_CAP_RGB BIT(24)
/* set_brightness_work / blink_timer flags, atomic, private. */
unsigned long work_flags;
@@ -107,7 +110,7 @@ struct led_classdev {
void (*flash_resume)(struct led_classdev *led_cdev);
struct work_struct set_brightness_work;
- int delayed_set_value;
+ enum led_brightness delayed_set_value;
#ifdef CONFIG_LEDS_TRIGGERS
/* Protects the trigger data below */
@@ -245,6 +248,28 @@ static inline bool led_sysfs_is_disabled(struct led_classdev *led_cdev)
return led_cdev->flags & LED_SYSFS_DISABLE;
}
+/* 0.32 fixed point */
+struct led_hsv {
+ u32 hue;
+ u32 saturation;
+ u32 value;
+};
+
+/* 0.32 fixed point */
+struct led_rgb {
+ u32 red;
+ u32 green;
+ u32 blue;
+};
+
+/**
+ * led_hsv_to_rgb - convert a hsv color value to rgb color model
+ * @hsv: the hsv value to convert
+ *
+ * Returns: the resulting rgb value
+ */
+struct led_rgb led_hsv_to_rgb(struct led_hsv hsv);
+
/*
* LED Triggers
*/