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
14 struct button_gpio_priv {
15 struct gpio_desc gpio;
16 };
17
button_gpio_get_state(struct udevice * dev)18 static 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
button_gpio_probe(struct udevice * dev)32 static 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
button_gpio_remove(struct udevice * dev)49 static 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
button_gpio_bind(struct udevice * parent)65 static 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
93 static const struct button_ops button_gpio_ops = {
94 .get_state = button_gpio_get_state,
95 };
96
97 static const struct udevice_id button_gpio_ids[] = {
98 { .compatible = "gpio-keys" },
99 { .compatible = "gpio-keys-polled" },
100 { }
101 };
102
103 U_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