lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250831-icm20948-v1-2-1fe560a38de4@gmail.com>
Date: Sun, 31 Aug 2025 00:12:46 +0530
From: Bharadwaj Raju <bharadwaj.raju777@...il.com>
To: Jonathan Cameron <jic23@...nel.org>, 
 David Lechner <dlechner@...libre.com>, 
 Nuno Sá <nuno.sa@...log.com>, 
 Andy Shevchenko <andy@...nel.org>, Rob Herring <robh@...nel.org>, 
 Krzysztof Kozlowski <krzk+dt@...nel.org>, 
 Conor Dooley <conor+dt@...nel.org>
Cc: linux-iio@...r.kernel.org, devicetree@...r.kernel.org, 
 linux-kernel@...r.kernel.org, shuah@...nel.org, 
 linux-kernel-mentees@...ts.linux.dev, 
 Bharadwaj Raju <bharadwaj.raju777@...il.com>
Subject: [PATCH 2/5] iio: imu: add inv_icm20948

Core parts of the new ICM20948 driver.

Add register definitions, probing, setup, and an IIO device for
reading the onboard temperature sensor.

Signed-off-by: Bharadwaj Raju <bharadwaj.raju777@...il.com>
---
 drivers/iio/imu/Kconfig                          |   1 +
 drivers/iio/imu/Makefile                         |   1 +
 drivers/iio/imu/inv_icm20948/Kconfig             |  17 ++++
 drivers/iio/imu/inv_icm20948/Makefile            |   8 ++
 drivers/iio/imu/inv_icm20948/inv_icm20948.h      |  47 +++++++++
 drivers/iio/imu/inv_icm20948/inv_icm20948_core.c | 122 +++++++++++++++++++++++
 drivers/iio/imu/inv_icm20948/inv_icm20948_i2c.c  |  48 +++++++++
 drivers/iio/imu/inv_icm20948/inv_icm20948_temp.c | 108 ++++++++++++++++++++
 8 files changed, 352 insertions(+)

diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 15612f0f189b5114deb414ef840339678abdc562..d59e5b0087398cfbd2719ca914fd147ab067155f 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -109,6 +109,7 @@ config KMX61
 	  be called kmx61.
 
 source "drivers/iio/imu/inv_icm42600/Kconfig"
+source "drivers/iio/imu/inv_icm20948/Kconfig"
 source "drivers/iio/imu/inv_mpu6050/Kconfig"
 
 config SMI240
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index e901aea498d37e5897e8b71268356a19eac2cb59..79e49bae59038c1ca1d54a64cf49b6ca5f57cb0b 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
 obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
 
 obj-y += inv_icm42600/
+obj-y += inv_icm20948/
 obj-y += inv_mpu6050/
 
 obj-$(CONFIG_KMX61) += kmx61.o
