Skip to content

Commit d04ad24

Browse files
Prasad Kumpatlabroonie
authored andcommitted
regmap-irq: Update interrupt clear register for proper reset
With the existing logic where clear_ack is true (HW doesn’t support auto clear for ICR), interrupt clear register reset is not handled properly. Due to this only the first interrupts get processed properly and further interrupts are blocked due to not resetting interrupt clear register. Example for issue case where Invert_ack is false and clear_ack is true: Say Default ISR=0x00 & ICR=0x00 and ISR is triggered with 2 interrupts making ISR = 0x11. Step 1: Say ISR is set 0x11 (store status_buff = ISR). ISR needs to be cleared with the help of ICR once the Interrupt is processed. Step 2: Write ICR = 0x11 (status_buff), this will clear the ISR to 0x00. Step 3: Issue - In the existing code, ICR is written with ICR = ~(status_buff) i.e ICR = 0xEE -> This will block all the interrupts from raising except for interrupts 0 and 4. So expectation here is to reset ICR, which will unblock all the interrupts. if (chip->clear_ack) { if (chip->ack_invert && !ret) ........ else if (!ret) ret = regmap_write(map, reg, ~data->status_buf[i]); So writing 0 and 0xff (when ack_invert is true) should have no effect, other than clearing the ACKs just set. Fixes: 3a6f0fb ("regmap: irq: Add support to clear ack registers") Signed-off-by: Prasad Kumpatla <quic_pkumpatl@quicinc.com> Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Link: https://lore.kernel.org/r/20220217085007.30218-1-quic_pkumpatl@quicinc.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent b56a7cb commit d04ad24

1 file changed

Lines changed: 6 additions & 14 deletions

File tree

drivers/base/regmap/regmap-irq.c

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,9 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
189189
ret = regmap_write(map, reg, d->mask_buf[i]);
190190
if (d->chip->clear_ack) {
191191
if (d->chip->ack_invert && !ret)
192-
ret = regmap_write(map, reg,
193-
d->mask_buf[i]);
192+
ret = regmap_write(map, reg, UINT_MAX);
194193
else if (!ret)
195-
ret = regmap_write(map, reg,
196-
~d->mask_buf[i]);
194+
ret = regmap_write(map, reg, 0);
197195
}
198196
if (ret != 0)
199197
dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
@@ -556,11 +554,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
556554
data->status_buf[i]);
557555
if (chip->clear_ack) {
558556
if (chip->ack_invert && !ret)
559-
ret = regmap_write(map, reg,
560-
data->status_buf[i]);
557+
ret = regmap_write(map, reg, UINT_MAX);
561558
else if (!ret)
562-
ret = regmap_write(map, reg,
563-
~data->status_buf[i]);
559+
ret = regmap_write(map, reg, 0);
564560
}
565561
if (ret != 0)
566562
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
@@ -817,13 +813,9 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
817813
d->status_buf[i] & d->mask_buf[i]);
818814
if (chip->clear_ack) {
819815
if (chip->ack_invert && !ret)
820-
ret = regmap_write(map, reg,
821-
(d->status_buf[i] &
822-
d->mask_buf[i]));
816+
ret = regmap_write(map, reg, UINT_MAX);
823817
else if (!ret)
824-
ret = regmap_write(map, reg,
825-
~(d->status_buf[i] &
826-
d->mask_buf[i]));
818+
ret = regmap_write(map, reg, 0);
827819
}
828820
if (ret != 0) {
829821
dev_err(map->dev, "Failed to ack 0x%x: %d\n",

0 commit comments

Comments
 (0)