mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
ASoC: Implement TDM configuration for WM8993
Note that the number of slots used internally is specified in terms of stereo slots while the external API works with mono slots. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
0182dcc52c
commit
d3c9e9a139
@ -218,6 +218,8 @@ struct wm8993_priv {
|
|||||||
struct snd_soc_codec codec;
|
struct snd_soc_codec codec;
|
||||||
int master;
|
int master;
|
||||||
int sysclk_source;
|
int sysclk_source;
|
||||||
|
int tdm_slots;
|
||||||
|
int tdm_width;
|
||||||
unsigned int mclk_rate;
|
unsigned int mclk_rate;
|
||||||
unsigned int sysclk_rate;
|
unsigned int sysclk_rate;
|
||||||
unsigned int fs;
|
unsigned int fs;
|
||||||
@ -1107,24 +1109,30 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
|
|||||||
/* What BCLK do we need? */
|
/* What BCLK do we need? */
|
||||||
wm8993->fs = params_rate(params);
|
wm8993->fs = params_rate(params);
|
||||||
wm8993->bclk = 2 * wm8993->fs;
|
wm8993->bclk = 2 * wm8993->fs;
|
||||||
switch (params_format(params)) {
|
if (wm8993->tdm_slots) {
|
||||||
case SNDRV_PCM_FORMAT_S16_LE:
|
dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n",
|
||||||
wm8993->bclk *= 16;
|
wm8993->tdm_slots, wm8993->tdm_width);
|
||||||
break;
|
wm8993->bclk *= wm8993->tdm_width * wm8993->tdm_slots;
|
||||||
case SNDRV_PCM_FORMAT_S20_3LE:
|
} else {
|
||||||
wm8993->bclk *= 20;
|
switch (params_format(params)) {
|
||||||
aif1 |= 0x8;
|
case SNDRV_PCM_FORMAT_S16_LE:
|
||||||
break;
|
wm8993->bclk *= 16;
|
||||||
case SNDRV_PCM_FORMAT_S24_LE:
|
break;
|
||||||
wm8993->bclk *= 24;
|
case SNDRV_PCM_FORMAT_S20_3LE:
|
||||||
aif1 |= 0x10;
|
wm8993->bclk *= 20;
|
||||||
break;
|
aif1 |= 0x8;
|
||||||
case SNDRV_PCM_FORMAT_S32_LE:
|
break;
|
||||||
wm8993->bclk *= 32;
|
case SNDRV_PCM_FORMAT_S24_LE:
|
||||||
aif1 |= 0x18;
|
wm8993->bclk *= 24;
|
||||||
break;
|
aif1 |= 0x10;
|
||||||
default:
|
break;
|
||||||
return -EINVAL;
|
case SNDRV_PCM_FORMAT_S32_LE:
|
||||||
|
wm8993->bclk *= 32;
|
||||||
|
aif1 |= 0x18;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk);
|
dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk);
|
||||||
@ -1243,12 +1251,67 @@ static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||||
|
unsigned int rx_mask, int slots, int slot_width)
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
struct wm8993_priv *wm8993 = codec->private_data;
|
||||||
|
int aif1 = 0;
|
||||||
|
int aif2 = 0;
|
||||||
|
|
||||||
|
/* Don't need to validate anything if we're turning off TDM */
|
||||||
|
if (slots == 0) {
|
||||||
|
wm8993->tdm_slots = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that we allow configurations we can't handle ourselves -
|
||||||
|
* for example, we can generate clocks for slots 2 and up even if
|
||||||
|
* we can't use those slots ourselves.
|
||||||
|
*/
|
||||||
|
aif1 |= WM8993_AIFADC_TDM;
|
||||||
|
aif2 |= WM8993_AIFDAC_TDM;
|
||||||
|
|
||||||
|
switch (rx_mask) {
|
||||||
|
case 3:
|
||||||
|
break;
|
||||||
|
case 0xc:
|
||||||
|
aif1 |= WM8993_AIFADC_TDM_CHAN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (tx_mask) {
|
||||||
|
case 3:
|
||||||
|
break;
|
||||||
|
case 0xc:
|
||||||
|
aif2 |= WM8993_AIFDAC_TDM_CHAN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
wm8993->tdm_width = slot_width;
|
||||||
|
wm8993->tdm_slots = slots / 2;
|
||||||
|
|
||||||
|
snd_soc_update_bits(codec, WM8993_AUDIO_INTERFACE_1,
|
||||||
|
WM8993_AIFADC_TDM | WM8993_AIFADC_TDM_CHAN, aif1);
|
||||||
|
snd_soc_update_bits(codec, WM8993_AUDIO_INTERFACE_2,
|
||||||
|
WM8993_AIFDAC_TDM | WM8993_AIFDAC_TDM_CHAN, aif2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct snd_soc_dai_ops wm8993_ops = {
|
static struct snd_soc_dai_ops wm8993_ops = {
|
||||||
.set_sysclk = wm8993_set_sysclk,
|
.set_sysclk = wm8993_set_sysclk,
|
||||||
.set_fmt = wm8993_set_dai_fmt,
|
.set_fmt = wm8993_set_dai_fmt,
|
||||||
.hw_params = wm8993_hw_params,
|
.hw_params = wm8993_hw_params,
|
||||||
.digital_mute = wm8993_digital_mute,
|
.digital_mute = wm8993_digital_mute,
|
||||||
.set_pll = wm8993_set_fll,
|
.set_pll = wm8993_set_fll,
|
||||||
|
.set_tdm_slot = wm8993_set_tdm_slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WM8993_RATES SNDRV_PCM_RATE_8000_48000
|
#define WM8993_RATES SNDRV_PCM_RATE_8000_48000
|
||||||
|
Loading…
Reference in New Issue
Block a user