当前位置:首页 > 单片机 > 单片机
[导读]/**********************************************************************************************************@Description:s3c2410的rtc驱动的实现,rtc(realtimeclock)实时时钟的驱动是个很好的*理解如果编写驱

/*********************************************************************************************************
*@Description:s3c2410的rtc驱动的实现,rtc(realtimeclock)实时时钟的驱动是个很好的
*理解如果编写驱动的硬件,它包括了最基本的硬中断,软中断的底层机制;
*s3c2410的RTC驱动的实现个人认为更是对linux设备驱动一个很好的例子,他是通过二层结构来
*实现的一个驱动,上层是一个armcommon的公共层,对上提供标准的通用的RTC操作接口,下层由
*我们来实现针对自己的chip和自己要提供的功能来实现的一层驱动;
*
*@FileTree:
**********************************************************************************************************
linux-2.6.14.6
|
|--arch
||
||--arm
|||--mach-s3c2410
||||-devs.c//包含了对各个部件的resource的分配和定义,在这看rtc的资源;
|||--common
||||-rtctime.c//一个arm平台的通用rtc函数层,它对上隐藏了各种soc的rtcdriver的区别;
|||--kernel
||||-time.c//内核的初始化例程time_init()会调用的xxx_cmos_xxx函数的实现;定义了全局自旋锁rtc_lock用来串行化所有CPU对RTC的操作
|
|--drivers
||--char
|||-s3c2410-rtc.c//具体的s3c2410上的rtcchip的驱动实现,如果需要在arm平台的
||板子上实现一个驱动,改写它就ok了。
|
|--include
||--asm-arm
|||--arch-s3c2410
||||-regs-rtc.h//S3C2410InternalRTCregisterdefinitionrefertodatasheet;
|||-rtc.h//arm平台rtc操作抽象层rtctime.c对应的.h
||--linux
|||-time.h//mktime的实现;
|||-rtc.h//公用RTC.h
*
*[小结]
*1) 提供给user的接口,在arch/arm/common/rtctime.c,include/asm-arm/rtc.h中实现,调用操作硬件驱动在 drivers/char/s3c2410-rtc.c,include/asm-arm/arch-s3c2410/regs-rtc.h实现;
*2) 提供给kernel的接口,在arch/arm/kernel/time.c,include/linux/time.h中实现,调用操作硬件驱动在 drivers/char/s3c2410-rtc.c,include/asm-arm/arch-s3c2410/regs-rtc.h实现;
**********************************************************************************************************
*
*@Author:liyangth@gmail.com
*
*@FunctionList:
*
*
*
*
*@Changelog:
*2007-06-24LiYangFirstversion
*
*@FQA:
*[50%]Q1.在驱动中要将设备注册到总线,必须将设备封装成structdevice_driver;调查这个结构体中的每个成员.
*[0%]Q2.在板子(什么类型)上什么样的设备要用总线(什么类型)注册?
*[90%]Q3.
*structdevice--总线设备
*structdevice_driver--总线设备驱动
*structplatform_device--平台设备
*structresource--平台资源
*
*[!0%]Q4.初始化rtcregister的函数的后面的flag具体控制什么?(在s2s65a里是否可以用它控制是softResetorhardwareReset)
*
*[0%]Q5.什么时候调用suspend,resume?
**********************************************************************************************************/

/*****************************************************************************
*Structures&Unions&Enums(#typedef)
*/
/*[include/linux/device.h]
*总线设备驱动结构体,将它注册到板子的总线上
*/
staticstructdevice_drivers3c2410_rtcdrv={
.name="s3c2410-rtc",
.owner=THIS_MODULE,
.bus=&platform_bus_type,//总线类型,貌似不用管
.probe=s3c2410_rtc_probe,//自检->初始化REG->注册到上一层
.remove=s3c2410_rtc_remove,//注销
.suspend=s3c2410_rtc_suspend,//[挂起???]
.resume=s3c2410_rtc_resume,//[重起???]
};

/*[/include/asm-arm/rtc.h]
*底层特别操作集,将他注册到上层的armcommon操作层
*/
staticstructrtc_opss3c2410_rtcops={
.owner=THIS_MODULE,
.open=s3c2410_rtc_open,
.release=s3c2410_rtc_release,
.ioctl=s3c2410_rtc_ioctl,
.read_time=s3c2410_rtc_gettime,
.set_time=s3c2410_rtc_settime,
.read_alarm=s3c2410_rtc_getalarm,
.set_alarm=s3c2410_rtc_setalarm,
.proc=s3c2410_rtc_proc,
};


/*****************************************************************************
*GlobalVariables
*/



