Commit e6a3215f authored by Andrei Kuchynski's avatar Andrei Kuchynski Committed by Tzung-Bi Shih
Browse files

platform/chrome: cros_ec_sysfs: Expose PD mux status



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: default avatarAndrei Kuchynski <akuchynski@chromium.org>
Link: https://lore.kernel.org/r/20250203125947.2701106-2-akuchynski@chromium.org


Signed-off-by: default avatarTzung-Bi Shih <tzungbi@kernel.org>
parent d83c45ae
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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
+58 −0
Original line number Diff line number Diff line
@@ -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;
}