aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds/trigger
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds/trigger')
-rw-r--r--drivers/leds/trigger/Kconfig103
-rw-r--r--drivers/leds/trigger/Makefile9
-rw-r--r--drivers/leds/trigger/ledtrig-backlight.c166
-rw-r--r--drivers/leds/trigger/ledtrig-cpu.c142
-rw-r--r--drivers/leds/trigger/ledtrig-default-on.c45
-rw-r--r--drivers/leds/trigger/ledtrig-gpio.c253
-rw-r--r--drivers/leds/trigger/ledtrig-heartbeat.c161
-rw-r--r--drivers/leds/trigger/ledtrig-ide-disk.c47
-rw-r--r--drivers/leds/trigger/ledtrig-oneshot.c204
-rw-r--r--drivers/leds/trigger/ledtrig-timer.c130
-rw-r--r--drivers/leds/trigger/ledtrig-transient.c237
11 files changed, 1497 insertions, 0 deletions
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
new file mode 100644
index 000000000000..eaa286dc494e
--- /dev/null
+++ b/drivers/leds/trigger/Kconfig
@@ -0,0 +1,103 @@
1menuconfig LEDS_TRIGGERS
2 bool "LED Trigger support"
3 depends on LEDS_CLASS
4 help
5 This option enables trigger support for the leds class.
6 These triggers allow kernel events to drive the LEDs and can
7 be configured via sysfs. If unsure, say Y.
8
9if LEDS_TRIGGERS
10
11config LEDS_TRIGGER_TIMER
12 tristate "LED Timer Trigger"
13 depends on LEDS_TRIGGERS
14 help
15 This allows LEDs to be controlled by a programmable timer
16 via sysfs. Some LED hardware can be programmed to start
17 blinking the LED without any further software interaction.
18 For more details read Documentation/leds/leds-class.txt.
19
20 If unsure, say Y.
21
22config LEDS_TRIGGER_ONESHOT
23 tristate "LED One-shot Trigger"
24 depends on LEDS_TRIGGERS
25 help
26 This allows LEDs to blink in one-shot pulses with parameters
27 controlled via sysfs. It's useful to notify the user on
28 sporadic events, when there are no clear begin and end trap points,
29 or on dense events, where this blinks the LED at constant rate if
30 rearmed continuously.
31
32 It also shows how to use the led_blink_set_oneshot() function.
33
34 If unsure, say Y.
35
36config LEDS_TRIGGER_IDE_DISK
37 bool "LED IDE Disk Trigger"
38 depends on IDE_GD_ATA
39 depends on LEDS_TRIGGERS
40 help
41 This allows LEDs to be controlled by IDE disk activity.
42 If unsure, say Y.
43
44config LEDS_TRIGGER_HEARTBEAT
45 tristate "LED Heartbeat Trigger"
46 depends on LEDS_TRIGGERS
47 help
48 This allows LEDs to be controlled by a CPU load average.
49 The flash frequency is a hyperbolic function of the 1-minute
50 load average.
51 If unsure, say Y.
52
53config LEDS_TRIGGER_BACKLIGHT
54 tristate "LED backlight Trigger"
55 depends on LEDS_TRIGGERS
56 help
57 This allows LEDs to be controlled as a backlight device: they
58 turn off and on when the display is blanked and unblanked.
59
60 If unsure, say N.
61
62config LEDS_TRIGGER_CPU
63 bool "LED CPU Trigger"
64 depends on LEDS_TRIGGERS
65 help
66 This allows LEDs to be controlled by active CPUs. This shows
67 the active CPUs across an array of LEDs so you can see which
68 CPUs are active on the system at any given moment.
69
70 If unsure, say N.
71
72config LEDS_TRIGGER_GPIO
73 tristate "LED GPIO Trigger"
74 depends on LEDS_TRIGGERS
75 depends on GPIOLIB
76 help
77 This allows LEDs to be controlled by gpio events. It's good
78 when using gpios as switches and triggering the needed LEDs
79 from there. One use case is n810's keypad LEDs that could
80 be triggered by this trigger when user slides up to show
81 keypad.
82
83 If unsure, say N.
84
85config LEDS_TRIGGER_DEFAULT_ON
86 tristate "LED Default ON Trigger"
87 depends on LEDS_TRIGGERS
88 help
89 This allows LEDs to be initialised in the ON state.
90 If unsure, say Y.
91
92comment "iptables trigger is under Netfilter config (LED target)"
93 depends on LEDS_TRIGGERS
94
95config LEDS_TRIGGER_TRANSIENT
96 tristate "LED Transient Trigger"
97 depends on LEDS_TRIGGERS
98 help
99 This allows one time activation of a transient state on
100 GPIO/PWM based hardware.
101 If unsure, say Y.
102
103endif # LEDS_TRIGGERS
diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile
new file mode 100644
index 000000000000..554e46ee4c24
--- /dev/null
+++ b/drivers/leds/trigger/Makefile
@@ -0,0 +1,9 @@
1obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
2obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o
3obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
4obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
5obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
6obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
7obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o
8obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
9obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
diff --git a/drivers/leds/trigger/ledtrig-backlight.c b/drivers/leds/trigger/ledtrig-backlight.c
new file mode 100644
index 000000000000..3c9c88a07eb8
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-backlight.c
@@ -0,0 +1,166 @@
1/*
2 * Backlight emulation LED trigger
3 *
4 * Copyright 2008 (C) Rodolfo Giometti <giometti@linux.it>
5 * Copyright 2008 (C) Eurotech S.p.A. <info@eurotech.it>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/init.h>
17#include <linux/fb.h>
18#include <linux/leds.h>
19#include "../leds.h"
20
21#define BLANK 1
22#define UNBLANK 0
23
24struct bl_trig_notifier {
25 struct led_classdev *led;
26 int brightness;
27 int old_status;
28 struct notifier_block notifier;
29 unsigned invert;
30};
31
32static int fb_notifier_callback(struct notifier_block *p,
33 unsigned long event, void *data)
34{
35 struct bl_trig_notifier *n = container_of(p,
36 struct bl_trig_notifier, notifier);
37 struct led_classdev *led = n->led;
38 struct fb_event *fb_event = data;
39 int *blank = fb_event->data;
40 int new_status = *blank ? BLANK : UNBLANK;
41
42 switch (event) {
43 case FB_EVENT_BLANK:
44 if (new_status == n->old_status)
45 break;
46
47 if ((n->old_status == UNBLANK) ^ n->invert) {
48 n->brightness = led->brightness;
49 __led_set_brightness(led, LED_OFF);
50 } else {
51 __led_set_brightness(led, n->brightness);
52 }
53
54 n->old_status = new_status;
55
56 break;
57 }
58
59 return 0;
60}
61
62static ssize_t bl_trig_invert_show(struct device *dev,
63 struct device_attribute *attr, char *buf)
64{
65 struct led_classdev *led = dev_get_drvdata(dev);
66 struct bl_trig_notifier *n = led->trigger_data;
67
68 return sprintf(buf, "%u\n", n->invert);
69}
70
71static ssize_t bl_trig_invert_store(struct device *dev,
72 struct device_attribute *attr, const char *buf, size_t num)
73{
74 struct led_classdev *led = dev_get_drvdata(dev);
75 struct bl_trig_notifier *n = led->trigger_data;
76 unsigned long invert;
77 int ret;
78
79 ret = kstrtoul(buf, 10, &invert);
80 if (ret < 0)
81 return ret;
82
83 if (invert > 1)
84 return -EINVAL;
85
86 n->invert = invert;
87
88 /* After inverting, we need to update the LED. */
89 if ((n->old_status == BLANK) ^ n->invert)
90 __led_set_brightness(led, LED_OFF);
91 else
92 __led_set_brightness(led, n->brightness);
93
94 return num;
95}
96static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store);
97
98static void bl_trig_activate(struct led_classdev *led)
99{
100 int ret;
101
102 struct bl_trig_notifier *n;
103
104 n = kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL);
105 led->trigger_data = n;
106 if (!n) {
107 dev_err(led->dev, "unable to allocate backlight trigger\n");
108 return;
109 }
110
111 ret = device_create_file(led->dev, &dev_attr_inverted);
112 if (ret)
113 goto err_invert;
114
115 n->led = led;
116 n->brightness = led->brightness;
117 n->old_status = UNBLANK;
118 n->notifier.notifier_call = fb_notifier_callback;
119
120 ret = fb_register_client(&n->notifier);
121 if (ret)
122 dev_err(led->dev, "unable to register backlight trigger\n");
123 led->activated = true;
124
125 return;
126
127err_invert:
128 led->trigger_data = NULL;
129 kfree(n);
130}
131
132static void bl_trig_deactivate(struct led_classdev *led)
133{
134 struct bl_trig_notifier *n =
135 (struct bl_trig_notifier *) led->trigger_data;
136
137 if (led->activated) {
138 device_remove_file(led->dev, &dev_attr_inverted);
139 fb_unregister_client(&n->notifier);
140 kfree(n);
141 led->activated = false;
142 }
143}
144
145static struct led_trigger bl_led_trigger = {
146 .name = "backlight",
147 .activate = bl_trig_activate,
148 .deactivate = bl_trig_deactivate
149};
150
151static int __init bl_trig_init(void)
152{
153 return led_trigger_register(&bl_led_trigger);
154}
155
156static void __exit bl_trig_exit(void)
157{
158 led_trigger_unregister(&bl_led_trigger);
159}
160
161module_init(bl_trig_init);
162module_exit(bl_trig_exit);
163
164MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
165MODULE_DESCRIPTION("Backlight emulation LED trigger");
166MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c
new file mode 100644
index 000000000000..118335eccc56
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-cpu.c
@@ -0,0 +1,142 @@
1/*
2 * ledtrig-cpu.c - LED trigger based on CPU activity
3 *
4 * This LED trigger will be registered for each possible CPU and named as
5 * cpu0, cpu1, cpu2, cpu3, etc.
6 *
7 * It can be bound to any LED just like other triggers using either a
8 * board file or via sysfs interface.
9 *
10 * An API named ledtrig_cpu is exported for any user, who want to add CPU
11 * activity indication in their code
12 *
13 * Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
14 * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com>
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/kernel.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/percpu.h>
27#include <linux/syscore_ops.h>
28#include <linux/rwsem.h>
29#include "../leds.h"
30
31#define MAX_NAME_LEN 8
32
33struct led_trigger_cpu {
34 char name[MAX_NAME_LEN];
35 struct led_trigger *_trig;
36};
37
38static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
39
40/**
41 * ledtrig_cpu - emit a CPU event as a trigger
42 * @evt: CPU event to be emitted
43 *
44 * Emit a CPU event on a CPU core, which will trigger a
45 * binded LED to turn on or turn off.
46 */
47void ledtrig_cpu(enum cpu_led_event ledevt)
48{
49 struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig);
50
51 /* Locate the correct CPU LED */
52 switch (ledevt) {
53 case CPU_LED_IDLE_END:
54 case CPU_LED_START:
55 /* Will turn the LED on, max brightness */
56 led_trigger_event(trig->_trig, LED_FULL);
57 break;
58
59 case CPU_LED_IDLE_START:
60 case CPU_LED_STOP:
61 case CPU_LED_HALTED:
62 /* Will turn the LED off */
63 led_trigger_event(trig->_trig, LED_OFF);
64 break;
65
66 default:
67 /* Will leave the LED as it is */
68 break;
69 }
70}
71EXPORT_SYMBOL(ledtrig_cpu);
72
73static int ledtrig_cpu_syscore_suspend(void)
74{
75 ledtrig_cpu(CPU_LED_STOP);
76 return 0;
77}
78
79static void ledtrig_cpu_syscore_resume(void)
80{
81 ledtrig_cpu(CPU_LED_START);
82}
83
84static void ledtrig_cpu_syscore_shutdown(void)
85{
86 ledtrig_cpu(CPU_LED_HALTED);
87}
88
89static struct syscore_ops ledtrig_cpu_syscore_ops = {
90 .shutdown = ledtrig_cpu_syscore_shutdown,
91 .suspend = ledtrig_cpu_syscore_suspend,
92 .resume = ledtrig_cpu_syscore_resume,
93};
94
95static int __init ledtrig_cpu_init(void)
96{
97 int cpu;
98
99 /* Supports up to 9999 cpu cores */
100 BUILD_BUG_ON(CONFIG_NR_CPUS > 9999);
101
102 /*
103 * Registering CPU led trigger for each CPU core here
104 * ignores CPU hotplug, but after this CPU hotplug works
105 * fine with this trigger.
106 */
107 for_each_possible_cpu(cpu) {
108 struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
109
110 snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
111
112 led_trigger_register_simple(trig->name, &trig->_trig);
113 }
114
115 register_syscore_ops(&ledtrig_cpu_syscore_ops);
116
117 pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n");
118
119 return 0;
120}
121module_init(ledtrig_cpu_init);
122
123static void __exit ledtrig_cpu_exit(void)
124{
125 int cpu;
126
127 for_each_possible_cpu(cpu) {
128 struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
129
130 led_trigger_unregister_simple(trig->_trig);
131 trig->_trig = NULL;
132 memset(trig->name, 0, MAX_NAME_LEN);
133 }
134
135 unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
136}
137module_exit(ledtrig_cpu_exit);
138
139MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
140MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>");
141MODULE_DESCRIPTION("CPU LED trigger");
142MODULE_LICENSE("GPL");
diff --git a/drivers/leds/trigger/ledtrig-default-on.c b/drivers/leds/trigger/ledtrig-default-on.c
new file mode 100644
index 000000000000..81a91be8e18d
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-default-on.c
@@ -0,0 +1,45 @@
1/*
2 * LED Kernel Default ON Trigger
3 *
4 * Copyright 2008 Nick Forbes <nick.forbes@incepta.com>
5 *
6 * Based on Richard Purdie's ledtrig-timer.c.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/leds.h>
18#include "../leds.h"
19
20static void defon_trig_activate(struct led_classdev *led_cdev)
21{
22 __led_set_brightness(led_cdev, led_cdev->max_brightness);
23}
24
25static struct led_trigger defon_led_trigger = {
26 .name = "default-on",
27 .activate = defon_trig_activate,
28};
29
30static int __init defon_trig_init(void)
31{
32 return led_trigger_register(&defon_led_trigger);
33}
34
35static void __exit defon_trig_exit(void)
36{
37 led_trigger_unregister(&defon_led_trigger);
38}
39
40module_init(defon_trig_init);
41module_exit(defon_trig_exit);
42
43MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>");
44MODULE_DESCRIPTION("Default-ON LED trigger");
45MODULE_LICENSE("GPL");
diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c
new file mode 100644
index 000000000000..35812e3a37f2
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-gpio.c
@@ -0,0 +1,253 @@
1/*
2 * ledtrig-gio.c - LED Trigger Based on GPIO events
3 *
4 * Copyright 2009 Felipe Balbi <me@felipebalbi.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/gpio.h>
16#include <linux/interrupt.h>
17#include <linux/workqueue.h>
18#include <linux/leds.h>
19#include <linux/slab.h>
20#include "../leds.h"
21
22struct gpio_trig_data {
23 struct led_classdev *led;
24 struct work_struct work;
25
26 unsigned desired_brightness; /* desired brightness when led is on */
27 unsigned inverted; /* true when gpio is inverted */
28 unsigned gpio; /* gpio that triggers the leds */
29};
30
31static irqreturn_t gpio_trig_irq(int irq, void *_led)
32{
33 struct led_classdev *led = _led;
34 struct gpio_trig_data *gpio_data = led->trigger_data;
35
36 /* just schedule_work since gpio_get_value can sleep */
37 schedule_work(&gpio_data->work);
38
39 return IRQ_HANDLED;
40};
41
42static void gpio_trig_work(struct work_struct *work)
43{
44 struct gpio_trig_data *gpio_data = container_of(work,
45 struct gpio_trig_data, work);
46 int tmp;
47
48 if (!gpio_data->gpio)
49 return;
50
51 tmp = gpio_get_value(gpio_data->gpio);
52 if (gpio_data->inverted)
53 tmp = !tmp;
54
55 if (tmp) {
56 if (gpio_data->desired_brightness)
57 __led_set_brightness(gpio_data->led,
58 gpio_data->desired_brightness);
59 else
60 __led_set_brightness(gpio_data->led, LED_FULL);
61 } else {
62 __led_set_brightness(gpio_data->led, LED_OFF);
63 }
64}
65
66static ssize_t gpio_trig_brightness_show(struct device *dev,
67 struct device_attribute *attr, char *buf)
68{
69 struct led_classdev *led = dev_get_drvdata(dev);
70 struct gpio_trig_data *gpio_data = led->trigger_data;
71
72 return sprintf(buf, "%u\n", gpio_data->desired_brightness);
73}
74
75static ssize_t gpio_trig_brightness_store(struct device *dev,
76 struct device_attribute *attr, const char *buf, size_t n)
77{
78 struct led_classdev *led = dev_get_drvdata(dev);
79 struct gpio_trig_data *gpio_data = led->trigger_data;
80 unsigned desired_brightness;
81 int ret;
82
83 ret = sscanf(buf, "%u", &desired_brightness);
84 if (ret < 1 || desired_brightness > 255) {
85 dev_err(dev, "invalid value\n");
86 return -EINVAL;
87 }
88
89 gpio_data->desired_brightness = desired_brightness;
90
91 return n;
92}
93static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show,
94 gpio_trig_brightness_store);
95
96static ssize_t gpio_trig_inverted_show(struct device *dev,
97 struct device_attribute *attr, char *buf)
98{
99 struct led_classdev *led = dev_get_drvdata(dev);
100 struct gpio_trig_data *gpio_data = led->trigger_data;
101
102 return sprintf(buf, "%u\n", gpio_data->inverted);
103}
104
105static ssize_t gpio_trig_inverted_store(struct device *dev,
106 struct device_attribute *attr, const char *buf, size_t n)
107{
108 struct led_classdev *led = dev_get_drvdata(dev);
109 struct gpio_trig_data *gpio_data = led->trigger_data;
110 unsigned long inverted;
111 int ret;
112
113 ret = kstrtoul(buf, 10, &inverted);
114 if (ret < 0)
115 return ret;
116
117 if (inverted > 1)
118 return -EINVAL;
119
120 gpio_data->inverted = inverted;
121
122 /* After inverting, we need to update the LED. */
123 schedule_work(&gpio_data->work);
124
125 return n;
126}
127static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show,
128 gpio_trig_inverted_store);
129
130static ssize_t gpio_trig_gpio_show(struct device *dev,
131 struct device_attribute *attr, char *buf)
132{
133 struct led_classdev *led = dev_get_drvdata(dev);
134 struct gpio_trig_data *gpio_data = led->trigger_data;
135
136 return sprintf(buf, "%u\n", gpio_data->gpio);
137}
138
139static ssize_t gpio_trig_gpio_store(struct device *dev,
140 struct device_attribute *attr, const char *buf, size_t n)
141{
142 struct led_classdev *led = dev_get_drvdata(dev);
143 struct gpio_trig_data *gpio_data = led->trigger_data;
144 unsigned gpio;
145 int ret;
146
147 ret = sscanf(buf, "%u", &gpio);
148 if (ret < 1) {
149 dev_err(dev, "couldn't read gpio number\n");
150 flush_work(&gpio_data->work);
151 return -EINVAL;
152 }
153
154 if (gpio_data->gpio == gpio)
155 return n;
156
157 if (!gpio) {
158 if (gpio_data->gpio != 0)
159 free_irq(gpio_to_irq(gpio_data->gpio), led);
160 gpio_data->gpio = 0;
161 return n;
162 }
163
164 ret = request_irq(gpio_to_irq(gpio), gpio_trig_irq,
165 IRQF_SHARED | IRQF_TRIGGER_RISING
166 | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led);
167 if (ret) {
168 dev_err(dev, "request_irq failed with error %d\n", ret);
169 } else {
170 if (gpio_data->gpio != 0)
171 free_irq(gpio_to_irq(gpio_data->gpio), led);
172 gpio_data->gpio = gpio;
173 }
174
175 return ret ? ret : n;
176}
177static DEVICE_ATTR(gpio, 0644, gpio_trig_gpio_show, gpio_trig_gpio_store);
178
179static void gpio_trig_activate(struct led_classdev *led)
180{
181 struct gpio_trig_data *gpio_data;
182 int ret;
183
184 gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL);
185 if (!gpio_data)
186 return;
187
188 ret = device_create_file(led->dev, &dev_attr_gpio);
189 if (ret)
190 goto err_gpio;
191
192 ret = device_create_file(led->dev, &dev_attr_inverted);
193 if (ret)
194 goto err_inverted;
195
196 ret = device_create_file(led->dev, &dev_attr_desired_brightness);
197 if (ret)
198 goto err_brightness;
199
200 gpio_data->led = led;
201 led->trigger_data = gpio_data;
202 INIT_WORK(&gpio_data->work, gpio_trig_work);
203 led->activated = true;
204
205 return;
206
207err_brightness:
208 device_remove_file(led->dev, &dev_attr_inverted);
209
210err_inverted:
211 device_remove_file(led->dev, &dev_attr_gpio);
212
213err_gpio:
214 kfree(gpio_data);
215}
216
217static void gpio_trig_deactivate(struct led_classdev *led)
218{
219 struct gpio_trig_data *gpio_data = led->trigger_data;
220
221 if (led->activated) {
222 device_remove_file(led->dev, &dev_attr_gpio);
223 device_remove_file(led->dev, &dev_attr_inverted);
224 device_remove_file(led->dev, &dev_attr_desired_brightness);
225 flush_work(&gpio_data->work);
226 if (gpio_data->gpio != 0)
227 free_irq(gpio_to_irq(gpio_data->gpio), led);
228 kfree(gpio_data);
229 led->activated = false;
230 }
231}
232
233static struct led_trigger gpio_led_trigger = {
234 .name = "gpio",
235 .activate = gpio_trig_activate,
236 .deactivate = gpio_trig_deactivate,
237};
238
239static int __init gpio_trig_init(void)
240{
241 return led_trigger_register(&gpio_led_trigger);
242}
243module_init(gpio_trig_init);
244
245static void __exit gpio_trig_exit(void)
246{
247 led_trigger_unregister(&gpio_led_trigger);
248}
249module_exit(gpio_trig_exit);
250
251MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>");
252MODULE_DESCRIPTION("GPIO LED trigger");
253MODULE_LICENSE("GPL");
diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c
new file mode 100644
index 000000000000..5c8464a33172
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-heartbeat.c
@@ -0,0 +1,161 @@
1/*
2 * LED Heartbeat Trigger
3 *
4 * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
5 *
6 * Based on Richard Purdie's ledtrig-timer.c and some arch's
7 * CONFIG_HEARTBEAT code.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/timer.h>
19#include <linux/sched.h>
20#include <linux/leds.h>
21#include <linux/reboot.h>
22#include "../leds.h"
23
24static int panic_heartbeats;
25
26struct heartbeat_trig_data {
27 unsigned int phase;
28 unsigned int period;
29 struct timer_list timer;
30};
31
32static void led_heartbeat_function(unsigned long data)
33{
34 struct led_classdev *led_cdev = (struct led_classdev *) data;
35 struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
36 unsigned long brightness = LED_OFF;
37 unsigned long delay = 0;
38
39 if (unlikely(panic_heartbeats)) {
40 led_set_brightness(led_cdev, LED_OFF);
41 return;
42 }
43
44 /* acts like an actual heart beat -- ie thump-thump-pause... */
45 switch (heartbeat_data->phase) {
46 case 0:
47 /*
48 * The hyperbolic function below modifies the
49 * heartbeat period length in dependency of the
50 * current (1min) load. It goes through the points
51 * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
52 */
53 heartbeat_data->period = 300 +
54 (6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
55 heartbeat_data->period =
56 msecs_to_jiffies(heartbeat_data->period);
57 delay = msecs_to_jiffies(70);
58 heartbeat_data->phase++;
59 brightness = led_cdev->max_brightness;
60 break;
61 case 1:
62 delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
63 heartbeat_data->phase++;
64 break;
65 case 2:
66 delay = msecs_to_jiffies(70);
67 heartbeat_data->phase++;
68 brightness = led_cdev->max_brightness;
69 break;
70 default:
71 delay = heartbeat_data->period - heartbeat_data->period / 4 -
72 msecs_to_jiffies(70);
73 heartbeat_data->phase = 0;
74 break;
75 }
76
77 __led_set_brightness(led_cdev, brightness);
78 mod_timer(&heartbeat_data->timer, jiffies + delay);
79}
80
81static void heartbeat_trig_activate(struct led_classdev *led_cdev)
82{
83 struct heartbeat_trig_data *heartbeat_data;
84
85 heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
86 if (!heartbeat_data)
87 return;
88
89 led_cdev->trigger_data = heartbeat_data;
90 setup_timer(&heartbeat_data->timer,
91 led_heartbeat_function, (unsigned long) led_cdev);
92 heartbeat_data->phase = 0;
93 led_heartbeat_function(heartbeat_data->timer.data);
94 led_cdev->activated = true;
95}
96
97static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
98{
99 struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
100
101 if (led_cdev->activated) {
102 del_timer_sync(&heartbeat_data->timer);
103 kfree(heartbeat_data);
104 led_cdev->activated = false;
105 }
106}
107
108static struct led_trigger heartbeat_led_trigger = {
109 .name = "heartbeat",
110 .activate = heartbeat_trig_activate,
111 .deactivate = heartbeat_trig_deactivate,
112};
113
114static int heartbeat_reboot_notifier(struct notifier_block *nb,
115 unsigned long code, void *unused)
116{
117 led_trigger_unregister(&heartbeat_led_trigger);
118 return NOTIFY_DONE;
119}
120
121static int heartbeat_panic_notifier(struct notifier_block *nb,
122 unsigned long code, void *unused)
123{
124 panic_heartbeats = 1;
125 return NOTIFY_DONE;
126}
127
128static struct notifier_block heartbeat_reboot_nb = {
129 .notifier_call = heartbeat_reboot_notifier,
130};
131
132static struct notifier_block heartbeat_panic_nb = {
133 .notifier_call = heartbeat_panic_notifier,
134};
135
136static int __init heartbeat_trig_init(void)
137{
138 int rc = led_trigger_register(&heartbeat_led_trigger);
139
140 if (!rc) {
141 atomic_notifier_chain_register(&panic_notifier_list,
142 &heartbeat_panic_nb);
143 register_reboot_notifier(&heartbeat_reboot_nb);
144 }
145 return rc;
146}
147
148static void __exit heartbeat_trig_exit(void)
149{
150 unregister_reboot_notifier(&heartbeat_reboot_nb);
151 atomic_notifier_chain_unregister(&panic_notifier_list,
152 &heartbeat_panic_nb);
153 led_trigger_unregister(&heartbeat_led_trigger);
154}
155
156module_init(heartbeat_trig_init);
157module_exit(heartbeat_trig_exit);
158
159MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
160MODULE_DESCRIPTION("Heartbeat LED trigger");
161MODULE_LICENSE("GPL");
diff --git a/drivers/leds/trigger/ledtrig-ide-disk.c b/drivers/leds/trigger/ledtrig-ide-disk.c
new file mode 100644
index 000000000000..2cd7c0cf5924
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-ide-disk.c
@@ -0,0 +1,47 @@
1/*
2 * LED IDE-Disk Activity Trigger
3 *
4 * Copyright 2006 Openedhand Ltd.
5 *
6 * Author: Richard Purdie <rpurdie@openedhand.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/leds.h>
18
19#define BLINK_DELAY 30
20
21DEFINE_LED_TRIGGER(ledtrig_ide);
22static unsigned long ide_blink_delay = BLINK_DELAY;
23
24void ledtrig_ide_activity(void)
25{
26 led_trigger_blink_oneshot(ledtrig_ide,
27 &ide_blink_delay, &ide_blink_delay, 0);
28}
29EXPORT_SYMBOL(ledtrig_ide_activity);
30
31static int __init ledtrig_ide_init(void)
32{
33 led_trigger_register_simple("ide-disk", &ledtrig_ide);
34 return 0;
35}
36
37static void __exit ledtrig_ide_exit(void)
38{
39 led_trigger_unregister_simple(ledtrig_ide);
40}
41
42module_init(ledtrig_ide_init);
43module_exit(ledtrig_ide_exit);
44
45MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
46MODULE_DESCRIPTION("LED IDE Disk Activity Trigger");
47MODULE_LICENSE("GPL");
diff --git a/drivers/leds/trigger/ledtrig-oneshot.c b/drivers/leds/trigger/ledtrig-oneshot.c
new file mode 100644
index 000000000000..cb4c7466692a
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-oneshot.c
@@ -0,0 +1,204 @@
1/*
2 * One-shot LED Trigger
3 *
4 * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
5 *
6 * Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/device.h>
18#include <linux/ctype.h>
19#include <linux/slab.h>
20#include <linux/leds.h>
21#include "../leds.h"
22
23#define DEFAULT_DELAY 100
24
25struct oneshot_trig_data {
26 unsigned int invert;
27};
28
29static ssize_t led_shot(struct device *dev,
30 struct device_attribute *attr, const char *buf, size_t size)
31{
32 struct led_classdev *led_cdev = dev_get_drvdata(dev);
33 struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
34
35 led_blink_set_oneshot(led_cdev,
36 &led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
37 oneshot_data->invert);
38
39 /* content is ignored */
40 return size;
41}
42static ssize_t led_invert_show(struct device *dev,
43 struct device_attribute *attr, char *buf)
44{
45 struct led_classdev *led_cdev = dev_get_drvdata(dev);
46 struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
47
48 return sprintf(buf, "%u\n", oneshot_data->invert);
49}
50
51static ssize_t led_invert_store(struct device *dev,
52 struct device_attribute *attr, const char *buf, size_t size)
53{
54 struct led_classdev *led_cdev = dev_get_drvdata(dev);
55 struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
56 unsigned long state;
57 int ret;
58
59 ret = kstrtoul(buf, 0, &state);
60 if (ret)
61 return ret;
62
63 oneshot_data->invert = !!state;
64
65 if (oneshot_data->invert)
66 __led_set_brightness(led_cdev, LED_FULL);
67 else
68 __led_set_brightness(led_cdev, LED_OFF);
69
70 return size;
71}
72
73static ssize_t led_delay_on_show(struct device *dev,
74 struct device_attribute *attr, char *buf)
75{
76 struct led_classdev *led_cdev = dev_get_drvdata(dev);
77
78 return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
79}
80
81static ssize_t led_delay_on_store(struct device *dev,
82 struct device_attribute *attr, const char *buf, size_t size)
83{
84 struct led_classdev *led_cdev = dev_get_drvdata(dev);
85 unsigned long state;
86 int ret;
87
88 ret = kstrtoul(buf, 0, &state);
89 if (ret)
90 return ret;
91
92 led_cdev->blink_delay_on = state;
93
94 return size;
95}
96static ssize_t led_delay_off_show(struct device *dev,
97 struct device_attribute *attr, char *buf)
98{
99 struct led_classdev *led_cdev = dev_get_drvdata(dev);
100
101 return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
102}
103
104static ssize_t led_delay_off_store(struct device *dev,
105 struct device_attribute *attr, const char *buf, size_t size)
106{
107 struct led_classdev *led_cdev = dev_get_drvdata(dev);
108 unsigned long state;
109 int ret;
110
111 ret = kstrtoul(buf, 0, &state);
112 if (ret)
113 return ret;
114
115 led_cdev->blink_delay_off = state;
116
117 return size;
118}
119
120static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
121static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
122static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
123static DEVICE_ATTR(shot, 0200, NULL, led_shot);
124
125static void oneshot_trig_activate(struct led_classdev *led_cdev)
126{
127 struct oneshot_trig_data *oneshot_data;
128 int rc;
129
130 oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
131 if (!oneshot_data)
132 return;
133
134 led_cdev->trigger_data = oneshot_data;
135
136 rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
137 if (rc)
138 goto err_out_trig_data;
139 rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
140 if (rc)
141 goto err_out_delayon;
142 rc = device_create_file(led_cdev->dev, &dev_attr_invert);
143 if (rc)
144 goto err_out_delayoff;
145 rc = device_create_file(led_cdev->dev, &dev_attr_shot);
146 if (rc)
147 goto err_out_invert;
148
149 led_cdev->blink_delay_on = DEFAULT_DELAY;
150 led_cdev->blink_delay_off = DEFAULT_DELAY;
151
152 led_cdev->activated = true;
153
154 return;
155
156err_out_invert:
157 device_remove_file(led_cdev->dev, &dev_attr_invert);
158err_out_delayoff:
159 device_remove_file(led_cdev->dev, &dev_attr_delay_off);
160err_out_delayon:
161 device_remove_file(led_cdev->dev, &dev_attr_delay_on);
162err_out_trig_data:
163 kfree(led_cdev->trigger_data);
164}
165
166static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
167{
168 struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
169
170 if (led_cdev->activated) {
171 device_remove_file(led_cdev->dev, &dev_attr_delay_on);
172 device_remove_file(led_cdev->dev, &dev_attr_delay_off);
173 device_remove_file(led_cdev->dev, &dev_attr_invert);
174 device_remove_file(led_cdev->dev, &dev_attr_shot);
175 kfree(oneshot_data);
176 led_cdev->activated = false;
177 }
178
179 /* Stop blinking */
180 led_set_brightness(led_cdev, LED_OFF);
181}
182
183static struct led_trigger oneshot_led_trigger = {
184 .name = "oneshot",
185 .activate = oneshot_trig_activate,
186 .deactivate = oneshot_trig_deactivate,
187};
188
189static int __init oneshot_trig_init(void)
190{
191 return led_trigger_register(&oneshot_led_trigger);
192}
193
194static void __exit oneshot_trig_exit(void)
195{
196 led_trigger_unregister(&oneshot_led_trigger);
197}
198
199module_init(oneshot_trig_init);
200module_exit(oneshot_trig_exit);
201
202MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
203MODULE_DESCRIPTION("One-shot LED trigger");
204MODULE_LICENSE("GPL");
diff --git a/drivers/leds/trigger/ledtrig-timer.c b/drivers/leds/trigger/ledtrig-timer.c
new file mode 100644
index 000000000000..8d09327b5719
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-timer.c
@@ -0,0 +1,130 @@
1/*
2 * LED Kernel Timer Trigger
3 *
4 * Copyright 2005-2006 Openedhand Ltd.
5 *
6 * Author: Richard Purdie <rpurdie@openedhand.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/device.h>
18#include <linux/ctype.h>
19#include <linux/leds.h>
20
21static ssize_t led_delay_on_show(struct device *dev,
22 struct device_attribute *attr, char *buf)
23{
24 struct led_classdev *led_cdev = dev_get_drvdata(dev);
25
26 return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
27}
28
29static ssize_t led_delay_on_store(struct device *dev,
30 struct device_attribute *attr, const char *buf, size_t size)
31{
32 struct led_classdev *led_cdev = dev_get_drvdata(dev);
33 unsigned long state;
34 ssize_t ret = -EINVAL;
35
36 ret = kstrtoul(buf, 10, &state);
37 if (ret)
38 return ret;
39
40 led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
41 led_cdev->blink_delay_on = state;
42
43 return size;
44}
45
46static ssize_t led_delay_off_show(struct device *dev,
47 struct device_attribute *attr, char *buf)
48{
49 struct led_classdev *led_cdev = dev_get_drvdata(dev);
50
51 return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
52}
53
54static ssize_t led_delay_off_store(struct device *dev,
55 struct device_attribute *attr, const char *buf, size_t size)
56{
57 struct led_classdev *led_cdev = dev_get_drvdata(dev);
58 unsigned long state;
59 ssize_t ret = -EINVAL;
60
61 ret = kstrtoul(buf, 10, &state);
62 if (ret)
63 return ret;
64
65 led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
66 led_cdev->blink_delay_off = state;
67
68 return size;
69}
70
71static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
72static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
73
74static void timer_trig_activate(struct led_classdev *led_cdev)
75{
76 int rc;
77
78 led_cdev->trigger_data = NULL;
79
80 rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
81 if (rc)
82 return;
83 rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
84 if (rc)
85 goto err_out_delayon;
86
87 led_blink_set(led_cdev, &led_cdev->blink_delay_on,
88 &led_cdev->blink_delay_off);
89 led_cdev->activated = true;
90
91 return;
92
93err_out_delayon:
94 device_remove_file(led_cdev->dev, &dev_attr_delay_on);
95}
96
97static void timer_trig_deactivate(struct led_classdev *led_cdev)
98{
99 if (led_cdev->activated) {
100 device_remove_file(led_cdev->dev, &dev_attr_delay_on);
101 device_remove_file(led_cdev->dev, &dev_attr_delay_off);
102 led_cdev->activated = false;
103 }
104
105 /* Stop blinking */
106 led_set_brightness(led_cdev, LED_OFF);
107}
108
109static struct led_trigger timer_led_trigger = {
110 .name = "timer",
111 .activate = timer_trig_activate,
112 .deactivate = timer_trig_deactivate,
113};
114
115static int __init timer_trig_init(void)
116{
117 return led_trigger_register(&timer_led_trigger);
118}
119
120static void __exit timer_trig_exit(void)
121{
122 led_trigger_unregister(&timer_led_trigger);
123}
124
125module_init(timer_trig_init);
126module_exit(timer_trig_exit);
127
128MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
129MODULE_DESCRIPTION("Timer LED trigger");
130MODULE_LICENSE("GPL");
diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c
new file mode 100644
index 000000000000..e5abc00bb00c
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-transient.c
@@ -0,0 +1,237 @@
1/*
2 * LED Kernel Transient Trigger
3 *
4 * Copyright (C) 2012 Shuah Khan <shuahkhan@gmail.com>
5 *
6 * Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's
7 * ledtrig-heartbeat.c
8 * Design and use-case input from Jonas Bonn <jonas@southpole.se> and
9 * Neil Brown <neilb@suse.de>
10 *
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.
14 *
15 */
16/*
17 * Transient trigger allows one shot timer activation. Please refer to
18 * Documentation/leds/ledtrig-transient.txt for details
19*/
20
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>
28#include "../leds.h"
29
30struct transient_trig_data {
31 int activate;
32 int state;
33 int restore_state;
34 unsigned long duration;
35 struct timer_list timer;
36};
37
38static void transient_timer_function(unsigned long data)
39{
40 struct led_classdev *led_cdev = (struct led_classdev *) data;
41 struct transient_trig_data *transient_data = led_cdev->trigger_data;
42
43 transient_data->activate = 0;
44 __led_set_brightness(led_cdev, transient_data->restore_state);
45}
46
47static ssize_t transient_activate_show(struct device *dev,
48 struct device_attribute *attr, char *buf)
49{
50 struct led_classdev *led_cdev = dev_get_drvdata(dev);
51 struct transient_trig_data *transient_data = led_cdev->trigger_data;
52
53 return sprintf(buf, "%d\n", transient_data->activate);
54}
55
56static ssize_t transient_activate_store(struct device *dev,
57 struct device_attribute *attr, const char *buf, size_t size)
58{
59 struct led_classdev *led_cdev = dev_get_drvdata(dev);
60 struct transient_trig_data *transient_data = led_cdev->trigger_data;
61 unsigned long state;
62 ssize_t ret;
63
64 ret = kstrtoul(buf, 10, &state);
65 if (ret)
66 return ret;
67
68 if (state != 1 && state != 0)
69 return -EINVAL;
70
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);
76 return size;
77 }
78
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);
88 }
89
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 */
94
95 return size;
96}
97
98static ssize_t transient_duration_show(struct device *dev,
99 struct device_attribute *attr, char *buf)
100{
101 struct led_classdev *led_cdev = dev_get_drvdata(dev);
102 struct transient_trig_data *transient_data = led_cdev->trigger_data;
103
104 return sprintf(buf, "%lu\n", transient_data->duration);
105}
106
107static ssize_t transient_duration_store(struct device *dev,
108 struct device_attribute *attr, const char *buf, size_t size)
109{
110 struct led_classdev *led_cdev = dev_get_drvdata(dev);
111 struct transient_trig_data *transient_data = led_cdev->trigger_data;
112 unsigned long state;
113 ssize_t ret;
114
115 ret = kstrtoul(buf, 10, &state);
116 if (ret)
117 return ret;
118
119 transient_data->duration = state;
120 return size;
121}
122
123static ssize_t transient_state_show(struct device *dev,
124 struct device_attribute *attr, char *buf)
125{
126 struct led_classdev *led_cdev = dev_get_drvdata(dev);
127 struct transient_trig_data *transient_data = led_cdev->trigger_data;
128 int state;
129
130 state = (transient_data->state == LED_FULL) ? 1 : 0;
131 return sprintf(buf, "%d\n", state);
132}
133
134static ssize_t transient_state_store(struct device *dev,
135 struct device_attribute *attr, const char *buf, size_t size)
136{
137 struct led_classdev *led_cdev = dev_get_drvdata(dev);
138 struct transient_trig_data *transient_data = led_cdev->trigger_data;
139 unsigned long state;
140 ssize_t ret;
141
142 ret = kstrtoul(buf, 10, &state);
143 if (ret)
144 return ret;
145
146 if (state != 1 && state != 0)
147 return -EINVAL;
148
149 transient_data->state = (state == 1) ? LED_FULL : LED_OFF;
150 return size;
151}
152
153static DEVICE_ATTR(activate, 0644, transient_activate_show,
154 transient_activate_store);
155static DEVICE_ATTR(duration, 0644, transient_duration_show,
156 transient_duration_store);
157static DEVICE_ATTR(state, 0644, transient_state_show, transient_state_store);
158
159static void transient_trig_activate(struct led_classdev *led_cdev)
160{
161 int rc;
162 struct transient_trig_data *tdata;
163
164 tdata = kzalloc(sizeof(struct transient_trig_data), GFP_KERNEL);
165 if (!tdata) {
166 dev_err(led_cdev->dev,
167 "unable to allocate transient trigger\n");
168 return;
169 }
170 led_cdev->trigger_data = tdata;
171
172 rc = device_create_file(led_cdev->dev, &dev_attr_activate);
173 if (rc)
174 goto err_out;
175
176 rc = device_create_file(led_cdev->dev, &dev_attr_duration);
177 if (rc)
178 goto err_out_duration;
179
180 rc = device_create_file(led_cdev->dev, &dev_attr_state);
181 if (rc)
182 goto err_out_state;
183
184 setup_timer(&tdata->timer, transient_timer_function,
185 (unsigned long) led_cdev);
186 led_cdev->activated = true;
187
188 return;
189
190err_out_state:
191 device_remove_file(led_cdev->dev, &dev_attr_duration);
192err_out_duration:
193 device_remove_file(led_cdev->dev, &dev_attr_activate);
194err_out:
195 dev_err(led_cdev->dev, "unable to register transient trigger\n");
196 led_cdev->trigger_data = NULL;
197 kfree(tdata);
198}
199
200static void transient_trig_deactivate(struct led_classdev *led_cdev)
201{
202 struct transient_trig_data *transient_data = led_cdev->trigger_data;
203
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);
213 }
214}
215
216static struct led_trigger transient_trigger = {
217 .name = "transient",
218 .activate = transient_trig_activate,
219 .deactivate = transient_trig_deactivate,
220};
221
222static int __init transient_trig_init(void)
223{
224 return led_trigger_register(&transient_trigger);
225}
226
227static void __exit transient_trig_exit(void)
228{
229 led_trigger_unregister(&transient_trigger);
230}
231
232module_init(transient_trig_init);
233module_exit(transient_trig_exit);
234
235MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>");
236MODULE_DESCRIPTION("Transient LED trigger");
237MODULE_LICENSE("GPL");