diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
commit | 2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch) | |
tree | 848558de17fb3008cdf4d861b01ac7781903ce39 /drivers/usb/typec/port-mapper.c | |
parent | Initial commit. (diff) | |
download | linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.tar.xz linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.zip |
Adding upstream version 6.1.76.upstream/6.1.76upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/usb/typec/port-mapper.c')
-rw-r--r-- | drivers/usb/typec/port-mapper.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/drivers/usb/typec/port-mapper.c b/drivers/usb/typec/port-mapper.c new file mode 100644 index 000000000..a929e000d --- /dev/null +++ b/drivers/usb/typec/port-mapper.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * USB Type-C Connector Class Port Mapping Utility + * + * Copyright (C) 2021, Intel Corporation + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> + */ + +#include <linux/acpi.h> +#include <linux/component.h> + +#include "class.h" + +static int typec_aggregate_bind(struct device *dev) +{ + return component_bind_all(dev, NULL); +} + +static void typec_aggregate_unbind(struct device *dev) +{ + component_unbind_all(dev, NULL); +} + +static const struct component_master_ops typec_aggregate_ops = { + .bind = typec_aggregate_bind, + .unbind = typec_aggregate_unbind, +}; + +struct each_port_arg { + struct typec_port *port; + struct component_match *match; +}; + +static int typec_port_compare(struct device *dev, void *fwnode) +{ + return device_match_fwnode(dev, fwnode); +} + +static int typec_port_match(struct device *dev, void *data) +{ + struct acpi_device *adev = to_acpi_device(dev); + struct each_port_arg *arg = data; + struct acpi_device *con_adev; + + con_adev = ACPI_COMPANION(&arg->port->dev); + if (con_adev == adev) + return 0; + + if (con_adev->pld_crc == adev->pld_crc) + component_match_add(&arg->port->dev, &arg->match, typec_port_compare, + acpi_fwnode_handle(adev)); + return 0; +} + +int typec_link_ports(struct typec_port *con) +{ + struct each_port_arg arg = { .port = con, .match = NULL }; + + if (!has_acpi_companion(&con->dev)) + return 0; + + acpi_bus_for_each_dev(typec_port_match, &arg); + if (!arg.match) + return 0; + + /* + * REVISIT: Now each connector can have only a single component master. + * So far only the USB ports connected to the USB Type-C connector share + * the _PLD with it, but if there one day is something else (like maybe + * the DisplayPort ACPI device object) that also shares the _PLD with + * the connector, every one of those needs to have its own component + * master, because each different type of component needs to be bind to + * the connector independently of the other components. That requires + * improvements to the component framework. Right now you can only have + * one master per device. + */ + return component_master_add_with_match(&con->dev, &typec_aggregate_ops, arg.match); +} + +void typec_unlink_ports(struct typec_port *con) +{ + if (has_acpi_companion(&con->dev)) + component_master_del(&con->dev, &typec_aggregate_ops); +} |