* (no subject)
@ 2026-06-27 0:58 Nikhil Gautam
2026-06-27 0:58 ` [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 Nikhil Gautam
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Nikhil Gautam @ 2026-06-27 0:58 UTC (permalink / raw)
To: linux-iio
Cc: jic23, dlechner, nuno.sa, andy, u.kleine-koenig, robh, krzk+dt,
conor+dt, devicetree, linux-kernel, Nikhil Gautam
Subject: [PATCH v3 0/2] iio: magnetometer: add support for Melexis MLX90393
Hi,
This series adds initial Industrial I/O subsystem support for the
Melexis MLX90393 3-axis magnetometer and temperature sensor.
The MLX90393 supports both I2C and SPI interfaces. This series
implements support for the I2C interface while keeping the driver
structure transport-independent to simplify future SPI support.
The device uses a command-based communication protocol rather than a
conventional register-addressed interface. A small transport abstraction
layer is therefore used instead of regmap to share the common sensor
logic between the current I2C implementation and future SPI support.
Currently supported features:
* Raw magnetic field measurements for X/Y/Z axes
* Raw temperature measurements
* Configurable gain/scale selection
* Configurable oversampling ratio
* Direct mode operation through the IIO subsystem
* I2C interface support
The driver has been tested on Raspberry Pi 5 hardware using an
MLX90393 sensor connected over I2C. Magnetic field and temperature
measurements were verified through the IIO sysfs interface.
Datasheet:
https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90393
Previous submission:
Link: https://lore.kernel.org/linux-iio/20260510191010.155380-1-nikhilgtr@gmail.com/
Changes in v3:
[DT]
* Made vdd-supply and vddio-supply required properties.
* Moved the MAINTAINERS entry to the correct alphabetical position.
[IIO]
* Added the publicly available MLX90393 datasheet reference.
* Clarified the motivation for introducing a dedicated MLX90393 driver.
* Added the I2C device ID table and switched to designated initializers.
* Added a forward declaration for struct device to reduce unnecessary
header dependencies.
* Added symbol namespaces.
* Improved include usage.
* Improved status validation and consistency of conditional checks.
* Added comments documenting protocol encoding, initialization delays,
and temperature conversion constants derived from the datasheet.
* Improved naming, formatting, indentation and general coding style.
* Addressed all review comments from Andy Shevchenko,
Uwe Kleine-König and Krzysztof Kozlowski.
Changes in v2:
[DT]
* Extended the DT binding to document power supply regulators and
optional interrupt and trigger GPIOs.
[IIO]
* Removed the RFC tag based on reviewer feedback.
* Added a MAINTAINERS entry as part of the initial submission and
expanded it in the driver patch.
* Reworked the scale availability implementation to simplify the
data layout and eliminate the need for constructing a temporary
table, avoiding potential race conditions.
* Replaced usleep_range() with fsleep() where appropriate and
documented initialization delays.
* Simplified helper functions and improved error handling by
returning directly where appropriate.
* Reduced unnecessary local variables and line wrapping to improve
readability and align with kernel coding style.
* Added comments for lock protection and command definitions to
improve code clarity.
* Switched to devm_mutex_init() and cleaned up include usage in
accordance with the "include what you use" principle.
* Improved consistency across the driver, including conditional
handling, switch statements, formatting and general code style.
* Addressed all review comments from Jonathan Cameron.
Many thanks to Jonathan Cameron, Andy Shevchenko,
Uwe Kleine-König and Krzysztof Kozlowski for their detailed reviews
and valuable feedback, which significantly improved this series.
Further review and comments are greatly appreciated.
Thanks,
Nikhil Gautam
Nikhil Gautam (2):
dt-bindings: iio: magnetometer: add Melexis MLX90393
iio: magnetometer: add support for Melexis MLX90393
.../iio/magnetometer/melexis,mlx90393.yaml | 54 ++
MAINTAINERS | 7 +
drivers/iio/magnetometer/Kconfig | 10 +
drivers/iio/magnetometer/Makefile | 2 +
drivers/iio/magnetometer/mlx90393.h | 73 ++
drivers/iio/magnetometer/mlx90393_core.c | 701 ++++++++++++++++++
drivers/iio/magnetometer/mlx90393_i2c.c | 76 ++
7 files changed, 923 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml
create mode 100644 drivers/iio/magnetometer/mlx90393.h
create mode 100644 drivers/iio/magnetometer/mlx90393_core.c
create mode 100644 drivers/iio/magnetometer/mlx90393_i2c.c
--
2.39.5
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 2026-06-27 0:58 Nikhil Gautam @ 2026-06-27 0:58 ` Nikhil Gautam 2026-06-27 1:04 ` sashiko-bot ` (2 more replies) 2026-06-27 0:58 ` [PATCH v3 2/2] iio: magnetometer: add support for " Nikhil Gautam 2026-06-27 18:30 ` [PATCH v3 0/2] " David Lechner 2 siblings, 3 replies; 8+ messages in thread From: Nikhil Gautam @ 2026-06-27 0:58 UTC (permalink / raw) To: linux-iio Cc: jic23, dlechner, nuno.sa, andy, u.kleine-koenig, robh, krzk+dt, conor+dt, devicetree, linux-kernel, Nikhil Gautam Add devicetree bindings for the Melexis MLX90393 3-axis magnetometer and temperature sensor. The device supports magnetic field and temperature measurements over I2C and SPI interfaces. This initial binding documents the I2C interface. Signed-off-by: Nikhil Gautam <nikhilgtr@gmail.com> --- .../iio/magnetometer/melexis,mlx90393.yaml | 54 +++++++++++++++++++ MAINTAINERS | 6 +++ 2 files changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml diff --git a/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml b/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml new file mode 100644 index 000000000000..33ab0be66345 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/magnetometer/melexis,mlx90393.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Melexis MLX90393 magnetometer sensor + +maintainers: + - Nikhil Gautam <nikhilgtr@gmail.com> + +description: + Melexis MLX90393 3-axis magnetometer and temperature sensor. + +properties: + compatible: + const: melexis,mlx90393 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + trigger-gpios: + maxItems: 1 + +required: + - compatible + - reg + - vdd-supply + - vddio-supply + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + magnetometer@c { + compatible = "melexis,mlx90393"; + reg = <0x0c>; + + interrupt-parent = <&gpio>; + interrupts = <17 IRQ_TYPE_EDGE_RISING>; + + trigger-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index a92290fffa16..469ae3f9aa0f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15501,6 +15501,12 @@ F: Documentation/scsi/megaraid.rst F: drivers/scsi/megaraid.* F: drivers/scsi/megaraid/ +MELEXIS MLX90393 MAGNETOMETER DRIVER +M: Nikhil Gautam <nikhilgtr@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml + MELEXIS MLX90614 DRIVER M: Crt Mori <cmo@melexis.com> L: linux-iio@vger.kernel.org -- 2.39.5 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 2026-06-27 0:58 ` [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 Nikhil Gautam @ 2026-06-27 1:04 ` sashiko-bot 2026-06-27 2:26 ` Rob Herring (Arm) 2026-06-27 18:41 ` David Lechner 2 siblings, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-06-27 1:04 UTC (permalink / raw) To: Nikhil Gautam; +Cc: devicetree, robh, conor+dt Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] The required properties `vdd-supply` and `vddio-supply` are omitted from the `properties:` block and missing from the `examples:` node, causing schema validation failures. -- commit c1fe5f8c39a4b8113c50e154a6674ac296637f70 Author: Nikhil Gautam <nikhilgtr@gmail.com> dt-bindings: iio: magnetometer: add Melexis MLX90393 Add devicetree bindings for the Melexis MLX90393 3-axis magnetometer and temperature sensor. > diff --git a/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml b/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml > new file mode 100644 > index 0000000000000..33ab0be663450 > --- /dev/null > +++ b/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml [ ... ] > +properties: > + compatible: > + const: melexis,mlx90393 > + > + reg: > + maxItems: 1 > + > + interrupts: > + maxItems: 1 > + > + trigger-gpios: > + maxItems: 1 > + > +required: > + - compatible > + - reg > + - vdd-supply > + - vddio-supply > + > +additionalProperties: false [Severity: Low] Will this binding fail schema validation when running dt_binding_check? The vdd-supply and vddio-supply properties are listed as required, but they are not defined in the properties block. Because additionalProperties is set to false, wouldn't the schema reject these supply properties during validation? > +examples: > + - | > + #include <dt-bindings/gpio/gpio.h> > + #include <dt-bindings/interrupt-controller/irq.h> > + > + i2c { > + #address-cells = <1>; > + #size-cells = <0>; > + > + magnetometer@c { > + compatible = "melexis,mlx90393"; > + reg = <0x0c>; > + > + interrupt-parent = <&gpio>; > + interrupts = <17 IRQ_TYPE_EDGE_RISING>; > + > + trigger-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; > + }; > + }; [Severity: Low] Does this example node need to include the vdd-supply and vddio-supply properties to pass validation, since they are marked as required above? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260627005843.7786-1-nikhilgtr@gmail.com?part=1 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 2026-06-27 0:58 ` [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 Nikhil Gautam 2026-06-27 1:04 ` sashiko-bot @ 2026-06-27 2:26 ` Rob Herring (Arm) 2026-06-27 18:41 ` David Lechner 2 siblings, 0 replies; 8+ messages in thread From: Rob Herring (Arm) @ 2026-06-27 2:26 UTC (permalink / raw) To: Nikhil Gautam Cc: jic23, krzk+dt, nuno.sa, linux-iio, devicetree, dlechner, linux-kernel, u.kleine-koenig, conor+dt, andy On Sat, 27 Jun 2026 06:28:42 +0530, Nikhil Gautam wrote: > Add devicetree bindings for the Melexis MLX90393 > 3-axis magnetometer and temperature sensor. > > The device supports magnetic field and temperature > measurements over I2C and SPI interfaces. > > This initial binding documents the I2C interface. > > Signed-off-by: Nikhil Gautam <nikhilgtr@gmail.com> > --- > .../iio/magnetometer/melexis,mlx90393.yaml | 54 +++++++++++++++++++ > MAINTAINERS | 6 +++ > 2 files changed, 60 insertions(+) > create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: dtschema/dtc warnings/errors: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.example.dtb: magnetometer@c (melexis,mlx90393): 'vdd-supply' is a required property from schema $id: http://devicetree.org/schemas/iio/magnetometer/melexis,mlx90393.yaml /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.example.dtb: magnetometer@c (melexis,mlx90393): 'vddio-supply' is a required property from schema $id: http://devicetree.org/schemas/iio/magnetometer/melexis,mlx90393.yaml doc reference errors (make refcheckdocs): See https://patchwork.kernel.org/project/devicetree/patch/20260627005843.7786-2-nikhilgtr@gmail.com The base for the series is generally the latest rc1. A different dependency should be noted in *this* patch. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit after running the above command yourself. Note that DT_SCHEMA_FILES can be set to your schema file to speed up checking your schema. However, it must be unset to test all examples with your schema. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 2026-06-27 0:58 ` [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 Nikhil Gautam 2026-06-27 1:04 ` sashiko-bot 2026-06-27 2:26 ` Rob Herring (Arm) @ 2026-06-27 18:41 ` David Lechner 2 siblings, 0 replies; 8+ messages in thread From: David Lechner @ 2026-06-27 18:41 UTC (permalink / raw) To: Nikhil Gautam, linux-iio Cc: jic23, nuno.sa, andy, u.kleine-koenig, robh, krzk+dt, conor+dt, devicetree, linux-kernel On 6/26/26 7:58 PM, Nikhil Gautam wrote: > Add devicetree bindings for the Melexis MLX90393 > 3-axis magnetometer and temperature sensor. > > The device supports magnetic field and temperature > measurements over I2C and SPI interfaces. > > This initial binding documents the I2C interface. > > Signed-off-by: Nikhil Gautam <nikhilgtr@gmail.com> > --- > .../iio/magnetometer/melexis,mlx90393.yaml | 54 +++++++++++++++++++ > MAINTAINERS | 6 +++ > 2 files changed, 60 insertions(+) > create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml > > diff --git a/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml b/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml > new file mode 100644 > index 000000000000..33ab0be66345 > --- /dev/null > +++ b/Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml > @@ -0,0 +1,54 @@ > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/iio/magnetometer/melexis,mlx90393.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: Melexis MLX90393 magnetometer sensor > + > +maintainers: > + - Nikhil Gautam <nikhilgtr@gmail.com> > + > +description: > + Melexis MLX90393 3-axis magnetometer and temperature sensor. > + > +properties: > + compatible: > + const: melexis,mlx90393 > + > + reg: > + maxItems: 1 > + > + interrupts: > + maxItems: 1 > + > + trigger-gpios: > + maxItems: 1 > + > +required: > + - compatible > + - reg > + - vdd-supply > + - vddio-supply The supplies are required but are missing from the properties and the example. Running `make dt_binding_check` before sending would have caught this. See: https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html > + > +additionalProperties: false > + > +examples: > + - | > + #include <dt-bindings/gpio/gpio.h> > + #include <dt-bindings/interrupt-controller/irq.h> > + > + i2c { > + #address-cells = <1>; > + #size-cells = <0>; > + > + magnetometer@c { > + compatible = "melexis,mlx90393"; > + reg = <0x0c>; > + > + interrupt-parent = <&gpio>; > + interrupts = <17 IRQ_TYPE_EDGE_RISING>; > + > + trigger-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; > + }; > + }; > diff --git a/MAINTAINERS b/MAINTAINERS > index a92290fffa16..469ae3f9aa0f 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -15501,6 +15501,12 @@ F: Documentation/scsi/megaraid.rst > F: drivers/scsi/megaraid.* > F: drivers/scsi/megaraid/ > > +MELEXIS MLX90393 MAGNETOMETER DRIVER > +M: Nikhil Gautam <nikhilgtr@gmail.com> > +L: linux-iio@vger.kernel.org > +S: Maintained > +F: Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml > + > MELEXIS MLX90614 DRIVER > M: Crt Mori <cmo@melexis.com> > L: linux-iio@vger.kernel.org ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 2/2] iio: magnetometer: add support for Melexis MLX90393 2026-06-27 0:58 Nikhil Gautam 2026-06-27 0:58 ` [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 Nikhil Gautam @ 2026-06-27 0:58 ` Nikhil Gautam 2026-06-27 1:10 ` sashiko-bot 2026-06-27 18:30 ` [PATCH v3 0/2] " David Lechner 2 siblings, 1 reply; 8+ messages in thread From: Nikhil Gautam @ 2026-06-27 0:58 UTC (permalink / raw) To: linux-iio Cc: jic23, dlechner, nuno.sa, andy, u.kleine-koenig, robh, krzk+dt, conor+dt, devicetree, linux-kernel, Nikhil Gautam Add Industrial I/O subsystem support for the Melexis MLX90393 3-axis magnetometer and temperature sensor. The driver currently supports: raw magnetic field measurements raw temperature measurements configurable gain/scale selection configurable oversampling ratio direct mode operation The MLX90393 supports both I2C and SPI interfaces. This initial implementation adds support for the I2C interface. The device uses a command-based communication protocol rather than a conventional register-addressed interface. A small transport abstraction layer is therefore used instead of regmap to share the common sensor logic between the current I2C implementation and future SPI support without duplicating code. Signed-off-by: Nikhil Gautam <nikhilgtr@gmail.com> --- MAINTAINERS | 1 + drivers/iio/magnetometer/Kconfig | 10 + drivers/iio/magnetometer/Makefile | 2 + drivers/iio/magnetometer/mlx90393.h | 73 +++ drivers/iio/magnetometer/mlx90393_core.c | 701 +++++++++++++++++++++++ drivers/iio/magnetometer/mlx90393_i2c.c | 76 +++ 6 files changed, 863 insertions(+) create mode 100644 drivers/iio/magnetometer/mlx90393.h create mode 100644 drivers/iio/magnetometer/mlx90393_core.c create mode 100644 drivers/iio/magnetometer/mlx90393_i2c.c diff --git a/MAINTAINERS b/MAINTAINERS index 469ae3f9aa0f..177dda261801 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15506,6 +15506,7 @@ M: Nikhil Gautam <nikhilgtr@gmail.com> L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml +F: drivers/iio/magnetometer/mlx90393* MELEXIS MLX90614 DRIVER M: Crt Mori <cmo@melexis.com> diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 3debf1320ad1..e6b74e7e3317 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -128,6 +128,16 @@ config HID_SENSOR_MAGNETOMETER_3D Say yes here to build support for the HID SENSOR Magnetometer 3D. +config MLX90393 + tristate "MELEXIS MLX90393 3-axis magnetometer sensor" + depends on I2C + help + Say yes here to build support for the MELEXIS MLX90393 3-axis + magnetometer. + + To compile this driver as a module, choose M here: the module + will be called mlx90393. + config MMC35240 tristate "MEMSIC MMC35240 3-axis magnetic sensor" select REGMAP_I2C diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 9297723a97d8..542c89d38a59 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -14,6 +14,8 @@ obj-$(CONFIG_BMC150_MAGN_SPI) += bmc150_magn_spi.o obj-$(CONFIG_MAG3110) += mag3110.o obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o +obj-$(CONFIG_MLX90393) += mlx90393_core.o +obj-$(CONFIG_MLX90393) += mlx90393_i2c.o obj-$(CONFIG_MMC35240) += mmc35240.o obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o diff --git a/drivers/iio/magnetometer/mlx90393.h b/drivers/iio/magnetometer/mlx90393.h new file mode 100644 index 000000000000..6a646ac05198 --- /dev/null +++ b/drivers/iio/magnetometer/mlx90393.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * MLX90393 magnetometer & temperature sensor driver + * + * Copyright (c) 2026 Nikhil Gautam <nikhilgtr@gmail.com> + */ + +#ifndef MLX90393_H +#define MLX90393_H + +#include <linux/bits.h> +#include <linux/types.h> + +#define MLX90393_AXIS_MAX 2 +#define MLX90393_GAIN_MAX 8 +#define MLX90393_RES_MAX 4 +#define MLX90393_OSR2_MAX 4 +#define MLX90393_OSR_MAX 4 + +#define MLX90393_CMD_MASK GENMASK(7, 4) + +/* Commands (datasheet, Table 11 - Command List) */ +#define MLX90393_CMD_SB 0x10 /* Start Burst Mode */ +#define MLX90393_CMD_SW 0x20 /* Start Wake-up on Change Mode */ +#define MLX90393_CMD_SM 0x30 /* Start Single Measurement Mode */ +#define MLX90393_CMD_RM 0x40 /* Read Measurement */ +#define MLX90393_CMD_RR 0x50 /* Read Register */ +#define MLX90393_CMD_WR 0x60 /* Write Register */ +#define MLX90393_CMD_EX 0x80 /* Exit Mode */ +#define MLX90393_CMD_HR 0xD0 /* Memory Recall */ +#define MLX90393_CMD_HS 0xE0 /* Memory Store */ +#define MLX90393_CMD_RT 0xF0 /* Reset Device */ + +#define MLX90393_MEASURE_Z BIT(0) +#define MLX90393_MEASURE_Y BIT(1) +#define MLX90393_MEASURE_X BIT(2) +#define MLX90393_MEASURE_TEMP BIT(3) + +#define MLX90393_MEASURE_ALL (MLX90393_MEASURE_TEMP | \ + MLX90393_MEASURE_X | MLX90393_MEASURE_Y | MLX90393_MEASURE_Z) + +#define MLX90393_NUM_CHANNELS 4 + +#define MLX90393_STATUS_RESP GENMASK(1, 0) +#define MLX90393_STATUS_RT BIT(2) +#define MLX90393_STATUS_ERROR BIT(4) + +#define MLX90393_REG_CONF1 0x00 +#define MLX90393_REG_CONF2 0x01 +#define MLX90393_REG_CONF3 0x02 +#define MLX90393_REG_CONF4 0x03 + +#define MLX90393_CONF1_GAIN_SEL GENMASK(6, 4) +#define MLX90393_CONF1_HALLCONF GENMASK(3, 0) + +#define MLX90393_CONF3_OSR GENMASK(1, 0) +#define MLX90393_CONF3_DIG_FILT GENMASK(4, 2) +#define MLX90393_CONF3_RES_X GENMASK(6, 5) +#define MLX90393_CONF3_RES_Y GENMASK(8, 7) +#define MLX90393_CONF3_RES_Z GENMASK(10, 9) +#define MLX90393_CONF3_OSR2 GENMASK(12, 11) + +struct device; + +struct mlx90393_transfer_ops { + int (*xfer)(void *context, const u8 *tx, int tx_len, u8 *rx, int rx_len); +}; + +int mlx90393_core_probe(struct device *dev, + const struct mlx90393_transfer_ops *ops, + void *context); + +#endif diff --git a/drivers/iio/magnetometer/mlx90393_core.c b/drivers/iio/magnetometer/mlx90393_core.c new file mode 100644 index 000000000000..78fcab8a2b56 --- /dev/null +++ b/drivers/iio/magnetometer/mlx90393_core.c @@ -0,0 +1,701 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MLX90393 magnetometer & temperature sensor driver + * + * Copyright (c) 2026 Nikhil Gautam <nikhilgtr@gmail.com> + * + * Datasheet: https://media.melexis.com/-/media/files/documents/datasheets/mlx90393-datasheet-melexis.pdf + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/time64.h> +#include <linux/unaligned.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> + +#include "mlx90393.h" + +struct mlx90393_data { + /* Protects sensor configuration and measurement operations */ + struct mutex lock; + struct device *dev; + void *bus_context; + const struct mlx90393_transfer_ops *ops; + u8 gain_sel; + u8 hallconf; + + u8 res_xy; + u8 res_z; + + u8 dig_filt; + u8 osr; + u8 osr2; +}; + +enum mlx90393_channels { + MLX90393_CHAN_X, + MLX90393_CHAN_Y, + MLX90393_CHAN_Z, + MLX90393_CHAN_TEMP, +}; + +enum mlx90393_axis_type { + MLX90393_AXIS_TYPE_XY, + MLX90393_AXIS_TYPE_Z, +}; + +/* Datasheet: Table no.17 */ +static const int mlx90393_scale_table[MLX90393_AXIS_MAX][MLX90393_GAIN_MAX] + [MLX90393_RES_MAX] = { + /* XY axis */ + { + { 751, 1502, 3004, 6009}, + { 601, 1202, 2403, 4840}, + { 451, 901, 1803, 3605}, + { 376, 751, 1502, 3004}, + { 300, 601, 1202, 2403}, + { 250, 501, 1001, 2003}, + { 200, 401, 801, 1602}, + { 150, 300, 601, 1202}, + }, + /* Z axis */ + { + { 1210, 2420, 4840, 9680}, + { 968, 1936, 3872, 7744}, + { 726, 1452, 2904, 5808}, + { 605, 1210, 2420, 4840}, + { 484, 968, 1936, 3872}, + { 403, 807, 1613, 3227}, + { 323, 645, 1291, 2581}, + { 242, 484, 968, 1936}, + } +}; + +static const int mlx90393_osr2_avail[MLX90393_OSR2_MAX] = { + 0, 1, 2, 3, +}; + +static const int mlx90393_osr_avail[MLX90393_OSR_MAX] = { + 1, 2, 4, 8, +}; + +#define MLX90393_CHAN(idx, axis, addr) { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel = idx, \ + .address = addr, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),\ + .info_mask_separate_available = \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ +} + +static const struct iio_chan_spec mlx90393_channels[] = { + MLX90393_CHAN(0, X, MLX90393_CHAN_X), + MLX90393_CHAN(1, Y, MLX90393_CHAN_Y), + MLX90393_CHAN(2, Z, MLX90393_CHAN_Z), + { + .type = IIO_TEMP, + .address = MLX90393_CHAN_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +/* + * Calculate total conversion time in microseconds. + * + * Formula derived from datasheet timing equations. + * Datasheet: Table 8, Page no. 12 + * + * Abbreviations: + * TCONVM -> Single Magnetic axis conversion time + * TCONVT -> Temperature conversion time + * TSTBY -> Time from IDLE to STANDBY + * TACTIVE -> Time from STBY to ACTIVE + * TCONV_END -> Time to end analog active mode + */ +static int mlx90393_get_tconv_us(struct mlx90393_data *data) +{ + const int osr = data->osr; + const int osr2 = data->osr2; + const int df = data->dig_filt; + + int tconvm; + int tconvt; + + int m = 3; /* X,Y,Z */ + + /* + * TCONVM = 67 + 64 * 2^OSR * (2 + 2^DIG_FILT) + */ + tconvm = 67 + (64 * BIT(osr) * (2 + BIT(df))); + + /* + * TCONVT = 67 + 192 * 2^OSR2 + */ + tconvt = 67 + (192 * BIT(osr2)); + /* + * Total conversion time: + * TSTBY + TACTIVE + m * TCONVM + TCONVT + TCONV_END + */ + return 220 + 360 + (m * tconvm) + tconvt + 120; +} + +static int mlx90393_xfer(struct mlx90393_data *data, + const u8 *tx, int tx_len, + u8 *rx, int rx_len) +{ + return data->ops->xfer(data->bus_context, tx, tx_len, rx, rx_len); +} + +static int mlx90393_check_status(u8 cmd, u8 status) +{ + /* Datasheet: Table 12: Status byte definition */ + + /* Always validate error bit */ + if (status & MLX90393_STATUS_ERROR) + return -EIO; + + switch (cmd & MLX90393_CMD_MASK) { + case MLX90393_CMD_RM: + /* + * D1:D0 indicates response availability + * 00 means invalid/no measurement + */ + if ((status & MLX90393_STATUS_RESP) == 0) + return -EIO; + return 0; + case MLX90393_CMD_RT: + /* Reset acknowledge */ + if ((status & MLX90393_STATUS_RT) == 0) + return -EIO; + return 0; + default: + return 0; + } +} + +static int mlx90393_write_cmd(struct mlx90393_data *data, u8 cmd) +{ + u8 status; + int ret; + + ret = mlx90393_xfer(data, &cmd, 1, &status, 1); + if (ret) + return ret; + + return mlx90393_check_status(cmd, status); +} + +static int mlx90393_read_cmd(struct mlx90393_data *data, u8 cmd, u8 *rx, + int rx_len) +{ + int ret; + + ret = mlx90393_xfer(data, &cmd, 1, rx, rx_len); + if (ret) + return ret; + + return mlx90393_check_status(cmd, rx[0]); +} + +static int mlx90393_read_reg(struct mlx90393_data *data, u8 reg, u16 *val) +{ + u8 tx[2]; + u8 rx[3]; + int ret; + + tx[0] = MLX90393_CMD_RR; + /* Register address is encoded in bits [7:2] */ + tx[1] = reg << 2; + + ret = mlx90393_xfer(data, tx, sizeof(tx), rx, sizeof(rx)); + if (ret) + return ret; + + ret = mlx90393_check_status(tx[0], rx[0]); + if (ret) + return ret; + + *val = get_unaligned_be16(&rx[1]); + + return 0; +} + +static int mlx90393_write_reg(struct mlx90393_data *data, u8 reg, u16 val) +{ + u8 tx[4]; + u8 status; + int ret; + + tx[0] = MLX90393_CMD_WR; + put_unaligned_be16(val, &tx[1]); + /* Register address is encoded in bits [7:2] */ + tx[3] = reg << 2; + + ret = mlx90393_xfer(data, tx, sizeof(tx), &status, 1); + if (ret) + return ret; + + return mlx90393_check_status(tx[0], status); +} + +static int mlx90393_update_bits(struct mlx90393_data *data, u8 reg, + u16 mask, u16 val) +{ + u16 reg_val; + int ret; + + ret = mlx90393_read_reg(data, reg, ®_val); + if (ret) + return ret; + + reg_val &= ~mask; + reg_val |= (val << __ffs(mask)) & mask; + + return mlx90393_write_reg(data, reg, reg_val); +} + +static int mlx90393_read_measurement(struct mlx90393_data *data, + enum mlx90393_channels chan, int *val) +{ + u8 rx[9]; + int ret; + + /* Start measurement */ + ret = mlx90393_write_cmd(data, MLX90393_CMD_SM | MLX90393_MEASURE_ALL); + if (ret) + return ret; + + /* Wait conversion */ + fsleep(mlx90393_get_tconv_us(data)); + + /* Read measurement */ + ret = mlx90393_read_cmd(data, MLX90393_CMD_RM | MLX90393_MEASURE_ALL, + rx, sizeof(rx)); + if (ret) + return ret; + /* + * Measurement response layout: + * [status][temp][x][y][z] + */ + + switch (chan) { + case MLX90393_CHAN_TEMP: + *val = get_unaligned_be16(&rx[1]); + return 0; + + case MLX90393_CHAN_X: + *val = sign_extend32(get_unaligned_be16(&rx[3]), 15); + return 0; + + case MLX90393_CHAN_Y: + *val = sign_extend32(get_unaligned_be16(&rx[5]), 15); + return 0; + + case MLX90393_CHAN_Z: + *val = sign_extend32(get_unaligned_be16(&rx[7]), 15); + return 0; + + default: + return -EINVAL; + } +} + +static int mlx90393_get_scale(struct mlx90393_data *data, + const struct iio_chan_spec *chan, + int *val, int *val2) +{ + enum mlx90393_axis_type axis; + u8 res; + + if (chan->channel2 == IIO_MOD_Z) { + axis = MLX90393_AXIS_TYPE_Z; + res = data->res_z; + } else { + axis = MLX90393_AXIS_TYPE_XY; + res = data->res_xy; + } + + *val = 0; + *val2 = mlx90393_scale_table[axis][data->gain_sel][res]; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int mlx90393_find_scale(struct mlx90393_data *data, bool z_axis, + int val, int val2, + int *gain) +{ + u8 res; + enum mlx90393_axis_type axis; + + if (z_axis) { + axis = MLX90393_AXIS_TYPE_Z; + res = data->res_z; + } else { + axis = MLX90393_AXIS_TYPE_XY; + res = data->res_xy; + } + + if (val != 0) + return -EINVAL; + + for (unsigned int i = 0; i < ARRAY_SIZE(mlx90393_scale_table[0]); i++) { + if (mlx90393_scale_table[axis][i][res] == val2) { + *gain = i; + return 0; + } + } + + return -EINVAL; +} + +static int mlx90393_set_scale(struct mlx90393_data *data, + const struct iio_chan_spec *chan, + int val, int val2) +{ + bool z_axis; + int gain; + int ret; + + z_axis = chan->channel2 == IIO_MOD_Z; + + ret = mlx90393_find_scale(data, z_axis, val, val2, &gain); + if (ret) + return ret; + + ret = mlx90393_update_bits(data, MLX90393_REG_CONF1, MLX90393_CONF1_GAIN_SEL, + gain); + if (ret) + return ret; + + data->gain_sel = gain; + return 0; +} + +static int mlx90393_get_osr(struct mlx90393_data *data, int *val) +{ + *val = mlx90393_osr_avail[data->osr]; + return IIO_VAL_INT; +} + +static int mlx90393_find_osr(int val, int *osr) +{ + for (unsigned int i = 0; i < MLX90393_OSR_MAX; i++) { + if (mlx90393_osr_avail[i] == val) { + *osr = i; + return 0; + } + } + + return -EINVAL; +} + +static int mlx90393_get_temp_osr2(struct mlx90393_data *data, int *val) +{ + *val = mlx90393_osr2_avail[data->osr2]; + return IIO_VAL_INT; +} + +static int mlx90393_set_osr(struct mlx90393_data *data, int val) +{ + int osr; + int ret; + + ret = mlx90393_find_osr(val, &osr); + if (ret) + return ret; + + if (osr == data->osr) + return 0; + + ret = mlx90393_update_bits(data, MLX90393_REG_CONF3, MLX90393_CONF3_OSR, + osr); + if (ret) + return ret; + + data->osr = osr; + return 0; +} + +static int mlx90393_set_temp_osr2(struct mlx90393_data *data, int val) +{ + int ret; + + if (val < 0 || val >= MLX90393_OSR2_MAX) + return -EINVAL; + + if (val == data->osr2) + return 0; + + ret = mlx90393_update_bits(data, MLX90393_REG_CONF3, MLX90393_CONF3_OSR2, + val); + if (ret) + return ret; + + data->osr2 = val; + + return 0; +} + +static int mlx90393_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int mlx90393_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int val, int val2, + long mask) +{ + struct mlx90393_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->lock); + return mlx90393_set_scale(data, chan, val, val2); + } + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + guard(mutex)(&data->lock); + switch (chan->type) { + case IIO_TEMP: + return mlx90393_set_temp_osr2(data, val); + + case IIO_MAGN: + return mlx90393_set_osr(data, val); + + default: + return -EINVAL; + } + } + default: + return -EINVAL; + } +} + +static int mlx90393_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mlx90393_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&data->lock); + ret = mlx90393_read_measurement(data, chan->address, val); + if (ret) + return ret; + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_MAGN: + return mlx90393_get_scale(data, chan, val, val2); + + case IIO_TEMP: + /* + * Datasheet Table 7: Thermal Specification + */ + *val = 0; + *val2 = 22124; + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } + + case IIO_CHAN_INFO_OFFSET: + if (chan->type != IIO_TEMP) + return -EINVAL; + /* + * Datasheet Table 7: Thermal Specification + */ + + *val = -45114; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_TEMP: + return mlx90393_get_temp_osr2(data, val); + case IIO_MAGN: + return mlx90393_get_osr(data, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int mlx90393_read_avail(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + const int **vals, + int *type, + int *length, + long mask) +{ + struct mlx90393_data *data = iio_priv(indio_dev); + static int scale_avail[MLX90393_GAIN_MAX][MLX90393_AXIS_MAX]; + enum mlx90393_axis_type axis; + u8 res; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->lock); + axis = chan->channel2 == IIO_MOD_Z; + res = axis ? data->res_z : data->res_xy; + + for (unsigned int i = 0; i < MLX90393_GAIN_MAX; i++) { + scale_avail[i][0] = 0; + scale_avail[i][1] = + mlx90393_scale_table[axis][i][res]; + } + + *vals = &scale_avail[0][0]; + *type = IIO_VAL_INT_PLUS_NANO; + *length = MLX90393_GAIN_MAX * MLX90393_AXIS_MAX; + return IIO_AVAIL_LIST; + } + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (chan->type == IIO_TEMP) { + *vals = mlx90393_osr2_avail; + *type = IIO_VAL_INT; + *length = MLX90393_OSR2_MAX; + } else { + *vals = mlx90393_osr_avail; + *type = IIO_VAL_INT; + *length = MLX90393_OSR_MAX; + } + return IIO_AVAIL_LIST; + + default: + return -EINVAL; + } +} + +static const struct iio_info mlx90393_info = { + .read_raw = mlx90393_read_raw, + .write_raw = mlx90393_write_raw, + .read_avail = mlx90393_read_avail, + .write_raw_get_fmt = mlx90393_write_raw_get_fmt, +}; + +static int mlx90393_init(struct mlx90393_data *data) +{ + int ret; + u16 reg; + + /* Exit mode */ + ret = mlx90393_write_cmd(data, MLX90393_CMD_EX); + if (ret) + return ret; + + /* + * Datasheet section 15.4.1.2 (RT command), Figure 16: + * Wait 1 ms after EX command before issuing RT. + */ + fsleep(1 * USEC_PER_MSEC); + + /* Reset device */ + ret = mlx90393_write_cmd(data, MLX90393_CMD_RT); + if (ret) + return ret; + + /* + * Datasheet section 15.4.1.2 (RT command), Figure 16: + * Wait 1.5 ms for the start-up sequence to complete. + */ + fsleep(1.5 * USEC_PER_MSEC); + + ret = mlx90393_read_reg(data, MLX90393_REG_CONF1, ®); + if (ret) + return ret; + + data->gain_sel = FIELD_GET(MLX90393_CONF1_GAIN_SEL, reg); + data->hallconf = FIELD_GET(MLX90393_CONF1_HALLCONF, reg); + + ret = mlx90393_read_reg(data, MLX90393_REG_CONF3, ®); + if (ret) + return ret; + + data->res_xy = FIELD_GET(MLX90393_CONF3_RES_X, reg); + data->res_z = FIELD_GET(MLX90393_CONF3_RES_Z, reg); + data->dig_filt = FIELD_GET(MLX90393_CONF3_DIG_FILT, reg); + data->osr = FIELD_GET(MLX90393_CONF3_OSR, reg); + data->osr2 = FIELD_GET(MLX90393_CONF3_OSR2, reg); + + return 0; +} + +int mlx90393_core_probe(struct device *dev, + const struct mlx90393_transfer_ops *ops, + void *context) +{ + struct iio_dev *indio_dev; + struct mlx90393_data *data; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; + + data->dev = dev; + data->ops = ops; + data->bus_context = context; + + indio_dev->name = "mlx90393"; + indio_dev->info = &mlx90393_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mlx90393_channels; + indio_dev->num_channels = ARRAY_SIZE(mlx90393_channels); + + ret = mlx90393_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to initialize device\n"); + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(mlx90393_core_probe, "IIO_MLX90393"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nikhil Gautam <nikhilgtr@gmail.com>"); +MODULE_DESCRIPTION("MLX90393 magnetometer sensor driver"); diff --git a/drivers/iio/magnetometer/mlx90393_i2c.c b/drivers/iio/magnetometer/mlx90393_i2c.c new file mode 100644 index 000000000000..a9f0a40d15e8 --- /dev/null +++ b/drivers/iio/magnetometer/mlx90393_i2c.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/array_size.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> + +#include "mlx90393.h" + +/* + * MLX90393 commands use repeated-start transfers where + * every command is followed by a status/data response. + */ +static int mlx90393_i2c_xfer(void *context, + const u8 *tx, int tx_len, + u8 *rx, int rx_len) +{ + struct i2c_client *client = context; + int ret; + struct i2c_msg msgs[2] = { + [0] = { + .addr = client->addr, + .len = tx_len, + .buf = (u8 *)tx, + }, + [1] = { + .addr = client->addr, + .flags = I2C_M_RD, + .len = rx_len, + .buf = rx, + }, + }; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static const struct mlx90393_transfer_ops mlx90393_i2c_ops = { + .xfer = mlx90393_i2c_xfer, +}; + +static int mlx90393_i2c_probe(struct i2c_client *client) +{ + return mlx90393_core_probe(&client->dev, &mlx90393_i2c_ops, client); +} + +static const struct i2c_device_id mlx90393_id[] = { + { .name = "mlx90393" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mlx90393_id); + +static const struct of_device_id mlx90393_of_match[] = { + { .compatible = "melexis,mlx90393" }, + { } +}; +MODULE_DEVICE_TABLE(of, mlx90393_of_match); + +static struct i2c_driver mlx90393_i2c_driver = { + .driver = { + .name = "mlx90393", + .of_match_table = mlx90393_of_match, + }, + .probe = mlx90393_i2c_probe, + .id_table = mlx90393_id, +}; + +module_i2c_driver(mlx90393_i2c_driver); + +MODULE_IMPORT_NS("IIO_MLX90393"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nikhil Gautam <nikhilgtr@gmail.com>"); +MODULE_DESCRIPTION("MLX90393 magnetometer sensor driver"); -- 2.39.5 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/2] iio: magnetometer: add support for Melexis MLX90393 2026-06-27 0:58 ` [PATCH v3 2/2] iio: magnetometer: add support for " Nikhil Gautam @ 2026-06-27 1:10 ` sashiko-bot 0 siblings, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-06-27 1:10 UTC (permalink / raw) To: Nikhil Gautam; +Cc: devicetree, robh, conor+dt Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider: - [High] TOCTOU data race in `mlx90393_read_avail` due to static array. - [High] Stack-allocated buffers passed to I2C transport violate DMA rules. - [High] `mlx90393_check_status` rejects valid responses for 4-axis reads. - [Medium] Writing to `in_temp_scale` silently corrupts magnetometer gain configuration. - [Medium] Incorrect physical units exposed for IIO scales (ABI violation). - [Medium] Temperature oversampling ratio exposes internal register indices (ABI violation). - [Low] Use of floating-point literal in `fsleep` duration. - [Low] Misuse of `MLX90393_AXIS_MAX` for scale array length. - [Low] Data race on configuration variables in `mlx90393_read_raw`. -- commit 615b644e2712a4949015c117e64d449d197438d8 Author: Nikhil Gautam <nikhilgtr@gmail.com> iio: magnetometer: add support for Melexis MLX90393 Add Industrial I/O subsystem support for the Melexis MLX90393 3-axis magnetometer and temperature sensor. > diff --git a/drivers/iio/magnetometer/mlx90393_core.c b/drivers/iio/magnetometer/mlx90393_core.c > index 0000000000000..78fcab8a2b566 100644 > --- /dev/null > +++ b/drivers/iio/magnetometer/mlx90393_core.c [ ... ] > +static const int mlx90393_osr2_avail[MLX90393_OSR2_MAX] = { > + 0, 1, 2, 3, > +}; [Severity: Medium] Should this array expose the physical oversampling ratios (e.g., 1, 2, 4, 8) rather than the internal register values, to comply with IIO ABI standards? [ ... ] > +static int mlx90393_check_status(u8 cmd, u8 status) > +{ > + /* Datasheet: Table 12: Status byte definition */ > + > + /* Always validate error bit */ > + if (status & MLX90393_STATUS_ERROR) > + return -EIO; > + > + switch (cmd & MLX90393_CMD_MASK) { > + case MLX90393_CMD_RM: > + /* > + * D1:D0 indicates response availability > + * 00 means invalid/no measurement > + */ > + if ((status & MLX90393_STATUS_RESP) == 0) > + return -EIO; [Severity: High] Does this validation break 4-axis reads? If MLX90393_MEASURE_ALL requests 4 words, could the 2-bit counter overflow to 00, causing the driver to incorrectly reject valid responses? [ ... ] > +static int mlx90393_write_reg(struct mlx90393_data *data, u8 reg, u16 val) > +{ > + u8 tx[4]; > + u8 status; > + int ret; > + > + tx[0] = MLX90393_CMD_WR; > + put_unaligned_be16(val, &tx[1]); > + /* Register address is encoded in bits [7:2] */ > + tx[3] = reg << 2; > + > + ret = mlx90393_xfer(data, tx, sizeof(tx), &status, 1); [Severity: High] Can passing stack-allocated buffers to the I2C transport cause memory corruption or a kernel panic? If the underlying I2C controller uses DMA, mapping stack memory (which might be CONFIG_VMAP_STACK) is generally not allowed. This also applies to the rx buffer in mlx90393_read_measurement(). [ ... ] > +static int mlx90393_get_scale(struct mlx90393_data *data, > + const struct iio_chan_spec *chan, > + int *val, int *val2) > +{ > + enum mlx90393_axis_type axis; > + u8 res; > + > + if (chan->channel2 == IIO_MOD_Z) { > + axis = MLX90393_AXIS_TYPE_Z; > + res = data->res_z; > + } else { > + axis = MLX90393_AXIS_TYPE_XY; > + res = data->res_xy; > + } > + > + *val = 0; > + *val2 = mlx90393_scale_table[axis][data->gain_sel][res]; > + > + return IIO_VAL_INT_PLUS_NANO; [Severity: Medium] Do these return values violate the IIO ABI? Is the magnetometer scale exposing Tesla (nano scale) instead of Gauss? [ ... ] > +static int mlx90393_write_raw(struct iio_dev *indio_dev, > + const struct iio_chan_spec *chan, > + int val, int val2, > + long mask) > +{ > + struct mlx90393_data *data = iio_priv(indio_dev); > + > + switch (mask) { > + case IIO_CHAN_INFO_SCALE: { > + guard(mutex)(&data->lock); > + return mlx90393_set_scale(data, chan, val, val2); > + } [Severity: Medium] Does this lack of chan->type checking mean writes to the temperature scale sysfs attribute will fall through to mlx90393_set_scale()? Could this unintentionally alter the magnetometer gain configuration? [ ... ] > +static int mlx90393_read_raw(struct iio_dev *indio_dev, > + const struct iio_chan_spec *chan, > + int *val, int *val2, long mask) > +{ > + struct mlx90393_data *data = iio_priv(indio_dev); > + int ret; > + > + switch (mask) { > + case IIO_CHAN_INFO_RAW: { > + guard(mutex)(&data->lock); > + ret = mlx90393_read_measurement(data, chan->address, val); > + if (ret) > + return ret; > + > + return IIO_VAL_INT; > + } > + case IIO_CHAN_INFO_SCALE: > + switch (chan->type) { > + case IIO_MAGN: > + return mlx90393_get_scale(data, chan, val, val2); [Severity: Low] Does reading driver configuration fields like data->gain_sel in mlx90393_get_scale() without holding data->lock introduce a data race with concurrent sysfs writes in mlx90393_write_raw()? > + > + case IIO_TEMP: > + /* > + * Datasheet Table 7: Thermal Specification > + */ > + *val = 0; > + *val2 = 22124; > + return IIO_VAL_INT_PLUS_MICRO; [Severity: Medium] Does this violate the IIO ABI by exposing Celsius instead of milli-Celsius? [ ... ] > +static int mlx90393_read_avail(struct iio_dev *indio_dev, > + const struct iio_chan_spec *chan, > + const int **vals, > + int *type, > + int *length, > + long mask) > +{ > + struct mlx90393_data *data = iio_priv(indio_dev); > + static int scale_avail[MLX90393_GAIN_MAX][MLX90393_AXIS_MAX]; [Severity: High] Is it safe to populate and return a pointer to a static array here? Since the IIO core reads this array outside the driver's lock, couldn't a concurrent sysfs read from another thread or device overwrite the array contents while it's being read? [ ... ] > + *vals = &scale_avail[0][0]; > + *type = IIO_VAL_INT_PLUS_NANO; > + *length = MLX90393_GAIN_MAX * MLX90393_AXIS_MAX; [Severity: Low] Is MLX90393_AXIS_MAX being misused here to calculate the length? While it evaluates to 2, shouldn't length represent the number of values (entries * 2 elements per IIO value pair) rather than axis count? [ ... ] > +static int mlx90393_init(struct mlx90393_data *data) > +{ > + int ret; > + u16 reg; > + > + /* Exit mode */ > + ret = mlx90393_write_cmd(data, MLX90393_CMD_EX); > + if (ret) > + return ret; > + > + /* > + * Datasheet section 15.4.1.2 (RT command), Figure 16: > + * Wait 1 ms after EX command before issuing RT. > + */ > + fsleep(1 * USEC_PER_MSEC); > + > + /* Reset device */ > + ret = mlx90393_write_cmd(data, MLX90393_CMD_RT); > + if (ret) > + return ret; > + > + /* > + * Datasheet section 15.4.1.2 (RT command), Figure 16: > + * Wait 1.5 ms for the start-up sequence to complete. > + */ > + fsleep(1.5 * USEC_PER_MSEC); [Severity: Low] Could using a floating-point literal (1.5) cause build or linkage errors on architectures where hardware floating-point arithmetic is not supported in the kernel? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260627005843.7786-1-nikhilgtr@gmail.com?part=2 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 0/2] iio: magnetometer: add support for Melexis MLX90393 2026-06-27 0:58 Nikhil Gautam 2026-06-27 0:58 ` [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 Nikhil Gautam 2026-06-27 0:58 ` [PATCH v3 2/2] iio: magnetometer: add support for " Nikhil Gautam @ 2026-06-27 18:30 ` David Lechner 2 siblings, 0 replies; 8+ messages in thread From: David Lechner @ 2026-06-27 18:30 UTC (permalink / raw) To: Nikhil Gautam, linux-iio Cc: jic23, nuno.sa, andy, u.kleine-koenig, robh, krzk+dt, conor+dt, devicetree, linux-kernel On 6/26/26 7:58 PM, Nikhil Gautam wrote: > Subject: [PATCH v3 0/2] iio: magnetometer: add support for Melexis MLX90393 > It is best not to manually edit the emails before sending. Somehow the subject ended up in the email body. ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-06-27 18:41 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-27 0:58 Nikhil Gautam 2026-06-27 0:58 ` [PATCH v3 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393 Nikhil Gautam 2026-06-27 1:04 ` sashiko-bot 2026-06-27 2:26 ` Rob Herring (Arm) 2026-06-27 18:41 ` David Lechner 2026-06-27 0:58 ` [PATCH v3 2/2] iio: magnetometer: add support for " Nikhil Gautam 2026-06-27 1:10 ` sashiko-bot 2026-06-27 18:30 ` [PATCH v3 0/2] " David Lechner
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox