转自:http://blog.csdn.net/weiqing1981127/article/details/8484268

实时时钟的作用主要是为操作系统提供一个可靠的时间,并在断电下,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子系统的更多相关文章

  1. Linux下的Backlight子系统(一)【转】

    转自:http://blog.csdn.net/weiqing1981127/article/details/8511676 版权所有,转载必须说明转自 http://my.csdn.net/weiq ...

  2. Linux下的Backlight子系统(二)【转】

    转自:http://blog.csdn.net/weiqing1981127/article/details/8515847 版权所有,转载必须说明转自 http://my.csdn.net/weiq ...

  3. Linux下触摸屏驱动程序分析

    [摘要: 本文以linux3.5--Exynos4412仄台,剖析触摸屏驱动焦点内容.Linux下触摸屏驱动(以ft5x06_ts为例)须要懂得以下学问: 1. I2C协定 2. Exynos4412 ...

  4. ARM Linux内核Input输入子系统浅解

    --以触摸屏驱动为例 第一章.了解linux input子系统         Linux输入设备总类繁杂,常见的包括有按键.键盘.触摸屏.鼠标.摇杆等等,他们本身就是字符设备,而linux内核将这些 ...

  5. Linux下的定时器类实现(select定时+线程)

    更好的计时器类实现:LINUX RTC机制实现计时器类(原创) 很多时候需要在LINUX下用到定时器,但像setitimer()和alarm()这样的定时器有时会和sleep()函数发生冲突,这样就给 ...

  6. Linux驱动修炼之道-RTC子系统框架与源码分析【转】

    转自:http://helloyesyes.iteye.com/blog/1072433 努力成为linux kernel hacker的人李万鹏原创作品,为梦而战.转载请标明出处 http://bl ...

  7. linux驱动基础系列--linux rtc子系统

    前言 linux驱动子系统太多了,连时钟也搞了个子系统,这导致一般的时钟芯片的驱动也会涉及到至少2个子系统,一个是时钟芯片接口子系统(比如I2c接口的时钟芯片),一个是内核给所有时钟芯片提供的rtc子 ...

  8. RTC子系统

    目录 RTC子系统 引入 hctosys.c interface.c class.c 小结 流程一览 框架分析 rtc_init rtc_device_register s3c_rtc_probe o ...

  9. linux下目录简介——/sys

    Linux下/sys目录介绍    1. 概述 ramdisk 文件系统基于磁盘模拟技术,实际文件系统是ex2 ex3等.sysfs是一种基于ram文件系统和proc一样.Sysfs文件系统是一个类似 ...

随机推荐

  1. openssl之BIO系列之12---文件描写叙述符(fd)类型BIO

    文件描写叙述符(fd)类型BIO ---依据openssl doc\crypto\bio_s_fd.pod翻译和自己的理解写成 (作者:DragonKing Mailwzhah@263.net 公布于 ...

  2. mysql复制表命令

    http://hi.baidu.com/dwspider/item/908bf5e1746275bd2e140b03     上面命令是实现复制表的一种方法,缺陷就是索引等表信息不会复制过去,只是复制 ...

  3. Objective-C中单例

    单例模式,由于其简单好用容易理解.同时在出问题时也容易定位的特点,在开发中经常用到的一个设计模式. 一般在程序中,经常调用的类,如工具类.公共跳转类等,我都会采用单例模式 这个写法是苹果推荐的写法   ...

  4. An unexpected error occured when contacting the server .

    I logged into to the arcsight command center ,however I found an unexpected error occurred when cont ...

  5. Django1.11.4中文文档

    Django管理站点¶ 自动管理界面是Django最强大的部分之一.它从您的模型中读取元数据,以提供一个快速,以模型为中心的界面,让受信任的用户可以管理您网站上的内容.管理员建议的使用仅限于组织的内部 ...

  6. how to run a continuous background task on OpenShift

    https://stackoverflow.com/questions/27152438/best-way-to-run-rails-background-jobs-with-openshift ht ...

  7. 宜信开源|分布式任务调度平台SIA-TASK的架构设计与运行流程

    一.分布式任务调度的背景 无论是互联网应用或者企业级应用,都充斥着大量的批处理任务.我们常常需要一些任务调度系统来帮助解决问题.随着微服务化架构的逐步演进,单体架构逐渐演变为分布式.微服务架构.在此背 ...

  8. PS 魔法棒

    魔术棒工具是通过选取图像中颜色相近或大面积单色区域的像素来制作选区,魔术棒用于纯色背景中较多. 容差数值越大,选择出的选区就越大,容差越小,对颜色差别的要求也就越严格,选择出的选区也就越小 按住shi ...

  9. java操作redis学习(一):安装及连接

    文章参考自:http://www.cnblogs.com/edisonfeng/p/3571870.html,在此基础上进行了修改. 一.下载安装Redis redis官网显示暂时不支持Windows ...

  10. Android组件系列----ContentProvider内容提供者【4】

    (4)单元測试类: 这里须要涉及到另外一个知识:ContentResolver内容訪问者. 要想訪问ContentProvider.则必须使用ContentResolver. 能够通过ContentR ...