blob: dbb000622c7812a7be2262c4a1e772990be7af92 [file] [log] [blame]
Philippe Reynes7686d9f2020-07-24 18:19:46 +02001// 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{
Simon Glass71fa5b42020-12-03 16:55:18 -070034 struct button_uc_plat *uc_plat = dev_get_uclass_plat(dev);
Philippe Reynes7686d9f2020-07-24 18:19:46 +020035 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;
Simon Glass71fa5b42020-12-03 16:55:18 -070086 uc_plat = dev_get_uclass_plat(dev);
Philippe Reynes7686d9f2020-07-24 18:19:46 +020087 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,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700108 .priv_auto = sizeof(struct button_gpio_priv),
Philippe Reynes7686d9f2020-07-24 18:19:46 +0200109 .bind = button_gpio_bind,
110 .probe = button_gpio_probe,
111 .remove = button_gpio_remove,
112};