From 7f31538897c8f1504f37bc837e7be9a356e2f863 Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Wed, 19 Jan 2011 23:06:45 +0530 Subject: sound: tegra: Enabled Recording and fixed volume - Enabled Recording for WM8753. - Fixed low Volume in Play Back by enabling LDO7 - Fixed noise in PlayBack and Recording by using a bclk of 2.82 Mhz Bug 771506 Change-Id: I0c43adafa83969929cfdff700a71a68225ab4c22 Reviewed-on: http://git-master/r/16260 Tested-by: Nikesh Oswal Reviewed-by: Sachin Nikam Tested-by: Sachin Nikam Reviewed-by: Bharat Nihalani --- sound/soc/tegra/tegra_i2s.c | 16 +++ sound/soc/tegra/tegra_soc_wm8753.c | 246 ++++++++++++++++++++++++++++++++----- 2 files changed, 228 insertions(+), 34 deletions(-) diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 92d4f4a2ca65..8d023d10d7f0 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -257,6 +257,22 @@ static int tegra_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, static int tegra_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { + struct tegra_i2s_info* info = cpu_dai->private_data; + + if (info && info->i2s_clk) { + clk_set_rate(info->i2s_clk, freq); + if (clk_enable(info->i2s_clk)) { + pr_err("%s: failed to enable i2s-%d clock\n", __func__, + cpu_dai->id+1); + return -EIO; + } + } + else { + pr_err("%s: could not get i2s-%d clock\n", __func__, + cpu_dai->id+1); + return -EIO; + } + return 0; } diff --git a/sound/soc/tegra/tegra_soc_wm8753.c b/sound/soc/tegra/tegra_soc_wm8753.c index 5a562f9e119d..103774e60639 100644 --- a/sound/soc/tegra/tegra_soc_wm8753.c +++ b/sound/soc/tegra/tegra_soc_wm8753.c @@ -26,93 +26,252 @@ #include "tegra_soc.h" #include "../codecs/wm8753.h" - -#define WM8753_PWR1_VMIDSEL_EN 0x80 /* Vmid divider enable and select */ -#define WM8753_PWR1_VREF_EN 0x40 /* VREF Enable */ -#define WM8753_PWR1_DACL_EN 0x08 /* DAC Left Enable */ -#define WM8753_PWR1_DACR_EN 0x04 /* VREF Enable */ - -#define WM8753_PWR3_LOU1_EN 0x100 /* LOUT1 Enable */ -#define WM8753_PWR3_ROU1_EN 0x70 /* ROUT1 Enable */ - -#define WM8753_PWR4_RIGHTMIX_EN 0x02 /* Right mixer enable */ -#define WM8753_PWR4_LEFTMIX_EN 0x01 /* Left mixer enable */ - -#define WM8753_LOUTM1_LD2LO 0x100 /* Left DAC to Left Mixer */ -#define WM8753_LOUTM1_LM2LO 0x80 -#define WM8753_LOUTM1_LM2LOVOL 0x70 /* LM Signal to Left Mixer Volume */ - -#define WM8753_ROUTM1_RD2RO 0x100 /* Right DAC to Right Mixer */ -#define WM8753_ROUTM1_RM2RO 0x80 -#define WM8753_ROUTM1_RM2ROVOL 0x70 /* RM Signal to Right Mixer Volume */ +#include + +#define WM8753_PWR1_VMIDSEL_1 1<<8 +#define WM8753_PWR1_VMIDSEL_0 1<<7 +#define WM8753_PWR1_VREF 1<<6 +#define WM8753_PWR1_MICB 1<<5 +#define WM8753_PWR1_DACL 1<<3 +#define WM8753_PWR1_DACR 1<<2 + +#define WM8753_PWR2_MICAMP1EN 1<<8 +#define WM8753_PWR2_MICAMP2EN 1<<7 +#define WM8753_PWR2_ALCMIX 1<<6 +#define WM8753_PWR2_PGAL 1<<5 +#define WM8753_PWR2_PGAR 1<<4 +#define WM8753_PWR2_ADCL 1<<3 +#define WM8753_PWR2_ADCR 1<<2 +#define WM8753_PWR2_RXMIX 1<<1 +#define WM8753_PWR2_LINEMIX 1<<0 + +#define WM8753_PWR3_LOUT1 1<<8 +#define WM8753_PWR3_ROUT1 1<<7 +#define WM8753_PWR3_LOUT2 1<<6 +#define WM8753_PWR3_ROUT2 1<<5 +#define WM8753_PWR3_OUT3 1<<4 +#define WM8753_PWR3_OUT4 1<<3 +#define WM8753_PWR3_MONO1 1<<2 +#define WM8753_PWR3_MONO2 1<<1 + +#define WM8753_PWR4_RECMIX 1<<3 +#define WM8753_PWR4_MONOMIX 1<<2 +#define WM8753_PWR4_RIGHTMIX 1<<1 +#define WM8753_PWR4_LEFTMIX 1<<0 + +#define WM8753_IOCTL_VXCLKTRI 1<<7 +#define WM8753_IOCTL_BCCLKTRI 1<<6 +#define WM8753_IOCTL_VXDTRI 1<<5 +#define WM8753_IOCTL_ADCTRI 1<<4 +#define WM8753_IOCTL_IFMODE_1 1<<3 +#define WM8753_IOCTL_IFMODE_0 1<<2 +#define WM8753_IOCTL_VXFSOE 1<<1 +#define WM8753_IOCTL_LRCOE 1<<0 + +#define WM8753_LOUTM1_LD2LO 1<<8 + +#define WM8753_ROUTM1_RD2RO 1<<8 + +#define WM8753_ADCIN_MONOMIX_1 1<<5 +#define WM8753_ADCIN_MONOMIX_0 1<<4 +#define WM8753_ADCIN_RADCSEL_1 1<<3 +#define WM8753_ADCIN_RADCSEL_0 1<<2 +#define WM8753_ADCIN_LADCSEL_1 1<<1 +#define WM8753_ADCIN_LADCSEL_0 1<<0 + +#define WM8753_INCTL1_MIC2BOOST_1 1<<8 +#define WM8753_INCTL1_MIC2BOOST_0 1<<7 + +#define WM8753_INCTL2_MICMUX_1 1<<5 +#define WM8753_INCTL2_MICMUX_0 1<<4 + +#define WM8753_ADC_DATSEL_1 1<<8 +#define WM8753_ADC_DATSEL_0 1<<7 +#define WM8753_ADC_ADCPOL_1 1<<6 +#define WM8753_ADC_ADCPOL_0 1<<5 +#define WM8753_ADC_VXFILT 1<<4 +#define WM8753_ADC_HPMODE_1 1<<3 +#define WM8753_ADC_HPMODE_0 1<<2 +#define WM8753_ADC_HPOR 1<<1 +#define WM8753_ADC_ADCHPD 1<<0 + +#define WM8753_LINVOL_MAX 0x11F + +#define WM8753_RINVOL_MAX 0x11F static struct platform_device *tegra_snd_device; +static struct regulator* wm8753_reg; extern struct snd_soc_dai tegra_i2s_dai[]; extern struct snd_soc_platform tegra_soc_platform; static int tegra_hifi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; int err; unsigned int value; + unsigned int channels, rate, bit_size = 16; + struct snd_soc_codec *codec = codec_dai->codec; + + rate = params_rate(params); /* Sampling Rate in Hz */ + channels = params_channels(params); /* Number of channels */ + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + bit_size = 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + bit_size = 20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + bit_size = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bit_size = 32; + break; + default: + pr_err(KERN_ERR "Invalid pcm format size\n"); + return EINVAL; + } err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); if (err < 0) { - pr_err(KERN_ERR "codec_dai fmt not set \n"); + pr_err(KERN_ERR "codec_dai fmt not set\n"); return err; } err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); if (err < 0) { - pr_err(KERN_ERR "cpu_dai fmt not set \n"); + pr_err(KERN_ERR "cpu_dai fmt not set\n"); return err; } - err = snd_soc_dai_set_sysclk(codec_dai, 0, I2S_CLK, SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(codec_dai, 0, bit_size*rate*channels*2*4, + SND_SOC_CLOCK_IN); if (err < 0) { pr_err(KERN_ERR "codec_dai clock not set\n"); return err; } - err = snd_soc_dai_set_sysclk(cpu_dai, 0, I2S_CLK, SND_SOC_CLOCK_IN); + err = snd_soc_dai_set_sysclk(cpu_dai, 0, bit_size*rate*channels*2, + SND_SOC_CLOCK_IN); if (err < 0) { pr_err(KERN_ERR "cpu_dai clock not set\n"); return err; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Enables MICBIAS, VMIDSEL and VREF, DAC-L and DAC-R */ value = snd_soc_read(codec_dai->codec, WM8753_PWR1); - value |= WM8753_PWR1_VMIDSEL_EN | WM8753_PWR1_VREF_EN | - WM8753_PWR1_DACL_EN |WM8753_PWR1_DACR_EN; + value |= (WM8753_PWR1_VMIDSEL_0 | WM8753_PWR1_VREF | + WM8753_PWR1_MICB | WM8753_PWR1_DACL | + WM8753_PWR1_DACR); + value &= ~(WM8753_PWR1_VMIDSEL_1); snd_soc_write(codec_dai->codec, WM8753_PWR1, value); + /* Enables Lout1 and Rout1 */ value = snd_soc_read(codec_dai->codec, WM8753_PWR3); - value |= WM8753_PWR3_LOU1_EN | WM8753_PWR3_ROU1_EN; + value |= (WM8753_PWR3_LOUT1 | WM8753_PWR3_ROUT1); snd_soc_write(codec_dai->codec, WM8753_PWR3, value); + /* Left and Right Mix Enabled */ value = snd_soc_read(codec_dai->codec, WM8753_PWR4); - value |= WM8753_PWR4_RIGHTMIX_EN | WM8753_PWR4_LEFTMIX_EN; + value |= (WM8753_PWR4_RIGHTMIX | WM8753_PWR4_LEFTMIX); snd_soc_write(codec_dai->codec, WM8753_PWR4, value); + /* Mode set to HiFi over HiFi interface and VXDOUT,ADCDAT, + VXCLK and BCLK pin enabled */ + value = snd_soc_read(codec_dai->codec, WM8753_IOCTL); + value |= (WM8753_IOCTL_IFMODE_1); + value &= ~(WM8753_IOCTL_VXCLKTRI | WM8753_IOCTL_BCCLKTRI | + WM8753_IOCTL_VXDTRI | WM8753_IOCTL_ADCTRI | + WM8753_IOCTL_IFMODE_0 | WM8753_IOCTL_VXFSOE | + WM8753_IOCTL_LRCOE); + snd_soc_write(codec_dai->codec, WM8753_IOCTL, value); + + /* L-DAC to L-Mix */ value = snd_soc_read(codec_dai->codec, WM8753_LOUTM1); value |= WM8753_LOUTM1_LD2LO; snd_soc_write(codec_dai->codec, WM8753_LOUTM1, value); + /* R-DAC to R-Mix */ value = snd_soc_read(codec_dai->codec, WM8753_ROUTM1); value |= WM8753_ROUTM1_RD2RO; snd_soc_write(codec_dai->codec, WM8753_ROUTM1, value); } + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + /* PGA i/p's to L and R ADC and operation in stero mode */ + value = snd_soc_read(codec_dai->codec, WM8753_ADCIN); + value &= ~(WM8753_ADCIN_MONOMIX_1 | WM8753_ADCIN_MONOMIX_0 | + WM8753_ADCIN_RADCSEL_1 | WM8753_ADCIN_RADCSEL_0 | + WM8753_ADCIN_LADCSEL_1 | WM8753_ADCIN_LADCSEL_0); + snd_soc_write(codec_dai->codec, WM8753_ADCIN, value); + + /* 24 db boost for Mic2 */ + value = snd_soc_read(codec_dai->codec, WM8753_INCTL1); + value |= (WM8753_INCTL1_MIC2BOOST_1); + value &= ~(WM8753_INCTL1_MIC2BOOST_0); + snd_soc_write(codec_dai->codec, WM8753_INCTL1, value); + + /* Side-Tone-Mic2 preamp o/p */ + value = snd_soc_read(codec_dai->codec, WM8753_INCTL2); + value |= (WM8753_INCTL2_MICMUX_1); + value &= ~(WM8753_INCTL2_MICMUX_0); + snd_soc_write(codec_dai->codec, WM8753_INCTL2, value); + + /* L and R data from R-ADC */ + value = snd_soc_read(codec_dai->codec, WM8753_ADC); + value |= (WM8753_ADC_DATSEL_1); + value &= ~(WM8753_ADC_DATSEL_0 | WM8753_ADC_ADCPOL_1 | + WM8753_ADC_ADCPOL_0 | WM8753_ADC_VXFILT | + WM8753_ADC_HPMODE_1 | WM8753_ADC_HPMODE_0 | + WM8753_ADC_HPOR | WM8753_ADC_ADCHPD); + snd_soc_write(codec_dai->codec, WM8753_ADC, value); + + /* Disable Mute and set L-PGA Vol to max */ + snd_soc_write(codec, WM8753_LINVOL, WM8753_LINVOL_MAX); + + /* Disable Mute and set R-PGA Vol to max */ + snd_soc_write(codec, WM8753_RINVOL, WM8753_RINVOL_MAX); + + /* Enables MICBIAS, VMIDSEL and VREF */ + value = snd_soc_read(codec_dai->codec, WM8753_PWR1); + value |= (WM8753_PWR1_VMIDSEL_0|WM8753_PWR1_VREF| + WM8753_PWR1_MICB); + value &= ~(WM8753_PWR1_VMIDSEL_1); + snd_soc_write(codec_dai->codec, WM8753_PWR1, value); + + /* Enable Mic2 preamp, PGA-R and ADC-R (Mic1 preamp,ALC Mix, + PGA-L , ADC-L, RXMIX and LINEMIX disabled) */ + value = snd_soc_read(codec_dai->codec, WM8753_PWR2); + value |= (WM8753_PWR2_MICAMP2EN | WM8753_PWR2_PGAR| + WM8753_PWR2_ADCR); + value &= ~(WM8753_PWR2_MICAMP1EN | WM8753_PWR2_ALCMIX | + WM8753_PWR2_PGAL | WM8753_PWR2_ADCL | + WM8753_PWR2_RXMIX | WM8753_PWR2_LINEMIX); + snd_soc_write(codec, WM8753_PWR2, value); + + /* Mode set to HiFi over HiFi interface and VXDOUT,ADCDAT, + VXCLK and BCLK pin enabled */ + value = snd_soc_read(codec_dai->codec, WM8753_IOCTL); + value |= (WM8753_IOCTL_IFMODE_1); + value &= ~(WM8753_IOCTL_VXCLKTRI | WM8753_IOCTL_BCCLKTRI | + WM8753_IOCTL_VXDTRI | WM8753_IOCTL_ADCTRI | + WM8753_IOCTL_IFMODE_0 | WM8753_IOCTL_VXFSOE | + WM8753_IOCTL_LRCOE); + snd_soc_write(codec_dai->codec, WM8753_IOCTL, value); + } + return 0; } @@ -198,6 +357,19 @@ static int __init tegra_init(void) goto fail; } + wm8753_reg = regulator_get(NULL, "avddio_audio"); + if (IS_ERR(wm8753_reg)) { + ret = PTR_ERR(wm8753_reg); + pr_err("unable to get wm8753 regulator\n"); + goto fail; + } + + ret = regulator_enable(wm8753_reg); + if (ret) { + pr_err("wm8753 regulator enable failed\n"); + goto err_put_regulator; + } + return 0; fail: @@ -207,12 +379,18 @@ fail: } return ret; + +err_put_regulator: + regulator_put(wm8753_reg); + return ret; } static void __exit tegra_exit(void) { tegra_controls_exit(); platform_device_unregister(tegra_snd_device); + regulator_disable(wm8753_reg); + regulator_put(wm8753_reg); } module_init(tegra_init); -- cgit v1.2.3