From wsa+renesas at sang-engineering.com  Tue May  6 00:52:11 2025
From: wsa+renesas at sang-engineering.com (Wolfram Sang)
Date: Tue,  6 May 2025 09:52:11 +0200
Subject: [PATCH] i3c: controllers do not need to depend on I3C
Message-ID: <20250506075247.1545-2-wsa+renesas@sang-engineering.com>

The Kconfig file for controller drivers is only sourced if the I3C
symbol is enabled. No need to check for that in individual drivers.

Signed-off-by: Wolfram Sang <wsa+renesas at sang-engineering.com>
---

Based on linux-next.

 drivers/i3c/master/Kconfig | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig
index 77da199c7413..7b30db3253af 100644
--- a/drivers/i3c/master/Kconfig
+++ b/drivers/i3c/master/Kconfig
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config CDNS_I3C_MASTER
 	tristate "Cadence I3C master driver"
-	depends on I3C
 	depends on HAS_IOMEM
 	depends on !(ALPHA || PARISC)
 	help
@@ -9,7 +8,6 @@ config CDNS_I3C_MASTER
 
 config DW_I3C_MASTER
 	tristate "Synospsys DesignWare I3C master driver"
-	depends on I3C
 	depends on HAS_IOMEM
 	depends on !(ALPHA || PARISC)
 	# ALPHA and PARISC needs {read,write}sl()
@@ -38,7 +36,6 @@ config AST2600_I3C_MASTER
 
 config SVC_I3C_MASTER
 	tristate "Silvaco I3C Dual-Role Master driver"
-	depends on I3C
 	depends on HAS_IOMEM
 	depends on !(ALPHA || PARISC)
 	help
@@ -46,7 +43,6 @@ config SVC_I3C_MASTER
 
 config MIPI_I3C_HCI
 	tristate "MIPI I3C Host Controller Interface driver (EXPERIMENTAL)"
-	depends on I3C
 	depends on HAS_IOMEM
 	help
 	  Support for hardware following the MIPI Aliance's I3C Host Controller
-- 
2.47.2



From quic_msavaliy at quicinc.com  Wed May  7 08:55:10 2025
From: quic_msavaliy at quicinc.com (Mukesh Kumar Savaliya)
Date: Wed, 7 May 2025 21:25:10 +0530
Subject: [External] : [PATCH v5 2/3] :i3c: master: Add Qualcomm I3C
 controller driver
In-Reply-To: <06a94366-cc81-4127-9edc-501e696301b0@oracle.com>
References: <20250420081530.2708238-1-quic_msavaliy@quicinc.com>
 <20250420081530.2708238-3-quic_msavaliy@quicinc.com>
 <06a94366-cc81-4127-9edc-501e696301b0@oracle.com>
Message-ID: <dbd50a7f-53ed-45d5-9973-2e2512b843e3@quicinc.com>


Thanks Alok ! Since there are no other major comments except the 
cosmetic changes, will address your comments and make all the changes 
suggested in final Patch V6.

On 4/21/2025 1:07 AM, ALOK TIWARI wrote:
> Hi Mukesh,
> 
> On 20-04-2025 13:45, Mukesh Kumar Savaliya wrote:
>> Add support for the Qualcomm I3C controller driver, which implements
>> I3C master functionality as defined in the MIPI Alliance Specification
>> for I3C, Version 1.0.
>>
>> This driver supports master role in SDR mode.
>>
>> Unlike some other I3C master controllers, this implementation
>> does not support In-Band Interrupts (IBI) and Hot-join requests.
>>
>> Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy at quicinc.com>
>> ---
> [clip]
>> +};
>> +
>> +/*
>> + * Hardware uses the underlying formula to calculate time periods of
>> + * SCL clock cycle. Firmware uses some additional cycles excluded 
>> from the
>> + * below formula and it is confirmed that the time periods are within
>> + * specification limits.
>> + *
>> + * time of high period of I2C SCL:
>> + *???????? i2c_t_high = (i2c_t_high_cnt * clk_div) / source_clock
>> + * time of low period of I2C SCL:
>> + *???????? i2c_t_low = (i2c_t_low_cnt * clk_div) / source_clock
>> + * time of full period of I2C SCL:
>> + *???????? i2c_t_cycle = (i2c_t_cycle_cnt * clk_div) / source_clock
>> + * time of high period of I3C SCL:
>> + *???????? i3c_t_high = (i3c_t_high_cnt * clk_div) / source_clock
>> + * time of full period of I3C SCL:
>> + *???????? i3c_t_cycle = (i3c_t_cycle_cnt * clk_div) / source_clock
>> + * clk_freq_out = t / t_cycle
>> + */
> 
> Here is a polished version, if you'd like. Otherwise, feel free to 
> ignore it
> /*
>  ?* The hardware uses the following formulas to calculate the time periods
>  ?* of the SCL clock cycle. The firmware adds a few extra cycles that 
> are not
>  ?* included in the formulas below. It has been verified that the resulting
>  ?* timings remain within the I2C/I3C specification limits.
>  ?*
>  ?* I2C SCL high period:
>  ?*???? i2c_t_high = (i2c_t_high_cnt * clk_div) / source_clock
>  ?*
>  ?* I2C SCL low period:
>  ?*???? i2c_t_low = (i2c_t_low_cnt * clk_div) / source_clock
>  ?*
>  ?* I2C SCL full cycle:
>  ?*???? i2c_t_cycle = (i2c_t_cycle_cnt * clk_div) / source_clock
>  ?*
>  ?* I3C SCL high period:
>  ?*???? i3c_t_high = (i3c_t_high_cnt * clk_div) / source_clock
>  ?*
>  ?* I3C SCL full cycle:
>  ?*???? i3c_t_cycle = (i3c_t_cycle_cnt * clk_div) / source_clock
>  ?*
>  ?* Output clock frequency:
>  ?*???? clk_freq_out = t / t_cycle
>  ?*/
> 
Sure, will make the changes.
>> +static const struct geni_i3c_clk_settings geni_i3c_clk_map[] = {
>> +??? {
>> +??????? .clk_freq_out = 100 * HZ_PER_KHZ,
>> +??????? .clk_src_freq = 19200 * HZ_PER_KHZ,
>> +??????? .clk_div = 1,
>> +??????? .i2c_t_high_cnt = 76,
>> +??????? .i2c_t_low_cnt = 90,
>> +??????? .i3c_t_high_cnt = 7,
>> +??????? .i3c_t_cycle_cnt = 8,
>> +??????? .i2c_t_cycle_cnt = 192,
>> +??? },
> [clip]
>> +
>> +static int i3c_geni_execute_read_command(struct geni_i3c_dev *gi3c,
>> +???????????????????? struct geni_i3c_xfer_params *xfer, u8 *buf, u32 
>> len)
>> +{
>> +??? gi3c->cur_is_write = false;
>> +??? gi3c->cur_buf = buf;
>> +??? gi3c->cur_len = len;
> 
> a '\n' before return
> 
Done
>> +??? return _i3c_geni_execute_command(gi3c, xfer);
>> +}
>> +
>> +static int i3c_geni_execute_write_command(struct geni_i3c_dev *gi3c,
>> +????????????????????? struct geni_i3c_xfer_params *xfer, u8 *buf, u32 
>> len)
>> +{
>> +??? gi3c->cur_is_write = true;
>> +??? gi3c->cur_buf = buf;
>> +??? gi3c->cur_len = len;
> 
> a '\n' before return
> 
done
>> +??? return _i3c_geni_execute_command(gi3c, xfer);
>> +}
>> +
>> +static void geni_i3c_perform_daa(struct geni_i3c_dev *gi3c)
>> +{
>> +??? u8 last_dyn_addr = 0;
>> +??? int ret;
>> +
>> +??? while (1) {
>> +??????? u8 rx_buf[8], tx_buf[8];
>> +??????? struct geni_i3c_xfer_params xfer = { GENI_SE_FIFO };
>> +??????? struct i3c_device_info info = { 0 };
>> +??????? struct i3c_dev_desc *i3cdev;
>> +??????? bool new_device = true;
>> +??????? u64 pid;
>> +??????? u8 bcr, dcr, addr;
>> +
>> +??????? xfer.m_cmd = I2C_READ;
>> +??????? xfer.m_param = STOP_STRETCH | CONTINUOUS_MODE_DAA | USE_7E;
>> +??????? ret = i3c_geni_execute_read_command(gi3c, &xfer, rx_buf, 8);
>> +??????? if (ret)
>> +??????????? break;
>> +
>> +??????? dcr = FIELD_PREP(GENMASK(7, 0), rx_buf[7]);
>> +??????? bcr = FIELD_PREP(GENMASK(7, 0), rx_buf[6]);
>> +??????? pid = FIELD_PREP(GENMASK(47, 40), (u64)rx_buf[0]) |
>> +??????????? FIELD_PREP(GENMASK(39, 32), (u64)rx_buf[1]) |
>> +??????????? FIELD_PREP(GENMASK(31, 24), (u64)rx_buf[2]) |
>> +??????????? FIELD_PREP(GENMASK(23, 16), (u64)rx_buf[3]) |
>> +??????????? FIELD_PREP(GENMASK(15, 8), (u64)rx_buf[4]) |
>> +??????????? FIELD_PREP(GENMASK(7, 0), (u64)rx_buf[5]);
>> +
>> +??????? i3c_bus_for_each_i3cdev(&gi3c->ctrlr.bus, i3cdev) {
>> +??????????? i3c_device_get_info(i3cdev->dev, &info);
>> +??????????? if (pid == info.pid && dcr == info.dcr && bcr == info.bcr) {
>> +??????????????? new_device = false;
>> +??????????????? addr = info.dyn_addr ? : info.static_addr;
>> +??????????????? break;
>> +??????????? }
>> +??????? }
>> +
>> +??????? if (new_device) {
>> +??????????? ret = i3c_master_get_free_addr(&gi3c->ctrlr, 
>> last_dyn_addr + 1);
>> +??????????? if (ret < 0)
>> +??????????????? break;
>> +??????????? addr = (u8)ret;
>> +??????????? last_dyn_addr = addr;
>> +??????????? set_new_addr_slot(gi3c->newaddrslots, addr);
>> +??????? }
>> +
>> +??????? /* Set Parity bit at BIT(7) */
>> +??????? tx_buf[0] = (addr & I3C_ADDR_MASK) << 1;
>> +??????? tx_buf[0] |= parity8(addr & I3C_ADDR_MASK);
>> +
>> +??????? xfer.m_cmd = I2C_WRITE;
>> +??????? xfer.m_param = STOP_STRETCH | BYPASS_ADDR_PHASE | USE_7E;
>> +
>> +??????? ret = i3c_geni_execute_write_command(gi3c, &xfer, tx_buf, 1);
>> +??????? if (ret)
>> +??????????? break;
>> +??? }
>> +}
>> +
>> +static int geni_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
>> +??????????????????? struct i3c_ccc_cmd *cmd)
>> +{
>> +??? struct geni_i3c_dev *gi3c = to_geni_i3c_master(m);
>> +??? int i, ret;
>> +
>> +??? if (!(cmd->id & I3C_CCC_DIRECT) && cmd->ndests != 1)
>> +??????? return -EINVAL;
>> +
>> +??? ret = i3c_geni_runtime_get_mutex_lock(gi3c);
>> +??? if (ret)
>> +??????? return ret;
>> +
>> +??? qcom_geni_i3c_conf(gi3c, OPEN_DRAIN_MODE);
>> +??? for (i = 0; i < cmd->ndests; i++) {
>> +??????? int stall = (i < (cmd->ndests - 1)) ||
>> +??????????? (cmd->id == I3C_CCC_ENTDAA);
>> +??????? struct geni_i3c_xfer_params xfer = { GENI_SE_FIFO };
>> +
>> +??????? xfer.m_param? = (stall ? STOP_STRETCH : 0);
> 
> remove extra ' ' before =
sure
> 
>> +??????? xfer.m_param |= FIELD_PREP(CCC_HDR_CMD_MSK, cmd->id);
>> +??????? xfer.m_param |= IBI_NACK_TBL_CTRL;
>> +??????? if (cmd->id & I3C_CCC_DIRECT) {
>> +??????????? xfer.m_param |= FIELD_PREP(SLAVE_ADDR_MASK, cmd- 
>> >dests[i].addr);
>> +??????????? if (cmd->rnw) {
>> +??????????????? if (i == 0)
>> +??????????????????? xfer.m_cmd = I3C_DIRECT_CCC_READ;
>> +??????????????? else
>> +??????????????????? xfer.m_cmd = I3C_PRIVATE_READ;
>> +??????????? } else {
>> +??????????????? if (i == 0)
>> +??????????????????? xfer.m_cmd =
>> +?????????????????????? (cmd->dests[i].payload.len > 0) ?
>> +??????????????????????? I3C_DIRECT_CCC_WRITE :
>> +??????????????????????? I3C_DIRECT_CCC_ADDR_ONLY;
>> +??????????????? else
>> +??????????????????? xfer.m_cmd = I3C_PRIVATE_WRITE;
>> +??????????? }
>> +??????? } else {
>> +??????????? if (cmd->dests[i].payload.len > 0)
>> +??????????????? xfer.m_cmd = I3C_BCAST_CCC_WRITE;
>> +??????????? else
>> +??????????????? xfer.m_cmd = I3C_BCAST_CCC_ADDR_ONLY;
>> +??????? }
>> +
>> +??????? if (i == 0)
>> +??????????? xfer.m_param |= USE_7E;
>> +
>> +??????? if (cmd->rnw)
>> +??????????? ret = i3c_geni_execute_read_command(gi3c, &xfer,
>> +??????????????????????????????? cmd->dests[i].payload.data,
>> +??????????????????????????????? cmd->dests[i].payload.len);
>> +??????? else
>> +??????????? ret = i3c_geni_execute_write_command(gi3c, &xfer,
>> +???????????????????????????????? cmd->dests[i].payload.data,
>> +???????????????????????????????? cmd->dests[i].payload.len);
>> +??????? if (ret)
>> +??????????? break;
>> +
>> +??????? if (cmd->id == I3C_CCC_ENTDAA)
>> +??????????? geni_i3c_perform_daa(gi3c);
>> +??? }
>> +
>> +??? i3c_geni_runtime_put_mutex_unlock(gi3c);
> 
> a '\n' before return
> 
Done
>> +??? return ret;
>> +}
>> +
>> +static int geni_i3c_master_priv_xfers(struct i3c_dev_desc *dev, 
>> struct i3c_priv_xfer *xfers,
>> +????????????????????? int nxfers)
>> +{
>> +??? struct i3c_master_controller *m = i3c_dev_get_master(dev);
>> +??? struct geni_i3c_dev *gi3c = to_geni_i3c_master(m);
>> +??? bool use_7e = false;
>> +??? int i, ret;
>> +
>> +??? ret = i3c_geni_runtime_get_mutex_lock(gi3c);
>> +??? if (ret)
>> +??????? return ret;
>> +
>> +??? qcom_geni_i3c_conf(gi3c, PUSH_PULL_MODE);
>> +
>> +??? for (i = 0; i < nxfers; i++) {
>> +??????? bool stall = (i < (nxfers - 1));
>> +??????? struct geni_i3c_xfer_params xfer = { GENI_SE_FIFO };
>> +
>> +??????? xfer.m_param? = (stall ? STOP_STRETCH : 0);
> 
> remove extra ' ' before =
> 
Done
>> +??????? xfer.m_param |= FIELD_PREP(SLAVE_ADDR_MASK, dev->info.dyn_addr);
>> +??????? xfer.m_param |= (use_7e) ? USE_7E : 0;
>> +
>> +??????? /* use_7e = true only for last transfer */
>> +??????? use_7e = (i == nxfers - 1);
>> +
>> +??????? if (xfers[i].rnw) {
>> +??????????? xfer.m_cmd = I3C_PRIVATE_READ;
>> +??????????? ret = i3c_geni_execute_read_command(gi3c, &xfer, (u8 
>> *)xfers[i].data.in,
>> +??????????????????????????????? xfers[i].len);
>> +??????? } else {
>> +??????????? xfer.m_cmd = I3C_PRIVATE_WRITE;
>> +??????????? ret = i3c_geni_execute_write_command(gi3c, &xfer, (u8 
>> *)xfers[i].data.out,
>> +???????????????????????????????? xfers[i].len);
>> +??????? }
>> +
>> +??????? if (ret)
>> +??????????? break;
>> +??? }
>> +
>> +??? dev_dbg(gi3c->se.dev, "i3c priv: txn ret:%d\n", ret);
>> +??? i3c_geni_runtime_put_mutex_unlock(gi3c);
> 
> a '\n' before return
> 
Done
>> +??? return ret;
>> +}
>> +
>> +static int geni_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, struct 
>> i2c_msg *msgs, int num)
>> +{
>> +??? struct i3c_master_controller *m = i2c_dev_get_master(dev);
>> +??? struct geni_i3c_dev *gi3c = to_geni_i3c_master(m);
>> +??? int i, ret;
>> +
>> +??? ret = i3c_geni_runtime_get_mutex_lock(gi3c);
>> +??? if (ret)
>> +??????? return ret;
>> +
>> +??? qcom_geni_i3c_conf(gi3c, PUSH_PULL_MODE);
>> +
>> +??? for (i = 0; i < num; i++) {
>> +??????? struct geni_i3c_xfer_params xfer;
>> +
>> +??????? xfer.m_cmd??? = (msgs[i].flags & I2C_M_RD) ? I2C_READ : 
>> I2C_WRITE;
>> +??????? xfer.m_param? = (i < (num - 1)) ? STOP_STRETCH : 0;
>> +??????? xfer.m_param |= FIELD_PREP(SLAVE_ADDR_MASK, msgs[i].addr);
>> +??????? xfer.mode???? = msgs[i].len > 32 ? GENI_SE_DMA : GENI_SE_FIFO;
> 
> remove extra ' ' before =
> 
>> +??????? if (msgs[i].flags & I2C_M_RD)
>> +??????????? ret = i3c_geni_execute_read_command(gi3c, &xfer, 
>> msgs[i].buf, msgs[i].len);
>> +??????? else
>> +??????????? ret = i3c_geni_execute_write_command(gi3c, &xfer, 
>> msgs[i].buf, msgs[i].len);
>> +??????? if (ret)
>> +??????????? break;
>> +??? }
>> +
>> +??? dev_dbg(gi3c->se.dev, "i2c: txn ret:%d\n", ret);
>> +??? i3c_geni_runtime_put_mutex_unlock(gi3c);
> 
> a '\n' before return
> 
Done
>> +??? return ret;
>> +}
>> +
>> +static int geni_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
>> +{
>> +??? struct geni_i3c_i2c_dev_data *data;
>> +
>> +??? data = kzalloc(sizeof(*data), GFP_KERNEL);
>> +??? if (!data)
>> +??????? return -ENOMEM;
>> +
>> +??? i2c_dev_set_master_data(dev, data);
> 
> a '\n' before return
> 
Done
>> +??? return 0;
>> +}
>> +
>> +static void geni_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
>> +{
>> +??? struct geni_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev);
>> +
>> +??? i2c_dev_set_master_data(dev, NULL);
>> +??? kfree(data);
>> +}
>> +
>> +static int geni_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
>> +{
>> +??? struct geni_i3c_i2c_dev_data *data;
>> +
>> +??? data = kzalloc(sizeof(*data), GFP_KERNEL);
>> +??? if (!data)
>> +??????? return -ENOMEM;
>> +
>> +??? i3c_dev_set_master_data(dev, data);
> 
> a '\n' before return
> 
Done
>> +??? return 0;
>> +}
>> +
>> +static void geni_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev)
>> +{
>> +??? struct geni_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
>> +
>> +??? i3c_dev_set_master_data(dev, NULL);
>> +??? kfree(data);
>> +}
>> +
>> +static int geni_i3c_master_do_daa(struct i3c_master_controller *m)
>> +{
>> +??? struct geni_i3c_dev *gi3c = to_geni_i3c_master(m);
>> +??? u8 addr;
>> +??? int ret;
>> +
>> +??? ret = i3c_master_entdaa_locked(m);
>> +??? if (ret && ret != I3C_ERROR_M2)
>> +??????? return ret;
>> +
>> +??? for (addr = 0; addr <= I3C_ADDR_MASK; addr++) {
>> +??????? if (is_new_addr_slot_set(gi3c->newaddrslots, addr)) {
>> +??????????? clear_new_addr_slot(gi3c->newaddrslots, addr);
>> +??????????? i3c_master_add_i3c_dev_locked(m, addr);
>> +??????? }
>> +??? }
>> +
>> +??? return 0;
>> +}
>> +
>> +static int geni_i3c_master_bus_init(struct i3c_master_controller *m)
>> +{
>> +??? struct geni_i3c_dev *gi3c = to_geni_i3c_master(m);
>> +??? struct i3c_bus *bus = i3c_master_get_bus(m);
>> +??? struct i3c_device_info info = { };
>> +??? int ret;
>> +
>> +??? /* Get an address for the master. */
>> +??? ret = i3c_master_get_free_addr(m, 0);
>> +??? if (ret < 0)
>> +??????? dev_err(gi3c->se.dev, "%s: error No free addr:%d\n", 
>> __func__, ret);
>> +
>> +??? info.dyn_addr = ret;
>> +??? info.dcr = I3C_DCR_GENERIC_DEVICE;
>> +??? info.bcr = I3C_BCR_I3C_MASTER | I3C_BCR_HDR_CAP;
>> +??? info.pid = 0;
>> +
>> +??? ret = geni_i3c_clk_map_idx(gi3c);
>> +??? if (ret) {
>> +??????? dev_err(gi3c->se.dev,
>> +??????????? "Invalid clk frequency %d Hz src for %ld Hz bus: %d\n",
>> +??????????? gi3c->clk_src_freq, bus->scl_rate.i3c, ret);
>> +??????? return ret; //This was missed in upstream : TBD
>> +??? }
>> +
>> +??? ret = i3c_geni_runtime_get_mutex_lock(gi3c);
>> +??? if (ret)
>> +??????? return ret;
>> +
>> +??? qcom_geni_i3c_conf(gi3c, OPEN_DRAIN_MODE);
>> +
>> +??? ret = i3c_master_set_info(&gi3c->ctrlr, &info);
>> +??? i3c_geni_runtime_put_mutex_unlock(gi3c);
> 
> a '\n' before return
> 
Done
>> +??? return ret;
>> +}
>> +
>> +static bool geni_i3c_master_supports_ccc_cmd(struct 
>> i3c_master_controller *m,
>> +???????????????????????? const struct i3c_ccc_cmd *cmd)
>> +{
>> +??? switch (cmd->id) {
>> +??? case I3C_CCC_ENEC(true):
>> +??????? fallthrough;
>> +??? case I3C_CCC_ENEC(false):
>> +??????? fallthrough;
>> +??? case I3C_CCC_DISEC(true):
>> +??????? fallthrough;
>> +??? case I3C_CCC_DISEC(false):
>> +??????? fallthrough;
>> +??? case I3C_CCC_ENTAS(0, true):
>> +??????? fallthrough;
>> +??? case I3C_CCC_ENTAS(0, false):
>> +??????? fallthrough;
>> +??? case I3C_CCC_RSTDAA(true):
>> +??????? fallthrough;
>> +??? case I3C_CCC_RSTDAA(false):
>> +??????? fallthrough;
>> +??? case I3C_CCC_ENTDAA:
>> +??????? fallthrough;
>> +??? case I3C_CCC_SETMWL(true):
>> +??????? fallthrough;
>> +??? case I3C_CCC_SETMWL(false):
>> +??????? fallthrough;
>> +??? case I3C_CCC_SETMRL(true):
>> +??????? fallthrough;
>> +??? case I3C_CCC_SETMRL(false):
>> +??????? fallthrough;
>> +??? case I3C_CCC_DEFSLVS:
>> +??????? fallthrough;
>> +??? case I3C_CCC_SETDASA:
>> +??????? fallthrough;
>> +??? case I3C_CCC_SETNEWDA:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETMWL:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETMRL:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETPID:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETBCR:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETDCR:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETSTATUS:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETACCMST:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETMXDS:
>> +??????? fallthrough;
>> +??? case I3C_CCC_GETHDRCAP:
>> +??????? return true;
>> +
>> +??? default:
>> +??????? return false;
>> +??? }
>> +}
>> +
> [clip]
>> +
>> +static int geni_i3c_runtime_suspend(struct device *dev)
>> +{
>> +??? struct geni_i3c_dev *gi3c = dev_get_drvdata(dev);
>> +
>> +??? disable_irq(gi3c->irq);
>> +??? geni_se_resources_off(&gi3c->se);
> 
> a '\n' before return
> 
Done
>> +??? return 0;
>> +}
>> +
>> +static int geni_i3c_runtime_resume(struct device *dev)
>> +{
>> +??? int ret;
>> +??? struct geni_i3c_dev *gi3c = dev_get_drvdata(dev);
>> +
>> +??? ret = geni_se_resources_on(&gi3c->se);
>> +??? if (ret)
>> +??????? return ret;
>> +??? enable_irq(gi3c->irq);
> 
> a '\n' before return
> 
Done
>> +??? return 0;
>> +}
>> +
>> +static const struct dev_pm_ops geni_i3c_pm_ops = {
>> +??? SET_RUNTIME_PM_OPS(geni_i3c_runtime_suspend, 
>> geni_i3c_runtime_resume, NULL)
>> +};
>> +
>> +static const struct of_device_id geni_i3c_dt_match[] = {
>> +??? { .compatible = "qcom,geni-i3c" },
>> +??? { }
>> +};
>> +MODULE_DEVICE_TABLE(of, geni_i3c_dt_match);
>> +
>> +static struct platform_driver geni_i3c_master = {
>> +??? .probe? = geni_i3c_probe,
> 
> remove extra ' ' before =
> 
Done
>> +??? .remove = geni_i3c_remove,
>> +??? .driver = {
>> +??????? .name = "geni_i3c",
>> +??????? .pm = &geni_i3c_pm_ops,
>> +??????? .of_match_table = geni_i3c_dt_match,
>> +??? },
>> +};
>> +
>> +module_platform_driver(geni_i3c_master);
>> +
>> +MODULE_AUTHOR("Mukesh Kumar Savaliya <quic_msavaliy at quicinc.com>");
>> +MODULE_DESCRIPTION("Qualcomm I3C Controller Driver for GENI based QUP 
>> cores");
>> +MODULE_LICENSE("GPL");
> 
> 
> Thanks,
> Alok



From krzk at kernel.org  Wed May  7 23:07:49 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 8 May 2025 08:07:49 +0200
Subject: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x i3c-hub support
In-Reply-To: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
Message-ID: <17145d2f-5d07-4939-8381-74e27cde303c@kernel.org>

On 08/05/2025 06:57, Aman Kumar Pandey wrote:
> Add bindings for the NXP P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841)
> multiport I3C hub family. These devices connect to a host via
> I3C/I2C/SMBus and allow communication with multiple downstream
> peripherals.
> 
> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey at nxp.com>
> Signed-off-by: Vikash Bansal <vikash.bansal at nxp.com>
> ---
> V1 -> V2: Cleaned up coding style and addressed review comments
> ---
>  .../bindings/i3c/p3h2840-i3c-hub.yaml         | 332 ++++++++++++++++++

Not much improved. I have doubts that you really looked at other bindings.

Filename matching compatible.


>  MAINTAINERS                                   |   8 +
>  2 files changed, 340 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml
> 
> diff --git a/Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml b/Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml
> new file mode 100644
> index 000000000000..f3b5aabf5fe0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml
> @@ -0,0 +1,332 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright 2025 NXP
> +
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/i3c/p3h2840-i3c-hub.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: P3H2X4X I3C HUB

nvidia? NXP? What is it?

> +


> +maintainers:
> +  - Vikash Bansal <vikash.bansal at nxp.com>
> +  - Aman Kumar Pandey <aman.kumarpandey at nxp.com>
> +
> +description: |
> +  P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841) is a family of multiport I3C
> +  hub devices that connect to:-
> +  1. A host CPU via I3C/I2C/SMBus bus on upstream side and connect to multiple
> +     peripheral devices on the downstream  side.
> +  2. Have two Controller Ports which can support either
> +     I2C/SMBus or I3C buses and connect to a CPU, BMC or SOC.
> +  3. P3H2840/ P3H2841 are 8 port I3C hub with eight I3C/I2C Target Port.
> +  4. P3H2440/ P3H2441 are 4 port I3C hub with four I3C/I2C Target Port.
> +     Target ports can be configured as I2C/SMBus, I3C or GPIO and connect to
> +     peripherals.
> +
> +allOf:
> +  - $ref: i3c.yaml#
> +
> +properties:
> +  $nodename:
> +    pattern: "^hub@[@.*]+,[0-9a-f]+$"

Drop


> +
> +  Compatible:

Nothing improved. There is no single code with such syntax and I asked
to use existing files as an example. You just ignored that comment and
this is not acceptable.


> +    const: nxp,p3h2x4x

No, you need specific compatibles.

> +
> +  cp0-ldo-enable:
> +    type: boolean
> +    description:
> +      Enables the on-die LDO for controller Port 0.
> +
> +  cp1-ldo-enable:
> +    type: boolean
> +    description:
> +      Enables the on-die LDO for controller Port 1.
> +
> +  tp0145-ldo-enable:
> +    type: boolean
> +    description:
> +      Enables the on-die LDO for target ports 0/1/4/5.
> +
> +  tp2367-ldo-enable:
> +    type: boolean
> +    description:
> +      Enables the on-die LDO for target ports 2/3/6/7.
> +

NAK for all above properties.

> +  cp0-ldo-microvolt:

Do you see anywhere device properties named like that? Without prefix?

I am not going to review the rest. You did not try hard enough to
fulfill previous review request, you did not really test it.

Start from scratch from latest accepted schema or from example-schema.

Best regards,
Krzysztof


From robh at kernel.org  Wed May  7 23:09:21 2025
From: robh at kernel.org (Rob Herring (Arm))
Date: Thu, 08 May 2025 01:09:21 -0500
Subject: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x i3c-hub
 support
In-Reply-To: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
Message-ID: <174668456098.3462718.13659996753700192660.robh@kernel.org>


On Thu, 08 May 2025 07:57:10 +0300, Aman Kumar Pandey wrote:
> Add bindings for the NXP P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841)
> multiport I3C hub family. These devices connect to a host via
> I3C/I2C/SMBus and allow communication with multiple downstream
> peripherals.
> 
> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey at nxp.com>
> Signed-off-by: Vikash Bansal <vikash.bansal at nxp.com>
> ---
> V1 -> V2: Cleaned up coding style and addressed review comments
> ---
>  .../bindings/i3c/p3h2840-i3c-hub.yaml         | 332 ++++++++++++++++++
>  MAINTAINERS                                   |   8 +
>  2 files changed, 340 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:


doc reference errors (make refcheckdocs):
Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/i3c/p3h2x4x_i3c_hub.yaml
MAINTAINERS: Documentation/devicetree/bindings/i3c/p3h2x4x_i3c_hub.yaml

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250508045711.2810207-1-aman.kumarpandey at nxp.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.



From krzk at kernel.org  Wed May  7 23:09:45 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 8 May 2025 08:09:45 +0200
Subject: [PATCH v2 2/2] drivers: i3c: Add driver for NXP P3H2x4x i3c-hub
 device
In-Reply-To: <20250508045711.2810207-2-aman.kumarpandey@nxp.com>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
 <20250508045711.2810207-2-aman.kumarpandey@nxp.com>
Message-ID: <b46e3766-75b7-4635-a505-3039e4394f07@kernel.org>

