diff options
Diffstat (limited to 'target/linux/generic-2.6/patches-2.6.25')
7 files changed, 528 insertions, 18 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.25/910-m25p80_redboot_partitions.patch b/target/linux/generic-2.6/patches-2.6.25/910-m25p80_redboot_partitions.patch new file mode 100644 index 0000000..5f35f00 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.25/910-m25p80_redboot_partitions.patch @@ -0,0 +1,17 @@ +diff -Nur a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c +--- a/drivers/mtd/devices/m25p80.c 2008-07-06 14:36:59.000000000 +0200 ++++ b/drivers/mtd/devices/m25p80.c 2008-07-06 15:17:48.000000000 +0200 +@@ -631,12 +631,10 @@ + struct mtd_partition *parts = NULL; + int nr_parts = 0; + +-#ifdef CONFIG_MTD_CMDLINE_PARTS +- static const char *part_probes[] = { "cmdlinepart", NULL, }; ++ static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL, }; + + nr_parts = parse_mtd_partitions(&flash->mtd, + part_probes, &parts, 0); +-#endif + + if (nr_parts <= 0 && data && data->parts) { + parts = data->parts; diff --git a/target/linux/generic-2.6/patches-2.6.25/920-backport-gpio-is-valid.patch b/target/linux/generic-2.6/patches-2.6.25/920-backport-gpio-is-valid.patch deleted file mode 100644 index 966270b..0000000 --- a/target/linux/generic-2.6/patches-2.6.25/920-backport-gpio-is-valid.patch +++ /dev/null @@ -1,18 +0,0 @@ -Backport gpio_is_valid() for gpiolib from linux-2.6.26 -Index: linux-2.6.25.10/include/asm-generic/gpio.h -=================================================================== ---- linux-2.6.25.10.orig/include/asm-generic/gpio.h 2008-07-03 05:46:47.000000000 +0200 -+++ linux-2.6.25.10/include/asm-generic/gpio.h 2008-07-20 20:32:12.000000000 +0200 -@@ -16,6 +16,12 @@ - #define ARCH_NR_GPIOS 256 - #endif - -+static inline int gpio_is_valid(int number) -+{ -+ /* only some non-negative numbers are valid */ -+ return ((unsigned)number) < ARCH_NR_GPIOS; -+} -+ - struct seq_file; - - /** diff --git a/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch b/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch new file mode 100644 index 0000000..a6822fc --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.25/960-backport_gpiolib_better_rmmod_infrastructure.patch @@ -0,0 +1,93 @@ +From: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> +Date: Mon, 28 Apr 2008 09:14:44 +0000 (-0700) +Subject: gpiolib: better rmmod infrastructure +X-Git-Tag: v2.6.26-rc1~851 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=438d8908b379b6322fc3b28d45c9ebdddf58bc20 + +gpiolib: better rmmod infrastructure + +As long as one or more GPIOs on a gpio chip are used its driver should not be +unloaded. The existing mechanism (gpiochip_remove failure) doesn't address +that, since rmmod can no longer be made to fail by having the cleanup code +report errors. Module usecounts are the solution. + +Assuming standard "initialize struct to zero" policies, this change won't +affect SOC platform drivers. However, drivers for external chips (on I2C and +SPI busses) should be updated if they can be built as modules. + +Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> +[ gpio_ensure_requested() needs to update module usecounts too ] +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 d8db2f8..eb75d12 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -68,6 +68,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc) + if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { + pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc)); + desc_set_label(desc, "[auto]"); ++ if (!try_module_get(desc->chip->owner)) ++ pr_err("GPIO-%d: module can't be gotten \n", ++ (int)(desc - gpio_desc)); + } + } + +@@ -177,6 +180,9 @@ int gpio_request(unsigned gpio, const char *label) + if (desc->chip == NULL) + goto done; + ++ if (!try_module_get(desc->chip->owner)) ++ goto done; ++ + /* NOTE: gpio_request() can be called in early boot, + * before IRQs are enabled. + */ +@@ -184,8 +190,10 @@ int gpio_request(unsigned gpio, const char *label) + if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { + desc_set_label(desc, label ? : "?"); + status = 0; +- } else ++ } else { + status = -EBUSY; ++ module_put(desc->chip->owner); ++ } + + done: + if (status) +@@ -209,9 +217,10 @@ void gpio_free(unsigned gpio) + spin_lock_irqsave(&gpio_lock, flags); + + desc = &gpio_desc[gpio]; +- if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) ++ if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) { + desc_set_label(desc, NULL); +- else ++ module_put(desc->chip->owner); ++ } else + WARN_ON(extra_checks); + + spin_unlock_irqrestore(&gpio_lock, flags); +diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h +index f29a502..7e77b6f 100644 +--- a/include/asm-generic/gpio.h ++++ b/include/asm-generic/gpio.h +@@ -17,6 +17,7 @@ + #endif + + struct seq_file; ++struct module; + + /** + * struct gpio_chip - abstract a GPIO controller +@@ -48,6 +49,7 @@ struct seq_file; + */ + struct gpio_chip { + char *label; ++ struct module *owner; + + int (*direction_input)(struct gpio_chip *chip, + unsigned offset); diff --git a/target/linux/generic-2.6/patches-2.6.25/961-backport_gpio_define_gpio_valid.patch b/target/linux/generic-2.6/patches-2.6.25/961-backport_gpio_define_gpio_valid.patch new file mode 100644 index 0000000..2e826d4 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.25/961-backport_gpio_define_gpio_valid.patch @@ -0,0 +1,136 @@ +From: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> +Date: Mon, 28 Apr 2008 09:14:46 +0000 (-0700) +Subject: gpio: define gpio_is_valid() +X-Git-Tag: v2.6.26-rc1~849 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=e6de1808f8ebfeb7e49f3c5a30cb8f2032beb287 + +gpio: define gpio_is_valid() + +Introduce a gpio_is_valid() predicate; use it in gpiolib. + +Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> + [ use inline function; follow the gpio_* naming convention; + work without gpiolib; all programming interfaces need docs ] +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/Documentation/gpio.txt b/Documentation/gpio.txt +index 5463009..c35ca9e 100644 +--- a/Documentation/gpio.txt ++++ b/Documentation/gpio.txt +@@ -107,6 +107,16 @@ type of GPIO controller, and on one particular board 80-95 with an FPGA. + The numbers need not be contiguous; either of those platforms could also + use numbers 2000-2063 to identify GPIOs in a bank of I2C GPIO expanders. + ++If you want to initialize a structure with an invalid GPIO number, use ++some negative number (perhaps "-EINVAL"); that will never be valid. To ++test if a number could reference a GPIO, you may use this predicate: ++ ++ int gpio_is_valid(int number); ++ ++A number that's not valid will be rejected by calls which may request ++or free GPIOs (see below). Other numbers may also be rejected; for ++example, a number might be valid but unused on a given board. ++ + Whether a platform supports multiple GPIO controllers is currently a + platform-specific implementation issue. + +diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c +index eb75d12..623fcd9 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -99,7 +99,7 @@ int gpiochip_add(struct gpio_chip *chip) + * dynamic allocation. We don't currently support that. + */ + +- if (chip->base < 0 || (chip->base + chip->ngpio) >= ARCH_NR_GPIOS) { ++ if (chip->base < 0 || !gpio_is_valid(chip->base + chip->ngpio)) { + status = -EINVAL; + goto fail; + } +@@ -174,7 +174,7 @@ int gpio_request(unsigned gpio, const char *label) + + spin_lock_irqsave(&gpio_lock, flags); + +- if (gpio >= ARCH_NR_GPIOS) ++ if (!gpio_is_valid(gpio)) + goto done; + desc = &gpio_desc[gpio]; + if (desc->chip == NULL) +@@ -209,7 +209,7 @@ void gpio_free(unsigned gpio) + unsigned long flags; + struct gpio_desc *desc; + +- if (gpio >= ARCH_NR_GPIOS) { ++ if (!gpio_is_valid(gpio)) { + WARN_ON(extra_checks); + return; + } +@@ -245,7 +245,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) + { + unsigned gpio = chip->base + offset; + +- if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip) ++ if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip) + return NULL; + if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0) + return NULL; +@@ -276,7 +276,7 @@ int gpio_direction_input(unsigned gpio) + + spin_lock_irqsave(&gpio_lock, flags); + +- if (gpio >= ARCH_NR_GPIOS) ++ if (!gpio_is_valid(gpio)) + goto fail; + chip = desc->chip; + if (!chip || !chip->get || !chip->direction_input) +@@ -314,7 +314,7 @@ int gpio_direction_output(unsigned gpio, int value) + + spin_lock_irqsave(&gpio_lock, flags); + +- if (gpio >= ARCH_NR_GPIOS) ++ if (!gpio_is_valid(gpio)) + goto fail; + chip = desc->chip; + if (!chip || !chip->set || !chip->direction_output) +@@ -531,7 +531,7 @@ static int gpiolib_show(struct seq_file *s, void *unused) + + /* REVISIT this isn't locked against gpio_chip removal ... */ + +- for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { ++ for (gpio = 0; gpio_is_valid(gpio); gpio++) { + if (chip == gpio_desc[gpio].chip) + continue; + chip = gpio_desc[gpio].chip; +diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h +index 7e77b6f..464c5b3 100644 +--- a/include/asm-generic/gpio.h ++++ b/include/asm-generic/gpio.h +@@ -16,6 +16,12 @@ + #define ARCH_NR_GPIOS 256 + #endif + ++static inline int gpio_is_valid(int number) ++{ ++ /* only some non-negative numbers are valid */ ++ return ((unsigned)number) < ARCH_NR_GPIOS; ++} ++ + struct seq_file; + struct module; + +@@ -99,6 +105,12 @@ extern int __gpio_cansleep(unsigned gpio); + + #else + ++static inline int gpio_is_valid(int number) ++{ ++ /* only non-negative numbers are valid */ ++ return number >= 0; ++} ++ + /* platforms that don't directly support access to GPIOs through I2C, SPI, + * or other blocking infrastructure can use these wrappers. + */ 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... */ diff --git a/target/linux/generic-2.6/patches-2.6.25/963-backport_gpio_chip_reserve.patch b/target/linux/generic-2.6/patches-2.6.25/963-backport_gpio_chip_reserve.patch new file mode 100644 index 0000000..306fb0a --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.25/963-backport_gpio_chip_reserve.patch @@ -0,0 +1,116 @@ +From: Anton Vorontsov <avorontsov@ru.mvista.com> +Date: Mon, 28 Apr 2008 09:14:47 +0000 (-0700) +Subject: gpiochip_reserve() +X-Git-Tag: v2.6.26-rc1~847 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=169b6a7a6e91e1ea32136681b475cbaf2074bf35 + +gpiochip_reserve() + +Add a new function gpiochip_reserve() to reserve ranges of gpios that platform +code has pre-allocated. That is, this marks gpio numbers which will be +claimed by drivers that haven't yet been loaded, and thus are not available +for dynamic gpio number allocation. + +[akpm@linux-foundation.org: remove unneeded __must_check] +[david-b@pacbell.net: don't export gpiochip_reserve (section fix)] +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 2ba6127..24c62b8 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -43,6 +43,7 @@ struct gpio_desc { + /* flag symbols are bit numbers */ + #define FLAG_REQUESTED 0 + #define FLAG_IS_OUT 1 ++#define FLAG_RESERVED 2 + + #ifdef CONFIG_DEBUG_FS + const char *label; +@@ -88,9 +89,10 @@ static int gpiochip_find_base(int ngpio) + int base = -ENOSPC; + + for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) { +- struct gpio_chip *chip = gpio_desc[i].chip; ++ struct gpio_desc *desc = &gpio_desc[i]; ++ struct gpio_chip *chip = desc->chip; + +- if (!chip) { ++ if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { + spare++; + if (spare == ngpio) { + base = i; +@@ -98,7 +100,8 @@ static int gpiochip_find_base(int ngpio) + } + } else { + spare = 0; +- i -= chip->ngpio - 1; ++ if (chip) ++ i -= chip->ngpio - 1; + } + } + +@@ -108,6 +111,47 @@ static int gpiochip_find_base(int ngpio) + } + + /** ++ * gpiochip_reserve() - reserve range of gpios to use with platform code only ++ * @start: starting gpio number ++ * @ngpio: number of gpios to reserve ++ * Context: platform init, potentially before irqs or kmalloc will work ++ * ++ * Returns a negative errno if any gpio within the range is already reserved ++ * or registered, else returns zero as a success code. Use this function ++ * to mark a range of gpios as unavailable for dynamic gpio number allocation, ++ * for example because its driver support is not yet loaded. ++ */ ++int __init gpiochip_reserve(int start, int ngpio) ++{ ++ int ret = 0; ++ unsigned long flags; ++ int i; ++ ++ if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&gpio_lock, flags); ++ ++ for (i = start; i < start + ngpio; i++) { ++ struct gpio_desc *desc = &gpio_desc[i]; ++ ++ if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) { ++ ret = -EBUSY; ++ goto err; ++ } ++ ++ set_bit(FLAG_RESERVED, &desc->flags); ++ } ++ ++ pr_debug("%s: reserved gpios from %d to %d\n", ++ __func__, start, start + ngpio - 1); ++err: ++ spin_unlock_irqrestore(&gpio_lock, flags); ++ ++ return ret; ++} ++ ++/** + * gpiochip_add() - register a gpio_chip + * @chip: the chip to register, with chip->base initialized + * Context: potentially before irqs or kmalloc will work +diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h +index 464c5b3..ecf675a 100644 +--- a/include/asm-generic/gpio.h ++++ b/include/asm-generic/gpio.h +@@ -74,6 +74,7 @@ struct gpio_chip { + + extern const char *gpiochip_is_requested(struct gpio_chip *chip, + unsigned offset); ++extern int __init __must_check gpiochip_reserve(int start, int ngpio); + + /* add/remove chips */ + extern int gpiochip_add(struct gpio_chip *chip); diff --git a/target/linux/generic-2.6/patches-2.6.25/964-backport_gpiolib_fix_off_by_one_errors.patch b/target/linux/generic-2.6/patches-2.6.25/964-backport_gpiolib_fix_off_by_one_errors.patch new file mode 100644 index 0000000..715f9ab --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.25/964-backport_gpiolib_fix_off_by_one_errors.patch @@ -0,0 +1,48 @@ +From: Trent Piepho <xyzzy@speakeasy.org> +Date: Fri, 23 May 2008 20:04:44 +0000 (-0700) +Subject: gpiolib: fix off by one errors +X-Git-Tag: v2.6.26-rc4~31 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=bff5fda972dc23bd1806a47c2098ae173585d013 + +gpiolib: fix off by one errors + +The last gpio belonging to a chip is chip->base + chip->ngpios - 1. Some +places in the code, but not all, forgot the critical minus one. + +Signed-off-by: Trent Piepho <xyzzy@speakeasy.org> +Acked-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 7f138c6..beaf6b3 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -127,7 +127,7 @@ int __init gpiochip_reserve(int start, int ngpio) + unsigned long flags; + int i; + +- if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio)) ++ if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1)) + return -EINVAL; + + spin_lock_irqsave(&gpio_lock, flags); +@@ -170,7 +170,7 @@ int gpiochip_add(struct gpio_chip *chip) + unsigned id; + int base = chip->base; + +- if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio)) ++ if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1)) + && base >= 0) { + status = -EINVAL; + goto fail; +@@ -207,7 +207,7 @@ fail: + /* failures here can mean systems won't boot... */ + if (status) + pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n", +- chip->base, chip->base + chip->ngpio, ++ chip->base, chip->base + chip->ngpio - 1, + chip->label ? : "generic"); + return status; + } |