Skip to contentSkip to conversation

iio: magnetometer: add support for Melexis MLX90393

PATCH Superseded Nikhil Gautam 5 participants 13 messages Jun 18 – Jun 22

Subsystems (2)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v2 cover 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.

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.

Previous Submission:

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.

I would like to thank Jonathan Cameron for the prompt and thorough review of the previous revision. The detailed feedback on both the submission process and the implementation has significantly improved the quality and maintainability of 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    |  55 ++
 MAINTAINERS                                   |   7 +
 drivers/iio/magnetometer/Kconfig              |  10 +
 drivers/iio/magnetometer/Makefile             |   2 +
 drivers/iio/magnetometer/mlx90393.h           |  74 ++
 drivers/iio/magnetometer/mlx90393_core.c      | 681 ++++++++++++++++++
 drivers/iio/magnetometer/mlx90393_i2c.c       |  72 ++
 7 files changed, 901 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
Signature · 1 line
2.39.5
#1 lore raw

PATCH v2 1/2 dt-bindings: iio: magnetometer: add Melexis MLX90393

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.

---
 .../iio/magnetometer/melexis,mlx90393.yaml    | 55 +++++++++++++++++++
 MAINTAINERS                                   |  6 ++
 2 files changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml
Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml new file +55 -0
new file mode 100644
index 000000000000..79e7e4a124b6
@@ -0,0 +1,55 @@
+# 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 <[email protected]>
+
+description:
+  Melexis MLX90393 3-axis magnetometer and temperature sensor.
+
+properties:
+  compatible:
+    const: melexis,mlx90393
+
+  reg:
+    maxItems: 1
+
+  vdd-supply: true
+  vddio-supply: true
+
+  interrupts:
+    maxItems: 1
+
+  trigger-gpios:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+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>;
+        };
+    };
MAINTAINERS +6 -0
index a92290fffa16..e9ddcd12feb5 100644
@@ -24926,6 +24926,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml
 F:	drivers/iio/magnetometer/tmag5273.c
 
+MELEXIS MLX90393 MAGNETOMETER DRIVER
+M:	Nikhil Gautam <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml
+
 TI TRF7970A NFC DRIVER
 M:	Mark Greer <[email protected]>
 L:	[email protected]
Signature · 1 line
2.39.5
#2 lore raw

Re: [PATCH v2 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] The new entry for 'MELEXIS MLX90393 MAGNETOMETER DRIVER' in the MAINTAINERS file is inserted out of…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The new entry for 'MELEXIS MLX90393 MAGNETOMETER DRIVER' in the MAINTAINERS file is inserted out of alphabetical order. --

commit 756049ed43f6fd027532ae2aea78e2889e87ad8e
Author: Nikhil Gautam <[email protected]>

dt-bindings: iio: magnetometer: add Melexis MLX90393

This commit adds devicetree bindings for the Melexis MLX90393 3-axis magnetometer and temperature sensor. The initial binding documents the I2C interface.

[ ... ]

Quoted 5 lines
MAINTAINERS +0 -0
index a92290fffa163..e9ddcd12feb5e 100644

MAINTAINERS S: Maintained · line 24935

Quoted 10 lines
MAINTAINERS +6 -0
@@ -24926,6 +24926,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml
 F:	drivers/iio/magnetometer/tmag5273.c
 
+MELEXIS MLX90393 MAGNETOMETER DRIVER
+M:	Nikhil Gautam <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml
+
 TI TRF7970A NFC DRIVER

[Severity: Low]
This isn't a bug, but should this new entry be placed earlier in the file? The MAINTAINERS list is generally sorted alphabetically, and the "MELEXIS" driver block is currently being inserted in the "T" section, between "TI TMAG5273" and "TI TRF7970A".

Quoted 2 lines
MAINTAINERS +0 -0
 M:	Mark Greer <[email protected]>
 L:	[email protected]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#3 lore raw

Re: [PATCH v2 1/2] dt-bindings: iio: magnetometer: add Melexis MLX90393

In reply to Nikhil Gautam
Quoted 12 lines · Nikhil Gautam
Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml new file +12 -0
+description:
+  Melexis MLX90393 3-axis magnetometer and temperature sensor.
+
+properties:
+  compatible:
+    const: melexis,mlx90393
+
+  reg:
+    maxItems: 1
+
+  vdd-supply: true
+  vddio-supply: true

Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml line 33

Quoted 10 lines
Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml new file +10 -0
+
+  interrupts:
+    maxItems: 1
+
+  trigger-gpios:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg

Supplies should be required.

Quoted 27 lines
Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml new file +22 -0
+
+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>;
+        };
+    };
MAINTAINERS +0 -0
index a92290fffa16..e9ddcd12feb5 100644

MAINTAINERS S: Maintained · line 24935

Quoted 10 lines
MAINTAINERS +6 -0
@@ -24926,6 +24926,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml
 F:	drivers/iio/magnetometer/tmag5273.c
 
+MELEXIS MLX90393 MAGNETOMETER DRIVER
+M:	Nikhil Gautam <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml
+
 TI TRF7970A NFC DRIVER

This feels like completely random order.

Quoted 5 lines
MAINTAINERS +0 -0
 M:	Mark Greer <[email protected]>
 L:	[email protected]
Signature · 1 line
2.39.5
#4 lore raw

PATCH v2 2/2 iio: magnetometer: add support for Melexis MLX90393

In reply to 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 driver is structured around a shared sensor core with a small transport abstraction layer to simplify future SPI support without duplicating sensor logic.

---
 MAINTAINERS                              |   1 +
 drivers/iio/magnetometer/Kconfig         |  10 +
 drivers/iio/magnetometer/Makefile        |   2 +
 drivers/iio/magnetometer/mlx90393.h      |  74 +++
 drivers/iio/magnetometer/mlx90393_core.c | 681 +++++++++++++++++++++++
 drivers/iio/magnetometer/mlx90393_i2c.c  |  72 +++
 6 files changed, 840 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
MAINTAINERS +1 -0
index e9ddcd12feb5..ef7eb6fec0c2 100644
@@ -24931,6 +24931,7 @@ M:	Nikhil Gautam <[email protected]>
 L:	[email protected]
 S:	Maintained
 F:	Documentation/devicetree/bindings/iio/magnetometer/melexis,mlx90393.yaml
+F:	drivers/iio/magnetometer/mlx90393*
 
 TI TRF7970A NFC DRIVER
 M:	Mark Greer <[email protected]>
drivers/iio/magnetometer/Kconfig +10 -0
index 3debf1320ad1..e6b74e7e3317 100644
@@ -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
drivers/iio/magnetometer/Makefile +2 -0
index 9297723a97d8..542c89d38a59 100644
@@ -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
drivers/iio/magnetometer/mlx90393.h new file +74 -0

74 lines not on this page · raw message

drivers/iio/magnetometer/mlx90393_core.c new file +681 -0

681 lines not on this page · raw message

drivers/iio/magnetometer/mlx90393_i2c.c new file +72 -0

72 lines not on this page · raw message

Signature · 1 line
2.39.5
#5 lore raw
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider: - [High] Data race on statically allocated `scale_avail` array. - [High] DMA safety violation due to…

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Data race on statically allocated scale_avail array.
- [High] DMA safety violation due to stack-allocated transfer buffers.
- [High] Writing to the temperature scale attribute corrupts the magnetometer gain configuration.
- [Medium] IIO scale values violate ABI standard (Tesla and Celsius instead of Gauss and milli-Celsius).
- [Medium] Missing id_table assignment in the I2C driver structure.
- [Medium] Temperature channel exposes raw register exponent values instead of true oversampling ratios.
- [Medium] Lockless state reads in mlx90393_read_raw lead to data races.
--

commit bdec68e57f45f6e35e5c0c76d37b8ee5efa9691b
Author: Nikhil Gautam <[email protected]>

iio: magnetometer: add support for Melexis MLX90393

Add Industrial I/O subsystem support for the Melexis MLX90393 3-axis magnetometer and temperature sensor.

Quoted 5 lines
drivers/iio/magnetometer/mlx90393_core.c new file +0 -0
new file mode 100644
index 0000000000000..0ad4a30c0be96

[ ... ]

drivers/iio/magnetometer/mlx90393_core.c line 241

Quoted 12 lines
drivers/iio/magnetometer/mlx90393_core.c new file +12 -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);

[Severity: High]
Is it safe to allocate the transfer buffers on the stack here and in mlx90393_read_measurement()?

If the I2C host adapter uses DMA and CONFIG_VMAP_STACK is enabled, mapping stack memory for DMA operations will fail. Should these buffers be dynamically allocated to ensure DMA safety?

[ ... ]

Quoted 14 lines
drivers/iio/magnetometer/mlx90393_core.c new file +14 -0
+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;
+	}

drivers/iio/magnetometer/mlx90393_core.c line 333

Quoted 10 lines
drivers/iio/magnetometer/mlx90393_core.c new file +10 -0
+
+	/*
+	 * Convert:
+	 * µT × 1000 → nT
+	 */
+	*val = 0;
+	*val2 = mlx90393_scale_table[axis][data->gain_sel][res];
+
+	return IIO_VAL_INT_PLUS_NANO;
+}

[Severity: Medium]
Does this return the scale in Gauss as required by the IIO ABI for in_magn_scale? Using IIO_VAL_INT_PLUS_NANO with the current scale table yields Tesla, which is off by a factor of 10,000 compared to Gauss.

[ ... ]

Quoted 4 lines
drivers/iio/magnetometer/mlx90393_core.c new file +4 -0
+static int mlx90393_write_raw(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan,
+			      int val, int val2,
+			      long mask)

drivers/iio/magnetometer/mlx90393_core.c line 480

Quoted 10 lines
drivers/iio/magnetometer/mlx90393_core.c new file +10 -0
+{
+	struct mlx90393_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE: {
+		guard(mutex)(&data->lock);
+		ret = mlx90393_set_scale(data, chan, val, val2);
+		return ret;
+	}

[Severity: High]
Can writing to the temperature scale attribute corrupt the magnetometer gain configuration?

The IIO_TEMP channel exposes a writable scale attribute, but this case does not check chan->type before calling mlx90393_set_scale(). Because the temperature channel's channel2 field is 0, it evaluates as an XY magnetometer channel and will reconfigure the global gain_sel register.

[ ... ]

Quoted 10 lines
drivers/iio/magnetometer/mlx90393_core.c new file +10 -0
+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);

drivers/iio/magnetometer/mlx90393_core.c line 518

Quoted 10 lines
drivers/iio/magnetometer/mlx90393_core.c new file +10 -0
+		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: Medium]
Is a lock needed here?

