diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-12-05 07:41:52 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-12-22 06:08:45 -0500 |
commit | 6d3c26bcb7a129a11a54d78644e264ec872547e1 (patch) | |
tree | dba0757ba053f29e83521f783a746a29269a83fd | |
parent | 722bc28384accb67c0bfbbe1914fd82d4d0c996a (diff) |
ASoC: Use delayed work to debounce WM8350 jack IRQs
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>
-rw-r--r-- | sound/soc/codecs/wm8350.c | 62 |
1 files changed, 43 insertions, 19 deletions
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 07ba7e3f6a8c..3e0362e62f8f 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -53,6 +53,7 @@ struct wm8350_output { | |||
53 | 53 | ||
54 | struct wm8350_jack_data { | 54 | struct wm8350_jack_data { |
55 | struct snd_soc_jack *jack; | 55 | struct snd_soc_jack *jack; |
56 | struct delayed_work work; | ||
56 | int report; | 57 | int report; |
57 | int short_report; | 58 | int short_report; |
58 | }; | 59 | }; |
@@ -1335,45 +1336,63 @@ static int wm8350_resume(struct snd_soc_codec *codec) | |||
1335 | return 0; | 1336 | return 0; |
1336 | } | 1337 | } |
1337 | 1338 | ||
1338 | static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) | 1339 | static void wm8350_hp_work(struct wm8350_data *priv, |
1340 | struct wm8350_jack_data *jack, | ||
1341 | u16 mask) | ||
1339 | { | 1342 | { |
1340 | struct wm8350_data *priv = data; | ||
1341 | struct wm8350 *wm8350 = priv->codec.control_data; | 1343 | struct wm8350 *wm8350 = priv->codec.control_data; |
1342 | u16 reg; | 1344 | u16 reg; |
1343 | int report; | 1345 | int report; |
1344 | int mask; | 1346 | |
1347 | reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); | ||
1348 | if (reg & mask) | ||
1349 | report = jack->report; | ||
1350 | else | ||
1351 | report = 0; | ||
1352 | |||
1353 | snd_soc_jack_report(jack->jack, report, jack->report); | ||
1354 | |||
1355 | } | ||
1356 | |||
1357 | static void wm8350_hpl_work(struct work_struct *work) | ||
1358 | { | ||
1359 | struct wm8350_data *priv = | ||
1360 | container_of(work, struct wm8350_data, hpl.work.work); | ||
1361 | |||
1362 | wm8350_hp_work(priv, &priv->hpl, WM8350_JACK_L_LVL); | ||
1363 | } | ||
1364 | |||
1365 | static void wm8350_hpr_work(struct work_struct *work) | ||
1366 | { | ||
1367 | struct wm8350_data *priv = | ||
1368 | container_of(work, struct wm8350_data, hpr.work.work); | ||
1369 | |||
1370 | wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL); | ||
1371 | } | ||
1372 | |||
1373 | static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) | ||
1374 | { | ||
1375 | struct wm8350_data *priv = data; | ||
1376 | struct wm8350 *wm8350 = priv->codec.control_data; | ||
1345 | struct wm8350_jack_data *jack = NULL; | 1377 | struct wm8350_jack_data *jack = NULL; |
1346 | 1378 | ||
1347 | switch (irq - wm8350->irq_base) { | 1379 | switch (irq - wm8350->irq_base) { |
1348 | case WM8350_IRQ_CODEC_JCK_DET_L: | 1380 | case WM8350_IRQ_CODEC_JCK_DET_L: |
1349 | jack = &priv->hpl; | 1381 | jack = &priv->hpl; |
1350 | mask = WM8350_JACK_L_LVL; | ||
1351 | break; | 1382 | break; |
1352 | 1383 | ||
1353 | case WM8350_IRQ_CODEC_JCK_DET_R: | 1384 | case WM8350_IRQ_CODEC_JCK_DET_R: |
1354 | jack = &priv->hpr; | 1385 | jack = &priv->hpr; |
1355 | mask = WM8350_JACK_R_LVL; | ||
1356 | break; | 1386 | break; |
1357 | 1387 | ||
1358 | default: | 1388 | default: |
1359 | BUG(); | 1389 | BUG(); |
1360 | } | 1390 | } |
1361 | 1391 | ||
1362 | if (!jack->jack) { | 1392 | if (device_may_wakeup(wm8350->dev)) |
1363 | dev_warn(wm8350->dev, "Jack interrupt called with no jack\n"); | 1393 | pm_wakeup_event(wm8350->dev, 250); |
1364 | return IRQ_NONE; | ||
1365 | } | ||
1366 | 1394 | ||
1367 | /* Debounce */ | 1395 | schedule_delayed_work(&jack->work, 200); |
1368 | msleep(200); | ||
1369 | |||
1370 | reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); | ||
1371 | if (reg & mask) | ||
1372 | report = jack->report; | ||
1373 | else | ||
1374 | report = 0; | ||
1375 | |||
1376 | snd_soc_jack_report(jack->jack, report, jack->report); | ||
1377 | 1396 | ||
1378 | return IRQ_HANDLED; | 1397 | return IRQ_HANDLED; |
1379 | } | 1398 | } |
@@ -1552,6 +1571,8 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) | |||
1552 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); | 1571 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); |
1553 | 1572 | ||
1554 | INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work); | 1573 | INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work); |
1574 | INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work); | ||
1575 | INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work); | ||
1555 | 1576 | ||
1556 | /* Enable the codec */ | 1577 | /* Enable the codec */ |
1557 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); | 1578 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); |
@@ -1641,6 +1662,9 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) | |||
1641 | priv->hpr.jack = NULL; | 1662 | priv->hpr.jack = NULL; |
1642 | priv->mic.jack = NULL; | 1663 | priv->mic.jack = NULL; |
1643 | 1664 | ||
1665 | cancel_delayed_work_sync(&priv->hpl.work); | ||
1666 | cancel_delayed_work_sync(&priv->hpr.work); | ||
1667 | |||
1644 | /* if there was any work waiting then we run it now and | 1668 | /* if there was any work waiting then we run it now and |
1645 | * wait for its completion */ | 1669 | * wait for its completion */ |
1646 | flush_delayed_work_sync(&codec->dapm.delayed_work); | 1670 | flush_delayed_work_sync(&codec->dapm.delayed_work); |