Root/target/linux/generic/patches-2.6.39/105-alix_platform_leds.patch

1From: Ed Wildgoose <git@wildgooses.com>
2Date: Wed, 3 Aug 2011 00:52:36 +0000 (+1000)
3Subject: This new driver replaces the old PCEngines Alix 2/3 LED driver with a new
4X-Git-Tag: next-20110812~1^2~75
5X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=2cd7b3e8f8078c214c93a2c60cb845500c92df4a;hp=dc849eae35bbf651ab3ee459f5683e1ff780413d
6
7This new driver replaces the old PCEngines Alix 2/3 LED driver with a new
8driver that controls the LEDs through the leds-gpio driver. The old
9driver accessed GPIOs directly, which created a conflict and prevented
10also loading the cs5535-gpio driver to read other GPIOs on the Alix board.
11 With this new driver, we hook into leds-gpio which in turn uses GPIO to
12control the LEDs and therefore it's possible to control both the LEDs and
13access onboard GPIOs
14
15Driver is moved to platform/geode and any other geode initialisation
16modules should move here also.
17
18This driver is inspired by leds-net5501.c by Alessandro Zummo.
19
20Ideally, leds-net5501.c should also be moved to platform/geode.
21Additionally the driver relies on parts of the patch: 7f131cf3ed ("leds:
22leds-alix2c - take port address from MSR) by Daniel Mack to perform
23detection of the Alix board.
24
25Signed-off-by: Ed Wildgoose <kernel@wildgooses.com>
26Cc: Alessandro Zummo <a.zummo@towertech.it>
27Cc: Daniel Mack <daniel@caiaq.de>
28Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
29Cc: Ingo Molnar <mingo@elte.hu>
30Cc: Thomas Gleixner <tglx@linutronix.de>
31Cc: "H. Peter Anvin" <hpa@zytor.com>
32Cc: Richard Purdie <rpurdie@rpsys.net>
33Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
34---
35
36--- a/arch/x86/Kconfig
37+++ b/arch/x86/Kconfig
38@@ -2087,6 +2087,20 @@ config OLPC_XO1
39     ---help---
40       Add support for non-essential features of the OLPC XO-1 laptop.
41 
42+config ALIX
43+ bool "PCEngines ALIX System Support (LED setup)"
44+ select GPIOLIB
45+ ---help---
46+ This option enables system support for the PCEngines ALIX.
47+ At present this just sets up LEDs for GPIO control on
48+ ALIX2/3/6 boards. However, other system specific setup should
49+ get added here.
50+
51+ Note: You must still enable the drivers for GPIO and LED support
52+ (GPIO_CS5535 & LEDS_GPIO) to actually use the LEDs
53+
54+ Note: You have to set alix.force=1 for boards with Award BIOS.
55+
56 endif # X86_32
57 
58 config AMD_NB
59--- a/arch/x86/platform/Makefile
60+++ b/arch/x86/platform/Makefile
61@@ -1,6 +1,7 @@
62 # Platform specific code goes here
63 obj-y += ce4100/
64 obj-y += efi/
65+obj-y += geode/
66 obj-y += iris/
67 obj-y += mrst/
68 obj-y += olpc/
69--- /dev/null
70+++ b/arch/x86/platform/geode/Makefile
71@@ -0,0 +1 @@
72+obj-$(CONFIG_ALIX) += alix.o
73--- /dev/null
74+++ b/arch/x86/platform/geode/alix.c
75@@ -0,0 +1,141 @@
76+/*
77+ * System Specific setup for PCEngines ALIX.
78+ * At the moment this means setup of GPIO control of LEDs
79+ * on Alix.2/3/6 boards.
80+ *
81+ *
82+ * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
83+ * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
84+ *
85+ * TODO: There are large similarities with leds-net5501.c
86+ * by Alessandro Zummo <a.zummo@towertech.it>
87+ * In the future leds-net5501.c should be migrated over to platform
88+ *
89+ * This program is free software; you can redistribute it and/or modify
90+ * it under the terms of the GNU General Public License version 2
91+ * as published by the Free Software Foundation.
92+ */
93+
94+#include <linux/kernel.h>
95+#include <linux/init.h>
96+#include <linux/io.h>
97+#include <linux/string.h>
98+#include <linux/leds.h>
99+#include <linux/platform_device.h>
100+#include <linux/gpio.h>
101+
102+#include <asm/geode.h>
103+
104+static int force = 0;
105+module_param(force, bool, 0444);
106+/* FIXME: Award bios is not automatically detected as Alix platform */
107+MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
108+
109+static struct gpio_led alix_leds[] = {
110+ {
111+ .name = "alix:1",
112+ .gpio = 6,
113+ .default_trigger = "default-on",
114+ .active_low = 1,
115+ },
116+ {
117+ .name = "alix:2",
118+ .gpio = 25,
119+ .default_trigger = "default-off",
120+ .active_low = 1,
121+ },
122+ {
123+ .name = "alix:3",
124+ .gpio = 27,
125+ .default_trigger = "default-off",
126+ .active_low = 1,
127+ },
128+};
129+
130+static struct gpio_led_platform_data alix_leds_data = {
131+ .num_leds = ARRAY_SIZE(alix_leds),
132+ .leds = alix_leds,
133+};
134+
135+static struct platform_device alix_leds_dev = {
136+ .name = "leds-gpio",
137+ .id = -1,
138+ .dev.platform_data = &alix_leds_data,
139+};
140+
141+static void __init register_alix(void)
142+{
143+ /* Setup LED control through leds-gpio driver */
144+ platform_device_register(&alix_leds_dev);
145+}
146+
147+static int __init alix_present(unsigned long bios_phys,
148+ const char *alix_sig,
149+ size_t alix_sig_len)
150+{
151+ const size_t bios_len = 0x00010000;
152+ const char *bios_virt;
153+ const char *scan_end;
154+ const char *p;
155+ char name[64];
156+
157+ if (force) {
158+ printk(KERN_NOTICE "%s: forced to skip BIOS test, "
159+ "assume system is ALIX.2/ALIX.3\n",
160+ KBUILD_MODNAME);
161+ return 1;
162+ }
163+
164+ bios_virt = phys_to_virt(bios_phys);
165+ scan_end = bios_virt + bios_len - (alix_sig_len + 2);
166+ for (p = bios_virt; p < scan_end; p++) {
167+ const char *tail;
168+ char *a;
169+
170+ if (memcmp(p, alix_sig, alix_sig_len) != 0)
171+ continue;
172+
173+ memcpy(name, p, sizeof(name));
174+
175+ /* remove the first \0 character from string */
176+ a = strchr(name, '\0');
177+ if (a)
178+ *a = ' ';
179+
180+ /* cut the string at a newline */
181+ a = strchr(name, '\r');
182+ if (a)
183+ *a = '\0';
184+
185+ tail = p + alix_sig_len;
186+ if ((tail[0] == '2' || tail[0] == '3')) {
187+ printk(KERN_INFO
188+ "%s: system is recognized as \"%s\"\n",
189+ KBUILD_MODNAME, name);
190+ return 1;
191+ }
192+ }
193+
194+ return 0;
195+}
196+
197+static int __init alix_init(void)
198+{
199+ const char tinybios_sig[] = "PC Engines ALIX.";
200+ const char coreboot_sig[] = "PC Engines\0ALIX.";
201+
202+ if (!is_geode())
203+ return 0;
204+
205+ if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
206+ alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
207+ register_alix();
208+
209+ return 0;
210+}
211+
212+module_init(alix_init);
213+
214+MODULE_AUTHOR("Ed Wildgoose <kernel@wildgooses.com>");
215+MODULE_DESCRIPTION("PCEngines ALIX System Setup");
216+MODULE_LICENSE("GPL");
217--- a/drivers/leds/Kconfig
218+++ b/drivers/leds/Kconfig
219@@ -107,14 +107,6 @@ config LEDS_WRAP
220     help
221       This option enables support for the PCEngines WRAP programmable LEDs.
222 
223-config LEDS_ALIX2
224- tristate "LED Support for ALIX.2 and ALIX.3 series"
225- depends on LEDS_CLASS
226- depends on X86 && !GPIO_CS5535 && !CS5535_GPIO
227- help
228- This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
229- You have to set leds-alix2.force=1 for boards with Award BIOS.
230-
231 config LEDS_H1940
232     tristate "LED Support for iPAQ H1940 device"
233     depends on LEDS_CLASS
234--- a/drivers/leds/Makefile
235+++ b/drivers/leds/Makefile
236@@ -16,7 +16,6 @@ obj-$(CONFIG_LEDS_AMS_DELTA) += leds-am
237 obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
238 obj-$(CONFIG_LEDS_NET5501) += leds-net5501.o
239 obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
240-obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o
241 obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
242 obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
243 obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
244--- a/drivers/leds/leds-alix2.c
245+++ /dev/null
246@@ -1,239 +0,0 @@
247-/*
248- * LEDs driver for PCEngines ALIX.2 and ALIX.3
249- *
250- * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
251- */
252-
253-#include <linux/err.h>
254-#include <linux/io.h>
255-#include <linux/kernel.h>
256-#include <linux/leds.h>
257-#include <linux/module.h>
258-#include <linux/platform_device.h>
259-#include <linux/string.h>
260-#include <linux/pci.h>
261-
262-static int force = 0;
263-module_param(force, bool, 0444);
264-MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
265-
266-#define MSR_LBAR_GPIO 0x5140000C
267-#define CS5535_GPIO_SIZE 256
268-
269-static u32 gpio_base;
270-
271-static struct pci_device_id divil_pci[] = {
272- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
273- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
274- { } /* NULL entry */
275-};
276-MODULE_DEVICE_TABLE(pci, divil_pci);
277-
278-struct alix_led {
279- struct led_classdev cdev;
280- unsigned short port;
281- unsigned int on_value;
282- unsigned int off_value;
283-};
284-
285-static void alix_led_set(struct led_classdev *led_cdev,
286- enum led_brightness brightness)
287-{
288- struct alix_led *led_dev =
289- container_of(led_cdev, struct alix_led, cdev);
290-
291- if (brightness)
292- outl(led_dev->on_value, gpio_base + led_dev->port);
293- else
294- outl(led_dev->off_value, gpio_base + led_dev->port);
295-}
296-
297-static struct alix_led alix_leds[] = {
298- {
299- .cdev = {
300- .name = "alix:1",
301- .brightness_set = alix_led_set,
302- },
303- .port = 0x00,
304- .on_value = 1 << 22,
305- .off_value = 1 << 6,
306- },
307- {
308- .cdev = {
309- .name = "alix:2",
310- .brightness_set = alix_led_set,
311- },
312- .port = 0x80,
313- .on_value = 1 << 25,
314- .off_value = 1 << 9,
315- },
316- {
317- .cdev = {
318- .name = "alix:3",
319- .brightness_set = alix_led_set,
320- },
321- .port = 0x80,
322- .on_value = 1 << 27,
323- .off_value = 1 << 11,
324- },
325-};
326-
327-static int __init alix_led_probe(struct platform_device *pdev)
328-{
329- int i;
330- int ret;
331-
332- for (i = 0; i < ARRAY_SIZE(alix_leds); i++) {
333- alix_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME;
334- ret = led_classdev_register(&pdev->dev, &alix_leds[i].cdev);
335- if (ret < 0)
336- goto fail;
337- }
338- return 0;
339-
340-fail:
341- while (--i >= 0)
342- led_classdev_unregister(&alix_leds[i].cdev);
343- return ret;
344-}
345-
346-static int alix_led_remove(struct platform_device *pdev)
347-{
348- int i;
349-
350- for (i = 0; i < ARRAY_SIZE(alix_leds); i++)
351- led_classdev_unregister(&alix_leds[i].cdev);
352- return 0;
353-}
354-
355-static struct platform_driver alix_led_driver = {
356- .remove = alix_led_remove,
357- .driver = {
358- .name = KBUILD_MODNAME,
359- .owner = THIS_MODULE,
360- },
361-};
362-
363-static int __init alix_present(unsigned long bios_phys,
364- const char *alix_sig,
365- size_t alix_sig_len)
366-{
367- const size_t bios_len = 0x00010000;
368- const char *bios_virt;
369- const char *scan_end;
370- const char *p;
371- char name[64];
372-
373- if (force) {
374- printk(KERN_NOTICE "%s: forced to skip BIOS test, "
375- "assume system has ALIX.2 style LEDs\n",
376- KBUILD_MODNAME);
377- return 1;
378- }
379-
380- bios_virt = phys_to_virt(bios_phys);
381- scan_end = bios_virt + bios_len - (alix_sig_len + 2);
382- for (p = bios_virt; p < scan_end; p++) {
383- const char *tail;
384- char *a;
385-
386- if (memcmp(p, alix_sig, alix_sig_len) != 0)
387- continue;
388-
389- memcpy(name, p, sizeof(name));
390-
391- /* remove the first \0 character from string */
392- a = strchr(name, '\0');
393- if (a)
394- *a = ' ';
395-
396- /* cut the string at a newline */
397- a = strchr(name, '\r');
398- if (a)
399- *a = '\0';
400-
401- tail = p + alix_sig_len;
402- if ((tail[0] == '2' || tail[0] == '3')) {
403- printk(KERN_INFO
404- "%s: system is recognized as \"%s\"\n",
405- KBUILD_MODNAME, name);
406- return 1;
407- }
408- }
409-
410- return 0;
411-}
412-
413-static struct platform_device *pdev;
414-
415-static int __init alix_pci_led_init(void)
416-{
417- u32 low, hi;
418-
419- if (pci_dev_present(divil_pci) == 0) {
420- printk(KERN_WARNING KBUILD_MODNAME": DIVIL not found\n");
421- return -ENODEV;
422- }
423-
424- /* Grab the GPIO I/O range */
425- rdmsr(MSR_LBAR_GPIO, low, hi);
426-
427- /* Check the mask and whether GPIO is enabled (sanity check) */
428- if (hi != 0x0000f001) {
429- printk(KERN_WARNING KBUILD_MODNAME": GPIO not enabled\n");
430- return -ENODEV;
431- }
432-
433- /* Mask off the IO base address */
434- gpio_base = low & 0x0000ff00;
435-
436- if (!request_region(gpio_base, CS5535_GPIO_SIZE, KBUILD_MODNAME)) {
437- printk(KERN_ERR KBUILD_MODNAME": can't allocate I/O for GPIO\n");
438- return -ENODEV;
439- }
440-
441- /* Set GPIO function to output */
442- outl(1 << 6, gpio_base + 0x04);
443- outl(1 << 9, gpio_base + 0x84);
444- outl(1 << 11, gpio_base + 0x84);
445-
446- return 0;
447-}
448-
449-static int __init alix_led_init(void)
450-{
451- int ret = -ENODEV;
452- const char tinybios_sig[] = "PC Engines ALIX.";
453- const char coreboot_sig[] = "PC Engines\0ALIX.";
454-
455- if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
456- alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
457- ret = alix_pci_led_init();
458-
459- if (ret < 0)
460- return ret;
461-
462- pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
463- if (!IS_ERR(pdev)) {
464- ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
465- if (ret)
466- platform_device_unregister(pdev);
467- } else
468- ret = PTR_ERR(pdev);
469-
470- return ret;
471-}
472-
473-static void __exit alix_led_exit(void)
474-{
475- platform_device_unregister(pdev);
476- platform_driver_unregister(&alix_led_driver);
477- release_region(gpio_base, CS5535_GPIO_SIZE);
478-}
479-
480-module_init(alix_led_init);
481-module_exit(alix_led_exit);
482-
483-MODULE_AUTHOR("Constantin Baranov <const@mimas.ru>");
484-MODULE_DESCRIPTION("PCEngines ALIX.2 and ALIX.3 LED driver");
485-MODULE_LICENSE("GPL");
486

Archive Download this file



interactive