Skip to content

Commit 730b49a

Browse files
Heikki Krogerusgregkh
authored andcommitted
usb: typec: port-mapper: Convert to the component framework
Instead of trying to keep track of the connections to the USB Type-C connectors separately, letting the component framework take care of that. From now on every USB Type-C connector will register itself as "aggregate" - component master - and anything that can be connected to it inside the system can then simply register itself as a generic component. The matching of the components and the connector shall rely on ACPI _PLD initially. Before registering itself as the aggregate, the connector will find all other ACPI devices that have matching _PLD crc hash with it (matching value in the pld_crc member of struct acpi_device), and add a component match entry for each one of them. Because only ACPI is supported for now, the driver shall only be build when ACPI is supported. This removes the need for the custom API that the driver exposed. The components and the connector can therefore exist completely independently of each other. The order in which they are registered, as well as are they modules or not, is now irrelevant. Acked-by: Rafael J. Wysocki <[email protected]> Signed-off-by: Heikki Krogerus <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8c67d06 commit 730b49a

File tree

5 files changed

+46
-260
lines changed

5 files changed

+46
-260
lines changed

drivers/usb/typec/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22
obj-$(CONFIG_TYPEC) += typec.o
3-
typec-y := class.o mux.o bus.o port-mapper.o
3+
typec-y := class.o mux.o bus.o
4+
typec-$(CONFIG_ACPI) += port-mapper.o
45
obj-$(CONFIG_TYPEC) += altmodes/
56
obj-$(CONFIG_TYPEC_TCPM) += tcpm/
67
obj-$(CONFIG_TYPEC_UCSI) += ucsi/

drivers/usb/typec/class.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,8 +2039,6 @@ struct typec_port *typec_register_port(struct device *parent,
20392039

20402040
ida_init(&port->mode_ids);
20412041
mutex_init(&port->port_type_lock);
2042-
mutex_init(&port->port_list_lock);
2043-
INIT_LIST_HEAD(&port->port_list);
20442042

20452043
port->id = id;
20462044
port->ops = cap->ops;

drivers/usb/typec/class.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,6 @@ struct typec_port {
5454

5555
const struct typec_capability *cap;
5656
const struct typec_operations *ops;
57-
58-
struct list_head port_list;
59-
struct mutex port_list_lock; /* Port list lock */
60-
61-
void *pld;
6257
};
6358

6459
#define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
@@ -79,7 +74,12 @@ extern const struct device_type typec_port_dev_type;
7974
extern struct class typec_mux_class;
8075
extern struct class typec_class;
8176

77+
#if defined(CONFIG_ACPI)
8278
int typec_link_ports(struct typec_port *connector);
8379
void typec_unlink_ports(struct typec_port *connector);
80+
#else
81+
static inline int typec_link_ports(struct typec_port *connector) { return 0; }
82+
static inline void typec_unlink_ports(struct typec_port *connector) { }
83+
#endif
8484

8585
#endif /* __USB_TYPEC_CLASS__ */

drivers/usb/typec/port-mapper.c

Lines changed: 39 additions & 240 deletions
Original file line numberDiff line numberDiff line change
@@ -7,273 +7,72 @@
77
*/
88

99
#include <linux/acpi.h>
10-
#include <linux/usb.h>
11-
#include <linux/usb/typec.h>
10+
#include <linux/component.h>
1211

1312
#include "class.h"
1413

15-
struct port_node {
16-
struct list_head list;
17-
struct device *dev;
18-
void *pld;
19-
};
20-
21-
static int acpi_pld_match(const struct acpi_pld_info *pld1,
22-
const struct acpi_pld_info *pld2)
23-
{
24-
if (!pld1 || !pld2)
25-
return 0;
26-
27-
/*
28-
* To speed things up, first checking only the group_position. It seems
29-
* to often have the first unique value in the _PLD.
30-
*/
31-
if (pld1->group_position == pld2->group_position)
32-
return !memcmp(pld1, pld2, sizeof(struct acpi_pld_info));
33-
34-
return 0;
35-
}
36-
37-
static void *get_pld(struct device *dev)
14+
static int typec_aggregate_bind(struct device *dev)
3815
{
39-
#ifdef CONFIG_ACPI
40-
struct acpi_pld_info *pld;
41-
acpi_status status;
42-
43-
if (!has_acpi_companion(dev))
44-
return NULL;
45-
46-
status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld);
47-
if (ACPI_FAILURE(status))
48-
return NULL;
49-
50-
return pld;
51-
#else
52-
return NULL;
53-
#endif
54-
}
55-
56-
static void free_pld(void *pld)
57-
{
58-
#ifdef CONFIG_ACPI
59-
ACPI_FREE(pld);
60-
#endif
16+
return component_bind_all(dev, NULL);
6117
}
6218

