当前位置: 首页 > article >正文

坑多多之AC8257 i2c1 rtc-pcf8563

pcf85163

ordering information

Ordering information

Package

Description

Version

Marking code

PCF85163T/1

SO8

SOT96-1

PF85163

PCF85163TS/1

TSSOP8

SOT505-1

85163

①plastic small outline package; 8 leads;body width 3.9 mm

②plastic thin shrink small outline package;8 leads; body width 3 mm

register

HYM8563 vs PCF85163

regHYM8563PCF85163
0x00CTL1
0x01CTL2
0x02SEC
0x03MIN
0x04HOUR
0x05DAY
0x06WEEKDAY
0x07MONTH
0x08YEAR
0x09ALM_MIN
0x0aALM_HOUR
0x0bALM_DAY
0x0cALM_WEEK
0x0dCLKOUT
0x0eTMR_CTL
0x0fTMR_CNT

detail 

Bit positions labeled as x are not relevant. Bit positions labeled with N should always be written with logic 0; if read, they couldbe either logic 0 or logic 1. 

76543210
TESTNSTOPNTESTCNNN
NNNTI_TPAFTFAIETIE
VL
x
xx
xx
xxxxx
CENTURYxx
AE_M
AE_Hx
AE_Dx
AE_Wxxxx
FExxxxx
TExxxxx

clkout_ops

clkout_opsfunction
pcf8563_clkout_preparepcf8563_clkout_controlRW
pcf8563_clkout_unpreparepcf8563_clkout_controlRW
pcf8563_clkout_is_preparedR
pcf8563_clkout_recalc_rateR
pcf8563_clkout_round_rate
pcf8563_clkout_set_rateRW

问题

佰维BWMECX32H2A-08Gb停产,内存颗粒换成BWMZFX32H2A-8G-X,linux内核启动时间与之前的内存颗粒比提前100ms左右,rtc芯片驱动访问i2c1与MTK sensor hub协处理器访问i2c1冲突导致i2c读写失败,最终probe失败,rtc设备不存在,厂测失败,厂线停产。rtc驱动初始化时增加100毫秒延时可以避开冲突。

日志

异常

<3>[    0.523511] (2)[1:swapper/0]rtc-pcf8563 1-0051: pcf8563_read_block_data: read error
<3>[    0.523516] (2)[1:swapper/0]rtc-pcf8563 1-0051: pcf8563_probe: read error

       996        : preloader
       813        : lk

<3>[    0.520859] (3)[1:swapper/0]rtc-pcf8563 1-0051: pcf8563_write_block_data: err=-121 addr=0e, data=03
<3>[    0.520867] (3)[1:swapper/0]rtc-pcf8563 1-0051: pcf8563_probe: write error
<4>[    0.520892] (3)[1:swapper/0]rtc-pcf8563: probe of 1-0051 failed with error -5

<3>[    0.524627] (3)[1:swapper/0]rtc-pcf8563 1-0051: low voltage detected, date/time is not reliable.
<6>[    0.524737] (3)[1:swapper/0]rtc-pcf8563 1-0051: rtc core: registered rtc-pcf8563 as rtc1
<3>[    0.525180] (3)[1:swapper/0]rtc-pcf8563 1-0051: pcf8563_write_block_data: err=-121 addr=0d, data=00
<6>[    0.739091] (3)[1:swapper/0]rtc-pcf8563 1-0051: setting system clock to 2009-01-01 00:01:11 UTC (1230768071)

正常

       991        : preloader
       977        : lk
<6>[    0.574644] (2)[1:swapper/0]rtc-pcf8563 1-0051: rtc core: registered rtc-pcf8563 as rtc1
<6>[    0.782513] (3)[1:swapper/0]rtc-pcf8563 1-0051: setting system clock to 2009-01-01 23:38:17 UTC (1230853097)

0121 i2c1 rtc-pcf8563

设备上电3.18秒左右访问0xee,9次,1ms后2个9次,3ms后访问0x18,3个9次。对应的kernel时间0.841042左右。lk里boot_linux_fdt不启动linux kernel,不会有0xee 0x18访问。

delayed work

--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -650,7 +650,39 @@ static struct i2c_driver pcf8563_driver = {
    .id_table   = pcf8563_id,
 };

+#ifdef MODULE
 module_i2c_driver(pcf8563_driver);
+#else
+static struct delayed_work rtc_init_work;
+
+static void rtc_init_work_callback(struct work_struct *work)
+{
+   i2c_add_driver(&pcf8563_driver);
+   return;
+}
+
+static int __init pcf8563_init(void)
+{
+   int rval = 0;
+
+   INIT_DELAYED_WORK(&rtc_init_work, rtc_init_work_callback);
+   rval = schedule_delayed_work(&rtc_init_work, HZ * 2);
+   if (rval < 0) {
+       pr_info("pcf8563 init fail %d\n", rval);
+   }
+
+   return rval;
+}
+
+static void __exit pcf8563_exit(void)
+{
+   i2c_del_driver(&pcf8563_driver);
+   return;
+}
+
+module_init(pcf8563_init)
+module_exit(pcf8563_exit)
+#endif

 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");

