rtc为操作系统提供时钟、日历、闹钟、周期性中断等功能,并且在断电的情况下,可以由电池供电,以很小的耗电继续运行下去,Linux内核已经支持s3c2416的rtc驱动。
1. rtc设备
rtc设备包含了名字、独有的资源等等一些驱动程序的硬件或自定义信息。通过platform_add_devices(platform_device_register)函数将定义的平台设备注册到内核中,用于匹配设备驱动。
内核在drivers\rtc\rtc-s3c.c中实现了s3c2416 rtc驱动, rtc设备平台代码如下。
static struct resources3c_rtc_resource[] = {
[0]= DEFINE_RES_MEM(S3C24XX_PA_RTC, SZ_256),
[1]= DEFINE_RES_IRQ(IRQ_RTC),
[2]= DEFINE_RES_IRQ(IRQ_TICK),
};
struct platform_device s3c_device_rtc ={
.name = "s3c2410-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_rtc_resource),
.resource = s3c_rtc_resource,
};
在static struct platform_device *home2416_devices[]板级平台设备列表中加入&3c_device_rtc,使rtc设备能够注册到内核中。
rtc-s3c.c默认只支持devices tree匹配驱动的方式,修改rtc-s3c.c使之支持平台匹配的驱动方式。
s3c_rtc_driver结构体中加入s3c_rtc_driver_id。
// add
static const struct platform_device_ids3c_rtc_driver_ids[] = {
{
.name = "s3c2410-rtc",
.driver_data = (unsigned long)&s3c2410_rtc_data,
},{
.name = "s3c2416-rtc",
.driver_data = (unsigned long)&s3c2416_rtc_data,
},{
.name = "s3c2443-rtc",
.driver_data = (unsigned long)&s3c2443_rtc_data,
},{
.name = "e3c6410-rtc",
.driver_data = (unsigned long)&s3c6410_rtc_data,
},{
.name = "exynos3250-rtc",
.driver_data = (unsigned long)&s3c6410_rtc_data,
},
{},
};
MODULE_DEVICE_TABLE(platform,s3c_rtc_driver_ids);
static struct platform_drivers3c_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = s3c_rtc_remove,
.id_table = s3c_rtc_driver_ids, // add
.driver = {
.name = "s3c-rtc",
.pm = &s3c_rtc_pm_ops,
.of_match_table = of_match_ptr(s3c_rtc_dt_match),
},
};
s3c_rtc_probe函数中更改从platform_device_id表中获取rtc的driver data。
conststruct platform_device_id *platid; // add
// info->data= s3c_rtc_get_data(pdev); // delete
platid= platform_get_device_id(pdev); // add
info->data= (struct s3c_rtc_data *)platid->driver_data; // add
2. 内核配置
Linux配置支持rtc设备驱动,选中Device Drivers-> Real Time Clock ->Samsung S3C series SoC RTC。
3. rtc测试
编译内核并启动。用date命令设置、显示时间。
4. 应用编程
cat/proc/devices可以知道rtc的主设备号为253,次设备号为0,在/dev目录中创建rtc设备文件。
mknod /dev/rtc0 c 253 0
应用程序可以通过设备文件访问rtc,rtc应用测试代码rtc_test.c如下。
#include "fcntl.h"
#include <stdio.h>
#include <stdlib.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
int main(void)
{
intfd;
intret;
structrtc_time rtc_tm;
fd= open("/dev/rtc0", O_RDONLY);
if(fd == -1) {
printf("Openrtc failed\n");
exit(1);
}
ret= ioctl(fd, RTC_RD_TIME, &rtc_tm);
if(ret == -1) {
printf("Readrtc failed\n");
close(fd);
exit(1);
}
printf("Oldtime: %d-%d-%d, %02d:%02d:%02d\n",
rtc_tm.tm_year + 1900,rtc_tm.tm_mon + 1,rtc_tm.tm_mday,
rtc_tm.tm_hour, rtc_tm.tm_min,rtc_tm.tm_sec);
rtc_tm.tm_year= 2017 - 1900;
rtc_tm.tm_mon= 2 - 1;
rtc_tm.tm_mday= 20;
rtc_tm.tm_hour= 21;
rtc_tm.tm_min= 0;
rtc_tm.tm_sec= 0;
ret= ioctl(fd, RTC_SET_TIME, &rtc_tm);
if(ret == -1) {
printf("Writertc failed\n");
close(fd);
exit(1);
}
printf("Settime: %d-%d-%d, %02d:%02d:%02d\n",
rtc_tm.tm_year + 1900,rtc_tm.tm_mon + 1,rtc_tm.tm_mday,
rtc_tm.tm_hour, rtc_tm.tm_min,rtc_tm.tm_sec);
ret= ioctl(fd, RTC_RD_TIME, &rtc_tm);
if(ret == -1) {
printf("Readrtc failed\n");
close(fd);
exit(1);
}
printf("Newtime: %d-%d-%d, %02d:%02d:%02d\n",
rtc_tm.tm_year + 1900,rtc_tm.tm_mon + 1,rtc_tm.tm_mday,
rtc_tm.tm_hour, rtc_tm.tm_min,rtc_tm.tm_sec);
close(fd);
return0;
}
用arm-linux-gcc静态编译,使之生成arm cpu可执行的指令,并且可脱离任何库独立运行,arm-linux-gcc -static -o rtc_test rtc_test.c,生成rtc_test可执行文件。复制可执行文件到根文件系统,目标板启动后在目录输入./rtc_test即可执行。
5、附录
文件 | 下载地址 |
---|---|
bootloader源码以及使用说明 | https://pan.baidu.com/s/1slczwhJ |
Qt5.8官网源码 | https://pan.baidu.com/s/1eRDJtNs |
本系列例程的根文件系统 | https://pan.baidu.com/s/1nuGmSqt |
opev3.2.0官网源码 | https://pan.baidu.com/s/1i5btLGT |
yaffs官网源码 | https://pan.baidu.com/s/1pLpuHw3 |
busybox-1.26.2官网源码 | https://pan.baidu.com/s/1bpkZynt |
tslib官网源码 | https://pan.baidu.com/s/1i4EtjfR |
mplayer-1.3.0官网源码 | https://pan.baidu.com/s/1i5MGRhb |
基于S3C2416修改的linux-4.10.10源码 | https://pan.baidu.com/s/1sl0fXlr |