/* * Copyright (c) 2011 The Chromium OS Authors. * SPDX-License-Identifier: GPL-2.0+ */ #include #include /* Flags for each GPIO */ #define GPIOF_OUTPUT (1 << 0) /* Currently set as an output */ #define GPIOF_HIGH (1 << 1) /* Currently set high */ #define GPIOF_RESERVED (1 << 2) /* Is in use / requested */ struct gpio_state { const char *label; /* label given by requester */ u8 flags; /* flags (GPIOF_...) */ }; /* * State of GPIOs * TODO: Put this into sandbox state */ static struct gpio_state state[CONFIG_SANDBOX_GPIO_COUNT]; /* Access routines for GPIO state */ static u8 *get_gpio_flags(unsigned gp) { /* assert()'s could be disabled, so make sure we handle that */ assert(gp < ARRAY_SIZE(state)); if (gp >= ARRAY_SIZE(state)) { static u8 invalid_flags; printf("sandbox_gpio: error: invalid gpio %u\n", gp); return &invalid_flags; } return &state[gp].flags; } static int get_gpio_flag(unsigned gp, int flag) { return (*get_gpio_flags(gp) & flag) != 0; } static int set_gpio_flag(unsigned gp, int flag, int value) { u8 *gpio = get_gpio_flags(gp); if (value) *gpio |= flag; else *gpio &= ~flag; return 0; } static int check_reserved(unsigned gpio, const char *func) { if (!get_gpio_flag(gpio, GPIOF_RESERVED)) { printf("sandbox_gpio: %s: error: gpio %u not reserved\n", func, gpio); return -1; } return 0; } /* * Back-channel sandbox-internal-only access to GPIO state */ int sandbox_gpio_get_value(unsigned gp) { if (get_gpio_flag(gp, GPIOF_OUTPUT)) debug("sandbox_gpio: get_value on output gpio %u\n", gp); return get_gpio_flag(gp, GPIOF_HIGH); } int sandbox_gpio_set_value(unsigned gp, int value) { return set_gpio_flag(gp, GPIOF_HIGH, value); } int sandbox_gpio_get_direction(unsigned gp) { return get_gpio_flag(gp, GPIOF_OUTPUT); } int sandbox_gpio_set_direction(unsigned gp, int output) { return set_gpio_flag(gp, GPIOF_OUTPUT, output); } /* * These functions implement the public interface within U-Boot */ /* set GPIO port 'gp' as an input */ int gpio_direction_input(unsigned gp) { debug("%s: gp:%u\n", __func__, gp); if (check_reserved(gp, __func__)) return -1; return sandbox_gpio_set_direction(gp, 0); } /* set GPIO port 'gp' as an output, with polarity 'value' */ int gpio_direction_output(unsigned gp, int value) { debug("%s: gp:%u, value = %d\n", __func__, gp, value); if (check_reserved(gp, __func__)) return -1; return sandbox_gpio_set_direction(gp, 1) | sandbox_gpio_set_value(gp, value); } /* read GPIO IN value of port 'gp' */ int gpio_get_value(unsigned gp) { debug("%s: gp:%u\n", __func__, gp); if (check_reserved(gp, __func__)) return -1; return sandbox_gpio_get_value(gp); } /* write GPIO OUT value to port 'gp' */ int gpio_set_value(unsigned gp, int value) { debug("%s: gp:%u, value = %d\n", __func__, gp, value); if (check_reserved(gp, __func__)) return -1; if (!sandbox_gpio_get_direction(gp)) { printf("sandbox_gpio: error: set_value on input gpio %u\n", gp); return -1; } return sandbox_gpio_set_value(gp, value); } int gpio_request(unsigned gp, const char *label) { debug("%s: gp:%u, label:%s\n", __func__, gp, label); if (gp >= ARRAY_SIZE(state)) { printf("sandbox_gpio: error: invalid gpio %u\n", gp); return -1; } if (get_gpio_flag(gp, GPIOF_RESERVED)) { printf("sandbox_gpio: error: gpio %u already reserved\n", gp); return -1; } state[gp].label = label; return set_gpio_flag(gp, GPIOF_RESERVED, 1); } int gpio_free(unsigned gp) { debug("%s: gp:%u\n", __func__, gp); if (check_reserved(gp, __func__)) return -1; state[gp].label = NULL; return set_gpio_flag(gp, GPIOF_RESERVED, 0); } /* Display GPIO information */ void gpio_info(void) { unsigned gpio; puts("Sandbox GPIOs\n"); for (gpio = 0; gpio < ARRAY_SIZE(state); ++gpio) { const char *label = state[gpio].label; printf("%4d: %s: %d [%c] %s\n", gpio, sandbox_gpio_get_direction(gpio) ? "out" : " in", sandbox_gpio_get_value(gpio), get_gpio_flag(gpio, GPIOF_RESERVED) ? 'x' : ' ', label ? label : ""); } }