mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 20:53:53 +08:00
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);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -1267,6 +1289,15 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
|
||||
if (twl4030->configured)
|
||||
twl4030_constraints(twl4030, twl4030->master_substream);
|
||||
} 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;
|
||||
}
|
||||
|
||||
@ -1292,6 +1323,10 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
|
||||
twl4030->configured = 0;
|
||||
else if (!twl4030->master_substream->runtime->channels)
|
||||
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,
|
||||
@ -1304,6 +1339,16 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
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)
|
||||
/* Ignoring hw_params for already configured DAI */
|
||||
return 0;
|
||||
@ -1461,6 +1506,9 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
format |= TWL4030_AIF_FORMAT_CODEC;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
format |= TWL4030_AIF_FORMAT_TDM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1642,13 +1690,13 @@ struct snd_soc_dai twl4030_dai[] = {
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.channels_max = 4,
|
||||
.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
|
||||
.formats = TWL4030_FORMATS,},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.channels_max = 4,
|
||||
.rates = TWL4030_RATES,
|
||||
.formats = TWL4030_FORMATS,},
|
||||
.ops = &twl4030_dai_ops,
|
||||
|
@ -116,6 +116,17 @@
|
||||
#define TWL4030_OPTION_1 (1 << 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 */
|
||||
|
||||
#define TWL4030_MICBIAS2_CTL 0x40
|
||||
|
Loading…
Reference in New Issue
Block a user