aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/pcm3168a.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sound/soc/codecs/pcm3168a.c233
1 files changed, 124 insertions, 109 deletions
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 9711fab296eb..9d6431338fb7 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -33,10 +33,8 @@
#define PCM3168A_FMT_DSP_B 0x5
#define PCM3168A_FMT_I2S_TDM 0x6
#define PCM3168A_FMT_LEFT_J_TDM 0x7
-#define PCM3168A_FMT_DSP_MASK 0x4
-#define PCM3168A_NUM_SUPPLIES 6
-static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
+static const char *const pcm3168a_supply_names[] = {
"VDD1",
"VDD2",
"VCCAD1",
@@ -50,15 +48,15 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = {
/* ADC/DAC side parameters */
struct pcm3168a_io_params {
- bool master_mode;
- unsigned int fmt;
+ bool provider_mode;
+ unsigned int format;
int tdm_slots;
u32 tdm_mask;
int slot_width;
};
struct pcm3168a_priv {
- struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
+ struct regulator_bulk_data supplies[ARRAY_SIZE(pcm3168a_supply_names)];
struct regmap *regmap;
struct clk *scki;
struct gpio_desc *gpio_rst;
@@ -290,7 +288,7 @@ static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
PCM3168A_MRST_MASK | PCM3168A_SRST_MASK);
}
-static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute)
+static int pcm3168a_mute(struct snd_soc_dai *dai, int mute, int direction)
{
struct snd_soc_component *component = dai->component;
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
@@ -306,6 +304,13 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component);
int ret;
+ /*
+ * Some sound card sets 0 Hz as reset,
+ * but it is impossible to set. Ignore it here
+ */
+ if (freq == 0)
+ return 0;
+
if (freq > PCM3168A_MAX_SYSCLK)
return -EINVAL;
@@ -322,10 +327,11 @@ static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai)
{
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];
u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE;
unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6;
- if (pcm3168a->io_params[dai->id].fmt == PCM3168A_FMT_RIGHT_J) {
+ if (io_params->format == SND_SOC_DAIFMT_RIGHT_J) {
/* S16_LE is only supported in RIGHT_J mode */
formats |= SNDRV_PCM_FMTBIT_S16_LE;
@@ -333,7 +339,7 @@ static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai)
* If multi DIN/DOUT is not selected, RIGHT_J can only support
* two channels (no TDM support)
*/
- if (pcm3168a->io_params[dai->id].tdm_slots != 2)
+ if (io_params->tdm_slots != 2)
channel_max = 2;
}
@@ -350,39 +356,30 @@ 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);
- u32 fmt, reg, mask, shift;
- bool master_mode;
+ struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
+ bool provider_mode;
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_LEFT_J:
- fmt = PCM3168A_FMT_LEFT_J;
- break;
case SND_SOC_DAIFMT_I2S:
- fmt = PCM3168A_FMT_I2S;
- break;
case SND_SOC_DAIFMT_RIGHT_J:
- fmt = PCM3168A_FMT_RIGHT_J;
- break;
case SND_SOC_DAIFMT_DSP_A:
- fmt = PCM3168A_FMT_DSP_A;
- break;
case SND_SOC_DAIFMT_DSP_B:
- fmt = PCM3168A_FMT_DSP_B;
break;
default:
dev_err(component->dev, "unsupported dai format\n");
return -EINVAL;
}
- switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- master_mode = false;
+ switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ provider_mode = false;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
- master_mode = true;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ provider_mode = true;
break;
default:
- dev_err(component->dev, "unsupported master/slave mode\n");
+ dev_err(component->dev, "unsupported provider mode\n");
return -EINVAL;
}
@@ -393,20 +390,8 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
return -EINVAL;
}
- if (dai->id == PCM3168A_DAI_DAC) {
- reg = PCM3168A_DAC_PWR_MST_FMT;
- mask = PCM3168A_DAC_FMT_MASK;
- shift = PCM3168A_DAC_FMT_SHIFT;
- } else {
- reg = PCM3168A_ADC_MST_FMT;
- mask = PCM3168A_ADC_FMTAD_MASK;
- shift = PCM3168A_ADC_FMTAD_SHIFT;
- }
-
- 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);
+ io_params->provider_mode = provider_mode;
+ io_params->format = format & SND_SOC_DAIFMT_FORMAT_MASK;
pcm3168a_update_fixup_pcm_stream(dai);
@@ -455,41 +440,47 @@ 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);
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;
- int i, slot_width;
-
- rate = params_rate(params);
-
- ratio = pcm3168a->sysclk / rate;
+ bool provider_mode, tdm_mode;
+ unsigned int format;
+ unsigned int reg, mask, ms, ms_shift, fmt, fmt_shift, ratio, tdm_slots;
+ int i, num_scki_ratios, slot_width;
if (dai->id == PCM3168A_DAI_DAC) {
- max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC;
+ num_scki_ratios = PCM3168A_NUM_SCKI_RATIOS_DAC;
reg = PCM3168A_DAC_PWR_MST_FMT;
- mask = PCM3168A_DAC_MSDA_MASK;
- shift = PCM3168A_DAC_MSDA_SHIFT;
+ mask = PCM3168A_DAC_MSDA_MASK | PCM3168A_DAC_FMT_MASK;
+ ms_shift = PCM3168A_DAC_MSDA_SHIFT;
+ fmt_shift = PCM3168A_DAC_FMT_SHIFT;
} else {
- max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC;
+ num_scki_ratios = PCM3168A_NUM_SCKI_RATIOS_ADC;
reg = PCM3168A_ADC_MST_FMT;
- mask = PCM3168A_ADC_MSAD_MASK;
- shift = PCM3168A_ADC_MSAD_SHIFT;
+ mask = PCM3168A_ADC_MSAD_MASK | PCM3168A_ADC_FMTAD_MASK;
+ ms_shift = PCM3168A_ADC_MSAD_SHIFT;
+ fmt_shift = PCM3168A_ADC_FMTAD_SHIFT;
}
- master_mode = io_params->master_mode;
- fmt = io_params->fmt;
+ provider_mode = io_params->provider_mode;
- for (i = 0; i < max_ratio; i++) {
- if (pcm3168a_scki_ratios[i] == ratio)
- break;
- }
+ if (provider_mode) {
+ ratio = pcm3168a->sysclk / params_rate(params);
- if (i == max_ratio) {
- dev_err(component->dev, "unsupported sysclk ratio\n");
- return -EINVAL;
+ for (i = 0; i < num_scki_ratios; i++) {
+ if (pcm3168a_scki_ratios[i] == ratio)
+ break;
+ }
+
+ if (i == num_scki_ratios) {
+ dev_err(component->dev, "unsupported sysclk ratio\n");
+ return -EINVAL;
+ }
+
+ ms = (i + 1);
+ } else {
+ ms = 0;
}
+ format = io_params->format;
+
if (io_params->slot_width)
slot_width = io_params->slot_width;
else
@@ -497,15 +488,15 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
switch (slot_width) {
case 16:
- if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) {
- dev_err(component->dev, "16-bit slots are supported only for slave mode using right justified\n");
+ if (provider_mode || (format != SND_SOC_DAIFMT_RIGHT_J)) {
+ dev_err(component->dev, "16-bit slots are supported only for consumer mode using right justified\n");
return -EINVAL;
}
- fmt = PCM3168A_FMT_RIGHT_J_16;
break;
case 24:
- if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) {
- dev_err(component->dev, "24-bit slots not supported in master mode, or slave mode using DSP\n");
+ if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) ||
+ (format == SND_SOC_DAIFMT_DSP_B)) {
+ dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n");
return -EINVAL;
}
break;
@@ -529,15 +520,14 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
* If pcm3168a->tdm_slots is set to 2 then DIN1/2/3/4 and DOUT1/2/3 is
* used in normal mode, no need to switch to TDM modes.
*/
- if (tdm_slots > 2) {
- switch (fmt) {
- case PCM3168A_FMT_I2S:
- case PCM3168A_FMT_DSP_A:
- fmt = PCM3168A_FMT_I2S_TDM;
- break;
- case PCM3168A_FMT_LEFT_J:
- case PCM3168A_FMT_DSP_B:
- fmt = PCM3168A_FMT_LEFT_J_TDM;
+ tdm_mode = (tdm_slots > 2);
+
+ if (tdm_mode) {
+ switch (format) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_DSP_B:
break;
default:
dev_err(component->dev,
@@ -546,32 +536,66 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
}
}
- if (master_mode)
- val = ((i + 1) << shift);
- else
- val = 0;
-
- regmap_update_bits(pcm3168a->regmap, reg, mask, val);
-
- if (dai->id == PCM3168A_DAI_DAC) {
- mask = PCM3168A_DAC_FMT_MASK;
- shift = PCM3168A_DAC_FMT_SHIFT;
- } else {
- mask = PCM3168A_ADC_FMTAD_MASK;
- shift = PCM3168A_ADC_FMTAD_SHIFT;
+ switch (format) {
+ case SND_SOC_DAIFMT_I2S:
+ fmt = tdm_mode ? PCM3168A_FMT_I2S_TDM : PCM3168A_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ fmt = tdm_mode ? PCM3168A_FMT_LEFT_J_TDM : PCM3168A_FMT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ fmt = (slot_width == 16) ? PCM3168A_FMT_RIGHT_J_16 :
+ PCM3168A_FMT_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ fmt = tdm_mode ? PCM3168A_FMT_I2S_TDM : PCM3168A_FMT_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ fmt = tdm_mode ? PCM3168A_FMT_LEFT_J_TDM : PCM3168A_FMT_DSP_B;
+ break;
+ default:
+ return -EINVAL;
}
- regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
+ regmap_update_bits(pcm3168a->regmap, reg, mask,
+ (ms << ms_shift) | (fmt << fmt_shift));
return 0;
}
+static u64 pcm3168a_dai_formats[] = {
+ /*
+ * Select below from Sound Card, not here
+ * SND_SOC_DAIFMT_CBC_CFC
+ * SND_SOC_DAIFMT_CBP_CFP
+ */
+
+ /*
+ * First Priority
+ */
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J,
+ /*
+ * Second Priority
+ *
+ * These have picky limitation.
+ * see
+ * pcm3168a_hw_params()
+ */
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B,
+};
+
static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
.set_fmt = pcm3168a_set_dai_fmt,
.set_sysclk = pcm3168a_set_dai_sysclk,
.hw_params = pcm3168a_hw_params,
- .digital_mute = pcm3168a_digital_mute,
+ .mute_stream = pcm3168a_mute,
.set_tdm_slot = pcm3168a_set_tdm_slot,
+ .no_capture_mute = 1,
+ .auto_selectable_formats = pcm3168a_dai_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(pcm3168a_dai_formats),
};
static struct snd_soc_dai_driver pcm3168a_dais[] = {
@@ -692,7 +716,6 @@ static const struct snd_soc_component_driver pcm3168a_driver = {
.num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes),
.use_pmdown_time = 1,
.endianness = 1,
- .non_legacy_dai_naming = 1,
};
int pcm3168a_probe(struct device *dev, struct regmap *regmap)
@@ -717,21 +740,14 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW |
GPIOD_FLAGS_BIT_NONEXCLUSIVE);
- if (IS_ERR(pcm3168a->gpio_rst)) {
- ret = PTR_ERR(pcm3168a->gpio_rst);
- if (ret != -EPROBE_DEFER )
- dev_err(dev, "failed to acquire RST gpio: %d\n", ret);
-
- return ret;
- }
+ if (IS_ERR(pcm3168a->gpio_rst))
+ return dev_err_probe(dev, PTR_ERR(pcm3168a->gpio_rst),
+ "failed to acquire RST gpio\n");
pcm3168a->scki = devm_clk_get(dev, "scki");
- if (IS_ERR(pcm3168a->scki)) {
- ret = PTR_ERR(pcm3168a->scki);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to acquire clock 'scki': %d\n", ret);
- return ret;
- }
+ if (IS_ERR(pcm3168a->scki))
+ return dev_err_probe(dev, PTR_ERR(pcm3168a->scki),
+ "failed to acquire clock 'scki'\n");
ret = clk_prepare_enable(pcm3168a->scki);
if (ret) {
@@ -747,8 +763,7 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
ret = devm_regulator_bulk_get(dev,
ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies);
if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to request supplies: %d\n", ret);
+ dev_err_probe(dev, ret, "failed to request supplies\n");
goto err_clk;
}