ASoC: ts3a227e: do not report jack status when there is i2c read err
diff mbox

Message ID 1435724282-109761-1-git-send-email-yang.a.fang@intel.com
State New
Headers show

Commit Message

yang.a.fang@intel.com July 1, 2015, 4:18 a.m. UTC
From: "Fang, Yang A" <yang.a.fang@intel.com>

After suspend -> resume the ts3a227e_interrupt sometimes comes before i2c
controller resume is called .regmap_read will return incorrect status
and report a wrong jack status.We should return if there is read err,the
interrupt will come again since it is level triggered and we are not yet
clear the interrupt. In addtion,cht_bsw_max98090_ti machine driver
registered additional notifier base on jack event which will program
the audio codec.there will be codec timeout err if such event occurs
prior to i2c controller is resumed.

Signed-off-by: Fang, Yang A <yang.a.fang@intel.com>
---
 sound/soc/codecs/ts3a227e.c |   18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

Comments

Dylan Reid July 1, 2015, 5:12 p.m. UTC | #1
On Tue, Jun 30, 2015 at 9:18 PM,  <yang.a.fang@intel.com> wrote:
> From: "Fang, Yang A" <yang.a.fang@intel.com>
>
> After suspend -> resume the ts3a227e_interrupt sometimes comes before i2c
> controller resume is called .regmap_read will return incorrect status
> and report a wrong jack status.We should return if there is read err,the
> interrupt will come again since it is level triggered and we are not yet
> clear the interrupt. In addtion,cht_bsw_max98090_ti machine driver
> registered additional notifier base on jack event which will program
> the audio codec.there will be codec timeout err if such event occurs
> prior to i2c controller is resumed.

Thanks, I think the error checking is good to have anyway, but should
the interrupt also be disabled across suspend/resume?  I'd hope this
device's resume callback wouldn't happen until after the parent i2c
bus is ready.

>
> Signed-off-by: Fang, Yang A <yang.a.fang@intel.com>
> ---
>  sound/soc/codecs/ts3a227e.c |   18 ++++++++++++++++--
>  1 file changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
> index 12232d7..12d0f2a 100644
> --- a/sound/soc/codecs/ts3a227e.c
> +++ b/sound/soc/codecs/ts3a227e.c
> @@ -23,6 +23,7 @@
>  #include "ts3a227e.h"
>
>  struct ts3a227e {
> +       struct device *dev;
>         struct regmap *regmap;
>         struct snd_soc_jack *jack;
>         bool plugged;
> @@ -189,16 +190,28 @@ static irqreturn_t ts3a227e_interrupt(int irq, void *data)
>         struct ts3a227e *ts3a227e = (struct ts3a227e *)data;
>         struct regmap *regmap = ts3a227e->regmap;
>         unsigned int int_reg, kp_int_reg, acc_reg, i;
> +       struct device *dev = ts3a227e->dev;
> +       int ret;
>
>         /* Check for plug/unplug. */
> -       regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
> +       ret = regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
> +       if (ret) {
> +               dev_err(dev, "failed to clear interrupt ret=%d\n", ret);
> +               return IRQ_HANDLED;
> +       }
> +
>         if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) {
>                 regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg);
>                 ts3a227e_new_jack_state(ts3a227e, acc_reg);
>         }
>
>         /* Report any key events. */
> -       regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
> +       ret = regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
> +       if (ret) {
> +               dev_err(dev, "failed to clear key interrupt ret=%d\n", ret);
> +               return IRQ_HANDLED;
> +       }
> +
>         for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
>                 if (kp_int_reg & PRESS_MASK(i))
>                         ts3a227e->buttons_held |= (1 << i);
> @@ -283,6 +296,7 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
>                 return -ENOMEM;
>
>         i2c_set_clientdata(i2c, ts3a227e);
> +       ts3a227e->dev = dev;
>
>         ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config);
>         if (IS_ERR(ts3a227e->regmap))
> --
> 1.7.9.5
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
yang.a.fang@intel.com July 1, 2015, 5:34 p.m. UTC | #2
On Wed, Jul 01, 2015 at 10:12:37AM -0700, Dylan Reid wrote:
> On Tue, Jun 30, 2015 at 9:18 PM,  <yang.a.fang@intel.com> wrote:
> > From: "Fang, Yang A" <yang.a.fang@intel.com>
> >
> > After suspend -> resume the ts3a227e_interrupt sometimes comes before i2c
> > controller resume is called .regmap_read will return incorrect status
> > and report a wrong jack status.We should return if there is read err,the
> > interrupt will come again since it is level triggered and we are not yet
> > clear the interrupt. In addtion,cht_bsw_max98090_ti machine driver
> > registered additional notifier base on jack event which will program
> > the audio codec.there will be codec timeout err if such event occurs
> > prior to i2c controller is resumed.
> 
> Thanks, I think the error checking is good to have anyway, but should
> the interrupt also be disabled across suspend/resume?  I'd hope this
> device's resume callback wouldn't happen until after the parent i2c
> bus is ready.
I am looping Mika. I was expecting that interrupt would come after i2c
bus is ready. but with current pinctrl-cherryview driver the interrupt
comes in random order after resume.
> 
> >
> > Signed-off-by: Fang, Yang A <yang.a.fang@intel.com>
> > ---
> >  sound/soc/codecs/ts3a227e.c |   18 ++++++++++++++++--
> >  1 file changed, 16 insertions(+), 2 deletions(-)
> >
> > diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
> > index 12232d7..12d0f2a 100644
> > --- a/sound/soc/codecs/ts3a227e.c
> > +++ b/sound/soc/codecs/ts3a227e.c
> > @@ -23,6 +23,7 @@
> >  #include "ts3a227e.h"
> >
> >  struct ts3a227e {
> > +       struct device *dev;
> >         struct regmap *regmap;
> >         struct snd_soc_jack *jack;
> >         bool plugged;
> > @@ -189,16 +190,28 @@ static irqreturn_t ts3a227e_interrupt(int irq, void *data)
> >         struct ts3a227e *ts3a227e = (struct ts3a227e *)data;
> >         struct regmap *regmap = ts3a227e->regmap;
> >         unsigned int int_reg, kp_int_reg, acc_reg, i;
> > +       struct device *dev = ts3a227e->dev;
> > +       int ret;
> >
> >         /* Check for plug/unplug. */
> > -       regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
> > +       ret = regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
> > +       if (ret) {
> > +               dev_err(dev, "failed to clear interrupt ret=%d\n", ret);
> > +               return IRQ_HANDLED;
> > +       }
> > +
> >         if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) {
> >                 regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg);
> >                 ts3a227e_new_jack_state(ts3a227e, acc_reg);
> >         }
> >
> >         /* Report any key events. */
> > -       regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
> > +       ret = regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
> > +       if (ret) {
> > +               dev_err(dev, "failed to clear key interrupt ret=%d\n", ret);
> > +               return IRQ_HANDLED;
> > +       }
> > +
> >         for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
> >                 if (kp_int_reg & PRESS_MASK(i))
> >                         ts3a227e->buttons_held |= (1 << i);
> > @@ -283,6 +296,7 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
> >                 return -ENOMEM;
> >
> >         i2c_set_clientdata(i2c, ts3a227e);
> > +       ts3a227e->dev = dev;
> >
> >         ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config);
> >         if (IS_ERR(ts3a227e->regmap))
> > --
> > 1.7.9.5
> >
> > _______________________________________________
> > Alsa-devel mailing list
> > Alsa-devel@alsa-project.org
> > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Mark Brown July 1, 2015, 6:05 p.m. UTC | #3
On Wed, Jul 01, 2015 at 10:34:09AM -0700, Yang Fang wrote:
> On Wed, Jul 01, 2015 at 10:12:37AM -0700, Dylan Reid wrote:

