X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fgpio%2Fgpio-uclass.c;h=4cce11fe215f05b2cfbc1d55b5c4e020940b1ee6;hb=ef159abf99a2c6654c14f7db14df465a964b50c6;hp=0a4d9e421781cd1b7eedf7707cc347e2cf36f23c;hpb=0dac4d51f50e9252dbc00075cf65eeba57017926;p=u-boot diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 0a4d9e4217..4cce11fe21 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -12,6 +12,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + /** * gpio_to_device() - Convert global GPIO number to device, number * @@ -32,7 +34,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; @@ -46,8 +48,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; @@ -55,15 +56,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 */ @@ -82,18 +81,39 @@ 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 = dev; + *devp = NULL; + ret = dm_gpio_lookup_name(name, &desc); + if (ret) + return ret; + + if (devp) + *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_find_and_xlate(struct gpio_desc *desc, - struct fdtdec_phandle_args *args) +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); @@ -107,14 +127,14 @@ int gpio_find_and_xlate(struct gpio_desc *desc, return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0; } -static int dm_gpio_request(struct gpio_desc *desc, const char *label) +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); @@ -132,6 +152,17 @@ 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, ...) +{ + 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); +} + /** * gpio_request() - [COMPAT] Request GPIO * gpio: GPIO number @@ -182,7 +213,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) { @@ -219,8 +250,12 @@ int gpio_free(unsigned gpio) static int check_reserved(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, @@ -389,7 +424,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; @@ -407,7 +442,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)); @@ -455,7 +490,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; @@ -482,25 +517,202 @@ 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; } +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; + 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) { @@ -518,7 +730,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; } @@ -527,9 +739,21 @@ static int gpio_renumber(struct udevice *removed_dev) return 0; } +int gpio_get_number(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) @@ -540,7 +764,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++) { @@ -555,6 +779,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),