Amlogic S905X3外设驱动之RTC驱动:HYM8563驱动 您所在的位置:网站首页 AmlogicS905D3固件 Amlogic S905X3外设驱动之RTC驱动:HYM8563驱动

Amlogic S905X3外设驱动之RTC驱动:HYM8563驱动

#Amlogic S905X3外设驱动之RTC驱动:HYM8563驱动| 来源: 网络整理| 查看: 265

软硬件环境:

• 主控: Amlogic S905X3 • 系统: Android9.0 • Kernel: 4.9.113

概述:

因S905X3 内部无专用RTC,采用的是定时器实现rtc,因项目需要,需要提供准确的时间,并能够掉电保存时间,故选用昊昱微半导体的HYM8563,作为本次的主角。

移植以及问题解决分析过程:

1: 查看内核,发现已经支持了此芯片,故直接修改:common/arch/arm/configs/meson64_a32_defconfig 添加 CONFIG_RTC_DRV_HYM8563=y

2:查看HYM8563硬件设计原理图, 确定I2C引脚为(GPIOAO_2_I2C_AO_MO_SCL,GPIOAO_3_I2C_AO_M0_SDA): 在这里插入图片描述

3:查看I2C相关描述:

/* i2c_ao */ static const unsigned int i2c_ao_sck_pins[] = {GPIOAO_2}; static const unsigned int i2c_ao_sda_pins[] = {GPIOAO_3}; # 查看 mesonsm1.dtsi中关于ao_i2c_master_pins1相关描述 ao_i2c_master_pins1:ao_i2c_pins1 {mux {groups = "i2c_ao_sck","i2c_ao_sda";function = "i2c_ao";drive-strength = ;}; };

4:在dts中添加关于HYM8563相应描述,PS:由于我们不使用HYM8563的中断输出功能,暂时不配置与HYM8563中断相连的引脚。