> > Thanks, I think the error checking is good to have anyway, but should
> > the interrupt also be disabled across suspend/resume?  I'd hope this
> > device's resume callback wouldn't happen until after the parent i2c
> > bus is ready.

> I am looping Mika. I was expecting that interrupt would come after i2c
> bus is ready. but with current pinctrl-cherryview driver the interrupt
> comes in random order after resume.

I wouldn't rely on this, it's not going to be true in general - the
interrupt could flag at any time after the interrupt controller is
resumed so unless the I2C controller takes steps to ensure it is resumed
before interrupts (which has its own complications) you could get an
interrupt delivered prior to the I2C controller being ready.  Look at
how arizona handles this for one example of dealing with this problem,
though it's not ideal.
yang.a.fang@intel.com July 1, 2015, 6:24 p.m. UTC | #4
> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Wednesday, July 01, 2015 11:05 AM
> To: Fang, Yang A
> Cc: Dylan Reid; Liam Girdwood; alsa-devel@alsa-project.org; Sripathi, Srinivas;
> Jain, Praveen K; Iriawan, Denny; Nujella, Sathyanarayana;
> kevin.strasser@linux.intel.com; mika.westerberg@linux.intel.com
> Subject: Re: [alsa-devel] [PATCH] ASoC: ts3a227e: do not report jack status
> when there is i2c read err
> 
> On Wed, Jul 01, 2015 at 10:34:09AM -0700, Yang Fang wrote:
> > On Wed, Jul 01, 2015 at 10:12:37AM -0700, Dylan Reid wrote:
> 
> > > Thanks, I think the error checking is good to have anyway, but
> > > should the interrupt also be disabled across suspend/resume?  I'd
> > > hope this device's resume callback wouldn't happen until after the
> > > parent i2c bus is ready.
> 
> > I am looping Mika. I was expecting that interrupt would come after i2c
> > bus is ready. but with current pinctrl-cherryview driver the interrupt
> > comes in random order after resume.
> 
> I wouldn't rely on this, it's not going to be true in general - the interrupt could
> flag at any time after the interrupt controller is resumed so unless the I2C
> controller takes steps to ensure it is resumed before interrupts (which has its
> own complications) you could get an interrupt delivered prior to the I2C
> controller being ready.  Look at how arizona handles this for one example of
> dealing with this problem, though it's not ideal.

