From 4ae0ac33936d497b09fb8794d236f86a9d3e3229 Mon Sep 17 00:00:00 2001 From: Dmitry Ermakov <7954832+dimerr@users.noreply.github.com> Date: Fri, 6 Nov 2026 11:25:09 +0000 Subject: [PATCH] i2cdetect: stop wedging a GC4653 on Hi3516CV610 Scanning a CV610 board with a GC4653 killed the sensor bus at once. On stock firmware the streamer then tripped the watchdog; on OpenIPC every later transfer on i2c-0 failed until the sensor was reset. i2cdetect read register 0 with a one-byte address, and the GC4653 takes two. Single transfers on the board isolated it: i2cget 0x52 0x00 kills the bus and a pulse of the sensor reset in 0x11018440 recovers it, while a NACK at an empty address, 0x78 and the general call at 0x00 do nothing. On HISI_OT the scan now writes one byte and a stop. A read alone also found the sensor, but it took about 500 ms per table line: without an interrupt, bsp-i2c waits for data on every address that does not answer, where a write fails on the NACK. A zero-length write is out too, as the driver loads len - 1 into its loop counter. Tested on a Hi3516CV610 QFN board with a GC4653 on OpenIPC: the scan is immediate, finds the sensor, and the sensor still answers afterwards. Other CV610 sensors and a scan during a live stream are untested. Other chips keep the old probe. Sensor detection still wedges this sensor: detect_galaxycore_sensor reads 0xf0 with a one-byte address first, since #238. That needs its own fix. --- src/i2cspi.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/i2cspi.c b/src/i2cspi.c index 1afc0cbc..0bf29a44 100644 --- a/src/i2cspi.c +++ b/src/i2cspi.c @@ -2,9 +2,11 @@ #include #include #include +#include #include "chipid.h" #include "hal/common.h" +#include "hal/hisi/hal_hisi.h" #include "i2cspi.h" #define SELECT_WIDE(reg_addr) reg_addr > 0xff ? 2 : 1 @@ -186,6 +188,26 @@ static int i2cdump(int argc, char **argv, bool script_mode) { return EXIT_SUCCESS; } +/* Is anything at the address i2c_change_addr() last set? + * + * The register read below sends a one-byte address and then a repeated start, + * and on a Hi3516CV610 that wedges a GC4653, which takes two-byte addresses: + * every later transfer on the bus fails until the sensor is reset. + * + * So one byte and a stop, read nothing back. A read alone would be gentler + * still, but bsp-i2c without an interrupt waits 51 ms for data on every + * address that does not answer, where a write fails on the NACK at once. A + * zero-length write is no use either: the driver loads len - 1 into its loop + * counter and the controller then waits on an empty FIFO. */ +static int i2cdetect_probe(int fd, unsigned char i2c_addr) { + if (chip_generation == HISI_OT) { + unsigned char byte = 0; + return write(fd, &byte, 1) == 1 ? 0 : -1; + } + + return i2c_read_register(fd, i2c_addr, 0x00, SELECT_WIDE(0), 1); +} + static int i2cdetect(int argc, char **argv, bool script_mode) { (void)argv; (void)script_mode; @@ -203,7 +225,7 @@ static int i2cdetect(int argc, char **argv, bool script_mode) { do { ++i2c_addr; i2c_change_addr(fd, i2c_addr); - int res = i2c_read_register(fd, i2c_addr, 0x00, SELECT_WIDE(0), 1); + int res = i2cdetect_probe(fd, i2c_addr); if (i2c_addr % 16 == 0) printf("%4.x: ", i2c_addr);