diff options
Diffstat (limited to 'arch/arm/mach-shark/leds.c')
-rw-r--r-- | arch/arm/mach-shark/leds.c | 220 |
1 files changed, 86 insertions, 134 deletions
diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c index 25609076921f..081c778a10ac 100644 --- a/arch/arm/mach-shark/leds.c +++ b/arch/arm/mach-shark/leds.c | |||
@@ -1,165 +1,117 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/mach-shark/leds.c | ||
3 | * by Alexander Schulz | ||
4 | * | ||
5 | * derived from: | ||
6 | * arch/arm/kernel/leds-footbridge.c | ||
7 | * Copyright (C) 1998-1999 Russell King | ||
8 | * | ||
9 | * DIGITAL Shark LED control routines. | 2 | * DIGITAL Shark LED control routines. |
10 | * | 3 | * |
11 | * The leds use is as follows: | 4 | * Driver for the 3 user LEDs found on the Shark |
12 | * - Green front - toggles state every 50 timer interrupts | 5 | * Based on Versatile and RealView machine LED code |
13 | * - Amber front - Unused, this is a dual color led (Amber/Green) | ||
14 | * - Amber back - On if system is not idle | ||
15 | * | 6 | * |
16 | * Changelog: | 7 | * License terms: GNU General Public License (GPL) version 2 |
8 | * Author: Bryan Wu <bryan.wu@canonical.com> | ||
17 | */ | 9 | */ |
18 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | 11 | #include <linux/init.h> |
21 | #include <linux/spinlock.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/io.h> | 12 | #include <linux/io.h> |
13 | #include <linux/ioport.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/leds.h> | ||
24 | 16 | ||
25 | #include <asm/leds.h> | 17 | #include <asm/mach-types.h> |
26 | 18 | ||
27 | #define LED_STATE_ENABLED 1 | 19 | #if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) |
28 | #define LED_STATE_CLAIMED 2 | 20 | struct shark_led { |
21 | struct led_classdev cdev; | ||
22 | u8 mask; | ||
23 | }; | ||
29 | 24 | ||
30 | #define SEQUOIA_LED_GREEN (1<<6) | 25 | /* |
31 | #define SEQUOIA_LED_AMBER (1<<5) | 26 | * The triggers lines up below will only be used if the |
32 | #define SEQUOIA_LED_BACK (1<<7) | 27 | * LED triggers are compiled in. |
28 | */ | ||
29 | static const struct { | ||
30 | const char *name; | ||
31 | const char *trigger; | ||
32 | } shark_leds[] = { | ||
33 | { "shark:amber0", "default-on", }, /* Bit 5 */ | ||
34 | { "shark:green", "heartbeat", }, /* Bit 6 */ | ||
35 | { "shark:amber1", "cpu0" }, /* Bit 7 */ | ||
36 | }; | ||
37 | |||
38 | static u16 led_reg_read(void) | ||
39 | { | ||
40 | outw(0x09, 0x24); | ||
41 | return inw(0x26); | ||
42 | } | ||
33 | 43 | ||
34 | static char led_state; | 44 | static void led_reg_write(u16 value) |
35 | static short hw_led_state; | 45 | { |
36 | static short saved_state; | 46 | outw(0x09, 0x24); |
47 | outw(value, 0x26); | ||
48 | } | ||
37 | 49 | ||
38 | static DEFINE_RAW_SPINLOCK(leds_lock); | 50 | static void shark_led_set(struct led_classdev *cdev, |
51 | enum led_brightness b) | ||
52 | { | ||
53 | struct shark_led *led = container_of(cdev, | ||
54 | struct shark_led, cdev); | ||
55 | u16 reg = led_reg_read(); | ||
39 | 56 | ||
40 | short sequoia_read(int addr) { | 57 | if (b != LED_OFF) |
41 | outw(addr,0x24); | 58 | reg |= led->mask; |
42 | return inw(0x26); | 59 | else |
43 | } | 60 | reg &= ~led->mask; |
44 | 61 | ||
45 | void sequoia_write(short value,short addr) { | 62 | led_reg_write(reg); |
46 | outw(addr,0x24); | ||
47 | outw(value,0x26); | ||
48 | } | 63 | } |
49 | 64 | ||
50 | static void sequoia_leds_event(led_event_t evt) | 65 | static enum led_brightness shark_led_get(struct led_classdev *cdev) |
51 | { | 66 | { |
52 | unsigned long flags; | 67 | struct shark_led *led = container_of(cdev, |
53 | 68 | struct shark_led, cdev); | |
54 | raw_spin_lock_irqsave(&leds_lock, flags); | 69 | u16 reg = led_reg_read(); |
55 | 70 | ||
56 | hw_led_state = sequoia_read(0x09); | 71 | return (reg & led->mask) ? LED_FULL : LED_OFF; |
72 | } | ||
57 | 73 | ||
58 | switch (evt) { | 74 | static int __init shark_leds_init(void) |
59 | case led_start: | 75 | { |
60 | hw_led_state |= SEQUOIA_LED_GREEN; | 76 | int i; |
61 | hw_led_state |= SEQUOIA_LED_AMBER; | 77 | u16 reg; |
62 | #ifdef CONFIG_LEDS_CPU | ||
63 | hw_led_state |= SEQUOIA_LED_BACK; | ||
64 | #else | ||
65 | hw_led_state &= ~SEQUOIA_LED_BACK; | ||
66 | #endif | ||
67 | led_state |= LED_STATE_ENABLED; | ||
68 | break; | ||
69 | |||
70 | case led_stop: | ||
71 | hw_led_state &= ~SEQUOIA_LED_BACK; | ||
72 | hw_led_state |= SEQUOIA_LED_GREEN; | ||
73 | hw_led_state |= SEQUOIA_LED_AMBER; | ||
74 | led_state &= ~LED_STATE_ENABLED; | ||
75 | break; | ||
76 | |||
77 | case led_claim: | ||
78 | led_state |= LED_STATE_CLAIMED; | ||
79 | saved_state = hw_led_state; | ||
80 | hw_led_state &= ~SEQUOIA_LED_BACK; | ||
81 | hw_led_state |= SEQUOIA_LED_GREEN; | ||
82 | hw_led_state |= SEQUOIA_LED_AMBER; | ||
83 | break; | ||
84 | |||
85 | case led_release: | ||
86 | led_state &= ~LED_STATE_CLAIMED; | ||
87 | hw_led_state = saved_state; | ||
88 | break; | ||
89 | |||
90 | #ifdef CONFIG_LEDS_TIMER | ||
91 | case led_timer: | ||
92 | if (!(led_state & LED_STATE_CLAIMED)) | ||
93 | hw_led_state ^= SEQUOIA_LED_GREEN; | ||
94 | break; | ||
95 | #endif | ||
96 | 78 | ||
97 | #ifdef CONFIG_LEDS_CPU | 79 | if (!machine_is_shark()) |
98 | case led_idle_start: | 80 | return -ENODEV; |
99 | if (!(led_state & LED_STATE_CLAIMED)) | ||
100 | hw_led_state &= ~SEQUOIA_LED_BACK; | ||
101 | break; | ||
102 | 81 | ||
103 | case led_idle_end: | 82 | for (i = 0; i < ARRAY_SIZE(shark_leds); i++) { |
104 | if (!(led_state & LED_STATE_CLAIMED)) | 83 | struct shark_led *led; |
105 | hw_led_state |= SEQUOIA_LED_BACK; | ||
106 | break; | ||
107 | #endif | ||
108 | 84 | ||
109 | case led_green_on: | 85 | led = kzalloc(sizeof(*led), GFP_KERNEL); |
110 | if (led_state & LED_STATE_CLAIMED) | 86 | if (!led) |
111 | hw_led_state &= ~SEQUOIA_LED_GREEN; | 87 | break; |
112 | break; | ||
113 | |||
114 | case led_green_off: | ||
115 | if (led_state & LED_STATE_CLAIMED) | ||
116 | hw_led_state |= SEQUOIA_LED_GREEN; | ||
117 | break; | ||
118 | |||
119 | case led_amber_on: | ||
120 | if (led_state & LED_STATE_CLAIMED) | ||
121 | hw_led_state &= ~SEQUOIA_LED_AMBER; | ||
122 | break; | ||
123 | |||
124 | case led_amber_off: | ||
125 | if (led_state & LED_STATE_CLAIMED) | ||
126 | hw_led_state |= SEQUOIA_LED_AMBER; | ||
127 | break; | ||
128 | |||
129 | case led_red_on: | ||
130 | if (led_state & LED_STATE_CLAIMED) | ||
131 | hw_led_state |= SEQUOIA_LED_BACK; | ||
132 | break; | ||
133 | |||
134 | case led_red_off: | ||
135 | if (led_state & LED_STATE_CLAIMED) | ||
136 | hw_led_state &= ~SEQUOIA_LED_BACK; | ||
137 | break; | ||
138 | |||
139 | default: | ||
140 | break; | ||
141 | } | ||
142 | 88 | ||
143 | if (led_state & LED_STATE_ENABLED) | 89 | led->cdev.name = shark_leds[i].name; |
144 | sequoia_write(hw_led_state,0x09); | 90 | led->cdev.brightness_set = shark_led_set; |
91 | led->cdev.brightness_get = shark_led_get; | ||
92 | led->cdev.default_trigger = shark_leds[i].trigger; | ||
145 | 93 | ||
146 | raw_spin_unlock_irqrestore(&leds_lock, flags); | 94 | /* Count in 5 bits offset */ |
147 | } | 95 | led->mask = BIT(i + 5); |
148 | 96 | ||
149 | static int __init leds_init(void) | 97 | if (led_classdev_register(NULL, &led->cdev) < 0) { |
150 | { | 98 | kfree(led); |
151 | extern void (*leds_event)(led_event_t); | 99 | break; |
152 | short temp; | 100 | } |
153 | 101 | } | |
154 | leds_event = sequoia_leds_event; | ||
155 | 102 | ||
156 | /* Make LEDs independent of power-state */ | 103 | /* Make LEDs independent of power-state */ |
157 | request_region(0x24,4,"sequoia"); | 104 | request_region(0x24, 4, "led_reg"); |
158 | temp = sequoia_read(0x09); | 105 | reg = led_reg_read(); |
159 | temp |= 1<<10; | 106 | reg |= 1 << 10; |
160 | sequoia_write(temp,0x09); | 107 | led_reg_write(reg); |
161 | leds_event(led_start); | 108 | |
162 | return 0; | 109 | return 0; |
163 | } | 110 | } |
164 | 111 | ||
165 | __initcall(leds_init); | 112 | /* |
113 | * Since we may have triggers on any subsystem, defer registration | ||
114 | * until after subsystem_init. | ||
115 | */ | ||
116 | fs_initcall(shark_leds_init); | ||
117 | #endif | ||