Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d3c9e9a1 authored by Mark Brown's avatar Mark Brown
Browse files

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: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 0182dcc5
Loading
Loading
Loading
Loading
+81 −18
Original line number Diff line number Diff line
@@ -218,6 +218,8 @@ struct wm8993_priv {
	struct snd_soc_codec codec;
	int master;
	int sysclk_source;
	int tdm_slots;
	int tdm_width;
	unsigned int mclk_rate;
	unsigned int sysclk_rate;
	unsigned int fs;
@@ -1107,6 +1109,11 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
	/* What BCLK do we need? */
	wm8993->fs = params_rate(params);
	wm8993->bclk = 2 * wm8993->fs;
	if (wm8993->tdm_slots) {
		dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n",
			wm8993->tdm_slots, wm8993->tdm_width);
		wm8993->bclk *= wm8993->tdm_width * wm8993->tdm_slots;
	} else {
		switch (params_format(params)) {
		case SNDRV_PCM_FORMAT_S16_LE:
			wm8993->bclk *= 16;
@@ -1126,6 +1133,7 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
		default:
			return -EINVAL;
		}
	}

	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;
}

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 = {
	.set_sysclk = wm8993_set_sysclk,
	.set_fmt = wm8993_set_dai_fmt,
	.hw_params = wm8993_hw_params,
	.digital_mute = wm8993_digital_mute,
	.set_pll = wm8993_set_fll,
	.set_tdm_slot = wm8993_set_tdm_slot,
};

#define WM8993_RATES SNDRV_PCM_RATE_8000_48000