[PATCH v3 0/5] iio: magnetometer: add driver for QST QMC5883P

Hardik Phalet posted 5 patches 1 month, 3 weeks ago
.../iio/magnetometer/qstcorp,qmc5883p.yaml         |  48 ++
.../devicetree/bindings/vendor-prefixes.yaml       |   2 +
MAINTAINERS                                        |   7 +
drivers/iio/magnetometer/Kconfig                   |  11 +
drivers/iio/magnetometer/Makefile                  |   2 +
drivers/iio/magnetometer/qmc5883p.c                | 673 +++++++++++++++++++++
6 files changed, 743 insertions(+)
[PATCH v3 0/5] iio: magnetometer: add driver for QST QMC5883P
Posted by Hardik Phalet 1 month, 3 weeks ago
This series adds an IIO driver for the QST QMC5883P, a 3-axis
anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC,
communicating over I2C. To my knowledge there is no existing
upstream driver for this device (see "Prior-art register-map check"
below).

The driver supports:
  - Raw magnetic field readings on X, Y and Z axes
  - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G),
    selectable via IIO_CHAN_INFO_SCALE
  - Four output data rates (10, 50, 100, 200 Hz), selectable via
    IIO_CHAN_INFO_SAMP_FREQ
  - Four oversampling ratios (1, 2, 4, 8), selectable via
    IIO_CHAN_INFO_OVERSAMPLING_RATIO
  - Runtime PM with a 2 s autosuspend delay
  - System suspend/resume delegated to the runtime callbacks

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 probe-time init sequence is: soft reset, wait 300 us for POR
to complete, deassert reset, drop the register cache so subsequent
RMW writes read fresh values, then enter normal mode. 300 us
comfortably covers the 250 us POR time given in the datasheet.

Patches:
  1/5 - dt-bindings: vendor-prefixes: Add QST Corporation
  2/5 - dt-bindings: iio: magnetometer: QSTCORP QMC5883P
  3/5 - iio: magnetometer: add driver for QST QMC5883P
  4/5 - iio: magnetometer: qmc5883p: add oversampling ratio support
  5/5 - iio: magnetometer: qmc5883p: add PM support

Patches 4 and 5 are split out from the main driver so that the core
(1-3) can be reviewed and picked independently, per review feedback
on v2. 4/5 exposes the CTRL_1 OSR field via
IIO_CHAN_INFO_OVERSAMPLING_RATIO. 5/5 adds runtime PM that puts the
chip into MODE_SUSPEND when idle and wakes it to MODE_NORMAL on
demand.

Changes in v3
=============
Addressing review feedback on v2:

  - Moved the driver out of staging and into drivers/iio/magnetometer/
    (Greg Kroah-Hartman).

  - Changed the vendor prefix from "qst" to "qstcorp" to match the
    manufacturer's domain (qstcorp.com) (Krzysztof Kozlowski).

  - Subject of the binding patch no longer says "Add binding for";
    "dt-bindings:" already conveys that (Krzysztof Kozlowski).

  - Dropped the redundant last sentence of the binding commit message
    (Krzysztof Kozlowski).

  - VDD supply is now made required (Krzysztof Kozlowski).

  - Split runtime PM + system sleep handling out of the core driver
    patch into its own patch (5/5), so the core driver can be reviewed
    independently (David Lechner).

  - Split oversampling-ratio support out into its own patch (4/5)
    (David Lechner).

  - Dropped the custom downsampling_ratio sysfs attribute entirely.
    The datasheet describes OSR2 only as "another filter ... depth can
    be adjusted through OSR2", with no further characterisation, and
    no application note clarifying it. Without a precise definition
    of what the filter actually does it is not possible to map OSR2
    to any existing IIO ABI, so support for it is dropped from this
    series (David Lechner).

  - qmc5883p_verify_chip_id() -> qmc5883p_read_chip_id() no longer
    treats an ID mismatch as a probe failure; the chip-ID check is
    informational only (David Lechner).

  - qmc5883p_chip_init() no longer programs driver-chosen defaults
    for RNG/OSR/DSR/ODR. The hardware defaults are sufficient and the
    explicit writes were a development artifact (David Lechner).

  - Post-reset delay in qmc5883p_chip_init() uses fsleep() with a
    comment citing the 250 us POR time from the datasheet
    (David Lechner).

  - Timeout in regmap_read_poll_timeout() written as
    150 * (MICRO / MILLI) instead of 150000 (David Lechner).

  - Channel spec duplication collapsed behind a QMC5883P_CHAN(ch)
    macro (David Lechner).

  - qmc5883p_rf_init() moved up in probe, before the regulator and
    chip-ID reads, so the regmap fields are available by the time
    they are needed (David Lechner).

  - Trailing comma and extra whitespace in the of_device_id and
    i2c_device_id sentinel entries cleaned up (David Lechner).

  - Verified that there is no existing driver in drivers/iio/,
    drivers/hwmon/, drivers/input/, drivers/staging/iio/ or
    drivers/misc/ that matches the QMC5883P register map. Summary
    of candidates inspected is included in the "Testing" section
    below (Andy Shevchenko).

  - Waited ~10 days before sending v3 to allow time for review
    (Andy Shevchenko).