&i2c_AO {status = "okay";pinctrl-names="default";pinctrl-0=;clock-frequency = ; /* default 100k *//* for rtc hym8563 */hym8563: hym8563@51 {compatible = "haoyu,hym8563";reg = ;#clock-cells = ;}; };

5:重新编译内核(boot.img),以及dts(dt.img)

make bootimage -j16 make dtbimage -j16

6:烧录img文件

adb reboot fastboot fastboot flashing unlock_critical fastboot flashing unlock fastboot flash boot boot.img fastboot flash dts dt.img fastboot reboot

7:此处是不是应该欢呼雀跃,驱动已经移植完成?那你就想多了,开发要是这么简单就好了。

A: hym8563 驱动抛错:“no valid clock/calendar values available”,“hctosys: unable to read the hardware clock” bh905x3:/ # date Thu Jan 1 08:03:21 GMT 2009 bh905x3:/ # dmesg |grep rtc [ 3.314649] rtc-hym8563 4-0051: no valid clock/calendar values available [ 3.316066] rtc-hym8563 4-0051: rtc core: registered hym8563 as rtc0 [ 3.720134] aml_vrtc rtc: rtc core: registered aml_vrtc as rtc1 [ 3.720348] input: aml_vkeypad as /devices/platform/rtc/input/input1 [ 4.576520] rtc-hym8563 4-0051: no valid clock/calendar values available [ 4.576523] rtc-hym8563 4-0051: hctosys: unable to read the hardware clock [ 15.719979] type=1400 audit(15.600:29): avc: denied { open } for pid=3472 comm="system_server" path="/sys/devices/platform/soc/ff800000.aobus/ff805000.i2c/i2c-4/4-0051/rtc/rtc0/hctosys" dev="sysfs" ino=17355 scontext=u:r:system_server:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1 [ 15.845900] type=1400 audit(15.600:29): avc: denied { open } for pid=3472 comm="system_server" path="/sys/devices/platform/soc/ff800000.aobus/ff805000.i2c/i2c-4/4-0051/rtc/rtc0/hctosys" dev="sysfs" ino=17355 scontext=u:r:system_server:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1 B: 我们使用hwclock 查看一下,插上网线,让系统通过NTP服务器校时,通过logcat 查看一下HAL调用情况(logcat |grep AlarmManagerService)结果报错,找不到设备。难道要像网上说的手动去创建“/dev/misc/rtc”?答案是否定的。 bh905x3:/ # hwclock hwclock: /dev/misc/rtc: No such file or directorybh905x3:/ # logcat |grep AlarmManagerService 01-01 08:00:21.111 3505 3691 D SntpClient: round trip: 304ms, clock offset: 396574693935ms 01-01 08:00:21.112 3505 3691 D AlarmManagerService: Setting time of day to sec=1627371515 07-27 07:38:35.046 3505 3691 W AlarmManagerService: Unable to set rtc to 1627371515: No such device C:我们查看hwclock(externa/toybox/toys/other/hwclock.c)源码,以及HAL层 com_android_server_AlarmManagerService.cpp 源码(frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp)来分析:/sys/class/rtc/rtc0/hctosys 的值要为1才行。 /*hwclock.c*/ static int rtc_find(struct dirtree* node) {FILE *fp;if (!node->parent) return DIRTREE_RECURSE;sprintf(toybuf, "/sys/class/rtc/%s/hctosys", node->name);fp = fopen(toybuf, "r");if (fp) {int hctosys = 0, items = fscanf(fp, "%d", &hctosys);fclose(fp);if (items == 1 && hctosys == 1) {sprintf(toybuf, "/dev/%s", node->name);TT.fname = toybuf;return DIRTREE_ABORT;}}return 0; } /*com_android_server_AlarmManagerService.cpp*/ static const char rtc_sysfs[] = "/sys/class/rtc"; static bool rtc_is_hctosys(unsigned int rtc_id) {android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",rtc_sysfs, rtc_id);FILE *file = fopen(hctosys_path.string(), "re");if (!file) {ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));return false;}unsigned int hctosys;bool ret = false;int err = fscanf(file, "%u", &hctosys);if (err == EOF)ALOGE("failed to read from %s: %s", hctosys_path.string(),strerror(errno));else if (err == 0)ALOGE("%s did not have expected contents", hctosys_path.string());elseret = hctosys;fclose(file);return ret; } static int wall_clock_rtc() {std::unique_ptr dir(opendir(rtc_sysfs), closedir);if (!dir.get()) {ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));return -1;}struct dirent *dirent;while (errno = 0, dirent = readdir(dir.get())) {unsigned int rtc_id;int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id);if (matched #ifdef CONFIG_RTC_HCTOSYS_DEVICEif (rtc_hctosys_ret == 0 &&strcmp(dev_name(&to_rtc_device(dev)->dev),CONFIG_RTC_HCTOSYS_DEVICE) == 0)return sprintf(buf, "1\n");else #endifreturn sprintf(buf, "0\n"); } static DEVICE_ATTR_RO(hctosys); **********************************rtc-hym8563.c*********************************** #define HYM8563_SEC 0x02 #define HYM8563_SEC_VL BIT(7) /** RTC handling*/ static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm) {struct i2c_client *client = to_i2c_client(dev);struct hym8563 *hym8563 = i2c_get_clientdata(client);u8 buf[7];int ret;if (!hym8563->valid) {dev_warn(&client->dev, "no valid clock/calendar values available\n");return -EPERM;}ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf);tm->tm_sec = bcd2bin(buf[0] & HYM8563_SEC_MASK);tm->tm_min = bcd2bin(buf[1] & HYM8563_MIN_MASK);tm->tm_hour = bcd2bin(buf[2] & HYM8563_HOUR_MASK);tm->tm_mday = bcd2bin(buf[3] & HYM8563_DAY_MASK);tm->tm_wday = bcd2bin(buf[4] & HYM8563_WEEKDAY_MASK); /* 0 = Sun */tm->tm_mon = bcd2bin(buf[5] & HYM8563_MONTH_MASK) - 1; /* 0 = Jan */tm->tm_year = bcd2bin(buf[6]) + 100;return 0; } static int hym8563_probe(struct i2c_client *client,const struct i2c_device_id *id) { ..................................................................../* check state of calendar information */ret = i2c_smbus_read_byte_data(client, HYM8563_SEC);if (ret valid = !(ret & HYM8563_SEC_VL);dev_dbg(&client->dev, "rtc information is %s\n",hym8563->valid ? "valid" : "invalid"); .................................................................... }

B:通过源码分析 hym8563->valid 通过HYM8563_SEC的寄存器第BIT(7)位来确定。查看数据手册可知,当未给hym8563设置时间时,hym8563,的02H寄存器的第七位为 1 (VL=1:不保证准确的时钟/日历数据)。

C:解决办法呼之欲出了,在读取到VL=1的时候,我们给hym8563设置一个默认的日期,即可解决。(也可以在HAL层修改,给rtc一个默认值。但博主觉得,在内核层修改更具通用性,因为不管你在dts设置何值,最终都会通过NTP校时获取到当前时间。最终如何修改就看各位观众老爷们的喜好了)。

最终修改方案,供大家参考:

一 :在dts中添加init_date项,当hym8563_probe的时候,检测到系统如果未设置时间,则给时钟芯片一个默认值(init_date 设置的值)。

• DTS修改信息:

&i2c_AO {status = "okay";pinctrl-names="default";pinctrl-0=;clock-frequency = ; /* default 100k *//* for rtc hym8563 */hym8563: hym8563@51 {compatible = "haoyu,hym8563";reg = ;init_date = "2021/07/28";#clock-cells = ;}; };

二:修改内核驱动:drivers/rtc/rtc-hym8563.c • rtc-hym8563.c的修改记录

Signed-off-by: mleaf --- diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index e5ad527cb75e..acf00fe25ae6 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -524,11 +524,96 @@ static int hym8563_resume(struct device *dev)static SIMPLE_DEV_PM_OPS(hym8563_pm_ops, hym8563_suspend, hym8563_resume);+#define TIME_LEN 10 +static int parse_init_date(const char *date, struct rtc_time *rtm) +{ + unsigned int init_date; + char local_str[TIME_LEN + 1]; + char *year_s, *month_s, *day_s, *str; + unsigned int year_d, month_d, day_d; + int ret; + + if (strlen(date) != 10) + return -1; + memset(local_str, 0, TIME_LEN + 1); + strncpy(local_str, date, TIME_LEN); + str = local_str; + year_s = strsep(&str, "/"); + if (!year_s) + return -1; + month_s = strsep(&str, "/"); + if (!month_s) + return -1; + day_s = str; + pr_debug("year: %s\nmonth: %s\nday: %s\n", year_s, month_s, day_s); + ret = kstrtou32(year_s, 10, &year_d); + if (ret 2100 || year_d struct hym8563 *hym8563;int ret; + struct device_node *node = client->dev.of_node; + const char *str = NULL; + int init_date_valid = -1; + struct rtc_time tm;hym8563 = devm_kzalloc(&client->dev, sizeof(*hym8563), GFP_KERNEL);if (!hym8563) @@ -556,7 +641,12 @@ static int hym8563_probe(struct i2c_client *client,return ret;}} - + /* optional override of the init_date */ + ret = of_property_read_string(node, "init_date", &str); + if (!ret) { + dev_dbg(&client->dev, "init_date: %s\n", str); + init_date_valid = parse_init_date(str, &tm); + }/* check state of calendar information */ret = i2c_smbus_read_byte_data(client, HYM8563_SEC);if (ret valid = !(ret & HYM8563_SEC_VL);dev_dbg(&client->dev, "rtc information is %s\n",hym8563->valid ? "valid" : "invalid"); - + if (!hym8563->valid) { + dev_warn(&client->dev, "no valid clock/calendar values available\n"); + if(init_date_valid == 0){ + dev_info(&client->dev, "setting hym8563 clock to %s\n", str); + ret = hym8563_rtc_init_time(client, &tm); + if (!ret) { + dev_dbg(&client->dev, "hym8563_rtc_init_time: %s\n", str); + hym8563->valid = true; + } + } + }hym8563->rtc = devm_rtc_device_register(&client->dev, client->name,&hym8563_rtc_ops, THIS_MODULE);if (IS_ERR(hym8563->rtc)) selinux权限添加: # 修改system_server.te #add by mleaf for rtc allow system_server sysfs:file open;//libsepol.report_failure: neverallow on line 31 of system/sepolicy/private/domain.te (or line 26822 of policy.conf) violated by allow system_server sysfs:file { open }; //libsepol.check_assertions: 1 neverallow failures occurred# 修改 system/sepolicy/private/domain.teneverallow {coredomain-init-ueventd-vold-system_server} sysfs:file no_rw_file_perms;#修改后拷贝到system/sepolicy/prebuilts/api/28.0/private/,使两个文件保持一致cp system/sepolicy/private/domain.te system/sepolicy/prebuilts/api/28.0/private/domain.te

• 调试log信息:

bh905x3:/ # dmesg |grep rtc [ 3.317770] rtc-hym8563 4-0051: no valid clock/calendar values available [ 3.319012] rtc-hym8563 4-0051: setting hym8563 clock to 2021/07/28 [ 3.326972] rtc-hym8563 4-0051: hym8563_rtc_init_time: 2021/07/28 [ 3.338555] rtc-hym8563 4-0051: rtc core: registered hym8563 as rtc0 [ 3.749774] aml_vrtc rtc: rtc core: registered aml_vrtc as rtc1 [ 3.750000] input: aml_vkeypad as /devices/platform/rtc/input/input1 [ 4.608679] rtc-hym8563 4-0051: setting system clock to 2021-07-28 00:00:01 UTC (1627430401) bh905x3:/ # cat /sys/class/rtc/rtc0/hctosys 1#通过ntp校时后时间也能正确设置,不会报错。 bh905x3:/ # logcat |grep AlarmManagerService 07-28 00:00:28.062 3492 3694 D AlarmManagerService: Setting time of day to sec=1627441608 bh905x3:/ # date Wed Jul 28 03:07:36 GMT 2021 bh905x3:/ # cat /sys/class/rtc/rtc0/date 2021-07-28 bh905x3:/ # cat /sys/class/rtc/rtc0/time 03:07:47 bh905x3:/ # 参考:

• common/arch/arm/boot/dts/amlogic/mesonsm1.dtsi

rtc{compatible = "amlogic, aml_vrtc";alarm_reg_addr = ;timer_e_addr = ;init_date = "2015/01/01";status = "okay"; };

• common/drivers/amlogic/vrtc/aml_vrtc.c

附上HYM8563 datasheet 下载地址


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有