]>
Commit | Line | Data |
---|---|---|
1 | // SPDX-License-Identifier: GPL-2.0+ | |
2 | /* | |
3 | * Copyright (c), Vaisala Oyj | |
4 | */ | |
5 | ||
6 | #include <common.h> | |
7 | #include <asm/gpio.h> | |
8 | #include <dm.h> | |
9 | #include <dm/devres.h> | |
10 | #include <errno.h> | |
11 | #include <reboot-mode/reboot-mode-gpio.h> | |
12 | #include <reboot-mode/reboot-mode.h> | |
13 | ||
14 | DECLARE_GLOBAL_DATA_PTR; | |
15 | ||
16 | static int reboot_mode_get(struct udevice *dev, u32 *buf) | |
17 | { | |
18 | int ret; | |
19 | struct reboot_mode_gpio_platdata *plat_data; | |
20 | ||
21 | if (!buf) | |
22 | return -EINVAL; | |
23 | ||
24 | plat_data = dev_get_plat(dev); | |
25 | if (!plat_data) | |
26 | return -EINVAL; | |
27 | ||
28 | ret = dm_gpio_get_values_as_int(plat_data->gpio_desc, | |
29 | plat_data->gpio_count); | |
30 | if (ret < 0) | |
31 | return ret; | |
32 | ||
33 | *buf = ret; | |
34 | ||
35 | return 0; | |
36 | } | |
37 | ||
38 | static int reboot_mode_probe(struct udevice *dev) | |
39 | { | |
40 | struct reboot_mode_gpio_platdata *plat_data; | |
41 | ||
42 | plat_data = dev_get_plat(dev); | |
43 | if (!plat_data) | |
44 | return -EINVAL; | |
45 | ||
46 | int ret; | |
47 | ||
48 | #if CONFIG_IS_ENABLED(OF_CONTROL) | |
49 | ret = gpio_get_list_count(dev, "gpios"); | |
50 | if (ret < 0) | |
51 | return ret; | |
52 | ||
53 | plat_data->gpio_count = ret; | |
54 | #endif | |
55 | ||
56 | if (plat_data->gpio_count <= 0) | |
57 | return -EINVAL; | |
58 | ||
59 | plat_data->gpio_desc = devm_kcalloc(dev, plat_data->gpio_count, | |
60 | sizeof(struct gpio_desc), 0); | |
61 | if (!plat_data->gpio_desc) | |
62 | return -ENOMEM; | |
63 | ||
64 | #if CONFIG_IS_ENABLED(OF_CONTROL) | |
65 | ret = gpio_request_list_by_name(dev, "gpios", plat_data->gpio_desc, | |
66 | plat_data->gpio_count, GPIOD_IS_IN); | |
67 | if (ret < 0) | |
68 | return ret; | |
69 | #else | |
70 | for (int i = 0; i < plat_data->gpio_count; i++) { | |
71 | struct reboot_mode_gpio_config *gpio = | |
72 | plat_data->gpios_config + i; | |
73 | struct gpio_desc *desc = plat_data->gpio_desc + i; | |
74 | ||
75 | ret = uclass_get_device_by_seq(UCLASS_GPIO, | |
76 | gpio->gpio_dev_offset, | |
77 | &desc->dev); | |
78 | if (ret < 0) | |
79 | return ret; | |
80 | ||
81 | desc->flags = gpio->flags; | |
82 | desc->offset = gpio->gpio_offset; | |
83 | ||
84 | ret = dm_gpio_request(desc, ""); | |
85 | if (ret < 0) | |
86 | return ret; | |
87 | ||
88 | ret = dm_gpio_set_dir(desc); | |
89 | if (ret < 0) | |
90 | return ret; | |
91 | } | |
92 | #endif | |
93 | return 0; | |
94 | } | |
95 | ||
96 | static int reboot_mode_remove(struct udevice *dev) | |
97 | { | |
98 | struct reboot_mode_gpio_platdata *plat_data; | |
99 | ||
100 | plat_data = dev_get_plat(dev); | |
101 | if (!plat_data) | |
102 | return -EINVAL; | |
103 | ||
104 | return gpio_free_list(dev, plat_data->gpio_desc, plat_data->gpio_count); | |
105 | } | |
106 | ||
107 | #if CONFIG_IS_ENABLED(OF_CONTROL) | |
108 | static const struct udevice_id reboot_mode_ids[] = { | |
109 | { .compatible = "reboot-mode-gpio", 0 }, | |
110 | { } | |
111 | }; | |
112 | #endif | |
113 | ||
114 | static const struct reboot_mode_ops reboot_mode_gpio_ops = { | |
115 | .get = reboot_mode_get, | |
116 | }; | |
117 | ||
118 | U_BOOT_DRIVER(reboot_mode_gpio) = { | |
119 | .name = "reboot-mode-gpio", | |
120 | .id = UCLASS_REBOOT_MODE, | |
121 | .probe = reboot_mode_probe, | |
122 | .remove = reboot_mode_remove, | |
123 | #if CONFIG_IS_ENABLED(OF_CONTROL) | |
124 | .of_match = reboot_mode_ids, | |
125 | #endif | |
126 | .plat_auto = sizeof(struct reboot_mode_gpio_platdata), | |
127 | .ops = &reboot_mode_gpio_ops, | |
128 | }; |