Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: xilinx-ams: Unmask interrupts after updating alarms

To convert level-triggered alarms into edge-triggered IIO events, alarms
are masked when they are triggered. To ensure we catch subsequent
alarms, we then periodically poll to see if the alarm is still active.
If it isn't, we unmask it. Active but masked alarms are stored in
current_masked_alarm.

If an active alarm is disabled, it will remain set in
current_masked_alarm until ams_unmask_worker clears it. If the alarm is
re-enabled before ams_unmask_worker runs, then it will never be cleared
from current_masked_alarm. This will prevent the alarm event from being
pushed even if the alarm is still active.

Fix this by recalculating current_masked_alarm immediately when enabling
or disabling alarms.

Fixes: d5c70627a794 ("iio: adc: Add Xilinx AMS driver")
Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
Reviewed-by: O'Griofa, Conall <conall.ogriofa@amd.com>
Tested-by: Erim, Salih <Salih.Erim@amd.com>
Acked-by: Erim, Salih <Salih.Erim@amd.com>
Link: https://patch.msgid.link/20250715002847.2035228-1-sean.anderson@linux.dev
Cc: <Stable@vger.kernel.org>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Sean Anderson and committed by
Jonathan Cameron
feb500c7 3c63ba1c

+25 -20
+25 -20
drivers/iio/adc/xilinx-ams.c
··· 389 389 ams_pl_update_reg(ams, AMS_REG_CONFIG3, AMS_REGCFG3_ALARM_MASK, cfg); 390 390 } 391 391 392 + static void ams_unmask(struct ams *ams) 393 + { 394 + unsigned int status, unmask; 395 + 396 + status = readl(ams->base + AMS_ISR_0); 397 + 398 + /* Clear those bits which are not active anymore */ 399 + unmask = (ams->current_masked_alarm ^ status) & ams->current_masked_alarm; 400 + 401 + /* Clear status of disabled alarm */ 402 + unmask |= ams->intr_mask; 403 + 404 + ams->current_masked_alarm &= status; 405 + 406 + /* Also clear those which are masked out anyway */ 407 + ams->current_masked_alarm &= ~ams->intr_mask; 408 + 409 + /* Clear the interrupts before we unmask them */ 410 + writel(unmask, ams->base + AMS_ISR_0); 411 + 412 + ams_update_intrmask(ams, ~AMS_ALARM_MASK, ~AMS_ALARM_MASK); 413 + } 414 + 392 415 static void ams_update_alarm(struct ams *ams, unsigned long alarm_mask) 393 416 { 394 417 unsigned long flags; ··· 424 401 425 402 spin_lock_irqsave(&ams->intr_lock, flags); 426 403 ams_update_intrmask(ams, AMS_ISR0_ALARM_MASK, ~alarm_mask); 404 + ams_unmask(ams); 427 405 spin_unlock_irqrestore(&ams->intr_lock, flags); 428 406 } 429 407 ··· 1059 1035 static void ams_unmask_worker(struct work_struct *work) 1060 1036 { 1061 1037 struct ams *ams = container_of(work, struct ams, ams_unmask_work.work); 1062 - unsigned int status, unmask; 1063 1038 1064 1039 spin_lock_irq(&ams->intr_lock); 1065 - 1066 - status = readl(ams->base + AMS_ISR_0); 1067 - 1068 - /* Clear those bits which are not active anymore */ 1069 - unmask = (ams->current_masked_alarm ^ status) & ams->current_masked_alarm; 1070 - 1071 - /* Clear status of disabled alarm */ 1072 - unmask |= ams->intr_mask; 1073 - 1074 - ams->current_masked_alarm &= status; 1075 - 1076 - /* Also clear those which are masked out anyway */ 1077 - ams->current_masked_alarm &= ~ams->intr_mask; 1078 - 1079 - /* Clear the interrupts before we unmask them */ 1080 - writel(unmask, ams->base + AMS_ISR_0); 1081 - 1082 - ams_update_intrmask(ams, ~AMS_ALARM_MASK, ~AMS_ALARM_MASK); 1083 - 1040 + ams_unmask(ams); 1084 1041 spin_unlock_irq(&ams->intr_lock); 1085 1042 1086 1043 /* If still pending some alarm re-trigger the timer */