blob: 05f17928f0a7fc7f156160e19b9916111d7b8535 [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 */
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010025 ulong dir_flags; /* dir_flags (GPIOD_...) */
Simon Glassb43d0442012-02-15 15:51:13 -080026};
27
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010028/* Access routines for GPIO dir flags */
29static ulong *get_gpio_dir_flags(struct udevice *dev, unsigned int 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) {
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010035 static ulong invalid_dir_flags;
Simon Glassb4d70702014-02-26 15:59:25 -070036 printf("sandbox_gpio: error: invalid gpio %u\n", offset);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010037 return &invalid_dir_flags;
Simon Glassb43d0442012-02-15 15:51:13 -080038 }
39
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010040 return &state[offset].dir_flags;
41
Simon Glassb43d0442012-02-15 15:51:13 -080042}
43
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010044static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
Simon Glassb43d0442012-02-15 15:51:13 -080045{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010046 return (*get_gpio_dir_flags(dev, offset) & flag) != 0;
Simon Glassb43d0442012-02-15 15:51:13 -080047}
48
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010049static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
Simon Glassb4d70702014-02-26 15:59:25 -070050 int value)
Simon Glassb43d0442012-02-15 15:51:13 -080051{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010052 ulong *gpio = get_gpio_dir_flags(dev, offset);
Simon Glassb43d0442012-02-15 15:51:13 -080053
54 if (value)
55 *gpio |= flag;
56 else
57 *gpio &= ~flag;
58
59 return 0;
60}
61
Simon Glassb43d0442012-02-15 15:51:13 -080062/*
63 * Back-channel sandbox-internal-only access to GPIO state
64 */
65
Heiko Schocherb74fcb42014-05-22 12:43:05 +020066int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -080067{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010068 if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
Simon Glassb4d70702014-02-26 15:59:25 -070069 debug("sandbox_gpio: get_value on output gpio %u\n", offset);
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010070 return get_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE);
Simon Glassb43d0442012-02-15 15:51:13 -080071}
72
Heiko Schocherb74fcb42014-05-22 12:43:05 +020073int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
Simon Glassb43d0442012-02-15 15:51:13 -080074{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010075 return set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE, value);
Simon Glassb43d0442012-02-15 15:51:13 -080076}
77
Heiko Schocherb74fcb42014-05-22 12:43:05 +020078int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -080079{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010080 return get_gpio_flag(dev, offset, GPIOD_IS_OUT);
Simon Glassb43d0442012-02-15 15:51:13 -080081}
82
Heiko Schocherb74fcb42014-05-22 12:43:05 +020083int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
Simon Glassb43d0442012-02-15 15:51:13 -080084{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +010085 set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
86 set_gpio_flag(dev, offset, GPIOD_IS_IN, !(output));
87
88 return 0;
89}
90
91ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset)
92{
93 return *get_gpio_dir_flags(dev, offset);
94}
95
96int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
97 ulong flags)
98{
99 *get_gpio_dir_flags(dev, offset) = flags;
100
101 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800102}
103
104/*
105 * These functions implement the public interface within U-Boot
106 */
107
Simon Glassb4d70702014-02-26 15:59:25 -0700108/* set GPIO port 'offset' as an input */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200109static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
Simon Glassb43d0442012-02-15 15:51:13 -0800110{
Simon Glassb4d70702014-02-26 15:59:25 -0700111 debug("%s: offset:%u\n", __func__, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800112
Simon Glassb4d70702014-02-26 15:59:25 -0700113 return sandbox_gpio_set_direction(dev, offset, 0);
Simon Glassb43d0442012-02-15 15:51:13 -0800114}
115
Simon Glassb4d70702014-02-26 15:59:25 -0700116/* set GPIO port 'offset' as an output, with polarity 'value' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200117static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
Simon Glassb4d70702014-02-26 15:59:25 -0700118 int value)
Simon Glassb43d0442012-02-15 15:51:13 -0800119{
Simon Glassb4d70702014-02-26 15:59:25 -0700120 debug("%s: offset:%u, value = %d\n", __func__, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800121
Simon Glassb4d70702014-02-26 15:59:25 -0700122 return sandbox_gpio_set_direction(dev, offset, 1) |
123 sandbox_gpio_set_value(dev, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800124}
125
Simon Glassb4d70702014-02-26 15:59:25 -0700126/* read GPIO IN value of port 'offset' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200127static int sb_gpio_get_value(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_get_value(dev, offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800132}
133
Simon Glassb4d70702014-02-26 15:59:25 -0700134/* write GPIO OUT value to port 'offset' */
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200135static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
Simon Glassb43d0442012-02-15 15:51:13 -0800136{
Simon Glassb4d70702014-02-26 15:59:25 -0700137 debug("%s: offset:%u, value = %d\n", __func__, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800138
Simon Glassb4d70702014-02-26 15:59:25 -0700139 if (!sandbox_gpio_get_direction(dev, offset)) {
140 printf("sandbox_gpio: error: set_value on input gpio %u\n",
141 offset);
Simon Glassb43d0442012-02-15 15:51:13 -0800142 return -1;
143 }
144
Simon Glassb4d70702014-02-26 15:59:25 -0700145 return sandbox_gpio_set_value(dev, offset, value);
Simon Glassb43d0442012-02-15 15:51:13 -0800146}
147
Simon Glass32048632014-10-04 11:29:45 -0600148static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
149{
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100150 if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
Simon Glass32048632014-10-04 11:29:45 -0600151 return GPIOF_OUTPUT;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100152 if (get_gpio_flag(dev, offset, GPIOD_IS_IN))
153 return GPIOF_INPUT;
154
155 return GPIOF_INPUT; /*GPIO is not configurated */
Simon Glass32048632014-10-04 11:29:45 -0600156}
157
Simon Glass16e10402015-01-05 20:05:29 -0700158static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
Simon Glass12faa022017-05-18 20:09:18 -0600159 struct ofnode_phandle_args *args)
Simon Glass16e10402015-01-05 20:05:29 -0700160{
161 desc->offset = args->args[0];
162 if (args->args_count < 2)
163 return 0;
Patrick Delaunay23aee612020-01-13 11:35:13 +0100164 /* treat generic binding with gpio uclass */
165 gpio_xlate_offs_flags(dev, desc, args);
166
167 /* sandbox test specific, not defined in gpio.h */
168 if (args->args[1] & GPIO_IN)
Simon Glass16e10402015-01-05 20:05:29 -0700169 desc->flags |= GPIOD_IS_IN;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100170
Patrick Delaunay23aee612020-01-13 11:35:13 +0100171 if (args->args[1] & GPIO_OUT)
Simon Glass16e10402015-01-05 20:05:29 -0700172 desc->flags |= GPIOD_IS_OUT;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100173
Patrick Delaunay23aee612020-01-13 11:35:13 +0100174 if (args->args[1] & GPIO_OUT_ACTIVE)
Simon Glass16e10402015-01-05 20:05:29 -0700175 desc->flags |= GPIOD_IS_OUT_ACTIVE;
176
177 return 0;
178}
179
Simon Glass54befdd2021-02-04 21:21:55 -0700180static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset,
181 ulong flags)
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100182{
183 ulong *dir_flags;
184
185 debug("%s: offset:%u, dir_flags = %lx\n", __func__, offset, flags);
186
187 dir_flags = get_gpio_dir_flags(dev, offset);
188
Heinrich Schuchardt5355be62020-09-14 12:50:55 +0200189 /*
190 * For testing purposes keep the output value when switching to input.
191 * This allows us to manipulate the input value via the gpio command.
192 */
193 if (flags & GPIOD_IS_IN)
194 *dir_flags = (flags & ~GPIOD_IS_OUT_ACTIVE) |
195 (*dir_flags & GPIOD_IS_OUT_ACTIVE);
196 else
197 *dir_flags = flags;
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100198
199 return 0;
200}
201
202static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
203 ulong *flags)
204{
205 debug("%s: offset:%u\n", __func__, offset);
206 *flags = *get_gpio_dir_flags(dev, offset);
207
208 return 0;
209}
210
Simon Glass3176b6c2020-07-07 13:11:44 -0600211#if CONFIG_IS_ENABLED(ACPIGEN)
212static int sb_gpio_get_acpi(const struct gpio_desc *desc,
213 struct acpi_gpio *gpio)
214{
215 int ret;
216
217 /* Note that gpio_get_acpi() zeroes *gpio before calling here */
218 gpio->pin_count = 1;
219 gpio->pins[0] = desc->offset;
220 ret = acpi_device_scope(desc->dev, gpio->resource,
221 sizeof(gpio->resource));
222 if (ret)
223 return log_ret(ret);
224
225 /* All of these values are just used for testing */
226 if (desc->flags & GPIOD_ACTIVE_LOW) {
227 gpio->pin0_addr = 0x80012 + desc->offset;
228 gpio->type = ACPI_GPIO_TYPE_INTERRUPT;
229 gpio->pull = ACPI_GPIO_PULL_DOWN;
230 gpio->interrupt_debounce_timeout = 4321;
231
232 /* We use the GpioInt part */
233 gpio->irq.pin = desc->offset;
234 gpio->irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
235 gpio->irq.shared = ACPI_IRQ_SHARED;
236 gpio->irq.wake = ACPI_IRQ_WAKE;
237
238 /* The GpioIo part is only used for testing */
239 gpio->polarity = ACPI_GPIO_ACTIVE_LOW;
240 } else {
241 gpio->pin0_addr = 0xc00dc + desc->offset;
242 gpio->type = ACPI_GPIO_TYPE_IO;
243 gpio->pull = ACPI_GPIO_PULL_UP;
244 gpio->interrupt_debounce_timeout = 0;
245
246 /* The GpioInt part is not used */
247
248 /* We use the GpioIo part */
249 gpio->output_drive_strength = 1234;
250 gpio->io_shared = true;
251 gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_INPUT;
252 gpio->polarity = 0;
253 }
254
255 return 0;
256}
257
258static int sb_gpio_get_name(const struct udevice *dev, char *out_name)
259{
260 return acpi_copy_name(out_name, "GPIO");
261}
262
263struct acpi_ops gpio_sandbox_acpi_ops = {
264 .get_name = sb_gpio_get_name,
265};
266#endif /* ACPIGEN */
267
Simon Glassb4d70702014-02-26 15:59:25 -0700268static const struct dm_gpio_ops gpio_sandbox_ops = {
Simon Glassb4d70702014-02-26 15:59:25 -0700269 .direction_input = sb_gpio_direction_input,
270 .direction_output = sb_gpio_direction_output,
271 .get_value = sb_gpio_get_value,
272 .set_value = sb_gpio_set_value,
Simon Glass32048632014-10-04 11:29:45 -0600273 .get_function = sb_gpio_get_function,
Simon Glass16e10402015-01-05 20:05:29 -0700274 .xlate = sb_gpio_xlate,
Simon Glass54befdd2021-02-04 21:21:55 -0700275 .set_flags = sb_gpio_set_flags,
Patrick Delaunay28bdaa52020-01-13 11:35:14 +0100276 .get_dir_flags = sb_gpio_get_dir_flags,
Simon Glass3176b6c2020-07-07 13:11:44 -0600277#if CONFIG_IS_ENABLED(ACPIGEN)
278 .get_acpi = sb_gpio_get_acpi,
279#endif
Simon Glassb4d70702014-02-26 15:59:25 -0700280};
281
Simon Glassaad29ae2020-12-03 16:55:21 -0700282static int sandbox_gpio_of_to_plat(struct udevice *dev)
Simon Glassb43d0442012-02-15 15:51:13 -0800283{
Simon Glassde0977b2015-03-05 12:25:20 -0700284 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb43d0442012-02-15 15:51:13 -0800285
Simon Glass9e7ab232018-02-03 10:36:59 -0700286 uc_priv->gpio_count = dev_read_u32_default(dev, "sandbox,gpio-count",
287 0);
Simon Glass1185fcb2017-05-18 20:09:20 -0600288 uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
Simon Glassb43d0442012-02-15 15:51:13 -0800289
Simon Glassb4d70702014-02-26 15:59:25 -0700290 return 0;
291}
Simon Glassb43d0442012-02-15 15:51:13 -0800292
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200293static int gpio_sandbox_probe(struct udevice *dev)
Simon Glassb4d70702014-02-26 15:59:25 -0700294{
Simon Glassde0977b2015-03-05 12:25:20 -0700295 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glassb4d70702014-02-26 15:59:25 -0700296
Simon Glassf1d50f72020-12-19 10:40:13 -0700297 if (!dev_has_ofnode(dev))
Simon Glassb4d70702014-02-26 15:59:25 -0700298 /* Tell the uclass how many GPIOs we have */
299 uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
Simon Glassb4d70702014-02-26 15:59:25 -0700300
Simon Glass95588622020-12-22 19:30:28 -0700301 dev_set_priv(dev,
302 calloc(sizeof(struct gpio_state), uc_priv->gpio_count));
Simon Glassb4d70702014-02-26 15:59:25 -0700303
304 return 0;
Simon Glassb43d0442012-02-15 15:51:13 -0800305}
Simon Glassb4d70702014-02-26 15:59:25 -0700306
Simon Glassa367f1d2014-10-04 11:29:46 -0600307static int gpio_sandbox_remove(struct udevice *dev)
308{
Simon Glass95588622020-12-22 19:30:28 -0700309 free(dev_get_priv(dev));
Simon Glassa367f1d2014-10-04 11:29:46 -0600310
311 return 0;
312}
313
Simon Glass767827a2014-06-11 23:29:45 -0600314static const struct udevice_id sandbox_gpio_ids[] = {
Simon Glassb4d70702014-02-26 15:59:25 -0700315 { .compatible = "sandbox,gpio" },
316 { }
317};
318
Walter Lozano2901ac62020-06-25 01:10:04 -0300319U_BOOT_DRIVER(sandbox_gpio) = {
320 .name = "sandbox_gpio",
Simon Glassb4d70702014-02-26 15:59:25 -0700321 .id = UCLASS_GPIO,
322 .of_match = sandbox_gpio_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700323 .of_to_plat = sandbox_gpio_of_to_plat,
Simon Glassb4d70702014-02-26 15:59:25 -0700324 .probe = gpio_sandbox_probe,
Simon Glassa367f1d2014-10-04 11:29:46 -0600325 .remove = gpio_sandbox_remove,
Simon Glassb4d70702014-02-26 15:59:25 -0700326 .ops = &gpio_sandbox_ops,
Simon Glass3176b6c2020-07-07 13:11:44 -0600327 ACPI_OPS_PTR(&gpio_sandbox_acpi_ops)
Simon Glassb4d70702014-02-26 15:59:25 -0700328};
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100329
Simon Glassdf65db82020-12-28 20:34:57 -0700330DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
Walter Lozano48e5b042020-06-25 01:10:06 -0300331
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100332/* pincontrol: used only to check GPIO pin configuration (pinmux command) */
333
334struct sb_pinctrl_priv {
335 int pinctrl_ngpios;
336 struct list_head gpio_dev;
337};
338
339struct sb_gpio_bank {
340 struct udevice *gpio_dev;
341 struct list_head list;
342};
343
344static int sb_populate_gpio_dev_list(struct udevice *dev)
345{
346 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
347 struct udevice *gpio_dev;
348 struct udevice *child;
349 struct sb_gpio_bank *gpio_bank;
350 int ret;
351
352 /*
353 * parse pin-controller sub-nodes (ie gpio bank nodes) and fill
354 * a list with all gpio device reference which belongs to the
355 * current pin-controller. This list is used to find pin_name and
356 * pin muxing
357 */
358 list_for_each_entry(child, &dev->child_head, sibling_node) {
359 ret = uclass_get_device_by_name(UCLASS_GPIO, child->name,
360 &gpio_dev);
361 if (ret < 0)
362 continue;
363
364 gpio_bank = malloc(sizeof(*gpio_bank));
365 if (!gpio_bank) {
366 dev_err(dev, "Not enough memory\n");
367 return -ENOMEM;
368 }
369
370 gpio_bank->gpio_dev = gpio_dev;
371 list_add_tail(&gpio_bank->list, &priv->gpio_dev);
372 }
373
374 return 0;
375}
376
377static int sb_pinctrl_get_pins_count(struct udevice *dev)
378{
379 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
380 struct gpio_dev_priv *uc_priv;
381 struct sb_gpio_bank *gpio_bank;
382
383 /*
384 * if get_pins_count has already been executed once on this
385 * pin-controller, no need to run it again
386 */
387 if (priv->pinctrl_ngpios)
388 return priv->pinctrl_ngpios;
389
390 if (list_empty(&priv->gpio_dev))
391 sb_populate_gpio_dev_list(dev);
392 /*
393 * walk through all banks to retrieve the pin-controller
394 * pins number
395 */
396 list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
397 uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
398
399 priv->pinctrl_ngpios += uc_priv->gpio_count;
400 }
401
402 return priv->pinctrl_ngpios;
403}
404
405static struct udevice *sb_pinctrl_get_gpio_dev(struct udevice *dev,
406 unsigned int selector,
407 unsigned int *idx)
408{
409 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
410 struct sb_gpio_bank *gpio_bank;
411 struct gpio_dev_priv *uc_priv;
412 int pin_count = 0;
413
414 if (list_empty(&priv->gpio_dev))
415 sb_populate_gpio_dev_list(dev);
416
417 /* look up for the bank which owns the requested pin */
418 list_for_each_entry(gpio_bank, &priv->gpio_dev, list) {
419 uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev);
420
421 if (selector < (pin_count + uc_priv->gpio_count)) {
422 /*
423 * we found the bank, convert pin selector to
424 * gpio bank index
425 */
426 *idx = selector - pin_count;
427
428 return gpio_bank->gpio_dev;
429 }
430 pin_count += uc_priv->gpio_count;
431 }
432
433 return NULL;
434}
435
436static const char *sb_pinctrl_get_pin_name(struct udevice *dev,
437 unsigned int selector)
438{
439 struct gpio_dev_priv *uc_priv;
440 struct udevice *gpio_dev;
441 unsigned int gpio_idx;
442 static char pin_name[PINNAME_SIZE];
443
444 /* look up for the bank which owns the requested pin */
445 gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
446 if (!gpio_dev) {
447 snprintf(pin_name, PINNAME_SIZE, "Error");
448 } else {
449 uc_priv = dev_get_uclass_priv(gpio_dev);
450
451 snprintf(pin_name, PINNAME_SIZE, "%s%d",
452 uc_priv->bank_name,
453 gpio_idx);
454 }
455
456 return pin_name;
457}
458
459static char *get_dir_flags_string(ulong flags)
460{
461 if (flags & GPIOD_OPEN_DRAIN)
462 return "drive-open-drain";
463 if (flags & GPIOD_OPEN_SOURCE)
464 return "drive-open-source";
465 if (flags & GPIOD_PULL_UP)
466 return "bias-pull-up";
467 if (flags & GPIOD_PULL_DOWN)
468 return "bias-pull-down";
469 return ".";
470}
471
472static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
473 unsigned int selector,
474 char *buf, int size)
475{
476 struct udevice *gpio_dev;
477 unsigned int gpio_idx;
478 ulong dir_flags;
479 int function;
480
481 /* look up for the bank which owns the requested pin */
482 gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx);
483 if (!gpio_dev) {
484 snprintf(buf, size, "Error");
485 } else {
486 function = sb_gpio_get_function(gpio_dev, gpio_idx);
487 dir_flags = *get_gpio_dir_flags(gpio_dev, gpio_idx);
488
489 snprintf(buf, size, "gpio %s %s",
490 function == GPIOF_OUTPUT ? "output" : "input",
491 get_dir_flags_string(dir_flags));
492 }
493
494 return 0;
495}
Simon Glass3176b6c2020-07-07 13:11:44 -0600496
497#if CONFIG_IS_ENABLED(ACPIGEN)
498static int sb_pinctrl_get_name(const struct udevice *dev, char *out_name)
499{
500 return acpi_copy_name(out_name, "PINC");
501}
502#endif
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100503
504static int sandbox_pinctrl_probe(struct udevice *dev)
505{
506 struct sb_pinctrl_priv *priv = dev_get_priv(dev);
507
508 INIT_LIST_HEAD(&priv->gpio_dev);
509
510 return 0;
511}
512
513static struct pinctrl_ops sandbox_pinctrl_gpio_ops = {
514 .get_pin_name = sb_pinctrl_get_pin_name,
515 .get_pins_count = sb_pinctrl_get_pins_count,
516 .get_pin_muxing = sb_pinctrl_get_pin_muxing,
517};
Simon Glass3176b6c2020-07-07 13:11:44 -0600518
519#if CONFIG_IS_ENABLED(ACPIGEN)
520struct acpi_ops pinctrl_sandbox_acpi_ops = {
521 .get_name = sb_pinctrl_get_name,
522};
523#endif
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100524
525static const struct udevice_id sandbox_pinctrl_gpio_match[] = {
526 { .compatible = "sandbox,pinctrl-gpio" },
527 { /* sentinel */ }
528};
529
530U_BOOT_DRIVER(sandbox_pinctrl_gpio) = {
531 .name = "sandbox_pinctrl_gpio",
532 .id = UCLASS_PINCTRL,
533 .of_match = sandbox_pinctrl_gpio_match,
534 .ops = &sandbox_pinctrl_gpio_ops,
535 .bind = dm_scan_fdt_dev,
536 .probe = sandbox_pinctrl_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700537 .priv_auto = sizeof(struct sb_pinctrl_priv),
Simon Glass3176b6c2020-07-07 13:11:44 -0600538 ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
Patrick Delaunay1b4a22f2020-01-13 11:35:15 +0100539};