63-
static int __link_port(struct typec_port *con, struct port_node *node)
19+
static void typec_aggregate_unbind(struct device *dev)
6420
{
65-
int ret;
66-
67-
ret = sysfs_create_link(&node->dev->kobj, &con->dev.kobj, "connector");
68-
if (ret)
69-
return ret;
70-
71-
ret = sysfs_create_link(&con->dev.kobj, &node->dev->kobj,
72-
dev_name(node->dev));
73-
if (ret) {
74-
sysfs_remove_link(&node->dev->kobj, "connector");
75-
return ret;
76-
}
77-
78-
list_add_tail(&node->list, &con->port_list);
79-
80-
return 0;
21+
component_unbind_all(dev, NULL);
8122
}
8223

83-
static int link_port(struct typec_port *con, struct port_node *node)
84-
{
85-
int ret;
86-
87-
mutex_lock(&con->port_list_lock);
88-
ret = __link_port(con, node);
89-
mutex_unlock(&con->port_list_lock);
90-
91-
return ret;
92-
}
93-
94-
static void __unlink_port(struct typec_port *con, struct port_node *node)
95-
{
96-
sysfs_remove_link(&con->dev.kobj, dev_name(node->dev));
97-
sysfs_remove_link(&node->dev->kobj, "connector");
98-
list_del(&node->list);
99-
}
100-
101-
static void unlink_port(struct typec_port *con, struct port_node *node)
102-
{
103-
mutex_lock(&con->port_list_lock);
104-
__unlink_port(con, node);
105-
mutex_unlock(&con->port_list_lock);
106-
}
107-
108-
static struct port_node *create_port_node(struct device *port)
109-
{
110-
struct port_node *node;
111-
112-
node = kzalloc(sizeof(*node), GFP_KERNEL);
113-
if (!node)
114-
return ERR_PTR(-ENOMEM);
115-
116-
node->dev = get_device(port);
117-
node->pld = get_pld(port);
118-
119-
return node;
120-
}
121-
122-
static void remove_port_node(struct port_node *node)
123-
{
124-
put_device(node->dev);
125-
free_pld(node->pld);
126-
kfree(node);
127-
}
128-
129-
static int connector_match(struct device *dev, const void *data)
130-
{
131-
const struct port_node *node = data;
132-
133-
if (!is_typec_port(dev))
134-
return 0;
135-
136-
return acpi_pld_match(to_typec_port(dev)->pld, node->pld);
137-
}
138-
139-
static struct device *find_connector(struct port_node *node)
140-
{
141-
if (!node->pld)
142-
return NULL;
143-
144-
return class_find_device(&typec_class, NULL, node, connector_match);
145-
}
146-
147-
/**
148-
* typec_link_port - Link a port to its connector
149-
* @port: The port device
150-
*
151-
* Find the connector of @port and create symlink named "connector" for it.
152-
* Returns 0 on success, or errno in case of a failure.
153-
*
154-
* NOTE. The function increments the reference count of @port on success.
155-
*/
156-
int typec_link_port(struct device *port)
157-
{
158-
struct device *connector;
159-
struct port_node *node;
160-
int ret;
161-
162-
node = create_port_node(port);
163-
if (IS_ERR(node))
164-
return PTR_ERR(node);
165-
166-
connector = find_connector(node);
167-
if (!connector) {
168-
ret = 0;
169-
goto remove_node;
170-
}
171-
172-
ret = link_port(to_typec_port(connector), node);
173-
if (ret)
174-
goto put_connector;
175-
176-
return 0;
177-
178-
put_connector:
179-
put_device(connector);
180-
remove_node:
181-
remove_port_node(node);
182-
183-
return ret;
184-
}
185-
EXPORT_SYMBOL_GPL(typec_link_port);
186-
187-
static int port_match_and_unlink(struct device *connector, void *port)
188-
{
189-
struct port_node *node;
190-
struct port_node *tmp;
191-
int ret = 0;
192-
193-
if (!is_typec_port(connector))
194-
return 0;
195-
196-
mutex_lock(&to_typec_port(connector)->port_list_lock);
197-
list_for_each_entry_safe(node, tmp, &to_typec_port(connector)->port_list, list) {
198-
ret = node->dev == port;
199-
if (ret) {
200-
unlink_port(to_typec_port(connector), node);
201-
remove_port_node(node);
202-
put_device(connector);
203-
break;
204-
}
205-
}
206-
mutex_unlock(&to_typec_port(connector)->port_list_lock);
24+
static const struct component_master_ops typec_aggregate_ops = {
25+
.bind = typec_aggregate_bind,
26+
.unbind = typec_aggregate_unbind,
27+
};
20728

208-
return ret;
209-
}
29+
struct each_port_arg {
30+
struct typec_port *port;
31+
struct component_match *match;
32+
};
21033

