diff options
author | Rojhalat Ibrahim <imr@rtschenk.de> | 2015-01-14 09:46:38 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-01-19 05:07:00 -0500 |
commit | 73c4ceda09db2c9a2ff8bb2e90cc98ce1a827c34 (patch) | |
tree | 9faaca3e916d5e87f6083643fc2942d815d1b253 /drivers/gpio | |
parent | 513858585202171d7603024ea65659335df4c8e9 (diff) |
gpio-generic: add bgpio_set_multiple functions
Add set_multiple functions to the generic driver for memory-mapped GPIO
controllers to improve performance when setting multiple outputs
simultaneously.
Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpio-generic.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 16f6115e5bdb..b92a690f5765 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c | |||
@@ -190,6 +190,79 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) | |||
190 | spin_unlock_irqrestore(&bgc->lock, flags); | 190 | spin_unlock_irqrestore(&bgc->lock, flags); |
191 | } | 191 | } |
192 | 192 | ||
193 | static void bgpio_multiple_get_masks(struct bgpio_chip *bgc, | ||
194 | unsigned long *mask, unsigned long *bits, | ||
195 | unsigned long *set_mask, | ||
196 | unsigned long *clear_mask) | ||
197 | { | ||
198 | int i; | ||
199 | |||
200 | *set_mask = 0; | ||
201 | *clear_mask = 0; | ||
202 | |||
203 | for (i = 0; i < bgc->bits; i++) { | ||
204 | if (*mask == 0) | ||
205 | break; | ||
206 | if (__test_and_clear_bit(i, mask)) { | ||
207 | if (test_bit(i, bits)) | ||
208 | *set_mask |= bgc->pin2mask(bgc, i); | ||
209 | else | ||
210 | *clear_mask |= bgc->pin2mask(bgc, i); | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc, | ||
216 | unsigned long *mask, | ||
217 | unsigned long *bits, | ||
218 | void __iomem *reg) | ||
219 | { | ||
220 | unsigned long flags; | ||
221 | unsigned long set_mask, clear_mask; | ||
222 | |||
223 | spin_lock_irqsave(&bgc->lock, flags); | ||
224 | |||
225 | bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask); | ||
226 | |||
227 | bgc->data |= set_mask; | ||
228 | bgc->data &= ~clear_mask; | ||
229 | |||
230 | bgc->write_reg(reg, bgc->data); | ||
231 | |||
232 | spin_unlock_irqrestore(&bgc->lock, flags); | ||
233 | } | ||
234 | |||
235 | static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, | ||
236 | unsigned long *bits) | ||
237 | { | ||
238 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | ||
239 | |||
240 | bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_dat); | ||
241 | } | ||
242 | |||
243 | static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask, | ||
244 | unsigned long *bits) | ||
245 | { | ||
246 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | ||
247 | |||
248 | bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_set); | ||
249 | } | ||
250 | |||
251 | static void bgpio_set_multiple_with_clear(struct gpio_chip *gc, | ||
252 | unsigned long *mask, | ||
253 | unsigned long *bits) | ||
254 | { | ||
255 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | ||
256 | unsigned long set_mask, clear_mask; | ||
257 | |||
258 | bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask); | ||
259 | |||
260 | if (set_mask) | ||
261 | bgc->write_reg(bgc->reg_set, set_mask); | ||
262 | if (clear_mask) | ||
263 | bgc->write_reg(bgc->reg_clr, clear_mask); | ||
264 | } | ||
265 | |||
193 | static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) | 266 | static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) |
194 | { | 267 | { |
195 | return 0; | 268 | return 0; |
@@ -354,11 +427,14 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, | |||
354 | bgc->reg_set = set; | 427 | bgc->reg_set = set; |
355 | bgc->reg_clr = clr; | 428 | bgc->reg_clr = clr; |
356 | bgc->gc.set = bgpio_set_with_clear; | 429 | bgc->gc.set = bgpio_set_with_clear; |
430 | bgc->gc.set_multiple = bgpio_set_multiple_with_clear; | ||
357 | } else if (set && !clr) { | 431 | } else if (set && !clr) { |
358 | bgc->reg_set = set; | 432 | bgc->reg_set = set; |
359 | bgc->gc.set = bgpio_set_set; | 433 | bgc->gc.set = bgpio_set_set; |
434 | bgc->gc.set_multiple = bgpio_set_multiple_set; | ||
360 | } else { | 435 | } else { |
361 | bgc->gc.set = bgpio_set; | 436 | bgc->gc.set = bgpio_set; |
437 | bgc->gc.set_multiple = bgpio_set_multiple; | ||
362 | } | 438 | } |
363 | 439 | ||
364 | bgc->gc.get = bgpio_get; | 440 | bgc->gc.get = bgpio_get; |