diff --git a/drivers/iio/imu/inv_icm20948/Kconfig b/drivers/iio/imu/inv_icm20948/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..79ffbe273e71f27ec33fffa0286eafd7dd11aa29
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20948/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config INV_ICM20948
+	tristate
+
+config INV_ICM20948_I2C
+	tristate "InvenSense ICM-20948 I2C driver"
+	depends on I2C
+	select INV_ICM20948
+	select REGMAP_I2C
+	help
+	  This driver supports the InvenSense ICM-20948 motion tracking
+	  device over I2C.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm20948-i2c.
+
diff --git a/drivers/iio/imu/inv_icm20948/Makefile b/drivers/iio/imu/inv_icm20948/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c508c2dc3eee2c32be20067e3e0868a203d8aa1a
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20948/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-$(CONFIG_INV_ICM20948) += inv-icm20948.o
+inv-icm20948-y += inv_icm20948_core.o
+inv-icm20948-y += inv_icm20948_temp.o
+
+obj-$(CONFIG_INV_ICM20948_I2C) += inv-icm20948-i2c.o
+inv-icm20948-i2c-y += inv_icm20948_i2c.o
diff --git a/drivers/iio/imu/inv_icm20948/inv_icm20948.h b/drivers/iio/imu/inv_icm20948/inv_icm20948.h
new file mode 100644
index 0000000000000000000000000000000000000000..f9830645fbe96fd02eef7c54d1e5908647d5a0fe
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20948/inv_icm20948.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2025 Bharadwaj Raju <bharadwaj.raju777@...il.com>
+ */
+
+#ifndef INV_ICM20948_H_
+#define INV_ICM20948_H_
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/err.h>
+
+/* accel takes 20ms, gyro takes 35ms to wake from full-chip sleep */
+#define INV_ICM20948_SLEEP_WAKEUP_MS 35
+
+#define INV_ICM20948_REG_BANK_SEL 0x7F
+#define INV_ICM20948_BANK_SEL_MASK GENMASK(5, 4)
+
+#define INV_ICM20948_REG_WHOAMI 0x0000
+#define INV_ICM20948_WHOAMI 0xEA
+
+#define INV_ICM20948_REG_FIFO_RW 0x0072
+
+#define INV_ICM20948_REG_PWR_MGMT_1 0x0006
+#define INV_ICM20948_PWR_MGMT_1_DEV_RESET BIT(7)
+#define INV_ICM20948_PWR_MGMT_1_SLEEP BIT(6)
+
+#define INV_ICM20948_REG_TEMP_DATA 0x0039
+
+extern const struct regmap_config inv_icm20948_regmap_config;
+
+struct inv_icm20948_state {
+	struct device *dev;
+	struct regmap *regmap;
+	struct iio_dev *temp_dev;
+	struct mutex lock;
+};
+
+extern int inv_icm20948_core_probe(struct regmap *regmap);
+
+struct iio_dev *inv_icm20948_temp_init(struct inv_icm20948_state *state);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm20948/inv_icm20948_core.c b/drivers/iio/imu/inv_icm20948/inv_icm20948_core.c
new file mode 100644
index 0000000000000000000000000000000000000000..ee9e4159cffa261f0326b146a4b3df2cbfbd7697
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20948/inv_icm20948_core.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025 Bharadwaj Raju <bharadwaj.raju777@...il.com>
+ */
+
+#include "inv_icm20948.h"
+
+static const struct regmap_range_cfg inv_icm20948_regmap_ranges[] = {
+	{
+		.name = "user banks",
+		.range_min = 0x0000,
+		.range_max = 0x3FFF,
+		.selector_reg = INV_ICM20948_REG_BANK_SEL,
+		.selector_mask = INV_ICM20948_BANK_SEL_MASK,
+		.window_start = 0,
+		.window_len = 0x1000,
+	},
+};
+
+static const struct regmap_range inv_icm20948_regmap_volatile_yes_ranges[] = {
+	/* WHOAMI */
+	regmap_reg_range(0x0000, 0x0000),
+	/* PWR_MGMT_1 */
+	regmap_reg_range(0x0006, 0x0006),
+	/* I2C and INT status */
+	regmap_reg_range(0x0017, 0x001C),
+	/* Sensor readouts */
+	regmap_reg_range(0x0028, 0x0052),
+	/* FIFO count and data */
+	regmap_reg_range(0x0070, 0x0072),
+	/* Data ready status */
+	regmap_reg_range(0x0074, 0x0074),
+	/* GYRO_CONFIG_1 */
+	regmap_reg_range(0x2001, 0x2001),
+	/* I2C SLV4 data in */
+	regmap_reg_range(0x307F, 0x307F),
+};
+
+static const struct regmap_access_table inv_icm20948_regmap_volatile_accesses = {
+	.yes_ranges = inv_icm20948_regmap_volatile_yes_ranges,
+	.n_yes_ranges = ARRAY_SIZE(inv_icm20948_regmap_volatile_yes_ranges),
+};
+
+static const struct regmap_range inv_icm20948_rd_noinc_no_ranges[] = {
+	regmap_reg_range(0x0000, INV_ICM20948_REG_FIFO_RW - 1),
+	regmap_reg_range(INV_ICM20948_REG_FIFO_RW + 1, 0x3FFF),
+};
+
+static const struct regmap_access_table inv_icm20948_regmap_rd_noinc_table = {
+	.no_ranges = inv_icm20948_rd_noinc_no_ranges,
+	.n_no_ranges = ARRAY_SIZE(inv_icm20948_rd_noinc_no_ranges),
+};
+
+const struct regmap_config inv_icm20948_regmap_config = {
+	.name = "inv_icm20948",
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0x3FFF,
+	.ranges = inv_icm20948_regmap_ranges,
+	.num_ranges = ARRAY_SIZE(inv_icm20948_regmap_ranges),
+	.volatile_table = &inv_icm20948_regmap_volatile_accesses,
+	.rd_noinc_table = &inv_icm20948_regmap_rd_noinc_table,
+	.cache_type = REGCACHE_MAPLE,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm20948_regmap_config, "IIO_ICM20948");
+
+static int inv_icm20948_setup(struct inv_icm20948_state *state)
+{
+	guard(mutex)(&state->lock);
+
+	int reported_whoami;
+	int ret = regmap_read(state->regmap, INV_ICM20948_REG_WHOAMI,
+			      &reported_whoami);
+	if (ret)
+		return ret;
+	if (reported_whoami != INV_ICM20948_WHOAMI) {
+		dev_err(state->dev, "invalid whoami %d, expected %d\n",
+			reported_whoami, INV_ICM20948_WHOAMI);
+		return -ENODEV;
+	}
+
+	ret = regmap_write_bits(state->regmap, INV_ICM20948_REG_PWR_MGMT_1,
+				INV_ICM20948_PWR_MGMT_1_DEV_RESET,
+				INV_ICM20948_PWR_MGMT_1_DEV_RESET);
+	if (ret)
+		return ret;
+	msleep(INV_ICM20948_SLEEP_WAKEUP_MS);
+
+	ret = regmap_write_bits(state->regmap, INV_ICM20948_REG_PWR_MGMT_1,
+				INV_ICM20948_PWR_MGMT_1_SLEEP, 0);
+	if (ret)
+		return ret;
+	msleep(INV_ICM20948_SLEEP_WAKEUP_MS);
+
+	state->temp_dev = inv_icm20948_temp_init(state);
+	if (IS_ERR(state->temp_dev))
+		return PTR_ERR(state->temp_dev);
+
+	return 0;
+}
+
+int inv_icm20948_core_probe(struct regmap *regmap)
+{
+	struct device *dev = regmap_get_device(regmap);
+
+	struct inv_icm20948_state *state;
+
+	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	state->regmap = regmap;
+	state->dev = dev;
+
+	mutex_init(&state->lock);
+
+	return inv_icm20948_setup(state);
+}
+
+MODULE_AUTHOR("Bharadwaj Raju <bharadwaj.raju777@...il.com>");
+MODULE_DESCRIPTION("InvenSense ICM-20948 device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm20948/inv_icm20948_i2c.c b/drivers/iio/imu/inv_icm20948/inv_icm20948_i2c.c
new file mode 100644
index 0000000000000000000000000000000000000000..cf04d82e014a2497592c9a15bbde6e36f431dd56
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20948/inv_icm20948_i2c.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025 Bharadwaj Raju <bharadwaj.raju777@...il.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/property.h>
+
+#include "inv_icm20948.h"
+
+static int inv_icm20948_probe(struct i2c_client *client)
+{
+	struct regmap *regmap =
+		devm_regmap_init_i2c(client, &inv_icm20948_regmap_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return inv_icm20948_core_probe(regmap);
+}
+
+static const struct i2c_device_id inv_icm20948_id[] = { { "icm20948" }, {} };
+MODULE_DEVICE_TABLE(i2c, inv_icm20948_id);
+
+static const struct of_device_id inv_icm20948_of_matches[] = {
+	{ .compatible = "invensense,icm20948" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, inv_icm20948_of_matches);
+
+static struct i2c_driver inv_icm20948_driver = {
+	.driver = {
+		.name = "icm20948",
+		.of_match_table = inv_icm20948_of_matches,
+	},
+	.probe = inv_icm20948_probe,
+	.id_table = inv_icm20948_id,
+};
+module_i2c_driver(inv_icm20948_driver);
+
+MODULE_AUTHOR("Bharadwaj Raju <bharadwaj.raju777@...il.com>");
+MODULE_DESCRIPTION("InvenSense ICM-20948 device driver (I2C)");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM20948");
diff --git a/drivers/iio/imu/inv_icm20948/inv_icm20948_temp.c b/drivers/iio/imu/inv_icm20948/inv_icm20948_temp.c
new file mode 100644
index 0000000000000000000000000000000000000000..916053740cc5acda0316c76504d4086eff5ec7f0
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20948/inv_icm20948_temp.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025 Bharadwaj Raju <bharadwaj.raju777@...il.com>
+ */
+
+#include <linux/bits.h>
+
+#include <linux/iio/iio.h>
+
+#include "inv_icm20948.h"
+
+static const struct iio_chan_spec
+	inv_icm20948_temp_chan = { .type = IIO_TEMP,
+				   .info_mask_separate =
+					   BIT(IIO_CHAN_INFO_RAW) |
+					   BIT(IIO_CHAN_INFO_OFFSET) |
+					   BIT(IIO_CHAN_INFO_SCALE),
+				   .scan_index = 0,
+				   .scan_type = {
+					   .sign = 's',
+					   .realbits = 16,
+				   } };
+
+static int inv_icm20948_temp_read_sensor(struct inv_icm20948_state *state,
+					 s16 *temp)
+{
+	guard(mutex)(&state->lock);
+
+	__be16 raw;
+	int ret = regmap_bulk_read(state->regmap, INV_ICM20948_REG_TEMP_DATA,
+				   &raw, sizeof(raw));
+	if (ret)
+		return ret;
+
+	*temp = __be16_to_cpu(raw);
+
+	return 0;
+}
+
+static int inv_icm20948_temp_read_raw(struct iio_dev *temp_dev,
+				      struct iio_chan_spec const *chan,
+				      int *val, int *val2, long mask)
+{
+	struct inv_icm20948_state *state = iio_device_get_drvdata(temp_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (!iio_device_claim_direct(temp_dev))
+			return -EBUSY;
+		s16 temp;
+		int ret = inv_icm20948_temp_read_sensor(state, &temp);
+
+		if (ret)
+			return ret;
+		iio_device_release_direct(temp_dev);
+		*val = temp;
+		return IIO_VAL_INT;
+	/*
+	 * Sensitivity = 333.87
+	 * RoomTempOff = 21
+	 * T_degC = ((T_raw - RoomTempOff) / Sensitivity) + RoomTempOff
+	 * T_degC = ((T_raw - 21) / 333.87) + 21
+	 * T_milliDegC = 1000 * (((T_raw - 21) / 333.87) + 21)
+	 * T_milliDegC = (1000 / 333.87) * (T_raw - 21 + (21 * 333.87))
+	 * T_milliDegC = (T_raw + 6990.27) * 2.995177
+
+	 * scale = 2.995177
+	 * offset = 6990.27
+	 */
+	case IIO_CHAN_INFO_SCALE:
+		*val = 2;
+		*val2 = 995177;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = 6990;
+		*val2 = 270000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm20948_temp_info = {
+	.read_raw = inv_icm20948_temp_read_raw,
+};
+
+struct iio_dev *inv_icm20948_temp_init(struct inv_icm20948_state *state)
+{
+	struct iio_dev *temp_dev = devm_iio_device_alloc(state->dev, 0);
+
+	if (!temp_dev)
+		return ERR_PTR(-ENOMEM);
+
+	iio_device_set_drvdata(temp_dev, state);
+
+	temp_dev->name = "icm20948-temp";
+	temp_dev->info = &inv_icm20948_temp_info;
+	temp_dev->modes = INDIO_DIRECT_MODE;
+	temp_dev->channels = &inv_icm20948_temp_chan;
+	temp_dev->num_channels = 1;
+
+	int ret = devm_iio_device_register(state->dev, temp_dev);
+
+	if (ret)
+		return ERR_PTR(ret);
+
+	return temp_dev;
+}

-- 
2.51.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