211-
/**
212-
* typec_unlink_port - Unlink port from its connector
213-
* @port: The port device
214-
*
215-
* Removes the symlink "connector" and decrements the reference count of @port.
216-
*/
217-
void typec_unlink_port(struct device *port)
34+
static int typec_port_compare(struct device *dev, void *fwnode)
21835
{
219-
class_for_each_device(&typec_class, NULL, port, port_match_and_unlink);
36+
return device_match_fwnode(dev, fwnode);
22037
}
221-
EXPORT_SYMBOL_GPL(typec_unlink_port);
22238

223-
static int each_port(struct device *port, void *connector)
39+
static int typec_port_match(struct device *dev, void *data)
22440
{
225-
struct port_node *node;
226-
int ret;
227-
228-
node = create_port_node(port);
229-
if (IS_ERR(node))
230-
return PTR_ERR(node);
41+
struct acpi_device *adev = to_acpi_device(dev);
42+
struct each_port_arg *arg = data;
43+
struct acpi_device *con_adev;
23144

232-
if (!connector_match(connector, node)) {
233-
remove_port_node(node);
45+
con_adev = ACPI_COMPANION(&arg->port->dev);
46+
if (con_adev == adev)
23447
return 0;
235-
}
236-
237-
ret = link_port(to_typec_port(connector), node);
238-
if (ret) {
239-
remove_port_node(node->pld);
240-
return ret;
241-
}
242-
243-
get_device(connector);
24448

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));
24552
return 0;
24653
}
24754

24855
int typec_link_ports(struct typec_port *con)
24956
{
250-
int ret = 0;
57+
struct each_port_arg arg = { .port = con, .match = NULL };
25158

252-
con->pld = get_pld(&con->dev);
253-
if (!con->pld)
254-
return 0;
59+
bus_for_each_dev(&acpi_bus_type, NULL, &arg, typec_port_match);
25560

256-
ret = usb_for_each_port(&con->dev, each_port);
257-
if (ret)
258-
typec_unlink_ports(con);
259-
260-
return ret;
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);
26173
}
26274

26375
void typec_unlink_ports(struct typec_port *con)
26476
{
265-
struct port_node *node;
266-
struct port_node *tmp;
267-
268-
mutex_lock(&con->port_list_lock);
269-
270-
list_for_each_entry_safe(node, tmp, &con->port_list, list) {
271-
__unlink_port(con, node);
272-
remove_port_node(node);
273-
put_device(&con->dev);
274-
}
275-
276-
mutex_unlock(&con->port_list_lock);
277-
278-
free_pld(con->pld);
77+
component_master_del(&con->dev, &typec_aggregate_ops);
27978
}

include/linux/usb/typec.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -305,16 +305,4 @@ void typec_partner_set_svdm_version(struct typec_partner *partner,
305305
enum usb_pd_svdm_ver svdm_version);
306306
int typec_get_negotiated_svdm_version(struct typec_port *port);
307307

308-
#if IS_REACHABLE(CONFIG_TYPEC)
309-
int typec_link_port(struct device *port);
310-
void typec_unlink_port(struct device *port);
311-
#else
312-
static inline int typec_link_port(struct device *port)
313-
{
314-
return 0;
315-
}
316-
317-
static inline void typec_unlink_port(struct device *port) { }
318-
#endif
319-
320308
#endif /* __LINUX_USB_TYPEC_H */

0 commit comments

Comments
 (0)