Coverage Report

Created: 2026-03-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/u-boot/drivers/button/button-gpio.c
Line
Count
Source
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
13
struct button_gpio_priv {
14
  struct gpio_desc gpio;
15
  int linux_code;
16
};
17
18
static enum button_state_t button_gpio_get_state(struct udevice *dev)
19
0
{
20
0
  struct button_gpio_priv *priv = dev_get_priv(dev);
21
0
  int ret;
22
23
0
  if (!priv)
24
0
    return -ENODATA;
25
26
0
  if (!dm_gpio_is_valid(&priv->gpio))
27
0
    return -EREMOTEIO;
28
0
  ret = dm_gpio_get_value(&priv->gpio);
29
0
  if (ret < 0)
30
0
    return ret;
31
32
0
  return ret ? BUTTON_ON : BUTTON_OFF;
33
0
}
34
35
static int button_gpio_get_code(struct udevice *dev)
36
0
{
37
0
  struct button_gpio_priv *priv = dev_get_priv(dev);
38
0
  if (!priv)
39
0
    return -ENODATA;
40
0
  int code = priv->linux_code;
41
42
0
  if (!code)
43
0
    return -ENODATA;
44
45
0
  return code;
46
0
}
47
48
static int button_gpio_probe(struct udevice *dev)
49
0
{
50
0
  struct button_uc_plat *uc_plat = dev_get_uclass_plat(dev);
51
0
  struct button_gpio_priv *priv = dev_get_priv(dev);
52
0
  int ret;
53
54
  /* Ignore the top-level button node */
55
0
  if (!uc_plat->label)
56
0
    return 0;
57
58
0
  ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_IN);
59
0
  if (ret || !dm_gpio_is_valid(&priv->gpio))
60
0
    return ret;
61
62
0
  ret = dev_read_u32(dev, "linux,code", &priv->linux_code);
63
64
0
  return ret;
65
0
}
66
67
static int button_gpio_remove(struct udevice *dev)
68
0
{
69
  /*
70
   * The GPIO driver may have already been removed. We will need to
71
   * address this more generally.
72
   */
73
0
  if (!IS_ENABLED(CONFIG_SANDBOX)) {
74
0
    struct button_gpio_priv *priv = dev_get_priv(dev);
75
76
0
    if (dm_gpio_is_valid(&priv->gpio))
77
0
      dm_gpio_free(dev, &priv->gpio);
78
0
  }
79
80
0
  return 0;
81
0
}
82
83
static int button_gpio_bind(struct udevice *parent)
84
0
{
85
0
  struct udevice *dev;
86
0
  ofnode node;
87
0
  int ret;
88
89
0
  dev_for_each_subnode(node, parent) {
90
0
    struct button_uc_plat *uc_plat;
91
0
    const char *label;
92
93
0
    label = ofnode_read_string(node, "label");
94
0
    if (!label) {
95
0
      debug("%s: node %s has no label\n", __func__,
96
0
            ofnode_get_name(node));
97
0
      return -EINVAL;
98
0
    }
99
0
    ret = device_bind_driver_to_node(parent, "button_gpio",
100
0
             ofnode_get_name(node),
101
0
             node, &dev);
102
0
    if (ret)
103
0
      return ret;
104
0
    uc_plat = dev_get_uclass_plat(dev);
105
0
    uc_plat->label = label;
106
0
    debug("Button '%s' bound to driver '%s'\n", label,
107
0
          dev->driver->name);
108
0
  }
109
110
0
  return 0;
111
0
}
112
113
static const struct button_ops button_gpio_ops = {
114
  .get_state  = button_gpio_get_state,
115
  .get_code = button_gpio_get_code,
116
};
117
118
static const struct udevice_id button_gpio_ids[] = {
119
  { .compatible = "gpio-keys" },
120
  { .compatible = "gpio-keys-polled" },
121
  { }
122
};
123
124
U_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
};