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