On 08/05/2025 06:57, Aman Kumar Pandey wrote:
> +
> +static void p3h2x4x_of_get_tp_dt_conf(struct device *dev,
> +				      const struct device_node *node)
> +{
> +	struct p3h2x4x *priv = dev_get_drvdata(dev);
> +	struct device_node *dev_node;
> +	u64 tp_port;
> +
> +	for_each_available_child_of_node(node, dev_node) {
> +		if (!dev_node->name || of_node_cmp(dev_node->name, "target-port"))


Same NAK as before. You ignored the comment and nothing improved.

> +			continue;
> +
> +		if (of_property_read_reg(dev_node, 0, &tp_port, NULL))
> +			continue;
> +
> +		if (tp_port < P3H2x4x_TP_MAX_COUNT) {
> +			priv->tp_bus[tp_port].dt_available = true;
> +			priv->tp_bus[tp_port].of_node = dev_node;
> +			priv->tp_bus[tp_port].tp_mask = BIT(tp_port);
> +			priv->tp_bus[tp_port].priv = priv;
> +			priv->tp_bus[tp_port].tp_port = tp_port;
> +		}
> +	}
> +}
> +
> +/* return true when backend node exist */
> +static bool p3h2x4x_is_backend_node_exist(int port, struct p3h2x4x *priv, u32 addr)
> +{
> +	struct smbus_device *backend = NULL;
> +
> +	list_for_each_entry(backend,
> +			    &priv->tp_bus[port].tp_device_entry, list) {
> +		if (backend->addr == addr)
> +			return true;
> +	}
> +	return false;
> +}
> +
> +static int p3h2x4x_read_backend_from_dts(struct device_node *i3c_node_target,
> +					 struct p3h2x4x *priv)
> +{
> +	struct device_node *tp_node;
> +	const char *compatible;
> +	u64 tp_port, addr_dts;
> +	int ret;
> +
> +	struct smbus_device *backend;
> +
> +	if (of_property_read_reg(i3c_node_target, 0, &tp_port, NULL))
> +		return -EINVAL;
> +
> +	if (tp_port >= P3H2x4x_TP_MAX_COUNT || tp_port < 0)
> +		return -ERANGE;
> +
> +	INIT_LIST_HEAD(&priv->tp_bus[tp_port].tp_device_entry);
> +
> +	if (priv->settings.tp[tp_port].mode == P3H2x4x_TP_MODE_I3C)
> +		return 0;
> +
> +	for_each_available_child_of_node(i3c_node_target, tp_node) {
> +		ret = of_property_read_reg(tp_node, 0, &addr_dts, NULL);
> +		if (ret)
> +			return ret;
> +
> +		if (p3h2x4x_is_backend_node_exist(tp_port, priv, addr_dts))
> +			continue;
> +
> +		ret = of_property_read_string(tp_node, "compatible", &compatible);
> +		if (ret)
> +			return ret;
> +
> +		backend = kzalloc(sizeof(*backend), GFP_KERNEL);
> +		if (!backend)
> +			return -ENOMEM;
> +
> +		backend->addr = addr_dts;
> +		backend->compatible = compatible;
> +		backend->tp_device_dt_node = tp_node;
> +		backend->client = NULL;
> +
> +		list_add(&backend->list,
> +			 &priv->tp_bus[tp_port].tp_device_entry);
> +	}
> +
> +	return 0;
> +}
> +
> +static void p3h2x4x_parse_dt_tp(struct device *dev,
> +				const struct device_node *i3c_node_hub,
> +				struct p3h2x4x *priv)
> +{
> +	struct device_node *i3c_node_target;
> +	int ret;
> +
> +	for_each_available_child_of_node(i3c_node_hub, i3c_node_target) {
> +		if (of_node_cmp(i3c_node_target->name, "target-port") == 0) {
> +			ret = p3h2x4x_read_backend_from_dts(i3c_node_target, priv);
> +			if (ret)
> +				dev_err(dev, "DTS entry invalid - error %d", ret);
> +		}
> +	}
> +}
> +
> +static int p3h2x4x_get_tp_local_device_dt_setting(struct device *dev,
> +						  const struct device_node *node, u32 id)
> +{
> +	struct p3h2x4x *priv = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = of_property_read_variable_u8_array(node, "local_dev", priv->tp_bus[id].local_dev_list,

Nothing improved.

Just like for first patch you send the same buggy code ignoring review.


Best regards,
Krzysztof


From lkp at intel.com  Fri May  9 01:10:39 2025
From: lkp at intel.com (kernel test robot)
Date: Fri, 9 May 2025 16:10:39 +0800
Subject: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x i3c-hub support
In-Reply-To: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
Message-ID: <202505091515.KKkEYL9A-lkp@intel.com>

Hi Aman,

kernel test robot noticed the following build warnings:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.15-rc5 next-20250508]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Aman-Kumar-Pandey/drivers-i3c-Add-driver-for-NXP-P3H2x4x-i3c-hub-device/20250508-125929
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20250508045711.2810207-1-aman.kumarpandey%40nxp.com
patch subject: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x i3c-hub support
reproduce: (https://download.01.org/0day-ci/archive/20250509/202505091515.KKkEYL9A-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505091515.KKkEYL9A-lkp at intel.com/

All warnings (new ones prefixed by >>):

   Warning: Documentation/translations/ja_JP/process/submit-checklist.rst references a file that doesn't exist: Documentation/translations/ja_JP/SubmitChecklist
   Warning: Documentation/translations/zh_CN/admin-guide/README.rst references a file that doesn't exist: Documentation/dev-tools/kgdb.rst
   Warning: Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst references a file that doesn't exist: Documentation/dev-tools/gdb-kernel-debugging.rst
   Warning: Documentation/translations/zh_TW/admin-guide/README.rst references a file that doesn't exist: Documentation/dev-tools/kgdb.rst
   Warning: Documentation/translations/zh_TW/dev-tools/gdb-kernel-debugging.rst references a file that doesn't exist: Documentation/dev-tools/gdb-kernel-debugging.rst
>> Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/i3c/p3h2x4x_i3c_hub.yaml
   Can't build as 1 mandatory dependency is missing at ./scripts/sphinx-pre-install line 984.
   make[2]: *** [Documentation/Makefile:121: htmldocs] Error 255
   make[1]: *** [Makefile:1801: htmldocs] Error 2
   make: *** [Makefile:248: __sub-make] Error 2
   make: Target 'htmldocs' not remade because of errors.

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From lkp at intel.com  Fri May  9 05:28:12 2025
From: lkp at intel.com (kernel test robot)
Date: Fri, 9 May 2025 20:28:12 +0800
Subject: [PATCH v2 2/2] drivers: i3c: Add driver for NXP P3H2x4x i3c-hub
 device
In-Reply-To: <20250508045711.2810207-2-aman.kumarpandey@nxp.com>
References: <20250508045711.2810207-2-aman.kumarpandey@nxp.com>
Message-ID: <202505092036.D5saUso4-lkp@intel.com>

Hi Aman,

kernel test robot noticed the following build errors:

[auto build test ERROR on robh/for-next]
[also build test ERROR on linus/master v6.15-rc5 next-20250508]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Aman-Kumar-Pandey/drivers-i3c-Add-driver-for-NXP-P3H2x4x-i3c-hub-device/20250508-125929
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20250508045711.2810207-2-aman.kumarpandey%40nxp.com
patch subject: [PATCH v2 2/2] drivers: i3c: Add driver for NXP P3H2x4x i3c-hub device
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20250509/202505092036.D5saUso4-lkp at intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250509/202505092036.D5saUso4-lkp at intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp at intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505092036.D5saUso4-lkp at intel.com/

All errors (new ones prefixed by >>):

>> drivers/i3c/hub/p3h2840_i3c_hub_common.c:125:12: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     125 |                 value |= P3H2x4x_TP0145_PULLUP_CONF(p3h2x4x_pullup_dt_to_reg
         |                          ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:93:3: note: expanded from macro 'P3H2x4x_TP0145_PULLUP_CONF'
      93 |                 FIELD_PREP(P3H2x4x_TP0145_PULLUP_CONF_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:131:12: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     131 |                 value |= P3H2x4x_TP2367_PULLUP_CONF(p3h2x4x_pullup_dt_to_reg
         |                          ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:96:3: note: expanded from macro 'P3H2x4x_TP2367_PULLUP_CONF'
      96 |                 FIELD_PREP(P3H2x4x_TP2367_PULLUP_CONF_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:168:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     168 |                 val = P3H2x4x_CP0_VCCIO_LDO_VOLTAGE(p3h2x4x_ldo_dt_to_reg
         |                       ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:68:3: note: expanded from macro 'P3H2x4x_CP0_VCCIO_LDO_VOLTAGE'
      68 |                 FIELD_PREP(P3H2x4x_CP0_VCCIO_LDO_VOLTAGE_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:178:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     178 |                 val = P3H2x4x_CP1_VCCIO_LDO_VOLTAGE(p3h2x4x_ldo_dt_to_reg
         |                       ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:71:3: note: expanded from macro 'P3H2x4x_CP1_VCCIO_LDO_VOLTAGE'
      71 |                 FIELD_PREP(P3H2x4x_CP1_VCCIO_LDO_VOLTAGE_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:188:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     188 |                 val = P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE(p3h2x4x_ldo_dt_to_reg
         |                       ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:74:3: note: expanded from macro 'P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE'
      74 |                 FIELD_PREP(P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:198:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     198 |                 val = P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE(p3h2x4x_ldo_dt_to_reg
         |                       ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:77:3: note: expanded from macro 'P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE'
      77 |                 FIELD_PREP(P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:246:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     246 |                 val = P3H2x4x_CP0_IO_STRENGTH(p3h2x4x_io_strength_dt_to_reg
         |                       ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:59:3: note: expanded from macro 'P3H2x4x_CP0_IO_STRENGTH'
      59 |                 FIELD_PREP(P3H2x4x_CP0_IO_STRENGTH_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:252:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     252 |                 val = P3H2x4x_CP1_IO_STRENGTH(p3h2x4x_io_strength_dt_to_reg
         |                       ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:62:3: note: expanded from macro 'P3H2x4x_CP1_IO_STRENGTH'
      62 |                 FIELD_PREP(P3H2x4x_CP1_IO_STRENGTH_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:258:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     258 |                 val = P3H2x4x_TP0145_IO_STRENGTH(p3h2x4x_io_strength_dt_to_reg
         |                       ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:53:3: note: expanded from macro 'P3H2x4x_TP0145_IO_STRENGTH'
      53 |                 FIELD_PREP(P3H2x4x_TP0145_IO_STRENGTH_MASK, x)
         |                 ^
   drivers/i3c/hub/p3h2840_i3c_hub_common.c:264:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     264 |                 val = P3H2x4x_TP2367_IO_STRENGTH(p3h2x4x_io_strength_dt_to_reg
         |                       ^
   drivers/i3c/hub/p3h2840_i3c_hub.h:56:3: note: expanded from macro 'P3H2x4x_TP2367_IO_STRENGTH'
      56 |                 FIELD_PREP(P3H2x4x_TP2367_IO_STRENGTH_MASK, x)
         |                 ^
   10 errors generated.


vim +/FIELD_PREP +125 drivers/i3c/hub/p3h2840_i3c_hub_common.c

   117	
   118	static int p3h2x4x_configure_pullup(struct device *dev)
   119	{
   120		struct p3h2x4x *priv = dev_get_drvdata(dev);
   121		u8 mask = 0, value = 0;
   122	
   123		if (priv->settings.tp0145_pullup != P3H2x4x_TP_PULLUP_NOT_SET) {
   124			mask |= P3H2x4x_TP0145_PULLUP_CONF_MASK;
 > 125			value |= P3H2x4x_TP0145_PULLUP_CONF(p3h2x4x_pullup_dt_to_reg
   126							    (priv->settings.tp0145_pullup));
   127		}
   128	
   129		if (priv->settings.tp2367_pullup != P3H2x4x_TP_PULLUP_NOT_SET) {
   130			mask |= P3H2x4x_TP2367_PULLUP_CONF_MASK;
   131			value |= P3H2x4x_TP2367_PULLUP_CONF(p3h2x4x_pullup_dt_to_reg
   132							    (priv->settings.tp2367_pullup));
   133		}
   134	
   135		return regmap_update_bits(priv->regmap, P3H2x4x_LDO_AND_PULLUP_CONF,
   136					  mask, value);
   137	}
   138	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


From miquel.raynal at bootlin.com  Mon May 12 02:25:16 2025
From: miquel.raynal at bootlin.com (Miquel Raynal)
Date: Mon, 12 May 2025 11:25:16 +0200
Subject: [PATCH v2 1/1] i3c: master: svc: skip address resend on repeat
 START
In-Reply-To: <20250429054234.4013929-1-Frank.Li@nxp.com> (Frank Li's message
	of "Tue, 29 Apr 2025 01:42:34 -0400")
References: <20250429054234.4013929-1-Frank.Li@nxp.com>
Message-ID: <877c2mmb9f.fsf@bootlin.com>

On 29/04/2025 at 01:42:34 -04, Frank Li <Frank.Li at nxp.com> wrote:

> According to the I3C specification, address arbitration only happens during
> the START. Repeated START do not initiate arbitration, and In-Band
> Interrupts (IBIs) cannot occur at this stage.
>
> Resending the address upon a NACK in a repeat START is therefore redundant
> and unnecessary. Avoid redundant retries, improving efficiency and ensuring
> protocol compliance.
>
> Signed-off-by: Frank Li <Frank.Li at nxp.com>
> ---

Reviewed-by: Miquel Raynal <miquel.raynal at bootlin.com>


From carlos.song at nxp.com  Tue May 13 19:04:29 2025
From: carlos.song at nxp.com (Carlos Song)
Date: Wed, 14 May 2025 02:04:29 +0000
Subject: [PATCH V4 3/3] arm64: dts: imx95: correct i3c node in imx95
In-Reply-To: <20250427083230.3325700-4-carlos.song@nxp.com>
References: <20250427083230.3325700-1-carlos.song@nxp.com>
 <20250427083230.3325700-4-carlos.song@nxp.com>
Message-ID: <VI2PR04MB11147377F1A706A4676D29CFFE891A@VI2PR04MB11147.eurprd04.prod.outlook.com>

Ping to avoid missing..

> -----Original Message-----
> From: carlos.song at nxp.com <carlos.song at nxp.com>
> Sent: Sunday, April 27, 2025 4:33 PM
> To: miquel.raynal at bootlin.com; Frank Li <frank.li at nxp.com>;
> alexandre.belloni at bootlin.com; robh at kernel.org; krzk+dt at kernel.org;
> conor+dt at kernel.org; shawnguo at kernel.org; s.hauer at pengutronix.de;
> kernel at pengutronix.de; festevam at gmail.com; conor.culhane at silvaco.com
> Cc: linux-i3c at lists.infradead.org; imx at lists.linux.dev;
> devicetree at vger.kernel.org; linux-kernel at vger.kernel.org;
> linux-arm-kernel at lists.infradead.org
> Subject: [EXT] [PATCH V4 3/3] arm64: dts: imx95: correct i3c node in imx95
> 
> Caution: This is an external email. Please take care when clicking links or
> opening attachments. When in doubt, report the message using the 'Report this
> email' button
> 
> 
> From: Carlos Song <carlos.song at nxp.com>
> 
> I.MX95 I3C only need two clocks so add clock fix. Add "nxp,imx95-i3c"
> compatible string for all imx95 i3c nodes.
> 
> Signed-off-by: Carlos Song <carlos.song at nxp.com>
> ---
> Change for V4:
> - No change
> Change for V3:
> - Remove unrelated fix in imx95.dtsi
> Change for V2:
> - No change
> ---
>  arch/arm64/boot/dts/freescale/imx95.dtsi | 10 ++++------
>  1 file changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi
> b/arch/arm64/boot/dts/freescale/imx95.dtsi
> index 59f057ba6fa7..ce0787410f9d 100644
> --- a/arch/arm64/boot/dts/freescale/imx95.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
> @@ -681,15 +681,14 @@ tpm6: pwm at 42510000 {
>                         };
> 
>                         i3c2: i3c at 42520000 {
> -                               compatible = "silvaco,i3c-master-v1";
> +                               compatible = "nxp,imx95-i3c",
> "silvaco,i3c-master-v1";
>                                 reg = <0x42520000 0x10000>;
>                                 interrupts = <GIC_SPI 57
> IRQ_TYPE_LEVEL_HIGH>;
>                                 #address-cells = <3>;
>                                 #size-cells = <0>;
>                                 clocks = <&scmi_clk
> IMX95_CLK_BUSAON>,
> -                                        <&scmi_clk
> IMX95_CLK_I3C2>,
>                                          <&scmi_clk
> IMX95_CLK_I3C2SLOW>;
> -                               clock-names = "pclk", "fast_clk",
> "slow_clk";
> +                               clock-names = "pclk", "fast_clk";
>                                 status = "disabled";
>                         };
> 
> @@ -1266,15 +1265,14 @@ tpm2: pwm at 44320000 {
>                         };
> 
>                         i3c1: i3c at 44330000 {
> -                               compatible = "silvaco,i3c-master-v1";
> +                               compatible = "nxp,imx95-i3c",
> "silvaco,i3c-master-v1";
>                                 reg = <0x44330000 0x10000>;
>                                 interrupts = <GIC_SPI 12
> IRQ_TYPE_LEVEL_HIGH>;
>                                 #address-cells = <3>;
>                                 #size-cells = <0>;
>                                 clocks = <&scmi_clk
> IMX95_CLK_BUSAON>,
> -                                        <&scmi_clk
> IMX95_CLK_I3C1>,
>                                          <&scmi_clk
> IMX95_CLK_I3C1SLOW>;
> -                               clock-names = "pclk", "fast_clk",
> "slow_clk";
> +                               clock-names = "pclk", "fast_clk";
>                                 status = "disabled";
>                         };
> 
> --
> 2.34.1
> 



From krzk at kernel.org  Wed May 14 03:05:14 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 14 May 2025 12:05:14 +0200
Subject: [EXT] Re: [PATCH v2 2/2] drivers: i3c: Add driver for NXP P3H2x4x
 i3c-hub device
In-Reply-To: <GVXPR04MB9778CD46464F6BEE25D5D0529997A@GVXPR04MB9778.eurprd04.prod.outlook.com>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
 <20250508045711.2810207-2-aman.kumarpandey@nxp.com>
 <b46e3766-75b7-4635-a505-3039e4394f07@kernel.org>
 <GVXPR04MB9778CD46464F6BEE25D5D0529997A@GVXPR04MB9778.eurprd04.prod.outlook.com>
Message-ID: <e4317fef-c4e9-405c-9bcb-4d5447dd8367@kernel.org>

On 12/05/2025 13:45, Aman Kumar Pandey wrote:
> 
>> -----Original Message-----
>> From: Krzysztof Kozlowski <krzk at kernel.org>
>> Sent: Thursday, May 8, 2025 11:40 AM
>> To: Aman Kumar Pandey <aman.kumarpandey at nxp.com>; linux-
>> kernel at vger.kernel.org; linux-i3c at lists.infradead.org;
>> alexandre.belloni at bootlin.com; krzk+dt at kernel.org; robh at kernel.org;
>> conor+dt at kernel.org; devicetree at vger.kernel.org
>> Cc: Vikash Bansal <vikash.bansal at nxp.com>; Priyanka Jain
>> <priyanka.jain at nxp.com>; Shashank Rebbapragada
>> <shashank.rebbapragada at nxp.com>; Frank Li <frank.li at nxp.com>
>> Subject: [EXT] Re: [PATCH v2 2/2] drivers: i3c: Add driver for NXP P3H2x4x i3c-
>> hub device
>>
>> [Some people who received this message don't often get email from
>> krzk at kernel.org. Learn why this is important at
>> https://aka.ms/LearnAboutSenderIdentification ]
>>
>> Caution: This is an external email. Please take care when clicking links or
>> opening attachments. When in doubt, report the message using the 'Report
>> this email' button
>>
>>
>> On 08/05/2025 06:57, Aman Kumar Pandey wrote:
>>> +
>>> +static void p3h2x4x_of_get_tp_dt_conf(struct device *dev,
>>> +                                   const struct device_node *node) {
>>> +     struct p3h2x4x *priv = dev_get_drvdata(dev);
>>> +     struct device_node *dev_node;
>>> +     u64 tp_port;
>>> +
>>> +     for_each_available_child_of_node(node, dev_node) {
>>> +             if (!dev_node->name || of_node_cmp(dev_node->name,
>>> + "target-port"))
>>
>>
>> Same NAK as before. You ignored the comment and nothing improved.
>>
> 
> Thanks for reviewing the patch.
> As per your comment I have used proper function to get reg instead of sscanf. And our driver is not having direct interface with userspace.

What was the comment - undocumented ABI.

> What should I change here ?

How did you solve that comment?


Best regards,
Krzysztof


From krzk at kernel.org  Wed May 14 03:10:11 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 14 May 2025 12:10:11 +0200
Subject: [EXT] Re: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x
 i3c-hub support
In-Reply-To: <GVXPR04MB9778335A5DFAB37CC8D011FC9997A@GVXPR04MB9778.eurprd04.prod.outlook.com>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
 <17145d2f-5d07-4939-8381-74e27cde303c@kernel.org>
 <GVXPR04MB9778335A5DFAB37CC8D011FC9997A@GVXPR04MB9778.eurprd04.prod.outlook.com>
Message-ID: <ef92c390-d136-46b4-8219-294c449e4092@kernel.org>

On 12/05/2025 13:45, Aman Kumar Pandey wrote:
>>>
>>> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey at nxp.com>
>>> Signed-off-by: Vikash Bansal <vikash.bansal at nxp.com>
>>> ---
>>> V1 -> V2: Cleaned up coding style and addressed review comments
>>> ---
>>>  .../bindings/i3c/p3h2840-i3c-hub.yaml         | 332 ++++++++++++++++++
>>
>> Not much improved. I have doubts that you really looked at other bindings.
>>
>> Filename matching compatible.
>>
>>
> 
> Thanks for reviewing the patch.
> There is no existing entry like this one. It is the first device tree entry for any i3c target device being added to Linux upstream. 
> For I3C target device, compatible is not required as per i3c.yml. I am adding compatible for backward compatibility with i2c binding ( i3c target device have backward compatibility). 
> Should I use compatible matching filename in this case ?

Do you have compatible here? Yes, you have, so I do not get what is
unclear in my comment. Rename the binding to match the compatible, which
you have here.


> 
>>>  MAINTAINERS                                   |   8 +
>>>  2 files changed, 340 insertions(+)
>  
>  
>>> +
>>> +properties:
>>> +  $nodename:
>>> +    pattern: "^hub@[@.*]+,[0-9a-f]+$"
>>
>> Drop
>>
> 
> Sorry, did not understand your point. Could you please give some clarification ?

Drop this nodename. Remove it.

> 
>>> +
> 
>>> +
>>> +  cp0-ldo-enable:
>>> +    type: boolean
>>> +    description:
>>> +      Enables the on-die LDO for controller Port 0.
>>> +
>>> +  cp1-ldo-enable:
>>> +    type: boolean
>>> +    description:
>>> +      Enables the on-die LDO for controller Port 1.
>>> +
>>> +  tp0145-ldo-enable:
>>> +    type: boolean
>>> +    description:
>>> +      Enables the on-die LDO for target ports 0/1/4/5.
>>> +
>>> +  tp2367-ldo-enable:
>>> +    type: boolean
>>> +    description:
>>> +      Enables the on-die LDO for target ports 2/3/6/7.
>>> +
>>
>> NAK for all above properties.
>>
> 
> These are not vender specific properties. all these properties are as per i3c hub specification.
>  What should I change for above properties ?


What do they represent? Regulators? Why would you add custom properties
for controlling regulators? Why would you enable LDOs for ports which
have nothing connected? Why would you not enable LDOs for ports which
have something there? Why these are not properties of the ports?

So many questions.


Best regards,
Krzysztof


From krzk at kernel.org  Wed May 14 03:18:46 2025
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 14 May 2025 12:18:46 +0200
Subject: [EXT] Re: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x
 i3c-hub support
In-Reply-To: <GVXPR04MB9778335A5DFAB37CC8D011FC9997A@GVXPR04MB9778.eurprd04.prod.outlook.com>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
 <17145d2f-5d07-4939-8381-74e27cde303c@kernel.org>
 <GVXPR04MB9778335A5DFAB37CC8D011FC9997A@GVXPR04MB9778.eurprd04.prod.outlook.com>
Message-ID: <18d6951a-860e-4479-837e-9edc90adeaea@kernel.org>

On 12/05/2025 13:45, Aman Kumar Pandey wrote:
>>
> 
> These are not vender specific properties. all these properties are as per i3c hub specification.
>  What should I change for above properties ?

BTW, if this was I3C spec, then I would also expect all of such
spec-related-properties to be in shared schema.

Best regards,
Krzysztof


From sashal at kernel.org  Mon May  5 15:05:24 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 18:05:24 -0400
Subject: [PATCH AUTOSEL 6.14 108/642] i3c: master: svc: Fix missing STOP for master request
In-Reply-To: <20250505221419.2672473-1-sashal@kernel.org>
References: <20250505221419.2672473-1-sashal@kernel.org>
Message-ID: <20250505221419.2672473-108-sashal@kernel.org>

From: Stanley Chu <yschu at nuvoton.com>

[ Upstream commit 0430bf9bc1ac068c8b8c540eb93e5751872efc51 ]

The controller driver nacked the master request but didn't emit a
STOP to end the transaction. The driver shall refuse the unsupported
requests and return the controller state to IDLE by emitting a STOP.

Signed-off-by: Stanley Chu <yschu at nuvoton.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Link: https://lore.kernel.org/r/20250318053606.3087121-4-yschu at nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 0fc03bb5d0a6e..a18fe62962b0c 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -551,6 +551,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
 			queue_work(master->base.wq, &master->hj_work);
 		break;
 	case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
+		svc_i3c_master_emit_stop(master);
 	default:
 		break;
 	}
-- 
2.39.5



From sashal at kernel.org  Mon May  5 15:09:52 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 18:09:52 -0400
Subject: [PATCH AUTOSEL 6.14 376/642] i3c: master: svc: Flush FIFO before sending Dynamic Address Assignment(DAA)
In-Reply-To: <20250505221419.2672473-1-sashal@kernel.org>
References: <20250505221419.2672473-1-sashal@kernel.org>
Message-ID: <20250505221419.2672473-376-sashal@kernel.org>

From: Frank Li <Frank.Li at nxp.com>

[ Upstream commit a892ee4cf22a50e1d6988d0464a9a421f3e5db2f ]

Ensure the FIFO is empty before issuing the DAA command to prevent
incorrect command data from being sent. Align with other data transfers,
such as svc_i3c_master_start_xfer_locked(), which flushes the FIFO before
sending a command.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Miquel Raynal <miquel.raynal at bootlin.com>
Link: https://lore.kernel.org/r/20250129162250.3629189-1-Frank.Li at nxp.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index a18fe62962b0c..2cf2c567f8931 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -899,6 +899,8 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
 	u32 reg;
 	int ret, i;
 
+	svc_i3c_master_flush_fifo(master);
+
 	while (true) {
 		/* clean SVC_I3C_MINT_IBIWON w1c bits */
 		writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
-- 
2.39.5



From sashal at kernel.org  Mon May  5 15:13:58 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 18:13:58 -0400
Subject: [PATCH AUTOSEL 6.14 622/642] i3c: master: svc: Fix implicit fallthrough in svc_i3c_master_ibi_work()
In-Reply-To: <20250505221419.2672473-1-sashal@kernel.org>
References: <20250505221419.2672473-1-sashal@kernel.org>
Message-ID: <20250505221419.2672473-622-sashal@kernel.org>

From: Nathan Chancellor <nathan at kernel.org>

[ Upstream commit e8d2d287e26d9bd9114cf258a123a6b70812442e ]

Clang warns (or errors with CONFIG_WERROR=y):

  drivers/i3c/master/svc-i3c-master.c:596:2: error: unannotated fall-through between switch labels [-Werror,-Wimplicit-fallthrough]
    596 |         default:
        |         ^
  drivers/i3c/master/svc-i3c-master.c:596:2: note: insert 'break;' to avoid fall-through
    596 |         default:
        |         ^
        |         break;
  1 error generated.

Clang is a little more pedantic than GCC, which does not warn when
falling through to a case that is just break or return. Clang's version
is more in line with the kernel's own stance in deprecated.rst, which
states that all switch/case blocks must end in either break,
fallthrough, continue, goto, or return. Add the missing break to silence
the warning.

Fixes: 0430bf9bc1ac ("i3c: master: svc: Fix missing STOP for master request")
Signed-off-by: Nathan Chancellor <nathan at kernel.org>
Link: https://lore.kernel.org/r/20250319-i3c-fix-clang-fallthrough-v1-1-d8e02be1ef5c at kernel.org
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 2cf2c567f8931..75127b6c161f0 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -552,6 +552,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
 		break;
 	case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
 		svc_i3c_master_emit_stop(master);
+		break;
 	default:
 		break;
 	}
-- 
2.39.5



From sashal at kernel.org  Mon May  5 15:32:41 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 18:32:41 -0400
Subject: [PATCH AUTOSEL 6.12 085/486] i3c: master: svc: Fix missing STOP for master request
In-Reply-To: <20250505223922.2682012-1-sashal@kernel.org>
References: <20250505223922.2682012-1-sashal@kernel.org>
Message-ID: <20250505223922.2682012-85-sashal@kernel.org>

From: Stanley Chu <yschu at nuvoton.com>

[ Upstream commit 0430bf9bc1ac068c8b8c540eb93e5751872efc51 ]

The controller driver nacked the master request but didn't emit a
STOP to end the transaction. The driver shall refuse the unsupported
requests and return the controller state to IDLE by emitting a STOP.

Signed-off-by: Stanley Chu <yschu at nuvoton.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Link: https://lore.kernel.org/r/20250318053606.3087121-4-yschu at nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 7911814ad82ac..6ffe022dbb5b4 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -511,6 +511,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
 			queue_work(master->base.wq, &master->hj_work);
 		break;
 	case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
+		svc_i3c_master_emit_stop(master);
 	default:
 		break;
 	}
-- 
2.39.5



From sashal at kernel.org  Mon May  5 15:36:11 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 18:36:11 -0400
Subject: [PATCH AUTOSEL 6.12 295/486] i3c: master: svc: Flush FIFO before sending Dynamic Address Assignment(DAA)
In-Reply-To: <20250505223922.2682012-1-sashal@kernel.org>
References: <20250505223922.2682012-1-sashal@kernel.org>
Message-ID: <20250505223922.2682012-295-sashal@kernel.org>

From: Frank Li <Frank.Li at nxp.com>

[ Upstream commit a892ee4cf22a50e1d6988d0464a9a421f3e5db2f ]

Ensure the FIFO is empty before issuing the DAA command to prevent
incorrect command data from being sent. Align with other data transfers,
such as svc_i3c_master_start_xfer_locked(), which flushes the FIFO before
sending a command.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Miquel Raynal <miquel.raynal at bootlin.com>
Link: https://lore.kernel.org/r/20250129162250.3629189-1-Frank.Li at nxp.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 6ffe022dbb5b4..62913feae45dd 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -860,6 +860,8 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
 	u32 reg;
 	int ret, i;
 
+	svc_i3c_master_flush_fifo(master);
+
 	while (true) {
 		/* SVC_I3C_MCTRL_REQUEST_PROC_DAA have two mode, ENTER DAA or PROCESS DAA.
 		 *
-- 
2.39.5



From sashal at kernel.org  Mon May  5 15:52:32 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 18:52:32 -0400
Subject: [PATCH AUTOSEL 6.6 052/294] i3c: master: svc: Fix missing STOP for master request
In-Reply-To: <20250505225634.2688578-1-sashal@kernel.org>
References: <20250505225634.2688578-1-sashal@kernel.org>
Message-ID: <20250505225634.2688578-52-sashal@kernel.org>

From: Stanley Chu <yschu at nuvoton.com>

[ Upstream commit 0430bf9bc1ac068c8b8c540eb93e5751872efc51 ]

The controller driver nacked the master request but didn't emit a
STOP to end the transaction. The driver shall refuse the unsupported
requests and return the controller state to IDLE by emitting a STOP.

Signed-off-by: Stanley Chu <yschu at nuvoton.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Link: https://lore.kernel.org/r/20250318053606.3087121-4-yschu at nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index fa1f12a89158c..3cef3794f10d3 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -503,6 +503,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
 			queue_work(master->base.wq, &master->hj_work);
 		break;
 	case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
+		svc_i3c_master_emit_stop(master);
 	default:
 		break;
 	}
-- 
2.39.5



From sashal at kernel.org  Mon May  5 15:54:44 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 18:54:44 -0400
Subject: [PATCH AUTOSEL 6.6 184/294] i3c: master: svc: Flush FIFO before sending Dynamic Address Assignment(DAA)
In-Reply-To: <20250505225634.2688578-1-sashal@kernel.org>
References: <20250505225634.2688578-1-sashal@kernel.org>
Message-ID: <20250505225634.2688578-184-sashal@kernel.org>

From: Frank Li <Frank.Li at nxp.com>

[ Upstream commit a892ee4cf22a50e1d6988d0464a9a421f3e5db2f ]

Ensure the FIFO is empty before issuing the DAA command to prevent
incorrect command data from being sent. Align with other data transfers,
such as svc_i3c_master_start_xfer_locked(), which flushes the FIFO before
sending a command.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Miquel Raynal <miquel.raynal at bootlin.com>
Link: https://lore.kernel.org/r/20250129162250.3629189-1-Frank.Li at nxp.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 3cef3794f10d3..3d1734849e0d9 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -841,6 +841,8 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
 	u32 reg;
 	int ret, i;
 
+	svc_i3c_master_flush_fifo(master);
+
 	while (true) {
 		/* Enter/proceed with DAA */
 		writel(SVC_I3C_MCTRL_REQUEST_PROC_DAA |
-- 
2.39.5



From sashal at kernel.org  Mon May  5 16:03:34 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 19:03:34 -0400
Subject: [PATCH AUTOSEL 6.1 042/212] i3c: master: svc: Fix missing STOP for master request
In-Reply-To: <20250505230624.2692522-1-sashal@kernel.org>
References: <20250505230624.2692522-1-sashal@kernel.org>
Message-ID: <20250505230624.2692522-42-sashal@kernel.org>

From: Stanley Chu <yschu at nuvoton.com>

[ Upstream commit 0430bf9bc1ac068c8b8c540eb93e5751872efc51 ]

The controller driver nacked the master request but didn't emit a
STOP to end the transaction. The driver shall refuse the unsupported
requests and return the controller state to IDLE by emitting a STOP.

Signed-off-by: Stanley Chu <yschu at nuvoton.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Link: https://lore.kernel.org/r/20250318053606.3087121-4-yschu at nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 38095649ed276..cf0550c6e95f0 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -495,6 +495,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
 			queue_work(master->base.wq, &master->hj_work);
 		break;
 	case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
+		svc_i3c_master_emit_stop(master);
 	default:
 		break;
 	}
-- 
2.39.5



From sashal at kernel.org  Mon May  5 16:05:15 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 19:05:15 -0400
Subject: [PATCH AUTOSEL 6.1 143/212] i3c: master: svc: Flush FIFO before sending Dynamic Address Assignment(DAA)
In-Reply-To: <20250505230624.2692522-1-sashal@kernel.org>
References: <20250505230624.2692522-1-sashal@kernel.org>
Message-ID: <20250505230624.2692522-143-sashal@kernel.org>

From: Frank Li <Frank.Li at nxp.com>

[ Upstream commit a892ee4cf22a50e1d6988d0464a9a421f3e5db2f ]

Ensure the FIFO is empty before issuing the DAA command to prevent
incorrect command data from being sent. Align with other data transfers,
such as svc_i3c_master_start_xfer_locked(), which flushes the FIFO before
sending a command.

Signed-off-by: Frank Li <Frank.Li at nxp.com>
Reviewed-by: Miquel Raynal <miquel.raynal at bootlin.com>
Link: https://lore.kernel.org/r/20250129162250.3629189-1-Frank.Li at nxp.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index cf0550c6e95f0..8cf3aa800d89d 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -833,6 +833,8 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
 	u32 reg;
 	int ret, i;
 
+	svc_i3c_master_flush_fifo(master);
+
 	while (true) {
 		/* Enter/proceed with DAA */
 		writel(SVC_I3C_MCTRL_REQUEST_PROC_DAA |
-- 
2.39.5



From sashal at kernel.org  Mon May  5 16:11:15 2025
From: sashal at kernel.org (Sasha Levin)
Date: Mon,  5 May 2025 19:11:15 -0400
Subject: [PATCH AUTOSEL 5.15 028/153] i3c: master: svc: Fix missing STOP for master request
In-Reply-To: <20250505231320.2695319-1-sashal@kernel.org>
References: <20250505231320.2695319-1-sashal@kernel.org>
Message-ID: <20250505231320.2695319-28-sashal@kernel.org>

From: Stanley Chu <yschu at nuvoton.com>

[ Upstream commit 0430bf9bc1ac068c8b8c540eb93e5751872efc51 ]

The controller driver nacked the master request but didn't emit a
STOP to end the transaction. The driver shall refuse the unsupported
requests and return the controller state to IDLE by emitting a STOP.

Signed-off-by: Stanley Chu <yschu at nuvoton.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
Link: https://lore.kernel.org/r/20250318053606.3087121-4-yschu at nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni at bootlin.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/i3c/master/svc-i3c-master.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 368429a34d600..92488ba5b5f2a 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -437,6 +437,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
 		queue_work(master->base.wq, &master->hj_work);
 		break;
 	case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
+		svc_i3c_master_emit_stop(master);
 	default:
 		break;
 	}
-- 
2.39.5



From aman.kumarpandey at nxp.com  Wed May  7 21:57:10 2025
From: aman.kumarpandey at nxp.com (Aman Kumar Pandey)
Date: Thu,  8 May 2025 07:57:10 +0300
Subject: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x i3c-hub support
Message-ID: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>

Add bindings for the NXP P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841)
multiport I3C hub family. These devices connect to a host via
I3C/I2C/SMBus and allow communication with multiple downstream
peripherals.

Signed-off-by: Aman Kumar Pandey <aman.kumarpandey at nxp.com>
Signed-off-by: Vikash Bansal <vikash.bansal at nxp.com>
---
V1 -> V2: Cleaned up coding style and addressed review comments
---
 .../bindings/i3c/p3h2840-i3c-hub.yaml         | 332 ++++++++++++++++++
 MAINTAINERS                                   |   8 +
 2 files changed, 340 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml

diff --git a/Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml b/Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml
new file mode 100644
index 000000000000..f3b5aabf5fe0
--- /dev/null
+++ b/Documentation/devicetree/bindings/i3c/p3h2840-i3c-hub.yaml
@@ -0,0 +1,332 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2025 NXP
+
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i3c/p3h2840-i3c-hub.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: P3H2X4X I3C HUB
+
+maintainers:
+  - Vikash Bansal <vikash.bansal at nxp.com>
+  - Aman Kumar Pandey <aman.kumarpandey at nxp.com>
+
+description: |
+  P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841) is a family of multiport I3C
+  hub devices that connect to:-
+  1. A host CPU via I3C/I2C/SMBus bus on upstream side and connect to multiple
+     peripheral devices on the downstream  side.
+  2. Have two Controller Ports which can support either
+     I2C/SMBus or I3C buses and connect to a CPU, BMC or SOC.
+  3. P3H2840/ P3H2841 are 8 port I3C hub with eight I3C/I2C Target Port.
+  4. P3H2440/ P3H2441 are 4 port I3C hub with four I3C/I2C Target Port.
+     Target ports can be configured as I2C/SMBus, I3C or GPIO and connect to
+     peripherals.
+
+allOf:
+  - $ref: i3c.yaml#
+
+properties:
+  $nodename:
+    pattern: "^hub@[@.*]+,[0-9a-f]+$"
+
+  Compatible:
+    const: nxp,p3h2x4x
+
+  cp0-ldo-enable:
+    type: boolean
+    description:
+      Enables the on-die LDO for controller Port 0.
+
+  cp1-ldo-enable:
+    type: boolean
+    description:
+      Enables the on-die LDO for controller Port 1.
+
+  tp0145-ldo-enable:
+    type: boolean
+    description:
+      Enables the on-die LDO for target ports 0/1/4/5.
+
+  tp2367-ldo-enable:
+    type: boolean
+    description:
+      Enables the on-die LDO for target ports 2/3/6/7.
+
+  cp0-ldo-microvolt:
+    description:
+      Selects the voltage for controller Port 0, in microvolts.
+    enum: [1000000, 1100000, 1200000, 1800000]
+    default: 1000000
+
+  cp1-ldo-microvolt:
+    description:
+      Selects the voltage for controller Port 1, in microvolts.
+    enum: [1000000, 1100000, 1200000, 1800000]
+    default: 1000000
+
+  tp0145-ldo-microvolt:
+    description:
+      Selects the voltage for target Port 0/1/4/5, in microvolts.
+    enum: [1000000, 1100000, 1200000, 1800000]
+    default: 1000000
+
+  tp2367-ldo-microvolt:
+    description:
+      Selects the voltage for target Port 2/3/6/7, in microvolts.
+    enum: [1000000, 1100000, 1200000, 1800000]
+    default: 1000000
+
+  tp0145-pullup-ohm:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Selects the pull up resistance for target Port 0/1/4/5, in ohms.
+    enum: [250, 500, 1000, 2000]
+    default: 500
+
+  tp2367-pullup-ohm:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Selects the pull up resistance for target Port 2/3/6/7, in ohms.
+    enum: [250, 500, 1000, 2000]
+    default: 500
+
+  cp0-io-strength-ohm:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Selects the IO drive strength for controller Port 0, in ohms.
+    enum: [20, 30, 40, 50]
+    default: 20
+
+  cp1-io-strength-ohm:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Selects the IO drive strength for controller Port 1, in ohms.
+    enum: [20, 30, 40, 50]
+    default: 20
+
+  tp0145-io-strength-ohm:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Selects the IO drive strength for target port 0/1/4/5, in ohms.
+    enum: [20, 30, 40, 50]
+    default: 20
+
+  tp2367-io-strength-ohm:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Selects the IO drive strength for target port 2/3/6/7, in ohms.
+    enum: [20, 30, 40, 50]
+    default: 20
+
+patternProperties:
+  "@[0-7]$":
+    type: object
+    additionalProperties: false
+    description:
+      I3C HUB Target Port child, should be named as target-port@<target-port-id>
+
+    properties:
+      reg:
+        description: |
+          The I3C HUB Target Port number.
+        minimum: 0
+        maximum: 0x07
+
+      mode:
+        enum: [i3c, smbus, i2c, gpio]
+        description:
+          I3C HUB Target Port mode setting to control Target Port functionality.
+          As per now it is oly supporting SMBus, i2c and i3c( i2c mode will work
+          with hub network).
+
+      pullup-enable:
+        type: boolean
+        description:
+          Enables the on-die pull-up for Target Port.
+
+      ibi-enable:
+        type: boolean
+        description:
+          Enables the IBI for Target Port.
+
+      local_dev:
+        $ref: /schemas/types.yaml#/definitions/uint8-array
+        description: |
+          SMBus Target Agent can discard transactions of downstream device and not generate an IBI to upstream I3C Hub
+          Controller Port. Up to 8 device (addresses) can be configured as local Devices.
+
+          This property is optional. If not provided, local device list will empty.
+
+      always-enable:
+        type: boolean
+        description:
+          Enables the hub network (Controller port -> target port).
+
+    patternProperties:
+      "@[0-9a-f]+$":
+        type: object
+        additionalProperties: false
+        description: |
+          I2C child, should be named: <device-type>@<i2c-address>
+
+        properties:
+          compatible:
+            description:
+              Compatible of the I2C/SMBus downstream device.
+
+          reg:
+            description: |
+              I2C address, Downstream device address which are connected to target port.
+            minimum: 0
+            maximum: 0x7f
+
+    required:
+      - compatible
+      - reg
+
+  "@[0-9a-f]+,[0-9a-f]+$":
+    type: object
+    additionalProperties: false
+    description: |
+      I3C child, should be named: <device-type>@<static-i2c-address>,<i3c-pid>
+
+    properties:
+      reg:
+        items:
+          - items:
+              - description: |
+                  Encodes the static I2C address. Should be 0 if the device does
+                  not have one (0 is not a valid I2C address).
+                minimum: 0
+                maximum: 0x7f
+              - description: |
+                  First half of the Provisioned ID (following the PID
+                  definition provided by the I3C specification).
+
+                  Contains the manufacturer ID left-shifted by 1.
+              - description: |
+                  Second half of the Provisioned ID (following the PID
+                  definition provided by the I3C specification).
+
+                  Contains the ORing of the part ID left-shifted by 16,
+                  the instance ID left-shifted by 12 and extra information.
+
+      assigned-address:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0x1
+        maximum: 0xff
+        description: |
+          Dynamic address to be assigned to this device. In case static address is
+          present (first cell of the reg property != 0), this address is assigned
+          through SETDASA. If static address is not present, this address is assigned
+          through SETNEWDA after assigning a temporary address via ENTDAA.
+
+    required:
+      - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i3c {
+        #address-cells = <3>;
+        #size-cells = <0>;
+
+        hub at 70,236153000c2{
+            #address-cells = <1>;
+            #size-cells = <0>;
+            reg = <0x70 0x236 0x3000c2>;
+            assigned-address = <0x50>;
+
+            cp0-ldo-microvolt = <1800000>;
+            cp1-ldo-microvolt = <1800000>;
+            tp0145-ldo-microvolt = <1800000>;
+            tp2367-ldo-microvolt = <1800000>;
+            tp0145-pullup-ohm = <1000>;
+            tp2367-pullup-ohm = <1000>;
+            cp0-io-strength-ohm = <50>;
+            cp1-io-strength-ohm = <50>;
+            tp0145-io-strength-ohm = <50>;
+            tp2367-io-strength-ohm = <50>;
+
+            target-port at 0 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                reg = <0x0>;
+                mode = "smbus";
+                pullup-enable;
+
+                eeprom at 57 {
+                    compatible = "atmel,24c32";
+                    reg = <0x57>;
+                    pagesize = <32>;
+                    wp-gpios = <&gpio2 2 0>;
+                    num-addresses = <8>;
+                };
+            };
+
+            target-port at 2 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                reg = <0x2>;
+                mode = "i3c";
+                pullup-enable;
+
+                sensor at 68,39200144004 {
+                  reg = <0x68 0x392 0x144004>;
+                  assigned-address = <0xa>;
+                };
+            };
+        };
+    };
+
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        hub at 70 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "nxp,p3h2x4x";
+            reg = <0x70>;
+
+            cp0-ldo-microvolt = <1800000>;
+            cp1-ldo-microvolt = <1800000>;
+            tp0145-ldo-microvolt = <1800000>;
+            tp2367-ldo-microvolt = <1800000>;
+            tp0145-pullup-ohm = <1000>;
+            tp2367-pullup-ohm = <1000>;
+            cp0-io-strength-ohm = <50>;
+            cp1-io-strength-ohm = <50>;
+            tp0145-io-strength-ohm = <50>;
+            tp2367-io-strength-ohm = <50>;
+
+            target-port at 0 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                reg = <0x0>;
+                mode = "smbus";
+                pullup-enable;
+
+                eeprom at 57 {
+                    compatible = "atmel,24c32";
+                    reg = <0x57>;
+                    pagesize = <32>;
+                    wp-gpios = <&gpio2 2 0>;
+                    num-addresses = <8>;
+                };
+            };
+
+            target-port at 2 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                reg = <0x2>;
+                mode = "i2c";
+                pullup-enable;
+                always-enable;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index af686e0bb6d7..38e197f20683 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17167,6 +17167,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
 F:	sound/soc/codecs/tfa989x.c
 
+NXP P3H2X4X I3C-HUB DRIVER
+M:	Vikash Bansal <vikash.bansal at nxp.com>
+M:	Aman Kumar Pandey <aman.kumarpandey at nxp.com>
+L:	linux-kernel at vger.kernel.org
+L:	linux-i3c-owner at lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/i3c/p3h2x4x_i3c_hub.yaml
+
 NZXT-KRAKEN2 HARDWARE MONITORING DRIVER
 M:	Jonas Malaco <jonas at protocubo.io>
 L:	linux-hwmon at vger.kernel.org
-- 
2.25.1



From aman.kumarpandey at nxp.com  Wed May  7 21:57:11 2025
From: aman.kumarpandey at nxp.com (Aman Kumar Pandey)
Date: Thu,  8 May 2025 07:57:11 +0300
Subject: [PATCH v2 2/2] drivers: i3c: Add driver for NXP P3H2x4x i3c-hub device
In-Reply-To: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
Message-ID: <20250508045711.2810207-2-aman.kumarpandey@nxp.com>

Add support for the NXP P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841)
family of multiport I3C hub devices. These hubs connect to a host
via I3C/I2C/SMBus and provide multiple downstream target ports.

The driver supports:
1. I3C/I2C communication between host and hub
2. Transparent I3C/I2C communication between host and downstream devices
3. Configurable target ports (I2C/SMBus or I3C)
4. MCTP device support
5. In-band interrupt handling

P3H2440/P3H2441 support 4 target ports;
P3H2840/P3H2841 support 8 target ports.

Signed-off-by: Aman Kumar Pandey <aman.kumarpandey at nxp.com>
Signed-off-by: Vikash Bansal <vikash.bansal at nxp.com>
---
V1 -> V2: Cleaned up coding style and addressed review comments
---
 MAINTAINERS                              |   1 +
 drivers/i3c/Kconfig                      |   1 +
 drivers/i3c/Makefile                     |   1 +
 drivers/i3c/hub/Kconfig                  |  11 +
 drivers/i3c/hub/Makefile                 |   4 +
 drivers/i3c/hub/p3h2840_i3c_hub.h        | 409 ++++++++++
 drivers/i3c/hub/p3h2840_i3c_hub_common.c | 910 +++++++++++++++++++++++
 drivers/i3c/hub/p3h2840_i3c_hub_i3c.c    | 353 +++++++++
 drivers/i3c/hub/p3h2840_i3c_hub_smbus.c  | 725 ++++++++++++++++++
 include/linux/i3c/device.h               |   1 +
 10 files changed, 2416 insertions(+)
 create mode 100644 drivers/i3c/hub/Kconfig
 create mode 100644 drivers/i3c/hub/Makefile
 create mode 100644 drivers/i3c/hub/p3h2840_i3c_hub.h
 create mode 100644 drivers/i3c/hub/p3h2840_i3c_hub_common.c
 create mode 100644 drivers/i3c/hub/p3h2840_i3c_hub_i3c.c
 create mode 100644 drivers/i3c/hub/p3h2840_i3c_hub_smbus.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 38e197f20683..e9d9f7b0c989 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17174,6 +17174,7 @@ L:	linux-kernel at vger.kernel.org
 L:	linux-i3c-owner at lists.infradead.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/i3c/p3h2x4x_i3c_hub.yaml
+F:	i3c/hub/*
 
 NZXT-KRAKEN2 HARDWARE MONITORING DRIVER
 M:	Jonas Malaco <jonas at protocubo.io>
diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
index 30a441506f61..254c50c3d33a 100644
--- a/drivers/i3c/Kconfig
+++ b/drivers/i3c/Kconfig
@@ -21,4 +21,5 @@ menuconfig I3C
 
 if I3C
 source "drivers/i3c/master/Kconfig"
+source "drivers/i3c/hub/Kconfig"
 endif # I3C
diff --git a/drivers/i3c/Makefile b/drivers/i3c/Makefile
index 11982efbc6d9..ea01bdda938d 100644
--- a/drivers/i3c/Makefile
+++ b/drivers/i3c/Makefile
@@ -2,3 +2,4 @@
 i3c-y				:= device.o master.o
 obj-$(CONFIG_I3C)		+= i3c.o
 obj-$(CONFIG_I3C)		+= master/
+obj-$(CONFIG_I3C)		+= hub/
diff --git a/drivers/i3c/hub/Kconfig b/drivers/i3c/hub/Kconfig
new file mode 100644
index 000000000000..26f1acddd2f1
--- /dev/null
+++ b/drivers/i3c/hub/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright 2025 NXP
+config P3H2X4X_I3C_HUB
+    tristate "P3H2X4X I3C HUB support"
+    depends on I3C
+    select REGMAP_I3C
+    help
+      This enables support for NXP P3H244x/P3H284x I3C HUB. These hubs
+      connect to a host via I3C/I2C/SMBus and allow communication with
+      multiple downstream peripherals. The Say Y or M here to use I3C
+      HUB driver to configure I3C HUB device.
diff --git a/drivers/i3c/hub/Makefile b/drivers/i3c/hub/Makefile
new file mode 100644
index 000000000000..9dbd8a7b4184
--- /dev/null
+++ b/drivers/i3c/hub/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright 2025 NXP
+p3h2840_i3c_hub-y := p3h2840_i3c_hub_common.o p3h2840_i3c_hub_i3c.o p3h2840_i3c_hub_smbus.o
+obj-$(CONFIG_P3H2X4X_I3C_HUB)	+= p3h2840_i3c_hub.o
diff --git a/drivers/i3c/hub/p3h2840_i3c_hub.h b/drivers/i3c/hub/p3h2840_i3c_hub.h
new file mode 100644
index 000000000000..7a39cf298e74
--- /dev/null
+++ b/drivers/i3c/hub/p3h2840_i3c_hub.h
@@ -0,0 +1,409 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2025 NXP
+ * This header file contain private device structure definition, Reg address and its bit
+ * mapping etc.
+ */
+
+#ifndef P3H2840_I3C_HUB_H
+#define P3H2840_I3C_HUB_H
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/i3c/device.h>
+#include <linux/i3c/master.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+/* I3C HUB REGISTERS */
+
+/* Device Information Registers */
+#define P3H2x4x_DEV_INFO_0					0x00
+#define P3H2x4x_DEV_INFO_1					0x01
+#define P3H2x4x_PID_5						0x02
+#define P3H2x4x_PID_4						0x03
+#define P3H2x4x_PID_3						0x04
+#define P3H2x4x_PID_2						0x05
+#define P3H2x4x_PID_1						0x06
+#define P3H2x4x_PID_0						0x07
+#define P3H2x4x_BCR						0x08
+#define P3H2x4x_DCR						0x09
+#define P3H2x4x_DEV_CAPAB					0x0a
+#define P3H2x4x_DEV_REV						0x0b
+
+/* Device Configuration Registers */
+#define P3H2x4x_DEV_REG_PROTECTION_CODE				0x10
+#define P3H2x4x_REGISTERS_LOCK_CODE				0x00
+#define P3H2x4x_REGISTERS_UNLOCK_CODE				0x69
+#define P3H2x4x_CP1_REGISTERS_UNLOCK_CODE			0x6a
+
+#define P3H2x4x_CP_CONF						0x11
+#define P3H2x4x_TP_ENABLE					0x12
+#define P3H2x4x_TPn_ENABLE(n)					BIT(n)
+
+#define P3H2x4x_DEV_CONF					0x13
+#define P3H2x4x_IO_STRENGTH					0x14
+#define P3H2x4x_TP0145_IO_STRENGTH_MASK				GENMASK(1, 0)
+#define P3H2x4x_TP0145_IO_STRENGTH(x)	\
+		FIELD_PREP(P3H2x4x_TP0145_IO_STRENGTH_MASK, x)
+#define P3H2x4x_TP2367_IO_STRENGTH_MASK				GENMASK(3, 2)
+#define P3H2x4x_TP2367_IO_STRENGTH(x)	\
+		FIELD_PREP(P3H2x4x_TP2367_IO_STRENGTH_MASK, x)
+#define P3H2x4x_CP0_IO_STRENGTH_MASK				GENMASK(5, 4)
+#define P3H2x4x_CP0_IO_STRENGTH(x)	\
+		FIELD_PREP(P3H2x4x_CP0_IO_STRENGTH_MASK, x)
+#define P3H2x4x_CP1_IO_STRENGTH_MASK				GENMASK(7, 6)
+#define P3H2x4x_CP1_IO_STRENGTH(x)	\
+		FIELD_PREP(P3H2x4x_CP1_IO_STRENGTH_MASK, x)
+
+#define P3H2x4x_NET_OPER_MODE_CONF				0x15
+#define P3H2x4x_VCCIO_LDO_CONF					0x16
+#define P3H2x4x_CP0_VCCIO_LDO_VOLTAGE_MASK			GENMASK(1, 0)
+#define P3H2x4x_CP0_VCCIO_LDO_VOLTAGE(x)	\
+		FIELD_PREP(P3H2x4x_CP0_VCCIO_LDO_VOLTAGE_MASK, x)
+#define P3H2x4x_CP1_VCCIO_LDO_VOLTAGE_MASK			GENMASK(3, 2)
+#define P3H2x4x_CP1_VCCIO_LDO_VOLTAGE(x)	\
+		FIELD_PREP(P3H2x4x_CP1_VCCIO_LDO_VOLTAGE_MASK, x)
+#define P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE_MASK			GENMASK(5, 4)
+#define P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE(x)	\
+		FIELD_PREP(P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE_MASK, x)
+#define P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE_MASK			GENMASK(7, 6)
+#define P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE(x)	\
+		FIELD_PREP(P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE_MASK, x)
+
+#define P3H2x4x_TP_IO_MODE_CONF					0x17
+#define P3H2x4x_TP_SMBUS_AGNT_EN				0x18
+#define P3H2x4x_TPn_SMBUS_MODE_EN(n)				BIT(n)
+#define P3H2x4x_TPn_I2C_MODE_EN(n)				BIT(n)
+
+#define P3H2x4x_LDO_AND_PULLUP_CONF				0x19
+#define P3H2x4x_LDO_ENABLE_DISABLE_MASK				GENMASK(3, 0)
+#define P3H2x4x_CP0_EN_LDO				        BIT(0)
+#define P3H2x4x_CP1_EN_LDO				        BIT(1)
+#define P3H2x4x_TP0145_EN_LDO					BIT(2)
+#define P3H2x4x_TP2367_EN_LDO					BIT(3)
+
+#define P3H2x4x_TP0145_PULLUP_CONF_MASK				GENMASK(7, 6)
+#define P3H2x4x_TP0145_PULLUP_CONF(x)	\
+		FIELD_PREP(P3H2x4x_TP0145_PULLUP_CONF_MASK, x)
+#define P3H2x4x_TP2367_PULLUP_CONF_MASK				GENMASK(5, 4)
+#define P3H2x4x_TP2367_PULLUP_CONF(x)	\
+		FIELD_PREP(P3H2x4x_TP2367_PULLUP_CONF_MASK, x)
+
+#define P3H2x4x_CP_IBI_CONF					0x1a
+
+#define P3H2x4x_TP_SMBUS_AGNT_IBI_CONFIG			0x1b
+#define P3H2x4x_TPn_IBI_EN(n)					BIT(n)
+#define P3H2x4x_ALL_TP_IBI_EN					0xff
+#define P3H2x4x_ALL_TP_IBI_DIS					0x00
+
+#define P3H2x4x_IBI_MDB_CUSTOM					0x1c
+#define P3H2x4x_JEDEC_CONTEXT_ID				0x1d
+#define P3H2x4x_TP_GPIO_MODE_EN					0x1e
+#define P3H2x4x_TPn_GPIO_MODE_EN(n)				BIT(n)
+
+/* Device Status and IBI Registers */
+#define P3H2x4x_DEV_AND_IBI_STS					0x20
+#define P3H2x4x_TP_SMBUS_AGNT_IBI_STS				0x21
+#define P3H2x4x_SMBUS_AGENT_EVENT_FLAG_STATUS			BIT(4)
+
+/* Controller Port Control/Status Registers */
+#define P3H2x4x_CP_MUX_SET					0x38
+#define P3H2x4x_CONTROLLER_PORT_MUX_REQ				BIT(0)
+#define P3H2x4x_CP_MUX_STS					0x39
+#define P3H2x4x_CONTROLLER_PORT_MUX_CONNECTION_STATUS		BIT(0)
+
+/* Target Ports Control Registers */
+#define P3H2x4x_TP_SMBUS_AGNT_TRANS_START			0x50
+#define P3H2x4x_TP_NET_CON_CONF					0x51
+#define P3H2x4x_TPn_NET_CON(n)					BIT(n)
+
+#define P3H2x4x_TP_PULLUP_EN					0x53
+#define P3H2x4x_TPn_PULLUP_EN(n)				BIT(n)
+
+#define P3H2x4x_TP_SCL_OUT_EN					0x54
+#define P3H2x4x_TP_SDA_OUT_EN					0x55
+#define P3H2x4x_TP_SCL_OUT_LEVEL				0x56
+#define P3H2x4x_TP_SDA_OUT_LEVEL				0x57
+#define P3H2x4x_TP_IN_DETECT_MODE_CONF				0x58
+#define P3H2x4x_TP_SCL_IN_DETECT_IBI_EN				0x59
+#define P3H2x4x_TP_SDA_IN_DETECT_IBI_EN				0x5a
+
+/* Target Ports Status Registers */
+#define P3H2x4x_TP_SCL_IN_LEVEL_STS				0x60
+#define P3H2x4x_TP_SDA_IN_LEVEL_STS				0x61
+#define P3H2x4x_TP_SCL_IN_DETECT_FLG				0x62
+#define P3H2x4x_TP_SDA_IN_DETECT_FLG				0x63
+
+/* SMBus Agent Configuration and Status Registers */
+#define P3H2x4x_TP0_SMBUS_AGNT_STS				0x64
+#define P3H2x4x_TP1_SMBUS_AGNT_STS				0x65
+#define P3H2x4x_TP2_SMBUS_AGNT_STS				0x66
+#define P3H2x4x_TP3_SMBUS_AGNT_STS				0x67
+#define P3H2x4x_TP4_SMBUS_AGNT_STS				0x68
+#define P3H2x4x_TP5_SMBUS_AGNT_STS				0x69
+#define P3H2x4x_TP6_SMBUS_AGNT_STS				0x6a
+#define P3H2x4x_TP7_SMBUS_AGNT_STS				0x6b
+#define P3H2x4x_ONCHIP_TD_AND_SMBUS_AGNT_CONF			0x6c
+
+/* buf receive flag set */
+#define P3H2x4x_TARGET_BUF_CA_TF				BIT(0)
+#define P3H2x4x_TARGET_BUF_0_RECEIVE				BIT(1)
+#define P3H2x4x_TARGET_BUF_1_RECEIVE				BIT(2)
+#define P3H2x4x_TARGET_BUF_0_1_RECEIVE				GENMASK(2, 1)
+#define P3H2x4x_TARGET_BUF_OVRFL				GENMASK(3, 1)
+#define BUF_RECEIVED_FLAG_MASK					GENMASK(3, 1)
+#define BUF_RECEIVED_FLAG_TF_MASK				GENMASK(3, 0)
+
+#define P3H2x4x_TARGET_AGENT_LOCAL_DEV				0x11
+#define P3H2x4x_TARGET_BUFF_0_PAGE				0x12
+#define P3H2x4x_TARGET_BUFF_1_PAGE				0x13
+
+/* Special Function Registers */
+#define P3H2x4x_LDO_AND_CPSEL_STS				0x79
+#define P3H2x4x_CP_SDA1_LEVEL					BIT(7)
+#define P3H2x4x_CP_SCL1_LEVEL					BIT(6)
+
+#define P3H2x4x_CP_SEL_PIN_INPUT_CODE_MASK			GENMASK(5, 4)
+#define P3H2x4x_CP_SEL_PIN_INPUT_CODE_GET(x)	\
+		(((x) & P3H2x4x_CP_SEL_PIN_INPUT_CODE_MASK) >> 4)
+#define P3H2x4x_CP_SDA1_SCL1_PINS_CODE_MASK			GENMASK(7, 6)
+#define P3H2x4x_CP_SDA1_SCL1_PINS_CODE_GET(x)	\
+		(((x) & P3H2x4x_CP_SDA1_SCL1_PINS_CODE_MASK) >> 6)
+#define P3H2x4x_VCCIO1_PWR_GOOD					BIT(3)
+#define P3H2x4x_VCCIO0_PWR_GOOD					BIT(2)
+#define P3H2x4x_CP1_VCCIO_PWR_GOOD				BIT(1)
+#define P3H2x4x_CP0_VCCIO_PWR_GOOD				BIT(0)
+
+#define P3H2x4x_BUS_RESET_SCL_TIMEOUT				0x7a
+#define P3H2x4x_ONCHIP_TD_PROTO_ERR_FLG				0x7b
+#define P3H2x4x_DEV_CMD						0x7c
+#define P3H2x4x_ONCHIP_TD_STS					0x7d
+#define P3H2x4x_ONCHIP_TD_ADDR_CONF				0x7e
+#define P3H2x4x_PAGE_PTR					0x7f
+
+/* Paged Transaction Registers */
+#define P3H2x4x_CONTROLLER_BUFFER_PAGE				0x10
+#define P3H2x4x_CONTROLLER_AGENT_BUFF				0x80
+#define P3H2x4x_CONTROLLER_AGENT_BUFF_DATA			0x84
+
+#define P3H2x4x_TARGET_BUFF_LENGTH				0x80
+#define P3H2x4x_TARGET_BUFF_ADDRESS				0x81
+#define P3H2x4x_TARGET_BUFF_DATA				0x82
+
+#define P3H2x4x_TP_MAX_COUNT					0x08
+#define P3H2x4x_CP_MAX_COUNT					0x02
+#define P3H2x4x_TP_LOCAL_DEV					0x08
+
+/* LDO Disable/Enable DT settings */
+#define P3H2x4x_LDO_VOLT_1_0V					0x00
+#define P3H2x4x_LDO_VOLT_1_1V					0x01
+#define P3H2x4x_LDO_VOLT_1_2V					0x02
+#define P3H2x4x_LDO_VOLT_1_8V					0x03
+#define P3H2x4x_DT_LDO_VOLT_NOT_SET				0x04
+
+#define P3H2x4x_LDO_DISABLED					0x00
+#define P3H2x4x_LDO_ENABLED					0x01
+
+#define P3H2x4x_IBI_DISABLED					0x00
+#define P3H2x4x_IBI_ENABLED					0x01
+
+/* Pullup selection DT settings */
+#define P3H2x4x_TP_PULLUP_250R					0x00
+#define P3H2x4x_TP_PULLUP_500R					0x01
+#define P3H2x4x_TP_PULLUP_1000R					0x02
+#define P3H2x4x_TP_PULLUP_2000R					0x03
+#define P3H2x4x_TP_PULLUP_NOT_SET				0x04
+
+#define P3H2x4x_TP_PULLUP_DISABLED				0x00
+#define P3H2x4x_TP_PULLUP_ENABLED				0x01
+
+#define P3H2x4x_IO_STRENGTH_20_OHM				0x00
+#define P3H2x4x_IO_STRENGTH_30_OHM				0x01
+#define P3H2x4x_IO_STRENGTH_40_OHM				0x02
+#define P3H2x4x_IO_STRENGTH_50_OHM				0x03
+#define P3H2x4x_IO_STRENGTH_NOT_SET				0x04
+
+#define P3H2x4x_TP_MODE_I3C					0x00
+#define P3H2x4x_TP_MODE_SMBUS					0x01
+#define P3H2x4x_TP_MODE_GPIO					0x02
+#define P3H2x4x_TP_MODE_I2C					0x03
+#define P3H2x4x_TP_MODE_NOT_SET					0x04
+
+#define ONE_BYTE_SIZE						0x01
+
+/* holding SDA low when both SMBus Target Agent received data buffers are full.
+ * This feature can be used as a flow-control mechanism for MCTP applications to
+ * avoid MCTP transmitters on Target Ports time out when the SMBus agent buffers
+ * are not serviced in time by upstream controller and only receives write message
+ * from its downstream ports.
+ * SMBUS_AGENT_TX_RX_LOOPBACK_EN/TARGET_AGENT_BUF_FULL_SDA_LOW_EN
+ */
+
+#define P3H2x4x_TARGET_AGENT_DFT_IBI_CONF			0x20
+#define P3H2x4x_TARGET_AGENT_DFT_IBI_CONF_MASK			0x21
+
+/* Transaction status checking mask */
+#define P3H2x4x_XFER_SUCCESS					0x01
+#define P3H2x4x_TP_BUFFER_STATUS_MASK				0x0f
+#define P3H2x4x_TP_TRANSACTION_CODE_MASK			0xf0
+
+/* SMBus transaction types fields */
+#define P3H2x4x_SMBUS_400kHz					BIT(2)
+
+/* SMBus polling */
+#define P3H2x4x_POLLING_ROLL_PERIOD_MS				10
+
+/* Hub buffer size */
+#define P3H2x4x_CONTROLLER_BUFFER_SIZE				88
+#define P3H2x4x_TARGET_BUFFER_SIZE				80
+#define P3H2x4x_SMBUS_DESCRIPTOR_SIZE				4
+#define P3H2x4x_SMBUS_PAYLOAD_SIZE	\
+		(P3H2x4x_CONTROLLER_BUFFER_SIZE - P3H2x4x_SMBUS_DESCRIPTOR_SIZE)
+#define P3H2x4x_SMBUS_TARGET_PAYLOAD_SIZE	(P3H2x4x_TARGET_BUFFER_SIZE - 2)
+
+/* Hub SMBus transaction time */
+#define P3H2x4x_SMBUS_400kHz_TRANSFER_TIMEOUT(x)		((20 * (x)) + 80)
+
+#define P3H2x4x_NO_PAGE_PER_TP					4
+
+#define P3H2x4x_MAX_PAYLOAD_LEN					2
+#define P3H2x4x_NUM_SLOTS					10
+
+#define P3H2x4x_HUB_ID						0
+
+/* Reg config for Regmap */
+#define P3H2x4x_REG_BITS					8
+#define P3H2x4x_VAL_BITS					8
+
+enum p3h2x4x_tp {
+	TP_0,
+	TP_1,
+	TP_2,
+	TP_3,
+	TP_4,
+	TP_5,
+	TP_6,
+	TP_7,
+};
+
+enum p3h2x4x_rcv_buf {
+	RCV_BUF_0,
+	RCV_BUF_1,
+	RCV_BUF_OF,
+};
+
+struct p3h2x4x_setting {
+	const char *const name;
+	const u8 value;
+};
+
+struct tp_setting {
+	int mode;
+	bool pullup_en;
+	bool ibi_en;
+	bool always_enable;
+};
+
+/*
+ * struct svc_i3c_i2c_dev_data - Device specific data
+ * @index: Index in the master tables corresponding to this device
+ * @ibi: IBI slot index in the master structure
+ * @ibi_pool: IBI pool associated to this device
+ */
+struct dt_settings {
+	bool cp0_ldo_en;
+	bool cp1_ldo_en;
+	bool tp0145_ldo_en;
+	bool tp2367_ldo_en;
+	int cp0_ldo_volt;
+	int cp1_ldo_volt;
+	int tp0145_ldo_volt;
+	int tp2367_ldo_volt;
+	int tp0145_pullup;
+	int tp2367_pullup;
+	int cp0_io_strength;
+	int cp1_io_strength;
+	int tp0145_io_strength;
+	int tp2367_io_strength;
+	struct tp_setting tp[P3H2x4x_TP_MAX_COUNT];
+};
+
+struct smbus_device {
+	struct i2c_client *client;
+	const char *compatible;
+	int addr;
+	struct list_head list;
+	struct device_node *tp_device_dt_node;
+};
+
+struct tp_bus {
+	bool dt_available;      /* bus configuration is available in DT. */
+	bool is_registered;	    /* bus was registered in the framework. */
+	u8 tp_mask;
+	u8 tp_port;
+	u8 local_dev_list[P3H2x4x_TP_LOCAL_DEV];
+	u8 local_dev_count;
+	struct i3c_master_controller i3c_port_controller;
+	struct i2c_adapter smbus_port_adapter;
+	struct device_node *of_node;
+	struct p3h2x4x *priv;
+	struct list_head tp_device_entry;
+	struct mutex port_mutex;      /* per port mutex */
+};
+
+struct p3h2x4x {
+	struct i3c_device *i3cdev;
+	struct i2c_client *i2cdev;
+	struct i3c_master_controller *driving_master;
+	struct regmap *regmap;
+	struct mutex etx_mutex;      /* all port mutex */
+	struct dt_settings settings;
+	struct tp_bus tp_bus[P3H2x4x_TP_MAX_COUNT];
+	/* Offset for reading HUB's register. */
+	u8 tp_ibi_mask;
+	u8 tp_i3c_bus_mask;
+	u8 tp_always_enable_mask;
+	u8 is_slave_reg;
+	bool is_p3h2x4x_in_i3c;
+};
+
+/*
+ * p3h2x4x_tp_add_downstream_device - prove downstream devices for target port who
+ * configured as SMBus.
+ * @priv: p3h2x4x device structure.
+ * Return: 0 in case of success, a negative EINVAL code if the error.
+ */
+int p3h2x4x_tp_add_downstream_device(struct p3h2x4x *priv);
+
+/*
+ * p3h2x4x_tp_smbus_algo - add i2c adapter for target port who
+ * configured as SMBus.
+ * @priv: p3h2x4x device structure.
+ * @tp: target port.
+ * Return: 0 in case of success, a negative EINVAL code if the error.
+ */
+int p3h2x4x_tp_smbus_algo(struct p3h2x4x *priv, int tp);
+
+/*
+ * p3h2x4x_tp_i3c_algo - register i3c master for target port who
+ * configured as I3C.
+ * @priv: p3h2x4x device structure.
+ * @tp: target port.
+ * Return: 0 in case of success, a negative EINVAL code if the error.
+ */
+int p3h2x4x_tp_i3c_algo(struct p3h2x4x *priv, int tp);
+
+/*
+ * p3h2x4x_ibi_handler - IBI handler.
+ * @i3cdev: i3c device.
+ * @payload: two byte IBI payload data.
+ */
+void p3h2x4x_ibi_handler(struct i3c_device *i3cdev,
+			 const struct i3c_ibi_payload *payload);
+#endif /* P3H2840_I3C_HUB_H */
diff --git a/drivers/i3c/hub/p3h2840_i3c_hub_common.c b/drivers/i3c/hub/p3h2840_i3c_hub_common.c
new file mode 100644
index 000000000000..9da6bab70f1c
--- /dev/null
+++ b/drivers/i3c/hub/p3h2840_i3c_hub_common.c
@@ -0,0 +1,910 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ * This P3H2x4x driver file implements functions for Hub probe and DT parsing.
+ */
+
+#include "p3h2840_i3c_hub.h"
+
+/* LDO voltage DT settings */
+#define P3H2x4x_DT_LDO_VOLT_1_0V                1000
+#define P3H2x4x_DT_LDO_VOLT_1_1V		1100
+#define P3H2x4x_DT_LDO_VOLT_1_2V		1200
+#define P3H2x4x_DT_LDO_VOLT_1_8V		1800
+
+/* target port pull-up settings */
+#define P3H2x4x_DT_TP_PULLUP_250R		250
+#define P3H2x4x_DT_TP_PULLUP_500R		500
+#define P3H2x4x_DT_TP_PULLUP_1000R		1000
+#define P3H2x4x_DT_TP_PULLUP_2000R		2000
+
+/*  IO strenght settings */
+#define P3H2x4x_DT_IO_STRENGTH_20_OHM		20
+#define P3H2x4x_DT_IO_STRENGTH_30_OHM		30
+#define P3H2x4x_DT_IO_STRENGTH_40_OHM		40
+#define P3H2x4x_DT_IO_STRENGTH_50_OHM		50
+
+/* target port mode settings */
+static const struct p3h2x4x_setting tp_mode_settings[] = {
+	{ "i3c",		P3H2x4x_TP_MODE_I3C },
+	{ "smbus",		P3H2x4x_TP_MODE_SMBUS },
+	{ "gpio",		P3H2x4x_TP_MODE_GPIO },
+	{ "i2c",		P3H2x4x_TP_MODE_I2C },
+};
+
+static const struct i3c_ibi_setup p3h2x4x_ibireq = {
+		.handler = p3h2x4x_ibi_handler,
+		.max_payload_len = P3H2x4x_MAX_PAYLOAD_LEN,
+		.num_slots = P3H2x4x_NUM_SLOTS,
+};
+
+static const struct regmap_config p3h2x4x_regmap_config = {
+		.reg_bits = P3H2x4x_REG_BITS,
+		.val_bits = P3H2x4x_VAL_BITS,
+};
+
+static void p3h2x4x_of_get_dt_setting(struct device *dev,
+				      const struct device_node *node,
+				      const char *setting_name,
+				      const struct p3h2x4x_setting settings[],
+				      const int settings_count,
+				      int *setting_value)
+{
+	const char *sval;
+	int ret;
+	int i;
+
+	ret = of_property_read_string(node, setting_name, &sval);
+	if (ret) {
+		if (ret != -EINVAL)
+			dev_warn(dev, "No setting or invalid setting for %s, err=%i\n",
+				 setting_name, ret);
+		return;
+	}
+
+	for (i = 0; i < settings_count; ++i) {
+		const struct p3h2x4x_setting *const setting = &settings[i];
+
+		if (!strcmp(setting->name, sval)) {
+			*setting_value = setting->value;
+			return;
+		}
+	}
+	dev_warn(dev, "Unknown setting for %s\n", setting_name);
+}
+
+static u8 p3h2x4x_ldo_dt_to_reg(int dt_value)
+{
+	switch (dt_value) {
+	case P3H2x4x_DT_LDO_VOLT_1_8V:
+		return P3H2x4x_LDO_VOLT_1_8V;
+	case P3H2x4x_DT_LDO_VOLT_1_2V:
+		return P3H2x4x_LDO_VOLT_1_2V;
+	case P3H2x4x_DT_LDO_VOLT_1_1V:
+		return P3H2x4x_LDO_VOLT_1_1V;
+	default:
+		return P3H2x4x_LDO_VOLT_1_0V;
+	}
+}
+
+static u8 p3h2x4x_pullup_dt_to_reg(int dt_value)
+{
+	switch (dt_value) {
+	case P3H2x4x_DT_TP_PULLUP_2000R:
+		return P3H2x4x_TP_PULLUP_2000R;
+	case P3H2x4x_DT_TP_PULLUP_1000R:
+		return P3H2x4x_TP_PULLUP_1000R;
+	case P3H2x4x_DT_TP_PULLUP_250R:
+		return P3H2x4x_TP_PULLUP_250R;
+	default:
+		return P3H2x4x_TP_PULLUP_500R;
+	}
+}
+
+static u8 p3h2x4x_io_strength_dt_to_reg(int dt_value)
+{
+	switch (dt_value) {
+	case P3H2x4x_DT_IO_STRENGTH_50_OHM:
+		return P3H2x4x_IO_STRENGTH_50_OHM;
+	case P3H2x4x_DT_IO_STRENGTH_40_OHM:
+		return P3H2x4x_IO_STRENGTH_40_OHM;
+	case P3H2x4x_DT_IO_STRENGTH_30_OHM:
+		return P3H2x4x_IO_STRENGTH_30_OHM;
+	default:
+		return P3H2x4x_IO_STRENGTH_20_OHM;
+	}
+}
+
+static int p3h2x4x_configure_pullup(struct device *dev)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	u8 mask = 0, value = 0;
+
+	if (priv->settings.tp0145_pullup != P3H2x4x_TP_PULLUP_NOT_SET) {
+		mask |= P3H2x4x_TP0145_PULLUP_CONF_MASK;
+		value |= P3H2x4x_TP0145_PULLUP_CONF(p3h2x4x_pullup_dt_to_reg
+						    (priv->settings.tp0145_pullup));
+	}
+
+	if (priv->settings.tp2367_pullup != P3H2x4x_TP_PULLUP_NOT_SET) {
+		mask |= P3H2x4x_TP2367_PULLUP_CONF_MASK;
+		value |= P3H2x4x_TP2367_PULLUP_CONF(p3h2x4x_pullup_dt_to_reg
+						    (priv->settings.tp2367_pullup));
+	}
+
+	return regmap_update_bits(priv->regmap, P3H2x4x_LDO_AND_PULLUP_CONF,
+				  mask, value);
+}
+
+static int p3h2x4x_configure_ldo(struct device *dev)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	u8 ldo_config_mask = 0, ldo_config_val = 0;
+	u8 ldo_disable_mask = 0, ldo_en_val = 0;
+	u32 reg_val;
+	int ret;
+	u8 val;
+
+	/* Enable or Disable LDO's. If there is no DT entry - disable LDO for safety reasons */
+	if (priv->settings.cp0_ldo_en)
+		ldo_en_val |= P3H2x4x_CP0_EN_LDO;
+	if (priv->settings.cp1_ldo_en)
+		ldo_en_val |= P3H2x4x_CP1_EN_LDO;
+	if (priv->settings.tp0145_ldo_en)
+		ldo_en_val |= P3H2x4x_TP0145_EN_LDO;
+	if (priv->settings.tp2367_ldo_en)
+		ldo_en_val |= P3H2x4x_TP2367_EN_LDO;
+
+	/* Get current LDOs configuration */
+	ret = regmap_read(priv->regmap, P3H2x4x_VCCIO_LDO_CONF, &reg_val);
+	if (ret)
+		return ret;
+
+	/*
+	 * LDOs Voltage level (Skip if not defined in the DT)
+	 * Set the mask only if there is a change from current value
+	 */
+	if (priv->settings.cp0_ldo_volt != P3H2x4x_DT_LDO_VOLT_NOT_SET) {
+		val = P3H2x4x_CP0_VCCIO_LDO_VOLTAGE(p3h2x4x_ldo_dt_to_reg
+						    (priv->settings.cp0_ldo_volt));
+		if ((reg_val & P3H2x4x_CP0_VCCIO_LDO_VOLTAGE_MASK) != val) {
+			ldo_config_mask |= P3H2x4x_CP0_VCCIO_LDO_VOLTAGE_MASK;
+			ldo_config_val |= val;
+
+			ldo_disable_mask |= P3H2x4x_CP0_EN_LDO;
+		}
+	}
+	if (priv->settings.cp1_ldo_volt != P3H2x4x_DT_LDO_VOLT_NOT_SET) {
+		val = P3H2x4x_CP1_VCCIO_LDO_VOLTAGE(p3h2x4x_ldo_dt_to_reg
+						    (priv->settings.cp1_ldo_volt));
+		if ((reg_val & P3H2x4x_CP1_VCCIO_LDO_VOLTAGE_MASK) != val) {
+			ldo_config_mask |= P3H2x4x_CP1_VCCIO_LDO_VOLTAGE_MASK;
+			ldo_config_val |= val;
+
+			ldo_disable_mask |= P3H2x4x_CP1_EN_LDO;
+		}
+	}
+	if (priv->settings.tp0145_ldo_volt != P3H2x4x_DT_LDO_VOLT_NOT_SET) {
+		val = P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE(p3h2x4x_ldo_dt_to_reg
+						       (priv->settings.tp0145_ldo_volt));
+		if ((reg_val & P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE_MASK) != val) {
+			ldo_config_mask |= P3H2x4x_TP0145_VCCIO_LDO_VOLTAGE_MASK;
+			ldo_config_val |= val;
+
+			ldo_disable_mask |= P3H2x4x_TP0145_EN_LDO;
+		}
+	}
+	if (priv->settings.tp2367_ldo_volt != P3H2x4x_DT_LDO_VOLT_NOT_SET) {
+		val = P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE(p3h2x4x_ldo_dt_to_reg
+						       (priv->settings.tp2367_ldo_volt));
+		if ((reg_val & P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE_MASK) != val) {
+			ldo_config_mask |= P3H2x4x_TP2367_VCCIO_LDO_VOLTAGE_MASK;
+			ldo_config_val |= val;
+
+			ldo_disable_mask |= P3H2x4x_TP2367_EN_LDO;
+		}
+	}
+
+	/*
+	 * Update LDO voltage configuration only if value is changed from already existing register
+	 * value. It is a good practice to disable the LDO's before making any voltage changes.
+	 * Presence of config mask indicates voltage change to be applied.
+	 */
+	if (ldo_config_mask) {
+		/* Disable LDO's before making voltage changes */
+		ret = regmap_clear_bits(priv->regmap,
+					P3H2x4x_LDO_AND_PULLUP_CONF,
+					ldo_disable_mask);
+		if (ret)
+			return ret;
+
+		/* Update the LDOs configuration */
+		ret = regmap_update_bits(priv->regmap, P3H2x4x_VCCIO_LDO_CONF,
+					 ldo_config_mask, ldo_config_val);
+		if (ret)
+			return ret;
+	}
+
+	/* Update the LDOs Enable/disable register. This will enable only LDOs enabled in DT */
+	return regmap_update_bits(priv->regmap, P3H2x4x_LDO_AND_PULLUP_CONF,
+				  P3H2x4x_LDO_ENABLE_DISABLE_MASK, ldo_en_val);
+}
+
+static int p3h2x4x_configure_io_strength(struct device *dev)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	u8 mask_all = 0, val_all = 0;
+	u32 reg_val;
+	int ret;
+	u8 val;
+
+	ret = regmap_read(priv->regmap, P3H2x4x_IO_STRENGTH, &reg_val);
+	if (ret)
+		return ret;
+
+	if (priv->settings.cp0_io_strength != P3H2x4x_IO_STRENGTH_NOT_SET) {
+		val = P3H2x4x_CP0_IO_STRENGTH(p3h2x4x_io_strength_dt_to_reg
+					      (priv->settings.cp0_io_strength));
+		mask_all |= P3H2x4x_CP0_IO_STRENGTH_MASK;
+		val_all |= val;
+	}
+	if (priv->settings.cp1_io_strength != P3H2x4x_IO_STRENGTH_NOT_SET) {
+		val = P3H2x4x_CP1_IO_STRENGTH(p3h2x4x_io_strength_dt_to_reg
+					      (priv->settings.cp1_io_strength));
+		mask_all |= P3H2x4x_CP1_IO_STRENGTH_MASK;
+		val_all |= val;
+	}
+	if (priv->settings.tp0145_io_strength != P3H2x4x_IO_STRENGTH_NOT_SET) {
+		val = P3H2x4x_TP0145_IO_STRENGTH(p3h2x4x_io_strength_dt_to_reg
+						 (priv->settings.tp0145_io_strength));
+		mask_all |= P3H2x4x_TP0145_IO_STRENGTH_MASK;
+		val_all |= val;
+	}
+	if (priv->settings.tp2367_io_strength != P3H2x4x_IO_STRENGTH_NOT_SET) {
+		val = P3H2x4x_TP2367_IO_STRENGTH(p3h2x4x_io_strength_dt_to_reg
+						 (priv->settings.tp2367_io_strength));
+		mask_all |= P3H2x4x_TP2367_IO_STRENGTH_MASK;
+		val_all |= val;
+	}
+
+	/* Set IO strength if required */
+	return regmap_update_bits(priv->regmap, P3H2x4x_IO_STRENGTH, mask_all, val_all);
+}
+
+static int p3h2x4x_configure_tp(struct device *dev)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	u8 pullup_mask = 0, pullup_val = 0;
+	u8 smbus_mask = 0, smbus_val = 0;
+	u8 gpio_mask = 0, gpio_val = 0;
+	u8 i3c_mask = 0, i3c_val = 0;
+	u8 ibi_mask = 0, ibi_val = 0;
+	u8 i2c_mask = 0, i2c_val = 0;
+	int ret;
+	int i;
+
+	/* TBD: Read type of HUB from register P3H2x4x_DEV_INFO_0 to learn target ports count. */
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; ++i) {
+		if (priv->settings.tp[i].mode != P3H2x4x_TP_MODE_NOT_SET) {
+			i3c_mask |= P3H2x4x_TPn_NET_CON(i);
+			smbus_mask |= P3H2x4x_TPn_SMBUS_MODE_EN(i);
+			gpio_mask |= P3H2x4x_TPn_GPIO_MODE_EN(i);
+			i2c_mask |= P3H2x4x_TPn_I2C_MODE_EN(i);
+
+			if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_I3C)
+				i3c_val |= P3H2x4x_TPn_NET_CON(i);
+			else if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_SMBUS)
+				smbus_val |= P3H2x4x_TPn_SMBUS_MODE_EN(i);
+			else if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_GPIO)
+				gpio_val |= P3H2x4x_TPn_GPIO_MODE_EN(i);
+			else if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_I2C)
+				i2c_val |= P3H2x4x_TPn_I2C_MODE_EN(i);
+		}
+		if (priv->settings.tp[i].pullup_en) {
+			pullup_mask |= P3H2x4x_TPn_PULLUP_EN(i);
+			pullup_val |= P3H2x4x_TPn_PULLUP_EN(i);
+		}
+
+		if (priv->settings.tp[i].ibi_en) {
+			ibi_mask |= P3H2x4x_TPn_IBI_EN(i);
+			ibi_val |= P3H2x4x_TPn_IBI_EN(i);
+		}
+	}
+
+	ret = regmap_update_bits(priv->regmap, P3H2x4x_TP_IO_MODE_CONF, (smbus_mask | i2c_mask),
+				 (smbus_val | i2c_val));
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(priv->regmap, P3H2x4x_TP_PULLUP_EN, pullup_mask, pullup_val);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(priv->regmap, P3H2x4x_TP_SMBUS_AGNT_IBI_CONFIG, ibi_mask, ibi_val);
+	if (ret)
+		return ret;
+	priv->tp_ibi_mask = ibi_val;
+
+	ret = regmap_update_bits(priv->regmap, P3H2x4x_TP_SMBUS_AGNT_EN, smbus_mask, smbus_val);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(priv->regmap, P3H2x4x_TP_GPIO_MODE_EN, gpio_mask, gpio_val);
+	if (ret)
+		return ret;
+
+	/* Request for HUB Network connection in case any TP is configured in I3C mode */
+	if ((i3c_val) || (i2c_val)) {
+		ret = regmap_write(priv->regmap, P3H2x4x_CP_MUX_SET,
+				   P3H2x4x_CONTROLLER_PORT_MUX_REQ);
+		if (ret)
+			return ret;
+	}
+
+	/* Enable TP here in case TP was configured */
+	ret = regmap_update_bits(priv->regmap, P3H2x4x_TP_ENABLE,
+				 i3c_mask | smbus_mask | gpio_mask | i2c_mask,
+				 i3c_val | smbus_val | gpio_val | i2c_val);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int p3h2x4x_configure_smbus_local_dev(struct device *dev)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	u8 target_buffer_page, hub_tp;
+	int ret = 0;
+
+	for (hub_tp = 0; hub_tp < P3H2x4x_TP_MAX_COUNT; hub_tp++) {
+		if (priv->tp_bus[hub_tp].local_dev_count &&
+		    priv->settings.tp[hub_tp].mode == P3H2x4x_TP_MODE_SMBUS) {
+			target_buffer_page = P3H2x4x_TARGET_AGENT_LOCAL_DEV + 4 * hub_tp;
+			ret = regmap_write(priv->regmap, P3H2x4x_PAGE_PTR, target_buffer_page);
+			if (ret) {
+				dev_err(dev, "Failed to configure local device settings\n");
+				break;
+			}
+
+			ret = regmap_bulk_write(priv->regmap,
+						P3H2x4x_CONTROLLER_AGENT_BUFF,
+						priv->tp_bus[hub_tp].local_dev_list,
+						priv->tp_bus[hub_tp].local_dev_count);
+			if (ret) {
+				dev_err(dev, "Failed to add local devices\n");
+				break;
+			}
+		}
+	}
+	regmap_write(priv->regmap, P3H2x4x_PAGE_PTR, 0x00);
+	return ret;
+}
+
+static int p3h2x4x_configure_hw(struct device *dev)
+{
+	int ret;
+
+	ret = p3h2x4x_configure_ldo(dev);
+	if (ret)
+		return ret;
+
+	ret = p3h2x4x_configure_io_strength(dev);
+	if (ret)
+		return ret;
+
+	ret = p3h2x4x_configure_pullup(dev);
+	if (ret)
+		return ret;
+
+	ret = p3h2x4x_configure_smbus_local_dev(dev);
+	if (ret)
+		return ret;
+
+	return p3h2x4x_configure_tp(dev);
+}
+
+static void p3h2x4x_of_get_tp_dt_conf(struct device *dev,
+				      const struct device_node *node)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	struct device_node *dev_node;
+	u64 tp_port;
+
+	for_each_available_child_of_node(node, dev_node) {
+		if (!dev_node->name || of_node_cmp(dev_node->name, "target-port"))
+			continue;
+
+		if (of_property_read_reg(dev_node, 0, &tp_port, NULL))
+			continue;
+
+		if (tp_port < P3H2x4x_TP_MAX_COUNT) {
+			priv->tp_bus[tp_port].dt_available = true;
+			priv->tp_bus[tp_port].of_node = dev_node;
+			priv->tp_bus[tp_port].tp_mask = BIT(tp_port);
+			priv->tp_bus[tp_port].priv = priv;
+			priv->tp_bus[tp_port].tp_port = tp_port;
+		}
+	}
+}
+
+/* return true when backend node exist */
+static bool p3h2x4x_is_backend_node_exist(int port, struct p3h2x4x *priv, u32 addr)
+{
+	struct smbus_device *backend = NULL;
+
+	list_for_each_entry(backend,
+			    &priv->tp_bus[port].tp_device_entry, list) {
+		if (backend->addr == addr)
+			return true;
+	}
+	return false;
+}
+
+static int p3h2x4x_read_backend_from_dts(struct device_node *i3c_node_target,
+					 struct p3h2x4x *priv)
+{
+	struct device_node *tp_node;
+	const char *compatible;
+	u64 tp_port, addr_dts;
+	int ret;
+
+	struct smbus_device *backend;
+
+	if (of_property_read_reg(i3c_node_target, 0, &tp_port, NULL))
+		return -EINVAL;
+
+	if (tp_port >= P3H2x4x_TP_MAX_COUNT || tp_port < 0)
+		return -ERANGE;
+
+	INIT_LIST_HEAD(&priv->tp_bus[tp_port].tp_device_entry);
+
+	if (priv->settings.tp[tp_port].mode == P3H2x4x_TP_MODE_I3C)
+		return 0;
+
+	for_each_available_child_of_node(i3c_node_target, tp_node) {
+		ret = of_property_read_reg(tp_node, 0, &addr_dts, NULL);
+		if (ret)
+			return ret;
+
+		if (p3h2x4x_is_backend_node_exist(tp_port, priv, addr_dts))
+			continue;
+
+		ret = of_property_read_string(tp_node, "compatible", &compatible);
+		if (ret)
+			return ret;
+
+		backend = kzalloc(sizeof(*backend), GFP_KERNEL);
+		if (!backend)
+			return -ENOMEM;
+
+		backend->addr = addr_dts;
+		backend->compatible = compatible;
+		backend->tp_device_dt_node = tp_node;
+		backend->client = NULL;
+
+		list_add(&backend->list,
+			 &priv->tp_bus[tp_port].tp_device_entry);
+	}
+
+	return 0;
+}
+
+static void p3h2x4x_parse_dt_tp(struct device *dev,
+				const struct device_node *i3c_node_hub,
+				struct p3h2x4x *priv)
+{
+	struct device_node *i3c_node_target;
+	int ret;
+
+	for_each_available_child_of_node(i3c_node_hub, i3c_node_target) {
+		if (of_node_cmp(i3c_node_target->name, "target-port") == 0) {
+			ret = p3h2x4x_read_backend_from_dts(i3c_node_target, priv);
+			if (ret)
+				dev_err(dev, "DTS entry invalid - error %d", ret);
+		}
+	}
+}
+
+static int p3h2x4x_get_tp_local_device_dt_setting(struct device *dev,
+						  const struct device_node *node, u32 id)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	int ret;
+
+	ret = of_property_read_variable_u8_array(node, "local_dev", priv->tp_bus[id].local_dev_list,
+						 sizeof(u8), P3H2x4x_TP_LOCAL_DEV);
+	if (ret > 0 && ret <= P3H2x4x_TP_LOCAL_DEV)
+		priv->tp_bus[id].local_dev_count = ret;
+	else if (ret == -EOVERFLOW)
+		dev_warn(dev,
+			 "local Devices list is out of range or invalid\n");
+
+	return ret;
+}
+
+static void p3h2x4x_get_tp_of_get_setting(struct device *dev,
+					  const struct device_node *node,
+					  struct tp_setting tp_setting[])
+{
+	struct device_node *tp_node;
+	u64 id;
+
+	for_each_available_child_of_node(node, tp_node) {
+		if (!tp_node->name || of_node_cmp(tp_node->name, "target-port"))
+			continue;
+
+		if (of_property_read_reg(tp_node, 0, &id, NULL))
+			continue;
+
+		if (id >= P3H2x4x_TP_MAX_COUNT) {
+			dev_warn(dev, "Invalid target port index found in DT: %lli\n", id);
+			continue;
+		}
+		p3h2x4x_of_get_dt_setting(dev, tp_node, "mode", tp_mode_settings,
+					  ARRAY_SIZE(tp_mode_settings),
+					  &tp_setting[id].mode);
+
+		tp_setting[id].pullup_en =
+					of_property_read_bool(tp_node, "pullup-enable");
+		tp_setting[id].ibi_en =
+					of_property_read_bool(tp_node, "ibi-enable");
+		tp_setting[id].always_enable =
+					of_property_read_bool(tp_node, "always-enable");
+
+		p3h2x4x_get_tp_local_device_dt_setting(dev, tp_node, id);
+	}
+}
+
+static void p3h2x4x_of_get_p3h2x4x_conf(struct device *dev,
+					const struct device_node *node)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+
+	priv->settings.cp0_ldo_en =
+				of_property_read_bool(node, "cp0-ldo-enable");
+	priv->settings.cp1_ldo_en =
+				of_property_read_bool(node, "cp1-ldo-enable");
+	priv->settings.tp0145_ldo_en =
+				of_property_read_bool(node, "tp0145-ldo-enable");
+	priv->settings.tp2367_ldo_en =
+				of_property_read_bool(node, "tp2367-ldo-enable");
+
+	of_property_read_u32(node, "cp0-ldo-microvolt", &priv->settings.cp0_ldo_volt);
+	of_property_read_u32(node, "cp1-ldo-microvolt", &priv->settings.cp1_ldo_volt);
+	of_property_read_u32(node, "tp0145-ldo-microvolt", &priv->settings.tp0145_ldo_volt);
+	of_property_read_u32(node, "tp2367-ldo-microvolt", &priv->settings.tp2367_ldo_volt);
+	of_property_read_u32(node, "tp0145-pullup-ohm", &priv->settings.tp0145_pullup);
+	of_property_read_u32(node, "tp2367-pullup-ohm", &priv->settings.tp2367_pullup);
+	of_property_read_u32(node, "cp0-io-strength-ohm", &priv->settings.cp0_io_strength);
+	of_property_read_u32(node, "cp1-io-strength-ohm", &priv->settings.cp1_io_strength);
+	of_property_read_u32(node, "tp0145-io-strength-ohm", &priv->settings.tp0145_io_strength);
+	of_property_read_u32(node, "tp2367-io-strength-ohm", &priv->settings.tp2367_io_strength);
+
+	p3h2x4x_get_tp_of_get_setting(dev, node, priv->settings.tp);
+}
+
+static void p3h2x4x_of_default_configuration(struct device *dev)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	int tp_count;
+
+	priv->settings.cp0_ldo_volt = P3H2x4x_DT_LDO_VOLT_NOT_SET;
+	priv->settings.cp1_ldo_volt = P3H2x4x_DT_LDO_VOLT_NOT_SET;
+	priv->settings.tp0145_ldo_volt = P3H2x4x_DT_LDO_VOLT_NOT_SET;
+	priv->settings.tp2367_ldo_volt = P3H2x4x_DT_LDO_VOLT_NOT_SET;
+	priv->settings.tp0145_pullup = P3H2x4x_TP_PULLUP_NOT_SET;
+	priv->settings.tp2367_pullup = P3H2x4x_TP_PULLUP_NOT_SET;
+	priv->settings.cp0_io_strength = P3H2x4x_IO_STRENGTH_NOT_SET;
+	priv->settings.cp1_io_strength = P3H2x4x_IO_STRENGTH_NOT_SET;
+	priv->settings.tp0145_io_strength = P3H2x4x_IO_STRENGTH_NOT_SET;
+	priv->settings.tp2367_io_strength = P3H2x4x_IO_STRENGTH_NOT_SET;
+
+	for (tp_count = 0; tp_count < P3H2x4x_TP_MAX_COUNT; ++tp_count)
+		priv->settings.tp[tp_count].mode =  P3H2x4x_TP_MODE_NOT_SET;
+}
+
+static int p3h2x4x_device_probe_i3c(struct i3c_device *i3cdev)
+{
+	struct device_node *node __free(device_node) = NULL;
+	struct device *dev = &i3cdev->dev;
+	struct regmap *regmap;
+	struct p3h2x4x *priv;
+	int ret, i;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->i3cdev = i3cdev;
+	priv->driving_master = i3c_dev_get_master(i3cdev->desc);
+	i3cdev_set_drvdata(i3cdev, priv);
+	p3h2x4x_of_default_configuration(dev);
+	regmap = devm_regmap_init_i3c(i3cdev, &p3h2x4x_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		return dev_err_probe(dev, ret, "Failed to register I3C HUB regmap\n");
+	}
+	priv->regmap = regmap;
+	priv->is_p3h2x4x_in_i3c = true;
+
+	mutex_init(&priv->etx_mutex);
+
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++)
+		mutex_init(&priv->tp_bus[i].port_mutex);
+
+	/* get hub node from DT */
+	node = of_get_child_by_name(dev->parent->of_node, "hub");
+	if (!node) {
+		dev_dbg(dev, "No DT entry - running with hardware defaults.\n");
+	} else {
+		p3h2x4x_of_get_p3h2x4x_conf(dev, node);
+		p3h2x4x_of_get_tp_dt_conf(dev, node);
+		/* Parse DTS to find backend device on the SMBus target mode */
+		p3h2x4x_parse_dt_tp(dev, node, priv);
+	}
+
+	/* Unlock access to protected registers */
+	ret = regmap_write(priv->regmap, P3H2x4x_DEV_REG_PROTECTION_CODE,
+			   P3H2x4x_REGISTERS_UNLOCK_CODE);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to unlock HUB's protected registers\n");
+
+	ret = p3h2x4x_configure_hw(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to configure the HUB\n");
+
+	/* Register logic for native SMBus ports */
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++) {
+		if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_SMBUS)
+			ret = p3h2x4x_tp_smbus_algo(priv, i);
+	}
+
+	/* Register logic for native vertual I3C ports */
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++) {
+		if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_I3C &&
+		    !priv->settings.tp[i].always_enable)
+			ret = p3h2x4x_tp_i3c_algo(priv, i);
+	}
+
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; ++i) {
+		if (priv->tp_bus[i].dt_available) {
+			if (priv->settings.tp[i].always_enable)
+				priv->tp_always_enable_mask =
+						(priv->tp_always_enable_mask |  BIT(i));
+
+			if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_I3C)
+				priv->tp_i3c_bus_mask = (priv->tp_i3c_bus_mask |  BIT(i));
+		}
+	}
+
+	ret = regmap_write(priv->regmap, P3H2x4x_TP_NET_CON_CONF, priv->tp_always_enable_mask);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to open Target Port(s)\n");
+
+	ret = i3c_master_do_daa(priv->driving_master);
+	if (ret)
+		dev_warn(dev, "Failed to run DAA\n");
+
+	/*
+	 * holding SDA low when both SMBus Target Agent received data buffers are full.
+	 * This feature can be used as a flow-control mechanism for MCTP applications to
+	 * avoid MCTP transmitters on Target Ports time out when the SMBus agent buffers
+	 * are not serviced in time by upstream controller and only receives write message
+	 * from its downstream ports.
+	 */
+	ret = regmap_update_bits(priv->regmap, P3H2x4x_ONCHIP_TD_AND_SMBUS_AGNT_CONF,
+				 P3H2x4x_TARGET_AGENT_DFT_IBI_CONF_MASK,
+				 P3H2x4x_TARGET_AGENT_DFT_IBI_CONF);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to P3H2x4x_ONCHIP_TD_AND_SMBUS_AGNT_CONF\n");
+
+	ret = i3c_device_request_ibi(i3cdev, &p3h2x4x_ibireq);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to request IBI\n");
+
+	ret = i3c_device_enable_ibi(i3cdev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to Enable IBI\n");
+
+	ret = p3h2x4x_tp_add_downstream_device(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add backend device\n");
+
+	/* Lock access to protected registers */
+	ret = regmap_write(priv->regmap, P3H2x4x_DEV_REG_PROTECTION_CODE,
+			   P3H2x4x_REGISTERS_LOCK_CODE);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to lock HUB's protected registers\n");
+
+	return 0;
+}
+
+static void p3h2x4x_device_remove_i3c(struct i3c_device *i3cdev)
+{
+	struct p3h2x4x *priv = i3cdev_get_drvdata(i3cdev);
+	struct i3c_master_controller *tp_controller;
+	struct smbus_device *backend = NULL;
+	struct i2c_adapter *tp_adap;
+	int i;
+
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++) {
+		tp_adap = &priv->tp_bus[i].smbus_port_adapter;
+		tp_controller = &priv->tp_bus[i].i3c_port_controller;
+
+		if (priv->tp_bus[i].is_registered) {
+			if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_SMBUS) {
+				list_for_each_entry(backend,
+						    &priv->tp_bus[i].tp_device_entry,
+						    list) {
+					i2c_unregister_device(backend->client);
+					kfree(backend);
+				}
+				i2c_del_adapter(tp_adap);
+			} else if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_I3C) {
+				i3c_master_unregister(tp_controller);
+			}
+		}
+	}
+
+	i3c_device_disable_ibi(i3cdev);
+	i3c_device_free_ibi(i3cdev);
+
+	mutex_destroy(&priv->etx_mutex);
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++)
+		mutex_destroy(&priv->tp_bus[i].port_mutex);
+}
+
+static int p3h2x4x_device_probe_i2c(struct i2c_client *client)
+{
+	struct device_node *node __free(device_node) = NULL;
+	struct device *dev = &client->dev;
+	struct regmap *regmap;
+	struct p3h2x4x *priv;
+	int ret, i;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->i2cdev = client;
+	i2c_set_clientdata(client, priv);
+
+	p3h2x4x_of_default_configuration(dev);
+
+	regmap = devm_regmap_init_i2c(client, &p3h2x4x_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		return dev_err_probe(dev, ret, "Failed to register I3C HUB regmap\n");
+	}
+	priv->regmap = regmap;
+	priv->is_p3h2x4x_in_i3c = false;
+
+	mutex_init(&priv->etx_mutex);
+
+	/* Register logic for native SMBus ports */
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++)
+		mutex_init(&priv->tp_bus[i].port_mutex);
+
+	/* get hub node from DT */
+	node = of_get_child_by_name(dev->parent->of_node, "hub");
+	if (!node) {
+		dev_dbg(dev, "No DT entry - running with hardware defaults.\n");
+	} else {
+		p3h2x4x_of_get_p3h2x4x_conf(dev, node);
+		p3h2x4x_of_get_tp_dt_conf(dev, node);
+		/* Parse DTS to find backend device on the SMBus target mode */
+		p3h2x4x_parse_dt_tp(dev, node, priv);
+	}
+
+	/* Unlock access to protected registers */
+	ret = regmap_write(priv->regmap, P3H2x4x_DEV_REG_PROTECTION_CODE,
+			   P3H2x4x_REGISTERS_UNLOCK_CODE);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to unlock HUB's protected registers\n");
+
+	ret = p3h2x4x_configure_hw(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to configure the HUB\n");
+
+	/* Register logic for native SMBus ports */
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++) {
+		if (priv->settings.tp[i].mode == P3H2x4x_TP_MODE_SMBUS)
+			ret = p3h2x4x_tp_smbus_algo(priv, i);
+	}
+
+	ret = p3h2x4x_tp_add_downstream_device(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add backend device\n");
+
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; ++i) {
+		if (priv->tp_bus[i].dt_available) {
+			if (priv->settings.tp[i].always_enable)
+				priv->tp_always_enable_mask =
+							(priv->tp_always_enable_mask |  BIT(i));
+		}
+	}
+
+	ret = regmap_write(priv->regmap, P3H2x4x_TP_NET_CON_CONF, priv->tp_always_enable_mask);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to open Target Port(s)\n");
+
+	/* Lock access to protected registers */
+	ret = regmap_write(priv->regmap, P3H2x4x_DEV_REG_PROTECTION_CODE,
+			   P3H2x4x_REGISTERS_LOCK_CODE);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to lock HUB's protected registers\n");
+
+	return 0;
+}
+
+static void p3h2x4x_device_remove_i2c(struct i2c_client *client)
+{
+	struct p3h2x4x *priv = i2c_get_clientdata(client);
+	struct smbus_device *backend = NULL;
+	struct i2c_adapter *tp_adap;
+	int i;
+
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++) {
+		tp_adap = &priv->tp_bus[i].smbus_port_adapter;
+		if (priv->tp_bus[i].is_registered) {
+			list_for_each_entry(backend, &priv->tp_bus[i].tp_device_entry, list) {
+				i2c_unregister_device(backend->client);
+				kfree(backend);
+			}
+			i2c_del_adapter(tp_adap);
+		}
+	}
+
+	mutex_destroy(&priv->etx_mutex);
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++)
+		mutex_destroy(&priv->tp_bus[i].port_mutex);
+}
+
+/* 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,p3h2x4x",
+	},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, p3h2x4x_i2c_of_match);
+static struct i3c_driver p3h2x4x_i3c = {
+	.driver = {
+		.name = "p3h2x4x_i3c_drv",
+	},
+	.id_table = p3h2x4x_i3c_ids,
+	.probe = p3h2x4x_device_probe_i3c,
+	.remove = p3h2x4x_device_remove_i3c,
+};
+
+static struct i2c_driver p3h2x4x_i2c = {
+	.driver = {
+		.name = "p3h2x4x_i2c_drv",
+		.of_match_table = p3h2x4x_i2c_of_match,
+	},
+	.probe =  p3h2x4x_device_probe_i2c,
+	.remove = p3h2x4x_device_remove_i2c,
+	.id_table = p3h2x4x_i2c_id_table,
+};
+
+module_i3c_i2c_driver(p3h2x4x_i3c, &p3h2x4x_i2c);
+
+MODULE_AUTHOR("Aman Kumar Pandey <aman.kumarpandey at nxp.com>");
+MODULE_AUTHOR("vikash Bansal <vikash.bansal at nxp.com>");
+MODULE_DESCRIPTION("P3H2x4x I3C HUB driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i3c/hub/p3h2840_i3c_hub_i3c.c b/drivers/i3c/hub/p3h2840_i3c_hub_i3c.c
new file mode 100644
index 000000000000..b455efbf71a7
--- /dev/null
+++ b/drivers/i3c/hub/p3h2840_i3c_hub_i3c.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ * This P3H2x4x driver file contain functions for I3C virtual Bus creation, connect/disconnect
+ * hub network and read/write.
+ */
+#include "p3h2840_i3c_hub.h"
+
+static void p3h2x4x_en_p3h2x4x_ntwk_tp(struct tp_bus *bus)
+{
+	struct p3h2x4x *priv = bus->priv;
+	struct device *dev = i3cdev_to_dev(priv->i3cdev);
+	int ret;
+
+	if (priv->settings.tp[bus->tp_port].always_enable)
+		return;
+
+	ret = regmap_write(priv->regmap, P3H2x4x_TP_NET_CON_CONF,
+			   (bus->tp_mask | priv->tp_always_enable_mask));
+	if (ret)
+		dev_warn(dev, "Failed to open Target Port(s)\n");
+}
+
+static void p3h2x4x_dis_p3h2x4x_ntwk_tp(struct tp_bus *bus)
+{
+	struct p3h2x4x *priv = bus->priv;
+	struct device *dev = i3cdev_to_dev(priv->i3cdev);
+	int ret;
+
+	if (priv->settings.tp[bus->tp_port].always_enable)
+		return;
+
+	ret = regmap_write(priv->regmap, P3H2x4x_TP_NET_CON_CONF, priv->tp_always_enable_mask);
+	if (ret)
+		dev_warn(dev, "Failed to close Target Port(s)\n");
+}
+
+static struct tp_bus *p3h2x4x_bus_from_i3c_desc(struct i3c_dev_desc *desc)
+{
+	struct i3c_master_controller *controller = i3c_dev_get_master(desc);
+
+	return container_of(controller, struct tp_bus, i3c_port_controller);
+}
+
+static struct tp_bus *p3h2x4x_bus_from_i2c_desc(struct i2c_dev_desc *desc)
+{
+	struct i3c_master_controller *controller = i2c_dev_get_master(desc);
+
+	return container_of(controller, struct tp_bus, i3c_port_controller);
+}
+
+static struct i3c_master_controller
+*get_parent_controller(struct i3c_master_controller *controller)
+{
+	struct tp_bus *bus = container_of(controller, struct tp_bus, i3c_port_controller);
+
+	return bus->priv->driving_master;
+}
+
+static struct i3c_master_controller
+*get_parent_controller_from_i3c_desc(struct i3c_dev_desc *desc)
+{
+	struct i3c_master_controller *controller = i3c_dev_get_master(desc);
+	struct tp_bus *bus = container_of(controller, struct tp_bus, i3c_port_controller);
+
+	return bus->priv->driving_master;
+}
+
+static struct i3c_master_controller
+*get_parent_controller_from_i2c_desc(struct i2c_dev_desc *desc)
+{
+	struct i3c_master_controller *controller = desc->common.master;
+	struct tp_bus *bus = container_of(controller, struct tp_bus, i3c_port_controller);
+
+	return bus->priv->driving_master;
+}
+
+static struct i3c_master_controller
+*update_i3c_i2c_desc_parent(struct i3c_i2c_dev_desc *desc,
+				struct i3c_master_controller *parent)
+{
+	struct i3c_master_controller *orig_parent = desc->master;
+
+	desc->master = parent;
+
+	return orig_parent;
+}
+
+static void restore_i3c_i2c_desc_parent(struct i3c_i2c_dev_desc *desc,
+					struct i3c_master_controller *parent)
+{
+	desc->master = parent;
+}
+
+static int p3h2x4x_i3c_bus_init(struct i3c_master_controller *controller)
+{
+	struct tp_bus *bus = container_of(controller, struct tp_bus, i3c_port_controller);
+
+	controller->this = bus->priv->i3cdev->desc;
+	return 0;
+}
+
+static void p3h2x4x_i3c_bus_cleanup(struct i3c_master_controller *controller)
+{
+	controller->this = NULL;
+}
+
+static int p3h2x4x_attach_i3c_dev(struct i3c_dev_desc *dev)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+	int ret;
+
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	ret = parent->ops->attach_i3c_dev(dev);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	return ret;
+}
+
+static int p3h2x4x_reattach_i3c_dev(struct i3c_dev_desc *dev, u8 old_dyn_addr)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+	int ret;
+
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	ret = parent->ops->reattach_i3c_dev(dev, old_dyn_addr);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	return ret;
+}
+
+static void p3h2x4x_detach_i3c_dev(struct i3c_dev_desc *dev)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	parent->ops->detach_i3c_dev(dev);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+}
+
+static int p3h2x4x_do_daa(struct i3c_master_controller *controller)
+{
+	struct tp_bus *bus = container_of(controller, struct tp_bus, i3c_port_controller);
+	struct i3c_master_controller *parent = get_parent_controller(controller);
+
+	int ret;
+
+	p3h2x4x_en_p3h2x4x_ntwk_tp(bus);
+	down_write(&parent->bus.lock);
+	ret = parent->ops->do_daa(parent);
+	up_write(&parent->bus.lock);
+	p3h2x4x_dis_p3h2x4x_ntwk_tp(bus);
+
+	return ret;
+}
+
+static bool p3h2x4x_supports_ccc_cmd(struct i3c_master_controller *controller,
+				     const struct i3c_ccc_cmd *cmd)
+{
+	struct i3c_master_controller *parent = get_parent_controller(controller);
+
+	return parent->ops->supports_ccc_cmd(parent, cmd);
+}
+
+static int p3h2x4x_send_ccc_cmd(struct i3c_master_controller *controller,
+				struct i3c_ccc_cmd *cmd)
+{
+	struct tp_bus *bus = container_of(controller, struct tp_bus, i3c_port_controller);
+	struct i3c_master_controller *parent = get_parent_controller(controller);
+	int ret;
+
+	if (cmd->id == I3C_CCC_RSTDAA(true))
+		return 0;
+
+	p3h2x4x_en_p3h2x4x_ntwk_tp(bus);
+	ret = parent->ops->send_ccc_cmd(parent, cmd);
+	p3h2x4x_dis_p3h2x4x_ntwk_tp(bus);
+
+	return ret;
+}
+
+static int p3h2x4x_priv_xfers(struct i3c_dev_desc *dev,
+			      struct i3c_priv_xfer *xfers, int nxfers)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct tp_bus *bus = p3h2x4x_bus_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+	int res;
+
+	p3h2x4x_en_p3h2x4x_ntwk_tp(bus);
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	res = parent->ops->priv_xfers(dev, xfers, nxfers);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	p3h2x4x_dis_p3h2x4x_ntwk_tp(bus);
+
+	return res;
+}
+
+static int p3h2x4x_attach_i2c_dev(struct i2c_dev_desc *dev)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i2c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+	int ret;
+
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	ret = parent->ops->attach_i2c_dev(dev);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	return ret;
+}
+
+static void p3h2x4x_detach_i2c_dev(struct i2c_dev_desc *dev)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i2c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	parent->ops->detach_i2c_dev(dev);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+}
+
+static int p3h2x4x_i2c_xfers(struct i2c_dev_desc *dev,
+			     const struct i2c_msg *xfers, int nxfers)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i2c_desc(dev);
+	struct tp_bus *bus = p3h2x4x_bus_from_i2c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+	int ret;
+
+	p3h2x4x_en_p3h2x4x_ntwk_tp(bus);
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	ret = parent->ops->i2c_xfers(dev, xfers, nxfers);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	p3h2x4x_dis_p3h2x4x_ntwk_tp(bus);
+	return ret;
+}
+
+static int p3h2x4x_request_ibi(struct i3c_dev_desc *dev,
+			       const struct i3c_ibi_setup *req)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct tp_bus *bus = p3h2x4x_bus_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+	int ret;
+
+	p3h2x4x_en_p3h2x4x_ntwk_tp(bus);
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	ret = parent->ops->request_ibi(dev, req);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	p3h2x4x_dis_p3h2x4x_ntwk_tp(bus);
+	return ret;
+}
+
+static void p3h2x4x_free_ibi(struct i3c_dev_desc *dev)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct tp_bus *bus = p3h2x4x_bus_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+
+	p3h2x4x_en_p3h2x4x_ntwk_tp(bus);
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	parent->ops->free_ibi(dev);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	p3h2x4x_dis_p3h2x4x_ntwk_tp(bus);
+}
+
+static int p3h2x4x_enable_ibi(struct i3c_dev_desc *dev)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct tp_bus *bus = p3h2x4x_bus_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+	int ret;
+
+	p3h2x4x_en_p3h2x4x_ntwk_tp(bus);
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	ret = parent->ops->enable_ibi(dev);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	p3h2x4x_dis_p3h2x4x_ntwk_tp(bus);
+	return ret;
+}
+
+static int p3h2x4x_disable_ibi(struct i3c_dev_desc *dev)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct tp_bus *bus = p3h2x4x_bus_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+	int ret;
+
+	p3h2x4x_en_p3h2x4x_ntwk_tp(bus);
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	ret = parent->ops->disable_ibi(dev);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+	p3h2x4x_dis_p3h2x4x_ntwk_tp(bus);
+	return ret;
+}
+
+static void p3h2x4x_recycle_ibi_slot(struct i3c_dev_desc *dev,
+				     struct i3c_ibi_slot *slot)
+{
+	struct i3c_master_controller *parent = get_parent_controller_from_i3c_desc(dev);
+	struct i3c_master_controller *orig_parent;
+
+	orig_parent = update_i3c_i2c_desc_parent(&dev->common, parent);
+	parent->ops->recycle_ibi_slot(dev, slot);
+	restore_i3c_i2c_desc_parent(&dev->common, orig_parent);
+}
+
+static const struct i3c_master_controller_ops p3h2x4x_i3c_ops = {
+	.bus_init = p3h2x4x_i3c_bus_init,
+	.bus_cleanup = p3h2x4x_i3c_bus_cleanup,
+	.attach_i3c_dev = p3h2x4x_attach_i3c_dev,
+	.reattach_i3c_dev = p3h2x4x_reattach_i3c_dev,
+	.detach_i3c_dev = p3h2x4x_detach_i3c_dev,
+	.do_daa = p3h2x4x_do_daa,
+	.supports_ccc_cmd = p3h2x4x_supports_ccc_cmd,
+	.send_ccc_cmd = p3h2x4x_send_ccc_cmd,
+	.priv_xfers = p3h2x4x_priv_xfers,
+	.attach_i2c_dev = p3h2x4x_attach_i2c_dev,
+	.detach_i2c_dev = p3h2x4x_detach_i2c_dev,
+	.i2c_xfers = p3h2x4x_i2c_xfers,
+	.request_ibi = p3h2x4x_request_ibi,
+	.free_ibi = p3h2x4x_free_ibi,
+	.enable_ibi = p3h2x4x_enable_ibi,
+	.disable_ibi = p3h2x4x_disable_ibi,
+	.recycle_ibi_slot = p3h2x4x_recycle_ibi_slot,
+};
+
+/**
+ * p3h2x4x_tp_i3c_algo - register i3c master for target port who
+ * configured as i3c.
+ * @priv: p3h2x4x device structure.
+ * @tp: target port.
+ *
+ * Return: 0 in case of success, a negative EINVAL code if the error.
+ */
+int p3h2x4x_tp_i3c_algo(struct p3h2x4x *priv, int tp)
+{
+	struct device *dev = i3cdev_to_dev(priv->i3cdev);
+	int ret;
+
+	priv->tp_bus[tp].tp_mask =  BIT(tp);
+	dev->of_node = priv->tp_bus[tp].of_node;
+
+	ret = i3c_master_register(&priv->tp_bus[tp].i3c_port_controller,
+				  dev, &p3h2x4x_i3c_ops, false);
+	if (ret) {
+		dev_warn(dev, "Failed to register i3c controller for tp %d\n", tp);
+		return -EINVAL;
+	}
+
+	priv->tp_bus[tp].is_registered = true;
+	return 0;
+}
diff --git a/drivers/i3c/hub/p3h2840_i3c_hub_smbus.c b/drivers/i3c/hub/p3h2840_i3c_hub_smbus.c
new file mode 100644
index 000000000000..079c3b3c6dfa
--- /dev/null
+++ b/drivers/i3c/hub/p3h2840_i3c_hub_smbus.c
@@ -0,0 +1,725 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ * This P3H2x4x driver file contain functions for SMBus/I2C virtual Bus creation and read/write.
+ */
+#include "p3h2840_i3c_hub.h"
+
+static struct device *i2cdev_to_dev(struct i2c_client *i2cdev)
+{
+	return &i2cdev->dev;
+}
+
+static void p3h2x4x_read_smbus_agent_rx_buf(struct i3c_device *i3cdev, enum p3h2x4x_rcv_buf rfbuf,
+					    enum p3h2x4x_tp tp, bool is_of)
+{
+	struct device *dev = i3cdev_to_dev(i3cdev);
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	struct smbus_device *backend = NULL;
+
+	u8 target_buffer_page, flag_clear = 0x0f, rx_data, temp, i;
+	u8 slave_rx_buffer[P3H2x4x_SMBUS_TARGET_PAYLOAD_SIZE] = { 0 };
+	u32 packet_len, slave_address, ret;
+
+	target_buffer_page = (((rfbuf) ? P3H2x4x_TARGET_BUFF_1_PAGE : P3H2x4x_TARGET_BUFF_0_PAGE)
+							+  (P3H2x4x_NO_PAGE_PER_TP * tp));
+	ret = regmap_write(priv->regmap, P3H2x4x_PAGE_PTR, target_buffer_page);
+	if (ret)
+		goto ibi_err;
+
+	/* read buffer length */
+	ret = regmap_read(priv->regmap, P3H2x4x_TARGET_BUFF_LENGTH, &packet_len);
+	if (ret)
+		goto ibi_err;
+
+	if (packet_len)
+		packet_len = packet_len - 1;
+
+	if (packet_len > P3H2x4x_SMBUS_TARGET_PAYLOAD_SIZE) {
+		dev_err(dev, "Received message too big for p3h2x4x buffer\n");
+		return;
+	}
+
+	/* read slave  address */
+	ret = regmap_read(priv->regmap, P3H2x4x_TARGET_BUFF_ADDRESS, &slave_address);
+	if (ret)
+		goto ibi_err;
+
+	/* read data */
+	if (packet_len) {
+		ret = regmap_bulk_read(priv->regmap, P3H2x4x_TARGET_BUFF_DATA,
+				       slave_rx_buffer, packet_len);
+		if (ret)
+			goto ibi_err;
+	}
+
+	if (is_of)
+		flag_clear = BUF_RECEIVED_FLAG_TF_MASK;
+	else
+		flag_clear = (((rfbuf == RCV_BUF_0) ? P3H2x4x_TARGET_BUF_0_RECEIVE :
+					P3H2x4x_TARGET_BUF_1_RECEIVE));
+
+	/* notify slave driver about received data */
+	list_for_each_entry(backend, &priv->tp_bus[tp].tp_device_entry, list) {
+		if (slave_address >> 1 == backend->addr && priv->is_slave_reg) {
+			i2c_slave_event(backend->client, I2C_SLAVE_WRITE_REQUESTED,
+					(u8 *)&slave_address);
+
+			for (i = 0; i < packet_len; i++) {
+				rx_data = slave_rx_buffer[i];
+				i2c_slave_event(backend->client, I2C_SLAVE_WRITE_RECEIVED,
+						&rx_data);
+			}
+			i2c_slave_event(backend->client, I2C_SLAVE_STOP, &temp);
+			break;
+		}
+	}
+
+ibi_err:
+	regmap_write(priv->regmap, P3H2x4x_PAGE_PTR, 0x00);
+	regmap_write(priv->regmap, P3H2x4x_TP0_SMBUS_AGNT_STS + tp, flag_clear);
+}
+
+/**
+ * p3h2x4x_ibi_handler - IBI handler.
+ * @i3cdev: i3c device.
+ * @payload: two byte IBI payload data.
+ *
+ */
+void p3h2x4x_ibi_handler(struct i3c_device *i3cdev,
+			 const struct i3c_ibi_payload *payload)
+{
+	struct device *dev = i3cdev_to_dev(i3cdev);
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+
+	u32 target_port_status, payload_byte_one, payload_byte_two;
+	u8 i;
+	int  ret;
+
+	payload_byte_one = (*(int *)payload->data);
+	payload_byte_two = (*(int *)(payload->data + 4));
+
+	if (!(payload_byte_one & P3H2x4x_SMBUS_AGENT_EVENT_FLAG_STATUS))
+		goto err;
+
+	mutex_lock(&priv->etx_mutex);
+	ret = regmap_write(priv->regmap, P3H2x4x_TP_SMBUS_AGNT_IBI_CONFIG, P3H2x4x_ALL_TP_IBI_DIS);
+	if (ret) {
+		dev_err(dev, "Failed to Disable IBI\n");
+		goto err;
+	}
+
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; ++i) {
+		if (priv->tp_bus[i].is_registered && (payload_byte_two >> i) & 0x01) {
+			ret = regmap_read(priv->regmap, P3H2x4x_TP0_SMBUS_AGNT_STS + i,
+					  &target_port_status);
+			if (ret) {
+				dev_err(dev, "target port read status failed %d\n", ret);
+				goto err;
+			}
+
+			/* process data receive buffer */
+			switch (target_port_status & BUF_RECEIVED_FLAG_MASK) {
+			case P3H2x4x_TARGET_BUF_CA_TF:
+				break;
+			case P3H2x4x_TARGET_BUF_0_RECEIVE:
+				p3h2x4x_read_smbus_agent_rx_buf(i3cdev, RCV_BUF_0, i, false);
+				break;
+			case P3H2x4x_TARGET_BUF_1_RECEIVE:
+				p3h2x4x_read_smbus_agent_rx_buf(i3cdev, RCV_BUF_1, i, false);
+				break;
+			case P3H2x4x_TARGET_BUF_0_1_RECEIVE:
+				p3h2x4x_read_smbus_agent_rx_buf(i3cdev, RCV_BUF_0, i, false);
+				p3h2x4x_read_smbus_agent_rx_buf(i3cdev, RCV_BUF_1, i, false);
+				break;
+			case P3H2x4x_TARGET_BUF_OVRFL:
+				p3h2x4x_read_smbus_agent_rx_buf(i3cdev, RCV_BUF_0, i, false);
+				p3h2x4x_read_smbus_agent_rx_buf(i3cdev, RCV_BUF_1, i, true);
+				dev_err(dev, "Overflow, reading buffer zero and one\n");
+				break;
+			default:
+				regmap_write(priv->regmap, P3H2x4x_TP0_SMBUS_AGNT_STS + i,
+					     BUF_RECEIVED_FLAG_TF_MASK);
+				break;
+			}
+		}
+	}
+err:
+	regmap_write(priv->regmap, P3H2x4x_TP_SMBUS_AGNT_IBI_CONFIG, priv->tp_ibi_mask);
+	mutex_unlock(&priv->etx_mutex);
+}
+
+static int p3h2x4x_read_p3h2x4x_id(struct device *dev)
+{
+	struct p3h2x4x *priv = dev_get_drvdata(dev);
+	u32 reg_val;
+	int ret;
+
+	ret = regmap_read(priv->regmap, P3H2x4x_LDO_AND_CPSEL_STS, &reg_val);
+	if (ret) {
+		dev_err(dev, "Failed to read status register\n");
+		return ret;
+	}
+	if (P3H2x4x_CP_SEL_PIN_INPUT_CODE_GET(reg_val) == 3)
+		return 1;
+	else
+		return 0;
+}
+
+static void unlock_port_ext_mutex(struct mutex *ext, struct mutex *port)
+{
+	mutex_unlock(ext);
+	mutex_unlock(port);
+}
+
+static void lock_port_ext_mutex(struct mutex *ext, struct mutex *port)
+{
+	mutex_lock(ext);
+	mutex_lock(port);
+}
+
+static int p3h2x4x_read_smbus_transaction_status(struct p3h2x4x *priv,
+						 u8 target_port_status,
+						 u8 *status, u8 data_length)
+{
+	unsigned int status_read;
+	int ret;
+
+	mutex_unlock(&priv->etx_mutex);
+	fsleep(P3H2x4x_SMBUS_400kHz_TRANSFER_TIMEOUT(data_length));
+	mutex_lock(&priv->etx_mutex);
+
+	ret = regmap_read(priv->regmap, target_port_status, &status_read);
+	if (ret)
+		return ret;
+
+	*status = (u8)status_read;
+
+	if ((*status & P3H2x4x_TP_BUFFER_STATUS_MASK) == P3H2x4x_XFER_SUCCESS)
+		return 0;
+
+	dev_err(&priv->i3cdev->dev, "Status read timeout reached\n");
+	return 0;
+}
+
+/*
+ * p3h2x4x_tp_i2c_xfer_msg() - This starts a SMBus write transaction by writing a descriptor
+ * and a message to the p3h2x4x registers. Controller buffer page is determined by multiplying the
+ * target port index by four and adding the base page number to it.
+ */
+static int p3h2x4x_tp_i2c_xfer_msg(struct p3h2x4x *priv,
+				   struct i2c_msg *xfers,
+				   u8 target_port,
+				   u8 nxfers_i, u8 rw, u8 *return_status)
+{
+	u8 controller_buffer_page = P3H2x4x_CONTROLLER_BUFFER_PAGE + 4 * target_port;
+	u8 target_port_status = P3H2x4x_TP0_SMBUS_AGNT_STS + target_port;
+	u8 desc[P3H2x4x_SMBUS_DESCRIPTOR_SIZE] = { 0 };
+	u8 transaction_type = P3H2x4x_SMBUS_400kHz;
+	u8 target_port_code = BIT(target_port);
+	int write_length = xfers[nxfers_i].len;
+	int read_length = xfers[nxfers_i].len;
+	u8 addr = xfers[nxfers_i].addr;
+	u8 rw_address = 2 * addr;
+	u8 status;
+	int ret;
+
+	if (rw) {
+		rw_address |= BIT(0);
+		write_length = 0;
+	} else {
+		read_length = 0;
+	}
+
+	desc[0] = rw_address;
+	desc[1] = transaction_type;
+	desc[2] = write_length;
+	desc[3] = read_length;
+
+	ret = regmap_write(priv->regmap, target_port_status,
+			   P3H2x4x_TP_BUFFER_STATUS_MASK);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(priv->regmap, P3H2x4x_PAGE_PTR, controller_buffer_page);
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_write(priv->regmap, P3H2x4x_CONTROLLER_AGENT_BUFF,
+				desc, P3H2x4x_SMBUS_DESCRIPTOR_SIZE);
+	if (ret)
+		return ret;
+
+	if (!rw) {
+		ret = regmap_bulk_write(priv->regmap,
+					P3H2x4x_CONTROLLER_AGENT_BUFF_DATA,
+					xfers[nxfers_i].buf, xfers[nxfers_i].len);
+		if (ret)
+			return ret;
+	}
+
+	ret = regmap_write(priv->regmap, P3H2x4x_TP_SMBUS_AGNT_TRANS_START,
+			   target_port_code);
+	if (ret)
+		return ret;
+
+	ret = p3h2x4x_read_smbus_transaction_status(priv, target_port_status,
+						    &status,
+						    (write_length + read_length));
+	if (ret)
+		return ret;
+
+	*return_status = status;
+
+	if (rw) {
+		ret = regmap_bulk_read(priv->regmap,
+				       P3H2x4x_CONTROLLER_AGENT_BUFF_DATA,
+				       xfers[nxfers_i].buf, xfers[nxfers_i].len);
+		if (ret)
+			return ret;
+	}
+
+	ret = regmap_write(priv->regmap, P3H2x4x_PAGE_PTR, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * This function will be called whenever you call I2C read, write APIs like
+ * i2c_master_send(), i2c_master_recv() etc.
+ */
+static s32 p3h2x4x_tp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	u8 return_status;
+	int ret_sum = 0;
+	u8 msg_count;
+	int ret;
+	u8 rw;
+
+	struct device *dev;
+	struct tp_bus *bus =
+		container_of(adap, struct tp_bus, smbus_port_adapter);
+	struct p3h2x4x *priv = bus->priv;
+
+	if (priv->is_p3h2x4x_in_i3c)
+		dev = i3cdev_to_dev(priv->i3cdev);
+	else
+		dev = i2cdev_to_dev(priv->i2cdev);
+
+	lock_port_ext_mutex(&priv->etx_mutex, &bus->port_mutex);
+
+	if (priv->is_p3h2x4x_in_i3c) {
+		ret = i3c_device_disable_ibi(priv->i3cdev);
+		if (ret) {
+			dev_err(dev, "Failed to Disable IBI\n");
+			unlock_port_ext_mutex(&priv->etx_mutex, &bus->port_mutex);
+			return ret;
+		}
+	}
+
+	for (msg_count = 0; msg_count < num; msg_count++) {
+		if (msgs[msg_count].len > P3H2x4x_SMBUS_PAYLOAD_SIZE) {
+			dev_err(&adap->dev,
+				"Message nr. %d not sent - length over %d bytes.\n",
+				msg_count, P3H2x4x_SMBUS_PAYLOAD_SIZE);
+			continue;
+		}
+		rw = msgs[msg_count].flags % 2;
+
+		ret = p3h2x4x_tp_i2c_xfer_msg(priv,
+					      msgs,
+					      bus->tp_port,
+					      msg_count, rw, &return_status);
+
+		if (ret)
+			goto error;
+
+		if (return_status == P3H2x4x_XFER_SUCCESS)
+			ret_sum++;
+	}
+
+error:
+	if (priv->is_p3h2x4x_in_i3c) {
+		ret =  i3c_device_enable_ibi(priv->i3cdev);
+		if (ret) {
+			dev_err(dev, "Failed to Enable IBI\n");
+			unlock_port_ext_mutex(&priv->etx_mutex, &bus->port_mutex);
+			return ret;
+		}
+	}
+	unlock_port_ext_mutex(&priv->etx_mutex, &bus->port_mutex);
+	return ret_sum;
+}
+
+static int p3h2x4x_tp_smbus_xfer_msg(struct p3h2x4x *priv,
+				     u8 target_port,
+				     u8 addr,
+				     u8 rw,
+				     u8 cmd,
+				     int sz,
+				     union i2c_smbus_data *data,
+				     u8 *return_status)
+{
+	u8 controller_buffer_page = P3H2x4x_CONTROLLER_BUFFER_PAGE + 4 * target_port;
+	u8 target_port_status = P3H2x4x_TP0_SMBUS_AGNT_STS + target_port;
+	u8 desc[P3H2x4x_SMBUS_DESCRIPTOR_SIZE] = { 0 };
+	u8 transaction_type = P3H2x4x_SMBUS_400kHz;
+	u8 target_port_code = BIT(target_port);
+	u8 buf[I2C_SMBUS_BLOCK_MAX + 2] = {0};
+	u8 read_length = 0, write_length = 0;
+	u8 rw_address = 2 * addr;
+	struct device *dev;
+	int ret, i;
+	u8 status;
+
+	if (priv->is_p3h2x4x_in_i3c)
+		dev = i3cdev_to_dev(priv->i3cdev);
+	else
+		dev = i2cdev_to_dev(priv->i2cdev);
+
+	/* Map the size to what the chip understands */
+	switch (sz) {
+	case I2C_SMBUS_QUICK:
+	case I2C_SMBUS_BYTE:
+		if (rw)	{
+			buf[0] = data->byte;
+			read_length = ONE_BYTE_SIZE;
+			write_length = 0;
+			rw_address |= BIT(0);
+		} else {
+			buf[0] = cmd;
+			write_length = ONE_BYTE_SIZE;
+			read_length = 0;
+		}
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		if (rw) {   /* read write */
+			buf[0] = cmd;
+			write_length = ONE_BYTE_SIZE;
+			read_length = ONE_BYTE_SIZE;
+			transaction_type |= BIT(0);
+		} else {  /* only write */
+			buf[0] = cmd;
+			buf[1] = data->byte;
+			write_length = ONE_BYTE_SIZE + 1;
+			read_length = 0;
+		}
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		if (rw) {         /* read write */
+			buf[0] = cmd;
+			write_length = ONE_BYTE_SIZE;
+			read_length = 2;
+			transaction_type |= BIT(0);
+		} else {  /* only write */
+			buf[0] = cmd;
+			buf[1] = data->word & 0xff;
+			buf[2] = (data->word & 0xff00) >> 8;
+			write_length = ONE_BYTE_SIZE + 2;
+			read_length = 0;
+		}
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		if (rw) {         /* read write */
+			buf[0] = cmd;
+			write_length = ONE_BYTE_SIZE;
+			read_length = data->block[0] + 1;
+			transaction_type |= BIT(0);
+		} else {  /* only write */
+			buf[0] = cmd;
+			for (i = 0 ; i <= data->block[0]; i++)
+				buf[i + 1] = data->block[i];
+
+			write_length = data->block[0] + 2;
+			read_length = 0;
+		}
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (rw) {         /* read write */
+			buf[0] = cmd;
+			write_length = ONE_BYTE_SIZE;
+			read_length = data->block[0];
+			transaction_type |= BIT(0);
+		} else {  /* only write */
+			buf[0] = cmd;
+			for (i = 0 ; i < data->block[0]; i++)
+				buf[i + 1] = data->block[i + 1];
+
+			write_length = data->block[0] + 1;
+			read_length = 0;
+		}
+		break;
+	default:
+		dev_warn(dev, "Unsupported transaction %d\n", sz);
+		break;
+	}
+
+	desc[0] = rw_address;
+	desc[1] = transaction_type;
+	desc[2] = write_length;
+	desc[3] = read_length;
+
+	ret = regmap_write(priv->regmap, target_port_status,
+			   P3H2x4x_TP_BUFFER_STATUS_MASK);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(priv->regmap, P3H2x4x_PAGE_PTR, controller_buffer_page);
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_write(priv->regmap, P3H2x4x_CONTROLLER_AGENT_BUFF,
+				desc, P3H2x4x_SMBUS_DESCRIPTOR_SIZE);
+	if (ret)
+		return ret;
+
+	if (write_length) {
+		ret = regmap_bulk_write(priv->regmap,
+					P3H2x4x_CONTROLLER_AGENT_BUFF_DATA,
+					buf, write_length);
+		if (ret)
+			return ret;
+	}
+
+	ret = regmap_write(priv->regmap, P3H2x4x_TP_SMBUS_AGNT_TRANS_START,
+			   target_port_code);
+	if (ret)
+		return ret;
+
+	ret = p3h2x4x_read_smbus_transaction_status(priv, target_port_status, &status,
+						    (write_length + read_length));
+	if (ret)
+		return ret;
+
+	*return_status = status;
+
+	if (rw) {
+		switch (sz) {
+		case I2C_SMBUS_QUICK:
+		case I2C_SMBUS_BYTE:
+		case I2C_SMBUS_BYTE_DATA:
+			{
+				ret = regmap_bulk_read(priv->regmap,
+						       P3H2x4x_CONTROLLER_AGENT_BUFF_DATA +
+						       write_length,
+						       &data->byte, read_length);
+				break;
+			}
+		case I2C_SMBUS_WORD_DATA:
+			{
+				ret = regmap_bulk_read(priv->regmap,
+						       P3H2x4x_CONTROLLER_AGENT_BUFF_DATA +
+						       write_length,
+						       (u8 *)&data->word, read_length);
+				break;
+			}
+		case I2C_SMBUS_BLOCK_DATA:
+			{
+				ret = regmap_bulk_read(priv->regmap,
+						       P3H2x4x_CONTROLLER_AGENT_BUFF_DATA +
+						       write_length,
+						       data->block, read_length);
+				break;
+			}
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			{
+				ret = regmap_bulk_read(priv->regmap,
+						       P3H2x4x_CONTROLLER_AGENT_BUFF_DATA +
+						       write_length,
+						       data->block + 1, read_length);
+				break;
+			}
+		default:
+				dev_warn(dev, "Unsupported transaction %d\n", sz);
+				break;
+		}
+
+		if (ret)
+			return ret;
+	}
+
+	ret = regmap_write(priv->regmap, P3H2x4x_PAGE_PTR, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static s32 p3h2x4x_tp_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
+				 char read_write, u8 command, int size,
+				 union i2c_smbus_data *data)
+{
+	struct tp_bus *bus =
+		container_of(adap, struct tp_bus, smbus_port_adapter);
+
+	struct p3h2x4x *priv = bus->priv;
+	struct device *dev;
+
+	if (priv->is_p3h2x4x_in_i3c)
+		dev = i3cdev_to_dev(priv->i3cdev);
+	else
+		dev = i2cdev_to_dev(priv->i2cdev);
+
+	int ret, ret_status;
+	u8 return_status;
+
+	lock_port_ext_mutex(&priv->etx_mutex, &bus->port_mutex);
+
+	if (priv->is_p3h2x4x_in_i3c) {
+		ret = i3c_device_disable_ibi(priv->i3cdev);
+		if (ret) {
+			dev_err(dev, "Failed to Disable IBI\n");
+			unlock_port_ext_mutex(&priv->etx_mutex, &bus->port_mutex);
+			return ret;
+		}
+	}
+
+	ret_status = p3h2x4x_tp_smbus_xfer_msg(priv,
+					       (u8)bus->tp_port,
+					       (u8)addr,
+					       (u8)read_write,
+					       (u8)command,
+					       size,
+					       data,
+					       &return_status);
+
+	if (priv->is_p3h2x4x_in_i3c) {
+		ret = i3c_device_enable_ibi(priv->i3cdev);
+		if (ret) {
+			dev_err(dev, "Failed to Enable IBI\n");
+			unlock_port_ext_mutex(&priv->etx_mutex, &bus->port_mutex);
+			return ret;
+		}
+	}
+	unlock_port_ext_mutex(&priv->etx_mutex, &bus->port_mutex);
+
+	if (ret_status)
+		return ret_status;
+
+	if (return_status == P3H2x4x_XFER_SUCCESS)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static u32 p3h2x4x_tp_smbus_funcs(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+			I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_WORD_DATA |
+			I2C_FUNC_SMBUS_I2C_BLOCK  | I2C_FUNC_SMBUS_BLOCK_DATA |
+			I2C_FUNC_I2C;
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static int p3h2x4x_tp_i2c_reg_slave(struct i2c_client *slave)
+{
+	struct tp_bus *bus =
+		container_of(slave->adapter, struct tp_bus, smbus_port_adapter);
+	struct p3h2x4x *priv = bus->priv;
+
+	priv->is_slave_reg = true;
+
+	return 0;
+}
+
+static int p3h2x4x_tp_i2c_unreg_slave(struct i2c_client *slave)
+{
+	struct tp_bus *bus =
+		container_of(slave->adapter, struct tp_bus, smbus_port_adapter);
+	struct p3h2x4x *priv = bus->priv;
+
+	priv->is_slave_reg = false;
+
+	return 0;
+}
+#endif
+
+/*
+ * I2C algorithm Structure
+ */
+static struct i2c_algorithm p3h2x4x_tp_i2c_algorithm = {
+	.master_xfer    = p3h2x4x_tp_i2c_xfer,
+	.smbus_xfer = p3h2x4x_tp_smbus_xfer,
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+	.reg_slave = p3h2x4x_tp_i2c_reg_slave,
+	.unreg_slave = p3h2x4x_tp_i2c_unreg_slave,
+#endif
+	.functionality  = p3h2x4x_tp_smbus_funcs,
+};
+
+/*
+ * p3h2x4x_tp_add_downstream_device - prove downstream devices for target port who
+ * configured as SMBus.
+ * @priv: p3h2x4x device structure.
+ * Return: 0 in case of success, a negative EINVAL code if the error.
+ */
+int p3h2x4x_tp_add_downstream_device(struct p3h2x4x *priv)
+{
+	struct i2c_board_info smbus_tp_device_info = {0};
+	struct smbus_device *backend = NULL;
+	struct tp_bus *bus;
+	struct device *dev;
+	int i;
+
+	if (priv->is_p3h2x4x_in_i3c)
+		dev = i3cdev_to_dev(priv->i3cdev);
+	else
+		dev = i2cdev_to_dev(priv->i2cdev);
+
+	for (i = 0; i < P3H2x4x_TP_MAX_COUNT; i++) {
+		bus = &priv->tp_bus[i];
+		if (!bus->is_registered)
+			continue;
+
+		list_for_each_entry(backend,
+				    &bus->tp_device_entry, list) {
+			smbus_tp_device_info.addr = backend->addr;
+			smbus_tp_device_info.flags = I2C_CLIENT_SLAVE;
+			smbus_tp_device_info.of_node = backend->tp_device_dt_node;
+			snprintf(smbus_tp_device_info.type, I2C_NAME_SIZE, backend->compatible);
+			backend->client = i2c_new_client_device(&bus->smbus_port_adapter,
+								&smbus_tp_device_info);
+			if (IS_ERR(backend->client)) {
+				dev_warn(dev, "Error while registering backend\n");
+				return -EINVAL;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * p3h2x4x_tp_smbus_algo - add i2c adapter for target port who
+ * configured as SMBus.
+ * @priv: p3h2x4x device structure.
+ * @tp: target port.
+ * Return: 0 in case of success, a negative EINVAL code if the error.
+ */
+int p3h2x4x_tp_smbus_algo(struct p3h2x4x *priv, int tp)
+{
+	int ret;
+	struct device *dev;
+
+	if (priv->is_p3h2x4x_in_i3c)
+		dev = i3cdev_to_dev(priv->i3cdev);
+	else
+		dev = i2cdev_to_dev(priv->i2cdev);
+
+	priv->tp_bus[tp].smbus_port_adapter.owner = THIS_MODULE;
+	priv->tp_bus[tp].smbus_port_adapter.class = I2C_CLASS_HWMON;
+	priv->tp_bus[tp].smbus_port_adapter.algo = &p3h2x4x_tp_i2c_algorithm;
+
+	sprintf(priv->tp_bus[tp].smbus_port_adapter.name, "p3h2x4x-cp-%d.tp-port-%d",
+		p3h2x4x_read_p3h2x4x_id(dev), tp);
+
+	ret = i2c_add_adapter(&priv->tp_bus[tp].smbus_port_adapter);
+	if (ret) {
+		dev_warn(dev, "failled to add adapter for tp %d\n", tp);
+		return -EINVAL;
+	}
+	priv->tp_bus[tp].is_registered = true;
+
+	return 0;
+}
diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h
index b674f64d0822..5ab199abb653 100644
--- a/include/linux/i3c/device.h
+++ b/include/linux/i3c/device.h
@@ -77,6 +77,7 @@ struct i3c_priv_xfer {
  */
 enum i3c_dcr {
 	I3C_DCR_GENERIC_DEVICE = 0,
+	I3C_DCR_HUB = 194,
 };
 
 #define I3C_PID_MANUF_ID(pid)		(((pid) & GENMASK_ULL(47, 33)) >> 33)
-- 
2.25.1



From aman.kumarpandey at nxp.com  Mon May 12 04:45:33 2025
From: aman.kumarpandey at nxp.com (Aman Kumar Pandey)
Date: Mon, 12 May 2025 11:45:33 +0000
Subject: [EXT] Re: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x
 i3c-hub support
In-Reply-To: <17145d2f-5d07-4939-8381-74e27cde303c@kernel.org>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
 <17145d2f-5d07-4939-8381-74e27cde303c@kernel.org>
Message-ID: <GVXPR04MB9778335A5DFAB37CC8D011FC9997A@GVXPR04MB9778.eurprd04.prod.outlook.com>


> -----Original Message-----
> From: Krzysztof Kozlowski <krzk at kernel.org>
> Sent: Thursday, May 8, 2025 11:38 AM
> To: Aman Kumar Pandey <aman.kumarpandey at nxp.com>; linux-
> kernel at vger.kernel.org; linux-i3c at lists.infradead.org;
> alexandre.belloni at bootlin.com; krzk+dt at kernel.org; robh at kernel.org;
> conor+dt at kernel.org; devicetree at vger.kernel.org
> Cc: Vikash Bansal <vikash.bansal at nxp.com>; Priyanka Jain
> <priyanka.jain at nxp.com>; Shashank Rebbapragada
> <shashank.rebbapragada at nxp.com>; Frank Li <frank.li at nxp.com>
> Subject: [EXT] Re: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x i3c-hub
> support
> 
> Caution: This is an external email. Please take care when clicking links or
> opening attachments. When in doubt, report the message using the 'Report
> this email' button
> 
> 
> On 08/05/2025 06:57, Aman Kumar Pandey wrote:
> > Add bindings for the NXP P3H2x4x (P3H2440/P3H2441/P3H2840/P3H2841)
> > multiport I3C hub family. These devices connect to a host via
> > I3C/I2C/SMBus and allow communication with multiple downstream
> > peripherals.
> >
> > Signed-off-by: Aman Kumar Pandey <aman.kumarpandey at nxp.com>
> > Signed-off-by: Vikash Bansal <vikash.bansal at nxp.com>
> > ---
> > V1 -> V2: Cleaned up coding style and addressed review comments
> > ---
> >  .../bindings/i3c/p3h2840-i3c-hub.yaml         | 332 ++++++++++++++++++
> 
> Not much improved. I have doubts that you really looked at other bindings.
> 
> Filename matching compatible.
> 
> 

Thanks for reviewing the patch.
There is no existing entry like this one. It is the first device tree entry for any i3c target device being added to Linux upstream. 
For I3C target device, compatible is not required as per i3c.yml. I am adding compatible for backward compatibility with i2c binding ( i3c target device have backward compatibility). 
Should I use compatible matching filename in this case ?

> >  MAINTAINERS                                   |   8 +
> >  2 files changed, 340 insertions(+)
 
 
> > +
> > +properties:
> > +  $nodename:
> > +    pattern: "^hub@[@.*]+,[0-9a-f]+$"
> 
> Drop
> 

Sorry, did not understand your point. Could you please give some clarification ?

> > +

> > +
> > +  cp0-ldo-enable:
> > +    type: boolean
> > +    description:
> > +      Enables the on-die LDO for controller Port 0.
> > +
> > +  cp1-ldo-enable:
> > +    type: boolean
> > +    description:
> > +      Enables the on-die LDO for controller Port 1.
> > +
> > +  tp0145-ldo-enable:
> > +    type: boolean
> > +    description:
> > +      Enables the on-die LDO for target ports 0/1/4/5.
> > +
> > +  tp2367-ldo-enable:
> > +    type: boolean
> > +    description:
> > +      Enables the on-die LDO for target ports 2/3/6/7.
> > +
> 
> NAK for all above properties.
> 

These are not vender specific properties. all these properties are as per i3c hub specification.
 What should I change for above properties ?

> > +  cp0-ldo-microvolt:
> 
> Do you see anywhere device properties named like that? Without prefix?
> 
> I am not going to review the rest. You did not try hard enough to fulfill
> previous review request, you did not really test it.
> 
> Start from scratch from latest accepted schema or from example-schema.
> 


> Best regards,
> Krzysztof


From aman.kumarpandey at nxp.com  Mon May 12 04:45:59 2025
From: aman.kumarpandey at nxp.com (Aman Kumar Pandey)
Date: Mon, 12 May 2025 11:45:59 +0000
Subject: [EXT] Re: [PATCH v2 2/2] drivers: i3c: Add driver for NXP P3H2x4x
 i3c-hub device
In-Reply-To: <b46e3766-75b7-4635-a505-3039e4394f07@kernel.org>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
 <20250508045711.2810207-2-aman.kumarpandey@nxp.com>
 <b46e3766-75b7-4635-a505-3039e4394f07@kernel.org>
Message-ID: <GVXPR04MB9778CD46464F6BEE25D5D0529997A@GVXPR04MB9778.eurprd04.prod.outlook.com>


> -----Original Message-----
> From: Krzysztof Kozlowski <krzk at kernel.org>
> Sent: Thursday, May 8, 2025 11:40 AM
> To: Aman Kumar Pandey <aman.kumarpandey at nxp.com>; linux-
> kernel at vger.kernel.org; linux-i3c at lists.infradead.org;
> alexandre.belloni at bootlin.com; krzk+dt at kernel.org; robh at kernel.org;
> conor+dt at kernel.org; devicetree at vger.kernel.org
> Cc: Vikash Bansal <vikash.bansal at nxp.com>; Priyanka Jain
> <priyanka.jain at nxp.com>; Shashank Rebbapragada
> <shashank.rebbapragada at nxp.com>; Frank Li <frank.li at nxp.com>
> Subject: [EXT] Re: [PATCH v2 2/2] drivers: i3c: Add driver for NXP P3H2x4x i3c-
> hub device
> 
> [Some people who received this message don't often get email from
> krzk at kernel.org. Learn why this is important at
> https://aka.ms/LearnAboutSenderIdentification ]
> 
> Caution: This is an external email. Please take care when clicking links or
> opening attachments. When in doubt, report the message using the 'Report
> this email' button
> 
> 
> On 08/05/2025 06:57, Aman Kumar Pandey wrote:
> > +
> > +static void p3h2x4x_of_get_tp_dt_conf(struct device *dev,
> > +                                   const struct device_node *node) {
> > +     struct p3h2x4x *priv = dev_get_drvdata(dev);
> > +     struct device_node *dev_node;
> > +     u64 tp_port;
> > +
> > +     for_each_available_child_of_node(node, dev_node) {
> > +             if (!dev_node->name || of_node_cmp(dev_node->name,
> > + "target-port"))
> 
> 
> Same NAK as before. You ignored the comment and nothing improved.
> 

Thanks for reviewing the patch.
As per your comment I have used proper function to get reg instead of sscanf. And our driver is not having direct interface with userspace.
What should I change here ?

> > +                     continue;
> > +
> > +             if (of_property_read_reg(dev_node, 0, &tp_port, NULL))
> > +                     continue;
> > +
> > +             if (tp_port < P3H2x4x_TP_MAX_COUNT) {
> > +                     priv->tp_bus[tp_port].dt_available = true;
> > +                     priv->tp_bus[tp_port].of_node = dev_node;
> > +                     priv->tp_bus[tp_port].tp_mask = BIT(tp_port);
> > +                     priv->tp_bus[tp_port].priv = priv;
> > +                     priv->tp_bus[tp_port].tp_port = tp_port;
> > +             }
> > +     }
> > +}
> > +
 


From alexandre.belloni at bootlin.com  Thu May 15 02:45:47 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Thu, 15 May 2025 11:45:47 +0200
Subject: [PATCH v3 1/5] i3c: mipi-i3c-hci: Allow only relevant
 INTR_STATUS bit updates
In-Reply-To: <20250409140401.299251-1-jarkko.nikula@linux.intel.com>
References: <20250409140401.299251-1-jarkko.nikula@linux.intel.com>
Message-ID: <174730228204.1307590.17878462961499587911.b4-ty@bootlin.com>

On Wed, 09 Apr 2025 17:03:57 +0300, Jarkko Nikula wrote:
> Since MIPI I3C HCI specification version v0.8 INTR_STATUS bits 9:0 are
> reserved. Version v0.5 has bits 9 and 5:0 in use but not handled by the
> current driver code and not needed in DMA transfers.
> 
> PIO transfers with v0.5 would require changes to both
> core.c: i3c_hci_irq_handler() and pio.c: hci_pio_irq_handler() though.
> 
> [...]

Applied, thanks!

[1/5] i3c: mipi-i3c-hci: Allow only relevant INTR_STATUS bit updates
      https://git.kernel.org/abelloni/c/eeeec6c5475e
[2/5] i3c: mipi-i3c-hci: Fix handling status of i3c_hci_irq_handler()
      https://git.kernel.org/abelloni/c/279c24021b83
[3/5] i3c: mipi-i3c-hci: Clear INTR_STATUS unconditionally
      https://git.kernel.org/abelloni/c/a7035a8ee966
[4/5] i3c: mipi-i3c-hci: Change name of INTR_STATUS bit 11
      https://git.kernel.org/abelloni/c/7479d2675c50
[5/5] i3c: mipi-i3c-hci: Move unexpected INTR_STATUS print before IO handler
      https://git.kernel.org/abelloni/c/bd916806632d

Best regards,

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From alexandre.belloni at bootlin.com  Thu May 15 02:54:14 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Thu, 15 May 2025 11:54:14 +0200
Subject: [PATCH v1 0/2] svc-i3c-master: Reduce IBI transaction time
In-Reply-To: <20250415051808.88091-1-yschu@nuvoton.com>
References: <20250415051808.88091-1-yschu@nuvoton.com>
Message-ID: <174730284585.1309105.12276937340014821403.b4-ty@bootlin.com>

On Tue, 15 Apr 2025 13:18:06 +0800, Stanley Chu wrote:
> This patchset reduces the IBI transaction time by the following
> improvements.
> 1. Receive the request in interrupt context.
> 2. Emit the STOP as soon as possible.
> 
> Stanley Chu (2):
>   i3c: master: svc: Receive IBI requests in interrupt context
>   i3c: master: svc: Emit STOP asap in the IBI transaction
> 
> [...]

Applied, thanks!

[1/2] i3c: master: svc: Receive IBI requests in interrupt context
      https://git.kernel.org/abelloni/c/8d29fa6d921c
[2/2] i3c: master: svc: Emit STOP asap in the IBI transaction
      https://git.kernel.org/abelloni/c/81f2a9af9821

Best regards,

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From alexandre.belloni at bootlin.com  Thu May 15 02:56:33 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Thu, 15 May 2025 11:56:33 +0200
Subject: [PATCH v2 1/1] i3c: master: svc: skip address resend on repeat
 START
In-Reply-To: <20250429054234.4013929-1-Frank.Li@nxp.com>
References: <20250429054234.4013929-1-Frank.Li@nxp.com>
Message-ID: <174730297355.1309338.10386281682864531931.b4-ty@bootlin.com>

On Tue, 29 Apr 2025 01:42:34 -0400, Frank Li wrote:
> According to the I3C specification, address arbitration only happens during
> the START. Repeated START do not initiate arbitration, and In-Band
> Interrupts (IBIs) cannot occur at this stage.
> 
> Resending the address upon a NACK in a repeat START is therefore redundant
> and unnecessary. Avoid redundant retries, improving efficiency and ensuring
> protocol compliance.
> 
> [...]

Applied, thanks!

[1/1] i3c: master: svc: skip address resend on repeat START
      https://git.kernel.org/abelloni/c/12cbd1573448

Best regards,

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From Frank.li at nxp.com  Thu May 22 11:38:30 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 22 May 2025 14:38:30 -0400
Subject: [EXT] Re: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x
 i3c-hub support
In-Reply-To: <18d6951a-860e-4479-837e-9edc90adeaea@kernel.org>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
 <17145d2f-5d07-4939-8381-74e27cde303c@kernel.org>
 <GVXPR04MB9778335A5DFAB37CC8D011FC9997A@GVXPR04MB9778.eurprd04.prod.outlook.com>
 <18d6951a-860e-4479-837e-9edc90adeaea@kernel.org>
Message-ID: <aC9vJiiOi1E7PesF@lizhi-Precision-Tower-5810>

On Wed, May 14, 2025 at 12:18:46PM +0200, Krzysztof Kozlowski wrote:
> On 12/05/2025 13:45, Aman Kumar Pandey wrote:
> >>
> >
> > These are not vender specific properties. all these properties are as per i3c hub specification.
> >  What should I change for above properties ?
>
> BTW, if this was I3C spec, then I would also expect all of such
> spec-related-properties to be in shared schema.

At least I have not found it at mipi org. I supposed some vendors choose the
similar design like other's i2c sensor/gpio expander chips.

So I think we can keep this property here until it is prompted to standard.

Frank

>
> Best regards,
> Krzysztof


From Frank.li at nxp.com  Thu May 22 11:46:44 2025
From: Frank.li at nxp.com (Frank Li)
Date: Thu, 22 May 2025 14:46:44 -0400
Subject: [EXT] Re: [PATCH v2 1/2] dt-bindings: i3c: Add NXP P3H2x4x
 i3c-hub support
In-Reply-To: <ef92c390-d136-46b4-8219-294c449e4092@kernel.org>
References: <20250508045711.2810207-1-aman.kumarpandey@nxp.com>
 <17145d2f-5d07-4939-8381-74e27cde303c@kernel.org>
 <GVXPR04MB9778335A5DFAB37CC8D011FC9997A@GVXPR04MB9778.eurprd04.prod.outlook.com>
 <ef92c390-d136-46b4-8219-294c449e4092@kernel.org>
Message-ID: <aC9xFMKG88OOH2xV@lizhi-Precision-Tower-5810>

On Wed, May 14, 2025 at 12:10:11PM +0200, Krzysztof Kozlowski wrote:
> On 12/05/2025 13:45, Aman Kumar Pandey wrote:
> >>>
> >>> Signed-off-by: Aman Kumar Pandey <aman.kumarpandey at nxp.com>
> >>> Signed-off-by: Vikash Bansal <vikash.bansal at nxp.com>
> >>> ---
> >>> V1 -> V2: Cleaned up coding style and addressed review comments
> >>> ---
> >>>  .../bindings/i3c/p3h2840-i3c-hub.yaml         | 332 ++++++++++++++++++
> >>
> >> Not much improved. I have doubts that you really looked at other bindings.
> >>
> >> Filename matching compatible.
> >>
> >>
> >
> > Thanks for reviewing the patch.
> > There is no existing entry like this one. It is the first device tree entry for any i3c target device being added to Linux upstream.
> > For I3C target device, compatible is not required as per i3c.yml. I am adding compatible for backward compatibility with i2c binding ( i3c target device have backward compatibility).
> > Should I use compatible matching filename in this case ?
>
> Do you have compatible here? Yes, you have, so I do not get what is
> unclear in my comment. Rename the binding to match the compatible, which
> you have here.
>
>
> >
> >>>  MAINTAINERS                                   |   8 +
> >>>  2 files changed, 340 insertions(+)
> >
> >
> >>> +
> >>> +properties:
> >>> +  $nodename:
> >>> +    pattern: "^hub@[@.*]+,[0-9a-f]+$"
> >>
> >> Drop
> >>
> >
> > Sorry, did not understand your point. Could you please give some clarification ?
>
> Drop this nodename. Remove it.
>
> >
> >>> +
> >
> >>> +
> >>> +  cp0-ldo-enable:
> >>> +    type: boolean
> >>> +    description:
> >>> +      Enables the on-die LDO for controller Port 0.
> >>> +
> >>> +  cp1-ldo-enable:
> >>> +    type: boolean
> >>> +    description:
> >>> +      Enables the on-die LDO for controller Port 1.
> >>> +
> >>> +  tp0145-ldo-enable:
> >>> +    type: boolean
> >>> +    description:
> >>> +      Enables the on-die LDO for target ports 0/1/4/5.
> >>> +
> >>> +  tp2367-ldo-enable:
> >>> +    type: boolean
> >>> +    description:
> >>> +      Enables the on-die LDO for target ports 2/3/6/7.
> >>> +
> >>
> >> NAK for all above properties.
> >>
> >
> > These are not vender specific properties. all these properties are as per i3c hub specification.
> >  What should I change for above properties ?
>
>
> What do they represent? Regulators? Why would you add custom properties
> for controlling regulators? Why would you enable LDOs for ports which
> have nothing connected? Why would you not enable LDOs for ports which
> have something there? Why these are not properties of the ports?
>

power supply cp[0,1] has two options: one from internal ldo, the other from the
other regulator.

So I think it should be *-supply

cp0-supply:
  description: phandle to cp0 power supply.

because internal ldo can provide difference voltage, I suggest export as
standard regulator

regulators:
  properties:
    cp0:
      type: object
      $ref: /schemas/regulator/regulator.yaml#
      unevaluatedProperties: false

Frank


> So many questions.
>
>
> Best regards,
> Krzysztof


From alexandre.belloni at bootlin.com  Sat May 24 13:51:03 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Sat, 24 May 2025 22:51:03 +0200
Subject: (subset) [PATCH V4 0/3] support different number of clocks for
 svc i3c controller
In-Reply-To: <20250427083230.3325700-1-carlos.song@nxp.com>
References: <20250427083230.3325700-1-carlos.song@nxp.com>
Message-ID: <174811981012.1255947.3023044294163637573.b4-ty@bootlin.com>

On Sun, 27 Apr 2025 16:32:27 +0800, carlos.song at nxp.com wrote:
> From: Carlos Song <carlos.song at nxp.com>
> 
> I.MX94 and I.MX95 I3C only need two clocks and legacy I3C needs three
> clocks. So add restrictions for clock and clock-names properties for
> different Socs. In driver, use the clk_bulk API to handle clocks to
> support different numbers of clocks more easily. Make the code cleaner
> and more flexible.
> 
> [...]

Applied, thanks!

[1/3] dt-bindings: i3c: silvaco,i3c-master: add i.MX94 and i.MX95 I3C
      https://git.kernel.org/abelloni/c/489c773a68de
[2/3] i3c: master: svc: switch to bulk clk API for flexible clock support
      https://git.kernel.org/abelloni/c/cd1a6a0c69e7

Best regards,

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


From alexandre.belloni at bootlin.com  Sat May 24 13:51:16 2025
From: alexandre.belloni at bootlin.com (Alexandre Belloni)
Date: Sat, 24 May 2025 22:51:16 +0200
Subject: [PATCH] i3c: controllers do not need to depend on I3C
In-Reply-To: <20250506075247.1545-2-wsa+renesas@sang-engineering.com>
References: <20250506075247.1545-2-wsa+renesas@sang-engineering.com>
Message-ID: <174811981014.1255947.11041838527327968781.b4-ty@bootlin.com>

On Tue, 06 May 2025 09:52:11 +0200, Wolfram Sang wrote:
> The Kconfig file for controller drivers is only sourced if the I3C
> symbol is enabled. No need to check for that in individual drivers.
> 
> 

Applied, thanks!

[1/1] i3c: controllers do not need to depend on I3C
      https://git.kernel.org/abelloni/c/00286d7d643d

Best regards,

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


