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

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.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 79631210
...@@ -44,18 +44,25 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = { ...@@ -44,18 +44,25 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
"VCCDA2" "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 pcm3168a_priv {
struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
struct regmap *regmap; struct regmap *regmap;
struct clk *scki; struct clk *scki;
bool adc_master_mode;
bool dac_master_mode;
unsigned long sysclk; unsigned long sysclk;
unsigned int adc_fmt;
unsigned int dac_fmt; struct pcm3168a_io_params io_params[2];
int tdm_slots;
u32 tdm_mask[2];
int slot_width;
}; };
static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" }; static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
...@@ -308,8 +315,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, ...@@ -308,8 +315,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
return 0; return 0;
} }
static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
unsigned int format, bool dac)
{ {
struct snd_soc_component *component = dai->component; struct snd_soc_component *component = dai->component;
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(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, ...@@ -356,43 +362,31 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai,
return -EINVAL; return -EINVAL;
} }
if (dac) { if (dai->id == PCM3168A_DAI_DAC) {
reg = PCM3168A_DAC_PWR_MST_FMT; reg = PCM3168A_DAC_PWR_MST_FMT;
mask = PCM3168A_DAC_FMT_MASK; mask = PCM3168A_DAC_FMT_MASK;
shift = PCM3168A_DAC_FMT_SHIFT; shift = PCM3168A_DAC_FMT_SHIFT;
pcm3168a->dac_master_mode = master_mode;
pcm3168a->dac_fmt = fmt;
} else { } else {
reg = PCM3168A_ADC_MST_FMT; reg = PCM3168A_ADC_MST_FMT;
mask = PCM3168A_ADC_FMTAD_MASK; mask = PCM3168A_ADC_FMTAD_MASK;
shift = PCM3168A_ADC_FMTAD_SHIFT; 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); regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
return 0; 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, static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, unsigned int rx_mask, int slots,
int slot_width) int slot_width)
{ {
struct snd_soc_component *component = dai->component; struct snd_soc_component *component = dai->component;
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(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)) { if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
dev_err(component->dev, dev_err(component->dev,
...@@ -408,22 +402,25 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ...@@ -408,22 +402,25 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
return -EINVAL; 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", dev_err(component->dev, "Not matching slots %d vs %d\n",
pcm3168a->tdm_slots, slots); io_params->tdm_slots, slots);
return -EINVAL; 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", 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; return -EINVAL;
} }
pcm3168a->tdm_slots = slots; io_params->tdm_slots = slots;
pcm3168a->slot_width = slot_width; io_params->slot_width = slot_width;
pcm3168a->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; /* Ignore the not relevant mask for the DAI/direction */
pcm3168a->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; if (dai->id == PCM3168A_DAI_DAC)
io_params->tdm_mask = tx_mask;
else
io_params->tdm_mask = rx_mask;
return 0; return 0;
} }
...@@ -434,7 +431,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, ...@@ -434,7 +431,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
{ {
struct snd_soc_component *component = dai->component; struct snd_soc_component *component = dai->component;
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(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; u32 val, mask, shift, reg;
unsigned int rate, fmt, ratio, max_ratio; unsigned int rate, fmt, ratio, max_ratio;
unsigned int tdm_slots; unsigned int tdm_slots;
...@@ -444,23 +442,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, ...@@ -444,23 +442,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
ratio = pcm3168a->sysclk / rate; ratio = pcm3168a->sysclk / rate;
tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; if (dai->id == PCM3168A_DAI_DAC) {
if (tx) {
max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC; max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
reg = PCM3168A_DAC_PWR_MST_FMT; reg = PCM3168A_DAC_PWR_MST_FMT;
mask = PCM3168A_DAC_MSDA_MASK; mask = PCM3168A_DAC_MSDA_MASK;
shift = PCM3168A_DAC_MSDA_SHIFT; shift = PCM3168A_DAC_MSDA_SHIFT;
master_mode = pcm3168a->dac_master_mode;
fmt = pcm3168a->dac_fmt;
} else { } else {
max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC; max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
reg = PCM3168A_ADC_MST_FMT; reg = PCM3168A_ADC_MST_FMT;
mask = PCM3168A_ADC_MSAD_MASK; mask = PCM3168A_ADC_MSAD_MASK;
shift = PCM3168A_ADC_MSAD_SHIFT; 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++) { for (i = 0; i < max_ratio; i++) {
if (pcm3168a_scki_ratios[i] == ratio) if (pcm3168a_scki_ratios[i] == ratio)
break; break;
...@@ -471,8 +467,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, ...@@ -471,8 +467,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
if (pcm3168a->slot_width) if (io_params->slot_width)
slot_width = pcm3168a->slot_width; slot_width = io_params->slot_width;
else else
slot_width = params_width(params); slot_width = params_width(params);
...@@ -497,8 +493,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, ...@@ -497,8 +493,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
if (pcm3168a->tdm_slots) if (io_params->tdm_slots)
tdm_slots = pcm3168a->tdm_slots; tdm_slots = io_params->tdm_slots;
else else
tdm_slots = params_channels(params); tdm_slots = params_channels(params);
...@@ -534,7 +530,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, ...@@ -534,7 +530,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(pcm3168a->regmap, reg, mask, val); regmap_update_bits(pcm3168a->regmap, reg, mask, val);
if (tx) { if (dai->id == PCM3168A_DAI_DAC) {
mask = PCM3168A_DAC_FMT_MASK; mask = PCM3168A_DAC_FMT_MASK;
shift = PCM3168A_DAC_FMT_SHIFT; shift = PCM3168A_DAC_FMT_SHIFT;
} else { } else {
...@@ -552,20 +548,13 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, ...@@ -552,20 +548,13 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
{ {
struct snd_soc_component *component = dai->component; struct snd_soc_component *component = dai->component;
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(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 sample_min;
unsigned int channel_max; unsigned int channel_max;
unsigned int channel_maxs[] = { unsigned int channel_maxs[] = {
6, /* rx */ 8, /* DAC */
8 /* tx */ 6 /* ADC */
}; };
if (tx)
fmt = pcm3168a->dac_fmt;
else
fmt = pcm3168a->adc_fmt;
/* /*
* Available Data Bits * Available Data Bits
* *
...@@ -578,7 +567,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, ...@@ -578,7 +567,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
* I2S * I2S
* LEFT_J * LEFT_J
*/ */
switch (fmt) { switch (pcm3168a->io_params[dai->id].fmt) {
case PCM3168A_FMT_RIGHT_J: case PCM3168A_FMT_RIGHT_J:
sample_min = 16; sample_min = 16;
channel_max = 2; channel_max = 2;
...@@ -588,7 +577,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, ...@@ -588,7 +577,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
case PCM3168A_FMT_DSP_A: case PCM3168A_FMT_DSP_A:
case PCM3168A_FMT_DSP_B: case PCM3168A_FMT_DSP_B:
sample_min = 24; sample_min = 24;
channel_max = channel_maxs[tx]; channel_max = channel_maxs[dai->id];
break; break;
default: default:
sample_min = 24; sample_min = 24;
...@@ -600,8 +589,8 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, ...@@ -600,8 +589,8 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
sample_min, 32); sample_min, 32);
/* Allow all channels in multi DIN/DOUT mode */ /* Allow all channels in multi DIN/DOUT mode */
if (pcm3168a->tdm_slots == 2) if (pcm3168a->io_params[dai->id].tdm_slots == 2)
channel_max = channel_maxs[tx]; channel_max = channel_maxs[dai->id];
snd_pcm_hw_constraint_minmax(substream->runtime, snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, SNDRV_PCM_HW_PARAM_CHANNELS,
...@@ -609,26 +598,19 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, ...@@ -609,26 +598,19 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
return 0; 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, .startup = pcm3168a_startup,
.set_fmt = pcm3168a_set_dai_fmt_dac, .set_fmt = pcm3168a_set_dai_fmt,
.set_sysclk = pcm3168a_set_dai_sysclk, .set_sysclk = pcm3168a_set_dai_sysclk,
.hw_params = pcm3168a_hw_params, .hw_params = pcm3168a_hw_params,
.digital_mute = pcm3168a_digital_mute, .digital_mute = pcm3168a_digital_mute,
.set_tdm_slot = pcm3168a_set_tdm_slot, .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[] = { static struct snd_soc_dai_driver pcm3168a_dais[] = {
{ {
.name = "pcm3168a-dac", .name = "pcm3168a-dac",
.id = PCM3168A_DAI_DAC,
.playback = { .playback = {
.stream_name = "Playback", .stream_name = "Playback",
.channels_min = 1, .channels_min = 1,
...@@ -636,10 +618,11 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = { ...@@ -636,10 +618,11 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
.rates = SNDRV_PCM_RATE_8000_192000, .rates = SNDRV_PCM_RATE_8000_192000,
.formats = PCM3168A_FORMATS .formats = PCM3168A_FORMATS
}, },
.ops = &pcm3168a_dac_dai_ops .ops = &pcm3168a_dai_ops
}, },
{ {
.name = "pcm3168a-adc", .name = "pcm3168a-adc",
.id = PCM3168A_DAI_ADC,
.capture = { .capture = {
.stream_name = "Capture", .stream_name = "Capture",
.channels_min = 1, .channels_min = 1,
...@@ -647,7 +630,7 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = { ...@@ -647,7 +630,7 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = {
.rates = SNDRV_PCM_RATE_8000_96000, .rates = SNDRV_PCM_RATE_8000_96000,
.formats = PCM3168A_FORMATS .formats = PCM3168A_FORMATS
}, },
.ops = &pcm3168a_adc_dai_ops .ops = &pcm3168a_dai_ops
}, },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment