Commit 298c9bab authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Hans de Goede

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: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Acked-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/ZsV6MNS_tUPPSffJ@google.comSigned-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent 1bda29ae
...@@ -2979,9 +2979,13 @@ config OLPC_XO15_SCI ...@@ -2979,9 +2979,13 @@ config OLPC_XO15_SCI
- AC adapter status updates - AC adapter status updates
- Battery status updates - Battery status updates
config GEODE_COMMON
bool
config ALIX config ALIX
bool "PCEngines ALIX System Support (LED setup)" bool "PCEngines ALIX System Support (LED setup)"
select GPIOLIB select GPIOLIB
select GEODE_COMMON
help help
This option enables system support for the PCEngines ALIX. This option enables system support for the PCEngines ALIX.
At present this just sets up LEDs for GPIO control on At present this just sets up LEDs for GPIO control on
...@@ -2996,12 +3000,14 @@ config ALIX ...@@ -2996,12 +3000,14 @@ config ALIX
config NET5501 config NET5501
bool "Soekris Engineering net5501 System Support (LEDS, GPIO, etc)" bool "Soekris Engineering net5501 System Support (LEDS, GPIO, etc)"
select GPIOLIB select GPIOLIB
select GEODE_COMMON
help help
This option enables system support for the Soekris Engineering net5501. This option enables system support for the Soekris Engineering net5501.
config GEOS config GEOS
bool "Traverse Technologies GEOS System Support (LEDS, GPIO, etc)" bool "Traverse Technologies GEOS System Support (LEDS, GPIO, etc)"
select GPIOLIB select GPIOLIB
select GEODE_COMMON
depends on DMI depends on DMI
help help
This option enables system support for the Traverse Technologies GEOS. This option enables system support for the Traverse Technologies GEOS.
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_GEODE_COMMON) += geode-common.o
obj-$(CONFIG_ALIX) += alix.o obj-$(CONFIG_ALIX) += alix.o
obj-$(CONFIG_NET5501) += net5501.o obj-$(CONFIG_NET5501) += net5501.o
obj-$(CONFIG_GEOS) += geos.o obj-$(CONFIG_GEOS) += geos.o
...@@ -18,15 +18,12 @@ ...@@ -18,15 +18,12 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/gpio/machine.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <asm/geode.h> #include <asm/geode.h>
#include "geode-common.h"
#define BIOS_SIGNATURE_TINYBIOS 0xf0000 #define BIOS_SIGNATURE_TINYBIOS 0xf0000
#define BIOS_SIGNATURE_COREBOOT 0x500 #define BIOS_SIGNATURE_COREBOOT 0x500
#define BIOS_REGION_SIZE 0x10000 #define BIOS_REGION_SIZE 0x10000
...@@ -41,79 +38,16 @@ module_param(force, bool, 0444); ...@@ -41,79 +38,16 @@ module_param(force, bool, 0444);
/* FIXME: Award bios is not automatically detected as Alix platform */ /* FIXME: Award bios is not automatically detected as Alix platform */
MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform"); MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
static struct gpio_keys_button alix_gpio_buttons[] = { static const struct geode_led alix_leds[] __initconst = {
{ { 6, true },
.code = KEY_RESTART, { 25, false },
.gpio = 24, { 27, false },
.active_low = 1,
.desc = "Reset button",
.type = EV_KEY,
.wakeup = 0,
.debounce_interval = 100,
.can_disable = 0,
}
};
static struct gpio_keys_platform_data alix_buttons_data = {
.buttons = alix_gpio_buttons,
.nbuttons = ARRAY_SIZE(alix_gpio_buttons),
.poll_interval = 20,
};
static struct platform_device alix_buttons_dev = {
.name = "gpio-keys-polled",
.id = 1,
.dev = {
.platform_data = &alix_buttons_data,
}
};
static struct gpio_led alix_leds[] = {
{
.name = "alix:1",
.default_trigger = "default-on",
},
{
.name = "alix:2",
.default_trigger = "default-off",
},
{
.name = "alix:3",
.default_trigger = "default-off",
},
};
static struct gpio_led_platform_data alix_leds_data = {
.num_leds = ARRAY_SIZE(alix_leds),
.leds = alix_leds,
};
static struct gpiod_lookup_table alix_leds_gpio_table = {
.dev_id = "leds-gpio",
.table = {
/* The Geode GPIOs should be on the CS5535 companion chip */
GPIO_LOOKUP_IDX("cs5535-gpio", 6, NULL, 0, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("cs5535-gpio", 25, NULL, 1, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("cs5535-gpio", 27, NULL, 2, GPIO_ACTIVE_LOW),
{ }
},
};
static struct platform_device alix_leds_dev = {
.name = "leds-gpio",
.id = -1,
.dev.platform_data = &alix_leds_data,
};
static struct platform_device *alix_devs[] __initdata = {
&alix_buttons_dev,
&alix_leds_dev,
}; };
static void __init register_alix(void) static void __init register_alix(void)
{ {
/* Setup LED control through leds-gpio driver */ geode_create_restart_key(24);
gpiod_add_lookup_table(&alix_leds_gpio_table); geode_create_leds("alix", alix_leds, ARRAY_SIZE(alix_leds));
platform_add_devices(alix_devs, ARRAY_SIZE(alix_devs));
} }
static bool __init alix_present(unsigned long bios_phys, static bool __init alix_present(unsigned long bios_phys,
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Shared helpers to register GPIO-connected buttons and LEDs
* on AMD Geode boards.
*/
#include <linux/err.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "geode-common.h"
static const struct software_node geode_gpiochip_node = {
.name = "cs5535-gpio",
};
static const struct property_entry geode_gpio_keys_props[] = {
PROPERTY_ENTRY_U32("poll-interval", 20),
{ }
};
static const struct software_node geode_gpio_keys_node = {
.name = "geode-gpio-keys",
.properties = geode_gpio_keys_props,
};
static struct property_entry geode_restart_key_props[] = {
{ /* Placeholder for GPIO property */ },
PROPERTY_ENTRY_U32("linux,code", KEY_RESTART),
PROPERTY_ENTRY_STRING("label", "Reset button"),
PROPERTY_ENTRY_U32("debounce-interval", 100),
{ }
};
static const struct software_node geode_restart_key_node = {
.parent = &geode_gpio_keys_node,
.properties = geode_restart_key_props,
};
static const struct software_node *geode_gpio_keys_swnodes[] __initconst = {
&geode_gpiochip_node,
&geode_gpio_keys_node,
&geode_restart_key_node,
NULL
};
/*
* Creates gpio-keys-polled device for the restart key.
*
* Note that it needs to be called first, before geode_create_leds(),
* because it registers gpiochip software node used by both gpio-keys and
* leds-gpio devices.
*/
int __init geode_create_restart_key(unsigned int pin)
{
struct platform_device_info keys_info = {
.name = "gpio-keys-polled",
.id = 1,
};
struct platform_device *pd;
int err;
geode_restart_key_props[0] = PROPERTY_ENTRY_GPIO("gpios",
&geode_gpiochip_node,
pin, GPIO_ACTIVE_LOW);
err = software_node_register_node_group(geode_gpio_keys_swnodes);
if (err) {
pr_err("failed to register gpio-keys software nodes: %d\n", err);
return err;
}
keys_info.fwnode = software_node_fwnode(&geode_gpio_keys_node);
pd = platform_device_register_full(&keys_info);
err = PTR_ERR_OR_ZERO(pd);
if (err) {
pr_err("failed to create gpio-keys device: %d\n", err);
software_node_unregister_node_group(geode_gpio_keys_swnodes);
return err;
}
return 0;
}
static const struct software_node geode_gpio_leds_node = {
.name = "geode-leds",
};
#define MAX_LEDS 3
int __init geode_create_leds(const char *label, const struct geode_led *leds,
unsigned int n_leds)
{
const struct software_node *group[MAX_LEDS + 2] = { 0 };
struct software_node *swnodes;
struct property_entry *props;
struct platform_device_info led_info = {
.name = "leds-gpio",
.id = PLATFORM_DEVID_NONE,
};
struct platform_device *led_dev;
const char *node_name;
int err;
int i;
if (n_leds > MAX_LEDS) {
pr_err("%s: too many LEDs\n", __func__);
return -EINVAL;
}
swnodes = kcalloc(n_leds, sizeof(*swnodes), GFP_KERNEL);
if (!swnodes)
return -ENOMEM;
/*
* Each LED is represented by 3 properties: "gpios",
* "linux,default-trigger", and am empty terminator.
*/
props = kcalloc(n_leds * 3, sizeof(*props), GFP_KERNEL);
if (!props) {
err = -ENOMEM;
goto err_free_swnodes;
}
group[0] = &geode_gpio_leds_node;
for (i = 0; i < n_leds; i++) {
node_name = kasprintf(GFP_KERNEL, "%s:%d", label, i);
if (!node_name) {
err = -ENOMEM;
goto err_free_names;
}
props[i * 3 + 0] =
PROPERTY_ENTRY_GPIO("gpios", &geode_gpiochip_node,
leds[i].pin, GPIO_ACTIVE_LOW);
props[i * 3 + 1] =
PROPERTY_ENTRY_STRING("linux,default-trigger",
leds[i].default_on ?
"default-on" : "default-off");
/* props[i * 3 + 2] is an empty terminator */
swnodes[i] = SOFTWARE_NODE(node_name, &props[i * 3],
&geode_gpio_leds_node);
group[i + 1] = &swnodes[i];
}
err = software_node_register_node_group(group);
if (err) {
pr_err("failed to register LED software nodes: %d\n", err);
goto err_free_names;
}
led_info.fwnode = software_node_fwnode(&geode_gpio_leds_node);
led_dev = platform_device_register_full(&led_info);
err = PTR_ERR_OR_ZERO(led_dev);
if (err) {
pr_err("failed to create LED device: %d\n", err);
goto err_unregister_group;
}
return 0;
err_unregister_group:
software_node_unregister_node_group(group);
err_free_names:
while (--i >= 0)
kfree(swnodes[i].name);
kfree(props);
err_free_swnodes:
kfree(swnodes);
return err;
}
// SPDX-License-Identifier: GPL-2.0-only
/*
* Shared helpers to register GPIO-connected buttons and LEDs
* on AMD Geode boards.
*/
#ifndef __PLATFORM_GEODE_COMMON_H
#define __PLATFORM_GEODE_COMMON_H
#include <linux/property.h>
struct geode_led {
unsigned int pin;
bool default_on;
};
int geode_create_restart_key(unsigned int pin);
int geode_create_leds(const char *label, const struct geode_led *leds,
unsigned int n_leds);
#endif /* __PLATFORM_GEODE_COMMON_H */
...@@ -16,88 +16,22 @@ ...@@ -16,88 +16,22 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/gpio/machine.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <asm/geode.h> #include <asm/geode.h>
static struct gpio_keys_button geos_gpio_buttons[] = { #include "geode-common.h"
{
.code = KEY_RESTART,
.gpio = 3,
.active_low = 1,
.desc = "Reset button",
.type = EV_KEY,
.wakeup = 0,
.debounce_interval = 100,
.can_disable = 0,
}
};
static struct gpio_keys_platform_data geos_buttons_data = {
.buttons = geos_gpio_buttons,
.nbuttons = ARRAY_SIZE(geos_gpio_buttons),
.poll_interval = 20,
};
static struct platform_device geos_buttons_dev = {
.name = "gpio-keys-polled",
.id = 1,
.dev = {
.platform_data = &geos_buttons_data,
}
};
static struct gpio_led geos_leds[] = {
{
.name = "geos:1",
.default_trigger = "default-on",
},
{
.name = "geos:2",
.default_trigger = "default-off",
},
{
.name = "geos:3",
.default_trigger = "default-off",
},
};
static struct gpio_led_platform_data geos_leds_data = {
.num_leds = ARRAY_SIZE(geos_leds),
.leds = geos_leds,
};
static struct gpiod_lookup_table geos_leds_gpio_table = {
.dev_id = "leds-gpio",
.table = {
/* The Geode GPIOs should be on the CS5535 companion chip */
GPIO_LOOKUP_IDX("cs5535-gpio", 6, NULL, 0, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("cs5535-gpio", 25, NULL, 1, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("cs5535-gpio", 27, NULL, 2, GPIO_ACTIVE_LOW),
{ }
},
};
static struct platform_device geos_leds_dev = {
.name = "leds-gpio",
.id = -1,
.dev.platform_data = &geos_leds_data,
};
static struct platform_device *geos_devs[] __initdata = { static const struct geode_led geos_leds[] __initconst = {
&geos_buttons_dev, { 6, true },
&geos_leds_dev, { 25, false },
{ 27, false },
}; };
static void __init register_geos(void) static void __init register_geos(void)
{ {
/* Setup LED control through leds-gpio driver */ geode_create_restart_key(3);
gpiod_add_lookup_table(&geos_leds_gpio_table); geode_create_leds("geos", geos_leds, ARRAY_SIZE(geos_leds));
platform_add_devices(geos_devs, ARRAY_SIZE(geos_devs));
} }
static int __init geos_init(void) static int __init geos_init(void)
......
...@@ -16,80 +16,25 @@ ...@@ -16,80 +16,25 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
#include <asm/geode.h> #include <asm/geode.h>
#include "geode-common.h"
#define BIOS_REGION_BASE 0xffff0000 #define BIOS_REGION_BASE 0xffff0000
#define BIOS_REGION_SIZE 0x00010000 #define BIOS_REGION_SIZE 0x00010000
static struct gpio_keys_button net5501_gpio_buttons[] = { static const struct geode_led net5501_leds[] __initconst = {
{ { 6, true },
.code = KEY_RESTART,
.gpio = 24,
.active_low = 1,
.desc = "Reset button",
.type = EV_KEY,
.wakeup = 0,
.debounce_interval = 100,
.can_disable = 0,
}
};
static struct gpio_keys_platform_data net5501_buttons_data = {
.buttons = net5501_gpio_buttons,
.nbuttons = ARRAY_SIZE(net5501_gpio_buttons),
.poll_interval = 20,
};
static struct platform_device net5501_buttons_dev = {
.name = "gpio-keys-polled",
.id = 1,
.dev = {
.platform_data = &net5501_buttons_data,
}
};
static struct gpio_led net5501_leds[] = {
{
.name = "net5501:1",
.default_trigger = "default-on",
},
};
static struct gpio_led_platform_data net5501_leds_data = {
.num_leds = ARRAY_SIZE(net5501_leds),
.leds = net5501_leds,
};
static struct gpiod_lookup_table net5501_leds_gpio_table = {
.dev_id = "leds-gpio",
.table = {
/* The Geode GPIOs should be on the CS5535 companion chip */
GPIO_LOOKUP_IDX("cs5535-gpio", 6, NULL, 0, GPIO_ACTIVE_HIGH),
{ }
},
};
static struct platform_device net5501_leds_dev = {
.name = "leds-gpio",
.id = -1,
.dev.platform_data = &net5501_leds_data,
};
static struct platform_device *net5501_devs[] __initdata = {
&net5501_buttons_dev,
&net5501_leds_dev,
}; };
static void __init register_net5501(void) static void __init register_net5501(void)
{ {
/* Setup LED control through leds-gpio driver */ geode_create_restart_key(24);
gpiod_add_lookup_table(&net5501_leds_gpio_table); geode_create_leds("net5501", net5501_leds, ARRAY_SIZE(net5501_leds));
platform_add_devices(net5501_devs, ARRAY_SIZE(net5501_devs));
} }
struct net5501_board { struct net5501_board {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment