File: /usr/src/linux/arch/arm/mach-shark/leds.c

1     /*
2      * arch/arm/kernel/leds-shark.c
3      * by Alexander Schulz <aschulz@netwinder.org>
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 spinlock_t leds_lock = SPIN_LOCK_UNLOCKED;
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);
164