RTC(Real-time clock)本身是一个时钟,用来记录真实时间,当软件系统关机后保留系统时间并继续进行计时,系统重新开启后在将时间同步进软件系统。
可以看到,主要电池供电和系统供电双供电电路和晶振电路。
1.双供电系统主要作用是系统供电是整体由系统供电,如果是可供电电池,电池还可以充电。系统关机后使用电池仅仅对rtc 部分进行供电,维持记录的时间不丢失,系统时间还能够继续进行计时,防止系统重启后记录的确实上次异常关机的时间省去了系统重启后设置系统时间的步骤。
2.晶振一般采用32.768kHz,至于为什么是这个古怪的频率,主要是由于32768是2的15次方。计时频率越高时间误差越小,但是由于旧系统一般也只有16位,不像现在都是64位机,所以计数归零定义为秒进位,也就是秒增加1就是32768,其实这是一个性能个功耗成本的中和。
rtc 内部计时的结构:
以上就是一般的rtc 的内部寄存器的结构图,一般有天、时、分、秒寄存器。但是有些芯片内部做了年月日自动计算,闰年闰月识别的功能,这样就不需要软件将天寄存器计算成年月日,但由于这样做会增加些许复杂度一般的小公司产品不敢干,毕竟硬件错了不好补救了,做好没奖励做错反而给自己找麻烦的心态。
以上是三星的6410的rtc 寄存器设计,他就做了内部年月日分开。
驱动设计:
1.驱动需要调用一个注册函数,系统就知道你使用了硬件rtc了。
rtc = rtc_device_register(rtc_platform_info->dev_name,\
&pdev->dev, &fh_rtcops,
THIS_MODULE);
2.实现rtc 操作需要的几个函数
static const struct rtc_class_ops fh_rtcops = {
.open = fh_rtc_open,
.release = fh_rtc_release,
.read_time = fh_rtc_gettime_nosync,
.set_time = fh_rtc_settime,
.read_alarm = fh_rtc_getalarm,
.set_alarm = fh_rtc_setalarm,
.alarm_irq_enable = fh_rtc_irq_enable,
};
最重要的函数是
.read_time = fh_rtc_gettime_nosync,
.set_time = fh_rtc_settime,
像alarm 这样的功能也是可以不支持的,或者使用软件进行模拟。
读取时间的接口函数类型:
rtc_tm 中存放的时分秒 年月日信息,驱动需要把这些时间信息给这个指针结构体,然后返回给调用这个地址。
static int fh_rtc_gettime_nosync(struct device *dev, struct rtc_time *rtc_tm)
{
unsigned int temp;
temp = fh_rtc_get_hw_sec_data(TIME_FUNC);
rtc_time_to_tm(temp, rtc_tm);
RTC_PRINT_DBG("rtc read date:0x%x\n", temp);
return 0;
}
设置时间的接口函数类型:
同样tm 结构体中存放的时分秒 年月日,驱动需要把这些时间信息存放到硬件,硬件IP从这个时间点继续计时。
static int fh_rtc_settime(struct device *dev, struct rtc_time *tm)
{
struct rtc_time rtc_tm_read0;
unsigned int status;
unsigned int loop_count;
struct platform_device *pdev = to_platform_device(dev);
struct fh_rtc_controller *fh_rtc = platform_get_drvdata(pdev);
int cnt, ret, read_count = 0;
RTC_PRINT_DBG("rtc write %d-%d-%d %d:%d:%d\n",
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
这个驱动就正式完成了。