diff options
author | Pavel <pavel@ucw.cz> | 2018-10-28 13:14:47 +0100 |
---|---|---|
committer | Pavel <pavel@ucw.cz> | 2019-01-07 11:21:58 +0100 |
commit | 347e0cd3da949ba484e93eb65cfafe3d1dcce4e6 (patch) | |
tree | 23d2d0200708d9e4ade8f5ea412699315ea655a4 | |
parent | 5e607f898a6861f0f84fbb6471ff153a027c63d5 (diff) | |
download | linux-k-347e0cd3da949ba484e93eb65cfafe3d1dcce4e6.tar.gz |
leds: RGB support
-rw-r--r-- | drivers/leds/Kconfig | 12 | ||||
-rw-r--r-- | drivers/leds/led-class.c | 79 | ||||
-rw-r--r-- | drivers/leds/led-rgb-core.c | 64 | ||||
-rw-r--r-- | include/linux/leds.h | 27 |
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 */ |