2 * LED Kernel Transient Trigger
4 * Copyright (C) 2012 Shuah Khan <shuahkhan@gmail.com>
6 * Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's
8 * Design and use-case input from Jonas Bonn <jonas@southpole.se> and
9 * Neil Brown <neilb@suse.de>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
17 * Transient trigger allows one shot timer activation. Please refer to
18 * Documentation/leds/ledtrig-transient.txt for details
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/device.h>
25 #include <linux/slab.h>
26 #include <linux/timer.h>
27 #include <linux/leds.h>
30 struct transient_trig_data
{
34 unsigned long duration
;
35 struct timer_list timer
;
38 static void transient_timer_function(unsigned long data
)
40 struct led_classdev
*led_cdev
= (struct led_classdev
*) data
;
41 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
43 transient_data
->activate
= 0;
44 led_set_brightness_async(led_cdev
, transient_data
->restore_state
);
47 static ssize_t
transient_activate_show(struct device
*dev
,
48 struct device_attribute
*attr
, char *buf
)
50 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
51 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
53 return sprintf(buf
, "%d\n", transient_data
->activate
);
56 static ssize_t
transient_activate_store(struct device
*dev
,
57 struct device_attribute
*attr
, const char *buf
, size_t size
)
59 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
60 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
64 ret
= kstrtoul(buf
, 10, &state
);
68 if (state
!= 1 && state
!= 0)
71 /* cancel the running timer */
72 if (state
== 0 && transient_data
->activate
== 1) {
73 del_timer(&transient_data
->timer
);
74 transient_data
->activate
= state
;
75 led_set_brightness_async(led_cdev
,
76 transient_data
->restore_state
);
80 /* start timer if there is no active timer */
81 if (state
== 1 && transient_data
->activate
== 0 &&
82 transient_data
->duration
!= 0) {
83 transient_data
->activate
= state
;
84 led_set_brightness_async(led_cdev
, transient_data
->state
);
85 transient_data
->restore_state
=
86 (transient_data
->state
== LED_FULL
) ? LED_OFF
: LED_FULL
;
87 mod_timer(&transient_data
->timer
,
88 jiffies
+ transient_data
->duration
);
91 /* state == 0 && transient_data->activate == 0
92 timer is not active - just return */
93 /* state == 1 && transient_data->activate == 1
94 timer is already active - just return */
99 static ssize_t
transient_duration_show(struct device
*dev
,
100 struct device_attribute
*attr
, char *buf
)
102 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
103 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
105 return sprintf(buf
, "%lu\n", transient_data
->duration
);
108 static ssize_t
transient_duration_store(struct device
*dev
,
109 struct device_attribute
*attr
, const char *buf
, size_t size
)
111 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
112 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
116 ret
= kstrtoul(buf
, 10, &state
);
120 transient_data
->duration
= state
;
124 static ssize_t
transient_state_show(struct device
*dev
,
125 struct device_attribute
*attr
, char *buf
)
127 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
128 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
131 state
= (transient_data
->state
== LED_FULL
) ? 1 : 0;
132 return sprintf(buf
, "%d\n", state
);
135 static ssize_t
transient_state_store(struct device
*dev
,
136 struct device_attribute
*attr
, const char *buf
, size_t size
)
138 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
139 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
143 ret
= kstrtoul(buf
, 10, &state
);
147 if (state
!= 1 && state
!= 0)
150 transient_data
->state
= (state
== 1) ? LED_FULL
: LED_OFF
;
154 static DEVICE_ATTR(activate
, 0644, transient_activate_show
,
155 transient_activate_store
);
156 static DEVICE_ATTR(duration
, 0644, transient_duration_show
,
157 transient_duration_store
);
158 static DEVICE_ATTR(state
, 0644, transient_state_show
, transient_state_store
);
160 static void transient_trig_activate(struct led_classdev
*led_cdev
)
163 struct transient_trig_data
*tdata
;
165 tdata
= kzalloc(sizeof(struct transient_trig_data
), GFP_KERNEL
);
167 dev_err(led_cdev
->dev
,
168 "unable to allocate transient trigger\n");
171 led_cdev
->trigger_data
= tdata
;
173 rc
= device_create_file(led_cdev
->dev
, &dev_attr_activate
);
177 rc
= device_create_file(led_cdev
->dev
, &dev_attr_duration
);
179 goto err_out_duration
;
181 rc
= device_create_file(led_cdev
->dev
, &dev_attr_state
);
185 setup_timer(&tdata
->timer
, transient_timer_function
,
186 (unsigned long) led_cdev
);
187 led_cdev
->activated
= true;
192 device_remove_file(led_cdev
->dev
, &dev_attr_duration
);
194 device_remove_file(led_cdev
->dev
, &dev_attr_activate
);
196 dev_err(led_cdev
->dev
, "unable to register transient trigger\n");
197 led_cdev
->trigger_data
= NULL
;
201 static void transient_trig_deactivate(struct led_classdev
*led_cdev
)
203 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
205 if (led_cdev
->activated
) {
206 del_timer_sync(&transient_data
->timer
);
207 led_set_brightness_async(led_cdev
,
208 transient_data
->restore_state
);
209 device_remove_file(led_cdev
->dev
, &dev_attr_activate
);
210 device_remove_file(led_cdev
->dev
, &dev_attr_duration
);
211 device_remove_file(led_cdev
->dev
, &dev_attr_state
);
212 led_cdev
->trigger_data
= NULL
;
213 led_cdev
->activated
= false;
214 kfree(transient_data
);
218 static struct led_trigger transient_trigger
= {
220 .activate
= transient_trig_activate
,
221 .deactivate
= transient_trig_deactivate
,
224 static int __init
transient_trig_init(void)
226 return led_trigger_register(&transient_trigger
);
229 static void __exit
transient_trig_exit(void)
231 led_trigger_unregister(&transient_trigger
);
234 module_init(transient_trig_init
);
235 module_exit(transient_trig_exit
);
237 MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>");
238 MODULE_DESCRIPTION("Transient LED trigger");
239 MODULE_LICENSE("GPL");