Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Dmitry Torokhov and committed by
Hans de Goede
298c9bab 1bda29ae

+228 -209
+6
arch/x86/Kconfig
··· 2979 2979 - AC adapter status updates 2980 2980 - Battery status updates 2981 2981 2982 + config GEODE_COMMON 2983 + bool 2984 + 2982 2985 config ALIX 2983 2986 bool "PCEngines ALIX System Support (LED setup)" 2984 2987 select GPIOLIB 2988 + select GEODE_COMMON 2985 2989 help 2986 2990 This option enables system support for the PCEngines ALIX. 2987 2991 At present this just sets up LEDs for GPIO control on ··· 3000 2996 config NET5501 3001 2997 bool "Soekris Engineering net5501 System Support (LEDS, GPIO, etc)" 3002 2998 select GPIOLIB 2999 + select GEODE_COMMON 3003 3000 help 3004 3001 This option enables system support for the Soekris Engineering net5501. 3005 3002 3006 3003 config GEOS 3007 3004 bool "Traverse Technologies GEOS System Support (LEDS, GPIO, etc)" 3008 3005 select GPIOLIB 3006 + select GEODE_COMMON 3009 3007 depends on DMI 3010 3008 help 3011 3009 This option enables system support for the Traverse Technologies GEOS.
+1
arch/x86/platform/geode/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 + obj-$(CONFIG_GEODE_COMMON) += geode-common.o 2 3 obj-$(CONFIG_ALIX) += alix.o 3 4 obj-$(CONFIG_NET5501) += net5501.o 4 5 obj-$(CONFIG_GEOS) += geos.o
+8 -74
arch/x86/platform/geode/alix.c
··· 18 18 #include <linux/io.h> 19 19 #include <linux/string.h> 20 20 #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> 26 21 #include <linux/dmi.h> 27 22 28 23 #include <asm/geode.h> 24 + 25 + #include "geode-common.h" 29 26 30 27 #define BIOS_SIGNATURE_TINYBIOS 0xf0000 31 28 #define BIOS_SIGNATURE_COREBOOT 0x500 ··· 38 41 /* FIXME: Award bios is not automatically detected as Alix platform */ 39 42 MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform"); 40 43 41 - static struct gpio_keys_button alix_gpio_buttons[] = { 42 - { 43 - .code = KEY_RESTART, 44 - .gpio = 24, 45 - .active_low = 1, 46 - .desc = "Reset button", 47 - .type = EV_KEY, 48 - .wakeup = 0, 49 - .debounce_interval = 100, 50 - .can_disable = 0, 51 - } 52 - }; 53 - static struct gpio_keys_platform_data alix_buttons_data = { 54 - .buttons = alix_gpio_buttons, 55 - .nbuttons = ARRAY_SIZE(alix_gpio_buttons), 56 - .poll_interval = 20, 57 - }; 58 - 59 - static struct platform_device alix_buttons_dev = { 60 - .name = "gpio-keys-polled", 61 - .id = 1, 62 - .dev = { 63 - .platform_data = &alix_buttons_data, 64 - } 65 - }; 66 - 67 - static struct gpio_led alix_leds[] = { 68 - { 69 - .name = "alix:1", 70 - .default_trigger = "default-on", 71 - }, 72 - { 73 - .name = "alix:2", 74 - .default_trigger = "default-off", 75 - }, 76 - { 77 - .name = "alix:3", 78 - .default_trigger = "default-off", 79 - }, 80 - }; 81 - 82 - static struct gpio_led_platform_data alix_leds_data = { 83 - .num_leds = ARRAY_SIZE(alix_leds), 84 - .leds = alix_leds, 85 - }; 86 - 87 - static struct gpiod_lookup_table alix_leds_gpio_table = { 88 - .dev_id = "leds-gpio", 89 - .table = { 90 - /* The Geode GPIOs should be on the CS5535 companion chip */ 91 - GPIO_LOOKUP_IDX("cs5535-gpio", 6, NULL, 0, GPIO_ACTIVE_LOW), 92 - GPIO_LOOKUP_IDX("cs5535-gpio", 25, NULL, 1, GPIO_ACTIVE_LOW), 93 - GPIO_LOOKUP_IDX("cs5535-gpio", 27, NULL, 2, GPIO_ACTIVE_LOW), 94 - { } 95 - }, 96 - }; 97 - 98 - static struct platform_device alix_leds_dev = { 99 - .name = "leds-gpio", 100 - .id = -1, 101 - .dev.platform_data = &alix_leds_data, 102 - }; 103 - 104 - static struct platform_device *alix_devs[] __initdata = { 105 - &alix_buttons_dev, 106 - &alix_leds_dev, 44 + static const struct geode_led alix_leds[] __initconst = { 45 + { 6, true }, 46 + { 25, false }, 47 + { 27, false }, 107 48 }; 108 49 109 50 static void __init register_alix(void) 110 51 { 111 - /* Setup LED control through leds-gpio driver */ 112 - gpiod_add_lookup_table(&alix_leds_gpio_table); 113 - platform_add_devices(alix_devs, ARRAY_SIZE(alix_devs)); 52 + geode_create_restart_key(24); 53 + geode_create_leds("alix", alix_leds, ARRAY_SIZE(alix_leds)); 114 54 } 115 55 116 56 static bool __init alix_present(unsigned long bios_phys,
+178
arch/x86/platform/geode/geode-common.c
··· 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 + }
+21
arch/x86/platform/geode/geode-common.h
··· 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 */
+7 -73
arch/x86/platform/geode/geos.c
··· 16 16 #include <linux/init.h> 17 17 #include <linux/io.h> 18 18 #include <linux/string.h> 19 - #include <linux/leds.h> 20 - #include <linux/platform_device.h> 21 - #include <linux/input.h> 22 - #include <linux/gpio_keys.h> 23 - #include <linux/gpio/machine.h> 24 19 #include <linux/dmi.h> 25 20 26 21 #include <asm/geode.h> 27 22 28 - static struct gpio_keys_button geos_gpio_buttons[] = { 29 - { 30 - .code = KEY_RESTART, 31 - .gpio = 3, 32 - .active_low = 1, 33 - .desc = "Reset button", 34 - .type = EV_KEY, 35 - .wakeup = 0, 36 - .debounce_interval = 100, 37 - .can_disable = 0, 38 - } 39 - }; 40 - static struct gpio_keys_platform_data geos_buttons_data = { 41 - .buttons = geos_gpio_buttons, 42 - .nbuttons = ARRAY_SIZE(geos_gpio_buttons), 43 - .poll_interval = 20, 44 - }; 23 + #include "geode-common.h" 45 24 46 - static struct platform_device geos_buttons_dev = { 47 - .name = "gpio-keys-polled", 48 - .id = 1, 49 - .dev = { 50 - .platform_data = &geos_buttons_data, 51 - } 52 - }; 53 - 54 - static struct gpio_led geos_leds[] = { 55 - { 56 - .name = "geos:1", 57 - .default_trigger = "default-on", 58 - }, 59 - { 60 - .name = "geos:2", 61 - .default_trigger = "default-off", 62 - }, 63 - { 64 - .name = "geos:3", 65 - .default_trigger = "default-off", 66 - }, 67 - }; 68 - 69 - static struct gpio_led_platform_data geos_leds_data = { 70 - .num_leds = ARRAY_SIZE(geos_leds), 71 - .leds = geos_leds, 72 - }; 73 - 74 - static struct gpiod_lookup_table geos_leds_gpio_table = { 75 - .dev_id = "leds-gpio", 76 - .table = { 77 - /* The Geode GPIOs should be on the CS5535 companion chip */ 78 - GPIO_LOOKUP_IDX("cs5535-gpio", 6, NULL, 0, GPIO_ACTIVE_LOW), 79 - GPIO_LOOKUP_IDX("cs5535-gpio", 25, NULL, 1, GPIO_ACTIVE_LOW), 80 - GPIO_LOOKUP_IDX("cs5535-gpio", 27, NULL, 2, GPIO_ACTIVE_LOW), 81 - { } 82 - }, 83 - }; 84 - 85 - static struct platform_device geos_leds_dev = { 86 - .name = "leds-gpio", 87 - .id = -1, 88 - .dev.platform_data = &geos_leds_data, 89 - }; 90 - 91 - static struct platform_device *geos_devs[] __initdata = { 92 - &geos_buttons_dev, 93 - &geos_leds_dev, 25 + static const struct geode_led geos_leds[] __initconst = { 26 + { 6, true }, 27 + { 25, false }, 28 + { 27, false }, 94 29 }; 95 30 96 31 static void __init register_geos(void) 97 32 { 98 - /* Setup LED control through leds-gpio driver */ 99 - gpiod_add_lookup_table(&geos_leds_gpio_table); 100 - platform_add_devices(geos_devs, ARRAY_SIZE(geos_devs)); 33 + geode_create_restart_key(3); 34 + geode_create_leds("geos", geos_leds, ARRAY_SIZE(geos_leds)); 101 35 } 102 36 103 37 static int __init geos_init(void)
+7 -62
arch/x86/platform/geode/net5501.c
··· 16 16 #include <linux/init.h> 17 17 #include <linux/io.h> 18 18 #include <linux/string.h> 19 - #include <linux/leds.h> 20 - #include <linux/platform_device.h> 21 19 #include <linux/input.h> 22 - #include <linux/gpio_keys.h> 23 20 #include <linux/gpio/machine.h> 21 + #include <linux/gpio/property.h> 24 22 25 23 #include <asm/geode.h> 24 + 25 + #include "geode-common.h" 26 26 27 27 #define BIOS_REGION_BASE 0xffff0000 28 28 #define BIOS_REGION_SIZE 0x00010000 29 29 30 - static struct gpio_keys_button net5501_gpio_buttons[] = { 31 - { 32 - .code = KEY_RESTART, 33 - .gpio = 24, 34 - .active_low = 1, 35 - .desc = "Reset button", 36 - .type = EV_KEY, 37 - .wakeup = 0, 38 - .debounce_interval = 100, 39 - .can_disable = 0, 40 - } 41 - }; 42 - static struct gpio_keys_platform_data net5501_buttons_data = { 43 - .buttons = net5501_gpio_buttons, 44 - .nbuttons = ARRAY_SIZE(net5501_gpio_buttons), 45 - .poll_interval = 20, 46 - }; 47 - 48 - static struct platform_device net5501_buttons_dev = { 49 - .name = "gpio-keys-polled", 50 - .id = 1, 51 - .dev = { 52 - .platform_data = &net5501_buttons_data, 53 - } 54 - }; 55 - 56 - static struct gpio_led net5501_leds[] = { 57 - { 58 - .name = "net5501:1", 59 - .default_trigger = "default-on", 60 - }, 61 - }; 62 - 63 - static struct gpio_led_platform_data net5501_leds_data = { 64 - .num_leds = ARRAY_SIZE(net5501_leds), 65 - .leds = net5501_leds, 66 - }; 67 - 68 - static struct gpiod_lookup_table net5501_leds_gpio_table = { 69 - .dev_id = "leds-gpio", 70 - .table = { 71 - /* The Geode GPIOs should be on the CS5535 companion chip */ 72 - GPIO_LOOKUP_IDX("cs5535-gpio", 6, NULL, 0, GPIO_ACTIVE_HIGH), 73 - { } 74 - }, 75 - }; 76 - 77 - static struct platform_device net5501_leds_dev = { 78 - .name = "leds-gpio", 79 - .id = -1, 80 - .dev.platform_data = &net5501_leds_data, 81 - }; 82 - 83 - static struct platform_device *net5501_devs[] __initdata = { 84 - &net5501_buttons_dev, 85 - &net5501_leds_dev, 30 + static const struct geode_led net5501_leds[] __initconst = { 31 + { 6, true }, 86 32 }; 87 33 88 34 static void __init register_net5501(void) 89 35 { 90 - /* Setup LED control through leds-gpio driver */ 91 - gpiod_add_lookup_table(&net5501_leds_gpio_table); 92 - platform_add_devices(net5501_devs, ARRAY_SIZE(net5501_devs)); 36 + geode_create_restart_key(24); 37 + geode_create_leds("net5501", net5501_leds, ARRAY_SIZE(net5501_leds)); 93 38 } 94 39 95 40 struct net5501_board {