When ACPI table includes _PLD field for a Type C connector, share _PLD values in its sysfs. _PLD stands for physical location of device. Currently without connector's location information, when there are multiple Type C ports, it is hard to distinguish which connector corresponds to which physical port at which location. For example, when there are two Type C connectors, it is hard to find out which connector corresponds to the Type C port on the left panel versus the Type C port on the right panel. With location information provided, we can determine which specific device at which location is doing what. _PLD output includes much more fields, but only generic fields are added and exposed to sysfs, so that non-ACPI devices can also support it in the future. The minimal generic fields needed for locating a port are the following. - panel - horizontal_position - vertical_position - dock - lid Signed-off-by: Won Chung <wonchung@xxxxxxxxxx> --- Documentation/ABI/testing/sysfs-class-typec | 43 +++++++++++++++++ drivers/usb/typec/class.c | 52 +++++++++++++++++++++ drivers/usb/typec/class.h | 3 ++ 3 files changed, 98 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec index 75088ecad202..2879bc6e6ad2 100644 --- a/Documentation/ABI/testing/sysfs-class-typec +++ b/Documentation/ABI/testing/sysfs-class-typec @@ -141,6 +141,49 @@ Description: - "reverse": CC2 orientation - "unknown": Orientation cannot be determined. +What: /sys/class/typec/<port>/location/panel +Date: February 2022 +Contact: Won Chung <wonchung@xxxxxxxxxx> +Description: + Describes which panel surface of the system’s housing the + Type C port resides on: + 0 - Top + 1 - Bottom + 2 - Left + 3 - Right + 4 - Front + 5 - Back + 6 - Unknown (Vertical Position and Horizontal Position will be + ignored) + +What: /sys/class/typec/<port>/location/vertical_position +Date: February 2022 +Contact: Won Chung <wonchung@xxxxxxxxxx> +Description: + 0 - Upper + 1 - Center + 2 - Lower + +What: /sys/class/typec/<port>/location/horizontal_position +Date: Feb, 2022 +Contact: Won Chung <wonchung@xxxxxxxxxx> +Description: + 0 - Left + 1 - Center + 2 - Right + +What: /sys/class/typec/<port>/location/dock +Date: Feb, 2022 +Contact: Won Chung <wonchung@xxxxxxxxxx> +Description: + Set if the port resides in a docking station or a port replicator. + +What: /sys/class/typec/<port>/location/lid +Date: Feb, 2022 +Contact: Won Chung <wonchung@xxxxxxxxxx> +Description: + Set if the port resides on the lid of laptop system. + USB Type-C partner devices (eg. /sys/class/typec/port0-partner/) What: /sys/class/typec/<port>-partner/accessory_mode diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 45a6f0c807cb..43b23c221f95 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1579,8 +1579,40 @@ static const struct attribute_group typec_group = { .attrs = typec_attrs, }; +#define DEV_ATTR_LOCATION_PROP(prop) \ + static ssize_t prop##_show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ + { \ + struct typec_port *port = to_typec_port(dev); \ + if (port->pld) \ + return sprintf(buf, "%u\n", port->pld->prop); \ + return 0; \ + }; \ +static DEVICE_ATTR_RO(prop) + +DEV_ATTR_LOCATION_PROP(panel); +DEV_ATTR_LOCATION_PROP(vertical_position); +DEV_ATTR_LOCATION_PROP(horizontal_position); +DEV_ATTR_LOCATION_PROP(dock); +DEV_ATTR_LOCATION_PROP(lid); + +static struct attribute *typec_location_attrs[] = { + &dev_attr_panel.attr, + &dev_attr_vertical_position.attr, + &dev_attr_horizontal_position.attr, + &dev_attr_dock.attr, + &dev_attr_lid.attr, + NULL, +}; + +static const struct attribute_group typec_location_group = { + .name = "location", + .attrs = typec_location_attrs, +}; + static const struct attribute_group *typec_groups[] = { &typec_group, + &typec_location_group, NULL }; @@ -1614,6 +1646,24 @@ const struct device_type typec_port_dev_type = { .release = typec_release, }; +void *get_pld(struct device *dev) +{ +#ifdef CONFIG_ACPI + struct acpi_pld_info *pld; + acpi_status status; + + if (!has_acpi_companion(dev)) + return NULL; + + status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld); + if (ACPI_FAILURE(status)) + return NULL; + return pld; +#else + return NULL; +#endif +} + /* --------------------------------------- */ /* Driver callbacks to report role updates */ @@ -2073,6 +2123,8 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_PTR(ret); } + port->pld = get_pld(&port->dev); + ret = device_add(&port->dev); if (ret) { dev_err(parent, "failed to register port (%d)\n", ret); diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index 0f1bd6d19d67..1b52633400c8 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -3,6 +3,7 @@ #ifndef __USB_TYPEC_CLASS__ #define __USB_TYPEC_CLASS__ +#include <linux/acpi.h> #include <linux/device.h> #include <linux/usb/typec.h> @@ -54,6 +55,8 @@ struct typec_port { const struct typec_capability *cap; const struct typec_operations *ops; + + struct acpi_pld_info *pld; }; #define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev) -- 2.35.1.574.g5d30c73bfb-goog