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>
This commit is contained in:
Rojhalat Ibrahim 2015-01-14 15:46:38 +01:00 committed by Linus Walleij
parent 5138585852
commit 73c4ceda09

View File

@ -190,6 +190,79 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
spin_unlock_irqrestore(&bgc->lock, flags); spin_unlock_irqrestore(&bgc->lock, flags);
} }
static void bgpio_multiple_get_masks(struct bgpio_chip *bgc,
unsigned long *mask, unsigned long *bits,
unsigned long *set_mask,
unsigned long *clear_mask)
{
int i;
*set_mask = 0;
*clear_mask = 0;
for (i = 0; i < bgc->bits; i++) {
if (*mask == 0)
break;
if (__test_and_clear_bit(i, mask)) {
if (test_bit(i, bits))
*set_mask |= bgc->pin2mask(bgc, i);
else
*clear_mask |= bgc->pin2mask(bgc, i);
}
}
}
static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc,
unsigned long *mask,
unsigned long *bits,
void __iomem *reg)
{
unsigned long flags;
unsigned long set_mask, clear_mask;
spin_lock_irqsave(&bgc->lock, flags);
bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask);
bgc->data |= set_mask;
bgc->data &= ~clear_mask;
bgc->write_reg(reg, bgc->data);
spin_unlock_irqrestore(&bgc->lock, flags);
}
static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
unsigned long *bits)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_dat);
}
static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask,
unsigned long *bits)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_set);
}
static void bgpio_set_multiple_with_clear(struct gpio_chip *gc,
unsigned long *mask,
unsigned long *bits)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long set_mask, clear_mask;
bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask);
if (set_mask)
bgc->write_reg(bgc->reg_set, set_mask);
if (clear_mask)
bgc->write_reg(bgc->reg_clr, clear_mask);
}
static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
{ {
return 0; return 0;
@ -354,11 +427,14 @@ static int bgpio_setup_io(struct bgpio_chip *bgc,
bgc->reg_set = set; bgc->reg_set = set;
bgc->reg_clr = clr; bgc->reg_clr = clr;
bgc->gc.set = bgpio_set_with_clear; bgc->gc.set = bgpio_set_with_clear;
bgc->gc.set_multiple = bgpio_set_multiple_with_clear;
} else if (set && !clr) { } else if (set && !clr) {
bgc->reg_set = set; bgc->reg_set = set;
bgc->gc.set = bgpio_set_set; bgc->gc.set = bgpio_set_set;
bgc->gc.set_multiple = bgpio_set_multiple_set;
} else { } else {
bgc->gc.set = bgpio_set; bgc->gc.set = bgpio_set;
bgc->gc.set_multiple = bgpio_set_multiple;
} }
bgc->gc.get = bgpio_get; bgc->gc.get = bgpio_get;