test: dm: update test for pins configuration in gpio
[oweals/u-boot.git] / drivers / gpio / sandbox.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2011 The Chromium OS Authors.
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <fdtdec.h>
9 #include <malloc.h>
10 #include <asm/gpio.h>
11 #include <dm/lists.h>
12 #include <dm/of.h>
13 #include <dm/pinctrl.h>
14 #include <dt-bindings/gpio/gpio.h>
15 #include <dt-bindings/gpio/sandbox-gpio.h>
16
17
18 struct gpio_state {
19         const char *label;      /* label given by requester */
20         ulong dir_flags;        /* dir_flags (GPIOD_...) */
21 };
22
23 /* Access routines for GPIO dir flags */
24 static ulong *get_gpio_dir_flags(struct udevice *dev, unsigned int offset)
25 {
26         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
27         struct gpio_state *state = dev_get_priv(dev);
28
29         if (offset >= uc_priv->gpio_count) {
30                 static ulong invalid_dir_flags;
31                 printf("sandbox_gpio: error: invalid gpio %u\n", offset);
32                 return &invalid_dir_flags;
33         }
34
35         return &state[offset].dir_flags;
36
37 }
38
39 static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
40 {
41         return (*get_gpio_dir_flags(dev, offset) & flag) != 0;
42 }
43
44 static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
45                          int value)
46 {
47         ulong *gpio = get_gpio_dir_flags(dev, offset);
48
49         if (value)
50                 *gpio |= flag;
51         else
52                 *gpio &= ~flag;
53
54         return 0;
55 }
56
57 /*
58  * Back-channel sandbox-internal-only access to GPIO state
59  */
60
61 int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
62 {
63         if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
64                 debug("sandbox_gpio: get_value on output gpio %u\n", offset);
65         return get_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE);
66 }
67
68 int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
69 {
70         return set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE, value);
71 }
72
73 int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
74 {
75         return get_gpio_flag(dev, offset, GPIOD_IS_OUT);
76 }
77
78 int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
79 {
80         set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
81         set_gpio_flag(dev, offset, GPIOD_IS_IN, !(output));
82
83         return 0;
84 }
85
86 ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset)
87 {
88         return *get_gpio_dir_flags(dev, offset);
89 }
90
91 int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
92                                ulong flags)
93 {
94         *get_gpio_dir_flags(dev, offset) = flags;
95
96         return 0;
97 }
98
99 /*
100  * These functions implement the public interface within U-Boot
101  */
102
103 /* set GPIO port 'offset' as an input */
104 static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
105 {
106         debug("%s: offset:%u\n", __func__, offset);
107
108         return sandbox_gpio_set_direction(dev, offset, 0);
109 }
110
111 /* set GPIO port 'offset' as an output, with polarity 'value' */
112 static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
113                                     int value)
114 {
115         debug("%s: offset:%u, value = %d\n", __func__, offset, value);
116
117         return sandbox_gpio_set_direction(dev, offset, 1) |
118                 sandbox_gpio_set_value(dev, offset, value);
119 }
120
121 /* read GPIO IN value of port 'offset' */
122 static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
123 {
124         debug("%s: offset:%u\n", __func__, offset);
125
126         return sandbox_gpio_get_value(dev, offset);
127 }
128
129 /* write GPIO OUT value to port 'offset' */
130 static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
131 {
132         debug("%s: offset:%u, value = %d\n", __func__, offset, value);
133
134         if (!sandbox_gpio_get_direction(dev, offset)) {
135                 printf("sandbox_gpio: error: set_value on input gpio %u\n",
136                        offset);
137                 return -1;
138         }
139
140         return sandbox_gpio_set_value(dev, offset, value);
141 }
142
143 static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
144 {
145         if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
146                 return GPIOF_OUTPUT;
147         if (get_gpio_flag(dev, offset, GPIOD_IS_IN))
148                 return GPIOF_INPUT;
149
150         return GPIOF_INPUT; /*GPIO is not configurated */
151 }
152
153 static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
154                          struct ofnode_phandle_args *args)
155 {
156         desc->offset = args->args[0];
157         if (args->args_count < 2)
158                 return 0;
159         /* treat generic binding with gpio uclass */
160         gpio_xlate_offs_flags(dev, desc, args);
161
162         /* sandbox test specific, not defined in gpio.h */
163         if (args->args[1] & GPIO_IN)
164                 desc->flags |= GPIOD_IS_IN;
165
166         if (args->args[1] & GPIO_OUT)
167                 desc->flags |= GPIOD_IS_OUT;
168
169         if (args->args[1] & GPIO_OUT_ACTIVE)
170                 desc->flags |= GPIOD_IS_OUT_ACTIVE;
171
172         return 0;
173 }
174
175 static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
176                                  ulong flags)
177 {
178         ulong *dir_flags;
179
180         debug("%s: offset:%u, dir_flags = %lx\n", __func__, offset, flags);
181
182         dir_flags = get_gpio_dir_flags(dev, offset);
183
184         *dir_flags = flags;
185
186         return 0;
187 }
188
189 static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
190                                  ulong *flags)
191 {
192         debug("%s: offset:%u\n", __func__, offset);
193         *flags = *get_gpio_dir_flags(dev, offset);
194
195         return 0;
196 }
197
198 static const struct dm_gpio_ops gpio_sandbox_ops = {
199         .direction_input        = sb_gpio_direction_input,
200         .direction_output       = sb_gpio_direction_output,
201         .get_value              = sb_gpio_get_value,
202         .set_value              = sb_gpio_set_value,
203         .get_function           = sb_gpio_get_function,
204         .xlate                  = sb_gpio_xlate,
205         .set_dir_flags          = sb_gpio_set_dir_flags,
206         .get_dir_flags          = sb_gpio_get_dir_flags,
207 };
208
209 static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
210 {
211         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
212
213         uc_priv->gpio_count = dev_read_u32_default(dev, "sandbox,gpio-count",
214                                                    0);
215         uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
216
217         return 0;
218 }
219
220 static int gpio_sandbox_probe(struct udevice *dev)
221 {
222         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
223
224         if (!dev_of_valid(dev))
225                 /* Tell the uclass how many GPIOs we have */
226                 uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
227
228         dev->priv = calloc(sizeof(struct gpio_state), uc_priv->gpio_count);
229
230         return 0;
231 }
232
233 static int gpio_sandbox_remove(struct udevice *dev)
234 {
235         free(dev->priv);
236
237         return 0;
238 }
239
240 static const struct udevice_id sandbox_gpio_ids[] = {
241         { .compatible = "sandbox,gpio" },
242         { }
243 };
244
245 U_BOOT_DRIVER(gpio_sandbox) = {
246         .name   = "gpio_sandbox",
247         .id     = UCLASS_GPIO,
248         .of_match = sandbox_gpio_ids,
249         .ofdata_to_platdata = sandbox_gpio_ofdata_to_platdata,
250         .probe  = gpio_sandbox_probe,
251         .remove = gpio_sandbox_remove,
252         .ops    = &gpio_sandbox_ops,
253 };