?? pxa270-rtc.c
字號:
/* drivers/char/pxa270_rtc.c * * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> * http://www.simtec.co.uk/products/SWLINUX/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * PXA270 Internal RTC Driver * * Changelog: * 08-Nov-2004 BJD Initial creation * 12-Nov-2004 BJD Added periodic IRQ and PM code * 22-Nov-2004 BJD Sign-test on alarm code to check for <0*/#include <linux/module.h>#include <linux/fs.h>#include <linux/string.h>#include <linux/init.h>#include <linux/device.h>#include <linux/interrupt.h>#include <linux/rtc.h>#include <linux/bcd.h>#include <linux/delay.h>#include <asm/hardware.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/rtc.h>#include <asm/mach/time.h>#include <linux/moduleparam.h>#include <linux/types.h>#include <linux/timer.h>#include <linux/jiffies.h>#include <linux/config.h>#include <linux/wait.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/watchdog.h>#include <linux/notifier.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/reboot.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/hardware/clock.h>#include <asm/arch/pxa-regs.h>#include <asm-arm/delay.h>/* need this for the RTC_AF definitions *///#include <linux/mc146818rtc.h>#undef PXA270_VA_RTC#define PXA270_VA_RTC pxa270_rtc_base#define DEBUGstatic struct resource *pxa270_rtc_mem;static void __iomem *pxa270_rtc_base;static int pxa270_rtc_alarmno = NO_IRQ;static int pxa270_rtc_tickno = NO_IRQ;static int pxa270_rtc_freq = 1;static spinlock_t pxa270_rtc_pie_lock = SPIN_LOCK_UNLOCKED;/* IRQ Handlers */static irqreturn_t pxa270_rtc_alarmirq(int irq, void *id, struct pt_regs *r){/// rtc_update(1, RTC_AF | RTC_IRQF); return IRQ_HANDLED;}static irqreturn_t pxa270_rtc_tickirq(int irq, void *id, struct pt_regs *r){/// rtc_update(1, RTC_PF | RTC_IRQF); return IRQ_HANDLED;}/* Update control registers */static void pxa270_rtc_setaie(int to){ unsigned int tmp; pr_debug("%s: aie=%d\n", __FUNCTION__, to);#if 0 tmp = readb(PXA270_RTCALM); if (to) tmp |= PXA270_RTCALM_ALMEN; else tmp &= ~PXA270_RTCALM_ALMEN; writeb(tmp, PXA270_RTCALM);#endif}static void pxa270_rtc_setpie(int to){ unsigned int tmp; pr_debug("%s: pie=%d\n", __FUNCTION__, to);#if 0 spin_lock_irq(&pxa270_rtc_pie_lock); tmp = readb(PXA270_TICNT) & ~PXA270_TICNT_ENABLE; if (to) tmp |= PXA270_TICNT_ENABLE; writeb(tmp, PXA270_TICNT); spin_unlock_irq(&pxa270_rtc_pie_lock);#endif}static void pxa270_rtc_setfreq(int freq){ unsigned int tmp;#if 0 spin_lock_irq(&pxa270_rtc_pie_lock); tmp = readb(PXA270_TICNT) & PXA270_TICNT_ENABLE; pxa270_rtc_freq = freq; tmp |= (128 / freq)-1; writeb(tmp, PXA270_TICNT); spin_unlock_irq(&pxa270_rtc_pie_lock);#endif}/* Time read/write */static void pxa270_rtc_gettime(struct rtc_time *rtc_tm)/* Written by Kenan */{ rtc_tm->tm_sec = (RDCR >> 0) & 0x3F; rtc_tm->tm_min = (RDCR >> 6) & 0x3F; rtc_tm->tm_hour = (RDCR >> 12) & 0x1F; rtc_tm->tm_mday = (RYCR >> 0) & 0x1F; rtc_tm->tm_mon = (RYCR >> 5) & 0xF; rtc_tm->tm_year = (RYCR >> 9) & 0xFFF; #if 0 unsigned int have_retried = 0; retry_get_time: rtc_tm->tm_min = readb(PXA270_RTCMIN); rtc_tm->tm_hour = readb(PXA270_RTCHOUR); rtc_tm->tm_mday = readb(PXA270_RTCDATE); rtc_tm->tm_mon = readb(PXA270_RTCMON); rtc_tm->tm_year = readb(PXA270_RTCYEAR); rtc_tm->tm_sec = readb(PXA270_RTCSEC); /* the only way to work out wether the system was mid-update * when we read it is to check the second counter, and if it * is zero, then we re-try the entire read */ if (rtc_tm->tm_sec == 0 && !have_retried) { have_retried = 1; goto retry_get_time; } pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); BCD_TO_BIN(rtc_tm->tm_sec); BCD_TO_BIN(rtc_tm->tm_min); BCD_TO_BIN(rtc_tm->tm_hour); BCD_TO_BIN(rtc_tm->tm_mday); BCD_TO_BIN(rtc_tm->tm_mon); BCD_TO_BIN(rtc_tm->tm_year); rtc_tm->tm_year += 100; rtc_tm->tm_mon -= 1;#endif}static int pxa270_rtc_settime(struct rtc_time *tm)/* written by Kenan */{ /* the rtc gets round the y2k problem by just not supporting it */ RYCR = ( (tm->tm_mday <<0) | (tm->tm_mon << 5) | (tm->tm_year <<9)); RDCR = ( (tm->tm_sec <<0) | (tm->tm_min << 6) | (tm->tm_hour << 12)); #if 0 if (tm->tm_year < 100) return -EINVAL; writeb(BIN2BCD(tm->tm_sec), PXA270_RTCSEC); writeb(BIN2BCD(tm->tm_min), PXA270_RTCMIN); writeb(BIN2BCD(tm->tm_hour), PXA270_RTCHOUR); writeb(BIN2BCD(tm->tm_mday), PXA270_RTCDATE); writeb(BIN2BCD(tm->tm_mon + 1), PXA270_RTCMON); writeb(BIN2BCD(tm->tm_year - 100), PXA270_RTCYEAR);#endif return 0;}static void pxa270_rtc_getalarm(struct rtc_wkalrm *alrm){ struct rtc_time *alm_tm = &alrm->time; unsigned int alm_en;#if 0 printk("pxa270_rtc:RTTR=%2x\n",readb(RTTR)); alm_tm->tm_sec = readb(PXA270_ALMSEC); alm_tm->tm_min = readb(PXA270_ALMMIN); alm_tm->tm_hour = readb(PXA270_ALMHOUR); alm_tm->tm_mon = readb(PXA270_ALMMON); alm_tm->tm_mday = readb(PXA270_ALMDATE); alm_tm->tm_year = readb(PXA270_ALMYEAR); alm_en = readb(PXA270_RTCALM); pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", alm_en, alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); /* decode the alarm enable field */ if (alm_en & PXA270_RTCALM_SECEN) { BCD_TO_BIN(alm_tm->tm_sec); } else { alm_tm->tm_sec = 0xff; } if (alm_en & PXA270_RTCALM_MINEN) { BCD_TO_BIN(alm_tm->tm_min); } else { alm_tm->tm_min = 0xff; } if (alm_en & PXA270_RTCALM_HOUREN) { BCD_TO_BIN(alm_tm->tm_hour); } else { alm_tm->tm_hour = 0xff; } if (alm_en & PXA270_RTCALM_DAYEN) { BCD_TO_BIN(alm_tm->tm_mday); } else { alm_tm->tm_mday = 0xff; } if (alm_en & PXA270_RTCALM_MONEN) { BCD_TO_BIN(alm_tm->tm_mon); alm_tm->tm_mon -= 1; } else { alm_tm->tm_mon = 0xff; } if (alm_en & PXA270_RTCALM_YEAREN) { BCD_TO_BIN(alm_tm->tm_year); } else { alm_tm->tm_year = 0xffff; }#endif /* todo - set alrm->enabled ? */}static int pxa270_rtc_setalarm(struct rtc_wkalrm *alrm){ struct rtc_time *tm = &alrm->time; unsigned int alrm_en;#if 0 pr_debug("pxa270_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", alrm->enabled, tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); if (alrm->enabled || 1) { alrm_en = readb(PXA270_RTCALM) & PXA270_RTCALM_ALMEN; writeb(0x00, PXA270_RTCALM); if (tm->tm_sec < 60 && tm->tm_sec >= 0) { alrm_en |= PXA270_RTCALM_SECEN; writeb(BIN2BCD(tm->tm_sec), PXA270_ALMSEC); } if (tm->tm_min < 60 && tm->tm_min >= 0) { alrm_en |= PXA270_RTCALM_MINEN; writeb(BIN2BCD(tm->tm_min), PXA270_ALMMIN); } if (tm->tm_hour < 24 && tm->tm_hour >= 0) { alrm_en |= PXA270_RTCALM_HOUREN; writeb(BIN2BCD(tm->tm_hour), PXA270_ALMHOUR); } pr_debug("setting PXA270_RTCALM to %08x\n", alrm_en); writeb(alrm_en, PXA270_RTCALM); enable_irq_wake(pxa270_rtc_alarmno); } else { alrm_en = readb(PXA270_RTCALM); alrm_en &= ~PXA270_RTCALM_ALMEN; writeb(alrm_en, PXA270_RTCALM); disable_irq_wake(pxa270_rtc_alarmno); }#endif return 0;}static int pxa270_rtc_ioctl(unsigned int cmd, unsigned long arg){#if 0 switch (cmd) { case RTC_AIE_OFF: case RTC_AIE_ON: pxa270_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0); return 0; case RTC_PIE_OFF: case RTC_PIE_ON: pxa270_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0); return 0; case RTC_IRQP_READ: return put_user(pxa270_rtc_freq, (unsigned long __user *)arg); case RTC_IRQP_SET: if (arg < 1 || arg > 64) return -EINVAL; if (!capable(CAP_SYS_RESOURCE)) return -EACCES; /* check for power of 2 */ if ((arg & (arg-1)) != 0)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -