summaryrefslogtreecommitdiff
path: root/drivers/usb/typec
diff options
context:
space:
mode:
authorRD Babiera <rdbabiera@google.com>2025-06-23 20:49:45 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-06-24 15:39:58 +0100
commit8b4f6fafed6cd9a36716dd4846f27cc543f52303 (patch)
treecc1afba0aa93b7128de8a889010a56048fa21a7f /drivers/usb/typec
parent9962d0433a86c7d1222206dff1f8eafaab6faafa (diff)
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>
Diffstat (limited to 'drivers/usb/typec')
-rw-r--r--drivers/usb/typec/altmodes/displayport.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
index b09b58d7311d..7f9f1f98f450 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -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
};