1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * USB PHY defines |
4 | * |
5 | * These APIs may be used between USB controllers. USB device drivers |
6 | * (for either host or peripheral roles) don't use these calls; they |
7 | * continue to use just usb_device and usb_gadget. |
8 | */ |
9 | |
10 | #ifndef __LINUX_USB_PHY_H |
11 | #define __LINUX_USB_PHY_H |
12 | |
13 | #include <linux/extcon.h> |
14 | #include <linux/notifier.h> |
15 | #include <linux/usb.h> |
16 | #include <uapi/linux/usb/charger.h> |
17 | |
18 | enum usb_phy_interface { |
19 | USBPHY_INTERFACE_MODE_UNKNOWN, |
20 | USBPHY_INTERFACE_MODE_UTMI, |
21 | USBPHY_INTERFACE_MODE_UTMIW, |
22 | USBPHY_INTERFACE_MODE_ULPI, |
23 | USBPHY_INTERFACE_MODE_SERIAL, |
24 | USBPHY_INTERFACE_MODE_HSIC, |
25 | }; |
26 | |
27 | enum usb_phy_events { |
28 | USB_EVENT_NONE, /* no events or cable disconnected */ |
29 | USB_EVENT_VBUS, /* vbus valid event */ |
30 | USB_EVENT_ID, /* id was grounded */ |
31 | USB_EVENT_CHARGER, /* usb dedicated charger */ |
32 | USB_EVENT_ENUMERATED, /* gadget driver enumerated */ |
33 | }; |
34 | |
35 | /* associate a type with PHY */ |
36 | enum usb_phy_type { |
37 | USB_PHY_TYPE_UNDEFINED, |
38 | USB_PHY_TYPE_USB2, |
39 | USB_PHY_TYPE_USB3, |
40 | }; |
41 | |
42 | /* OTG defines lots of enumeration states before device reset */ |
43 | enum usb_otg_state { |
44 | OTG_STATE_UNDEFINED = 0, |
45 | |
46 | /* single-role peripheral, and dual-role default-b */ |
47 | OTG_STATE_B_IDLE, |
48 | OTG_STATE_B_SRP_INIT, |
49 | OTG_STATE_B_PERIPHERAL, |
50 | |
51 | /* extra dual-role default-b states */ |
52 | OTG_STATE_B_WAIT_ACON, |
53 | OTG_STATE_B_HOST, |
54 | |
55 | /* dual-role default-a */ |
56 | OTG_STATE_A_IDLE, |
57 | OTG_STATE_A_WAIT_VRISE, |
58 | OTG_STATE_A_WAIT_BCON, |
59 | OTG_STATE_A_HOST, |
60 | OTG_STATE_A_SUSPEND, |
61 | OTG_STATE_A_PERIPHERAL, |
62 | OTG_STATE_A_WAIT_VFALL, |
63 | OTG_STATE_A_VBUS_ERR, |
64 | }; |
65 | |
66 | struct usb_phy; |
67 | struct usb_otg; |
68 | |
69 | /* for phys connected thru an ULPI interface, the user must |
70 | * provide access ops |
71 | */ |
72 | struct usb_phy_io_ops { |
73 | int (*read)(struct usb_phy *x, u32 reg); |
74 | int (*write)(struct usb_phy *x, u32 val, u32 reg); |
75 | }; |
76 | |
77 | struct usb_charger_current { |
78 | unsigned int sdp_min; |
79 | unsigned int sdp_max; |
80 | unsigned int dcp_min; |
81 | unsigned int dcp_max; |
82 | unsigned int cdp_min; |
83 | unsigned int cdp_max; |
84 | unsigned int aca_min; |
85 | unsigned int aca_max; |
86 | }; |
87 | |
88 | struct usb_phy { |
89 | struct device *dev; |
90 | const char *label; |
91 | unsigned int flags; |
92 | |
93 | enum usb_phy_type type; |
94 | enum usb_phy_events last_event; |
95 | |
96 | struct usb_otg *otg; |
97 | |
98 | struct device *io_dev; |
99 | struct usb_phy_io_ops *io_ops; |
100 | void __iomem *io_priv; |
101 | |
102 | /* to support extcon device */ |
103 | struct extcon_dev *edev; |
104 | struct extcon_dev *id_edev; |
105 | struct notifier_block vbus_nb; |
106 | struct notifier_block id_nb; |
107 | struct notifier_block type_nb; |
108 | |
109 | /* Support USB charger */ |
110 | enum usb_charger_type chg_type; |
111 | enum usb_charger_state chg_state; |
112 | struct usb_charger_current chg_cur; |
113 | struct work_struct chg_work; |
114 | |
115 | /* for notification of usb_phy_events */ |
116 | struct atomic_notifier_head notifier; |
117 | |
118 | /* to pass extra port status to the root hub */ |
119 | u16 port_status; |
120 | u16 port_change; |
121 | |
122 | /* to support controllers that have multiple phys */ |
123 | struct list_head head; |
124 | |
125 | /* initialize/shutdown the phy */ |
126 | int (*init)(struct usb_phy *x); |
127 | void (*shutdown)(struct usb_phy *x); |
128 | |
129 | /* enable/disable VBUS */ |
130 | int (*set_vbus)(struct usb_phy *x, int on); |
131 | |
132 | /* effective for B devices, ignored for A-peripheral */ |
133 | int (*set_power)(struct usb_phy *x, |
134 | unsigned mA); |
135 | |
136 | /* Set phy into suspend mode */ |
137 | int (*set_suspend)(struct usb_phy *x, |
138 | int suspend); |
139 | |
140 | /* |
141 | * Set wakeup enable for PHY, in that case, the PHY can be |
142 | * woken up from suspend status due to external events, |
143 | * like vbus change, dp/dm change and id. |
144 | */ |
145 | int (*set_wakeup)(struct usb_phy *x, bool enabled); |
146 | |
147 | /* notify phy port status change */ |
148 | int (*notify_port_status)(struct usb_phy *x, int port, |
149 | u16 portstatus, u16 portchange); |
150 | |
151 | /* notify phy connect status change */ |
152 | int (*notify_connect)(struct usb_phy *x, |
153 | enum usb_device_speed speed); |
154 | int (*notify_disconnect)(struct usb_phy *x, |
155 | enum usb_device_speed speed); |
156 | |
157 | /* |
158 | * Charger detection method can be implemented if you need to |
159 | * manually detect the charger type. |
160 | */ |
161 | enum usb_charger_type (*charger_detect)(struct usb_phy *x); |
162 | }; |
163 | |
164 | /* for board-specific init logic */ |
165 | extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type); |
166 | extern int usb_add_phy_dev(struct usb_phy *); |
167 | extern void usb_remove_phy(struct usb_phy *); |
168 | |
169 | /* helpers for direct access thru low-level io interface */ |
170 | static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) |
171 | { |
172 | if (x && x->io_ops && x->io_ops->read) |
173 | return x->io_ops->read(x, reg); |
174 | |
175 | return -EINVAL; |
176 | } |
177 | |
178 | static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) |
179 | { |
180 | if (x && x->io_ops && x->io_ops->write) |
181 | return x->io_ops->write(x, val, reg); |
182 | |
183 | return -EINVAL; |
184 | } |
185 | |
186 | static inline int |
187 | usb_phy_init(struct usb_phy *x) |
188 | { |
189 | if (x && x->init) |
190 | return x->init(x); |
191 | |
192 | return 0; |
193 | } |
194 | |
195 | static inline void |
196 | usb_phy_shutdown(struct usb_phy *x) |
197 | { |
198 | if (x && x->shutdown) |
199 | x->shutdown(x); |
200 | } |
201 | |
202 | static inline int |
203 | usb_phy_vbus_on(struct usb_phy *x) |
204 | { |
205 | if (!x || !x->set_vbus) |
206 | return 0; |
207 | |
208 | return x->set_vbus(x, true); |
209 | } |
210 | |
211 | static inline int |
212 | usb_phy_vbus_off(struct usb_phy *x) |
213 | { |
214 | if (!x || !x->set_vbus) |
215 | return 0; |
216 | |
217 | return x->set_vbus(x, false); |
218 | } |
219 | |
220 | /* for usb host and peripheral controller drivers */ |
221 | #if IS_ENABLED(CONFIG_USB_PHY) |
222 | extern struct usb_phy *usb_get_phy(enum usb_phy_type type); |
223 | extern struct usb_phy *devm_usb_get_phy(struct device *dev, |
224 | enum usb_phy_type type); |
225 | extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, |
226 | const char *phandle, u8 index); |
227 | extern struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, |
228 | struct device_node *node, struct notifier_block *nb); |
229 | extern void usb_put_phy(struct usb_phy *); |
230 | extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); |
231 | extern void usb_phy_set_event(struct usb_phy *x, unsigned long event); |
232 | extern void usb_phy_set_charger_current(struct usb_phy *usb_phy, |
233 | unsigned int mA); |
234 | extern void usb_phy_get_charger_current(struct usb_phy *usb_phy, |
235 | unsigned int *min, unsigned int *max); |
236 | extern void usb_phy_set_charger_state(struct usb_phy *usb_phy, |
237 | enum usb_charger_state state); |
238 | #else |
239 | static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) |
240 | { |
241 | return ERR_PTR(-ENXIO); |
242 | } |
243 | |
244 | static inline struct usb_phy *devm_usb_get_phy(struct device *dev, |
245 | enum usb_phy_type type) |
246 | { |
247 | return ERR_PTR(-ENXIO); |
248 | } |
249 | |
250 | static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, |
251 | const char *phandle, u8 index) |
252 | { |
253 | return ERR_PTR(-ENXIO); |
254 | } |
255 | |
256 | static inline struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, |
257 | struct device_node *node, struct notifier_block *nb) |
258 | { |
259 | return ERR_PTR(-ENXIO); |
260 | } |
261 | |
262 | static inline void usb_put_phy(struct usb_phy *x) |
263 | { |
264 | } |
265 | |
266 | static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x) |
267 | { |
268 | } |
269 | |
270 | static inline void usb_phy_set_event(struct usb_phy *x, unsigned long event) |
271 | { |
272 | } |
273 | |
274 | static inline void usb_phy_set_charger_current(struct usb_phy *usb_phy, |
275 | unsigned int mA) |
276 | { |
277 | } |
278 | |
279 | static inline void usb_phy_get_charger_current(struct usb_phy *usb_phy, |
280 | unsigned int *min, |
281 | unsigned int *max) |
282 | { |
283 | } |
284 | |
285 | static inline void usb_phy_set_charger_state(struct usb_phy *usb_phy, |
286 | enum usb_charger_state state) |
287 | { |
288 | } |
289 | #endif |
290 | |
291 | static inline int |
292 | usb_phy_set_power(struct usb_phy *x, unsigned mA) |
293 | { |
294 | if (!x) |
295 | return 0; |
296 | |
297 | usb_phy_set_charger_current(usb_phy: x, mA); |
298 | |
299 | if (x->set_power) |
300 | return x->set_power(x, mA); |
301 | return 0; |
302 | } |
303 | |
304 | /* Context: can sleep */ |
305 | static inline int |
306 | usb_phy_set_suspend(struct usb_phy *x, int suspend) |
307 | { |
308 | if (x && x->set_suspend != NULL) |
309 | return x->set_suspend(x, suspend); |
310 | else |
311 | return 0; |
312 | } |
313 | |
314 | static inline int |
315 | usb_phy_set_wakeup(struct usb_phy *x, bool enabled) |
316 | { |
317 | if (x && x->set_wakeup) |
318 | return x->set_wakeup(x, enabled); |
319 | else |
320 | return 0; |
321 | } |
322 | |
323 | static inline int |
324 | usb_phy_notify_port_status(struct usb_phy *x, int port, u16 portstatus, u16 portchange) |
325 | { |
326 | if (x && x->notify_port_status) |
327 | return x->notify_port_status(x, port, portstatus, portchange); |
328 | else |
329 | return 0; |
330 | } |
331 | |
332 | static inline int |
333 | usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) |
334 | { |
335 | if (x && x->notify_connect) |
336 | return x->notify_connect(x, speed); |
337 | else |
338 | return 0; |
339 | } |
340 | |
341 | static inline int |
342 | usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed) |
343 | { |
344 | if (x && x->notify_disconnect) |
345 | return x->notify_disconnect(x, speed); |
346 | else |
347 | return 0; |
348 | } |
349 | |
350 | /* notifiers */ |
351 | static inline int |
352 | usb_register_notifier(struct usb_phy *x, struct notifier_block *nb) |
353 | { |
354 | return atomic_notifier_chain_register(nh: &x->notifier, nb); |
355 | } |
356 | |
357 | static inline void |
358 | usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb) |
359 | { |
360 | atomic_notifier_chain_unregister(nh: &x->notifier, nb); |
361 | } |
362 | |
363 | static inline const char *usb_phy_type_string(enum usb_phy_type type) |
364 | { |
365 | switch (type) { |
366 | case USB_PHY_TYPE_USB2: |
367 | return "USB2 PHY" ; |
368 | case USB_PHY_TYPE_USB3: |
369 | return "USB3 PHY" ; |
370 | default: |
371 | return "UNKNOWN PHY TYPE" ; |
372 | } |
373 | } |
374 | #endif /* __LINUX_USB_PHY_H */ |
375 | |