Skip to content

Commit

Permalink
ASoC: Use delayed work to debounce WM8350 jack IRQs
Browse files Browse the repository at this point in the history
This avoids blocking the IRQ thread and allows further bounces to extend
the debounce time.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
  • Loading branch information
Mark Brown committed Dec 22, 2010
1 parent 722bc28 commit 6d3c26b
Showing 1 changed file with 43 additions and 19 deletions.
62 changes: 43 additions & 19 deletions sound/soc/codecs/wm8350.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct wm8350_output {

struct wm8350_jack_data {
struct snd_soc_jack *jack;
struct delayed_work work;
int report;
int short_report;
};
Expand Down Expand Up @@ -1335,45 +1336,63 @@ static int wm8350_resume(struct snd_soc_codec *codec)
return 0;
}

static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
static void wm8350_hp_work(struct wm8350_data *priv,
struct wm8350_jack_data *jack,
u16 mask)
{
struct wm8350_data *priv = data;
struct wm8350 *wm8350 = priv->codec.control_data;
u16 reg;
int report;
int mask;

reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
if (reg & mask)
report = jack->report;
else
report = 0;

snd_soc_jack_report(jack->jack, report, jack->report);

}

static void wm8350_hpl_work(struct work_struct *work)
{
struct wm8350_data *priv =
container_of(work, struct wm8350_data, hpl.work.work);

wm8350_hp_work(priv, &priv->hpl, WM8350_JACK_L_LVL);
}

static void wm8350_hpr_work(struct work_struct *work)
{
struct wm8350_data *priv =
container_of(work, struct wm8350_data, hpr.work.work);

wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
}

static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
{
struct wm8350_data *priv = data;
struct wm8350 *wm8350 = priv->codec.control_data;
struct wm8350_jack_data *jack = NULL;

switch (irq - wm8350->irq_base) {
case WM8350_IRQ_CODEC_JCK_DET_L:
jack = &priv->hpl;
mask = WM8350_JACK_L_LVL;
break;

case WM8350_IRQ_CODEC_JCK_DET_R:
jack = &priv->hpr;
mask = WM8350_JACK_R_LVL;
break;

default:
BUG();
}

if (!jack->jack) {
dev_warn(wm8350->dev, "Jack interrupt called with no jack\n");
return IRQ_NONE;
}
if (device_may_wakeup(wm8350->dev))
pm_wakeup_event(wm8350->dev, 250);

/* Debounce */
msleep(200);

reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
if (reg & mask)
report = jack->report;
else
report = 0;

snd_soc_jack_report(jack->jack, report, jack->report);
schedule_delayed_work(&jack->work, 200);

return IRQ_HANDLED;
}
Expand Down Expand Up @@ -1552,6 +1571,8 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);

INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work);
INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work);
INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work);

/* Enable the codec */
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
Expand Down Expand Up @@ -1641,6 +1662,9 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec)
priv->hpr.jack = NULL;
priv->mic.jack = NULL;

cancel_delayed_work_sync(&priv->hpl.work);
cancel_delayed_work_sync(&priv->hpr.work);

/* if there was any work waiting then we run it now and
* wait for its completion */
flush_delayed_work_sync(&codec->dapm.delayed_work);
Expand Down

0 comments on commit 6d3c26b

Please sign in to comment.