Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: typec: altmodes/displayport: add irq_hpd to sysfs

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>

authored by

RD Babiera and committed by
Greg Kroah-Hartman
8b4f6faf 9962d043

+38
+10
Documentation/ABI/testing/sysfs-driver-typec-displayport
··· 62 62 by VESA DisplayPort Alt Mode on USB Type-C Standard. 63 63 - 0 when HPD’s logical state is low (HPD_Low) as defined by 64 64 VESA DisplayPort Alt Mode on USB Type-C Standard. 65 + 66 + What: /sys/bus/typec/devices/.../displayport/irq_hpd 67 + Date: June 2025 68 + Contact: RD Babiera <rdbabiera@google.com> 69 + Description: 70 + IRQ_HPD events are sent over the USB PD protocol in Status Update and 71 + Attention messages. IRQ_HPD can only be asserted when HPD is high, 72 + and is asserted when an IRQ_HPD has been issued since the last Status 73 + Update. This is a read only node that returns the number of IRQ events 74 + raised in the driver's lifetime.
+28
drivers/usb/typec/altmodes/displayport.c
··· 65 65 enum dp_state state; 66 66 bool hpd; 67 67 bool pending_hpd; 68 + u32 irq_hpd_count; 69 + /* 70 + * hpd is mandatory for irq_hpd assertion, so irq_hpd also needs its own pending flag if 71 + * both hpd and irq_hpd are asserted in the first Status Update before the pin assignment 72 + * is configured. 73 + */ 74 + bool pending_irq_hpd; 68 75 69 76 struct mutex lock; /* device lock */ 70 77 struct work_struct work; ··· 158 151 { 159 152 bool configured = !!DP_CONF_GET_PIN_ASSIGN(dp->data.conf); 160 153 bool hpd = !!(dp->data.status & DP_STATUS_HPD_STATE); 154 + bool irq_hpd = !!(dp->data.status & DP_STATUS_IRQ_HPD); 161 155 u8 con = DP_STATUS_CONNECTION(dp->data.status); 162 156 int ret = 0; 163 157 ··· 178 170 dp->hpd = hpd; 179 171 dp->pending_hpd = true; 180 172 } 173 + if (dp->hpd && dp->pending_hpd && irq_hpd) 174 + dp->pending_irq_hpd = true; 181 175 } 182 176 } else { 183 177 drm_connector_oob_hotplug_event(dp->connector_fwnode, ··· 187 177 connector_status_disconnected); 188 178 dp->hpd = hpd; 189 179 sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); 180 + if (hpd && irq_hpd) { 181 + dp->irq_hpd_count++; 182 + sysfs_notify(&dp->alt->dev.kobj, "displayport", "irq_hpd"); 183 + } 190 184 } 191 185 192 186 return ret; ··· 210 196 connector_status_connected); 211 197 sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); 212 198 dp->pending_hpd = false; 199 + if (dp->pending_irq_hpd) { 200 + dp->irq_hpd_count++; 201 + sysfs_notify(&dp->alt->dev.kobj, "displayport", "irq_hpd"); 202 + dp->pending_irq_hpd = false; 203 + } 213 204 } 214 205 215 206 return dp_altmode_notify(dp); ··· 726 707 } 727 708 static DEVICE_ATTR_RO(hpd); 728 709 710 + static ssize_t irq_hpd_show(struct device *dev, struct device_attribute *attr, char *buf) 711 + { 712 + struct dp_altmode *dp = dev_get_drvdata(dev); 713 + 714 + return sysfs_emit(buf, "%d\n", dp->irq_hpd_count); 715 + } 716 + static DEVICE_ATTR_RO(irq_hpd); 717 + 729 718 static struct attribute *displayport_attrs[] = { 730 719 &dev_attr_configuration.attr, 731 720 &dev_attr_pin_assignment.attr, 732 721 &dev_attr_hpd.attr, 722 + &dev_attr_irq_hpd.attr, 733 723 NULL 734 724 }; 735 725