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

Unverified Commit abe51c35 authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Mark Brown
Browse files

ASoC: pcm3168a: Retain the independence of DAC and ADC side of the codec



The DAC and ADC path of the codec is independent, have dedicated LRCK (FS)
and BCK for DAC/ADC.

They can be configured to use different format, TDM slots and slot_width if
needed.

Move these parameters under dedicated io_params structure and manage them
independently based on the dai.

Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Link: https://lore.kernel.org/r/20190812095226.18870-2-peter.ujfalusi@ti.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 79631210
Loading
Loading
Loading
Loading
+54 −71
Original line number Diff line number Diff line
@@ -44,18 +44,25 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
	"VCCDA2"
};

#define PCM3168A_DAI_DAC		0
#define PCM3168A_DAI_ADC		1

/* ADC/DAC side parameters */
struct pcm3168a_io_params {
	bool master_mode;
	unsigned int fmt;
	int tdm_slots;
	u32 tdm_mask;
	int slot_width;
};

struct pcm3168a_priv {
	struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
	struct regmap *regmap;
	struct clk *scki;
	bool adc_master_mode;
	bool dac_master_mode;
	unsigned long sysclk;
	unsigned int adc_fmt;
	unsigned int dac_fmt;
	int tdm_slots;
	u32 tdm_mask[2];
	int slot_width;

	struct pcm3168a_io_params io_params[2];
};

static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
@@ -308,8 +315,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
	return 0;
}

static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
			       unsigned int format, bool dac)
static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
{
	struct snd_soc_component *component = dai->component;
	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
@@ -356,43 +362,31 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
		return -EINVAL;
	}

	if (dac) {
	if (dai->id == PCM3168A_DAI_DAC) {
		reg = PCM3168A_DAC_PWR_MST_FMT;
		mask = PCM3168A_DAC_FMT_MASK;
		shift = PCM3168A_DAC_FMT_SHIFT;
		pcm3168a->dac_master_mode = master_mode;
		pcm3168a->dac_fmt = fmt;
	} else {
		reg = PCM3168A_ADC_MST_FMT;
		mask = PCM3168A_ADC_FMTAD_MASK;
		shift = PCM3168A_ADC_FMTAD_SHIFT;
		pcm3168a->adc_master_mode = master_mode;
		pcm3168a->adc_fmt = fmt;
	}

	pcm3168a->io_params[dai->id].master_mode = master_mode;
	pcm3168a->io_params[dai->id].fmt = fmt;

	regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);

	return 0;
}

static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai,
			       unsigned int format)
{
	return pcm3168a_set_dai_fmt(dai, format, true);
}

static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai,
			       unsigned int format)
{
	return pcm3168a_set_dai_fmt(dai, format, false);
}

static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
				 unsigned int rx_mask, int slots,
				 int slot_width)
{
	struct snd_soc_component *component = dai->component;
	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
	struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];

	if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
		dev_err(component->dev,
@@ -408,22 +402,25 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
		return -EINVAL;
	}

	if (pcm3168a->tdm_slots && pcm3168a->tdm_slots != slots) {
	if (io_params->tdm_slots && io_params->tdm_slots != slots) {
		dev_err(component->dev, "Not matching slots %d vs %d\n",
			pcm3168a->tdm_slots, slots);
			io_params->tdm_slots, slots);
		return -EINVAL;
	}

	if (pcm3168a->slot_width && pcm3168a->slot_width != slot_width) {
	if (io_params->slot_width && io_params->slot_width != slot_width) {
		dev_err(component->dev, "Not matching slot_width %d vs %d\n",
			pcm3168a->slot_width, slot_width);
			io_params->slot_width, slot_width);
		return -EINVAL;
	}

	pcm3168a->tdm_slots = slots;
	pcm3168a->slot_width = slot_width;
	pcm3168a->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
	pcm3168a->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
	io_params->tdm_slots = slots;
	io_params->slot_width = slot_width;
	/* Ignore the not relevant mask for the DAI/direction */
	if (dai->id == PCM3168A_DAI_DAC)
		io_params->tdm_mask = tx_mask;
	else
		io_params->tdm_mask = rx_mask;

	return 0;
}
@@ -434,7 +431,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
{
	struct snd_soc_component *component = dai->component;
	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
	bool tx, master_mode;
	struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
	bool master_mode;
	u32 val, mask, shift, reg;
	unsigned int rate, fmt, ratio, max_ratio;
	unsigned int tdm_slots;
@@ -444,23 +442,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,

	ratio = pcm3168a->sysclk / rate;

	tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
	if (tx) {
	if (dai->id == PCM3168A_DAI_DAC) {
		max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
		reg = PCM3168A_DAC_PWR_MST_FMT;
		mask = PCM3168A_DAC_MSDA_MASK;
		shift = PCM3168A_DAC_MSDA_SHIFT;
		master_mode = pcm3168a->dac_master_mode;
		fmt = pcm3168a->dac_fmt;
	} else {
		max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
		reg = PCM3168A_ADC_MST_FMT;
		mask = PCM3168A_ADC_MSAD_MASK;
		shift = PCM3168A_ADC_MSAD_SHIFT;
		master_mode = pcm3168a->adc_master_mode;
		fmt = pcm3168a->adc_fmt;
	}

	master_mode = io_params->master_mode;
	fmt = io_params->fmt;

	for (i = 0; i < max_ratio; i++) {
		if (pcm3168a_scki_ratios[i] == ratio)
			break;
@@ -471,8 +467,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
		return -EINVAL;
	}

	if (pcm3168a->slot_width)
		slot_width = pcm3168a->slot_width;
	if (io_params->slot_width)
		slot_width = io_params->slot_width;
	else
		slot_width = params_width(params);

@@ -497,8 +493,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
		return -EINVAL;
	}

	if (pcm3168a->tdm_slots)
		tdm_slots = pcm3168a->tdm_slots;
	if (io_params->tdm_slots)
		tdm_slots = io_params->tdm_slots;
	else
		tdm_slots = params_channels(params);

@@ -534,7 +530,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,

	regmap_update_bits(pcm3168a->regmap, reg, mask, val);

	if (tx) {
	if (dai->id == PCM3168A_DAI_DAC) {
		mask = PCM3168A_DAC_FMT_MASK;
		shift = PCM3168A_DAC_FMT_SHIFT;
	} else {
@@ -552,20 +548,13 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
{
	struct snd_soc_component *component = dai->component;
	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
	unsigned int fmt;
	unsigned int sample_min;
	unsigned int channel_max;
	unsigned int channel_maxs[] = {
		6, /* rx */
		8  /* tx */
		8, /* DAC */
		6  /* ADC */
	};

	if (tx)
		fmt = pcm3168a->dac_fmt;
	else
		fmt = pcm3168a->adc_fmt;

	/*
	 * Available Data Bits
	 *
@@ -578,7 +567,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
	 * I2S
	 * LEFT_J
	 */
	switch (fmt) {
	switch (pcm3168a->io_params[dai->id].fmt) {
	case PCM3168A_FMT_RIGHT_J:
		sample_min  = 16;
		channel_max =  2;
@@ -588,7 +577,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
	case PCM3168A_FMT_DSP_A:
	case PCM3168A_FMT_DSP_B:
		sample_min  = 24;
		channel_max = channel_maxs[tx];
		channel_max = channel_maxs[dai->id];
		break;
	default:
		sample_min  = 24;
@@ -600,8 +589,8 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
				     sample_min, 32);

	/* Allow all channels in multi DIN/DOUT mode */
	if (pcm3168a->tdm_slots == 2)
		channel_max = channel_maxs[tx];
	if (pcm3168a->io_params[dai->id].tdm_slots == 2)
		channel_max = channel_maxs[dai->id];

	snd_pcm_hw_constraint_minmax(substream->runtime,
				     SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -609,26 +598,19 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,

	return 0;
}
static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = {
static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
	.startup	= pcm3168a_startup,
	.set_fmt	= pcm3168a_set_dai_fmt_dac,
	.set_fmt	= pcm3168a_set_dai_fmt,
	.set_sysclk	= pcm3168a_set_dai_sysclk,
	.hw_params	= pcm3168a_hw_params,
	.digital_mute	= pcm3168a_digital_mute,
	.set_tdm_slot	= pcm3168a_set_tdm_slot,
};

static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = {
	.startup	= pcm3168a_startup,
	.set_fmt	= pcm3168a_set_dai_fmt_adc,
	.set_sysclk	= pcm3168a_set_dai_sysclk,
	.hw_params	= pcm3168a_hw_params,
	.set_tdm_slot	= pcm3168a_set_tdm_slot,
};

static struct snd_soc_dai_driver pcm3168a_dais[] = {
	{
		.name = "pcm3168a-dac",
		.id = PCM3168A_DAI_DAC,
		.playback = {
			.stream_name = "Playback",
			.channels_min = 1,
@@ -636,10 +618,11 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
			.rates = SNDRV_PCM_RATE_8000_192000,
			.formats = PCM3168A_FORMATS
		},
		.ops = &pcm3168a_dac_dai_ops
		.ops = &pcm3168a_dai_ops
	},
	{
		.name = "pcm3168a-adc",
		.id = PCM3168A_DAI_ADC,
		.capture = {
			.stream_name = "Capture",
			.channels_min = 1,
@@ -647,7 +630,7 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
			.rates = SNDRV_PCM_RATE_8000_96000,
			.formats = PCM3168A_FORMATS
		},
		.ops = &pcm3168a_adc_dai_ops
		.ops = &pcm3168a_dai_ops
	},
};