Galileo gen 2 uses the PCAL9535 as the GPIO expansion, it is different from PCA9535 and includes interrupt mask/status registers, The current driver does not support the interrupt registers configuration, it causes some gpio pins cannot trigger interrupt events, this patch fix this issue.
Signed-off-by: Yong Li <sdliy...@gmail.com> --- drivers/gpio/gpio-pca953x.c | 106 +++++++++++++++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 25 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index f99706f..ad3e0c1 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -39,13 +39,17 @@ #define PCA957X_MSK 6 #define PCA957X_INTS 7 +#define PCAL953X_IN_LATCH 34 #define PCA953X_PUPD_EN 35 #define PCA953X_PUPD_SEL 36 +#define PCAL953X_INT_MASK 37 +#define PCAL953X_INT_STAT 38 #define PCA_GPIO_MASK 0x00FF #define PCA_INT 0x0100 #define PCA953X_TYPE 0x1000 #define PCA957X_TYPE 0x2000 +#define PCAL953X_TYPE 0x4000 #define PCA_TYPE_MASK 0xF000 #define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK) @@ -54,6 +58,7 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9505", 40 | PCA953X_TYPE | PCA_INT, }, { "pca9534", 8 | PCA953X_TYPE | PCA_INT, }, { "pca9535", 16 | PCA953X_TYPE | PCA_INT, }, + { "pcal9535", 16 | PCAL953X_TYPE | PCA_INT, }, { "pca9536", 4 | PCA953X_TYPE, }, { "pca9537", 4 | PCA953X_TYPE | PCA_INT, }, { "pca9538", 8 | PCA953X_TYPE | PCA_INT, }, @@ -125,7 +130,7 @@ static void pca953x_setup_int3491(struct pca953x_chip *chip) } static const struct pca953x_info pca953x_info_int3491 = { - .driver_data = 16 | PCA953X_TYPE | PCA_INT, + .driver_data = 16 | PCAL953X_TYPE | PCA_INT, .setup = pca953x_setup_int3491, }; @@ -191,8 +196,9 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) } else { switch (chip->chip_type) { case PCA953X_TYPE: + case PCAL953X_TYPE: ret = i2c_smbus_write_word_data(chip->client, - reg << 1, (u16) *val); + reg << 1, *(u16 *)val); break; case PCA957X_TYPE: ret = i2c_smbus_write_byte_data(chip->client, reg << 1, @@ -251,6 +257,7 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) switch (chip->chip_type) { case PCA953X_TYPE: + case PCAL953X_TYPE: offset = PCA953X_DIRECTION; break; case PCA957X_TYPE: @@ -286,6 +293,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, switch (chip->chip_type) { case PCA953X_TYPE: + case PCAL953X_TYPE: offset = PCA953X_OUTPUT; break; case PCA957X_TYPE: @@ -302,6 +310,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: + case PCAL953X_TYPE: offset = PCA953X_DIRECTION; break; case PCA957X_TYPE: @@ -328,6 +337,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) mutex_lock(&chip->i2c_lock); switch (chip->chip_type) { case PCA953X_TYPE: + case PCAL953X_TYPE: offset = PCA953X_INPUT; break; case PCA957X_TYPE: @@ -363,6 +373,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) switch (chip->chip_type) { case PCA953X_TYPE: + case PCAL953X_TYPE: offset = PCA953X_OUTPUT; break; case PCA957X_TYPE: @@ -387,7 +398,7 @@ static int pca953x_gpio_set_drive(struct gpio_chip *gc, chip = container_of(gc, struct pca953x_chip, gpio_chip); - if (chip->chip_type != PCA953X_TYPE) + if (chip->chip_type != PCAL953X_TYPE) return -EINVAL; mutex_lock(&chip->i2c_lock); @@ -434,7 +445,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->owner = THIS_MODULE; gc->names = chip->names; - if (chip->chip_type == PCA953X_TYPE) + if (chip->chip_type == PCAL953X_TYPE) gc->set_drive = pca953x_gpio_set_drive; } @@ -469,6 +480,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) struct pca953x_chip *chip = to_pca(gc); u8 new_irqs; int level, i; + u8 invert_irq_mask[MAX_BANK]; /* Look for any newly setup interrupt */ for (i = 0; i < NBANK(chip); i++) { @@ -483,6 +495,17 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) } } + if (chip->chip_type == PCAL953X_TYPE) { + /* Enable latch on interrupt-enabled inputs */ + pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask); + + for (i = 0; i < NBANK(chip); i++) + invert_irq_mask[i] = ~chip->irq_mask[i]; + + /* Unmask enabled interrupts */ + pca953x_write_regs(chip, PCAL953X_INT_MASK, invert_irq_mask); + } + mutex_unlock(&chip->irq_lock); } @@ -530,6 +553,29 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) u8 trigger[MAX_BANK]; int ret, i, offset = 0; + if (chip->chip_type == PCAL953X_TYPE) { + /* Read the current interrupt status from the device */ + ret = pca953x_read_regs(chip, PCAL953X_INT_STAT, trigger); + if (ret) + return 0; + + /* Check latched inputs and clear interrupt status */ + ret = pca953x_read_regs(chip, PCA953X_INPUT, cur_stat); + if (ret) + return 0; + + for (i = 0; i < NBANK(chip); i++) { + /* Apply filter for rising/falling edge selection */ + pending[i] = (~cur_stat[i] & chip->irq_trig_fall[i]) | + (cur_stat[i] & chip->irq_trig_raise[i]); + pending[i] &= trigger[i]; + if (pending[i]) + pending_seen = true; + } + + return pending_seen; + } + switch (chip->chip_type) { case PCA953X_TYPE: offset = PCA953X_INPUT; @@ -599,38 +645,48 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, { struct i2c_client *client = chip->client; int ret, i, offset = 0; + unsigned long flags; if (client->irq && irq_base != -1 && (chip->driver_data & PCA_INT)) { - switch (chip->chip_type) { - case PCA953X_TYPE: - offset = PCA953X_INPUT; - break; - case PCA957X_TYPE: - offset = PCA957X_IN; - break; + if (chip->chip_type != PCAL953X_TYPE) { + switch (chip->chip_type) { + case PCA953X_TYPE: + offset = PCA953X_INPUT; + break; + case PCA957X_TYPE: + offset = PCA957X_IN; + break; + } + ret = pca953x_read_regs(chip, offset, chip->irq_stat); + if (ret) + return ret; + + /* + * There is no way to know which GPIO line generated the + * interrupt. We have to rely on the previous read for + * this purpose. + */ + for (i = 0; i < NBANK(chip); i++) + chip->irq_stat[i] &= chip->reg_direction[i]; } - ret = pca953x_read_regs(chip, offset, chip->irq_stat); - if (ret) - return ret; - - /* - * There is no way to know which GPIO line generated the - * interrupt. We have to rely on the previous read for - * this purpose. - */ - for (i = 0; i < NBANK(chip); i++) - chip->irq_stat[i] &= chip->reg_direction[i]; mutex_init(&chip->irq_lock); + if (chip->chip_type == PCAL953X_TYPE) + flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | + IRQF_SHARED; + else + flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT | + IRQF_SHARED; + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pca953x_irq_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT | - IRQF_SHARED, + flags, dev_name(&client->dev), chip); + if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); @@ -781,7 +837,7 @@ static int pca953x_probe(struct i2c_client *client, */ pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK); - if (chip->chip_type == PCA953X_TYPE) + if (chip->chip_type & (PCA953X_TYPE | PCAL953X_TYPE)) ret = device_pca953x_init(chip, invert); else ret = device_pca957x_init(chip, invert); -- 2.1.4 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto