diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 821 |
1 files changed, 410 insertions, 411 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 71a69908ccf6..b3175860bcb4 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -12,11 +12,11 @@ * * Notes: * The AIC3X is a driver for a low power stereo audio - * codecs aic31, aic32, aic33. + * codecs aic31, aic32, aic33, aic3007. * * It supports full aic33 codec functionality. - * The compatibility with aic32, aic31 is as follows: - * aic32 | aic31 + * The compatibility with aic32, aic31 and aic3007 is as follows: + * aic32/aic3007 | aic31 * --------------------------------------- * MONO_LOUT -> N/A | MONO_LOUT -> N/A * | IN1L -> LINE1L @@ -63,11 +63,17 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { /* codec private data */ struct aic3x_priv { - struct snd_soc_codec codec; struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; + enum snd_soc_control_type control_type; + struct aic3x_setup_data *setup; + void *control_data; unsigned int sysclk; int master; int gpio_reset; +#define AIC3X_MODEL_3X 0 +#define AIC3X_MODEL_33 1 +#define AIC3X_MODEL_3007 2 + u16 model; }; /* @@ -286,64 +292,102 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_DOUBLE_R_TLV("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv), + /* + * 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("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), SOC_DOUBLE_R_TLV("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0), - SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R_TLV("LineL DAC Playback Volume", - DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL, - 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume", - PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume", - PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume", - LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL, + + SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume", + LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume", - LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL, + SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume", + PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume", - PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL, + + 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("Mono Line2 Bypass Playback Volume", - LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, + SOC_DOUBLE_R_TLV("HP PGA Bypass Volume", + PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, - 0x01, 0), - SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume", - PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, + + SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume", + LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume", - PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume", - PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume", - LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, + SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume", + PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, + + /* Output pin mute controls */ + SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, + 0x01, 0), + SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), + SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, + 0x01, 0), + SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, 0x01, 0), - SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume", - PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), - SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume", - PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), - SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume", - LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, - 0, 118, 1, output_stage_tlv), /* * Note: enable Automatic input Gain Controller with care. It can @@ -359,6 +403,14 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), }; +/* + * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps + */ +static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0); + +static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = + SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv); + /* Left DAC Mux */ static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); @@ -375,22 +427,74 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]); static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); -/* Left DAC_L1 Mixer */ -static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), +/* 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), +}; + +/* 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), +}; + +/* Mono Mixer */ +static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = { + SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), +}; + +/* 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), +}; + +/* 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), +}; + +/* 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), }; -/* Right DAC_R1 Mixer */ -static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_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), }; /* Left PGA Mixer */ @@ -427,54 +531,11 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]); static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); -/* Left PGA Bypass Mixer */ -static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), -}; - -/* Right PGA Bypass Mixer */ -static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), -}; - -/* Left Line2 Bypass Mixer */ -static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), -}; - -/* Right Line2 Bypass Mixer */ -static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), -}; - static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { /* Left DAC to Left Outputs */ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0), SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_dac_mux_controls), - SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_left_dac_mixer_controls[0], - ARRAY_SIZE(aic3x_left_dac_mixer_controls)), SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_hpcom_mux_controls), SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0), @@ -485,9 +546,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0), SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_dac_mux_controls), - SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_right_dac_mixer_controls[0], - ARRAY_SIZE(aic3x_right_dac_mixer_controls)), SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_hpcom_mux_controls), SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0), @@ -551,25 +609,28 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", MICBIAS_CTRL, 6, 3, 3, 0), - /* Left PGA to Left Output bypass */ - SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_left_pga_bp_mixer_controls[0], - ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)), - - /* Right PGA to Right Output bypass */ - SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_right_pga_bp_mixer_controls[0], - ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)), - - /* Left Line2 to Left Output bypass */ - SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_left_line2_bp_mixer_controls[0], - ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)), - - /* Right Line2 to Right Output bypass */ - SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, - &aic3x_right_line2_bp_mixer_controls[0], - ARRAY_SIZE(aic3x_right_line2_bp_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)), + 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)), + SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, + &aic3x_mono_mixer_controls[0], + ARRAY_SIZE(aic3x_mono_mixer_controls)), + 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)), + 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)), + 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)), + 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)), SND_SOC_DAPM_OUTPUT("LLOUT"), SND_SOC_DAPM_OUTPUT("RLOUT"), @@ -587,67 +648,16 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_INPUT("LINE2R"), }; -static const struct snd_soc_dapm_route intercon[] = { - /* Left Output */ - {"Left DAC Mux", "DAC_L1", "Left DAC"}, - {"Left DAC Mux", "DAC_L2", "Left DAC"}, - {"Left DAC Mux", "DAC_L3", "Left DAC"}, - - {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"}, - {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"}, - {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, - {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, - {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, - {"Left Line Out", NULL, "Left DAC Mux"}, - {"Left HP Out", NULL, "Left DAC Mux"}, +static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = { + /* Class-D outputs */ + SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0), - {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"}, - {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"}, - {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"}, - - {"Left Line Out", NULL, "Left DAC_L1 Mixer"}, - {"Mono Out", NULL, "Left DAC_L1 Mixer"}, - {"Left HP Out", NULL, "Left DAC_L1 Mixer"}, - {"Left HP Com", NULL, "Left HPCOM Mux"}, - - {"LLOUT", NULL, "Left Line Out"}, - {"LLOUT", NULL, "Left Line Out"}, - {"HPLOUT", NULL, "Left HP Out"}, - {"HPLCOM", NULL, "Left HP Com"}, - - /* Right Output */ - {"Right DAC Mux", "DAC_R1", "Right DAC"}, - {"Right DAC Mux", "DAC_R2", "Right DAC"}, - {"Right DAC Mux", "DAC_R3", "Right DAC"}, - - {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"}, - {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"}, - {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, - {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, - {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, - {"Right Line Out", NULL, "Right DAC Mux"}, - {"Right HP Out", NULL, "Right DAC Mux"}, - - {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"}, - {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"}, - {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"}, - {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"}, - {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"}, - - {"Right Line Out", NULL, "Right DAC_R1 Mixer"}, - {"Mono Out", NULL, "Right DAC_R1 Mixer"}, - {"Right HP Out", NULL, "Right DAC_R1 Mixer"}, - {"Right HP Com", NULL, "Right HPCOM Mux"}, - - {"RLOUT", NULL, "Right Line Out"}, - {"RLOUT", NULL, "Right Line Out"}, - {"HPROUT", NULL, "Right HP Out"}, - {"HPRCOM", NULL, "Right HP Com"}, - - /* Mono Output */ - {"MONO_LOUT", NULL, "Mono Out"}, - {"MONO_LOUT", NULL, "Mono Out"}, + SND_SOC_DAPM_OUTPUT("SPOP"), + SND_SOC_DAPM_OUTPUT("SPOM"), +}; +static const struct snd_soc_dapm_route intercon[] = { /* Left Input */ {"Left Line1L Mux", "single-ended", "LINE1L"}, {"Left Line1L Mux", "differential", "LINE1L"}, @@ -680,74 +690,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right ADC", NULL, "Right PGA Mixer"}, {"Right ADC", NULL, "GPIO1 dmic modclk"}, - /* Left PGA Bypass */ - {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"}, - - {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, - {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, - {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"}, - - {"Left Line Out", NULL, "Left PGA Bypass Mixer"}, - {"Mono Out", NULL, "Left PGA Bypass Mixer"}, - {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, - - /* Right PGA Bypass */ - {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"}, - - {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, - {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, - {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"}, - {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"}, - {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"}, - - {"Right Line Out", NULL, "Right PGA Bypass Mixer"}, - {"Mono Out", NULL, "Right PGA Bypass Mixer"}, - {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, - - /* Left Line2 Bypass */ - {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"}, - - {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, - {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, - {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"}, - - {"Left Line Out", NULL, "Left Line2 Bypass Mixer"}, - {"Mono Out", NULL, "Left Line2 Bypass Mixer"}, - {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, - - /* Right Line2 Bypass */ - {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"}, - - {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, - {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, - {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"}, - {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"}, - {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"}, - - {"Right Line Out", NULL, "Right Line2 Bypass Mixer"}, - {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, - {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, - /* * Logical path between digital mic enable and GPIO1 modulator clock * output function @@ -755,16 +697,131 @@ static const struct snd_soc_dapm_route intercon[] = { {"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"}, + {"Left DAC Mux", "DAC_L2", "Left DAC"}, + {"Left DAC Mux", "DAC_L3", "Left DAC"}, + + /* Right DAC Output */ + {"Right DAC Mux", "DAC_R1", "Right DAC"}, + {"Right DAC Mux", "DAC_R2", "Right DAC"}, + {"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"}, + + {"Left Line Out", NULL, "Left Line Mixer"}, + {"Left Line Out", NULL, "Left DAC Mux"}, + {"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"}, + + {"Right Line Out", NULL, "Right Line Mixer"}, + {"Right Line Out", NULL, "Right DAC Mux"}, + {"RLOUT", NULL, "Right Line Out"}, + + /* Mono Output */ + {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, + {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, + {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"}, + {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, + {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, + {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"}, + + {"Mono Out", NULL, "Mono Mixer"}, + {"MONO_LOUT", NULL, "Mono 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"}, + + {"Left HP Out", NULL, "Left HP Mixer"}, + {"Left HP Out", NULL, "Left DAC Mux"}, + {"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"}, + + {"Right HP Out", NULL, "Right HP Mixer"}, + {"Right HP Out", NULL, "Right DAC Mux"}, + {"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"}, + + {"Left HPCOM Mux", "differential of HPLOUT", "Left HP Mixer"}, + {"Left HPCOM Mux", "constant VCM", "Left HPCOM Mixer"}, + {"Left HPCOM Mux", "single-ended", "Left HPCOM Mixer"}, + {"Left HP Com", NULL, "Left HPCOM Mux"}, + {"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"}, + + {"Right HPCOM Mux", "differential of HPROUT", "Right HP Mixer"}, + {"Right HPCOM Mux", "constant VCM", "Right HPCOM Mixer"}, + {"Right HPCOM Mux", "single-ended", "Right HPCOM Mixer"}, + {"Right HPCOM Mux", "differential of HPLCOM", "Left HPCOM Mixer"}, + {"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"}, + {"Right HP Com", NULL, "Right HPCOM Mux"}, + {"HPRCOM", NULL, "Right HP Com"}, +}; + +static const struct snd_soc_dapm_route intercon_3007[] = { + /* Class-D outputs */ + {"Left Class-D Out", NULL, "Left Line Out"}, + {"Right Class-D Out", NULL, "Left Line Out"}, + {"SPOP", NULL, "Left Class-D Out"}, + {"SPOM", NULL, "Right Class-D Out"}, }; static int aic3x_add_widgets(struct snd_soc_codec *codec) { + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, ARRAY_SIZE(aic3x_dapm_widgets)); /* set up audio path interconnects */ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + if (aic3x->model == AIC3X_MODEL_3007) { + snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets, + ARRAY_SIZE(aic3007_dapm_widgets)); + snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007)); + } + return 0; } @@ -773,8 +830,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; + struct snd_soc_codec *codec =rtd->codec; struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; @@ -1101,8 +1157,8 @@ static struct snd_soc_dai_ops aic3x_dai_ops = { .set_fmt = aic3x_set_dai_fmt, }; -struct snd_soc_dai aic3x_dai = { - .name = "tlv320aic3x", +static struct snd_soc_dai_driver aic3x_dai = { + .name = "tlv320aic3x-hifi", .playback = { .stream_name = "Playback", .channels_min = 1, @@ -1116,23 +1172,18 @@ struct snd_soc_dai aic3x_dai = { .rates = AIC3X_RATES, .formats = AIC3X_FORMATS,}, .ops = &aic3x_dai_ops, + .symmetric_rates = 1, }; -EXPORT_SYMBOL_GPL(aic3x_dai); -static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) +static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } -static int aic3x_resume(struct platform_device *pdev) +static int aic3x_resume(struct snd_soc_codec *codec) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; int i; u8 data[2]; u8 *cache = codec->reg_cache; @@ -1155,24 +1206,9 @@ static int aic3x_resume(struct platform_device *pdev) */ static int aic3x_init(struct snd_soc_codec *codec) { + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int reg; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->name = "tlv320aic3x"; - codec->owner = THIS_MODULE; - codec->read = aic3x_read_reg_cache; - codec->write = aic3x_write; - codec->set_bias_level = aic3x_set_bias_level; - codec->dai = &aic3x_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(aic3x_reg); - codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); aic3x_write(codec, AIC3X_RESET, SOFT_RESET); @@ -1239,68 +1275,83 @@ static int aic3x_init(struct snd_soc_codec *codec) aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); + if (aic3x->model == AIC3X_MODEL_3007) { + /* Class-D speaker driver init; datasheet p. 46 */ + aic3x_write(codec, AIC3X_PAGE_SELECT, 0x0D); + aic3x_write(codec, 0xD, 0x0D); + aic3x_write(codec, 0x8, 0x5C); + aic3x_write(codec, 0x8, 0x5D); + aic3x_write(codec, 0x8, 0x5C); + aic3x_write(codec, AIC3X_PAGE_SELECT, 0x00); + aic3x_write(codec, CLASSD_CTRL, 0); + } + /* off, with power on */ aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } -static struct snd_soc_codec *aic3x_codec; - -static int aic3x_register(struct snd_soc_codec *codec) +static int aic3x_probe(struct snd_soc_codec *codec) { - int ret; + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); - ret = aic3x_init(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to initialise device\n"); - return ret; - } + codec->hw_write = (hw_write_t) i2c_master_send; + codec->control_data = aic3x->control_data; - aic3x_codec = codec; + aic3x_init(codec); - ret = snd_soc_register_codec(codec); - if (ret) { - dev_err(codec->dev, "Failed to register codec\n"); - return ret; + if (aic3x->setup) { + /* setup GPIO functions */ + aic3x_write(codec, AIC3X_GPIO1_REG, + (aic3x->setup->gpio_func[0] & 0xf) << 4); + aic3x_write(codec, AIC3X_GPIO2_REG, + (aic3x->setup->gpio_func[1] & 0xf) << 4); } - ret = snd_soc_register_dai(&aic3x_dai); - if (ret) { - dev_err(codec->dev, "Failed to register dai\n"); - snd_soc_unregister_codec(codec); - return ret; - } + snd_soc_add_controls(codec, aic3x_snd_controls, + ARRAY_SIZE(aic3x_snd_controls)); + if (aic3x->model == AIC3X_MODEL_3007) + snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); + + aic3x_add_widgets(codec); return 0; } -static int aic3x_unregister(struct aic3x_priv *aic3x) +static int aic3x_remove(struct snd_soc_codec *codec) { - aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF); - - snd_soc_unregister_dai(&aic3x_dai); - snd_soc_unregister_codec(&aic3x->codec); - - if (aic3x->gpio_reset >= 0) { - gpio_set_value(aic3x->gpio_reset, 0); - gpio_free(aic3x->gpio_reset); - } - regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); - regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); - - kfree(aic3x); - aic3x_codec = NULL; - + aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } +static struct snd_soc_codec_driver soc_codec_dev_aic3x = { + .read = aic3x_read_reg_cache, + .write = aic3x_write, + .set_bias_level = aic3x_set_bias_level, + .reg_cache_size = ARRAY_SIZE(aic3x_reg), + .reg_word_size = sizeof(u8), + .reg_cache_default = aic3x_reg, + .probe = aic3x_probe, + .remove = aic3x_remove, + .suspend = aic3x_suspend, + .resume = aic3x_resume, +}; + #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /* * AIC3X 2 wire address can be up to 4 devices with device addresses * 0x18, 0x19, 0x1A, 0x1B */ +static const struct i2c_device_id aic3x_i2c_id[] = { + [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 }, + [AIC3X_MODEL_33] = { "tlv320aic33", 0 }, + [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); + /* * If the i2c layer weren't so broken, we could pass this kind of data * around @@ -1308,10 +1359,10 @@ static int aic3x_unregister(struct aic3x_priv *aic3x) static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct snd_soc_codec *codec; - struct aic3x_priv *aic3x; struct aic3x_pdata *pdata = i2c->dev.platform_data; + struct aic3x_priv *aic3x; int ret, i; + const struct i2c_device_id *tbl; aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); if (aic3x == NULL) { @@ -1319,37 +1370,42 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, return -ENOMEM; } - codec = &aic3x->codec; - codec->dev = &i2c->dev; - snd_soc_codec_set_drvdata(codec, aic3x); - codec->control_data = i2c; - codec->hw_write = (hw_write_t) i2c_master_send; - + aic3x->control_data = i2c; i2c_set_clientdata(i2c, aic3x); + if (pdata) { + aic3x->gpio_reset = pdata->gpio_reset; + aic3x->setup = pdata->setup; + } else { + aic3x->gpio_reset = -1; + } - aic3x->gpio_reset = -1; - if (pdata && pdata->gpio_reset >= 0) { - ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset"); + if (aic3x->gpio_reset >= 0) { + ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); if (ret != 0) goto err_gpio; - aic3x->gpio_reset = pdata->gpio_reset; gpio_direction_output(aic3x->gpio_reset, 0); } + for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) { + if (!strcmp(tbl->name, id->name)) + break; + } + aic3x->model = tbl - aic3x_i2c_id; + for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) aic3x->supplies[i].supply = aic3x_supply_names[i]; - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), + ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); goto err_get; } ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); goto err_enable; } @@ -1358,7 +1414,11 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, gpio_set_value(aic3x->gpio_reset, 1); } - return aic3x_register(codec); + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_aic3x, &aic3x_dai, 1); + if (ret < 0) + goto err_enable; + return ret; err_enable: regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); @@ -1374,20 +1434,22 @@ static int aic3x_i2c_remove(struct i2c_client *client) { struct aic3x_priv *aic3x = i2c_get_clientdata(client); - return aic3x_unregister(aic3x); -} + if (aic3x->gpio_reset >= 0) { + gpio_set_value(aic3x->gpio_reset, 0); + gpio_free(aic3x->gpio_reset); + } + regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); + regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); -static const struct i2c_device_id aic3x_i2c_id[] = { - { "tlv320aic3x", 0 }, - { "tlv320aic33", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); + snd_soc_unregister_codec(&client->dev); + kfree(i2c_get_clientdata(client)); + return 0; +} /* machine i2c codec control layer */ static struct i2c_driver aic3x_i2c_driver = { .driver = { - .name = "aic3x I2C Codec", + .name = "tlv320aic3x-codec", .owner = THIS_MODULE, }, .probe = aic3x_i2c_probe, @@ -1409,90 +1471,27 @@ static inline void aic3x_i2c_exit(void) { i2c_del_driver(&aic3x_i2c_driver); } -#else -static inline void aic3x_i2c_init(void) { } -static inline void aic3x_i2c_exit(void) { } #endif -static int aic3x_probe(struct platform_device *pdev) +static int __init aic3x_modinit(void) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct aic3x_setup_data *setup; - struct snd_soc_codec *codec; int ret = 0; - - codec = aic3x_codec; - if (!codec) { - dev_err(&pdev->dev, "Codec not registered\n"); - return -ENODEV; - } - - socdev->card->codec = codec; - setup = socdev->codec_data; - - if (setup) { - /* setup GPIO functions */ - aic3x_write(codec, AIC3X_GPIO1_REG, - (setup->gpio_func[0] & 0xf) << 4); - aic3x_write(codec, AIC3X_GPIO2_REG, - (setup->gpio_func[1] & 0xf) << 4); - } - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "aic3x: failed to create pcms\n"); - goto pcm_err; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&aic3x_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n", + ret); } - - snd_soc_add_controls(codec, aic3x_snd_controls, - ARRAY_SIZE(aic3x_snd_controls)); - - aic3x_add_widgets(codec); - - return ret; - -pcm_err: - kfree(codec->reg_cache); +#endif return ret; } - -static int aic3x_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - /* power down chip */ - if (codec->control_data) - aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - kfree(codec->reg_cache); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_aic3x = { - .probe = aic3x_probe, - .remove = aic3x_remove, - .suspend = aic3x_suspend, - .resume = aic3x_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); - -static int __init aic3x_modinit(void) -{ - aic3x_i2c_init(); - - return 0; -} module_init(aic3x_modinit); static void __exit aic3x_exit(void) { - aic3x_i2c_exit(); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&aic3x_i2c_driver); +#endif } module_exit(aic3x_exit); |