硬件平台:RK3128
Android版本:6.0
Kernel版本:3.10.92
任务描述:
Rk3128 Android 6.0平台调试rtc芯片PCF8563,本以为很容易,结果碰到一些问题,在此记录下来。
一、添加设备信息
Dts中添加I2C设备:
rtc@51 {
compatible = "nxp,pcf8563";
reg = <0x51>;
irq_gpio = <&gpio0 GPIO_D4 IRQ_TYPE_EDGE_FALLING>;
};
二、驱动调试
配置内核开关,使用内核默认驱动kernel/drivers/rtc/rtc-pcf8563.c。
I2C通信成功后,RTC就可以工作了。
但后来又遇到两个问题:
问题一、开机显示初始时间
通过查看开机日志发现如下错误:
low voltage detected, date/time is not reliable.
retrieved date/time is not valid.
出现第一条错误后,读取的时间有错误,校验不过,因此开机并不显示rtc中保存的时间,查看AT8563规格书(AT8563完全兼容PCF8563)发现这是VL位被置位。当VL为1时无法保证时间的准确,同样根据规格书提示,在检测到VL为1时,重新初始化寄存器时间值。
解决办法:
在驱动初始化时如果检测到VL=1,即重新初始化寄存器,同时把VL置0;
问题二、开机设置正确时间后,重启机器,时间仍为RTC中原始值,也就是说正确的时间并没有设置到RTC中,而RTC一直走着一个错误的时间,并在开机时显示。
分析过程:
通过查看日志发现在系统时间更改后,pcf8563_set_datetime并未执行,也就是说正确的时间并没有写入到RTC中,再往前跟发现alarm_set_rtc中alarmtimer_get_rtcdev出了问题。即没有获取到设备,而设备就是rtcdev这个全局变量。
然后祭出我们的度娘大法,找到了http://bbs.csdn.net/topics/391882411
这个帖子,帖子里已经说的很清楚了。
根本原因:
根据帖子描述,rtc注册到alarmtimer_rtc_add_device这一步时有两个判断条件:
static int alarmtimer_rtc_add_device(struct device *dev,
struct class_interface *class_intf)
{
unsigned long flags;
struct rtc_device *rtc = to_rtc_device(dev);
if (rtcdev)
return -EBUSY;
if (!rtc->ops->set_alarm)
return -1;
if (!device_may_wakeup(rtc->dev.parent))
return -1;
spin_lock_irqsave(&rtcdev_lock, flags);
if (!rtcdev) {
rtcdev = rtc;
/* hold a reference so it doesn't go away */
get_device(dev);
}
spin_unlock_irqrestore(&rtcdev_lock, flags);
return 0;
}
首先,pcf8563驱动中没有实现set_alarm,所以此处直接返回。
其次,实现了set_alarm后,第二条仍然不能通过。
所以,rtc设备并没有赋值给rtcdev,设置时间时当然也就获取不到了。
解决办法:
1、实现set_alarm函数,此项目并不需要alarm功能,随便写个空函数即可。
2、在pcf8563_probe中添加device_init_wakeup(&client->dev, true);
device_init_wakeup是设置该设备能不能唤醒设备,我们这里设为true。
总结:
没想到小小的RTC也几经波折,内核修炼之路任重道远...