FILE
port-mapper.c
File preview with syntax highlighting.
linux-6.19.14/drivers/usb/typec/port-mapper.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.