[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260113114529.1692213-3-aman.kumarpandey@nxp.com>
Date: Tue, 13 Jan 2026 13:45:27 +0200
From: Aman Kumar Pandey <aman.kumarpandey@....com>
To: linux-kernel@...r.kernel.org,
linux-i3c@...ts.infradead.org,
alexandre.belloni@...tlin.com,
krzk+dt@...nel.org,
robh@...nel.org,
conor+dt@...nel.org,
devicetree@...r.kernel.org,
broonie@...nel.org,
lee@...nel.org,
Frank.Li@....com,
lgirdwood@...il.com
Cc: vikash.bansal@....com,
priyanka.jain@....com,
shashank.rebbapragada@....com,
Aman Kumar Pandey <aman.kumarpandey@....com>
Subject: [PATCH v4 3/5] mfd: p3h2x4x: Add driver for NXP P3H2x4x i3c hub and on-die regulator
Add core MFD support for the NXP P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841)
family of multiport I3C hub devices. These devices connect to a host via
I3C/I2C/SMBus and expose multiple downstream target ports.
This patch introduces the MFD driver that registers sub-devices for the
I3C hub and on-die regulators.
Signed-off-by: Aman Kumar Pandey <aman.kumarpandey@....com>
Signed-off-by: Vikash Bansal <vikash.bansal@....com>
---
Changes in v4:
- Split the driver into three separate patches(mfd, regulator and I3C hub)
- Added support for NXP P3H2x4x MFD functionality
---
---
MAINTAINERS | 4 ++
drivers/mfd/Kconfig | 12 ++++
drivers/mfd/Makefile | 2 +
drivers/mfd/p3h2840.c | 128 ++++++++++++++++++++++++++++++++++++
include/linux/mfd/p3h2840.h | 22 +++++++
5 files changed, 168 insertions(+)
create mode 100644 drivers/mfd/p3h2840.c
create mode 100644 include/linux/mfd/p3h2840.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 03a66efbcc4c..aa7043499223 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18931,6 +18931,10 @@ L: linux-kernel@...r.kernel.org
L: linux-i3c-owner@...ts.infradead.org
S: Maintained
F: Documentation/devicetree/bindings/mfd/nxp,p3h2840-i3c-hub.yaml
+F: drivers/mfd/Kconfig
+F: drivers/mfd/Makefile
+F: drivers/mfd/p3h2840.c
+F: include/linux/mfd/p3h2840.h
NXP SGTL5000 DRIVER
M: Fabio Estevam <festevam@...il.com>
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index aace5766b38a..6c41beb0db88 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2540,6 +2540,18 @@ config MFD_RSMU_SPI
Additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_P3H2X4X
+ tristate "NXP P3H2X4X I3C Hub Device"
+ depends on I3C
+ select MFD_CORE
+ select REGMAP_I3C
+ help
+ Enable Support for NXP P3H244x/P3H284x I3C HUB device using I3C/I2c
+ communication interface.
+
+ This driver provides support for I3C Hub and regulator, additional
+ drivers must be enabled in order to use the functionality of the device.
+
config MFD_UPBOARD_FPGA
tristate "Support for the AAeon UP board FPGA"
depends on (X86 && ACPI)
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e75e8045c28a..223142cdd803 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -301,6 +301,8 @@ obj-$(CONFIG_MFD_QNAP_MCU) += qnap-mcu.o
obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o
obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o
+obj-$(CONFIG_MFD_P3H2X4X) += p3h2840.o
+
obj-$(CONFIG_MFD_UPBOARD_FPGA) += upboard-fpga.o
obj-$(CONFIG_MFD_LOONGSON_SE) += loongson-se.o
diff --git a/drivers/mfd/p3h2840.c b/drivers/mfd/p3h2840.c
new file mode 100644
index 000000000000..f6a99291c305
--- /dev/null
+++ b/drivers/mfd/p3h2840.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ * P3H2x4x i3c hub and regulator device.
+ */
+
+#include <linux/i3c/master.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
+#include <linux/mfd/p3h2840.h>
+
+static const struct mfd_cell p3h2x4x_devs[] = {
+ {
+ .name = "p3h2x4x-regulator",
+ },
+ {
+ .name = "p3h2x4x-i3c-hub",
+ },
+};
+
+static const struct regmap_config p3h2x4x_regmap_config = {
+ .reg_bits = P3H2x4x_REG_BITS,
+ .val_bits = P3H2x4x_VAL_BITS,
+ .max_register = 0xFF,
+};
+
+static int p3h2x4x_device_probe_i3c(struct i3c_device *i3cdev)
+{
+ struct p3h2x4x_dev *p3h2x4x;
+ int ret;
+
+ p3h2x4x = devm_kzalloc(&i3cdev->dev, sizeof(*p3h2x4x), GFP_KERNEL);
+ if (!p3h2x4x)
+ return -ENOMEM;
+
+ i3cdev_set_drvdata(i3cdev, p3h2x4x);
+
+ p3h2x4x->regmap = devm_regmap_init_i3c(i3cdev, &p3h2x4x_regmap_config);
+ if (IS_ERR(p3h2x4x->regmap)) {
+ return dev_err_probe(&i3cdev->dev, PTR_ERR(p3h2x4x->regmap),
+ "Failed to register I3C HUB regmap\n");
+ }
+
+ p3h2x4x->is_p3h2x4x_in_i3c = true;
+ p3h2x4x->i3cdev = i3cdev;
+
+ ret = devm_mfd_add_devices(&i3cdev->dev, PLATFORM_DEVID_NONE,
+ p3h2x4x_devs, ARRAY_SIZE(p3h2x4x_devs),
+ NULL, 0, NULL);
+ if (ret)
+ return dev_err_probe(&i3cdev->dev, ret, "Failed to add sub devices\n");
+
+ return 0;
+}
+
+static int p3h2x4x_device_probe_i2c(struct i2c_client *client)
+{
+ struct p3h2x4x_dev *p3h2x4x;
+ int ret;
+
+ p3h2x4x = devm_kzalloc(&client->dev, sizeof(*p3h2x4x), GFP_KERNEL);
+ if (!p3h2x4x)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, p3h2x4x);
+
+ p3h2x4x->regmap = devm_regmap_init_i2c(client, &p3h2x4x_regmap_config);
+ if (IS_ERR(p3h2x4x->regmap)) {
+ ret = PTR_ERR(p3h2x4x->regmap);
+ return dev_err_probe(&client->dev, ret, "Failed to register I3C HUB regmap\n");
+ }
+
+ p3h2x4x->is_p3h2x4x_in_i3c = false;
+ p3h2x4x->i2c_client = client;
+
+ ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+ p3h2x4x_devs, ARRAY_SIZE(p3h2x4x_devs),
+ NULL, 0, NULL);
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "Failed to add sub devices\n");
+
+ return 0;
+}
+
+/* p3h2x4x ids (i3c) */
+static const struct i3c_device_id p3h2x4x_i3c_ids[] = {
+ I3C_CLASS(I3C_DCR_HUB, NULL),
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(i3c, p3h2x4x_i3c_ids);
+
+/* p3h2x4x ids (i2c) */
+static const struct i2c_device_id p3h2x4x_i2c_id_table[] = {
+ { "nxp-i3c-hub" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, p3h2x4x_i2c_id_table);
+
+static const struct of_device_id p3h2x4x_i2c_of_match[] = {
+ { .compatible = "nxp,p3h2840", },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, p3h2x4x_i2c_of_match);
+static struct i3c_driver p3h2x4x_i3c = {
+ .driver = {
+ .name = "p3h2x4x_i3c_drv",
+ },
+ .probe = p3h2x4x_device_probe_i3c,
+ .id_table = p3h2x4x_i3c_ids,
+};
+
+static struct i2c_driver p3h2x4x_i2c = {
+ .driver = {
+ .name = "p3h2x4x_i2c_drv",
+ .of_match_table = p3h2x4x_i2c_of_match,
+ },
+ .probe = p3h2x4x_device_probe_i2c,
+ .id_table = p3h2x4x_i2c_id_table,
+};
+
+module_i3c_i2c_driver(p3h2x4x_i3c, &p3h2x4x_i2c);
+
+MODULE_AUTHOR("Aman Kumar Pandey <aman.kumarpandey@....com>");
+MODULE_AUTHOR("vikash Bansal <vikash.bansal@....com>");
+MODULE_DESCRIPTION("P3H2x4x I3C HUB driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/p3h2840.h b/include/linux/mfd/p3h2840.h
new file mode 100644
index 000000000000..3c989426bb4d
--- /dev/null
+++ b/include/linux/mfd/p3h2840.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2025 NXP
+ * This header file contain private Reg address and its bit mapping etc.
+ */
+
+#ifndef P3H2840_H
+#define P3H2840_H
+
+#include <linux/types.h>
+
+/* Reg config for Regmap */
+#define P3H2x4x_REG_BITS 8
+#define P3H2x4x_VAL_BITS 8
+
+struct p3h2x4x_dev {
+ struct i3c_device *i3cdev;
+ struct i2c_client *i2c_client;
+ struct regmap *regmap;
+ bool is_p3h2x4x_in_i3c;
+};
+#endif /* P3H2840_H */
--
2.25.1
Powered by blists - more mailing lists