s3c2410-rtc.c
|
|/*IRQHandlers*/
|-s3c2410_rtc_alarmirq(intirq,void*id,structpt_regs*r)
||
||-rtc_update(1,RTC_AF|RTC_IRQF);//获得中断标志,和唤醒read阻塞,异步通知;
|
|-s3c2410_rtc_tickirq(intirq,void*id,structpt_regs*r)
|
|/*Updatecontrolregisters,与硬件实现有关,refertodatasheet*/
|-s3c2410_rtc_setaie(intto)
|-s3c2410_rtc_setpie(intto)
|-s3c2410_rtc_setfreq(intfreq)
|
|/*实现了要插到上层armcommon层的具体的硬件操作,来填充structrtc_ops,这个具体与硬件相关的操作集会用
|register_rtc注册到上层的*/
|
|-s3c2410_rtc_gettime(structrtc_time*rtc_tm)
|
|-s3c2410_rtc_settime(structrtc_time*tm)
|
|-s3c2410_rtc_getalarm(structrtc_wkalrm*alrm)
|
|-s3c2410_rtc_setalarm(structrtc_wkalrm*alrm)
|
|/*
|*插入到上层ioctl中的ioctl,上层中已经通过这个driver中的gettime,settime在其ioctl中实现了取得和设置时间
|*,和一些共同的ioctl操作了
|*所以我们在这只要实现与硬件不同部分的ioctl操作*/
|-s3c2410_rtc_ioctl(unsignedintcmd,unsignedlongarg)
|
|-s3c2410_rtc_proc(char*buf)
|-s3c2410_rtc_open(void)
||
||1.注册申请闹钟中断ISQ--s3c2410_rtc_alarmirq
||2.周期中断ISQ--s3c2410_rtc_tickirq
|
|-s3c2410_rtc_release(void)
|
|/*InitializeRTCRegs*/
|-s3c2410_rtc_enable(structdevice*dev,inten)
||
||-if(!en)
||/*beforepoweroff,theRTCENbitshouldbeclearedto
||0topreventinadvertentwritingintoRTCregisters.*/
||1.将控制R的RTCEN位清0;
||
||2.disableinterrupt.
||
||-else/*re-enablethedevice,andcheckitisok*/
||
||1.将控制R的RTCEN位致1。
||
||2.BCDcountselect.--0=MergeBCDcounters
||
||3.RTCclockcountreset.--0=noreset
||
|
|
|
|-s3c2410_rtc_probe(structdevice*dev)
||[??]structplatform_device*pdev=to_platform_device(dev);//通过这个设备找到它宿主平台的大设备;
||structresource*res;
||
||/*findtheIRQs,RTC有2中中断,周期中断和闹钟中断*/
||-s3c2410_rtc_tickno=platform_get_irq(pdev,1);//从平台上取得一个IRQ号给这个设备;
||
||/*getthememoryregion*/
||-res=platform_get_resource(pdev,IORESOURCE_MEM,0);
||
||/*向内核申请资源空间*/
||-s3c2410_rtc_mem=request_mem_region(res->start,res->end-res->start+1,
pdev->name);//res->start这些资源的分配和在哪个段下,可以看../mach-s3c2410/devs.c
||
||/*然后将物理地址映射到虚拟地址,这样驱动和内核就可以看到设备的I/Oregs了*/
||-s3c2410_rtc_base=ioremap(res->start,res->end-res->start+1);
||
||/*初始化设备regs*/
||-s3c2410_rtc_enable(dev,1);//可以用后面这个1(这个flag在s2s65a中可以用ram0-7来保存,掉电不清的)来控制是softreset还是hardwarereset.
||
||-s3c2410_rtc_setfreq(s3c2410_rtc_freq);//设定RTC周期频率;
||
||/*最关键的一步,将与具体不同的底层硬件相关的设备驱动注册给arm通用操作层common/rtctime.c*/
||-register_rtc(&s3c2410_rtcops);
|
|-s3c2410_rtc_remove(structdevice*dev)
||-unregister_rtc(&s3c2410_rtcops);//从上一层将s3c2410的rtc的devicedirveroperationset拔下来。
||
||-s3c2410_rtc_setpie(0);//disable周期中断
||
||-s3c2410_rtc_setaie(0);//disablealarminterrupt
||
||-iounmap(s3c2410_rtc_base);
||
||-release_resource(s3c2410_rtc_mem);
||
||-kfree(s3c2410_rtc_mem);//[MQA]哪块kmalloc了呢,为什么这要free?
|
|
|#ifdefCONFIG_PM//如果电源控制开关打开
|
|-s3c2410_rtc_suspend(structdevice*dev,pm_message_tstate,u32level)
||
||if(level==SUSPEND_POWER_DOWN)//SUSPEND_POWER_DOWN在include/linux/device.h(generic,centralizeddrivermodel)中定义,这个里面是否是对设备的一些公用的行为的操作宏的定义呢?
|||1.保存周期中断寄存器的值;
|||
|||2.从RTC中读出时间
|||-s3c2410_rtc_gettime(&tm);//[localvariable]structrtc_timetm;
|||
|||3.将从RTC取出的时间ConvertGregoriandatetosecondssince01-01-197000:00:00.
|||-rtc_tm_to_time(&tm,&time.tv_sec);//[arch/arm/common/rtctime.c]
|||
|||4.将系统时间和RTC时间的差值保存到s3c2410_rtc_delta里;
|||-save_time_delta(&s3c2410_rtc_delta,&time);
|||
|||5.启动RTC,注意这次启动后面的falg为0了;
|||-s3c2410_rtc_enable(dev,0);
|
|
|-s3c2410_rtc_resume(structdevice*dev,u32level)
||
||1.启动RTC,注意这次启动后面的falg为1了;
||-s3c2410_rtc_enable(dev,1);
||
||2.从RTC中读出时间
||-s3c2410_rtc_gettime(&tm);
||
||3.转换
||-rtc_tm_to_time(&tm,&time.tv_sec);
||
||4.利用在suspend中保存的delta来恢复系统时间
||-restore_time_delta(&s3c2410_rtc_delta,&time);
||
||5.恢复周期中断寄存器的值;
|
|[LiY]
|suspend(暂停,挂起)和resume(恢复,再开始)有点象关机前保存现场和开机后再恢复现场一样;
|
|#else
|#defines3c2410_rtc_suspendNULL
|#defines3c2410_rtc_resumeNULL
|#endif
|
|
|module_init(s3c2410_rtc_init)
|-s3c2410_rtc_init
||-driver_register(&s3c2410_rtcdrv);
|||[purpose]registerdriverwithbus;
|
|module_exit(s3c2410_rtc_exit)
|-s3c2410_rtc_exit(void)
||-driver_unregister(&s3c2410_rtcdrv)

