Skip to content

Commit 298c9ba

Browse files
dtorjwrdegoede
authored andcommitted
x86/platform/geode: switch GPIO buttons and LEDs to software properties
Convert GPIO-connected buttons and LEDs in Geode boards to software nodes/properties, so that support for platform data can be removed from gpio-keys driver (which will rely purely on generic device properties for configuration). To avoid repeating the same data structures over and over and over factor them out into a new geode-common.c file. Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/ZsV6MNS_tUPPSffJ@google.com Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1 parent 1bda29a commit 298c9ba

7 files changed

Lines changed: 228 additions & 209 deletions

File tree

arch/x86/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2979,9 +2979,13 @@ config OLPC_XO15_SCI
29792979
- AC adapter status updates
29802980
- Battery status updates
29812981

2982+
config GEODE_COMMON
2983+
bool
2984+
29822985
config ALIX
29832986
bool "PCEngines ALIX System Support (LED setup)"
29842987
select GPIOLIB
2988+
select GEODE_COMMON
29852989
help
29862990
This option enables system support for the PCEngines ALIX.
29872991
At present this just sets up LEDs for GPIO control on
@@ -2996,12 +3000,14 @@ config ALIX
29963000
config NET5501
29973001
bool "Soekris Engineering net5501 System Support (LEDS, GPIO, etc)"
29983002
select GPIOLIB
3003+
select GEODE_COMMON
29993004
help
30003005
This option enables system support for the Soekris Engineering net5501.
30013006

30023007
config GEOS
30033008
bool "Traverse Technologies GEOS System Support (LEDS, GPIO, etc)"
30043009
select GPIOLIB
3010+
select GEODE_COMMON
30053011
depends on DMI
30063012
help
30073013
This option enables system support for the Traverse Technologies GEOS.

arch/x86/platform/geode/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0-only
2+
obj-$(CONFIG_GEODE_COMMON) += geode-common.o
23
obj-$(CONFIG_ALIX) += alix.o
34
obj-$(CONFIG_NET5501) += net5501.o
45
obj-$(CONFIG_GEOS) += geos.o

arch/x86/platform/geode/alix.c

Lines changed: 8 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,12 @@
1818
#include <linux/io.h>
1919
#include <linux/string.h>
2020
#include <linux/moduleparam.h>
21-
#include <linux/leds.h>
22-
#include <linux/platform_device.h>
23-
#include <linux/input.h>
24-
#include <linux/gpio_keys.h>
25-
#include <linux/gpio/machine.h>
2621
#include <linux/dmi.h>
2722

2823
#include <asm/geode.h>
2924

25+
#include "geode-common.h"
26+
3027
#define BIOS_SIGNATURE_TINYBIOS 0xf0000
3128
#define BIOS_SIGNATURE_COREBOOT 0x500
3229
#define BIOS_REGION_SIZE 0x10000
@@ -41,79 +38,16 @@ module_param(force, bool, 0444);
4138
/* FIXME: Award bios is not automatically detected as Alix platform */
4239
MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
4340

