[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260113140430.207990-3-heikki.krogerus@linux.intel.com>
Date: Tue, 13 Jan 2026 15:04:28 +0100
From: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
To: Wolfram Sang <wsa+renesas@...g-engineering.com>
Cc: Jeremy Kerr <jk@...econstruct.com.au>,
Matt Johnston <matt@...econstruct.com.au>,
linux-i2c@...r.kernel.org,
netdev@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH v1 2/4] i2c: Sysfs attribute files for the Unique Device Identifier fields
In order to utilise the SMBus Address Resolution Protocol's
(ARP) Unique Device Identifier (UDID) also in user space,
the UDID details need to be exposed. With ARP the address is
also dynamically assigned (and may be reset) so it also
needs to be exposed to the user space with its own file.
The UDID details are only visible with ARP devices, but the
address file is made always visible for all I2C client
devices.
Signed-off-by: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
---
Documentation/ABI/testing/sysfs-bus-i2c | 53 ++++++++++++
drivers/i2c/i2c-core-base.c | 107 +++++++++++++++++++++++-
2 files changed, 159 insertions(+), 1 deletion(-)
create mode 100644 Documentation/ABI/testing/sysfs-bus-i2c
diff --git a/Documentation/ABI/testing/sysfs-bus-i2c b/Documentation/ABI/testing/sysfs-bus-i2c
new file mode 100644
index 000000000000..b9ebfc2e1b9d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-i2c
@@ -0,0 +1,53 @@
+What: /sys/bus/i2c/devices/.../address
+Date: September 2025
+Contact: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
+Description:
+ This file has the target address the I2C client responds to.
+
+What: /sys/bus/i2c/devices/.../vendor
+Date: September 2025
+Contact: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
+Description:
+ This file is only visible for ARP devices. It returns the Vendor
+ ID field from the SMBus ARP Unique Device Identifier. It is the
+ device manufacturer's ID assigned by the SBS Implementers Forum
+ or the PCI SIG.
+
+What: /sys/bus/i2c/devices/.../device
+Date: September 2025
+Contact: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
+Description:
+ This file is only visible for ARP devices. It returns the Device
+ ID field from the SMBus ARP Unique Device Identifier. The
+ device ID is assigned by the device manufacturer.
+
+What: /sys/bus/i2c/devices/.../interface
+Date: September 2025
+Contact: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
+Description:
+ This file is only visible for ARP devices. It returns the
+ Interface field from the SMBus ARP Unique Device Identifier.
+
+What: /sys/bus/i2c/devices/.../subsystem_vendor
+Date: September 2025
+Contact: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
+Description:
+ This file is only visible for ARP devices. It returns the
+ Subsystem Vendor ID field from the SMBus ARP Unique Device
+ Identifier.
+
+What: /sys/bus/i2c/devices/.../subsystem_device
+Date: September 2025
+Contact: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
+Description:
+ This file is only visible for ARP devices. It returns the
+ Subsystem Device ID field from the SMBus ARP Unique Device
+ Identifier.
+
+What: /sys/bus/i2c/devices/.../vendor_specific_id
+Date: September 2025
+Contact: Heikki Krogerus <heikki.krogerus@...ux.intel.com>
+Description:
+ This file is only visible for ARP devices. It returns the
+ Vendor Specific ID field from the SMBus ARP Unique Device
+ Identifier.
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 2e61f1be8de6..6a3452a25972 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -685,6 +685,13 @@ name_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR_RO(name);
+static ssize_t
+address_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "0x%02x\n", to_i2c_client(dev)->addr);
+}
+static DEVICE_ATTR_RO(address);
+
static ssize_t
modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -712,11 +719,109 @@ static DEVICE_ATTR_RO(modalias);
static struct attribute *i2c_dev_attrs[] = {
&dev_attr_name.attr,
+ &dev_attr_address.attr,
/* modalias helps coldplug: modprobe $(cat .../modalias) */
&dev_attr_modalias.attr,
NULL
};
-ATTRIBUTE_GROUPS(i2c_dev);
+
+static const struct attribute_group i2c_dev_group = {
+ .attrs = i2c_dev_attrs,
+};
+
+static ssize_t
+capabilities_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return sysfs_emit(buf, "0x%02x\n", client->udid->capabilities);
+}
+static DEVICE_ATTR_RO(capabilities);
+
+static ssize_t
+vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return sysfs_emit(buf, "0x%04x\n", client->udid->vendor);
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t
+device_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return sysfs_emit(buf, "0x%04x\n", client->udid->device);
+}
+static DEVICE_ATTR_RO(device);
+
+static ssize_t
+interface_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return sysfs_emit(buf, "0x%04x\n", client->udid->interface);
+}
+static DEVICE_ATTR_RO(interface);
+
+static ssize_t
+subsystem_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return sysfs_emit(buf, "0x%04x\n", client->udid->subvendor);
+}
+static DEVICE_ATTR_RO(subsystem_vendor);
+
+static ssize_t
+subsystem_device_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return sysfs_emit(buf, "0x%04x\n", client->udid->subdevice);
+}
+static DEVICE_ATTR_RO(subsystem_device);
+
+static ssize_t
+vendor_specific_id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return sysfs_emit(buf, "0x%08x\n", client->udid->vendor_specific_id);
+}
+static DEVICE_ATTR_RO(vendor_specific_id);
+
+static struct attribute *udid_attrs[] = {
+ &dev_attr_capabilities.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_device.attr,
+ &dev_attr_interface.attr,
+ &dev_attr_subsystem_vendor.attr,
+ &dev_attr_subsystem_device.attr,
+ &dev_attr_vendor_specific_id.attr,
+ NULL
+};
+
+static umode_t
+udid_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+ if (to_i2c_client(kobj_to_dev(kobj))->udid)
+ return attr->mode;
+
+ return 0;
+}
+
+static const struct attribute_group udid_group = {
+ .is_visible = udid_is_visible,
+ .attrs = udid_attrs,
+};
+
+static const struct attribute_group *i2c_dev_groups[] = {
+ &i2c_dev_group,
+ &udid_group,
+ NULL
+};
const struct bus_type i2c_bus_type = {
.name = "i2c",
--
2.50.1
Powered by blists - more mailing lists