[PATCH v2 0/4] Add QST QMC5883P magnetometer driver

Hardik Phalet
2026-04-09T21:07:26Z

This series adds initial Linux support for the QST QMC5883P, a 3-axis
anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC that
communicates over I2C. To my knowledge there is no existing upstream
driver for this device.

The driver supports:
- Raw magnetic field readings on X, Y, and Z axes
- Four selectable full-scale ranges (±2 G, ±8 G, ±12 G, ±30 G)
- Configurable output data rate (10, 50, 100, 200 Hz)
- Configurable oversampling ratio (1, 2, 4, 8)
- Configurable downsampling ratio (1, 2, 4, 8) via a custom sysfs
attribute
- Runtime PM with a 2 s autosuspend delay
- System suspend/resume via pm_runtime_force_suspend/resume

Regmap with an rbtree cache is used throughout. CTRL_1 and CTRL_2
bit fields are accessed via regmap_field to avoid read-modify-write
races. The STATUS register is marked precious so regmap never reads
it speculatively and clears the DRDY/OVFL bits unexpectedly.

The init sequence on probe is: soft reset → wait 1 ms → deassert
reset → configure SET/RESET control → apply default ODR/OSR/DSR/RNG
→ enter normal mode. This ordering was determined empirically on
hardware to produce reliable, non-zero axis readings.

The driver is placed under drivers/staging/iio/magnetometer/ with a
TODO file tracking the remaining work before it can graduate:
- Triggered buffer support (iio_triggered_buffer_setup)
- DRDY interrupt support
- Self-test implementation

Patches:
1/4 - dt-bindings: vendor-prefixes: Add 'qst' for QST Corporation
2/4 - dt-bindings: iio: magnetometer: Add binding for QST QMC5883P
3/4 - staging: iio: magnetometer: Add QST QMC5883P driver
4/4 - MAINTAINERS: Add entry for QST QMC5883P magnetometer driver

Testing
-------
Tested on a Raspberry Pi 4B running a mainline kernel (aarch64) with a
GY-271 HM-246 board connected via I2C bus 1. The chip was confirmed to
enumerate at address 0x2C via i2cdetect.

The driver was cross-compiled from Fedora (x86_64) targeting aarch64
and loaded as a module (qmc5883p.ko) with the Device Tree overlay
pointing at i2c1:0x2c.

Verification steps performed:
- Chip ID register (0x00) reads back 0x80 on probe, confirming the
correct device is present
- All three axes (in_magn_x_raw, in_magn_y_raw, in_magn_z_raw) return
non-zero, stable values when the board is held still and change
appropriately when the board is rotated
- in_magn_x_scale (and Y, Z) returns the expected fractional value for
the default ±8 G range (1/37500000)
- in_magn_sampling_frequency / _available, in_magn_oversampling_ratio /
_available, and downsampling_ratio / downsampling_ratio_available all
read and write correctly; the chip responds without error to each
valid setting
- Runtime PM: after 2 s of inactivity the device enters suspend mode
(MODE = 0x00 confirmed via i2cdump); the next sysfs read correctly
resumes the device and returns valid data
- System suspend/resume (echo mem > /sys/power/state) leaves the
driver in a consistent state; readings remain valid after resume
- dt_binding_check passes for patch 2/4
- Kernel builds cleanly with W=1 and no new warnings

Changes in v2:
- Use get_unaligned_le16() from <linux/unaligned.h> instead of manual
byte-shifting for deserialising axis data (review feedback)
- Fix pm_runtime_* calls in downsampling_ratio_store() to use
data->dev (the i2c parent device) instead of dev (the iio device),
avoiding PM refcount imbalances (review feedback)
- Replace manual pm_runtime_disable() devm action with
devm_pm_runtime_enable(), which avoids a kcfi-violating function
pointer cast (review feedback)
- Move chip suspend into a devm action (qmc5883p_suspend_action)
registered before devm_iio_device_register() so that devres LIFO
ordering guarantees the IIO interface is fully unregistered before
the hardware is put to sleep, closing a race window on removal
(review feedback)
- Drop qmc5883p_remove() and the .remove hook entirely, as the above
devm action subsumes it (review feedback)
- Remove the empty qmc5883p_runtime_idle() stub; passing NULL in
RUNTIME_PM_OPS already provides the correct default behaviour
- Add regulator support: use devm_regulator_get_enable_optional() for
the vdd-supply documented in the dt-binding, with a 50 ms post-enable
delay per datasheet section 5.3 (PSUP ramp + POR time) (review
feedback)
- Reinitialise the chip in qmc5883p_system_resume() via
qmc5883p_chip_init() followed by regcache_mark_dirty() +
regcache_sync(), so that the driver recovers correctly if the
regulator was physically cut during system suspend and POR reset all
registers (review feedback)

v1: https://lore.kernel.org/all/20260409162308.2590385-1-hardik.phalet@pm.me/

Hardik Phalet (4):
dt-bindings: vendor-prefixes: Add QST Corporation
dt-bindings: iio: magnetometer: Add binding for QST QMC5883P
staging: iio: magnetometer: Add QST QMC5883P driver
MAINTAINERS: Add entry for QST QMC5883P magnetometer driver

.../iio/magnetometer/qst,qmc5883p.yaml | 48 +
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 7 +
drivers/staging/iio/Kconfig | 1 +
drivers/staging/iio/Makefile | 1 +
drivers/staging/iio/magnetometer/Kconfig | 20 +
drivers/staging/iio/magnetometer/Makefile | 7 +
drivers/staging/iio/magnetometer/TODO | 5 +
drivers/staging/iio/magnetometer/qmc5883p.c | 830 ++++++++++++++++++
9 files changed, 921 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/qst,qmc5883p.yaml
create mode 100644 drivers/staging/iio/magnetometer/Kconfig
create mode 100644 drivers/staging/iio/magnetometer/Makefile
create mode 100644 drivers/staging/iio/magnetometer/TODO
create mode 100644 drivers/staging/iio/magnetometer/qmc5883p.c

--
2.53.0