]>
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 | ||
8f88731d BW |
22 | #include <linux/kernel.h> |
23 | #include <linux/init.h> | |
24 | #include <linux/slab.h> | |
25 | #include <linux/percpu.h> | |
26 | #include <linux/syscore_ops.h> | |
27 | #include <linux/rwsem.h> | |
fba14ae8 | 28 | #include <linux/cpu.h> |
f07fb521 | 29 | #include "../leds.h" |
8f88731d BW |
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 | |
e602fda1 | 45 | * bound LED to turn on or turn off. |
8f88731d BW |
46 | */ |
47 | void ledtrig_cpu(enum cpu_led_event ledevt) | |
48 | { | |
24c9301f | 49 | struct led_trigger_cpu *trig = this_cpu_ptr(&cpu_trig); |
8f88731d | 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 | ||
cd894f14 | 95 | static int ledtrig_online_cpu(unsigned int cpu) |
fba14ae8 | 96 | { |
911a359d RC |
97 | ledtrig_cpu(CPU_LED_START); |
98 | return 0; | |
fba14ae8 PM |
99 | } |
100 | ||
cd894f14 | 101 | static int ledtrig_prepare_down_cpu(unsigned int cpu) |
911a359d RC |
102 | { |
103 | ledtrig_cpu(CPU_LED_STOP); | |
104 | return 0; | |
105 | } | |
fba14ae8 | 106 | |
8f88731d BW |
107 | static int __init ledtrig_cpu_init(void) |
108 | { | |
109 | int cpu; | |
cd894f14 | 110 | int ret; |
8f88731d BW |
111 | |
112 | /* Supports up to 9999 cpu cores */ | |
113 | BUILD_BUG_ON(CONFIG_NR_CPUS > 9999); | |
114 | ||
115 | /* | |
116 | * Registering CPU led trigger for each CPU core here | |
117 | * ignores CPU hotplug, but after this CPU hotplug works | |
118 | * fine with this trigger. | |
119 | */ | |
120 | for_each_possible_cpu(cpu) { | |
121 | struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); | |
122 | ||
8f88731d BW |
123 | snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); |
124 | ||
8f88731d | 125 | led_trigger_register_simple(trig->name, &trig->_trig); |
8f88731d BW |
126 | } |
127 | ||
128 | register_syscore_ops(&ledtrig_cpu_syscore_ops); | |
911a359d | 129 | |
73c1b41e | 130 | ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "leds/trigger:starting", |
cd894f14 SAS |
131 | ledtrig_online_cpu, ledtrig_prepare_down_cpu); |
132 | if (ret < 0) | |
133 | pr_err("CPU hotplug notifier for ledtrig-cpu could not be registered: %d\n", | |
134 | ret); | |
8f88731d BW |
135 | |
136 | pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n"); | |
137 | ||
138 | return 0; | |
139 | } | |
227a0ca1 | 140 | device_initcall(ledtrig_cpu_init); |