的晶振接口图
我们从S3C2440内部RTC模块结构图和数据手册得知,RTC在Linux中主要实现两种功能,分别是系统掉电后的时间日期维持和时间日期报警(类似定时器功能)。
①、时间日期维持功能:
主要是由RTC实时时钟控制寄存器RTCCON进行功能的使能控制,由节拍时间计数寄存器TICNT来产生节拍时间中断来实现实时操作系统功能相关的时间和实时同步。其中对时间日期的操作实际上是对BCD码操作,而BCD码则是由一系列的寄存器组成(BCD秒寄存器BCDSEC、BCD分寄存器BCDMIN、BCD小时寄存器BCDHOUR、BCD日期寄存器BCDDATE、BCD日寄存器BCDDAY、BCD月寄存器BCDMON、BCD年寄存器BCDYEAR)。
②、报警功能:
主要由RTC报警控制寄存器RTCALM进行功能使能控制,并产生报警中断。报警时间日期的设置也是对一系列的寄存器进行操作(报警秒数据寄存器ALMSEC、报警分钟数据寄存器ALMMIN、报警小时数据寄存器ALMHOUR、报警日期数据寄存器ALMDATE、报警月数据寄存器ALMMON、报警年数据寄存器ALMYEAR)。
3、RTC驱动实现步骤(建立驱动文件my2440_rtc.c):
注意:在每步中,为了让代码逻辑更加有条理和容易理解,就没有考虑代码的顺序,比如函数要先定义后调用。如果要编译此代码,请严格按照C语言的规范来调整代码的顺序。
①、依然是驱动程序的最基本结构:RTC驱动的初始化和退出部分及其他,如下:
#include #include #include #include #include
/*RTC平台驱动结构体,平台驱动结构体定义在platform_device.h中,该结构体内的接口函数在第②、④步中实现*/ static struct platform_driver rtc_driver = { .probe= rtc_probe, /*RTC探测函数,在第②步中实现*/ .remove= __devexit_p(rtc_remove),/*RTC移除函数,在第④步实现,为何使用__devexit_p,在该函数实现的地方再讲*/ .suspend = rtc_suspend, /*RTC挂起函数,在第④步中实现*/ .resume= rtc_resume, /*RTC恢复函数,在第④步中实现*/ .driver= { /*注意这里的名称一定要和系统中定义平台设备的地方一致,这样才能把平台设备与该平台设备的驱动关联起来*/ .name= "s3c2410-rtc", .owner= THIS_MODULE, }, };
static int __init rtc_init(void) { /*将RTC注册成平台设备驱动*/ return platform_driver_register(&rtc_driver); }
static void __exit rtc_exit(void) { /*注销RTC平台设备驱动*/ platform_driver_unregister(&rtc_driver); }
module_init(rtc_init); module_exit(rtc_exit);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huang Gang"); MODULE_DESCRIPTION("My2440 RTC driver"); |
②、RTC平台驱动结构中探测函数rtc_probe的实现。探测就意味着在系统总线中去检测设备的存在,然后获取设备有用的相关资源信息,以便我们使用这些信息。代码如下:
#include #include #include #include #include
/*定义了一个用来保存RTC的IO端口占用的IO空间和经过虚拟映射后的内存地址*/ static struct resource *rtc_mem; static void __iomem *rtc_base;
/*定义了两个变量来保存RTC报警中断号和TICK节拍时间中断号,NO_IRQ宏定义在irq.h中*/ static int rtc_alarmno = NO_IRQ; static int rtc_tickno = NO_IRQ;
/*申明并初始化一个自旋锁rtc_pie_lock,对RTC资源进行互斥访问*/ static DEFINE_SPINLOCK(rtc_pie_lock);
/*RTC平台驱动探测函数,注意这里为什么要使用一个__devinit,也到rtc_remove实现的地方一起讲*/ static int __devinit rtc_probe(struct platform_device *pdev) { int ret; struct rtc_device *rtc; /*定义一个RTC设备类,rtc_device定义在rtc.h中*/ struct resource *res; /*定义一个资源,用来保存获取的RTC的资源*/
/*在系统定义的RTC平台设备中获取RTC报警中断号 platform_get_irq定义在platform_device.h中*/ rtc_alarmno = platform_get_irq(pdev, 0); if (rtc_alarmno < 0) { /*获取RTC报警中断号不成功错误处理 dev_err定义在device.h中,在platform_device.h中已经引用,所以这里就不需再引用了*/ dev_err(&pdev->dev, "no irq for alarm\n"); return -ENOENT; }
//在系统定义的RTC平台设备中获取TICK节拍时间中断号 rtc_tickno = platform_get_irq(pdev, 1); if (rtc_tickno < 0) { /*获取TICK节拍时间中断号不成功错误处理*/ dev_err(&pdev->dev, "no irq for rtc tick\n"); return -ENOENT; }
/*获取RTC平台设备所使用的IO端口资源,注意这个IORESOURCE_MEM标志和RTC平台设备定义中的一致*/ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { /*错误处理*/ dev_err(&pdev->dev, "fai |