14fc179b6SThomas Perrot // SPDX-License-Identifier: BSD-2-Clause
24fc179b6SThomas Perrot /*
34fc179b6SThomas Perrot * Copyright (c) 2022, Microchip
44fc179b6SThomas Perrot */
54fc179b6SThomas Perrot
64fc179b6SThomas Perrot #include <drivers/gpio.h>
74fc179b6SThomas Perrot #include <libfdt.h>
84fc179b6SThomas Perrot #include <stdio.h>
94fc179b6SThomas Perrot #include <tee_api_defines.h>
104fc179b6SThomas Perrot #include <tee_api_types.h>
114fc179b6SThomas Perrot #include <util.h>
124fc179b6SThomas Perrot
13a37f67edSPatrick Delaunay /* gpio suffixes used for device tree lookup */
14a37f67edSPatrick Delaunay static const char * const gpio_suffixes[] = { "gpios", "gpio" };
15a37f67edSPatrick Delaunay
gpio_dt_alloc_pin(struct dt_pargs * pargs,struct gpio ** out_gpio)16b357d34fSEtienne Carriere TEE_Result gpio_dt_alloc_pin(struct dt_pargs *pargs, struct gpio **out_gpio)
174fc179b6SThomas Perrot {
184fc179b6SThomas Perrot struct gpio *gpio = NULL;
194fc179b6SThomas Perrot
20b357d34fSEtienne Carriere if (pargs->args_count != 2)
21b357d34fSEtienne Carriere return TEE_ERROR_BAD_PARAMETERS;
224fc179b6SThomas Perrot
234fc179b6SThomas Perrot gpio = calloc(1, sizeof(struct gpio));
24b357d34fSEtienne Carriere if (!gpio)
25b357d34fSEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY;
264fc179b6SThomas Perrot
278fd620f7SEtienne Carriere gpio->pin = pargs->args[0];
288fd620f7SEtienne Carriere gpio->dt_flags = pargs->args[1];
294fc179b6SThomas Perrot
30b357d34fSEtienne Carriere *out_gpio = gpio;
31b357d34fSEtienne Carriere
32b357d34fSEtienne Carriere return TEE_SUCCESS;
334fc179b6SThomas Perrot }
344fc179b6SThomas Perrot
gpio_dt_get_by_index(const void * fdt,int nodeoffset,unsigned int index,const char * gpio_name,struct gpio ** gpio)354fc179b6SThomas Perrot TEE_Result gpio_dt_get_by_index(const void *fdt, int nodeoffset,
364fc179b6SThomas Perrot unsigned int index, const char *gpio_name,
374fc179b6SThomas Perrot struct gpio **gpio)
384fc179b6SThomas Perrot {
394fc179b6SThomas Perrot TEE_Result res = TEE_ERROR_GENERIC;
40a37f67edSPatrick Delaunay char prop_name[32]; /* 32 is max size of property name in DT */
41b357d34fSEtienne Carriere void *out_gpio = NULL;
42a37f67edSPatrick Delaunay unsigned int i = 0;
434fc179b6SThomas Perrot
44a37f67edSPatrick Delaunay /* Try GPIO properties "foo-gpios" and "foo-gpio" */
45a37f67edSPatrick Delaunay for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
46a37f67edSPatrick Delaunay if (gpio_name)
47a37f67edSPatrick Delaunay snprintf(prop_name, sizeof(prop_name), "%s-%s",
48a37f67edSPatrick Delaunay gpio_name, gpio_suffixes[i]);
49a37f67edSPatrick Delaunay else
50a37f67edSPatrick Delaunay snprintf(prop_name, sizeof(prop_name), "%s",
51a37f67edSPatrick Delaunay gpio_suffixes[i]);
524fc179b6SThomas Perrot
53a37f67edSPatrick Delaunay res = dt_driver_device_from_node_idx_prop(prop_name, fdt,
54a37f67edSPatrick Delaunay nodeoffset,
554fc179b6SThomas Perrot index, DT_DRIVER_GPIO,
56b357d34fSEtienne Carriere &out_gpio);
57a37f67edSPatrick Delaunay
58a37f67edSPatrick Delaunay if (res != TEE_ERROR_ITEM_NOT_FOUND)
59a37f67edSPatrick Delaunay break;
60a37f67edSPatrick Delaunay }
61a37f67edSPatrick Delaunay
62b357d34fSEtienne Carriere if (!res)
63b357d34fSEtienne Carriere *gpio = out_gpio;
644fc179b6SThomas Perrot
654fc179b6SThomas Perrot return res;
664fc179b6SThomas Perrot }
6739d1e320SPatrick Delaunay
gpio_configure(struct gpio * gpio,enum gpio_flags flags)6839d1e320SPatrick Delaunay TEE_Result gpio_configure(struct gpio *gpio, enum gpio_flags flags)
6939d1e320SPatrick Delaunay {
7039d1e320SPatrick Delaunay enum gpio_level value = GPIO_LEVEL_LOW;
71*396e1f07SPatrick Delaunay TEE_Result res = TEE_ERROR_GENERIC;
72*396e1f07SPatrick Delaunay
73*396e1f07SPatrick Delaunay assert(gpio && gpio->chip && gpio->chip->ops);
74*396e1f07SPatrick Delaunay
75*396e1f07SPatrick Delaunay /* Configure GPIO with DT flags */
76*396e1f07SPatrick Delaunay if (gpio && gpio->chip->ops->configure) {
77*396e1f07SPatrick Delaunay res = gpio->chip->ops->configure(gpio->chip, gpio);
78*396e1f07SPatrick Delaunay if (res)
79*396e1f07SPatrick Delaunay return res;
80*396e1f07SPatrick Delaunay }
8139d1e320SPatrick Delaunay
8239d1e320SPatrick Delaunay /* Process requester flags */
8339d1e320SPatrick Delaunay if (flags & GPIO_FLAGS_BIT_DIR_SET) {
8439d1e320SPatrick Delaunay if (flags & GPIO_FLAGS_BIT_DIR_OUT) {
8539d1e320SPatrick Delaunay if (flags & GPIO_FLAGS_BIT_DIR_VAL)
8639d1e320SPatrick Delaunay value = GPIO_LEVEL_HIGH;
8739d1e320SPatrick Delaunay gpio_set_value(gpio, value);
8839d1e320SPatrick Delaunay gpio_set_direction(gpio, GPIO_DIR_OUT);
8939d1e320SPatrick Delaunay } else {
9039d1e320SPatrick Delaunay gpio_set_direction(gpio, GPIO_DIR_IN);
9139d1e320SPatrick Delaunay }
9239d1e320SPatrick Delaunay }
9339d1e320SPatrick Delaunay
9439d1e320SPatrick Delaunay return TEE_SUCCESS;
9539d1e320SPatrick Delaunay }
9639d1e320SPatrick Delaunay
gpio_dt_cfg_by_index(const void * fdt,int nodeoffset,unsigned int index,const char * gpio_name,enum gpio_flags flags,struct gpio ** gpio)9739d1e320SPatrick Delaunay TEE_Result gpio_dt_cfg_by_index(const void *fdt, int nodeoffset,
9839d1e320SPatrick Delaunay unsigned int index, const char *gpio_name,
9939d1e320SPatrick Delaunay enum gpio_flags flags, struct gpio **gpio)
10039d1e320SPatrick Delaunay {
10139d1e320SPatrick Delaunay TEE_Result res = TEE_ERROR_GENERIC;
10239d1e320SPatrick Delaunay
10339d1e320SPatrick Delaunay res = gpio_dt_get_by_index(fdt, nodeoffset, index, gpio_name, gpio);
10439d1e320SPatrick Delaunay if (!res)
10539d1e320SPatrick Delaunay return gpio_configure(*gpio, flags);
10639d1e320SPatrick Delaunay
10739d1e320SPatrick Delaunay return res;
10839d1e320SPatrick Delaunay }
109