]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
i3c: add sysfs entry and attribute for Device NACK Retry count
authorAdrian Ng Ho Yin <adrianhoyin.ng@altera.com>
Fri, 12 Dec 2025 09:02:55 +0000 (17:02 +0800)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Tue, 13 Jan 2026 17:26:47 +0000 (18:26 +0100)
Document sysfs attribute dev_nack_retry_cnt that controls the number of
automatic retries performed by the I3C controller when a target device
returns a NACK

Add a `dev_nack_retry_count` sysfs attribute to allow reading and updating
the device NACK retry count. A new `dev_nack_retry_count` field and an
optional `set_dev_nack_retry()` callback are added to
i3c_master_controller. The attribute is created only when the callback is
implemented.

Updates are applied under the I3C bus maintenance lock to ensure safe
hardware reconfiguration.

Signed-off-by: Adrian Ng Ho Yin <adrianhoyin.ng@altera.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/3c4b5082bde64024fc383c44bebeef89ad3c7ed3.1765529948.git.adrianhoyin.ng@altera.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Documentation/ABI/testing/sysfs-bus-i3c
drivers/i3c/master.c
include/linux/i3c/master.h

index c812ab180ff40cc7f3b3453d266d7425fcdfbc19..c1e048957a0103dc6e76f8b607a48e98d61419d7 100644 (file)
@@ -161,3 +161,14 @@ Contact:   linux-i3c@vger.kernel.org
 Description:
                These directories are just symbolic links to
                /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>.
+
+What:          /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>/dev_nack_retry_count
+KernelVersion:  6.18
+Contact:       linux-i3c@vger.kernel.org
+Description:
+               Expose the dev_nak_retry_count which controls the number of
+               automatic retries that will be performed by the controller when
+               the target device returns a NACK response. A value of 0 disables
+               the automatic retries. Exist only when I3C constroller supports
+               this retry on nack feature.
+
index 7f606c8716480cea86e8ad1280e215772a7859cd..5e37ccc758e47e18f48823f94ea992ed5bbd092b 100644 (file)
@@ -683,6 +683,39 @@ static ssize_t hotjoin_show(struct device *dev, struct device_attribute *da, cha
 
 static DEVICE_ATTR_RW(hotjoin);
 
+static ssize_t dev_nack_retry_count_show(struct device *dev,
+                                        struct device_attribute *attr, char *buf)
+{
+       return sysfs_emit(buf, "%u\n", dev_to_i3cmaster(dev)->dev_nack_retry_count);
+}
+
+static ssize_t dev_nack_retry_count_store(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
+{
+       struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
+       struct i3c_master_controller *master = dev_to_i3cmaster(dev);
+       unsigned long val;
+       int ret;
+
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       i3c_bus_maintenance_lock(i3cbus);
+       ret = master->ops->set_dev_nack_retry(master, val);
+       i3c_bus_maintenance_unlock(i3cbus);
+
+       if (ret)
+               return ret;
+
+       master->dev_nack_retry_count = val;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(dev_nack_retry_count);
+
 static struct attribute *i3c_masterdev_attrs[] = {
        &dev_attr_mode.attr,
        &dev_attr_current_master.attr,
@@ -2959,6 +2992,9 @@ int i3c_master_register(struct i3c_master_controller *master,
        i3c_master_register_new_i3c_devs(master);
        i3c_bus_normaluse_unlock(&master->bus);
 
+       if (master->ops->set_dev_nack_retry)
+               device_create_file(&master->dev, &dev_attr_dev_nack_retry_count);
+
        return 0;
 
 err_del_dev:
@@ -2984,6 +3020,9 @@ void i3c_master_unregister(struct i3c_master_controller *master)
 {
        i3c_bus_notify(&master->bus, I3C_NOTIFY_BUS_REMOVE);
 
+       if (master->ops->set_dev_nack_retry)
+               device_remove_file(&master->dev, &dev_attr_dev_nack_retry_count);
+
        i3c_master_i2c_adapter_cleanup(master);
        i3c_master_unregister_i3c_devs(master);
        i3c_master_bus_cleanup(master);
index 58d01ed4cce759cce4b2481630959f2b06d370f7..d231c4fbc58b855de8ec86581216f706cc65cbd2 100644 (file)
@@ -462,6 +462,8 @@ struct i3c_bus {
  * @enable_hotjoin: enable hot join event detect.
  * @disable_hotjoin: disable hot join event detect.
  * @set_speed: adjust I3C open drain mode timing.
+ * @set_dev_nack_retry: configure device NACK retry count for the master
+ *                      controller.
  */
 struct i3c_master_controller_ops {
        int (*bus_init)(struct i3c_master_controller *master);
@@ -491,6 +493,8 @@ struct i3c_master_controller_ops {
        int (*enable_hotjoin)(struct i3c_master_controller *master);
        int (*disable_hotjoin)(struct i3c_master_controller *master);
        int (*set_speed)(struct i3c_master_controller *master, enum i3c_open_drain_speed speed);
+       int (*set_dev_nack_retry)(struct i3c_master_controller *master,
+                                 unsigned long dev_nack_retry_cnt);
 };
 
 /**
@@ -514,6 +518,7 @@ struct i3c_master_controller_ops {
  *     in a thread context. Typical examples are Hot Join processing which
  *     requires taking the bus lock in maintenance, which in turn, can only
  *     be done from a sleep-able context
+ * @dev_nack_retry_count: retry count when slave device nack
  *
  * A &struct i3c_master_controller has to be registered to the I3C subsystem
  * through i3c_master_register(). None of &struct i3c_master_controller fields
@@ -534,6 +539,7 @@ struct i3c_master_controller {
        } boardinfo;
        struct i3c_bus bus;
        struct workqueue_struct *wq;
+       unsigned int dev_nack_retry_count;
 };
 
 /**