RK3399添加外部独立RTC
背景
- Platform: RK3399
- OS: Android7.1.2
- Kernel: v4.4.103
以前使用的是RK808内部的RTC,说电流较大,电池不耐用,后面就外置了一个独立的RTC芯片–ISL1208。
现在这2个RTC同时存在,或只有以前的RK808,需做兼容处理。
Kernel内核部分:
- 添加对应RTC芯片的驱动源码(
kernel/drivers/rtc/rtc-isl1208.c
) - 修改Kconfig和Makefile,添加对应的编译选项
- dts添加节点配置:
&i2c3 { status = "okay"; i2c-scl-rising-time-ns = <450>; i2c-scl-falling-time-ns = <15>; /*RTC*/ rtc: isl1208@6f { status = "okay"; compatible = "rtc,isl1208"; reg = <0x6f>; }; };
I2C3的问题
RTC开始是接在I2C3上面的,但调试许久发现I2C都不正常,后面发现该I2C已经被复用为内部I2C给HDMI使用了。
默认HDMI使用的是内部I2C(内部I2C只能使用I2C3),即配置如下。但如果使用了内部I2C,普通I2C是无法使用的,因为被复用成了RK_FUNC_3
,普通I2C为RK_FUNC_1
hdmi:hdmi@ff940000 { ...... pinctrl-names = "default"; pinctrl-0 = <&hdmi_i2c_xfer>; ...... } hdmi { hdmi_i2c_xfer: hdmi-i2c-xfer { rockchip,pins = <4 17 RK_FUNC_3 &pcfg_pull_none>, <4 16 RK_FUNC_3 &pcfg_pull_none>; }; };
若要将I2C3作为普通I2C使用,需要将pinctrl-0
属性注释掉,并在hdmi的配置中配置ddc-i2c-bus
属性,即:
&hdmi {
status = "okay";
ddc-i2c-bus = <&i2c3>; //选择硬件对应的I2C
};
测试
硬件OK和驱动OK后,会在/dev
下生成对应的设备节点rtcx
测试节点属性(/sys/class/rtc/
、/proc/driver/rtc
):
cat /sys/class/rtc/rtc0/time
cat /sys/class/rtc/rtc0/name
使用hwclock
命令进行测试:
usage: hwclock [-rswtluf]
-f FILE Use specified device file instead of /dev/rtc (--rtc)
-l Hardware clock uses localtime (--localtime)
-r Show hardware clock time (--show)
-s Set system time from hardware clock (--hctosys)
-t Set the system time based on the current timezone (--systz)
-u Hardware clock uses UTC (--utc)
-w Set hardware clock from system time (--systohc)
#hwclock -f /dev/rtc0
注意需要先写时间进去,不然如果读取RTC会返回-1
hctosys
config属性CONFIG_RTC_HCTOSYS_DEVICE
会配置默认的hctosys设备,通过/sys/class/rtc/rtc0/hctosys
可查看状态
兼容处理:
CONFIG_RTC_HCTOSYS_DEVICE
和CONFIG_RTC_SYSTOHC_DEVICE
都配置为rtc1
rtc_hctosys
函数(kernel/drivers/rtc/hctosys.c
):... if (rtc == NULL) { pr_info("unable to open rtc device (%s), try rtc0\n", CONFIG_RTC_HCTOSYS_DEVICE); /*zdd add rtc0+rtc1, try rtc0, CONFIG_RTC_HCTOSYS_DEVICE="rtc1"*/ rtc = rtc_class_open("rtc0"); if (rtc == NULL) { pr_info("unable to open rtc device (%s)\n", CONFIG_RTC_HCTOSYS_DEVICE); goto err_open; } } ...
hctosys_show
函数(kernel/drivers/rtc/rtc-sysfs.c
):#ifdef CONFIG_RTC_HCTOSYS_DEVICE /*zdd add rtc0/rtc1, CONFIG_RTC_HCTOSYS_DEVICE="rtc1"*/ struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); //如果没有rtc1, 且查询的是rtc0 if (rtc == NULL) { if (rtc_hctosys_ret == 0 && strcmp(dev_name(&to_rtc_device(dev)->dev), "rtc0") == 0) return sprintf(buf, "1\n"); } //如果有rtc1, 且查询的是CONFIG_RTC_HCTOSYS_DEVICE else if (rtc_hctosys_ret == 0 && strcmp(dev_name(&to_rtc_device(dev)->dev), CONFIG_RTC_HCTOSYS_DEVICE) == 0) return sprintf(buf, "1\n"); else #endif return sprintf(buf, "0\n");
注意:
ISL1208生产第一次RTC内无时间数据,读取会失败,需初始化一个默认值,否则RTC不能正常工作
Android部分添加修改
应用APK同步时间时需调用hwclock
命令将系统时间同步到硬件RTC时间,不能只调用date
命令。
注意调用hwclock
命令需要su权限
FrameWork:frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
HAL:frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp