diff options
Diffstat (limited to 'drivers/leds/trigger')
-rw-r--r-- | drivers/leds/trigger/Kconfig | 103 | ||||
-rw-r--r-- | drivers/leds/trigger/Makefile | 9 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-backlight.c | 166 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-cpu.c | 142 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-default-on.c | 45 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-gpio.c | 253 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-heartbeat.c | 161 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-ide-disk.c | 47 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-oneshot.c | 204 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-timer.c | 130 | ||||
-rw-r--r-- | drivers/leds/trigger/ledtrig-transient.c | 237 |
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 @@ | |||
1 | menuconfig 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 | |||
9 | if LEDS_TRIGGERS | ||
10 | |||
11 | config 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 | |||
22 | config 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 | |||
36 | config 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 | |||
44 | config 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 | |||
53 | config 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 | |||
62 | config 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 | |||
72 | config 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 | |||
85 | config 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 | |||
92 | comment "iptables trigger is under Netfilter config (LED target)" | ||
93 | depends on LEDS_TRIGGERS | ||
94 | |||
95 | config 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 | |||
103 | endif # 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 @@ | |||
1 | obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o | ||
2 | obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o | ||
3 | obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o | ||
4 | obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o | ||
5 | obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o | ||
6 | obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o | ||
7 | obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o | ||
8 | obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o | ||
9 | obj-$(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 | |||
24 | struct 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 | |||
32 | static 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 | |||
62 | static 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 | |||
71 | static 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 | } | ||
96 | static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store); | ||
97 | |||
98 | static 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 | |||
127 | err_invert: | ||
128 | led->trigger_data = NULL; | ||
129 | kfree(n); | ||
130 | } | ||
131 | |||
132 | static 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 | |||
145 | static struct led_trigger bl_led_trigger = { | ||
146 | .name = "backlight", | ||
147 | .activate = bl_trig_activate, | ||
148 | .deactivate = bl_trig_deactivate | ||
149 | }; | ||
150 | |||
151 | static int __init bl_trig_init(void) | ||
152 | { | ||
153 | return led_trigger_register(&bl_led_trigger); | ||
154 | } | ||
155 | |||
156 | static void __exit bl_trig_exit(void) | ||
157 | { | ||
158 | led_trigger_unregister(&bl_led_trigger); | ||
159 | } | ||
160 | |||
161 | module_init(bl_trig_init); | ||
162 | module_exit(bl_trig_exit); | ||
163 | |||
164 | MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); | ||
165 | MODULE_DESCRIPTION("Backlight emulation LED trigger"); | ||
166 | MODULE_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 | |||
33 | struct led_trigger_cpu { | ||
34 | char name[MAX_NAME_LEN]; | ||
35 | struct led_trigger *_trig; | ||
36 | }; | ||
37 | |||
38 | static 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 | */ | ||
47 | void 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 | } | ||
71 | EXPORT_SYMBOL(ledtrig_cpu); | ||
72 | |||
73 | static int ledtrig_cpu_syscore_suspend(void) | ||
74 | { | ||
75 | ledtrig_cpu(CPU_LED_STOP); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static void ledtrig_cpu_syscore_resume(void) | ||
80 | { | ||
81 | ledtrig_cpu(CPU_LED_START); | ||
82 | } | ||
83 | |||
84 | static void ledtrig_cpu_syscore_shutdown(void) | ||
85 | { | ||
86 | ledtrig_cpu(CPU_LED_HALTED); | ||
87 | } | ||
88 | |||
89 | static 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 | |||
95 | static 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 | } | ||
121 | module_init(ledtrig_cpu_init); | ||
122 | |||
123 | static 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 | } | ||
137 | module_exit(ledtrig_cpu_exit); | ||
138 | |||
139 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); | ||
140 | MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>"); | ||
141 | MODULE_DESCRIPTION("CPU LED trigger"); | ||
142 | MODULE_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 | |||
20 | static void defon_trig_activate(struct led_classdev *led_cdev) | ||
21 | { | ||
22 | __led_set_brightness(led_cdev, led_cdev->max_brightness); | ||
23 | } | ||
24 | |||
25 | static struct led_trigger defon_led_trigger = { | ||
26 | .name = "default-on", | ||
27 | .activate = defon_trig_activate, | ||
28 | }; | ||
29 | |||
30 | static int __init defon_trig_init(void) | ||
31 | { | ||
32 | return led_trigger_register(&defon_led_trigger); | ||
33 | } | ||
34 | |||
35 | static void __exit defon_trig_exit(void) | ||
36 | { | ||
37 | led_trigger_unregister(&defon_led_trigger); | ||
38 | } | ||
39 | |||
40 | module_init(defon_trig_init); | ||
41 | module_exit(defon_trig_exit); | ||
42 | |||
43 | MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>"); | ||
44 | MODULE_DESCRIPTION("Default-ON LED trigger"); | ||
45 | MODULE_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 | |||
22 | struct 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 | |||
31 | static 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 | |||
42 | static 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 | |||
66 | static 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 | |||
75 | static 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 | } | ||
93 | static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show, | ||
94 | gpio_trig_brightness_store); | ||
95 | |||
96 | static 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 | |||
105 | static 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 | } | ||
127 | static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show, | ||
128 | gpio_trig_inverted_store); | ||
129 | |||
130 | static 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 | |||
139 | static 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 | } | ||
177 | static DEVICE_ATTR(gpio, 0644, gpio_trig_gpio_show, gpio_trig_gpio_store); | ||
178 | |||
179 | static 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 | |||
207 | err_brightness: | ||
208 | device_remove_file(led->dev, &dev_attr_inverted); | ||
209 | |||
210 | err_inverted: | ||
211 | device_remove_file(led->dev, &dev_attr_gpio); | ||
212 | |||
213 | err_gpio: | ||
214 | kfree(gpio_data); | ||
215 | } | ||
216 | |||
217 | static 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 | |||
233 | static struct led_trigger gpio_led_trigger = { | ||
234 | .name = "gpio", | ||
235 | .activate = gpio_trig_activate, | ||
236 | .deactivate = gpio_trig_deactivate, | ||
237 | }; | ||
238 | |||
239 | static int __init gpio_trig_init(void) | ||
240 | { | ||
241 | return led_trigger_register(&gpio_led_trigger); | ||
242 | } | ||
243 | module_init(gpio_trig_init); | ||
244 | |||
245 | static void __exit gpio_trig_exit(void) | ||
246 | { | ||
247 | led_trigger_unregister(&gpio_led_trigger); | ||
248 | } | ||
249 | module_exit(gpio_trig_exit); | ||
250 | |||
251 | MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>"); | ||
252 | MODULE_DESCRIPTION("GPIO LED trigger"); | ||
253 | MODULE_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 | |||
24 | static int panic_heartbeats; | ||
25 | |||
26 | struct heartbeat_trig_data { | ||
27 | unsigned int phase; | ||
28 | unsigned int period; | ||
29 | struct timer_list timer; | ||
30 | }; | ||
31 | |||
32 | static 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 | |||
81 | static 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 | |||
97 | static 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 | |||
108 | static struct led_trigger heartbeat_led_trigger = { | ||
109 | .name = "heartbeat", | ||
110 | .activate = heartbeat_trig_activate, | ||
111 | .deactivate = heartbeat_trig_deactivate, | ||
112 | }; | ||
113 | |||
114 | static 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 | |||
121 | static 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 | |||
128 | static struct notifier_block heartbeat_reboot_nb = { | ||
129 | .notifier_call = heartbeat_reboot_notifier, | ||
130 | }; | ||
131 | |||
132 | static struct notifier_block heartbeat_panic_nb = { | ||
133 | .notifier_call = heartbeat_panic_notifier, | ||
134 | }; | ||
135 | |||
136 | static 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 | |||
148 | static 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 | |||
156 | module_init(heartbeat_trig_init); | ||
157 | module_exit(heartbeat_trig_exit); | ||
158 | |||
159 | MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); | ||
160 | MODULE_DESCRIPTION("Heartbeat LED trigger"); | ||
161 | MODULE_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 | |||
21 | DEFINE_LED_TRIGGER(ledtrig_ide); | ||
22 | static unsigned long ide_blink_delay = BLINK_DELAY; | ||
23 | |||
24 | void ledtrig_ide_activity(void) | ||
25 | { | ||
26 | led_trigger_blink_oneshot(ledtrig_ide, | ||
27 | &ide_blink_delay, &ide_blink_delay, 0); | ||
28 | } | ||
29 | EXPORT_SYMBOL(ledtrig_ide_activity); | ||
30 | |||
31 | static int __init ledtrig_ide_init(void) | ||
32 | { | ||
33 | led_trigger_register_simple("ide-disk", &ledtrig_ide); | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static void __exit ledtrig_ide_exit(void) | ||
38 | { | ||
39 | led_trigger_unregister_simple(ledtrig_ide); | ||
40 | } | ||
41 | |||
42 | module_init(ledtrig_ide_init); | ||
43 | module_exit(ledtrig_ide_exit); | ||
44 | |||
45 | MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); | ||
46 | MODULE_DESCRIPTION("LED IDE Disk Activity Trigger"); | ||
47 | MODULE_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 | |||
25 | struct oneshot_trig_data { | ||
26 | unsigned int invert; | ||
27 | }; | ||
28 | |||
29 | static 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 | } | ||
42 | static 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 | |||
51 | static 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 | |||
73 | static 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 | |||
81 | static 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 | } | ||
96 | static 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 | |||
104 | static 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 | |||
120 | static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); | ||
121 | static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); | ||
122 | static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store); | ||
123 | static DEVICE_ATTR(shot, 0200, NULL, led_shot); | ||
124 | |||
125 | static 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 | |||
156 | err_out_invert: | ||
157 | device_remove_file(led_cdev->dev, &dev_attr_invert); | ||
158 | err_out_delayoff: | ||
159 | device_remove_file(led_cdev->dev, &dev_attr_delay_off); | ||
160 | err_out_delayon: | ||
161 | device_remove_file(led_cdev->dev, &dev_attr_delay_on); | ||
162 | err_out_trig_data: | ||
163 | kfree(led_cdev->trigger_data); | ||
164 | } | ||
165 | |||
166 | static 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 | |||
183 | static struct led_trigger oneshot_led_trigger = { | ||
184 | .name = "oneshot", | ||
185 | .activate = oneshot_trig_activate, | ||
186 | .deactivate = oneshot_trig_deactivate, | ||
187 | }; | ||
188 | |||
189 | static int __init oneshot_trig_init(void) | ||
190 | { | ||
191 | return led_trigger_register(&oneshot_led_trigger); | ||
192 | } | ||
193 | |||
194 | static void __exit oneshot_trig_exit(void) | ||
195 | { | ||
196 | led_trigger_unregister(&oneshot_led_trigger); | ||
197 | } | ||
198 | |||
199 | module_init(oneshot_trig_init); | ||
200 | module_exit(oneshot_trig_exit); | ||
201 | |||
202 | MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>"); | ||
203 | MODULE_DESCRIPTION("One-shot LED trigger"); | ||
204 | MODULE_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 | |||
21 | static 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 | |||
29 | static 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 | |||
46 | static 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 | |||
54 | static 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 | |||
71 | static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); | ||
72 | static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); | ||
73 | |||
74 | static 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 | |||
93 | err_out_delayon: | ||
94 | device_remove_file(led_cdev->dev, &dev_attr_delay_on); | ||
95 | } | ||
96 | |||
97 | static 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 | |||
109 | static struct led_trigger timer_led_trigger = { | ||
110 | .name = "timer", | ||
111 | .activate = timer_trig_activate, | ||
112 | .deactivate = timer_trig_deactivate, | ||
113 | }; | ||
114 | |||
115 | static int __init timer_trig_init(void) | ||
116 | { | ||
117 | return led_trigger_register(&timer_led_trigger); | ||
118 | } | ||
119 | |||
120 | static void __exit timer_trig_exit(void) | ||
121 | { | ||
122 | led_trigger_unregister(&timer_led_trigger); | ||
123 | } | ||
124 | |||
125 | module_init(timer_trig_init); | ||
126 | module_exit(timer_trig_exit); | ||
127 | |||
128 | MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); | ||
129 | MODULE_DESCRIPTION("Timer LED trigger"); | ||
130 | MODULE_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 | |||
30 | struct transient_trig_data { | ||
31 | int activate; | ||
32 | int state; | ||
33 | int restore_state; | ||
34 | unsigned long duration; | ||
35 | struct timer_list timer; | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
47 | static 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 | |||
56 | static 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 | |||
98 | static 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 | |||
107 | static 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 | |||
123 | static 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 | |||
134 | static 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 | |||
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); | ||
158 | |||
159 | static 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 | |||
190 | err_out_state: | ||
191 | device_remove_file(led_cdev->dev, &dev_attr_duration); | ||
192 | err_out_duration: | ||
193 | device_remove_file(led_cdev->dev, &dev_attr_activate); | ||
194 | err_out: | ||
195 | dev_err(led_cdev->dev, "unable to register transient trigger\n"); | ||
196 | led_cdev->trigger_data = NULL; | ||
197 | kfree(tdata); | ||
198 | } | ||
199 | |||
200 | static 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 | |||
216 | static struct led_trigger transient_trigger = { | ||
217 | .name = "transient", | ||
218 | .activate = transient_trig_activate, | ||
219 | .deactivate = transient_trig_deactivate, | ||
220 | }; | ||
221 | |||
222 | static int __init transient_trig_init(void) | ||
223 | { | ||
224 | return led_trigger_register(&transient_trigger); | ||
225 | } | ||
226 | |||
227 | static void __exit transient_trig_exit(void) | ||
228 | { | ||
229 | led_trigger_unregister(&transient_trigger); | ||
230 | } | ||
231 | |||
232 | module_init(transient_trig_init); | ||
233 | module_exit(transient_trig_exit); | ||
234 | |||
235 | MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>"); | ||
236 | MODULE_DESCRIPTION("Transient LED trigger"); | ||
237 | MODULE_LICENSE("GPL"); | ||