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