Additional v3 changes not directly from review:

  - Scale encoding changed from IIO_VAL_FRACTIONAL to
    IIO_VAL_INT_PLUS_NANO with a matching write_raw_get_fmt(),
    because the IIO core defaults sysfs writes to
    IIO_VAL_INT_PLUS_MICRO and was silently truncating nano-precision
    writes. The truncation on the 8 G and 2 G entries is documented
    in a comment above the scale table.

  - STATUS register marked precious (in addition to volatile) so
    regmap never reads it speculatively and clears DRDY/OVFL.

  - Added regcache_drop_region() after the soft-reset deassert, so
    subsequent RMW writes read fresh values rather than cached
    pre-reset values.

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).

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

Testing
=======
Hardware
  A GY-271 HM-246 breakout (this board is a QMC5883P, not a QMC5883L,
  despite what some vendors put on the silkscreen), connected over
  I2C bus 1 to a Raspberry Pi 4B running a mainline aarch64 kernel.
  The chip enumerates at address 0x2C via i2cdetect, and CHIP_ID
  (register 0x00) reads back 0x80 as expected.

Prior-art register-map check (for Andy)
  I grepped drivers/iio/magnetometer/, drivers/hwmon/,
  drivers/input/misc/, drivers/staging/iio/ and drivers/misc/ for
  the distinctive offsets 0x09 (STATUS) and 0x0A (CTRL_1), narrowed
  to files containing both, and manually compared each candidate's
  register layout and control-bit encoding against the QMC5883P.

  Closest candidates:
    ak8975.c    - four register offsets coincide (0x00, 0x09, 0x0A,
                  0x0B) but the data registers sit at 0x03-0x08
                  (shifted +2 vs QMC5883P's 0x01-0x06), DRDY is in
                  ST1 at 0x02 rather than STATUS at 0x09, and CNTL
                  encodes a 4-bit mode only - no packed ODR/OSR/range
                  fields.
    hmc5843.c   - STATUS matches at 0x09, but 0x0A is a read-only ID
                  register, configuration spans 0x00-0x02 rather than
                  a single CTRL_1 byte, and data is MSB-first at 0x03
                  in X/Z/Y order.
    af8133j.c   - 0x0A and 0x0B carry mode and range, but STATUS is
                  at 0x02, data starts at 0x03, and the mode field is
                  2-valued (standby/work) rather than 4-valued.
    mmc35240.c  - data at 0x00-0x05 overlaps, but STATUS and control
                  land at 0x06-0x08.

  No overlap worth discussing: mmc5633, mag3110, tlv493d, tmag5273,
  bmc150_magn, rm3100, yamaha-yas530, st_magn, si7210, als31300. No
  magnetometer driver under drivers/hwmon/, drivers/input/misc/ or
  drivers/staging/.

  Conclusion: no existing driver can be extended to cover the
  QMC5883P without restructuring its register addressing and
  control-bit model. A new driver is warranted.

Functional testing on v3
  - Chip ID read: 0x80 (matches datasheet).
  - Raw axis reads: in_magn_{x,y,z}_raw return stable s16 values
    and track manual reorientation of the board.
  - Scale: all four ranges (+/-2/8/12/30 G) selectable via
    in_magn_scale; in_magn_scale_available lists all four; sysfs
    write-back round-trips cleanly at nano precision.
  - Sampling frequency: 10/50/100/200 Hz all selectable via
    in_magn_sampling_frequency; _available lists all four.
  - Oversampling ratio (patch 4): 1/2/4/8 selectable via
    in_magn_oversampling_ratio; _available lists all four.
  - DRDY polling: verified STATUS.DRDY asserts and clears on read,
    and that OVFL is captured in the same read as DRDY.
  - Soft reset: register state after qmc5883p_chip_init() matches
    the datasheet defaults; regcache_drop_region() confirmed by
    observing fresh values being read on the first post-reset RMW.
  - Runtime PM (patch 5): power/runtime_status transitions to
    "suspended" after the 2 s autosuspend delay (MODE_SUSPEND on
    the wire, verified by i2cdump); next sysfs read resumes the
    device and returns valid data.
  - System sleep: echo mem > /sys/power/state (s2idle on the Pi)
    followed by wake; readings are valid after resume.
  - Unbind: echo <dev> > /sys/bus/i2c/drivers/qmc5883p/unbind
    leaves the chip in MODE_SUSPEND, confirming the devm LIFO
    teardown order.
  - Build: CONFIG_QMC5883P=y and =m both clean; W=1 clean on
    aarch64; sparse clean; checkpatch --strict clean.
  - dt_binding_check: passes for patch 2/5.

Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
Hardik Phalet (5):
      dt-bindings: vendor-prefixes: Add QST Corporation
      dt-bindings: iio: magnetometer: QSTCORP QMC5883P
      iio: magnetometer: add driver for QST QMC5883P
      iio: magnetometer: qmc5883p: add oversampling ratio support
      iio: magnetometer: qmc5883p: add PM support

 .../iio/magnetometer/qstcorp,qmc5883p.yaml         |  48 ++
 .../devicetree/bindings/vendor-prefixes.yaml       |   2 +
 MAINTAINERS                                        |   7 +
 drivers/iio/magnetometer/Kconfig                   |  11 +
 drivers/iio/magnetometer/Makefile                  |   2 +
 drivers/iio/magnetometer/qmc5883p.c                | 673 +++++++++++++++++++++
 6 files changed, 743 insertions(+)
---
base-commit: d2a4ec19d2a2e54c23b5180e939994d3da4a6b91
change-id: 20260418-qmc5883p-driver-dcc74bd4a789

Best regards,
--  
Hardik Phalet <hardik.phalet@pm.me>
Re: [PATCH v3 0/5] iio: magnetometer: add driver for QST QMC5883P
Posted by Jonathan Cameron 1 month, 3 weeks ago
On Sun, 19 Apr 2026 22:32:09 +0000
Hardik Phalet <hardik.phalet@pm.me> wrote:

> This series adds an IIO driver for the QST QMC5883P, a 3-axis
> anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC,
> communicating over I2C. To my knowledge there is no existing
> upstream driver for this device (see "Prior-art register-map check"
> below).
> 
> The driver supports:
>   - Raw magnetic field readings on X, Y and Z axes
>   - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G),
>     selectable via IIO_CHAN_INFO_SCALE
>   - Four output data rates (10, 50, 100, 200 Hz), selectable via
>     IIO_CHAN_INFO_SAMP_FREQ
>   - Four oversampling ratios (1, 2, 4, 8), selectable via
>     IIO_CHAN_INFO_OVERSAMPLING_RATIO

I'm suspicious about this one based on a very quick read of the datasheet.
Conventional oversampling would involve running the internal sampling
engine at a multiple of the sampling frequency, and then averaging the
results.  The datasheet describes this as:
"Over sample Rate (OSR1) registers are used to control bandwidth of an
 internal digital filter. Larger OSR value leads to smaller filter bandwidth,
 less in-band noise and higher power consumption. It could be used to reach a
 good balance between noise and power. Four over sample ratios can be selected,
 8,4,2 or 1."

That sounds like a boxcar filter to me not oversampling (which would be
a combination of box car and reducing the output data rate).

If possible, can you enable the data ready output and put a scope on it
to see if that changes frequency when OSR or OSR2 are modified.

Trickier to do would be looking at the noise levels whilst playing with
these filters and see if they at least match with standard filter types.

If we can't figure these out, then it may be a case of picking something
that works well and hard coding that rather than letting userspace
change things in a fashion that might not match the ABI.

>   - Runtime PM with a 2 s autosuspend delay
>   - System suspend/resume delegated to the runtime callbacks
Re: [PATCH v3 0/5] iio: magnetometer: add driver for QST QMC5883P
Posted by Hardik Phalet 4 weeks, 1 day ago
On Mon Apr 20, 2026 at 7:15 PM IST, Jonathan Cameron wrote:
> On Sun, 19 Apr 2026 22:32:09 +0000
> Hardik Phalet <hardik.phalet@pm.me> wrote:
>
>> This series adds an IIO driver for the QST QMC5883P, a 3-axis
>> anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC,
>> communicating over I2C. To my knowledge there is no existing
>> upstream driver for this device (see "Prior-art register-map check"
>> below).
>>
>> The driver supports:
>>   - Raw magnetic field readings on X, Y and Z axes
>>   - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G),
>>     selectable via IIO_CHAN_INFO_SCALE
>>   - Four output data rates (10, 50, 100, 200 Hz), selectable via
>>     IIO_CHAN_INFO_SAMP_FREQ
>>   - Four oversampling ratios (1, 2, 4, 8), selectable via
>>     IIO_CHAN_INFO_OVERSAMPLING_RATIO
>
> I'm suspicious about this one based on a very quick read of the datasheet.
> Conventional oversampling would involve running the internal sampling
> engine at a multiple of the sampling frequency, and then averaging the
> results.  The datasheet describes this as:
> "Over sample Rate (OSR1) registers are used to control bandwidth of an
>  internal digital filter. Larger OSR value leads to smaller filter bandwidth,
>  less in-band noise and higher power consumption. It could be used to reach a
>  good balance between noise and power. Four over sample ratios can be selected,
>  8,4,2 or 1."
>
> That sounds like a boxcar filter to me not oversampling (which would be
> a combination of box car and reducing the output data rate).
>
> If possible, can you enable the data ready output and put a scope on it
> to see if that changes frequency when OSR or OSR2 are modified.
>
> Trickier to do would be looking at the noise levels whilst playing with
> these filters and see if they at least match with standard filter types.
>
> If we can't figure these out, then it may be a case of picking something
> that works well and hard coding that rather than letting userspace
> change things in a fashion that might not match the ABI.

I could not arrange a oscilloscope. So wrote a small standalone tool that drives
the chip directly over /dev/i2c-N (skipping the driver) on a Pi 4 and
characterised all three fields in CTRL_1 with timing + noise measurements.
Summary:

  Field    Bits     Role per measurement
  ODR      [3:2]    output rate, accurate to ~3% of nominal in Normal Mode
  OSR1     [5:4]    low-pass filter (bandwidth control), no rate change
  OSR2     [7:6]    N-sample averaging, no rate change (real oversampling)

1. DRDY interval vs each field (median of 500 samples per setting,
   ms; SCHED_FIFO, pinned CPU):

   vary ODR (OSR1=1, OSR2=1):
     ODR=10 Hz  -> 100.9 ms       ODR=100 Hz -> 10.30 ms
     ODR=50 Hz  ->  20.5 ms       ODR=200 Hz ->  5.14 ms

   vary OSR1 (ODR=200 Hz, OSR2=1):
     OSR1=1 -> 5.142 ms           OSR1=4 -> 5.139 ms
     OSR1=2 -> 5.143 ms           OSR1=8 -> 5.141 ms

   vary OSR2 (ODR=200 Hz, OSR1=1):
     OSR2=1 -> 5.142 ms           OSR2=4 -> 5.142 ms
     OSR2=2 -> 5.140 ms           OSR2=8 -> 5.141 ms

   ODR is the only knob that changes the rate.

2. Per-axis noise stddev (2000 samples, sensor still, ratios vs N=1):

   vary OSR1:                   vary OSR2:
     OSR1=1 -> 1.000              OSR2=1 -> 1.000
     OSR1=2 -> 0.723              OSR2=2 -> 0.706
     OSR1=4 -> 0.544              OSR2=4 -> 0.494
     OSR1=8 -> 0.416              OSR2=8 -> 0.333

   Reference for N-sample averaging (1/sqrt(N)):
     1.000 / 0.707 / 0.500 / 0.354

   OSR2 matches within measurement noise; OSR1 trails the curve,
   which is the expected signature of a bandwidth-limiting filter
   on non-white input noise.

So to my understanding, OSR2 is true oversampling. OSR1 is a filter.

v4 plan, pending your input on (c):

  (a) Add an OSR2 regmap_field and expose it as
      IIO_CHAN_INFO_OVERSAMPLING_RATIO with values {1, 2, 4, 8}.
  (b) Drop the OVERSAMPLING_RATIO mapping on OSR1.
  (c) For OSR1, two options:
        i)  expose as IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY.
            The public datasheet does not give cutoff frequencies,
            so I'd have to either characterise them empirically and
            document them in the driver, or use placeholder values
            derived from the OSR1 setting alone (which feels wrong).
        ii) hard-code OSR1=1 in chip_init and not expose it. Loses
            the noise-vs-bandwidth tradeoff but keeps the ABI clean.
      Slight preference for (ii) unless you'd rather see the filter
      knob exposed.
  (d) Keep ODR mapped to IIO_CHAN_INFO_SAMP_FREQ as in v3.

One other finding worth mentioning: the datasheet's setup examples
(sec 7.1, 7.2, 7.3) all write 0x06 to register 0x29 before entering
an active mode, with the comment "Define the sign for X Y and Z axis".
This register is not listed in the documented register map but the
write is required for axes Y and Z to come out with the documented
orientation. v4 will add this write to chip_init().

If you have other measurements you'd like to see before v4, happy to
run them.

>
>>   - Runtime PM with a 2 s autosuspend delay
>>   - System suspend/resume delegated to the runtime callbacks

Best regards,
Hardik
Re: [PATCH v3 0/5] iio: magnetometer: add driver for QST QMC5883P
Posted by David Lechner 4 weeks, 1 day ago
On 5/17/26 2:17 PM, Hardik Phalet wrote:
> On Mon Apr 20, 2026 at 7:15 PM IST, Jonathan Cameron wrote:
>> On Sun, 19 Apr 2026 22:32:09 +0000
>> Hardik Phalet <hardik.phalet@pm.me> wrote:
>>
>>> This series adds an IIO driver for the QST QMC5883P, a 3-axis
>>> anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC,
>>> communicating over I2C. To my knowledge there is no existing
>>> upstream driver for this device (see "Prior-art register-map check"
>>> below).
>>>
>>> The driver supports:
>>>   - Raw magnetic field readings on X, Y and Z axes
>>>   - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G),
>>>     selectable via IIO_CHAN_INFO_SCALE
>>>   - Four output data rates (10, 50, 100, 200 Hz), selectable via
>>>     IIO_CHAN_INFO_SAMP_FREQ
>>>   - Four oversampling ratios (1, 2, 4, 8), selectable via
>>>     IIO_CHAN_INFO_OVERSAMPLING_RATIO
>>
>> I'm suspicious about this one based on a very quick read of the datasheet.
>> Conventional oversampling would involve running the internal sampling
>> engine at a multiple of the sampling frequency, and then averaging the
>> results.  The datasheet describes this as:
>> "Over sample Rate (OSR1) registers are used to control bandwidth of an
>>  internal digital filter. Larger OSR value leads to smaller filter bandwidth,
>>  less in-band noise and higher power consumption. It could be used to reach a
>>  good balance between noise and power. Four over sample ratios can be selected,
>>  8,4,2 or 1."
>>
>> That sounds like a boxcar filter to me not oversampling (which would be
>> a combination of box car and reducing the output data rate).
>>
>> If possible, can you enable the data ready output and put a scope on it
>> to see if that changes frequency when OSR or OSR2 are modified.
>>
>> Trickier to do would be looking at the noise levels whilst playing with
>> these filters and see if they at least match with standard filter types.
>>
>> If we can't figure these out, then it may be a case of picking something
>> that works well and hard coding that rather than letting userspace
>> change things in a fashion that might not match the ABI.
> 
> I could not arrange a oscilloscope. So wrote a small standalone tool that drives
> the chip directly over /dev/i2c-N (skipping the driver) on a Pi 4 and
> characterised all three fields in CTRL_1 with timing + noise measurements.
> Summary:
> 
>   Field    Bits     Role per measurement
>   ODR      [3:2]    output rate, accurate to ~3% of nominal in Normal Mode
>   OSR1     [5:4]    low-pass filter (bandwidth control), no rate change
>   OSR2     [7:6]    N-sample averaging, no rate change (real oversampling)
> 
> 1. DRDY interval vs each field (median of 500 samples per setting,
>    ms; SCHED_FIFO, pinned CPU):
> 
>    vary ODR (OSR1=1, OSR2=1):
>      ODR=10 Hz  -> 100.9 ms       ODR=100 Hz -> 10.30 ms
>      ODR=50 Hz  ->  20.5 ms       ODR=200 Hz ->  5.14 ms
> 
>    vary OSR1 (ODR=200 Hz, OSR2=1):
>      OSR1=1 -> 5.142 ms           OSR1=4 -> 5.139 ms
>      OSR1=2 -> 5.143 ms           OSR1=8 -> 5.141 ms
> 
>    vary OSR2 (ODR=200 Hz, OSR1=1):
>      OSR2=1 -> 5.142 ms           OSR2=4 -> 5.142 ms
>      OSR2=2 -> 5.140 ms           OSR2=8 -> 5.141 ms
> 
>    ODR is the only knob that changes the rate.
> 
> 2. Per-axis noise stddev (2000 samples, sensor still, ratios vs N=1):
> 
>    vary OSR1:                   vary OSR2:
>      OSR1=1 -> 1.000              OSR2=1 -> 1.000
>      OSR1=2 -> 0.723              OSR2=2 -> 0.706
>      OSR1=4 -> 0.544              OSR2=4 -> 0.494
>      OSR1=8 -> 0.416              OSR2=8 -> 0.333
> 
>    Reference for N-sample averaging (1/sqrt(N)):
>      1.000 / 0.707 / 0.500 / 0.354
> 
>    OSR2 matches within measurement noise; OSR1 trails the curve,
>    which is the expected signature of a bandwidth-limiting filter
>    on non-white input noise.
> 
> So to my understanding, OSR2 is true oversampling. OSR1 is a filter.

The datasheet says that power consumption changes based on OSR1,
so that makes me think that OSR1 is really oversampling since it
would take more energy to do more conversions in the same amount
of time. (Note 1 on table 2.1)

Another chip by the same mfg that looks like it has the same OSR1/
OSR2 has a bit more info in the same table [1]. It looks like OSR2
affects the sensitivity (and calls OSR2 a low pass filter instead
of "down sampling rate").

[1] https://www.qstcorp.com/upload/pdf/202601/CF382A94E1424763B3DE87DC967757FC.pdf

> 
> v4 plan, pending your input on (c):
> 
>   (a) Add an OSR2 regmap_field and expose it as
>       IIO_CHAN_INFO_OVERSAMPLING_RATIO with values {1, 2, 4, 8}.
>   (b) Drop the OVERSAMPLING_RATIO mapping on OSR1.
>   (c) For OSR1, two options:
>         i)  expose as IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY.
>             The public datasheet does not give cutoff frequencies,
>             so I'd have to either characterise them empirically and
>             document them in the driver, or use placeholder values
>             derived from the OSR1 setting alone (which feels wrong).
>         ii) hard-code OSR1=1 in chip_init and not expose it. Loses
>             the noise-vs-bandwidth tradeoff but keeps the ABI clean.
>       Slight preference for (ii) unless you'd rather see the filter
>       knob exposed.

It sounds like we already figured out that OSR2 is just a moving average
so might as well implement IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY.

>   (d) Keep ODR mapped to IIO_CHAN_INFO_SAMP_FREQ as in v3.
> 
> One other finding worth mentioning: the datasheet's setup examples
> (sec 7.1, 7.2, 7.3) all write 0x06 to register 0x29 before entering
> an active mode, with the comment "Define the sign for X Y and Z axis".
> This register is not listed in the documented register map but the
> write is required for axes Y and Z to come out with the documented
> orientation. v4 will add this write to chip_init().
> 
> If you have other measurements you'd like to see before v4, happy to
> run them.
> 
>>
>>>   - Runtime PM with a 2 s autosuspend delay
>>>   - System suspend/resume delegated to the runtime callbacks
> 
> Best regards,
> Hardik
Re: [PATCH v3 0/5] iio: magnetometer: add driver for QST QMC5883P
Posted by Jonathan Cameron 4 weeks ago
On Sun, 17 May 2026 15:28:22 -0500
David Lechner <dlechner@baylibre.com> wrote:

> On 5/17/26 2:17 PM, Hardik Phalet wrote:
> > On Mon Apr 20, 2026 at 7:15 PM IST, Jonathan Cameron wrote:  
> >> On Sun, 19 Apr 2026 22:32:09 +0000
> >> Hardik Phalet <hardik.phalet@pm.me> wrote:
> >>  
> >>> This series adds an IIO driver for the QST QMC5883P, a 3-axis
> >>> anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC,
> >>> communicating over I2C. To my knowledge there is no existing
> >>> upstream driver for this device (see "Prior-art register-map check"
> >>> below).
> >>>
> >>> The driver supports:
> >>>   - Raw magnetic field readings on X, Y and Z axes
> >>>   - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G),
> >>>     selectable via IIO_CHAN_INFO_SCALE
> >>>   - Four output data rates (10, 50, 100, 200 Hz), selectable via
> >>>     IIO_CHAN_INFO_SAMP_FREQ
> >>>   - Four oversampling ratios (1, 2, 4, 8), selectable via
> >>>     IIO_CHAN_INFO_OVERSAMPLING_RATIO  
> >>
> >> I'm suspicious about this one based on a very quick read of the datasheet.
> >> Conventional oversampling would involve running the internal sampling
> >> engine at a multiple of the sampling frequency, and then averaging the
> >> results.  The datasheet describes this as:
> >> "Over sample Rate (OSR1) registers are used to control bandwidth of an
> >>  internal digital filter. Larger OSR value leads to smaller filter bandwidth,
> >>  less in-band noise and higher power consumption. It could be used to reach a
> >>  good balance between noise and power. Four over sample ratios can be selected,
> >>  8,4,2 or 1."
> >>
> >> That sounds like a boxcar filter to me not oversampling (which would be
> >> a combination of box car and reducing the output data rate).
> >>
> >> If possible, can you enable the data ready output and put a scope on it
> >> to see if that changes frequency when OSR or OSR2 are modified.
> >>
> >> Trickier to do would be looking at the noise levels whilst playing with
> >> these filters and see if they at least match with standard filter types.
> >>
> >> If we can't figure these out, then it may be a case of picking something
> >> that works well and hard coding that rather than letting userspace
> >> change things in a fashion that might not match the ABI.  
> > 
> > I could not arrange a oscilloscope. So wrote a small standalone tool that drives
> > the chip directly over /dev/i2c-N (skipping the driver) on a Pi 4 and
> > characterised all three fields in CTRL_1 with timing + noise measurements.
> > Summary:
> > 
> >   Field    Bits     Role per measurement
> >   ODR      [3:2]    output rate, accurate to ~3% of nominal in Normal Mode
> >   OSR1     [5:4]    low-pass filter (bandwidth control), no rate change
> >   OSR2     [7:6]    N-sample averaging, no rate change (real oversampling)
> > 
> > 1. DRDY interval vs each field (median of 500 samples per setting,
> >    ms; SCHED_FIFO, pinned CPU):
> > 
> >    vary ODR (OSR1=1, OSR2=1):
> >      ODR=10 Hz  -> 100.9 ms       ODR=100 Hz -> 10.30 ms
> >      ODR=50 Hz  ->  20.5 ms       ODR=200 Hz ->  5.14 ms
> > 
> >    vary OSR1 (ODR=200 Hz, OSR2=1):
> >      OSR1=1 -> 5.142 ms           OSR1=4 -> 5.139 ms
> >      OSR1=2 -> 5.143 ms           OSR1=8 -> 5.141 ms
> > 
> >    vary OSR2 (ODR=200 Hz, OSR1=1):
> >      OSR2=1 -> 5.142 ms           OSR2=4 -> 5.142 ms
> >      OSR2=2 -> 5.140 ms           OSR2=8 -> 5.141 ms
> > 
> >    ODR is the only knob that changes the rate.
> > 
> > 2. Per-axis noise stddev (2000 samples, sensor still, ratios vs N=1):
> > 
> >    vary OSR1:                   vary OSR2:
> >      OSR1=1 -> 1.000              OSR2=1 -> 1.000
> >      OSR1=2 -> 0.723              OSR2=2 -> 0.706
> >      OSR1=4 -> 0.544              OSR2=4 -> 0.494
> >      OSR1=8 -> 0.416              OSR2=8 -> 0.333
> > 
> >    Reference for N-sample averaging (1/sqrt(N)):
> >      1.000 / 0.707 / 0.500 / 0.354
> > 
> >    OSR2 matches within measurement noise; OSR1 trails the curve,
> >    which is the expected signature of a bandwidth-limiting filter
> >    on non-white input noise.

Nice data.

> > 
> > So to my understanding, OSR2 is true oversampling. OSR1 is a filter. 

Oversampling might also be tied to an integration period which would
reduce as oversampling goes up, somewhat undoing the noise improvements.
So it might be worse than an averaging.  Without introducing
some dynamic motion it's going to be hard to figure this out. Maybe stick
the thing on a pendulum or if you happen to have one a record deck?
(assuming you can wire it!)
Anything to be able to repeat something that will vary the signal.
That should let you separate box car across a fixed sampling rate
from oversampling.
 
> 
> The datasheet says that power consumption changes based on OSR1,
> so that makes me think that OSR1 is really oversampling since it
> would take more energy to do more conversions in the same amount
> of time. (Note 1 on table 2.1)
Is it possible it's a sampling / resampling ADC or similar so the
actual resolution is dropping? That saves some power.  Mind you
puttting that in a place called OSR1 would be odd ;)

Or as you suggest it's actually triggering burst conversion and averaging.
So datarate fixed but actual sampling time is much lower so it can
do lots of samples without the effective sampling rate changing.
> 
> Another chip by the same mfg that looks like it has the same OSR1/
> OSR2 has a bit more info in the same table [1]. It looks like OSR2
> affects the sensitivity (and calls OSR2 a low pass filter instead
> of "down sampling rate").
> 
> [1] https://www.qstcorp.com/upload/pdf/202601/CF382A94E1424763B3DE87DC967757FC.pdf

Ah ok. Good detective work.  Though it would be far from the first datasheet
to confuse oversampling with straight forward filtering.
> 
> > 
> > v4 plan, pending your input on (c):
> > 
> >   (a) Add an OSR2 regmap_field and expose it as
> >       IIO_CHAN_INFO_OVERSAMPLING_RATIO with values {1, 2, 4, 8}.
> >   (b) Drop the OVERSAMPLING_RATIO mapping on OSR1.
> >   (c) For OSR1, two options:
> >         i)  expose as IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY.
> >             The public datasheet does not give cutoff frequencies,
> >             so I'd have to either characterise them empirically and
> >             document them in the driver, or use placeholder values
> >             derived from the OSR1 setting alone (which feels wrong).
> >         ii) hard-code OSR1=1 in chip_init and not expose it. Loses
> >             the noise-vs-bandwidth tradeoff but keeps the ABI clean.
> >       Slight preference for (ii) unless you'd rather see the filter
> >       knob exposed.  
> 
> It sounds like we already figured out that OSR2 is just a moving average
> so might as well implement IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY.

Maybe... We might have to just go for best guess and document it clearly.

Jonathan

> 
> >   (d) Keep ODR mapped to IIO_CHAN_INFO_SAMP_FREQ as in v3.
> > 
> > One other finding worth mentioning: the datasheet's setup examples
> > (sec 7.1, 7.2, 7.3) all write 0x06 to register 0x29 before entering
> > an active mode, with the comment "Define the sign for X Y and Z axis".
> > This register is not listed in the documented register map but the
> > write is required for axes Y and Z to come out with the documented
> > orientation. v4 will add this write to chip_init().
> > 
> > If you have other measurements you'd like to see before v4, happy to
> > run them.
> >   
> >>  
> >>>   - Runtime PM with a 2 s autosuspend delay
> >>>   - System suspend/resume delegated to the runtime callbacks  
> > 
> > Best regards,
> > Hardik  
> 
>
Re: [PATCH v3 0/5] iio: magnetometer: add driver for QST QMC5883P
Posted by Andy Shevchenko 1 month, 3 weeks ago
On Sun, Apr 19, 2026 at 10:32:09PM +0000, Hardik Phalet wrote:
> This series adds an IIO driver for the QST QMC5883P, a 3-axis
> anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC,
> communicating over I2C. To my knowledge there is no existing
> upstream driver for this device (see "Prior-art register-map check"
> below).
> 
> The driver supports:
>   - Raw magnetic field readings on X, Y and Z axes
>   - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G),
>     selectable via IIO_CHAN_INFO_SCALE
>   - Four output data rates (10, 50, 100, 200 Hz), selectable via
>     IIO_CHAN_INFO_SAMP_FREQ
>   - Four oversampling ratios (1, 2, 4, 8), selectable via
>     IIO_CHAN_INFO_OVERSAMPLING_RATIO
>   - Runtime PM with a 2 s autosuspend delay
>   - System suspend/resume delegated to the runtime callbacks
> 
> Regmap with an rbtree cache is used throughout. CTRL_1 and CTRL_2

I'm not sure this paragraph answers the question "why not maple tree?"

> 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 probe-time init sequence is: soft reset, wait 300 us for POR
> to complete, deassert reset, drop the register cache so subsequent
> RMW writes read fresh values, then enter normal mode. 300 us
> comfortably covers the 250 us POR time given in the datasheet.
> 
> Patches:
>   1/5 - dt-bindings: vendor-prefixes: Add QST Corporation
>   2/5 - dt-bindings: iio: magnetometer: QSTCORP QMC5883P
>   3/5 - iio: magnetometer: add driver for QST QMC5883P
>   4/5 - iio: magnetometer: qmc5883p: add oversampling ratio support
>   5/5 - iio: magnetometer: qmc5883p: add PM support
> 
> Patches 4 and 5 are split out from the main driver so that the core
> (1-3) can be reviewed and picked independently, per review feedback
> on v2. 4/5 exposes the CTRL_1 OSR field via
> IIO_CHAN_INFO_OVERSAMPLING_RATIO. 5/5 adds runtime PM that puts the
> chip into MODE_SUSPEND when idle and wakes it to MODE_NORMAL on
> demand.

-- 
With Best Regards,
Andy Shevchenko