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