diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/mc13783.c | 10 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 345 | ||||
-rw-r--r-- | sound/soc/codecs/ts3a227e.c | 35 | ||||
-rw-r--r-- | sound/soc/fsl/eukrea-tlv320.c | 2 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 4 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_utils.c | 27 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_utils.h | 3 | ||||
-rw-r--r-- | sound/soc/fsl/imx-mc13783.c | 5 | ||||
-rw-r--r-- | sound/soc/fsl/imx-ssi.c | 5 | ||||
-rw-r--r-- | sound/soc/fsl/wm1133-ev1.c | 4 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 20 | ||||
-rw-r--r-- | sound/soc/tegra/Kconfig | 10 | ||||
-rw-r--r-- | sound/soc/tegra/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_rt5677.c | 347 |
14 files changed, 665 insertions, 154 deletions
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index c1e441c2c8af..2ffb9a0570dc 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -328,16 +328,16 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai, } switch (rx_mask) { - case 0xfffffffc: + case 0x03: val |= SSI_NETWORK_DAC_RXSLOT_0_1; break; - case 0xfffffff3: + case 0x0c: val |= SSI_NETWORK_DAC_RXSLOT_2_3; break; - case 0xffffffcf: + case 0x30: val |= SSI_NETWORK_DAC_RXSLOT_4_5; break; - case 0xffffff3f: + case 0xc0: val |= SSI_NETWORK_DAC_RXSLOT_6_7; break; default: @@ -360,7 +360,7 @@ static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai, if (slots != 4) return -EINVAL; - if (tx_mask != 0xfffffffc) + if (tx_mask != 0x3) return -EINVAL; val |= (0x00 << 2); /* primary timeslot RX/TX(?) is 0 */ diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 07603d142923..51c4713ac6e3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -87,6 +87,7 @@ struct aic3x_priv { #define AIC3X_MODEL_3X 0 #define AIC3X_MODEL_33 1 #define AIC3X_MODEL_3007 2 +#define AIC3X_MODEL_3104 3 u16 model; /* Selects the micbias voltage */ @@ -316,52 +317,37 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { * only for swapped L-to-R and R-to-L routes. See below stereo controls * for direct L-to-L and R-to-R routes. */ - SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume", - LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume", PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume", DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume", - LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume", PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume", DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume", - LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume", PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume", DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume", - LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume", PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume", DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume", - LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume", PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume", DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume", - LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume", PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume", DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), /* Stereo output controls for direct L-to-L and R-to-R routes */ - SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume", - LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL, - 0, 118, 1, output_stage_tlv), SOC_DOUBLE_R_TLV("Line PGA Bypass Volume", PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), @@ -369,9 +355,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume", - LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, - 0, 118, 1, output_stage_tlv), SOC_DOUBLE_R_TLV("HP PGA Bypass Volume", PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), @@ -379,9 +362,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume", - LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, - 0, 118, 1, output_stage_tlv), SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume", PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), @@ -424,6 +404,45 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum), }; +/* For other than tlv320aic3104 */ +static const struct snd_kcontrol_new aic3x_extra_snd_controls[] = { + /* + * Output controls that map to output mixer switches. Note these are + * only for swapped L-to-R and R-to-L routes. See below stereo controls + * for direct L-to-L and R-to-R routes. + */ + SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume", + LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume", + LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume", + LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume", + LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume", + LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), + + SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume", + LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), + + /* Stereo output controls for direct L-to-L and R-to-R routes */ + SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume", + LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL, + 0, 118, 1, output_stage_tlv), + + SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume", + LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, + 0, 118, 1, output_stage_tlv), + + SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume", + LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, + 0, 118, 1, output_stage_tlv), +}; + static const struct snd_kcontrol_new aic3x_mono_controls[] = { SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume", LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, @@ -464,22 +483,24 @@ SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum); /* Left Line Mixer */ static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), }; /* Right Line Mixer */ static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), }; /* Mono Mixer */ @@ -494,42 +515,46 @@ static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = { /* Left HP Mixer */ static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0), }; /* Right HP Mixer */ static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), }; /* Left HPCOM Mixer */ static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0), }; /* Right HPCOM Mixer */ static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = { - SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), + /* Not on tlv320aic3104 */ + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), }; /* Left PGA Mixer */ @@ -550,6 +575,22 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), }; +/* Left PGA Mixer for tlv320aic3104 */ +static const struct snd_kcontrol_new aic3104_left_pga_mixer_controls[] = { + SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1), +}; + +/* Right PGA Mixer for tlv320aic3104 */ +static const struct snd_kcontrol_new aic3104_right_pga_mixer_controls[] = { + SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), +}; + /* Left Line1 Mux */ static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum); @@ -593,26 +634,56 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { /* Inputs to Left ADC */ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), - SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_left_pga_mixer_controls[0], - ARRAY_SIZE(aic3x_left_pga_mixer_controls)), SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line1l_mux_controls), SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line1r_mux_controls), - SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, - &aic3x_left_line2_mux_controls), /* Inputs to Right ADC */ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", LINE1R_2_RADC_CTRL, 2, 0), - SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_right_pga_mixer_controls[0], - ARRAY_SIZE(aic3x_right_pga_mixer_controls)), SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line1l_mux_controls), SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line1r_mux_controls), + + /* Mic Bias */ + SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0, + mic_bias_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUTPUT("LLOUT"), + SND_SOC_DAPM_OUTPUT("RLOUT"), + SND_SOC_DAPM_OUTPUT("HPLOUT"), + SND_SOC_DAPM_OUTPUT("HPROUT"), + SND_SOC_DAPM_OUTPUT("HPLCOM"), + SND_SOC_DAPM_OUTPUT("HPRCOM"), + + SND_SOC_DAPM_INPUT("LINE1L"), + SND_SOC_DAPM_INPUT("LINE1R"), + + /* + * Virtual output pin to detection block inside codec. This can be + * used to keep codec bias on if gpio or detection features are needed. + * Force pin on or construct a path with an input jack and mic bias + * widgets. + */ + SND_SOC_DAPM_OUTPUT("Detection"), +}; + +/* For other than tlv320aic3104 */ +static const struct snd_soc_dapm_widget aic3x_extra_dapm_widgets[] = { + /* Inputs to Left ADC */ + SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_left_pga_mixer_controls[0], + ARRAY_SIZE(aic3x_left_pga_mixer_controls)), + SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, + &aic3x_left_line2_mux_controls), + + /* Inputs to Right ADC */ + SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_right_pga_mixer_controls[0], + ARRAY_SIZE(aic3x_right_pga_mixer_controls)), SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line2_mux_controls), @@ -637,11 +708,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), - /* Mic Bias */ - SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0, - mic_bias_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - /* Output mixers */ SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, &aic3x_left_line_mixer_controls[0], @@ -662,27 +728,46 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { &aic3x_right_hpcom_mixer_controls[0], ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)), - SND_SOC_DAPM_OUTPUT("LLOUT"), - SND_SOC_DAPM_OUTPUT("RLOUT"), - SND_SOC_DAPM_OUTPUT("HPLOUT"), - SND_SOC_DAPM_OUTPUT("HPROUT"), - SND_SOC_DAPM_OUTPUT("HPLCOM"), - SND_SOC_DAPM_OUTPUT("HPRCOM"), - SND_SOC_DAPM_INPUT("MIC3L"), SND_SOC_DAPM_INPUT("MIC3R"), - SND_SOC_DAPM_INPUT("LINE1L"), - SND_SOC_DAPM_INPUT("LINE1R"), SND_SOC_DAPM_INPUT("LINE2L"), SND_SOC_DAPM_INPUT("LINE2R"), +}; - /* - * Virtual output pin to detection block inside codec. This can be - * used to keep codec bias on if gpio or detection features are needed. - * Force pin on or construct a path with an input jack and mic bias - * widgets. - */ - SND_SOC_DAPM_OUTPUT("Detection"), +/* For tlv320aic3104 */ +static const struct snd_soc_dapm_widget aic3104_extra_dapm_widgets[] = { + /* Inputs to Left ADC */ + SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, + &aic3104_left_pga_mixer_controls[0], + ARRAY_SIZE(aic3104_left_pga_mixer_controls)), + + /* Inputs to Right ADC */ + SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, + &aic3104_right_pga_mixer_controls[0], + ARRAY_SIZE(aic3104_right_pga_mixer_controls)), + + /* Output mixers */ + SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_left_line_mixer_controls[0], + ARRAY_SIZE(aic3x_left_line_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_right_line_mixer_controls[0], + ARRAY_SIZE(aic3x_right_line_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_left_hp_mixer_controls[0], + ARRAY_SIZE(aic3x_left_hp_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_right_hp_mixer_controls[0], + ARRAY_SIZE(aic3x_right_hp_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_left_hpcom_mixer_controls[0], + ARRAY_SIZE(aic3x_left_hpcom_mixer_controls) - 2), + SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_right_hpcom_mixer_controls[0], + ARRAY_SIZE(aic3x_right_hpcom_mixer_controls) - 2), + + SND_SOC_DAPM_INPUT("MIC2L"), + SND_SOC_DAPM_INPUT("MIC2R"), }; static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = { @@ -712,17 +797,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left Line1R Mux", "single-ended", "LINE1R"}, {"Left Line1R Mux", "differential", "LINE1R"}, - {"Left Line2L Mux", "single-ended", "LINE2L"}, - {"Left Line2L Mux", "differential", "LINE2L"}, - {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"}, - {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, - {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, - {"Left PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Left ADC", NULL, "Left PGA Mixer"}, - {"Left ADC", NULL, "GPIO1 dmic modclk"}, /* Right Input */ {"Right Line1R Mux", "single-ended", "LINE1R"}, @@ -730,25 +808,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right Line1L Mux", "single-ended", "LINE1L"}, {"Right Line1L Mux", "differential", "LINE1L"}, - {"Right Line2R Mux", "single-ended", "LINE2R"}, - {"Right Line2R Mux", "differential", "LINE2R"}, - {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"}, {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, - {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, - {"Right PGA Mixer", "Mic3L Switch", "MIC3L"}, - {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Right ADC", NULL, "Right PGA Mixer"}, - {"Right ADC", NULL, "GPIO1 dmic modclk"}, - - /* - * Logical path between digital mic enable and GPIO1 modulator clock - * output function - */ - {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, - {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, - {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, /* Left DAC Output */ {"Left DAC Mux", "DAC_L1", "Left DAC"}, @@ -761,10 +824,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right DAC Mux", "DAC_R3", "Right DAC"}, /* Left Line Output */ - {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -773,10 +834,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"LLOUT", NULL, "Left Line Out"}, /* Right Line Output */ - {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -785,10 +844,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"RLOUT", NULL, "Right Line Out"}, /* Left HP Output */ - {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -797,10 +854,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HPLOUT", NULL, "Left HP Out"}, /* Right HP Output */ - {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -809,10 +864,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HPROUT", NULL, "Right HP Out"}, /* Left HPCOM Output */ - {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -823,10 +876,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HPLCOM", NULL, "Left HP Com"}, /* Right HPCOM Output */ - {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"}, - {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"}, @@ -839,6 +890,72 @@ static const struct snd_soc_dapm_route intercon[] = { {"HPRCOM", NULL, "Right HP Com"}, }; +/* For other than tlv320aic3104 */ +static const struct snd_soc_dapm_route intercon_extra[] = { + /* Left Input */ + {"Left Line2L Mux", "single-ended", "LINE2L"}, + {"Left Line2L Mux", "differential", "LINE2L"}, + + {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, + {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, + {"Left PGA Mixer", "Mic3R Switch", "MIC3R"}, + + {"Left ADC", NULL, "GPIO1 dmic modclk"}, + + /* Right Input */ + {"Right Line2R Mux", "single-ended", "LINE2R"}, + {"Right Line2R Mux", "differential", "LINE2R"}, + + {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, + {"Right PGA Mixer", "Mic3L Switch", "MIC3L"}, + {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, + + {"Right ADC", NULL, "GPIO1 dmic modclk"}, + + /* + * Logical path between digital mic enable and GPIO1 modulator clock + * output function + */ + {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, + {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, + {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, + + /* Left Line Output */ + {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Right Line Output */ + {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Left HP Output */ + {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Right HP Output */ + {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Left HPCOM Output */ + {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + + /* Right HPCOM Output */ + {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, +}; + +/* For tlv320aic3104 */ +static const struct snd_soc_dapm_route intercon_extra_3104[] = { + /* Left Input */ + {"Left PGA Mixer", "Mic2L Switch", "MIC2L"}, + {"Left PGA Mixer", "Mic2R Switch", "MIC2R"}, + + /* Right Input */ + {"Right PGA Mixer", "Mic2L Switch", "MIC2L"}, + {"Right PGA Mixer", "Mic2R Switch", "MIC2R"}, +}; + static const struct snd_soc_dapm_route intercon_mono[] = { /* Mono Output */ {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, @@ -867,17 +984,31 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) switch (aic3x->model) { case AIC3X_MODEL_3X: case AIC3X_MODEL_33: + snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets, + ARRAY_SIZE(aic3x_extra_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, intercon_extra, + ARRAY_SIZE(intercon_extra)); snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets, ARRAY_SIZE(aic3x_dapm_mono_widgets)); snd_soc_dapm_add_routes(dapm, intercon_mono, ARRAY_SIZE(intercon_mono)); break; case AIC3X_MODEL_3007: + snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets, + ARRAY_SIZE(aic3x_extra_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, intercon_extra, + ARRAY_SIZE(intercon_extra)); snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets, ARRAY_SIZE(aic3007_dapm_widgets)); snd_soc_dapm_add_routes(dapm, intercon_3007, ARRAY_SIZE(intercon_3007)); break; + case AIC3X_MODEL_3104: + snd_soc_dapm_new_controls(dapm, aic3104_extra_dapm_widgets, + ARRAY_SIZE(aic3104_extra_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, intercon_extra_3104, + ARRAY_SIZE(intercon_extra_3104)); + break; } return 0; @@ -1438,23 +1569,33 @@ static int aic3x_probe(struct snd_soc_codec *codec) aic3x_init(codec); if (aic3x->setup) { - /* setup GPIO functions */ - snd_soc_write(codec, AIC3X_GPIO1_REG, - (aic3x->setup->gpio_func[0] & 0xf) << 4); - snd_soc_write(codec, AIC3X_GPIO2_REG, - (aic3x->setup->gpio_func[1] & 0xf) << 4); + if (aic3x->model != AIC3X_MODEL_3104) { + /* setup GPIO functions */ + snd_soc_write(codec, AIC3X_GPIO1_REG, + (aic3x->setup->gpio_func[0] & 0xf) << 4); + snd_soc_write(codec, AIC3X_GPIO2_REG, + (aic3x->setup->gpio_func[1] & 0xf) << 4); + } else { + dev_warn(codec->dev, "GPIO functionality is not supported on tlv320aic3104\n"); + } } switch (aic3x->model) { case AIC3X_MODEL_3X: case AIC3X_MODEL_33: + snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls, + ARRAY_SIZE(aic3x_extra_snd_controls)); snd_soc_add_codec_controls(codec, aic3x_mono_controls, ARRAY_SIZE(aic3x_mono_controls)); break; case AIC3X_MODEL_3007: + snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls, + ARRAY_SIZE(aic3x_extra_snd_controls)); snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); break; + case AIC3X_MODEL_3104: + break; } /* set mic bias voltage */ @@ -1522,6 +1663,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = { { "tlv320aic33", AIC3X_MODEL_33 }, { "tlv320aic3007", AIC3X_MODEL_3007 }, { "tlv320aic3106", AIC3X_MODEL_3X }, + { "tlv320aic3104", AIC3X_MODEL_3104 }, { } }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); @@ -1673,6 +1815,7 @@ static const struct of_device_id tlv320aic3x_of_match[] = { { .compatible = "ti,tlv320aic33" }, { .compatible = "ti,tlv320aic3007" }, { .compatible = "ti,tlv320aic3106" }, + { .compatible = "ti,tlv320aic3104" }, {}, }; MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 9f2dced046de..9fd80ac1897f 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -20,6 +20,8 @@ #include <sound/jack.h> #include <sound/soc.h> +#include "ts3a227e.h" + struct ts3a227e { struct regmap *regmap; struct snd_soc_jack *jack; @@ -79,6 +81,10 @@ static const int ts3a227e_buttons[] = { /* TS3A227E_REG_SETTING_2 0x05 */ #define KP_ENABLE 0x04 +/* TS3A227E_REG_SETTING_3 0x06 */ +#define MICBIAS_SETTING_SFT (3) +#define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT) + /* TS3A227E_REG_ACCESSORY_STATUS 0x0b */ #define TYPE_3_POLE 0x01 #define TYPE_4_POLE_OMTP 0x02 @@ -221,9 +227,9 @@ int ts3a227e_enable_jack_detect(struct snd_soc_component *component, struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component); snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); ts3a227e->jack = jack; ts3a227e_jack_report(ts3a227e); @@ -248,6 +254,21 @@ static const struct regmap_config ts3a227e_regmap_config = { .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults), }; +static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np) +{ + u32 micbias; + int err; + + err = of_property_read_u32(np, "ti,micbias", &micbias); + if (!err) { + regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3, + MICBIAS_SETTING_MASK, + (micbias & 0x07) << MICBIAS_SETTING_SFT); + } + + return 0; +} + static int ts3a227e_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -266,6 +287,14 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, if (IS_ERR(ts3a227e->regmap)) return PTR_ERR(ts3a227e->regmap); + if (dev->of_node) { + ret = ts3a227e_parse_dt(ts3a227e, dev->of_node); + if (ret) { + dev_err(dev, "Failed to parse device tree: %d\n", ret); + return ret; + } + } + ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "TS3A227E", ts3a227e); diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 8c9e9006dd84..e1aa3834b101 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -50,7 +50,7 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, return ret; } - snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); + snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0); ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 46549de60e50..2595611e8a6d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -992,8 +992,8 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN); - regmap_write(regs, CCSR_SSI_STMSK, tx_mask); - regmap_write(regs, CCSR_SSI_SRMSK, rx_mask); + regmap_write(regs, CCSR_SSI_STMSK, ~tx_mask); + regmap_write(regs, CCSR_SSI_SRMSK, ~rx_mask); regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, val); diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index 2ac7755da876..b9e42b503a37 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -86,33 +86,6 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, } EXPORT_SYMBOL(fsl_asoc_get_dma_channel); -/** - * fsl_asoc_xlate_tdm_slot_mask - generate TDM slot TX/RX mask. - * - * @slots: Number of slots in use. - * @tx_mask: bitmask representing active TX slots. - * @rx_mask: bitmask representing active RX slots. - * - * This function used to generate the TDM slot TX/RX mask. And the TX/RX - * mask will use a 0 bit for an active slot as default, and the default - * active bits are at the LSB of the mask value. - */ -int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots, - unsigned int *tx_mask, - unsigned int *rx_mask) -{ - if (!slots) - return -EINVAL; - - if (tx_mask) - *tx_mask = ~((1 << slots) - 1); - if (rx_mask) - *rx_mask = ~((1 << slots) - 1); - - return 0; -} -EXPORT_SYMBOL_GPL(fsl_asoc_xlate_tdm_slot_mask); - MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); MODULE_DESCRIPTION("Freescale ASoC utility code"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h index df535db40313..1687b66ef18e 100644 --- a/sound/soc/fsl/fsl_utils.h +++ b/sound/soc/fsl/fsl_utils.h @@ -22,7 +22,4 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name, struct snd_soc_dai_link *dai, unsigned int *dma_channel_id, unsigned int *dma_id); -int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots, - unsigned int *tx_mask, - unsigned int *rx_mask); #endif /* _FSL_UTILS_H */ diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 6bf5bce01a92..9e6493d4e7ff 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -37,8 +37,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret; - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xfffffffc, 0xfffffffc, - 4, 16); + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 4, 16); if (ret) return ret; @@ -46,7 +45,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x0, 0xfffffffc, 2, 16); + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16); if (ret) return ret; diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index fa801e17c51e..461ce27b884f 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -74,8 +74,8 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, sccr |= SSI_STCCR_DC(slots - 1); writel(sccr, ssi->base + SSI_SRCCR); - writel(tx_mask, ssi->base + SSI_STMSK); - writel(rx_mask, ssi->base + SSI_SRMSK); + writel(~tx_mask, ssi->base + SSI_STMSK); + writel(~rx_mask, ssi->base + SSI_SRMSK); return 0; } @@ -340,7 +340,6 @@ static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { .set_fmt = imx_ssi_set_dai_fmt, .set_clkdiv = imx_ssi_set_dai_clkdiv, .set_sysclk = imx_ssi_set_dai_sysclk, - .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask, .set_tdm_slot = imx_ssi_set_dai_tdm_slot, .trigger = imx_ssi_trigger, }; diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index d072bd13db09..a958937ab405 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c @@ -106,10 +106,10 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream, /* TODO: The SSI driver should figure this out for us */ switch (channels) { case 2: - snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); + snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0); break; case 1: - snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffe, 0xffffffe, 1, 0); + snd_soc_dai_set_tdm_slot(cpu_dai, 0x1, 0x1, 1, 0); break; default: return -EINVAL; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c29b6caf2927..d94434d6138e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2140,15 +2140,27 @@ static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, } /** - * snd_soc_dai_set_tdm_slot - configure DAI TDM. - * @dai: DAI + * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation + * @dai: The DAI to configure * @tx_mask: bitmask representing active TX slots. * @rx_mask: bitmask representing active RX slots. * @slots: Number of slots in use. * @slot_width: Width in bits for each slot. * - * Configures a DAI for TDM operation. Both mask and slots are codec and DAI - * specific. + * This function configures the specified DAI for TDM operation. @slot contains + * the total number of slots of the TDM stream and @slot_with the width of each + * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the + * active slots of the TDM stream for the specified DAI, i.e. which slots the + * DAI should write to or read from. If a bit is set the corresponding slot is + * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to + * the first slot, bit 1 to the second slot and so on. The first active slot + * maps to the first channel of the DAI, the second active slot to the second + * channel and so on. + * + * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, + * @rx_mask and @slot_width will be ignored. + * + * Returns 0 on success, a negative error code otherwise. */ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 31198cf7f88d..a6768f832c6f 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -128,3 +128,13 @@ config SND_SOC_TEGRA_MAX98090 help Say Y or M here if you want to add support for SoC audio on Tegra boards using the MAX98090 codec, such as Venice2. + +config SND_SOC_TEGRA_RT5677 + tristate "SoC Audio support for Tegra boards using a RT5677 codec" + depends on SND_SOC_TEGRA && I2C && GPIOLIB + select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC + select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC + select SND_SOC_RT5677 + help + Say Y or M here if you want to add support for SoC audio on Tegra + boards using the RT5677 codec, such as Ryu. diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 5ae588cd96c4..9171655ad843 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o # Tegra machine Support snd-soc-tegra-rt5640-objs := tegra_rt5640.o +snd-soc-tegra-rt5677-objs := tegra_rt5677.o snd-soc-tegra-wm8753-objs := tegra_wm8753.o snd-soc-tegra-wm8903-objs := tegra_wm8903.o snd-soc-tegra-wm9712-objs := tegra_wm9712.o @@ -27,6 +28,7 @@ snd-soc-tegra-alc5632-objs := tegra_alc5632.o snd-soc-tegra-max98090-objs := tegra_max98090.o obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o +obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c new file mode 100644 index 000000000000..e4cf978a6e3a --- /dev/null +++ b/sound/soc/tegra/tegra_rt5677.c @@ -0,0 +1,347 @@ +/* +* tegra_rt5677.c - Tegra machine ASoC driver for boards using RT5677 codec. + * + * Copyright (c) 2014, The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Based on code copyright/by: + * + * Copyright (C) 2010-2012 - NVIDIA, Inc. + * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net> + * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. + * Copyright 2007 Wolfson Microelectronics PLC. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> + +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "../codecs/rt5677.h" + +#include "tegra_asoc_utils.h" + +#define DRV_NAME "tegra-snd-rt5677" + +struct tegra_rt5677 { + struct tegra_asoc_utils_data util_data; + int gpio_hp_det; + int gpio_hp_en; + int gpio_mic_present; + int gpio_dmic_clk_en; +}; + +static int tegra_rt5677_asoc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_card *card = rtd->card; + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); + int srate, mclk, err; + + srate = params_rate(params); + mclk = 256 * srate; + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + + err = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, mclk, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return err; + } + + return 0; +} + +static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); + + if (!gpio_is_valid(machine->gpio_hp_en)) + return 0; + + gpio_set_value_cansleep(machine->gpio_hp_en, + SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static struct snd_soc_ops tegra_rt5677_ops = { + .hw_params = tegra_rt5677_asoc_hw_params, +}; + +static struct snd_soc_jack tegra_rt5677_hp_jack; + +static struct snd_soc_jack_pin tegra_rt5677_hp_jack_pins = { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, +}; +static struct snd_soc_jack_gpio tegra_rt5677_hp_jack_gpio = { + .name = "Headphone detection", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, +}; + +static struct snd_soc_jack tegra_rt5677_mic_jack; + +static struct snd_soc_jack_pin tegra_rt5677_mic_jack_pins = { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, +}; + +static struct snd_soc_jack_gpio tegra_rt5677_mic_jack_gpio = { + .name = "Headset Mic detection", + .report = SND_JACK_MICROPHONE, + .debounce_time = 150, + .invert = 1 +}; + +static const struct snd_soc_dapm_widget tegra_rt5677_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_HP("Headphone", tegra_rt5677_event_hp), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic 1", NULL), + SND_SOC_DAPM_MIC("Internal Mic 2", NULL), +}; + +static const struct snd_kcontrol_new tegra_rt5677_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic 1"), + SOC_DAPM_PIN_SWITCH("Internal Mic 2"), +}; + +static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card); + + snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, + &tegra_rt5677_hp_jack); + snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1, + &tegra_rt5677_hp_jack_pins); + + if (gpio_is_valid(machine->gpio_hp_det)) { + tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det; + snd_soc_jack_add_gpios(&tegra_rt5677_hp_jack, 1, + &tegra_rt5677_hp_jack_gpio); + } + + + snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, + &tegra_rt5677_mic_jack); + snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1, + &tegra_rt5677_mic_jack_pins); + + if (gpio_is_valid(machine->gpio_mic_present)) { + tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present; + snd_soc_jack_add_gpios(&tegra_rt5677_mic_jack, 1, + &tegra_rt5677_mic_jack_gpio); + } + + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + + return 0; +} + +static int tegra_rt5677_card_remove(struct snd_soc_card *card) +{ + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); + + if (gpio_is_valid(machine->gpio_hp_det)) { + snd_soc_jack_free_gpios(&tegra_rt5677_hp_jack, 1, + &tegra_rt5677_hp_jack_gpio); + } + + if (gpio_is_valid(machine->gpio_mic_present)) { + snd_soc_jack_free_gpios(&tegra_rt5677_mic_jack, 1, + &tegra_rt5677_mic_jack_gpio); + } + + return 0; +} + +static struct snd_soc_dai_link tegra_rt5677_dai = { + .name = "RT5677", + .stream_name = "RT5677 PCM", + .codec_dai_name = "rt5677-aif1", + .init = tegra_rt5677_asoc_init, + .ops = &tegra_rt5677_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_tegra_rt5677 = { + .name = "tegra-rt5677", + .owner = THIS_MODULE, + .remove = tegra_rt5677_card_remove, + .dai_link = &tegra_rt5677_dai, + .num_links = 1, + .controls = tegra_rt5677_controls, + .num_controls = ARRAY_SIZE(tegra_rt5677_controls), + .dapm_widgets = tegra_rt5677_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra_rt5677_dapm_widgets), + .fully_routed = true, +}; + +static int tegra_rt5677_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct snd_soc_card *card = &snd_soc_tegra_rt5677; + struct tegra_rt5677 *machine; + int ret; + + machine = devm_kzalloc(&pdev->dev, + sizeof(struct tegra_rt5677), GFP_KERNEL); + if (!machine) + return -ENOMEM; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + + machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); + if (machine->gpio_hp_det == -EPROBE_DEFER) + return -EPROBE_DEFER; + + machine->gpio_mic_present = of_get_named_gpio(np, + "nvidia,mic-present-gpios", 0); + if (machine->gpio_mic_present == -EPROBE_DEFER) + return -EPROBE_DEFER; + + machine->gpio_hp_en = of_get_named_gpio(np, "nvidia,hp-en-gpios", 0); + if (machine->gpio_hp_en == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(machine->gpio_hp_en)) { + ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_en, + GPIOF_OUT_INIT_LOW, "hp_en"); + if (ret) { + dev_err(card->dev, "cannot get hp_en gpio\n"); + return ret; + } + } + + machine->gpio_dmic_clk_en = of_get_named_gpio(np, + "nvidia,dmic-clk-en-gpios", 0); + if (machine->gpio_dmic_clk_en == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(machine->gpio_dmic_clk_en)) { + ret = devm_gpio_request_one(&pdev->dev, + machine->gpio_dmic_clk_en, + GPIOF_OUT_INIT_HIGH, "dmic_clk_en"); + if (ret) { + dev_err(card->dev, "cannot get dmic_clk_en gpio\n"); + return ret; + } + } + + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); + if (ret) + goto err; + + tegra_rt5677_dai.codec_of_node = of_parse_phandle(np, + "nvidia,audio-codec", 0); + if (!tegra_rt5677_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_rt5677_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); + if (!tegra_rt5677_dai.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + tegra_rt5677_dai.platform_of_node = tegra_rt5677_dai.cpu_of_node; + + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + if (ret) + goto err; + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_fini_utils; + } + + return 0; + +err_fini_utils: + tegra_asoc_utils_fini(&machine->util_data); +err: + return ret; +} + +static int tegra_rt5677_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card); + + snd_soc_unregister_card(card); + + tegra_asoc_utils_fini(&machine->util_data); + + return 0; +} + +static const struct of_device_id tegra_rt5677_of_match[] = { + { .compatible = "nvidia,tegra-audio-rt5677", }, + {}, +}; + +static struct platform_driver tegra_rt5677_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = tegra_rt5677_of_match, + }, + .probe = tegra_rt5677_probe, + .remove = tegra_rt5677_remove, +}; +module_platform_driver(tegra_rt5677_driver); + +MODULE_AUTHOR("Anatol Pomozov <anatol@google.com>"); +MODULE_DESCRIPTION("Tegra+RT5677 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_rt5677_of_match); |