summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/pcm3168a.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/pcm3168a.c')
-rw-r--r--sound/soc/codecs/pcm3168a.c133
1 files changed, 54 insertions, 79 deletions
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index f1104d7d6426..50ed86d45c26 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -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" };
@@ -263,7 +270,7 @@ static unsigned int pcm3168a_scki_ratios[] = {
#define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios)
#define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
-#define PCM1368A_MAX_SYSCLK 36864000
+#define PCM3168A_MAX_SYSCLK 36864000
static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
{
@@ -296,7 +303,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component);
int ret;
- if (freq > PCM1368A_MAX_SYSCLK)
+ if (freq > PCM3168A_MAX_SYSCLK)
return -EINVAL;
ret = clk_set_rate(pcm3168a->scki, freq);
@@ -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,13 @@ 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) {
- dev_err(component->dev, "Not matching slots %d vs %d\n",
- pcm3168a->tdm_slots, slots);
- return -EINVAL;
- }
-
- if (pcm3168a->slot_width && pcm3168a->slot_width != slot_width) {
- dev_err(component->dev, "Not matching slot_width %d vs %d\n",
- pcm3168a->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 +419,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 +430,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 +455,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 +481,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 +518,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 +536,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 +555,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 +565,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;
@@ -599,32 +576,29 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
sample_min, 32);
+ /* Allow all channels in multi DIN/DOUT mode */
+ 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,
2, channel_max);
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,
@@ -632,10 +606,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,
@@ -643,7 +618,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
},
};