Commit | Line | Data |
---|---|---|
8f88731d BW |
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; | |
8f88731d BW |
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 | ||
8f88731d BW |
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 | } | |
8f88731d BW |
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 | ||
8f88731d BW |
110 | snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); |
111 | ||
8f88731d | 112 | led_trigger_register_simple(trig->name, &trig->_trig); |
8f88731d BW |
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 | ||
8f88731d BW |
130 | led_trigger_unregister_simple(trig->_trig); |
131 | trig->_trig = NULL; | |
132 | memset(trig->name, 0, MAX_NAME_LEN); | |
8f88731d BW |
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"); |