]>
Commit | Line | Data |
---|---|---|
e8779962 DS |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com> | |
4 | */ | |
5 | ||
6 | #include <stdlib.h> | |
7 | #include <common.h> | |
8 | #include <dm.h> | |
9 | #include <fdtdec.h> | |
10 | #include <input.h> | |
11 | #include <keyboard.h> | |
12 | #include <button.h> | |
13 | #include <dm/device-internal.h> | |
14 | #include <log.h> | |
15 | #include <asm/io.h> | |
16 | #include <asm/gpio.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/input.h> | |
19 | ||
20 | /** | |
21 | * struct button_kbd_priv - driver private data | |
22 | * | |
23 | * @input: input configuration | |
24 | * @button_size: number of buttons found | |
25 | * @old_state: a pointer to old button states array. Used to determine button state change. | |
26 | */ | |
27 | struct button_kbd_priv { | |
28 | struct input_config *input; | |
29 | u32 button_size; | |
30 | u32 *old_state; | |
31 | }; | |
32 | ||
33 | static int button_kbd_start(struct udevice *dev) | |
34 | { | |
35 | struct button_kbd_priv *priv = dev_get_priv(dev); | |
36 | int i = 0; | |
37 | struct udevice *button_gpio_devp; | |
38 | ||
39 | uclass_foreach_dev_probe(UCLASS_BUTTON, button_gpio_devp) { | |
40 | struct button_uc_plat *uc_plat = dev_get_uclass_plat(button_gpio_devp); | |
41 | /* Ignore the top-level button node */ | |
42 | if (!uc_plat->label) | |
43 | continue; | |
44 | debug("Found button %s #%d - %s, probing...\n", | |
45 | uc_plat->label, i, button_gpio_devp->name); | |
46 | i++; | |
47 | } | |
48 | ||
49 | priv->button_size = i; | |
50 | priv->old_state = calloc(i, sizeof(int)); | |
51 | ||
52 | return 0; | |
53 | } | |
54 | ||
55 | int button_read_keys(struct input_config *input) | |
56 | { | |
57 | struct button_kbd_priv *priv = dev_get_priv(input->dev); | |
58 | struct udevice *button_gpio_devp; | |
59 | struct uclass *uc; | |
60 | int i = 0; | |
61 | u32 code, state, state_changed = 0; | |
62 | ||
63 | uclass_id_foreach_dev(UCLASS_BUTTON, button_gpio_devp, uc) { | |
64 | struct button_uc_plat *uc_plat = dev_get_uclass_plat(button_gpio_devp); | |
65 | /* Ignore the top-level button node */ | |
66 | if (!uc_plat->label) | |
67 | continue; | |
68 | code = button_get_code(button_gpio_devp); | |
69 | if (!code) | |
70 | continue; | |
71 | ||
72 | state = button_get_state(button_gpio_devp); | |
73 | state_changed = state != priv->old_state[i]; | |
74 | ||
75 | if (state_changed) { | |
76 | debug("%s: %d\n", uc_plat->label, code); | |
77 | priv->old_state[i] = state; | |
78 | input_add_keycode(input, code, state); | |
79 | } | |
80 | i++; | |
81 | } | |
82 | return 0; | |
83 | } | |
84 | ||
85 | static const struct keyboard_ops button_kbd_ops = { | |
86 | .start = button_kbd_start, | |
87 | }; | |
88 | ||
89 | static int button_kbd_probe(struct udevice *dev) | |
90 | { | |
91 | struct button_kbd_priv *priv = dev_get_priv(dev); | |
92 | struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev); | |
93 | struct stdio_dev *sdev = &uc_priv->sdev; | |
94 | struct input_config *input = &uc_priv->input; | |
95 | int ret = 0; | |
96 | ||
97 | input_init(input, false); | |
98 | input_add_tables(input, false); | |
99 | ||
100 | /* Register the device. */ | |
101 | priv->input = input; | |
102 | input->dev = dev; | |
103 | input->read_keys = button_read_keys; | |
104 | strcpy(sdev->name, "button-kbd"); | |
105 | ret = input_stdio_register(sdev); | |
106 | if (ret) { | |
107 | debug("%s: input_stdio_register() failed\n", __func__); | |
108 | return ret; | |
109 | } | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
e8779962 DS |
114 | U_BOOT_DRIVER(button_kbd) = { |
115 | .name = "button_kbd", | |
116 | .id = UCLASS_KEYBOARD, | |
e8779962 DS |
117 | .ops = &button_kbd_ops, |
118 | .priv_auto = sizeof(struct button_kbd_priv), | |
119 | .probe = button_kbd_probe, | |
120 | }; | |
25df9152 SR |
121 | |
122 | U_BOOT_DRVINFO(button_kbd) = { | |
123 | .name = "button_kbd" | |
124 | }; |