问题描述

开机设置正确时间后,重启机器,时间仍为RTC中原始值,也就是说正确的时间并没有设置到RTC中,而RTC一直走着一个错误的时间,并在开机时显示

分析过程:

  1. 通过查看日志发现在系统时间更改后,pcf8563_set_datetime并未执行,也就是说正确的时间并没有写入到RTC中,再往前跟发现alarm_set_rtc中alarmtimer_get_rtcdev出了问题。即没有获取到设备,而设备就是rtcdev这个全局变量。
    • android系统设置时间时,会调用 到kernel中的drivers/staging/android/alarm-dev.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static int alarm_set_rtc(struct timespec *ts)
{
    struct rtc_time new_rtc_tm;
    struct rtc_device *rtc_dev;
    unsigned long flags;
    int rv = 0;
 
    rtc_time_to_tm(ts->tv_sec, &new_rtc_tm);
    rtc_dev = alarmtimer_get_rtcdev();    //rtc注册到i2c device中时,这里就找获取不到rtc_dev
     
    rv = do_settimeofday(ts);
 
    if (rv < 0)
        return rv;
         
    if (rtc_dev)
    {
        printk("#### [kernel] %s %s %d ####\n", __FILE__, __FUNCTION__, __LINE__);
        rv = rtc_set_time(rtc_dev, &new_rtc_tm);
    }
     
    spin_lock_irqsave(&alarm_slock, flags);
    alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
    wake_up(&alarm_wait_queue);
    spin_unlock_irqrestore(&alarm_slock, flags);
 
    return rv;
}
  1. 然后祭出我们的度娘大法,找到了http://bbs.csdn.net/topics/391882411 这个帖子,帖子里已经说的很清楚了。

根本原因:

  • 根据帖子描述,rtc注册到alarmtimer_rtc_add_device这一步时有两个判断条件:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index bc0677d..d0a43c5 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -183,9 +183,17 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	return pcf8563_set_datetime(to_i2c_client(dev), tm);
 }
 
+static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_time *tm)
+{
+	/*空函数*/
+	//mzd:解决alarm_set_rtc alarmtimer_get_rtcdev=(null)
+	return 0;
+}
+
 static const struct rtc_class_ops pcf8563_rtc_ops = {
 	.read_time	= pcf8563_rtc_read_time,
 	.set_time	= pcf8563_rtc_set_time,
+    .set_alarm  = pcf8563_rtc_set_alarm, //mzd:解决alarm_set_rtc alarmtimer_get_rtcdev=(null)
 };
 
 static int pcf8563_probe(struct i2c_client *client,
@@ -204,6 +212,8 @@ static int pcf8563_probe(struct i2c_client *client,
 	if (!pcf8563)
 		return -ENOMEM;
 
+	device_init_wakeup(&client->dev, true); //mzd:解决alarm_set_rtc alarmtimer_get_rtcdev=(null)
+
 	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
 
 	i2c_set_clientdata(client, pcf8563);