Configuration variables like gain_sel, osr, and osr2 are updated while holding data->lock in mlx90393_write_raw(), but mlx90393_read_raw() reads these properties without acquiring the lock.

Can concurrent updates result in stale or inconsistently-read configurations?

drivers/iio/magnetometer/mlx90393_core.c line 524

Quoted 6 lines
drivers/iio/magnetometer/mlx90393_core.c new file +6 -0
+
+		case IIO_TEMP:
+			/* Datasheet: 22124 millidegC/LSB */
+			*val = 0;
+			*val2 = 22124;
+			return IIO_VAL_INT_PLUS_MICRO;

[Severity: Medium]
Does this return the temperature scale in milli-Celsius as required by the IIO ABI? Returning 22124 with IIO_VAL_INT_PLUS_MICRO yields Celsius, which is off by a factor of 1,000.

[ ... ]

drivers/iio/magnetometer/mlx90393_core.c line 560

Quoted 9 lines
drivers/iio/magnetometer/mlx90393_core.c new file +9 -0
+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 use a statically allocated local array for scale_avail?

The lock is released before the IIO core iterates over the returned pointer. Can concurrent sysfs reads across different channels or multiple device instances clobber the shared array and return corrupted lists to userspace?

Quoted 14 lines
drivers/iio/magnetometer/mlx90393_core.c new file +14 -0
+	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];
+		}
+

drivers/iio/magnetometer/mlx90393_core.c line 584

Quoted 10 lines
drivers/iio/magnetometer/mlx90393_core.c new file +10 -0
+		*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;

[Severity: Medium]
Does this expose raw register exponent values instead of true oversampling ratios for the temperature channel?

Returning the register exponents (0, 1, 2, 3) directly violates the IIO ABI which dictates reflecting the actual number of hardware samples applied.

[ ... ]

Quoted 5 lines
drivers/iio/magnetometer/mlx90393_i2c.c new file +0 -0
new file mode 100644
index 0000000000000..52233b6295c2b

[ ... ]

drivers/iio/magnetometer/mlx90393_i2c.c line 66

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_i2c.c new file +7 -0
+static struct i2c_driver mlx90393_i2c_driver = {
+	.driver = {
+		.name = "mlx90393",
+		.of_match_table = mlx90393_of_match,
+	},
+	.probe = mlx90393_i2c_probe,
+};

[Severity: Medium]
Is the id_table assignment missing here?

The driver defines the mlx90393_id table and exports it, but it is not assigned to the id_table field of this structure. Could this prevent the driver from binding on systems relying on legacy board-file setups or sysfs new_device instantiation?

[ ... ]

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#6 lore raw
In reply to Nikhil Gautam

Hello,

drivers/iio/magnetometer/mlx90393_i2c.c line 50

Quoted 3 lines · Nikhil Gautam
drivers/iio/magnetometer/mlx90393_i2c.c new file +3 -0
+static const struct i2c_device_id mlx90393_id[] = {
+	{ "mlx90393" },
+	{ }

Please make that:

	{ .name = "mlx90393" },
Quoted 5 lines
drivers/iio/magnetometer/mlx90393_i2c.c new file +5 -0
+};
+MODULE_DEVICE_TABLE(i2c, mlx90393_id);
+
+static const struct of_device_id mlx90393_of_match[] = {
+	{ .compatible = "melexis,mlx90393" },

drivers/iio/magnetometer/mlx90393_i2c.c line 65

Quoted 10 lines
drivers/iio/magnetometer/mlx90393_i2c.c new file +10 -0
+	{ }
+};
+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,

I guess you want

	.id_table = mlx90393_id,

here.

Best regards
Uwe

#7 lore raw
Quoted 6 lines · Uwe Kleine-König

Hello,

On Thu, Jun 18, 2026 at 09:31:41PM +0530, Nikhil Gautam wrote:
Please make that:

	{ .name = "mlx90393" },

Thanks for pointing this out. I'll update it in v3.

Quoted 3 lines

I guess you want

	.id_table = mlx90393_id,

Yes, that's correct. I'll add the missing .id_table entry in the next version.

Thanks for the review!

Best regards,
Nikhil

#8 lore raw
In reply to Nikhil Gautam
Quoted 17 lines · 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 driver is structured around a shared sensor core with a small transport abstraction layer to simplify future SPI support without duplicating sensor logic.

...

drivers/iio/magnetometer/Kconfig config HID_SENSOR_MAGNETOMETER_3D · line 133

Quoted 3 lines
drivers/iio/magnetometer/Kconfig +3 -0
+config MLX90393
+	tristate "MELEXIS MLX90393 3-axis magnetometer sensor"
+	depends on I2C

Why not a regmap?

Quoted 21 lines
drivers/iio/magnetometer/Kconfig +7 -0
+	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
drivers/iio/magnetometer/Makefile +2 -0
index 9297723a97d8..542c89d38a59 100644
@@ -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

...

drivers/iio/magnetometer/Makefile

Quoted 6 lines
drivers/iio/magnetometer/Makefile +4 -0
+#ifndef MLX90393_H
+#define MLX90393_H
 
+#include <linux/bitops.h>
 
+#include <linux/bits.h>

Not required, it's covered by bitops.h.

Quoted 1 line

+#include <linux/types.h>

...

drivers/iio/magnetometer/Makefile

