Skip to content

Commit

Permalink
ASoC: ts3a227e: do not report jack status when there is i2c read err
Browse files Browse the repository at this point in the history
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.This patch will disable irq on suspend
and enable irq again on the resume to make sure interrupt is coming
after TI resumes. Also 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>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Fang, Yang A authored and Mark Brown committed Jul 8, 2015
1 parent d770e55 commit c4a99a4
Showing 1 changed file with 45 additions and 2 deletions.
47 changes: 45 additions & 2 deletions sound/soc/codecs/ts3a227e.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
#include "ts3a227e.h"

struct ts3a227e {
struct device *dev;
struct regmap *regmap;
struct snd_soc_jack *jack;
bool plugged;
bool mic_present;
unsigned int buttons_held;
int irq;
};

/* Button values to be reported on the jack */
Expand Down Expand Up @@ -189,16 +191,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_NONE;
}

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_NONE;
}

for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
if (kp_int_reg & PRESS_MASK(i))
ts3a227e->buttons_held |= (1 << i);
Expand Down Expand Up @@ -283,6 +297,8 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;

i2c_set_clientdata(i2c, ts3a227e);
ts3a227e->dev = dev;
ts3a227e->irq = i2c->irq;

ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config);
if (IS_ERR(ts3a227e->regmap))
Expand Down Expand Up @@ -320,6 +336,32 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
return 0;
}

#ifdef CONFIG_PM_SLEEP
static int ts3a227e_suspend(struct device *dev)
{
struct ts3a227e *ts3a227e = dev_get_drvdata(dev);

dev_dbg(ts3a227e->dev, "suspend disable irq\n");
disable_irq(ts3a227e->irq);

return 0;
}

static int ts3a227e_resume(struct device *dev)
{
struct ts3a227e *ts3a227e = dev_get_drvdata(dev);

dev_dbg(ts3a227e->dev, "resume enable irq\n");
enable_irq(ts3a227e->irq);

return 0;
}
#endif

static const struct dev_pm_ops ts3a227e_pm = {
SET_SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume)
};

static const struct i2c_device_id ts3a227e_i2c_ids[] = {
{ "ts3a227e", 0 },
{ }
Expand All @@ -336,6 +378,7 @@ static struct i2c_driver ts3a227e_driver = {
.driver = {
.name = "ts3a227e",
.owner = THIS_MODULE,
.pm = &ts3a227e_pm,
.of_match_table = of_match_ptr(ts3a227e_of_match),
},
.probe = ts3a227e_i2c_probe,
Expand Down

0 comments on commit c4a99a4

Please sign in to comment.