aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorRojhalat Ibrahim <imr@rtschenk.de>2015-01-14 09:46:38 -0500
committerLinus Walleij <linus.walleij@linaro.org>2015-01-19 05:07:00 -0500
commit73c4ceda09db2c9a2ff8bb2e90cc98ce1a827c34 (patch)
tree9faaca3e916d5e87f6083643fc2942d815d1b253 /drivers/gpio
parent513858585202171d7603024ea65659335df4c8e9 (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.c76
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
193static 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
215static 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
235static 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
243static 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
251static 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
193static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) 266static 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;