Commit 801a5656 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/tdm-slot', 'asoc/topic/tegra',...

Merge remote-tracking branches 'asoc/topic/tdm-slot', 'asoc/topic/tegra', 'asoc/topic/tlv320aic3x', 'asoc/topic/ts3a227e' and 'asoc/topic/ts3a277e' into asoc-next
NVIDIA Tegra audio complex, with RT5677 CODEC
Required properties:
- compatible : "nvidia,tegra-audio-rt5677"
- clocks : Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names : Must include the following entries:
- pll_a
- pll_a_out0
- mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
- nvidia,model : The user-visible name of this sound complex.
- nvidia,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the RT5677's pins (as documented in its binding), and the jacks
on the board:
* Headphone
* Speaker
* Headset Mic
* Internal Mic 1
* Internal Mic 2
- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
connected to the CODEC.
- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding
assumes that AIF1 on the CODEC is connected to Tegra.
Optional properties:
- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in
- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier
- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in
- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal
Example:
sound {
compatible = "nvidia,tegra-audio-rt5677-ryu",
"nvidia,tegra-audio-rt5677";
nvidia,model = "NVIDIA Tegra Ryu";
nvidia,audio-routing =
"Headphone", "LOUT2",
"Headphone", "LOUT1",
"Headset Mic", "MICBIAS1",
"IN1P", "Headset Mic",
"IN1N", "Headset Mic",
"DMIC L1", "Internal Mic 1",
"DMIC R1", "Internal Mic 1",
"DMIC L2", "Internal Mic 2",
"DMIC R2", "Internal Mic 2",
"Speaker", "PDM1L",
"Speaker", "PDM1R";
nvidia,i2s-controller = <&tegra_i2s1>;
nvidia,audio-codec = <&rt5677>;
nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>;
nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>;
nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>;
nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>;
clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
<&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA124_CLK_EXTERN1>;
clock-names = "pll_a", "pll_a_out0", "mclk";
};
......@@ -9,6 +9,7 @@ Required properties:
"ti,tlv320aic33" - TLV320AIC33
"ti,tlv320aic3007" - TLV320AIC3007
"ti,tlv320aic3106" - TLV320AIC3106
"ti,tlv320aic3104" - TLV320AIC3104
- reg - <int> - I2C slave address
......@@ -18,6 +19,7 @@ Optional properties:
- gpio-reset - gpio pin number used for codec reset
- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
- Not supported on tlv320aic3104
- ai3x-micbias-vg - MicBias Voltage required.
1 - MICBIAS output is powered to 2.0V,
2 - MICBIAS output is powered to 2.5V,
......@@ -36,7 +38,13 @@ CODEC output pins:
* HPLCOM
* HPRCOM
CODEC input pins:
CODEC input pins for TLV320AIC3104:
* MIC2L
* MIC2R
* LINE1L
* LINE1R
CODEC input pins for other compatible codecs:
* MIC3L
* MIC3R
* LINE1L
......
......@@ -13,6 +13,11 @@ Required properties:
- interrupt-parent: The parent interrupt controller
- interrupts: Interrupt number for /INT pin from the 227e
Optional properies:
- ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7).
Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
Default value is "1" (2.2V).
Examples:
......
......@@ -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 */
......
......@@ -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) {
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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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");
......@@ -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 */
......@@ -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;
......
......@@ -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,
};
......
......@@ -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;
......
......@@ -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)
......
......@@ -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.
......@@ -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
......
/*
* 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment