]> Git Repo - linux.git/blob - drivers/usb/typec/mux.c
kvm: mmu: Add guest_mode to kvm_mmu_page_role
[linux.git] / drivers / usb / typec / mux.c
1 // SPDX-License-Identifier: GPL-2.0
2 /**
3  * USB Type-C Multiplexer/DeMultiplexer Switch support
4  *
5  * Copyright (C) 2018 Intel Corporation
6  * Author: Heikki Krogerus <[email protected]>
7  *         Hans de Goede <[email protected]>
8  */
9
10 #include <linux/device.h>
11 #include <linux/list.h>
12 #include <linux/mutex.h>
13 #include <linux/usb/typec_mux.h>
14
15 static DEFINE_MUTEX(switch_lock);
16 static DEFINE_MUTEX(mux_lock);
17 static LIST_HEAD(switch_list);
18 static LIST_HEAD(mux_list);
19
20 static void *typec_switch_match(struct device_connection *con, int ep,
21                                 void *data)
22 {
23         struct typec_switch *sw;
24
25         list_for_each_entry(sw, &switch_list, entry)
26                 if (!strcmp(con->endpoint[ep], dev_name(sw->dev)))
27                         return sw;
28
29         /*
30          * We only get called if a connection was found, tell the caller to
31          * wait for the switch to show up.
32          */
33         return ERR_PTR(-EPROBE_DEFER);
34 }
35
36 /**
37  * typec_switch_get - Find USB Type-C orientation switch
38  * @dev: The caller device
39  *
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.
44  */
45 struct typec_switch *typec_switch_get(struct device *dev)
46 {
47         struct typec_switch *sw;
48
49         mutex_lock(&switch_lock);
50         sw = device_connection_find_match(dev, "typec-switch", NULL,
51                                           typec_switch_match);
52         if (!IS_ERR_OR_NULL(sw))
53                 get_device(sw->dev);
54         mutex_unlock(&switch_lock);
55
56         return sw;
57 }
58 EXPORT_SYMBOL_GPL(typec_switch_get);
59
60 /**
61  * typec_put_switch - Release USB Type-C orientation switch
62  * @sw: USB Type-C orientation switch
63  *
64  * Decrement reference count for @sw.
65  */
66 void typec_switch_put(struct typec_switch *sw)
67 {
68         if (!IS_ERR_OR_NULL(sw))
69                 put_device(sw->dev);
70 }
71 EXPORT_SYMBOL_GPL(typec_switch_put);
72
73 /**
74  * typec_switch_register - Register USB Type-C orientation switch
75  * @sw: USB Type-C orientation switch
76  *
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.
81  */
82 int typec_switch_register(struct typec_switch *sw)
83 {
84         mutex_lock(&switch_lock);
85         list_add_tail(&sw->entry, &switch_list);
86         mutex_unlock(&switch_lock);
87
88         return 0;
89 }
90 EXPORT_SYMBOL_GPL(typec_switch_register);
91
92 /**
93  * typec_switch_unregister - Unregister USB Type-C orientation switch
94  * @sw: USB Type-C orientation switch
95  *
96  * Unregister switch that was registered with typec_switch_register().
97  */
98 void typec_switch_unregister(struct typec_switch *sw)
99 {
100         mutex_lock(&switch_lock);
101         list_del(&sw->entry);
102         mutex_unlock(&switch_lock);
103 }
104 EXPORT_SYMBOL_GPL(typec_switch_unregister);
105
106 /* ------------------------------------------------------------------------- */
107
108 static void *typec_mux_match(struct device_connection *con, int ep, void *data)
109 {
110         struct typec_mux *mux;
111
112         list_for_each_entry(mux, &mux_list, entry)
113                 if (!strcmp(con->endpoint[ep], dev_name(mux->dev)))
114                         return mux;
115
116         /*
117          * We only get called if a connection was found, tell the caller to
118          * wait for the switch to show up.
119          */
120         return ERR_PTR(-EPROBE_DEFER);
121 }
122
123 /**
124  * typec_mux_get - Find USB Type-C Multiplexer
125  * @dev: The caller device
126  *
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.
131  */
132 struct typec_mux *typec_mux_get(struct device *dev)
133 {
134         struct typec_mux *mux;
135
136         mutex_lock(&mux_lock);
137         mux = device_connection_find_match(dev, "typec-mux", NULL,
138                                            typec_mux_match);
139         if (!IS_ERR_OR_NULL(mux))
140                 get_device(mux->dev);
141         mutex_unlock(&mux_lock);
142
143         return mux;
144 }
145 EXPORT_SYMBOL_GPL(typec_mux_get);
146
147 /**
148  * typec_mux_put - Release handle to a Multiplexer
149  * @mux: USB Type-C Connector Multiplexer/DeMultiplexer
150  *
151  * Decrements reference count for @mux.
152  */
153 void typec_mux_put(struct typec_mux *mux)
154 {
155         if (!IS_ERR_OR_NULL(mux))
156                 put_device(mux->dev);
157 }
158 EXPORT_SYMBOL_GPL(typec_mux_put);
159
160 /**
161  * typec_mux_register - Register Multiplexer routing USB Type-C pins
162  * @mux: USB Type-C Connector Multiplexer/DeMultiplexer
163  *
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.
168  */
169 int typec_mux_register(struct typec_mux *mux)
170 {
171         mutex_lock(&mux_lock);
172         list_add_tail(&mux->entry, &mux_list);
173         mutex_unlock(&mux_lock);
174
175         return 0;
176 }
177 EXPORT_SYMBOL_GPL(typec_mux_register);
178
179 /**
180  * typec_mux_unregister - Unregister Multiplexer Switch
181  * @sw: USB Type-C Connector Multiplexer/DeMultiplexer
182  *
183  * Unregister mux that was registered with typec_mux_register().
184  */
185 void typec_mux_unregister(struct typec_mux *mux)
186 {
187         mutex_lock(&mux_lock);
188         list_del(&mux->entry);
189         mutex_unlock(&mux_lock);
190 }
191 EXPORT_SYMBOL_GPL(typec_mux_unregister);
This page took 0.043464 seconds and 4 git commands to generate.