platform/chrome: cros_ec_sysfs: Expose PD mux status
authorAndrei Kuchynski <akuchynski@chromium.org>
Mon, 3 Feb 2025 12:59:46 +0000 (12:59 +0000)
committerTzung-Bi Shih <tzungbi@kernel.org>
Wed, 5 Feb 2025 04:02:27 +0000 (04:02 +0000)
This adds sysfs attribute /sys/class/chromeos/cros_ec/usbpdmuxinfo
to expose the PD mux status for each Type-C port.
This allows user-space applications to easily determine
the current mux state without using ioctls.

Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
Link: https://lore.kernel.org/r/20250203125947.2701106-2-akuchynski@chromium.org
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Documentation/ABI/testing/sysfs-class-chromeos
drivers/platform/chrome/cros_ec_sysfs.c

index 74ece942722e71ec139f544f0701725f1125c68b..e067dbdab170a22b1259012fd1f74cd2ffa947da 100644 (file)
@@ -31,3 +31,16 @@ Date:                August 2015
 KernelVersion: 4.2
 Description:
                Show the information about the EC software and hardware.
+
+What:          /sys/class/chromeos/cros_ec/usbpdmuxinfo
+Date:          February 2025
+Description:
+               Show PD mux status for each typec port with following flags:
+               - "USB": USB connected
+               - "DP": DP connected
+               - "POLARITY": CC line Polarity inverted
+               - "HPD_IRQ": Hot Plug Detect interrupt is asserted
+               - "HPD_LVL": Hot Plug Detect level is asserted
+               - "SAFE": DP is in safe mode
+               - "TBT": TBT enabled
+               - "USB4": USB4 enabled
index bc1a5ba0952815755cd9abe9d8880650a69539d9..93e9ed87249cf449ca80895232350ea3c06ad113 100644 (file)
@@ -296,18 +296,69 @@ static ssize_t kb_wake_angle_store(struct device *dev,
        return count;
 }
 
+static ssize_t usbpdmuxinfo_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct cros_ec_dev *ec = to_cros_ec_dev(dev);
+       ssize_t count = 0;
+       struct ec_response_usb_pd_ports resp_pd_ports;
+       int ret;
+       int i;
+
+       ret = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
+                         &resp_pd_ports, sizeof(resp_pd_ports));
+       if (ret < 0)
+               return -EIO;
+
+       for (i = 0; i < resp_pd_ports.num_ports; i++) {
+               struct ec_response_usb_pd_mux_info resp_mux;
+               struct ec_params_usb_pd_mux_info req = {
+                       .port = i,
+               };
+
+               ret = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_USB_PD_MUX_INFO,
+                         &req, sizeof(req), &resp_mux, sizeof(resp_mux));
+
+               if (ret >= 0) {
+                       count += sysfs_emit_at(buf, count, "Port %d:", i);
+                       count += sysfs_emit_at(buf, count, " USB=%d",
+                                       !!(resp_mux.flags & USB_PD_MUX_USB_ENABLED));
+                       count += sysfs_emit_at(buf, count, " DP=%d",
+                                       !!(resp_mux.flags & USB_PD_MUX_DP_ENABLED));
+                       count += sysfs_emit_at(buf, count, " POLARITY=%s",
+                                       (resp_mux.flags & USB_PD_MUX_POLARITY_INVERTED) ?
+                                       "INVERTED" : "NORMAL");
+                       count += sysfs_emit_at(buf, count, " HPD_IRQ=%d",
+                                       !!(resp_mux.flags & USB_PD_MUX_HPD_IRQ));
+                       count += sysfs_emit_at(buf, count, " HPD_LVL=%d",
+                                       !!(resp_mux.flags & USB_PD_MUX_HPD_LVL));
+                       count += sysfs_emit_at(buf, count, " SAFE=%d",
+                                       !!(resp_mux.flags & USB_PD_MUX_SAFE_MODE));
+                       count += sysfs_emit_at(buf, count, " TBT=%d",
+                                       !!(resp_mux.flags & USB_PD_MUX_TBT_COMPAT_ENABLED));
+                       count += sysfs_emit_at(buf, count, " USB4=%d\n",
+                                       !!(resp_mux.flags & USB_PD_MUX_USB4_ENABLED));
+               }
+       }
+
+       return count ? : -EIO;
+}
+
 /* Module initialization */
 
 static DEVICE_ATTR_RW(reboot);
 static DEVICE_ATTR_RO(version);
 static DEVICE_ATTR_RO(flashinfo);
 static DEVICE_ATTR_RW(kb_wake_angle);
+static DEVICE_ATTR_RO(usbpdmuxinfo);
 
 static struct attribute *__ec_attrs[] = {
        &dev_attr_kb_wake_angle.attr,
        &dev_attr_reboot.attr,
        &dev_attr_version.attr,
        &dev_attr_flashinfo.attr,
+       &dev_attr_usbpdmuxinfo.attr,
        NULL,
 };
 
@@ -320,6 +371,13 @@ static umode_t cros_ec_ctrl_visible(struct kobject *kobj,
        if (a == &dev_attr_kb_wake_angle.attr && !ec->has_kb_wake_angle)
                return 0;
 
+       if (a == &dev_attr_usbpdmuxinfo.attr) {
+               struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
+
+               if (strcmp(ec_platform->ec_name, CROS_EC_DEV_NAME))
+                       return 0;
+       }
+
        return a->mode;
 }