]> www.infradead.org Git - users/willy/xarray.git/commitdiff
usb: typec: altmodes/displayport: add irq_hpd to sysfs
authorRD Babiera <rdbabiera@google.com>
Mon, 23 Jun 2025 20:49:45 +0000 (20:49 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Jun 2025 14:39:58 +0000 (15:39 +0100)
Add irq_hpd sysfs node to displayport driver. This allows the userspace
to subscribe to irq events similar to how it can subscribe to changes in
hpd.

irq_hpd is read only and returns the number of irq events generated since
driver probe. pending_irq_hpd is added so that a sysfs_emit can be
generated if the HPD high event belonging to the same status message
is delayed until a successful configuration.

Signed-off-by: RD Babiera <rdbabiera@google.com>
Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20250623204947.732915-2-rdbabiera@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-driver-typec-displayport
drivers/usb/typec/altmodes/displayport.c

index 256c87c5219a69b55ab9c7e70fad0b6512fb6100..314acd54e13e4c63be0d590ee3672daab00c055f 100644 (file)
@@ -62,3 +62,13 @@ Description:
                             by VESA DisplayPort Alt Mode on USB Type-C Standard.
                        - 0 when HPD’s logical state is low (HPD_Low) as defined by
                             VESA DisplayPort Alt Mode on USB Type-C Standard.
+
+What:          /sys/bus/typec/devices/.../displayport/irq_hpd
+Date:          June 2025
+Contact:       RD Babiera <rdbabiera@google.com>
+Description:
+               IRQ_HPD events are sent over the USB PD protocol in Status Update and
+               Attention messages. IRQ_HPD can only be asserted when HPD is high,
+               and is asserted when an IRQ_HPD has been issued since the last Status
+               Update. This is a read only node that returns the number of IRQ events
+               raised in the driver's lifetime.
index b09b58d7311de9003a0d2eff901da5d720cfab5d..7f9f1f98f45022b7151591043d4ae6e268843f1c 100644 (file)
@@ -65,6 +65,13 @@ struct dp_altmode {
        enum dp_state state;
        bool hpd;
        bool pending_hpd;
+       u32 irq_hpd_count;
+       /*
+        * hpd is mandatory for irq_hpd assertion, so irq_hpd also needs its own pending flag if
+        * both hpd and irq_hpd are asserted in the first Status Update before the pin assignment
+        * is configured.
+        */
+       bool pending_irq_hpd;
 
        struct mutex lock; /* device lock */
        struct work_struct work;
@@ -151,6 +158,7 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
 {
        bool configured = !!DP_CONF_GET_PIN_ASSIGN(dp->data.conf);
        bool hpd = !!(dp->data.status & DP_STATUS_HPD_STATE);
+       bool irq_hpd = !!(dp->data.status & DP_STATUS_IRQ_HPD);
        u8 con = DP_STATUS_CONNECTION(dp->data.status);
        int ret = 0;
 
@@ -170,6 +178,8 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
                                dp->hpd = hpd;
                                dp->pending_hpd = true;
                        }
+                       if (dp->hpd && dp->pending_hpd && irq_hpd)
+                               dp->pending_irq_hpd = true;
                }
        } else {
                drm_connector_oob_hotplug_event(dp->connector_fwnode,
@@ -177,6 +187,10 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
                                                      connector_status_disconnected);
                dp->hpd = hpd;
                sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
+               if (hpd && irq_hpd) {
+                       dp->irq_hpd_count++;
+                       sysfs_notify(&dp->alt->dev.kobj, "displayport", "irq_hpd");
+               }
        }
 
        return ret;
@@ -196,6 +210,11 @@ static int dp_altmode_configured(struct dp_altmode *dp)
                                                connector_status_connected);
                sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
                dp->pending_hpd = false;
+               if (dp->pending_irq_hpd) {
+                       dp->irq_hpd_count++;
+                       sysfs_notify(&dp->alt->dev.kobj, "displayport", "irq_hpd");
+                       dp->pending_irq_hpd = false;
+               }
        }
 
        return dp_altmode_notify(dp);
@@ -707,10 +726,19 @@ static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char
 }
 static DEVICE_ATTR_RO(hpd);
 
+static ssize_t irq_hpd_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct dp_altmode *dp = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%d\n", dp->irq_hpd_count);
+}
+static DEVICE_ATTR_RO(irq_hpd);
+
 static struct attribute *displayport_attrs[] = {
        &dev_attr_configuration.attr,
        &dev_attr_pin_assignment.attr,
        &dev_attr_hpd.attr,
+       &dev_attr_irq_hpd.attr,
        NULL
 };