.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | | -/** |
---|
| 2 | +/* |
---|
3 | 3 | * Bus for USB Type-C Alternate Modes |
---|
4 | 4 | * |
---|
5 | 5 | * Copyright (C) 2018 Intel Corporation |
---|
.. | .. |
---|
10 | 10 | |
---|
11 | 11 | #include "bus.h" |
---|
12 | 12 | |
---|
13 | | -static inline int typec_altmode_set_mux(struct altmode *alt, u8 state) |
---|
| 13 | +static inline int |
---|
| 14 | +typec_altmode_set_mux(struct altmode *alt, unsigned long conf, void *data) |
---|
14 | 15 | { |
---|
15 | | - return alt->mux ? alt->mux->set(alt->mux, state) : 0; |
---|
| 16 | + struct typec_mux_state state; |
---|
| 17 | + |
---|
| 18 | + if (!alt->mux) |
---|
| 19 | + return 0; |
---|
| 20 | + |
---|
| 21 | + state.alt = &alt->adev; |
---|
| 22 | + state.mode = conf; |
---|
| 23 | + state.data = data; |
---|
| 24 | + |
---|
| 25 | + return alt->mux->set(alt->mux, &state); |
---|
16 | 26 | } |
---|
17 | 27 | |
---|
18 | | -static int typec_altmode_set_state(struct typec_altmode *adev, int state) |
---|
| 28 | +static int typec_altmode_set_state(struct typec_altmode *adev, |
---|
| 29 | + unsigned long conf, void *data) |
---|
19 | 30 | { |
---|
20 | 31 | bool is_port = is_typec_port(adev->dev.parent); |
---|
21 | 32 | struct altmode *port_altmode; |
---|
22 | | - int ret; |
---|
23 | 33 | |
---|
24 | 34 | port_altmode = is_port ? to_altmode(adev) : to_altmode(adev)->partner; |
---|
25 | 35 | |
---|
26 | | - ret = typec_altmode_set_mux(port_altmode, state); |
---|
27 | | - if (ret) |
---|
28 | | - return ret; |
---|
29 | | - |
---|
30 | | - blocking_notifier_call_chain(&port_altmode->nh, state, NULL); |
---|
31 | | - |
---|
32 | | - return 0; |
---|
| 36 | + return typec_altmode_set_mux(port_altmode, conf, data); |
---|
33 | 37 | } |
---|
34 | 38 | |
---|
35 | 39 | /* -------------------------------------------------------------------------- */ |
---|
.. | .. |
---|
67 | 71 | is_port = is_typec_port(adev->dev.parent); |
---|
68 | 72 | partner = altmode->partner; |
---|
69 | 73 | |
---|
70 | | - ret = typec_altmode_set_mux(is_port ? altmode : partner, (u8)conf); |
---|
| 74 | + ret = typec_altmode_set_mux(is_port ? altmode : partner, conf, data); |
---|
71 | 75 | if (ret) |
---|
72 | 76 | return ret; |
---|
73 | | - |
---|
74 | | - blocking_notifier_call_chain(is_port ? &altmode->nh : &partner->nh, |
---|
75 | | - conf, data); |
---|
76 | 77 | |
---|
77 | 78 | if (partner->adev.ops && partner->adev.ops->notify) |
---|
78 | 79 | return partner->adev.ops->notify(&partner->adev, conf, data); |
---|
.. | .. |
---|
84 | 85 | /** |
---|
85 | 86 | * typec_altmode_enter - Enter Mode |
---|
86 | 87 | * @adev: The alternate mode |
---|
| 88 | + * @vdo: VDO for the Enter Mode command |
---|
87 | 89 | * |
---|
88 | 90 | * The alternate mode drivers use this function to enter mode. The port drivers |
---|
89 | 91 | * use this to inform the alternate mode drivers that the partner has initiated |
---|
90 | | - * Enter Mode command. |
---|
| 92 | + * Enter Mode command. If the alternate mode does not require VDO, @vdo must be |
---|
| 93 | + * NULL. |
---|
91 | 94 | */ |
---|
92 | | -int typec_altmode_enter(struct typec_altmode *adev) |
---|
| 95 | +int typec_altmode_enter(struct typec_altmode *adev, u32 *vdo) |
---|
93 | 96 | { |
---|
94 | 97 | struct altmode *partner = to_altmode(adev)->partner; |
---|
95 | 98 | struct typec_altmode *pdev = &partner->adev; |
---|
.. | .. |
---|
101 | 104 | if (!pdev->ops || !pdev->ops->enter) |
---|
102 | 105 | return -EOPNOTSUPP; |
---|
103 | 106 | |
---|
| 107 | + if (is_typec_port(pdev->dev.parent) && !pdev->active) |
---|
| 108 | + return -EPERM; |
---|
| 109 | + |
---|
104 | 110 | /* Moving to USB Safe State */ |
---|
105 | | - ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE); |
---|
| 111 | + ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE, NULL); |
---|
106 | 112 | if (ret) |
---|
107 | 113 | return ret; |
---|
108 | 114 | |
---|
109 | 115 | /* Enter Mode */ |
---|
110 | | - return pdev->ops->enter(pdev); |
---|
| 116 | + return pdev->ops->enter(pdev, vdo); |
---|
111 | 117 | } |
---|
112 | 118 | EXPORT_SYMBOL_GPL(typec_altmode_enter); |
---|
113 | 119 | |
---|
.. | .. |
---|
126 | 132 | if (!adev || !adev->active) |
---|
127 | 133 | return 0; |
---|
128 | 134 | |
---|
129 | | - if (!pdev->ops || !pdev->ops->enter) |
---|
| 135 | + if (!pdev->ops || !pdev->ops->exit) |
---|
130 | 136 | return -EOPNOTSUPP; |
---|
131 | 137 | |
---|
132 | 138 | /* Moving to USB Safe State */ |
---|
133 | | - ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE); |
---|
| 139 | + ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE, NULL); |
---|
134 | 140 | if (ret) |
---|
135 | 141 | return ret; |
---|
136 | 142 | |
---|
.. | .. |
---|
146 | 152 | * |
---|
147 | 153 | * Notifies the partner of @adev about Attention command. |
---|
148 | 154 | */ |
---|
149 | | -void typec_altmode_attention(struct typec_altmode *adev, u32 vdo) |
---|
| 155 | +int typec_altmode_attention(struct typec_altmode *adev, u32 vdo) |
---|
150 | 156 | { |
---|
151 | | - struct typec_altmode *pdev = &to_altmode(adev)->partner->adev; |
---|
| 157 | + struct altmode *partner = to_altmode(adev)->partner; |
---|
| 158 | + struct typec_altmode *pdev; |
---|
| 159 | + |
---|
| 160 | + if (!partner) |
---|
| 161 | + return -ENODEV; |
---|
| 162 | + |
---|
| 163 | + pdev = &partner->adev; |
---|
152 | 164 | |
---|
153 | 165 | if (pdev->ops && pdev->ops->attention) |
---|
154 | 166 | pdev->ops->attention(pdev, vdo); |
---|
| 167 | + |
---|
| 168 | + return 0; |
---|
155 | 169 | } |
---|
156 | 170 | EXPORT_SYMBOL_GPL(typec_altmode_attention); |
---|
157 | 171 | |
---|
.. | .. |
---|
386 | 400 | drv->remove(to_typec_altmode(dev)); |
---|
387 | 401 | |
---|
388 | 402 | if (adev->active) { |
---|
389 | | - WARN_ON(typec_altmode_set_state(adev, TYPEC_STATE_SAFE)); |
---|
| 403 | + WARN_ON(typec_altmode_set_state(adev, TYPEC_STATE_SAFE, NULL)); |
---|
390 | 404 | typec_altmode_update_active(adev, false); |
---|
391 | 405 | } |
---|
392 | 406 | |
---|