Thanks. i did a quick look at Arizona-core.c it disabled irq on suspend and enable irq
on resume.  I will give a try if this is what you referred to. 

In addition, current patch can address the issue even if the interrupt came prior to 
I2c bus is reumed . can I keep the err checking ?
yang.a.fang@intel.com July 1, 2015, 11:20 p.m. UTC | #5
> -----Original Message-----
> From: Fang, Yang A
> Sent: Wednesday, July 01, 2015 11:25 AM
> To: 'Mark Brown'
> Cc: Dylan Reid; Liam Girdwood; alsa-devel@alsa-project.org; Sripathi, Srinivas;
> Jain, Praveen K; Iriawan, Denny; Nujella, Sathyanarayana;
> kevin.strasser@linux.intel.com; mika.westerberg@linux.intel.com
> Subject: RE: [alsa-devel] [PATCH] ASoC: ts3a227e: do not report jack status
> when there is i2c read err
> 
> 
> 
> > -----Original Message-----
> > From: Mark Brown [mailto:broonie@kernel.org]
> > Sent: Wednesday, July 01, 2015 11:05 AM
> > To: Fang, Yang A
> > Cc: Dylan Reid; Liam Girdwood; alsa-devel@alsa-project.org; Sripathi,
> > Srinivas; Jain, Praveen K; Iriawan, Denny; Nujella, Sathyanarayana;
> > kevin.strasser@linux.intel.com; mika.westerberg@linux.intel.com
> > Subject: Re: [alsa-devel] [PATCH] ASoC: ts3a227e: do not report jack
> > status when there is i2c read err
> >
> > On Wed, Jul 01, 2015 at 10:34:09AM -0700, Yang Fang wrote:
> > > On Wed, Jul 01, 2015 at 10:12:37AM -0700, Dylan Reid wrote:
> >
> > > > Thanks, I think the error checking is good to have anyway, but
> > > > should the interrupt also be disabled across suspend/resume?  I'd
> > > > hope this device's resume callback wouldn't happen until after the
> > > > parent i2c bus is ready.
> >
> > > I am looping Mika. I was expecting that interrupt would come after
> > > i2c bus is ready. but with current pinctrl-cherryview driver the
> > > interrupt comes in random order after resume.
> >
> > I wouldn't rely on this, it's not going to be true in general - the
> > interrupt could flag at any time after the interrupt controller is
> > resumed so unless the I2C controller takes steps to ensure it is
> > resumed before interrupts (which has its own complications) you could
> > get an interrupt delivered prior to the I2C controller being ready.
> > Look at how arizona handles this for one example of dealing with this
> problem, though it's not ideal.
> 
> Thanks. i did a quick look at Arizona-core.c it disabled irq on suspend and
> enable irq on resume.  I will give a try if this is what you referred to.
> 
> In addition, current patch can address the issue even if the interrupt came
> prior to I2c bus is reumed . can I keep the err checking ?

Disable irq on suspend and enable irq on resume works well. I saw interrupt
 occurs after TI resume. I will post V2 patch

Patch
diff mbox

diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index 12232d7..12d0f2a 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -23,6 +23,7 @@ 
 #include "ts3a227e.h"
 
 struct ts3a227e {
+	struct device *dev;
 	struct regmap *regmap;
 	struct snd_soc_jack *jack;
 	bool plugged;
@@ -189,16 +190,28 @@  static irqreturn_t ts3a227e_interrupt(int irq, void *data)
 	struct ts3a227e *ts3a227e = (struct ts3a227e *)data;
 	struct regmap *regmap = ts3a227e->regmap;
 	unsigned int int_reg, kp_int_reg, acc_reg, i;
+	struct device *dev = ts3a227e->dev;
+	int ret;
 
 	/* Check for plug/unplug. */
-	regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
+	ret = regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
+	if (ret) {
+		dev_err(dev, "failed to clear interrupt ret=%d\n", ret);
+		return IRQ_HANDLED;
+	}
+
 	if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) {
 		regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg);
 		ts3a227e_new_jack_state(ts3a227e, acc_reg);
 	}
 
 	/* Report any key events. */
-	regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
+	ret = regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
+	if (ret) {
+		dev_err(dev, "failed to clear key interrupt ret=%d\n", ret);
+		return IRQ_HANDLED;
+	}
+
 	for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
 		if (kp_int_reg & PRESS_MASK(i))
 			ts3a227e->buttons_held |= (1 << i);
@@ -283,6 +296,7 @@  static int ts3a227e_i2c_probe(struct i2c_client *i2c,
 		return -ENOMEM;
 
 	i2c_set_clientdata(i2c, ts3a227e);
+	ts3a227e->dev = dev;
 
 	ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config);
 	if (IS_ERR(ts3a227e->regmap))