/** * gpio_free() - [COMPAT] Relinquish GPIO * gpio: GPIO number * * This function implements the API that's compatible with current * GPIO API used in U-Boot. The request is forwarded to particular * GPIO driver. Returns 0 on success, negative value on error. */ int gpio_free(unsigned gpio) { unsigned int offset; struct device *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); if (ret) return ret; if (!gpio_get_ops(dev)->free) return 0; return gpio_get_ops(dev)->free(dev, offset); }
/** * gpio_request() - [COMPAT] Request GPIO * gpio: GPIO number * label: Name for the requested GPIO * * This function implements the API that's compatible with current * GPIO API used in U-Boot. The request is forwarded to particular * GPIO driver. Returns 0 on success, negative value on error. */ int gpio_request(unsigned gpio, const char *label) { unsigned int offset; struct device *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); if (ret) return ret; if (!gpio_get_ops(dev)->request) return 0; return gpio_get_ops(dev)->request(dev, offset, label); }
static int get_function(struct udevice *dev, int offset, bool skip_unused, const char **namep) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct dm_gpio_ops *ops = gpio_get_ops(dev); BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function)); if (!device_active(dev)) return -ENODEV; if (offset < 0 || offset >= uc_priv->gpio_count) return -EINVAL; if (namep) *namep = uc_priv->name[offset]; if (skip_unused && !uc_priv->name[offset]) return GPIOF_UNUSED; if (ops->get_function) { int ret; ret = ops->get_function(dev, offset); if (ret < 0) return ret; if (ret >= ARRAY_SIZE(gpio_function)) return -ENODATA; return ret; } return GPIOF_UNKNOWN; }
int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) { struct udevice *dev = desc->dev; struct dm_gpio_ops *ops = gpio_get_ops(dev); int ret; ret = check_reserved(desc, "set_dir"); if (ret) return ret; if (flags & GPIOD_IS_OUT) { int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0; if (flags & GPIOD_ACTIVE_LOW) value = !value; ret = ops->direction_output(dev, desc->offset, value); } else if (flags & GPIOD_IS_IN) { ret = ops->direction_input(dev, desc->offset); } if (ret) return ret; /* * Update desc->flags here, so that GPIO_ACTIVE_LOW is honoured in * futures */ desc->flags = flags; return 0; }
int _dm_gpio_free(struct udevice *dev, uint offset) { struct gpio_dev_priv *uc_priv; int ret; uc_priv = dev_get_uclass_priv(dev); if (!uc_priv->name[offset]) return -ENXIO; if (gpio_get_ops(dev)->free) { ret = gpio_get_ops(dev)->free(dev, offset); if (ret) return ret; } free(uc_priv->name[offset]); uc_priv->name[offset] = NULL; return 0; }
static int gpio_find_and_xlate(struct gpio_desc *desc, struct ofnode_phandle_args *args) { struct dm_gpio_ops *ops = gpio_get_ops(desc->dev); if (ops->xlate) return ops->xlate(desc->dev, desc, args); else return gpio_xlate_offs_flags(desc->dev, desc, args); }
/** * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin * gpio: GPIO number * value: Logical value to be set on the GPIO pin. * * This function implements the API that's compatible with current * GPIO API used in U-Boot. The request is forwarded to particular * GPIO driver. Returns 0 on success, negative value on error. */ int gpio_set_value(unsigned gpio, int value) { unsigned int offset; struct device *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); if (ret) return ret; return gpio_get_ops(dev)->set_value(dev, offset, value); }
/** * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value * gpio: GPIO number * value: Logical value to be set on the GPIO pin * * This function implements the API that's compatible with current * GPIO API used in U-Boot. The request is forwarded to particular * GPIO driver. Returns 0 on success, negative value on error. */ int gpio_direction_output(unsigned gpio, int value) { unsigned int offset; struct device *dev; int ret; ret = gpio_to_device(gpio, &dev, &offset); if (ret) return ret; return gpio_get_ops(dev)->direction_output(dev, offset, value); }
int dm_gpio_set_value(const struct gpio_desc *desc, int value) { int ret; ret = check_reserved(desc, "set_value"); if (ret) return ret; if (desc->flags & GPIOD_ACTIVE_LOW) value = !value; gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value); return 0; }
int dm_gpio_get_value(const struct gpio_desc *desc) { int value; int ret; ret = check_reserved(desc, "get_value"); if (ret) return ret; value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset); return desc->flags & GPIOD_ACTIVE_LOW ? !value : value; }
static int gpio_find_and_xlate(struct gpio_desc *desc, struct fdtdec_phandle_args *args) { struct dm_gpio_ops *ops = gpio_get_ops(desc->dev); /* Use the first argument as the offset by default */ if (args->args_count > 0) desc->offset = args->args[0]; else desc->offset = -1; desc->flags = 0; return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0; }
int dm_gpio_get_open_drain(struct gpio_desc *desc) { struct dm_gpio_ops *ops = gpio_get_ops(desc->dev); int ret; ret = check_reserved(desc, "get_open_drain"); if (ret) return ret; if (ops->set_open_drain) return ops->get_open_drain(desc->dev, desc->offset); else return -ENOSYS; }
/** * gpio_direction_input() - [COMPAT] Set GPIO direction to input * gpio: GPIO number * * This function implements the API that's compatible with current * GPIO API used in U-Boot. The request is forwarded to particular * GPIO driver. Returns 0 on success, negative value on error. */ int gpio_direction_input(unsigned gpio) { struct gpio_desc desc; int ret; ret = gpio_to_device(gpio, &desc); if (ret) return ret; ret = check_reserved(&desc, "dir_input"); if (ret) return ret; return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset); }
int dm_gpio_request(struct gpio_desc *desc, const char *label) { struct udevice *dev = desc->dev; struct gpio_dev_priv *uc_priv; char *str; int ret; uc_priv = dev_get_uclass_priv(dev); if (uc_priv->name[desc->offset]) return -EBUSY; str = strdup(label); if (!str) return -ENOMEM; if (gpio_get_ops(dev)->request) { ret = gpio_get_ops(dev)->request(dev, desc->offset, label); if (ret) { free(str); return ret; } } uc_priv->name[desc->offset] = str; return 0; }
int dm_gpio_set_open_drain(struct gpio_desc *desc, int value) { struct dm_gpio_ops *ops = gpio_get_ops(desc->dev); int ret; ret = check_reserved(desc, "set_open_drain"); if (ret) return ret; if (ops->set_open_drain) ret = ops->set_open_drain(desc->dev, desc->offset, value); else return 0; /* feature not supported -> ignore setting */ return ret; }
int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize) { struct dm_gpio_ops *ops = gpio_get_ops(dev); struct gpio_dev_priv *priv; char *str = buf; int func; int ret; int len; BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function)); *buf = 0; priv = dev_get_uclass_priv(dev); ret = gpio_get_raw_function(dev, offset, NULL); if (ret < 0) return ret; func = ret; len = snprintf(str, buffsize, "%s%d: %s", priv->bank_name ? priv->bank_name : "", offset, gpio_function[func]); if (func == GPIOF_INPUT || func == GPIOF_OUTPUT || func == GPIOF_UNUSED) { const char *label; bool used; ret = ops->get_value(dev, offset); if (ret < 0) return ret; used = gpio_get_function(dev, offset, &label) != GPIOF_UNUSED; snprintf(str + len, buffsize - len, ": %d [%c]%s%s", ret, used ? 'x' : ' ', used ? " " : "", label ? label : ""); } return 0; }
/* Test that sandbox GPIOs work correctly */ static int dm_test_gpio(struct dm_test_state *dms) { unsigned int offset, gpio; struct dm_gpio_ops *ops; struct udevice *dev; const char *name; int offset_count; char buf[80]; /* * We expect to get 3 banks. One is anonymous (just numbered) and * comes from platdata. The other two are named a (20 gpios) * and b (10 gpios) and come from the device tree. See * test/dm/test.dts. */ ut_assertok(gpio_lookup_name("b4", &dev, &offset, &gpio)); ut_asserteq_str(dev->name, "extra-gpios"); ut_asserteq(4, offset); ut_asserteq(CONFIG_SANDBOX_GPIO_COUNT + 20 + 4, gpio); name = gpio_get_bank_info(dev, &offset_count); ut_asserteq_str("b", name); ut_asserteq(10, offset_count); /* Get the operations for this device */ ops = gpio_get_ops(dev); ut_assert(ops->get_state); /* Cannot get a value until it is reserved */ ut_asserteq(-1, ops->get_value(dev, offset)); /* * Now some tests that use the 'sandbox' back door. All GPIOs * should default to input, include b4 that we are using here. */ ut_assertok(ops->get_state(dev, offset, buf, sizeof(buf))); ut_asserteq_str("b4: in: 0 [ ]", buf); /* Change it to an output */ sandbox_gpio_set_direction(dev, offset, 1); ut_assertok(ops->get_state(dev, offset, buf, sizeof(buf))); ut_asserteq_str("b4: out: 0 [ ]", buf); sandbox_gpio_set_value(dev, offset, 1); ut_assertok(ops->get_state(dev, offset, buf, sizeof(buf))); ut_asserteq_str("b4: out: 1 [ ]", buf); ut_assertok(ops->request(dev, offset, "testing")); ut_assertok(ops->get_state(dev, offset, buf, sizeof(buf))); ut_asserteq_str("b4: out: 1 [x] testing", buf); /* Change the value a bit */ ut_asserteq(1, ops->get_value(dev, offset)); ut_assertok(ops->set_value(dev, offset, 0)); ut_asserteq(0, ops->get_value(dev, offset)); ut_assertok(ops->get_state(dev, offset, buf, sizeof(buf))); ut_asserteq_str("b4: out: 0 [x] testing", buf); ut_assertok(ops->set_value(dev, offset, 1)); ut_asserteq(1, ops->get_value(dev, offset)); /* Make it an input */ ut_assertok(ops->direction_input(dev, offset)); ut_assertok(ops->get_state(dev, offset, buf, sizeof(buf))); ut_asserteq_str("b4: in: 1 [x] testing", buf); sandbox_gpio_set_value(dev, offset, 0); ut_asserteq(0, sandbox_gpio_get_value(dev, offset)); ut_assertok(ops->get_state(dev, offset, buf, sizeof(buf))); ut_asserteq_str("b4: in: 0 [x] testing", buf); ut_assertok(ops->free(dev, offset)); ut_assertok(ops->get_state(dev, offset, buf, sizeof(buf))); ut_asserteq_str("b4: in: 0 [ ]", buf); /* Check the 'a' bank also */ ut_assertok(gpio_lookup_name("a15", &dev, &offset, &gpio)); ut_asserteq_str(dev->name, "base-gpios"); ut_asserteq(15, offset); ut_asserteq(CONFIG_SANDBOX_GPIO_COUNT + 15, gpio); name = gpio_get_bank_info(dev, &offset_count); ut_asserteq_str("a", name); ut_asserteq(20, offset_count); /* And the anonymous bank */ ut_assertok(gpio_lookup_name("14", &dev, &offset, &gpio)); ut_asserteq_str(dev->name, "gpio_sandbox"); ut_asserteq(14, offset); ut_asserteq(14, gpio); name = gpio_get_bank_info(dev, &offset_count); ut_asserteq_ptr(NULL, name); ut_asserteq(CONFIG_SANDBOX_GPIO_COUNT, offset_count); return 0; }