This list has been moved to linux-omap@xxxxxxxxxxxxxxx Please, keep that in Cc, also for ASoC development, send it also to the proper alsa mailing list alsa-devel@xxxxxxxxxxxxxxxx Tony, I think you should apply this patch in mainline tree: diff --git a/MAINTAINERS b/MAINTAINERS index 8dae455..54c8e90 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4010,6 +4010,13 @@ P: Alex Dubov M: oakad@xxxxxxxxx S: Maintained +TI OMAP +P: Tony Lindgren +M: tony@xxxxxxxxxxx +L: linux-omap@xxxxxxxxxxxxxxx +T: git kernel.org:/pub/scm/linux/tmlind/linux-omap-2.6.git +S: Maintained + TI OMAP MMC INTERFACE DRIVER P: Carlos Aguiar, Anderson Briglia and Syed Khasim M: linux-omap@xxxxxxxxxxxxxxx On Thu, Nov 20, 2008 at 12:02 PM, naveen krishna ch <naveenkrishna.ch@xxxxxxxxx> wrote: > Hi All > > I have been working on TWL4030 codec driver for ALSA SOC. > I have taken sound/soc/codec/twl4030.c as reference from main line > > This Patch adds some kcontrols, widgets and interconnection map for some of > the TWL4030 ASOC codec > I was building it for a custom board as it was for OVERO > > > Suggestions on the DAPM part of the driver would be helpful > > Thanks in advance. > > The patch is as follows. > > > --- twl4030.c 2008-11-19 12:04:32.000000000 +0530 > +++ /home/chnaveen/Desktop/twl4030.c 2008-11-21 15:08:06.000000000 +0530 > @@ -16,7 +16,9 @@ > * along with this program; if not, write to the Free Software > * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA > * 02110-1301 USA > - * > + * Modified by : Naveen Krishna Ch > + * Added Kcontrols for OMAP3 WaterlooBoard > + * Dated : 28th october 2008 > */ > > #include <linux/module.h> > @@ -29,24 +31,27 @@ > #include <linux/i2c/twl4030.h> > #include <sound/core.h> > #include <sound/pcm.h> > +#include <sound/jack.h> > #include <sound/pcm_params.h> > #include <sound/soc.h> > #include <sound/soc-dapm.h> > #include <sound/initval.h> > - > +#include <asm/arch/twl4030.h> > #include "twl4030.h" > > +static int twl4030_jack_func; > + > /* > * twl4030 register cache & default register settings > */ > static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { > 0x00, /* this register not used */ > - 0x93, /* REG_CODEC_MODE (0x1) */ > + 0x03, /* REG_CODEC_MODE (0x1) */ > 0xc3, /* REG_OPTION (0x2) */ > 0x00, /* REG_UNKNOWN (0x3) */ > 0x00, /* REG_MICBIAS_CTL (0x4) */ > - 0x24, /* REG_ANAMICL (0x5) */ > - 0x04, /* REG_ANAMICR (0x6) */ > + 0xb0, /* REG_ANAMICL (0x5) */ > + 0x10, /* REG_ANAMICR (0x6) */ > 0x0a, /* REG_AVADC_CTL (0x7) */ > 0x00, /* REG_ADCMICSEL (0x8) */ > 0x00, /* REG_DIGMIXING (0x9) */ > @@ -67,22 +72,22 @@ > 0x00, /* REG_ARX2VTXPGA (0x18) */ > 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ > 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ > - 0x4b, /* REG_ARXL2_APGA_CTL (0x1B) */ > - 0x4b, /* REG_ARXR2_APGA_CTL (0x1C) */ > + 0x2b, /* REG_ARXL2_APGA_CTL (0x1B) */ > + 0x2b, /* REG_ARXR2_APGA_CTL (0x1C) */ > 0x00, /* REG_ATX2ARXPGA (0x1D) */ > 0x00, /* REG_BT_IF (0x1E) */ > 0x00, /* REG_BTPGA (0x1F) */ > 0x00, /* REG_BTSTPGA (0x20) */ > - 0x00, /* REG_EAR_CTL (0x21) */ > - 0x24, /* REG_HS_SEL (0x22) */ > - 0x0a, /* REG_HS_GAIN_SET (0x23) */ > - 0x00, /* REG_HS_POPN_SET (0x24) */ > - 0x00, /* REG_PREDL_CTL (0x25) */ > - 0x00, /* REG_PREDR_CTL (0x26) */ > - 0x00, /* REG_PRECKL_CTL (0x27) */ > - 0x00, /* REG_PRECKR_CTL (0x28) */ > - 0x00, /* REG_HFL_CTL (0x29) */ > - 0x00, /* REG_HFR_CTL (0x2A) */ > + 0x20, /* REG_EAR_CTL (0x21) */ > + 0x00, /* REG_HS_SEL (0x22) */ > + 0x05, /* REG_HS_GAIN_SET (0x23) */ > + 0x42, /* REG_HS_POPN_SET (0x24) */ > + 0x20, /* REG_PREDL_CTL (0x25) */ > + 0x20, /* REG_PREDR_CTL (0x26) */ > + 0x20, /* REG_PRECKL_CTL (0x27) */ > + 0x20, /* REG_PRECKR_CTL (0x28) */ > + 0x1f, /* REG_HFL_CTL (0x29) */ > + 0x1f, /* REG_HFR_CTL (0x2A) */ > 0x00, /* REG_ALC_CTL (0x2B) */ > 0x00, /* REG_ALC_SET1 (0x2C) */ > 0x00, /* REG_ALC_SET2 (0x2D) */ > @@ -112,9 +117,40 @@ > 0x00, /* REG_VIBRA_CTL (0x45) */ > 0x00, /* REG_VIBRA_SET (0x46) */ > 0x00, /* REG_VIBRA_PWM_SET (0x47) */ > - 0x00, /* REG_ANAMIC_GAIN (0x48) */ > + 0x24, /* REG_ANAMIC_GAIN (0x48) */ > 0x00, /* REG_MISC_SET_2 (0x49) */ > }; > +static void twl4030_ext_control(struct snd_soc_codec *codec) > +{ > + if (twl4030_jack_func) > + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); > + else > + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); > + > + snd_soc_dapm_sync(codec); > +} > + > +static int twl4030_get_jack(struct snd_kcontrol *kcontrol, > + struct snd_ctl_elem_value *ucontrol) > +{ > + ucontrol->value.integer.value[0] = twl4030_jack_func; > + > + return 0; > +} > + > +static int twl4030_set_jack(struct snd_kcontrol *kcontrol, > + struct snd_ctl_elem_value *ucontrol) > +{ > + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); > + > + if (twl4030_jack_func == ucontrol->value.integer.value[0]) > + return 0; > + > + twl4030_jack_func = ucontrol->value.integer.value[0]; > + twl4030_ext_control(codec); > + > + return 1; > +} > > /* > * read twl4030 register cache > @@ -188,14 +224,83 @@ > twl4030_write(codec, i, twl4030_reg[i]); > > } > +static const char *jack_function[] = {"Off", "Headphone"}; > + > +static const struct soc_enum twl4030_enum[] = { > + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), > +}; > + > > static const struct snd_kcontrol_new twl4030_snd_controls[] = { > - SOC_DOUBLE_R("Master Playback Volume", > - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, > - 0, 127, 0), > - SOC_DOUBLE_R("Capture Volume", > - TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, > - 0, 127, 0), > + > + /* Master Playback Volume Controls */ > + SOC_DOUBLE_R("Master PLayback Course Gain ctrl", > + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, > + 6, 3, 0), > + SOC_DOUBLE_R("Master Playback Fine Gain ctrl", > + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, > + 0, 63, 0), > + > + /* Playback Speaker volume controls */ > + SOC_DOUBLE_R("Speaker R2+L2 Volume ctrls", > + TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, > + 3, 17, 0), > + > + /* Capture Gain controls */ > + SOC_DOUBLE_R("Master Capture Gain ctrl", > + TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, > + 0, 31, 0), > + /* Loop gain controls*/ > + SOC_DOUBLE("Loop Gain ctrl", TWL4030_REG_ATX2ARXPGA, > + 3 , 0, 7, 0), > + > + SOC_DOUBLE("Main +Sub mic capture gain ctrl", > + TWL4030_REG_ANAMIC_GAIN, 3 , 0, 5, 0), > + > + SOC_DOUBLE_R("External Speaker Volume control", > + TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL, > + 4, 3, 0), > + > + SOC_DOUBLE_R("Pre Car kit Volume control", > + TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL, > + 4, 3, 0), > + > + SOC_SINGLE("DACL2", TWL4030_REG_AVDAC_CTL, 3, 1, 0), > + SOC_SINGLE("DACR2", TWL4030_REG_AVDAC_CTL, 2, 1, 0), > + > + SOC_ENUM_EXT("Jack Function", twl4030_enum[0], > + twl4030_get_jack, twl4030_set_jack), > +}; > + > +/* Right PGA Mixer control switches */ > +static const struct snd_kcontrol_new twl4030_right_pga_mixer_controls[] = { > + SOC_DAPM_SINGLE("HS Mic switch", TWL4030_REG_ANAMICL, 1, 1, 0), > + SOC_DAPM_SINGLE("Aux/FM right switch", TWL4030_REG_ANAMICR, 2, 1, > 0), > + SOC_DAPM_SINGLE("Sub Mic switch", TWL4030_REG_ANAMICR, 0, 1, 0), > +}; > + > +/* Left PGA Mixer control switches */ > +static const struct snd_kcontrol_new twl4030_left_pga_mixer_controls[] = { > + SOC_DAPM_SINGLE("HS Mic switch", TWL4030_REG_ANAMICL, 1, 1, 0), > + SOC_DAPM_SINGLE("Aux/FM left switch", TWL4030_REG_ANAMICL, 2, 1, > 0), > + SOC_DAPM_SINGLE("Main Mic switch", TWL4030_REG_ANAMICL, 0, 1, 0), > +}; > + > +/* Right DACR2 Mixer */ > +static const struct snd_kcontrol_new twl4030_dacr2_mixer_controls[] = { > + SOC_DAPM_SINGLE("Headset-R switch", TWL4030_REG_HS_SEL, 5, 1, 0), > + SOC_DAPM_SINGLE("Handsfree-R switch", TWL4030_REG_HFR_CTL, 5, 1, > 0), > + SOC_DAPM_SINGLE("PRECK-R switch", TWL4030_REG_PRECKR_CTL, 2, 1, > 0), > + SOC_DAPM_DOUBLE("E class-D amp-R switch", TWL4030_REG_PREDR_CTL, 3, 2, > 1, 0, 0), > +}; > + > +/* Left DACL2 Mixer */ > +static const struct snd_kcontrol_new twl4030_dacl2_mixer_controls[] = { > + SOC_DAPM_SINGLE("Headset-L switch", TWL4030_REG_HS_SEL, 2, 1, 0), > + SOC_DAPM_SINGLE("Handsfree-L switch", TWL4030_REG_HFL_CTL, 5, 1, > 0), > + SOC_DAPM_SINGLE("Ear peice switch", TWL4030_REG_EAR_CTL, 2, 1, > 0), > + SOC_DAPM_SINGLE("PRECK-L switch", TWL4030_REG_PRECKL_CTL, 2, 1, 0), > + SOC_DAPM_DOUBLE("E class-D amp-L switch", TWL4031_REG_PREDL_CTL, 3, > 2, 1, 0, 0), > }; > > /* add non dapm controls */ > @@ -215,27 +320,96 @@ > } > > static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { > - SND_SOC_DAPM_INPUT("INL"), > - SND_SOC_DAPM_INPUT("INR"), > - > - SND_SOC_DAPM_OUTPUT("OUTL"), > - SND_SOC_DAPM_OUTPUT("OUTR"), > - > - SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0), > - SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0), > - > - SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), > - SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), > + > + SND_SOC_DAPM_HP("Headphone Jack", NULL), > + > + /* Left ADC for capture */ > + SND_SOC_DAPM_ADC("ADCL", "Left Capture ADC", TWL4030_REG_AVADC_CTL, > 3, 0), > + > + /* dapm widget (path domain) for left PGA mixer */ > + SND_SOC_DAPM_MIXER("LINEIN-L", SND_SOC_NOPM, 0, 0, > + &twl4030_left_pga_mixer_controls[0], > + ARRAY_SIZE(twl4030_left_pga_mixer_controls)), > + > + /* Right ADC for capture*/ > + SND_SOC_DAPM_ADC("ADCR", "Right Capture ADC", > TWL4030_REG_AVADC_CTL, 1, 0), > + > + /* dapm widget (path domain) for right PGA mixer */ > + SND_SOC_DAPM_MIXER("LINEIN-R", SND_SOC_NOPM, 0, 0, > + &twl4030_right_pga_mixer_controls[0], > + ARRAY_SIZE(twl4030_right_pga_mixer_controls)), > + > + /* dapm widget (path domain) for left DACL2 Mixer */ > + > + SND_SOC_DAPM_MIXER("DACL2 Mixer", SND_SOC_NOPM, 0, 0, > + &twl4030_dacl2_mixer_controls[0], > + ARRAY_SIZE(twl4030_dacl2_mixer_controls)), > + > + /* dapm widget (path domain) for DACR2 Mixer */ > + SND_SOC_DAPM_MIXER("DACR2 Mixer", SND_SOC_NOPM, 0, 0, > + &twl4030_dacr2_mixer_controls[0], > + ARRAY_SIZE(twl4030_dacr2_mixer_controls)), > + > + /* Inputs Left*/ > + SND_SOC_DAPM_INPUT("HSMIC"), > + SND_SOC_DAPM_INPUT("Aux/fm left"), > + SND_SOC_DAPM_INPUT("Main mic"), > + > + /* Inputs Right*/ > + SND_SOC_DAPM_INPUT("HSMIC"), > + SND_SOC_DAPM_INPUT("Aux/fm right"), > + SND_SOC_DAPM_INPUT("Sub mic"), > + > + /* Outputs Left*/ > + SND_SOC_DAPM_OUTPUT("HSOL"), > + SND_SOC_DAPM_OUTPUT("IHF_LEFT"), > + SND_SOC_DAPM_OUTPUT("EAR"), > + SND_SOC_DAPM_OUTPUT("E class-D L"), > + SND_SOC_DAPM_OUTPUT("PRECK-L"); > + > + /* Outputs Right */ > + SND_SOC_DAPM_OUTPUT("HSOR"), > + SND_SOC_DAPM_OUTPUT("IHF_RIGHT"), > + SND_SOC_DAPM_OUTPUT("E class-D R"), > + SND_SOC_DAPM_OUTPUT("PRECK-R"); > }; > > static const struct snd_soc_dapm_route intercon[] = { > - /* outputs */ > - {"OUTL", NULL, "DACL"}, > - {"OUTR", NULL, "DACR"}, > - > - /* inputs */ > - {"ADCL", NULL, "INL"}, > - {"ADCR", NULL, "INR"}, > + > + /* ******** Left input ******** */ > + {"LINEIN-L", "HS Mic switch", "HSMIC"}, > + {"LINEIN-L", "Aux/FM left switch", "Aux/fm left"}, > + {"LINEIN-L", "Main Mic switch", "Main mic"}, > + > + {"ADCL", NULL, "LINEIN-L"}, > + > + > + /* ******** Right Input ******** */ > + {"LINEIN-R", "HS Mic switch", "HSMIC"}, > + {"LINEIN-R", "Aux/FM right switch", "Aux/fm right"}, > + {"LINEIN-R", "Sub Mic switch", "Sub mic"}, > + > + {"ADCR", NULL, "LINEIN-R"}, > + > + /* ******** Left Output ******** */ > + //{"DACL2", NULL, "DACL2 Mixer"}, > + > + {"DACL2 Mixer", "Headset-L switch", "HSOL"}, > + {"DACL2 Mixer", "Handsfree-L switch", "IHF_LEFT"}, > + {"DACL2 Mixer", "Ear peice switch", "EAR"}, > + {"DACL2 Mixer", "PRECK-L switch", "PRECK-L"}, > + {"DACL2 Mixer","E class-D amp-L switch","E class-D L"}, > + > + {"Headphone Jack",NULL, "HSOL"}, > + /* ******** Right Output ******** */ > + //{"DACR2", NULL, "DACR2 Mixer"}, > + > + {"DACR2 Mixer", "Headset-R switch","HSOR"}, > + {"DACR2 Mixer", "Handsfree-R switch","IHF_RIGHT"}, > + {"DACR2 Mixer", "PRECK-R switch", "PRECK-R"}, > + {"DACR2 Mixer","E class-D amp-R switch","E class-D R"}, > + > + {"Headphone Jack",NULL, "HSOR"}, > }; > > static int twl4030_add_widgets(struct snd_soc_codec *codec) > @@ -280,7 +454,7 @@ > /* toggle CODECPDZ as per TRM */ > twl4030_clear_codecpdz(codec); > twl4030_set_codecpdz(codec); > - > + > /* program anti-pop with bias ramp delay */ > popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); > popn &= TWL4030_RAMP_DELAY; > @@ -384,6 +558,9 @@ > case 48000: > mode |= TWL4030_APLL_RATE_48000; > break; > + case 96000: > + mode |= TWL4030_APLL_RATE_96000; > + break; > default: > printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", > params_rate(params)); > @@ -434,6 +611,7 @@ > u8 infreq; > > switch (freq) { > + > case 19200000: > infreq = TWL4030_APLL_INFREQ_19200KHZ; > break; > @@ -504,20 +682,24 @@ > return 0; > } > > -#define TWL4030_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) > +#define TWL4030_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ > + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ > + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ > + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) > + > #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | > SNDRV_PCM_FORMAT_S24_LE) > > struct snd_soc_dai twl4030_dai = { > .name = "twl4030", > .playback = { > .stream_name = "Playback", > - .channels_min = 2, > + .channels_min = 1, > .channels_max = 2, > .rates = TWL4030_RATES, > .formats = TWL4030_FORMATS,}, > .capture = { > .stream_name = "Capture", > - .channels_min = 2, > + .channels_min = 1, > .channels_max = 2, > .rates = TWL4030_RATES, > .formats = TWL4030_FORMATS,}, > @@ -616,13 +798,14 @@ > > codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); > if (codec == NULL) > - return -ENOMEM; > - > + return -ENOMEM; > + > socdev->codec = codec; > mutex_init(&codec->mutex); > INIT_LIST_HEAD(&codec->dapm_widgets); > INIT_LIST_HEAD(&codec->dapm_paths); > - > + > + > twl4030_socdev = socdev; > twl4030_init(socdev); > > Patch ends.. > > Thanks and Regards, > > (: Naveen Krishna Ch :) > _______________________________________________ > Linux-omap-open-source mailing list > Linux-omap-open-source@xxxxxxxxxxxxxx > http://linux.omap.com/mailman/listinfo/linux-omap-open-source > -- Best Regards, Felipe Balbi felipebalbi@xxxxxxxxxxxxxxxxxxxxx -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html