/*! * 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 platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; int ret; spin_lock_irq(&rtc_lock); if (rtc_valid_tm(&alrm->time)) { if (alrm->time.tm_sec > 59 || alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) { ret = -EINVAL; goto out; } ret = rtc_update_alarm(dev, &alrm->time); } else { if ((ret = rtc_valid_tm(&alrm->time))) goto out; ret = rtc_update_alarm(dev, &alrm->time); } if (ret == 0) { memcpy(&g_rtc_alarm, &alrm->time, sizeof(struct rtc_time)); if (alrm->enabled) { writew((readw(ioaddr + RTC_RTCIENR) | RTC_ALM_BIT), ioaddr + RTC_RTCIENR); } else { writew((readw(ioaddr + RTC_RTCIENR) & ~RTC_ALM_BIT), ioaddr + RTC_RTCIENR); } } out: spin_unlock_irq(&rtc_lock); return ret; }
/*! * 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; }
/*! * 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_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; u32 status; u32 events = 0; spin_lock(&rtc_lock); status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR); /* clear interrupt sources */ writew(status, ioaddr + RTC_RTCISR); /* clear alarm interrupt if it has occurred */ if (status & RTC_ALM_BIT) { status &= ~RTC_ALM_BIT; } /* update irq data & counter */ if (status & RTC_ALM_BIT) { events |= (RTC_AF | RTC_IRQF); } if (status & RTC_1HZ_BIT) { events |= (RTC_UF | RTC_IRQF); } if (status & PIT_ALL_ON) { events |= (RTC_PF | RTC_IRQF); } if ((status & RTC_ALM_BIT) && rtc_valid_tm(&g_rtc_alarm)) { rtc_update_alarm(&pdev->dev, &g_rtc_alarm); } spin_unlock(&rtc_lock); rtc_update_irq(pdata->rtc, 1, events); return IRQ_HANDLED; }