Chip Catalogue
The SDK ships 80 chip drivers under chips/<part>/, described by 84 manifests under metadata/chips/. Each driver is independent, opt-in, and named after the chip's natural manufacturer name (no alp_ prefix — that's reserved for SDK-level abstractions). The four manifests without a driver are declared planned (Murata radio modules that are BOM candidates only) — the manifest/driver parity is CI-enforced, so a manifest can't quietly imply code that doesn't exist.
The Tier-0 drivers (on-module silicon for AEN / V2N / V2N-M1, plus the EVK board-side parts) carry the [ABI-STABLE] annotation and ride the SDK's normal ABI guarantees. The drivers added in the §D ecosystem expansion are marked [ABI-EXPERIMENTAL].
Every chip manifest in the tree declares verification.hil_silicon: untested. There are no exceptions — not the on-module Tier-0 parts, not the drivers with the richest feature coverage. Treat every lifecycle sequence, register value, and timing number in this catalogue as paper-correct until the v1.0 verification sweep lands.
What the drivers do have is host-side smoke coverage: null_arg_guard-style contract tests that prove a driver rejects NULL arguments, refuses calls on an uninitialised context, and bounds-checks its tables. Those are argument-validation contract tests, not simulated bus transactions — they say nothing about whether the part works.
(One nearby claim is genuine but belongs elsewhere: the GD32 bridge's boot-select, dual-bank erase, and background-erase OTA paths are silicon-validated. That's bridge firmware, not the gd32g553 chip driver, which remains partial / untested.)
Driver status vocabulary
Every manifest carries a driver_status: — the single source of truth for how complete a driver is. A CI gate keeps each C header's @par Driver status: label in lockstep with its manifest, so a header can't misreport what's implemented.
| Status | Meaning |
|---|---|
complete | The driver's intended surface is implemented |
partial | A useful subset works; the manifest's inline comment names what's deferred |
stub | Skeleton only — compiles and validates arguments |
planned | Manifest exists, no driver code yet |
Roughly 30 drivers each are complete, partial, and stub, plus the 4 planned. These four words are the whole vocabulary, enforced by scripts/check_chip_header_status.py.
Two honest caveats about that gate: the header status tag is optional (only about 32 of 80 headers carry one — the gate skips the rest), and the JSON schema types driver_status as a free string, so the vocabulary is enforced on headers rather than on the manifests themselves. The status definitions in the table above are this page's editorial reading — the SDK doesn't ship a glossary for them.
Opting in
Two equivalent ways to enable a chip driver:
# board.yaml — recommended
chips:
- lsm6dso
- ssd1306
# prj.conf — manual
CONFIG_ALP_SDK_CHIP_LSM6DSO=y
CONFIG_ALP_SDK_CHIP_SSD1306=y
The board.yaml path is preferred because it lets the loader cross-check that the SoM actually routes the bus the chip needs.
Driver shape
Every driver follows the same shape:
#include <alp/chips/<part>.h>
<part>_t ctx;
<part>_init(&ctx, bus, address_or_handle);
// Per-feature getters / setters
<part>_<op>(&ctx, ...);
_init() ACK-probes the chip on its bus. If the chip isn't populated, _init returns ALP_ERR_NOT_READY; well-written firmware handles this gracefully.
Catalogue (selected)
Sensors
| Driver | Part | Bus | Use |
|---|---|---|---|
lsm6dso | ST LSM6DSO | I²C / SPI | 6-axis IMU |
bmi323 | Bosch BMI323 | I²C / SPI | 6-axis IMU |
icm42670 | TDK ICM-42670 | I²C / SPI | 6-axis IMU |
lis2dw12 | ST LIS2DW12 | I²C / SPI | 3-axis accelerometer |
bmp581 | Bosch BMP581 | I²C | Barometric pressure |
bme280 | Bosch BME280 | I²C | T/RH/pressure |
tmp112 | TI TMP112 | I²C | Temperature (on every Alp Lab SoM) |
ina236 | TI INA236 | I²C | Current / voltage monitor |
Power
| Driver | Part | Notes |
|---|---|---|
act8760 | Qorvo ACT88760-120.E1 | Primary PMIC (V2N family). Datasheet-verified two-slave register map (ADD1: master + Buck1–6; ADD2: Buck7 + LDOs). act8760_rail_get/set_vset() program the VSET0 slot only — DVS slots go via the raw register helpers. |
da9292 | Renesas DA9292 | Secondary PMIC (V2N family). Register map verified against datasheet Rev 2.2. Fault pins (INT / TW) land on Renesas pads, not the GD32 — read them with da9292_get_fault_pins() or register-level via BRD_I2C. |
tps628640 | TI TPS628640 | Optional / DEEPX rail bucks |
pca9451a | NXP PCA9451A | Primary PMIC (i.MX 93 / E1M-NX9101). Probe (ACK-only DEV_ID read), raw register R/W, INT1 latched-interrupt decode, and per-rail enable/voltage on all 6 bucks + 5 LDOs. See the caveat below. |
pca9451a — the E1M-NX9101 board doesn't exist on the bench yetdriver_status: partial. The register map is transcribed from the upstream Linux pca9450-regulator.c (which lists the PCA9451A type), and the driver has never been exercised on real E1M-NX9101 silicon — that board isn't on the bench yet. Every number and sequencing decision is paper-correct only, validated by host-side unit tests against NULL-arg / uninitialised-context / table-bounds properties, not against a real transceiver. Silicon validation is deferred to the NX9101 HiL bring-up.
Clocks + RTC
| Driver | Part | Notes |
|---|---|---|
clk_5l35023b | Renesas / IDT 5L35023B | Clock generator (V2N family) |
rv3028c7 | Micro Crystal RV-3028-C7 | Battery-backed RTC (every Alp Lab SoM) |
Storage + memory
| Driver | Part | Notes |
|---|---|---|
eeprom_24c128 | Onsemi N24S128 | 128-byte SoM manifest EEPROM |
Connectivity
| Driver | Part | Notes |
|---|---|---|
cc3501e | TI CC3501E | Wi-Fi 6 + BLE 5.4 coprocessor (AEN family); SDK-embedded bridge firmware over SPI/SDIO — Wi-Fi/BLE, GPIO proxy, OTA-over-bridge |
murata_lbee5hy2fy | Murata LBEE5HY2FY-922 | Wi-Fi 6 + BLE 5.4 combo (V2N family) |
rtl8211fdi | Realtek RTL8211FDI | Gigabit Ethernet PHY (×2 on V2N) |
murata_lbee0zz2kl | Murata LBEE0ZZ2KL | planned — SDIO radio, BOM candidate, no driver code |
murata_lbee5pl2dl | Murata LBEE5PL2DL | planned — SDIO radio, BOM candidate, no driver code |
murata_lbes0zz2ll | Murata LBES0ZZ2LL | planned — SDIO radio, BOM candidate, no driver code |
murata_lbes5pl2el | Murata LBES5PL2EL | planned — SDIO radio, BOM candidate, no driver code |
Security
| Driver | Part | Notes |
|---|---|---|
optiga_trust_m | Infineon OPTIGA Trust M | Secure element (every Alp Lab SoM). Probe-only — see below. |
optiga_trust_m is scoped to probe-onlyThe driver is deliberately limited to confirming the part is wired correctly. It does: compile, validate its public arguments, and probe the chip by reading the I2C_STATE register.
It does not send OPEN_APPLICATION, or implement product-info (Coprocessor UID) or raw-APDU transport — those entry points are declared so you can compile against the planned surface, but they return ALP_ERR_NOSUPPORT after argument validation. No CalcSign, GenKeyPair, or ECDH. The full APDU transport lands when Infineon's host library is integrated; the probe-only contract is pinned by a test so it can't drift silently.
If you're planning a secure-boot or attestation flow around this part, the crypto operations are not available yet. (Its machine-readable driver_status is partial — "probe-only" is a prose refinement, not a status tier.)
Co-processors + bridges
| Driver | Part | Notes |
|---|---|---|
gd32g553 | GD GD32G553 | V2N supervisor MCU (8 PWM, 8 ADC, 2 DAC, 4 QEnc, 18 GPIO) |
deepx_dxm1 | DEEPX DX-M1 | NPU (V2N-M1 only) — bring_up sequencer |
gd32_swd | bit-bang controller | SWD recovery for the GD32 bridge |
pi3dbs12212 | Diodes PI3DBS12212A | PCIe mux — routes the lanes to the DEEPX NPU or the external slot (V2N-M1); deepx_dxm1_bring_up() drives it |
IO + UI
| Driver | Part | Notes |
|---|---|---|
tcal9538 | NXP TCAL9538 | 8-bit I/O expander — also drives the register-compatible TCA6408A / PCA9538 (see below) |
ssd1306 | Solomon SSD1306 | Monochrome 128×64 OLED |
ssd1331 | Solomon SSD1331 | Small colour OLED |
ov5640 | OmniVision OV5640 | 5 MP MIPI CSI camera |
cam_mux_pi3wvr626 | Diodes PI3WVR626 | Camera input mux — GPIO-driven select shim |
tas2563 | TI TAS2563 | Class-D speaker amplifier |
pdm_mic | PDM microphone helper | Front-end for <alp/audio.h> |
button_led | helper | Composite button + LED widget driver |
tcal9538_init() accepts two strap families: the TCA9538 / TCAL9538 A1A0 range 0x70..0x73 (TCAL9538_I2C_ADDR_BASE), and — as of v0.11.0 — the register-compatible TCA6408A / PCA9538 single-A0 range 0x20..0x21 (TCAL9538_I2C_ADDR_ALT_BASE). The alt part is the E1M EVK's U35 alt-population (TCA6408ARSVR, R112 fitted / R145 DNP); 0x20 is bench-confirmed on the E1M EVK. On the E1M EVK's default population the expander sits on ALP_E1M_I2C0 at 0x72 (A1=1, A0=0). Pass 0 for the address to fall back to TCAL9538_I2C_ADDR_BASE.
The §D ecosystem set
The drivers added under the chip-and-library ecosystem design. Every entry below ships with header + _init/probe + Kconfig + metadata YAML + NULL-arg ZTEST.
The [UNTESTED] markers below mean no HiL silicon bring-up — which, per the warning at the top of this page, is currently true of every driver in the catalogue, not just these. What distinguishes this set is the [ABI-EXPERIMENTAL] annotation: their APIs may still change. Check each driver's driver_status: in metadata/chips/<id>.yaml for how much of its surface is actually implemented — many here are stub.
Camera sensors [UNTESTED]
| Driver | Part | Bus / interface | Notes |
|---|---|---|---|
ov2640 | OmniVision OV2640 | DVP | 2 MP general-purpose |
ov5645 | OmniVision OV5645 | MIPI CSI-2 | 5 MP autofocus |
ov7670 | OmniVision OV7670 | DVP | VGA cost-sensitive |
ov9281 | OmniVision OV9281 | MIPI CSI-2 | 1 MP global-shutter mono |
ar0234 | onsemi AR0234 | MIPI CSI-2 | 1080p global-shutter |
imx219 | Sony IMX219 | MIPI CSI-2 | 8 MP — RPi Cam v2 |
imx477 | Sony IMX477 | MIPI CSI-2 | 12 MP — RPi HQ Camera |
gc2145 | GalaxyCore GC2145 | DVP | 2 MP cost-sensitive |
Camera SerDes [UNTESTED]
| Driver | Part | Standard |
|---|---|---|
ti_ds90ub953_954 | TI DS90UB953 / 954 | FPD-Link III |
maxim_max9295_9296 | Maxim MAX9295 / 9296 | GMSL2 |
Displays [UNTESTED]
| Driver | Part | Notes |
|---|---|---|
st7789 | Sitronix ST7789 | 240×240 / 240×320 SPI TFT |
ili9341 | Ilitek ILI9341 | 240×320 SPI TFT |
ili9488 | Ilitek ILI9488 | 320×480 SPI TFT |
ra8875 | RAiO RA8875 | 5–7″ TFT controller w/ resistive touch |
sh1106 | Sino Wealth SH1106 | 128×64 mono OLED — drop-in alt to SSD1306 |
il3820 | Solomon IL3820 | 4.2″ tri-colour e-paper |
gdew0154t8 | GoodDisplay 1.54″ | 1.54″ e-paper |
External NPU [UNTESTED]
| Driver | Part | Notes |
|---|---|---|
hailo_8l | Hailo-8L | M.2 PCIe NPU — host-side bring-up sequence |
Industrial sensing [UNTESTED]
| Driver | Part | Class |
|---|---|---|
bmp390 | Bosch BMP390 | Barometric pressure |
ms5611 | TE MS5611 | Barometric pressure |
lps22hb | ST LPS22HB | Barometric pressure |
vl53l1x | ST VL53L1X | Time-of-flight distance |
vl53l5cx | ST VL53L5CX | 8×8 ToF array |
a02yyuw | DFRobot A02YYUW | Ultrasonic distance (UART) |
tsl2591 | AMS TSL2591 | Ambient light (2-channel) |
veml7700 | Vishay VEML7700 | Ambient light (16-bit) |
qmc5883l | QST QMC5883L | 3-axis magnetometer |
as5048a_b | AMS AS5048 A/B | Magnetic rotary encoder (I²C) |
mt6701 | MagnTek MT6701 | Magnetic rotary encoder (I²C) |
hx711 | Avia HX711 | 24-bit strain-gauge ADC |
max31855 | Maxim MAX31855 | Thermocouple → signed milli-C |
max31865 | Maxim MAX31865 | RTD (PT100/PT1000) — 15-bit + fault |
Motor / actuator control [UNTESTED]
| Driver | Part | Notes |
|---|---|---|
drv8833 | TI DRV8833 | Dual H-bridge |
drv8825 | TI DRV8825 | Stepper driver (STEP/DIR) |
tmc2209 | Trinamic TMC2209 | Stepper w/ UART tuning (CRC-8) |
a4988 | Allegro A4988 | Stepper driver |
Cellular / RF / GNSS [UNTESTED]
| Driver | Part | Class |
|---|---|---|
quectel_bg95 | Quectel BG95 | LTE-M / NB-IoT modem (AT) |
quectel_bg77 | Quectel BG77 | LTE-M / NB-IoT modem (AT) |
ublox_sara_r5 | u-blox SARA-R5 | LTE-M modem (AT) |
semtech_sx1262 | Semtech SX1262 | LoRa radio (opcode) |
semtech_sx1276 | Semtech SX1276 | LoRa radio (register) |
ublox_neo_m9n | u-blox NEO-M9N | GNSS (UART NMEA) |
ublox_max_m10s | u-blox MAX-M10S | GNSS (UART NMEA) |
atgm336h | Zhongkewei ATGM336H | GNSS (UART NMEA) |
atecc608b | Microchip ATECC608B | Crypto co-processor (ATCA) |
Audio [UNTESTED]
| Driver | Part | Notes |
|---|---|---|
ics_43434 | InvenSense ICS-43434 | MEMS mic (I²S) |
inmp441 | InvenSense INMP441 | MEMS mic (I²S, cost-sensitive) |
wm8960 | Cirrus / Wolfson WM8960 | Stereo codec (I²C config + I²S) |
tlv320aic3204 | TI TLV320AIC3204 | Premium stereo codec w/ miniDSP |
max98357a | ADI MAX98357A | 3W class-D mono amp |
es8388 | Everest ES8388 | Stereo codec (China-domestic) |
Browse the full per-driver metadata under metadata/chips/; each .yaml carries verification: status alongside vendor / MPN / bus / Kconfig binding.
Driver status
Each driver carries a status field in its metadata/chips/<part>.yaml:
| Status | Meaning |
|---|---|
stub | Header exists; calls return ALP_ERR_NOSUPPORT. |
partial | Core operations implemented; some advanced features pending. |
complete | Full feature coverage; HW-verified. |
The current per-driver status is tracked in docs/test-plan.md.
Per-SoM populated chips
Which drivers are populated on each SoM family:
| Driver | AEN | V2N | V2N-M1 | N93 |
|---|---|---|---|---|
cc3501e | ✓ | |||
murata_lbee5hy2fy | ✓ | ✓ | ||
rtl8211fdi | ✓×2 | ✓×2 | ||
gd32g553 | ✓ | ✓ | ||
deepx_dxm1 | ✓ | |||
act8760 / da9292 | ✓ | ✓ | ||
pca9451a | ✓ | |||
rv3028c7 | ✓ | ✓ | ✓ | TBD |
optiga_trust_m | ✓ | ✓ | ✓ | TBD |
eeprom_24c128 | ✓ | ✓ | ✓ | TBD |
tmp112 | ✓ | ✓ | ✓ | TBD |
Each EVK populates its own board-side chip set. The two overlap (e.g. bmp581, bmi323, icm42670, tas2563, ina236, tcal9538) but differ: the E1M EVK carries lsm6dso, the ssd1306 / ssd1331 OLEDs, and an on-board ov5640 + cam_mux, whereas the E1M-X EVK drives MIPI-DSI panels and exposes dedicated CSI camera connectors instead. Declare preset: e1m-evk or e1m-x-evk in board.yaml to pick up that board's set.
Idiomatic usage
#include <alp/peripheral.h>
#include <alp/chips/lsm6dso.h>
alp_i2c_t *bus = alp_i2c_open(&(alp_i2c_config_t){
.bus_id = 0u,
.bitrate_hz = 400000u,
});
lsm6dso_t imu;
if (lsm6dso_init(&imu, bus, LSM6DSO_I2C_ADDR_LOW) != ALP_OK) {
printk("[lsm6dso] init failed\n");
return;
}
/* ODR and full-scale are set together, in one call per sensor. */
if (lsm6dso_set_accel(&imu, LSM6DSO_ODR_104_HZ, LSM6DSO_ACCEL_FS_2G) != ALP_OK) {
printk("[lsm6dso] set_accel rejected\n");
return;
}
lsm6dso_axes_t a;
while (1) {
lsm6dso_read_accel(&imu, &a);
printk("ax=%d ay=%d az=%d\n", a.x, a.y, a.z);
k_msleep(10);
}
The address is strap-selected: LSM6DSO_I2C_ADDR_LOW is 0x6A (SDO/SA0 tied low), LSM6DSO_I2C_ADDR_HIGH is 0x6B. Gyro is symmetric — lsm6dso_set_gyro() + lsm6dso_read_gyro() into the same lsm6dso_axes_t; lsm6dso_read_temp() yields a raw int16_t.
bmi323_set_accel / _set_gyro, icm42670_set_accel / _set_gyro, lsm6dso_set_accel / _set_gyro and lis2dw12_set_accel now return ALP_ERR_INVAL when an ODR or full-scale argument is not a declared enum member, and they validate before any bus write.
Previously these masked the argument straight into the register field: where an enum's declared members didn't fill that field, an undeclared value was written to the chip as a reserved hardware encoding and the call still returned ALP_OK. If you passed a computed or cast value rather than a named enumerator, a call that used to "succeed" may now correctly fail — check the return.
icm42670_odr_t is sparse (it declares 0x0, 0x4..0x8, 0xA..0xF), so the reserved encodings inside its range are rejected too. Enums whose declared values already fill their register field (icm42670 / lsm6dso / lis2dw12 full-scale, tmp112_rate_t) are unchanged, as are a4988 / drv8825 / lis2dw12_mode_t, which already validated.