diff options
Diffstat (limited to 'drivers/usb/phy/phy-twl6030-usb.c')
-rw-r--r-- | drivers/usb/phy/phy-twl6030-usb.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 24e2b3cf1867..a72e8d670adc 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c | |||
@@ -97,6 +97,9 @@ struct twl6030_usb { | |||
97 | 97 | ||
98 | struct regulator *usb3v3; | 98 | struct regulator *usb3v3; |
99 | 99 | ||
100 | /* used to check initial cable status after probe */ | ||
101 | struct delayed_work get_status_work; | ||
102 | |||
100 | /* used to set vbus, in atomic path */ | 103 | /* used to set vbus, in atomic path */ |
101 | struct work_struct set_vbus_work; | 104 | struct work_struct set_vbus_work; |
102 | 105 | ||
@@ -227,12 +230,16 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) | |||
227 | twl->asleep = 1; | 230 | twl->asleep = 1; |
228 | status = MUSB_VBUS_VALID; | 231 | status = MUSB_VBUS_VALID; |
229 | twl->linkstat = status; | 232 | twl->linkstat = status; |
230 | musb_mailbox(status); | 233 | ret = musb_mailbox(status); |
234 | if (ret) | ||
235 | twl->linkstat = MUSB_UNKNOWN; | ||
231 | } else { | 236 | } else { |
232 | if (twl->linkstat != MUSB_UNKNOWN) { | 237 | if (twl->linkstat != MUSB_UNKNOWN) { |
233 | status = MUSB_VBUS_OFF; | 238 | status = MUSB_VBUS_OFF; |
234 | twl->linkstat = status; | 239 | twl->linkstat = status; |
235 | musb_mailbox(status); | 240 | ret = musb_mailbox(status); |
241 | if (ret) | ||
242 | twl->linkstat = MUSB_UNKNOWN; | ||
236 | if (twl->asleep) { | 243 | if (twl->asleep) { |
237 | regulator_disable(twl->usb3v3); | 244 | regulator_disable(twl->usb3v3); |
238 | twl->asleep = 0; | 245 | twl->asleep = 0; |
@@ -264,7 +271,9 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) | |||
264 | twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET); | 271 | twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET); |
265 | status = MUSB_ID_GROUND; | 272 | status = MUSB_ID_GROUND; |
266 | twl->linkstat = status; | 273 | twl->linkstat = status; |
267 | musb_mailbox(status); | 274 | ret = musb_mailbox(status); |
275 | if (ret) | ||
276 | twl->linkstat = MUSB_UNKNOWN; | ||
268 | } else { | 277 | } else { |
269 | twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR); | 278 | twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR); |
270 | twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); | 279 | twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); |
@@ -274,6 +283,15 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) | |||
274 | return IRQ_HANDLED; | 283 | return IRQ_HANDLED; |
275 | } | 284 | } |
276 | 285 | ||
286 | static void twl6030_status_work(struct work_struct *work) | ||
287 | { | ||
288 | struct twl6030_usb *twl = container_of(work, struct twl6030_usb, | ||
289 | get_status_work.work); | ||
290 | |||
291 | twl6030_usb_irq(twl->irq2, twl); | ||
292 | twl6030_usbotg_irq(twl->irq1, twl); | ||
293 | } | ||
294 | |||
277 | static int twl6030_enable_irq(struct twl6030_usb *twl) | 295 | static int twl6030_enable_irq(struct twl6030_usb *twl) |
278 | { | 296 | { |
279 | twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); | 297 | twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); |
@@ -284,8 +302,6 @@ static int twl6030_enable_irq(struct twl6030_usb *twl) | |||
284 | REG_INT_MSK_LINE_C); | 302 | REG_INT_MSK_LINE_C); |
285 | twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, | 303 | twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, |
286 | REG_INT_MSK_STS_C); | 304 | REG_INT_MSK_STS_C); |
287 | twl6030_usb_irq(twl->irq2, twl); | ||
288 | twl6030_usbotg_irq(twl->irq1, twl); | ||
289 | 305 | ||
290 | return 0; | 306 | return 0; |
291 | } | 307 | } |
@@ -371,6 +387,7 @@ static int twl6030_usb_probe(struct platform_device *pdev) | |||
371 | dev_warn(&pdev->dev, "could not create sysfs file\n"); | 387 | dev_warn(&pdev->dev, "could not create sysfs file\n"); |
372 | 388 | ||
373 | INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work); | 389 | INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work); |
390 | INIT_DELAYED_WORK(&twl->get_status_work, twl6030_status_work); | ||
374 | 391 | ||
375 | status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, | 392 | status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, |
376 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | 393 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, |
@@ -395,6 +412,7 @@ static int twl6030_usb_probe(struct platform_device *pdev) | |||
395 | 412 | ||
396 | twl->asleep = 0; | 413 | twl->asleep = 0; |
397 | twl6030_enable_irq(twl); | 414 | twl6030_enable_irq(twl); |
415 | schedule_delayed_work(&twl->get_status_work, HZ); | ||
398 | dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); | 416 | dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); |
399 | 417 | ||
400 | return 0; | 418 | return 0; |
@@ -404,6 +422,7 @@ static int twl6030_usb_remove(struct platform_device *pdev) | |||
404 | { | 422 | { |
405 | struct twl6030_usb *twl = platform_get_drvdata(pdev); | 423 | struct twl6030_usb *twl = platform_get_drvdata(pdev); |
406 | 424 | ||
425 | cancel_delayed_work(&twl->get_status_work); | ||
407 | twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, | 426 | twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, |
408 | REG_INT_MSK_LINE_C); | 427 | REG_INT_MSK_LINE_C); |
409 | twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, | 428 | twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, |