Commit d4f3e350172a1dc769ed5e7f5bd540feb0c475d8

Authored by Ed Wildgoose
Committed by Thomas Gleixner
1 parent 9d037a7776

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>

Showing 7 changed files with 158 additions and 248 deletions Side-by-side Diff

... ... @@ -2064,6 +2064,20 @@
2064 2064 - AC adapter status updates
2065 2065 - Battery status updates
2066 2066  
  2067 +config ALIX
  2068 + bool "PCEngines ALIX System Support (LED setup)"
  2069 + select GPIOLIB
  2070 + ---help---
  2071 + This option enables system support for the PCEngines ALIX.
  2072 + At present this just sets up LEDs for GPIO control on
  2073 + ALIX2/3/6 boards. However, other system specific setup should
  2074 + get added here.
  2075 +
  2076 + Note: You must still enable the drivers for GPIO and LED support
  2077 + (GPIO_CS5535 & LEDS_GPIO) to actually use the LEDs
  2078 +
  2079 + Note: You have to set alix.force=1 for boards with Award BIOS.
  2080 +
2067 2081 endif # X86_32
2068 2082  
2069 2083 config AMD_NB
arch/x86/platform/Makefile
1 1 # Platform specific code goes here
2 2 obj-y += ce4100/
3 3 obj-y += efi/
  4 +obj-y += geode/
4 5 obj-y += iris/
5 6 obj-y += mrst/
6 7 obj-y += olpc/
arch/x86/platform/geode/Makefile
  1 +obj-$(CONFIG_ALIX) += alix.o
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/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 +
  30 +static int force = 0;
  31 +module_param(force, bool, 0444);
  32 +/* FIXME: Award bios is not automatically detected as Alix platform */
  33 +MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
  34 +
  35 +static 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 +
  56 +static struct gpio_led_platform_data alix_leds_data = {
  57 + .num_leds = ARRAY_SIZE(alix_leds),
  58 + .leds = alix_leds,
  59 +};
  60 +
  61 +static struct platform_device alix_leds_dev = {
  62 + .name = "leds-gpio",
  63 + .id = -1,
  64 + .dev.platform_data = &alix_leds_data,
  65 +};
  66 +
  67 +static void __init register_alix(void)
  68 +{
  69 + /* Setup LED control through leds-gpio driver */
  70 + platform_device_register(&alix_leds_dev);
  71 +}
  72 +
  73 +static 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 +
  123 +static 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 +
  138 +module_init(alix_init);
  139 +
  140 +MODULE_AUTHOR("Ed Wildgoose <kernel@wildgooses.com>");
  141 +MODULE_DESCRIPTION("PCEngines ALIX System Setup");
  142 +MODULE_LICENSE("GPL");
drivers/leds/Kconfig
... ... @@ -113,14 +113,6 @@
113 113 help
114 114 This option enables support for the PCEngines WRAP programmable LEDs.
115 115  
116   -config 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   -
124 116 config LEDS_COBALT_QUBE
125 117 tristate "LED Support for the Cobalt Qube series front LED"
126 118 depends on LEDS_CLASS
drivers/leds/Makefile
... ... @@ -16,7 +16,6 @@
16 16 obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
17 17 obj-$(CONFIG_LEDS_NET5501) += leds-net5501.o
18 18 obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
19   -obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o
20 19 obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
21 20 obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
22 21 obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
drivers/leds/leds-alix2.c
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   -
16   -static int force = 0;
17   -module_param(force, bool, 0444);
18   -MODULE_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   -
23   -static u32 gpio_base;
24   -
25   -static 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   -};
30   -MODULE_DEVICE_TABLE(pci, divil_pci);
31   -
32   -struct alix_led {
33   - struct led_classdev cdev;
34   - unsigned short port;
35   - unsigned int on_value;
36   - unsigned int off_value;
37   -};
38   -
39   -static 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   -
51   -static 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   -
81   -static 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   -
94   -fail:
95   - while (--i >= 0)
96   - led_classdev_unregister(&alix_leds[i].cdev);
97   - return ret;
98   -}
99   -
100   -static 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   -
109   -static struct platform_driver alix_led_driver = {
110   - .remove = alix_led_remove,
111   - .driver = {
112   - .name = KBUILD_MODNAME,
113   - .owner = THIS_MODULE,
114   - },
115   -};
116   -
117   -static 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   -
167   -static struct platform_device *pdev;
168   -
169   -static 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   -
203   -static 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   -
227   -static 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   -
234   -module_init(alix_led_init);
235   -module_exit(alix_led_exit);
236   -
237   -MODULE_AUTHOR("Constantin Baranov <const@mimas.ru>");
238   -MODULE_DESCRIPTION("PCEngines ALIX.2 and ALIX.3 LED driver");
239   -MODULE_LICENSE("GPL");