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: <20250929094543.2512264-2-lakshay.piplani@nxp.com>
Date: Mon, 29 Sep 2025 15:15:43 +0530
From: Lakshay Piplani <lakshay.piplani@....com>
To: linux-kernel@...r.kernel.org,
	linux-iio@...r.kernel.org,
	jic23@...nel.org,
	dlechner@...libre.com,
	nuno.sa@...log.com,
	andy@...nel.org,
	marcelo.schmitt1@...il.com,
	gregkh@...uxfoundation.org,
	viro@...iv.linux.org.uk,
	peterz@...radead.org,
	jstephan@...libre.com,
	robh@...nel.org,
	krzk+dt@...nel.org,
	conor+dt@...nel.org,
	devicetree@...r.kernel.org,
	jonathan.cameron@...wei.com
Cc: vikash.bansal@....com,
	priyanka.jain@....com,
	shashank.rebbapragada@....com,
	Lakshay Piplani <lakshay.piplani@....com>
Subject: [PATCH v3 2/2] iio: temperature: Add driver for NXP P3T175x temperature sensor

Add support for the NXP P3T175x (P3T1750/P3T1755) family of temperature
sensor devices. These devices communicates via both I2C or I3C interfaces.

Signed-off-by: Lakshay Piplani <lakshay.piplani@....com>
---
V2 -> V3: Changes since V2:
          - Dropped nxp,interrupt-mode and nxp,fault-queue from driver and YAML (not suitable for DT)
          - Removed trigger_one_shot sysfs attribute and its ABI doc
          - Applied IWYU principle: cleaned up unused headers
          - Fixed sampling frequency handling
          - Removed dev_err/dev_dbg statements wherever not necessary
V1 -> V2: Changes since V1:
          - Added endian-safe handling for register read (__be16 conversion)
          - Replaced manual bit masking with FIELD_GET bit extraction
          - Dropped sysfs attributes for fault queue length and thermostat mode (comparator or interrupt)
          - Added ABI doc: Documentation/ABI/testing/sysfs-bus-iio-temperature-p3t1755 describing
            trigger_one_shot attribute
          - Updated Kconfig to allow building both I2C and I3C drivers simultaneously
          - I3C: switched to device_property_* from of_property_*
          - Added devm_add_action_or_reset() for IBI disable/free

 drivers/iio/temperature/Kconfig            |   2 +
 drivers/iio/temperature/p3t/Kconfig        |  28 ++
 drivers/iio/temperature/p3t/Makefile       |   5 +
 drivers/iio/temperature/p3t/p3t1755.h      |  45 +++
 drivers/iio/temperature/p3t/p3t1755_core.c | 362 +++++++++++++++++++++
 drivers/iio/temperature/p3t/p3t1755_i2c.c  |  68 ++++
 drivers/iio/temperature/p3t/p3t1755_i3c.c  | 108 ++++++
 7 files changed, 618 insertions(+)
 create mode 100644 drivers/iio/temperature/p3t/Kconfig
 create mode 100644 drivers/iio/temperature/p3t/Makefile
 create mode 100644 drivers/iio/temperature/p3t/p3t1755.h
 create mode 100644 drivers/iio/temperature/p3t/p3t1755_core.c
 create mode 100644 drivers/iio/temperature/p3t/p3t1755_i2c.c
 create mode 100644 drivers/iio/temperature/p3t/p3t1755_i3c.c

diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index 1244d8e17d50..d249721c1ea1 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -182,4 +182,6 @@ config MCP9600
 	  This driver can also be built as a module. If so, the module
 	  will be called mcp9600.
 
+source "drivers/iio/temperature/p3t/Kconfig"
+
 endmenu
