"Das U-Boot" Source Tree
at master 133 lines 2.9 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com> 4 */ 5 6#include <button.h> 7#include <dm.h> 8#include <dm/lists.h> 9#include <dm/uclass-internal.h> 10#include <log.h> 11#include <asm/gpio.h> 12 13struct button_gpio_priv { 14 struct gpio_desc gpio; 15 int linux_code; 16}; 17 18static enum button_state_t button_gpio_get_state(struct udevice *dev) 19{ 20 struct button_gpio_priv *priv = dev_get_priv(dev); 21 int ret; 22 23 if (!priv) 24 return -ENODATA; 25 26 if (!dm_gpio_is_valid(&priv->gpio)) 27 return -EREMOTEIO; 28 ret = dm_gpio_get_value(&priv->gpio); 29 if (ret < 0) 30 return ret; 31 32 return ret ? BUTTON_ON : BUTTON_OFF; 33} 34 35static int button_gpio_get_code(struct udevice *dev) 36{ 37 struct button_gpio_priv *priv = dev_get_priv(dev); 38 if (!priv) 39 return -ENODATA; 40 int code = priv->linux_code; 41 42 if (!code) 43 return -ENODATA; 44 45 return code; 46} 47 48static int button_gpio_probe(struct udevice *dev) 49{ 50 struct button_uc_plat *uc_plat = dev_get_uclass_plat(dev); 51 struct button_gpio_priv *priv = dev_get_priv(dev); 52 int ret; 53 54 /* Ignore the top-level button node */ 55 if (!uc_plat->label) 56 return 0; 57 58 ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_IN); 59 if (ret || !dm_gpio_is_valid(&priv->gpio)) 60 return ret; 61 62 ret = dev_read_u32(dev, "linux,code", &priv->linux_code); 63 64 return ret; 65} 66 67static int button_gpio_remove(struct udevice *dev) 68{ 69 /* 70 * The GPIO driver may have already been removed. We will need to 71 * address this more generally. 72 */ 73 if (!IS_ENABLED(CONFIG_SANDBOX)) { 74 struct button_gpio_priv *priv = dev_get_priv(dev); 75 76 if (dm_gpio_is_valid(&priv->gpio)) 77 dm_gpio_free(dev, &priv->gpio); 78 } 79 80 return 0; 81} 82 83static int button_gpio_bind(struct udevice *parent) 84{ 85 struct udevice *dev; 86 ofnode node; 87 int ret; 88 89 dev_for_each_subnode(node, parent) { 90 struct button_uc_plat *uc_plat; 91 const char *label; 92 93 label = ofnode_read_string(node, "label"); 94 if (!label) { 95 debug("%s: node %s has no label\n", __func__, 96 ofnode_get_name(node)); 97 return -EINVAL; 98 } 99 ret = device_bind_driver_to_node(parent, "button_gpio", 100 ofnode_get_name(node), 101 node, &dev); 102 if (ret) 103 return ret; 104 uc_plat = dev_get_uclass_plat(dev); 105 uc_plat->label = label; 106 debug("Button '%s' bound to driver '%s'\n", label, 107 dev->driver->name); 108 } 109 110 return 0; 111} 112 113static const struct button_ops button_gpio_ops = { 114 .get_state = button_gpio_get_state, 115 .get_code = button_gpio_get_code, 116}; 117 118static const struct udevice_id button_gpio_ids[] = { 119 { .compatible = "gpio-keys" }, 120 { .compatible = "gpio-keys-polled" }, 121 { } 122}; 123 124U_BOOT_DRIVER(button_gpio) = { 125 .name = "button_gpio", 126 .id = UCLASS_BUTTON, 127 .of_match = button_gpio_ids, 128 .ops = &button_gpio_ops, 129 .priv_auto = sizeof(struct button_gpio_priv), 130 .bind = button_gpio_bind, 131 .probe = button_gpio_probe, 132 .remove = button_gpio_remove, 133};