diff options
author | Tony Lindgren <tony@atomide.com> | 2014-08-24 08:14:22 -0400 |
---|---|---|
committer | Kishon Vijay Abraham I <kishon@ti.com> | 2014-08-24 08:17:54 -0400 |
commit | 85601b8d81e24ce9ae2d31e93f35468ab7616b18 (patch) | |
tree | 7e80131fa23c9bd0077da659af6a1e145d6ab2c6 /drivers/phy | |
parent | 96be39ab34b77c6f6f5cd6ae03aac6c6449ee5c4 (diff) |
usb: phy: twl4030-usb: Fix lost interrupts after ID pin goes down
Commit 249751f22380 ("usb: phy: twl4030-usb: poll for ID disconnect")
added twl4030_id_workaround_work() to deal with lost interrupts
after ID pin goes down. Looks like commit f1ddc24c9e33 ("usb: phy:
twl4030-usb: remove *set_suspend* and *phy_init* ops") changed
things around for the generic phy framework, and delayed work no
longer got called except initially during boot.
The PHY connect and disconnect interrupts for twl4030-usb are not
working after disconnecting a USB-A cable from the board, and the
deeper idle states for omap are blocked as the USB controller
stays busy.
The issue can be solved by calling delayed work from twl4030_usb_irq()
when ID pin is down and the PHY is not asleep like we already do
in twl4030_id_workaround_work().
But as both twl4030_usb_irq() and twl4030_id_workaround_work()
already do pretty much the same thing, let's call twl4030_usb_irq()
from twl4030_id_workaround_work() instead of adding some more
duplicate code. We also must call sysfs_notify() only when we have
an interrupt and not from the delayed work as notified by
Grazvydas Ignotas <notasas@gmail.com>.
Fixes: f1ddc24c9e33 ("usb: phy: twl4030-usb: remove *set_suspend* and *phy_init* ops")
Cc: stable@vger.kernel.org # v3.13+
Acked-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/phy-twl4030-usb.c | 33 |
1 files changed, 10 insertions, 23 deletions
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 0cb872bdbe7e..9cd33a4bcfb1 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c | |||
@@ -589,7 +589,15 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) | |||
589 | } | 589 | } |
590 | omap_musb_mailbox(status); | 590 | omap_musb_mailbox(status); |
591 | } | 591 | } |
592 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); | 592 | |
593 | /* don't schedule during sleep - irq works right then */ | ||
594 | if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) { | ||
595 | cancel_delayed_work(&twl->id_workaround_work); | ||
596 | schedule_delayed_work(&twl->id_workaround_work, HZ); | ||
597 | } | ||
598 | |||
599 | if (irq) | ||
600 | sysfs_notify(&twl->dev->kobj, NULL, "vbus"); | ||
593 | 601 | ||
594 | return IRQ_HANDLED; | 602 | return IRQ_HANDLED; |
595 | } | 603 | } |
@@ -598,29 +606,8 @@ static void twl4030_id_workaround_work(struct work_struct *work) | |||
598 | { | 606 | { |
599 | struct twl4030_usb *twl = container_of(work, struct twl4030_usb, | 607 | struct twl4030_usb *twl = container_of(work, struct twl4030_usb, |
600 | id_workaround_work.work); | 608 | id_workaround_work.work); |
601 | enum omap_musb_vbus_id_status status; | ||
602 | bool status_changed = false; | ||
603 | |||
604 | status = twl4030_usb_linkstat(twl); | ||
605 | |||
606 | spin_lock_irq(&twl->lock); | ||
607 | if (status >= 0 && status != twl->linkstat) { | ||
608 | twl->linkstat = status; | ||
609 | status_changed = true; | ||
610 | } | ||
611 | spin_unlock_irq(&twl->lock); | ||
612 | |||
613 | if (status_changed) { | ||
614 | dev_dbg(twl->dev, "handle missing status change to %d\n", | ||
615 | status); | ||
616 | omap_musb_mailbox(status); | ||
617 | } | ||
618 | 609 | ||
619 | /* don't schedule during sleep - irq works right then */ | 610 | twl4030_usb_irq(0, twl); |
620 | if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) { | ||
621 | cancel_delayed_work(&twl->id_workaround_work); | ||
622 | schedule_delayed_work(&twl->id_workaround_work, HZ); | ||
623 | } | ||
624 | } | 611 | } |
625 | 612 | ||
626 | static int twl4030_phy_init(struct phy *phy) | 613 | static int twl4030_phy_init(struct phy *phy) |