aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/board-h4.c14
-rw-r--r--arch/arm/plat-omap/Kconfig5
-rw-r--r--arch/arm/plat-omap/Makefile2
-rw-r--r--arch/arm/plat-omap/debug-leds.c319
5 files changed, 340 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index aab97ccf1e63..2a1aca7a6371 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -20,6 +20,7 @@ config MACH_OMAP_GENERIC
20config MACH_OMAP_H4 20config MACH_OMAP_H4
21 bool "OMAP 2420 H4 board" 21 bool "OMAP 2420 H4 board"
22 depends on ARCH_OMAP2 && ARCH_OMAP24XX 22 depends on ARCH_OMAP2 && ARCH_OMAP24XX
23 select OMAP_DEBUG_LEDS if LEDS || LEDS_OMAP_DEBUG
23 24
24config MACH_OMAP_APOLLON 25config MACH_OMAP_APOLLON
25 bool "OMAP 2420 Apollon board" 26 bool "OMAP 2420 Apollon board"
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 1e7ed6d22ca9..452193f01531 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -266,12 +266,26 @@ static struct platform_device h4_lcd_device = {
266 .id = -1, 266 .id = -1,
267}; 267};
268 268
269static struct resource h4_led_resources[] = {
270 [0] = {
271 .flags = IORESOURCE_MEM,
272 },
273};
274
275static struct platform_device h4_led_device = {
276 .name = "omap_dbg_led",
277 .id = -1,
278 .num_resources = ARRAY_SIZE(h4_led_resources),
279 .resource = h4_led_resources,
280};
281
269static struct platform_device *h4_devices[] __initdata = { 282static struct platform_device *h4_devices[] __initdata = {
270 &h4_smc91x_device, 283 &h4_smc91x_device,
271 &h4_flash_device, 284 &h4_flash_device,
272 &h4_irda_device, 285 &h4_irda_device,
273 &h4_kp_device, 286 &h4_kp_device,
274 &h4_lcd_device, 287 &h4_lcd_device,
288 &h4_led_device,
275}; 289};
276 290
277static inline void __init h4_init_smc91x(void) 291static inline void __init h4_init_smc91x(void)
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index f2dc363de66b..ce8bc3304e19 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -19,6 +19,11 @@ endchoice
19 19
20comment "OMAP Feature Selections" 20comment "OMAP Feature Selections"
21 21
22config OMAP_DEBUG_LEDS
23 bool
24 help
25 For debug card leds on TI reference boards.
26
22config OMAP_RESET_CLOCKS 27config OMAP_RESET_CLOCKS
23 bool "Reset unused clocks during boot" 28 bool "Reset unused clocks during boot"
24 depends on ARCH_OMAP 29 depends on ARCH_OMAP
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 2896b4546411..4ce277d3485a 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -16,4 +16,4 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
16 16
17obj-$(CONFIG_CPU_FREQ) += cpu-omap.o 17obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
18obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o 18obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
19 19obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
new file mode 100644
index 000000000000..511d6a50041e
--- /dev/null
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -0,0 +1,319 @@
1/*
2 * linux/arch/arm/plat-omap/debug-leds.c
3 *
4 * Copyright 2003 by Texas Instruments Incorporated
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/init.h>
12#include <linux/platform_device.h>
13#include <linux/leds.h>
14
15#include <asm/io.h>
16#include <asm/hardware.h>
17#include <asm/leds.h>
18#include <asm/system.h>
19#include <asm/mach-types.h>
20
21#include <asm/arch/fpga.h>
22#include <asm/arch/gpio.h>
23
24
25/* Many OMAP development platforms reuse the same "debug board"; these
26 * platforms include H2, H3, H4, and Perseus2. There are 16 LEDs on the
27 * debug board (all green), accessed through FPGA registers.
28 *
29 * The "surfer" expansion board and H2 sample board also have two-color
30 * green+red LEDs (in parallel), used here for timer and idle indicators
31 * in preference to the ones on the debug board, for a "Disco LED" effect.
32 *
33 * This driver exports either the original ARM LED API, the new generic
34 * one, or both.
35 */
36
37static spinlock_t lock;
38static struct h2p2_dbg_fpga __iomem *fpga;
39static u16 led_state, hw_led_state;
40
41
42#ifdef CONFIG_LEDS
43#define old_led_api() 1
44#else
45#define old_led_api() 0
46#endif
47
48#ifdef CONFIG_LEDS_OMAP_DEBUG
49#define new_led_api() 1
50#else
51#define new_led_api() 0
52#endif
53
54
55/*-------------------------------------------------------------------------*/
56
57/* original ARM debug LED API:
58 * - timer and idle leds (some boards use non-FPGA leds here);
59 * - up to 4 generic leds, easily accessed in-kernel (any context)
60 */
61
62#define GPIO_LED_RED 3
63#define GPIO_LED_GREEN OMAP_MPUIO(4)
64
65#define LED_STATE_ENABLED 0x01
66#define LED_STATE_CLAIMED 0x02
67#define LED_TIMER_ON 0x04
68
69#define GPIO_IDLE GPIO_LED_GREEN
70#define GPIO_TIMER GPIO_LED_RED
71
72static void h2p2_dbg_leds_event(led_event_t evt)
73{
74 unsigned long flags;
75
76 spin_lock_irqsave(&lock, flags);
77
78 if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
79 goto done;
80
81 switch (evt) {
82 case led_start:
83 if (fpga)
84 led_state |= LED_STATE_ENABLED;
85 break;
86
87 case led_stop:
88 case led_halted:
89 /* all leds off during suspend or shutdown */
90
91 if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
92 omap_set_gpio_dataout(GPIO_TIMER, 0);
93 omap_set_gpio_dataout(GPIO_IDLE, 0);
94 }
95
96 __raw_writew(~0, &fpga->leds);
97 led_state &= ~LED_STATE_ENABLED;
98 goto done;
99
100 case led_claim:
101 led_state |= LED_STATE_CLAIMED;
102 hw_led_state = 0;
103 break;
104
105 case led_release:
106 led_state &= ~LED_STATE_CLAIMED;
107 break;
108
109#ifdef CONFIG_LEDS_TIMER
110 case led_timer:
111 led_state ^= LED_TIMER_ON;
112
113 if (machine_is_omap_perseus2() || machine_is_omap_h4())
114 hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
115 else {
116 omap_set_gpio_dataout(GPIO_TIMER,
117 led_state & LED_TIMER_ON);
118 goto done;
119 }
120
121 break;
122#endif
123
124#ifdef CONFIG_LEDS_CPU
125 /* LED lit iff busy */
126 case led_idle_start:
127 if (machine_is_omap_perseus2() || machine_is_omap_h4())
128 hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
129 else {
130 omap_set_gpio_dataout(GPIO_IDLE, 1);
131 goto done;
132 }
133
134 break;
135
136 case led_idle_end:
137 if (machine_is_omap_perseus2() || machine_is_omap_h4())
138 hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
139 else {
140 omap_set_gpio_dataout(GPIO_IDLE, 0);
141 goto done;
142 }
143
144 break;
145#endif
146
147 case led_green_on:
148 hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
149 break;
150 case led_green_off:
151 hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
152 break;
153
154 case led_amber_on:
155 hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
156 break;
157 case led_amber_off:
158 hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
159 break;
160
161 case led_red_on:
162 hw_led_state |= H2P2_DBG_FPGA_LED_RED;
163 break;
164 case led_red_off:
165 hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
166 break;
167
168 case led_blue_on:
169 hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
170 break;
171 case led_blue_off:
172 hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
173 break;
174
175 default:
176 break;
177 }
178
179
180 /*
181 * Actually burn the LEDs
182 */
183 if (led_state & LED_STATE_ENABLED)
184 __raw_writew(~hw_led_state, &fpga->leds);
185
186done:
187 spin_unlock_irqrestore(&lock, flags);
188}
189
190/*-------------------------------------------------------------------------*/
191
192/* "new" LED API
193 * - with syfs access and generic triggering
194 * - not readily accessible to in-kernel drivers
195 */
196
197struct dbg_led {
198 struct led_classdev cdev;
199 u16 mask;
200};
201
202static struct dbg_led dbg_leds[] = {
203 /* REVISIT at least H2 uses different timer & cpu leds... */
204#ifndef CONFIG_LEDS_TIMER
205 { .mask = 1 << 0, .cdev.name = "d4:green", }, /* timer */
206#endif
207#ifndef CONFIG_LEDS_CPU
208 { .mask = 1 << 1, .cdev.name = "d5:green", }, /* !idle */
209#endif
210 { .mask = 1 << 2, .cdev.name = "d6:green", },
211 { .mask = 1 << 3, .cdev.name = "d7:green", },
212
213 { .mask = 1 << 4, .cdev.name = "d8:green", },
214 { .mask = 1 << 5, .cdev.name = "d9:green", },
215 { .mask = 1 << 6, .cdev.name = "d10:green", },
216 { .mask = 1 << 7, .cdev.name = "d11:green", },
217
218 { .mask = 1 << 8, .cdev.name = "d12:green", },
219 { .mask = 1 << 9, .cdev.name = "d13:green", },
220 { .mask = 1 << 10, .cdev.name = "d14:green", },
221 { .mask = 1 << 11, .cdev.name = "d15:green", },
222
223#ifndef CONFIG_LEDS
224 { .mask = 1 << 12, .cdev.name = "d16:green", },
225 { .mask = 1 << 13, .cdev.name = "d17:green", },
226 { .mask = 1 << 14, .cdev.name = "d18:green", },
227 { .mask = 1 << 15, .cdev.name = "d19:green", },
228#endif
229};
230
231static void
232fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
233{
234 struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
235 unsigned long flags;
236
237 spin_lock_irqsave(&lock, flags);
238 if (value == LED_OFF)
239 hw_led_state &= ~led->mask;
240 else
241 hw_led_state |= led->mask;
242 __raw_writew(~hw_led_state, &fpga->leds);
243 spin_unlock_irqrestore(&lock, flags);
244}
245
246static void __init newled_init(struct device *dev)
247{
248 unsigned i;
249 struct dbg_led *led;
250 int status;
251
252 for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
253 led->cdev.brightness_set = fpga_led_set;
254 status = led_classdev_register(dev, &led->cdev);
255 if (status < 0)
256 break;
257 }
258 return;
259}
260
261
262/*-------------------------------------------------------------------------*/
263
264static int /* __init */ fpga_probe(struct platform_device *pdev)
265{
266 struct resource *iomem;
267
268 spin_lock_init(&lock);
269
270 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
271 if (!iomem)
272 return -ENODEV;
273
274 fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
275 __raw_writew(~0, &fpga->leds);
276
277 if (old_led_api()) {
278 leds_event = h2p2_dbg_leds_event;
279 leds_event(led_start);
280 }
281
282 if (new_led_api()) {
283 newled_init(&pdev->dev);
284 }
285
286 return 0;
287}
288
289static int fpga_suspend_late(struct platform_device *pdev, pm_message_t mesg)
290{
291 __raw_writew(~0, &fpga->leds);
292 return 0;
293}
294
295static int fpga_resume_early(struct platform_device *pdev)
296{
297 __raw_writew(~hw_led_state, &fpga->leds);
298 return 0;
299}
300
301
302static struct platform_driver led_driver = {
303 .driver.name = "omap_dbg_led",
304 .probe = fpga_probe,
305 .suspend_late = fpga_suspend_late,
306 .resume_early = fpga_resume_early,
307};
308
309static int __init fpga_init(void)
310{
311 if (machine_is_omap_h4()
312 || machine_is_omap_h3()
313 || machine_is_omap_h2()
314 || machine_is_omap_perseus2()
315 )
316 return platform_driver_register(&led_driver);
317 return 0;
318}
319fs_initcall(fpga_init);