aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-28 08:04:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-28 08:04:26 -0400
commita93f3e9f424ffb82b4983d2ebf8667ef20255015 (patch)
tree7e1f9b0092289b59b20ac8d70261d8dc68e64b4b
parent107095a9463dc1c64168c7e6592d3a47c474fec8 (diff)
parentd4f3e350172a1dc769ed5e7f5bd540feb0c475d8 (diff)
Merge branch 'x86-geode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'x86-geode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86: geode: New PCEngines Alix system driver
-rw-r--r--arch/x86/Kconfig14
-rw-r--r--arch/x86/platform/Makefile1
-rw-r--r--arch/x86/platform/geode/Makefile1
-rw-r--r--arch/x86/platform/geode/alix.c142
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-alix2.c239
7 files changed, 158 insertions, 248 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f49767716c70..16db864c42b7 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2066,6 +2066,20 @@ config OLPC_XO15_SCI
2066 - AC adapter status updates 2066 - AC adapter status updates
2067 - Battery status updates 2067 - Battery status updates
2068 2068
2069config ALIX
2070 bool "PCEngines ALIX System Support (LED setup)"
2071 select GPIOLIB
2072 ---help---
2073 This option enables system support for the PCEngines ALIX.
2074 At present this just sets up LEDs for GPIO control on
2075 ALIX2/3/6 boards. However, other system specific setup should
2076 get added here.
2077
2078 Note: You must still enable the drivers for GPIO and LED support
2079 (GPIO_CS5535 & LEDS_GPIO) to actually use the LEDs
2080
2081 Note: You have to set alix.force=1 for boards with Award BIOS.
2082
2069endif # X86_32 2083endif # X86_32
2070 2084
2071config AMD_NB 2085config AMD_NB
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
index 021eee91c056..8d874396cb29 100644
--- a/arch/x86/platform/Makefile
+++ b/arch/x86/platform/Makefile
@@ -1,6 +1,7 @@
1# Platform specific code goes here 1# Platform specific code goes here
2obj-y += ce4100/ 2obj-y += ce4100/
3obj-y += efi/ 3obj-y += efi/
4obj-y += geode/
4obj-y += iris/ 5obj-y += iris/
5obj-y += mrst/ 6obj-y += mrst/
6obj-y += olpc/ 7obj-y += olpc/
diff --git a/arch/x86/platform/geode/Makefile b/arch/x86/platform/geode/Makefile
new file mode 100644
index 000000000000..07c9cd05021a
--- /dev/null
+++ b/arch/x86/platform/geode/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_ALIX) += alix.o
diff --git a/arch/x86/platform/geode/alix.c b/arch/x86/platform/geode/alix.c
new file mode 100644
index 000000000000..ca1973699d3d
--- /dev/null
+++ b/arch/x86/platform/geode/alix.c
@@ -0,0 +1,142 @@
1/*
2 * System Specific setup for PCEngines ALIX.
3 * At the moment this means setup of GPIO control of LEDs
4 * on Alix.2/3/6 boards.
5 *
6 *
7 * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
8 * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
9 *
10 * TODO: There are large similarities with leds-net5501.c
11 * by Alessandro Zummo <a.zummo@towertech.it>
12 * In the future leds-net5501.c should be migrated over to platform
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2
16 * as published by the Free Software Foundation.
17 */
18
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/io.h>
22#include <linux/string.h>
23#include <linux/module.h>
24#include <linux/leds.h>
25#include <linux/platform_device.h>
26#include <linux/gpio.h>
27
28#include <asm/geode.h>
29
30static int force = 0;
31module_param(force, bool, 0444);
32/* FIXME: Award bios is not automatically detected as Alix platform */
33MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
34
35static struct gpio_led alix_leds[] = {
36 {
37 .name = "alix:1",
38 .gpio = 6,
39 .default_trigger = "default-on",
40 .active_low = 1,
41 },
42 {
43 .name = "alix:2",
44 .gpio = 25,
45 .default_trigger = "default-off",
46 .active_low = 1,
47 },
48 {
49 .name = "alix:3",
50 .gpio = 27,
51 .default_trigger = "default-off",
52 .active_low = 1,
53 },
54};
55
56static struct gpio_led_platform_data alix_leds_data = {
57 .num_leds = ARRAY_SIZE(alix_leds),
58 .leds = alix_leds,
59};
60
61static struct platform_device alix_leds_dev = {
62 .name = "leds-gpio",
63 .id = -1,
64 .dev.platform_data = &alix_leds_data,
65};
66
67static void __init register_alix(void)
68{
69 /* Setup LED control through leds-gpio driver */
70 platform_device_register(&alix_leds_dev);
71}
72
73static int __init alix_present(unsigned long bios_phys,
74 const char *alix_sig,
75 size_t alix_sig_len)
76{
77 const size_t bios_len = 0x00010000;
78 const char *bios_virt;
79 const char *scan_end;
80 const char *p;
81 char name[64];
82
83 if (force) {
84 printk(KERN_NOTICE "%s: forced to skip BIOS test, "
85 "assume system is ALIX.2/ALIX.3\n",
86 KBUILD_MODNAME);
87 return 1;
88 }
89
90 bios_virt = phys_to_virt(bios_phys);
91 scan_end = bios_virt + bios_len - (alix_sig_len + 2);
92 for (p = bios_virt; p < scan_end; p++) {
93 const char *tail;
94 char *a;
95
96 if (memcmp(p, alix_sig, alix_sig_len) != 0)
97 continue;
98
99 memcpy(name, p, sizeof(name));
100
101 /* remove the first \0 character from string */
102 a = strchr(name, '\0');
103 if (a)
104 *a = ' ';
105
106 /* cut the string at a newline */
107 a = strchr(name, '\r');
108 if (a)
109 *a = '\0';
110
111 tail = p + alix_sig_len;
112 if ((tail[0] == '2' || tail[0] == '3')) {
113 printk(KERN_INFO
114 "%s: system is recognized as \"%s\"\n",
115 KBUILD_MODNAME, name);
116 return 1;
117 }
118 }
119
120 return 0;
121}
122
123static int __init alix_init(void)
124{
125 const char tinybios_sig[] = "PC Engines ALIX.";
126 const char coreboot_sig[] = "PC Engines\0ALIX.";
127
128 if (!is_geode())
129 return 0;
130
131 if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
132 alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
133 register_alix();
134
135 return 0;
136}
137
138module_init(alix_init);
139
140MODULE_AUTHOR("Ed Wildgoose <kernel@wildgooses.com>");
141MODULE_DESCRIPTION("PCEngines ALIX System Setup");
142MODULE_LICENSE("GPL");
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 807c875f1c2e..dc7caaddecf4 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");