leds: trigger: pattern: Add per-tuple RGB color
- Extend pattern trigger to parse optional RGB per tuple - Plumb color data through include/linux/leds.h - Preserve existing tuple semantics when color omitted Signed-off-by: Maxim Laschinsky <maxim.laschinsky@wago.com>
This commit is contained in:
committed by
Heinrich Toews
parent
995017b4bf
commit
91007560a1
@@ -13,6 +13,9 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/led-class-multicolor.h>
|
||||
|
||||
#define MAX_PATTERNS 1024
|
||||
/*
|
||||
@@ -34,8 +37,56 @@ struct pattern_trig_data {
|
||||
bool is_indefinite;
|
||||
bool is_hw_pattern;
|
||||
struct timer_list timer;
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR)
|
||||
struct led_classdev_mc *mcled;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR)
|
||||
static void pattern_trig_apply_color(struct pattern_trig_data *data,
|
||||
const struct led_pattern *pat)
|
||||
{
|
||||
int i;
|
||||
unsigned int max_intensity;
|
||||
bool has_red = false, has_green = false, has_blue = false;
|
||||
|
||||
if (!data->mcled || !pat->has_color)
|
||||
return;
|
||||
|
||||
max_intensity = data->mcled->led_cdev.max_brightness;
|
||||
|
||||
for (i = 0; i < data->mcled->num_colors; i++) {
|
||||
switch (data->mcled->subled_info[i].color_index) {
|
||||
case LED_COLOR_ID_RED:
|
||||
data->mcled->subled_info[i].intensity =
|
||||
DIV_ROUND_CLOSEST(pat->red * max_intensity, 255);
|
||||
has_red = true;
|
||||
break;
|
||||
case LED_COLOR_ID_GREEN:
|
||||
data->mcled->subled_info[i].intensity =
|
||||
DIV_ROUND_CLOSEST(pat->green * max_intensity, 255);
|
||||
has_green = true;
|
||||
break;
|
||||
case LED_COLOR_ID_BLUE:
|
||||
data->mcled->subled_info[i].intensity =
|
||||
DIV_ROUND_CLOSEST(pat->blue * max_intensity, 255);
|
||||
has_blue = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!has_red && pat->red) || (!has_green && pat->green) ||
|
||||
(!has_blue && pat->blue))
|
||||
dev_warn_once(data->led_cdev->dev,
|
||||
"pattern: color component set for absent channel\n");
|
||||
}
|
||||
#else
|
||||
static inline void pattern_trig_apply_color(struct pattern_trig_data *data,
|
||||
const struct led_pattern *pat) { }
|
||||
#endif
|
||||
|
||||
static void pattern_trig_update_patterns(struct pattern_trig_data *data)
|
||||
{
|
||||
data->curr = data->next;
|
||||
@@ -81,6 +132,7 @@ static void pattern_trig_timer_function(struct timer_list *t)
|
||||
|
||||
if (data->curr->brightness == data->next->brightness) {
|
||||
/* Step change of brightness */
|
||||
pattern_trig_apply_color(data, data->curr);
|
||||
led_set_brightness(data->led_cdev,
|
||||
data->curr->brightness);
|
||||
mod_timer(&data->timer,
|
||||
@@ -104,6 +156,8 @@ static void pattern_trig_timer_function(struct timer_list *t)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data->delta_t == 0)
|
||||
pattern_trig_apply_color(data, data->curr);
|
||||
led_set_brightness(data->led_cdev,
|
||||
pattern_trig_compute_brightness(data));
|
||||
mod_timer(&data->timer,
|
||||
@@ -207,10 +261,18 @@ static ssize_t pattern_trig_show_patterns(struct pattern_trig_data *data,
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < data->npatterns; i++) {
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"%d %u ",
|
||||
data->patterns[i].brightness,
|
||||
data->patterns[i].delta_t);
|
||||
const struct led_pattern *p = &data->patterns[i];
|
||||
|
||||
if (!hw_pattern && p->has_color)
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"%d:%02x%02x%02x %u ",
|
||||
p->brightness, p->red, p->green,
|
||||
p->blue, p->delta_t);
|
||||
else
|
||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
||||
"%d %u ",
|
||||
p->brightness,
|
||||
p->delta_t);
|
||||
}
|
||||
|
||||
buf[count - 1] = '\n';
|
||||
@@ -223,22 +285,52 @@ out:
|
||||
static int pattern_trig_store_patterns_string(struct pattern_trig_data *data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ccount, cr, offset = 0;
|
||||
int consumed, ccount;
|
||||
unsigned int brightness, delta_t;
|
||||
size_t offset = 0;
|
||||
u8 r, g, b;
|
||||
|
||||
while (offset < count - 1 && data->npatterns < MAX_PATTERNS) {
|
||||
cr = 0;
|
||||
ccount = sscanf(buf + offset, "%u %u %n",
|
||||
&data->patterns[data->npatterns].brightness,
|
||||
&data->patterns[data->npatterns].delta_t, &cr);
|
||||
while (offset < count && data->npatterns < MAX_PATTERNS) {
|
||||
while (offset < count && isspace(buf[offset]))
|
||||
offset++;
|
||||
if (offset >= count)
|
||||
break;
|
||||
|
||||
if (ccount != 2 ||
|
||||
data->patterns[data->npatterns].brightness > data->led_cdev->max_brightness) {
|
||||
if (!data->is_hw_pattern) {
|
||||
consumed = 0;
|
||||
ccount = sscanf(buf + offset,
|
||||
"%u:%2hhx%2hhx%2hhx %u %n",
|
||||
&brightness, &r, &g, &b,
|
||||
&delta_t, &consumed);
|
||||
if (ccount == 5) {
|
||||
if (brightness > data->led_cdev->max_brightness) {
|
||||
data->npatterns = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
data->patterns[data->npatterns].brightness = brightness;
|
||||
data->patterns[data->npatterns].delta_t = delta_t;
|
||||
data->patterns[data->npatterns].has_color = true;
|
||||
data->patterns[data->npatterns].red = r;
|
||||
data->patterns[data->npatterns].green = g;
|
||||
data->patterns[data->npatterns].blue = b;
|
||||
offset += consumed;
|
||||
data->npatterns++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
consumed = 0;
|
||||
ccount = sscanf(buf + offset, "%u %u %n", &brightness, &delta_t, &consumed);
|
||||
if (ccount != 2 || brightness > data->led_cdev->max_brightness) {
|
||||
data->npatterns = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
offset += cr;
|
||||
data->patterns[data->npatterns].brightness = brightness;
|
||||
data->patterns[data->npatterns].delta_t = delta_t;
|
||||
data->npatterns++;
|
||||
if (consumed == 0)
|
||||
break;
|
||||
offset += consumed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -274,6 +366,8 @@ static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
|
||||
|
||||
data->is_hw_pattern = hw_pattern;
|
||||
data->npatterns = 0;
|
||||
/* Zero all pattern entries so per-tuple color field clearing is unnecessary */
|
||||
memset(data->patterns, 0, sizeof(data->patterns));
|
||||
|
||||
if (buf)
|
||||
err = pattern_trig_store_patterns_string(data, buf, count);
|
||||
@@ -404,6 +498,11 @@ static int pattern_trig_activate(struct led_classdev *led_cdev)
|
||||
data->last_repeat = -1;
|
||||
mutex_init(&data->lock);
|
||||
data->led_cdev = led_cdev;
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR)
|
||||
if (led_cdev->color == LED_COLOR_ID_MULTI ||
|
||||
led_cdev->color == LED_COLOR_ID_RGB)
|
||||
data->mcled = lcdev_to_mccdev(led_cdev);
|
||||
#endif
|
||||
led_set_trigger_data(led_cdev, data);
|
||||
timer_setup(&data->timer, pattern_trig_timer_function, 0);
|
||||
led_cdev->activated = true;
|
||||
@@ -459,5 +558,5 @@ module_exit(pattern_trig_exit);
|
||||
|
||||
MODULE_AUTHOR("Raphael Teysseyre <rteysseyre@gmail.com>");
|
||||
MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org>");
|
||||
MODULE_DESCRIPTION("LED Pattern trigger");
|
||||
MODULE_DESCRIPTION("LED Pattern trigger (optional per-node RGB)");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
+14
-3
@@ -706,13 +706,24 @@ static inline void led_classdev_notify_brightness_hw_changed(
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct led_pattern - pattern interval settings
|
||||
* @delta_t: pattern interval delay, in milliseconds
|
||||
* @brightness: pattern interval brightness
|
||||
* struct led_pattern - pattern interval settings (optional RGB per node)
|
||||
* @delta_t: pattern interval delay (ms)
|
||||
* @brightness: pattern interval brightness (0..max_brightness)
|
||||
* @has_color: true if this node specifies new RGB intensities
|
||||
* @red: red component (0..255, valid if has_color)
|
||||
* @green: green component (0..255, valid if has_color)
|
||||
* @blue: blue component (0..255, valid if has_color)
|
||||
*
|
||||
* If has_color is false the previously applied color (if any) remains
|
||||
* unchanged; only brightness/duration are processed.
|
||||
*/
|
||||
struct led_pattern {
|
||||
u32 delta_t;
|
||||
int brightness;
|
||||
bool has_color;
|
||||
u8 red;
|
||||
u8 green;
|
||||
u8 blue;
|
||||
};
|
||||
|
||||
enum led_audio {
|
||||
|
||||
Reference in New Issue
Block a user