diff options
Diffstat (limited to '')
-rw-r--r-- | sound/soc/codecs/pcm3168a.c | 233 |
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; } |