static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { unsigned status; unsigned long sl_irq_flags; int ret; spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); if(tegra_rtc_check_busy()) { /* wait for the busy bit to clear. */ spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); ret = tegra_rtc_wait_while_busy(dev); if (ret) return ret; spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); } /* read the original value, and OR in the flag. */ status = tegra_rtc_read(RTC_TEGRA_REG_INTR_MASK); if (enabled) status |= RTC_TEGRA_INTR_MASK_SEC_ALARM0; /* set it */ else status &= ~RTC_TEGRA_INTR_MASK_SEC_ALARM0; /* clear it */ tegra_rtc_write(RTC_TEGRA_REG_INTR_MASK, status); spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); return 0; }
static irqreturn_t tegra_rtc_irq_handler(int irq, void *data) { struct device *dev = data; struct tegra_rtc_info *info = dev_get_drvdata(dev); unsigned long events = 0; unsigned status; unsigned long sl_irq_flags; status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); if (status) { /* clear the interrupt masks and status on any irq. */ tegra_rtc_wait_while_busy(dev); spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); } /* check if Alarm */ if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)) events |= RTC_IRQF | RTC_AF; /* check if Periodic */ if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)) events |= RTC_IRQF | RTC_PF; rtc_update_irq(info->rtc_dev, 1, events); return IRQ_HANDLED; }
static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct tegra_rtc_info *info = dev_get_drvdata(dev); unsigned long sec; if (alarm->enabled) rtc_tm_to_time(&alarm->time, &sec); else sec = 0; tegra_rtc_wait_while_busy(dev); writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); dev_vdbg(dev, "alarm read back as %d\n", readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0)); /* if successfully written and alarm is enabled ... */ if (sec) { tegra_rtc_alarm_irq_enable(dev, 1); dev_vdbg(dev, "alarm set as %lu. %d/%d/%d %d:%02u:%02u\n", sec, alarm->time.tm_mon+1, alarm->time.tm_mday, alarm->time.tm_year+1900, alarm->time.tm_hour, alarm->time.tm_min, alarm->time.tm_sec); } else { /* disable alarm if 0 or write error. */ dev_vdbg(dev, "alarm disabled\n"); tegra_rtc_alarm_irq_enable(dev, 0); } return 0; }
static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct tegra_rtc_info *info = dev_get_drvdata(dev); unsigned long sec; int ret; /* convert tm to seconds. */ ret = rtc_valid_tm(tm); if (ret) return ret; rtc_tm_to_time(tm, &sec); dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n", sec, tm->tm_mon+1, tm->tm_mday, tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec ); /* seconds only written if wait succeeded. */ ret = tegra_rtc_wait_while_busy(dev); if (!ret) writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS); dev_vdbg(dev, "time read back as %d\n", readl(info->rtc_base + TEGRA_RTC_REG_SECONDS)); return ret; }
void tegra_rtc_set_trigger(unsigned long cycles) { unsigned long msec; /* Convert to msec */ msec = cycles / 1000; if (msec) msec = 0x80000000 | (0x0fffffff & msec); tegra_rtc_wait_while_busy(); writel(msec, rtc_base + TEGRA_RTC_REG_MSEC_CDN_ALARM0); tegra_rtc_wait_while_busy(); if (msec) tegra_rtc_alarm_irq_enable(1); else tegra_rtc_alarm_irq_enable(0); }
/* waits for the RTC to not be busy accessing APB, then write a single value. */ static int tegra_rtc_write_not_busy(struct device *dev, unsigned ofs, u32 value) { unsigned long sl_irq_flags; int ret; spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); if(tegra_rtc_check_busy()) { spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); ret = tegra_rtc_wait_while_busy(dev); if (ret) return ret; spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); } tegra_rtc_write(ofs, value); spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); return 0; }
static irqreturn_t tegra_rtc_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = (struct clock_event_device *)dev_id; u32 status; status = readl(rtc_base + TEGRA_RTC_REG_INTR_STATUS); if (status) { /* clear the interrupt masks and status on any irq. */ tegra_rtc_wait_while_busy(); writel(0, rtc_base + TEGRA_RTC_REG_INTR_MASK); writel(status, rtc_base + TEGRA_RTC_REG_INTR_STATUS); } if ((status & TEGRA_RTC_INTR_STATUS_MSEC_CDN_ALARM)) evt->event_handler(evt); return IRQ_HANDLED; }
static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct tegra_rtc_info *info = dev_get_drvdata(dev); unsigned status; unsigned long sl_irq_flags; tegra_rtc_wait_while_busy(dev); spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); /* read the original value, and OR in the flag. */ status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK); if (enabled) status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */ else status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */ writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); return 0; }
static int tegra_rtc_suspend(struct platform_device *pdev, pm_message_t state) { struct device *dev = &pdev->dev; struct tegra_rtc_info *info = platform_get_drvdata(pdev); tegra_rtc_wait_while_busy(dev); /* only use ALARM0 as a wake source. */ writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); dev_vdbg(dev, "alarm sec = %d\n", readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0)); dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n", device_may_wakeup(dev), info->tegra_rtc_irq); /* leave the alarms on as a wake source. */ if (device_may_wakeup(dev)) enable_irq_wake(info->tegra_rtc_irq); return 0; }