Userspace Ingenic image-sensor detector for thingino. Probes the sensor I2C bus against a database of ~290 known sensors, driving the sensor's master clock and reset/power-down GPIOs itself, and reports what is on the board.
It is a userspace port of the ingenic-sdk sinfo kernel module.
Where the module needed a .ko built for the exact SoC and kernel
version, this is one static MIPS binary that runs on any kernel with:
CONFIG_I2C_CHARDEV(/dev/i2c-N)CONFIG_GPIO_SYSFS(/sys/class/gpio)CONFIG_DEVMEM(/dev/mem)
sinfo never touches the network. It opens no sockets, downloads
nothing, uploads nothing, and phones home to no one - the binary
contains no networking code at all. Everything happens locally on
the camera: registers are read over /dev/mem and /dev/i2c-N,
results go to your terminal, and nothing is written anywhere unless
you redirect it yourself. The static release binary has no
dependencies and runs the same on an air-gapped bench board as on a
networked camera. (Its predecessor downloaded a kernel module from
the internet at runtime; this tool exists partly to end that.)
sinfo # probe, auto-detecting the SoC
sinfo -v probe # verbose progress on stderr
sinfo -s t31 -b 0 -r 18 # explicit SoC / bus / reset GPIO
sinfo -b all # scan every /dev/i2c-* bus
sinfo -m 0 # select MCLK block (multi-sensor T40)
sinfo -p 21 # sensors needing a PWDN dance (e.g. T10)
sinfo open gc2053 # enable MCLK + reset for bench I2C work
sinfo i2c-r 0x37 1 # raw I2C read (after open)
sinfo release # stop MCLK, free GPIOs
Run as root. If a sensor kernel driver is loaded it owns the reset
GPIO and the bus; unload it (rmmod sensor_*) for a clean probe.
A found sensor is reported answer-first; probe progress ticks on stderr so stdout stays clean:
$ sinfo
Probing bus 0... 290/290
gc4653 on bus 0 at 0x29 (MCLK 24 MHz)
ID: 0x03F0=0x46 0x03F1=0x53
Rebadged twins are listed as also matches: under the lead name;
multi-sensor units get a numbered list (device 1 is the primary).
No match prints no sensors detected on bus N plus a pointer to
-v, which appends every answering address with the union of its
register reads (I2C devices seen).
Exit codes: 0 at least one sensor found, 1 none found, 2
error. Scripts use -q, which prints only the detected sensor
names, one per line.
The SoC is read from the chip-id registers over /dev/mem (the
same scheme as thingino's soc tool), so detection works on any
firmware with no kernel support beyond /dev/mem. -s overrides.
Three SKU codes are shared between T40 and T41 silicon
(t40n/t41n, t40xp/t41zn, t40nn/t41lc); those default to t40 with a
warning - pass -s t41 on the T41 variants. C100 identifies as
T31, whose clock layout it shares.
For every database entry the tool mirrors what the kernel module's probe did, from userspace:
- MCLK. Programs the CIM clock divider in the CPM (via
/dev/mem) for the sensor's rate: reads the currently selected PLL parent, computes the divider the same way the kernel clock framework does (smallest divider with parent/div <= rate), and programs it under the CE/BUSY handshake. If the selected parent PLL is parked it falls back to the first live PLL. The register is left gated with the parent preserved after the run. - Pin mux (XBurst2). T40/T41 MCLK pins are muxed to their device function through the GPIO set/clear registers, plus the T40 vendor VDD-select write, so probing works even when no sensor driver has run since boot.
- Reset/PWDN dance via sysfs GPIO, including the per-sensor timing quirks (sp1409, sc2336p/sc2337p/sc3336p).
- ID reads over
/dev/i2c-N(I2C_RDWR), including the sc2336p-vs-sc2337p disambiguation and the ov2735b alternate-ID check, then compares against the table.
Rebadged sensors with identical ID registers (gc5603/gc5613, gc2053/gc2063, imx291/imx307, ...) all match one physical chip; the report groups them into one device with the other names listed as aliases. Which name leads is table order.
- Two sensors on one bus at different addresses: found in one run.
- Sensors on different buses:
-b all, or per-bus runs. Each device is reported with its bus. - XBurst2 units with a second sensor on another MCLK block: one
block drives a run (
-m, T40: 0/1/2 = CIM0/1/2 on PC31/PC30/PC29, default CIM1); run once per block. Sensors clocked by an external oscillator (common on vanhua boards) probe regardless.
| SoC | MCLK reg | CIM parent mux | PLL format | status |
|---|---|---|---|---|
| t31 | CIMCDR 0x7c | APLL/MPLL/VPLL @30 | new | HW-validated |
| t23 | CIMCDR 0x7c | APLL/MPLL @30 | new | HW-validated |
| c100 | CIMCDR 0x7c | APLL/MPLL/VPLL @30 | new | untested |
| t20 | CIMCDR 0x7c | APLL/MPLL/VPLL @30 | new | HW-validated |
| t30 | CIMCDR 0x7c | APLL/MPLL/VPLL/EPLL @30 | old | HW-validated |
| t21 | CIMCDR 0x7c | APLL/MPLL/VPLL/EPLL @30 | old | HW-validated |
| t10 | CIMCDR 0x7c | APLL/MPLL @31 (1 bit) | new | HW-validated |
| t40 | CIM0/1/2CDR 0x90/94/98 | APLL/MPLL/VPLL/EPLL @30 | new | HW-validated |
| t41 | CIM0CDR 0x90 | APLL/MPLL/VPLL @30 | t41 | HW-validated |
| a1 | - | - | - | not implemented (module never supported it) |
PLL formats: "new" EXTAL*M/N/OD0/OD1; "old"
EXTAL*2*(M+1)/(N+1)/2^OD; "t41"
EXTAL*2*(M+1)/((N+1)*2^OD0*(OD1+1)). EXTAL is assumed 24 MHz.
Register data comes from the ingenic-u-boot-xburst1/-xburst2 trees
and the vendor 4.4.94 SDK; every hardware-validated row was proven
on a real board with the values cross-checked against the running
kernel's own clock programming.
The table lives in sensors.csv (one line per sensor); sensors.h
is generated from it.
- Add a line:
name,i2c_addr,mclk_hz,id_regs,id_vals,reg_bytes,val_bytes,soc(see the header comments in the csv for field details). Keep vendor families grouped; among rebadges with identical IDs the first entry becomes the reported primary name. make sensorsto regeneratesensors.h(validates widths, address range, and duplicates), and commit both files.make test- the table invariants run against the new entry, andcheck-tablefails the build if the two files drift.
Sensors that need a special probe sequence (unlock writes, alternate
ID values) are matched by name in sinfo.c's probe loop; those need
a code hook in addition to the table row.
If a chip responds but nothing matches, run the probe with -v:
the I2C devices seen section shows every address that answered
with the distinct register reads observed. To build the new csv line from that you need:
- the sensor model name (board silkscreen, vendor firmware, or the
value pattern - most vendors encode the model in the ID, e.g.
0x46:0x53= gc4653), - which registers are the chip's ID registers and their expected values (the reads in the report are your candidates),
- the register/value byte widths (what the working entries of the same vendor family use is almost always right),
- the MCLK frequency (24000000 unless the vendor driver says otherwise).
Each address appears once; partial reads from other table entries probing the same chip are folded into its register list.
make CROSS_COMPILE=mipsel-linux- # static MIPS binary (-Os)
make test # host tests under ASAN+UBSan
make sensors # regenerate sensors.h from csv
clang-format -i sinfo.c sinfo_hw.c # before committing
The tree splits into sinfo.c (probe/clock/report logic) and
sinfo_hw.c (the hw_* hardware seam: /dev/mem, I2C, sysfs).
tests/mock_hw.c implements the same seam in memory, so the whole
probe path runs host-side; the PLL test vectors are live register
values captured from the validated boards.
imx327's ID registers partially overlapimx307's and false-match on imx307 hardware.imx662expects all-zero ID values, which Sony sensors return for unmapped registers, so it false-matches any idle Sony chip.- The kernel module additionally has an
int8_tsensor-index bug: its/procprimary-sensor line andIOCTL_SINFO_GETare corrupt for any sensor past table index 127 (the whole SmartSens block). This port fixes the index type and carries a regression test.
GPL-2.0, same as the ingenic-sdk sinfo kernel module the sensor
database and probe behavior derive from.