Quoted 3 lines
drivers/iio/magnetometer/Makefile +3 -0
+#define MLX90393_MEASURE_ALL \
+	(MLX90393_MEASURE_TEMP | MLX90393_MEASURE_X | \
+	MLX90393_MEASURE_Y | MLX90393_MEASURE_Z)

Split logically.

#define MLX90393_MEASURE_ALL \
	(MLX90393_MEASURE_TEMP | \
	 MLX90393_MEASURE_X | MLX90393_MEASURE_Y | MLX90393_MEASURE_Z)

Or just a (long) single line.

...

drivers/iio/magnetometer/Makefile

Quoted 2 lines
drivers/iio/magnetometer/Makefile +2 -0
+	int (*xfer)(void *context, const u8 *tx, int tx_len,
+		    u8 *rx, int rx_len);

One line, it's only 81 characters.

drivers/iio/magnetometer/Makefile

Quoted 3 lines
drivers/iio/magnetometer/Makefile +3 -0
+};
+
+int mlx90393_core_probe(struct device *dev,

You want forward declaration for struct device.

drivers/iio/magnetometer/Makefile

Quoted 3 lines
drivers/iio/magnetometer/Makefile +3 -0
+			const struct mlx90393_transfer_ops *ops,
+			void *context);
+

...

+ array_size.h
+ bitfield.h // FIELD_GET()

Quoted 1 line

+#include <linux/delay.h>

+ errno.h // -Exxx

drivers/iio/magnetometer/Makefile

Quoted 2 lines
drivers/iio/magnetometer/Makefile +2 -0
+#include <linux/module.h>
+#include <linux/mutex.h>

+ types.h // uXX

drivers/iio/magnetometer/Makefile

Quoted 2 lines
drivers/iio/magnetometer/Makefile +2 -0
+#include <linux/unaligned.h>
+#include <linux/units.h>

IWYU, please (just pointed out a few missing above, there are more).

...

drivers/iio/magnetometer/Makefile

Quoted 4 lines
drivers/iio/magnetometer/Makefile +4 -0
+/* Datasheet: Table no.17 */
+static const int mlx90393_scale_table[MLX90393_AXIS_MAX]
+				[MLX90393_GAIN_MAX]
+				[MLX90393_RES_MAX] = {

This is broken indentation.

Quoted 23 lines
drivers/iio/magnetometer/Makefile +23 -0
+	/* 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},
+	}
+};

...

Quoted 4 lines

+/*
+ * Calculate total conversion time in microseconds.
+ *
+ * Formula derived from datasheet timing equations.

Which formula? Where is datasheet? What if I have no access to it? Always repeat the important details in the comment in the code.

Quoted 3 lines

+ */

+

Unneeded blank line.

drivers/iio/magnetometer/Makefile

Quoted 13 lines
drivers/iio/magnetometer/Makefile +13 -0
+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 */
+
+	/*
+	 * Datasheet:

What chapter/section/table name? Page number?

drivers/iio/magnetometer/Makefile

Quoted 1 line
drivers/iio/magnetometer/Makefile +1 -0
+	 * TCONVM = 67 + 64 * 2^OSR * (2 + 2^DIG_FILT)

What does this cryptic message mean? Please, accompany this with more English plain text.

Quoted 14 lines
drivers/iio/magnetometer/Makefile +14 -0
+	 */
+	tconvm = 67 + (64 * BIT(osr) * (2 + BIT(df)));
+
+	/*
+	 * Datasheet:
+	 * 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 + 1100;
+}

...

drivers/iio/magnetometer/Makefile

Quoted 7 lines
drivers/iio/magnetometer/Makefile +7 -0
+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);

It's perfectly one line.

Also you might want to have

	if (!...->xfer)
		return -E...;
Quoted 1 line

+}

...

Quoted 8 lines
drivers/iio/magnetometer/Makefile +8 -0
+static int mlx90393_check_status(u8 cmd, u8 status)
+{
+	/* Always validate error bit */
+	if (status & MLX90393_STATUS_ERROR)
+		return -EIO;
+
+	switch (cmd & MLX90393_CMD_MASK) {
+	case MLX90393_CMD_RM:

drivers/iio/magnetometer/Makefile

Quoted 10 lines
drivers/iio/magnetometer/Makefile +10 -0
+		/*
+		 * 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))

For sake of consistency you might want to also compare to 0 here.

Quoted 6 lines
drivers/iio/magnetometer/Makefile +6 -0
+			return -EIO;
+		return 0;
+	default:
+		return 0;
+	}
+}

...

Quoted 1 line

+static int mlx90393_write_reg(struct mlx90393_data *data, u8 reg, u16 val)

Here the variable is named 'reg' there is 'reg_addr'. As I can see the code is full of inconsistencies (like 2+ people with different style guidelines wrote it). Please. take your time and check the code and make it consistent.

Quoted 19 lines
drivers/iio/magnetometer/Makefile +19 -0
+{
+	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_addr,
+				u16 mask, u16 val)

drivers/iio/magnetometer/Makefile

Quoted 10 lines
drivers/iio/magnetometer/Makefile +9 -0
+{
+	u16 reg;
+	int ret;
+
+	ret = mlx90393_read_reg(data, reg_addr, &reg);
+	if (ret)
+		return ret;
 
+	reg &= ~mask;
+	reg |= (val << __ffs(mask)) & mask;

bitfield.h has macros for this.

Quoted 2 lines
drivers/iio/magnetometer/Makefile +2 -0
+	return mlx90393_write_reg(data, reg_addr, reg);
+}

...

drivers/iio/magnetometer/Makefile

Quoted 7 lines
drivers/iio/magnetometer/Makefile +7 -0
+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;
+		}

Missing {}.

Quoted 2 lines
drivers/iio/magnetometer/Makefile +2 -0
+	return -EINVAL;
+}

...

drivers/iio/magnetometer/Makefile

Quoted 3 lines
drivers/iio/magnetometer/Makefile +3 -0
+static int mlx90393_get_temp_osr2(struct mlx90393_data *data, int *val)
+{
+	*val = mlx90393_osr2_avail[data->osr2];

Missing blank line.

Quoted 2 lines
drivers/iio/magnetometer/Makefile +2 -0
+	return IIO_VAL_INT;
+}

...

drivers/iio/magnetometer/Makefile

Quoted 8 lines
drivers/iio/magnetometer/Makefile +7 -0
+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);
 
+	int ret;

Not needed, return directly.

Quoted 24 lines
drivers/iio/magnetometer/Makefile +24 -0
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE: {
+		guard(mutex)(&data->lock);
+		ret = mlx90393_set_scale(data, chan, val, val2);
+		return ret;
+	}
+	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;
+	}
+}

...

drivers/iio/magnetometer/Makefile

Quoted 2 lines
drivers/iio/magnetometer/Makefile +2 -0
+			/* Datasheet: 22124 millidegC/LSB */
+		/* Datasheet: temperature offset */

Again, at least put a page, better to have Section/Table/et cetera title.

...

Quoted 35 lines
drivers/iio/magnetometer/Makefile +35 -0
+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;

drivers/iio/magnetometer/Makefile

Quoted 10 lines
drivers/iio/magnetometer/Makefile +9 -0
+			*type = IIO_VAL_INT;
+			*length = MLX90393_OSR_MAX;
+		}
+		return IIO_AVAIL_LIST;
+
+	default:
+		return -EINVAL;
+	}
 
