mirror of https://gitee.com/openkylin/linux.git
ASoC: TWL4030: Add 4 channel TDM support
Support for 4 channel TDM (SND_SOC_DAIFMT_DSP_A) for twl4030 codec. The channel allocations are: Playback: TDM i2s TWL RX Channel 1 Left SDRL2 Channel 3 Right SDRR2 Channel 2 -- SDRL1 Channel 4 -- SDRR1 Capture: TDM i2s TWL TX Channel 1 Left TXL1 Channel 3 Right TXR1 Channel 2 -- TXL2 Channel 4 -- TXR2 Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
31a00c6b7c
commit
8a1f936acd
|
@ -1251,6 +1251,28 @@ static void twl4030_constraints(struct twl4030_priv *twl4030,
|
||||||
twl4030->channels);
|
twl4030->channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for
|
||||||
|
* capture has to be enabled/disabled. */
|
||||||
|
static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
|
||||||
|
int enable)
|
||||||
|
{
|
||||||
|
u8 reg, mask;
|
||||||
|
|
||||||
|
reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
|
||||||
|
|
||||||
|
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN;
|
||||||
|
else
|
||||||
|
mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
reg |= mask;
|
||||||
|
else
|
||||||
|
reg &= ~mask;
|
||||||
|
|
||||||
|
twl4030_write(codec, TWL4030_REG_OPTION, reg);
|
||||||
|
}
|
||||||
|
|
||||||
static int twl4030_startup(struct snd_pcm_substream *substream,
|
static int twl4030_startup(struct snd_pcm_substream *substream,
|
||||||
struct snd_soc_dai *dai)
|
struct snd_soc_dai *dai)
|
||||||
{
|
{
|
||||||
|
@ -1267,6 +1289,15 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
|
||||||
if (twl4030->configured)
|
if (twl4030->configured)
|
||||||
twl4030_constraints(twl4030, twl4030->master_substream);
|
twl4030_constraints(twl4030, twl4030->master_substream);
|
||||||
} else {
|
} else {
|
||||||
|
if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) &
|
||||||
|
TWL4030_OPTION_1)) {
|
||||||
|
/* In option2 4 channel is not supported, set the
|
||||||
|
* constraint for the first stream for channels, the
|
||||||
|
* second stream will 'inherit' this cosntraint */
|
||||||
|
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||||
|
SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||||
|
2, 2);
|
||||||
|
}
|
||||||
twl4030->master_substream = substream;
|
twl4030->master_substream = substream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1292,6 +1323,10 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
|
||||||
twl4030->configured = 0;
|
twl4030->configured = 0;
|
||||||
else if (!twl4030->master_substream->runtime->channels)
|
else if (!twl4030->master_substream->runtime->channels)
|
||||||
twl4030->configured = 0;
|
twl4030->configured = 0;
|
||||||
|
|
||||||
|
/* If the closing substream had 4 channel, do the necessary cleanup */
|
||||||
|
if (substream->runtime->channels == 4)
|
||||||
|
twl4030_tdm_enable(codec, substream->stream, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int twl4030_hw_params(struct snd_pcm_substream *substream,
|
static int twl4030_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
@ -1304,6 +1339,16 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
|
||||||
struct twl4030_priv *twl4030 = codec->private_data;
|
struct twl4030_priv *twl4030 = codec->private_data;
|
||||||
u8 mode, old_mode, format, old_format;
|
u8 mode, old_mode, format, old_format;
|
||||||
|
|
||||||
|
/* If the substream has 4 channel, do the necessary setup */
|
||||||
|
if (params_channels(params) == 4) {
|
||||||
|
/* Safety check: are we in the correct operating mode? */
|
||||||
|
if ((twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) &
|
||||||
|
TWL4030_OPTION_1))
|
||||||
|
twl4030_tdm_enable(codec, substream->stream, 1);
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (twl4030->configured)
|
if (twl4030->configured)
|
||||||
/* Ignoring hw_params for already configured DAI */
|
/* Ignoring hw_params for already configured DAI */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1461,6 +1506,9 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||||
case SND_SOC_DAIFMT_I2S:
|
case SND_SOC_DAIFMT_I2S:
|
||||||
format |= TWL4030_AIF_FORMAT_CODEC;
|
format |= TWL4030_AIF_FORMAT_CODEC;
|
||||||
break;
|
break;
|
||||||
|
case SND_SOC_DAIFMT_DSP_A:
|
||||||
|
format |= TWL4030_AIF_FORMAT_TDM;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1642,13 +1690,13 @@ struct snd_soc_dai twl4030_dai[] = {
|
||||||
.playback = {
|
.playback = {
|
||||||
.stream_name = "Playback",
|
.stream_name = "Playback",
|
||||||
.channels_min = 2,
|
.channels_min = 2,
|
||||||
.channels_max = 2,
|
.channels_max = 4,
|
||||||
.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
|
.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
|
||||||
.formats = TWL4030_FORMATS,},
|
.formats = TWL4030_FORMATS,},
|
||||||
.capture = {
|
.capture = {
|
||||||
.stream_name = "Capture",
|
.stream_name = "Capture",
|
||||||
.channels_min = 2,
|
.channels_min = 2,
|
||||||
.channels_max = 2,
|
.channels_max = 4,
|
||||||
.rates = TWL4030_RATES,
|
.rates = TWL4030_RATES,
|
||||||
.formats = TWL4030_FORMATS,},
|
.formats = TWL4030_FORMATS,},
|
||||||
.ops = &twl4030_dai_ops,
|
.ops = &twl4030_dai_ops,
|
||||||
|
|
|
@ -116,6 +116,17 @@
|
||||||
#define TWL4030_OPTION_1 (1 << 0)
|
#define TWL4030_OPTION_1 (1 << 0)
|
||||||
#define TWL4030_OPTION_2 (0 << 0)
|
#define TWL4030_OPTION_2 (0 << 0)
|
||||||
|
|
||||||
|
/* TWL4030_OPTION (0x02) Fields */
|
||||||
|
|
||||||
|
#define TWL4030_ATXL1_EN (1 << 0)
|
||||||
|
#define TWL4030_ATXR1_EN (1 << 1)
|
||||||
|
#define TWL4030_ATXL2_VTXL_EN (1 << 2)
|
||||||
|
#define TWL4030_ATXR2_VTXR_EN (1 << 3)
|
||||||
|
#define TWL4030_ARXL1_VRX_EN (1 << 4)
|
||||||
|
#define TWL4030_ARXR1_EN (1 << 5)
|
||||||
|
#define TWL4030_ARXL2_EN (1 << 6)
|
||||||
|
#define TWL4030_ARXR2_EN (1 << 7)
|
||||||
|
|
||||||
/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */
|
/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */
|
||||||
|
|
||||||
#define TWL4030_MICBIAS2_CTL 0x40
|
#define TWL4030_MICBIAS2_CTL 0x40
|
||||||
|
|
Loading…
Reference in New Issue