aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorJoonyoung Shim <jy0922.shim@samsung.com>2009-04-20 06:21:35 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-04-20 07:44:24 -0400
commit7154b3e80203ee91f9ba7d0a43d3daa05c49d9e9 (patch)
treed7741c68ea143dc4cfdb2ffbe3ef350e544a12d5 /sound/soc
parent6b87a91f5417226c7fe62100b0e7217e7096b789 (diff)
ASoC: TWL4030: Add support Voice DAI
Add Voice DAI to support the PCM voice interface of the twl4030 codec. The PCM voice interface can be used with 8-kHz(voice narrowband) or 16-kHz(voice wideband) sampling rates, and 16bits, and mono RX and mono TX or stereo TX. The PCM voice interface has two modes - PCM mode1 : This uses the normal FS polarity and the rising edge of the clock signal. - PCM mode2 : This uses the FS polarity inverted and the falling edge of the clock signal. If the system master clock is not 26MHz or the twl4030 codec mode is not option2, the voice PCM interface is not available. Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Acked-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/twl4030.c173
-rw-r--r--sound/soc/codecs/twl4030.h18
-rw-r--r--sound/soc/omap/omap2evm.c2
-rw-r--r--sound/soc/omap/omap3beagle.c2
-rw-r--r--sound/soc/omap/omap3pandora.c4
-rw-r--r--sound/soc/omap/overo.c2
-rw-r--r--sound/soc/omap/sdp3430.c2
7 files changed, 191 insertions, 12 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index a1b76d7fd130..cc2968cf6409 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -1484,6 +1484,144 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
1484 return 0; 1484 return 0;
1485} 1485}
1486 1486
1487static int twl4030_voice_startup(struct snd_pcm_substream *substream,
1488 struct snd_soc_dai *dai)
1489{
1490 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1491 struct snd_soc_device *socdev = rtd->socdev;
1492 struct snd_soc_codec *codec = socdev->card->codec;
1493 u8 infreq;
1494 u8 mode;
1495
1496 /* If the system master clock is not 26MHz, the voice PCM interface is
1497 * not avilable.
1498 */
1499 infreq = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL)
1500 & TWL4030_APLL_INFREQ;
1501
1502 if (infreq != TWL4030_APLL_INFREQ_26000KHZ) {
1503 printk(KERN_ERR "TWL4030 voice startup: "
1504 "MCLK is not 26MHz, call set_sysclk() on init\n");
1505 return -EINVAL;
1506 }
1507
1508 /* If the codec mode is not option2, the voice PCM interface is not
1509 * avilable.
1510 */
1511 mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
1512 & TWL4030_OPT_MODE;
1513
1514 if (mode != TWL4030_OPTION_2) {
1515 printk(KERN_ERR "TWL4030 voice startup: "
1516 "the codec mode is not option2\n");
1517 return -EINVAL;
1518 }
1519
1520 return 0;
1521}
1522
1523static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
1524 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
1525{
1526 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1527 struct snd_soc_device *socdev = rtd->socdev;
1528 struct snd_soc_codec *codec = socdev->card->codec;
1529 u8 old_mode, mode;
1530
1531 /* bit rate */
1532 old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
1533 & ~(TWL4030_CODECPDZ);
1534 mode = old_mode;
1535
1536 switch (params_rate(params)) {
1537 case 8000:
1538 mode &= ~(TWL4030_SEL_16K);
1539 break;
1540 case 16000:
1541 mode |= TWL4030_SEL_16K;
1542 break;
1543 default:
1544 printk(KERN_ERR "TWL4030 voice hw params: unknown rate %d\n",
1545 params_rate(params));
1546 return -EINVAL;
1547 }
1548
1549 if (mode != old_mode) {
1550 /* change rate and set CODECPDZ */
1551 twl4030_codec_enable(codec, 0);
1552 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
1553 twl4030_codec_enable(codec, 1);
1554 }
1555
1556 return 0;
1557}
1558
1559static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
1560 int clk_id, unsigned int freq, int dir)
1561{
1562 struct snd_soc_codec *codec = codec_dai->codec;
1563 u8 infreq;
1564
1565 switch (freq) {
1566 case 26000000:
1567 infreq = TWL4030_APLL_INFREQ_26000KHZ;
1568 break;
1569 default:
1570 printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n",
1571 freq);
1572 return -EINVAL;
1573 }
1574
1575 infreq |= TWL4030_APLL_EN;
1576 twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq);
1577
1578 return 0;
1579}
1580
1581static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
1582 unsigned int fmt)
1583{
1584 struct snd_soc_codec *codec = codec_dai->codec;
1585 u8 old_format, format;
1586
1587 /* get format */
1588 old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
1589 format = old_format;
1590
1591 /* set master/slave audio interface */
1592 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1593 case SND_SOC_DAIFMT_CBS_CFM:
1594 format &= ~(TWL4030_VIF_SLAVE_EN);
1595 break;
1596 case SND_SOC_DAIFMT_CBS_CFS:
1597 format |= TWL4030_VIF_SLAVE_EN;
1598 break;
1599 default:
1600 return -EINVAL;
1601 }
1602
1603 /* clock inversion */
1604 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1605 case SND_SOC_DAIFMT_IB_NF:
1606 format &= ~(TWL4030_VIF_FORMAT);
1607 break;
1608 case SND_SOC_DAIFMT_NB_IF:
1609 format |= TWL4030_VIF_FORMAT;
1610 break;
1611 default:
1612 return -EINVAL;
1613 }
1614
1615 if (format != old_format) {
1616 /* change format and set CODECPDZ */
1617 twl4030_codec_enable(codec, 0);
1618 twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
1619 twl4030_codec_enable(codec, 1);
1620 }
1621
1622 return 0;
1623}
1624
1487#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) 1625#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
1488#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) 1626#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
1489 1627
@@ -1495,7 +1633,15 @@ static struct snd_soc_dai_ops twl4030_dai_ops = {
1495 .set_fmt = twl4030_set_dai_fmt, 1633 .set_fmt = twl4030_set_dai_fmt,
1496}; 1634};
1497 1635
1498struct snd_soc_dai twl4030_dai = { 1636static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
1637 .startup = twl4030_voice_startup,
1638 .hw_params = twl4030_voice_hw_params,
1639 .set_sysclk = twl4030_voice_set_dai_sysclk,
1640 .set_fmt = twl4030_voice_set_dai_fmt,
1641};
1642
1643struct snd_soc_dai twl4030_dai[] = {
1644{
1499 .name = "twl4030", 1645 .name = "twl4030",
1500 .playback = { 1646 .playback = {
1501 .stream_name = "Playback", 1647 .stream_name = "Playback",
@@ -1510,6 +1656,23 @@ struct snd_soc_dai twl4030_dai = {
1510 .rates = TWL4030_RATES, 1656 .rates = TWL4030_RATES,
1511 .formats = TWL4030_FORMATS,}, 1657 .formats = TWL4030_FORMATS,},
1512 .ops = &twl4030_dai_ops, 1658 .ops = &twl4030_dai_ops,
1659},
1660{
1661 .name = "twl4030 Voice",
1662 .playback = {
1663 .stream_name = "Playback",
1664 .channels_min = 1,
1665 .channels_max = 1,
1666 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1667 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
1668 .capture = {
1669 .stream_name = "Capture",
1670 .channels_min = 1,
1671 .channels_max = 2,
1672 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1673 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
1674 .ops = &twl4030_dai_voice_ops,
1675},
1513}; 1676};
1514EXPORT_SYMBOL_GPL(twl4030_dai); 1677EXPORT_SYMBOL_GPL(twl4030_dai);
1515 1678
@@ -1550,8 +1713,8 @@ static int twl4030_init(struct snd_soc_device *socdev)
1550 codec->read = twl4030_read_reg_cache; 1713 codec->read = twl4030_read_reg_cache;
1551 codec->write = twl4030_write; 1714 codec->write = twl4030_write;
1552 codec->set_bias_level = twl4030_set_bias_level; 1715 codec->set_bias_level = twl4030_set_bias_level;
1553 codec->dai = &twl4030_dai; 1716 codec->dai = twl4030_dai;
1554 codec->num_dai = 1; 1717 codec->num_dai = ARRAY_SIZE(twl4030_dai),
1555 codec->reg_cache_size = sizeof(twl4030_reg); 1718 codec->reg_cache_size = sizeof(twl4030_reg);
1556 codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), 1719 codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
1557 GFP_KERNEL); 1720 GFP_KERNEL);
@@ -1645,13 +1808,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
1645 1808
1646static int __init twl4030_modinit(void) 1809static int __init twl4030_modinit(void)
1647{ 1810{
1648 return snd_soc_register_dai(&twl4030_dai); 1811 return snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
1649} 1812}
1650module_init(twl4030_modinit); 1813module_init(twl4030_modinit);
1651 1814
1652static void __exit twl4030_exit(void) 1815static void __exit twl4030_exit(void)
1653{ 1816{
1654 snd_soc_unregister_dai(&twl4030_dai); 1817 snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
1655} 1818}
1656module_exit(twl4030_exit); 1819module_exit(twl4030_exit);
1657 1820
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index cb63765db1df..981ec609495b 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -113,6 +113,8 @@
113#define TWL4030_SEL_16K 0x04 113#define TWL4030_SEL_16K 0x04
114#define TWL4030_CODECPDZ 0x02 114#define TWL4030_CODECPDZ 0x02
115#define TWL4030_OPT_MODE 0x01 115#define TWL4030_OPT_MODE 0x01
116#define TWL4030_OPTION_1 (1 << 0)
117#define TWL4030_OPTION_2 (0 << 0)
116 118
117/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ 119/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */
118 120
@@ -171,6 +173,17 @@
171#define TWL4030_CLK256FS_EN 0x02 173#define TWL4030_CLK256FS_EN 0x02
172#define TWL4030_AIF_EN 0x01 174#define TWL4030_AIF_EN 0x01
173 175
176/* VOICE_IF (0x0F) Fields */
177
178#define TWL4030_VIF_SLAVE_EN 0x80
179#define TWL4030_VIF_DIN_EN 0x40
180#define TWL4030_VIF_DOUT_EN 0x20
181#define TWL4030_VIF_SWAP 0x10
182#define TWL4030_VIF_FORMAT 0x08
183#define TWL4030_VIF_TRI_EN 0x04
184#define TWL4030_VIF_SUB_EN 0x02
185#define TWL4030_VIF_EN 0x01
186
174/* EAR_CTL (0x21) */ 187/* EAR_CTL (0x21) */
175#define TWL4030_EAR_GAIN 0x30 188#define TWL4030_EAR_GAIN 0x30
176 189
@@ -236,7 +249,10 @@
236#define TWL4030_SMOOTH_ANAVOL_EN 0x02 249#define TWL4030_SMOOTH_ANAVOL_EN 0x02
237#define TWL4030_DIGMIC_LR_SWAP_EN 0x01 250#define TWL4030_DIGMIC_LR_SWAP_EN 0x01
238 251
239extern struct snd_soc_dai twl4030_dai; 252#define TWL4030_DAI_HIFI 0
253#define TWL4030_DAI_VOICE 1
254
255extern struct snd_soc_dai twl4030_dai[2];
240extern struct snd_soc_codec_device soc_codec_dev_twl4030; 256extern struct snd_soc_codec_device soc_codec_dev_twl4030;
241 257
242#endif /* End of __TWL4030_AUDIO_H__ */ 258#endif /* End of __TWL4030_AUDIO_H__ */
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
index 0c2322dcf02a..027e1a40f8a1 100644
--- a/sound/soc/omap/omap2evm.c
+++ b/sound/soc/omap/omap2evm.c
@@ -86,7 +86,7 @@ static struct snd_soc_dai_link omap2evm_dai = {
86 .name = "TWL4030", 86 .name = "TWL4030",
87 .stream_name = "TWL4030", 87 .stream_name = "TWL4030",
88 .cpu_dai = &omap_mcbsp_dai[0], 88 .cpu_dai = &omap_mcbsp_dai[0],
89 .codec_dai = &twl4030_dai, 89 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
90 .ops = &omap2evm_ops, 90 .ops = &omap2evm_ops,
91}; 91};
92 92
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index fd24a4acd2f5..6aa428e07d86 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -83,7 +83,7 @@ static struct snd_soc_dai_link omap3beagle_dai = {
83 .name = "TWL4030", 83 .name = "TWL4030",
84 .stream_name = "TWL4030", 84 .stream_name = "TWL4030",
85 .cpu_dai = &omap_mcbsp_dai[0], 85 .cpu_dai = &omap_mcbsp_dai[0],
86 .codec_dai = &twl4030_dai, 86 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
87 .ops = &omap3beagle_ops, 87 .ops = &omap3beagle_ops,
88}; 88};
89 89
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index fe282d4ef422..ad219aaf7cb8 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -228,14 +228,14 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
228 .name = "PCM1773", 228 .name = "PCM1773",
229 .stream_name = "HiFi Out", 229 .stream_name = "HiFi Out",
230 .cpu_dai = &omap_mcbsp_dai[0], 230 .cpu_dai = &omap_mcbsp_dai[0],
231 .codec_dai = &twl4030_dai, 231 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
232 .ops = &omap3pandora_out_ops, 232 .ops = &omap3pandora_out_ops,
233 .init = omap3pandora_out_init, 233 .init = omap3pandora_out_init,
234 }, { 234 }, {
235 .name = "TWL4030", 235 .name = "TWL4030",
236 .stream_name = "Line/Mic In", 236 .stream_name = "Line/Mic In",
237 .cpu_dai = &omap_mcbsp_dai[1], 237 .cpu_dai = &omap_mcbsp_dai[1],
238 .codec_dai = &twl4030_dai, 238 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
239 .ops = &omap3pandora_in_ops, 239 .ops = &omap3pandora_in_ops,
240 .init = omap3pandora_in_init, 240 .init = omap3pandora_in_init,
241 } 241 }
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index a72dc4e159e5..ec4f8fd8b3a2 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -83,7 +83,7 @@ static struct snd_soc_dai_link overo_dai = {
83 .name = "TWL4030", 83 .name = "TWL4030",
84 .stream_name = "TWL4030", 84 .stream_name = "TWL4030",
85 .cpu_dai = &omap_mcbsp_dai[0], 85 .cpu_dai = &omap_mcbsp_dai[0],
86 .codec_dai = &twl4030_dai, 86 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
87 .ops = &overo_ops, 87 .ops = &overo_ops,
88}; 88};
89 89
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 10f1c867f11d..1c7974101a0b 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -197,7 +197,7 @@ static struct snd_soc_dai_link sdp3430_dai = {
197 .name = "TWL4030", 197 .name = "TWL4030",
198 .stream_name = "TWL4030", 198 .stream_name = "TWL4030",
199 .cpu_dai = &omap_mcbsp_dai[0], 199 .cpu_dai = &omap_mcbsp_dai[0],
200 .codec_dai = &twl4030_dai, 200 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
201 .init = sdp3430_twl4030_init, 201 .init = sdp3430_twl4030_init,
202 .ops = &sdp3430_ops, 202 .ops = &sdp3430_ops,
203}; 203};