Re: [PATCH v5 1/5] i3c: master: Expose the APIs to support I3C hub
From: Frank Li <Frank.li@nxp.com>
Date: 2026-02-06 17:06:41
Also in:
linux-i3c, lkml
On Fri, Feb 06, 2026 at 02:01:17PM +0200, Aman Kumar Pandey wrote:
quoted hunk ↗ jump to hunk
Expose i3c_master_send_ccc_cmd(), i3c_master_supports_ccc_cmd(), i3c_master_reattach_i3c_dev(), i3c_master_direct_attach_i3c_dev(), and i3c_master_direct_detach_i3c_dev() to support I3C hub. Signed-off-by: Aman Kumar Pandey <redacted> --- Changes in v5: - No change Changes in v4: - Updated I3C master to handle hub support --- --- drivers/i3c/master.c | 123 ++++++++++++++++++++++++++++++++++++- include/linux/i3c/master.h | 11 ++++ 2 files changed, 132 insertions(+), 2 deletions(-)diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 7f606c871648..c92152ff795f 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c@@ -1544,8 +1544,76 @@ static int i3c_master_attach_i3c_dev(struct i3c_master_controller *master, return 0; } -static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, - u8 old_dyn_addr) +/** + * i3c_master_direct_attach_i3c_dev() - attach an I3C device to a master + * @master: I3C master controller to attach the device to + * @dev: I3C device descriptor representing the device + * + * This function attaches an I3C device to its master controller once the + * device has a valid address on the bus. Devices without + * an assigned address are ignored. The master device itself is never + * attached through this bus. + * + * Return: 0 on success, or a negative error code if the attach operation + * fails in the master controller driver. + */ +int i3c_master_direct_attach_i3c_dev(struct i3c_master_controller *master, + struct i3c_dev_desc *dev) +{ + int ret = 0; + + /* + * We don't attach devices to the controller until they are + * addressable on the bus. + */ + + if (!dev->info.static_addr && !dev->info.dyn_addr) + return 0;
AI: - Silent success on invalid input is questionable - should this be -EINVAL?
+
+ /* Do not attach the master device itself. */
+ if (master->this != dev && master->ops->attach_i3c_dev)
+ ret = master->ops->attach_i3c_dev(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_master_direct_attach_i3c_dev);
+
+/**
+ * i3c_master_direct_detach_i3c_dev - Detach an I3C device from its master
+ * @dev: I3C device descriptor to be detached
+ *
+ * This function detaches an I3C device from its master controller.
+ * It ensures that the master itself is not detached. If the device is not
+ * the master and the master controller provides a detach operation,
+ * the detach callback is invoked to perform the actual removal.
+ */
+void i3c_master_direct_detach_i3c_dev(struct i3c_dev_desc *dev)
+{
+ struct i3c_master_controller *master = i3c_dev_get_master(dev);
+
+ /* Do not detach the master device itself. */
+ if (master->this != dev && master->ops->detach_i3c_dev)
+ master->ops->detach_i3c_dev(dev);
+}
+EXPORT_SYMBOL_GPL(i3c_master_direct_detach_i3c_dev);Can you create two patch, - change existed static function to API. - add new APIs. Frank
quoted hunk ↗ jump to hunk
+ +/** + * i3c_master_reattach_i3c_dev() - reattach an I3C device with a new address + * @dev: I3C device descriptor to reattach + * @old_dyn_addr: previous dynamic address of the device + * + * This function reattaches an existing I3C device to the bus when its dynamic + * address has changed. It updates the bus address slot status accordingly: + * - Marks the new dynamic address as occupied by an I3C device. + * - Frees the old dynamic address slot if applicable. + * + * This function must be called with the bus lock held in write mode. + * + * Return: 0 on success, or a negative error code if reattachment fails + * (e.g. -EBUSY if the new address slot is not free). + */ +int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, + u8 old_dyn_addr) { struct i3c_master_controller *master = i3c_dev_get_master(dev); int ret;@@ -1569,6 +1637,7 @@ static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, return 0; } +EXPORT_SYMBOL_GPL(i3c_master_reattach_i3c_dev); static void i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev) {@@ -1692,6 +1761,56 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master) } } +/** + * i3c_master_supports_ccc_cmd() - check CCC command support + * @master: I3C master controller + * @cmd: CCC command to verify + * + * This function verifies whether the given I3C master controller supports + * the specified Common Command Code (CCC). + * + * Return: 0 if the CCC command is supported and executed successfully, + * -EINVAL if arguments are invalid, + * -EOPNOTSUPP if the master does not support CCC commands, + * or another negative error code from the master's operation. + */ +int i3c_master_supports_ccc_cmd(struct i3c_master_controller *master, + const struct i3c_ccc_cmd *cmd) +{ + if (!cmd || !master) + return -EINVAL; + + if (!master->ops->supports_ccc_cmd) + return -EOPNOTSUPP; + + return master->ops->supports_ccc_cmd(master, cmd); +} +EXPORT_SYMBOL_GPL(i3c_master_supports_ccc_cmd); + +/** + * i3c_master_send_ccc_cmd() - send a CCC command + * @master: I3C master controller issuing the command + * @cmd: CCC command to be sent + * + * This function sends a Common Command Code (CCC) command to devices on the + * I3C bus. It acquires the bus maintenance lock, executes the command, and + * then releases the lock to ensure safe access to the bus. + * + * Return: 0 on success, or a negative error code on failure. + */ +int i3c_master_send_ccc_cmd(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd) +{ + int ret; + + i3c_bus_maintenance_lock(&master->bus); + ret = i3c_master_send_ccc_cmd_locked(master, cmd); + i3c_bus_maintenance_unlock(&master->bus); + + return ret; +} +EXPORT_SYMBOL_GPL(i3c_master_send_ccc_cmd); + /** * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment) * @master: master doing the DAAdiff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 58d01ed4cce7..b059da7777d7 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h@@ -602,6 +602,17 @@ void i3c_master_dma_unmap_single(struct i3c_dma *dma_xfer); DEFINE_FREE(i3c_master_dma_unmap_single, void *, if (_T) i3c_master_dma_unmap_single(_T)) +int i3c_master_send_ccc_cmd(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd); + +int i3c_master_supports_ccc_cmd(struct i3c_master_controller *master, + const struct i3c_ccc_cmd *cmd); + +int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, + u8 old_dyn_addr); +int i3c_master_direct_attach_i3c_dev(struct i3c_master_controller *master, + struct i3c_dev_desc *dev); +void i3c_master_direct_detach_i3c_dev(struct i3c_dev_desc *dev); int i3c_master_set_info(struct i3c_master_controller *master, const struct i3c_device_info *info); --2.25.1