dts

--- a/arch/arm/boot/dts/ac8257_demo_1g_32.dts
+++ b/arch/arm/boot/dts/ac8257_demo_1g_32.dts
@@ -993,7 +993,7 @@
                compatible = "autochips,lcm_bridge_ic";
                reg = <0x0c>;
                lcm_id = <0>;
-               status = "okay";
+               status = "disabled";
         };
 };

@@ -1007,7 +1007,7 @@
                compatible = "autochips,lcm_bridge_ic";
                reg = <0x0c>;
                lcm_id = <1>;
-               status = "okay";
+               status = "disabled";
        };

        /* 720P demo board */
@@ -1038,7 +1038,7 @@
                interrupt-parent = <&pio>;
                interrupts = <12 IRQ_TYPE_EDGE_FALLING 12 0>;

-               status = "okay";
+               status = "disabled";
        };

        /* 720P Main  */

delay 100ms

--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/err.h>
+#include <linux/delay.h>

 #define PCF8563_REG_ST1                0x00 /* status */
 #define PCF8563_REG_ST2                0x01
@@ -650,7 +651,31 @@ static struct i2c_driver pcf8563_driver = {
        .id_table       = pcf8563_id,
 };

+#ifdef MODULE
 module_i2c_driver(pcf8563_driver);
+#else
+static int __init pcf8563_init(void)
+{
+       int rval = 0;
+
+       msleep(100);
+       rval = i2c_add_driver(&pcf8563_driver);
+       if (rval < 0) {
+               pr_info("pcf8563 init fail %d\n", rval);
+       }
+
+       return rval;
+}
+
+static void __exit pcf8563_exit(void)
+{
+       i2c_del_driver(&pcf8563_driver);
+       return;
+}
+
+module_init(pcf8563_init)
+module_exit(pcf8563_exit)
+#endif

 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");

0122 debug

i2c1接pcf8563(写地址0xa2,读地址0xa3),2ms后访问0xee,9次,1ms后2个9次,3ms后访问0x18,3个9次。

kernel设备树中禁用pcf8563,示波器已经量不到pcf8563驱动的i2c操作;在此基础上,把i2c1上的rtc芯片pcf8563断开,示波器抓到的i2c信号变成,访问0xa2 3个9次,访问0xee 3个9次,访问0x18 3个9次。

dts

--- a/arch/arm/boot/dts/ac8257_demo_1g_32.dts
+++ b/arch/arm/boot/dts/ac8257_demo_1g_32.dts
@@ -1106,7 +1106,7 @@
    };

    rtc: pcf8563@51 {
-       status = "okay";
+       status = "disabled";
        compatible = "nxp,pcf8563";
        reg = <0x51>;
    };

i2c-mtk.c

--- a/drivers/i2c/busses/i2c-mtk.c
+++ b/drivers/i2c/busses/i2c-mtk.c
@@ -1428,6 +1428,9 @@ static int mt_i2c_transfer(struct i2c_adapter *adap,
    int ret;
    struct mt_i2c *i2c = i2c_get_adapdata(adap);

+   if (1 == i2c->adap.nr) {
+       pr_info("zzz i2c bus %d, client 0x%02x\n", i2c->adap.nr, msgs->addr);
+   }
    if (i2c->multiplexing) {
        /* Once AP use i2c to transfer, It means bus belong AP.*/
        i2c->multiplexing = 0;

 rtc-pcf8563.c

--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -13,6 +13,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#define DEBUG

 #include <linux/clk-provider.h>
 #include <linux/i2c.h>
@@ -245,6 +246,8 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
        tm->tm_sec, tm->tm_min, tm->tm_hour,
        tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);

+   dump_stack();
+
    return 0;
 }

@@ -357,6 +360,7 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
        tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday,
        tm->enabled, tm->pending);

+   dump_stack();
    return 0;
 }

main.c

--- a/init/main.c
+++ b/init/main.c
@@ -979,6 +979,7 @@ static int __ref kernel_init(void *unused)
 {
    int ret;

+   msleep(5000);
    kernel_init_freeable();
    /* need to finish all async __init code before freeing the memory */
    async_synchronize_full();

0123 /proc/interrupts

proc.c

--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -441,6 +441,12 @@ int show_interrupts(struct seq_file *p, void *v)
    int i = *(loff_t *) v, j;
    struct irqaction *action;
    struct irq_desc *desc;
+   const char *trigger_type_sz[IRQ_TYPE_PROBE] = {
+       "", "rising", "falling", "both",
+       "high", "", "", "",
+       "low", "", "", "",
+       "high|low", "", "", "",
+   };

    if (i > ACTUAL_NR_IRQS)
        return 0;
@@ -489,6 +495,7 @@ int show_interrupts(struct seq_file *p, void *v)
        seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq);
 #ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
    seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
