Skip to content

Commit

Permalink
gpio-generic: add bgpio_set_multiple functions
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Linus Walleij <[email protected]>
  • Loading branch information
Rojhalat Ibrahim authored and linusw committed Jan 19, 2015
1 parent 5138585 commit 73c4ced
Showing 1 changed file with 76 additions and 0 deletions.
76 changes: 76 additions & 0 deletions drivers/gpio/gpio-generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,79 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
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)
{
return 0;
Expand Down Expand Up @@ -354,11 +427,14 @@ static int bgpio_setup_io(struct bgpio_chip *bgc,
bgc->reg_set = set;
bgc->reg_clr = clr;
bgc->gc.set = bgpio_set_with_clear;
bgc->gc.set_multiple = bgpio_set_multiple_with_clear;
} else if (set && !clr) {
bgc->reg_set = set;
bgc->gc.set = bgpio_set_set;
bgc->gc.set_multiple = bgpio_set_multiple_set;
} else {
bgc->gc.set = bgpio_set;
bgc->gc.set_multiple = bgpio_set_multiple;
}

bgc->gc.get = bgpio_get;
Expand Down

0 comments on commit 73c4ced

Please sign in to comment.