X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fgpio%2Fgpio-uclass.c;h=4559739d619c637d79495e349290b7ae93646de9;hb=ca75159d8abc085b39e3e468ca34ccb2940d2bf5;hp=2f3c36b48ff652d4f81a169a67f97c6a45acfab5;hpb=ae7123f876357a81fc4c393239a378f1058cad5e;p=u-boot diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 2f3c36b48f..4559739d61 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -6,11 +6,16 @@ #include #include +#include #include +#include #include #include +#include #include +DECLARE_GLOBAL_DATA_PTR; + /** * gpio_to_device() - Convert global GPIO number to device, number * @@ -31,7 +36,7 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc) for (ret = uclass_first_device(UCLASS_GPIO, &dev); dev; ret = uclass_next_device(&dev)) { - uc_priv = dev->uclass_priv; + uc_priv = dev_get_uclass_priv(dev); if (gpio >= uc_priv->gpio_base && gpio < uc_priv->gpio_base + uc_priv->gpio_count) { desc->dev = dev; @@ -45,8 +50,7 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc) return ret ? ret : -ENOENT; } -int gpio_lookup_name(const char *name, struct udevice **devp, - unsigned int *offsetp, unsigned int *gpiop) +int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc) { struct gpio_dev_priv *uc_priv = NULL; struct udevice *dev; @@ -54,15 +58,13 @@ int gpio_lookup_name(const char *name, struct udevice **devp, int numeric; int ret; - if (devp) - *devp = NULL; numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1; for (ret = uclass_first_device(UCLASS_GPIO, &dev); dev; ret = uclass_next_device(&dev)) { int len; - uc_priv = dev->uclass_priv; + uc_priv = dev_get_uclass_priv(dev); if (numeric != -1) { offset = numeric - uc_priv->gpio_base; /* Allow GPIOs to be numbered from 0 */ @@ -81,24 +83,74 @@ int gpio_lookup_name(const char *name, struct udevice **devp, if (!dev) return ret ? ret : -EINVAL; + desc->dev = dev; + desc->offset = offset; + + return 0; +} + +int gpio_lookup_name(const char *name, struct udevice **devp, + unsigned int *offsetp, unsigned int *gpiop) +{ + struct gpio_desc desc; + int ret; + + if (devp) + *devp = NULL; + ret = dm_gpio_lookup_name(name, &desc); + if (ret) + return ret; + if (devp) - *devp = dev; + *devp = desc.dev; if (offsetp) - *offsetp = offset; - if (gpiop) - *gpiop = uc_priv->gpio_base + offset; + *offsetp = desc.offset; + if (gpiop) { + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc.dev); + + *gpiop = uc_priv->gpio_base + desc.offset; + } + + return 0; +} + +int gpio_xlate_offs_flags(struct udevice *dev, + struct gpio_desc *desc, + struct fdtdec_phandle_args *args) +{ + if (args->args_count < 1) + return -EINVAL; + + desc->offset = args->args[0]; + + if (args->args_count < 2) + return 0; + + if (args->args[1] & GPIO_ACTIVE_LOW) + desc->flags = GPIOD_ACTIVE_LOW; return 0; } -static int dm_gpio_request(struct gpio_desc *desc, const char *label) +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); + + if (ops->xlate) + return ops->xlate(desc->dev, desc, args); + else + return gpio_xlate_offs_flags(desc->dev, desc, args); +} + +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->uclass_priv; + uc_priv = dev_get_uclass_priv(dev); if (uc_priv->name[desc->offset]) return -EBUSY; str = strdup(label); @@ -116,6 +168,21 @@ static int dm_gpio_request(struct gpio_desc *desc, const char *label) return 0; } +static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...) +{ +#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_USE_TINY_PRINTF) + va_list args; + char buf[40]; + + va_start(args, fmt); + vscnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + return dm_gpio_request(desc, buf); +#else + return dm_gpio_request(desc, fmt); +#endif +} + /** * gpio_request() - [COMPAT] Request GPIO * gpio: GPIO number @@ -152,6 +219,7 @@ int gpio_request(unsigned gpio, const char *label) */ int gpio_requestf(unsigned gpio, const char *fmt, ...) { +#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_USE_TINY_PRINTF) va_list args; char buf[40]; @@ -159,6 +227,9 @@ int gpio_requestf(unsigned gpio, const char *fmt, ...) vscnprintf(buf, sizeof(buf), fmt, args); va_end(args); return gpio_request(gpio, buf); +#else + return gpio_request(gpio, fmt); +#endif } int _dm_gpio_free(struct udevice *dev, uint offset) @@ -166,7 +237,7 @@ int _dm_gpio_free(struct udevice *dev, uint offset) struct gpio_dev_priv *uc_priv; int ret; - uc_priv = dev->uclass_priv; + uc_priv = dev_get_uclass_priv(dev); if (!uc_priv->name[offset]) return -ENXIO; if (gpio_get_ops(dev)->free) { @@ -201,10 +272,14 @@ int gpio_free(unsigned gpio) return _dm_gpio_free(desc.dev, desc.offset); } -static int check_reserved(struct gpio_desc *desc, const char *func) +static int check_reserved(const struct gpio_desc *desc, const char *func) { - struct gpio_dev_priv *uc_priv = desc->dev->uclass_priv; + struct gpio_dev_priv *uc_priv; + + if (!dm_gpio_is_valid(desc)) + return -ENOENT; + uc_priv = dev_get_uclass_priv(desc->dev); if (!uc_priv->name[desc->offset]) { printf("%s: %s: error: gpio %s%d not reserved\n", desc->dev->name, func, @@ -264,7 +339,7 @@ int gpio_direction_output(unsigned gpio, int value) desc.offset, value); } -int dm_gpio_get_value(struct gpio_desc *desc) +int dm_gpio_get_value(const struct gpio_desc *desc) { int value; int ret; @@ -278,7 +353,7 @@ int dm_gpio_get_value(struct gpio_desc *desc) return desc->flags & GPIOD_ACTIVE_LOW ? !value : value; } -int dm_gpio_set_value(struct gpio_desc *desc, int value) +int dm_gpio_set_value(const struct gpio_desc *desc, int value) { int ret; @@ -292,6 +367,38 @@ int dm_gpio_set_value(struct gpio_desc *desc, int value) return 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; +} + +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 dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) { struct udevice *dev = desc->dev; @@ -373,7 +480,7 @@ const char *gpio_get_bank_info(struct udevice *dev, int *bit_count) struct gpio_dev_priv *priv; /* Must be called on an active device */ - priv = dev->uclass_priv; + priv = dev_get_uclass_priv(dev); assert(priv); *bit_count = priv->gpio_count; @@ -391,7 +498,7 @@ static const char * const gpio_function[GPIOF_COUNT] = { int get_function(struct udevice *dev, int offset, bool skip_unused, const char **namep) { - struct gpio_dev_priv *uc_priv = dev->uclass_priv; + 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)); @@ -439,7 +546,7 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize) BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function)); *buf = 0; - priv = dev->uclass_priv; + priv = dev_get_uclass_priv(dev); ret = gpio_get_raw_function(dev, offset, NULL); if (ret < 0) return ret; @@ -466,25 +573,221 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize) return 0; } +int gpio_claim_vector(const int *gpio_num_array, const char *fmt) +{ + int i, ret; + int gpio; + + for (i = 0; i < 32; i++) { + gpio = gpio_num_array[i]; + if (gpio == -1) + break; + ret = gpio_requestf(gpio, fmt, i); + if (ret) + goto err; + ret = gpio_direction_input(gpio); + if (ret) { + gpio_free(gpio); + goto err; + } + } + + return 0; +err: + for (i--; i >= 0; i--) + gpio_free(gpio_num_array[i]); + + return ret; +} + /* * get a number comprised of multiple GPIO values. gpio_num_array points to * the array of gpio pin numbers to scan, terminated by -1. */ -unsigned gpio_get_values_as_int(const int *gpio_num_array) +int gpio_get_values_as_int(const int *gpio_list) { int gpio; unsigned bitmask = 1; unsigned vector = 0; + int ret; while (bitmask && - ((gpio = *gpio_num_array++) != -1)) { - if (gpio_get_value(gpio)) + ((gpio = *gpio_list++) != -1)) { + ret = gpio_get_value(gpio); + if (ret < 0) + return ret; + else if (ret) + vector |= bitmask; + bitmask <<= 1; + } + + return vector; +} + +int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count) +{ + unsigned bitmask = 1; + unsigned vector = 0; + int ret, i; + + for (i = 0; i < count; i++) { + ret = dm_gpio_get_value(&desc_list[i]); + if (ret < 0) + return ret; + else if (ret) vector |= bitmask; bitmask <<= 1; } + return vector; } +static int _gpio_request_by_name_nodev(const void *blob, int node, + const char *list_name, int index, + struct gpio_desc *desc, int flags, + bool add_index) +{ + struct fdtdec_phandle_args args; + int ret; + + desc->dev = NULL; + desc->offset = 0; + desc->flags = 0; + ret = fdtdec_parse_phandle_with_args(blob, node, list_name, + "#gpio-cells", 0, index, &args); + if (ret) { + debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__); + goto err; + } + + ret = uclass_get_device_by_of_offset(UCLASS_GPIO, args.node, + &desc->dev); + if (ret) { + debug("%s: uclass_get_device_by_of_offset failed\n", __func__); + goto err; + } + ret = gpio_find_and_xlate(desc, &args); + if (ret) { + debug("%s: gpio_find_and_xlate failed\n", __func__); + goto err; + } + ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s", + fdt_get_name(blob, node, NULL), + list_name, index); + if (ret) { + debug("%s: dm_gpio_requestf failed\n", __func__); + goto err; + } + ret = dm_gpio_set_dir_flags(desc, flags | desc->flags); + if (ret) { + debug("%s: dm_gpio_set_dir failed\n", __func__); + goto err; + } + + return 0; +err: + debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n", + __func__, fdt_get_name(blob, node, NULL), list_name, index, ret); + return ret; +} + +int gpio_request_by_name_nodev(const void *blob, int node, + const char *list_name, int index, + struct gpio_desc *desc, int flags) +{ + return _gpio_request_by_name_nodev(blob, node, list_name, index, desc, + flags, index > 0); +} + +int gpio_request_by_name(struct udevice *dev, const char *list_name, int index, + struct gpio_desc *desc, int flags) +{ + /* + * This isn't ideal since we don't use dev->name in the debug() + * calls in gpio_request_by_name(), but we can do this until + * gpio_request_by_name_nodev() can be dropped. + */ + return gpio_request_by_name_nodev(gd->fdt_blob, dev->of_offset, + list_name, index, desc, flags); +} + +int gpio_request_list_by_name_nodev(const void *blob, int node, + const char *list_name, + struct gpio_desc *desc, int max_count, + int flags) +{ + int count; + int ret; + + for (count = 0; count < max_count; count++) { + ret = _gpio_request_by_name_nodev(blob, node, list_name, count, + &desc[count], flags, true); + if (ret == -ENOENT) + break; + else if (ret) + goto err; + } + + /* We ran out of GPIOs in the list */ + return count; + +err: + gpio_free_list_nodev(desc, count - 1); + + return ret; +} + +int gpio_request_list_by_name(struct udevice *dev, const char *list_name, + struct gpio_desc *desc, int max_count, + int flags) +{ + /* + * This isn't ideal since we don't use dev->name in the debug() + * calls in gpio_request_by_name(), but we can do this until + * gpio_request_list_by_name_nodev() can be dropped. + */ + return gpio_request_list_by_name_nodev(gd->fdt_blob, dev->of_offset, + list_name, desc, max_count, + flags); +} + +int gpio_get_list_count(struct udevice *dev, const char *list_name) +{ + int ret; + + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, + list_name, "#gpio-cells", 0, -1, + NULL); + if (ret) { + debug("%s: Node '%s', property '%s', GPIO count failed: %d\n", + __func__, dev->name, list_name, ret); + } + + return ret; +} + +int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc) +{ + /* For now, we don't do any checking of dev */ + return _dm_gpio_free(desc->dev, desc->offset); +} + +int gpio_free_list(struct udevice *dev, struct gpio_desc *desc, int count) +{ + int i; + + /* For now, we don't do any checking of dev */ + for (i = 0; i < count; i++) + dm_gpio_free(dev, &desc[i]); + + return 0; +} + +int gpio_free_list_nodev(struct gpio_desc *desc, int count) +{ + return gpio_free_list(NULL, desc, count); +} + /* We need to renumber the GPIOs when any driver is probed/removed */ static int gpio_renumber(struct udevice *removed_dev) { @@ -502,7 +805,7 @@ static int gpio_renumber(struct udevice *removed_dev) base = 0; uclass_foreach_dev(dev, uc) { if (device_active(dev) && dev != removed_dev) { - uc_priv = dev->uclass_priv; + uc_priv = dev_get_uclass_priv(dev); uc_priv->gpio_base = base; base += uc_priv->gpio_count; } @@ -511,9 +814,21 @@ static int gpio_renumber(struct udevice *removed_dev) return 0; } +int gpio_get_number(const struct gpio_desc *desc) +{ + struct udevice *dev = desc->dev; + struct gpio_dev_priv *uc_priv; + + if (!dev) + return -1; + uc_priv = dev->uclass_priv; + + return uc_priv->gpio_base + desc->offset; +} + static int gpio_post_probe(struct udevice *dev) { - struct gpio_dev_priv *uc_priv = dev->uclass_priv; + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); uc_priv->name = calloc(uc_priv->gpio_count, sizeof(char *)); if (!uc_priv->name) @@ -524,7 +839,7 @@ static int gpio_post_probe(struct udevice *dev) static int gpio_pre_remove(struct udevice *dev) { - struct gpio_dev_priv *uc_priv = dev->uclass_priv; + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); int i; for (i = 0; i < uc_priv->gpio_count; i++) { @@ -539,6 +854,7 @@ static int gpio_pre_remove(struct udevice *dev) UCLASS_DRIVER(gpio) = { .id = UCLASS_GPIO, .name = "gpio", + .flags = DM_UC_FLAG_SEQ_ALIAS, .post_probe = gpio_post_probe, .pre_remove = gpio_pre_remove, .per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),