Linux下的RTC子系统
版权所有,转载必须说明转自 http://my.csdn.net/weiqing1981127
实时时钟的作用主要是为操作系统提供一个可靠的时间,并在断电下,RTC时钟也可以通过电池供电一直运行下去。实时时钟驱动也有一个子系统,叫做RTC子系统,其源代码目录是/driver/rtc/,在这个目录下有一个rtc核心代码区,主要是Rtc-dev.c、Rtc-sysfs.c和Rtc-proc.c三个文件,其中Rtc-dev.c主要是增加一个字符设备的作用,例如用户层的ioctl命令就是通过访问该文件;Rtc-sysfs.c主要是创建device_attribute机制;Rtc-proc.c文件主要创建/proc属性文件。另外对于RTC设备。内核中的说明文档在/Document/Rtc.txt中
我们这里讲的是基于mini2440的RTC驱动,其对应驱动是/driver/rtc/Rtc-s3c.c
RTC驱动源码路径在/driver/rtc/Rtc-s3c.c
查看/driver/rtc/Makefile
rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
查看/driver/rtc//Konfig
config RTC_INTF_DEV
boolean "/dev/rtcN (character devices)"
default RTC_CLASS
config RTC_INTF_PROC
boolean "/proc/driver/rtc (procfs for rtc0)"
depends on PROC_FS
config RTC_INTF_SYSFS
boolean "/sys/class/rtc/rtcN (sysfs)"
depends on SYSFS
default RTC_CLASS
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
depends on ARCH_S3C2410
所以配置内核make menuconfig 时,需要选中这几项。
现在先来看如何移植,下面就看移植代码了,因为通过查看"s3c2410-rtc"名知道,在内核Devs.c文件中已经定义如下代码
struct platform_device s3c_device_rtc = {
.name = "s3c2410-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_rtc_resource),
.resource = s3c_rtc_resource,
};
所以只要在mach-mini2440.c这个mini2440开发板的BSP中把这个s3c_device_rtc加入到mini2440_devices数组
static struct platform_device *mini2440_devices[] __initdata = {
……
& s3c_device_rtc, //添加
};
这样配置完后,进行make zImage生成zImage内核镜像。
下面大致说说/driver/rtc/Rtc-s3c.c
static struct platform_driver s3c2410_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = __devexit_p(s3c_rtc_remove),
.suspend = s3c_rtc_suspend,
.resume = s3c_rtc_resume,
.driver = {
.name = "s3c2410-rtc", //驱动名
.owner = THIS_MODULE,
},
};
跟踪下探测函数probe
static int __devinit s3c_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
int ret;
pr_debug("%s: probe=%p\n", __func__, pdev);
s3c_rtc_tickno = platform_get_irq(pdev, 1); //获取滴答中断号
if (s3c_rtc_tickno < 0) {
dev_err(&pdev->dev, "no irq for rtc tick\n");
return -ENOENT;
}
s3c_rtc_alarmno = platform_get_irq(pdev, 0); //获取闹钟中断号
if (s3c_rtc_alarmno < 0) {
dev_err(&pdev->dev, "no irq for alarm\n");
return -ENOENT;
}
pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
s3c_rtc_tickno, s3c_rtc_alarmno);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取资源
if (res == NULL) {
dev_err(&pdev->dev, "failed to get memory region resource\n");
return -ENOENT;
}
s3c_rtc_mem = request_mem_region(res->start,
res->end-res->start+1,
pdev->name); //申请资源
if (s3c_rtc_mem == NULL) {
dev_err(&pdev->dev, "failed to reserve memory region\n");
ret = -ENOENT;
goto err_nores;
}
s3c_rtc_base = ioremap(res->start, res->end - res->start + 1); //物理地址到虚拟地址的映射
if (s3c_rtc_base == NULL) {
dev_err(&pdev->dev, "failed ioremap()\n");
ret = -EINVAL;
goto err_nomap;
}
s3c_rtc_enable(pdev, 1);
pr_debug("s3c2410_rtc: RTCCON=%02x\n",
readb(s3c_rtc_base + S3C2410_RTCCON));
s3c_rtc_setfreq(&pdev->dev, 1); //设置频率
device_init_wakeup(&pdev->dev, 1);
rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
THIS_MODULE); //注册rtc设备
if (IS_ERR(rtc)) {
dev_err(&pdev->dev, "cannot attach rtc\n");
ret = PTR_ERR(rtc);
goto err_nortc;
}
rtc->max_user_freq = 128;
platform_set_drvdata(pdev, rtc);
return 0;
err_nortc:
s3c_rtc_enable(pdev, 0);
iounmap(s3c_rtc_base);
err_nomap:
release_resource(s3c_rtc_mem);
err_nores:
return ret;
}
我们主要关注注册rtc设备的时传入参数s3c_rtcops
static const struct rtc_class_ops s3c_rtcops = {
.open = s3c_rtc_open, //打开
.release = s3c_rtc_release, //关闭
.read_time = s3c_rtc_gettime, //获取当前时间
.set_time = s3c_rtc_settime, //设置当前时间
.read_alarm = s3c_rtc_getalarm, //获取闹钟时间
.set_alarm = s3c_rtc_setalarm, //设置闹钟时间
.irq_set_freq = s3c_rtc_setfreq, //设置频率
.irq_set_state = s3c_rtc_setpie,
.proc = s3c_rtc_proc,
};
对于struct rtc_class_ops结构体中的成员,其每个函数的具体实现,都是跟自己使用的设备相关的,比如我们这样使用的是S3C2410,那么在struct rtc_class_ops里定义的函数使用的就是三星平台下的资源。如果要在其他平台下使用,那么就是修改这里的struct rtc_class_ops操作函数。
在rtc_device_register中,会调用rtc_dev_prepare函数,而rtc_dev_prepare函数会把rtc_dev_fops注册进内核,而rtc_dev_fops就是我们在增加字符设备的文件Rtc-dev.c中定义的file_operations操作函数,这样注册rtc设备其实就表示用户可以访问通过访问file_operations函数来达到访问rtc设备的目的。
在我们的/driver/rtc/Class.c中的模块加载函数中调用rtc_sysfs_init来完成注册sys文件系统,而rtc_sysfs_init就是我们在Rtc-sysyfs.c中定义的,跟踪下rtc_sysfs_ini
void __init rtc_sysfs_init(struct class *rtc_class)
{
rtc_class->dev_attrs = rtc_attrs;
}
然后看看rtc_attrs属性
static struct device_attribute rtc_attrs[] = {
__ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
__ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
__ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
__ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
__ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
rtc_sysfs_set_max_user_freq),
__ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
{ },
};
好了,这就是给用户的第二个操作接口,我们来看看这些属性的show和store属性是不是真的能调用在Rtc-s3c.c中的RTC操作函数s3c_rtcops。我们把注意力放在time的show属性函数rtc_sysfs_show_time上
static ssize_t rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
char *buf)
{
ssize_t retval;
struct rtc_time tm;
retval = rtc_read_time(to_rtc_device(dev), &tm); //调用封装的读时间函数
if (retval == 0) {
retval = sprintf(buf, "%02d:%02d:%02d\n",
tm.tm_hour, tm.tm_min, tm.tm_sec);
}
return retval;
}
跟踪rtc_read_time函数
int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err;
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err;
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->read_time)
err = -EINVAL;
else {
memset(tm, 0, sizeof(struct rtc_time));
err = rtc->ops->read_time(rtc->dev.parent, tm); //调用s3c_rtcops操作中读时间函数
}
mutex_unlock(&rtc->ops_lock);
return err;
}
好了,我已经跟踪到我们需要找的信息了,这样我们就能证实在Rtc-sysyfs.c中定义的设备的show和store属性是真的能调用在Rtc-s3c.c中的RTC操作函数s3c_rtcops的。
RTC驱动测试
Linux 中更改时间的方法一般使用date 命令,为了把S3C2440 内部带的时钟与linux 系统时钟同步,
一般使用hwclock 命令,下面是它们的使用方法:
(1) date -s 042916352007 #设置时间为 2007-04-29 16:34
(2) hwclock -w #把刚刚设置的时间存入S3C2440 内部的RTC
(3).开机时使用hwclock -s 命令可以恢复 linux 系统时钟为RTC, 一般把该语句放入
/etc/init.d/rcS 文件自动执行。
另外需要注意的是:有时候你会发现自己的实时时钟会在走时一段时间后不准,这注意是设计时钟电路时匹配电容的取值不对,电容公式是C1*C2/(C1+C2)+C3,其中C1和C2是两个并联电容,C3是寄生电容,C3一般取3-5PF。
Linux下的RTC子系统相关推荐
- linux i2c子系统看不懂啊,Linux 下的I2C子系统
Linux 下的I2C子系统 2013.7.16 本文分为两部分,一.设备模型 二.平台相关 . ================================================ 第一 ...
- linux下测试RTC驱动相关的命令date和hwclock常见用法简介
之前对Linux下面时间相关的内容,一无所知,第一次见到hwclock,不知为何物,也没找到解释清楚的帖子.故此整理一下,简单介绍Linux下验证rtc驱动是否工作正常,相关的的命令:date和hwc ...
- linux input子系统 pdf,Linux下的Input子系统.pdf
计 算 机 系 统 应 用 ||ww.c·S-a.org.cn 2013年 第 22卷 第 l2期 Linux下的Input子系统① 朱银瑞,吴庆洪,吴华玲 (辽宁科技大学 电子与信息工程学院,鞍山) ...
- linux input子系统 pdf,Linux下的Input子系统①.PDF
Linux下的Input子系统①.PDF 计 算 机 系 统 应 用 2013 年 第 22 卷 第 12 期 Linux 下的Input 子系统① 朱银瑞, 吴庆洪, 吴华玲 (辽宁科技大学 电子与 ...
- linux下的rtc设备驱动,linux下测试RTC驱动相关的命令date和hwclock常见用法讲解
之前对Linux下面时间相关的内容,一无所知,第一次见到hwclock,不知为何物,也没找到解释清楚的帖子.故此整理一下,简单介绍Linux下验证rtc驱动是否工作正常,相关的的命令:date和hwc ...
- Linux下的Keyboard子系统
版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127 最简单的按键驱动就是一个中断处理函数,当用户有按键,通过read函数向应用层上报按键信息.而我们这里讲的k ...
- Linux下的Backlight子系统
版权所有,转载必须说明转自 http://my.csdn.net/weiqing1981127 原创作者:南京邮电大学 通信与信息系统专业 研二 魏清 一.Backlight背光子系统概述 我们的L ...
- Linux下的LED子系统
最简单的led驱动就是从端口输出0或1来关闭或点亮灯.而我们这里讲的led子系统,主要是对led事件进行了分装和优化,这里我们主要讲的是可以实现跨平台的led驱动.不管你是使用三星的平台,还是Atme ...
- linux下的rtc机制
Linux的RTC驱动相对还是比较简单的,可以将它作为一个普通的字符型设备,或者一个misc设备,也可以是一个平台设备,这都没有关系,主要还是对rtc_ops这个文件操作结构体中的成员填充,这里主要涉 ...
最新文章
- Lecture 2: Preliminary Review--Mind Map
- 做创业公司长期价值的共建者,高榕资本完成5亿美元新基金募资
- axure元件库 文件上传_一库:便捷的前后台元件库
- 计算机设计大赛校赛攻略(郑州轻工业大学)
- storm32云台说明书_STorM32 BGC三轴云台控制板电机驱动电路设计(驱动芯片DRV8313)
- python 抓取微博评论破亿_利用python实现爬取微博评论的方法
- Linux复制文件到当前目录
- 高频交易巨头GETCO的发达史
- 抖音高贵气质的签名_抖音签名大全2020最新版-抖音个性签名男生女生-抖音个性签名霸气-腾牛个性网...
- 复杂网络盘传播搜索关键字
- 解决phpstudy的Apache启动失败
- FindMeChat(盲盒社交)-匿名聊天-好玩有趣的社交平台
- 回调函数,监听函数 关系 个人学习理解
- ssh免密码登录3种解决方法
- 【react】This synthetic event is reused for performance reasons.
- stack unwinding
- ubuntu20.04下载安装有道词典
- RaspBerry Pi 系统安装——Raspbian(精简版)
- 准大三学生暑期社会实践真实感悟
- 一年前, 打了一份关于谷歌英雄迟暮的草稿, 终究和它一起迟暮了
热门文章
- Boost.Math 和 Boost.Multiprecision 以提供 许多十进制数字精度的测试程序
- boost::make_maximal_planar用法的测试程序
- boost::dijkstra_shortest_paths_no_color_map用法的测试程序
- boost::fusion::move用法的测试程序
- VTK:相互作用之SelectAnActor
- QtObject QML类型
- QDoc包括外部代码includingexternalcode
- Qt Creator在外部应用程序上运行Valgrind工具
- C语言Huffman Encode霍夫曼编码的算法(附完整源码)
- C语言实现Trie字典树 (附完整源码)