Path: blob/master/arch/x86/platform/geode/geode-common.c
26493 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Shared helpers to register GPIO-connected buttons and LEDs3* on AMD Geode boards.4*/56#include <linux/err.h>7#include <linux/gpio/machine.h>8#include <linux/gpio/property.h>9#include <linux/input.h>10#include <linux/leds.h>11#include <linux/platform_device.h>12#include <linux/slab.h>1314#include "geode-common.h"1516static const struct software_node geode_gpiochip_node = {17.name = "cs5535-gpio",18};1920static const struct property_entry geode_gpio_keys_props[] = {21PROPERTY_ENTRY_U32("poll-interval", 20),22{ }23};2425static const struct software_node geode_gpio_keys_node = {26.name = "geode-gpio-keys",27.properties = geode_gpio_keys_props,28};2930static struct property_entry geode_restart_key_props[] = {31{ /* Placeholder for GPIO property */ },32PROPERTY_ENTRY_U32("linux,code", KEY_RESTART),33PROPERTY_ENTRY_STRING("label", "Reset button"),34PROPERTY_ENTRY_U32("debounce-interval", 100),35{ }36};3738static const struct software_node geode_restart_key_node = {39.parent = &geode_gpio_keys_node,40.properties = geode_restart_key_props,41};4243static const struct software_node *geode_gpio_keys_swnodes[] __initconst = {44&geode_gpiochip_node,45&geode_gpio_keys_node,46&geode_restart_key_node,47NULL48};4950/*51* Creates gpio-keys-polled device for the restart key.52*53* Note that it needs to be called first, before geode_create_leds(),54* because it registers gpiochip software node used by both gpio-keys and55* leds-gpio devices.56*/57int __init geode_create_restart_key(unsigned int pin)58{59struct platform_device_info keys_info = {60.name = "gpio-keys-polled",61.id = 1,62};63struct platform_device *pd;64int err;6566geode_restart_key_props[0] = PROPERTY_ENTRY_GPIO("gpios",67&geode_gpiochip_node,68pin, GPIO_ACTIVE_LOW);6970err = software_node_register_node_group(geode_gpio_keys_swnodes);71if (err) {72pr_err("failed to register gpio-keys software nodes: %d\n", err);73return err;74}7576keys_info.fwnode = software_node_fwnode(&geode_gpio_keys_node);7778pd = platform_device_register_full(&keys_info);79err = PTR_ERR_OR_ZERO(pd);80if (err) {81pr_err("failed to create gpio-keys device: %d\n", err);82software_node_unregister_node_group(geode_gpio_keys_swnodes);83return err;84}8586return 0;87}8889static const struct software_node geode_gpio_leds_node = {90.name = "geode-leds",91};9293#define MAX_LEDS 39495int __init geode_create_leds(const char *label, const struct geode_led *leds,96unsigned int n_leds)97{98const struct software_node *group[MAX_LEDS + 2] = { 0 };99struct software_node *swnodes;100struct property_entry *props;101struct platform_device_info led_info = {102.name = "leds-gpio",103.id = PLATFORM_DEVID_NONE,104};105struct platform_device *led_dev;106const char *node_name;107int err;108int i;109110if (n_leds > MAX_LEDS) {111pr_err("%s: too many LEDs\n", __func__);112return -EINVAL;113}114115swnodes = kcalloc(n_leds, sizeof(*swnodes), GFP_KERNEL);116if (!swnodes)117return -ENOMEM;118119/*120* Each LED is represented by 3 properties: "gpios",121* "linux,default-trigger", and am empty terminator.122*/123props = kcalloc(n_leds * 3, sizeof(*props), GFP_KERNEL);124if (!props) {125err = -ENOMEM;126goto err_free_swnodes;127}128129group[0] = &geode_gpio_leds_node;130for (i = 0; i < n_leds; i++) {131node_name = kasprintf(GFP_KERNEL, "%s:%d", label, i);132if (!node_name) {133err = -ENOMEM;134goto err_free_names;135}136137props[i * 3 + 0] =138PROPERTY_ENTRY_GPIO("gpios", &geode_gpiochip_node,139leds[i].pin, GPIO_ACTIVE_LOW);140props[i * 3 + 1] =141PROPERTY_ENTRY_STRING("linux,default-trigger",142leds[i].default_on ?143"default-on" : "default-off");144/* props[i * 3 + 2] is an empty terminator */145146swnodes[i] = SOFTWARE_NODE(node_name, &props[i * 3],147&geode_gpio_leds_node);148group[i + 1] = &swnodes[i];149}150151err = software_node_register_node_group(group);152if (err) {153pr_err("failed to register LED software nodes: %d\n", err);154goto err_free_names;155}156157led_info.fwnode = software_node_fwnode(&geode_gpio_leds_node);158159led_dev = platform_device_register_full(&led_info);160err = PTR_ERR_OR_ZERO(led_dev);161if (err) {162pr_err("failed to create LED device: %d\n", err);163goto err_unregister_group;164}165166return 0;167168err_unregister_group:169software_node_unregister_node_group(group);170err_free_names:171while (--i >= 0)172kfree(swnodes[i].name);173kfree(props);174err_free_swnodes:175kfree(swnodes);176return err;177}178179180