]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/x86/platform/geode/alix.c
This new driver replaces the old PCEngines Alix 2/3 LED driver with a new
[karo-tx-linux.git] / arch / x86 / platform / geode / alix.c
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/leds.h>
24 #include <linux/platform_device.h>
25 #include <linux/gpio.h>
26
27 #include <asm/geode.h>
28
29 static int force = 0;
30 module_param(force, bool, 0444);
31 /* FIXME: Award bios is not automatically detected as Alix platform */
32 MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
33
34 static struct gpio_led alix_leds[] = {
35         {
36                 .name = "alix:1",
37                 .gpio = 6,
38                 .default_trigger = "default-on",
39                 .active_low = 1,
40         },
41         {
42                 .name = "alix:2",
43                 .gpio = 25,
44                 .default_trigger = "default-off",
45                 .active_low = 1,
46         },
47         {
48                 .name = "alix:3",
49                 .gpio = 27,
50                 .default_trigger = "default-off",
51                 .active_low = 1,
52         },
53 };
54
55 static struct gpio_led_platform_data alix_leds_data = {
56         .num_leds = ARRAY_SIZE(alix_leds),
57         .leds = alix_leds,
58 };
59
60 static struct platform_device alix_leds_dev = {
61         .name = "leds-gpio",
62         .id = -1,
63         .dev.platform_data = &alix_leds_data,
64 };
65
66 static void __init register_alix(void)
67 {
68         /* Setup LED control through leds-gpio driver */
69         platform_device_register(&alix_leds_dev);
70 }
71
72 static int __init alix_present(unsigned long bios_phys,
73                                 const char *alix_sig,
74                                 size_t alix_sig_len)
75 {
76         const size_t bios_len = 0x00010000;
77         const char *bios_virt;
78         const char *scan_end;
79         const char *p;
80         char name[64];
81
82         if (force) {
83                 printk(KERN_NOTICE "%s: forced to skip BIOS test, "
84                        "assume system is ALIX.2/ALIX.3\n",
85                        KBUILD_MODNAME);
86                 return 1;
87         }
88
89         bios_virt = phys_to_virt(bios_phys);
90         scan_end = bios_virt + bios_len - (alix_sig_len + 2);
91         for (p = bios_virt; p < scan_end; p++) {
92                 const char *tail;
93                 char *a;
94
95                 if (memcmp(p, alix_sig, alix_sig_len) != 0)
96                         continue;
97
98                 memcpy(name, p, sizeof(name));
99
100                 /* remove the first \0 character from string */
101                 a = strchr(name, '\0');
102                 if (a)
103                         *a = ' ';
104
105                 /* cut the string at a newline */
106                 a = strchr(name, '\r');
107                 if (a)
108                         *a = '\0';
109
110                 tail = p + alix_sig_len;
111                 if ((tail[0] == '2' || tail[0] == '3')) {
112                         printk(KERN_INFO
113                                "%s: system is recognized as \"%s\"\n",
114                                KBUILD_MODNAME, name);
115                         return 1;
116                 }
117         }
118
119         return 0;
120 }
121
122 static int __init alix_init(void)
123 {
124         const char tinybios_sig[] = "PC Engines ALIX.";
125         const char coreboot_sig[] = "PC Engines\0ALIX.";
126
127         if (!is_geode())
128                 return 0;
129
130         if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
131             alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
132                 register_alix();
133
134         return 0;
135 }
136
137 module_init(alix_init);
138
139 MODULE_AUTHOR("Ed Wildgoose <kernel@wildgooses.com>");
140 MODULE_DESCRIPTION("PCEngines ALIX System Setup");
141 MODULE_LICENSE("GPL");