0%

Linux驱动之RTC

概述

RTC和系统时钟有不同的用途。前者是硬件时钟,以非易失方式维护绝对时间和日期,而后者是内核维护的软件时钟,用于实现gettimeofday(2)和time(2)系统调用,以及在文件上设置时间戳等。系统时钟报告从起点开始的秒和微秒,起点定义为 POSIX 纪元:1970-01-0100:00:00 +0000(UTC)。

数据结构

rtc数据结构如下:原图

  • rtc_device
    内核中使用rtc_device结构体来抽象一个rtc设备,rtc_device结构体屏蔽了不同RTC硬件之间的差异,通过rtc_class_ops结构体为上层提供了访问硬件设备的统一接口

  • rtc_class_ops
    该结构体提供了对底层差异的抽象,rtc_device用于描述一个rtc设备,而访问该设备的方法对于不同的设备是不同的,rtc_class_ops用于抽象对rtc设备的访问,对上屏蔽了底层操作的差异。编写一个rtc设备驱动就是构造一个rtc_device结构体并注册进系统,rtc的访问方法就是rtc_class_ops结构体

  • rtc_time
    这是一个描述时间的结构体

  • rtc_timer
    用于对rtc设备的管理

实现

rtc实现的整体框架如下:原图

  • 在rtc设备驱动模型的最上层,针对procfs 文件、sysfs 属性文件、字符设备文件相关的处理接口,分别抽象出rtc-dev相关接口、rtc-sysfs相关接口、rtc-procfs相关接口,分别存储在rtc-dev.c、rtc-sysfs.c、rtc-proc.c这三个文件中
  • 在rtc-dev.c、rtc-sysfs.c、rtc-proc.c中定义了这三类文件的操作接口(open、read、write、close…)
  • 上述三类文件的操作接口(open、read、write、close…),会借助rtc interface接口,调用各设备的操作接口,rtc interface接口可以理解为调用设备驱动的桥梁; 针对rtc设备驱动,均需要实现rtc class ops中的方法,以便被rtc上层接口调用,从而完成与rtc设备的通信操作
  • 应用程序通过系统调用接口、vfs相关接口、设备文件系统的inode的操作接口、sysfs文件系统的inode的操作接口、procfs文件系统的inode的操作接口,方才进入rtc设备驱动模型的处理接口中

实现流程如下:原图

devm_rtc_device_register函数就是注册一个rtc设备的api。注册流程如下:

  • devm_rtc_allocate_device分配并设置rtc_device结构体
  • devm_rtc_register_device注册rtc_device结构体。这里是/linux/drivers/rtc/dev.c文件里提供的cdev的file_operations结构体,该结构体函数指针提供了对interface的访问
  • 在/linux/drivers/rtc/interface.c文件里向上为/linux/drivers/rtc/dev.c提供接口,向下提供访问rtc_class_ops的接口
  • rtc_class_ops由具体的rtc设备在注册的时候提供

sysfs接口

在Linux系统上,从用户空间正确管理RTC需要关注两个内核选项。这两个选项是CONFIG_RTC_HCTOSYS 和CONFIG_RTC_HCTOSYS_DEVICE。 要使用CONFIG_RTC_HCTOSYS应在内核构建过程中包含代码文件driversrtc/hctosys.c,它在启动和恢复时从RTC设置系统时间。一旦启用此选项,就将使用从指定RTC设备读取的值设置系统时间。RTC设备应该在CONFIG_RTC_HCTOSYSDEVICE 中指定:

1
2
CONFIG_RTC_HCTOSYS=y
CONFIG_RTC_HCTOSYS_DEVICE="rtcO"

负责在sysfs 中实例化RTC属性的内核代码在内核源码树的drivers/rtc/rtc_sysfs.c中定义。一旦注册,RTC设备就将在/sys/class/rtc下创建rtc 目录,该目录包含一组只读属性,其中重要的属性如下。

  • date: 该文件打印RTC接口的当前日期:

    1
    2
    $ cat /sys/class/rtc/rtc0/date
    2017-8-28

  • time:打印此RTC的当前时间:

    1
    2
    $ cat /sys/class/rtc/rtc0/time
    14:54:20

  • hctosys: 该属性指出RTC设备是否是CONFIG_RTC_HCTOSYS_DEVICE 中指定的设备,也就是在启动和恢复时是否使用该RTC设置系统时间。其值为1表示真,0表示假:

    1
    2
    $ cat /sys/class/rtc/rtc0/hctosys
    1

  • dev: 此属性显示设备的主设备号和次设备号。数据格式为主设备号:次设备号:

    1
    2
    $ cat /sys/class/rtc/rtc0/dev
    251:0

  • since_epoch: 该属性将显示从UNIX纪元(自1970年1月1日起)以来的秒数:

    1
    2
    $ cat /sys/class/rtc/rtc0/since epoch
    1503931738

hwclock工具

硬件时钟(hwclock)工具用于访问RTC设备。man hwclock命令可能比本节讨论的所有内容都更有意义。尽管如此,下面还是编写一些命令,以从系统时钟设置hwclockRTC:

1
2
3
4
$ sudo ntpd -q              #确保系统时钟是从网络时间设置的
$ sudo hwclock --systohc #从系统时钟设置RTC
$ sudo hwclock --show #设置RTC
Sat May 17 17:36:50 2017 -0.671045 seconds

上面的例子假定主机具有网络连接,可以访问NTP服务器。也可以手动设置系统时间:

1
2
$ sudo date -s '2017-08-28 17:14:00'+s' #手动设置系统时钟
$ sudo hwclock 一systohc #在系统时间上同步RTC芯片

如果没有给出参数,hwclock假定RTC设备文件是/dev/rtc,它实际上是真正RTC设备的符号链接:

1
2
ls -l /dev/rtc
lrwxrwxrwx 1 root root 4 aout 27 17:50 /dev/rtc -> rtc0

参考文献

https://www.cnblogs.com/053179hu/p/14130300.html
https://blog.csdn.net/lickylin/article/details/103841941?spm=1001.2014.3001.5501