.. | .. |
---|
122 | 122 | struct cpcap_phy_ddata { |
---|
123 | 123 | struct regmap *reg; |
---|
124 | 124 | struct device *dev; |
---|
125 | | - struct clk *refclk; |
---|
126 | 125 | struct usb_phy phy; |
---|
127 | 126 | struct delayed_work detect_work; |
---|
128 | 127 | struct pinctrl *pins; |
---|
.. | .. |
---|
134 | 133 | struct iio_channel *id; |
---|
135 | 134 | struct regulator *vusb; |
---|
136 | 135 | atomic_t active; |
---|
| 136 | + unsigned int vbus_provider:1; |
---|
| 137 | + unsigned int docked:1; |
---|
137 | 138 | }; |
---|
138 | 139 | |
---|
139 | 140 | static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata) |
---|
.. | .. |
---|
233 | 234 | if (error) |
---|
234 | 235 | return; |
---|
235 | 236 | |
---|
236 | | - if (s.id_ground) { |
---|
| 237 | + vbus = cpcap_usb_vbus_valid(ddata); |
---|
| 238 | + |
---|
| 239 | + /* We need to kick the VBUS as USB A-host */ |
---|
| 240 | + if (s.id_ground && ddata->vbus_provider) { |
---|
| 241 | + dev_dbg(ddata->dev, "still in USB A-host mode, kicking VBUS\n"); |
---|
| 242 | + |
---|
| 243 | + cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); |
---|
| 244 | + |
---|
| 245 | + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, |
---|
| 246 | + CPCAP_BIT_VBUSSTBY_EN | |
---|
| 247 | + CPCAP_BIT_VBUSEN_SPI, |
---|
| 248 | + CPCAP_BIT_VBUSEN_SPI); |
---|
| 249 | + if (error) |
---|
| 250 | + goto out_err; |
---|
| 251 | + |
---|
| 252 | + return; |
---|
| 253 | + } |
---|
| 254 | + |
---|
| 255 | + if (vbus && s.id_ground && ddata->docked) { |
---|
| 256 | + dev_dbg(ddata->dev, "still docked as A-host, signal ID down\n"); |
---|
| 257 | + |
---|
| 258 | + cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); |
---|
| 259 | + |
---|
| 260 | + return; |
---|
| 261 | + } |
---|
| 262 | + |
---|
| 263 | + /* No VBUS needed with docks */ |
---|
| 264 | + if (vbus && s.id_ground && !ddata->vbus_provider) { |
---|
| 265 | + dev_dbg(ddata->dev, "connected to a dock\n"); |
---|
| 266 | + |
---|
| 267 | + ddata->docked = true; |
---|
| 268 | + |
---|
| 269 | + error = cpcap_usb_set_usb_mode(ddata); |
---|
| 270 | + if (error) |
---|
| 271 | + goto out_err; |
---|
| 272 | + |
---|
| 273 | + cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); |
---|
| 274 | + |
---|
| 275 | + /* |
---|
| 276 | + * Force check state again after musb has reoriented, |
---|
| 277 | + * otherwise devices won't enumerate after loading PHY |
---|
| 278 | + * driver. |
---|
| 279 | + */ |
---|
| 280 | + schedule_delayed_work(&ddata->detect_work, |
---|
| 281 | + msecs_to_jiffies(1000)); |
---|
| 282 | + |
---|
| 283 | + return; |
---|
| 284 | + } |
---|
| 285 | + |
---|
| 286 | + if (s.id_ground && !ddata->docked) { |
---|
237 | 287 | dev_dbg(ddata->dev, "id ground, USB host mode\n"); |
---|
| 288 | + |
---|
| 289 | + ddata->vbus_provider = true; |
---|
| 290 | + |
---|
238 | 291 | error = cpcap_usb_set_usb_mode(ddata); |
---|
239 | 292 | if (error) |
---|
240 | 293 | goto out_err; |
---|
.. | .. |
---|
242 | 295 | cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); |
---|
243 | 296 | |
---|
244 | 297 | error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, |
---|
245 | | - CPCAP_BIT_VBUSSTBY_EN, |
---|
246 | | - CPCAP_BIT_VBUSSTBY_EN); |
---|
| 298 | + CPCAP_BIT_VBUSSTBY_EN | |
---|
| 299 | + CPCAP_BIT_VBUSEN_SPI, |
---|
| 300 | + CPCAP_BIT_VBUSEN_SPI); |
---|
247 | 301 | if (error) |
---|
248 | 302 | goto out_err; |
---|
249 | 303 | |
---|
.. | .. |
---|
251 | 305 | } |
---|
252 | 306 | |
---|
253 | 307 | error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, |
---|
254 | | - CPCAP_BIT_VBUSSTBY_EN, 0); |
---|
| 308 | + CPCAP_BIT_VBUSSTBY_EN | |
---|
| 309 | + CPCAP_BIT_VBUSEN_SPI, 0); |
---|
255 | 310 | if (error) |
---|
256 | 311 | goto out_err; |
---|
257 | 312 | |
---|
258 | 313 | vbus = cpcap_usb_vbus_valid(ddata); |
---|
259 | 314 | |
---|
| 315 | + /* Otherwise assume we're connected to a USB host */ |
---|
260 | 316 | if (vbus) { |
---|
261 | | - /* Are we connected to a docking station with vbus? */ |
---|
262 | | - if (s.id_ground) { |
---|
263 | | - dev_dbg(ddata->dev, "connected to a dock\n"); |
---|
264 | | - |
---|
265 | | - /* No VBUS needed with docks */ |
---|
266 | | - error = cpcap_usb_set_usb_mode(ddata); |
---|
267 | | - if (error) |
---|
268 | | - goto out_err; |
---|
269 | | - cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); |
---|
270 | | - |
---|
271 | | - return; |
---|
272 | | - } |
---|
273 | | - |
---|
274 | | - /* Otherwise assume we're connected to a USB host */ |
---|
275 | 317 | dev_dbg(ddata->dev, "connected to USB host\n"); |
---|
276 | 318 | error = cpcap_usb_set_usb_mode(ddata); |
---|
277 | 319 | if (error) |
---|
.. | .. |
---|
281 | 323 | return; |
---|
282 | 324 | } |
---|
283 | 325 | |
---|
| 326 | + ddata->vbus_provider = false; |
---|
| 327 | + ddata->docked = false; |
---|
284 | 328 | cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF); |
---|
285 | 329 | |
---|
286 | 330 | /* Default to debug UART mode */ |
---|
.. | .. |
---|
320 | 364 | |
---|
321 | 365 | error = devm_request_threaded_irq(ddata->dev, irq, NULL, |
---|
322 | 366 | cpcap_phy_irq_thread, |
---|
323 | | - IRQF_SHARED, |
---|
| 367 | + IRQF_SHARED | |
---|
| 368 | + IRQF_ONESHOT, |
---|
324 | 369 | name, ddata); |
---|
325 | 370 | if (error) { |
---|
326 | 371 | dev_err(ddata->dev, "could not get irq %s: %i\n", |
---|
.. | .. |
---|
441 | 486 | |
---|
442 | 487 | error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1, |
---|
443 | 488 | CPCAP_BIT_VBUSPD, 0); |
---|
444 | | - if (error) |
---|
445 | | - goto out_err; |
---|
446 | | - |
---|
447 | | - error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2, |
---|
448 | | - CPCAP_BIT_USBXCVREN, |
---|
449 | | - CPCAP_BIT_USBXCVREN); |
---|
450 | 489 | if (error) |
---|
451 | 490 | goto out_err; |
---|
452 | 491 | |
---|
.. | .. |
---|
675 | 714 | |
---|
676 | 715 | usb_remove_phy(&ddata->phy); |
---|
677 | 716 | cancel_delayed_work_sync(&ddata->detect_work); |
---|
678 | | - clk_unprepare(ddata->refclk); |
---|
679 | 717 | regulator_disable(ddata->vusb); |
---|
680 | 718 | |
---|
681 | 719 | return 0; |
---|