aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2008-04-28 05:14:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:34 -0400
commit8d0aab2f16c4fa170f32e7a74a52cd0122bbafef (patch)
treec9e559489af8f2cbcceda8a323e4ac496114765a /drivers/gpio/gpiolib.c
parente6de1808f8ebfeb7e49f3c5a30cb8f2032beb287 (diff)
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>
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c52
1 files changed, 45 insertions, 7 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 623fcd9b547a..2ba6127c4fae 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)
80 return gpio_desc[gpio].chip; 80 return gpio_desc[gpio].chip;
81} 81}
82 82
83/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
84static int gpiochip_find_base(int ngpio)
85{
86 int i;
87 int spare = 0;
88 int base = -ENOSPC;
89
90 for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
91 struct gpio_chip *chip = gpio_desc[i].chip;
92
93 if (!chip) {
94 spare++;
95 if (spare == ngpio) {
96 base = i;
97 break;
98 }
99 } else {
100 spare = 0;
101 i -= chip->ngpio - 1;
102 }
103 }
104
105 if (gpio_is_valid(base))
106 pr_debug("%s: found new base at %d\n", __func__, base);
107 return base;
108}
109
83/** 110/**
84 * gpiochip_add() - register a gpio_chip 111 * gpiochip_add() - register a gpio_chip
85 * @chip: the chip to register, with chip->base initialized 112 * @chip: the chip to register, with chip->base initialized
@@ -88,38 +115,49 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
88 * Returns a negative errno if the chip can't be registered, such as 115 * Returns a negative errno if the chip can't be registered, such as
89 * because the chip->base is invalid or already associated with a 116 * because the chip->base is invalid or already associated with a
90 * different chip. Otherwise it returns zero as a success code. 117 * different chip. Otherwise it returns zero as a success code.
118 *
119 * If chip->base is negative, this requests dynamic assignment of
120 * a range of valid GPIOs.
91 */ 121 */
92int gpiochip_add(struct gpio_chip *chip) 122int gpiochip_add(struct gpio_chip *chip)
93{ 123{
94 unsigned long flags; 124 unsigned long flags;
95 int status = 0; 125 int status = 0;
96 unsigned id; 126 unsigned id;
127 int base = chip->base;
97 128
98 /* NOTE chip->base negative is reserved to mean a request for 129 if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio))
99 * dynamic allocation. We don't currently support that. 130 && base >= 0) {
100 */
101
102 if (chip->base < 0 || !gpio_is_valid(chip->base + chip->ngpio)) {
103 status = -EINVAL; 131 status = -EINVAL;
104 goto fail; 132 goto fail;
105 } 133 }
106 134
107 spin_lock_irqsave(&gpio_lock, flags); 135 spin_lock_irqsave(&gpio_lock, flags);
108 136
137 if (base < 0) {
138 base = gpiochip_find_base(chip->ngpio);
139 if (base < 0) {
140 status = base;
141 goto fail_unlock;
142 }
143 chip->base = base;
144 }
145
109 /* these GPIO numbers must not be managed by another gpio_chip */ 146 /* these GPIO numbers must not be managed by another gpio_chip */
110 for (id = chip->base; id < chip->base + chip->ngpio; id++) { 147 for (id = base; id < base + chip->ngpio; id++) {
111 if (gpio_desc[id].chip != NULL) { 148 if (gpio_desc[id].chip != NULL) {
112 status = -EBUSY; 149 status = -EBUSY;
113 break; 150 break;
114 } 151 }
115 } 152 }
116 if (status == 0) { 153 if (status == 0) {
117 for (id = chip->base; id < chip->base + chip->ngpio; id++) { 154 for (id = base; id < base + chip->ngpio; id++) {
118 gpio_desc[id].chip = chip; 155 gpio_desc[id].chip = chip;
119 gpio_desc[id].flags = 0; 156 gpio_desc[id].flags = 0;
120 } 157 }
121 } 158 }
122 159
160fail_unlock:
123 spin_unlock_irqrestore(&gpio_lock, flags); 161 spin_unlock_irqrestore(&gpio_lock, flags);
124fail: 162fail:
125 /* failures here can mean systems won't boot... */ 163 /* failures here can mean systems won't boot... */