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