i2c-msm-v2: Fix for unhandle IRQ

I2C msm v2 driver handle scenario where runtime
PM is not enabled and enables clocks explicitly.
I2C qup driver handle scenario where runtime
PM is not enabled and enables clocks explicitly.
But it checks runtime PM suspended state in ISR
routine before processing further which can lead to
issue of unhandled valid IRQ sometimes because I2C
client can initiate transaction very early after system
resume and runtime PM is not enabled.

Add atomic flag to synchronize between active transaction
request when clocks are enabled and ISR.

CRs-Fixed: 671063
Change-Id: Ic57afe0cfb0815746d9590157fbdde6ea53b9c18
Signed-off-by: Sana Venkat Raju <c_vsana@codeaurora.org>
Signed-off-by: Alok Chauhan <alokc@codeaurora.org>
This commit is contained in:
Sana Venkat Raju 2014-05-23 11:31:07 +05:30 committed by Gerrit - the friendly Code Review server
parent 29fdcf3656
commit 9e98a0b835
2 changed files with 15 additions and 12 deletions

View file

@ -2254,24 +2254,18 @@ static irqreturn_t i2c_msm_qup_isr(int irq, void *devid)
u32 clr_flds = 0; u32 clr_flds = 0;
bool dump_details = false; bool dump_details = false;
bool log_event = false; bool log_event = false;
bool spurious_irq = false;
bool signal_complete = false; bool signal_complete = false;
i2c_msm_prof_evnt_add(ctrl, MSM_PROF, i2c_msm_prof_dump_irq_begn, i2c_msm_prof_evnt_add(ctrl, MSM_PROF, i2c_msm_prof_dump_irq_begn,
irq, 0, 0); irq, 0, 0);
if (pm_runtime_suspended(ctrl->dev)) { if (!atomic_read(&ctrl->is_ctrl_active)) {
dev_info(ctrl->dev, dev_info(ctrl->dev, "irq:%d when PM suspended\n", irq);
"irq:%d when PM suspended\n", irq); return IRQ_NONE;
spurious_irq = true;
} }
if (!ctrl->xfer.msgs) { if (!ctrl->xfer.msgs) {
dev_info(ctrl->dev, "irq:%d when no active transfer\n", irq); dev_info(ctrl->dev, "irq:%d when no active transfer\n", irq);
spurious_irq = true;
}
if (spurious_irq) {
writel_relaxed(QUP_STATE_RESET, base + QUP_STATE); writel_relaxed(QUP_STATE_RESET, base + QUP_STATE);
/* Ensure that state is written before ISR exits */ /* Ensure that state is written before ISR exits */
wmb(); wmb();
@ -2848,7 +2842,8 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
i2c_msm_prof_evnt_dump(ctrl); i2c_msm_prof_evnt_dump(ctrl);
/* mark end of transfer */ /* mark end of transfer */
xfer->msg_cnt = 0; xfer->msg_cnt = 0;
xfer->msgs = NULL;
mutex_unlock(&ctrl->mlock); mutex_unlock(&ctrl->mlock);
return ret; return ret;
} }
@ -3417,6 +3412,7 @@ static int i2c_msm_pm_resume_impl(struct device *dev)
enable_irq(ctrl->rsrcs.irq); enable_irq(ctrl->rsrcs.irq);
(*ctrl->ver.init)(ctrl); (*ctrl->ver.init)(ctrl);
ctrl->pwr_state = MSM_I2C_PM_ACTIVE; ctrl->pwr_state = MSM_I2C_PM_ACTIVE;
atomic_set(&ctrl->is_ctrl_active, 1);
return 0; return 0;
} }
@ -3435,6 +3431,7 @@ static int i2c_msm_pm_sys_suspend_noirq(struct device *dev)
mutex_lock(&ctrl->mlock); mutex_lock(&ctrl->mlock);
ctrl->pwr_state = MSM_I2C_PM_SYS_SUSPENDED; ctrl->pwr_state = MSM_I2C_PM_SYS_SUSPENDED;
mutex_unlock(&ctrl->mlock); mutex_unlock(&ctrl->mlock);
atomic_set(&ctrl->is_ctrl_active, 0);
if (curr_state == MSM_I2C_PM_ACTIVE) { if (curr_state == MSM_I2C_PM_ACTIVE) {
ret = i2c_msm_pm_suspend_impl(dev); ret = i2c_msm_pm_suspend_impl(dev);
@ -3466,6 +3463,7 @@ static int i2c_msm_pm_sys_resume_noirq(struct device *dev)
*/ */
i2c_msm_dbg(ctrl, MSM_DBG, "pm_sys_noirq: resuming..."); i2c_msm_dbg(ctrl, MSM_DBG, "pm_sys_noirq: resuming...");
ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; ctrl->pwr_state = MSM_I2C_PM_SUSPENDED;
atomic_set(&ctrl->is_ctrl_active, 0);
return 0; return 0;
} }
#endif #endif
@ -3490,6 +3488,7 @@ static int i2c_msm_pm_rt_suspend(struct device *dev)
i2c_msm_dbg(ctrl, MSM_DBG, "pm_runtime: suspending..."); i2c_msm_dbg(ctrl, MSM_DBG, "pm_runtime: suspending...");
ret = i2c_msm_pm_suspend_impl(dev); ret = i2c_msm_pm_suspend_impl(dev);
ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; ctrl->pwr_state = MSM_I2C_PM_SUSPENDED;
atomic_set(&ctrl->is_ctrl_active, 0);
return ret; return ret;
} }
@ -3536,6 +3535,7 @@ static void i2c_msm_pm_suspend_adptr(struct i2c_msm_ctrl *ctrl)
i2c_msm_pm_suspend_clk(ctrl); i2c_msm_pm_suspend_clk(ctrl);
i2c_msm_pm_suspend_impl(ctrl->dev); i2c_msm_pm_suspend_impl(ctrl->dev);
ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; ctrl->pwr_state = MSM_I2C_PM_SUSPENDED;
atomic_set(&ctrl->is_ctrl_active, 0);
} }
#endif #endif
@ -3605,6 +3605,7 @@ static int i2c_msm_probe(struct platform_device *pdev)
ctrl->dbgfs.force_xfer_mode = I2C_MSM_XFER_MODE_NONE; ctrl->dbgfs.force_xfer_mode = I2C_MSM_XFER_MODE_NONE;
mutex_init(&ctrl->mlock); mutex_init(&ctrl->mlock);
ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; ctrl->pwr_state = MSM_I2C_PM_SUSPENDED;
atomic_set(&ctrl->is_ctrl_active, 0);
if (!pdev->dev.of_node) { if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "error: null device-tree node"); dev_err(&pdev->dev, "error: null device-tree node");
@ -3700,6 +3701,7 @@ static int i2c_msm_remove(struct platform_device *pdev)
mutex_lock(&ctrl->mlock); mutex_lock(&ctrl->mlock);
ctrl->pwr_state = MSM_I2C_PM_SYS_SUSPENDED; ctrl->pwr_state = MSM_I2C_PM_SYS_SUSPENDED;
mutex_unlock(&ctrl->mlock); mutex_unlock(&ctrl->mlock);
atomic_set(&ctrl->is_ctrl_active, 0);
i2c_msm_pm_suspend_impl(ctrl->dev); i2c_msm_pm_suspend_impl(ctrl->dev);
mutex_destroy(&ctrl->mlock); mutex_destroy(&ctrl->mlock);

View file

@ -652,8 +652,9 @@ struct i2c_msm_ctrl {
int noise_rjct_scl; int noise_rjct_scl;
int noise_rjct_sda; int noise_rjct_sda;
struct i2c_msm_v2_platform_data *pdata; struct i2c_msm_v2_platform_data *pdata;
enum msm_i2c_power_state pwr_state; enum msm_i2c_power_state pwr_state;
struct mutex mlock; atomic_t is_ctrl_active;
struct mutex mlock;
}; };
#endif /* _I2C_MSM_V2_H */ #endif /* _I2C_MSM_V2_H */