Lines Matching +full:leds +full:- +full:trigger +full:- +full:pattern
1 // SPDX-License-Identifier: GPL-2.0
4 * LED pattern trigger
11 #include <linux/leds.h>
41 data->curr = data->next; in pattern_trig_update_patterns()
42 if (!data->is_indefinite && data->curr == data->patterns) in pattern_trig_update_patterns()
43 data->repeat--; in pattern_trig_update_patterns()
45 if (data->next == data->patterns + data->npatterns - 1) in pattern_trig_update_patterns()
46 data->next = data->patterns; in pattern_trig_update_patterns()
48 data->next++; in pattern_trig_update_patterns()
50 data->delta_t = 0; in pattern_trig_update_patterns()
62 if (data->delta_t == 0 || data->curr->delta_t < UPDATE_INTERVAL) in pattern_trig_compute_brightness()
63 return data->curr->brightness; in pattern_trig_compute_brightness()
65 step_brightness = abs(data->next->brightness - data->curr->brightness); in pattern_trig_compute_brightness()
66 step_brightness = data->delta_t * step_brightness / data->curr->delta_t; in pattern_trig_compute_brightness()
68 if (data->next->brightness > data->curr->brightness) in pattern_trig_compute_brightness()
69 return data->curr->brightness + step_brightness; in pattern_trig_compute_brightness()
71 return data->curr->brightness - step_brightness; in pattern_trig_compute_brightness()
79 if (!data->is_indefinite && !data->repeat) in pattern_trig_timer_function()
82 if (data->curr->brightness == data->next->brightness) { in pattern_trig_timer_function()
84 led_set_brightness(data->led_cdev, in pattern_trig_timer_function()
85 data->curr->brightness); in pattern_trig_timer_function()
86 mod_timer(&data->timer, in pattern_trig_timer_function()
87 jiffies + msecs_to_jiffies(data->curr->delta_t)); in pattern_trig_timer_function()
88 if (!data->next->delta_t) { in pattern_trig_timer_function()
99 * tuple's duration, we should go next one and re-check in pattern_trig_timer_function()
102 if (data->delta_t > data->curr->delta_t) { in pattern_trig_timer_function()
107 led_set_brightness(data->led_cdev, in pattern_trig_timer_function()
109 mod_timer(&data->timer, in pattern_trig_timer_function()
113 data->delta_t += UPDATE_INTERVAL; in pattern_trig_timer_function()
122 struct pattern_trig_data *data = led_cdev->trigger_data; in pattern_trig_start_pattern()
124 if (!data->npatterns) in pattern_trig_start_pattern()
127 if (data->is_hw_pattern) { in pattern_trig_start_pattern()
128 return led_cdev->pattern_set(led_cdev, data->patterns, in pattern_trig_start_pattern()
129 data->npatterns, data->repeat); in pattern_trig_start_pattern()
132 /* At least 2 tuples for software pattern. */ in pattern_trig_start_pattern()
133 if (data->npatterns < 2) in pattern_trig_start_pattern()
134 return -EINVAL; in pattern_trig_start_pattern()
136 data->delta_t = 0; in pattern_trig_start_pattern()
137 data->curr = data->patterns; in pattern_trig_start_pattern()
138 data->next = data->patterns + 1; in pattern_trig_start_pattern()
139 data->timer.expires = jiffies; in pattern_trig_start_pattern()
140 add_timer(&data->timer); in pattern_trig_start_pattern()
149 struct pattern_trig_data *data = led_cdev->trigger_data; in repeat_show()
152 mutex_lock(&data->lock); in repeat_show()
154 repeat = data->last_repeat; in repeat_show()
156 mutex_unlock(&data->lock); in repeat_show()
165 struct pattern_trig_data *data = led_cdev->trigger_data; in repeat_store()
172 /* Number 0 and negative numbers except -1 are invalid. */ in repeat_store()
173 if (res < -1 || res == 0) in repeat_store()
174 return -EINVAL; in repeat_store()
176 mutex_lock(&data->lock); in repeat_store()
178 del_timer_sync(&data->timer); in repeat_store()
180 if (data->is_hw_pattern) in repeat_store()
181 led_cdev->pattern_clear(led_cdev); in repeat_store()
183 data->last_repeat = data->repeat = res; in repeat_store()
184 /* -1 means repeat indefinitely */ in repeat_store()
185 if (data->repeat == -1) in repeat_store()
186 data->is_indefinite = true; in repeat_store()
188 data->is_indefinite = false; in repeat_store()
192 mutex_unlock(&data->lock); in repeat_store()
204 mutex_lock(&data->lock); in pattern_trig_show_patterns()
206 if (!data->npatterns || (data->is_hw_pattern ^ hw_pattern)) in pattern_trig_show_patterns()
209 for (i = 0; i < data->npatterns; i++) { in pattern_trig_show_patterns()
210 count += scnprintf(buf + count, PAGE_SIZE - count, in pattern_trig_show_patterns()
212 data->patterns[i].brightness, in pattern_trig_show_patterns()
213 data->patterns[i].delta_t); in pattern_trig_show_patterns()
216 buf[count - 1] = '\n'; in pattern_trig_show_patterns()
219 mutex_unlock(&data->lock); in pattern_trig_show_patterns()
228 while (offset < count - 1 && data->npatterns < MAX_PATTERNS) { in pattern_trig_store_patterns_string()
231 &data->patterns[data->npatterns].brightness, in pattern_trig_store_patterns_string()
232 &data->patterns[data->npatterns].delta_t, &cr); in pattern_trig_store_patterns_string()
235 data->patterns[data->npatterns].brightness > data->led_cdev->max_brightness) { in pattern_trig_store_patterns_string()
236 data->npatterns = 0; in pattern_trig_store_patterns_string()
237 return -EINVAL; in pattern_trig_store_patterns_string()
241 data->npatterns++; in pattern_trig_store_patterns_string()
253 data->patterns[data->npatterns].brightness = buf[i]; in pattern_trig_store_patterns_int()
254 data->patterns[data->npatterns].delta_t = buf[i + 1]; in pattern_trig_store_patterns_int()
255 data->npatterns++; in pattern_trig_store_patterns_int()
265 struct pattern_trig_data *data = led_cdev->trigger_data; in pattern_trig_store_patterns()
268 mutex_lock(&data->lock); in pattern_trig_store_patterns()
270 del_timer_sync(&data->timer); in pattern_trig_store_patterns()
272 if (data->is_hw_pattern) in pattern_trig_store_patterns()
273 led_cdev->pattern_clear(led_cdev); in pattern_trig_store_patterns()
275 data->is_hw_pattern = hw_pattern; in pattern_trig_store_patterns()
276 data->npatterns = 0; in pattern_trig_store_patterns()
287 data->npatterns = 0; in pattern_trig_store_patterns()
290 mutex_unlock(&data->lock); in pattern_trig_store_patterns()
298 struct pattern_trig_data *data = led_cdev->trigger_data; in pattern_show()
311 static DEVICE_ATTR_RW(pattern);
317 struct pattern_trig_data *data = led_cdev->trigger_data; in hw_pattern_show()
340 return attr->mode; in pattern_trig_attrs_mode()
341 else if (attr == &dev_attr_hw_pattern.attr && led_cdev->pattern_set) in pattern_trig_attrs_mode()
342 return attr->mode; in pattern_trig_attrs_mode()
367 u32 *pattern; in pattern_init() local
370 pattern = led_get_default_pattern(led_cdev, &size); in pattern_init()
371 if (!pattern) in pattern_init()
375 dev_warn(led_cdev->dev, "Expected pattern of tuples\n"); in pattern_init()
379 err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, false); in pattern_init()
381 dev_warn(led_cdev->dev, in pattern_init()
382 "Pattern initialization failed with error %d\n", err); in pattern_init()
385 kfree(pattern); in pattern_init()
394 return -ENOMEM; in pattern_trig_activate()
396 if (!!led_cdev->pattern_set ^ !!led_cdev->pattern_clear) { in pattern_trig_activate()
397 dev_warn(led_cdev->dev, in pattern_trig_activate()
398 "Hardware pattern ops validation failed\n"); in pattern_trig_activate()
399 led_cdev->pattern_set = NULL; in pattern_trig_activate()
400 led_cdev->pattern_clear = NULL; in pattern_trig_activate()
403 data->is_indefinite = true; in pattern_trig_activate()
404 data->last_repeat = -1; in pattern_trig_activate()
405 mutex_init(&data->lock); in pattern_trig_activate()
406 data->led_cdev = led_cdev; in pattern_trig_activate()
408 timer_setup(&data->timer, pattern_trig_timer_function, 0); in pattern_trig_activate()
409 led_cdev->activated = true; in pattern_trig_activate()
411 if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { in pattern_trig_activate()
417 led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; in pattern_trig_activate()
425 struct pattern_trig_data *data = led_cdev->trigger_data; in pattern_trig_deactivate()
427 if (!led_cdev->activated) in pattern_trig_deactivate()
430 if (led_cdev->pattern_clear) in pattern_trig_deactivate()
431 led_cdev->pattern_clear(led_cdev); in pattern_trig_deactivate()
433 timer_shutdown_sync(&data->timer); in pattern_trig_deactivate()
437 led_cdev->activated = false; in pattern_trig_deactivate()
441 .name = "pattern",
462 MODULE_DESCRIPTION("LED Pattern trigger");