+	return -EINVAL;

Besides missing blank line, this is actually a dead code.

Quoted 1 line

+}

...

drivers/iio/magnetometer/Makefile

Quoted 11 lines
drivers/iio/magnetometer/Makefile +11 -0
+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;
+
+	/* Wait for device comes out of reset */

Datasheet? Empirical?

drivers/iio/magnetometer/Makefile

Quoted 1 line
drivers/iio/magnetometer/Makefile +1 -0
+	fsleep(1000);

1 * USEC_PER_MSEC
(will require time.h to be included).

drivers/iio/magnetometer/Makefile

Quoted 7 lines
drivers/iio/magnetometer/Makefile +7 -0
+	/* Reset device */
+	ret = mlx90393_write_cmd(data, MLX90393_CMD_RT);
+	if (ret)
+		return ret;
+
+	/* Wait for device to reset */
+	fsleep(6000);

As per above.

Quoted 19 lines
drivers/iio/magnetometer/Makefile +19 -0
+	ret = mlx90393_read_reg(data, MLX90393_REG_CONF1, &reg);
+	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, &reg);
+	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;
+}

...

Quoted 4 lines
drivers/iio/magnetometer/Makefile +4 -0
+int mlx90393_core_probe(struct device *dev,
+			const struct mlx90393_transfer_ops *ops,
+			void *context)
+{

drivers/iio/magnetometer/Makefile

Quoted 10 lines
drivers/iio/magnetometer/Makefile +10 -0
+	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);
+	devm_mutex_init(dev, &data->lock);

Nonsense. If we don't check the return code of devm_*(), there is a little reason to use it in the first place. But then one should not use devm further. Easy fix: check for returned errors.

Quoted 7 lines
drivers/iio/magnetometer/Makefile +7 -0
+	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;

drivers/iio/magnetometer/Makefile

Quoted 10 lines
drivers/iio/magnetometer/Makefile +10 -0
+	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_GPL(mlx90393_core_probe);

Make it namespaces.

...

+ array_size.h
+ errno.h

drivers/iio/magnetometer/Makefile

Quoted 3 lines
drivers/iio/magnetometer/Makefile +3 -0
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>

...and so on.

Same, follow the IWYU principle.

...

