1 // SPDX-License-Identifier: GPL-2.0
3 * USB Type-C Multiplexer/DeMultiplexer Switch support
5 * Copyright (C) 2018 Intel Corporation
10 #include <linux/device.h>
11 #include <linux/list.h>
12 #include <linux/mutex.h>
13 #include <linux/usb/typec_mux.h>
15 static DEFINE_MUTEX(switch_lock);
16 static DEFINE_MUTEX(mux_lock);
17 static LIST_HEAD(switch_list);
18 static LIST_HEAD(mux_list);
20 static void *typec_switch_match(struct device_connection *con, int ep,
23 struct typec_switch *sw;
25 list_for_each_entry(sw, &switch_list, entry)
26 if (!strcmp(con->endpoint[ep], dev_name(sw->dev)))
30 * We only get called if a connection was found, tell the caller to
31 * wait for the switch to show up.
33 return ERR_PTR(-EPROBE_DEFER);
37 * typec_switch_get - Find USB Type-C orientation switch
38 * @dev: The caller device
40 * Finds a switch linked with @dev. Returns a reference to the switch on
41 * success, NULL if no matching connection was found, or
42 * ERR_PTR(-EPROBE_DEFER) when a connection was found but the switch
43 * has not been enumerated yet.
45 struct typec_switch *typec_switch_get(struct device *dev)
47 struct typec_switch *sw;
49 mutex_lock(&switch_lock);
50 sw = device_connection_find_match(dev, "typec-switch", NULL,
52 if (!IS_ERR_OR_NULL(sw))
54 mutex_unlock(&switch_lock);
58 EXPORT_SYMBOL_GPL(typec_switch_get);
61 * typec_put_switch - Release USB Type-C orientation switch
62 * @sw: USB Type-C orientation switch
64 * Decrement reference count for @sw.
66 void typec_switch_put(struct typec_switch *sw)
68 if (!IS_ERR_OR_NULL(sw))
71 EXPORT_SYMBOL_GPL(typec_switch_put);
74 * typec_switch_register - Register USB Type-C orientation switch
75 * @sw: USB Type-C orientation switch
77 * This function registers a switch that can be used for routing the correct
78 * data pairs depending on the cable plug orientation from the USB Type-C
79 * connector to the USB controllers. USB Type-C plugs can be inserted
80 * right-side-up or upside-down.
82 int typec_switch_register(struct typec_switch *sw)
84 mutex_lock(&switch_lock);
85 list_add_tail(&sw->entry, &switch_list);
86 mutex_unlock(&switch_lock);
90 EXPORT_SYMBOL_GPL(typec_switch_register);
93 * typec_switch_unregister - Unregister USB Type-C orientation switch
94 * @sw: USB Type-C orientation switch
96 * Unregister switch that was registered with typec_switch_register().
98 void typec_switch_unregister(struct typec_switch *sw)
100 mutex_lock(&switch_lock);
101 list_del(&sw->entry);
102 mutex_unlock(&switch_lock);
104 EXPORT_SYMBOL_GPL(typec_switch_unregister);
106 /* ------------------------------------------------------------------------- */
108 static void *typec_mux_match(struct device_connection *con, int ep, void *data)
110 struct typec_mux *mux;
112 list_for_each_entry(mux, &mux_list, entry)
113 if (!strcmp(con->endpoint[ep], dev_name(mux->dev)))
117 * We only get called if a connection was found, tell the caller to
118 * wait for the switch to show up.
120 return ERR_PTR(-EPROBE_DEFER);
124 * typec_mux_get - Find USB Type-C Multiplexer
125 * @dev: The caller device
127 * Finds a mux linked to the caller. This function is primarily meant for the
128 * Type-C drivers. Returns a reference to the mux on success, NULL if no
129 * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection
130 * was found but the mux has not been enumerated yet.
132 struct typec_mux *typec_mux_get(struct device *dev)
134 struct typec_mux *mux;
136 mutex_lock(&mux_lock);
137 mux = device_connection_find_match(dev, "typec-mux", NULL,
139 if (!IS_ERR_OR_NULL(mux))
140 get_device(mux->dev);
141 mutex_unlock(&mux_lock);
145 EXPORT_SYMBOL_GPL(typec_mux_get);
148 * typec_mux_put - Release handle to a Multiplexer
149 * @mux: USB Type-C Connector Multiplexer/DeMultiplexer
151 * Decrements reference count for @mux.
153 void typec_mux_put(struct typec_mux *mux)
155 if (!IS_ERR_OR_NULL(mux))
156 put_device(mux->dev);
158 EXPORT_SYMBOL_GPL(typec_mux_put);
161 * typec_mux_register - Register Multiplexer routing USB Type-C pins
162 * @mux: USB Type-C Connector Multiplexer/DeMultiplexer
164 * USB Type-C connectors can be used for alternate modes of operation besides
165 * USB when Accessory/Alternate Modes are supported. With some of those modes,
166 * the pins on the connector need to be reconfigured. This function registers
167 * multiplexer switches routing the pins on the connector.
169 int typec_mux_register(struct typec_mux *mux)
171 mutex_lock(&mux_lock);
172 list_add_tail(&mux->entry, &mux_list);
173 mutex_unlock(&mux_lock);
177 EXPORT_SYMBOL_GPL(typec_mux_register);
180 * typec_mux_unregister - Unregister Multiplexer Switch
181 * @sw: USB Type-C Connector Multiplexer/DeMultiplexer
183 * Unregister mux that was registered with typec_mux_register().
185 void typec_mux_unregister(struct typec_mux *mux)
187 mutex_lock(&mux_lock);
188 list_del(&mux->entry);
189 mutex_unlock(&mux_lock);
191 EXPORT_SYMBOL_GPL(typec_mux_unregister);