供应商无法提供相应的驱动程序,不过在 linux 最新的内核倒是有一份 pcf85363 的驱动,看代码并核对寄存器功能,是可以兼容 pcf85263 芯片。只是我们用的内核比较老 linux 4.9,rtc 子系统的接口有些变化,不能直接拿来用。根据 Linux 4.9 现有的驱动程序,修改了 pcf85363 驱动,可以正常的使用。
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/rtc/rtc-pcf85363.c?h=v6.0
RTC 子系统的设备驱动还是非常简单的,只要按要求实现五个接口就能使用。
struct rtc_class_ops {
......
int (*read_time)(struct device *dev, struct rtc_time *tm);
int (*set_time)(struct device *dev, struct rtc_time *tm);
int (*read_alarm)(struct device *dev, struct rtc_wkalrm *alrm);
int (*set_alarm)(struct device *dev, struct rtc_wkalrm *alrm);
int (*alarm_irq_enable)(struct device *dev, unsigned int enabled);
......
};
通过以下接口即可注册到系统内:
devm_rtc_device_register(&client->dev, client->name, &rtc_ops, THIS_MODULE);
rtc_class_ops->read_time(struct device *dev, struct rtc_time *tm)
1. 应用层通过 ioctl(fd, RTC_RD_TIME, &rtc_tm) 读取时间的回调接口。
2. 驱动层需要读取芯片里面的时间日期寄存器组,转换为十进制更新到 rtc_tm。
rtc_class_ops->set_time(struct device *dev, struct rtc_time *tm)
1. 应用层通过 ioctl(fd, RTC_SET_TIME, &rtc_tm) 设置时间的回调接口。
2. 驱动层需要停止芯片计时,并将 tm 转换为 BCD 更新到时间日期寄存器组。
rtc_class_ops->read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
1. 应用层通过 ioctl(fd, RTC_ALM_READ, &rtc_tm) 读取闹钟的回调接口。
2. 驱动层需要读取芯片里面的 alarm 寄存器组,转换为十进制更新到 alrm->time。
3. 驱动层需要读取芯片里面的 alarm 控制寄存器,更新到 alrm->enabled。
rtc_class_ops->set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
1. 应用层通过 ioctl(fd, RTC_ALM_SET, &rtc_tm) 设置闹钟的回调接口。
rtc_class_ops->alarm_irq_enable(struct device *dev, unsigned int enabled)
1. 应用层通过 ioctl(fd, RTC_AIE_ON/RTC_AIE_OFF, 0) 命令开启关闭闹钟中断的回调接口。
2. 应用层通过 read(fd, &data, sizeof(unsigned long))/select() 等待被中断唤醒。
3. 驱动层需要通过 GPIO 注册中断,并在中断里读取中断标志位,通过标志位来确定调用如下接口,唤醒应用程序。
rtc_update_irq(pcf85x63->rtc, 1, RTC_IRQF | RTC_AF);
应用层访问设备驱动的流程:
APP ---> rtc/rtc-dev.c(/dev/rtcX) ---> rtc/interface.c ---> pcf85263.c
方法一:使用现成的命令 hwclock
root@localhost:~# hwclock -f /dev/rtc0 --show
2022-10-16 09:30: