Merge branch 'address-masking'
[linux-2.6-microblaze.git] / drivers / leds / trigger / ledtrig-pattern.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4  * LED pattern trigger
5  *
6  * Idea discussed with Pavel Machek. Raphael Teysseyre implemented
7  * the first version, Baolin Wang simplified and improved the approach.
8  */
9
10 #include <linux/kernel.h>
11 #include <linux/leds.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/slab.h>
15 #include <linux/timer.h>
16 #include <linux/hrtimer.h>
17
18 #define MAX_PATTERNS            1024
19 /*
20  * When doing gradual dimming, the led brightness will be updated
21  * every 50 milliseconds.
22  */
23 #define UPDATE_INTERVAL         50
24
25 enum pattern_type {
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 */
29 };
30
31 struct pattern_trig_data {
32         struct led_classdev *led_cdev;
33         struct led_pattern patterns[MAX_PATTERNS];
34         struct led_pattern *curr;
35         struct led_pattern *next;
36         struct mutex lock;
37         u32 npatterns;
38         int repeat;
39         int last_repeat;
40         int delta_t;
41         bool is_indefinite;
42         enum pattern_type type;
43         struct timer_list timer;
44         struct hrtimer hrtimer;
45 };
46
47 static void pattern_trig_update_patterns(struct pattern_trig_data *data)
48 {
49         data->curr = data->next;
50         if (!data->is_indefinite && data->curr == data->patterns)
51                 data->repeat--;
52
53         if (data->next == data->patterns + data->npatterns - 1)
54                 data->next = data->patterns;
55         else
56                 data->next++;
57
58         data->delta_t = 0;
59 }
60
61 static int pattern_trig_compute_brightness(struct pattern_trig_data *data)
62 {
63         int step_brightness;
64
65         /*
66          * If current tuple's duration is less than the dimming interval,
67          * we should treat it as a step change of brightness instead of
68          * doing gradual dimming.
69          */
70         if (data->delta_t == 0 || data->curr->delta_t < UPDATE_INTERVAL)
71                 return data->curr->brightness;
72
73         step_brightness = abs(data->next->brightness - data->curr->brightness);
74         step_brightness = data->delta_t * step_brightness / data->curr->delta_t;
75
76         if (data->next->brightness > data->curr->brightness)
77                 return data->curr->brightness + step_brightness;
78         else
79                 return data->curr->brightness - step_brightness;
80 }
81
82 static void pattern_trig_timer_start(struct pattern_trig_data *data)
83 {
84         if (data->type == PATTERN_TYPE_HR) {
85                 hrtimer_start(&data->hrtimer, ns_to_ktime(0), HRTIMER_MODE_REL);
86         } else {
87                 data->timer.expires = jiffies;
88                 add_timer(&data->timer);
89         }
90 }
91
92 static void pattern_trig_timer_cancel(struct pattern_trig_data *data)
93 {
94         if (data->type == PATTERN_TYPE_HR)
95                 hrtimer_cancel(&data->hrtimer);
96         else
97                 del_timer_sync(&data->timer);
98 }
99
100 static void pattern_trig_timer_restart(struct pattern_trig_data *data,
101                                        unsigned long interval)
102 {
103         if (data->type == PATTERN_TYPE_HR)
104                 hrtimer_forward_now(&data->hrtimer, ms_to_ktime(interval));
105         else
106                 mod_timer(&data->timer, jiffies + msecs_to_jiffies(interval));
107 }
108
109 static void pattern_trig_timer_common_function(struct pattern_trig_data *data)
110 {
111         for (;;) {
112                 if (!data->is_indefinite && !data->repeat)
113                         break;
114
115                 if (data->curr->brightness == data->next->brightness) {
116                         /* Step change of brightness */
117                         led_set_brightness(data->led_cdev,
118                                            data->curr->brightness);
119                         pattern_trig_timer_restart(data, data->curr->delta_t);
120                         if (!data->next->delta_t) {
121                                 /* Skip the tuple with zero duration */
122                                 pattern_trig_update_patterns(data);
123                         }
124                         /* Select next tuple */
125                         pattern_trig_update_patterns(data);
126                 } else {
127                         /* Gradual dimming */
128
129                         /*
130                          * If the accumulation time is larger than current
131                          * tuple's duration, we should go next one and re-check
132                          * if we repeated done.
133                          */
134                         if (data->delta_t > data->curr->delta_t) {
135                                 pattern_trig_update_patterns(data);
136                                 continue;
137                         }
138
139                         led_set_brightness(data->led_cdev,
140                                            pattern_trig_compute_brightness(data));
141                         pattern_trig_timer_restart(data, UPDATE_INTERVAL);
142
143                         /* Accumulate the gradual dimming time */
144                         data->delta_t += UPDATE_INTERVAL;
145                 }
146
147                 break;
148         }
149 }
150
151 static void pattern_trig_timer_function(struct timer_list *t)
152 {
153         struct pattern_trig_data *data = from_timer(data, t, timer);
154
155         return pattern_trig_timer_common_function(data);
156 }
157
158 static enum hrtimer_restart pattern_trig_hrtimer_function(struct hrtimer *t)
159 {
160         struct pattern_trig_data *data =
161                 container_of(t, struct pattern_trig_data, hrtimer);
162
163         pattern_trig_timer_common_function(data);
164         if (!data->is_indefinite && !data->repeat)
165                 return HRTIMER_NORESTART;
166
167         return HRTIMER_RESTART;
168 }
169
170 static int pattern_trig_start_pattern(struct led_classdev *led_cdev)
171 {
172         struct pattern_trig_data *data = led_cdev->trigger_data;
173
174         if (!data->npatterns)
175                 return 0;
176
177         if (data->type == PATTERN_TYPE_HW) {
178                 return led_cdev->pattern_set(led_cdev, data->patterns,
179                                              data->npatterns, data->repeat);
180         }
181
182         /* At least 2 tuples for software pattern. */
183         if (data->npatterns < 2)
184                 return -EINVAL;
185
186         data->delta_t = 0;
187         data->curr = data->patterns;
188         data->next = data->patterns + 1;
189         pattern_trig_timer_start(data);
190
191         return 0;
192 }
193
194 static ssize_t repeat_show(struct device *dev, struct device_attribute *attr,
195                            char *buf)
196 {
197         struct led_classdev *led_cdev = dev_get_drvdata(dev);
198         struct pattern_trig_data *data = led_cdev->trigger_data;
199         int repeat;
200
201         mutex_lock(&data->lock);
202
203         repeat = data->last_repeat;
204
205         mutex_unlock(&data->lock);
206
207         return sysfs_emit(buf, "%d\n", repeat);
208 }
209
210 static ssize_t repeat_store(struct device *dev, struct device_attribute *attr,
211                             const char *buf, size_t count)
212 {
213         struct led_classdev *led_cdev = dev_get_drvdata(dev);
214         struct pattern_trig_data *data = led_cdev->trigger_data;
215         int err, res;
216
217         err = kstrtos32(buf, 10, &res);
218         if (err)
219                 return err;
220
221         /* Number 0 and negative numbers except -1 are invalid. */
222         if (res < -1 || res == 0)
223                 return -EINVAL;
224
225         mutex_lock(&data->lock);
226
227         pattern_trig_timer_cancel(data);
228
229         if (data->type == PATTERN_TYPE_HW)
230                 led_cdev->pattern_clear(led_cdev);
231
232         data->last_repeat = data->repeat = res;
233         /* -1 means repeat indefinitely */
234         if (data->repeat == -1)
235                 data->is_indefinite = true;
236         else
237                 data->is_indefinite = false;
238
239         err = pattern_trig_start_pattern(led_cdev);
240
241         mutex_unlock(&data->lock);
242         return err < 0 ? err : count;
243 }
244
245 static DEVICE_ATTR_RW(repeat);
246
247 static ssize_t pattern_trig_show_patterns(struct pattern_trig_data *data,
248                                           char *buf, enum pattern_type type)
249 {
250         ssize_t count = 0;
251         int i;
252
253         mutex_lock(&data->lock);
254
255         if (!data->npatterns || data->type != type)
256                 goto out;
257
258         for (i = 0; i < data->npatterns; i++) {
259                 count += scnprintf(buf + count, PAGE_SIZE - count,
260                                    "%d %u ",
261                                    data->patterns[i].brightness,
262                                    data->patterns[i].delta_t);
263         }
264
265         buf[count - 1] = '\n';
266
267 out:
268         mutex_unlock(&data->lock);
269         return count;
270 }
271
272 static int pattern_trig_store_patterns_string(struct pattern_trig_data *data,
273                                               const char *buf, size_t count)
274 {
275         int ccount, cr, offset = 0;
276
277         while (offset < count - 1 && data->npatterns < MAX_PATTERNS) {
278                 cr = 0;
279                 ccount = sscanf(buf + offset, "%u %u %n",
280                                 &data->patterns[data->npatterns].brightness,
281                                 &data->patterns[data->npatterns].delta_t, &cr);
282
283                 if (ccount != 2 ||
284                     data->patterns[data->npatterns].brightness > data->led_cdev->max_brightness) {
285                         data->npatterns = 0;
286                         return -EINVAL;
287                 }
288
289                 offset += cr;
290                 data->npatterns++;
291         }
292
293         return 0;
294 }
295
296 static int pattern_trig_store_patterns_int(struct pattern_trig_data *data,
297                                            const u32 *buf, size_t count)
298 {
299         unsigned int i;
300
301         for (i = 0; i < count; i += 2) {
302                 data->patterns[data->npatterns].brightness = buf[i];
303                 data->patterns[data->npatterns].delta_t = buf[i + 1];
304                 data->npatterns++;
305         }
306
307         return 0;
308 }
309
310 static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
311                                            const char *buf, const u32 *buf_int,
312                                            size_t count, enum pattern_type type)
313 {
314         struct pattern_trig_data *data = led_cdev->trigger_data;
315         int err = 0;
316
317         mutex_lock(&data->lock);
318
319         pattern_trig_timer_cancel(data);
320
321         if (data->type == PATTERN_TYPE_HW)
322                 led_cdev->pattern_clear(led_cdev);
323
324         data->type = type;
325         data->npatterns = 0;
326
327         if (buf)
328                 err = pattern_trig_store_patterns_string(data, buf, count);
329         else
330                 err = pattern_trig_store_patterns_int(data, buf_int, count);
331         if (err)
332                 goto out;
333
334         err = pattern_trig_start_pattern(led_cdev);
335         if (err)
336                 data->npatterns = 0;
337
338 out:
339         mutex_unlock(&data->lock);
340         return err < 0 ? err : count;
341 }
342
343 static ssize_t pattern_show(struct device *dev, struct device_attribute *attr,
344                             char *buf)
345 {
346         struct led_classdev *led_cdev = dev_get_drvdata(dev);
347         struct pattern_trig_data *data = led_cdev->trigger_data;
348
349         return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_SW);
350 }
351
352 static ssize_t pattern_store(struct device *dev, struct device_attribute *attr,
353                              const char *buf, size_t count)
354 {
355         struct led_classdev *led_cdev = dev_get_drvdata(dev);
356
357         return pattern_trig_store_patterns(led_cdev, buf, NULL, count,
358                                            PATTERN_TYPE_SW);
359 }
360
361 static DEVICE_ATTR_RW(pattern);
362
363 static ssize_t hw_pattern_show(struct device *dev,
364                                struct device_attribute *attr, char *buf)
365 {
366         struct led_classdev *led_cdev = dev_get_drvdata(dev);
367         struct pattern_trig_data *data = led_cdev->trigger_data;
368
369         return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_HW);
370 }
371
372 static ssize_t hw_pattern_store(struct device *dev,
373                                 struct device_attribute *attr,
374                                 const char *buf, size_t count)
375 {
376         struct led_classdev *led_cdev = dev_get_drvdata(dev);
377
378         return pattern_trig_store_patterns(led_cdev, buf, NULL, count,
379                                            PATTERN_TYPE_HW);
380 }
381
382 static DEVICE_ATTR_RW(hw_pattern);
383
384 static ssize_t hr_pattern_show(struct device *dev,
385                                struct device_attribute *attr, char *buf)
386 {
387         struct led_classdev *led_cdev = dev_get_drvdata(dev);
388         struct pattern_trig_data *data = led_cdev->trigger_data;
389
390         return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_HR);
391 }
392
393 static ssize_t hr_pattern_store(struct device *dev,
394                                 struct device_attribute *attr,
395                                 const char *buf, size_t count)
396 {
397         struct led_classdev *led_cdev = dev_get_drvdata(dev);
398
399         return pattern_trig_store_patterns(led_cdev, buf, NULL, count,
400                                            PATTERN_TYPE_HR);
401 }
402
403 static DEVICE_ATTR_RW(hr_pattern);
404
405 static umode_t pattern_trig_attrs_mode(struct kobject *kobj,
406                                        struct attribute *attr, int index)
407 {
408         struct device *dev = kobj_to_dev(kobj);
409         struct led_classdev *led_cdev = dev_get_drvdata(dev);
410
411         if (attr == &dev_attr_repeat.attr || attr == &dev_attr_pattern.attr)
412                 return attr->mode;
413         else if (attr == &dev_attr_hr_pattern.attr)
414                 return attr->mode;
415         else if (attr == &dev_attr_hw_pattern.attr && led_cdev->pattern_set)
416                 return attr->mode;
417
418         return 0;
419 }
420
421 static struct attribute *pattern_trig_attrs[] = {
422         &dev_attr_pattern.attr,
423         &dev_attr_hw_pattern.attr,
424         &dev_attr_hr_pattern.attr,
425         &dev_attr_repeat.attr,
426         NULL
427 };
428
429 static const struct attribute_group pattern_trig_group = {
430         .attrs = pattern_trig_attrs,
431         .is_visible = pattern_trig_attrs_mode,
432 };
433
434 static const struct attribute_group *pattern_trig_groups[] = {
435         &pattern_trig_group,
436         NULL,
437 };
438
439 static void pattern_init(struct led_classdev *led_cdev)
440 {
441         unsigned int size = 0;
442         u32 *pattern;
443         int err;
444
445         pattern = led_get_default_pattern(led_cdev, &size);
446         if (!pattern)
447                 return;
448
449         if (size % 2) {
450                 dev_warn(led_cdev->dev, "Expected pattern of tuples\n");
451                 goto out;
452         }
453
454         err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size,
455                                           PATTERN_TYPE_SW);
456         if (err < 0)
457                 dev_warn(led_cdev->dev,
458                          "Pattern initialization failed with error %d\n", err);
459
460 out:
461         kfree(pattern);
462 }
463
464 static int pattern_trig_activate(struct led_classdev *led_cdev)
465 {
466         struct pattern_trig_data *data;
467
468         data = kzalloc(sizeof(*data), GFP_KERNEL);
469         if (!data)
470                 return -ENOMEM;
471
472         if (!!led_cdev->pattern_set ^ !!led_cdev->pattern_clear) {
473                 dev_warn(led_cdev->dev,
474                          "Hardware pattern ops validation failed\n");
475                 led_cdev->pattern_set = NULL;
476                 led_cdev->pattern_clear = NULL;
477         }
478
479         data->type = PATTERN_TYPE_SW;
480         data->is_indefinite = true;
481         data->last_repeat = -1;
482         mutex_init(&data->lock);
483         data->led_cdev = led_cdev;
484         led_set_trigger_data(led_cdev, data);
485         timer_setup(&data->timer, pattern_trig_timer_function, 0);
486         hrtimer_init(&data->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
487         data->hrtimer.function = pattern_trig_hrtimer_function;
488         led_cdev->activated = true;
489
490         if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) {
491                 pattern_init(led_cdev);
492                 /*
493                  * Mark as initialized even on pattern_init() error because
494                  * any consecutive call to it would produce the same error.
495                  */
496                 led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER;
497         }
498
499         return 0;
500 }
501
502 static void pattern_trig_deactivate(struct led_classdev *led_cdev)
503 {
504         struct pattern_trig_data *data = led_cdev->trigger_data;
505
506         if (!led_cdev->activated)
507                 return;
508
509         if (led_cdev->pattern_clear)
510                 led_cdev->pattern_clear(led_cdev);
511
512         timer_shutdown_sync(&data->timer);
513         hrtimer_cancel(&data->hrtimer);
514
515         led_set_brightness(led_cdev, LED_OFF);
516         kfree(data);
517         led_cdev->activated = false;
518 }
519
520 static struct led_trigger pattern_led_trigger = {
521         .name = "pattern",
522         .activate = pattern_trig_activate,
523         .deactivate = pattern_trig_deactivate,
524         .groups = pattern_trig_groups,
525 };
526
527 static int __init pattern_trig_init(void)
528 {
529         return led_trigger_register(&pattern_led_trigger);
530 }
531
532 static void __exit pattern_trig_exit(void)
533 {
534         led_trigger_unregister(&pattern_led_trigger);
535 }
536
537 module_init(pattern_trig_init);
538 module_exit(pattern_trig_exit);
539
540 MODULE_AUTHOR("Raphael Teysseyre <rteysseyre@gmail.com>");
541 MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org>");
542 MODULE_DESCRIPTION("LED Pattern trigger");
543 MODULE_LICENSE("GPL v2");