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(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(led_cdev
, transient_data
->restore_state
);
79 /* start timer if there is no active timer */
80 if (state
== 1 && transient_data
->activate
== 0 &&
81 transient_data
->duration
!= 0) {
82 transient_data
->activate
= state
;
83 __led_set_brightness(led_cdev
, transient_data
->state
);
84 transient_data
->restore_state
=
85 (transient_data
->state
== LED_FULL
) ? LED_OFF
: LED_FULL
;
86 mod_timer(&transient_data
->timer
,
87 jiffies
+ transient_data
->duration
);
90 /* state == 0 && transient_data->activate == 0
91 timer is not active - just return */
92 /* state == 1 && transient_data->activate == 1
93 timer is already active - just return */
98 static ssize_t
transient_duration_show(struct device
*dev
,
99 struct device_attribute
*attr
, char *buf
)
101 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
102 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
104 return sprintf(buf
, "%lu\n", transient_data
->duration
);
107 static ssize_t
transient_duration_store(struct device
*dev
,
108 struct device_attribute
*attr
, const char *buf
, size_t size
)
110 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
111 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
115 ret
= kstrtoul(buf
, 10, &state
);
119 transient_data
->duration
= state
;
123 static ssize_t
transient_state_show(struct device
*dev
,
124 struct device_attribute
*attr
, char *buf
)
126 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
127 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
130 state
= (transient_data
->state
== LED_FULL
) ? 1 : 0;
131 return sprintf(buf
, "%d\n", state
);
134 static ssize_t
transient_state_store(struct device
*dev
,
135 struct device_attribute
*attr
, const char *buf
, size_t size
)
137 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
138 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
142 ret
= kstrtoul(buf
, 10, &state
);
146 if (state
!= 1 && state
!= 0)
149 transient_data
->state
= (state
== 1) ? LED_FULL
: LED_OFF
;
153 static DEVICE_ATTR(activate
, 0644, transient_activate_show
,
154 transient_activate_store
);
155 static DEVICE_ATTR(duration
, 0644, transient_duration_show
,
156 transient_duration_store
);
157 static DEVICE_ATTR(state
, 0644, transient_state_show
, transient_state_store
);
159 static void transient_trig_activate(struct led_classdev
*led_cdev
)
162 struct transient_trig_data
*tdata
;
164 tdata
= kzalloc(sizeof(struct transient_trig_data
), GFP_KERNEL
);
166 dev_err(led_cdev
->dev
,
167 "unable to allocate transient trigger\n");
170 led_cdev
->trigger_data
= tdata
;
172 rc
= device_create_file(led_cdev
->dev
, &dev_attr_activate
);
176 rc
= device_create_file(led_cdev
->dev
, &dev_attr_duration
);
178 goto err_out_duration
;
180 rc
= device_create_file(led_cdev
->dev
, &dev_attr_state
);
184 setup_timer(&tdata
->timer
, transient_timer_function
,
185 (unsigned long) led_cdev
);
186 led_cdev
->activated
= true;
191 device_remove_file(led_cdev
->dev
, &dev_attr_duration
);
193 device_remove_file(led_cdev
->dev
, &dev_attr_activate
);
195 dev_err(led_cdev
->dev
, "unable to register transient trigger\n");
196 led_cdev
->trigger_data
= NULL
;
200 static void transient_trig_deactivate(struct led_classdev
*led_cdev
)
202 struct transient_trig_data
*transient_data
= led_cdev
->trigger_data
;
204 if (led_cdev
->activated
) {
205 del_timer_sync(&transient_data
->timer
);
206 __led_set_brightness(led_cdev
, transient_data
->restore_state
);
207 device_remove_file(led_cdev
->dev
, &dev_attr_activate
);
208 device_remove_file(led_cdev
->dev
, &dev_attr_duration
);
209 device_remove_file(led_cdev
->dev
, &dev_attr_state
);
210 led_cdev
->trigger_data
= NULL
;
211 led_cdev
->activated
= false;
212 kfree(transient_data
);
216 static struct led_trigger transient_trigger
= {
218 .activate
= transient_trig_activate
,
219 .deactivate
= transient_trig_deactivate
,
222 static int __init
transient_trig_init(void)
224 return led_trigger_register(&transient_trigger
);
227 static void __exit
transient_trig_exit(void)
229 led_trigger_unregister(&transient_trigger
);
232 module_init(transient_trig_init
);
233 module_exit(transient_trig_exit
);
235 MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>");
236 MODULE_DESCRIPTION("Transient LED trigger");
237 MODULE_LICENSE("GPL");