aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-03-15 17:22:58 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-03-16 11:57:43 -0400
commit7245387e36e16ae918467685c34510606fd74b7c (patch)
tree40ecf5eb8fb9eaa287c37d0dd99645380d3b0b90
parent8abd16a65d81756706016720e2cc7eeb81d06a2e (diff)
ASoC: Implement interrupt driven microphone detection for WM8903
Support use of the WM8903 IRQ for reporting of microphone presence and short detection. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r--include/sound/wm8903.h2
-rw-r--r--sound/soc/codecs/wm8903.c106
-rw-r--r--sound/soc/codecs/wm8903.h4
3 files changed, 109 insertions, 3 deletions
diff --git a/include/sound/wm8903.h b/include/sound/wm8903.h
index 49bb1a844bfc..b4a0db2307ef 100644
--- a/include/sound/wm8903.h
+++ b/include/sound/wm8903.h
@@ -241,6 +241,8 @@ struct wm8903_platform_data {
241 */ 241 */
242 u16 micdet_cfg; 242 u16 micdet_cfg;
243 243
244 int micdet_delay; /* Delay after microphone detection (ms) */
245
244 u32 gpio_cfg[5]; /* Default register values for GPIO pin mux */ 246 u32 gpio_cfg[5]; /* Default register values for GPIO pin mux */
245}; 247};
246 248
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 7aa2adbe6fba..b5427b47d6fd 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -23,6 +23,7 @@
23#include <linux/i2c.h> 23#include <linux/i2c.h>
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <sound/core.h> 25#include <sound/core.h>
26#include <sound/jack.h>
26#include <sound/pcm.h> 27#include <sound/pcm.h>
27#include <sound/pcm_params.h> 28#include <sound/pcm_params.h>
28#include <sound/tlv.h> 29#include <sound/tlv.h>
@@ -223,6 +224,12 @@ struct wm8903_priv {
223 224
224 struct completion wseq; 225 struct completion wseq;
225 226
227 struct snd_soc_jack *mic_jack;
228 int mic_det;
229 int mic_short;
230 int mic_last_report;
231 int mic_delay;
232
226 struct snd_pcm_substream *master_substream; 233 struct snd_pcm_substream *master_substream;
227 struct snd_pcm_substream *slave_substream; 234 struct snd_pcm_substream *slave_substream;
228}; 235};
@@ -1437,19 +1444,112 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
1437 return 0; 1444 return 0;
1438} 1445}
1439 1446
1447/**
1448 * wm8903_mic_detect - Enable microphone detection via the WM8903 IRQ
1449 *
1450 * @codec: WM8903 codec
1451 * @jack: jack to report detection events on
1452 * @det: value to report for presence detection
1453 * @shrt: value to report for short detection
1454 *
1455 * Enable microphone detection via IRQ on the WM8903. If GPIOs are
1456 * being used to bring out signals to the processor then only platform
1457 * data configuration is needed for WM8903 and processor GPIOs should
1458 * be configured using snd_soc_jack_add_gpios() instead.
1459 *
1460 * The current threasholds for detection should be configured using
1461 * micdet_cfg in the platform data. Using this function will force on
1462 * the microphone bias for the device.
1463 */
1464int wm8903_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
1465 int det, int shrt)
1466{
1467 struct wm8903_priv *wm8903 = codec->private_data;
1468 int irq_mask = 0;
1469
1470 dev_dbg(codec->dev, "Enabling microphone detection: %x %x\n",
1471 det, shrt);
1472
1473 /* Store the configuration */
1474 wm8903->mic_jack = jack;
1475 wm8903->mic_det = det;
1476 wm8903->mic_short = shrt;
1477
1478 /* Enable interrupts we've got a report configured for */
1479 if (det)
1480 irq_mask &= ~WM8903_MICDET_EINT;
1481 if (shrt)
1482 irq_mask &= ~WM8903_MICSHRT_EINT;
1483
1484 snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK,
1485 WM8903_MICDET_EINT | WM8903_MICSHRT_EINT,
1486 irq_mask);
1487
1488 /* Enable mic detection, this may not have been set through
1489 * platform data (eg, if the defaults are OK). */
1490 snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
1491 WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
1492 snd_soc_update_bits(codec, WM8903_MIC_BIAS_CONTROL_0,
1493 WM8903_MICDET_ENA, WM8903_MICDET_ENA);
1494
1495 /* Force the microphone bias on; this will trigger an initial
1496 * detection. */
1497 snd_soc_dapm_force_enable_pin(codec, "Mic Bias");
1498
1499 return 0;
1500}
1501EXPORT_SYMBOL_GPL(wm8903_mic_detect);
1502
1440static irqreturn_t wm8903_irq(int irq, void *data) 1503static irqreturn_t wm8903_irq(int irq, void *data)
1441{ 1504{
1442 struct wm8903_priv *wm8903 = data; 1505 struct wm8903_priv *wm8903 = data;
1443 struct snd_soc_codec *codec = &wm8903->codec; 1506 struct snd_soc_codec *codec = &wm8903->codec;
1444 int reg; 1507 int mic_report;
1508 int int_pol;
1509 int int_val = 0;
1510 int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK);
1445 1511
1446 reg = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1); 1512 int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask;
1447 1513
1448 if (reg & WM8903_WSEQ_BUSY_EINT) { 1514 if (int_val & WM8903_WSEQ_BUSY_EINT) {
1449 dev_dbg(codec->dev, "Write sequencer done\n"); 1515 dev_dbg(codec->dev, "Write sequencer done\n");
1450 complete(&wm8903->wseq); 1516 complete(&wm8903->wseq);
1451 } 1517 }
1452 1518
1519 /*
1520 * The rest is microphone jack detection. We need to manually
1521 * invert the polarity of the interrupt after each event - to
1522 * simplify the code keep track of the last state we reported
1523 * and just invert the relevant bits in both the report and
1524 * the polarity register.
1525 */
1526 mic_report = wm8903->mic_last_report;
1527 int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1);
1528
1529 if (int_val & WM8903_MICSHRT_EINT) {
1530 dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol);
1531
1532 mic_report ^= wm8903->mic_short;
1533 int_pol ^= WM8903_MICSHRT_INV;
1534 }
1535
1536 if (int_val & WM8903_MICDET_EINT) {
1537 dev_dbg(codec->dev, "Microphone detect (pol=%x)\n", int_pol);
1538
1539 mic_report ^= wm8903->mic_det;
1540 int_pol ^= WM8903_MICDET_INV;
1541
1542 msleep(wm8903->mic_delay);
1543 }
1544
1545 snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1,
1546 WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
1547
1548 snd_soc_jack_report(wm8903->mic_jack, mic_report,
1549 wm8903->mic_short | wm8903->mic_det);
1550
1551 wm8903->mic_last_report = mic_report;
1552
1453 return IRQ_HANDLED; 1553 return IRQ_HANDLED;
1454} 1554}
1455 1555
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
index 8f19a2413785..ce384a2ad820 100644
--- a/sound/soc/codecs/wm8903.h
+++ b/sound/soc/codecs/wm8903.h
@@ -18,6 +18,10 @@
18extern struct snd_soc_dai wm8903_dai; 18extern struct snd_soc_dai wm8903_dai;
19extern struct snd_soc_codec_device soc_codec_dev_wm8903; 19extern struct snd_soc_codec_device soc_codec_dev_wm8903;
20 20
21extern int wm8903_mic_detect(struct snd_soc_codec *codec,
22 struct snd_soc_jack *jack,
23 int det, int shrt);
24
21#define WM8903_MCLK_DIV_2 1 25#define WM8903_MCLK_DIV_2 1
22#define WM8903_CLK_SYS 2 26#define WM8903_CLK_SYS 2
23#define WM8903_BCLK 3 27#define WM8903_BCLK 3