From 2655e6ac0981113fe8a3833f6a739337f3638650 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Tue, 26 Feb 2013 01:11:22 +0200 Subject: [PATCH] usb: otg: twl4030-usb: check if vbus is driven by twl itself At least on pandora, STS_VBUS gets set even when VBUS is driven by twl itself. Reporting VBUS in this case confuses OMAP musb glue and charger driver, so check if OTG VBUS charge pump is on before reporting VBUS event to avoid this problem. --- drivers/usb/otg/twl4030-usb.c | 38 ++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index f5904763ac9f..3374fbeb33bb 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -246,10 +246,30 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits) /*-------------------------------------------------------------------------*/ +static bool twl4030_is_driving_vbus(struct twl4030_usb *twl) +{ + int ret; + + ret = twl4030_usb_read(twl, PHY_CLK_CTRL_STS); + if (ret < 0 || !(ret & PHY_DPLL_CLK)) + /* + * if clocks are off, registers are not updated, + * but we can assume we don't drive VBUS in this case + */ + return false; + + ret = twl4030_usb_read(twl, ULPI_OTG_CTRL); + if (ret < 0) + return false; + + return (ret & (ULPI_OTG_DRVVBUS | ULPI_OTG_CHRGVBUS)) ? true : false; +} + static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl) { int status; int linkstat = USB_EVENT_NONE; + bool driving_vbus = false; twl->vbus_supplied = false; @@ -268,18 +288,22 @@ static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl) if (status < 0) dev_err(twl->dev, "USB link status err %d\n", status); else if (status & (BIT(7) | BIT(2))) { - if (status & (BIT(7))) - twl->vbus_supplied = true; + if (status & BIT(7)) { + driving_vbus = twl4030_is_driving_vbus(twl); + if (driving_vbus) + status &= ~BIT(7); + } if (status & BIT(2)) linkstat = USB_EVENT_ID; - else + else if (status & BIT(7)) { linkstat = USB_EVENT_VBUS; - } else - linkstat = USB_EVENT_NONE; + twl->vbus_supplied = true; + } + } - dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", - status, status, linkstat); + dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x; link %d, driving_vbus %d\n", + status, linkstat, driving_vbus); if (twl->otg.last_event == linkstat) return linkstat; -- 2.39.2