xref: /linux/arch/x86/platform/geode/alix.c (revision 476bc0015bf09dad39d36a8b19f76f0c181d1ec9)
1d4f3e350SEd Wildgoose /*
2d4f3e350SEd Wildgoose  * System Specific setup for PCEngines ALIX.
3d4f3e350SEd Wildgoose  * At the moment this means setup of GPIO control of LEDs
4d4f3e350SEd Wildgoose  * on Alix.2/3/6 boards.
5d4f3e350SEd Wildgoose  *
6d4f3e350SEd Wildgoose  *
7d4f3e350SEd Wildgoose  * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
8d4f3e350SEd Wildgoose  * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
9d4f3e350SEd Wildgoose  *
10d4f3e350SEd Wildgoose  * TODO: There are large similarities with leds-net5501.c
11d4f3e350SEd Wildgoose  * by Alessandro Zummo <a.zummo@towertech.it>
12d4f3e350SEd Wildgoose  * In the future leds-net5501.c should be migrated over to platform
13d4f3e350SEd Wildgoose  *
14d4f3e350SEd Wildgoose  * This program is free software; you can redistribute it and/or modify
15d4f3e350SEd Wildgoose  * it under the terms of the GNU General Public License version 2
16d4f3e350SEd Wildgoose  * as published by the Free Software Foundation.
17d4f3e350SEd Wildgoose  */
18d4f3e350SEd Wildgoose 
19d4f3e350SEd Wildgoose #include <linux/kernel.h>
20d4f3e350SEd Wildgoose #include <linux/init.h>
21d4f3e350SEd Wildgoose #include <linux/io.h>
22d4f3e350SEd Wildgoose #include <linux/string.h>
23d4f3e350SEd Wildgoose #include <linux/module.h>
24d4f3e350SEd Wildgoose #include <linux/leds.h>
25d4f3e350SEd Wildgoose #include <linux/platform_device.h>
26d4f3e350SEd Wildgoose #include <linux/gpio.h>
27d4f3e350SEd Wildgoose 
28d4f3e350SEd Wildgoose #include <asm/geode.h>
29d4f3e350SEd Wildgoose 
30*476bc001SRusty Russell static bool force = 0;
31d4f3e350SEd Wildgoose module_param(force, bool, 0444);
32d4f3e350SEd Wildgoose /* FIXME: Award bios is not automatically detected as Alix platform */
33d4f3e350SEd Wildgoose MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
34d4f3e350SEd Wildgoose 
35d4f3e350SEd Wildgoose static struct gpio_led alix_leds[] = {
36d4f3e350SEd Wildgoose 	{
37d4f3e350SEd Wildgoose 		.name = "alix:1",
38d4f3e350SEd Wildgoose 		.gpio = 6,
39d4f3e350SEd Wildgoose 		.default_trigger = "default-on",
40d4f3e350SEd Wildgoose 		.active_low = 1,
41d4f3e350SEd Wildgoose 	},
42d4f3e350SEd Wildgoose 	{
43d4f3e350SEd Wildgoose 		.name = "alix:2",
44d4f3e350SEd Wildgoose 		.gpio = 25,
45d4f3e350SEd Wildgoose 		.default_trigger = "default-off",
46d4f3e350SEd Wildgoose 		.active_low = 1,
47d4f3e350SEd Wildgoose 	},
48d4f3e350SEd Wildgoose 	{
49d4f3e350SEd Wildgoose 		.name = "alix:3",
50d4f3e350SEd Wildgoose 		.gpio = 27,
51d4f3e350SEd Wildgoose 		.default_trigger = "default-off",
52d4f3e350SEd Wildgoose 		.active_low = 1,
53d4f3e350SEd Wildgoose 	},
54d4f3e350SEd Wildgoose };
55d4f3e350SEd Wildgoose 
56d4f3e350SEd Wildgoose static struct gpio_led_platform_data alix_leds_data = {
57d4f3e350SEd Wildgoose 	.num_leds = ARRAY_SIZE(alix_leds),
58d4f3e350SEd Wildgoose 	.leds = alix_leds,
59d4f3e350SEd Wildgoose };
60d4f3e350SEd Wildgoose 
61d4f3e350SEd Wildgoose static struct platform_device alix_leds_dev = {
62d4f3e350SEd Wildgoose 	.name = "leds-gpio",
63d4f3e350SEd Wildgoose 	.id = -1,
64d4f3e350SEd Wildgoose 	.dev.platform_data = &alix_leds_data,
65d4f3e350SEd Wildgoose };
66d4f3e350SEd Wildgoose 
67d4f3e350SEd Wildgoose static void __init register_alix(void)
68d4f3e350SEd Wildgoose {
69d4f3e350SEd Wildgoose 	/* Setup LED control through leds-gpio driver */
70d4f3e350SEd Wildgoose 	platform_device_register(&alix_leds_dev);
71d4f3e350SEd Wildgoose }
72d4f3e350SEd Wildgoose 
73d4f3e350SEd Wildgoose static int __init alix_present(unsigned long bios_phys,
74d4f3e350SEd Wildgoose 				const char *alix_sig,
75d4f3e350SEd Wildgoose 				size_t alix_sig_len)
76d4f3e350SEd Wildgoose {
77d4f3e350SEd Wildgoose 	const size_t bios_len = 0x00010000;
78d4f3e350SEd Wildgoose 	const char *bios_virt;
79d4f3e350SEd Wildgoose 	const char *scan_end;
80d4f3e350SEd Wildgoose 	const char *p;
81d4f3e350SEd Wildgoose 	char name[64];
82d4f3e350SEd Wildgoose 
83d4f3e350SEd Wildgoose 	if (force) {
84d4f3e350SEd Wildgoose 		printk(KERN_NOTICE "%s: forced to skip BIOS test, "
85d4f3e350SEd Wildgoose 		       "assume system is ALIX.2/ALIX.3\n",
86d4f3e350SEd Wildgoose 		       KBUILD_MODNAME);
87d4f3e350SEd Wildgoose 		return 1;
88d4f3e350SEd Wildgoose 	}
89d4f3e350SEd Wildgoose 
90d4f3e350SEd Wildgoose 	bios_virt = phys_to_virt(bios_phys);
91d4f3e350SEd Wildgoose 	scan_end = bios_virt + bios_len - (alix_sig_len + 2);
92d4f3e350SEd Wildgoose 	for (p = bios_virt; p < scan_end; p++) {
93d4f3e350SEd Wildgoose 		const char *tail;
94d4f3e350SEd Wildgoose 		char *a;
95d4f3e350SEd Wildgoose 
96d4f3e350SEd Wildgoose 		if (memcmp(p, alix_sig, alix_sig_len) != 0)
97d4f3e350SEd Wildgoose 			continue;
98d4f3e350SEd Wildgoose 
99d4f3e350SEd Wildgoose 		memcpy(name, p, sizeof(name));
100d4f3e350SEd Wildgoose 
101d4f3e350SEd Wildgoose 		/* remove the first \0 character from string */
102d4f3e350SEd Wildgoose 		a = strchr(name, '\0');
103d4f3e350SEd Wildgoose 		if (a)
104d4f3e350SEd Wildgoose 			*a = ' ';
105d4f3e350SEd Wildgoose 
106d4f3e350SEd Wildgoose 		/* cut the string at a newline */
107d4f3e350SEd Wildgoose 		a = strchr(name, '\r');
108d4f3e350SEd Wildgoose 		if (a)
109d4f3e350SEd Wildgoose 			*a = '\0';
110d4f3e350SEd Wildgoose 
111d4f3e350SEd Wildgoose 		tail = p + alix_sig_len;
112d4f3e350SEd Wildgoose 		if ((tail[0] == '2' || tail[0] == '3')) {
113d4f3e350SEd Wildgoose 			printk(KERN_INFO
114d4f3e350SEd Wildgoose 			       "%s: system is recognized as \"%s\"\n",
115d4f3e350SEd Wildgoose 			       KBUILD_MODNAME, name);
116d4f3e350SEd Wildgoose 			return 1;
117d4f3e350SEd Wildgoose 		}
118d4f3e350SEd Wildgoose 	}
119d4f3e350SEd Wildgoose 
120d4f3e350SEd Wildgoose 	return 0;
121d4f3e350SEd Wildgoose }
122d4f3e350SEd Wildgoose 
123d4f3e350SEd Wildgoose static int __init alix_init(void)
124d4f3e350SEd Wildgoose {
125d4f3e350SEd Wildgoose 	const char tinybios_sig[] = "PC Engines ALIX.";
126d4f3e350SEd Wildgoose 	const char coreboot_sig[] = "PC Engines\0ALIX.";
127d4f3e350SEd Wildgoose 
128d4f3e350SEd Wildgoose 	if (!is_geode())
129d4f3e350SEd Wildgoose 		return 0;
130d4f3e350SEd Wildgoose 
131d4f3e350SEd Wildgoose 	if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
132d4f3e350SEd Wildgoose 	    alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
133d4f3e350SEd Wildgoose 		register_alix();
134d4f3e350SEd Wildgoose 
135d4f3e350SEd Wildgoose 	return 0;
136d4f3e350SEd Wildgoose }
137d4f3e350SEd Wildgoose 
138d4f3e350SEd Wildgoose module_init(alix_init);
139d4f3e350SEd Wildgoose 
140d4f3e350SEd Wildgoose MODULE_AUTHOR("Ed Wildgoose <kernel@wildgooses.com>");
141d4f3e350SEd Wildgoose MODULE_DESCRIPTION("PCEngines ALIX System Setup");
142d4f3e350SEd Wildgoose MODULE_LICENSE("GPL");
143