Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 364759
b: refs/heads/master
c: 249751f
h: refs/heads/master
i:
  364757: 2cf9112
  364755: efaa2f9
  364751: 82f39a1
v: v3
  • Loading branch information
Grazvydas Ignotas authored and Felipe Balbi committed Mar 21, 2013
1 parent 253c6e8 commit c0f25dd
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 15460de7f3d9cf0846af1cfdb4a3995d2f270ce7
refs/heads/master: 249751f22380386042056cce6a73c934f5b942a3
64 changes: 57 additions & 7 deletions trunk/drivers/usb/phy/phy-twl4030-usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ struct twl4030_usb {
bool vbus_supplied;
u8 asleep;
bool irq_enabled;

struct delayed_work id_workaround_work;
};

/* internal define on top of container_of */
Expand Down Expand Up @@ -287,10 +289,6 @@ static enum omap_musb_vbus_id_status
* are registered, and that both are active...
*/

spin_lock_irq(&twl->lock);
twl->linkstat = linkstat;
spin_unlock_irq(&twl->lock);

return linkstat;
}

Expand Down Expand Up @@ -412,6 +410,16 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
__twl4030_phy_resume(twl);
twl->asleep = 0;
dev_dbg(twl->dev, "%s\n", __func__);

/*
* XXX When VBUS gets driven after musb goes to A mode,
* ID_PRES related interrupts no longer arrive, why?
* Register itself is updated fine though, so we must poll.
*/
if (twl->linkstat == OMAP_MUSB_ID_GROUND) {
cancel_delayed_work(&twl->id_workaround_work);
schedule_delayed_work(&twl->id_workaround_work, HZ);
}
}

static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
Expand Down Expand Up @@ -483,10 +491,18 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
{
struct twl4030_usb *twl = _twl;
enum omap_musb_vbus_id_status status;
enum omap_musb_vbus_id_status status_prev = twl->linkstat;
bool status_changed = false;

status = twl4030_usb_linkstat(twl);
if (status > 0 && status != status_prev) {

spin_lock_irq(&twl->lock);
if (status >= 0 && status != twl->linkstat) {
twl->linkstat = status;
status_changed = true;
}
spin_unlock_irq(&twl->lock);

if (status_changed) {
/* FIXME add a set_power() method so that B-devices can
* configure the charger appropriately. It's not always
* correct to consume VBUS power, and how much current to
Expand All @@ -498,13 +514,42 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
* USB_LINK_VBUS state. musb_hdrc won't care until it
* starts to handle softconnect right.
*/
omap_musb_mailbox(twl->linkstat);
omap_musb_mailbox(status);
}
sysfs_notify(&twl->dev->kobj, NULL, "vbus");

return IRQ_HANDLED;
}

static void twl4030_id_workaround_work(struct work_struct *work)
{
struct twl4030_usb *twl = container_of(work, struct twl4030_usb,
id_workaround_work.work);
enum omap_musb_vbus_id_status status;
bool status_changed = false;

status = twl4030_usb_linkstat(twl);

spin_lock_irq(&twl->lock);
if (status >= 0 && status != twl->linkstat) {
twl->linkstat = status;
status_changed = true;
}
spin_unlock_irq(&twl->lock);

if (status_changed) {
dev_dbg(twl->dev, "handle missing status change to %d\n",
status);
omap_musb_mailbox(status);
}

/* don't schedule during sleep - irq works right then */
if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) {
cancel_delayed_work(&twl->id_workaround_work);
schedule_delayed_work(&twl->id_workaround_work, HZ);
}
}

static int twl4030_usb_phy_init(struct usb_phy *phy)
{
struct twl4030_usb *twl = phy_to_twl(phy);
Expand All @@ -518,6 +563,8 @@ static int twl4030_usb_phy_init(struct usb_phy *phy)
twl->asleep = 1;

status = twl4030_usb_linkstat(twl);
twl->linkstat = status;

if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID)
omap_musb_mailbox(twl->linkstat);

Expand Down Expand Up @@ -608,6 +655,8 @@ static int twl4030_usb_probe(struct platform_device *pdev)
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);

INIT_DELAYED_WORK(&twl->id_workaround_work, twl4030_id_workaround_work);

err = twl4030_usb_ldo_init(twl);
if (err) {
dev_err(&pdev->dev, "ldo init failed\n");
Expand Down Expand Up @@ -646,6 +695,7 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
struct twl4030_usb *twl = platform_get_drvdata(pdev);
int val;

cancel_delayed_work(&twl->id_workaround_work);
device_remove_file(twl->dev, &dev_attr_vbus);

/* set transceiver mode to power on defaults */
Expand Down

0 comments on commit c0f25dd

Please sign in to comment.