RTC驱动Word下载.docx

上传人:b****8 文档编号:22437679 上传时间:2023-02-04 格式:DOCX 页数:19 大小:25.56KB
下载 相关 举报
RTC驱动Word下载.docx_第1页
第1页 / 共19页
RTC驱动Word下载.docx_第2页
第2页 / 共19页
RTC驱动Word下载.docx_第3页
第3页 / 共19页
RTC驱动Word下载.docx_第4页
第4页 / 共19页
RTC驱动Word下载.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

RTC驱动Word下载.docx

《RTC驱动Word下载.docx》由会员分享,可在线阅读,更多相关《RTC驱动Word下载.docx(19页珍藏版)》请在冰豆网上搜索。

RTC驱动Word下载.docx

=THIS_MODULE,

},

};

staticint__initrtc_init(void)

/*将RTC注册成平台设备驱动*/

returnplatform_driver_register(&

rtc_driver);

}

staticvoid__exitrtc_exit(void)

/*注销RTC平台设备驱动*/

platform_driver_unregister(&

module_init(rtc_init);

module_exit(rtc_exit);

MODULE_LICENSE("

GPL"

);

MODULE_AUTHOR("

HuangGang"

MODULE_DESCRIPTION("

My2440RTCdriver"

2、RTC平台驱动结构中探测函数rtc_probe的实现。

探测就意味着在系统总线中去检测设备的存在,然后获取设备有用的相关资源信息,以便我们使用这些信息。

代码如下:

asm/irq.h>

asm/io.h>

linux/rtc.h>

linux/ioport.h>

plat/regs-rtc.h>

/*定义了一个用来保存RTC的IO端口占用的IO空间和经过虚拟映射后的内存地址*/

staticstructresource*rtc_mem;

staticvoid__iomem*rtc_base;

/*定义了两个变量来保存RTC报警中断号和TICK节拍时间中断号,NO_IRQ宏定义在irq.h中*/

staticintrtc_alarmno=NO_IRQ;

staticintrtc_tickno=NO_IRQ;

/*申明并初始化一个自旋锁rtc_pie_lock,对RTC资源进行互斥访问*/

staticDEFINE_SPINLOCK(rtc_pie_lock)

/*RTC平台驱动探测函数,注意这里为什么要使用一个__devinit,也到rtc_remove实现的地方一起讲*/

staticint__devinitrtc_probe(structplatform_device*pdev)

intret;

structrtc_device*rtc;

/*定义一个RTC设备类,rtc_device定义在rtc.h中*/

structresource*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,"

noirqforalarm\n"

return-ENOENT;

//在系统定义的RTC平台设备中获取TICK节拍时间中断号

rtc_tickno=platform_get_irq(pdev,1);

if(rtc_tickno<

/*获取TICK节拍时间中断号不成功错误处理*/

noirqforrtctick\n"

/*获取RTC平台设备所使用的IO端口资源,注意这个IORESOURCE_MEM标志和RTC平台设备定义中的一致*/

res=platform_get_resource(pdev,IORESOURCE_MEM,0);

if(res==NULL)

/*错误处理*/

failedtogetmemoryregionresource\n"

/*申请RTC的IO端口资源所占用的IO空间(要注意理解IO空间和内存空间的区别),

request_mem_region定义在ioport.h中*/

rtc_mem=request_mem_region(res->

start,res->

end-res->

start+1,pdev->

name);

if(rtc_mem==NULL)

failedtoreservememoryregion\n"

ret=-ENOENT;

gotoerr_nores;

/*将RTC的IO端口占用的这段IO空间映射到内存的虚拟地址,ioremap定义在io.h中。

注意:

IO空间要映射后才能使用,以后对虚拟地址的操作就是对IO空间的操作,*/

rtc_base=ioremap(res->

start+1);

if(rtc_base==NULL)

failedioremap()\n"

ret=-EINVAL;

gotoerr_nomap;

/*好了,通过上面的步骤已经将RTC的资源都准备好了,下面就开始使用啦*/

/*这两个函数开始对RTC寄存器操作,定义都在下面*/

rtc_enable(pdev,1);

/*对RTC的实时时钟控制寄存器RTCCON进行操作(功能是初始化或者使能RTC)*/

rtc_setfreq(&

dev,1);

/*对RTC的节拍时间计数寄存器TICNT的0-6位进行操作,即:

节拍时间计数值的设定*

/*device_init_wakeup该函数定义在pm_wakeup.h中,定义如下:

staticinlinevoiddevice_init_wakeup(structdevice*dev,intval){

dev->

power.can_wakeup=dev->

power.should_wakeup=!

!

val;

显然这个函数是让驱动支持电源管理的,这里只要知道,can_wakeup为1时表明这个设备可以被唤醒,设备驱动为了支持

Linux中的电源管理,有责任调用device_init_wakeup()来初始化can_wakeup,而should_wakeup则是在设备的电源状态

发生变化的时候被device_may_wakeup()用来测试,测试它该不该变化,因此can_wakeup表明的是一种能力,

而should_wakeup表明的是有了这种能力以后去不去做某件事。

好了,我们没有必要深入研究电源管理的内容了,

要不就扯远了,电源管理以后再讲*/

device_init_wakeup(&

/*将RTC注册为RTC设备类,RTC设备类在RTC驱动核心部分中由系统定义好的,

注意rtcops这个参数是一个结构体,该结构体的作用和里面的接口函数实现在第③步中。

rtc_device_register函数在rtc.h中定义,在drivers/rtc/class.c中实现*/

rtc=rtc_device_register("

my2440"

&

dev,&

rtcops,THIS_MODULE);

if(IS_ERR(rtc))

cannotattachrtc\n"

ret=PTR_ERR(rtc);

gotoerr_nortc;

/*设置RTC节拍时间计数寄存器TICNT的节拍时间计数值的用户最大相对值,

这里你可能不理解这句,没关系,等你看到rtc_setfreq函数实现后自然就明白了*/

rtc->

max_user_freq=128;

/*将RTC设备类的数据传递给系统平台设备。

platform_set_drvdata是定义在platform_device.h的宏,如下:

#defineplatform_set_drvdata(_dev,data) 

dev_set_drvdata(&

(_dev)->

dev,(data))

而dev_set_drvdata又被定义在include/linux/device.h中,如下:

staticinlinevoiddev_set_drvdata(structdevice*dev,void*data){

driver_data=data;

}*/

platform_set_drvdata(pdev,rtc);

return0;

//以下是上面错误处理的跳转点

err_nortc:

rtc_enable(pdev,0);

iounmap(rtc_base);

err_nomap:

release_resource(rtc_mem);

err_nores:

returnret;

/*该函数主要是初始化或者使能RTC,

以下RTC的各种寄存器的宏定义在arch/arm/plat-s3c/include/plat/regs-rtc.h中,

各寄存器的用途和设置请参考S3C2440数据手册的第十七章实时时钟部分*/

staticvoidrtc_enable(structplatform_device*pdev,intflag)

unsignedinttmp;

/*RTC的实时时钟控制寄存器RTCCON共有4个位,各位的初始值均为0,根据数据手册介绍第0位(即:

RCTEN位)

可以控制CPU和RTC之间的所有接口(即RTC使能功能),所以在系统复位后应该将RTCCON寄存器的第0为置为1;

在关闭电源前,又应该将该位清零,以避免无意的写RTC寄存器*/

if(!

flag)

/*当flag=0时(即属于关闭电源前的情况),RTCCON寄存器清零第一位*/

tmp=readb(rtc_base+S3C2410_RTCCON);

/*读取RTCCON寄存器的值*/

/*tmp&

~S3C2410_RTCCON_RTCEN=0即屏蔽RTC使能*/

writeb(tmp&

~S3C2410_RTCCON_RTCEN,rtc_base+S3C2410_RTCCON);

tmp=readb(rtc_base+S3C2410_TICNT);

/*读取TICNT寄存器的值*/

~S3C2410_TICNT_ENABLE后第7位为0,即屏蔽节拍时间中断使能*/

~S3C2410_TICNT_ENABLE,rtc_base+S3C2410_TICNT);

}

else

/*当flag!

=0时(即属于系统复位后的情况),使能RTC*/

if((readb(rtc_base+S3C2410_RTCCON)&

S3C2410_RTCCON_RTCEN)==0)

dev_info(&

rtcdisabled,re-enabling\n"

writeb(tmp|S3C2410_RTCCON_RTCEN,rtc_base+S3C2410_RTCCON);

S3C2410_RTCCON_CNTSEL))

removingRTCCON_CNTSEL\n"

~S3C2410_RTCCON_CNTSEL,rtc_base+S3C2410_RTCCON);

S3C2410_RTCCON_CLKRST))