diff --git a/drivers/iio/temperature/p3t/Kconfig b/drivers/iio/temperature/p3t/Kconfig
new file mode 100644
index 000000000000..0cfd881e065b
--- /dev/null
+++ b/drivers/iio/temperature/p3t/Kconfig
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config IIO_P3T1755
+	tristate
+	depends on (I2C || I3C)
+
+config IIO_P3T1755_I2C
+	tristate "NXP P3T1755 temperature sensor I2C driver"
+	select IIO_P3T1755
+	select REGMAP_I2C
+	help
+	  Say yes here to build support for NXP P3T1755 I2C temperature
+	  sensor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called p3t1755_i2c
+
+config IIO_P3T1755_I3C
+	tristate "NXP P3T1755 temperature sensor I3C driver"
+	select IIO_P3T1755
+	select REGMAP_I3C
+	depends on I3C
+	help
+	  Say yes here to build support for NXP P3T1755 I3C temperature
+	  sensor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called p3t1755_i3c
diff --git a/drivers/iio/temperature/p3t/Makefile b/drivers/iio/temperature/p3t/Makefile
new file mode 100644
index 000000000000..7d33b507f1f1
--- /dev/null
+++ b/drivers/iio/temperature/p3t/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_IIO_P3T1755) += p3t1755_core.o
+obj-$(CONFIG_IIO_P3T1755_I2C) += p3t1755_i2c.o
+obj-$(CONFIG_IIO_P3T1755_I3C) += p3t1755_i3c.o
diff --git a/drivers/iio/temperature/p3t/p3t1755.h b/drivers/iio/temperature/p3t/p3t1755.h
new file mode 100644
index 000000000000..1dc0e37322c6
--- /dev/null
+++ b/drivers/iio/temperature/p3t/p3t1755.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * NXP P3T175x Temperature Sensor Driver
+ *
+ * Copyright 2025 NXP
+ */
+#ifndef P3T1755_H
+#define P3T1755_H
+
+#include <linux/bits.h>
+#include <linux/iio/iio.h>
+
+#define P3T1755_REG_TEMP	0x0
+#define P3T1755_REG_CFGR	0x1
+#define P3T1755_REG_LOW_LIM	0x2
+#define P3T1755_REG_HIGH_LIM	0x3
+
+#define P3T1755_SHUTDOWN_BIT	BIT(0)
+#define P3T1755_TM_BIT	BIT(1)
+#define P3T1755_POL_BIT	BIT(2)
+#define P3T1755_ONE_SHOT_BIT	BIT(7)
+
+#define P3T1755_CONVERSION_TIME_BITS	GENMASK(6, 5)
+
+struct p3t1755_info {
+	const char *name;
+	const struct iio_chan_spec *channels;
+	int num_channels;
+};
+
+struct p3t1755_data {
+	struct device *dev;
+	struct regmap *regmap;
+};
+
+extern const struct p3t1755_info p3t1750_channels_info;
+extern const struct p3t1755_info p3t1755_channels_info;
+
+int p3t1755_probe(struct device *dev, const struct p3t1755_info *chip,
+		  struct regmap *regmap, int irq);
+int p3t1755_get_temp_and_limits(struct p3t1755_data *data,
+				int *temp_raw, int *thigh_raw, int *tlow_raw);
+void p3t1755_push_thresh_event(struct iio_dev *indio_dev);
+
+#endif /* P3T1755_H */
diff --git a/drivers/iio/temperature/p3t/p3t1755_core.c b/drivers/iio/temperature/p3t/p3t1755_core.c
new file mode 100644
index 000000000000..61486eb0e265
--- /dev/null
+++ b/drivers/iio/temperature/p3t/p3t1755_core.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * NXP P3T175x Temperature Sensor Driver
+ *
+ * Copyright 2025 NXP
+ */
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+
+#include "p3t1755.h"
+
+static const u32 p3t1755_samp_freqs_uhz[] = {
+	36363636,
+	18181818,
+	9090909,
+	4545454
+};
+
+int p3t1755_get_temp_and_limits(struct p3t1755_data *data,
+				int *temp_raw, int *thigh_raw, int *tlow_raw)
+{
+	__be16 be;
+	int ret;
+	int raw12;
+
+	ret = regmap_bulk_read(data->regmap, P3T1755_REG_TEMP, &be, sizeof(be));
+	if (ret)
+		return ret;
+
+	raw12 = sign_extend32(be16_to_cpu(be) >> 4, 11);
+	*temp_raw = raw12;
+
+	ret = regmap_bulk_read(data->regmap, P3T1755_REG_HIGH_LIM, &be, sizeof(be));
+	if (ret)
+		return ret;
+
+	raw12 = sign_extend32(be16_to_cpu(be) >> 4, 11);
+	*thigh_raw = raw12;
+
+	ret = regmap_bulk_read(data->regmap, P3T1755_REG_LOW_LIM, &be, sizeof(be));
+	if (ret)
+		return ret;
+
+	raw12 = sign_extend32(be16_to_cpu(be) >> 4, 11);
+	*tlow_raw = raw12;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(p3t1755_get_temp_and_limits, IIO_P3T1755);
+
+void p3t1755_push_thresh_event(struct iio_dev *indio_dev)
+{
+	struct p3t1755_data *data = iio_priv(indio_dev);
+	int ret, temp, thigh, tlow;
+	unsigned int cfgr;
+
+	/*
+	 * Read CFGR register to check device mode and implicitly clear the ALERT latch.
+	 * As per Datasheet: "Any register read will clear the interrupt"
+	 */
+	ret = regmap_read(data->regmap, P3T1755_REG_CFGR, &cfgr);
+	if (ret) {
+		dev_err(data->dev, "Failed to read CFGR register: %d\n", ret);
+		return;
+	}
+
+	if (FIELD_GET(P3T1755_SHUTDOWN_BIT, cfgr)) {
+		dev_dbg(data->dev, "Device is in shutdown mode, skipping event push\n");
+		return;
+	}
+
+	ret = p3t1755_get_temp_and_limits(data, &temp, &thigh, &tlow);
+	if (ret) {
+		dev_err(data->dev, "Failed to get temperature and limits: %d\n", ret);
+		return;
+	}
+
+	if (temp >= thigh || temp <= tlow) {
+		dev_dbg(data->dev, "Threshold event: DIR_EITHER (T=%d, TH=%d, TL=%d)\n",
+			temp, thigh, tlow);
+
+		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_TEMP, 0, IIO_NO_MOD,
+							     IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
+			       iio_get_time_ns(indio_dev));
+	} else {
+		dev_dbg(data->dev, "Temperature within limits: no event triggered (T=%d, TH=%d, TL=%d)\n",
+			temp, thigh, tlow);
+	}
+}
+EXPORT_SYMBOL_NS_GPL(p3t1755_push_thresh_event, IIO_P3T1755);
+
+static int p3t1755_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *channel, int *val,
+			    int *val2, long mask)
+{
+	struct p3t1755_data *data = iio_priv(indio_dev);
+	unsigned int cfgr;
+	__be16 be;
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = regmap_bulk_read(data->regmap, P3T1755_REG_TEMP, &be, sizeof(be));
+		if (ret)
+			return ret;
+
+		*val = sign_extend32(be16_to_cpu(be) >> 4, 11);
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = 625;
+		*val2 = 10000;
+
+		return IIO_VAL_FRACTIONAL;
+
+	case IIO_CHAN_INFO_ENABLE:
+		ret = regmap_read(data->regmap, P3T1755_REG_CFGR, &cfgr);
+		if (ret)
+			return ret;
+
+		*val = !FIELD_GET(P3T1755_SHUTDOWN_BIT, cfgr);
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SAMP_FREQ: {
+		unsigned int freq_uhz;
+		u8 sel;
+
+		ret = regmap_read(data->regmap, P3T1755_REG_CFGR, &cfgr);
+		if (ret)
+			return ret;
+
+		sel = FIELD_GET(P3T1755_CONVERSION_TIME_BITS, cfgr);
+		if (sel >= ARRAY_SIZE(p3t1755_samp_freqs_uhz))
+			return -EINVAL;
+
+		freq_uhz = p3t1755_samp_freqs_uhz[sel];
+
+		*val = freq_uhz / 1000000;
+		*val2 = freq_uhz % 1000000;
+
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int p3t1755_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int val,
+			     int val2, long mask)
+{
+	struct p3t1755_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_ENABLE:
+		ret = regmap_update_bits(data->regmap, P3T1755_REG_CFGR,
+					 P3T1755_SHUTDOWN_BIT,
+					 val == 0 ? P3T1755_SHUTDOWN_BIT : 0);
+		if (ret)
+			return ret;
+
+		return 0;
+	case IIO_CHAN_INFO_SAMP_FREQ: {
+		unsigned int i;
+		u32 regbits;
+		u64 input_uhz;
+
+		input_uhz = (u64)val * 1000000 + val2;
+
+		for (i = 0; i < ARRAY_SIZE(p3t1755_samp_freqs_uhz); i++) {
+			if (p3t1755_samp_freqs_uhz[i] == input_uhz)
+				break;
+		}
+
+		if (i == ARRAY_SIZE(p3t1755_samp_freqs_uhz))
+			return -EINVAL;
+
+		regbits = FIELD_PREP(P3T1755_CONVERSION_TIME_BITS, i);
+
+		return regmap_update_bits(data->regmap, P3T1755_REG_CFGR,
+					  P3T1755_CONVERSION_TIME_BITS,
+					  regbits);
+	}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int p3t1755_read_event_value(struct iio_dev *indio_dev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir,
+				    enum iio_event_info info, int *val,
+				    int *val2)
+{
+	struct p3t1755_data *data = iio_priv(indio_dev);
+	unsigned int reg;
+	__be16 be;
+	int ret, raw;
+
+	if (type != IIO_EV_TYPE_THRESH || info != IIO_EV_INFO_VALUE)
+		return -EINVAL;
+
+	reg = (dir == IIO_EV_DIR_RISING) ? P3T1755_REG_HIGH_LIM :
+	       P3T1755_REG_LOW_LIM;
+
+	ret = regmap_bulk_read(data->regmap, reg, &be, sizeof(be));
+	if (ret)
+		return ret;
+
+	raw = sign_extend32(be16_to_cpu(be) >> 4, 11);
+	*val = DIV_ROUND_CLOSEST(raw * 125, 2);
+
+	return IIO_VAL_INT;
+}
+
+static int p3t1755_write_event_value(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir,
+				     enum iio_event_info info,
+				     int val, int val2)
+{
+	struct p3t1755_data *data = iio_priv(indio_dev);
+	unsigned int reg;
+	__be16 be;
+	int raw;
+
+	if (type != IIO_EV_TYPE_THRESH || info != IIO_EV_INFO_VALUE)
+		return -EINVAL;
+
+	if (val2)
+		return -EINVAL;
+
+	reg = (dir == IIO_EV_DIR_RISING) ? P3T1755_REG_HIGH_LIM :
+	       P3T1755_REG_LOW_LIM;
+
+	raw = DIV_ROUND_CLOSEST(val * 2, 125);
+
+	if (raw < -2048 || raw > 2047)
+		return -ERANGE;
+
+	be = cpu_to_be16((u16)(raw << 4));
+
+	return regmap_raw_write(data->regmap, reg, &be, sizeof(be));
+}
+
+static const struct iio_event_spec p3t1755_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	},
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	},
+};
+
+static const struct iio_chan_spec p3t1755_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_ENABLE) |
+				      BIT(IIO_CHAN_INFO_SAMP_FREQ),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+		.event_spec = p3t1755_events,
+		.num_event_specs = ARRAY_SIZE(p3t1755_events),
+	},
+};
+
+const struct p3t1755_info p3t1755_channels_info = {
+	.name = "p3t1755",
+	.channels = p3t1755_channels,
+	.num_channels = ARRAY_SIZE(p3t1755_channels),
+};
+EXPORT_SYMBOL_NS(p3t1755_channels_info, IIO_P3T1755);
+
+const struct p3t1755_info p3t1750_channels_info = {
+	.name = "p3t1750",
+	.channels = p3t1755_channels,
+	.num_channels = ARRAY_SIZE(p3t1755_channels),
+};
+EXPORT_SYMBOL_NS(p3t1750_channels_info, IIO_P3T1755);
+
+static const struct iio_info p3t1755_info = {
+	.read_raw = p3t1755_read_raw,
+	.write_raw = p3t1755_write_raw,
+	.read_event_value = p3t1755_read_event_value,
+	.write_event_value = p3t1755_write_event_value,
+};
+
+static irqreturn_t p3t1755_irq_handler(int irq, void *dev_id)
+{
+	struct iio_dev *indio_dev = dev_id;
+
+	dev_dbg(&indio_dev->dev, "IRQ triggered, processing threshold event\n");
+
+	p3t1755_push_thresh_event(indio_dev);
+
+	return IRQ_HANDLED;
+}
+
+int p3t1755_probe(struct device *dev, const struct p3t1755_info *chip,
+		  struct regmap *regmap, int irq)
+{
+	struct p3t1755_data *data;
+	struct iio_dev *iio_dev;
+	int ret;
+
+	iio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!iio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(iio_dev);
+	data->dev = dev;
+	data->regmap = regmap;
+
+	iio_dev->name = chip->name;
+	iio_dev->modes = INDIO_DIRECT_MODE;
+	iio_dev->info = &p3t1755_info;
+	iio_dev->channels = chip->channels;
+	iio_dev->num_channels = chip->num_channels;
+
+	ret = regmap_update_bits(data->regmap, P3T1755_REG_CFGR,
+				 P3T1755_TM_BIT, P3T1755_TM_BIT);
+	if (ret)
+		return dev_err_probe(data->dev, ret, "Failed to update TM bit\n");
+
+	ret = devm_iio_device_register(dev, iio_dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Temperature sensor failed to register\n");
+
+	if (irq > 0) {
+		ret = devm_request_threaded_irq(dev, irq, NULL,
+						p3t1755_irq_handler, IRQF_ONESHOT,
+						"p3t175xdp", iio_dev);
+		if (ret)
+			dev_err_probe(dev, ret, "Failed to request IRQ: %d\n", ret);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_NS(p3t1755_probe, IIO_P3T1755);
+
+MODULE_AUTHOR("Lakshay Piplani <lakshay.piplani@....com>");
+MODULE_DESCRIPTION("NXP P3T175x Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/temperature/p3t/p3t1755_i2c.c b/drivers/iio/temperature/p3t/p3t1755_i2c.c
new file mode 100644
index 000000000000..f5d7799f091c
--- /dev/null
+++ b/drivers/iio/temperature/p3t/p3t1755_i2c.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * NXP P3T175x Temperature Sensor Driver
+ *
+ * Copyright 2025 NXP
+ */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "p3t1755.h"
+
+static const struct regmap_config p3t1755_i2c_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static const struct of_device_id p3t1755_i2c_of_match[] = {
+	{ .compatible = "nxp,p3t1750dp", .data = &p3t1750_channels_info },
+	{ .compatible = "nxp,p3t1755dp", .data = &p3t1755_channels_info },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, p3t1755_i2c_of_match);
+
+static const struct i2c_device_id p3t1755_i2c_id_table[] = {
+	{ "p3t1750", (kernel_ulong_t)&p3t1750_channels_info },
+	{ "p3t1755", (kernel_ulong_t)&p3t1755_channels_info },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, p3t1755_i2c_id_table);
+
+static int p3t1755_i2c_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	const struct p3t1755_info *chip;
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_i2c(client, &p3t1755_i2c_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "regmap init failed\n");
+
+	chip = i2c_get_match_data(client);
+
+	ret = p3t1755_probe(dev, chip, regmap, client->irq);
+
+	if (ret)
+		return dev_err_probe(dev, ret, "p3t175x probe failed: %d\n", ret);
+
+	return 0;
+}
+
+static struct i2c_driver p3t1755_driver = {
+	.driver = {
+		.name = "p3t175x_i2c",
+		.of_match_table = p3t1755_i2c_of_match,
+	},
+	.probe = p3t1755_i2c_probe,
+	.id_table = p3t1755_i2c_id_table,
+};
+module_i2c_driver(p3t1755_driver);
+
+MODULE_AUTHOR("Lakshay Piplani <lakshay.piplani@....com>");
+MODULE_DESCRIPTION("NXP P3T175x I2C Driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_P3T1755);
diff --git a/drivers/iio/temperature/p3t/p3t1755_i3c.c b/drivers/iio/temperature/p3t/p3t1755_i3c.c
new file mode 100644
index 000000000000..df031280e08d
--- /dev/null
+++ b/drivers/iio/temperature/p3t/p3t1755_i3c.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NXP P3T175x Temperature Sensor Driver
+ *
+ * Copyright 2025 NXP
+ */
+#include <linux/i3c/device.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/events.h>
+
+#include "p3t1755.h"
+
+static const struct regmap_config p3t1755_i3c_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static void p3t1755_ibi_handler(struct i3c_device *dev,
+				const struct i3c_ibi_payload *payload)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(&dev->dev);
+
+	p3t1755_push_thresh_event(indio_dev);
+}
+
+/*
+ * Both P3T1755 and P3T1750 share the same I3C PID (0x011B:0x152A),
+ * making runtime differentiation impossible, so using "p3t1755" as
+ * name in sysfs and IIO for I3C based instances.
+ */
+static const struct i3c_device_id p3t1755_i3c_ids[] = {
+	I3C_DEVICE(0x011B, 0x152A, &p3t1755_channels_info),
+	{ }
+};
+MODULE_DEVICE_TABLE(i3c, p3t1755_i3c_ids);
+
+static void p3t1755_disable_ibi(void *data)
+{
+	i3c_device_disable_ibi((struct i3c_device *)data);
+}
+
+static void p3t1755_free_ibi(void *data)
+{
+	i3c_device_free_ibi((struct i3c_device *)data);
+}
+
+static int p3t1755_i3c_probe(struct i3c_device *i3cdev)
+{
+	const struct i3c_device_id *id = i3c_device_match_id(i3cdev, p3t1755_i3c_ids);
+	const struct p3t1755_info *chip;
+	struct device *dev = &i3cdev->dev;
+	struct i3c_ibi_setup ibi_setup;
+	struct regmap *regmap;
+	int ret;
+
+	chip = id ? id->data : NULL;
+
+	regmap = devm_regmap_init_i3c(i3cdev, &p3t1755_i3c_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(&i3cdev->dev, PTR_ERR(regmap),
+				     "Failed to register I3C regmap %ld\n", PTR_ERR(regmap));
+
+	ret = p3t1755_probe(dev, chip, regmap, 0);
+	if (ret)
+		return dev_err_probe(dev, ret, "p3t175x probe failed: %d\n", ret);
+
+	ibi_setup = (struct i3c_ibi_setup) {
+		.handler = p3t1755_ibi_handler,
+		.num_slots = 4,
+		.max_payload_len = 0,
+	};
+
+	ret = i3c_device_request_ibi(i3cdev, &ibi_setup);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to request IBI\n");
+
+	ret = devm_add_action_or_reset(dev, p3t1755_free_ibi, i3cdev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register IBI free action\n");
+
+	ret = i3c_device_enable_ibi(i3cdev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable IBI\n");
+
+	ret = devm_add_action_or_reset(dev, p3t1755_disable_ibi, i3cdev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register IBI disable action\n");
+
+	return 0;
+}
+
+static struct i3c_driver p3t1755_driver = {
+	.driver = {
+		.name = "p3t175x_i3c",
+	},
+	.probe = p3t1755_i3c_probe,
+	.id_table = p3t1755_i3c_ids,
+};
+module_i3c_driver(p3t1755_driver);
+
+MODULE_AUTHOR("Lakshay Piplani <lakshay.piplani@....com>");
+MODULE_DESCRIPTION("NXP P3T175x I3C Driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_P3T1755);
-- 
2.25.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