clk: uniphier: Fix fixed-rate initialization
[linux-2.6-microblaze.git] / 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
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         bus_for_each_dev(&acpi_bus_type, NULL, &arg, typec_port_match);
60
61         /*
62          * REVISIT: Now each connector can have only a single component master.
63          * So far only the USB ports connected to the USB Type-C connector share
64          * the _PLD with it, but if there one day is something else (like maybe
65          * the DisplayPort ACPI device object) that also shares the _PLD with
66          * the connector, every one of those needs to have its own component
67          * master, because each different type of component needs to be bind to
68          * the connector independently of the other components. That requires
69          * improvements to the component framework. Right now you can only have
70          * one master per device.
71          */
72         return component_master_add_with_match(&con->dev, &typec_aggregate_ops, arg.match);
73 }
74
75 void typec_unlink_ports(struct typec_port *con)
76 {
77         component_master_del(&con->dev, &typec_aggregate_ops);
78 }