initial commit with v3.6.7
[linux-3.6.7-moxart.git] / arch / arm / plat-omap / debug-leds.c
blob39407cbe34c65ab0308a5b1585ad896d5c5f3c2f
1 /*
2 * linux/arch/arm/plat-omap/debug-leds.c
4 * Copyright 2003 by Texas Instruments Incorporated
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 #include <linux/gpio.h>
11 #include <linux/init.h>
12 #include <linux/platform_device.h>
13 #include <linux/leds.h>
14 #include <linux/io.h>
16 #include <mach/hardware.h>
17 #include <asm/leds.h>
18 #include <asm/mach-types.h>
20 #include <plat/fpga.h>
23 /* Many OMAP development platforms reuse the same "debug board"; these
24 * platforms include H2, H3, H4, and Perseus2. There are 16 LEDs on the
25 * debug board (all green), accessed through FPGA registers.
27 * The "surfer" expansion board and H2 sample board also have two-color
28 * green+red LEDs (in parallel), used here for timer and idle indicators
29 * in preference to the ones on the debug board, for a "Disco LED" effect.
31 * This driver exports either the original ARM LED API, the new generic
32 * one, or both.
35 static spinlock_t lock;
36 static struct h2p2_dbg_fpga __iomem *fpga;
37 static u16 led_state, hw_led_state;
40 #ifdef CONFIG_OMAP_DEBUG_LEDS
41 #define new_led_api() 1
42 #else
43 #define new_led_api() 0
44 #endif
47 /*-------------------------------------------------------------------------*/
49 /* original ARM debug LED API:
50 * - timer and idle leds (some boards use non-FPGA leds here);
51 * - up to 4 generic leds, easily accessed in-kernel (any context)
54 #define GPIO_LED_RED 3
55 #define GPIO_LED_GREEN OMAP_MPUIO(4)
57 #define LED_STATE_ENABLED 0x01
58 #define LED_STATE_CLAIMED 0x02
59 #define LED_TIMER_ON 0x04
61 #define GPIO_IDLE GPIO_LED_GREEN
62 #define GPIO_TIMER GPIO_LED_RED
64 static void h2p2_dbg_leds_event(led_event_t evt)
66 unsigned long flags;
68 spin_lock_irqsave(&lock, flags);
70 if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
71 goto done;
73 switch (evt) {
74 case led_start:
75 if (fpga)
76 led_state |= LED_STATE_ENABLED;
77 break;
79 case led_stop:
80 case led_halted:
81 /* all leds off during suspend or shutdown */
83 if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
84 gpio_set_value(GPIO_TIMER, 0);
85 gpio_set_value(GPIO_IDLE, 0);
88 __raw_writew(~0, &fpga->leds);
89 led_state &= ~LED_STATE_ENABLED;
90 goto done;
92 case led_claim:
93 led_state |= LED_STATE_CLAIMED;
94 hw_led_state = 0;
95 break;
97 case led_release:
98 led_state &= ~LED_STATE_CLAIMED;
99 break;
101 #ifdef CONFIG_LEDS_TIMER
102 case led_timer:
103 led_state ^= LED_TIMER_ON;
105 if (machine_is_omap_perseus2() || machine_is_omap_h4())
106 hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
107 else {
108 gpio_set_value(GPIO_TIMER,
109 led_state & LED_TIMER_ON);
110 goto done;
113 break;
114 #endif
116 #ifdef CONFIG_LEDS_CPU
117 /* LED lit iff busy */
118 case led_idle_start:
119 if (machine_is_omap_perseus2() || machine_is_omap_h4())
120 hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
121 else {
122 gpio_set_value(GPIO_IDLE, 1);
123 goto done;
126 break;
128 case led_idle_end:
129 if (machine_is_omap_perseus2() || machine_is_omap_h4())
130 hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
131 else {
132 gpio_set_value(GPIO_IDLE, 0);
133 goto done;
136 break;
137 #endif
139 case led_green_on:
140 hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
141 break;
142 case led_green_off:
143 hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
144 break;
146 case led_amber_on:
147 hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
148 break;
149 case led_amber_off:
150 hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
151 break;
153 case led_red_on:
154 hw_led_state |= H2P2_DBG_FPGA_LED_RED;
155 break;
156 case led_red_off:
157 hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
158 break;
160 case led_blue_on:
161 hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
162 break;
163 case led_blue_off:
164 hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
165 break;
167 default:
168 break;
173 * Actually burn the LEDs
175 if (led_state & LED_STATE_ENABLED)
176 __raw_writew(~hw_led_state, &fpga->leds);
178 done:
179 spin_unlock_irqrestore(&lock, flags);
182 /*-------------------------------------------------------------------------*/
184 /* "new" LED API
185 * - with syfs access and generic triggering
186 * - not readily accessible to in-kernel drivers
189 struct dbg_led {
190 struct led_classdev cdev;
191 u16 mask;
194 static struct dbg_led dbg_leds[] = {
195 /* REVISIT at least H2 uses different timer & cpu leds... */
196 #ifndef CONFIG_LEDS_TIMER
197 { .mask = 1 << 0, .cdev.name = "d4:green",
198 .cdev.default_trigger = "heartbeat", },
199 #endif
200 #ifndef CONFIG_LEDS_CPU
201 { .mask = 1 << 1, .cdev.name = "d5:green", }, /* !idle */
202 #endif
203 { .mask = 1 << 2, .cdev.name = "d6:green", },
204 { .mask = 1 << 3, .cdev.name = "d7:green", },
206 { .mask = 1 << 4, .cdev.name = "d8:green", },
207 { .mask = 1 << 5, .cdev.name = "d9:green", },
208 { .mask = 1 << 6, .cdev.name = "d10:green", },
209 { .mask = 1 << 7, .cdev.name = "d11:green", },
211 { .mask = 1 << 8, .cdev.name = "d12:green", },
212 { .mask = 1 << 9, .cdev.name = "d13:green", },
213 { .mask = 1 << 10, .cdev.name = "d14:green", },
214 { .mask = 1 << 11, .cdev.name = "d15:green", },
216 #ifndef CONFIG_LEDS
217 { .mask = 1 << 12, .cdev.name = "d16:green", },
218 { .mask = 1 << 13, .cdev.name = "d17:green", },
219 { .mask = 1 << 14, .cdev.name = "d18:green", },
220 { .mask = 1 << 15, .cdev.name = "d19:green", },
221 #endif
224 static void
225 fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
227 struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
228 unsigned long flags;
230 spin_lock_irqsave(&lock, flags);
231 if (value == LED_OFF)
232 hw_led_state &= ~led->mask;
233 else
234 hw_led_state |= led->mask;
235 __raw_writew(~hw_led_state, &fpga->leds);
236 spin_unlock_irqrestore(&lock, flags);
239 static void __init newled_init(struct device *dev)
241 unsigned i;
242 struct dbg_led *led;
243 int status;
245 for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
246 led->cdev.brightness_set = fpga_led_set;
247 status = led_classdev_register(dev, &led->cdev);
248 if (status < 0)
249 break;
251 return;
255 /*-------------------------------------------------------------------------*/
257 static int /* __init */ fpga_probe(struct platform_device *pdev)
259 struct resource *iomem;
261 spin_lock_init(&lock);
263 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
264 if (!iomem)
265 return -ENODEV;
267 fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
268 __raw_writew(~0, &fpga->leds);
270 #ifdef CONFIG_LEDS
271 leds_event = h2p2_dbg_leds_event;
272 leds_event(led_start);
273 #endif
275 if (new_led_api()) {
276 newled_init(&pdev->dev);
279 return 0;
282 static int fpga_suspend_noirq(struct device *dev)
284 __raw_writew(~0, &fpga->leds);
285 return 0;
288 static int fpga_resume_noirq(struct device *dev)
290 __raw_writew(~hw_led_state, &fpga->leds);
291 return 0;
294 static const struct dev_pm_ops fpga_dev_pm_ops = {
295 .suspend_noirq = fpga_suspend_noirq,
296 .resume_noirq = fpga_resume_noirq,
299 static struct platform_driver led_driver = {
300 .driver.name = "omap_dbg_led",
301 .driver.pm = &fpga_dev_pm_ops,
302 .probe = fpga_probe,
305 static int __init fpga_init(void)
307 if (machine_is_omap_h4()
308 || machine_is_omap_h3()
309 || machine_is_omap_h2()
310 || machine_is_omap_perseus2()
312 return platform_driver_register(&led_driver);
313 return 0;
315 fs_initcall(fpga_init);