Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * USB Type-C Connector Class Port Mapping Utility
0004  *
0005  * Copyright (C) 2021, Intel Corporation
0006  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
0007  */
0008 
0009 #include <linux/acpi.h>
0010 #include <linux/component.h>
0011 
0012 #include "class.h"
0013 
0014 static int typec_aggregate_bind(struct device *dev)
0015 {
0016     return component_bind_all(dev, NULL);
0017 }
0018 
0019 static void typec_aggregate_unbind(struct device *dev)
0020 {
0021     component_unbind_all(dev, NULL);
0022 }
0023 
0024 static const struct component_master_ops typec_aggregate_ops = {
0025     .bind = typec_aggregate_bind,
0026     .unbind = typec_aggregate_unbind,
0027 };
0028 
0029 struct each_port_arg {
0030     struct typec_port *port;
0031     struct component_match *match;
0032 };
0033 
0034 static int typec_port_compare(struct device *dev, void *fwnode)
0035 {
0036     return device_match_fwnode(dev, fwnode);
0037 }
0038 
0039 static int typec_port_match(struct device *dev, void *data)
0040 {
0041     struct acpi_device *adev = to_acpi_device(dev);
0042     struct each_port_arg *arg = data;
0043     struct acpi_device *con_adev;
0044 
0045     con_adev = ACPI_COMPANION(&arg->port->dev);
0046     if (con_adev == adev)
0047         return 0;
0048 
0049     if (con_adev->pld_crc == adev->pld_crc)
0050         component_match_add(&arg->port->dev, &arg->match, typec_port_compare,
0051                     acpi_fwnode_handle(adev));
0052     return 0;
0053 }
0054 
0055 int typec_link_ports(struct typec_port *con)
0056 {
0057     struct each_port_arg arg = { .port = con, .match = NULL };
0058 
0059     if (!has_acpi_companion(&con->dev))
0060         return 0;
0061 
0062     acpi_bus_for_each_dev(typec_port_match, &arg);
0063     if (!arg.match)
0064         return 0;
0065 
0066     /*
0067      * REVISIT: Now each connector can have only a single component master.
0068      * So far only the USB ports connected to the USB Type-C connector share
0069      * the _PLD with it, but if there one day is something else (like maybe
0070      * the DisplayPort ACPI device object) that also shares the _PLD with
0071      * the connector, every one of those needs to have its own component
0072      * master, because each different type of component needs to be bind to
0073      * the connector independently of the other components. That requires
0074      * improvements to the component framework. Right now you can only have
0075      * one master per device.
0076      */
0077     return component_master_add_with_match(&con->dev, &typec_aggregate_ops, arg.match);
0078 }
0079 
0080 void typec_unlink_ports(struct typec_port *con)
0081 {
0082     if (has_acpi_companion(&con->dev))
0083         component_master_del(&con->dev, &typec_aggregate_ops);
0084 }