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 12 #include "class.h" 13 14 static int typec_aggregate_bind(struct device *dev) 15 { 16 return component_bind_all(dev, NULL); 17 } 18 19 static void typec_aggregate_unbind(struct device *dev) 20 { 21 component_unbind_all(dev, NULL); 22 } 23 24 static const struct component_master_ops typec_aggregate_ops = { 25 .bind = typec_aggregate_bind, 26 .unbind = typec_aggregate_unbind, 27 }; 28 29 struct each_port_arg { 30 struct typec_port *port; 31 struct component_match *match; 32 }; 33 34 static int typec_port_compare(struct device *dev, void *fwnode) 35 { 36 return device_match_fwnode(dev, fwnode); 37 } 38 39 static int typec_port_match(struct device *dev, void *data) 40 { 41 struct acpi_device *adev = to_acpi_device(dev); 42 struct each_port_arg *arg = data; 43 struct acpi_device *con_adev; 44 45 con_adev = ACPI_COMPANION(&arg->port->dev); 46 if (con_adev == adev) 47 return 0; 48 49 if (con_adev->pld_crc == adev->pld_crc) 50 component_match_add(&arg->port->dev, &arg->match, typec_port_compare, 51 acpi_fwnode_handle(adev)); 52 return 0; 53 } 54 55 int typec_link_ports(struct typec_port *con) 56 { 57 struct each_port_arg arg = { .port = con, .match = NULL }; 58 59 if (!has_acpi_companion(&con->dev)) 60 return 0; 61 62 bus_for_each_dev(&acpi_bus_type, NULL, &arg, typec_port_match); 63 if (!arg.match) 64 return 0; 65 66 /* 67 * REVISIT: Now each connector can have only a single component master. 68 * So far only the USB ports connected to the USB Type-C connector share 69 * the _PLD with it, but if there one day is something else (like maybe 70 * the DisplayPort ACPI device object) that also shares the _PLD with 71 * the connector, every one of those needs to have its own component 72 * master, because each different type of component needs to be bind to 73 * the connector independently of the other components. That requires 74 * improvements to the component framework. Right now you can only have 75 * one master per device. 76 */ 77 return component_master_add_with_match(&con->dev, &typec_aggregate_ops, arg.match); 78 } 79 80 void typec_unlink_ports(struct typec_port *con) 81 { 82 if (has_acpi_companion(&con->dev)) 83 component_master_del(&con->dev, &typec_aggregate_ops); 84 } 85