aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-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... */