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>
This commit is contained in:
Pavankumar Kondeti 2012-11-06 16:45:10 +05:30 committed by Stephen Boyd
parent e4d7ef596b
commit d4bc4c74ff

View file

@ -1457,6 +1457,26 @@ static int msm_otg_set_peripheral(struct usb_otg *otg,
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_otg_is_mhl(struct msm_otg *motg)
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 @@ static void msm_otg_init_sm(struct msm_otg *motg)
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 @@ static void msm_otg_sm_work(struct work_struct *w)
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 @@ static void msm_pmic_id_status_w(struct work_struct *w)
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 @@ static void msm_pmic_id_status_w(struct work_struct *w)
else
queue_work(system_nrt_wq, &motg->sm_work);
}
local_irq_restore(flags);
}