44-
static struct gpio_keys_button alix_gpio_buttons[] = {
45-
{
46-
.code = KEY_RESTART,
47-
.gpio = 24,
48-
.active_low = 1,
49-
.desc = "Reset button",
50-
.type = EV_KEY,
51-
.wakeup = 0,
52-
.debounce_interval = 100,
53-
.can_disable = 0,
54-
}
55-
};
56-
static struct gpio_keys_platform_data alix_buttons_data = {
57-
.buttons = alix_gpio_buttons,
58-
.nbuttons = ARRAY_SIZE(alix_gpio_buttons),
59-
.poll_interval = 20,
60-
};
61-
62-
static struct platform_device alix_buttons_dev = {
63-
.name = "gpio-keys-polled",
64-
.id = 1,
65-
.dev = {
66-
.platform_data = &alix_buttons_data,
67-
}
68-
};
69-
70-
static struct gpio_led alix_leds[] = {
71-
{
72-
.name = "alix:1",
73-
.default_trigger = "default-on",
74-
},
75-
{
76-
.name = "alix:2",
77-
.default_trigger = "default-off",
78-
},
79-
{
80-
.name = "alix:3",
81-
.default_trigger = "default-off",
82-
},
83-
};
84-
85-
static struct gpio_led_platform_data alix_leds_data = {
86-
.num_leds = ARRAY_SIZE(alix_leds),
87-
.leds = alix_leds,
88-
};
89-
90-
static struct gpiod_lookup_table alix_leds_gpio_table = {
91-
.dev_id = "leds-gpio",
92-
.table = {
93-
/* The Geode GPIOs should be on the CS5535 companion chip */
94-
GPIO_LOOKUP_IDX("cs5535-gpio", 6, NULL, 0, GPIO_ACTIVE_LOW),
95-
GPIO_LOOKUP_IDX("cs5535-gpio", 25, NULL, 1, GPIO_ACTIVE_LOW),
96-
GPIO_LOOKUP_IDX("cs5535-gpio", 27, NULL, 2, GPIO_ACTIVE_LOW),
97-
{ }
98-
},
99-
};
100-
101-
static struct platform_device alix_leds_dev = {
102-
.name = "leds-gpio",
103-
.id = -1,
104-
.dev.platform_data = &alix_leds_data,
105-
};
106-
107-
static struct platform_device *alix_devs[] __initdata = {
108-
&alix_buttons_dev,
109-
&alix_leds_dev,
41+
static const struct geode_led alix_leds[] __initconst = {
42+
{ 6, true },
43+
{ 25, false },
44+
{ 27, false },
11045
};
11146

11247
static void __init register_alix(void)
11348
{
114-
/* Setup LED control through leds-gpio driver */
115-
gpiod_add_lookup_table(&alix_leds_gpio_table);
116-
platform_add_devices(alix_devs, ARRAY_SIZE(alix_devs));
49+
geode_create_restart_key(24);
50+
geode_create_leds("alix", alix_leds, ARRAY_SIZE(alix_leds));
11751
}
11852

11953
static bool __init alix_present(unsigned long bios_phys,
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Shared helpers to register GPIO-connected buttons and LEDs
4+
* on AMD Geode boards.
5+
*/
6+
7+
#include <linux/err.h>
8+
#include <linux/gpio/machine.h>
9+
#include <linux/gpio/property.h>
10+
#include <linux/input.h>
11+
#include <linux/leds.h>
12+
#include <linux/platform_device.h>
13+
#include <linux/slab.h>
14+
15+
#include "geode-common.h"
16+
17+
static const struct software_node geode_gpiochip_node = {
18+
.name = "cs5535-gpio",
19+
};
20+
21+
static const struct property_entry geode_gpio_keys_props[] = {
22+
PROPERTY_ENTRY_U32("poll-interval", 20),
23+
{ }
24+
};
25+
26+
static const struct software_node geode_gpio_keys_node = {
27+
.name = "geode-gpio-keys",
28+
.properties = geode_gpio_keys_props,
29+
};
30+
31+
static struct property_entry geode_restart_key_props[] = {
32+
{ /* Placeholder for GPIO property */ },
33+
PROPERTY_ENTRY_U32("linux,code", KEY_RESTART),
34+
PROPERTY_ENTRY_STRING("label", "Reset button"),
35+
PROPERTY_ENTRY_U32("debounce-interval", 100),
36+
{ }
37+
};
38+
39+
static const struct software_node geode_restart_key_node = {
40+
.parent = &geode_gpio_keys_node,
41+
.properties = geode_restart_key_props,
42+
};
43+
44+
static const struct software_node *geode_gpio_keys_swnodes[] __initconst = {
45+
&geode_gpiochip_node,
46+
&geode_gpio_keys_node,
47+
&geode_restart_key_node,
48+
NULL
49+
};
50+
51+
/*
52+
* Creates gpio-keys-polled device for the restart key.
53+
*
54+
* Note that it needs to be called first, before geode_create_leds(),
55+
* because it registers gpiochip software node used by both gpio-keys and
56+
* leds-gpio devices.
57+
*/
58+
int __init geode_create_restart_key(unsigned int pin)
59+
{
60+
struct platform_device_info keys_info = {
61+
.name = "gpio-keys-polled",
62+
.id = 1,
63+
};
64+
struct platform_device *pd;
65+
int err;
66+
67+
geode_restart_key_props[0] = PROPERTY_ENTRY_GPIO("gpios",
68+
&geode_gpiochip_node,
69+
pin, GPIO_ACTIVE_LOW);
70+
71+
err = software_node_register_node_group(geode_gpio_keys_swnodes);
72+
if (err) {
73+
pr_err("failed to register gpio-keys software nodes: %d\n", err);
74+
return err;
75+
}
76+
77+
keys_info.fwnode = software_node_fwnode(&geode_gpio_keys_node);
78+
79+
pd = platform_device_register_full(&keys_info);
80+
err = PTR_ERR_OR_ZERO(pd);
81+
if (err) {
82+
pr_err("failed to create gpio-keys device: %d\n", err);
83+
software_node_unregister_node_group(geode_gpio_keys_swnodes);
84+
return err;
85+
}
86+
87+
return 0;
88+
}
89+
90+
static const struct software_node geode_gpio_leds_node = {
91+
.name = "geode-leds",
92+
};
93+
94+
#define MAX_LEDS 3
95+
96+
int __init geode_create_leds(const char *label, const struct geode_led *leds,
97+
unsigned int n_leds)
98+
{
99+
const struct software_node *group[MAX_LEDS + 2] = { 0 };
100+
struct software_node *swnodes;
101+
struct property_entry *props;
102+
struct platform_device_info led_info = {
103+
.name = "leds-gpio",
104+
.id = PLATFORM_DEVID_NONE,
105+
};
106+
struct platform_device *led_dev;
107+
const char *node_name;
108+
int err;
109+
int i;
110+
111+
if (n_leds > MAX_LEDS) {
112+
pr_err("%s: too many LEDs\n", __func__);
113+
return -EINVAL;
114+
}
115+
116+
swnodes = kcalloc(n_leds, sizeof(*swnodes), GFP_KERNEL);
117+
if (!swnodes)
118+
return -ENOMEM;
119+
120+
/*
121+
* Each LED is represented by 3 properties: "gpios",
122+
* "linux,default-trigger", and am empty terminator.
123+
*/
124+
props = kcalloc(n_leds * 3, sizeof(*props), GFP_KERNEL);
125+
if (!props) {
126+
err = -ENOMEM;
127+
goto err_free_swnodes;
128+
}
129+
130+
group[0] = &geode_gpio_leds_node;
131+
for (i = 0; i < n_leds; i++) {
132+
node_name = kasprintf(GFP_KERNEL, "%s:%d", label, i);
133+
if (!node_name) {
134+
err = -ENOMEM;
135+
goto err_free_names;
136+
}
137+
138+
props[i * 3 + 0] =
139+
PROPERTY_ENTRY_GPIO("gpios", &geode_gpiochip_node,
140+
leds[i].pin, GPIO_ACTIVE_LOW);
141+
props[i * 3 + 1] =
142+
PROPERTY_ENTRY_STRING("linux,default-trigger",
143+
leds[i].default_on ?
144+
"default-on" : "default-off");
145+
/* props[i * 3 + 2] is an empty terminator */
146+
147+
swnodes[i] = SOFTWARE_NODE(node_name, &props[i * 3],
148+
&geode_gpio_leds_node);
149+
group[i + 1] = &swnodes[i];
150+
}
151+
152+
err = software_node_register_node_group(group);
153+
if (err) {
154+
pr_err("failed to register LED software nodes: %d\n", err);
155+
goto err_free_names;
156+
}
157+
158+
led_info.fwnode = software_node_fwnode(&geode_gpio_leds_node);
159+
160+
led_dev = platform_device_register_full(&led_info);
161+
err = PTR_ERR_OR_ZERO(led_dev);
162+
if (err) {
163+
pr_err("failed to create LED device: %d\n", err);
164+
goto err_unregister_group;
165+
}
166+
167+
return 0;
168+
169+
err_unregister_group:
170+
software_node_unregister_node_group(group);
171+
err_free_names:
172+
while (--i >= 0)
173+
kfree(swnodes[i].name);
174+
kfree(props);
175+
err_free_swnodes:
176+
kfree(swnodes);
177+
return err;
178+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Shared helpers to register GPIO-connected buttons and LEDs
4+
* on AMD Geode boards.
5+
*/
6+
7+
#ifndef __PLATFORM_GEODE_COMMON_H
8+
#define __PLATFORM_GEODE_COMMON_H
9+
10+
#include <linux/property.h>
11+
12+
struct geode_led {
13+
unsigned int pin;
14+
bool default_on;
15+
};
16+
17+
int geode_create_restart_key(unsigned int pin);
18+
int geode_create_leds(const char *label, const struct geode_led *leds,
19+
unsigned int n_leds);
20+
21+
#endif /* __PLATFORM_GEODE_COMMON_H */

0 commit comments

Comments
 (0)