Quoted 17 lines
drivers/iio/magnetometer/Makefile +17 -0
+/*
+ * 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] = {

drivers/iio/magnetometer/Makefile

Quoted 10 lines
drivers/iio/magnetometer/Makefile +10 -0
+			.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;

Please, make this to be the regular pattern

	if (ret < 0)
		return ret;
	if (ret != ARRAY_SIZE(msgs))
		return -EIO;
Quoted 2 lines
drivers/iio/magnetometer/Makefile +2 -0
+	return 0;
+}

...

drivers/iio/magnetometer/Makefile

Quoted 9 lines
drivers/iio/magnetometer/Makefile +8 -0
+static struct i2c_driver mlx90393_i2c_driver = {
+	.driver = {
+		.name = "mlx90393",
+		.of_match_table = mlx90393_of_match,
+	},
+	.probe = mlx90393_i2c_probe,
+};
 
+

Remove this blank line.

Quoted 1 line

+module_i2c_driver(mlx90393_i2c_driver);

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#9 lore raw
Quoted 1 line · Andy Shevchenko

On Thu, Jun 18, 2026 at 09:31:41PM +0530, Nikhil Gautam wrote:

Hi Andy,

Thank you very much for taking the time to do such a thorough review of this patch series.

Your detailed comments and suggestions are very helpful.
I'll address the issues you've pointed out, update the cover letter to better explain the design decisions, and incorporate the requested coding style and API changes in the next revision.

I appreciate your review and feedback.

Quoted 4 lines

drivers/iio/magnetometer/Kconfig config HID_SENSOR_MAGNETOMETER_3D · line 133

Quoted 3 lines
drivers/iio/magnetometer/Kconfig +3 -0
+config MLX90393
+	tristate "MELEXIS MLX90393 3-axis magnetometer sensor"
+	depends on I2C

Why not a regmap?

The MLX90393 uses both register-based and command-based transactions. Since regmap does not naturally model the command-based interface,
using it would require workarounds such as virtual registers or bypass paths. A custom transport abstraction is therefore simpler and better suited for this device.

I already discussed this on thread, Link : https://lore.kernel.org/linux-iio/[email protected]/

Quoted 6 lines

drivers/iio/magnetometer/mlx90393.h line 12

Quoted 5 lines
drivers/iio/magnetometer/mlx90393.h new file +4 -0
+#ifndef MLX90393_H
+#define MLX90393_H
 
+#include <linux/bitops.h>
+#include <linux/bits.h>

Not required, it's covered by bitops.h.

Noted. Thanks

Quoted 8 lines
Quoted 1 line

+#include <linux/types.h>

...

drivers/iio/magnetometer/mlx90393.h line 42

Quoted 3 lines
drivers/iio/magnetometer/mlx90393.h new file +3 -0
+#define MLX90393_MEASURE_ALL \
+	(MLX90393_MEASURE_TEMP | MLX90393_MEASURE_X | \
+	MLX90393_MEASURE_Y | MLX90393_MEASURE_Z)

Split logically.

Quoted 5 lines
#define MLX90393_MEASURE_ALL \
	(MLX90393_MEASURE_TEMP | \
	 MLX90393_MEASURE_X | MLX90393_MEASURE_Y | MLX90393_MEASURE_Z)

Or just a (long) single line.

Agreed. Thanks

Quoted 3 lines

drivers/iio/magnetometer/mlx90393.h line 67

Quoted 2 lines
drivers/iio/magnetometer/mlx90393.h new file +2 -0
+	int (*xfer)(void *context, const u8 *tx, int tx_len,
+		    u8 *rx, int rx_len);

One line, it's only 81 characters.

Agreed Thanks

Quoted 4 lines

drivers/iio/magnetometer/mlx90393.h line 70

Quoted 3 lines
drivers/iio/magnetometer/mlx90393.h new file +3 -0
+};
+
+int mlx90393_core_probe(struct device *dev,

You want forward declaration for struct device.

Agreed, Thanks

Quoted 6 lines

+ array_size.h
+ bitfield.h // FIELD_GET()

Quoted 1 line

+#include <linux/delay.h>

+ errno.h // -Exxx

Quoted 7 lines

drivers/iio/magnetometer/mlx90393_core.c line 10

Quoted 2 lines
drivers/iio/magnetometer/mlx90393_core.c new file +2 -0
+#include <linux/module.h>
+#include <linux/mutex.h>

+ types.h // uXX

drivers/iio/magnetometer/mlx90393_core.c line 12

Quoted 2 lines
drivers/iio/magnetometer/mlx90393_core.c new file +2 -0
+#include <linux/unaligned.h>
+#include <linux/units.h>

IWYU, please (just pointed out a few missing above, there are more).

Sure, will do it.

Quoted 5 lines

drivers/iio/magnetometer/mlx90393_core.c line 50

Quoted 4 lines
drivers/iio/magnetometer/mlx90393_core.c new file +4 -0
+/* Datasheet: Table no.17 */
+static const int mlx90393_scale_table[MLX90393_AXIS_MAX]
+				[MLX90393_GAIN_MAX]
+				[MLX90393_RES_MAX] = {

This is broken indentation.

Noted, Thanks

Quoted 6 lines
Quoted 4 lines

+/*
+ * Calculate total conversion time in microseconds.
+ *
+ * Formula derived from datasheet timing equations.

Which formula? Where is datasheet? What if I have no access to it? Always repeat the important details in the comment in the code.

Got it, will add all details from datasheet

Quoted 3 lines
Quoted 2 lines

+ */
+

Unneeded blank line.

Noted, Thanks

Quoted 6 lines
Quoted 6 lines
drivers/iio/magnetometer/mlx90393_core.c new file +6 -0
+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;
+
Quoted 8 lines

drivers/iio/magnetometer/mlx90393_core.c line 132

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_core.c new file +7 -0
+	int tconvm;
+	int tconvt;
+
+	int m = 3; /* X,Y,Z */
+
+	/*
+	 * Datasheet:

What chapter/section/table name? Page number?

Sure will add.

Quoted 3 lines

drivers/iio/magnetometer/mlx90393_core.c line 133

Quoted 1 line
drivers/iio/magnetometer/mlx90393_core.c new file +1 -0
+	 * TCONVM = 67 + 64 * 2^OSR * (2 + 2^DIG_FILT)

What does this cryptic message mean? Please, accompany this with more English plain text.

Agreed, Thanks

Quoted 9 lines

drivers/iio/magnetometer/mlx90393_core.c line 155

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_core.c new file +7 -0
+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);

It's perfectly one line.

Quoted 6 lines

Also you might want to have

	if (!...->xfer)
		return -E...;
Quoted 1 line

+}

Noted, Thanks

Quoted 11 lines
Quoted 11 lines
drivers/iio/magnetometer/mlx90393_core.c new file +11 -0
+static int mlx90393_check_status(u8 cmd, u8 status)
+{
+	/* 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
Quoted 8 lines

drivers/iio/magnetometer/mlx90393_core.c line 175

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_core.c new file +7 -0
+		 */
+		if ((status & MLX90393_STATUS_RESP) == 0)
+			return -EIO;
+		return 0;
+	case MLX90393_CMD_RT:
+		/* Reset acknowledge */
+		if (!(status & MLX90393_STATUS_RT))

For sake of consistency you might want to also compare to 0 here.

Thanks, I'll make that change.

Quoted 4 lines
Quoted 1 line

+static int mlx90393_write_reg(struct mlx90393_data *data, u8 reg, u16 val)

Here the variable is named 'reg' there is 'reg_addr'. As I can see the code is full of inconsistencies (like 2+ people with different style guidelines wrote it). Please. take your time and check the code and make it consistent.

Got it, will make it consistent across whole file.

Quoted 27 lines
Quoted 27 lines
drivers/iio/magnetometer/mlx90393_core.c new file +26 -0
+{
+	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_addr,
+				u16 mask, u16 val)
+{
+	u16 reg;
+	int ret;
+
+	ret = mlx90393_read_reg(data, reg_addr, &reg);
+	if (ret)
+		return ret;
Quoted 3 lines

drivers/iio/magnetometer/mlx90393_core.c line 259

Quoted 2 lines
drivers/iio/magnetometer/mlx90393_core.c new file +2 -0
+	reg &= ~mask;
+	reg |= (val << __ffs(mask)) & mask;

bitfield.h has macros for this.

Noted, Thanks

Quoted 8 lines

drivers/iio/magnetometer/mlx90393_core.c line 399

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_core.c new file +7 -0
+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;
+		}

Missing {}.

Agreed, removed intentionally as single statement, will add as per guidelines all the places where needed

Quoted 4 lines

drivers/iio/magnetometer/mlx90393_core.c line 406

Quoted 3 lines
drivers/iio/magnetometer/mlx90393_core.c new file +3 -0
+static int mlx90393_get_temp_osr2(struct mlx90393_data *data, int *val)
+{
+	*val = mlx90393_osr2_avail[data->osr2];

Missing blank line.

Noted, Thanks

Quoted 8 lines

drivers/iio/magnetometer/mlx90393_core.c line 473

Quoted 7 lines

int mlx90393_write_raw(struct iio_dev *indio_dev,

drivers/iio/magnetometer/mlx90393_core.c new file +6 -0
+			      const struct iio_chan_spec *chan,
+			      int val, int val2,
+			      long mask)
+{
+	struct mlx90393_data *data = iio_priv(indio_dev);
+	int ret;

Not needed, return directly.

Agreed.

Quoted 3 lines

drivers/iio/magnetometer/mlx90393_core.c line 534

Quoted 2 lines
drivers/iio/magnetometer/mlx90393_core.c new file +2 -0
+			/* Datasheet: 22124 millidegC/LSB */
+		/* Datasheet: temperature offset */

Again, at least put a page, better to have Section/Table/et cetera title.

Sure, will do it

Quoted 11 lines
drivers/iio/magnetometer/mlx90393_core.c new file +9 -0
+			*vals = mlx90393_osr_avail;
+			*type = IIO_VAL_INT;
+			*length = MLX90393_OSR_MAX;
+		}
+		return IIO_AVAIL_LIST;
+
+	default:
+		return -EINVAL;
+	}

Review

Quoted 1 line
(quoted diff) +1 -0
+	return -EINVAL;

Besides missing blank line, this is actually a dead code.

Correct, this will never be called. will fix

Quoted 4 lines
Quoted 4 lines
drivers/iio/magnetometer/mlx90393_core.c new file +4 -0
+static int mlx90393_init(struct mlx90393_data *data)
+{
+	int ret;
+	u16 reg;
Quoted 8 lines

drivers/iio/magnetometer/mlx90393_core.c line 615

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_core.c new file +7 -0
+
+	/* Exit mode */
+	ret = mlx90393_write_cmd(data, MLX90393_CMD_EX);
+	if (ret)
+		return ret;
+
+	/* Wait for device comes out of reset */

Datasheet? Empirical?

Agreed, Thanks

Quoted 3 lines

drivers/iio/magnetometer/mlx90393_core.c line 616

Quoted 1 line
drivers/iio/magnetometer/mlx90393_core.c new file +1 -0
+	fsleep(1000);

1 * USEC_PER_MSEC
(will require time.h to be included).

Noted, Thanks

Quoted 8 lines

drivers/iio/magnetometer/mlx90393_core.c line 624

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_core.c new file +7 -0
+	/* Reset device */
+	ret = mlx90393_write_cmd(data, MLX90393_CMD_RT);
+	if (ret)
+		return ret;
+
+	/* Wait for device to reset */
+	fsleep(6000);

As per above.

This delay is not 6000ms it is 1500ms as per datasheet, forgot to update in code Thanks for pointing out, will update all places delay requirement with datasheet reference.

Quoted 9 lines
Quoted 9 lines
drivers/iio/magnetometer/mlx90393_core.c new file +9 -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));
Quoted 8 lines

