static int davinci_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); u16 days; u8 rtc_cctrl; unsigned long flags; if (convert2days(&days, tm) < 0) return -EINVAL; spin_lock_irqsave(&davinci_rtc_lock, flags); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, bin2bcd(tm->tm_sec), PRTCSS_RTC_SEC); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, bin2bcd(tm->tm_min), PRTCSS_RTC_MIN); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, bin2bcd(tm->tm_hour), PRTCSS_RTC_HOUR); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, days & 0xFF, PRTCSS_RTC_DAY0); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, (days & 0xFF00) >> 8, PRTCSS_RTC_DAY1); rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL); rtc_cctrl |= PRTCSS_RTC_CCTRL_CAEN; rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL); spin_unlock_irqrestore(&davinci_rtc_lock, flags); return 0; }
static int __init davinci_rtc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct davinci_rtc *davinci_rtc; struct resource *res; int ret = 0; davinci_rtc = devm_kzalloc(&pdev->dev, sizeof(struct davinci_rtc), GFP_KERNEL); if (!davinci_rtc) return -ENOMEM; davinci_rtc->irq = platform_get_irq(pdev, 0); if (davinci_rtc->irq < 0) { dev_err(dev, "no RTC irq\n"); return davinci_rtc->irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); davinci_rtc->base = devm_ioremap_resource(dev, res); if (IS_ERR(davinci_rtc->base)) return PTR_ERR(davinci_rtc->base); platform_set_drvdata(pdev, davinci_rtc); davinci_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &davinci_rtc_ops, THIS_MODULE); if (IS_ERR(davinci_rtc->rtc)) { dev_err(dev, "unable to register RTC device, err %d\n", ret); return PTR_ERR(davinci_rtc->rtc); } rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); rtcss_write(davinci_rtc, 0, PRTCSS_RTC_INTC_EXTENA1); rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL); rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL); ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt, 0, "davinci_rtc", davinci_rtc); if (ret < 0) { dev_err(dev, "unable to register davinci RTC interrupt\n"); return ret; } /* Enable interrupts */ rtcif_write(davinci_rtc, PRTCIF_INTEN_RTCSS, PRTCIF_INTEN); rtcss_write(davinci_rtc, PRTCSS_RTC_INTC_EXTENA1_MASK, PRTCSS_RTC_INTC_EXTENA1); rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL); device_init_wakeup(&pdev->dev, 0); return 0; }
static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); unsigned long flags; u16 days; if (alm->time.tm_mday <= 0 && alm->time.tm_mon < 0 && alm->time.tm_year < 0) { struct rtc_time tm; unsigned long now, then; davinci_rtc_read_time(dev, &tm); rtc_tm_to_time(&tm, &now); alm->time.tm_mday = tm.tm_mday; alm->time.tm_mon = tm.tm_mon; alm->time.tm_year = tm.tm_year; rtc_tm_to_time(&alm->time, &then); if (then < now) { rtc_time_to_tm(now + 24 * 60 * 60, &tm); alm->time.tm_mday = tm.tm_mday; alm->time.tm_mon = tm.tm_mon; alm->time.tm_year = tm.tm_year; } } if (convert2days(&days, &alm->time) < 0) return -EINVAL; spin_lock_irqsave(&davinci_rtc_lock, flags); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, bin2bcd(alm->time.tm_min), PRTCSS_RTC_AMIN); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, bin2bcd(alm->time.tm_hour), PRTCSS_RTC_AHOUR); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, days & 0xFF, PRTCSS_RTC_ADAY0); davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, (days & 0xFF00) >> 8, PRTCSS_RTC_ADAY1); spin_unlock_irqrestore(&davinci_rtc_lock, flags); return 0; }
static int davinci_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); unsigned long flags; u8 rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL); spin_lock_irqsave(&davinci_rtc_lock, flags); if (enabled) rtc_cctrl |= PRTCSS_RTC_CCTRL_DAEN | PRTCSS_RTC_CCTRL_HAEN | PRTCSS_RTC_CCTRL_MAEN | PRTCSS_RTC_CCTRL_ALMFLG | PRTCSS_RTC_CCTRL_AIEN; else rtc_cctrl &= ~PRTCSS_RTC_CCTRL_AIEN; davinci_rtcss_calendar_wait(davinci_rtc); rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL); spin_unlock_irqrestore(&davinci_rtc_lock, flags); return 0; }
static int davinci_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev); u8 rtc_ctrl; unsigned long flags; int ret = 0; spin_lock_irqsave(&davinci_rtc_lock, flags); rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL); switch (cmd) { case RTC_WIE_ON: rtc_ctrl |= PRTCSS_RTC_CTRL_WEN | PRTCSS_RTC_CTRL_WDTFLG; break; case RTC_WIE_OFF: rtc_ctrl &= ~PRTCSS_RTC_CTRL_WEN; break; default: ret = -ENOIOCTLCMD; } rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL); spin_unlock_irqrestore(&davinci_rtc_lock, flags); return ret; }
static irqreturn_t davinci_rtc_interrupt(int irq, void *class_dev) { struct davinci_rtc *davinci_rtc = class_dev; unsigned long events = 0; u32 irq_flg; u8 alm_irq, tmr_irq; u8 rtc_ctrl, rtc_cctrl; int ret = IRQ_NONE; irq_flg = rtcif_read(davinci_rtc, PRTCIF_INTFLG) & PRTCIF_INTFLG_RTCSS; alm_irq = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL) & PRTCSS_RTC_CCTRL_ALMFLG; tmr_irq = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL) & PRTCSS_RTC_CTRL_TMRFLG; if (irq_flg) { if (alm_irq) { events |= RTC_IRQF | RTC_AF; rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL); rtc_cctrl |= PRTCSS_RTC_CCTRL_ALMFLG; rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL); } else if (tmr_irq) { events |= RTC_IRQF | RTC_PF; rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL); rtc_ctrl |= PRTCSS_RTC_CTRL_TMRFLG; rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL); } rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); rtc_update_irq(davinci_rtc->rtc, 1, events); ret = IRQ_HANDLED; } return ret; }
static int __init davinci_rtc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct davinci_rtc *davinci_rtc; struct resource *res, *mem; int ret = 0; davinci_rtc = kzalloc(sizeof(struct davinci_rtc), GFP_KERNEL); if (!davinci_rtc) { dev_dbg(dev, "could not allocate memory for private data\n"); return -ENOMEM; } davinci_rtc->irq = platform_get_irq(pdev, 0); if (davinci_rtc->irq < 0) { dev_err(dev, "no RTC irq\n"); ret = davinci_rtc->irq; goto fail1; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "no mem resource\n"); ret = -EINVAL; goto fail1; } davinci_rtc->pbase = res->start; davinci_rtc->base_size = resource_size(res); mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size, pdev->name); if (!mem) { dev_err(dev, "RTC registers at %08x are not free\n", davinci_rtc->pbase); ret = -EBUSY; goto fail1; } davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size); if (!davinci_rtc->base) { dev_err(dev, "unable to ioremap MEM resource\n"); ret = -ENOMEM; goto fail2; } platform_set_drvdata(pdev, davinci_rtc); davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &davinci_rtc_ops, THIS_MODULE); if (IS_ERR(davinci_rtc->rtc)) { dev_err(dev, "unable to register RTC device, err %ld\n", PTR_ERR(davinci_rtc->rtc)); goto fail3; } rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); rtcss_write(davinci_rtc, 0, PRTCSS_RTC_INTC_EXTENA1); rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL); rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL); ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt, 0, "davinci_rtc", davinci_rtc); if (ret < 0) { dev_err(dev, "unable to register davinci RTC interrupt\n"); goto fail4; } /* Enable interrupts */ rtcif_write(davinci_rtc, PRTCIF_INTEN_RTCSS, PRTCIF_INTEN); rtcss_write(davinci_rtc, PRTCSS_RTC_INTC_EXTENA1_MASK, PRTCSS_RTC_INTC_EXTENA1); rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL); device_init_wakeup(&pdev->dev, 0); return 0; fail4: rtc_device_unregister(davinci_rtc->rtc); fail3: platform_set_drvdata(pdev, NULL); iounmap(davinci_rtc->base); fail2: release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); fail1: kfree(davinci_rtc); return ret; }