Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73c4ceda authored by Rojhalat Ibrahim's avatar Rojhalat Ibrahim Committed by Linus Walleij
Browse files

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: default avatarRojhalat Ibrahim <imr@rtschenk.de>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 51385858
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;