static irqreturn_t cmos_interrupt(int irq, void *p) { u8 irqstat; u8 rtc_control; spin_lock(&rtc_lock); irqstat = CMOS_READ(RTC_INTR_FLAGS); rtc_control = CMOS_READ(RTC_CONTROL); if (is_hpet_enabled()) irqstat = (unsigned long)irq & 0xF0; irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (irqstat & RTC_AIE) { rtc_control &= ~RTC_AIE; CMOS_WRITE(rtc_control, RTC_CONTROL); hpet_mask_rtc_irq_bit(RTC_AIE); CMOS_READ(RTC_INTR_FLAGS); } spin_unlock(&rtc_lock); if (is_intr(irqstat)) { rtc_update_irq(p, 1, irqstat); return IRQ_HANDLED; } else return IRQ_NONE; }
static int mrst_resume(struct device *dev) { struct mrst_rtc *mrst = dev_get_drvdata(dev); unsigned char tmp = mrst->suspend_ctrl; /* Re-enable any irqs previously active */ if (tmp & RTC_IRQMASK) { unsigned char mask; if (mrst->enabled_wake) { disable_irq_wake(mrst->irq); mrst->enabled_wake = 0; } spin_lock_irq(&rtc_lock); do { vrtc_cmos_write(tmp, RTC_CONTROL); mask = vrtc_cmos_read(RTC_INTR_FLAGS); mask &= (tmp & RTC_IRQMASK) | RTC_IRQF; if (!is_intr(mask)) break; rtc_update_irq(mrst->rtc, 1, mask); tmp &= ~RTC_AIE; } while (mask & RTC_AIE); spin_unlock_irq(&rtc_lock); } dev_dbg(&mrst_rtc.rtc->dev, "resume, ctrl %02x\n", tmp); return 0; }
/* * When vRTC IRQ is captured by SCU FW, FW will clear the AIE bit in * Reg B, so no need for this driver to clear it */ static irqreturn_t mrst_rtc_irq(int irq, void *p) { u8 irqstat; int ret = 0; spin_lock(&rtc_lock); /* This read will clear all IRQ flags inside Reg C */ irqstat = vrtc_cmos_read(RTC_INTR_FLAGS); irqstat &= RTC_IRQMASK | RTC_IRQF; ret = is_valid_af(irqstat); spin_unlock(&rtc_lock); if (is_intr(irqstat)) { /* If it's an alarm-interrupt, update RTC-IRQ only if it's * for current day. Alarms beyond 24-hours will result in * interrupts at given time, everyday till actual alarm-date. * From hardware perspective, it's still a valid interrupt, * hence need to return IRQ_HANDLED. */ if (ret) rtc_update_irq(p, 1, irqstat); return IRQ_HANDLED; } else { printk(KERN_ERR "vRTC: error in IRQ handler\n"); return IRQ_NONE; } }
static int cmos_resume(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char tmp = cmos->suspend_ctrl; /* re-enable any irqs previously active */ if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { if (cmos->enabled_wake) { if (cmos->wake_off) cmos->wake_off(dev); else disable_irq_wake(cmos->irq); cmos->enabled_wake = 0; } spin_lock_irq(&rtc_lock); CMOS_WRITE(tmp, RTC_CONTROL); tmp = CMOS_READ(RTC_INTR_FLAGS); tmp &= (cmos->suspend_ctrl & RTC_IRQMASK) | RTC_IRQF; if (is_intr(tmp)) rtc_update_irq(cmos->rtc, 1, tmp); spin_unlock_irq(&rtc_lock); } pr_debug("%s: resume, ctrl %02x\n", cmos_rtc.rtc->dev.bus_id, cmos->suspend_ctrl); return 0; }
static int cmos_irq_set_state(struct device *dev, int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char rtc_control, rtc_intr; unsigned long flags; if (!is_valid_irq(cmos->irq)) return -ENXIO; spin_lock_irqsave(&rtc_lock, flags); rtc_control = CMOS_READ(RTC_CONTROL); if (enabled) rtc_control |= RTC_PIE; else rtc_control &= ~RTC_PIE; CMOS_WRITE(rtc_control, RTC_CONTROL); rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) rtc_update_irq(cmos->rtc, 1, rtc_intr); spin_unlock_irqrestore(&rtc_lock, flags); return 0; }
static int __maybe_unused cmos_resume(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char tmp; if (cmos->enabled_wake) { if (cmos->wake_off) cmos->wake_off(dev); else disable_irq_wake(cmos->irq); cmos->enabled_wake = 0; } /* The BIOS might have changed the alarm, restore it */ cmos_check_wkalrm(dev); spin_lock_irq(&rtc_lock); tmp = cmos->suspend_ctrl; cmos->suspend_ctrl = 0; /* re-enable any irqs previously active */ if (tmp & RTC_IRQMASK) { unsigned char mask; if (device_may_wakeup(dev)) hpet_rtc_timer_init(); do { CMOS_WRITE(tmp, RTC_CONTROL); hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK); mask = CMOS_READ(RTC_INTR_FLAGS); mask &= (tmp & RTC_IRQMASK) | RTC_IRQF; if (!is_hpet_enabled() || !is_intr(mask)) break; /* force one-shot behavior if HPET blocked * the wake alarm's irq */ rtc_update_irq(cmos->rtc, 1, mask); tmp &= ~RTC_AIE; hpet_mask_rtc_irq_bit(RTC_AIE); } while (mask & RTC_AIE); if (tmp & RTC_AIE) cmos_check_acpi_rtc_status(dev, &tmp); } spin_unlock_irq(&rtc_lock); dev_dbg(dev, "resume, ctrl %02x\n", tmp); return 0; }
static void mrst_checkintr(struct mrst_rtc *mrst, unsigned char rtc_control) { unsigned char rtc_intr; /* * NOTE after changing RTC_xIE bits we always read INTR_FLAGS; * allegedly some older rtcs need that to handle irqs properly */ rtc_intr = vrtc_cmos_read(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) rtc_update_irq(mrst->rtc, 1, rtc_intr); }
static void cmos_checkintr(struct cmos_rtc *cmos, unsigned char rtc_control) { unsigned char rtc_intr; rtc_intr = CMOS_READ(RTC_INTR_FLAGS); if (is_hpet_enabled()) return; rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) rtc_update_irq(cmos->rtc, 1, rtc_intr); }
static int cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char rtc_control, rtc_intr; unsigned long flags; switch (cmd) { case RTC_AIE_OFF: case RTC_AIE_ON: case RTC_UIE_OFF: case RTC_UIE_ON: case RTC_PIE_OFF: case RTC_PIE_ON: if (!is_valid_irq(cmos->irq)) return -EINVAL; break; default: return -ENOIOCTLCMD; } spin_lock_irqsave(&rtc_lock, flags); rtc_control = CMOS_READ(RTC_CONTROL); switch (cmd) { case RTC_AIE_OFF: /* alarm off */ rtc_control &= ~RTC_AIE; break; case RTC_AIE_ON: /* alarm on */ rtc_control |= RTC_AIE; break; case RTC_UIE_OFF: /* update off */ rtc_control &= ~RTC_UIE; break; case RTC_UIE_ON: /* update on */ rtc_control |= RTC_UIE; break; case RTC_PIE_OFF: /* periodic off */ rtc_control &= ~RTC_PIE; break; case RTC_PIE_ON: /* periodic on */ rtc_control |= RTC_PIE; break; } CMOS_WRITE(rtc_control, RTC_CONTROL); rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) rtc_update_irq(cmos->rtc, 1, rtc_intr); spin_unlock_irqrestore(&rtc_lock, flags); return 0; }
static irqreturn_t cmos_interrupt(int irq, void *p) { u8 irqstat; spin_lock(&rtc_lock); irqstat = CMOS_READ(RTC_INTR_FLAGS); irqstat &= (CMOS_READ(RTC_CONTROL) & RTC_IRQMASK) | RTC_IRQF; spin_unlock(&rtc_lock); if (is_intr(irqstat)) { rtc_update_irq(p, 1, irqstat); return IRQ_HANDLED; } else return IRQ_NONE; }
static void cmos_checkintr(struct cmos_rtc *cmos, unsigned char rtc_control) { unsigned char rtc_intr; /* NOTE after changing RTC_xIE bits we always read INTR_FLAGS; * allegedly some older rtcs need that to handle irqs properly */ rtc_intr = CMOS_READ(RTC_INTR_FLAGS); if (is_hpet_enabled()) return; rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) rtc_update_irq(cmos->rtc, 1, rtc_intr); }
/* * When vRTC IRQ is captured by SCU FW, FW will clear the AIE bit in * Reg B, so no need for this driver to clear it */ static irqreturn_t mrst_rtc_irq(int irq, void *p) { u8 irqstat; spin_lock(&rtc_lock); /* This read will clear all IRQ flags inside Reg C */ irqstat = vrtc_cmos_read(RTC_INTR_FLAGS); spin_unlock(&rtc_lock); irqstat &= RTC_IRQMASK | RTC_IRQF; if (is_intr(irqstat)) { rtc_update_irq(p, 1, irqstat); return IRQ_HANDLED; } return IRQ_NONE; }
static irqreturn_t cmos_interrupt(int irq, void *p) { u8 irqstat; u8 rtc_control; spin_lock(&rtc_lock); /* When the HPET interrupt handler calls us, the interrupt * status is passed as arg1 instead of the irq number. But * always clear irq status, even when HPET is in the way. * * Note that HPET and RTC are almost certainly out of phase, * giving different IRQ status ... */ irqstat = CMOS_READ(RTC_INTR_FLAGS); rtc_control = CMOS_READ(RTC_CONTROL); if (is_hpet_enabled()) irqstat = (unsigned long)irq & 0xF0; /* If we were suspended, RTC_CONTROL may not be accurate since the * bios may have cleared it. */ if (!cmos_rtc.suspend_ctrl) irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; else irqstat &= (cmos_rtc.suspend_ctrl & RTC_IRQMASK) | RTC_IRQF; /* All Linux RTC alarms should be treated as if they were oneshot. * Similar code may be needed in system wakeup paths, in case the * alarm woke the system. */ if (irqstat & RTC_AIE) { cmos_rtc.suspend_ctrl &= ~RTC_AIE; rtc_control &= ~RTC_AIE; CMOS_WRITE(rtc_control, RTC_CONTROL); hpet_mask_rtc_irq_bit(RTC_AIE); CMOS_READ(RTC_INTR_FLAGS); } spin_unlock(&rtc_lock); if (is_intr(irqstat)) { rtc_update_irq(p, 1, irqstat); return IRQ_HANDLED; } else return IRQ_NONE; }
static int cmos_resume(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char tmp = cmos->suspend_ctrl; /* re-enable any irqs previously active */ if (tmp & RTC_IRQMASK) { unsigned char mask; if (cmos->enabled_wake) { if (cmos->wake_off) cmos->wake_off(dev); else disable_irq_wake(cmos->irq); cmos->enabled_wake = 0; } spin_lock_irq(&rtc_lock); do { CMOS_WRITE(tmp, RTC_CONTROL); hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK); mask = CMOS_READ(RTC_INTR_FLAGS); mask &= (tmp & RTC_IRQMASK) | RTC_IRQF; if (!is_hpet_enabled() || !is_intr(mask)) break; /* force one-shot behavior if HPET blocked * the wake alarm's irq */ rtc_update_irq(cmos->rtc, 1, mask); tmp &= ~RTC_AIE; hpet_mask_rtc_irq_bit(RTC_AIE); hpet_rtc_timer_init(); } while (mask & RTC_AIE); spin_unlock_irq(&rtc_lock); } pr_debug("%s: resume, ctrl %02x\n", dev_name(&cmos_rtc.rtc->dev), tmp); return 0; }
static int cmos_suspend(struct device *dev, pm_message_t mesg) { struct cmos_rtc *cmos = dev_get_drvdata(dev); int do_wake = device_may_wakeup(dev); unsigned char tmp; /* only the alarm might be a wakeup event source */ spin_lock_irq(&rtc_lock); cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL); if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { unsigned char irqstat; if (do_wake) tmp &= ~(RTC_PIE|RTC_UIE); else tmp &= ~(RTC_PIE|RTC_AIE|RTC_UIE); CMOS_WRITE(tmp, RTC_CONTROL); irqstat = CMOS_READ(RTC_INTR_FLAGS); irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF; if (is_intr(irqstat)) rtc_update_irq(cmos->rtc, 1, irqstat); } spin_unlock_irq(&rtc_lock); if (tmp & RTC_AIE) { cmos->enabled_wake = 1; if (cmos->wake_on) cmos->wake_on(dev); else enable_irq_wake(cmos->irq); } pr_debug("%s: suspend%s, ctrl %02x\n", cmos_rtc.rtc->dev.bus_id, (tmp & RTC_AIE) ? ", alarm may wake" : "", tmp); return 0; }
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char mon, mday, hrs, min, sec; unsigned char rtc_control, rtc_intr; if (!is_valid_irq(cmos->irq)) return -EIO; /* REVISIT this assumes PC style usage: always BCD */ /* Writing 0xff means "don't care" or "match all". */ mon = t->time.tm_mon; mon = (mon < 12) ? BIN2BCD(mon) : 0xff; mon++; mday = t->time.tm_mday; mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff; hrs = t->time.tm_hour; hrs = (hrs < 24) ? BIN2BCD(hrs) : 0xff; min = t->time.tm_min; min = (min < 60) ? BIN2BCD(min) : 0xff; sec = t->time.tm_sec; sec = (sec < 60) ? BIN2BCD(sec) : 0xff; spin_lock_irq(&rtc_lock); /* next rtc irq must not be from previous alarm setting */ rtc_control = CMOS_READ(RTC_CONTROL); rtc_control &= ~RTC_AIE; CMOS_WRITE(rtc_control, RTC_CONTROL); rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) rtc_update_irq(cmos->rtc, 1, rtc_intr); /* update alarm */ CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); CMOS_WRITE(sec, RTC_SECONDS_ALARM); /* the system may support an "enhanced" alarm */ if (cmos->day_alrm) { CMOS_WRITE(mday, cmos->day_alrm); if (cmos->mon_alrm) CMOS_WRITE(mon, cmos->mon_alrm); } if (t->enabled) { rtc_control |= RTC_AIE; CMOS_WRITE(rtc_control, RTC_CONTROL); rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) rtc_update_irq(cmos->rtc, 1, rtc_intr); } spin_unlock_irq(&rtc_lock); return 0; }