diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2008-07-21 17:08:14 +0000 |
---|---|---|
committer | Gabor Juhos <juhosg@openwrt.org> | 2008-07-21 17:08:14 +0000 |
commit | f529a3742043a23da4f715c3664d5a822b1f970c (patch) | |
tree | a4cdaee84e23765d98072df25883f365cbc0d66a /target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch | |
parent | 3d9c4c9073deaf01d592d6940af21be81d92e88a (diff) | |
download | mtk-20170518-f529a3742043a23da4f715c3664d5a822b1f970c.zip mtk-20170518-f529a3742043a23da4f715c3664d5a822b1f970c.tar.gz mtk-20170518-f529a3742043a23da4f715c3664d5a822b1f970c.tar.bz2 |
surprise :p
SVN-Revision: 11894
Diffstat (limited to 'target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch')
-rw-r--r-- | target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch b/target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch new file mode 100644 index 0000000..0007423 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.25/962-backport_gpiolib_dynamic_gpio_number_allocation.patch @@ -0,0 +1,118 @@ +From: Anton Vorontsov <avorontsov@ru.mvista.com> +Date: Mon, 28 Apr 2008 09:14:46 +0000 (-0700) +Subject: gpiolib: dynamic gpio number allocation +X-Git-Tag: v2.6.26-rc1~848 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=8d0aab2f16c4fa170f32e7a74a52cd0122bbafef + +gpiolib: dynamic gpio number allocation + +If gpio_chip->base is negative during registration, gpiolib performs dynamic +base allocation. This is useful for devices that aren't always present, such +as GPIOs on hotplugged devices rather than mainboards. (This behavior was +previously specified but not implemented.) + +To avoid using any numbers that may have been explicitly assigned but not yet +registered, this dynamic allocation assigns GPIO numbers from the biggest +number on down, instead of from the smallest on up. + +Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c +index 623fcd9..2ba6127 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -80,6 +80,33 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio) + return gpio_desc[gpio].chip; + } + ++/* dynamic allocation of GPIOs, e.g. on a hotplugged device */ ++static int gpiochip_find_base(int ngpio) ++{ ++ int i; ++ int spare = 0; ++ int base = -ENOSPC; ++ ++ for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) { ++ struct gpio_chip *chip = gpio_desc[i].chip; ++ ++ if (!chip) { ++ spare++; ++ if (spare == ngpio) { ++ base = i; ++ break; ++ } ++ } else { ++ spare = 0; ++ i -= chip->ngpio - 1; ++ } ++ } ++ ++ if (gpio_is_valid(base)) ++ pr_debug("%s: found new base at %d\n", __func__, base); ++ return base; ++} ++ + /** + * gpiochip_add() - register a gpio_chip + * @chip: the chip to register, with chip->base initialized +@@ -88,38 +115,49 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio) + * Returns a negative errno if the chip can't be registered, such as + * because the chip->base is invalid or already associated with a + * different chip. Otherwise it returns zero as a success code. ++ * ++ * If chip->base is negative, this requests dynamic assignment of ++ * a range of valid GPIOs. + */ + int gpiochip_add(struct gpio_chip *chip) + { + unsigned long flags; + int status = 0; + unsigned id; ++ int base = chip->base; + +- /* NOTE chip->base negative is reserved to mean a request for +- * dynamic allocation. We don't currently support that. +- */ +- +- if (chip->base < 0 || !gpio_is_valid(chip->base + chip->ngpio)) { ++ if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio)) ++ && base >= 0) { + status = -EINVAL; + goto fail; + } + + spin_lock_irqsave(&gpio_lock, flags); + ++ if (base < 0) { ++ base = gpiochip_find_base(chip->ngpio); ++ if (base < 0) { ++ status = base; ++ goto fail_unlock; ++ } ++ chip->base = base; ++ } ++ + /* these GPIO numbers must not be managed by another gpio_chip */ +- for (id = chip->base; id < chip->base + chip->ngpio; id++) { ++ for (id = base; id < base + chip->ngpio; id++) { + if (gpio_desc[id].chip != NULL) { + status = -EBUSY; + break; + } + } + if (status == 0) { +- for (id = chip->base; id < chip->base + chip->ngpio; id++) { ++ for (id = base; id < base + chip->ngpio; id++) { + gpio_desc[id].chip = chip; + gpio_desc[id].flags = 0; + } + } + ++fail_unlock: + spin_unlock_irqrestore(&gpio_lock, flags); + fail: + /* failures here can mean systems won't boot... */ |