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>
26 PATTERN_TYPE_SW, /* Use standard timer for software pattern */
27 PATTERN_TYPE_HR, /* Use hrtimer for software pattern */
28 PATTERN_TYPE_HW, /* Hardware pattern */
49 data->curr = data->next; in pattern_trig_update_patterns()
50 if (!data->is_indefinite && data->curr == data->patterns) in pattern_trig_update_patterns()
51 data->repeat--; in pattern_trig_update_patterns()
53 if (data->next == data->patterns + data->npatterns - 1) in pattern_trig_update_patterns()
54 data->next = data->patterns; in pattern_trig_update_patterns()
56 data->next++; in pattern_trig_update_patterns()
58 data->delta_t = 0; in pattern_trig_update_patterns()
70 if (data->delta_t == 0 || data->curr->delta_t < UPDATE_INTERVAL) in pattern_trig_compute_brightness()
71 return data->curr->brightness; in pattern_trig_compute_brightness()
73 step_brightness = abs(data->next->brightness - data->curr->brightness); in pattern_trig_compute_brightness()
74 step_brightness = data->delta_t * step_brightness / data->curr->delta_t; in pattern_trig_compute_brightness()
76 if (data->next->brightness > data->curr->brightness) in pattern_trig_compute_brightness()
77 return data->curr->brightness + step_brightness; in pattern_trig_compute_brightness()
79 return data->curr->brightness - step_brightness; in pattern_trig_compute_brightness()
84 if (data->type == PATTERN_TYPE_HR) { in pattern_trig_timer_start()
85 hrtimer_start(&data->hrtimer, ns_to_ktime(0), HRTIMER_MODE_REL); in pattern_trig_timer_start()
87 data->timer.expires = jiffies; in pattern_trig_timer_start()
88 add_timer(&data->timer); in pattern_trig_timer_start()
94 if (data->type == PATTERN_TYPE_HR) in pattern_trig_timer_cancel()
95 hrtimer_cancel(&data->hrtimer); in pattern_trig_timer_cancel()
97 del_timer_sync(&data->timer); in pattern_trig_timer_cancel()
103 if (data->type == PATTERN_TYPE_HR) in pattern_trig_timer_restart()
104 hrtimer_forward_now(&data->hrtimer, ms_to_ktime(interval)); in pattern_trig_timer_restart()
106 mod_timer(&data->timer, jiffies + msecs_to_jiffies(interval)); in pattern_trig_timer_restart()
112 if (!data->is_indefinite && !data->repeat) in pattern_trig_timer_common_function()
115 if (data->curr->brightness == data->next->brightness) { in pattern_trig_timer_common_function()
117 led_set_brightness(data->led_cdev, in pattern_trig_timer_common_function()
118 data->curr->brightness); in pattern_trig_timer_common_function()
119 pattern_trig_timer_restart(data, data->curr->delta_t); in pattern_trig_timer_common_function()
120 if (!data->next->delta_t) { in pattern_trig_timer_common_function()
131 * tuple's duration, we should go next one and re-check in pattern_trig_timer_common_function()
134 if (data->delta_t > data->curr->delta_t) { in pattern_trig_timer_common_function()
139 led_set_brightness(data->led_cdev, in pattern_trig_timer_common_function()
144 data->delta_t += UPDATE_INTERVAL; in pattern_trig_timer_common_function()
164 if (!data->is_indefinite && !data->repeat) in pattern_trig_hrtimer_function()
172 struct pattern_trig_data *data = led_cdev->trigger_data; in pattern_trig_start_pattern()
174 if (!data->npatterns) in pattern_trig_start_pattern()
177 if (data->type == PATTERN_TYPE_HW) { in pattern_trig_start_pattern()
178 return led_cdev->pattern_set(led_cdev, data->patterns, in pattern_trig_start_pattern()
179 data->npatterns, data->repeat); in pattern_trig_start_pattern()
182 /* At least 2 tuples for software pattern. */ in pattern_trig_start_pattern()
183 if (data->npatterns < 2) in pattern_trig_start_pattern()
184 return -EINVAL; in pattern_trig_start_pattern()
186 data->delta_t = 0; in pattern_trig_start_pattern()
187 data->curr = data->patterns; in pattern_trig_start_pattern()
188 data->next = data->patterns + 1; in pattern_trig_start_pattern()
198 struct pattern_trig_data *data = led_cdev->trigger_data; in repeat_show()
201 mutex_lock(&data->lock); in repeat_show()
203 repeat = data->last_repeat; in repeat_show()
205 mutex_unlock(&data->lock); in repeat_show()
214 struct pattern_trig_data *data = led_cdev->trigger_data; in repeat_store()
221 /* Number 0 and negative numbers except -1 are invalid. */ in repeat_store()
222 if (res < -1 || res == 0) in repeat_store()
223 return -EINVAL; in repeat_store()
225 mutex_lock(&data->lock); in repeat_store()
229 if (data->type == PATTERN_TYPE_HW) in repeat_store()
230 led_cdev->pattern_clear(led_cdev); in repeat_store()
232 data->last_repeat = data->repeat = res; in repeat_store()
233 /* -1 means repeat indefinitely */ in repeat_store()
234 if (data->repeat == -1) in repeat_store()
235 data->is_indefinite = true; in repeat_store()
237 data->is_indefinite = false; in repeat_store()
241 mutex_unlock(&data->lock); in repeat_store()
253 mutex_lock(&data->lock); in pattern_trig_show_patterns()
255 if (!data->npatterns || data->type != type) in pattern_trig_show_patterns()
258 for (i = 0; i < data->npatterns; i++) { in pattern_trig_show_patterns()
259 count += scnprintf(buf + count, PAGE_SIZE - count, in pattern_trig_show_patterns()
261 data->patterns[i].brightness, in pattern_trig_show_patterns()
262 data->patterns[i].delta_t); in pattern_trig_show_patterns()
265 buf[count - 1] = '\n'; in pattern_trig_show_patterns()
268 mutex_unlock(&data->lock); in pattern_trig_show_patterns()
277 while (offset < count - 1 && data->npatterns < MAX_PATTERNS) { in pattern_trig_store_patterns_string()
280 &data->patterns[data->npatterns].brightness, in pattern_trig_store_patterns_string()
281 &data->patterns[data->npatterns].delta_t, &cr); in pattern_trig_store_patterns_string()
284 data->patterns[data->npatterns].brightness > data->led_cdev->max_brightness) { in pattern_trig_store_patterns_string()
285 data->npatterns = 0; in pattern_trig_store_patterns_string()
286 return -EINVAL; in pattern_trig_store_patterns_string()
290 data->npatterns++; in pattern_trig_store_patterns_string()
302 data->patterns[data->npatterns].brightness = buf[i]; in pattern_trig_store_patterns_int()
303 data->patterns[data->npatterns].delta_t = buf[i + 1]; in pattern_trig_store_patterns_int()
304 data->npatterns++; in pattern_trig_store_patterns_int()
314 struct pattern_trig_data *data = led_cdev->trigger_data; in pattern_trig_store_patterns()
317 mutex_lock(&data->lock); in pattern_trig_store_patterns()
321 if (data->type == PATTERN_TYPE_HW) in pattern_trig_store_patterns()
322 led_cdev->pattern_clear(led_cdev); in pattern_trig_store_patterns()
324 data->type = type; in pattern_trig_store_patterns()
325 data->npatterns = 0; in pattern_trig_store_patterns()
336 data->npatterns = 0; in pattern_trig_store_patterns()
339 mutex_unlock(&data->lock); in pattern_trig_store_patterns()
347 struct pattern_trig_data *data = led_cdev->trigger_data; in pattern_show()
361 static DEVICE_ATTR_RW(pattern);
367 struct pattern_trig_data *data = led_cdev->trigger_data; in hw_pattern_show()
388 struct pattern_trig_data *data = led_cdev->trigger_data; in hr_pattern_show()
412 return attr->mode; in pattern_trig_attrs_mode()
414 return attr->mode; in pattern_trig_attrs_mode()
415 else if (attr == &dev_attr_hw_pattern.attr && led_cdev->pattern_set) in pattern_trig_attrs_mode()
416 return attr->mode; in pattern_trig_attrs_mode()
442 u32 *pattern; in pattern_init() local
445 pattern = led_get_default_pattern(led_cdev, &size); in pattern_init()
446 if (!pattern) in pattern_init()
450 dev_warn(led_cdev->dev, "Expected pattern of tuples\n"); in pattern_init()
454 err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, in pattern_init()
457 dev_warn(led_cdev->dev, in pattern_init()
458 "Pattern initialization failed with error %d\n", err); in pattern_init()
461 kfree(pattern); in pattern_init()
470 return -ENOMEM; in pattern_trig_activate()
472 if (!!led_cdev->pattern_set ^ !!led_cdev->pattern_clear) { in pattern_trig_activate()
473 dev_warn(led_cdev->dev, in pattern_trig_activate()
474 "Hardware pattern ops validation failed\n"); in pattern_trig_activate()
475 led_cdev->pattern_set = NULL; in pattern_trig_activate()
476 led_cdev->pattern_clear = NULL; in pattern_trig_activate()
479 data->type = PATTERN_TYPE_SW; in pattern_trig_activate()
480 data->is_indefinite = true; in pattern_trig_activate()
481 data->last_repeat = -1; in pattern_trig_activate()
482 mutex_init(&data->lock); in pattern_trig_activate()
483 data->led_cdev = led_cdev; in pattern_trig_activate()
485 timer_setup(&data->timer, pattern_trig_timer_function, 0); in pattern_trig_activate()
486 hrtimer_init(&data->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); in pattern_trig_activate()
487 data->hrtimer.function = pattern_trig_hrtimer_function; in pattern_trig_activate()
488 led_cdev->activated = true; in pattern_trig_activate()
490 if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { in pattern_trig_activate()
496 led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; in pattern_trig_activate()
504 struct pattern_trig_data *data = led_cdev->trigger_data; in pattern_trig_deactivate()
506 if (!led_cdev->activated) in pattern_trig_deactivate()
509 if (led_cdev->pattern_clear) in pattern_trig_deactivate()
510 led_cdev->pattern_clear(led_cdev); in pattern_trig_deactivate()
512 timer_shutdown_sync(&data->timer); in pattern_trig_deactivate()
513 hrtimer_cancel(&data->hrtimer); in pattern_trig_deactivate()
517 led_cdev->activated = false; in pattern_trig_deactivate()
521 .name = "pattern",
542 MODULE_DESCRIPTION("LED Pattern trigger");