USB: msm_otg: Check ID state before entering into LPM
Fix a possible bug where id interrupt is not monitored during ID
detection circuit switch between ACA and PMIC. This can happen
during quick Micro-A cable reconnection.
(cherry picked from commit becab5ba0d6a342612ff31ff9514e324f2f02517)
CRs-Fixed: 404516
Change-Id: I7e7edda54d1a9f5c4334cab1c48413c7461df2f1
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Signed-off-by: Neha Pandey <nehap@codeaurora.org>
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index f1fef85..c69bc04 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1457,6 +1457,26 @@
return 0;
}
+static bool msm_otg_read_pmic_id_state(struct msm_otg *motg)
+{
+ unsigned long flags;
+ int id;
+
+ if (!motg->pdata->pmic_id_irq)
+ return -ENODEV;
+
+ local_irq_save(flags);
+ id = irq_read_line(motg->pdata->pmic_id_irq);
+ local_irq_restore(flags);
+
+ /*
+ * If we can not read ID line state for some reason, treat
+ * it as float. This would prevent MHL discovery and kicking
+ * host mode unnecessarily.
+ */
+ return !!id;
+}
+
static int msm_otg_mhl_register_callback(struct msm_otg *motg,
void (*callback)(int on))
{
@@ -1534,14 +1554,11 @@
static bool msm_chg_mhl_detect(struct msm_otg *motg)
{
bool ret, id;
- unsigned long flags;
if (!motg->mhl_enabled)
return false;
- local_irq_save(flags);
- id = irq_read_line(motg->pdata->pmic_id_irq);
- local_irq_restore(flags);
+ id = msm_otg_read_pmic_id_state(motg);
if (id)
return false;
@@ -2186,13 +2203,10 @@
clear_bit(B_SESS_VLD, &motg->inputs);
} else if (pdata->otg_control == OTG_PMIC_CONTROL) {
if (pdata->pmic_id_irq) {
- unsigned long flags;
- local_irq_save(flags);
- if (irq_read_line(pdata->pmic_id_irq))
+ if (msm_otg_read_pmic_id_state(motg))
set_bit(ID, &motg->inputs);
else
clear_bit(ID, &motg->inputs);
- local_irq_restore(flags);
}
/*
* VBUS initial state is reported after PMIC
@@ -2343,6 +2357,18 @@
motg->chg_type = USB_INVALID_CHARGER;
msm_otg_notify_charger(motg, 0);
msm_otg_reset(otg->phy);
+ /*
+ * There is a small window where ID interrupt
+ * is not monitored during ID detection circuit
+ * switch from ACA to PMIC. Check ID state
+ * before entering into low power mode.
+ */
+ if (!msm_otg_read_pmic_id_state(motg)) {
+ pr_debug("process missed ID intr\n");
+ clear_bit(ID, &motg->inputs);
+ work = 1;
+ break;
+ }
pm_runtime_put_noidle(otg->phy->dev);
pm_runtime_suspend(otg->phy->dev);
}
@@ -2994,10 +3020,8 @@
struct msm_otg *motg = container_of(w, struct msm_otg,
pmic_id_status_work.work);
int work = 0;
- unsigned long flags;
- local_irq_save(flags);
- if (irq_read_line(motg->pdata->pmic_id_irq)) {
+ if (msm_otg_read_pmic_id_state(motg)) {
if (!test_and_set_bit(ID, &motg->inputs)) {
pr_debug("PMIC: ID set\n");
work = 1;
@@ -3016,7 +3040,6 @@
else
queue_work(system_nrt_wq, &motg->sm_work);
}
- local_irq_restore(flags);
}