Commit 35d13d94 authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Linus Torvalds

gpio: pca953x: convert to use bitmap API

Instead of customized approach convert the driver to use bitmap API.

[andriy.shevchenko@linux.intel.com: reduce stack usage in couple of functions]
  Link: http://lkml.kernel.org/r/20191023153056.64262-1-andriy.shevchenko@linux.intel.com
Link: http://lkml.kernel.org/r/20191022172922.61232-11-andriy.shevchenko@linux.intel.comSigned-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Cc: William Breathitt Gray <vilhelm.gray@gmail.com>
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Cc: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Yury Norov <yury.norov@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0a0a0219
...@@ -9,8 +9,7 @@ ...@@ -9,8 +9,7 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/bits.h> #include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -116,6 +115,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids); ...@@ -116,6 +115,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
#define MAX_BANK 5 #define MAX_BANK 5
#define BANK_SZ 8 #define BANK_SZ 8
#define MAX_LINE (MAX_BANK * BANK_SZ)
#define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ) #define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
...@@ -147,10 +147,10 @@ struct pca953x_chip { ...@@ -147,10 +147,10 @@ struct pca953x_chip {
#ifdef CONFIG_GPIO_PCA953X_IRQ #ifdef CONFIG_GPIO_PCA953X_IRQ
struct mutex irq_lock; struct mutex irq_lock;
u8 irq_mask[MAX_BANK]; DECLARE_BITMAP(irq_mask, MAX_LINE);
u8 irq_stat[MAX_BANK]; DECLARE_BITMAP(irq_stat, MAX_LINE);
u8 irq_trig_raise[MAX_BANK]; DECLARE_BITMAP(irq_trig_raise, MAX_LINE);
u8 irq_trig_fall[MAX_BANK]; DECLARE_BITMAP(irq_trig_fall, MAX_LINE);
struct irq_chip irq_chip; struct irq_chip irq_chip;
#endif #endif
atomic_t wakeup_path; atomic_t wakeup_path;
...@@ -334,12 +334,16 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off, ...@@ -334,12 +334,16 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off,
return regaddr; return regaddr;
} }
static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
{ {
u8 regaddr = pca953x_recalc_addr(chip, reg, 0, true, true); u8 regaddr = pca953x_recalc_addr(chip, reg, 0, true, true);
int ret; u8 value[MAX_BANK];
int i, ret;
for (i = 0; i < NBANK(chip); i++)
value[i] = bitmap_get_value8(val, i * BANK_SZ);
ret = regmap_bulk_write(chip->regmap, regaddr, val, NBANK(chip)); ret = regmap_bulk_write(chip->regmap, regaddr, value, NBANK(chip));
if (ret < 0) { if (ret < 0) {
dev_err(&chip->client->dev, "failed writing register\n"); dev_err(&chip->client->dev, "failed writing register\n");
return ret; return ret;
...@@ -348,17 +352,21 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) ...@@ -348,17 +352,21 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
return 0; return 0;
} }
static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val) static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
{ {
u8 regaddr = pca953x_recalc_addr(chip, reg, 0, false, true); u8 regaddr = pca953x_recalc_addr(chip, reg, 0, false, true);
int ret; u8 value[MAX_BANK];
int i, ret;
ret = regmap_bulk_read(chip->regmap, regaddr, val, NBANK(chip)); ret = regmap_bulk_read(chip->regmap, regaddr, value, NBANK(chip));
if (ret < 0) { if (ret < 0) {
dev_err(&chip->client->dev, "failed reading register\n"); dev_err(&chip->client->dev, "failed reading register\n");
return ret; return ret;
} }
for (i = 0; i < NBANK(chip); i++)
bitmap_set_value8(val, value[i], i * BANK_SZ);
return 0; return 0;
} }
...@@ -460,10 +468,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc, ...@@ -460,10 +468,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits) unsigned long *mask, unsigned long *bits)
{ {
struct pca953x_chip *chip = gpiochip_get_data(gc); struct pca953x_chip *chip = gpiochip_get_data(gc);
unsigned long offset; DECLARE_BITMAP(reg_val, MAX_LINE);
unsigned long bank_mask;
int bank;
u8 reg_val[MAX_BANK];
int ret; int ret;
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
...@@ -471,11 +476,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc, ...@@ -471,11 +476,7 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
if (ret) if (ret)
goto exit; goto exit;
for_each_set_clump8(offset, bank_mask, mask, gc->ngpio) { bitmap_replace(reg_val, reg_val, bits, mask, gc->ngpio);
bank = offset / 8;
reg_val[bank] &= ~bank_mask;
reg_val[bank] |= bitmap_get_value8(bits, offset) & bank_mask;
}
pca953x_write_regs(chip, chip->regs->output, reg_val); pca953x_write_regs(chip, chip->regs->output, reg_val);
exit: exit:
...@@ -602,10 +603,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) ...@@ -602,10 +603,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pca953x_chip *chip = gpiochip_get_data(gc); struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 new_irqs; DECLARE_BITMAP(irq_mask, MAX_LINE);
int level, i; DECLARE_BITMAP(reg_direction, MAX_LINE);
u8 invert_irq_mask[MAX_BANK]; int level;
u8 reg_direction[MAX_BANK];
pca953x_read_regs(chip, chip->regs->direction, reg_direction); pca953x_read_regs(chip, chip->regs->direction, reg_direction);
...@@ -613,25 +613,18 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) ...@@ -613,25 +613,18 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
/* Enable latch on interrupt-enabled inputs */ /* Enable latch on interrupt-enabled inputs */
pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask); pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
for (i = 0; i < NBANK(chip); i++) bitmap_complement(irq_mask, chip->irq_mask, gc->ngpio);
invert_irq_mask[i] = ~chip->irq_mask[i];
/* Unmask enabled interrupts */ /* Unmask enabled interrupts */
pca953x_write_regs(chip, PCAL953X_INT_MASK, invert_irq_mask); pca953x_write_regs(chip, PCAL953X_INT_MASK, irq_mask);
} }
bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
bitmap_and(irq_mask, irq_mask, reg_direction, gc->ngpio);
/* Look for any newly setup interrupt */ /* Look for any newly setup interrupt */
for (i = 0; i < NBANK(chip); i++) { for_each_set_bit(level, irq_mask, gc->ngpio)
new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i]; pca953x_gpio_direction_input(&chip->gpio_chip, level);
new_irqs &= reg_direction[i];
while (new_irqs) {
level = __ffs(new_irqs);
pca953x_gpio_direction_input(&chip->gpio_chip,
level + (BANK_SZ * i));
new_irqs &= ~(1 << level);
}
}
mutex_unlock(&chip->irq_lock); mutex_unlock(&chip->irq_lock);
} }
...@@ -672,15 +665,15 @@ static void pca953x_irq_shutdown(struct irq_data *d) ...@@ -672,15 +665,15 @@ static void pca953x_irq_shutdown(struct irq_data *d)
chip->irq_trig_fall[d->hwirq / BANK_SZ] &= ~mask; chip->irq_trig_fall[d->hwirq / BANK_SZ] &= ~mask;
} }
static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pending)
{ {
u8 cur_stat[MAX_BANK]; struct gpio_chip *gc = &chip->gpio_chip;
u8 old_stat[MAX_BANK]; DECLARE_BITMAP(reg_direction, MAX_LINE);
bool pending_seen = false; DECLARE_BITMAP(old_stat, MAX_LINE);
bool trigger_seen = false; DECLARE_BITMAP(cur_stat, MAX_LINE);
u8 trigger[MAX_BANK]; DECLARE_BITMAP(new_stat, MAX_LINE);
u8 reg_direction[MAX_BANK]; DECLARE_BITMAP(trigger, MAX_LINE);
int ret, i; int ret;
if (chip->driver_data & PCA_PCAL) { if (chip->driver_data & PCA_PCAL) {
/* Read the current interrupt status from the device */ /* Read the current interrupt status from the device */
...@@ -693,16 +686,12 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) ...@@ -693,16 +686,12 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
if (ret) if (ret)
return false; return false;
for (i = 0; i < NBANK(chip); i++) {
/* Apply filter for rising/falling edge selection */ /* Apply filter for rising/falling edge selection */
pending[i] = (~cur_stat[i] & chip->irq_trig_fall[i]) | bitmap_replace(new_stat, chip->irq_trig_fall, chip->irq_trig_raise, cur_stat, gc->ngpio);
(cur_stat[i] & chip->irq_trig_raise[i]);
pending[i] &= trigger[i]; bitmap_and(pending, new_stat, trigger, gc->ngpio);
if (pending[i])
pending_seen = true;
}
return pending_seen; return !bitmap_empty(pending, gc->ngpio);
} }
ret = pca953x_read_regs(chip, chip->regs->input, cur_stat); ret = pca953x_read_regs(chip, chip->regs->input, cur_stat);
...@@ -711,51 +700,38 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) ...@@ -711,51 +700,38 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
/* Remove output pins from the equation */ /* Remove output pins from the equation */
pca953x_read_regs(chip, chip->regs->direction, reg_direction); pca953x_read_regs(chip, chip->regs->direction, reg_direction);
for (i = 0; i < NBANK(chip); i++)
cur_stat[i] &= reg_direction[i];
memcpy(old_stat, chip->irq_stat, NBANK(chip)); bitmap_copy(old_stat, chip->irq_stat, gc->ngpio);
for (i = 0; i < NBANK(chip); i++) { bitmap_and(new_stat, cur_stat, reg_direction, gc->ngpio);
trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i]; bitmap_xor(cur_stat, new_stat, old_stat, gc->ngpio);
if (trigger[i]) bitmap_and(trigger, cur_stat, chip->irq_mask, gc->ngpio);
trigger_seen = true;
}
if (!trigger_seen) if (bitmap_empty(trigger, gc->ngpio))
return false; return false;
memcpy(chip->irq_stat, cur_stat, NBANK(chip)); bitmap_copy(chip->irq_stat, new_stat, gc->ngpio);
for (i = 0; i < NBANK(chip); i++) { bitmap_and(cur_stat, chip->irq_trig_fall, old_stat, gc->ngpio);
pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) | bitmap_and(old_stat, chip->irq_trig_raise, new_stat, gc->ngpio);
(cur_stat[i] & chip->irq_trig_raise[i]); bitmap_or(new_stat, old_stat, cur_stat, gc->ngpio);
pending[i] &= trigger[i]; bitmap_and(pending, new_stat, trigger, gc->ngpio);
if (pending[i])
pending_seen = true;
}
return pending_seen; return !bitmap_empty(pending, gc->ngpio);
} }
static irqreturn_t pca953x_irq_handler(int irq, void *devid) static irqreturn_t pca953x_irq_handler(int irq, void *devid)
{ {
struct pca953x_chip *chip = devid; struct pca953x_chip *chip = devid;
u8 pending[MAX_BANK]; struct gpio_chip *gc = &chip->gpio_chip;
u8 level; DECLARE_BITMAP(pending, MAX_LINE);
int i; int level;
if (!pca953x_irq_pending(chip, pending)) if (!pca953x_irq_pending(chip, pending))
return IRQ_NONE; return IRQ_NONE;
for (i = 0; i < NBANK(chip); i++) { for_each_set_bit(level, pending, gc->ngpio)
while (pending[i]) { handle_nested_irq(irq_find_mapping(gc->irq.domain, level));
level = __ffs(pending[i]);
handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
level + (BANK_SZ * i)));
pending[i] &= ~(1 << level);
}
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -765,8 +741,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -765,8 +741,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
{ {
struct i2c_client *client = chip->client; struct i2c_client *client = chip->client;
struct irq_chip *irq_chip = &chip->irq_chip; struct irq_chip *irq_chip = &chip->irq_chip;
u8 reg_direction[MAX_BANK]; DECLARE_BITMAP(reg_direction, MAX_LINE);
int ret, i; DECLARE_BITMAP(irq_stat, MAX_LINE);
int ret;
if (!client->irq) if (!client->irq)
return 0; return 0;
...@@ -777,7 +754,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -777,7 +754,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
if (!(chip->driver_data & PCA_INT)) if (!(chip->driver_data & PCA_INT))
return 0; return 0;
ret = pca953x_read_regs(chip, chip->regs->input, chip->irq_stat); ret = pca953x_read_regs(chip, chip->regs->input, irq_stat);
if (ret) if (ret)
return ret; return ret;
...@@ -787,8 +764,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -787,8 +764,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
* this purpose. * this purpose.
*/ */
pca953x_read_regs(chip, chip->regs->direction, reg_direction); pca953x_read_regs(chip, chip->regs->direction, reg_direction);
for (i = 0; i < NBANK(chip); i++) bitmap_and(chip->irq_stat, irq_stat, reg_direction, chip->gpio_chip.ngpio);
chip->irq_stat[i] &= reg_direction[i];
mutex_init(&chip->irq_lock); mutex_init(&chip->irq_lock);
ret = devm_request_threaded_irq(&client->dev, client->irq, ret = devm_request_threaded_irq(&client->dev, client->irq,
...@@ -840,8 +816,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -840,8 +816,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert) static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
{ {
DECLARE_BITMAP(val, MAX_LINE);
int ret; int ret;
u8 val[MAX_BANK];
ret = regcache_sync_region(chip->regmap, chip->regs->output, ret = regcache_sync_region(chip->regmap, chip->regs->output,
chip->regs->output + NBANK(chip)); chip->regs->output + NBANK(chip));
...@@ -855,9 +831,9 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert) ...@@ -855,9 +831,9 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
/* set platform specific polarity inversion */ /* set platform specific polarity inversion */
if (invert) if (invert)
memset(val, 0xFF, NBANK(chip)); bitmap_fill(val, MAX_LINE);
else else
memset(val, 0, NBANK(chip)); bitmap_zero(val, MAX_LINE);
ret = pca953x_write_regs(chip, chip->regs->invert, val); ret = pca953x_write_regs(chip, chip->regs->invert, val);
out: out:
...@@ -866,8 +842,8 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert) ...@@ -866,8 +842,8 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
{ {
DECLARE_BITMAP(val, MAX_LINE);
int ret; int ret;
u8 val[MAX_BANK];
ret = device_pca95xx_init(chip, invert); ret = device_pca95xx_init(chip, invert);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment