Re: [PATCH 3/3] iio: magnetometer: st_magn: honour st,fullscale-mg DT property
From: Andy Shevchenko
Date: Fri Jun 05 2026 - 13:59:01 EST
On Fri, Jun 05, 2026 at 12:08:43PM +0200, Herman van Hazendonk wrote:
> The ST magnetometer core's common probe hardcodes fs_avl[0] -- the
> highest-sensitivity full-scale supported by the chip -- as the
> starting range. For the LSM303DLH that is +/-1.3 G; for the
> LSM303DLHC and LSM303DLM it is +/-2 G; for the LIS3MDL it is +/-4 G.
>
> That is the right default for "minimal noise floor at a desk", but
> it leaves no margin for boards that pick up appreciable DC bias from
> nearby PCB structures. On the HP TouchPad (apq8060 / tenderloin) the
> LSM303DLH magnetometer is mounted close enough to the surrounding
> power planes that X reads back as the chip's 0xF000 overflow
> sentinel (== -4096 raw, the value the chip publishes when the ADC
> saturates) on every sample at the chip-default range, while Y and Z
> fall well within the +/-1.3 G window.
>
> Parse the st,fullscale-mg device-tree property (documented separately
> in dt-bindings/iio/st,st-sensors.yaml) in the magnetometer common
> probe to select the initial fs_avl entry by its mg value. The driver
> tolerates an unknown / unsupported value by falling back to the chip
> default and warning, so the property is purely additive -- existing
> in-tree DTSes are unaffected.
>
> Per-sensor mg ranges are listed in st_magn_sensors_settings[]. For
> LSM303DLH the valid values are 1300, 1900, 2500, 4000, 4700, 5600
> and 8100; for LSM303DLHC they are 1300, 1900, 2500, 4000, 4700, 5600,
> 8100 (same code path); for LIS3MDL they are 4000, 8000, 12000, 16000;
> and so on. Sensors with a fixed full-scale (fs.addr == 0) simply
> ignore the property.
>
> Empirical scale sweep on the HP TouchPad confirmed that on this
> board any fs_avl >= 1 produces non-saturated X readings:
>
> scale (0.001 G/LSB) | X raw Y raw Z raw
> --------------------+-------------------------------
> 1.100 | -4096 44 46 (X saturated)
> 0.855 | -547 37 37 (clean)
> 0.670 | -433 94 103 (clean)
> 0.450 | -266 44 71 (clean)
> 0.400 | -235 34 65 (clean)
> 0.330 | -196 27 56 (clean)
> 0.230 | -145 15 40 (clean)
>
> 2500 mg is the natural choice for tenderloin: comfortably outside
> the saturation regime while keeping useful precision for compass
> applications.
...
> + {
Oh, no. Use
const char *propname;
...
propname = "st,fullscale-mg";
if (device_property_present(..., propname)) {
struct st_sensor_fullscale *fs = &mdata->sensor_settings->fs;
u32 fs_mg;
ret = device_property_read_u32(parent, propname, &fs_mg);
if (ret)
return ret;
...
}
instead.
> + u32 fs_mg;
> + if (!device_property_read_u32(parent, "st,fullscale-mg",
> + &fs_mg)) {
> + struct st_sensor_fullscale *fs =
> + &mdata->sensor_settings->fs;
> + int i;
> +
> + for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
> + if (!fs->fs_avl[i].num)
> + break;
This is strange. What's the point to go via the whole table? Does it have gaps?
> + if (fs->fs_avl[i].num == fs_mg) {
> + mdata->current_fullscale =
> + &fs->fs_avl[i];
> + break;
> + }
> + }
> + if (mdata->current_fullscale->num != fs_mg)
> + dev_warn(parent,
> + "st,fullscale-mg=%u not supported, using %u\n",
Also use %s and propname.
> + fs_mg, mdata->current_fullscale->num);
> + }
> + }
--
With Best Regards,
Andy Shevchenko