On 12. 02. 20 11:24, Srinivas Neeli wrote: > Fix multiple occurring interrupts for alarm interrupt. RTC module doesn't > clear the alarm interrupt status bit immediately after the interrupt is > triggered.This is due to the sticky nature of the alarm interrupt status > register. The alarm interrupt status register can be cleared only after > the second counter outruns the set alarm value. To fix multiple spurious > interrupts, disable alarm interrupt in the handler and clear the status > bit before enabling the alarm interrupt. > > Fixes: 11143c19eb57 ("rtc: add xilinx zynqmp rtc driver") > Signed-off-by: Srinivas Neeli <srinivas.neeli@xxxxxxxxxx> > --- > Changes in V2: > Addressed Michal Simek comments > - Removed new line in declartion part. > - Added new line before return. > --- > drivers/rtc/rtc-zynqmp.c | 27 +++++++++++++++++++++++---- > 1 file changed, 23 insertions(+), 4 deletions(-) > > diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c > index 5786866c09e9..4b1077e2f826 100644 > --- a/drivers/rtc/rtc-zynqmp.c > +++ b/drivers/rtc/rtc-zynqmp.c > @@ -38,6 +38,8 @@ > > #define RTC_CALIB_DEF 0x198233 > #define RTC_CALIB_MASK 0x1FFFFF > +#define RTC_ALRM_MASK BIT(1) > +#define RTC_MSEC 1000 > > struct xlnx_rtc_dev { > struct rtc_device *rtc; > @@ -123,11 +125,28 @@ static int xlnx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) > static int xlnx_rtc_alarm_irq_enable(struct device *dev, u32 enabled) > { > struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); > + unsigned int status; > + ulong timeout; > + > + timeout = jiffies + msecs_to_jiffies(RTC_MSEC); > + > + if (enabled) { > + while (1) { > + status = readl(xrtcdev->reg_base + RTC_INT_STS); > + if (!((status & RTC_ALRM_MASK) == RTC_ALRM_MASK)) > + break; > + > + if (time_after_eq(jiffies, timeout)) { > + dev_err(dev, "Time out occur, while clearing alarm status bit\n"); > + return -ETIMEDOUT; > + } > + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_STS); > + } > > - if (enabled) > writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN); > - else > + } else { > writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_DIS); > + } > > return 0; > } > @@ -183,8 +202,8 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id) > if (!(status & (RTC_INT_SEC | RTC_INT_ALRM))) > return IRQ_NONE; > > - /* Clear RTC_INT_ALRM interrupt only */ > - writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_STS); > + /* Disable RTC_INT_ALRM interrupt only */ > + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_DIS); > > if (status & RTC_INT_ALRM) > rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF); > Acked-by: Michal Simek <michal.simek@xxxxxxxxxx> Thanks, Michal