aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorEd Wildgoose <git@wildgooses.com>2011-09-20 17:00:12 -0400
committerThomas Gleixner <tglx@linutronix.de>2011-09-21 05:19:42 -0400
commitd4f3e350172a1dc769ed5e7f5bd540feb0c475d8 (patch)
treeddf2c6a7b32b9c91e003f7f60260ddf985e91b16 /drivers/leds
parent9d037a777695993ec7437e5f451647dea7919d4c (diff)
x86: geode: New PCEngines Alix system driver
This new driver replaces the old PCEngines Alix 2/3 LED driver with a new driver that controls the LEDs through the leds-gpio driver. The old driver accessed GPIOs directly, which created a conflict and prevented also loading the cs5535-gpio driver to read other GPIOs on the Alix board. With this new driver, we hook into leds-gpio which in turn uses GPIO to control the LEDs and therefore it's possible to control both the LEDs and access onboard GPIOs Driver is moved to platform/geode as requested by Grant and any other geode initialisation modules should move here also This driver is inspired by leds-net5501.c by Alessandro Zummo. Ideally, leds-net5501.c should also be moved to platform/geode. Additionally the driver relies on parts of the patch: 7f131cf3ed ("leds: leds-alix2c - take port address from MSR) by Daniel Mack to perform detection of the Alix board. [akpm@linux-foundation.org: include module.h] Signed-off-by: Ed Wildgoose <kernel@wildgooses.com> Cc: git@wildgooses.com Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Daniel Mack <daniel@caiaq.de> Cc: Ingo Molnar <mingo@elte.hu> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Richard Purdie <rpurdie@rpsys.net> Reviewed-by: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-alix2.c239
3 files changed, 0 insertions, 248 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index b591e726a6fa..8974d274334f 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -113,14 +113,6 @@ config LEDS_WRAP
113 help 113 help
114 This option enables support for the PCEngines WRAP programmable LEDs. 114 This option enables support for the PCEngines WRAP programmable LEDs.
115 115
116config LEDS_ALIX2
117 tristate "LED Support for ALIX.2 and ALIX.3 series"
118 depends on LEDS_CLASS
119 depends on X86 && !GPIO_CS5535 && !CS5535_GPIO
120 help
121 This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
122 You have to set leds-alix2.force=1 for boards with Award BIOS.
123
124config LEDS_COBALT_QUBE 116config LEDS_COBALT_QUBE
125 tristate "LED Support for the Cobalt Qube series front LED" 117 tristate "LED Support for the Cobalt Qube series front LED"
126 depends on LEDS_CLASS 118 depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index bbfd2e367dc0..a0a1b89d78a8 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
16obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o 16obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
17obj-$(CONFIG_LEDS_NET5501) += leds-net5501.o 17obj-$(CONFIG_LEDS_NET5501) += leds-net5501.o
18obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o 18obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
19obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o
20obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o 19obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
21obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o 20obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
22obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o 21obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c
deleted file mode 100644
index f59ffadf5125..000000000000
--- a/drivers/leds/leds-alix2.c
+++ /dev/null
@@ -1,239 +0,0 @@
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#include <linux/pci.h>
15
16static int force = 0;
17module_param(force, bool, 0444);
18MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
19
20#define MSR_LBAR_GPIO 0x5140000C
21#define CS5535_GPIO_SIZE 256
22
23static u32 gpio_base;
24
25static struct pci_device_id divil_pci[] = {
26 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
27 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
28 { } /* NULL entry */
29};
30MODULE_DEVICE_TABLE(pci, divil_pci);
31
32struct alix_led {
33 struct led_classdev cdev;
34 unsigned short port;
35 unsigned int on_value;
36 unsigned int off_value;
37};
38
39static void alix_led_set(struct led_classdev *led_cdev,
40 enum led_brightness brightness)
41{
42 struct alix_led *led_dev =
43 container_of(led_cdev, struct alix_led, cdev);
44
45 if (brightness)
46 outl(led_dev->on_value, gpio_base + led_dev->port);
47 else
48 outl(led_dev->off_value, gpio_base + led_dev->port);
49}
50
51static struct alix_led alix_leds[] = {
52 {
53 .cdev = {
54 .name = "alix:1",
55 .brightness_set = alix_led_set,
56 },
57 .port = 0x00,
58 .on_value = 1 << 22,
59 .off_value = 1 << 6,
60 },
61 {
62 .cdev = {
63 .name = "alix:2",
64 .brightness_set = alix_led_set,
65 },
66 .port = 0x80,
67 .on_value = 1 << 25,
68 .off_value = 1 << 9,
69 },
70 {
71 .cdev = {
72 .name = "alix:3",
73 .brightness_set = alix_led_set,
74 },
75 .port = 0x80,
76 .on_value = 1 << 27,
77 .off_value = 1 << 11,
78 },
79};
80
81static int __init alix_led_probe(struct platform_device *pdev)
82{
83 int i;
84 int ret;
85
86 for (i = 0; i < ARRAY_SIZE(alix_leds); i++) {
87 alix_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME;
88 ret = led_classdev_register(&pdev->dev, &alix_leds[i].cdev);
89 if (ret < 0)
90 goto fail;
91 }
92 return 0;
93
94fail:
95 while (--i >= 0)
96 led_classdev_unregister(&alix_leds[i].cdev);
97 return ret;
98}
99
100static int alix_led_remove(struct platform_device *pdev)
101{
102 int i;
103
104 for (i = 0; i < ARRAY_SIZE(alix_leds); i++)
105 led_classdev_unregister(&alix_leds[i].cdev);
106 return 0;
107}
108
109static struct platform_driver alix_led_driver = {
110 .remove = alix_led_remove,
111 .driver = {
112 .name = KBUILD_MODNAME,
113 .owner = THIS_MODULE,
114 },
115};
116
117static int __init alix_present(unsigned long bios_phys,
118 const char *alix_sig,
119 size_t alix_sig_len)
120{
121 const size_t bios_len = 0x00010000;
122 const char *bios_virt;
123 const char *scan_end;
124 const char *p;
125 char name[64];
126
127 if (force) {
128 printk(KERN_NOTICE "%s: forced to skip BIOS test, "
129 "assume system has ALIX.2 style LEDs\n",
130 KBUILD_MODNAME);
131 return 1;
132 }
133
134 bios_virt = phys_to_virt(bios_phys);
135 scan_end = bios_virt + bios_len - (alix_sig_len + 2);
136 for (p = bios_virt; p < scan_end; p++) {
137 const char *tail;
138 char *a;
139
140 if (memcmp(p, alix_sig, alix_sig_len) != 0)
141 continue;
142
143 memcpy(name, p, sizeof(name));
144
145 /* remove the first \0 character from string */
146 a = strchr(name, '\0');
147 if (a)
148 *a = ' ';
149
150 /* cut the string at a newline */
151 a = strchr(name, '\r');
152 if (a)
153 *a = '\0';
154
155 tail = p + alix_sig_len;
156 if ((tail[0] == '2' || tail[0] == '3')) {
157 printk(KERN_INFO
158 "%s: system is recognized as \"%s\"\n",
159 KBUILD_MODNAME, name);
160 return 1;
161 }
162 }
163
164 return 0;
165}
166
167static struct platform_device *pdev;
168
169static int __init alix_pci_led_init(void)
170{
171 u32 low, hi;
172
173 if (pci_dev_present(divil_pci) == 0) {
174 printk(KERN_WARNING KBUILD_MODNAME": DIVIL not found\n");
175 return -ENODEV;
176 }
177
178 /* Grab the GPIO I/O range */
179 rdmsr(MSR_LBAR_GPIO, low, hi);
180
181 /* Check the mask and whether GPIO is enabled (sanity check) */
182 if (hi != 0x0000f001) {
183 printk(KERN_WARNING KBUILD_MODNAME": GPIO not enabled\n");
184 return -ENODEV;
185 }
186
187 /* Mask off the IO base address */
188 gpio_base = low & 0x0000ff00;
189
190 if (!request_region(gpio_base, CS5535_GPIO_SIZE, KBUILD_MODNAME)) {
191 printk(KERN_ERR KBUILD_MODNAME": can't allocate I/O for GPIO\n");
192 return -ENODEV;
193 }
194
195 /* Set GPIO function to output */
196 outl(1 << 6, gpio_base + 0x04);
197 outl(1 << 9, gpio_base + 0x84);
198 outl(1 << 11, gpio_base + 0x84);
199
200 return 0;
201}
202
203static int __init alix_led_init(void)
204{
205 int ret = -ENODEV;
206 const char tinybios_sig[] = "PC Engines ALIX.";
207 const char coreboot_sig[] = "PC Engines\0ALIX.";
208
209 if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
210 alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
211 ret = alix_pci_led_init();
212
213 if (ret < 0)
214 return ret;
215
216 pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
217 if (!IS_ERR(pdev)) {
218 ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
219 if (ret)
220 platform_device_unregister(pdev);
221 } else
222 ret = PTR_ERR(pdev);
223
224 return ret;
225}
226
227static void __exit alix_led_exit(void)
228{
229 platform_device_unregister(pdev);
230 platform_driver_unregister(&alix_led_driver);
231 release_region(gpio_base, CS5535_GPIO_SIZE);
232}
233
234module_init(alix_led_init);
235module_exit(alix_led_exit);
236
237MODULE_AUTHOR("Constantin Baranov <const@mimas.ru>");
238MODULE_DESCRIPTION("PCEngines ALIX.2 and ALIX.3 LED driver");
239MODULE_LICENSE("GPL");