6.Ricoboard开发板上RTC模块简单分析和使用
1. 概念
RTC是real-time clock的缩写,其主要用途就是产生一个独立运行的计时器,Linux或者Windows系统启动后需要从这个计时器中读取时间,来设置系统时间。RTC具有断电保存的特性,防止因为意外断电导致系统时间混乱.
2. 硬件设备
2.1 I2c接口设备
Dallas/MaximDS1307/37/38/39/40, ST M41T00, EPSON RX-8025
Dallas/MaximDS1374 Dallas/Maxim DS1672 Dallas/Maxim DS3232
MaximMAX6900
Ricoh R2025S/D,RS5C372A/B, RV5C386, RV5C387A
Intersil ISL1208Intersil ISL12022
Xicor/IntersilX1205
PhilipsPCF8563/Epson RTC8564 PhilipsPCF8583
STM41T62/65/M41T80/81/82/83/84/85/87
TI BQ32000
SeikoInstruments S-35390A
Ramtron FM3130
EpsonRX-8581 Epson RX-8025SA/NB
EMMicroelectronic EM3027
Micro CrystalRTC
2.2 SPI接口设备
PC-style 'CMOS'
Dallas DS1286Dallas DS1511
Maxim/DallasDS1553 Maxim/Dallas DS1742/1743
Simtek STK17TA8
ST M48T86/DallasDS12887 ST M48T35 STM48T59/M48T08/M48T02
Oki MSM6242
TI BQ4802
RicohRP5C01
EMMicroelectronic V3020
2.3 CPU自带设备
ARM AMBA PL030RTC ARM AMBA PL031 RTC
NS2816 RTC
二、RTC驱动架构1. 核心文件
l myir_ricoboard.dts和am4372.dtsi文件在arch/arm/boot/dts文件夹下,设置rtc设备树数据
l rtc-omap.c cpu提供的与rtc设备相关的驱动,与硬件层和上层交互的函数。
l /include/linux/rtc.h rtc基础数据结构
l Class.c rtc类注册文件,rtc相关最早加载,并主动通过rtc_dev_init加载rtc-dev.c,通过rtc_sysfs_init加载rtc-sysfs.c,提供一些相关函数如:devm_rtc_device_register /kernel/dirvers/rtc
l rtc-dev.c 注册char驱动rtc,
l rtc-sysfs.c sysfs相关文件
l rtc-proc.c 与/proc设备节点相关文件
l systohc.c Save NTPsynchronized time to the RTC
l hctosys.c linux开机启动系统时间设置
l rtc-lib.c 时间转换相关函数实现
2. 驱动模型
说明:应用层可以通过三种方式访问RTC硬件,因为代码实现方式不同目前只有一种方式可写,其他方式只读。
1. 重要数据结构体
1.1 dts数据结构
myir_ricoboard.dts文件中加载rtc设备树
&rtc{
status = "okay";
};
am4372.dtsi文件中定义rtc数据结构
rtc: rtc@44e3e000 {
compatible= "ti,am4372-rtc","ti,da830-rtc";
reg = ;
interrupts= ;
ti,hwmods= "rtc";
clocks = ;
clock-names= "fck";
status ="disabled";
};
1.2 rtc设备驱动加载相关数据结构
static struct platform_device_idomap_rtc_devtype[] = {
{
.name = DRIVER_NAME,
},
[OMAP_RTC_DATA_AM3352_IDX]= {
.name = "am3352-rtc",
.driver_data= OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN,
},
[OMAP_RTC_DATA_DA830_IDX]= {
.name = "da830-rtc",
.driver_data= OMAP_RTC_HAS_KICKER,
},
{},
};
MODULE_DEVICE_TABLE(platform,omap_rtc_devtype);
static const struct of_device_idomap_rtc_of_match[] = {
{ .compatible = "ti,da830-rtc",
.data =&omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX],
},
{ .compatible = "ti,am3352-rtc",
.data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX],
},
{},
};
MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
1.3 rtc设备驱动与硬件层交互相关数据结构,
static struct rtc_class_ops omap_rtc_ops ={
.read_time = omap_rtc_read_time,
.set_time = omap_rtc_set_time,
.read_alarm = omap_rtc_read_alarm,
.set_alarm = omap_rtc_set_alarm,
.alarm_irq_enable= omap_rtc_alarm_irq_enable,
};
1.4 rtc设备驱动与GPIO设置相关数据结构
#define OMAP_RTC_BASE 0xfffb4800
/* OMAP_RTC_KICKER values */
#define KICK0_VALUE 0x83e70b13
#define KICK1_VALUE 0x95a4f1e0
1.5 rtc设备驱动与/dev设备节点交互相关数据结构
static const struct file_operationsrtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.unlocked_ioctl = rtc_dev_ioctl,
.open = rtc_dev_open,
.release = rtc_dev_release,
.fasync = rtc_dev_fasync,
};
ATTRIBUTE_GROUPS(rtc);
1.6 rtc设备驱动与/proc设备节点交互相关数据结构
static const struct file_operationsrtc_proc_fops = {
.open = rtc_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = rtc_proc_release,
};
1.7 rtc设备驱动与/sys/class/rtc相关数据结构
CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
static struct attribute *rtc_attrs[] = {
&dev_attr_name.attr,
&dev_attr_date.attr,
&dev_attr_time.attr,
&dev_attr_since_epoch.attr,
&dev_attr_max_user_freq.attr,
&dev_attr_hctosys.attr,
NULL,
};
1.8 时间转换相关结构体
static const unsigned charrtc_days_in_month[] = {
31,28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static const unsigned shortrtc_ydays[2][13] = {
/*Normal years */
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
/*Leap years */
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
三、RTC驱动重要函数介绍1. 驱动加载函数
1.1 rtc_init函数
static int __init rtc_init(void)
{
rtc_class= class_create(THIS_MODULE, "rtc");
if(IS_ERR(rtc_class)) {
pr_err("couldn'tcreate class\n");
returnPTR_ERR(rtc_class);
}
rtc_class->pm= RTC_CLASS_DEV_PM_OPS;
rtc_dev_init();
rtc_sysfs_init(rtc_class);
return0;
}
subsys_initcall(rtc_init);
1.2 omap_rtc_int
#if 0
module_platform_driver_probe(omap_rtc_driver, omap_rtc_probe);
#else
static int __init omap_rtc_driver_init(void)
{
printk("=1=omap_rtc_driver_initmodule_init\n");
returnplatform_driver_probe(&(omap_rtc_driver), omap_rtc_probe);
}
module_init(omap_rtc_driver_init);
static void __exit omap_rtc_driver_exit(void)
{
platform_driver_unregister(&(omap_rtc_driver));
}
module_exit(omap_rtc_driver_exit);
#endif
1.3 rtc_hctosys加载函数
static int __init rtc_hctosys(void)
{
………
}
late_initcall(rtc_hctosys);
voidrtc_proc_add_device(struct rtc_device *rtc)
{
if (is_rtc_hctosys(rtc))
proc_create_data("driver/rtc",0, NULL, &rtc_proc_fops, rtc);
}
2. Probe探针函数
static int __init omap_rtc_probe(structplatform_device *pdev)
{
//of_match_device
//omap_rtc_timer
//omap_rtc_alarm
//platform_get_device_id
//devm_rtc_device_register
//rtc gpio设置
}
devm_rtc_device_register –>rtc_device_register
{
rtc_dev_prepare;
device_register;
rtc_dev_add_device; //创建/dev/rtc*设备节点
rtc_sysfs_add_device; //创建/sys/class/rtc/rtc0设备节点
rtc_proc_add_device) //创建/proc/driver/rtc设备节点
}
3. 设备节点创建,操作函数
3.1 /dev/rtc*设备节点
3.1.1 创建函数
void rtc_dev_prepare(structrtc_device *rtc)
{
if(!rtc_devt)
return;
if(rtc->id >= RTC_DEV_MAX) {
dev_dbg(&rtc->dev,"%s: too many RTC devices\n", rtc->name);
return;
}
rtc->dev.devt= MKDEV(MAJOR(rtc_devt), rtc->id);
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
INIT_WORK(&rtc->uie_task,rtc_uie_task);
setup_timer(&rtc->uie_timer,rtc_uie_timer, (unsigned long)rtc);
#endif
cdev_init(&rtc->char_dev,&rtc_dev_fops);//在这里静态初始化/dev设备节点,访问函数在rtc_dev_fops结构体中定义。
rtc->char_dev.owner= rtc->owner;
}
void rtc_dev_add_device(struct rtc_device*rtc)
{
if(cdev_add(&rtc->char_dev, rtc->dev.devt, 1))//将初始化的设备节点加载到系统中
dev_warn(&rtc->dev,"%s: failed to add char device %d:%d\n",
rtc->name,MAJOR(rtc_devt), rtc->id);
else
dev_dbg(&rtc->dev,"%s: dev (%d:%d)\n", rtc->name,
MAJOR(rtc_devt),rtc->id);
}
3.1.2 open函数
static int rtc_dev_open(struct inode*inode, struct file *file)
{
interr;
structrtc_device *rtc = container_of(inode->i_cdev,
structrtc_device, char_dev);
conststruct rtc_class_ops *ops = rtc->ops;
printk("=1=rtc_dev_open\n");
if(test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
return-EBUSY;
printk("=2=rtc_dev_open\n");
file->private_data= rtc;
printk("=3=rtc_dev_open\n");
err= ops->open ? ops->open(rtc->dev.parent) : 0;
if(err == 0) {
spin_lock_irq(&rtc->irq_lock);
rtc->irq_data= 0;
spin_unlock_irq(&rtc->irq_lock);
return0;
}
printk("=4=rtc_dev_open\n");
/*something has gone wrong */
clear_bit_unlock(RTC_DEV_BUSY,&rtc->flags);
returnerr;
}//open函数相应打开设备节点动作
}
3.1.3 rtc_dev_ioctl函数
static long rtc_dev_ioctl(struct file*file,
unsignedint cmd, unsigned long arg)
{//这里是此设备节点读写的实现,注意其会继续调用
case RTC_RD_TIME:
mutex_unlock(&rtc->ops_lock);
err =rtc_read_time(rtc, &tm);
if (err ops_lock);
if(copy_from_user(&tm, uarg, sizeof(tm)))
return-EFAULT;
returnrtc_set_time(rtc, &tm);
…..
}
3.1.4 rtc_read_time函数
int rtc_read_time(struct rtc_device *rtc,struct rtc_time *tm)
{
interr;
err= mutex_lock_interruptible(&rtc->ops_lock);
if(err)
returnerr;
err= __rtc_read_time(rtc, tm);
mutex_unlock(&rtc->ops_lock);
returnerr;
}
EXPORT_SYMBOL_GPL(rtc_read_time);
3.1.5 rtc_set_time函数
int rtc_set_time(struct rtc_device *rtc,struct rtc_time *tm)
{
interr;
err= rtc_valid_tm(tm);
if(err != 0)
returnerr;
err= mutex_lock_interruptible(&rtc->ops_lock);
if(err)
returnerr;
if(!rtc->ops)
err= -ENODEV;
elseif (rtc->ops->set_time)
err= rtc->ops->set_time(rtc->dev.parent, tm);
elseif (rtc->ops->set_mmss) {
unsignedlong secs;
err= rtc_tm_to_time(tm, &secs);
if(err == 0)
err= rtc->ops->set_mmss(rtc->dev.parent, secs);
}else
err= -EINVAL;
mutex_unlock(&rtc->ops_lock);
/*A timer might have just expired */
schedule_work(&rtc->irqwork);
returnerr;
}
EXPORT_SYMBOL_GPL(rtc_set_time);
3.1.6 omap_rtc_set_time函数
static int omap_rtc_set_time(struct device*dev, struct rtc_time *tm)
{
if(tm2bcd(tm) tm_year,OMAP_RTC_YEARS_REG);
rtc_write(tm->tm_mon,OMAP_RTC_MONTHS_REG);
rtc_write(tm->tm_mday,OMAP_RTC_DAYS_REG);
rtc_write(tm->tm_hour,OMAP_RTC_HOURS_REG);
rtc_write(tm->tm_min,OMAP_RTC_MINUTES_REG);
rtc_write(tm->tm_sec,OMAP_RTC_SECONDS_REG);
local_irq_enable();
return0;
}
3.1.7 omap_rtc_read_time函数
static int omap_rtc_read_time(struct device*dev, struct rtc_time *tm)
{
/*we don't report wday/yday/isdst ... */
local_irq_disable();
rtc_wait_not_busy();
tm->tm_sec= rtc_read(OMAP_RTC_SECONDS_REG);
tm->tm_min= rtc_read(OMAP_RTC_MINUTES_REG);
tm->tm_hour= rtc_read(OMAP_RTC_HOURS_REG);
tm->tm_mday= rtc_read(OMAP_RTC_DAYS_REG);
tm->tm_mon= rtc_read(OMAP_RTC_MONTHS_REG);
tm->tm_year= rtc_read(OMAP_RTC_YEARS_REG);
local_irq_enable();
bcd2tm(tm);
return0;
}
3.1.8
omap_rtc_set_time函数
3.2 /sys/class/rtc/rtc0设备节点
3.2.1 注册函数
void __init rtc_sysfs_init(struct class*rtc_class)
{
printk("=1=rtc_sysfs_init\n");
rtc_class->dev_groups= rtc_groups;//将与设备节点相关的操作初始化
}
上面的赋值需要下面的结构体和ATTRIBUTE_GROUPS宏线运行。
static struct attribute *rtc_attrs[] = {
&dev_attr_name.attr,
&dev_attr_date.attr,
&dev_attr_time.attr,
&dev_attr_since_epoch.attr,
&dev_attr_max_user_freq.attr,
&dev_attr_hctosys.attr,
NULL,
};
ATTRIBUTE_GROUPS(rtc);//
void rtc_sysfs_add_device(struct rtc_device*rtc)
{
interr;
/*not all RTCs support both alarms and wakeup */
if(!rtc_does_wakealarm(rtc))
return;
err= device_create_file(&rtc->dev, &dev_attr_wakealarm);//设备节点真正创建
if(err)
dev_err(rtc->dev.parent,
"failedto create alarm attribute, %d\n", err);
}
3.2.2 操作节点相关函数
static DEVICE_ATTR_RO(name);注意其是RO模式
static ssize_t
name_show(struct device *dev, structdevice_attribute *attr, char *buf)
{
returnsprintf(buf, "%s\n", to_rtc_device(dev)->name);
}
static DEVICE_ATTR_RO(date);
static DEVICE_ATTR_RO(time);
static DEVICE_ATTR_RO(since_epoch);
static DEVICE_ATTR_RW(max_user_freq);
static DEVICE_ATTR_RO(hctosys);
ATTRIBUTE_GROUPS(rtc);
static DEVICE_ATTR(wakealarm, S_IRUGO |S_IWUSR,
rtc_sysfs_show_wakealarm,rtc_sysfs_set_wakealarm);
3.3 /proc/driver/rtc设备节点
3.3.1 设备节点创建
static const struct file_operationsrtc_proc_fops = {
.open = rtc_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = rtc_proc_release,
};
void rtc_proc_add_device(struct rtc_device*rtc)
{
printk("=1=rtc_proc_add_device\n");
if(is_rtc_hctosys(rtc))
proc_create_data("driver/rtc",0, NULL, &rtc_proc_fops, rtc);
printk("=2=rtc_proc_add_device\n");
}
3.3.2 Open函数
static int rtc_proc_open(struct inode*inode, struct file *file)
{
intret;
structrtc_device *rtc = PDE_DATA(inode);
if(!try_module_get(THIS_MODULE))
return-ENODEV;
ret= single_open(file, rtc_proc_show, rtc);
if(ret)
module_put(THIS_MODULE);
returnret;
}
3.3.3 rtc_proc_show函数实现。
static int rtc_proc_show(struct seq_file*seq, void *offset)
{
interr;
structrtc_device *rtc = seq->private;
conststruct rtc_class_ops *ops = rtc->ops;
structrtc_wkalrm alrm;
structrtc_time tm;
err= rtc_read_time(rtc, &tm);
if(err == 0) {
seq_printf(seq,
"rtc_time\t:%02d:%02d:%02d\n"
"rtc_date\t:%04d-%02d-%02d\n",
tm.tm_hour,tm.tm_min, tm.tm_sec,
tm.tm_year+ 1900, tm.tm_mon + 1, tm.tm_mday);
}
err= rtc_read_alarm(rtc, &alrm);
if(err == 0) {
seq_printf(seq,"alrm_time\t: ");
if((unsigned int)alrm.time.tm_hour uie_rtctimer.enabled)? "yes" : "no");
seq_printf(seq,"periodic IRQ enabled\t: %s\n",
(rtc->pie_enabled)? "yes" : "no");
seq_printf(seq,"periodic IRQ frequency\t: %d\n",
rtc->irq_freq);
seq_printf(seq,"max user IRQ frequency\t: %d\n",
rtc->max_user_freq);
}
seq_printf(seq,"24hr\t\t: yes\n");
if(ops->proc)
ops->proc(rtc->dev.parent,seq);
return0;
}
3.3.4 seq_read实现,与proc文件系统密切相关。
4. GPIO相关函数
rtc_read rtc_write rtc_writel
5. 时间转换函数
跟01-01-1970 00:00:00转化秒数为time结构体时间,函数比较多就不一一列举。
Convert seconds since 01-01-1970 00:00:00 to Gregoriandate.
void rtc_time_to_tm(unsigned long time,struct rtc_time *tm)
{
unsignedint month, year;
intdays;
days= time / 86400;
time-= (unsigned int) days * 86400;
/*day of the week, 1970-01-01 was a Thursday */
tm->tm_wday= (days + 4) % 7;
year= 1970 + days / 365;
days-= (year - 1970) * 365
+LEAPS_THRU_END_OF(year - 1)
-LEAPS_THRU_END_OF(1970 - 1);
if(days tm_year= year - 1900;
tm->tm_yday= days + 1;
for(month = 0; month tm_mon= month;
tm->tm_mday= days + 1;
tm->tm_hour= time / 3600;
time-= tm->tm_hour * 3600;
tm->tm_min= time / 60;
tm->tm_sec= time - tm->tm_min * 60;
tm->tm_isdst= 0;
}
四、用户层应用
1. 通过/proc文件系统访问rtc
1.1 源代码
直接通过cat命令访问设备节点cat /proc/driver/rtc
1.2 Kernel log和驱动响应
root@m437x-evm:~# cat /proc/driver/rtc
=1=rtc_proc_open
=2=rtc_proc_open
=3=rtc_proc_open
=4=rtc_proc_open
=1=rtc_read_time
=1=__rtc_read_time
=1=omap_rtc_read_time
=2=omap_rtc_read_time
=2=__rtc_read_time
=2=rtc_read_time
rtc_time : 14:38:18
rtc_date : 2016-11-09
alrm_time : 00:00:00
alrm_date : 2000-01-01
alarm_IRQ : no
alrm_pending : no
update IRQ enabled :no
periodic IRQ enabled : no
periodic IRQ frequency : 1
max user IRQ frequency : 64
24hr : yes
2. 通过/sys文件系统访问rtc
直接使用cat对/sys/class/rtc/rtc0下面的节点进行访问,不过只能读而已。
root@m437x-evm:/sys/class/rtc/rtc0# catdate
=1=rtc_read_time
=1=__rtc_read_time
=1=omap_rtc_read_time
=2=omap_rtc_read_time
=2=__rtc_read_time
=2=rtc_read_time
2016-11-09
root@m437x-evm:/sys/class/rtc/rtc0# cattime
=1=rtc_read_time
=1=__rtc_read_time
=1=omap_rtc_read_time
=2=omap_rtc_read_time
=2=__rtc_read_time
=2=rtc_read_time
14:39:40
3. 通过/dev目录访问rtc
3.1 源代码
/********************************************************************
* copyright(C) 2014 all rights reserved
* @file: rtc_test.c
* @Created: 2014-8-7 10:30
* @Author: conway chen
* @Description: read and write rtc time
* @modify Date: 2014-8-7 10:30
*********************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static const char default_rtc[] ="/dev/rtc0";
static char *program_name;
/**
*@brief: print help message
*/
static void help(void)
{
fprintf(stderr,
"\tUsage: %s [OPTION]...\n"
"\t-h,--help help\n"
"\t-s,--set set date/time given with you.\n\tinputformat:./rtc_test [hour] [minute] [second] [year] [month] [day]\n"
"\t-r,--show read hardware clock and print result\n"
"\n", program_name);
}
/**
*@brief: read RTC date and time
*@Param: fd: the file descriptor of rtc device
*/
void rtc_read_time(int fd)
{
intretval;
structrtc_time rtc_tm;
/*readthe RTC time/date*/
retval= ioctl(fd, RTC_RD_TIME, &rtc_tm);
if(retval == -1) {
perror("RTC_RD_TIMEioctl");
exit(errno);
}
fprintf(stderr,"\n\tCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n\n",
rtc_tm.tm_mday,rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
rtc_tm.tm_hour,rtc_tm.tm_min, rtc_tm.tm_sec);
}
/**
*@brief: set rtc date and time
*@Param: fd: the file descriptor of rtc device
*@Param: hour: the hour to set
*@Param: minute: the minute to set
*@Param: second: the hour to set
*@Param: year: the year to set
*@Param: month: the month to set
*@Param: day: the day to set
*/
void rtc_set_time(int fd, int hour, intminute, int second, int year, int month, int day)
{
intretval;
structrtc_time rtc_tm;
rtc_tm.tm_mday= day;
rtc_tm.tm_mon= month - 1;
rtc_tm.tm_year= year - 1900;
rtc_tm.tm_hour= hour;
rtc_tm.tm_min= minute;
rtc_tm.tm_wday= rtc_tm.tm_yday = rtc_tm.tm_isdst = 0;
rtc_tm.tm_sec= second;
/*setthe RTC time/date*/
retval= ioctl(fd, RTC_SET_TIME, &rtc_tm);
if(retval == -1) {
perror("RTC_SET_TIMEioctl");
exit(errno);
}
fprintf(stderr,"\n\t\tdate/time is updated to: %d-%d-%d, %02d:%02d:%02d.\n\n",
rtc_tm.tm_mday,rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
rtc_tm.tm_hour,rtc_tm.tm_min, rtc_tm.tm_sec);
}
/**
*@brief: main function
*@Param: argc: number of parameters
*@Param: argv: parameters list
*/
int main(int argc, char *argv[])
{
intfd, retval, c;
intset_flag = 0, read_flag = 0;
structrtc_time rtc_tm;
constchar *rtc = default_rtc;
structoption long_option[] =
{
{"help", 0, NULL, 'h'},
{"set", 1, NULL, 's'},
{"show", 0, NULL, 'r'},
{NULL, 0, NULL, 0},
};
program_name = argv[0];
while (1) {
if ((c = getopt_long(argc, argv,"hs:r", long_option, NULL)) < 0)
break;
switch (c) {
case'h':
help();
break;
case's':
if(argc < 8) {
fprintf(stderr,"\n\t\ttime format error!\n\n");
exit(errno);
}
set_flag= 1;
break;
case'r':
read_flag= 1;
break;
case'?':
help();
break;
default:
abort();
}
}
/* open rtc device */
fd = open(rtc, O_RDWR);
if(fd == -1) {
perror(rtc);
exit(errno);
}
if(argc == 1) {
rtc_read_time(fd);
}
if (set_flag)
rtc_set_time(fd,atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]), atoi(argv[6]),atoi(argv[7]));
if(read_flag)
rtc_read_time(fd);
close(fd);
return0;
}
3.2 驱动响应代码和Kernel log
4. linux系统命令hwclock
hwclock -w//将系统时钟写入硬件时钟
hwclock -s//将硬件时钟写入系统时钟
hwclock –r//显示硬件时钟
root@m437x-evm:/opt# hwclock -r
=1=rtc_dev_open
=2=rtc_dev_open
=3=rtc_dev_open
=RTC_RD_TIME=rtc_dev_ioctl
=1=rtc_read_time
=1=__rtc_read_time
=1=omap_rtc_read_time
=2=omap_rtc_read_time
=2=__rtc_read_time
=2=rtc_read_time
Sat Nov 19 11:15:12 2011 0.000000 seconds
5. linux系统命令date
root@m437x-evm:/opt# date
Wed Nov 9 14:43:25 UTC 2016
知识点总结:
1.RTC相关概念,驱动代码简单分析;
2.linux设置,读取RTC时钟的方式和大概流程;
3.proc和alarm相关知识后面有时间在详细总结。