.. | .. |
---|
23 | 23 | |
---|
24 | 24 | /** |
---|
25 | 25 | * hw_read_otgsc returns otgsc register bits value. |
---|
| 26 | + * @ci: the controller |
---|
26 | 27 | * @mask: bitfield mask |
---|
27 | 28 | */ |
---|
28 | 29 | u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) |
---|
.. | .. |
---|
35 | 36 | * detection overwrite OTGSC register value |
---|
36 | 37 | */ |
---|
37 | 38 | cable = &ci->platdata->vbus_extcon; |
---|
38 | | - if (!IS_ERR(cable->edev)) { |
---|
| 39 | + if (!IS_ERR(cable->edev) || ci->role_switch) { |
---|
39 | 40 | if (cable->changed) |
---|
40 | 41 | val |= OTGSC_BSVIS; |
---|
41 | 42 | else |
---|
.. | .. |
---|
53 | 54 | } |
---|
54 | 55 | |
---|
55 | 56 | cable = &ci->platdata->id_extcon; |
---|
56 | | - if (!IS_ERR(cable->edev)) { |
---|
| 57 | + if (!IS_ERR(cable->edev) || ci->role_switch) { |
---|
57 | 58 | if (cable->changed) |
---|
58 | 59 | val |= OTGSC_IDIS; |
---|
59 | 60 | else |
---|
.. | .. |
---|
75 | 76 | |
---|
76 | 77 | /** |
---|
77 | 78 | * hw_write_otgsc updates target bits of OTGSC register. |
---|
| 79 | + * @ci: the controller |
---|
78 | 80 | * @mask: bitfield mask |
---|
79 | 81 | * @data: to be written |
---|
80 | 82 | */ |
---|
.. | .. |
---|
83 | 85 | struct ci_hdrc_cable *cable; |
---|
84 | 86 | |
---|
85 | 87 | cable = &ci->platdata->vbus_extcon; |
---|
86 | | - if (!IS_ERR(cable->edev)) { |
---|
| 88 | + if (!IS_ERR(cable->edev) || ci->role_switch) { |
---|
87 | 89 | if (data & mask & OTGSC_BSVIS) |
---|
88 | 90 | cable->changed = false; |
---|
89 | 91 | |
---|
.. | .. |
---|
97 | 99 | } |
---|
98 | 100 | |
---|
99 | 101 | cable = &ci->platdata->id_extcon; |
---|
100 | | - if (!IS_ERR(cable->edev)) { |
---|
| 102 | + if (!IS_ERR(cable->edev) || ci->role_switch) { |
---|
101 | 103 | if (data & mask & OTGSC_IDIS) |
---|
102 | 104 | cable->changed = false; |
---|
103 | 105 | |
---|
.. | .. |
---|
164 | 166 | |
---|
165 | 167 | static void ci_handle_id_switch(struct ci_hdrc *ci) |
---|
166 | 168 | { |
---|
167 | | - enum ci_role role = ci_otg_role(ci); |
---|
| 169 | + enum ci_role role; |
---|
168 | 170 | |
---|
| 171 | + mutex_lock(&ci->mutex); |
---|
| 172 | + role = ci_otg_role(ci); |
---|
169 | 173 | if (role != ci->role) { |
---|
170 | 174 | dev_dbg(ci->dev, "switching from %s to %s\n", |
---|
171 | 175 | ci_role(ci)->name, ci->roles[role]->name); |
---|
| 176 | + |
---|
| 177 | + if (ci->vbus_active && ci->role == CI_ROLE_GADGET) |
---|
| 178 | + /* |
---|
| 179 | + * vbus disconnect event is lost due to role |
---|
| 180 | + * switch occurs during system suspend. |
---|
| 181 | + */ |
---|
| 182 | + usb_gadget_vbus_disconnect(&ci->gadget); |
---|
172 | 183 | |
---|
173 | 184 | ci_role_stop(ci); |
---|
174 | 185 | |
---|
.. | .. |
---|
188 | 199 | if (role == CI_ROLE_GADGET) |
---|
189 | 200 | ci_handle_vbus_change(ci); |
---|
190 | 201 | } |
---|
| 202 | + mutex_unlock(&ci->mutex); |
---|
191 | 203 | } |
---|
192 | 204 | /** |
---|
193 | 205 | * ci_otg_work - perform otg (vbus/id) event handle |
---|
.. | .. |
---|
222 | 234 | |
---|
223 | 235 | /** |
---|
224 | 236 | * ci_hdrc_otg_init - initialize otg struct |
---|
225 | | - * ci: the controller |
---|
| 237 | + * @ci: the controller |
---|
226 | 238 | */ |
---|
227 | 239 | int ci_hdrc_otg_init(struct ci_hdrc *ci) |
---|
228 | 240 | { |
---|
.. | .. |
---|
241 | 253 | |
---|
242 | 254 | /** |
---|
243 | 255 | * ci_hdrc_otg_destroy - destroy otg struct |
---|
244 | | - * ci: the controller |
---|
| 256 | + * @ci: the controller |
---|
245 | 257 | */ |
---|
246 | 258 | void ci_hdrc_otg_destroy(struct ci_hdrc *ci) |
---|
247 | 259 | { |
---|