blob: f5be278144387e54ad7badce83ece64588a9ae18 [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
Simon Glassb4d70702014-02-26 15:59:25 -07006#include <dm.h>
7#include <fdtdec.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Simon Glassb4d70702014-02-26 15:59:25 -07009#include <malloc.h>
Simon Glass3176b6c2020-07-07 13:11:44 -060010#include <acpi/acpi_device.h>
Simon Glassb43d0442012-02-15 15:51:13 -080011#include <asm/gpio.h>
Simon Glass3176b6c2020-07-07 13:11:44 -060012#include <dm/acpi.h>
Simon Glass95588622020-12-22 19:30:28 -070013#include <dm/device-internal.h>
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +010014#include <dm/device_compat.h>
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010015#include <dm/lists.h>
Simon Glass12faa022017-05-18 20:09:18 -060016#include <dm/of.h>
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010017#include <dm/pinctrl.h>
Simon Glass16e10402015-01-05 20:05:29 -070018#include <dt-bindings/gpio/gpio.h>
Patrick Delaunay23aee612020-01-13 11:35:13 +010019#include <dt-bindings/gpio/sandbox-gpio.h>
Simon Glassb43d0442012-02-15 15:51:13 -080020
Simon Glassb43d0442012-02-15 15:51:13 -080021struct gpio_state {
22 const char *label; /* label given by requester */
Simon Glass3f2d5752021-02-04 21:21:59 -070023 ulong flags; /* flags (GPIOD_...) */
Simon Glassb43d0442012-02-15 15:51:13 -080024};
25
Simon Glass3f2d5752021-02-04 21:21:59 -070026/* Access routines for GPIO info */
27static struct gpio_state *get_gpio_state(struct udevice *dev, uint offset)
Simon Glassb43d0442012-02-15 15:51:13 -080028{
Simon Glassde0977b2015-03-05 12:25:20 -070029 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb4d70702014-02-26 15:59:25 -070030 struct gpio_state *state = dev_get_priv(dev);
31
32 if (offset >= uc_priv->gpio_count) {
Simon Glassb4d70702014-02-26 15:59:25 -070033 printf("sandbox_gpio: error: invalid gpio %u\n", offset);
Simon Glass3f2d5752021-02-04 21:21:59 -070034 return NULL;
Simon Glassb43d0442012-02-15 15:51:13 -080035 }
36
Simon Glass3f2d5752021-02-04 21:21:59 -070037 return &state[offset];
38}
39
40/* Access routines for GPIO flags */
41static ulong *get_gpio_flags(struct udevice *dev, unsigned int offset)
42{
43 struct gpio_state *state = get_gpio_state(dev, offset);
44
45 if (!state)
46 return NULL;
47
48 return &state->flags;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010049
Simon Glassb43d0442012-02-15 15:51:13 -080050}
51
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010052static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
Simon Glassb43d0442012-02-15 15:51:13 -080053{
Simon Glass3f2d5752021-02-04 21:21:59 -070054 return (*get_gpio_flags(dev, offset) & flag) != 0;
Simon Glassb43d0442012-02-15 15:51:13 -080055}
56
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010057static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
Simon Glassb4d70702014-02-26 15:59:25 -070058 int value)
Simon Glassb43d0442012-02-15 15:51:13 -080059{
Simon Glass44a1a5b2021-02-04 21:22:00 -070060 struct gpio_state *state = get_gpio_state(dev, offset);
Simon Glassb43d0442012-02-15 15:51:13 -080061
62 if (value)
Simon Glass44a1a5b2021-02-04 21:22:00 -070063 state->flags |= flag;
Simon Glassb43d0442012-02-15 15:51:13 -080064 else
Simon Glass44a1a5b2021-02-04 21:22:00 -070065 state->flags &= ~flag;
Simon Glassb43d0442012-02-15 15:51:13 -080066
67 return 0;
68}
69
Simon Glassb43d0442012-02-15 15:51:13 -080070/*
71 * Back-channel sandbox-internal-only access to GPIO state
72 */
73
Heiko Schocherb74fcb42014-05-22 12:43:05 +020074int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -080075{
Simon Glass44a1a5b2021-02-04 21:22:00 -070076 struct gpio_state *state = get_gpio_state(dev, offset);
Simon Glass59356522021-02-04 21:22:07 -070077 bool val;
Simon Glass44a1a5b2021-02-04 21:22:00 -070078
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010079 if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
Simon Glassb4d70702014-02-26 15:59:25 -070080 debug("sandbox_gpio: get_value on output gpio %u\n", offset);
Simon Glass44a1a5b2021-02-04 21:22:00 -070081
Simon Glass247ccf22021-02-04 21:22:09 -070082 if (state->flags & GPIOD_EXT_DRIVEN) {
Simon Glass59356522021-02-04 21:22:07 -070083 val = state->flags & GPIOD_EXT_HIGH;
Simon Glass247ccf22021-02-04 21:22:09 -070084 } else {
85 if (state->flags & GPIOD_EXT_PULL_UP)
86 val = true;
87 else if (state->flags & GPIOD_EXT_PULL_DOWN)
88 val = false;
89 else
90 val = state->flags & GPIOD_PULL_UP;
91 }
Simon Glass59356522021-02-04 21:22:07 -070092
93 return val;
Simon Glassb43d0442012-02-15 15:51:13 -080094}
95
Heiko Schocherb74fcb42014-05-22 12:43:05 +020096int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
Simon Glassb43d0442012-02-15 15:51:13 -080097{
Simon Glass59356522021-02-04 21:22:07 -070098 set_gpio_flag(dev, offset, GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
Simon Glass44a1a5b2021-02-04 21:22:00 -070099
100 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800101}
102
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200103int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -0800104{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100105 return get_gpio_flag(dev, offset, GPIOD_IS_OUT);
Simon Glassb43d0442012-02-15 15:51:13 -0800106}
107
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200108int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
Simon Glassb43d0442012-02-15 15:51:13 -0800109{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100110 set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
Simon Glass44a1a5b2021-02-04 21:22:00 -0700111 set_gpio_flag(dev, offset, GPIOD_IS_IN, !output);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100112
113 return 0;
114}
115
Simon Glass3f2d5752021-02-04 21:21:59 -0700116ulong sandbox_gpio_get_flags(struct udevice *dev, uint offset)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100117{
Simon Glass44a1a5b2021-02-04 21:22:00 -0700118 ulong flags = *get_gpio_flags(dev, offset);
119
120 return flags & ~GPIOD_SANDBOX_MASK;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100121}
122
Simon Glass3f2d5752021-02-04 21:21:59 -0700123int sandbox_gpio_set_flags(struct udevice *dev, uint offset, ulong flags)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100124{
Simon Glass44a1a5b2021-02-04 21:22:00 -0700125 struct gpio_state *state = get_gpio_state(dev, offset);
126
Simon Glass4d3b73e2021-02-04 21:22:02 -0700127 state->flags = flags;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100128
129 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800130}
131
132/*
133 * These functions implement the public interface within U-Boot
134 */
135
Simon Glassb4d70702014-02-26 15:59:25 -0700136/* set GPIO port 'offset' as an input */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200137static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -0800138{
Simon Glassb4d70702014-02-26 15:59:25 -0700139 debug("%s: offset:%u\n", __func__, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800140
Simon Glassb4d70702014-02-26 15:59:25 -0700141 return sandbox_gpio_set_direction(dev, offset, 0);
Simon Glassb43d0442012-02-15 15:51:13 -0800142}
143
Simon Glassb4d70702014-02-26 15:59:25 -0700144/* set GPIO port 'offset' as an output, with polarity 'value' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200145static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
Simon Glassb4d70702014-02-26 15:59:25 -0700146 int value)
Simon Glassb43d0442012-02-15 15:51:13 -0800147{
Simon Glassae1e85b2021-02-04 21:22:01 -0700148 int ret;
149
Simon Glassb4d70702014-02-26 15:59:25 -0700150 debug("%s: offset:%u, value = %d\n", __func__, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800151
Simon Glassae1e85b2021-02-04 21:22:01 -0700152 ret = sandbox_gpio_set_direction(dev, offset, 1);
153 if (ret)
154 return ret;
Simon Glass59356522021-02-04 21:22:07 -0700155 ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
156 GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
Simon Glassae1e85b2021-02-04 21:22:01 -0700157 if (ret)
158 return ret;
159
160 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800161}
162
Simon Glassb4d70702014-02-26 15:59:25 -0700163/* read GPIO IN value of port 'offset' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200164static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -0800165{
Simon Glassb4d70702014-02-26 15:59:25 -0700166 debug("%s: offset:%u\n", __func__, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800167
Simon Glassb4d70702014-02-26 15:59:25 -0700168 return sandbox_gpio_get_value(dev, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800169}
170
Simon Glassb4d70702014-02-26 15:59:25 -0700171/* write GPIO OUT value to port 'offset' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200172static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
Simon Glassb43d0442012-02-15 15:51:13 -0800173{
Simon Glassae1e85b2021-02-04 21:22:01 -0700174 int ret;
175
Simon Glassb4d70702014-02-26 15:59:25 -0700176 debug("%s: offset:%u, value = %d\n", __func__, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800177
Simon Glassb4d70702014-02-26 15:59:25 -0700178 if (!sandbox_gpio_get_direction(dev, offset)) {
179 printf("sandbox_gpio: error: set_value on input gpio %u\n",
180 offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800181 return -1;
182 }
183
Simon Glass59356522021-02-04 21:22:07 -0700184 ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
185 GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
Simon Glassae1e85b2021-02-04 21:22:01 -0700186 if (ret)
187 return ret;
188
189 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800190}
191
Simon Glass32048632014-10-04 11:29:45 -0600192static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
193{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100194 if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
Simon Glass32048632014-10-04 11:29:45 -0600195 return GPIOF_OUTPUT;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100196 if (get_gpio_flag(dev, offset, GPIOD_IS_IN))
197 return GPIOF_INPUT;
Patrice Chotardf69c39d2022-08-30 14:09:14 +0200198 if (get_gpio_flag(dev, offset, GPIOD_IS_AF))
199 return GPIOF_FUNC;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100200
201 return GPIOF_INPUT; /*GPIO is not configurated */
Simon Glass32048632014-10-04 11:29:45 -0600202}
203
Simon Glass16e10402015-01-05 20:05:29 -0700204static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
Simon Glass12faa022017-05-18 20:09:18 -0600205 struct ofnode_phandle_args *args)
Simon Glass16e10402015-01-05 20:05:29 -0700206{
207 desc->offset = args->args[0];
208 if (args->args_count < 2)
209 return 0;
Patrick Delaunay23aee612020-01-13 11:35:13 +0100210 /* treat generic binding with gpio uclass */
211 gpio_xlate_offs_flags(dev, desc, args);
212
213 /* sandbox test specific, not defined in gpio.h */
214 if (args->args[1] & GPIO_IN)
Simon Glass16e10402015-01-05 20:05:29 -0700215 desc->flags |= GPIOD_IS_IN;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100216
Patrick Delaunay23aee612020-01-13 11:35:13 +0100217 if (args->args[1] & GPIO_OUT)
Simon Glass16e10402015-01-05 20:05:29 -0700218 desc->flags |= GPIOD_IS_OUT;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100219
Patrick Delaunay23aee612020-01-13 11:35:13 +0100220 if (args->args[1] & GPIO_OUT_ACTIVE)
Simon Glass16e10402015-01-05 20:05:29 -0700221 desc->flags |= GPIOD_IS_OUT_ACTIVE;
222
Patrice Chotardf69c39d2022-08-30 14:09:14 +0200223 if (args->args[1] & GPIO_AF)
224 desc->flags |= GPIOD_IS_AF;
225
Simon Glass16e10402015-01-05 20:05:29 -0700226 return 0;
227}
228
Simon Glass54befdd2021-02-04 21:21:55 -0700229static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset,
230 ulong flags)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100231{
Simon Glass3f2d5752021-02-04 21:21:59 -0700232 debug("%s: offset:%u, flags = %lx\n", __func__, offset, flags);
Simon Glass4d3b73e2021-02-04 21:22:02 -0700233 struct gpio_state *state = get_gpio_state(dev, offset);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100234
Simon Glass4d3b73e2021-02-04 21:22:02 -0700235 if (flags & GPIOD_IS_OUT) {
Simon Glass59356522021-02-04 21:22:07 -0700236 flags |= GPIOD_EXT_DRIVEN;
Simon Glass4d3b73e2021-02-04 21:22:02 -0700237 if (flags & GPIOD_IS_OUT_ACTIVE)
238 flags |= GPIOD_EXT_HIGH;
239 else
240 flags &= ~GPIOD_EXT_HIGH;
Simon Glass59356522021-02-04 21:22:07 -0700241 } else {
242 flags |= state->flags & GPIOD_SANDBOX_MASK;
Simon Glass4d3b73e2021-02-04 21:22:02 -0700243 }
244 state->flags = flags;
245
246 return 0;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100247}
248
Simon Glass3f2d5752021-02-04 21:21:59 -0700249static int sb_gpio_get_flags(struct udevice *dev, uint offset, ulong *flagsp)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100250{
251 debug("%s: offset:%u\n", __func__, offset);
Simon Glass4d3b73e2021-02-04 21:22:02 -0700252 *flagsp = *get_gpio_flags(dev, offset) & ~GPIOD_SANDBOX_MASK;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100253
254 return 0;
255}
256
Simon Glass3176b6c2020-07-07 13:11:44 -0600257#if CONFIG_IS_ENABLED(ACPIGEN)
258static int sb_gpio_get_acpi(const struct gpio_desc *desc,
259 struct acpi_gpio *gpio)
260{
261 int ret;
262
263 /* Note that gpio_get_acpi() zeroes *gpio before calling here */
264 gpio->pin_count = 1;
265 gpio->pins[0] = desc->offset;
266 ret = acpi_device_scope(desc->dev, gpio->resource,
267 sizeof(gpio->resource));
268 if (ret)
269 return log_ret(ret);
270
271 /* All of these values are just used for testing */
272 if (desc->flags & GPIOD_ACTIVE_LOW) {
273 gpio->pin0_addr = 0x80012 + desc->offset;
274 gpio->type = ACPI_GPIO_TYPE_INTERRUPT;
275 gpio->pull = ACPI_GPIO_PULL_DOWN;
276 gpio->interrupt_debounce_timeout = 4321;
277
278 /* We use the GpioInt part */
279 gpio->irq.pin = desc->offset;
280 gpio->irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
281 gpio->irq.shared = ACPI_IRQ_SHARED;
282 gpio->irq.wake = ACPI_IRQ_WAKE;
283
284 /* The GpioIo part is only used for testing */
285 gpio->polarity = ACPI_GPIO_ACTIVE_LOW;
286 } else {
287 gpio->pin0_addr = 0xc00dc + desc->offset;
288 gpio->type = ACPI_GPIO_TYPE_IO;
289 gpio->pull = ACPI_GPIO_PULL_UP;
290 gpio->interrupt_debounce_timeout = 0;
291
292 /* The GpioInt part is not used */
293
294 /* We use the GpioIo part */
295 gpio->output_drive_strength = 1234;
296 gpio->io_shared = true;
297 gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_INPUT;
298 gpio->polarity = 0;
299 }
300
301 return 0;
302}
303
304static int sb_gpio_get_name(const struct udevice *dev, char *out_name)
305{
306 return acpi_copy_name(out_name, "GPIO");
307}
308
309struct acpi_ops gpio_sandbox_acpi_ops = {
310 .get_name = sb_gpio_get_name,
311};
312#endif /* ACPIGEN */
313
Simon Glassb4d70702014-02-26 15:59:25 -0700314static const struct dm_gpio_ops gpio_sandbox_ops = {
Simon Glassb4d70702014-02-26 15:59:25 -0700315 .direction_input = sb_gpio_direction_input,
316 .direction_output = sb_gpio_direction_output,
317 .get_value = sb_gpio_get_value,
318 .set_value = sb_gpio_set_value,
Simon Glass32048632014-10-04 11:29:45 -0600319 .get_function = sb_gpio_get_function,
Simon Glass16e10402015-01-05 20:05:29 -0700320 .xlate = sb_gpio_xlate,
Simon Glass54befdd2021-02-04 21:21:55 -0700321 .set_flags = sb_gpio_set_flags,
Simon Glassd063ce92021-02-04 21:21:56 -0700322 .get_flags = sb_gpio_get_flags,
Simon Glass3176b6c2020-07-07 13:11:44 -0600323#if CONFIG_IS_ENABLED(ACPIGEN)
324 .get_acpi = sb_gpio_get_acpi,
325#endif
Simon Glassb4d70702014-02-26 15:59:25 -0700326};
327
Simon Glassaad29ae2020-12-03 16:55:21 -0700328static int sandbox_gpio_of_to_plat(struct udevice *dev)
Simon Glassb43d0442012-02-15 15:51:13 -0800329{
Simon Glass2149e112021-08-07 07:24:12 -0600330 if (CONFIG_IS_ENABLED(OF_REAL)) {
331 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb43d0442012-02-15 15:51:13 -0800332
Simon Glass2149e112021-08-07 07:24:12 -0600333 uc_priv->gpio_count =
334 dev_read_u32_default(dev, "sandbox,gpio-count", 0);
335 uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
336 }
Simon Glassb43d0442012-02-15 15:51:13 -0800337
Simon Glassb4d70702014-02-26 15:59:25 -0700338 return 0;
339}
Simon Glassb43d0442012-02-15 15:51:13 -0800340
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200341static int gpio_sandbox_probe(struct udevice *dev)
Simon Glassb4d70702014-02-26 15:59:25 -0700342{
Simon Glassde0977b2015-03-05 12:25:20 -0700343 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb4d70702014-02-26 15:59:25 -0700344
Simon Glassf1d50f72020-12-19 10:40:13 -0700345 if (!dev_has_ofnode(dev))
Simon Glassb4d70702014-02-26 15:59:25 -0700346 /* Tell the uclass how many GPIOs we have */
347 uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
Simon Glassb4d70702014-02-26 15:59:25 -0700348
Simon Glass95588622020-12-22 19:30:28 -0700349 dev_set_priv(dev,
350 calloc(sizeof(struct gpio_state), uc_priv->gpio_count));
Simon Glassb4d70702014-02-26 15:59:25 -0700351
352 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800353}
Simon Glassb4d70702014-02-26 15:59:25 -0700354
Simon Glassa367f1d2014-10-04 11:29:46 -0600355static int gpio_sandbox_remove(struct udevice *dev)
356{
Simon Glass95588622020-12-22 19:30:28 -0700357 free(dev_get_priv(dev));
Simon Glassa367f1d2014-10-04 11:29:46 -0600358
359 return 0;
360}
361
Simon Glass767827a2014-06-11 23:29:45 -0600362static const struct udevice_id sandbox_gpio_ids[] = {
Simon Glassb4d70702014-02-26 15:59:25 -0700363 { .compatible = "sandbox,gpio" },
364 { }
365};
366
Walter Lozano2901ac62020-06-25 01:10:04 -0300367U_BOOT_DRIVER(sandbox_gpio) = {
368 .name = "sandbox_gpio",
Simon Glassb4d70702014-02-26 15:59:25 -0700369 .id = UCLASS_GPIO,
370 .of_match = sandbox_gpio_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700371 .of_to_plat = sandbox_gpio_of_to_plat,
Simon Glassb4d70702014-02-26 15:59:25 -0700372 .probe = gpio_sandbox_probe,
Simon Glassa367f1d2014-10-04 11:29:46 -0600373 .remove = gpio_sandbox_remove,
Simon Glassb4d70702014-02-26 15:59:25 -0700374 .ops = &gpio_sandbox_ops,
Simon Glass3176b6c2020-07-07 13:11:44 -0600375 ACPI_OPS_PTR(&gpio_sandbox_acpi_ops)
Simon Glassb4d70702014-02-26 15:59:25 -0700376};
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100377
Simon Glassdf65db82020-12-28 20:34:57 -0700378DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
Walter Lozano48e5b042020-06-25 01:10:06 -0300379
Simon Glass2149e112021-08-07 07:24:12 -0600380#if CONFIG_IS_ENABLED(PINCTRL)
381
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100382/* pincontrol: used only to check GPIO pin configuration (pinmux command) */
383
384struct sb_pinctrl_priv {
385 int pinctrl_ngpios;
386 struct list_head gpio_dev;
387};
388
389struct sb_gpio_bank {
390 struct udevice *gpio_dev;
391 struct list_head list;
392};
393
394static int sb_populate_gpio_dev_list(struct udevice *dev)
395{
396 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
397 struct udevice *gpio_dev;
398 struct udevice *child;
399 struct sb_gpio_bank *gpio_bank;
400 int ret;
401
402 /*
403 * parse pin-controller sub-nodes (ie gpio bank nodes) and fill
404 * a list with all gpio device reference which belongs to the
405 * current pin-controller. This list is used to find pin_name and
406 * pin muxing
407 */
408 list_for_each_entry(child, &dev->child_head, sibling_node) {
409 ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
410 &gpio_dev);
411 if (ret < 0)
412 continue;
413
414 gpio_bank = malloc(sizeof(*gpio_bank));
415 if (!gpio_bank) {
416 dev_err(dev, "Not enough memory\n");
417 return -ENOMEM;
418 }
419
420 gpio_bank->gpio_dev = gpio_dev;
421 list_add_tail(&gpio_bank->list, &priv->gpio_dev);
422 }
423
424 return 0;
425}
426
427static int sb_pinctrl_get_pins_count(struct udevice *dev)
428{
429 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
430 struct gpio_dev_priv *uc_priv;
431 struct sb_gpio_bank *gpio_bank;
432
433 /*
434 * if get_pins_count has already been executed once on this
435 * pin-controller, no need to run it again
436 */
437 if (priv->pinctrl_ngpios)
438 return priv->pinctrl_ngpios;
439
440 if (list_empty(&priv->gpio_dev))
441 sb_populate_gpio_dev_list(dev);
442 /*
443 * walk through all banks to retrieve the pin-controller
444 * pins number
445 */
446 list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
447 uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
448
449 priv->pinctrl_ngpios += uc_priv->gpio_count;
450 }
451
452 return priv->pinctrl_ngpios;
453}
454
455static struct udevice *sb_pinctrl_get_gpio_dev(struct udevice *dev,
456 unsigned int selector,
457 unsigned int *idx)
458{
459 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
460 struct sb_gpio_bank *gpio_bank;
461 struct gpio_dev_priv *uc_priv;
462 int pin_count = 0;
463
464 if (list_empty(&priv->gpio_dev))
465 sb_populate_gpio_dev_list(dev);
466
467 /* look up for the bank which owns the requested pin */
468 list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
469 uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
470
471 if (selector < (pin_count + uc_priv->gpio_count)) {
472 /*
473 * we found the bank, convert pin selector to
474 * gpio bank index
475 */
476 *idx = selector - pin_count;
477
478 return gpio_bank->gpio_dev;
479 }
480 pin_count += uc_priv->gpio_count;
481 }
482
483 return NULL;
484}
485
486static const char *sb_pinctrl_get_pin_name(struct udevice *dev,
487 unsigned int selector)
488{
489 struct gpio_dev_priv *uc_priv;
490 struct udevice *gpio_dev;
491 unsigned int gpio_idx;
492 static char pin_name[PINNAME_SIZE];
493
494 /* look up for the bank which owns the requested pin */
495 gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
496 if (!gpio_dev) {
497 snprintf(pin_name, PINNAME_SIZE, "Error");
498 } else {
499 uc_priv = dev_get_uclass_priv(gpio_dev);
500
501 snprintf(pin_name, PINNAME_SIZE, "%s%d",
502 uc_priv->bank_name,
503 gpio_idx);
504 }
505
506 return pin_name;
507}
508
Simon Glass3f2d5752021-02-04 21:21:59 -0700509static char *get_flags_string(ulong flags)
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100510{
511 if (flags & GPIOD_OPEN_DRAIN)
512 return "drive-open-drain";
513 if (flags & GPIOD_OPEN_SOURCE)
514 return "drive-open-source";
515 if (flags & GPIOD_PULL_UP)
516 return "bias-pull-up";
517 if (flags & GPIOD_PULL_DOWN)
518 return "bias-pull-down";
519 return ".";
520}
521
522static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
523 unsigned int selector,
524 char *buf, int size)
525{
526 struct udevice *gpio_dev;
527 unsigned int gpio_idx;
Simon Glass3f2d5752021-02-04 21:21:59 -0700528 ulong flags;
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100529 int function;
530
531 /* look up for the bank which owns the requested pin */
532 gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
533 if (!gpio_dev) {
534 snprintf(buf, size, "Error");
535 } else {
536 function = sb_gpio_get_function(gpio_dev, gpio_idx);
Simon Glass3f2d5752021-02-04 21:21:59 -0700537 flags = *get_gpio_flags(gpio_dev, gpio_idx);
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100538
539 snprintf(buf, size, "gpio %s %s",
540 function == GPIOF_OUTPUT ? "output" : "input",
Simon Glass3f2d5752021-02-04 21:21:59 -0700541 get_flags_string(flags));
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100542 }
543
544 return 0;
545}
Simon Glass3176b6c2020-07-07 13:11:44 -0600546
547#if CONFIG_IS_ENABLED(ACPIGEN)
548static int sb_pinctrl_get_name(const struct udevice *dev, char *out_name)
549{
550 return acpi_copy_name(out_name, "PINC");
551}
552#endif
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100553
554static int sandbox_pinctrl_probe(struct udevice *dev)
555{
556 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
557
558 INIT_LIST_HEAD(&priv->gpio_dev);
559
560 return 0;
561}
562
563static struct pinctrl_ops sandbox_pinctrl_gpio_ops = {
564 .get_pin_name = sb_pinctrl_get_pin_name,
565 .get_pins_count = sb_pinctrl_get_pins_count,
566 .get_pin_muxing = sb_pinctrl_get_pin_muxing,
567};
Simon Glass3176b6c2020-07-07 13:11:44 -0600568
569#if CONFIG_IS_ENABLED(ACPIGEN)
570struct acpi_ops pinctrl_sandbox_acpi_ops = {
571 .get_name = sb_pinctrl_get_name,
572};
573#endif
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100574
575static const struct udevice_id sandbox_pinctrl_gpio_match[] = {
576 { .compatible = "sandbox,pinctrl-gpio" },
577 { /* sentinel */ }
578};
579
580U_BOOT_DRIVER(sandbox_pinctrl_gpio) = {
581 .name = "sandbox_pinctrl_gpio",
582 .id = UCLASS_PINCTRL,
583 .of_match = sandbox_pinctrl_gpio_match,
584 .ops = &sandbox_pinctrl_gpio_ops,
585 .bind = dm_scan_fdt_dev,
586 .probe = sandbox_pinctrl_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700587 .priv_auto = sizeof(struct sb_pinctrl_priv),
Simon Glass3176b6c2020-07-07 13:11:44 -0600588 ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100589};
Simon Glass2149e112021-08-07 07:24:12 -0600590
591#endif /* PINCTRL */