Merge branch 'async-scsi-resume' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / arch / arm / mach-integrator / leds.c
1 /*
2  * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
3  * Based on Versatile and RealView machine LED code
4  *
5  * License terms: GNU General Public License (GPL) version 2
6  * Author: Bryan Wu <bryan.wu@canonical.com>
7  */
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/io.h>
11 #include <linux/slab.h>
12 #include <linux/leds.h>
13
14 #include "hardware.h"
15 #include "cm.h"
16
17 #if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
18
19 #define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
20 #define LEDREG  (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
21
22 struct integrator_led {
23         struct led_classdev     cdev;
24         u8                      mask;
25 };
26
27 /*
28  * The triggers lines up below will only be used if the
29  * LED triggers are compiled in.
30  */
31 static const struct {
32         const char *name;
33         const char *trigger;
34 } integrator_leds[] = {
35         { "integrator:green0", "heartbeat", },
36         { "integrator:yellow", },
37         { "integrator:red", },
38         { "integrator:green1", },
39         { "integrator:core_module", "cpu0", },
40 };
41
42 static void integrator_led_set(struct led_classdev *cdev,
43                               enum led_brightness b)
44 {
45         struct integrator_led *led = container_of(cdev,
46                                                  struct integrator_led, cdev);
47         u32 reg = __raw_readl(LEDREG);
48
49         if (b != LED_OFF)
50                 reg |= led->mask;
51         else
52                 reg &= ~led->mask;
53
54         while (__raw_readl(ALPHA_REG) & 1)
55                 cpu_relax();
56
57         __raw_writel(reg, LEDREG);
58 }
59
60 static enum led_brightness integrator_led_get(struct led_classdev *cdev)
61 {
62         struct integrator_led *led = container_of(cdev,
63                                                  struct integrator_led, cdev);
64         u32 reg = __raw_readl(LEDREG);
65
66         return (reg & led->mask) ? LED_FULL : LED_OFF;
67 }
68
69 static void cm_led_set(struct led_classdev *cdev,
70                               enum led_brightness b)
71 {
72         if (b != LED_OFF)
73                 cm_control(CM_CTRL_LED, CM_CTRL_LED);
74         else
75                 cm_control(CM_CTRL_LED, 0);
76 }
77
78 static enum led_brightness cm_led_get(struct led_classdev *cdev)
79 {
80         u32 reg = cm_get();
81
82         return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
83 }
84
85 static int __init integrator_leds_init(void)
86 {
87         int i;
88
89         for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
90                 struct integrator_led *led;
91
92                 led = kzalloc(sizeof(*led), GFP_KERNEL);
93                 if (!led)
94                         break;
95
96
97                 led->cdev.name = integrator_leds[i].name;
98
99                 if (i == 4) { /* Setting for LED in core module */
100                         led->cdev.brightness_set = cm_led_set;
101                         led->cdev.brightness_get = cm_led_get;
102                 } else {
103                         led->cdev.brightness_set = integrator_led_set;
104                         led->cdev.brightness_get = integrator_led_get;
105                 }
106
107                 led->cdev.default_trigger = integrator_leds[i].trigger;
108                 led->mask = BIT(i);
109
110                 if (led_classdev_register(NULL, &led->cdev) < 0) {
111                         kfree(led);
112                         break;
113                 }
114         }
115
116         return 0;
117 }
118
119 /*
120  * Since we may have triggers on any subsystem, defer registration
121  * until after subsystem_init.
122  */
123 fs_initcall(integrator_leds_init);
124 #endif