| .. | .. |
|---|
| 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 | { |
|---|