removingRTCCON_CLKRST\n"

~S3C2410_RTCCON_CLKRST,rtc_base+S3C2410_RTCCON);

/*该函数主要是对RTC的节拍时间计数寄存器TICNT的0-6位进行操作,即:

节拍时间计数值的设定*/

staticintrtc_setfreq(structdevice*dev,intfreq)

is_power_of_2(freq))/*对freq的值进行检查*/

return-EINVAL;

spin_lock_irq(&

rtc_pie_lock);

/*获取自旋锁保护临界区资源*/

/*读取节拍时间计数寄存器TICNT的值*/

tmp=readb(rtc_base+S3C2410_TICNT)&

S3C2410_TICNT_ENABLE;

/*看数据手册得知,节拍时间计数值的范围是1-127,

还记得在rtc_enable函数中设置的rtc->

max_user_freq=128吗?

所以这里要减1*/

tmp|=(128/freq)-1;

*将经运算后值写入节拍时间计数寄存器TICNT中,这里主要是改变TICNT的第0-6位的值*/

writeb(tmp,rtc_base+S3C2410_TICNT);

spin_unlock_irq(&

/*释放自旋锁,即解锁*/

3、RTC设备类的操作。

在这一步中,才是对RTC硬件的各种寄存器进行操作,代码如下:

linux/interrupt.h>

linux/bcd.h>

/*rtc_class_ops是RTC设备类在RTC驱动核心部分中定义的对RTC设备类进行操作的结构体,

类似字符设备在驱动中的file_operations对字符设备进行操作的意思。

该结构体被定义

在rtc.h中,对RTC的操作主要有打开、关闭、设置或获取时间、设置或获取报警、设置节拍时间计数值等等,

该结构体内接口函数的实现都在下面*/

staticconststructrtc_class_opsrtcops={

.open 

=rtc_open,

.release 

=rtc_release,

.irq_set_freq 

=rtc_setfreq,/*在第②步中已实现*/

.irq_set_state 

=rtc_setpie,

.read_time 

=rtc_gettime,

.set_time 

=rtc_settime,

.read_alarm 

=rtc_getalarm,

.set_alarm 

=rtc_setalarm,

/*RTC设备类打开接口函数*/

staticintrtc_open(structdevice*dev)

/*这里主要的目的是从系统平台设备中获取RTC设备类的数据,和RTC探测函数rtc_probe中

的platform_set_drvdata(pdev,rtc)的操作刚好相反。

这些都定义在platform_device.h中*/

structplatform_device*pdev=to_platform_device(dev);

structrtc_device*rtc_dev=platform_get_drvdata(pdev);

/*申请RTC报警中断服务,中断号rtc_alarmno在RTC探测函数rtc_probe中已经获取得,

这里使用的是快速中断:

IRQF_DISABLED。

中断服务程序为:

rtc_alarmirq,将RTC设备类rtc_dev做参数传递过去了*/

ret=request_irq(rtc_alarmno,rtc_alarmirq,IRQF_DISABLED,"

my2440-rtcalarm"

rtc_dev);

if(ret)

dev_err(dev,"

IRQ%derror%d\n"

rtc_alarmno,ret);

/*同上面一样,这里申请的是RTC的TICK节拍时间中断服务,服务程序是:

rtc_tickirq*/

ret=request_irq(rtc_tickno,rtc_tickirq,IRQF_DISABLED,"

my2440-rtctick"

rtc_tickno,ret);

gototick_err;

tick_err:

/*错误处理,注意出现错误后也要释放掉已经申请成功的中断*/

free_irq(rtc_alarmno,rtc_dev);

/*RTC报警中断服务程序*/

staticirqreturn_trtc_alarmirq(intirq,void*argv)

structrtc_device*rdev=argv;

/*接收申请中断时传递过来的rtc_dev参数*/

/*当报警中断到来的时候,去设定RTC中报警的相关信息,具体设定的方法,RTC核心

部分已经在rtc_update_irq接口函数中实现,函数定义实现在interface.c中*/

rtc_update_irq(rdev,1,RTC_AF|RTC_IRQF);

returnIRQ_HANDLED;

/*RTC的TICK节拍时间中断服务*/

staticirqreturn_trtc_tickirq(intirq,void*argv)

/*节拍时间中断到来的时候,去设定RTC中节拍时间的相关信息,具体设定的方法,RTC核心

rtc_update_irq(rdev,1,RTC_PF|RTC_IRQF);

returnIRQ_HA

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 工学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1