+   seq_printf(p, "(%-8s)", trigger_type_sz[irqd_get_trigger_type(&desc->irq_data)]);
 #endif
    if (desc->name)
        seq_printf(p, "-%-8s", desc->name);

0213 MTK TINYSYS SCP

defconfig中禁用SCP后,i2c总线上不再有写地址0xee 0x18的访问。

defconfg

-CONFIG_MTK_TINYSYS_SCP_SUPPORT=y
+CONFIG_MTK_TINYSYS_SCP_SUPPORT=n

0214 i2c1

禁用SCP后i2c总线上只有rtc芯片相关的数据访问,示波器解码出来的i2c数据,与rtc-pcf8563驱动代码一致。

i2c1数据分析

functioni2c
pcf8563_probea2 0e 03Set timer to lowest frequency to save power
pcf8563_get_alarm_modea2 01 A3 00
pcf8563_rtc_read_timea2 00 a3 08 00 38 08 02 14 3d 22 25__rtc_read_alarm
pcf8563_rtc_read_alarma2 09 a3 80 81 80__rtc_read_alarm
  pcf8563_get_alarm_modea2 01 a3 00
pcf8563_rtc_read_timea2 00 a3 08 00 38 08 02 14 3d 22 25__rtc_read_alarm
pcf8563_rtc_read_timea2 00 a3 08 00 38 08 02 14 3d 22 25rtc_initialize_alarm
pcf8563_clkout_register_clka2 0d 00disable the clkout output
a2 0d a3 38pcf8563_clkout_recalc_rate
200ms
pcf8563_rtc_read_timea2 00 a3 08 00 38 08 02 14 3d 22 25rtc_hctosys

 usleep

可能出现返回值小于0,实际休眠时间可能比想要的时间短的情况,接触到的大部分人没有判断函数返回值、man命令查看帮助的习惯,量产后程序时不时出现莫名其妙的情况。

bionic/libc/upstream-freebsd/lib/libc/gen/usleep.c

sleep

bionic/libc/upstream-freebsd/lib/libc/gen/sleep.c

 43 unsigned int
 44 __sleep(unsigned int seconds)
 45 {
 46     struct timespec time_to_sleep;
 47     struct timespec time_remaining;
 48
 49     /*
 50      * Avoid overflow when `seconds' is huge.  This assumes that
 51      * the maximum value for a time_t is >= INT_MAX.
 52      */
 53     if (seconds > INT_MAX)
 54         return (seconds - INT_MAX + __sleep(INT_MAX));
 55
 56     time_to_sleep.tv_sec = seconds;
 57     time_to_sleep.tv_nsec = 0;
 58     if (_nanosleep(&time_to_sleep, &time_remaining) != -1)
 59         return (0);
 60     if (errno != EINTR)
 61         return (seconds);       /* best guess */
 62     return (time_remaining.tv_sec +
 63         (time_remaining.tv_nsec != 0)); /* round up */
 64 }
 65
 66 __weak_reference(__sleep, sleep);
 67 __weak_reference(__sleep, _sleep);

nanosleep

kernel/time/hrtimer.c

1666 SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
1667         struct timespec __user *, rmtp)
1668 {
1669     struct timespec tu;
1670
1671     if (copy_from_user(&tu, rqtp, sizeof(tu)))
1672         return -EFAULT;
1673
1674     if (!timespec_valid(&tu))
1675         return -EINVAL;
1676
1677     return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
1678 }


http://www.kler.cn/a/548343.html

相关文章:

  • C#学习之数据转换
  • 【Git】三、远程管理
  • 蓝桥杯 Java B 组之总结与模拟题练习
  • C++STL容器之map的使用及复现
  • windows10本地的JMeter+Influxdb+Grafana压测性能测试,【亲测,避坑】
  • 深入解析Jenkins——持续集成与持续交付的中坚力量
  • 算法与数据结构(除自身以外数组的乘积)
  • 在IntelliJIDEA中使用Gradle创建Web项目的步骤
  • 二分搜索法、二分查找法【C/C ++】
  • 湖仓分析|浙江霖梓基于 Doris + Paimon 打造实时/离线一体化湖仓架构
  • GC 基础入门
  • 哈希表(典型算法思想)—— OJ例题算法解析思路
  • git如何下载指定版本
  • 一个Jakarta Batch导出数据库(比如postgreSQL)的一个表的例子
  • 开发基础(8):鸿蒙图表开发
  • Linux 的目录结构
  • Selenium WebDriver自动化测试(扩展篇)--Jenkins持续集成
  • 华为小艺支持DeepSeek
  • Python Pandas(11):Pandas 数据可视化
  • Git 修改或删除某次提交信息