drivers/iio/magnetometer/mlx90393_core.c line 659

Quoted 5 lines
drivers/iio/magnetometer/mlx90393_core.c new file +5 -0
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	devm_mutex_init(dev, &data->lock);

Nonsense. If we don't check the return code of devm_*(), there is a little reason to use it in the first place. But then one should not use devm further. Easy fix: check for returned errors.

Agreed, I'll fix this in the next revision.

Quoted 10 lines
Quoted 10 lines
drivers/iio/magnetometer/mlx90393_core.c new file +10 -0
+	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);
+
Quoted 8 lines

drivers/iio/magnetometer/mlx90393_core.c line 677

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_core.c new file +7 -0
+	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_GPL(mlx90393_core_probe);

Make it namespaces.

Okay, will do it

Quoted 9 lines

+ array_size.h
+ errno.h

drivers/iio/magnetometer/mlx90393_i2c.c line 4

Quoted 3 lines
drivers/iio/magnetometer/mlx90393_i2c.c new file +3 -0
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>

...and so on.

Same, follow the IWYU principle.

Got it, will take care

Quoted 29 lines
Quoted 17 lines
drivers/iio/magnetometer/mlx90393_i2c.c new file +17 -0
+/*
+ * 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] = {

drivers/iio/magnetometer/mlx90393_i2c.c line 34

Quoted 10 lines
drivers/iio/magnetometer/mlx90393_i2c.c new file +10 -0
+			.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;

Please, make this to be the regular pattern

Quoted 7 lines
	if (ret < 0)
		return ret;
	if (ret != ARRAY_SIZE(msgs))
		return -EIO;

Review

Quoted 2 lines
(quoted diff) +2 -0
+	return 0;
+}

Thanks, I'll make that change.

Quoted 8 lines

drivers/iio/magnetometer/mlx90393_i2c.c line 66

Quoted 7 lines
drivers/iio/magnetometer/mlx90393_i2c.c new file +7 -0
+static struct i2c_driver mlx90393_i2c_driver = {
+	.driver = {
+		.name = "mlx90393",
+		.of_match_table = mlx90393_of_match,
+	},
+	.probe = mlx90393_i2c_probe,
+};

Remove this blank line.

Noted

Quoted 2 lines
Quoted 2 lines

+module_i2c_driver(mlx90393_i2c_driver);

Thanks & Regards,
Nikhil

#10 lore raw
Quoted 6 lines · Nikhil Gautam
Quoted 1 line · Andy Shevchenko

On Thu, Jun 18, 2026 at 09:31:41PM +0530, Nikhil Gautam wrote:

Thank you very much for taking the time to do such a thorough review of this patch series.

Quoted 7 lines

Your detailed comments and suggestions are very helpful. I'll address the issues you've pointed out, update the cover letter to better explain the design decisions,
and incorporate the requested coding style and API changes in the next revision.

I appreciate your review and feedback.

You're welcome!

...

Quoted 11 lines
Quoted 4 lines

drivers/iio/magnetometer/Kconfig config HID_SENSOR_MAGNETOMETER_3D · line 133

Quoted 3 lines
drivers/iio/magnetometer/Kconfig +3 -0
+config MLX90393
+	tristate "MELEXIS MLX90393 3-axis magnetometer sensor"
+	depends on I2C

Why not a regmap?

The MLX90393 uses both register-based and command-based transactions. Since regmap does not naturally model the command-based interface, using it would require workarounds such as virtual registers or bypass paths.
A custom transport abstraction is therefore simpler and better suited for this device.

Quoted 2 lines

I already discussed this on thread, Link :
https://lore.kernel.org/linux-iio/[email protected]/

Right, but please, put a summary in the commit message as it's important detail of implementation choice.

...

Quoted 9 lines
Quoted 6 lines

drivers/iio/magnetometer/mlx90393_core.c line 399

Quoted 5 lines
drivers/iio/magnetometer/mlx90393_core.c new file +5 -0
+	for (unsigned int i = 0; i < MLX90393_OSR_MAX;  i++)
+		if (mlx90393_osr_avail[i] == val) {
+			*osr = i;
+			return 0;
+		}

Missing {}.

Agreed, removed intentionally as single statement, will add as per guidelines all the places
where needed

It's also better to have them when it might be ambiguous. And also when even a single statement takes a few lines. TL;DR: Also apply a common sense.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#11 lore raw
In reply to Nikhil Gautam
Quoted 18 lines · Nikhil Gautam

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.

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

Quoted 3 lines

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.

This doesn't answer to two important questions:
- why do we need a brand new driver?
Can't one of the existing be updated to cover this HW?

- where to find the datasheet? Any Links or other means to get it?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#12 lore raw
Quoted 19 lines · Andy Shevchenko
Quoted 18 lines · Nikhil Gautam

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.

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

Quoted 8 lines
Quoted 3 lines

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.

This doesn't answer to two important questions:
- why do we need a brand new driver?
Can't one of the existing be updated to cover this HW?

- where to find the datasheet? Any Links or other means to get it?

Hi Andy,

I looked at the existing magnetometer drivers in the IIO subsystem,
but none support the MLX90393 or a sufficiently similar register map and command protocol. The MLX90393 uses its own command-based interface and device-specific configuration and conversion logic, so extending an existing driver would require substantial changes with little code reuse. Therefore, I chose to implement it as a separate driver.

The datasheet is publicly available from Melexis:

I'll include the datasheet link and clarify the rationale for introducing a new driver in the cover letter of the next revision.

Thanks,
Nikhil