aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/leds/Kconfig6
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-alix2.c209
3 files changed, 216 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index e7fb7d2fcbfc..b7f9e251b5a2 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -63,6 +63,12 @@ config LEDS_WRAP
63 help 63 help
64 This option enables support for the PCEngines WRAP programmable LEDs. 64 This option enables support for the PCEngines WRAP programmable LEDs.
65 65
66config LEDS_ALIX2
67 tristate "LED Support for ALIX.2 and ALIX.3 series"
68 depends on LEDS_CLASS && X86 && EXPERIMENTAL
69 help
70 This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
71
66config LEDS_H1940 72config LEDS_H1940
67 tristate "LED Support for iPAQ H1940 device" 73 tristate "LED Support for iPAQ H1940 device"
68 depends on LEDS_CLASS && ARCH_H1940 74 depends on LEDS_CLASS && ARCH_H1940
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index e1967a29850e..ff4616a49043 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
11obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o 11obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
12obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o 12obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
13obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o 13obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
14obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o
14obj-$(CONFIG_LEDS_H1940) += leds-h1940.o 15obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
15obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o 16obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
16obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o 17obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c
new file mode 100644
index 000000000000..d7666e6cb425
--- /dev/null
+++ b/drivers/leds/leds-alix2.c
@@ -0,0 +1,209 @@
1/*
2 * LEDs driver for PCEngines ALIX.2 and ALIX.3
3 *
4 * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
5 */
6
7#include <linux/err.h>
8#include <linux/io.h>
9#include <linux/kernel.h>
10#include <linux/leds.h>
11#include <linux/module.h>
12#include <linux/platform_device.h>
13#include <linux/string.h>
14
15static int force = 0;
16module_param(force, bool, 0444);
17MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs");
18
19struct alix_led {
20 struct led_classdev cdev;
21 unsigned short port;
22 unsigned int on_value;
23 unsigned int off_value;
24};
25
26static void alix_led_set(struct led_classdev *led_cdev,
27 enum led_brightness brightness)
28{
29 struct alix_led *led_dev =
30 container_of(led_cdev, struct alix_led, cdev);
31
32 if (brightness)
33 outl(led_dev->on_value, led_dev->port);
34 else
35 outl(led_dev->off_value, led_dev->port);
36}
37
38static struct alix_led alix_leds[] = {
39 {
40 .cdev = {
41 .name = "alix:1",
42 .brightness_set = alix_led_set,
43 },
44 .port = 0x6100,
45 .on_value = 1 << 22,
46 .off_value = 1 << 6,
47 },
48 {
49 .cdev = {
50 .name = "alix:2",
51 .brightness_set = alix_led_set,
52 },
53 .port = 0x6180,
54 .on_value = 1 << 25,
55 .off_value = 1 << 9,
56 },
57 {
58 .cdev = {
59 .name = "alix:3",
60 .brightness_set = alix_led_set,
61 },
62 .port = 0x6180,
63 .on_value = 1 << 27,
64 .off_value = 1 << 11,
65 },
66};
67
68#ifdef CONFIG_PM
69
70static int alix_led_suspend(struct platform_device *dev, pm_message_t state)
71{
72 int i;
73
74 for (i = 0; i < ARRAY_SIZE(alix_leds); i++)
75 led_classdev_suspend(&alix_leds[i].cdev);
76 return 0;
77}
78
79static int alix_led_resume(struct platform_device *dev)
80{
81 int i;
82
83 for (i = 0; i < ARRAY_SIZE(alix_leds); i++)
84 led_classdev_resume(&alix_leds[i].cdev);
85 return 0;
86}
87
88#else
89
90#define alix_led_suspend NULL
91#define alix_led_resume NULL
92
93#endif
94
95static int __init alix_led_probe(struct platform_device *pdev)
96{
97 int i;
98 int ret;
99
100 for (i = 0; i < ARRAY_SIZE(alix_leds); i++) {
101 ret = led_classdev_register(&pdev->dev, &alix_leds[i].cdev);
102 if (ret < 0)
103 goto fail;
104 }
105 return 0;
106
107fail:
108 while (--i >= 0)
109 led_classdev_unregister(&alix_leds[i].cdev);
110 return ret;
111}
112
113static int alix_led_remove(struct platform_device *pdev)
114{
115 int i;
116
117 for (i = 0; i < ARRAY_SIZE(alix_leds); i++)
118 led_classdev_unregister(&alix_leds[i].cdev);
119 return 0;
120}
121
122static struct platform_driver alix_led_driver = {
123 .remove = alix_led_remove,
124 .suspend = alix_led_suspend,
125 .resume = alix_led_resume,
126 .driver = {
127 .name = KBUILD_MODNAME,
128 .owner = THIS_MODULE,
129 },
130};
131
132static int __init alix_present(void)
133{
134 const unsigned long bios_phys = 0x000f0000;
135 const size_t bios_len = 0x00010000;
136 const char alix_sig[] = "PC Engines ALIX.";
137 const size_t alix_sig_len = sizeof(alix_sig) - 1;
138
139 const char *bios_virt;
140 const char *scan_end;
141 const char *p;
142 int ret = 0;
143
144 if (force) {
145 printk(KERN_NOTICE "%s: forced to skip BIOS test, "
146 "assume system has ALIX.2 style LEDs\n",
147 KBUILD_MODNAME);
148 ret = 1;
149 goto out;
150 }
151
152 bios_virt = phys_to_virt(bios_phys);
153 scan_end = bios_virt + bios_len - (alix_sig_len + 2);
154 for (p = bios_virt; p < scan_end; p++) {
155 const char *tail;
156
157 if (memcmp(p, alix_sig, alix_sig_len) != 0) {
158 continue;
159 }
160
161 tail = p + alix_sig_len;
162 if ((tail[0] == '2' || tail[0] == '3') && tail[1] == '\0') {
163 printk(KERN_INFO
164 "%s: system is recognized as \"%s\"\n",
165 KBUILD_MODNAME, p);
166 ret = 1;
167 break;
168 }
169 }
170
171out:
172 return ret;
173}
174
175static struct platform_device *pdev;
176
177static int __init alix_led_init(void)
178{
179 int ret;
180
181 if (!alix_present()) {
182 ret = -ENODEV;
183 goto out;
184 }
185
186 pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
187 if (!IS_ERR(pdev)) {
188 ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
189 if (ret)
190 platform_device_unregister(pdev);
191 } else
192 ret = PTR_ERR(pdev);
193
194out:
195 return ret;
196}
197
198static void __exit alix_led_exit(void)
199{
200 platform_device_unregister(pdev);
201 platform_driver_unregister(&alix_led_driver);
202}
203
204module_init(alix_led_init);
205module_exit(alix_led_exit);
206
207MODULE_AUTHOR("Constantin Baranov <const@mimas.ru>");
208MODULE_DESCRIPTION("PCEngines ALIX.2 and ALIX.3 LED driver");
209MODULE_LICENSE("GPL");