1313#include <linux/mutex.h>
1414#include <linux/slab.h>
1515#include <linux/timer.h>
16+ #include <linux/hrtimer.h>
1617
1718#define MAX_PATTERNS 1024
1819/*
2122 */
2223#define UPDATE_INTERVAL 50
2324
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+
2431struct pattern_trig_data {
2532 struct led_classdev * led_cdev ;
2633 struct led_pattern patterns [MAX_PATTERNS ];
@@ -32,8 +39,9 @@ struct pattern_trig_data {
3239 int last_repeat ;
3340 int delta_t ;
3441 bool is_indefinite ;
35- bool is_hw_pattern ;
42+ enum pattern_type type ;
3643 struct timer_list timer ;
44+ struct hrtimer hrtimer ;
3745};
3846
3947static 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)
7179 return data -> curr -> brightness - step_brightness ;
7280}
7381
74- static void pattern_trig_timer_function (struct timer_list * t )
82+ static void pattern_trig_timer_start (struct pattern_trig_data * data )
7583{
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+ }
7791
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+ {
78111 for (;;) {
79112 if (!data -> is_indefinite && !data -> repeat )
80113 break ;
@@ -83,8 +116,7 @@ static void pattern_trig_timer_function(struct timer_list *t)
83116 /* Step change of brightness */
84117 led_set_brightness (data -> led_cdev ,
85118 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 );
88120 if (!data -> next -> delta_t ) {
89121 /* Skip the tuple with zero duration */
90122 pattern_trig_update_patterns (data );
@@ -106,8 +138,7 @@ static void pattern_trig_timer_function(struct timer_list *t)
106138
107139 led_set_brightness (data -> led_cdev ,
108140 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 );
111142
112143 /* Accumulate the gradual dimming time */
113144 data -> delta_t += UPDATE_INTERVAL ;
@@ -117,14 +148,33 @@ static void pattern_trig_timer_function(struct timer_list *t)
117148 }
118149}
119150
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+
120170static int pattern_trig_start_pattern (struct led_classdev * led_cdev )
121171{
122172 struct pattern_trig_data * data = led_cdev -> trigger_data ;
123173
124174 if (!data -> npatterns )
125175 return 0 ;
126176
127- if (data -> is_hw_pattern ) {
177+ if (data -> type == PATTERN_TYPE_HW ) {
128178 return led_cdev -> pattern_set (led_cdev , data -> patterns ,
129179 data -> npatterns , data -> repeat );
130180 }
@@ -136,8 +186,7 @@ static int pattern_trig_start_pattern(struct led_classdev *led_cdev)
136186 data -> delta_t = 0 ;
137187 data -> curr = data -> patterns ;
138188 data -> next = data -> patterns + 1 ;
139- data -> timer .expires = jiffies ;
140- add_timer (& data -> timer );
189+ pattern_trig_timer_start (data );
141190
142191 return 0 ;
143192}
@@ -175,9 +224,9 @@ static ssize_t repeat_store(struct device *dev, struct device_attribute *attr,
175224
176225 mutex_lock (& data -> lock );
177226
178- del_timer_sync ( & data -> timer );
227+ pattern_trig_timer_cancel ( data );
179228
180- if (data -> is_hw_pattern )
229+ if (data -> type == PATTERN_TYPE_HW )
181230 led_cdev -> pattern_clear (led_cdev );
182231
183232 data -> last_repeat = data -> repeat = res ;
@@ -196,14 +245,14 @@ static ssize_t repeat_store(struct device *dev, struct device_attribute *attr,
196245static DEVICE_ATTR_RW (repeat );
197246
198247static ssize_t pattern_trig_show_patterns (struct pattern_trig_data * data ,
199- char * buf , bool hw_pattern )
248+ char * buf , enum pattern_type type )
200249{
201250 ssize_t count = 0 ;
202251 int i ;
203252
204253 mutex_lock (& data -> lock );
205254
206- if (!data -> npatterns || ( data -> is_hw_pattern ^ hw_pattern ) )
255+ if (!data -> npatterns || data -> type != type )
207256 goto out ;
208257
209258 for (i = 0 ; i < data -> npatterns ; i ++ ) {
@@ -260,19 +309,19 @@ static int pattern_trig_store_patterns_int(struct pattern_trig_data *data,
260309
261310static ssize_t pattern_trig_store_patterns (struct led_classdev * led_cdev ,
262311 const char * buf , const u32 * buf_int ,
263- size_t count , bool hw_pattern )
312+ size_t count , enum pattern_type type )
264313{
265314 struct pattern_trig_data * data = led_cdev -> trigger_data ;
266315 int err = 0 ;
267316
268317 mutex_lock (& data -> lock );
269318
270- del_timer_sync ( & data -> timer );
319+ pattern_trig_timer_cancel ( data );
271320
272- if (data -> is_hw_pattern )
321+ if (data -> type == PATTERN_TYPE_HW )
273322 led_cdev -> pattern_clear (led_cdev );
274323
275- data -> is_hw_pattern = hw_pattern ;
324+ data -> type = type ;
276325 data -> npatterns = 0 ;
277326
278327 if (buf )
@@ -297,15 +346,16 @@ static ssize_t pattern_show(struct device *dev, struct device_attribute *attr,
297346 struct led_classdev * led_cdev = dev_get_drvdata (dev );
298347 struct pattern_trig_data * data = led_cdev -> trigger_data ;
299348
300- return pattern_trig_show_patterns (data , buf , false );
349+ return pattern_trig_show_patterns (data , buf , PATTERN_TYPE_SW );
301350}
302351
303352static ssize_t pattern_store (struct device * dev , struct device_attribute * attr ,
304353 const char * buf , size_t count )
305354{
306355 struct led_classdev * led_cdev = dev_get_drvdata (dev );
307356
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 );
309359}
310360
311361static DEVICE_ATTR_RW (pattern );
@@ -316,7 +366,7 @@ static ssize_t hw_pattern_show(struct device *dev,
316366 struct led_classdev * led_cdev = dev_get_drvdata (dev );
317367 struct pattern_trig_data * data = led_cdev -> trigger_data ;
318368
319- return pattern_trig_show_patterns (data , buf , true );
369+ return pattern_trig_show_patterns (data , buf , PATTERN_TYPE_HW );
320370}
321371
322372static ssize_t hw_pattern_store (struct device * dev ,
@@ -325,11 +375,33 @@ static ssize_t hw_pattern_store(struct device *dev,
325375{
326376 struct led_classdev * led_cdev = dev_get_drvdata (dev );
327377
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 );
329380}
330381
331382static DEVICE_ATTR_RW (hw_pattern );
332383
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+
333405static umode_t pattern_trig_attrs_mode (struct kobject * kobj ,
334406 struct attribute * attr , int index )
335407{
@@ -338,6 +410,8 @@ static umode_t pattern_trig_attrs_mode(struct kobject *kobj,
338410
339411 if (attr == & dev_attr_repeat .attr || attr == & dev_attr_pattern .attr )
340412 return attr -> mode ;
413+ else if (attr == & dev_attr_hr_pattern .attr )
414+ return attr -> mode ;
341415 else if (attr == & dev_attr_hw_pattern .attr && led_cdev -> pattern_set )
342416 return attr -> mode ;
343417
@@ -347,6 +421,7 @@ static umode_t pattern_trig_attrs_mode(struct kobject *kobj,
347421static struct attribute * pattern_trig_attrs [] = {
348422 & dev_attr_pattern .attr ,
349423 & dev_attr_hw_pattern .attr ,
424+ & dev_attr_hr_pattern .attr ,
350425 & dev_attr_repeat .attr ,
351426 NULL
352427};
@@ -376,7 +451,8 @@ static void pattern_init(struct led_classdev *led_cdev)
376451 goto out ;
377452 }
378453
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 );
380456 if (err < 0 )
381457 dev_warn (led_cdev -> dev ,
382458 "Pattern initialization failed with error %d\n" , err );
@@ -400,12 +476,15 @@ static int pattern_trig_activate(struct led_classdev *led_cdev)
400476 led_cdev -> pattern_clear = NULL ;
401477 }
402478
479+ data -> type = PATTERN_TYPE_SW ;
403480 data -> is_indefinite = true;
404481 data -> last_repeat = -1 ;
405482 mutex_init (& data -> lock );
406483 data -> led_cdev = led_cdev ;
407484 led_set_trigger_data (led_cdev , data );
408485 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 ;
409488 led_cdev -> activated = true;
410489
411490 if (led_cdev -> flags & LED_INIT_DEFAULT_TRIGGER ) {
@@ -431,6 +510,7 @@ static void pattern_trig_deactivate(struct led_classdev *led_cdev)
431510 led_cdev -> pattern_clear (led_cdev );
432511
433512 timer_shutdown_sync (& data -> timer );
513+ hrtimer_cancel (& data -> hrtimer );
434514
435515 led_set_brightness (led_cdev , LED_OFF );
436516 kfree (data );
0 commit comments