static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { struct rtc_drv_data *pdata = dev_get_drvdata(dev); void __iomem *ioaddr = pdata->ioaddr; u32 lp_cr; unsigned long lock_flags = 0; spin_lock_irqsave(&rtc_lock, lock_flags); if (enable) { if (!pdata->irq_enable) { enable_irq(pdata->irq); pdata->irq_enable = true; } lp_cr = __raw_readl(ioaddr + SRTC_LPCR); lp_cr |= SRTC_LPCR_ALP | SRTC_LPCR_WAE; __raw_writel(lp_cr, ioaddr + SRTC_LPCR); } else { lp_cr = __raw_readl(ioaddr + SRTC_LPCR); lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE); if (((lp_cr & SRTC_LPCR_ALL_INT_EN) == 0) && (pdata->irq_enable)) { disable_irq(pdata->irq); pdata->irq_enable = false; } __raw_writel(lp_cr, ioaddr + SRTC_LPCR); } rtc_write_sync_lp(ioaddr); spin_unlock_irqrestore(&rtc_lock, lock_flags); return 0; }
/*! * This function sets the internal RTC time based on tm in Gregorian date. * * @param tm the time value to be set in the RTC * * @return 0 if successful; non-zero otherwise. */ static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct rtc_drv_data *pdata = dev_get_drvdata(dev); void __iomem *ioaddr = pdata->ioaddr; unsigned long time; u64 old_time_47bit, new_time_47bit; int ret; ret = rtc_tm_to_time(tm, &time); if (ret != 0) return ret; old_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 | ((u64) __raw_readl(ioaddr + SRTC_LPSCLR))); old_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH; __raw_writel(time, ioaddr + SRTC_LPSCMR); rtc_write_sync_lp(ioaddr); new_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 | ((u64) __raw_readl(ioaddr + SRTC_LPSCLR))); new_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH; /* update the difference between previous time and new time */ time_diff = new_time_47bit - old_time_47bit; /* signal all waiting threads that time changed */ complete_all(&srtc_completion); /* reinitialize completion variable */ INIT_COMPLETION(srtc_completion); return 0; }
/*! * This function sets the internal RTC time based on tm in Gregorian date. * * @param tm the time value to be set in the RTC * * @return 0 if successful; non-zero otherwise. */ static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct rtc_drv_data *pdata = dev_get_drvdata(dev); void __iomem *ioaddr = pdata->ioaddr; unsigned long time; int ret; ret = rtc_tm_to_time(tm, &time); if (ret != 0) return ret; __raw_writel(time, ioaddr + SRTC_LPSCMR); rtc_write_sync_lp(ioaddr); return 0; }
/*! * This function sets the RTC alarm based on passed in alrm. * * @param alrm the alarm value to be set in the RTC * * @return 0 if successful; non-zero otherwise. */ static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct rtc_drv_data *pdata = dev_get_drvdata(dev); void __iomem *ioaddr = pdata->ioaddr; unsigned long lock_flags = 0; u32 lp_cr; int ret; if (rtc_valid_tm(&alrm->time)) { if (alrm->time.tm_sec > 59 || alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) { return -EINVAL; } } spin_lock_irqsave(&rtc_lock, lock_flags); lp_cr = __raw_readl(ioaddr + SRTC_LPCR); ret = rtc_update_alarm(dev, &alrm->time); if (ret) goto out; if (alrm->enabled) lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE); else lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE); if (lp_cr & SRTC_LPCR_ALL_INT_EN) { if (!pdata->irq_enable) { enable_irq(pdata->irq); pdata->irq_enable = true; } } else { if (pdata->irq_enable) { disable_irq(pdata->irq); pdata->irq_enable = false; } } __raw_writel(lp_cr, ioaddr + SRTC_LPCR); out: spin_unlock_irqrestore(&rtc_lock, lock_flags); rtc_write_sync_lp(ioaddr); return ret; }
int rtc_internal_set(u32 time){ int ret; u32 lp_cr; u64 old_time_47bit, new_time_47bit; #ifdef DEBUG_RTC printf("\nSetting time to iMX6..."); #endif old_time_47bit = (((u64) (__raw_readl(SNVS_BASE_ADDR + SNVS_LPSRTCMR) & ((0x1 << CNTR_TO_SECS_SH) - 1)) << 32) | ((u64) __raw_readl(SNVS_BASE_ADDR + SNVS_LPSRTCLR))); /* Disable RTC first */ lp_cr = __raw_readl(SNVS_BASE_ADDR + SNVS_LPCR) & ~SNVS_LPCR_SRTC_ENV; __raw_writel(lp_cr,SNVS_BASE_ADDR + SNVS_LPCR); while (__raw_readl(SNVS_BASE_ADDR + SNVS_LPCR) & SNVS_LPCR_SRTC_ENV) ; /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */ __raw_writel(time << CNTR_TO_SECS_SH, SNVS_BASE_ADDR + SNVS_LPSRTCLR); __raw_writel(time >> (32 - CNTR_TO_SECS_SH), SNVS_BASE_ADDR + SNVS_LPSRTCMR); /* Enable RTC again */ __raw_writel(lp_cr | SNVS_LPCR_SRTC_ENV, SNVS_BASE_ADDR + SNVS_LPCR); while (!(__raw_readl(SNVS_BASE_ADDR + SNVS_LPCR) & SNVS_LPCR_SRTC_ENV)) ; rtc_write_sync_lp(); new_time_47bit = (((u64) (__raw_readl(SNVS_BASE_ADDR + SNVS_LPSRTCMR) & ((0x1 << CNTR_TO_SECS_SH) - 1)) << 32) | ((u64) __raw_readl(SNVS_BASE_ADDR + SNVS_LPSRTCLR))); #ifdef DEBUG_RTC printf("Done!\n"); #endif return 0; }
/*! * This function is the RTC interrupt service routine. * * @param irq RTC IRQ number * @param dev_id device ID which is not used * * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file. */ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id) { struct platform_device *pdev = dev_id; struct rtc_drv_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; u32 lp_status, lp_cr; u32 events = 0; lp_status = __raw_readl(ioaddr + SRTC_LPSR); lp_cr = __raw_readl(ioaddr + SRTC_LPCR); /* update irq data & counter */ if (lp_status & SRTC_LPSR_ALP) { if (lp_cr & SRTC_LPCR_ALP) events |= (RTC_AF | RTC_IRQF); /* disable further lp alarm interrupts */ lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE); } /* Update interrupt enables */ __raw_writel(lp_cr, ioaddr + SRTC_LPCR); /* If no interrupts are enabled, turn off interrupts in kernel */ if (((lp_cr & SRTC_LPCR_ALL_INT_EN) == 0) && (pdata->irq_enable)) { disable_irq_nosync(pdata->irq); pdata->irq_enable = false; } /* clear interrupt status */ __raw_writel(lp_status, ioaddr + SRTC_LPSR); rtc_write_sync_lp(ioaddr); rtc_update_irq(pdata->rtc, 1, events); return IRQ_HANDLED; }