correct email address of Manfred Spraul
[linux-2.6] / arch / arm / mach-shark / leds.c
1 /*
2  * arch/arm/kernel/leds-shark.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.
10  *
11  * The leds use is as follows:
12  *  - Green front - toggles state every 50 timer interrupts
13  *  - Amber front - Unused, this is a dual color led (Amber/Green)
14  *  - Amber back  - On if system is not idle
15  *
16  * Changelog:
17  */
18 #include <linux/config.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/init.h>
22 #include <linux/spinlock.h>
23 #include <linux/ioport.h>
24
25 #include <asm/hardware.h>
26 #include <asm/leds.h>
27 #include <asm/io.h>
28 #include <asm/system.h>
29
30 #define LED_STATE_ENABLED       1
31 #define LED_STATE_CLAIMED       2
32 static char led_state;
33 static short hw_led_state;
34 static short saved_state;
35
36 static DEFINE_SPINLOCK(leds_lock);
37
38 short sequoia_read(int addr) {
39   outw(addr,0x24);
40   return inw(0x26);
41 }
42
43 void sequoia_write(short value,short addr) {
44   outw(addr,0x24);
45   outw(value,0x26);
46 }
47
48 static void sequoia_leds_event(led_event_t evt)
49 {
50         unsigned long flags;
51
52         spin_lock_irqsave(&leds_lock, flags);
53
54         hw_led_state = sequoia_read(0x09);
55
56         switch (evt) {
57         case led_start:
58                 hw_led_state |= SEQUOIA_LED_GREEN;
59                 hw_led_state |= SEQUOIA_LED_AMBER;
60 #ifdef CONFIG_LEDS_CPU
61                 hw_led_state |= SEQUOIA_LED_BACK;
62 #else
63                 hw_led_state &= ~SEQUOIA_LED_BACK;
64 #endif
65                 led_state |= LED_STATE_ENABLED;
66                 break;
67
68         case led_stop:
69                 hw_led_state &= ~SEQUOIA_LED_BACK;
70                 hw_led_state |= SEQUOIA_LED_GREEN;
71                 hw_led_state |= SEQUOIA_LED_AMBER;
72                 led_state &= ~LED_STATE_ENABLED;
73                 break;
74
75         case led_claim:
76                 led_state |= LED_STATE_CLAIMED;
77                 saved_state = hw_led_state;
78                 hw_led_state &= ~SEQUOIA_LED_BACK;
79                 hw_led_state |= SEQUOIA_LED_GREEN;
80                 hw_led_state |= SEQUOIA_LED_AMBER;
81                 break;
82
83         case led_release:
84                 led_state &= ~LED_STATE_CLAIMED;
85                 hw_led_state = saved_state;
86                 break;
87
88 #ifdef CONFIG_LEDS_TIMER
89         case led_timer:
90                 if (!(led_state & LED_STATE_CLAIMED))
91                         hw_led_state ^= SEQUOIA_LED_GREEN;
92                 break;
93 #endif
94
95 #ifdef CONFIG_LEDS_CPU
96         case led_idle_start:
97                 if (!(led_state & LED_STATE_CLAIMED))
98                         hw_led_state &= ~SEQUOIA_LED_BACK;
99                 break;
100
101         case led_idle_end:
102                 if (!(led_state & LED_STATE_CLAIMED))
103                         hw_led_state |= SEQUOIA_LED_BACK;
104                 break;
105 #endif
106
107         case led_green_on:
108                 if (led_state & LED_STATE_CLAIMED)
109                         hw_led_state &= ~SEQUOIA_LED_GREEN;
110                 break;
111
112         case led_green_off:
113                 if (led_state & LED_STATE_CLAIMED)
114                         hw_led_state |= SEQUOIA_LED_GREEN;
115                 break;
116
117         case led_amber_on:
118                 if (led_state & LED_STATE_CLAIMED)
119                         hw_led_state &= ~SEQUOIA_LED_AMBER;
120                 break;
121
122         case led_amber_off:
123                 if (led_state & LED_STATE_CLAIMED)
124                         hw_led_state |= SEQUOIA_LED_AMBER;
125                 break;
126
127         case led_red_on:
128                 if (led_state & LED_STATE_CLAIMED)
129                         hw_led_state |= SEQUOIA_LED_BACK;
130                 break;
131
132         case led_red_off:
133                 if (led_state & LED_STATE_CLAIMED)
134                         hw_led_state &= ~SEQUOIA_LED_BACK;
135                 break;
136
137         default:
138                 break;
139         }
140
141         if  (led_state & LED_STATE_ENABLED)
142                 sequoia_write(hw_led_state,0x09);
143
144         spin_unlock_irqrestore(&leds_lock, flags);
145 }
146
147 static int __init leds_init(void)
148 {
149         extern void (*leds_event)(led_event_t);
150         short temp;
151         
152         leds_event = sequoia_leds_event;
153
154         /* Make LEDs independent of power-state */
155         request_region(0x24,4,"sequoia");
156         temp = sequoia_read(0x09);
157         temp |= 1<<10;
158         sequoia_write(temp,0x09);
159         leds_event(led_start);
160         return 0;
161 }
162
163 __initcall(leds_init);