File Index
Files and directories
Sign in
FILE

port-mapper.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/typec/port-mapper.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * USB Type-C Connector Class Port Mapping Utility
  4 *
  5 * Copyright (C) 2021, Intel Corporation
  6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
  7 */
  8
  9#include <linux/acpi.h>
 10#include <linux/component.h>
 11#include <linux/thunderbolt.h>
 12#include <linux/usb.h>
 13
 14#include "class.h"
 15
 16static int typec_aggregate_bind(struct device *dev)
 17{
 18	struct typec_port *port = to_typec_port(dev);
 19
 20	return component_bind_all(dev, &port->con);
 21}
 22
 23static void typec_aggregate_unbind(struct device *dev)
 24{
 25	struct typec_port *port = to_typec_port(dev);
 26
 27	component_unbind_all(dev, &port->con);
 28}
 29
 30static const struct component_master_ops typec_aggregate_ops = {
 31	.bind = typec_aggregate_bind,
 32	.unbind = typec_aggregate_unbind,
 33};
 34
 35struct each_port_arg {
 36	struct typec_port *port;
 37	struct component_match *match;
 38};
 39
 40static int usb4_port_compare(struct device *dev, void *fwnode)
 41{
 42	return usb4_usb3_port_match(dev, fwnode);
 43}
 44
 45static int typec_port_compare(struct device *dev, void *fwnode)
 46{
 47	return device_match_fwnode(dev, fwnode);
 48}
 49
 50static int typec_port_match(struct device *dev, void *data)
 51{
 52	struct acpi_device *adev = to_acpi_device(dev);
 53	struct each_port_arg *arg = data;
 54	struct acpi_device *con_adev;
 55
 56	con_adev = ACPI_COMPANION(&arg->port->dev);
 57	if (con_adev == adev)
 58		return 0;
 59
 60	if (con_adev->pld_crc == adev->pld_crc)	{
 61		struct fwnode_handle *adev_fwnode = acpi_fwnode_handle(adev);
 62
 63		component_match_add(&arg->port->dev, &arg->match, typec_port_compare,
 64				    adev_fwnode);
 65
 66		/*
 67		 * If dev is USB 3.x port, it may have reference to the
 68		 * USB4 host interface in which case we can also link the
 69		 * Type-C port with the USB4 port.
 70		 */
 71		if (fwnode_property_present(adev_fwnode, "usb4-host-interface"))
 72			component_match_add(&arg->port->dev, &arg->match,
 73					    usb4_port_compare, adev_fwnode);
 74	}
 75
 76	return 0;
 77}
 78
 79int typec_link_ports(struct typec_port *con)
 80{
 81	struct each_port_arg arg = { .port = con, .match = NULL };
 82
 83	if (!has_acpi_companion(&con->dev))
 84		return 0;
 85
 86	acpi_bus_for_each_dev(typec_port_match, &arg);
 87	if (!arg.match)
 88		return 0;
 89
 90	/*
 91	 * REVISIT: Now each connector can have only a single component master.
 92	 * So far only the USB ports connected to the USB Type-C connector share
 93	 * the _PLD with it, but if there one day is something else (like maybe
 94	 * the DisplayPort ACPI device object) that also shares the _PLD with
 95	 * the connector, every one of those needs to have its own component
 96	 * master, because each different type of component needs to be bind to
 97	 * the connector independently of the other components. That requires
 98	 * improvements to the component framework. Right now you can only have
 99	 * one master per device.
100	 */
101	return component_master_add_with_match(&con->dev, &typec_aggregate_ops, arg.match);
102}
103
104void typec_unlink_ports(struct typec_port *con)
105{
106	if (has_acpi_companion(&con->dev))
107		component_master_del(&con->dev, &typec_aggregate_ops);
108}
~/ Read-only file preview.