13
13
#include <linux/mutex.h>
14
14
#include <linux/slab.h>
15
15
#include <linux/timer.h>
16
+ #include <linux/hrtimer.h>
16
17
17
18
#define MAX_PATTERNS 1024
18
19
/*
21
22
*/
22
23
#define UPDATE_INTERVAL 50
23
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
+
24
31
struct pattern_trig_data {
25
32
struct led_classdev * led_cdev ;
26
33
struct led_pattern patterns [MAX_PATTERNS ];
@@ -32,8 +39,9 @@ struct pattern_trig_data {
32
39
int last_repeat ;
33
40
int delta_t ;
34
41
bool is_indefinite ;
35
- bool is_hw_pattern ;
42
+ enum pattern_type type ;
36
43
struct timer_list timer ;
44
+ struct hrtimer hrtimer ;
37
45
};
38
46
39
47
static void pattern_trig_update_patterns (struct pattern_trig_data * data )
@@ -71,10 +79,35 @@ static int pattern_trig_compute_brightness(struct pattern_trig_data *data)
71
79
return data -> curr -> brightness - step_brightness ;
72
80
}
73
81
74
- static void pattern_trig_timer_function (struct timer_list * t )
82
+ static void pattern_trig_timer_start (struct pattern_trig_data * data )
75
83
{
76
- struct pattern_trig_data * data = from_timer (data , t , timer );
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
+ }
77
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
+ {
78
111
for (;;) {
79
112
if (!data -> is_indefinite && !data -> repeat )
80
113
break ;
@@ -83,8 +116,7 @@ static void pattern_trig_timer_function(struct timer_list *t)
83
116
/* Step change of brightness */
84
117
led_set_brightness (data -> led_cdev ,
85
118
data -> curr -> brightness );
86
- mod_timer (& data -> timer ,
87
- jiffies + msecs_to_jiffies (data -> curr -> delta_t ));
119
+ pattern_trig_timer_restart (data , data -> curr -> delta_t );
88
120
if (!data -> next -> delta_t ) {
89
121
/* Skip the tuple with zero duration */
90
122
pattern_trig_update_patterns (data );
@@ -106,8 +138,7 @@ static void pattern_trig_timer_function(struct timer_list *t)
106
138
107
139
led_set_brightness (data -> led_cdev ,
108
140
pattern_trig_compute_brightness (data ));
109
- mod_timer (& data -> timer ,
110
- jiffies + msecs_to_jiffies (UPDATE_INTERVAL ));
141
+ pattern_trig_timer_restart (data , UPDATE_INTERVAL );
111
142
112
143
/* Accumulate the gradual dimming time */
113
144
data -> delta_t += UPDATE_INTERVAL ;
@@ -117,14 +148,33 @@ static void pattern_trig_timer_function(struct timer_list *t)
117
148
}
118
149
}
119
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
+
120
170
static int pattern_trig_start_pattern (struct led_classdev * led_cdev )
121
171
{
122
172
struct pattern_trig_data * data = led_cdev -> trigger_data ;
123
173
124
174
if (!data -> npatterns )
125
175
return 0 ;
126
176
127
- if (data -> is_hw_pattern ) {
177
+ if (data -> type == PATTERN_TYPE_HW ) {
128
178
return led_cdev -> pattern_set (led_cdev , data -> patterns ,
129
179
data -> npatterns , data -> repeat );
130
180
}
@@ -136,8 +186,7 @@ static int pattern_trig_start_pattern(struct led_classdev *led_cdev)
136
186
data -> delta_t = 0 ;
137
187
data -> curr = data -> patterns ;
138
188
data -> next = data -> patterns + 1 ;
139
- data -> timer .expires = jiffies ;
140
- add_timer (& data -> timer );
189
+ pattern_trig_timer_start (data );
141
190
142
191
return 0 ;
143
192
}
@@ -175,9 +224,9 @@ static ssize_t repeat_store(struct device *dev, struct device_attribute *attr,
175
224
176
225
mutex_lock (& data -> lock );
177
226
178
- del_timer_sync ( & data -> timer );
227
+ pattern_trig_timer_cancel ( data );
179
228
180
- if (data -> is_hw_pattern )
229
+ if (data -> type == PATTERN_TYPE_HW )
181
230
led_cdev -> pattern_clear (led_cdev );
182
231
183
232
data -> last_repeat = data -> repeat = res ;
@@ -196,14 +245,14 @@ static ssize_t repeat_store(struct device *dev, struct device_attribute *attr,
196
245
static DEVICE_ATTR_RW (repeat );
197
246
198
247
static ssize_t pattern_trig_show_patterns (struct pattern_trig_data * data ,
199
- char * buf , bool hw_pattern )
248
+ char * buf , enum pattern_type type )
200
249
{
201
250
ssize_t count = 0 ;
202
251
int i ;
203
252
204
253
mutex_lock (& data -> lock );
205
254
206
- if (!data -> npatterns || ( data -> is_hw_pattern ^ hw_pattern ) )
255
+ if (!data -> npatterns || data -> type != type )
207
256
goto out ;
208
257
209
258
for (i = 0 ; i < data -> npatterns ; i ++ ) {
@@ -260,19 +309,19 @@ static int pattern_trig_store_patterns_int(struct pattern_trig_data *data,
260
309
261
310
static ssize_t pattern_trig_store_patterns (struct led_classdev * led_cdev ,
262
311
const char * buf , const u32 * buf_int ,
263
- size_t count , bool hw_pattern )
312
+ size_t count , enum pattern_type type )
264
313
{
265
314
struct pattern_trig_data * data = led_cdev -> trigger_data ;
266
315
int err = 0 ;
267
316
268
317
mutex_lock (& data -> lock );
269
318
270
- del_timer_sync ( & data -> timer );
319
+ pattern_trig_timer_cancel ( data );
271
320
272
- if (data -> is_hw_pattern )
321
+ if (data -> type == PATTERN_TYPE_HW )
273
322
led_cdev -> pattern_clear (led_cdev );
274
323
275
- data -> is_hw_pattern = hw_pattern ;
324
+ data -> type = type ;
276
325
data -> npatterns = 0 ;
277
326
278
327
if (buf )
@@ -297,15 +346,16 @@ static ssize_t pattern_show(struct device *dev, struct device_attribute *attr,
297
346
struct led_classdev * led_cdev = dev_get_drvdata (dev );
298
347
struct pattern_trig_data * data = led_cdev -> trigger_data ;
299
348
300
- return pattern_trig_show_patterns (data , buf , false );
349
+ return pattern_trig_show_patterns (data , buf , PATTERN_TYPE_SW );
301
350
}
302
351
303
352
static ssize_t pattern_store (struct device * dev , struct device_attribute * attr ,
304
353
const char * buf , size_t count )
305
354
{
306
355
struct led_classdev * led_cdev = dev_get_drvdata (dev );
307
356
308
- return pattern_trig_store_patterns (led_cdev , buf , NULL , count , false);
357
+ return pattern_trig_store_patterns (led_cdev , buf , NULL , count ,
358
+ PATTERN_TYPE_SW );
309
359
}
310
360
311
361
static DEVICE_ATTR_RW (pattern );
@@ -316,7 +366,7 @@ static ssize_t hw_pattern_show(struct device *dev,
316
366
struct led_classdev * led_cdev = dev_get_drvdata (dev );
317
367
struct pattern_trig_data * data = led_cdev -> trigger_data ;
318
368
319
- return pattern_trig_show_patterns (data , buf , true );
369
+ return pattern_trig_show_patterns (data , buf , PATTERN_TYPE_HW );
320
370
}
321
371
322
372
static ssize_t hw_pattern_store (struct device * dev ,
@@ -325,11 +375,33 @@ static ssize_t hw_pattern_store(struct device *dev,
325
375
{
326
376
struct led_classdev * led_cdev = dev_get_drvdata (dev );
327
377
328
- return pattern_trig_store_patterns (led_cdev , buf , NULL , count , true);
378
+ return pattern_trig_store_patterns (led_cdev , buf , NULL , count ,
379
+ PATTERN_TYPE_HW );
329
380
}
330
381
331
382
static DEVICE_ATTR_RW (hw_pattern );
332
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
+
333
405
static umode_t pattern_trig_attrs_mode (struct kobject * kobj ,
334
406
struct attribute * attr , int index )
335
407
{
@@ -338,6 +410,8 @@ static umode_t pattern_trig_attrs_mode(struct kobject *kobj,
338
410
339
411
if (attr == & dev_attr_repeat .attr || attr == & dev_attr_pattern .attr )
340
412
return attr -> mode ;
413
+ else if (attr == & dev_attr_hr_pattern .attr )
414
+ return attr -> mode ;
341
415
else if (attr == & dev_attr_hw_pattern .attr && led_cdev -> pattern_set )
342
416
return attr -> mode ;
343
417
@@ -347,6 +421,7 @@ static umode_t pattern_trig_attrs_mode(struct kobject *kobj,
347
421
static struct attribute * pattern_trig_attrs [] = {
348
422
& dev_attr_pattern .attr ,
349
423
& dev_attr_hw_pattern .attr ,
424
+ & dev_attr_hr_pattern .attr ,
350
425
& dev_attr_repeat .attr ,
351
426
NULL
352
427
};
@@ -376,7 +451,8 @@ static void pattern_init(struct led_classdev *led_cdev)
376
451
goto out ;
377
452
}
378
453
379
- err = pattern_trig_store_patterns (led_cdev , NULL , pattern , size , false);
454
+ err = pattern_trig_store_patterns (led_cdev , NULL , pattern , size ,
455
+ PATTERN_TYPE_SW );
380
456
if (err < 0 )
381
457
dev_warn (led_cdev -> dev ,
382
458
"Pattern initialization failed with error %d\n" , err );
@@ -400,12 +476,15 @@ static int pattern_trig_activate(struct led_classdev *led_cdev)
400
476
led_cdev -> pattern_clear = NULL ;
401
477
}
402
478
479
+ data -> type = PATTERN_TYPE_SW ;
403
480
data -> is_indefinite = true;
404
481
data -> last_repeat = -1 ;
405
482
mutex_init (& data -> lock );
406
483
data -> led_cdev = led_cdev ;
407
484
led_set_trigger_data (led_cdev , data );
408
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 ;
409
488
led_cdev -> activated = true;
410
489
411
490
if (led_cdev -> flags & LED_INIT_DEFAULT_TRIGGER ) {
@@ -431,6 +510,7 @@ static void pattern_trig_deactivate(struct led_classdev *led_cdev)
431
510
led_cdev -> pattern_clear (led_cdev );
432
511
433
512
timer_shutdown_sync (& data -> timer );
513
+ hrtimer_cancel (& data -> hrtimer );
434
514
435
515
led_set_brightness (led_cdev , LED_OFF );
436
516
kfree (data );
0 commit comments