aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-03-15 14:25:26 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-03-16 11:57:15 -0400
commit8abd16a65d81756706016720e2cc7eeb81d06a2e (patch)
treee8031539c57c4add59dd84bbf943584ef58fb907 /sound/soc/codecs
parent37f88e8407f75fc6ced5cefb633c314556de3ad1 (diff)
ASoC: Add WM8903 interrupt support
Currently used to detect completion of the write sequencer. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/wm8903.c66
1 files changed, 61 insertions, 5 deletions
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 467e6c335c5a..7aa2adbe6fba 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -12,12 +12,12 @@
12 * TODO: 12 * TODO:
13 * - TDM mode configuration. 13 * - TDM mode configuration.
14 * - Digital microphone support. 14 * - Digital microphone support.
15 * - Interrupt support (mic detect and sequencer).
16 */ 15 */
17 16
18#include <linux/module.h> 17#include <linux/module.h>
19#include <linux/moduleparam.h> 18#include <linux/moduleparam.h>
20#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/completion.h>
21#include <linux/delay.h> 21#include <linux/delay.h>
22#include <linux/pm.h> 22#include <linux/pm.h>
23#include <linux/i2c.h> 23#include <linux/i2c.h>
@@ -29,6 +29,7 @@
29#include <sound/soc.h> 29#include <sound/soc.h>
30#include <sound/soc-dapm.h> 30#include <sound/soc-dapm.h>
31#include <sound/initval.h> 31#include <sound/initval.h>
32#include <sound/wm8903.h>
32 33
33#include "wm8903.h" 34#include "wm8903.h"
34 35
@@ -220,6 +221,8 @@ struct wm8903_priv {
220 int playback_active; 221 int playback_active;
221 int capture_active; 222 int capture_active;
222 223
224 struct completion wseq;
225
223 struct snd_pcm_substream *master_substream; 226 struct snd_pcm_substream *master_substream;
224 struct snd_pcm_substream *slave_substream; 227 struct snd_pcm_substream *slave_substream;
225}; 228};
@@ -242,6 +245,7 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
242{ 245{
243 u16 reg[5]; 246 u16 reg[5];
244 struct i2c_client *i2c = codec->control_data; 247 struct i2c_client *i2c = codec->control_data;
248 struct wm8903_priv *wm8903 = codec->private_data;
245 249
246 BUG_ON(start > 48); 250 BUG_ON(start > 48);
247 251
@@ -256,11 +260,11 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
256 start | WM8903_WSEQ_START); 260 start | WM8903_WSEQ_START);
257 261
258 /* Wait for it to complete. If we have the interrupt wired up then 262 /* Wait for it to complete. If we have the interrupt wired up then
259 * we could block waiting for an interrupt, though polling may still 263 * that will break us out of the poll early.
260 * be desirable for diagnostic purposes.
261 */ 264 */
262 do { 265 do {
263 msleep(10); 266 wait_for_completion_timeout(&wm8903->wseq,
267 msecs_to_jiffies(10));
264 268
265 reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4); 269 reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
266 } while (reg[4] & WM8903_WSEQ_BUSY); 270 } while (reg[4] & WM8903_WSEQ_BUSY);
@@ -1433,6 +1437,22 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
1433 return 0; 1437 return 0;
1434} 1438}
1435 1439
1440static irqreturn_t wm8903_irq(int irq, void *data)
1441{
1442 struct wm8903_priv *wm8903 = data;
1443 struct snd_soc_codec *codec = &wm8903->codec;
1444 int reg;
1445
1446 reg = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1);
1447
1448 if (reg & WM8903_WSEQ_BUSY_EINT) {
1449 dev_dbg(codec->dev, "Write sequencer done\n");
1450 complete(&wm8903->wseq);
1451 }
1452
1453 return IRQ_HANDLED;
1454}
1455
1436#define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\ 1456#define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
1437 SNDRV_PCM_RATE_11025 | \ 1457 SNDRV_PCM_RATE_11025 | \
1438 SNDRV_PCM_RATE_16000 | \ 1458 SNDRV_PCM_RATE_16000 | \
@@ -1527,9 +1547,11 @@ static struct snd_soc_codec *wm8903_codec;
1527static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, 1547static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
1528 const struct i2c_device_id *id) 1548 const struct i2c_device_id *id)
1529{ 1549{
1550 struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
1530 struct wm8903_priv *wm8903; 1551 struct wm8903_priv *wm8903;
1531 struct snd_soc_codec *codec; 1552 struct snd_soc_codec *codec;
1532 int ret, i; 1553 int ret, i;
1554 int trigger, irq_pol;
1533 u16 val; 1555 u16 val;
1534 1556
1535 wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); 1557 wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
@@ -1553,6 +1575,7 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
1553 codec->reg_cache = &wm8903->reg_cache[0]; 1575 codec->reg_cache = &wm8903->reg_cache[0];
1554 codec->private_data = wm8903; 1576 codec->private_data = wm8903;
1555 codec->volatile_register = wm8903_volatile_register; 1577 codec->volatile_register = wm8903_volatile_register;
1578 init_completion(&wm8903->wseq);
1556 1579
1557 i2c_set_clientdata(i2c, codec); 1580 i2c_set_clientdata(i2c, codec);
1558 codec->control_data = i2c; 1581 codec->control_data = i2c;
@@ -1596,6 +1619,32 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
1596 1619
1597 wm8903->mic_delay = pdata->micdet_delay; 1620 wm8903->mic_delay = pdata->micdet_delay;
1598 } 1621 }
1622
1623 if (i2c->irq) {
1624 if (pdata && pdata->irq_active_low) {
1625 trigger = IRQF_TRIGGER_LOW;
1626 irq_pol = WM8903_IRQ_POL;
1627 } else {
1628 trigger = IRQF_TRIGGER_HIGH;
1629 irq_pol = 0;
1630 }
1631
1632 snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
1633 WM8903_IRQ_POL, irq_pol);
1634
1635 ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
1636 trigger | IRQF_ONESHOT,
1637 "wm8903", wm8903);
1638 if (ret != 0) {
1639 dev_err(&i2c->dev, "Failed to request IRQ: %d\n",
1640 ret);
1641 goto err;
1642 }
1643
1644 /* Enable write sequencer interrupts */
1645 snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK,
1646 WM8903_IM_WSEQ_BUSY_EINT, 0);
1647 }
1599 1648
1600 /* power on device */ 1649 /* power on device */
1601 wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1650 wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1637,7 +1686,7 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
1637 ret = snd_soc_register_codec(codec); 1686 ret = snd_soc_register_codec(codec);
1638 if (ret != 0) { 1687 if (ret != 0) {
1639 dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); 1688 dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
1640 goto err; 1689 goto err_irq;
1641 } 1690 }
1642 1691
1643 ret = snd_soc_register_dai(&wm8903_dai); 1692 ret = snd_soc_register_dai(&wm8903_dai);
@@ -1650,6 +1699,9 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
1650 1699
1651err_codec: 1700err_codec:
1652 snd_soc_unregister_codec(codec); 1701 snd_soc_unregister_codec(codec);
1702err_irq:
1703 if (i2c->irq)
1704 free_irq(i2c->irq, wm8903);
1653err: 1705err:
1654 wm8903_codec = NULL; 1706 wm8903_codec = NULL;
1655 kfree(wm8903); 1707 kfree(wm8903);
@@ -1659,12 +1711,16 @@ err:
1659static __devexit int wm8903_i2c_remove(struct i2c_client *client) 1711static __devexit int wm8903_i2c_remove(struct i2c_client *client)
1660{ 1712{
1661 struct snd_soc_codec *codec = i2c_get_clientdata(client); 1713 struct snd_soc_codec *codec = i2c_get_clientdata(client);
1714 struct wm8903_priv *priv = codec->private_data;
1662 1715
1663 snd_soc_unregister_dai(&wm8903_dai); 1716 snd_soc_unregister_dai(&wm8903_dai);
1664 snd_soc_unregister_codec(codec); 1717 snd_soc_unregister_codec(codec);
1665 1718
1666 wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); 1719 wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
1667 1720
1721 if (client->irq)
1722 free_irq(client->irq, priv);
1723
1668 kfree(codec->private_data); 1724 kfree(codec->private_data);
1669 1725
1670 wm8903_codec = NULL; 1726 wm8903_codec = NULL;