/*****************************************************************************
*ExternFunctionDetails
*/
/**[drivers/base/driver.c]
*driver_register-registerdriverwithbus
*@drv:drivertoregister
*
*Wepassoffmostoftheworktothebus_add_driver()call,
*sincemostofthethingswehavetododealwiththebus
*structures.
*
*Theoneinterestingaspectisthatwesetup@drv->unloaded
*asacompletionthatgetscompletewhenthedriverreference
*countreaches0.
*/
intdriver_register(structdevice_driver*drv)
{
klist_init(&drv->klist_devices,klist_devices_get,klist_devices_put);
init_completion(&drv->unloaded);
returnbus_add_driver(drv);
}


/**[drivers/base/platform.c]
*platform_get_irq-getanIRQforadevice
*@dev:platformdevice
*@num:IRQnumberindex
*/
intplatform_get_irq(structplatform_device*dev,unsignedintnum)
{
structresource*r=platform_get_resource(dev,IORESOURCE_IRQ,num);

returnr?r->start:0;
}

/**[drivers/base/platform.c]
*platform_get_resource-getaresourceforadevice
*@dev:platformdevice
*@type:resourcetype
*@num:resourceindex
*/
structresource*
platform_get_resource(structplatform_device*dev,unsignedinttype,
unsignedintnum)
{
inti;

for(i=0;inum_resources;i++){
structresource*r=&dev->resource[i];

if((r->flags&(IORESOURCE_IO|IORESOURCE_MEM|
IORESOURCE_IRQ|IORESOURCE_DMA))
==type)
if(num--==0)
returnr;
}
returnNULL;
}

/*[../include/linux/ioport.h]
*Resourcesaretree-like,allowing
*nestingetc..
*/
structresource{
constchar*name;
unsignedlongstart,end;
unsignedlongflags;
structresource*parent,*sibling,*child;
};

/**[arch/arm/kernel/time.c]
*save_time_delta-SavetheoffsetbetweensystemtimeandRTCtime
*@delta:pointertotimespectostoredelta
*@rtc:pointertotimespecforcurrentRTCtime
*
*ReturnadeltabetweenthesystemtimeandtheRTCtime,such
*thatsystemtimecanberestoredlaterwithrestore_time_delta()
*
*[LiY]返回一个系统时间和RTC时间的差值,在重起或系统去读RTC后,可以再用这个差值(delta)来恢复系统时间(系统时间不一定非要和RTC时间相同的);
*/
voidsave_time_delta(structtimespec*delta,structtimespec*rtc)
{
set_normalized_timespec(delta,
xtime.tv_sec-rtc->tv_sec,
xtime.tv_nsec-rtc->tv_nsec);
}

/***[arch/arm/kernel/time.c]
*restore_time_delta-Restorethecurrentsystemtime
*@delta:deltareturnedbysave_time_delta()
*@rtc:pointertotimespecforcurrentRTCtime
*/
voidrestore_time_delta(structtimespec*delta,structtimespec*rtc)
{
structtimespects;

set_normalized_timespec(&ts,
delta->tv_sec+rtc->tv_sec,
delta->tv_nsec+rtc->tv_nsec);

do_settimeofday(&ts);
}

/*
*[arch/arm/common/rtctime.c]
*/
voidrtc_update(unsignedlongnum,unsignedlongevents)
{
spin_lock(&rtc_lock);
rtc_irq_data=(rtc_irq_data+(num<<8))|events;
spin_unlock(&rtc_lock);

wake_up_interruptible(&rtc_wait);
kill_fasync(&rtc_async_queue,SIGIO,POLL_IN);
}

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