diff options
Diffstat (limited to 'arch/arm/plat-versatile/leds.c')
-rw-r--r-- | arch/arm/plat-versatile/leds.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/arch/arm/plat-versatile/leds.c b/arch/arm/plat-versatile/leds.c new file mode 100644 index 000000000000..3169fa555ea6 --- /dev/null +++ b/arch/arm/plat-versatile/leds.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * Driver for the 8 user LEDs found on the RealViews and Versatiles | ||
3 | * Based on DaVinci's DM365 board code | ||
4 | * | ||
5 | * License terms: GNU General Public License (GPL) version 2 | ||
6 | * Author: Linus Walleij <triad@df.lth.se> | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/io.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/leds.h> | ||
13 | |||
14 | #include <mach/hardware.h> | ||
15 | #include <mach/platform.h> | ||
16 | |||
17 | #ifdef VERSATILE_SYS_BASE | ||
18 | #define LEDREG (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) | ||
19 | #endif | ||
20 | |||
21 | #ifdef REALVIEW_SYS_BASE | ||
22 | #define LEDREG (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET) | ||
23 | #endif | ||
24 | |||
25 | struct versatile_led { | ||
26 | struct led_classdev cdev; | ||
27 | u8 mask; | ||
28 | }; | ||
29 | |||
30 | /* | ||
31 | * The triggers lines up below will only be used if the | ||
32 | * LED triggers are compiled in. | ||
33 | */ | ||
34 | static const struct { | ||
35 | const char *name; | ||
36 | const char *trigger; | ||
37 | } versatile_leds[] = { | ||
38 | { "versatile:0", "heartbeat", }, | ||
39 | { "versatile:1", "mmc0", }, | ||
40 | { "versatile:2", }, | ||
41 | { "versatile:3", }, | ||
42 | { "versatile:4", }, | ||
43 | { "versatile:5", }, | ||
44 | { "versatile:6", }, | ||
45 | { "versatile:7", }, | ||
46 | }; | ||
47 | |||
48 | static void versatile_led_set(struct led_classdev *cdev, | ||
49 | enum led_brightness b) | ||
50 | { | ||
51 | struct versatile_led *led = container_of(cdev, | ||
52 | struct versatile_led, cdev); | ||
53 | u32 reg = readl(LEDREG); | ||
54 | |||
55 | if (b != LED_OFF) | ||
56 | reg |= led->mask; | ||
57 | else | ||
58 | reg &= ~led->mask; | ||
59 | writel(reg, LEDREG); | ||
60 | } | ||
61 | |||
62 | static enum led_brightness versatile_led_get(struct led_classdev *cdev) | ||
63 | { | ||
64 | struct versatile_led *led = container_of(cdev, | ||
65 | struct versatile_led, cdev); | ||
66 | u32 reg = readl(LEDREG); | ||
67 | |||
68 | return (reg & led->mask) ? LED_FULL : LED_OFF; | ||
69 | } | ||
70 | |||
71 | static int __init versatile_leds_init(void) | ||
72 | { | ||
73 | int i; | ||
74 | |||
75 | /* All ON */ | ||
76 | writel(0xff, LEDREG); | ||
77 | for (i = 0; i < ARRAY_SIZE(versatile_leds); i++) { | ||
78 | struct versatile_led *led; | ||
79 | |||
80 | led = kzalloc(sizeof(*led), GFP_KERNEL); | ||
81 | if (!led) | ||
82 | break; | ||
83 | |||
84 | led->cdev.name = versatile_leds[i].name; | ||
85 | led->cdev.brightness_set = versatile_led_set; | ||
86 | led->cdev.brightness_get = versatile_led_get; | ||
87 | led->cdev.default_trigger = versatile_leds[i].trigger; | ||
88 | led->mask = BIT(i); | ||
89 | |||
90 | if (led_classdev_register(NULL, &led->cdev) < 0) { | ||
91 | kfree(led); | ||
92 | break; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Since we may have triggers on any subsystem, defer registration | ||
101 | * until after subsystem_init. | ||
102 | */ | ||
103 | fs_initcall(versatile_leds_init); | ||