blob: d1e561ab5e6878c6bc82f03fc58c19fa971f5223 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassb43d0442012-02-15 15:51:13 -08002/*
3 * Copyright (c) 2011 The Chromium OS Authors.
Simon Glassb43d0442012-02-15 15:51:13 -08004 */
5
6#include <common.h>
Simon Glassb4d70702014-02-26 15:59:25 -07007#include <dm.h>
8#include <fdtdec.h>
Simon Glass0f2af882020-05-10 11:40:05 -06009#include <log.h>
Simon Glassb4d70702014-02-26 15:59:25 -070010#include <malloc.h>
Simon Glass3176b6c2020-07-07 13:11:44 -060011#include <acpi/acpi_device.h>
Simon Glassb43d0442012-02-15 15:51:13 -080012#include <asm/gpio.h>
Simon Glass3176b6c2020-07-07 13:11:44 -060013#include <dm/acpi.h>
Simon Glass95588622020-12-22 19:30:28 -070014#include <dm/device-internal.h>
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +010015#include <dm/device_compat.h>
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010016#include <dm/lists.h>
Simon Glass12faa022017-05-18 20:09:18 -060017#include <dm/of.h>
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010018#include <dm/pinctrl.h>
Simon Glass16e10402015-01-05 20:05:29 -070019#include <dt-bindings/gpio/gpio.h>
Patrick Delaunay23aee612020-01-13 11:35:13 +010020#include <dt-bindings/gpio/sandbox-gpio.h>
Simon Glassb43d0442012-02-15 15:51:13 -080021
Simon Glassb43d0442012-02-15 15:51:13 -080022
23struct gpio_state {
24 const char *label; /* label given by requester */
Simon Glass3f2d5752021-02-04 21:21:59 -070025 ulong flags; /* flags (GPIOD_...) */
Simon Glassb43d0442012-02-15 15:51:13 -080026};
27
Simon Glass3f2d5752021-02-04 21:21:59 -070028/* Access routines for GPIO info */
29static struct gpio_state *get_gpio_state(struct udevice *dev, uint offset)
Simon Glassb43d0442012-02-15 15:51:13 -080030{
Simon Glassde0977b2015-03-05 12:25:20 -070031 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb4d70702014-02-26 15:59:25 -070032 struct gpio_state *state = dev_get_priv(dev);
33
34 if (offset >= uc_priv->gpio_count) {
Simon Glassb4d70702014-02-26 15:59:25 -070035 printf("sandbox_gpio: error: invalid gpio %u\n", offset);
Simon Glass3f2d5752021-02-04 21:21:59 -070036 return NULL;
Simon Glassb43d0442012-02-15 15:51:13 -080037 }
38
Simon Glass3f2d5752021-02-04 21:21:59 -070039 return &state[offset];
40}
41
42/* Access routines for GPIO flags */
43static ulong *get_gpio_flags(struct udevice *dev, unsigned int offset)
44{
45 struct gpio_state *state = get_gpio_state(dev, offset);
46
47 if (!state)
48 return NULL;
49
50 return &state->flags;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010051
Simon Glassb43d0442012-02-15 15:51:13 -080052}
53
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010054static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
Simon Glassb43d0442012-02-15 15:51:13 -080055{
Simon Glass3f2d5752021-02-04 21:21:59 -070056 return (*get_gpio_flags(dev, offset) & flag) != 0;
Simon Glassb43d0442012-02-15 15:51:13 -080057}
58
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010059static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
Simon Glassb4d70702014-02-26 15:59:25 -070060 int value)
Simon Glassb43d0442012-02-15 15:51:13 -080061{
Simon Glass44a1a5b2021-02-04 21:22:00 -070062 struct gpio_state *state = get_gpio_state(dev, offset);
Simon Glassb43d0442012-02-15 15:51:13 -080063
64 if (value)
Simon Glass44a1a5b2021-02-04 21:22:00 -070065 state->flags |= flag;
Simon Glassb43d0442012-02-15 15:51:13 -080066 else
Simon Glass44a1a5b2021-02-04 21:22:00 -070067 state->flags &= ~flag;
Simon Glassb43d0442012-02-15 15:51:13 -080068
69 return 0;
70}
71
Simon Glassb43d0442012-02-15 15:51:13 -080072/*
73 * Back-channel sandbox-internal-only access to GPIO state
74 */
75
Heiko Schocherb74fcb42014-05-22 12:43:05 +020076int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -080077{
Simon Glass44a1a5b2021-02-04 21:22:00 -070078 struct gpio_state *state = get_gpio_state(dev, offset);
79
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010080 if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
Simon Glassb4d70702014-02-26 15:59:25 -070081 debug("sandbox_gpio: get_value on output gpio %u\n", offset);
Simon Glass44a1a5b2021-02-04 21:22:00 -070082
83 return state->flags & GPIOD_EXT_HIGH ? true : false;
Simon Glassb43d0442012-02-15 15:51:13 -080084}
85
Heiko Schocherb74fcb42014-05-22 12:43:05 +020086int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
Simon Glassb43d0442012-02-15 15:51:13 -080087{
Simon Glassae1e85b2021-02-04 21:22:01 -070088 set_gpio_flag(dev, offset, GPIOD_EXT_HIGH, value);
Simon Glass44a1a5b2021-02-04 21:22:00 -070089
90 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -080091}
92
Heiko Schocherb74fcb42014-05-22 12:43:05 +020093int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -080094{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010095 return get_gpio_flag(dev, offset, GPIOD_IS_OUT);
Simon Glassb43d0442012-02-15 15:51:13 -080096}
97
Heiko Schocherb74fcb42014-05-22 12:43:05 +020098int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
Simon Glassb43d0442012-02-15 15:51:13 -080099{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100100 set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
Simon Glass44a1a5b2021-02-04 21:22:00 -0700101 set_gpio_flag(dev, offset, GPIOD_IS_IN, !output);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100102
103 return 0;
104}
105
Simon Glass3f2d5752021-02-04 21:21:59 -0700106ulong sandbox_gpio_get_flags(struct udevice *dev, uint offset)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100107{
Simon Glass44a1a5b2021-02-04 21:22:00 -0700108 ulong flags = *get_gpio_flags(dev, offset);
109
110 return flags & ~GPIOD_SANDBOX_MASK;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100111}
112
Simon Glass3f2d5752021-02-04 21:21:59 -0700113int sandbox_gpio_set_flags(struct udevice *dev, uint offset, ulong flags)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100114{
Simon Glass44a1a5b2021-02-04 21:22:00 -0700115 struct gpio_state *state = get_gpio_state(dev, offset);
116
Simon Glass4d3b73e2021-02-04 21:22:02 -0700117 state->flags = flags;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100118
119 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800120}
121
122/*
123 * These functions implement the public interface within U-Boot
124 */
125
Simon Glassb4d70702014-02-26 15:59:25 -0700126/* set GPIO port 'offset' as an input */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200127static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -0800128{
Simon Glassb4d70702014-02-26 15:59:25 -0700129 debug("%s: offset:%u\n", __func__, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800130
Simon Glassb4d70702014-02-26 15:59:25 -0700131 return sandbox_gpio_set_direction(dev, offset, 0);
Simon Glassb43d0442012-02-15 15:51:13 -0800132}
133
Simon Glassb4d70702014-02-26 15:59:25 -0700134/* set GPIO port 'offset' as an output, with polarity 'value' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200135static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
Simon Glassb4d70702014-02-26 15:59:25 -0700136 int value)
Simon Glassb43d0442012-02-15 15:51:13 -0800137{
Simon Glassae1e85b2021-02-04 21:22:01 -0700138 int ret;
139
Simon Glassb4d70702014-02-26 15:59:25 -0700140 debug("%s: offset:%u, value = %d\n", __func__, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800141
Simon Glassae1e85b2021-02-04 21:22:01 -0700142 ret = sandbox_gpio_set_direction(dev, offset, 1);
143 if (ret)
144 return ret;
145 ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE | GPIOD_EXT_HIGH,
146 value);
147 if (ret)
148 return ret;
149
150 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800151}
152
Simon Glassb4d70702014-02-26 15:59:25 -0700153/* read GPIO IN value of port 'offset' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200154static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -0800155{
Simon Glassb4d70702014-02-26 15:59:25 -0700156 debug("%s: offset:%u\n", __func__, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800157
Simon Glassb4d70702014-02-26 15:59:25 -0700158 return sandbox_gpio_get_value(dev, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800159}
160
Simon Glassb4d70702014-02-26 15:59:25 -0700161/* write GPIO OUT value to port 'offset' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200162static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
Simon Glassb43d0442012-02-15 15:51:13 -0800163{
Simon Glassae1e85b2021-02-04 21:22:01 -0700164 int ret;
165
Simon Glassb4d70702014-02-26 15:59:25 -0700166 debug("%s: offset:%u, value = %d\n", __func__, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800167
Simon Glassb4d70702014-02-26 15:59:25 -0700168 if (!sandbox_gpio_get_direction(dev, offset)) {
169 printf("sandbox_gpio: error: set_value on input gpio %u\n",
170 offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800171 return -1;
172 }
173
Simon Glassae1e85b2021-02-04 21:22:01 -0700174 ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE | GPIOD_EXT_HIGH,
175 value);
176 if (ret)
177 return ret;
178
179 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800180}
181
Simon Glass32048632014-10-04 11:29:45 -0600182static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
183{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100184 if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
Simon Glass32048632014-10-04 11:29:45 -0600185 return GPIOF_OUTPUT;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100186 if (get_gpio_flag(dev, offset, GPIOD_IS_IN))
187 return GPIOF_INPUT;
188
189 return GPIOF_INPUT; /*GPIO is not configurated */
Simon Glass32048632014-10-04 11:29:45 -0600190}
191
Simon Glass16e10402015-01-05 20:05:29 -0700192static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
Simon Glass12faa022017-05-18 20:09:18 -0600193 struct ofnode_phandle_args *args)
Simon Glass16e10402015-01-05 20:05:29 -0700194{
195 desc->offset = args->args[0];
196 if (args->args_count < 2)
197 return 0;
Patrick Delaunay23aee612020-01-13 11:35:13 +0100198 /* treat generic binding with gpio uclass */
199 gpio_xlate_offs_flags(dev, desc, args);
200
201 /* sandbox test specific, not defined in gpio.h */
202 if (args->args[1] & GPIO_IN)
Simon Glass16e10402015-01-05 20:05:29 -0700203 desc->flags |= GPIOD_IS_IN;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100204
Patrick Delaunay23aee612020-01-13 11:35:13 +0100205 if (args->args[1] & GPIO_OUT)
Simon Glass16e10402015-01-05 20:05:29 -0700206 desc->flags |= GPIOD_IS_OUT;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100207
Patrick Delaunay23aee612020-01-13 11:35:13 +0100208 if (args->args[1] & GPIO_OUT_ACTIVE)
Simon Glass16e10402015-01-05 20:05:29 -0700209 desc->flags |= GPIOD_IS_OUT_ACTIVE;
210
211 return 0;
212}
213
Simon Glass54befdd2021-02-04 21:21:55 -0700214static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset,
215 ulong flags)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100216{
Simon Glass3f2d5752021-02-04 21:21:59 -0700217 debug("%s: offset:%u, flags = %lx\n", __func__, offset, flags);
Simon Glass4d3b73e2021-02-04 21:22:02 -0700218 struct gpio_state *state = get_gpio_state(dev, offset);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100219
Simon Glass4d3b73e2021-02-04 21:22:02 -0700220 if (flags & GPIOD_IS_OUT) {
221 if (flags & GPIOD_IS_OUT_ACTIVE)
222 flags |= GPIOD_EXT_HIGH;
223 else
224 flags &= ~GPIOD_EXT_HIGH;
225 }
226 state->flags = flags;
227
228 return 0;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100229}
230
Simon Glass3f2d5752021-02-04 21:21:59 -0700231static int sb_gpio_get_flags(struct udevice *dev, uint offset, ulong *flagsp)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100232{
233 debug("%s: offset:%u\n", __func__, offset);
Simon Glass4d3b73e2021-02-04 21:22:02 -0700234 *flagsp = *get_gpio_flags(dev, offset) & ~GPIOD_SANDBOX_MASK;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100235
236 return 0;
237}
238
Simon Glass3176b6c2020-07-07 13:11:44 -0600239#if CONFIG_IS_ENABLED(ACPIGEN)
240static int sb_gpio_get_acpi(const struct gpio_desc *desc,
241 struct acpi_gpio *gpio)
242{
243 int ret;
244
245 /* Note that gpio_get_acpi() zeroes *gpio before calling here */
246 gpio->pin_count = 1;
247 gpio->pins[0] = desc->offset;
248 ret = acpi_device_scope(desc->dev, gpio->resource,
249 sizeof(gpio->resource));
250 if (ret)
251 return log_ret(ret);
252
253 /* All of these values are just used for testing */
254 if (desc->flags & GPIOD_ACTIVE_LOW) {
255 gpio->pin0_addr = 0x80012 + desc->offset;
256 gpio->type = ACPI_GPIO_TYPE_INTERRUPT;
257 gpio->pull = ACPI_GPIO_PULL_DOWN;
258 gpio->interrupt_debounce_timeout = 4321;
259
260 /* We use the GpioInt part */
261 gpio->irq.pin = desc->offset;
262 gpio->irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
263 gpio->irq.shared = ACPI_IRQ_SHARED;
264 gpio->irq.wake = ACPI_IRQ_WAKE;
265
266 /* The GpioIo part is only used for testing */
267 gpio->polarity = ACPI_GPIO_ACTIVE_LOW;
268 } else {
269 gpio->pin0_addr = 0xc00dc + desc->offset;
270 gpio->type = ACPI_GPIO_TYPE_IO;
271 gpio->pull = ACPI_GPIO_PULL_UP;
272 gpio->interrupt_debounce_timeout = 0;
273
274 /* The GpioInt part is not used */
275
276 /* We use the GpioIo part */
277 gpio->output_drive_strength = 1234;
278 gpio->io_shared = true;
279 gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_INPUT;
280 gpio->polarity = 0;
281 }
282
283 return 0;
284}
285
286static int sb_gpio_get_name(const struct udevice *dev, char *out_name)
287{
288 return acpi_copy_name(out_name, "GPIO");
289}
290
291struct acpi_ops gpio_sandbox_acpi_ops = {
292 .get_name = sb_gpio_get_name,
293};
294#endif /* ACPIGEN */
295
Simon Glassb4d70702014-02-26 15:59:25 -0700296static const struct dm_gpio_ops gpio_sandbox_ops = {
Simon Glassb4d70702014-02-26 15:59:25 -0700297 .direction_input = sb_gpio_direction_input,
298 .direction_output = sb_gpio_direction_output,
299 .get_value = sb_gpio_get_value,
300 .set_value = sb_gpio_set_value,
Simon Glass32048632014-10-04 11:29:45 -0600301 .get_function = sb_gpio_get_function,
Simon Glass16e10402015-01-05 20:05:29 -0700302 .xlate = sb_gpio_xlate,
Simon Glass54befdd2021-02-04 21:21:55 -0700303 .set_flags = sb_gpio_set_flags,
Simon Glassd063ce92021-02-04 21:21:56 -0700304 .get_flags = sb_gpio_get_flags,
Simon Glass3176b6c2020-07-07 13:11:44 -0600305#if CONFIG_IS_ENABLED(ACPIGEN)
306 .get_acpi = sb_gpio_get_acpi,
307#endif
Simon Glassb4d70702014-02-26 15:59:25 -0700308};
309
Simon Glassaad29ae2020-12-03 16:55:21 -0700310static int sandbox_gpio_of_to_plat(struct udevice *dev)
Simon Glassb43d0442012-02-15 15:51:13 -0800311{
Simon Glassde0977b2015-03-05 12:25:20 -0700312 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb43d0442012-02-15 15:51:13 -0800313
Simon Glass9e7ab232018-02-03 10:36:59 -0700314 uc_priv->gpio_count = dev_read_u32_default(dev, "sandbox,gpio-count",
315 0);
Simon Glass1185fcb2017-05-18 20:09:20 -0600316 uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
Simon Glassb43d0442012-02-15 15:51:13 -0800317
Simon Glassb4d70702014-02-26 15:59:25 -0700318 return 0;
319}
Simon Glassb43d0442012-02-15 15:51:13 -0800320
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200321static int gpio_sandbox_probe(struct udevice *dev)
Simon Glassb4d70702014-02-26 15:59:25 -0700322{
Simon Glassde0977b2015-03-05 12:25:20 -0700323 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb4d70702014-02-26 15:59:25 -0700324
Simon Glassf1d50f72020-12-19 10:40:13 -0700325 if (!dev_has_ofnode(dev))
Simon Glassb4d70702014-02-26 15:59:25 -0700326 /* Tell the uclass how many GPIOs we have */
327 uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
Simon Glassb4d70702014-02-26 15:59:25 -0700328
Simon Glass95588622020-12-22 19:30:28 -0700329 dev_set_priv(dev,
330 calloc(sizeof(struct gpio_state), uc_priv->gpio_count));
Simon Glassb4d70702014-02-26 15:59:25 -0700331
332 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800333}
Simon Glassb4d70702014-02-26 15:59:25 -0700334
Simon Glassa367f1d2014-10-04 11:29:46 -0600335static int gpio_sandbox_remove(struct udevice *dev)
336{
Simon Glass95588622020-12-22 19:30:28 -0700337 free(dev_get_priv(dev));
Simon Glassa367f1d2014-10-04 11:29:46 -0600338
339 return 0;
340}
341
Simon Glass767827a2014-06-11 23:29:45 -0600342static const struct udevice_id sandbox_gpio_ids[] = {
Simon Glassb4d70702014-02-26 15:59:25 -0700343 { .compatible = "sandbox,gpio" },
344 { }
345};
346
Walter Lozano2901ac62020-06-25 01:10:04 -0300347U_BOOT_DRIVER(sandbox_gpio) = {
348 .name = "sandbox_gpio",
Simon Glassb4d70702014-02-26 15:59:25 -0700349 .id = UCLASS_GPIO,
350 .of_match = sandbox_gpio_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700351 .of_to_plat = sandbox_gpio_of_to_plat,
Simon Glassb4d70702014-02-26 15:59:25 -0700352 .probe = gpio_sandbox_probe,
Simon Glassa367f1d2014-10-04 11:29:46 -0600353 .remove = gpio_sandbox_remove,
Simon Glassb4d70702014-02-26 15:59:25 -0700354 .ops = &gpio_sandbox_ops,
Simon Glass3176b6c2020-07-07 13:11:44 -0600355 ACPI_OPS_PTR(&gpio_sandbox_acpi_ops)
Simon Glassb4d70702014-02-26 15:59:25 -0700356};
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100357
Simon Glassdf65db82020-12-28 20:34:57 -0700358DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
Walter Lozano48e5b042020-06-25 01:10:06 -0300359
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100360/* pincontrol: used only to check GPIO pin configuration (pinmux command) */
361
362struct sb_pinctrl_priv {
363 int pinctrl_ngpios;
364 struct list_head gpio_dev;
365};
366
367struct sb_gpio_bank {
368 struct udevice *gpio_dev;
369 struct list_head list;
370};
371
372static int sb_populate_gpio_dev_list(struct udevice *dev)
373{
374 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
375 struct udevice *gpio_dev;
376 struct udevice *child;
377 struct sb_gpio_bank *gpio_bank;
378 int ret;
379
380 /*
381 * parse pin-controller sub-nodes (ie gpio bank nodes) and fill
382 * a list with all gpio device reference which belongs to the
383 * current pin-controller. This list is used to find pin_name and
384 * pin muxing
385 */
386 list_for_each_entry(child, &dev->child_head, sibling_node) {
387 ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
388 &gpio_dev);
389 if (ret < 0)
390 continue;
391
392 gpio_bank = malloc(sizeof(*gpio_bank));
393 if (!gpio_bank) {
394 dev_err(dev, "Not enough memory\n");
395 return -ENOMEM;
396 }
397
398 gpio_bank->gpio_dev = gpio_dev;
399 list_add_tail(&gpio_bank->list, &priv->gpio_dev);
400 }
401
402 return 0;
403}
404
405static int sb_pinctrl_get_pins_count(struct udevice *dev)
406{
407 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
408 struct gpio_dev_priv *uc_priv;
409 struct sb_gpio_bank *gpio_bank;
410
411 /*
412 * if get_pins_count has already been executed once on this
413 * pin-controller, no need to run it again
414 */
415 if (priv->pinctrl_ngpios)
416 return priv->pinctrl_ngpios;
417
418 if (list_empty(&priv->gpio_dev))
419 sb_populate_gpio_dev_list(dev);
420 /*
421 * walk through all banks to retrieve the pin-controller
422 * pins number
423 */
424 list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
425 uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
426
427 priv->pinctrl_ngpios += uc_priv->gpio_count;
428 }
429
430 return priv->pinctrl_ngpios;
431}
432
433static struct udevice *sb_pinctrl_get_gpio_dev(struct udevice *dev,
434 unsigned int selector,
435 unsigned int *idx)
436{
437 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
438 struct sb_gpio_bank *gpio_bank;
439 struct gpio_dev_priv *uc_priv;
440 int pin_count = 0;
441
442 if (list_empty(&priv->gpio_dev))
443 sb_populate_gpio_dev_list(dev);
444
445 /* look up for the bank which owns the requested pin */
446 list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
447 uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
448
449 if (selector < (pin_count + uc_priv->gpio_count)) {
450 /*
451 * we found the bank, convert pin selector to
452 * gpio bank index
453 */
454 *idx = selector - pin_count;
455
456 return gpio_bank->gpio_dev;
457 }
458 pin_count += uc_priv->gpio_count;
459 }
460
461 return NULL;
462}
463
464static const char *sb_pinctrl_get_pin_name(struct udevice *dev,
465 unsigned int selector)
466{
467 struct gpio_dev_priv *uc_priv;
468 struct udevice *gpio_dev;
469 unsigned int gpio_idx;
470 static char pin_name[PINNAME_SIZE];
471
472 /* look up for the bank which owns the requested pin */
473 gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
474 if (!gpio_dev) {
475 snprintf(pin_name, PINNAME_SIZE, "Error");
476 } else {
477 uc_priv = dev_get_uclass_priv(gpio_dev);
478
479 snprintf(pin_name, PINNAME_SIZE, "%s%d",
480 uc_priv->bank_name,
481 gpio_idx);
482 }
483
484 return pin_name;
485}
486
Simon Glass3f2d5752021-02-04 21:21:59 -0700487static char *get_flags_string(ulong flags)
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100488{
489 if (flags & GPIOD_OPEN_DRAIN)
490 return "drive-open-drain";
491 if (flags & GPIOD_OPEN_SOURCE)
492 return "drive-open-source";
493 if (flags & GPIOD_PULL_UP)
494 return "bias-pull-up";
495 if (flags & GPIOD_PULL_DOWN)
496 return "bias-pull-down";
497 return ".";
498}
499
500static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
501 unsigned int selector,
502 char *buf, int size)
503{
504 struct udevice *gpio_dev;
505 unsigned int gpio_idx;
Simon Glass3f2d5752021-02-04 21:21:59 -0700506 ulong flags;
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100507 int function;
508
509 /* look up for the bank which owns the requested pin */
510 gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
511 if (!gpio_dev) {
512 snprintf(buf, size, "Error");
513 } else {
514 function = sb_gpio_get_function(gpio_dev, gpio_idx);
Simon Glass3f2d5752021-02-04 21:21:59 -0700515 flags = *get_gpio_flags(gpio_dev, gpio_idx);
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100516
517 snprintf(buf, size, "gpio %s %s",
518 function == GPIOF_OUTPUT ? "output" : "input",
Simon Glass3f2d5752021-02-04 21:21:59 -0700519 get_flags_string(flags));
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100520 }
521
522 return 0;
523}
Simon Glass3176b6c2020-07-07 13:11:44 -0600524
525#if CONFIG_IS_ENABLED(ACPIGEN)
526static int sb_pinctrl_get_name(const struct udevice *dev, char *out_name)
527{
528 return acpi_copy_name(out_name, "PINC");
529}
530#endif
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100531
532static int sandbox_pinctrl_probe(struct udevice *dev)
533{
534 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
535
536 INIT_LIST_HEAD(&priv->gpio_dev);
537
538 return 0;
539}
540
541static struct pinctrl_ops sandbox_pinctrl_gpio_ops = {
542 .get_pin_name = sb_pinctrl_get_pin_name,
543 .get_pins_count = sb_pinctrl_get_pins_count,
544 .get_pin_muxing = sb_pinctrl_get_pin_muxing,
545};
Simon Glass3176b6c2020-07-07 13:11:44 -0600546
547#if CONFIG_IS_ENABLED(ACPIGEN)
548struct acpi_ops pinctrl_sandbox_acpi_ops = {
549 .get_name = sb_pinctrl_get_name,
550};
551#endif
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100552
553static const struct udevice_id sandbox_pinctrl_gpio_match[] = {
554 { .compatible = "sandbox,pinctrl-gpio" },
555 { /* sentinel */ }
556};
557
558U_BOOT_DRIVER(sandbox_pinctrl_gpio) = {
559 .name = "sandbox_pinctrl_gpio",
560 .id = UCLASS_PINCTRL,
561 .of_match = sandbox_pinctrl_gpio_match,
562 .ops = &sandbox_pinctrl_gpio_ops,
563 .bind = dm_scan_fdt_dev,
564 .probe = sandbox_pinctrl_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700565 .priv_auto = sizeof(struct sb_pinctrl_priv),
Simon Glass3176b6c2020-07-07 13:11:44 -0600566 ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100567};