blob: 912c333e560c1b85719db0d051e3280c1b588707 [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
117 /*
118 * We don't need to clear GPIOD_EXT_HIGH here to make the tests pass,
119 * but this is handled in a future patch.
120 */
121 if (flags & GPIOD_IS_OUT_ACTIVE)
122 flags |= GPIOD_EXT_HIGH;
123 state->flags = (state->flags & GPIOD_SANDBOX_MASK) | flags;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100124
125 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800126}
127
128/*
129 * These functions implement the public interface within U-Boot
130 */
131
Simon Glassb4d70702014-02-26 15:59:25 -0700132/* set GPIO port 'offset' as an input */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200133static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -0800134{
Simon Glassb4d70702014-02-26 15:59:25 -0700135 debug("%s: offset:%u\n", __func__, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800136
Simon Glassb4d70702014-02-26 15:59:25 -0700137 return sandbox_gpio_set_direction(dev, offset, 0);
Simon Glassb43d0442012-02-15 15:51:13 -0800138}
139
Simon Glassb4d70702014-02-26 15:59:25 -0700140/* set GPIO port 'offset' as an output, with polarity 'value' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200141static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
Simon Glassb4d70702014-02-26 15:59:25 -0700142 int value)
Simon Glassb43d0442012-02-15 15:51:13 -0800143{
Simon Glassae1e85b2021-02-04 21:22:01 -0700144 int ret;
145
Simon Glassb4d70702014-02-26 15:59:25 -0700146 debug("%s: offset:%u, value = %d\n", __func__, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800147
Simon Glassae1e85b2021-02-04 21:22:01 -0700148 ret = sandbox_gpio_set_direction(dev, offset, 1);
149 if (ret)
150 return ret;
151 ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE | GPIOD_EXT_HIGH,
152 value);
153 if (ret)
154 return ret;
155
156 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800157}
158
Simon Glassb4d70702014-02-26 15:59:25 -0700159/* read GPIO IN value of port 'offset' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200160static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -0800161{
Simon Glassb4d70702014-02-26 15:59:25 -0700162 debug("%s: offset:%u\n", __func__, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800163
Simon Glassb4d70702014-02-26 15:59:25 -0700164 return sandbox_gpio_get_value(dev, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800165}
166
Simon Glassb4d70702014-02-26 15:59:25 -0700167/* write GPIO OUT value to port 'offset' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200168static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
Simon Glassb43d0442012-02-15 15:51:13 -0800169{
Simon Glassae1e85b2021-02-04 21:22:01 -0700170 int ret;
171
Simon Glassb4d70702014-02-26 15:59:25 -0700172 debug("%s: offset:%u, value = %d\n", __func__, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800173
Simon Glassb4d70702014-02-26 15:59:25 -0700174 if (!sandbox_gpio_get_direction(dev, offset)) {
175 printf("sandbox_gpio: error: set_value on input gpio %u\n",
176 offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800177 return -1;
178 }
179
Simon Glassae1e85b2021-02-04 21:22:01 -0700180 ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE | GPIOD_EXT_HIGH,
181 value);
182 if (ret)
183 return ret;
184
185 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800186}
187
Simon Glass32048632014-10-04 11:29:45 -0600188static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
189{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100190 if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
Simon Glass32048632014-10-04 11:29:45 -0600191 return GPIOF_OUTPUT;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100192 if (get_gpio_flag(dev, offset, GPIOD_IS_IN))
193 return GPIOF_INPUT;
194
195 return GPIOF_INPUT; /*GPIO is not configurated */
Simon Glass32048632014-10-04 11:29:45 -0600196}
197
Simon Glass16e10402015-01-05 20:05:29 -0700198static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
Simon Glass12faa022017-05-18 20:09:18 -0600199 struct ofnode_phandle_args *args)
Simon Glass16e10402015-01-05 20:05:29 -0700200{
201 desc->offset = args->args[0];
202 if (args->args_count < 2)
203 return 0;
Patrick Delaunay23aee612020-01-13 11:35:13 +0100204 /* treat generic binding with gpio uclass */
205 gpio_xlate_offs_flags(dev, desc, args);
206
207 /* sandbox test specific, not defined in gpio.h */
208 if (args->args[1] & GPIO_IN)
Simon Glass16e10402015-01-05 20:05:29 -0700209 desc->flags |= GPIOD_IS_IN;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100210
Patrick Delaunay23aee612020-01-13 11:35:13 +0100211 if (args->args[1] & GPIO_OUT)
Simon Glass16e10402015-01-05 20:05:29 -0700212 desc->flags |= GPIOD_IS_OUT;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100213
Patrick Delaunay23aee612020-01-13 11:35:13 +0100214 if (args->args[1] & GPIO_OUT_ACTIVE)
Simon Glass16e10402015-01-05 20:05:29 -0700215 desc->flags |= GPIOD_IS_OUT_ACTIVE;
216
217 return 0;
218}
219
Simon Glass54befdd2021-02-04 21:21:55 -0700220static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset,
221 ulong flags)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100222{
Simon Glass3f2d5752021-02-04 21:21:59 -0700223 debug("%s: offset:%u, flags = %lx\n", __func__, offset, flags);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100224
Simon Glass44a1a5b2021-02-04 21:22:00 -0700225 return sandbox_gpio_set_flags(dev, offset, flags);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100226}
227
Simon Glass3f2d5752021-02-04 21:21:59 -0700228static int sb_gpio_get_flags(struct udevice *dev, uint offset, ulong *flagsp)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100229{
230 debug("%s: offset:%u\n", __func__, offset);
Simon Glass3f2d5752021-02-04 21:21:59 -0700231 *flagsp = *get_gpio_flags(dev, offset);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100232
233 return 0;
234}
235
Simon Glass3176b6c2020-07-07 13:11:44 -0600236#if CONFIG_IS_ENABLED(ACPIGEN)
237static int sb_gpio_get_acpi(const struct gpio_desc *desc,
238 struct acpi_gpio *gpio)
239{
240 int ret;
241
242 /* Note that gpio_get_acpi() zeroes *gpio before calling here */
243 gpio->pin_count = 1;
244 gpio->pins[0] = desc->offset;
245 ret = acpi_device_scope(desc->dev, gpio->resource,
246 sizeof(gpio->resource));
247 if (ret)
248 return log_ret(ret);
249
250 /* All of these values are just used for testing */
251 if (desc->flags & GPIOD_ACTIVE_LOW) {
252 gpio->pin0_addr = 0x80012 + desc->offset;
253 gpio->type = ACPI_GPIO_TYPE_INTERRUPT;
254 gpio->pull = ACPI_GPIO_PULL_DOWN;
255 gpio->interrupt_debounce_timeout = 4321;
256
257 /* We use the GpioInt part */
258 gpio->irq.pin = desc->offset;
259 gpio->irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
260 gpio->irq.shared = ACPI_IRQ_SHARED;
261 gpio->irq.wake = ACPI_IRQ_WAKE;
262
263 /* The GpioIo part is only used for testing */
264 gpio->polarity = ACPI_GPIO_ACTIVE_LOW;
265 } else {
266 gpio->pin0_addr = 0xc00dc + desc->offset;
267 gpio->type = ACPI_GPIO_TYPE_IO;
268 gpio->pull = ACPI_GPIO_PULL_UP;
269 gpio->interrupt_debounce_timeout = 0;
270
271 /* The GpioInt part is not used */
272
273 /* We use the GpioIo part */
274 gpio->output_drive_strength = 1234;
275 gpio->io_shared = true;
276 gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_INPUT;
277 gpio->polarity = 0;
278 }
279
280 return 0;
281}
282
283static int sb_gpio_get_name(const struct udevice *dev, char *out_name)
284{
285 return acpi_copy_name(out_name, "GPIO");
286}
287
288struct acpi_ops gpio_sandbox_acpi_ops = {
289 .get_name = sb_gpio_get_name,
290};
291#endif /* ACPIGEN */
292
Simon Glassb4d70702014-02-26 15:59:25 -0700293static const struct dm_gpio_ops gpio_sandbox_ops = {
Simon Glassb4d70702014-02-26 15:59:25 -0700294 .direction_input = sb_gpio_direction_input,
295 .direction_output = sb_gpio_direction_output,
296 .get_value = sb_gpio_get_value,
297 .set_value = sb_gpio_set_value,
Simon Glass32048632014-10-04 11:29:45 -0600298 .get_function = sb_gpio_get_function,
Simon Glass16e10402015-01-05 20:05:29 -0700299 .xlate = sb_gpio_xlate,
Simon Glass54befdd2021-02-04 21:21:55 -0700300 .set_flags = sb_gpio_set_flags,
Simon Glassd063ce92021-02-04 21:21:56 -0700301 .get_flags = sb_gpio_get_flags,
Simon Glass3176b6c2020-07-07 13:11:44 -0600302#if CONFIG_IS_ENABLED(ACPIGEN)
303 .get_acpi = sb_gpio_get_acpi,
304#endif
Simon Glassb4d70702014-02-26 15:59:25 -0700305};
306
Simon Glassaad29ae2020-12-03 16:55:21 -0700307static int sandbox_gpio_of_to_plat(struct udevice *dev)
Simon Glassb43d0442012-02-15 15:51:13 -0800308{
Simon Glassde0977b2015-03-05 12:25:20 -0700309 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb43d0442012-02-15 15:51:13 -0800310
Simon Glass9e7ab232018-02-03 10:36:59 -0700311 uc_priv->gpio_count = dev_read_u32_default(dev, "sandbox,gpio-count",
312 0);
Simon Glass1185fcb2017-05-18 20:09:20 -0600313 uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
Simon Glassb43d0442012-02-15 15:51:13 -0800314
Simon Glassb4d70702014-02-26 15:59:25 -0700315 return 0;
316}
Simon Glassb43d0442012-02-15 15:51:13 -0800317
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200318static int gpio_sandbox_probe(struct udevice *dev)
Simon Glassb4d70702014-02-26 15:59:25 -0700319{
Simon Glassde0977b2015-03-05 12:25:20 -0700320 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb4d70702014-02-26 15:59:25 -0700321
Simon Glassf1d50f72020-12-19 10:40:13 -0700322 if (!dev_has_ofnode(dev))
Simon Glassb4d70702014-02-26 15:59:25 -0700323 /* Tell the uclass how many GPIOs we have */
324 uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
Simon Glassb4d70702014-02-26 15:59:25 -0700325
Simon Glass95588622020-12-22 19:30:28 -0700326 dev_set_priv(dev,
327 calloc(sizeof(struct gpio_state), uc_priv->gpio_count));
Simon Glassb4d70702014-02-26 15:59:25 -0700328
329 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800330}
Simon Glassb4d70702014-02-26 15:59:25 -0700331
Simon Glassa367f1d2014-10-04 11:29:46 -0600332static int gpio_sandbox_remove(struct udevice *dev)
333{
Simon Glass95588622020-12-22 19:30:28 -0700334 free(dev_get_priv(dev));
Simon Glassa367f1d2014-10-04 11:29:46 -0600335
336 return 0;
337}
338
Simon Glass767827a2014-06-11 23:29:45 -0600339static const struct udevice_id sandbox_gpio_ids[] = {
Simon Glassb4d70702014-02-26 15:59:25 -0700340 { .compatible = "sandbox,gpio" },
341 { }
342};
343
Walter Lozano2901ac62020-06-25 01:10:04 -0300344U_BOOT_DRIVER(sandbox_gpio) = {
345 .name = "sandbox_gpio",
Simon Glassb4d70702014-02-26 15:59:25 -0700346 .id = UCLASS_GPIO,
347 .of_match = sandbox_gpio_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700348 .of_to_plat = sandbox_gpio_of_to_plat,
Simon Glassb4d70702014-02-26 15:59:25 -0700349 .probe = gpio_sandbox_probe,
Simon Glassa367f1d2014-10-04 11:29:46 -0600350 .remove = gpio_sandbox_remove,
Simon Glassb4d70702014-02-26 15:59:25 -0700351 .ops = &gpio_sandbox_ops,
Simon Glass3176b6c2020-07-07 13:11:44 -0600352 ACPI_OPS_PTR(&gpio_sandbox_acpi_ops)
Simon Glassb4d70702014-02-26 15:59:25 -0700353};
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100354
Simon Glassdf65db82020-12-28 20:34:57 -0700355DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
Walter Lozano48e5b042020-06-25 01:10:06 -0300356
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100357/* pincontrol: used only to check GPIO pin configuration (pinmux command) */
358
359struct sb_pinctrl_priv {
360 int pinctrl_ngpios;
361 struct list_head gpio_dev;
362};
363
364struct sb_gpio_bank {
365 struct udevice *gpio_dev;
366 struct list_head list;
367};
368
369static int sb_populate_gpio_dev_list(struct udevice *dev)
370{
371 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
372 struct udevice *gpio_dev;
373 struct udevice *child;
374 struct sb_gpio_bank *gpio_bank;
375 int ret;
376
377 /*
378 * parse pin-controller sub-nodes (ie gpio bank nodes) and fill
379 * a list with all gpio device reference which belongs to the
380 * current pin-controller. This list is used to find pin_name and
381 * pin muxing
382 */
383 list_for_each_entry(child, &dev->child_head, sibling_node) {
384 ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
385 &gpio_dev);
386 if (ret < 0)
387 continue;
388
389 gpio_bank = malloc(sizeof(*gpio_bank));
390 if (!gpio_bank) {
391 dev_err(dev, "Not enough memory\n");
392 return -ENOMEM;
393 }
394
395 gpio_bank->gpio_dev = gpio_dev;
396 list_add_tail(&gpio_bank->list, &priv->gpio_dev);
397 }
398
399 return 0;
400}
401
402static int sb_pinctrl_get_pins_count(struct udevice *dev)
403{
404 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
405 struct gpio_dev_priv *uc_priv;
406 struct sb_gpio_bank *gpio_bank;
407
408 /*
409 * if get_pins_count has already been executed once on this
410 * pin-controller, no need to run it again
411 */
412 if (priv->pinctrl_ngpios)
413 return priv->pinctrl_ngpios;
414
415 if (list_empty(&priv->gpio_dev))
416 sb_populate_gpio_dev_list(dev);
417 /*
418 * walk through all banks to retrieve the pin-controller
419 * pins number
420 */
421 list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
422 uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
423
424 priv->pinctrl_ngpios += uc_priv->gpio_count;
425 }
426
427 return priv->pinctrl_ngpios;
428}
429
430static struct udevice *sb_pinctrl_get_gpio_dev(struct udevice *dev,
431 unsigned int selector,
432 unsigned int *idx)
433{
434 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
435 struct sb_gpio_bank *gpio_bank;
436 struct gpio_dev_priv *uc_priv;
437 int pin_count = 0;
438
439 if (list_empty(&priv->gpio_dev))
440 sb_populate_gpio_dev_list(dev);
441
442 /* look up for the bank which owns the requested pin */
443 list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
444 uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
445
446 if (selector < (pin_count + uc_priv->gpio_count)) {
447 /*
448 * we found the bank, convert pin selector to
449 * gpio bank index
450 */
451 *idx = selector - pin_count;
452
453 return gpio_bank->gpio_dev;
454 }
455 pin_count += uc_priv->gpio_count;
456 }
457
458 return NULL;
459}
460
461static const char *sb_pinctrl_get_pin_name(struct udevice *dev,
462 unsigned int selector)
463{
464 struct gpio_dev_priv *uc_priv;
465 struct udevice *gpio_dev;
466 unsigned int gpio_idx;
467 static char pin_name[PINNAME_SIZE];
468
469 /* look up for the bank which owns the requested pin */
470 gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
471 if (!gpio_dev) {
472 snprintf(pin_name, PINNAME_SIZE, "Error");
473 } else {
474 uc_priv = dev_get_uclass_priv(gpio_dev);
475
476 snprintf(pin_name, PINNAME_SIZE, "%s%d",
477 uc_priv->bank_name,
478 gpio_idx);
479 }
480
481 return pin_name;
482}
483
Simon Glass3f2d5752021-02-04 21:21:59 -0700484static char *get_flags_string(ulong flags)
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100485{
486 if (flags & GPIOD_OPEN_DRAIN)
487 return "drive-open-drain";
488 if (flags & GPIOD_OPEN_SOURCE)
489 return "drive-open-source";
490 if (flags & GPIOD_PULL_UP)
491 return "bias-pull-up";
492 if (flags & GPIOD_PULL_DOWN)
493 return "bias-pull-down";
494 return ".";
495}
496
497static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
498 unsigned int selector,
499 char *buf, int size)
500{
501 struct udevice *gpio_dev;
502 unsigned int gpio_idx;
Simon Glass3f2d5752021-02-04 21:21:59 -0700503 ulong flags;
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100504 int function;
505
506 /* look up for the bank which owns the requested pin */
507 gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
508 if (!gpio_dev) {
509 snprintf(buf, size, "Error");
510 } else {
511 function = sb_gpio_get_function(gpio_dev, gpio_idx);
Simon Glass3f2d5752021-02-04 21:21:59 -0700512 flags = *get_gpio_flags(gpio_dev, gpio_idx);
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100513
514 snprintf(buf, size, "gpio %s %s",
515 function == GPIOF_OUTPUT ? "output" : "input",
Simon Glass3f2d5752021-02-04 21:21:59 -0700516 get_flags_string(flags));
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100517 }
518
519 return 0;
520}
Simon Glass3176b6c2020-07-07 13:11:44 -0600521
522#if CONFIG_IS_ENABLED(ACPIGEN)
523static int sb_pinctrl_get_name(const struct udevice *dev, char *out_name)
524{
525 return acpi_copy_name(out_name, "PINC");
526}
527#endif
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100528
529static int sandbox_pinctrl_probe(struct udevice *dev)
530{
531 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
532
533 INIT_LIST_HEAD(&priv->gpio_dev);
534
535 return 0;
536}
537
538static struct pinctrl_ops sandbox_pinctrl_gpio_ops = {
539 .get_pin_name = sb_pinctrl_get_pin_name,
540 .get_pins_count = sb_pinctrl_get_pins_count,
541 .get_pin_muxing = sb_pinctrl_get_pin_muxing,
542};
Simon Glass3176b6c2020-07-07 13:11:44 -0600543
544#if CONFIG_IS_ENABLED(ACPIGEN)
545struct acpi_ops pinctrl_sandbox_acpi_ops = {
546 .get_name = sb_pinctrl_get_name,
547};
548#endif
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100549
550static const struct udevice_id sandbox_pinctrl_gpio_match[] = {
551 { .compatible = "sandbox,pinctrl-gpio" },
552 { /* sentinel */ }
553};
554
555U_BOOT_DRIVER(sandbox_pinctrl_gpio) = {
556 .name = "sandbox_pinctrl_gpio",
557 .id = UCLASS_PINCTRL,
558 .of_match = sandbox_pinctrl_gpio_match,
559 .ops = &sandbox_pinctrl_gpio_ops,
560 .bind = dm_scan_fdt_dev,
561 .probe = sandbox_pinctrl_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700562 .priv_auto = sizeof(struct sb_pinctrl_priv),
Simon Glass3176b6c2020-07-07 13:11:44 -0600563 ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100564};