From: Akhil R <akhilrajeev@nvidia.com>
To: Alexandre Belloni <alexandre.belloni@bootlin.com>,
Frank Li <Frank.Li@nxp.com>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
"Rafael J . Wysocki" <rafael@kernel.org>,
Robert Moore <robert.moore@intel.com>,
"Len Brown" <lenb@kernel.org>, Guenter Roeck <linux@roeck-us.net>,
Philipp Zabel <p.zabel@pengutronix.de>,
Eric Biggers <ebiggers@kernel.org>,
Sakari Ailus <sakari.ailus@linux.intel.com>,
Wolfram Sang <wsa+renesas@sang-engineering.com>,
Miquel Raynal <miquel.raynal@bootlin.com>,
<linux-i3c@lists.infradead.org>, <devicetree@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <linux-acpi@vger.kernel.org>,
<acpica-devel@lists.linux.dev>, <linux-hwmon@vger.kernel.org>
Cc: Akhil R <akhilrajeev@nvidia.com>
Subject: [PATCH v2 04/13] i3c: master: Support ACPI enumeration of child devices
Date: Thu, 9 Apr 2026 16:27:34 +0530 [thread overview]
Message-ID: <20260409105747.48158-5-akhilrajeev@nvidia.com> (raw)
In-Reply-To: <20260409105747.48158-1-akhilrajeev@nvidia.com>
Although the existing subsystem allows host controllers to register
through the ACPI table, it was not possible to describe I3C or I2C
devices when using ACPI. This is because the driver relied on reg
property to retrieve the PID, static address etc whereas ACPI uses
_ADR or serial resources to describe such devices.
Read _ADR and LVR from the ACPI resources and extract the data as per the
ACPI specification for an I3C bus. Also read mipi-i3c-static-address as
per the MIPI DISCO specifications [1] to get the static address to be
used. Hence enable describing the I3C or I2C devices in the ACPI
table, which is required if the device is using a static address or if it
needs some specific properties to be attached to it.
[1] https://www.mipi.org/mipi-disco-for-i3c-download
Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i3c/master.c | 140 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 132 insertions(+), 8 deletions(-)
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 5e0e926f61f3..08d0fcabd6f1 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -5,6 +5,7 @@
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
*/
+#include <linux/acpi.h>
#include <linux/atomic.h>
#include <linux/bug.h>
#include <linux/device.h>
@@ -2403,6 +2404,53 @@ EXPORT_SYMBOL_GPL(i3c_master_add_i3c_dev_locked);
#define OF_I3C_REG1_IS_I2C_DEV BIT(31)
+#ifdef CONFIG_ACPI
+static int i3c_acpi_get_i2c_resource(struct acpi_resource *ares, void *data)
+{
+ struct i2c_dev_boardinfo *boardinfo = data;
+ struct acpi_resource_i2c_serialbus *sb;
+
+ if (!i2c_acpi_get_i2c_resource(ares, &sb))
+ return 1;
+
+ boardinfo->base.addr = sb->slave_address;
+ if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+ boardinfo->base.flags |= I2C_CLIENT_TEN;
+
+ boardinfo->lvr = sb->lvr;
+
+ return 0;
+}
+
+static int i3c_acpi_add_i2c_boardinfo(struct i2c_dev_boardinfo *boardinfo,
+ struct fwnode_handle *fwnode)
+{
+ struct acpi_device *adev = to_acpi_device_node(fwnode);
+ LIST_HEAD(resources);
+ int ret;
+
+ boardinfo->base.fwnode = acpi_fwnode_handle(adev);
+
+ ret = acpi_dev_get_resources(adev, &resources,
+ i3c_acpi_get_i2c_resource, boardinfo);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&resources);
+
+ if (!boardinfo->base.addr)
+ return -ENODEV;
+
+ return 0;
+}
+#else
+static inline int i3c_acpi_add_i2c_boardinfo(struct i2c_dev_boardinfo *boardinfo,
+ struct fwnode_handle *fwnode)
+{
+ return -ENODEV;
+}
+#endif
+
static int
i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
struct fwnode_handle *fwnode, u32 *reg)
@@ -2419,6 +2467,13 @@ i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
ret = of_i2c_get_board_info(dev, to_of_node(fwnode), &boardinfo->base);
if (ret)
return ret;
+
+ /* LVR is encoded in reg[2] for Device Tree. */
+ boardinfo->lvr = reg[2];
+ } else if (is_acpi_device_node(fwnode)) {
+ ret = i3c_acpi_add_i2c_boardinfo(boardinfo, fwnode);
+ if (ret)
+ return ret;
} else {
return -EINVAL;
}
@@ -2433,9 +2488,6 @@ i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
return -EOPNOTSUPP;
}
- /* LVR is encoded in reg[2]. */
- boardinfo->lvr = reg[2];
-
list_add_tail(&boardinfo->node, &master->boardinfo.i2c);
fwnode_handle_get(fwnode);
@@ -2490,8 +2542,8 @@ i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master,
return 0;
}
-static int i3c_master_add_dev(struct i3c_master_controller *master,
- struct fwnode_handle *fwnode)
+static int i3c_master_add_of_dev(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode)
{
u32 reg[3];
int ret;
@@ -2515,6 +2567,67 @@ static int i3c_master_add_dev(struct i3c_master_controller *master,
return ret;
}
+#ifdef CONFIG_ACPI
+static int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode)
+{
+ struct acpi_device *adev = to_acpi_device_node(fwnode);
+ acpi_bus_address adr;
+ u32 reg[3] = { 0 };
+
+ /*
+ * If the ACPI table entry does not have _ADR method, it's an I2C device
+ * If the ACPI table entry has _ADR method, it's an I3C device
+ */
+ if (!acpi_has_method(adev->handle, "_ADR"))
+ return i3c_master_add_i2c_boardinfo(master, fwnode, reg);
+
+ adr = acpi_device_adr(adev);
+
+ /* For I3C devices, _ADR will have the 48 bit PID of the device */
+ reg[1] = upper_32_bits(adr);
+ reg[2] = lower_32_bits(adr);
+
+ fwnode_property_read_u32(fwnode, "mipi-i3c-static-address", ®[0]);
+
+ return i3c_master_add_i3c_boardinfo(master, fwnode, reg);
+}
+
+static u8 i3c_acpi_i2c_get_lvr(struct i2c_client *client)
+{
+ struct acpi_device *adev = to_acpi_device_node(client->dev.fwnode);
+ struct i2c_dev_boardinfo boardinfo = {};
+ LIST_HEAD(resources);
+ int ret;
+ u8 lvr;
+
+ lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
+
+ ret = acpi_dev_get_resources(adev, &resources,
+ i3c_acpi_get_i2c_resource, &boardinfo);
+ if (ret < 0)
+ return lvr;
+
+ if (boardinfo.base.addr)
+ lvr = boardinfo.lvr;
+
+ acpi_dev_free_resource_list(&resources);
+
+ return lvr;
+}
+#else
+static inline int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
+ struct fwnode_handle *fwnode)
+{
+ return -ENODEV;
+}
+
+static inline u8 i3c_acpi_i2c_get_lvr(struct i2c_client *client)
+{
+ return I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
+}
+#endif
+
static int fwnode_populate_i3c_bus(struct i3c_master_controller *master)
{
struct device *dev = &master->dev;
@@ -2526,7 +2639,13 @@ static int fwnode_populate_i3c_bus(struct i3c_master_controller *master)
return 0;
fwnode_for_each_available_child_node_scoped(fwnode, child) {
- ret = i3c_master_add_dev(master, child);
+ if (is_of_node(child))
+ ret = i3c_master_add_of_dev(master, child);
+ else if (is_acpi_device_node(child))
+ ret = i3c_master_add_acpi_dev(master, child);
+ else
+ continue;
+
if (ret)
return ret;
}
@@ -2594,8 +2713,13 @@ static u8 i3c_master_i2c_get_lvr(struct i2c_client *client)
u8 lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE;
u32 reg[3];
- if (!fwnode_property_read_u32_array(client->dev.fwnode, "reg", reg, ARRAY_SIZE(reg)))
- lvr = reg[2];
+ if (is_of_node(client->dev.fwnode)) {
+ if (!fwnode_property_read_u32_array(client->dev.fwnode, "reg",
+ reg, ARRAY_SIZE(reg)))
+ lvr = reg[2];
+ } else if (is_acpi_device_node(client->dev.fwnode)) {
+ lvr = i3c_acpi_i2c_get_lvr(client);
+ }
return lvr;
}
--
2.50.1
next prev parent reply other threads:[~2026-04-09 10:59 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-09 10:57 [PATCH v2 00/13] Support ACPI and SETAASA device discovery Akhil R
2026-04-09 10:57 ` [PATCH v2 01/13] dt-bindings: i3c: Add mipi-i3c-static-method to support SETAASA Akhil R
2026-04-09 10:57 ` [PATCH v2 02/13] ACPICA: Read LVR from the I2C resource descriptor Akhil R
2026-04-09 11:07 ` Rafael J. Wysocki
2026-04-09 10:57 ` [PATCH v2 03/13] i3c: master: Use unified device property interface Akhil R
2026-04-09 10:57 ` Akhil R [this message]
2026-04-09 10:57 ` [PATCH v2 05/13] i3c: master: Add support for devices using SETAASA Akhil R
2026-04-09 10:57 ` [PATCH v2 06/13] i3c: master: Add support for devices without PID Akhil R
2026-04-09 10:57 ` [PATCH v2 07/13] i3c: master: match I3C device through DT and ACPI Akhil R
2026-04-09 10:57 ` [PATCH v2 08/13] i3c: dw-i3c-master: Add SETAASA as supported CCC Akhil R
2026-04-09 10:57 ` [PATCH v2 09/13] i3c: dw-i3c-master: Add a quirk to skip clock and reset Akhil R
2026-04-09 10:57 ` [PATCH v2 10/13] i3c: dw-i3c-master: Add ACPI ID for Tegra410 Akhil R
2026-04-09 10:57 ` [PATCH v2 11/13] hwmon: spd5118: Remove 16-bit addressing Akhil R
2026-04-09 14:11 ` Guenter Roeck
2026-04-09 10:57 ` [PATCH v2 12/13] hwmon: spd5118: Add I3C support Akhil R
2026-04-09 14:19 ` Guenter Roeck
2026-04-09 10:57 ` [PATCH v2 13/13] arm64: defconfig: Enable I3C and SPD5118 hwmon Akhil R
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260409105747.48158-5-akhilrajeev@nvidia.com \
--to=akhilrajeev@nvidia.com \
--cc=Frank.Li@nxp.com \
--cc=acpica-devel@lists.linux.dev \
--cc=alexandre.belloni@bootlin.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=ebiggers@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-i3c@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=miquel.raynal@bootlin.com \
--cc=p.zabel@pengutronix.de \
--cc=rafael@kernel.org \
--cc=robert.moore@intel.com \
--cc=robh@kernel.org \
--cc=sakari.ailus@linux.intel.com \
--cc=wsa+renesas@sang-engineering.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox