aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shark/leds.c
blob: ccd49189bbd01a58156f922ea990b9dd377513ff (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * arch/arm/mach-shark/leds.c
 * by Alexander Schulz
 *
 * derived from:
 * arch/arm/kernel/leds-footbridge.c
 * Copyright (C) 1998-1999 Russell King
 *
 * DIGITAL Shark LED control routines.
 *
 * The leds use is as follows:
 *  - Green front - toggles state every 50 timer interrupts
 *  - Amber front - Unused, this is a dual color led (Amber/Green)
 *  - Amber back  - On if system is not idle
 *
 * Changelog:
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <linux/io.h>

#include <asm/leds.h>
#include <asm/system.h>

#define LED_STATE_ENABLED	1
#define LED_STATE_CLAIMED	2

#define SEQUOIA_LED_GREEN       (1<<6)
#define SEQUOIA_LED_AMBER       (1<<5)
#define SEQUOIA_LED_BACK        (1<<7)

static char led_state;
static short hw_led_state;
static short saved_state;

static DEFINE_RAW_SPINLOCK(leds_lock);

short sequoia_read(int addr) {
  outw(addr,0x24);
  return inw(0x26);
}

void sequoia_write(short value,short addr) {
  outw(addr,0x24);
  outw(value,0x26);
}

static void sequoia_leds_event(led_event_t evt)
{
	unsigned long flags;

	raw_spin_lock_irqsave(&leds_lock, flags);

	hw_led_state = sequoia_read(0x09);

	switch (evt) {
	case led_start:
		hw_led_state |= SEQUOIA_LED_GREEN;
		hw_led_state |= SEQUOIA_LED_AMBER;
#ifdef CONFIG_LEDS_CPU
		hw_led_state |= SEQUOIA_LED_BACK;
#else
		hw_led_state &= ~SEQUOIA_LED_BACK;
#endif
		led_state |= LED_STATE_ENABLED;
		break;

	case led_stop:
		hw_led_state &= ~SEQUOIA_LED_BACK;
		hw_led_state |= SEQUOIA_LED_GREEN;
		hw_led_state |= SEQUOIA_LED_AMBER;
		led_state &= ~LED_STATE_ENABLED;
		break;

	case led_claim:
		led_state |= LED_STATE_CLAIMED;
		saved_state = hw_led_state;
		hw_led_state &= ~SEQUOIA_LED_BACK;
		hw_led_state |= SEQUOIA_LED_GREEN;
		hw_led_state |= SEQUOIA_LED_AMBER;
		break;

	case led_release:
		led_state &= ~LED_STATE_CLAIMED;
		hw_led_state = saved_state;
		break;

#ifdef CONFIG_LEDS_TIMER
	case led_timer:
		if (!(led_state & LED_STATE_CLAIMED))
			hw_led_state ^= SEQUOIA_LED_GREEN;
		break;
#endif

#ifdef CONFIG_LEDS_CPU
	case led_idle_start:
		if (!(led_state & LED_STATE_CLAIMED))
			hw_led_state &= ~SEQUOIA_LED_BACK;
		break;

	case led_idle_end:
		if (!(led_state & LED_STATE_CLAIMED))
			hw_led_state |= SEQUOIA_LED_BACK;
		break;
#endif

	case led_green_on:
		if (led_state & LED_STATE_CLAIMED)
			hw_led_state &= ~SEQUOIA_LED_GREEN;
		break;

	case led_green_off:
		if (led_state & LED_STATE_CLAIMED)
			hw_led_state |= SEQUOIA_LED_GREEN;
		break;

	case led_amber_on:
		if (led_state & LED_STATE_CLAIMED)
			hw_led_state &= ~SEQUOIA_LED_AMBER;
		break;

	case led_amber_off:
		if (led_state & LED_STATE_CLAIMED)
			hw_led_state |= SEQUOIA_LED_AMBER;
		break;

	case led_red_on:
		if (led_state & LED_STATE_CLAIMED)
			hw_led_state |= SEQUOIA_LED_BACK;
		break;

	case led_red_off:
		if (led_state & LED_STATE_CLAIMED)
			hw_led_state &= ~SEQUOIA_LED_BACK;
		break;

	default:
		break;
	}

	if  (led_state & LED_STATE_ENABLED)
		sequoia_write(hw_led_state,0x09);

	raw_spin_unlock_irqrestore(&leds_lock, flags);
}

static int __init leds_init(void)
{
	extern void (*leds_event)(led_event_t);
	short temp;
	
	leds_event = sequoia_leds_event;

	/* Make LEDs independent of power-state */
	request_region(0x24,4,"sequoia");
	temp = sequoia_read(0x09);
	temp |= 1<<10;
	sequoia_write(temp,0x09);
	leds_event(led_start);
	return 0;
}

__initcall(leds_init);