From ad26098970b637f4565b110df929d74eb2c2652e Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Mon, 19 Oct 2020 09:48:57 -0700 Subject: ALSA: remove unneeded break A break is not needed if it is preceded by a return, goto or break Signed-off-by: Tom Rix Acked-by: Mark Brown Link: https://lore.kernel.org/r/20201019164857.27223-1-trix@redhat.com Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 1 - sound/pci/rme9652/hdspm.c | 8 -------- sound/pci/rme9652/rme9652.c | 7 ------- sound/soc/codecs/wcd-clsh-v2.c | 1 - sound/soc/codecs/wl1273.c | 1 - sound/soc/intel/skylake/skl-pcm.c | 1 - sound/soc/ti/davinci-mcasp.c | 1 - 7 files changed, 20 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 869af8a32c98..4eabece4dcba 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -468,7 +468,6 @@ static int snd_rme32_capture_getrate(struct rme32 * rme32, int *is_adat) return 32000; default: return -1; - break; } else switch (n) { /* supporting the CS8412 */ diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 4a1f576dd9cf..3382c069fd3d 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2286,7 +2286,6 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) case AIO: status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); return (status >> 16) & 0xF; - break; case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister); return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; @@ -2312,7 +2311,6 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) case AIO: status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); return (status >> 20) & 0xF; - break; case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister); return (status >> 1) & 0xF; @@ -2338,7 +2336,6 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) case AIO: status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); return (status >> 12) & 0xF; - break; default: break; } @@ -2358,7 +2355,6 @@ static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) case AES32: timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); return (timecode >> (4*index)) & 0xF; - break; default: break; } @@ -3845,7 +3841,6 @@ static int hdspm_wc_sync_check(struct hdspm *hdspm) return 1; } return 0; - break; case MADI: status2 = hdspm_read(hdspm, HDSPM_statusRegister2); @@ -3856,7 +3851,6 @@ static int hdspm_wc_sync_check(struct hdspm *hdspm) return 1; } return 0; - break; case RayDAT: case AIO: @@ -3868,8 +3862,6 @@ static int hdspm_wc_sync_check(struct hdspm *hdspm) return 1; return 0; - break; - case MADIface: break; } diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 7ab10028d9fa..012fbec5e6a7 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -732,34 +732,27 @@ static inline int rme9652_spdif_sample_rate(struct snd_rme9652 *s) switch (rme9652_decode_spdif_rate(rate_bits)) { case 0x7: return 32000; - break; case 0x6: return 44100; - break; case 0x5: return 48000; - break; case 0x4: return 88200; - break; case 0x3: return 96000; - break; case 0x0: return 64000; - break; default: dev_err(s->card->dev, "%s: unknown S/PDIF input rate (bits = 0x%x)\n", s->card_name, rate_bits); return 0; - break; } } diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index 1be82113c59a..817d8259758c 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -480,7 +480,6 @@ static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, case WCD_CLSH_STATE_HPHR: wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); break; - break; case WCD_CLSH_STATE_LO: wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); break; diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index c56b9329240f..d8ced4559bf2 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -311,7 +311,6 @@ static int wl1273_startup(struct snd_pcm_substream *substream, break; default: return -EINVAL; - break; } return 0; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index bbe8d782e0af..b1ca64d2f7ea 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -502,7 +502,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, if (ret < 0) return ret; return skl_run_pipe(skl, mconfig->pipe); - break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index a6b72ad53b43..2d85cc4c67fb 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2385,7 +2385,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret); case -EPROBE_DEFER: goto err; - break; } if (ret) { -- cgit v1.2.3 From 7826b8d15ec2cea1c1b8680ada1eb965d0660aa6 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:25 -0500 Subject: ASoC: sun8i-codec: Prepare to extend the DAI driver In preparation for adding additional DAIs to this component, convert the DAI driver definition to an array. Since this changes all of the lines in the definition anyway, let's move it closer to the ops function definitions, instead of on the far side of the DAPM arrays. And while moving the DAI driver ops, rename the set_fmt hook to match the usual naming scheme. Give the existing DAI an explicit ID and more meaningful stream names, so it will remain unique as more DAIs are added. The AIF widget streams must be updated to match. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-2-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 76 ++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 7590c4b04d14..6413873a0584 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -95,6 +95,11 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) +enum { + SUN8I_CODEC_AIF1, + SUN8I_CODEC_NAIFS +}; + struct sun8i_codec_quirks { bool legacy_widgets : 1; bool lrck_inversion : 1; @@ -165,7 +170,7 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) } } -static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); u32 value; @@ -336,6 +341,36 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, return 0; } +static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { + .set_fmt = sun8i_codec_set_fmt, + .hw_params = sun8i_codec_hw_params, +}; + +static struct snd_soc_dai_driver sun8i_codec_dais[] = { + { + .name = "sun8i-codec-aif1", + .id = SUN8I_CODEC_AIF1, + .ops = &sun8i_codec_dai_ops, + /* capture capabilities */ + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .sig_bits = 24, + }, + /* playback capabilities */ + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, +}; + static const char *const sun8i_aif_stereo_mux_enum_values[] = { "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono" }; @@ -438,10 +473,10 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0), /* AIF "ADC" Outputs */ - SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "Capture", 0, + SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "AIF1 Capture", 0, SUN8I_AIF1_ADCDAT_CTRL, SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0), - SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1, + SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1, SUN8I_AIF1_ADCDAT_CTRL, SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0), @@ -464,10 +499,10 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { &sun8i_aif1_da0_stereo_mux_control), /* AIF "DAC" Inputs */ - SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0, + SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "AIF1 Playback", 0, SUN8I_AIF1_DACDAT_CTRL, SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), - SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1, + SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1, SUN8I_AIF1_DACDAT_CTRL, SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), @@ -624,34 +659,6 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component) return 0; } -static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { - .hw_params = sun8i_codec_hw_params, - .set_fmt = sun8i_set_fmt, -}; - -static struct snd_soc_dai_driver sun8i_codec_dai = { - .name = "sun8i", - /* playback capabilities */ - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - /* capture capabilities */ - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .sig_bits = 24, - }, - /* pcm operations */ - .ops = &sun8i_codec_dai_ops, -}; - static const struct snd_soc_component_driver sun8i_soc_component = { .dapm_widgets = sun8i_codec_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), @@ -714,7 +721,8 @@ static int sun8i_codec_probe(struct platform_device *pdev) } ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component, - &sun8i_codec_dai, 1); + sun8i_codec_dais, + ARRAY_SIZE(sun8i_codec_dais)); if (ret) { dev_err(&pdev->dev, "Failed to register codec\n"); goto err_suspend; -- cgit v1.2.3 From fd57ed2de5b1a5e153abf2f8c02fc3c1bf40de3b Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:26 -0500 Subject: ASoC: sun8i-codec: Program DAI format before clock inversion The LRCK inversion bit has a different meaning in DSP mode: it selects between the DSP A and DSP B formats. To support this, we need to know if the selected format is a DSP format. One easy way to do this is to set the format field before the clock inversion fields. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-3-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 6413873a0584..53c9289a4249 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -173,7 +173,7 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); - u32 value; + u32 format, value; /* clock masters */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -190,6 +190,28 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD), value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD); + /* DAI format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + format = 0x0; + break; + case SND_SOC_DAIFMT_LEFT_J: + format = 0x1; + break; + case SND_SOC_DAIFMT_RIGHT_J: + format = 0x2; + break; + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + format = 0x3; + break; + default: + return -EINVAL; + } + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK, + format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT); + /* clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: /* Normal */ @@ -220,28 +242,6 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); - /* DAI format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - value = 0x0; - break; - case SND_SOC_DAIFMT_LEFT_J: - value = 0x1; - break; - case SND_SOC_DAIFMT_RIGHT_J: - value = 0x2; - break; - case SND_SOC_DAIFMT_DSP_A: - case SND_SOC_DAIFMT_DSP_B: - value = 0x3; - break; - default: - return -EINVAL; - } - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK, - value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT); - return 0; } -- cgit v1.2.3 From c56f5f1c0b23ac0cdcf8c73bf6f7363ef0cdfbc0 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:27 -0500 Subject: ASoC: sun8i-codec: Enable all supported clock inversions When using the I2S, LEFT_J, or RIGHT_J format, the hardware supports independent BCLK and LRCK inversion control. When using DSP_A or DSP_B, LRCK inversion is not supported. The register bit is repurposed to select between DSP_A and DSP_B. Extend the driver to support this. Signed-off-by: Samuel Holland Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/20201014061941.4306-4-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 61 +++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 53c9289a4249..77eb0fd01e3d 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -44,8 +44,7 @@ #define SUN8I_SYS_SR_CTRL_AIF2_FS 8 #define SUN8I_AIF1CLK_CTRL 0x040 #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD 15 -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV 14 -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13 +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV 13 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 @@ -90,6 +89,7 @@ #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4) #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12) #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) +#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK GENMASK(14, 13) #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) @@ -173,7 +173,7 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); - u32 format, value; + u32 dsp_format, format, invert, value; /* clock masters */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -202,8 +202,12 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) format = 0x2; break; case SND_SOC_DAIFMT_DSP_A: + format = 0x3; + dsp_format = 0x0; /* Set LRCK_INV to 0 */ + break; case SND_SOC_DAIFMT_DSP_B: format = 0x3; + dsp_format = 0x1; /* Set LRCK_INV to 1 */ break; default: return -EINVAL; @@ -215,32 +219,45 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: /* Normal */ - value = 0x0; + invert = 0x0; break; - case SND_SOC_DAIFMT_IB_IF: /* Inversion */ - value = 0x1; + case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */ + invert = 0x1; + break; + case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */ + invert = 0x2; + break; + case SND_SOC_DAIFMT_IB_IF: /* Both inverted */ + invert = 0x3; break; default: return -EINVAL; } - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV), - value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV); - /* - * It appears that the DAI and the codec in the A33 SoC don't - * share the same polarity for the LRCK signal when they mean - * 'normal' and 'inverted' in the datasheet. - * - * Since the DAI here is our regular i2s driver that have been - * tested with way more codecs than just this one, it means - * that the codec probably gets it backward, and we have to - * invert the value here. - */ - value ^= scodec->quirks->lrck_inversion; + if (format == 0x3) { + /* Inverted LRCK is not available in DSP mode. */ + if (invert & BIT(0)) + return -EINVAL; + + /* Instead, the bit selects between DSP A/B formats. */ + invert |= dsp_format; + } else { + /* + * It appears that the DAI and the codec in the A33 SoC don't + * share the same polarity for the LRCK signal when they mean + * 'normal' and 'inverted' in the datasheet. + * + * Since the DAI here is our regular i2s driver that have been + * tested with way more codecs than just this one, it means + * that the codec probably gets it backward, and we have to + * invert the value here. + */ + invert ^= scodec->quirks->lrck_inversion; + } + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), - value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); + SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK, + invert << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV); return 0; } -- cgit v1.2.3 From 1abb43aeadfb513c0a16013cd445fb7dd3b285bb Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:28 -0500 Subject: ASoC: sun8i-codec: Use the provided word size The hardware supports 8 to 24-bit word sizes on all three of its DAIs, only one of which is connected to the CPU DAI. Program the word size based on the actual selected format, instead of assuming limitations from another driver (which, incedentally, has patches pending to remove that limitation). Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-5-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 77eb0fd01e3d..82576066c249 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -48,7 +48,6 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 #define SUN8I_AIF1_ADCDAT_CTRL 0x044 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15 @@ -322,16 +321,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); - int sample_rate, lrck_div; + int lrck_div, sample_rate, word_size; u8 bclk_div; - /* - * The CPU DAI handles only a sample of 16 bits. Configure the - * codec to handle this type of sample resolution. - */ + /* word size */ + switch (params_width(params)) { + case 8: + word_size = 0x0; + break; + case 16: + word_size = 0x1; + break; + case 20: + word_size = 0x2; + break; + case 24: + word_size = 0x3; + break; + default: + return -EINVAL; + } + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, - SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16); + word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ); bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16); regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, -- cgit v1.2.3 From e511aed79632e8a2dd03068f8bd11b64cb0d7170 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:29 -0500 Subject: ASoC: sun8i-codec: Round up the LRCK divisor The codec supports only power-of-two BCLK/LRCK divisors. If either the slot width or the number of slots is not a power of two, the LRCK divisor must be rounded up to provide enough space. To do that, use order_base_2 (instead of ilog2, which rounds down). Since the rounded divisor is also needed for setting the SYSCLK/BCLK divisor, return the order base 2 instead of fully calculating the hardware register encoding. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-6-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 82576066c249..92fcef45097d 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -305,15 +305,15 @@ static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, return best_val; } -static int sun8i_codec_get_lrck_div(unsigned int channels, - unsigned int word_size) +static int sun8i_codec_get_lrck_div_order(unsigned int slots, + unsigned int slot_width) { - unsigned int div = word_size * channels; + unsigned int div = slots * slot_width; if (div < 16 || div > 256) return -EINVAL; - return ilog2(div) - 4; + return order_base_2(div); } static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, @@ -321,7 +321,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); - int lrck_div, sample_rate, word_size; + unsigned int slots = params_channels(params); + unsigned int slot_width = params_width(params); + int lrck_div_order, sample_rate, word_size; u8 bclk_div; /* word size */ @@ -351,14 +353,14 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); - lrck_div = sun8i_codec_get_lrck_div(params_channels(params), - params_physical_width(params)); - if (lrck_div < 0) - return lrck_div; + /* LRCK divider (BCLK/LRCK ratio) */ + lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width); + if (lrck_div_order < 0) + return lrck_div_order; regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, - lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); + (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); sample_rate = sun8i_codec_get_hw_rate(params); if (sample_rate < 0) -- cgit v1.2.3 From 68a4f2caaa17ce62890c51ef957dd008c2e42aae Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:30 -0500 Subject: ASoC: sun8i-codec: Correct the BCLK divisor calculation Previously, the BCLK divisor calculation assumed zero padding and exactly two slots. In order to support the TDM slot binding and 20/24-bit word sizes, those assumptions must be removed. Due to hardware limitations, the BCLK/LRCK ratio is not as simple as "slot_width * slots". However, the correct value is already calculated elsewhere in this function, since it must also be programmed into the hardware. Reuse that value to calculate the correct SYSCLK/BCLK divisor. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-7-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 92fcef45097d..ae885774c877 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -284,11 +284,11 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = { }; static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, - unsigned int rate, - unsigned int word_size) + unsigned int lrck_div_order, + unsigned int sample_rate) { unsigned long clk_rate = clk_get_rate(scodec->clk_module); - unsigned int div = clk_rate / rate / word_size / 2; + unsigned int div = clk_rate / sample_rate >> lrck_div_order; unsigned int best_val = 0, best_diff = ~0; int i; @@ -348,11 +348,6 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ); - bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16); - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, - bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); - /* LRCK divider (BCLK/LRCK ratio) */ lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width); if (lrck_div_order < 0) @@ -362,6 +357,12 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); + /* BCLK divider (SYSCLK/BCLK ratio) */ + bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, params_rate(params)); + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, + bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); + sample_rate = sun8i_codec_get_hw_rate(params); if (sample_rate < 0) return sample_rate; -- cgit v1.2.3 From afb1a6006299a8b6b5ad04363fd74aa66a6ac79b Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:31 -0500 Subject: ASoC: sun8i-codec: Support the TDM slot binding Now that BCLK and LRCK rate calculations in the driver can handle any hardware-supported slot width and number of slots, allow overriding those parameters from the device tree. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-8-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index ae885774c877..49e763d1891b 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -99,6 +99,11 @@ enum { SUN8I_CODEC_NAIFS }; +struct sun8i_codec_aif { + unsigned int slots; + unsigned int slot_width; +}; + struct sun8i_codec_quirks { bool legacy_widgets : 1; bool lrck_inversion : 1; @@ -108,6 +113,7 @@ struct sun8i_codec { struct regmap *regmap; struct clk *clk_module; const struct sun8i_codec_quirks *quirks; + struct sun8i_codec_aif aifs[SUN8I_CODEC_NAIFS]; }; static int sun8i_codec_runtime_resume(struct device *dev) @@ -261,6 +267,22 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); + struct sun8i_codec_aif *aif = &scodec->aifs[dai->id]; + + if (slot_width && !is_power_of_2(slot_width)) + return -EINVAL; + + aif->slots = slots; + aif->slot_width = slot_width; + + return 0; +} + struct sun8i_codec_clk_div { u8 div; u8 val; @@ -321,8 +343,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); - unsigned int slots = params_channels(params); - unsigned int slot_width = params_width(params); + struct sun8i_codec_aif *aif = &scodec->aifs[dai->id]; + unsigned int slots = aif->slots ?: params_channels(params); + unsigned int slot_width = aif->slot_width ?: params_width(params); int lrck_div_order, sample_rate, word_size; u8 bclk_div; @@ -376,6 +399,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { .set_fmt = sun8i_codec_set_fmt, + .set_tdm_slot = sun8i_codec_set_tdm_slot, .hw_params = sun8i_codec_hw_params, }; -- cgit v1.2.3 From e557148ac220b43bc6cbc06333f56b1c61e90825 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:32 -0500 Subject: ASoC: sun8i-codec: Enforce symmetric DAI parameters The AIFs have a single register controlling DAI parameters in both directions, including BCLK/LRCK divisor and word size. The DAIs produce only noise or silence if any of these parameters is wrong. Therefore, we need to enforce symmetry for these parameters, so starting a new substream will not break an existing substream. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-9-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 49e763d1891b..21104e6e8892 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -425,6 +425,9 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .symmetric_rates = true, + .symmetric_channels = true, + .symmetric_samplebits = true, }, }; -- cgit v1.2.3 From c2b751d769669467da1247c9c6c536a494c9c96e Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:33 -0500 Subject: ASoC: sun8i-codec: Enable all supported sample rates The system sample rate programmed into the hardware is really a clock divider from SYSCLK to the ADC and DAC. Since we support two SYSCLK frequencies, we can use all sample rates corresponding to one of those frequencies divided by any available divisor. This commit enables support for those sample rates. It also stops advertising support for a 64 kHz sample rate, which is not supported. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-10-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 21104e6e8892..38349d85fb17 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -94,6 +94,13 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) +#define SUN8I_CODEC_PCM_RATES (SNDRV_PCM_RATE_8000_48000|\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_KNOT) + enum { SUN8I_CODEC_AIF1, SUN8I_CODEC_NAIFS @@ -147,27 +154,31 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) unsigned int rate = params_rate(params); switch (rate) { - case 8000: case 7350: + case 8000: return 0x0; case 11025: return 0x1; case 12000: return 0x2; + case 14700: case 16000: return 0x3; case 22050: return 0x4; case 24000: return 0x5; + case 29400: case 32000: return 0x6; case 44100: return 0x7; case 48000: return 0x8; + case 88200: case 96000: return 0x9; + case 176400: case 192000: return 0xa; default: @@ -413,7 +424,7 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { .stream_name = "AIF1 Capture", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SUN8I_CODEC_PCM_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, .sig_bits = 24, }, @@ -422,7 +433,7 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { .stream_name = "AIF1 Playback", .channels_min = 1, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SUN8I_CODEC_PCM_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .symmetric_rates = true, -- cgit v1.2.3 From 6c5326bebd4041a21c77b2b96461a97b7f4e39ee Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:34 -0500 Subject: ASoC: sun8i-codec: Automatically set the system sample rate The sun8i codec has three clock/sample rate domains: - The AIF1 domain, with a sample rate equal to AIF1 LRCK - The AIF2 domain, with a sample rate equal to AIF2 LRCK - The SYSCLK domain, containing the ADC, DAC, and effects (AGC/DRC), with a sample rate given by a divisor from SYSCLK. The divisor is controlled by the AIF1_FS or AIF2_FS field in SYS_SR_CTRL, depending on if SYSCLK's source is AIF1CLK or AIF2CLK, respectively. The exact sample rate depends on if SYSCLK is running at 22.6 MHz or 24.6 MHz. When an AIF (currently only AIF1) is active, the ADC and DAC should run at that sample rate to avoid artifacting. Sample rate conversion is only available when multiple AIFs are active and are routed to each other; this means the sample rate conversion hardware usually cannot be used. Only attach the event hook to the channel 0 AIF widgets, since we only need one event when a DAI stream starts or stops. Channel 0 is always brought up with a DAI stream, regardless of the number of channels in the stream. The ADC and DAC (along with their effects blocks) can be used even if no AIFs are in use. In that case, we should select an appropriate sample rate divisor, instead of keeping the last-used AIF sample rate. 44.1/48 kHz was chosen to balance audio quality and power consumption. Since the sample rate is tied to active AIF paths, disabling pmdown_time allows switching to the optimal sample rate immediately, instead of after a 5 second delay. Signed-off-by: Samuel Holland Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/20201014061941.4306-11-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 103 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 38349d85fb17..468fa5f71bd3 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -94,6 +94,8 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) +#define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000 + #define SUN8I_CODEC_PCM_RATES (SNDRV_PCM_RATE_8000_48000|\ SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000 |\ @@ -107,8 +109,11 @@ enum { }; struct sun8i_codec_aif { + unsigned int sample_rate; unsigned int slots; unsigned int slot_width; + unsigned int active_streams : 2; + unsigned int open_streams : 2; }; struct sun8i_codec_quirks { @@ -149,11 +154,9 @@ static int sun8i_codec_runtime_suspend(struct device *dev) return 0; } -static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) +static int sun8i_codec_get_hw_rate(unsigned int sample_rate) { - unsigned int rate = params_rate(params); - - switch (rate) { + switch (sample_rate) { case 7350: case 8000: return 0x0; @@ -186,6 +189,33 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) } } +static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec) +{ + unsigned int max_rate = 0; + int hw_rate, i; + + for (i = SUN8I_CODEC_AIF1; i < SUN8I_CODEC_NAIFS; ++i) { + struct sun8i_codec_aif *aif = &scodec->aifs[i]; + + if (aif->active_streams) + max_rate = max(max_rate, aif->sample_rate); + } + + /* Set the sample rate for ADC->DAC passthrough when no AIF is active. */ + if (!max_rate) + max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE; + + hw_rate = sun8i_codec_get_hw_rate(max_rate); + if (hw_rate < 0) + return hw_rate; + + regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, + SUN8I_SYS_SR_CTRL_AIF1_FS_MASK, + hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS); + + return 0; +} + static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); @@ -355,9 +385,10 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, { struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); struct sun8i_codec_aif *aif = &scodec->aifs[dai->id]; + unsigned int sample_rate = params_rate(params); unsigned int slots = aif->slots ?: params_channels(params); unsigned int slot_width = aif->slot_width ?: params_width(params); - int lrck_div_order, sample_rate, word_size; + int lrck_div_order, word_size; u8 bclk_div; /* word size */ @@ -392,19 +423,30 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); /* BCLK divider (SYSCLK/BCLK ratio) */ - bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, params_rate(params)); + bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, sample_rate); regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); - sample_rate = sun8i_codec_get_hw_rate(params); - if (sample_rate < 0) - return sample_rate; + aif->sample_rate = sample_rate; + aif->open_streams |= BIT(substream->stream); - regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, - SUN8I_SYS_SR_CTRL_AIF1_FS_MASK, - sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS); + return sun8i_codec_update_sample_rate(scodec); +} + +static int sun8i_codec_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); + struct sun8i_codec_aif *aif = &scodec->aifs[dai->id]; + + if (aif->open_streams != BIT(substream->stream)) + goto done; + aif->sample_rate = 0; + +done: + aif->open_streams &= ~BIT(substream->stream); return 0; } @@ -412,6 +454,7 @@ static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { .set_fmt = sun8i_codec_set_fmt, .set_tdm_slot = sun8i_codec_set_tdm_slot, .hw_params = sun8i_codec_hw_params, + .hw_free = sun8i_codec_hw_free, }; static struct snd_soc_dai_driver sun8i_codec_dais[] = { @@ -442,6 +485,22 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { }, }; +static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); + struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1']; + int stream = w->id == snd_soc_dapm_aif_out; + + if (SND_SOC_DAPM_EVENT_ON(event)) + aif->active_streams |= BIT(stream); + else + aif->active_streams &= ~BIT(stream); + + return sun8i_codec_update_sample_rate(scodec); +} + static const char *const sun8i_aif_stereo_mux_enum_values[] = { "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono" }; @@ -544,9 +603,11 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0), /* AIF "ADC" Outputs */ - SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "AIF1 Capture", 0, - SUN8I_AIF1_ADCDAT_CTRL, - SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0), + SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0, + SUN8I_AIF1_ADCDAT_CTRL, + SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0, + sun8i_codec_aif_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1, SUN8I_AIF1_ADCDAT_CTRL, SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0), @@ -570,9 +631,11 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { &sun8i_aif1_da0_stereo_mux_control), /* AIF "DAC" Inputs */ - SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "AIF1 Playback", 0, - SUN8I_AIF1_DACDAT_CTRL, - SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), + SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0, + SUN8I_AIF1_DACDAT_CTRL, + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0, + sun8i_codec_aif_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1, SUN8I_AIF1_DACDAT_CTRL, SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), @@ -727,6 +790,9 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component) BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC), SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK); + /* Program the default sample rate. */ + sun8i_codec_update_sample_rate(scodec); + return 0; } @@ -737,7 +803,6 @@ static const struct snd_soc_component_driver sun8i_soc_component = { .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), .probe = sun8i_codec_component_probe, .idle_bias_on = 1, - .use_pmdown_time = 1, .endianness = 1, .non_legacy_dai_naming = 1, }; -- cgit v1.2.3 From 15b45912341e884a16322792525db7a2b2b9a1f9 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:35 -0500 Subject: ASoC: sun8i-codec: Constrain to compatible sample rates While another stream is active, only allow userspace to use sample rates that are compatible with the current SYSCLK frequency. This ensures the actual sample rate will always match what is given in hw_params. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-12-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 57 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 468fa5f71bd3..0e8b0ac31fed 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -126,6 +126,8 @@ struct sun8i_codec { struct clk *clk_module; const struct sun8i_codec_quirks *quirks; struct sun8i_codec_aif aifs[SUN8I_CODEC_NAIFS]; + unsigned int sysclk_rate; + int sysclk_refcnt; }; static int sun8i_codec_runtime_resume(struct device *dev) @@ -324,6 +326,47 @@ static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai, return 0; } +static const unsigned int sun8i_codec_rates[] = { + 7350, 8000, 11025, 12000, 14700, 16000, 22050, 24000, + 29400, 32000, 44100, 48000, 88200, 96000, 176400, 192000, +}; + +static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = { + .list = sun8i_codec_rates, + .count = ARRAY_SIZE(sun8i_codec_rates), +}; + +static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = { + .list = sun8i_codec_rates, + .count = ARRAY_SIZE(sun8i_codec_rates), + .mask = 0x5555, +}; + +static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = { + .list = sun8i_codec_rates, + .count = ARRAY_SIZE(sun8i_codec_rates), + .mask = 0xaaaa, +}; + +static int sun8i_codec_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); + const struct snd_pcm_hw_constraint_list *list; + + if (!scodec->sysclk_refcnt) + list = &sun8i_codec_all_rates; + else if (scodec->sysclk_rate == 22579200) + list = &sun8i_codec_22M_rates; + else if (scodec->sysclk_rate == 24576000) + list = &sun8i_codec_24M_rates; + else + return -EINVAL; + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, list); +} + struct sun8i_codec_clk_div { u8 div; u8 val; @@ -346,12 +389,11 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = { { .div = 192, .val = 13 }, }; -static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec, +static u8 sun8i_codec_get_bclk_div(unsigned int sysclk_rate, unsigned int lrck_div_order, unsigned int sample_rate) { - unsigned long clk_rate = clk_get_rate(scodec->clk_module); - unsigned int div = clk_rate / sample_rate >> lrck_div_order; + unsigned int div = sysclk_rate / sample_rate >> lrck_div_order; unsigned int best_val = 0, best_diff = ~0; int i; @@ -388,6 +430,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, unsigned int sample_rate = params_rate(params); unsigned int slots = aif->slots ?: params_channels(params); unsigned int slot_width = aif->slot_width ?: params_width(params); + unsigned int sysclk_rate = clk_get_rate(scodec->clk_module); int lrck_div_order, word_size; u8 bclk_div; @@ -423,11 +466,15 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); /* BCLK divider (SYSCLK/BCLK ratio) */ - bclk_div = sun8i_codec_get_bclk_div(scodec, lrck_div_order, sample_rate); + bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate); regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); + if (!aif->open_streams) + scodec->sysclk_refcnt++; + scodec->sysclk_rate = sysclk_rate; + aif->sample_rate = sample_rate; aif->open_streams |= BIT(substream->stream); @@ -443,6 +490,7 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream, if (aif->open_streams != BIT(substream->stream)) goto done; + scodec->sysclk_refcnt--; aif->sample_rate = 0; done: @@ -453,6 +501,7 @@ done: static const struct snd_soc_dai_ops sun8i_codec_dai_ops = { .set_fmt = sun8i_codec_set_fmt, .set_tdm_slot = sun8i_codec_set_tdm_slot, + .startup = sun8i_codec_startup, .hw_params = sun8i_codec_hw_params, .hw_free = sun8i_codec_hw_free, }; -- cgit v1.2.3 From 3952ec2ac55a5afcda84270fa203f17a6309af6b Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:36 -0500 Subject: ASoC: sun8i-codec: Protect the clock rate while streams are open The codec's clock input is shared among all AIFs, and shared with other audio-related hardware in the SoC, including I2S and SPDIF controllers. To ensure sample rates selected by userspace or by codec2codec DAI links are maintained, the clock rate must be protected while it is in use. Signed-off-by: Samuel Holland Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/20201014061941.4306-13-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 1 + sound/soc/sunxi/sun8i-codec.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 9cd7009cb570..69b9d8515335 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -14,6 +14,7 @@ config SND_SUN8I_CODEC tristate "Allwinner SUN8I audio codec" depends on OF depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST + select COMMON_CLK select REGMAP_MMIO help This option enables the digital part of the internal audio codec for diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 0e8b0ac31fed..253857e66f6f 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -421,6 +421,11 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots, return order_base_2(div); } +static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate) +{ + return sample_rate % 4000 ? 22579200 : 24576000; +} + static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -430,8 +435,8 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, unsigned int sample_rate = params_rate(params); unsigned int slots = aif->slots ?: params_channels(params); unsigned int slot_width = aif->slot_width ?: params_width(params); - unsigned int sysclk_rate = clk_get_rate(scodec->clk_module); - int lrck_div_order, word_size; + unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate); + int lrck_div_order, ret, word_size; u8 bclk_div; /* word size */ @@ -471,6 +476,24 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); + /* + * SYSCLK rate + * + * Clock rate protection is reference counted; but hw_params may be + * called many times per substream, without matching calls to hw_free. + * Protect the clock rate once per AIF, on the first hw_params call + * for the first substream. clk_set_rate() will allow clock rate + * changes on subsequent calls if only one AIF has open streams. + */ + ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module, + sysclk_rate); + if (ret == -EBUSY) + dev_err(dai->dev, + "%s sample rate (%u Hz) conflicts with other audio streams\n", + dai->name, sample_rate); + if (ret < 0) + return ret; + if (!aif->open_streams) scodec->sysclk_refcnt++; scodec->sysclk_rate = sysclk_rate; @@ -487,9 +510,11 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream, struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); struct sun8i_codec_aif *aif = &scodec->aifs[dai->id]; + /* Drop references when the last substream for the AIF is freed. */ if (aif->open_streams != BIT(substream->stream)) goto done; + clk_rate_exclusive_put(scodec->clk_module); scodec->sysclk_refcnt--; aif->sample_rate = 0; -- cgit v1.2.3 From 2464dccab7fef040bd6e85cd78ac33e2731925da Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:37 -0500 Subject: ASoC: sun8i-codec: Require an exact BCLK divisor match Now that we guarantee that SYSCLK is running at the optimal rate when hw_params succeeds, and that it will continue running at that rate, SYSCLK will always be an integer multiple of BCLK. So we can always pick the exact divider, not just the closest divider. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-14-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 253857e66f6f..a530e58018b7 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -389,25 +389,21 @@ static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = { { .div = 192, .val = 13 }, }; -static u8 sun8i_codec_get_bclk_div(unsigned int sysclk_rate, - unsigned int lrck_div_order, - unsigned int sample_rate) +static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate, + unsigned int lrck_div_order, + unsigned int sample_rate) { unsigned int div = sysclk_rate / sample_rate >> lrck_div_order; - unsigned int best_val = 0, best_diff = ~0; int i; for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) { const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i]; - unsigned int diff = abs(bdiv->div - div); - if (diff < best_diff) { - best_diff = diff; - best_val = bdiv->val; - } + if (bdiv->div == div) + return bdiv->val; } - return best_val; + return -EINVAL; } static int sun8i_codec_get_lrck_div_order(unsigned int slots, @@ -436,8 +432,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, unsigned int slots = aif->slots ?: params_channels(params); unsigned int slot_width = aif->slot_width ?: params_width(params); unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate); - int lrck_div_order, ret, word_size; - u8 bclk_div; + int bclk_div, lrck_div_order, ret, word_size; /* word size */ switch (params_width(params)) { @@ -472,6 +467,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, /* BCLK divider (SYSCLK/BCLK ratio) */ bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate); + if (bclk_div < 0) + return bclk_div; + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); -- cgit v1.2.3 From 342cacb92d627a7cc8df1b5fe3e404530164ea17 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:38 -0500 Subject: ASoC: sun8i-codec: Enable all supported PCM formats Now that the DAI clock setup is correct for all hardware-supported PCM formats, we can enable them in the driver. With the appropriate support in the CPU DAI driver, this allows userspace to access the additional formats. Since this codec is connected to the CPU via a DAI, not directly, we do not care if the CPU DAI is using 3-byte or 4-byte formats, so we can support them both. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-15-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index a530e58018b7..e3abf8363d9b 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -96,6 +96,13 @@ #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000 +#define SUN8I_CODEC_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 |\ + SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S20_3LE|\ + SNDRV_PCM_FMTBIT_S24_3LE) + #define SUN8I_CODEC_PCM_RATES (SNDRV_PCM_RATE_8000_48000|\ SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000 |\ @@ -540,7 +547,7 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { .channels_min = 1, .channels_max = 2, .rates = SUN8I_CODEC_PCM_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SUN8I_CODEC_PCM_FORMATS, .sig_bits = 24, }, /* playback capabilities */ @@ -549,7 +556,7 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { .channels_min = 1, .channels_max = 2, .rates = SUN8I_CODEC_PCM_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SUN8I_CODEC_PCM_FORMATS, }, .symmetric_rates = true, .symmetric_channels = true, -- cgit v1.2.3 From 7a6b937ec4e256b028be9b4e244d40287282c825 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:39 -0500 Subject: ASoC: sun8i-codec: Generalize AIF clock control The AIF clock control register has the same layout for all three AIFs. The only difference between them is that AIF3 is missing some fields. We can reuse the same register field definitions for all three registers, and use the DAI ID to select the correct register address. Signed-off-by: Samuel Holland Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/20201014061941.4306-16-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 62 ++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index e3abf8363d9b..6aa8751f7fa0 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -42,13 +42,13 @@ #define SUN8I_SYS_SR_CTRL 0x018 #define SUN8I_SYS_SR_CTRL_AIF1_FS 12 #define SUN8I_SYS_SR_CTRL_AIF2_FS 8 -#define SUN8I_AIF1CLK_CTRL 0x040 -#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD 15 -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV 13 -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 +#define SUN8I_AIF_CLK_CTRL(n) (0x040 * (1 + (n))) +#define SUN8I_AIF_CLK_CTRL_MSTR_MOD 15 +#define SUN8I_AIF_CLK_CTRL_CLK_INV 13 +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV 9 +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV 6 +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ 4 +#define SUN8I_AIF_CLK_CTRL_DATA_FMT 2 #define SUN8I_AIF1_ADCDAT_CTRL 0x044 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14 @@ -88,11 +88,11 @@ #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4) #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12) #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) -#define SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK GENMASK(14, 13) -#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9) -#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) -#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) -#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2) +#define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK GENMASK(14, 13) +#define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK GENMASK(12, 9) +#define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK GENMASK(8, 6) +#define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK GENMASK(5, 4) +#define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK GENMASK(3, 2) #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000 @@ -241,9 +241,10 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) default: return -EINVAL; } - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD), - value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD); + + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD), + value << SUN8I_AIF_CLK_CTRL_MSTR_MOD); /* DAI format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -267,9 +268,10 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) default: return -EINVAL; } - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK, - format << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT); + + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK, + format << SUN8I_AIF_CLK_CTRL_DATA_FMT); /* clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -310,9 +312,9 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) invert ^= scodec->quirks->lrck_inversion; } - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV_MASK, - invert << SUN8I_AIF1CLK_CTRL_AIF1_CLK_INV); + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + SUN8I_AIF_CLK_CTRL_CLK_INV_MASK, + invert << SUN8I_AIF_CLK_CTRL_CLK_INV); return 0; } @@ -459,27 +461,27 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, - word_size << SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ); + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK, + word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ); /* LRCK divider (BCLK/LRCK ratio) */ lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width); if (lrck_div_order < 0) return lrck_div_order; - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, - (lrck_div_order - 4) << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV); + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK, + (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV); /* BCLK divider (SYSCLK/BCLK ratio) */ bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate); if (bclk_div < 0) return bclk_div; - regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, - SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK, - bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV); + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK, + bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV); /* * SYSCLK rate -- cgit v1.2.3 From 50ec8422acd2cdadf5599cc046a5448770542aa7 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:40 -0500 Subject: ASoC: sun8i-codec: Add the AIF2 DAI, widgets, and routes This adds support for AIF2, which is stereo and has fullly independent clocking capability, making it very similar to AIF1. Acked-by: Maxime Ripard Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-17-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 215 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 6aa8751f7fa0..6a8232e07983 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -33,10 +33,12 @@ #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK (0x1 << 0) #define SUN8I_MOD_CLK_ENA 0x010 #define SUN8I_MOD_CLK_ENA_AIF1 15 +#define SUN8I_MOD_CLK_ENA_AIF2 14 #define SUN8I_MOD_CLK_ENA_ADC 3 #define SUN8I_MOD_CLK_ENA_DAC 2 #define SUN8I_MOD_RST_CTL 0x014 #define SUN8I_MOD_RST_CTL_AIF1 15 +#define SUN8I_MOD_RST_CTL_AIF2 14 #define SUN8I_MOD_RST_CTL_ADC 3 #define SUN8I_MOD_RST_CTL_DAC 2 #define SUN8I_SYS_SR_CTRL 0x018 @@ -68,6 +70,29 @@ #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8 +#define SUN8I_AIF2_ADCDAT_CTRL 0x084 +#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA 15 +#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA 14 +#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC 10 +#define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC 8 +#define SUN8I_AIF2_DACDAT_CTRL 0x088 +#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA 15 +#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA 14 +#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC 10 +#define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC 8 +#define SUN8I_AIF2_MXR_SRC 0x08c +#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L 15 +#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L 14 +#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR 13 +#define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL 12 +#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R 11 +#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R 10 +#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL 9 +#define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR 8 +#define SUN8I_AIF3_PATH_CTRL 0x0cc +#define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC 10 +#define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC 8 +#define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI 7 #define SUN8I_ADC_DIG_CTRL 0x100 #define SUN8I_ADC_DIG_CTRL_ENAD 15 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2 @@ -112,6 +137,7 @@ enum { SUN8I_CODEC_AIF1, + SUN8I_CODEC_AIF2, SUN8I_CODEC_NAIFS }; @@ -363,6 +389,10 @@ static int sun8i_codec_startup(struct snd_pcm_substream *substream, struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai); const struct snd_pcm_hw_constraint_list *list; + /* hw_constraints is not relevant for codec2codec DAIs. */ + if (dai->id != SUN8I_CODEC_AIF1) + return 0; + if (!scodec->sysclk_refcnt) list = &sun8i_codec_all_rates; else if (scodec->sysclk_rate == 22579200) @@ -564,6 +594,31 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { .symmetric_channels = true, .symmetric_samplebits = true, }, + { + .name = "sun8i-codec-aif2", + .id = SUN8I_CODEC_AIF2, + .ops = &sun8i_codec_dai_ops, + /* capture capabilities */ + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SUN8I_CODEC_PCM_RATES, + .formats = SUN8I_CODEC_PCM_FORMATS, + .sig_bits = 24, + }, + /* playback capabilities */ + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SUN8I_CODEC_PCM_RATES, + .formats = SUN8I_CODEC_PCM_FORMATS, + }, + .symmetric_rates = true, + .symmetric_channels = true, + .symmetric_samplebits = true, + }, }; static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w, @@ -596,6 +651,16 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control = SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route", sun8i_aif1_ad0_stereo_mux_enum); +static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum, + SUN8I_AIF2_ADCDAT_CTRL, + SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC, + SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC, + sun8i_aif_stereo_mux_enum_values); + +static const struct snd_kcontrol_new sun8i_aif2_adc_stereo_mux_control = + SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route", + sun8i_aif2_adc_stereo_mux_enum); + static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = { SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC, @@ -615,6 +680,38 @@ static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = { SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0), }; +static const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = { + SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch", + SUN8I_AIF2_MXR_SRC, + SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L, + SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0), + SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch", + SUN8I_AIF2_MXR_SRC, + SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L, + SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0), + SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", + SUN8I_AIF2_MXR_SRC, + SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR, + SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0), + SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch", + SUN8I_AIF2_MXR_SRC, + SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL, + SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0), +}; + +static const char *const sun8i_aif2_dac_mux_enum_values[] = { + "AIF2", "AIF3+2", "AIF2+3" +}; + +static SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum, + SUN8I_AIF3_PATH_CTRL, + SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC, + sun8i_aif2_dac_mux_enum_values); + +static const struct snd_kcontrol_new sun8i_aif2_dac_mux_control = + SOC_DAPM_ENUM("AIF2 DAC Source Playback Route", + sun8i_aif2_dac_mux_enum); + static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum, SUN8I_AIF1_DACDAT_CTRL, SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC, @@ -625,6 +722,16 @@ static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control = SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route", sun8i_aif1_da0_stereo_mux_enum); +static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_dac_stereo_mux_enum, + SUN8I_AIF2_DACDAT_CTRL, + SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC, + SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC, + sun8i_aif_stereo_mux_enum_values); + +static const struct snd_kcontrol_new sun8i_aif2_dac_stereo_mux_control = + SOC_DAPM_ENUM("AIF2 DAC Stereo Playback Route", + sun8i_aif2_dac_stereo_mux_enum); + static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = { SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC, @@ -649,6 +756,9 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("AIF1CLK", SUN8I_SYSCLK_CTL, SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("AIF2CLK", + SUN8I_SYSCLK_CTL, + SUN8I_SYSCLK_CTL_AIF2CLK_ENA, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL, SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0), @@ -657,6 +767,9 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("CLK AIF1", SUN8I_MOD_CLK_ENA, SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLK AIF2", + SUN8I_MOD_CLK_ENA, + SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CLK ADC", SUN8I_MOD_CLK_ENA, SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0), @@ -668,6 +781,9 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL, SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RST AIF2", + SUN8I_MOD_RST_CTL, + SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("RST ADC", SUN8I_MOD_RST_CTL, SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0), @@ -693,24 +809,54 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_AIF1_ADCDAT_CTRL, SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0), + SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0, + SUN8I_AIF2_ADCDAT_CTRL, + SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0, + sun8i_codec_aif_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1, + SUN8I_AIF2_ADCDAT_CTRL, + SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0), + /* AIF "ADC" Mono/Stereo Muxes */ SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0, &sun8i_aif1_ad0_stereo_mux_control), SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0, &sun8i_aif1_ad0_stereo_mux_control), + SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0, + &sun8i_aif2_adc_stereo_mux_control), + SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0, + &sun8i_aif2_adc_stereo_mux_control), + /* AIF "ADC" Mixers */ SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0, sun8i_aif1_ad0_mixer_controls), SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0, sun8i_aif1_ad0_mixer_controls), + SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0, + sun8i_aif2_adc_mixer_controls), + SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0, + sun8i_aif2_adc_mixer_controls), + + /* AIF "DAC" Input Muxes */ + SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0, + &sun8i_aif2_dac_mux_control), + SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0, + &sun8i_aif2_dac_mux_control), + /* AIF "DAC" Mono/Stereo Muxes */ SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0, &sun8i_aif1_da0_stereo_mux_control), SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0, &sun8i_aif1_da0_stereo_mux_control), + SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0, + &sun8i_aif2_dac_stereo_mux_control), + SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0, + &sun8i_aif2_dac_stereo_mux_control), + /* AIF "DAC" Inputs */ SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0, SUN8I_AIF1_DACDAT_CTRL, @@ -721,6 +867,15 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_AIF1_DACDAT_CTRL, SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), + SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0, + SUN8I_AIF2_DACDAT_CTRL, + SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0, + sun8i_codec_aif_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1, + SUN8I_AIF2_DACDAT_CTRL, + SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0), + /* ADC Inputs (connected to analog codec DAPM context) */ SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), @@ -750,6 +905,14 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "AIF1 DA0L", NULL, "RST AIF1" }, { "AIF1 DA0R", NULL, "RST AIF1" }, + { "CLK AIF2", NULL, "AIF2CLK" }, + { "CLK AIF2", NULL, "SYSCLK" }, + { "RST AIF2", NULL, "CLK AIF2" }, + { "AIF2 ADCL", NULL, "RST AIF2" }, + { "AIF2 ADCR", NULL, "RST AIF2" }, + { "AIF2 DACL", NULL, "RST AIF2" }, + { "AIF2 DACR", NULL, "RST AIF2" }, + { "CLK ADC", NULL, "SYSCLK" }, { "RST ADC", NULL, "CLK ADC" }, { "ADC", NULL, "RST ADC" }, @@ -766,6 +929,9 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" }, { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" }, + { "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" }, + { "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" }, + /* AIF "ADC" Mono/Stereo Mux Routes */ { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" }, { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" }, @@ -781,12 +947,45 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" }, { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" }, + { "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" }, + { "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" }, + { "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" }, + { "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" }, + { "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" }, + { "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" }, + + { "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" }, + { "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" }, + { "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" }, + { "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" }, + { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" }, + { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" }, + /* AIF "ADC" Mixer Routes */ { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" }, + { "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" }, { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" }, + { "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" }, { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" }, + { "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" }, { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" }, + { "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" }, + + { "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" }, + { "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" }, + { "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" }, + + { "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" }, + { "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" }, + { "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" }, + + /* AIF "DAC" Input Mux Routes */ + { "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" }, + { "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" }, + + { "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" }, + { "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" }, /* AIF "DAC" Mono/Stereo Mux Routes */ { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" }, @@ -803,15 +1002,31 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" }, { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" }, + { "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" }, + { "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" }, + { "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" }, + { "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" }, + { "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" }, + { "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" }, + + { "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" }, + { "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" }, + { "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" }, + { "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" }, + { "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" }, + { "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" }, + /* DAC Output Routes */ { "DACL", NULL, "DACL Mixer" }, { "DACR", NULL, "DACR Mixer" }, /* DAC Mixer Routes */ { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" }, + { "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" }, { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" }, { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" }, + { "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" }, { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" }, }; -- cgit v1.2.3 From 5a7f34ab0232bc50d39ac0627a470425227fed7d Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 14 Oct 2020 01:19:41 -0500 Subject: ASoC: sun8i-codec: Add the AIF3 DAI, widgets, and routes AIF3 has some differences from AIF1 and AIF2: - It supports one channel only - It supports master mode only - It is not directly connected to any of the mixers; instead all audio goes through a mux with AIF2. - It does not have its own clock dividers; instead it reuses AIF2 BCLK and LRCK. This means that when both AIF2 and AIF3 are active, they must use the same sample rate and total frame width. Since AIF2 and AIF3 are only used for codec2codec DAI links, constraints are not applicable here; the only thing we can do when the rates don't match is report an error. Make the necessary adjustments to support this AIF. Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20201014061941.4306-18-samuel@sholland.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 138 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 6a8232e07983..180442c62be1 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -34,11 +34,13 @@ #define SUN8I_MOD_CLK_ENA 0x010 #define SUN8I_MOD_CLK_ENA_AIF1 15 #define SUN8I_MOD_CLK_ENA_AIF2 14 +#define SUN8I_MOD_CLK_ENA_AIF3 13 #define SUN8I_MOD_CLK_ENA_ADC 3 #define SUN8I_MOD_CLK_ENA_DAC 2 #define SUN8I_MOD_RST_CTL 0x014 #define SUN8I_MOD_RST_CTL_AIF1 15 #define SUN8I_MOD_RST_CTL_AIF2 14 +#define SUN8I_MOD_RST_CTL_AIF3 13 #define SUN8I_MOD_RST_CTL_ADC 3 #define SUN8I_MOD_RST_CTL_DAC 2 #define SUN8I_SYS_SR_CTRL 0x018 @@ -89,6 +91,9 @@ #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R 10 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL 9 #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR 8 +#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1 (0x0 << 0) +#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2 (0x1 << 0) +#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK (0x2 << 0) #define SUN8I_AIF3_PATH_CTRL 0x0cc #define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC 10 #define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC 8 @@ -118,6 +123,7 @@ #define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK GENMASK(8, 6) #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK GENMASK(5, 4) #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK GENMASK(3, 2) +#define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK GENMASK(1, 0) #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000 @@ -138,10 +144,12 @@ enum { SUN8I_CODEC_AIF1, SUN8I_CODEC_AIF2, + SUN8I_CODEC_AIF3, SUN8I_CODEC_NAIFS }; struct sun8i_codec_aif { + unsigned int lrck_div_order; unsigned int sample_rate; unsigned int slots; unsigned int slot_width; @@ -163,6 +171,8 @@ struct sun8i_codec { int sysclk_refcnt; }; +static struct snd_soc_dai_driver sun8i_codec_dais[]; + static int sun8i_codec_runtime_resume(struct device *dev) { struct sun8i_codec *scodec = dev_get_drvdata(dev); @@ -268,9 +278,20 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), - BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD), - value << SUN8I_AIF_CLK_CTRL_MSTR_MOD); + if (dai->id == SUN8I_CODEC_AIF3) { + /* AIF3 only supports master mode. */ + if (value) + return -EINVAL; + + /* Use the AIF2 BCLK and LRCK for AIF3. */ + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK, + SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2); + } else { + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD), + value << SUN8I_AIF_CLK_CTRL_MSTR_MOD); + } /* DAI format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -295,9 +316,15 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), - SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK, - format << SUN8I_AIF_CLK_CTRL_DATA_FMT); + if (dai->id == SUN8I_CODEC_AIF3) { + /* AIF3 only supports DSP mode. */ + if (format != 3) + return -EINVAL; + } else { + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK, + format << SUN8I_AIF_CLK_CTRL_DATA_FMT); + } /* clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -472,6 +499,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, unsigned int slot_width = aif->slot_width ?: params_width(params); unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate); int bclk_div, lrck_div_order, ret, word_size; + u32 clk_reg; /* word size */ switch (params_width(params)) { @@ -500,7 +528,27 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, if (lrck_div_order < 0) return lrck_div_order; - regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + if (dai->id == SUN8I_CODEC_AIF2 || dai->id == SUN8I_CODEC_AIF3) { + /* AIF2 and AIF3 share AIF2's BCLK and LRCK generation circuitry. */ + int partner = (SUN8I_CODEC_AIF2 + SUN8I_CODEC_AIF3) - dai->id; + const struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner]; + const char *partner_name = sun8i_codec_dais[partner].name; + + if (partner_aif->open_streams && + (lrck_div_order != partner_aif->lrck_div_order || + sample_rate != partner_aif->sample_rate)) { + dev_err(dai->dev, + "%s sample and bit rates must match %s when both are used\n", + dai->name, partner_name); + return -EBUSY; + } + + clk_reg = SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF2); + } else { + clk_reg = SUN8I_AIF_CLK_CTRL(dai->id); + } + + regmap_update_bits(scodec->regmap, clk_reg, SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK, (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV); @@ -509,7 +557,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, if (bclk_div < 0) return bclk_div; - regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), + regmap_update_bits(scodec->regmap, clk_reg, SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK, bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV); @@ -535,6 +583,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, scodec->sysclk_refcnt++; scodec->sysclk_rate = sysclk_rate; + aif->lrck_div_order = lrck_div_order; aif->sample_rate = sample_rate; aif->open_streams |= BIT(substream->stream); @@ -553,6 +602,7 @@ static int sun8i_codec_hw_free(struct snd_pcm_substream *substream, clk_rate_exclusive_put(scodec->clk_module); scodec->sysclk_refcnt--; + aif->lrck_div_order = 0; aif->sample_rate = 0; done: @@ -619,6 +669,31 @@ static struct snd_soc_dai_driver sun8i_codec_dais[] = { .symmetric_channels = true, .symmetric_samplebits = true, }, + { + .name = "sun8i-codec-aif3", + .id = SUN8I_CODEC_AIF3, + .ops = &sun8i_codec_dai_ops, + /* capture capabilities */ + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SUN8I_CODEC_PCM_RATES, + .formats = SUN8I_CODEC_PCM_FORMATS, + .sig_bits = 24, + }, + /* playback capabilities */ + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SUN8I_CODEC_PCM_RATES, + .formats = SUN8I_CODEC_PCM_FORMATS, + }, + .symmetric_rates = true, + .symmetric_channels = true, + .symmetric_samplebits = true, + }, }; static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w, @@ -661,6 +736,19 @@ static const struct snd_kcontrol_new sun8i_aif2_adc_stereo_mux_control = SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route", sun8i_aif2_adc_stereo_mux_enum); +static const char *const sun8i_aif3_adc_mux_enum_values[] = { + "None", "AIF2 ADCL", "AIF2 ADCR" +}; + +static SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum, + SUN8I_AIF3_PATH_CTRL, + SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC, + sun8i_aif3_adc_mux_enum_values); + +static const struct snd_kcontrol_new sun8i_aif3_adc_mux_control = + SOC_DAPM_ENUM("AIF3 ADC Source Capture Route", + sun8i_aif3_adc_mux_enum); + static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = { SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC, @@ -770,6 +858,9 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("CLK AIF2", SUN8I_MOD_CLK_ENA, SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLK AIF3", + SUN8I_MOD_CLK_ENA, + SUN8I_MOD_CLK_ENA_AIF3, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CLK ADC", SUN8I_MOD_CLK_ENA, SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0), @@ -784,6 +875,9 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("RST AIF2", SUN8I_MOD_RST_CTL, SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RST AIF3", + SUN8I_MOD_RST_CTL, + SUN8I_MOD_RST_CTL_AIF3, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("RST ADC", SUN8I_MOD_RST_CTL, SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0), @@ -818,6 +912,11 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_AIF2_ADCDAT_CTRL, SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0), + SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0, + SND_SOC_NOPM, 0, 0, + sun8i_codec_aif_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* AIF "ADC" Mono/Stereo Muxes */ SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0, &sun8i_aif1_ad0_stereo_mux_control), @@ -829,6 +928,10 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0, &sun8i_aif2_adc_stereo_mux_control), + /* AIF "ADC" Output Muxes */ + SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0, + &sun8i_aif3_adc_mux_control), + /* AIF "ADC" Mixers */ SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0, sun8i_aif1_ad0_mixer_controls), @@ -876,6 +979,11 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_AIF2_DACDAT_CTRL, SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0), + SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0, + SND_SOC_NOPM, 0, 0, + sun8i_codec_aif_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* ADC Inputs (connected to analog codec DAPM context) */ SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), @@ -913,6 +1021,12 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "AIF2 DACL", NULL, "RST AIF2" }, { "AIF2 DACR", NULL, "RST AIF2" }, + { "CLK AIF3", NULL, "AIF1CLK" }, + { "CLK AIF3", NULL, "SYSCLK" }, + { "RST AIF3", NULL, "CLK AIF3" }, + { "AIF3 ADC", NULL, "RST AIF3" }, + { "AIF3 DAC", NULL, "RST AIF3" }, + { "CLK ADC", NULL, "SYSCLK" }, { "RST ADC", NULL, "CLK ADC" }, { "ADC", NULL, "RST ADC" }, @@ -932,6 +1046,8 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" }, { "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" }, + { "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" }, + /* AIF "ADC" Mono/Stereo Mux Routes */ { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" }, { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" }, @@ -961,6 +1077,10 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" }, { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" }, + /* AIF "ADC" Output Mux Routes */ + { "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" }, + { "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" }, + /* AIF "ADC" Mixer Routes */ { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" }, { "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" }, @@ -982,10 +1102,12 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { /* AIF "DAC" Input Mux Routes */ { "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" }, + { "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" }, { "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" }, { "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" }, { "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" }, + { "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" }, /* AIF "DAC" Mono/Stereo Mux Routes */ { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" }, -- cgit v1.2.3 From 2db5fa77cd7ea4bd18c7e1afb49417debc9f498a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Oct 2020 11:19:32 +0200 Subject: ASoC: wm8350: use semicolons rather than commas to separate statements Replace commas with semicolons. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1602407979-29038-2-git-send-email-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/codecs/wm8350.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index a6aa212fa0c8..15d42ce3b21d 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -218,7 +218,8 @@ static void wm8350_pga_work(struct work_struct *work) /* PGA volumes have 6 bits of resolution to ramp */ for (i = 0; i <= 63; i++) { - out1_complete = 1, out2_complete = 1; + out1_complete = 1; + out2_complete = 1; if (out1->ramp != WM8350_RAMP_NONE) out1_complete = wm8350_out1_ramp_step(wm8350_data); if (out2->ramp != WM8350_RAMP_NONE) -- cgit v1.2.3 From edc3f5b43a4446c84069e59df7e48663ec28579d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Oct 2020 11:19:34 +0200 Subject: ASoC: Intel: bytcr_rt5651: use semicolons rather than commas to separate statements Replace commas with semicolons. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Acked-by: Cezary Rojewski Link: https://lore.kernel.org/r/1602407979-29038-4-git-send-email-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 688b5e0a49e3..64d3fc4a3225 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -143,7 +143,7 @@ static int byt_rt5651_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, /* Configure the PLL before selecting it */ if (!(byt_rt5651_quirk & BYT_RT5651_MCLK_EN)) { - clk_id = RT5651_PLL1_S_BCLK1, + clk_id = RT5651_PLL1_S_BCLK1; clk_freq = rate * bclk_ratio; } else { clk_id = RT5651_PLL1_S_MCLK; -- cgit v1.2.3 From bed5ed644c741fd69a19a3cb811b5c1da1d50755 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Oct 2020 11:19:36 +0200 Subject: ASoC: SOF: Intel: hda: use semicolons rather than commas to separate statements Replace commas with semicolons. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/1602407979-29038-6-git-send-email-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 18ff1c2f5376..2b001151fe37 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -44,7 +44,7 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask); snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, - reset, reset), + reset, reset); /* poll with timeout to check if operation successful */ ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, -- cgit v1.2.3 From 40faaca03bf7d7ca1480677f0c8c543016cf426d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Oct 2020 11:19:37 +0200 Subject: ASoC: samsung: snow: use semicolons rather than commas to separate statements Replace commas with semicolons. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/1602407979-29038-7-git-send-email-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/samsung/snow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 07163f07c6d5..989af624dd11 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -189,7 +189,7 @@ static int snow_probe(struct platform_device *pdev) return PTR_ERR(priv->clk_i2s_bus); } } else { - link->codecs->dai_name = "HiFi", + link->codecs->dai_name = "HiFi"; link->cpus->of_node = of_parse_phandle(dev->of_node, "samsung,i2s-controller", 0); -- cgit v1.2.3 From 94fa760d01c21350261388f404e167d5cb752573 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Oct 2020 11:19:38 +0200 Subject: ASoC: madera: use semicolons rather than commas to separate statements Replace commas with semicolons. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1602407979-29038-8-git-send-email-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/codecs/madera.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 680f31a6493a..f4ed7e04673f 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -3019,11 +3019,11 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream, tar = 2 << MADERA_AIF1_RATE_SHIFT; break; case MADERA_CLK_ASYNCCLK_1: - reg = MADERA_ASYNC_SAMPLE_RATE_1, + reg = MADERA_ASYNC_SAMPLE_RATE_1; tar = 8 << MADERA_AIF1_RATE_SHIFT; break; case MADERA_CLK_ASYNCCLK_2: - reg = MADERA_ASYNC_SAMPLE_RATE_2, + reg = MADERA_ASYNC_SAMPLE_RATE_2; tar = 9 << MADERA_AIF1_RATE_SHIFT; break; default: -- cgit v1.2.3 From a1344daeab95b93dd1d19fcfbc7dbaf2a4735129 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Oct 2020 11:19:39 +0200 Subject: ASoC: dapm: use semicolons rather than commas to separate statements Replace commas with semicolons. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/1602407979-29038-9-git-send-email-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 980f2c330b87..6e764c793e49 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4764,7 +4764,7 @@ void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, if (component) { dapm->dev = component->dev; - dapm->idle_bias_off = !component->driver->idle_bias_on, + dapm->idle_bias_off = !component->driver->idle_bias_on; dapm->suspend_bias_off = component->driver->suspend_bias_off; } else { dapm->dev = card->dev; -- cgit v1.2.3 From 28564486866fa889b78264360022c94836fa8072 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Tue, 13 Oct 2020 15:17:32 +0300 Subject: ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver XCVR (Audio Transceiver) is a on-chip functional module found on i.MX8MP. It support HDMI2.1 eARC, HDMI1.4 ARC and SPDIF. Signed-off-by: Viorel Suman Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20201013121733.83684-2-viorel.suman@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 10 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_xcvr.c | 1359 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_xcvr.h | 266 +++++++++ 4 files changed, 1637 insertions(+) create mode 100644 sound/soc/fsl/fsl_xcvr.c create mode 100644 sound/soc/fsl/fsl_xcvr.h (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 3f76ff71ea47..d04b64d32dc1 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -95,6 +95,16 @@ config SND_SOC_FSL_EASRC destination sample rate. It is a new design module compare with the old ASRC. +config SND_SOC_FSL_XCVR + tristate "NXP Audio Transceiver (XCVR) module support" + select REGMAP_MMIO + select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y if you want to add Audio Transceiver (XCVR) support for NXP + iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC, + HDMI1.4 ARC and SPDIF. + config SND_SOC_FSL_UTILS tristate diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index b835eebf8825..1d2231f9cc47 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -25,6 +25,7 @@ snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o snd-soc-fsl-mqs-objs := fsl_mqs.o snd-soc-fsl-easrc-objs := fsl_easrc.o +snd-soc-fsl-xcvr-objs := fsl_xcvr.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o @@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o +obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o # MPC5200 Platform Support obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c new file mode 100644 index 000000000000..c055179e6d11 --- /dev/null +++ b/sound/soc/fsl/fsl_xcvr.c @@ -0,0 +1,1359 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2019 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_xcvr.h" +#include "imx-pcm.h" + +#define FSL_XCVR_CAPDS_SIZE 256 + +struct fsl_xcvr_soc_data { + const char *fw_name; +}; + +struct fsl_xcvr { + const struct fsl_xcvr_soc_data *soc_data; + struct platform_device *pdev; + struct regmap *regmap; + struct clk *ipg_clk; + struct clk *pll_ipg_clk; + struct clk *phy_clk; + struct clk *spba_clk; + struct reset_control *reset; + u8 streams; + u32 mode; + u32 arc_mode; + void __iomem *ram_addr; + struct snd_dmaengine_dai_dma_data dma_prms_rx; + struct snd_dmaengine_dai_dma_data dma_prms_tx; + struct snd_aes_iec958 rx_iec958; + struct snd_aes_iec958 tx_iec958; + u8 cap_ds[FSL_XCVR_CAPDS_SIZE]; +}; + +static const struct fsl_xcvr_pll_conf { + u8 mfi; /* min=0x18, max=0x38 */ + u32 mfn; /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */ + u32 mfd; /* unsigned int */ + u32 fout; /* Fout = Fref*(MFI + MFN/MFD), Fref is 24MHz */ +} fsl_xcvr_pll_cfg[] = { + { .mfi = 54, .mfn = 1, .mfd = 6, .fout = 1300000000, }, /* 1.3 GHz */ + { .mfi = 32, .mfn = 96, .mfd = 125, .fout = 786432000, }, /* 8000 Hz */ + { .mfi = 30, .mfn = 66, .mfd = 625, .fout = 722534400, }, /* 11025 Hz */ + { .mfi = 29, .mfn = 1, .mfd = 6, .fout = 700000000, }, /* 700 MHz */ +}; + +/* + * HDMI2.1 spec defines 6- and 12-channels layout for one bit audio + * stream. Todo: to check how this case can be considered below + */ +static const u32 fsl_xcvr_earc_channels[] = { 1, 2, 8, 16, 32, }; +static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_channels_constr = { + .count = ARRAY_SIZE(fsl_xcvr_earc_channels), + .list = fsl_xcvr_earc_channels, +}; + +static const u32 fsl_xcvr_earc_rates[] = { + 32000, 44100, 48000, 64000, 88200, 96000, + 128000, 176400, 192000, 256000, 352800, 384000, + 512000, 705600, 768000, 1024000, 1411200, 1536000, +}; +static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_rates_constr = { + .count = ARRAY_SIZE(fsl_xcvr_earc_rates), + .list = fsl_xcvr_earc_rates, +}; + +static const u32 fsl_xcvr_spdif_channels[] = { 2, }; +static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_channels_constr = { + .count = ARRAY_SIZE(fsl_xcvr_spdif_channels), + .list = fsl_xcvr_spdif_channels, +}; + +static const u32 fsl_xcvr_spdif_rates[] = { + 32000, 44100, 48000, 88200, 96000, 176400, 192000, +}; +static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_rates_constr = { + .count = ARRAY_SIZE(fsl_xcvr_spdif_rates), + .list = fsl_xcvr_spdif_rates, +}; + +static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + + xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]); + + return 0; +} + +static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + ucontrol->value.enumerated.item[0] = xcvr->arc_mode; + + return 0; +} + +static const u32 fsl_xcvr_phy_arc_cfg[] = { + FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN, FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN, +}; + +static const char * const fsl_xcvr_arc_mode[] = { "Single Ended", "Common", }; +static const struct soc_enum fsl_xcvr_arc_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_arc_mode), fsl_xcvr_arc_mode); +static struct snd_kcontrol_new fsl_xcvr_arc_mode_kctl = + SOC_ENUM_EXT("ARC Mode", fsl_xcvr_arc_mode_enum, + fsl_xcvr_arc_mode_get, fsl_xcvr_arc_mode_put); + +/* Capabilities data structure, bytes */ +static int fsl_xcvr_type_capds_bytes_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = FSL_XCVR_CAPDS_SIZE; + + return 0; +} + +static int fsl_xcvr_capds_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + memcpy(ucontrol->value.bytes.data, xcvr->cap_ds, FSL_XCVR_CAPDS_SIZE); + + return 0; +} + +static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + memcpy(xcvr->cap_ds, ucontrol->value.bytes.data, FSL_XCVR_CAPDS_SIZE); + + return 0; +} + +static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Capabilities Data Structure", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = fsl_xcvr_type_capds_bytes_info, + .get = fsl_xcvr_capds_get, + .put = fsl_xcvr_capds_put, +}; + +static int fsl_xcvr_activate_ctl(struct snd_soc_dai *dai, const char *name, + bool active) +{ + struct snd_soc_card *card = dai->component->card; + struct snd_kcontrol *kctl; + bool enabled; + + kctl = snd_soc_card_get_kcontrol(card, name); + if (kctl == NULL) + return -ENOENT; + + enabled = ((kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_WRITE) != 0); + if (active == enabled) + return 0; /* nothing to do */ + + if (active) + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_WRITE; + else + kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE; + + snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); + + return 1; +} + +static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + struct snd_soc_card *card = dai->component->card; + struct snd_soc_pcm_runtime *rtd; + + xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); + + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_ARC)); + fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_EARC)); + /* Allow playback for SPDIF only */ + rtd = snd_soc_get_pcm_runtime(card, card->dai_link); + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = + (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0); + return 0; +} + +static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + ucontrol->value.enumerated.item[0] = xcvr->mode; + + return 0; +} + +static const char * const fsl_xcvr_mode[] = { "SPDIF", "ARC RX", "eARC", }; +static const struct soc_enum fsl_xcvr_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_mode), fsl_xcvr_mode); +static struct snd_kcontrol_new fsl_xcvr_mode_kctl = + SOC_ENUM_EXT("XCVR Mode", fsl_xcvr_mode_enum, + fsl_xcvr_mode_get, fsl_xcvr_mode_put); + +/** phy: true => phy, false => pll */ +static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy) +{ + struct device *dev = &xcvr->pdev->dev; + u32 val, idx, tidx; + int ret; + + idx = BIT(phy ? 26 : 24); + tidx = BIT(phy ? 27 : 25); + + regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF); + regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg); + regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_WDATA, data); + regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx); + + ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val, + (val & idx) != ((val & tidx) >> 1), + 10, 10000); + if (ret) + dev_err(dev, "AI timeout: failed to set %s reg 0x%02x=0x%08x\n", + phy ? "PHY" : "PLL", reg, data); + return ret; +} + +static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) +{ + struct device *dev = &xcvr->pdev->dev; + u32 i, div = 0, log2; + int ret; + + for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) { + if (fsl_xcvr_pll_cfg[i].fout % freq == 0) { + div = fsl_xcvr_pll_cfg[i].fout / freq; + break; + } + } + + if (!div || i >= ARRAY_SIZE(fsl_xcvr_pll_cfg)) + return -EINVAL; + + log2 = ilog2(div); + + /* Release AI interface from reset */ + ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, + FSL_XCVR_PHY_AI_CTRL_AI_RESETN); + if (ret < 0) { + dev_err(dev, "Error while setting IER0: %d\n", ret); + return ret; + } + + /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, + FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); + + /* PLL: CTRL0: DIV_INTEGER */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); + /* PLL: NUMERATOR: MFN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); + /* PLL: DENOMINATOR: MFD */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); + /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); + udelay(25); + /* PLL: CTRL0: Clear Hold Ring Off */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, + FSL_XCVR_PLL_CTRL0_HROFF, 0); + udelay(100); + if (tx) { /* TX is enabled for SPDIF only */ + /* PLL: POSTDIV: PDIV0 */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, + FSL_XCVR_PLL_PDIVx(log2, 0), 0); + /* PLL: CTRL_SET: CLKMUX0_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_CM0_EN, 0); + } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */ + /* PLL: POSTDIV: PDIV1 */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, + FSL_XCVR_PLL_PDIVx(log2, 1), 0); + /* PLL: CTRL_SET: CLKMUX1_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_CM1_EN, 0); + } else { /* SPDIF / ARC RX */ + /* PLL: POSTDIV: PDIV2 */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, + FSL_XCVR_PLL_PDIVx(log2, 2), 0); + /* PLL: CTRL_SET: CLKMUX2_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_CM2_EN, 0); + } + + if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */ + /* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET, + FSL_XCVR_PHY_CTRL_TSDIFF_OE | + FSL_XCVR_PHY_CTRL_PHY_EN, 1); + /* PHY: CTRL2_SET: EARC_TX_MODE */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET, + FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1); + } else if (!tx) { /* SPDIF / ARC RX mode */ + if (xcvr->mode == FSL_XCVR_MODE_SPDIF) + /* PHY: CTRL_SET: SPDIF_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET, + FSL_XCVR_PHY_CTRL_SPDIF_EN, 1); + else /* PHY: CTRL_SET: ARC RX setup */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET, + FSL_XCVR_PHY_CTRL_PHY_EN | + FSL_XCVR_PHY_CTRL_RX_CM_EN | + fsl_xcvr_phy_arc_cfg[xcvr->arc_mode], 1); + } + + dev_dbg(dev, "PLL Fexp: %u, Fout: %u, mfi: %u, mfn: %u, mfd: %d, div: %u, pdiv0: %u\n", + freq, fsl_xcvr_pll_cfg[i].fout, fsl_xcvr_pll_cfg[i].mfi, + fsl_xcvr_pll_cfg[i].mfn, fsl_xcvr_pll_cfg[i].mfd, div, log2); + return 0; +} + +static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq) +{ + struct device *dev = &xcvr->pdev->dev; + int ret; + + clk_disable_unprepare(xcvr->phy_clk); + ret = clk_set_rate(xcvr->phy_clk, freq); + if (ret < 0) { + dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret); + return ret; + } + ret = clk_prepare_enable(xcvr->phy_clk); + if (ret) { + dev_err(dev, "failed to start PHY clock: %d\n", ret); + return ret; + } + + /* Release AI interface from reset */ + ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, + FSL_XCVR_PHY_AI_CTRL_AI_RESETN); + if (ret < 0) { + dev_err(dev, "Error while setting IER0: %d\n", ret); + return ret; + } + + if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */ + /* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET, + FSL_XCVR_PHY_CTRL_TSDIFF_OE | + FSL_XCVR_PHY_CTRL_PHY_EN, 1); + /* PHY: CTRL2_SET: EARC_TX_MODE */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET, + FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1); + } else { /* SPDIF mode */ + /* PHY: CTRL_SET: TX_CLK_AUD_SS | SPDIF_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET, + FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS | + FSL_XCVR_PHY_CTRL_SPDIF_EN, 1); + } + + dev_dbg(dev, "PLL Fexp: %u\n", freq); + + return 0; +} + +#define FSL_XCVR_SPDIF_RX_FREQ 175000000 +static int fsl_xcvr_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + u32 m_ctl = 0, v_ctl = 0; + u32 r = substream->runtime->rate, ch = substream->runtime->channels; + u32 fout = 32 * r * ch * 10 * 2; + int ret = 0; + + switch (xcvr->mode) { + case FSL_XCVR_MODE_SPDIF: + case FSL_XCVR_MODE_ARC: + if (tx) { + ret = fsl_xcvr_en_aud_pll(xcvr, fout); + if (ret < 0) { + dev_err(dai->dev, "Failed to set TX freq %u: %d\n", + fout, ret); + return ret; + } + + ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET, + FSL_XCVR_TX_DPTH_CTRL_FRM_FMT); + if (ret < 0) { + dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret); + return ret; + } + + /** + * set SPDIF MODE - this flag is used to gate + * SPDIF output, useless for SPDIF RX + */ + m_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE; + v_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE; + } else { + /** + * Clear RX FIFO, flip RX FIFO bits, + * disable eARC related HW mode detects + */ + ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET, + FSL_XCVR_RX_DPTH_CTRL_STORE_FMT | + FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO | + FSL_XCVR_RX_DPTH_CTRL_COMP | + FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL); + if (ret < 0) { + dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret); + return ret; + } + + ret = fsl_xcvr_en_phy_pll(xcvr, FSL_XCVR_SPDIF_RX_FREQ, tx); + if (ret < 0) { + dev_err(dai->dev, "Failed to set RX freq %u: %d\n", + FSL_XCVR_SPDIF_RX_FREQ, ret); + return ret; + } + } + break; + case FSL_XCVR_MODE_EARC: + if (!tx) { + /** Clear RX FIFO, flip RX FIFO bits */ + ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET, + FSL_XCVR_RX_DPTH_CTRL_STORE_FMT | + FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO); + if (ret < 0) { + dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret); + return ret; + } + + /** Enable eARC related HW mode detects */ + ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_CLR, + FSL_XCVR_RX_DPTH_CTRL_COMP | + FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL); + if (ret < 0) { + dev_err(dai->dev, "Failed to clr TX_DPTH: %d\n", ret); + return ret; + } + } + + /* clear CMDC RESET */ + m_ctl |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx); + /* set TX_RX_MODE */ + m_ctl |= FSL_XCVR_EXT_CTRL_TX_RX_MODE; + v_ctl |= (tx ? FSL_XCVR_EXT_CTRL_TX_RX_MODE : 0); + break; + } + + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, + FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); + if (ret < 0) { + dev_err(dai->dev, "Error while setting IER0: %d\n", ret); + return ret; + } + + /* clear DPATH RESET */ + m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl); + if (ret < 0) { + dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret); + return ret; + } + + return 0; +} + +static int fsl_xcvr_constr(const struct snd_pcm_substream *substream, + const struct snd_pcm_hw_constraint_list *channels, + const struct snd_pcm_hw_constraint_list *rates) +{ + struct snd_pcm_runtime *rt = substream->runtime; + int ret; + + ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + channels); + if (ret < 0) + return ret; + + ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE, + rates); + if (ret < 0) + return ret; + + return 0; +} + +static int fsl_xcvr_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + int ret = 0; + + if (xcvr->streams & BIT(substream->stream)) { + dev_err(dai->dev, "%sX busy\n", tx ? "T" : "R"); + return -EBUSY; + } + + switch (xcvr->mode) { + case FSL_XCVR_MODE_SPDIF: + case FSL_XCVR_MODE_ARC: + ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr, + &fsl_xcvr_spdif_rates_constr); + break; + case FSL_XCVR_MODE_EARC: + ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr, + &fsl_xcvr_earc_rates_constr); + break; + } + if (ret < 0) + return ret; + + xcvr->streams |= BIT(substream->stream); + + /* Disable XCVR controls if there is stream started */ + fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false); + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false); + fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false); + + return 0; +} + +static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + u32 mask = 0, val = 0; + int ret; + + xcvr->streams &= ~BIT(substream->stream); + + /* Enable XCVR controls if there is no stream started */ + if (!xcvr->streams) { + fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true); + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_ARC)); + fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_EARC)); + + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, + FSL_XCVR_IRQ_EARC_ALL, 0); + if (ret < 0) { + dev_err(dai->dev, "Failed to set IER0: %d\n", ret); + return; + } + + /* clear SPDIF MODE */ + if (xcvr->mode == FSL_XCVR_MODE_SPDIF) + mask |= FSL_XCVR_EXT_CTRL_SPDIF_MODE; + } + + if (xcvr->mode == FSL_XCVR_MODE_EARC) { + /* set CMDC RESET */ + mask |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx); + val |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx); + } + + /* set DPATH RESET */ + mask |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); + val |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); + + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val); + if (ret < 0) { + dev_err(dai->dev, "Err setting DPATH RESET: %d\n", ret); + return; + } +} + +static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (tx) { + switch (xcvr->mode) { + case FSL_XCVR_MODE_EARC: + /* set isr_cmdc_tx_en, w1c */ + ret = regmap_write(xcvr->regmap, + FSL_XCVR_ISR_SET, + FSL_XCVR_ISR_CMDC_TX_EN); + if (ret < 0) { + dev_err(dai->dev, "err updating isr %d\n", ret); + return ret; + } + fallthrough; + case FSL_XCVR_MODE_SPDIF: + ret = regmap_write(xcvr->regmap, + FSL_XCVR_TX_DPTH_CTRL_SET, + FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); + if (ret < 0) { + dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret); + return ret; + } + break; + } + } + + /* enable DMA RD/WR */ + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0); + if (ret < 0) { + dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); + return ret; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /* disable DMA RD/WR */ + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_DMA_DIS(tx), + FSL_XCVR_EXT_CTRL_DMA_DIS(tx)); + if (ret < 0) { + dev_err(dai->dev, "Failed to disable DMA: %d\n", ret); + return ret; + } + + if (tx) { + switch (xcvr->mode) { + case FSL_XCVR_MODE_SPDIF: + ret = regmap_write(xcvr->regmap, + FSL_XCVR_TX_DPTH_CTRL_CLR, + FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); + if (ret < 0) { + dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret); + return ret; + } + fallthrough; + case FSL_XCVR_MODE_EARC: + /* clear ISR_CMDC_TX_EN, W1C */ + ret = regmap_write(xcvr->regmap, + FSL_XCVR_ISR_CLR, + FSL_XCVR_ISR_CMDC_TX_EN); + if (ret < 0) { + dev_err(dai->dev, + "Err updating ISR %d\n", ret); + return ret; + } + break; + } + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) +{ + struct device *dev = &xcvr->pdev->dev; + const struct firmware *fw; + int ret = 0, rem, off, out, page = 0, size = FSL_XCVR_REG_OFFSET; + u32 mask, val; + + ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev); + if (ret) { + dev_err(dev, "failed to request firmware.\n"); + return ret; + } + + rem = fw->size; + + /* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */ + if (rem > 16384) { + dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem); + return -ENOMEM; + } + + for (page = 0; page < 10; page++) { + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_PAGE_MASK, + FSL_XCVR_EXT_CTRL_PAGE(page)); + if (ret < 0) { + dev_err(dev, "FW: failed to set page %d, err=%d\n", + page, ret); + goto err_firmware; + } + + off = page * size; + out = min(rem, size); + /* IPG clock is assumed to be running, otherwise it will hang */ + if (out > 0) { + /* write firmware into code memory */ + memcpy_toio(xcvr->ram_addr, fw->data + off, out); + rem -= out; + if (rem == 0) { + /* last part of firmware written */ + /* clean remaining part of code memory page */ + memset_io(xcvr->ram_addr + out, 0, size - out); + } + } else { + /* clean current page, including data memory */ + memset_io(xcvr->ram_addr, 0, size); + } + }; + +err_firmware: + release_firmware(fw); + if (ret < 0) + return ret; + + /* configure watermarks */ + mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK; + val = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX); + val |= FSL_XCVR_EXT_CTRL_TX_FWM(FSL_XCVR_FIFO_WMK_TX); + /* disable DMA RD/WR */ + mask |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS; + val |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS; + /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */ + mask |= FSL_XCVR_EXT_CTRL_PAGE_MASK; + val |= FSL_XCVR_EXT_CTRL_PAGE(8); + + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val); + if (ret < 0) { + dev_err(dev, "Failed to set watermarks: %d\n", ret); + return ret; + } + + /* Store Capabilities Data Structure into Data RAM */ + memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds, + FSL_XCVR_CAPDS_SIZE); + return 0; +} + +static int fsl_xcvr_type_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int fsl_xcvr_type_iec958_bytes_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof_field(struct snd_aes_iec958, status); + + return 0; +} + +static int fsl_xcvr_rx_cs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + memcpy(ucontrol->value.iec958.status, xcvr->rx_iec958.status, 24); + + return 0; +} + +static int fsl_xcvr_tx_cs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + memcpy(ucontrol->value.iec958.status, xcvr->tx_iec958.status, 24); + + return 0; +} + +static int fsl_xcvr_tx_cs_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + memcpy(xcvr->tx_iec958.status, ucontrol->value.iec958.status, 24); + + return 0; +} + +static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = { + /* Channel status controller */ + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = fsl_xcvr_type_iec958_info, + .get = fsl_xcvr_rx_cs_get, + }, + /* Capture channel status, bytes */ + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Capture Channel Status", + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = fsl_xcvr_type_iec958_bytes_info, + .get = fsl_xcvr_rx_cs_get, + }, +}; + +static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = { + /* Channel status controller */ + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = fsl_xcvr_type_iec958_info, + .get = fsl_xcvr_tx_cs_get, + .put = fsl_xcvr_tx_cs_put, + }, + /* Playback channel status, bytes */ + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Playback Channel Status", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = fsl_xcvr_type_iec958_bytes_info, + .get = fsl_xcvr_tx_cs_get, + .put = fsl_xcvr_tx_cs_put, + }, +}; + +static struct snd_soc_dai_ops fsl_xcvr_dai_ops = { + .prepare = fsl_xcvr_prepare, + .startup = fsl_xcvr_startup, + .shutdown = fsl_xcvr_shutdown, + .trigger = fsl_xcvr_trigger, +}; + +static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) +{ + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &xcvr->dma_prms_tx, &xcvr->dma_prms_rx); + snd_soc_dai_set_drvdata(dai, xcvr); + + snd_soc_add_dai_controls(dai, &fsl_xcvr_mode_kctl, 1); + snd_soc_add_dai_controls(dai, &fsl_xcvr_arc_mode_kctl, 1); + snd_soc_add_dai_controls(dai, &fsl_xcvr_earc_capds_kctl, 1); + snd_soc_add_dai_controls(dai, fsl_xcvr_tx_ctls, + ARRAY_SIZE(fsl_xcvr_tx_ctls)); + snd_soc_add_dai_controls(dai, fsl_xcvr_rx_ctls, + ARRAY_SIZE(fsl_xcvr_rx_ctls)); + return 0; +} + +static struct snd_soc_dai_driver fsl_xcvr_dai = { + .probe = fsl_xcvr_dai_probe, + .ops = &fsl_xcvr_dai_ops, + .playback = { + .stream_name = "CPU-Playback", + .channels_min = 1, + .channels_max = 32, + .rate_min = 32000, + .rate_max = 1536000, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, + }, + .capture = { + .stream_name = "CPU-Capture", + .channels_min = 1, + .channels_max = 32, + .rate_min = 32000, + .rate_max = 1536000, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, + }, +}; + +static const struct snd_soc_component_driver fsl_xcvr_comp = { + .name = "fsl-xcvr-dai", +}; + +static const struct reg_default fsl_xcvr_reg_defaults[] = { + { FSL_XCVR_VERSION, 0x00000000 }, + { FSL_XCVR_EXT_CTRL, 0xF8204040 }, + { FSL_XCVR_EXT_STATUS, 0x00000000 }, + { FSL_XCVR_EXT_IER0, 0x00000000 }, + { FSL_XCVR_EXT_IER1, 0x00000000 }, + { FSL_XCVR_EXT_ISR, 0x00000000 }, + { FSL_XCVR_EXT_ISR_SET, 0x00000000 }, + { FSL_XCVR_EXT_ISR_CLR, 0x00000000 }, + { FSL_XCVR_EXT_ISR_TOG, 0x00000000 }, + { FSL_XCVR_IER, 0x00000000 }, + { FSL_XCVR_ISR, 0x00000000 }, + { FSL_XCVR_ISR_SET, 0x00000000 }, + { FSL_XCVR_ISR_CLR, 0x00000000 }, + { FSL_XCVR_ISR_TOG, 0x00000000 }, + { FSL_XCVR_RX_DPTH_CTRL, 0x00002C89 }, + { FSL_XCVR_RX_DPTH_CTRL_SET, 0x00002C89 }, + { FSL_XCVR_RX_DPTH_CTRL_CLR, 0x00002C89 }, + { FSL_XCVR_RX_DPTH_CTRL_TOG, 0x00002C89 }, + { FSL_XCVR_TX_DPTH_CTRL, 0x00000000 }, + { FSL_XCVR_TX_DPTH_CTRL_SET, 0x00000000 }, + { FSL_XCVR_TX_DPTH_CTRL_CLR, 0x00000000 }, + { FSL_XCVR_TX_DPTH_CTRL_TOG, 0x00000000 }, + { FSL_XCVR_TX_CS_DATA_0, 0x00000000 }, + { FSL_XCVR_TX_CS_DATA_1, 0x00000000 }, + { FSL_XCVR_TX_CS_DATA_2, 0x00000000 }, + { FSL_XCVR_TX_CS_DATA_3, 0x00000000 }, + { FSL_XCVR_TX_CS_DATA_4, 0x00000000 }, + { FSL_XCVR_TX_CS_DATA_5, 0x00000000 }, + { FSL_XCVR_DEBUG_REG_0, 0x00000000 }, + { FSL_XCVR_DEBUG_REG_1, 0x00000000 }, +}; + +static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case FSL_XCVR_VERSION: + case FSL_XCVR_EXT_CTRL: + case FSL_XCVR_EXT_STATUS: + case FSL_XCVR_EXT_IER0: + case FSL_XCVR_EXT_IER1: + case FSL_XCVR_EXT_ISR: + case FSL_XCVR_EXT_ISR_SET: + case FSL_XCVR_EXT_ISR_CLR: + case FSL_XCVR_EXT_ISR_TOG: + case FSL_XCVR_IER: + case FSL_XCVR_ISR: + case FSL_XCVR_ISR_SET: + case FSL_XCVR_ISR_CLR: + case FSL_XCVR_ISR_TOG: + case FSL_XCVR_PHY_AI_CTRL: + case FSL_XCVR_PHY_AI_CTRL_SET: + case FSL_XCVR_PHY_AI_CTRL_CLR: + case FSL_XCVR_PHY_AI_CTRL_TOG: + case FSL_XCVR_PHY_AI_RDATA: + case FSL_XCVR_CLK_CTRL: + case FSL_XCVR_RX_DPTH_CTRL: + case FSL_XCVR_RX_DPTH_CTRL_SET: + case FSL_XCVR_RX_DPTH_CTRL_CLR: + case FSL_XCVR_RX_DPTH_CTRL_TOG: + case FSL_XCVR_TX_DPTH_CTRL: + case FSL_XCVR_TX_DPTH_CTRL_SET: + case FSL_XCVR_TX_DPTH_CTRL_CLR: + case FSL_XCVR_TX_DPTH_CTRL_TOG: + case FSL_XCVR_TX_CS_DATA_0: + case FSL_XCVR_TX_CS_DATA_1: + case FSL_XCVR_TX_CS_DATA_2: + case FSL_XCVR_TX_CS_DATA_3: + case FSL_XCVR_TX_CS_DATA_4: + case FSL_XCVR_TX_CS_DATA_5: + case FSL_XCVR_DEBUG_REG_0: + case FSL_XCVR_DEBUG_REG_1: + return true; + default: + return false; + } +} + +static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case FSL_XCVR_EXT_CTRL: + case FSL_XCVR_EXT_IER0: + case FSL_XCVR_EXT_IER1: + case FSL_XCVR_EXT_ISR: + case FSL_XCVR_EXT_ISR_SET: + case FSL_XCVR_EXT_ISR_CLR: + case FSL_XCVR_EXT_ISR_TOG: + case FSL_XCVR_IER: + case FSL_XCVR_ISR_SET: + case FSL_XCVR_ISR_CLR: + case FSL_XCVR_ISR_TOG: + case FSL_XCVR_PHY_AI_CTRL: + case FSL_XCVR_PHY_AI_CTRL_SET: + case FSL_XCVR_PHY_AI_CTRL_CLR: + case FSL_XCVR_PHY_AI_CTRL_TOG: + case FSL_XCVR_PHY_AI_WDATA: + case FSL_XCVR_CLK_CTRL: + case FSL_XCVR_RX_DPTH_CTRL: + case FSL_XCVR_RX_DPTH_CTRL_SET: + case FSL_XCVR_RX_DPTH_CTRL_CLR: + case FSL_XCVR_RX_DPTH_CTRL_TOG: + case FSL_XCVR_TX_DPTH_CTRL_SET: + case FSL_XCVR_TX_DPTH_CTRL_CLR: + case FSL_XCVR_TX_DPTH_CTRL_TOG: + case FSL_XCVR_TX_CS_DATA_0: + case FSL_XCVR_TX_CS_DATA_1: + case FSL_XCVR_TX_CS_DATA_2: + case FSL_XCVR_TX_CS_DATA_3: + case FSL_XCVR_TX_CS_DATA_4: + case FSL_XCVR_TX_CS_DATA_5: + return true; + default: + return false; + } +} + +static bool fsl_xcvr_volatile_reg(struct device *dev, unsigned int reg) +{ + return fsl_xcvr_readable_reg(dev, reg); +} + +static const struct regmap_config fsl_xcvr_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = FSL_XCVR_MAX_REG, + .reg_defaults = fsl_xcvr_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(fsl_xcvr_reg_defaults), + .readable_reg = fsl_xcvr_readable_reg, + .volatile_reg = fsl_xcvr_volatile_reg, + .writeable_reg = fsl_xcvr_writeable_reg, + .cache_type = REGCACHE_FLAT, +}; + +static irqreturn_t irq0_isr(int irq, void *devid) +{ + struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid; + struct device *dev = &xcvr->pdev->dev; + struct regmap *regmap = xcvr->regmap; + void __iomem *reg_ctrl, *reg_buff; + u32 isr, isr_clr = 0, val, i; + + regmap_read(regmap, FSL_XCVR_EXT_ISR, &isr); + + if (isr & FSL_XCVR_IRQ_NEW_CS) { + dev_dbg(dev, "Received new CS block\n"); + isr_clr |= FSL_XCVR_IRQ_NEW_CS; + /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */ + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_PAGE_MASK, + FSL_XCVR_EXT_CTRL_PAGE(8)); + + /* Find updated CS buffer */ + reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_0; + reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_0; + memcpy_fromio(&val, reg_ctrl, sizeof(val)); + if (!val) { + reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_1; + reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_1; + memcpy_fromio(&val, reg_ctrl, sizeof(val)); + } + + if (val) { + /* copy CS buffer */ + memcpy_fromio(&xcvr->rx_iec958.status, reg_buff, + sizeof(xcvr->rx_iec958.status)); + for (i = 0; i < 6; i++) { + val = *(u32 *)(xcvr->rx_iec958.status + i*4); + *(u32 *)(xcvr->rx_iec958.status + i*4) = + bitrev32(val); + } + /* clear CS control register */ + memset_io(reg_ctrl, 0, sizeof(val)); + } + } + if (isr & FSL_XCVR_IRQ_NEW_UD) { + dev_dbg(dev, "Received new UD block\n"); + isr_clr |= FSL_XCVR_IRQ_NEW_UD; + } + if (isr & FSL_XCVR_IRQ_MUTE) { + dev_dbg(dev, "HW mute bit detected\n"); + isr_clr |= FSL_XCVR_IRQ_MUTE; + } + if (isr & FSL_XCVR_IRQ_FIFO_UOFL_ERR) { + dev_dbg(dev, "RX/TX FIFO full/empty\n"); + isr_clr |= FSL_XCVR_IRQ_FIFO_UOFL_ERR; + } + if (isr & FSL_XCVR_IRQ_ARC_MODE) { + dev_dbg(dev, "CMDC SM falls out of eARC mode\n"); + isr_clr |= FSL_XCVR_IRQ_ARC_MODE; + } + if (isr & FSL_XCVR_IRQ_DMA_RD_REQ) { + dev_dbg(dev, "DMA read request\n"); + isr_clr |= FSL_XCVR_IRQ_DMA_RD_REQ; + } + if (isr & FSL_XCVR_IRQ_DMA_WR_REQ) { + dev_dbg(dev, "DMA write request\n"); + isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ; + } + + if (isr_clr) { + regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = { + .fw_name = "imx/xcvr/xcvr-imx8mp.bin", +}; + +static const struct of_device_id fsl_xcvr_dt_ids[] = { + { .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids); + +static int fsl_xcvr_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id; + struct fsl_xcvr *xcvr; + struct resource *ram_res, *regs_res, *rx_res, *tx_res; + void __iomem *regs; + int ret, irq; + + of_id = of_match_device(fsl_xcvr_dt_ids, dev); + if (!of_id) + return -EINVAL; + + xcvr = devm_kzalloc(dev, sizeof(*xcvr), GFP_KERNEL); + if (!xcvr) + return -ENOMEM; + + xcvr->pdev = pdev; + xcvr->soc_data = of_device_get_match_data(&pdev->dev); + + xcvr->ipg_clk = devm_clk_get(dev, "ipg"); + if (IS_ERR(xcvr->ipg_clk)) { + dev_err(dev, "failed to get ipg clock\n"); + return PTR_ERR(xcvr->ipg_clk); + } + + xcvr->phy_clk = devm_clk_get(dev, "phy"); + if (IS_ERR(xcvr->phy_clk)) { + dev_err(dev, "failed to get phy clock\n"); + return PTR_ERR(xcvr->phy_clk); + } + + xcvr->spba_clk = devm_clk_get(dev, "spba"); + if (IS_ERR(xcvr->spba_clk)) { + dev_err(dev, "failed to get spba clock\n"); + return PTR_ERR(xcvr->spba_clk); + } + + xcvr->pll_ipg_clk = devm_clk_get(dev, "pll_ipg"); + if (IS_ERR(xcvr->pll_ipg_clk)) { + dev_err(dev, "failed to get pll_ipg clock\n"); + return PTR_ERR(xcvr->pll_ipg_clk); + } + + ram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ram"); + xcvr->ram_addr = devm_ioremap_resource(dev, ram_res); + if (IS_ERR(xcvr->ram_addr)) + return PTR_ERR(xcvr->ram_addr); + + regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + regs = devm_ioremap_resource(dev, regs_res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + xcvr->regmap = devm_regmap_init_mmio_clk(dev, NULL, regs, + &fsl_xcvr_regmap_cfg); + if (IS_ERR(xcvr->regmap)) { + dev_err(dev, "failed to init XCVR regmap: %ld\n", + PTR_ERR(xcvr->regmap)); + return PTR_ERR(xcvr->regmap); + } + + xcvr->reset = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(xcvr->reset)) { + dev_err(dev, "failed to get XCVR reset control\n"); + return PTR_ERR(xcvr->reset); + } + + /* get IRQs */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq[0]: %d\n", irq); + return irq; + } + + ret = devm_request_irq(dev, irq, irq0_isr, 0, pdev->name, xcvr); + if (ret) { + dev_err(dev, "failed to claim IRQ0: %i\n", ret); + return ret; + } + + rx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rxfifo"); + tx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "txfifo"); + xcvr->dma_prms_rx.chan_name = "rx"; + xcvr->dma_prms_tx.chan_name = "tx"; + xcvr->dma_prms_rx.addr = rx_res->start; + xcvr->dma_prms_tx.addr = tx_res->start; + xcvr->dma_prms_rx.maxburst = FSL_XCVR_MAXBURST_RX; + xcvr->dma_prms_tx.maxburst = FSL_XCVR_MAXBURST_TX; + + platform_set_drvdata(pdev, xcvr); + pm_runtime_enable(dev); + regcache_cache_only(xcvr->regmap, true); + + ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp, + &fsl_xcvr_dai, 1); + if (ret) { + dev_err(dev, "failed to register component %s\n", + fsl_xcvr_comp.name); + return ret; + } + + ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); + if (ret) + dev_err(dev, "failed to pcm register\n"); + + return ret; +} + +static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) +{ + struct fsl_xcvr *xcvr = dev_get_drvdata(dev); + int ret; + + /* Assert M0+ reset */ + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_CORE_RESET, + FSL_XCVR_EXT_CTRL_CORE_RESET); + if (ret < 0) + dev_err(dev, "Failed to assert M0+ core: %d\n", ret); + + ret = reset_control_assert(xcvr->reset); + if (ret < 0) + dev_err(dev, "Failed to assert M0+ reset: %d\n", ret); + + regcache_cache_only(xcvr->regmap, true); + + clk_disable_unprepare(xcvr->spba_clk); + clk_disable_unprepare(xcvr->phy_clk); + clk_disable_unprepare(xcvr->pll_ipg_clk); + clk_disable_unprepare(xcvr->ipg_clk); + + return 0; +} + +static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev) +{ + struct fsl_xcvr *xcvr = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(xcvr->ipg_clk); + if (ret) { + dev_err(dev, "failed to start IPG clock.\n"); + return ret; + } + + ret = clk_prepare_enable(xcvr->pll_ipg_clk); + if (ret) { + dev_err(dev, "failed to start PLL IPG clock.\n"); + goto stop_ipg_clk; + } + + ret = clk_prepare_enable(xcvr->phy_clk); + if (ret) { + dev_err(dev, "failed to start PHY clock: %d\n", ret); + goto stop_pll_ipg_clk; + } + + ret = clk_prepare_enable(xcvr->spba_clk); + if (ret) { + dev_err(dev, "failed to start SPBA clock.\n"); + goto stop_phy_clk; + } + + regcache_cache_only(xcvr->regmap, false); + regcache_mark_dirty(xcvr->regmap); + ret = regcache_sync(xcvr->regmap); + + if (ret) { + dev_err(dev, "failed to sync regcache.\n"); + goto stop_spba_clk; + } + + ret = reset_control_deassert(xcvr->reset); + if (ret) { + dev_err(dev, "failed to deassert M0+ reset.\n"); + goto stop_spba_clk; + } + + ret = fsl_xcvr_load_firmware(xcvr); + if (ret) { + dev_err(dev, "failed to load firmware.\n"); + goto stop_spba_clk; + } + + /* Release M0+ reset */ + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_CORE_RESET, 0); + if (ret < 0) { + dev_err(dev, "M0+ core release failed: %d\n", ret); + goto stop_spba_clk; + } + + /* Let M0+ core complete firmware initialization */ + msleep(50); + + return 0; + +stop_spba_clk: + clk_disable_unprepare(xcvr->spba_clk); +stop_phy_clk: + clk_disable_unprepare(xcvr->phy_clk); +stop_pll_ipg_clk: + clk_disable_unprepare(xcvr->pll_ipg_clk); +stop_ipg_clk: + clk_disable_unprepare(xcvr->ipg_clk); + + return ret; +} + +static const struct dev_pm_ops fsl_xcvr_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend, + fsl_xcvr_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver fsl_xcvr_driver = { + .probe = fsl_xcvr_probe, + .driver = { + .name = "fsl,imx8mp-audio-xcvr", + .pm = &fsl_xcvr_pm_ops, + .of_match_table = fsl_xcvr_dt_ids, + }, +}; +module_platform_driver(fsl_xcvr_driver); + +MODULE_AUTHOR("Viorel Suman "); +MODULE_DESCRIPTION("NXP Audio Transceiver (XCVR) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h new file mode 100644 index 000000000000..7f2853c60085 --- /dev/null +++ b/sound/soc/fsl/fsl_xcvr.h @@ -0,0 +1,266 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * NXP XCVR ALSA SoC Digital Audio Interface (DAI) driver + * + * Copyright 2019 NXP + */ + +#ifndef __FSL_XCVR_H +#define __FSL_XCVR_H + +#define FSL_XCVR_MODE_SPDIF 0 +#define FSL_XCVR_MODE_ARC 1 +#define FSL_XCVR_MODE_EARC 2 + +/* XCVR Registers */ +#define FSL_XCVR_REG_OFFSET 0x800 /* regs offset */ +#define FSL_XCVR_FIFO_SIZE 0x80 /* 128 */ +#define FSL_XCVR_FIFO_WMK_RX (FSL_XCVR_FIFO_SIZE >> 1) /* 64 */ +#define FSL_XCVR_FIFO_WMK_TX (FSL_XCVR_FIFO_SIZE >> 1) /* 64 */ +#define FSL_XCVR_MAXBURST_RX (FSL_XCVR_FIFO_WMK_RX >> 2) /* 16 */ +#define FSL_XCVR_MAXBURST_TX (FSL_XCVR_FIFO_WMK_TX >> 2) /* 16 */ + +#define FSL_XCVR_RX_FIFO_ADDR 0x0C00 +#define FSL_XCVR_TX_FIFO_ADDR 0x0E00 + +#define FSL_XCVR_VERSION 0x00 /* Version */ +#define FSL_XCVR_EXT_CTRL 0x10 /* Control */ +#define FSL_XCVR_EXT_STATUS 0x20 /* Status */ +#define FSL_XCVR_EXT_IER0 0x30 /* Interrupt en 0 */ +#define FSL_XCVR_EXT_IER1 0x40 /* Interrupt en 1 */ +#define FSL_XCVR_EXT_ISR 0x50 /* Interrupt status */ +#define FSL_XCVR_EXT_ISR_SET 0x54 /* Interrupt status */ +#define FSL_XCVR_EXT_ISR_CLR 0x58 /* Interrupt status */ +#define FSL_XCVR_EXT_ISR_TOG 0x5C /* Interrupt status */ +#define FSL_XCVR_IER 0x70 /* Interrupt en for M0+ */ +#define FSL_XCVR_ISR 0x80 /* Interrupt status */ +#define FSL_XCVR_ISR_SET 0x84 /* Interrupt status set */ +#define FSL_XCVR_ISR_CLR 0x88 /* Interrupt status clear */ +#define FSL_XCVR_ISR_TOG 0x8C /* Interrupt status toggle */ +#define FSL_XCVR_PHY_AI_CTRL 0x90 +#define FSL_XCVR_PHY_AI_CTRL_SET 0x94 +#define FSL_XCVR_PHY_AI_CTRL_CLR 0x98 +#define FSL_XCVR_PHY_AI_CTRL_TOG 0x9C +#define FSL_XCVR_PHY_AI_WDATA 0xA0 +#define FSL_XCVR_PHY_AI_RDATA 0xA4 +#define FSL_XCVR_CLK_CTRL 0xB0 +#define FSL_XCVR_RX_DPTH_CTRL 0x180 /* RX datapath ctrl reg */ +#define FSL_XCVR_RX_DPTH_CTRL_SET 0x184 +#define FSL_XCVR_RX_DPTH_CTRL_CLR 0x188 +#define FSL_XCVR_RX_DPTH_CTRL_TOG 0x18c + +#define FSL_XCVR_TX_DPTH_CTRL 0x220 /* TX datapath ctrl reg */ +#define FSL_XCVR_TX_DPTH_CTRL_SET 0x224 +#define FSL_XCVR_TX_DPTH_CTRL_CLR 0x228 +#define FSL_XCVR_TX_DPTH_CTRL_TOG 0x22C +#define FSL_XCVR_TX_CS_DATA_0 0x230 /* TX channel status bits regs */ +#define FSL_XCVR_TX_CS_DATA_1 0x234 +#define FSL_XCVR_TX_CS_DATA_2 0x238 +#define FSL_XCVR_TX_CS_DATA_3 0x23C +#define FSL_XCVR_TX_CS_DATA_4 0x240 +#define FSL_XCVR_TX_CS_DATA_5 0x244 +#define FSL_XCVR_DEBUG_REG_0 0x2E0 +#define FSL_XCVR_DEBUG_REG_1 0x2F0 + +#define FSL_XCVR_MAX_REG FSL_XCVR_DEBUG_REG_1 + +#define FSL_XCVR_EXT_CTRL_CORE_RESET BIT(31) + +#define FSL_XCVR_EXT_CTRL_RX_CMDC_RESET BIT(30) +#define FSL_XCVR_EXT_CTRL_TX_CMDC_RESET BIT(29) +#define FSL_XCVR_EXT_CTRL_CMDC_RESET(t) (t ? BIT(29) : BIT(30)) + +#define FSL_XCVR_EXT_CTRL_RX_DPTH_RESET BIT(28) +#define FSL_XCVR_EXT_CTRL_TX_DPTH_RESET BIT(27) +#define FSL_XCVR_EXT_CTRL_DPTH_RESET(t) (t ? BIT(27) : BIT(28)) + +#define FSL_XCVR_EXT_CTRL_TX_RX_MODE BIT(26) +#define FSL_XCVR_EXT_CTRL_DMA_RD_DIS BIT(25) +#define FSL_XCVR_EXT_CTRL_DMA_WR_DIS BIT(24) +#define FSL_XCVR_EXT_CTRL_DMA_DIS(t) (t ? BIT(24) : BIT(25)) +#define FSL_XCVR_EXT_CTRL_SPDIF_MODE BIT(23) +#define FSL_XCVR_EXT_CTRL_SLEEP_MODE BIT(21) + +#define FSL_XCVR_EXT_CTRL_TX_FWM_SHFT 0 +#define FSL_XCVR_EXT_CTRL_TX_FWM_MASK GENMASK(6, 0) +#define FSL_XCVR_EXT_CTRL_TX_FWM(i) (((i) << FSL_XCVR_EXT_CTRL_TX_FWM_SHFT) \ + & FSL_XCVR_EXT_CTRL_TX_FWM_MASK) +#define FSL_XCVR_EXT_CTRL_RX_FWM_SHFT 8 +#define FSL_XCVR_EXT_CTRL_RX_FWM_MASK GENMASK(14, 8) +#define FSL_XCVR_EXT_CTRL_RX_FWM(i) (((i) << FSL_XCVR_EXT_CTRL_RX_FWM_SHFT) \ + & FSL_XCVR_EXT_CTRL_RX_FWM_MASK) +#define FSL_XCVR_EXT_CTRL_PAGE_SHFT 16 +#define FSL_XCVR_EXT_CTRL_PAGE_MASK GENMASK(19, 16) +#define FSL_XCVR_EXT_CTRL_PAGE(i) (((i) << FSL_XCVR_EXT_CTRL_PAGE_SHFT) \ + & FSL_XCVR_EXT_CTRL_PAGE_MASK) + +#define FSL_XCVR_EXT_STUS_NT_FIFO_ENTR GENMASK(7, 0) +#define FSL_XCVR_EXT_STUS_NR_FIFO_ENTR GENMASK(15, 8) +#define FSL_XCVR_EXT_STUS_CM0_SLEEPING BIT(16) +#define FSL_XCVR_EXT_STUS_CM0_DEEP_SLP BIT(17) +#define FSL_XCVR_EXT_STUS_CM0_SLP_HACK BIT(18) +#define FSL_XCVR_EXT_STUS_RX_CMDC_RSTO BIT(23) +#define FSL_XCVR_EXT_STUS_TX_CMDC_RSTO BIT(24) +#define FSL_XCVR_EXT_STUS_RX_CMDC_COTO BIT(25) +#define FSL_XCVR_EXT_STUS_TX_CMDC_COTO BIT(26) +#define FSL_XCVR_EXT_STUS_HB_STATUS BIT(27) +#define FSL_XCVR_EXT_STUS_NEW_UD4_REC BIT(28) +#define FSL_XCVR_EXT_STUS_NEW_UD5_REC BIT(29) +#define FSL_XCVR_EXT_STUS_NEW_UD6_REC BIT(30) +#define FSL_XCVR_EXT_STUS_HPD_INPUT BIT(31) + +#define FSL_XCVR_IRQ_NEW_CS BIT(0) +#define FSL_XCVR_IRQ_NEW_UD BIT(1) +#define FSL_XCVR_IRQ_MUTE BIT(2) +#define FSL_XCVR_IRQ_CMDC_RESP_TO BIT(3) +#define FSL_XCVR_IRQ_ECC_ERR BIT(4) +#define FSL_XCVR_IRQ_PREAMBLE_MISMATCH BIT(5) +#define FSL_XCVR_IRQ_FIFO_UOFL_ERR BIT(6) +#define FSL_XCVR_IRQ_HOST_WAKEUP BIT(7) +#define FSL_XCVR_IRQ_HOST_OHPD BIT(8) +#define FSL_XCVR_IRQ_DMAC_NO_DATA_REC BIT(9) +#define FSL_XCVR_IRQ_DMAC_FMT_CHG_DET BIT(10) +#define FSL_XCVR_IRQ_HB_STATE_CHG BIT(11) +#define FSL_XCVR_IRQ_CMDC_STATUS_UPD BIT(12) +#define FSL_XCVR_IRQ_TEMP_UPD BIT(13) +#define FSL_XCVR_IRQ_DMA_RD_REQ BIT(14) +#define FSL_XCVR_IRQ_DMA_WR_REQ BIT(15) +#define FSL_XCVR_IRQ_DMAC_BME_BIT_ERR BIT(16) +#define FSL_XCVR_IRQ_PREAMBLE_MATCH BIT(17) +#define FSL_XCVR_IRQ_M_W_PRE_MISMATCH BIT(18) +#define FSL_XCVR_IRQ_B_PRE_MISMATCH BIT(19) +#define FSL_XCVR_IRQ_UNEXP_PRE_REC BIT(20) +#define FSL_XCVR_IRQ_ARC_MODE BIT(21) +#define FSL_XCVR_IRQ_CH_UD_OFLOW BIT(22) +#define FSL_XCVR_IRQ_EARC_ALL (FSL_XCVR_IRQ_NEW_CS | \ + FSL_XCVR_IRQ_NEW_UD | \ + FSL_XCVR_IRQ_MUTE | \ + FSL_XCVR_IRQ_FIFO_UOFL_ERR | \ + FSL_XCVR_IRQ_HOST_WAKEUP | \ + FSL_XCVR_IRQ_ARC_MODE) + +#define FSL_XCVR_ISR_CMDC_TX_EN BIT(3) +#define FSL_XCVR_ISR_HPD_TGL BIT(15) +#define FSL_XCVR_ISR_DMAC_SPARE_INT BIT(19) +#define FSL_XCVR_ISR_SET_SPDIF_RX_INT BIT(20) +#define FSL_XCVR_ISR_SET_SPDIF_TX_INT BIT(21) +#define FSL_XCVR_ISR_SET_SPDIF_MODE(t) (t ? BIT(21) : BIT(20)) +#define FSL_XCVR_ISR_SET_ARC_CM_INT BIT(22) +#define FSL_XCVR_ISR_SET_ARC_SE_INT BIT(23) + +#define FSL_XCVR_PHY_AI_ADDR_MASK GENMASK(7, 0) +#define FSL_XCVR_PHY_AI_RESETN BIT(15) +#define FSL_XCVR_PHY_AI_TOG_PLL BIT(24) +#define FSL_XCVR_PHY_AI_TOG_DONE_PLL BIT(25) +#define FSL_XCVR_PHY_AI_TOG_PHY BIT(26) +#define FSL_XCVR_PHY_AI_TOG_DONE_PHY BIT(27) +#define FSL_XCVR_PHY_AI_RW_MASK BIT(31) + +#define FSL_XCVR_RX_DPTH_CTRL_PAPB_FIFO_STATUS BIT(0) +#define FSL_XCVR_RX_DPTH_CTRL_DIS_PRE_ERR_CHK BIT(1) +#define FSL_XCVR_RX_DPTH_CTRL_DIS_NOD_REC_CHK BIT(2) +#define FSL_XCVR_RX_DPTH_CTRL_ECC_VUC_BIT_CHK BIT(3) +#define FSL_XCVR_RX_DPTH_CTRL_EN_CMP_PAR_CALC BIT(4) +#define FSL_XCVR_RX_DPTH_CTRL_RST_PKT_CNT_FIFO BIT(5) +#define FSL_XCVR_RX_DPTH_CTRL_STORE_FMT BIT(6) +#define FSL_XCVR_RX_DPTH_CTRL_EN_PAR_CALC BIT(7) +#define FSL_XCVR_RX_DPTH_CTRL_UDR BIT(8) +#define FSL_XCVR_RX_DPTH_CTRL_CSR BIT(9) +#define FSL_XCVR_RX_DPTH_CTRL_UDA BIT(10) +#define FSL_XCVR_RX_DPTH_CTRL_CSA BIT(11) +#define FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO BIT(12) +#define FSL_XCVR_RX_DPTH_CTRL_DIS_B_PRE_ERR_CHK BIT(13) +#define FSL_XCVR_RX_DPTH_CTRL_PABS BIT(19) +#define FSL_XCVR_RX_DPTH_CTRL_DTS_CDS BIT(20) +#define FSL_XCVR_RX_DPTH_CTRL_BLKC BIT(21) +#define FSL_XCVR_RX_DPTH_CTRL_MUTE_CTRL BIT(22) +#define FSL_XCVR_RX_DPTH_CTRL_MUTE_MODE BIT(23) +#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_CTRL BIT(24) +#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_MODE BIT(25) +#define FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL BIT(26) +#define FSL_XCVR_RX_DPTH_CTRL_LAYB_MODE BIT(27) +#define FSL_XCVR_RX_DPTH_CTRL_PRC BIT(28) +#define FSL_XCVR_RX_DPTH_CTRL_COMP BIT(29) +#define FSL_XCVR_RX_DPTH_CTRL_FSM GENMASK(31, 30) + +#define FSL_XCVR_TX_DPTH_CTRL_CS_ACK BIT(0) +#define FSL_XCVR_TX_DPTH_CTRL_UD_ACK BIT(1) +#define FSL_XCVR_TX_DPTH_CTRL_CS_MOD BIT(2) +#define FSL_XCVR_TX_DPTH_CTRL_UD_MOD BIT(3) +#define FSL_XCVR_TX_DPTH_CTRL_VLD_MOD BIT(4) +#define FSL_XCVR_TX_DPTH_CTRL_FRM_VLD BIT(5) +#define FSL_XCVR_TX_DPTH_CTRL_EN_PARITY BIT(6) +#define FSL_XCVR_TX_DPTH_CTRL_EN_PREAMBLE BIT(7) +#define FSL_XCVR_TX_DPTH_CTRL_EN_ECC_INTER BIT(8) +#define FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM BIT(10) +#define FSL_XCVR_TX_DPTH_CTRL_FRM_FMT BIT(11) +#define FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX BIT(14) +#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_STR BIT(15) +#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_END BIT(16) +#define FSL_XCVR_TX_DPTH_CTRL_CLK_RATIO BIT(29) +#define FSL_XCVR_TX_DPTH_CTRL_TM_NO_PRE_BME GENMASK(31, 30) + +#define FSL_XCVR_PHY_AI_CTRL_AI_RESETN BIT(15) + +#define FSL_XCVR_PLL_CTRL0 0x00 +#define FSL_XCVR_PLL_CTRL0_SET 0x04 +#define FSL_XCVR_PLL_CTRL0_CLR 0x08 +#define FSL_XCVR_PLL_NUM 0x20 +#define FSL_XCVR_PLL_DEN 0x30 +#define FSL_XCVR_PLL_PDIV 0x40 +#define FSL_XCVR_PLL_BANDGAP_SET 0x54 +#define FSL_XCVR_PHY_CTRL 0x00 +#define FSL_XCVR_PHY_CTRL_SET 0x04 +#define FSL_XCVR_PHY_CTRL_CLR 0x08 +#define FSL_XCVR_PHY_CTRL2 0x70 +#define FSL_XCVR_PHY_CTRL2_SET 0x74 +#define FSL_XCVR_PHY_CTRL2_CLR 0x78 + +#define FSL_XCVR_PLL_BANDGAP_EN_VBG BIT(0) +#define FSL_XCVR_PLL_CTRL0_HROFF BIT(13) +#define FSL_XCVR_PLL_CTRL0_PWP BIT(14) +#define FSL_XCVR_PLL_CTRL0_CM0_EN BIT(24) +#define FSL_XCVR_PLL_CTRL0_CM1_EN BIT(25) +#define FSL_XCVR_PLL_CTRL0_CM2_EN BIT(26) +#define FSL_XCVR_PLL_PDIVx(v, i) ((v & 0x7) << (4 * i)) + +#define FSL_XCVR_PHY_CTRL_PHY_EN BIT(0) +#define FSL_XCVR_PHY_CTRL_RX_CM_EN BIT(1) +#define FSL_XCVR_PHY_CTRL_TSDIFF_OE BIT(5) +#define FSL_XCVR_PHY_CTRL_SPDIF_EN BIT(8) +#define FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN BIT(9) +#define FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN BIT(10) +#define FSL_XCVR_PHY_CTRL_TX_CLK_MASK GENMASK(26, 25) +#define FSL_XCVR_PHY_CTRL_TX_CLK_HDMI_SS BIT(25) +#define FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS BIT(26) +#define FSL_XCVR_PHY_CTRL2_EARC_TXMS BIT(14) + +#define FSL_XCVR_CS_DATA_0_FS_MASK GENMASK(31, 24) +#define FSL_XCVR_CS_DATA_0_FS_32000 0x3000000 +#define FSL_XCVR_CS_DATA_0_FS_44100 0x0000000 +#define FSL_XCVR_CS_DATA_0_FS_48000 0x2000000 +#define FSL_XCVR_CS_DATA_0_FS_64000 0xB000000 +#define FSL_XCVR_CS_DATA_0_FS_88200 0x8000000 +#define FSL_XCVR_CS_DATA_0_FS_96000 0xA000000 +#define FSL_XCVR_CS_DATA_0_FS_176400 0xC000000 +#define FSL_XCVR_CS_DATA_0_FS_192000 0xE000000 + +#define FSL_XCVR_CS_DATA_0_CH_MASK 0x3A +#define FSL_XCVR_CS_DATA_0_CH_U2LPCM 0x00 +#define FSL_XCVR_CS_DATA_0_CH_UMLPCM 0x20 +#define FSL_XCVR_CS_DATA_0_CH_U1BAUD 0x30 + +#define FSL_XCVR_CS_DATA_1_CH_MASK 0xF000 +#define FSL_XCVR_CS_DATA_1_CH_2 0x0000 +#define FSL_XCVR_CS_DATA_1_CH_8 0x7000 +#define FSL_XCVR_CS_DATA_1_CH_16 0xB000 +#define FSL_XCVR_CS_DATA_1_CH_32 0x3000 + +/* Data memory structures */ +#define FSL_XCVR_RX_CS_CTRL_0 0x20 /* First RX CS control register */ +#define FSL_XCVR_RX_CS_CTRL_1 0x24 /* Second RX CS control register */ +#define FSL_XCVR_RX_CS_BUFF_0 0x80 /* First RX CS buffer */ +#define FSL_XCVR_RX_CS_BUFF_1 0xA0 /* Second RX CS buffer */ +#define FSL_XCVR_CAP_DATA_STR 0x300 /* Capabilities data structure */ + +#endif /* __FSL_XCVR_H */ -- cgit v1.2.3 From 5027fe36032a1203d5a56bd8c0f9279feb48775f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Sep 2020 18:20:23 +0300 Subject: ASoC: SOF: control: remove const in sizeof() We should only use the type, the const attribute makes no sense in sizeof(). Reported-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Acked-by: Jaroslav Kysela Tested-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20200930152026.3902186-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 0352d2b61358..056c86ad5a47 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -309,7 +309,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, * the length (as bytes) is needed to know the correct copy * length of data from tlvd->tlv. */ - if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) + if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv))) return -EFAULT; /* make sure TLV info is consistent */ @@ -351,7 +351,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, } /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ - if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) { + if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) { dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n"); return -EINVAL; } @@ -405,15 +405,15 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ goto out; /* check data size doesn't exceed max coming from topology */ - if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) { + if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) { dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n", cdata->data->size, - be->max - sizeof(const struct sof_abi_hdr)); + be->max - sizeof(struct sof_abi_hdr)); ret = -EINVAL; goto out; } - data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); + data_size = cdata->data->size + sizeof(struct sof_abi_hdr); /* make sure we don't exceed size provided by user space for data */ if (data_size > size) { @@ -423,7 +423,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ header.numid = scontrol->cmd; header.length = data_size; - if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) { + if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) { ret = -EFAULT; goto out; } @@ -466,14 +466,14 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, cdata->data->abi = SOF_ABI_VERSION; /* check data size doesn't exceed max coming from topology */ - if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) { + if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) { dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n", cdata->data->size, - be->max - sizeof(const struct sof_abi_hdr)); + be->max - sizeof(struct sof_abi_hdr)); return -EINVAL; } - data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); + data_size = cdata->data->size + sizeof(struct sof_abi_hdr); /* make sure we don't exceed size provided by user space for data */ if (data_size > size) @@ -481,7 +481,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, header.numid = scontrol->cmd; header.length = data_size; - if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) + if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) return -EFAULT; if (copy_to_user(tlvd->tlv, cdata->data, data_size)) -- cgit v1.2.3 From 3381a989a92f12f401332f1c506465fff1a8870d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Sep 2020 18:20:24 +0300 Subject: ASoC: SOF: topology: remove const in sizeof() We should only use the type, the const attribute makes no sense in sizeof(). Reported-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Acked-by: Jaroslav Kysela Tested-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20200930152026.3902186-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 69313fbdb636..523a386fce4b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1201,7 +1201,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, ret = -EINVAL; goto out_free; } - if (cdata->data->size + sizeof(const struct sof_abi_hdr) != + if (cdata->data->size + sizeof(struct sof_abi_hdr) != le32_to_cpu(control->priv.size)) { dev_err(scomp->dev, "error: Conflict in bytes vs. priv size.\n"); -- cgit v1.2.3 From 64e2c37ea03545ff926de13ce79c8df27b939d8a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Sep 2020 18:20:25 +0300 Subject: ASoC: SOF: sof-audio: remove goto used for force-nocodec support Address smatch warnings: sound/soc/sof/sof-audio.c:375 sof_machine_check() warn: inconsistent indenting sound/soc/sof/sof-audio.c:380 sof_machine_check() warn: ignoring unreachable code. No functionality change. Reported-by: kernel test robot Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Acked-by: Jaroslav Kysela Tested-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20200930152026.3902186-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index afe7e503bf66..9a8ce25a8fc8 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -443,11 +443,7 @@ int sof_machine_check(struct snd_sof_dev *sdev) struct snd_soc_acpi_mach *mach; int ret; - /* force nocodec mode */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) - dev_warn(sdev->dev, "Force to use nocodec mode\n"); - goto nocodec; -#endif +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) /* find machine */ snd_sof_machine_select(sdev); @@ -460,8 +456,8 @@ int sof_machine_check(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); return -ENODEV; #endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) -nocodec: +#else + dev_warn(sdev->dev, "Force to use nocodec mode\n"); #endif /* select nocodec mode */ dev_warn(sdev->dev, "Using nocodec machine driver\n"); -- cgit v1.2.3 From ab49436eecf5cc779a1ff659ba59c88779685b47 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 29 Sep 2020 13:31:19 +0900 Subject: ASoC: soc-pcm: move soc_pcm_hw_free() next to soc_pcm_hw_params() This patch moves soc_pcm_hw_free() next to soc_pcm_hw_params(). This is prepare for soc_pcm_hw_params() cleanup Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87mu19gqbh.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 86 ++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index dcab9527ba3d..697c9cb4a127 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -860,6 +860,49 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, interval->max = channels; } +/* + * Frees resources allocated by hw_params, can be called multiple times + */ +static int soc_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *dai; + int i; + + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + + /* clear the corresponding DAIs parameters when going to be inactive */ + for_each_rtd_dais(rtd, i, dai) { + int active = snd_soc_dai_stream_active(dai, substream->stream); + + if (snd_soc_dai_active(dai) == 1) { + dai->rate = 0; + dai->channels = 0; + dai->sample_bits = 0; + } + + if (active == 1) + snd_soc_dai_digital_mute(dai, 1, substream->stream); + } + + /* free any machine hw params */ + snd_soc_link_hw_free(substream); + + /* free any component resources */ + snd_soc_pcm_component_hw_free(substream, NULL); + + /* now free hw params for the DAIs */ + for_each_rtd_dais(rtd, i, dai) { + if (!snd_soc_dai_stream_valid(dai, substream->stream)) + continue; + + snd_soc_dai_hw_free(dai, substream); + } + + mutex_unlock(&rtd->card->pcm_mutex); + return 0; +} + /* * Called by ALSA when the hardware params are set by application. This * function can also be called multiple times and can allocate buffers @@ -991,49 +1034,6 @@ codec_err: return ret; } -/* - * Frees resources allocated by hw_params, can be called multiple times - */ -static int soc_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *dai; - int i; - - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - - /* clear the corresponding DAIs parameters when going to be inactive */ - for_each_rtd_dais(rtd, i, dai) { - int active = snd_soc_dai_stream_active(dai, substream->stream); - - if (snd_soc_dai_active(dai) == 1) { - dai->rate = 0; - dai->channels = 0; - dai->sample_bits = 0; - } - - if (active == 1) - snd_soc_dai_digital_mute(dai, 1, substream->stream); - } - - /* free any machine hw params */ - snd_soc_link_hw_free(substream); - - /* free any component resources */ - snd_soc_pcm_component_hw_free(substream, NULL); - - /* now free hw params for the DAIs */ - for_each_rtd_dais(rtd, i, dai) { - if (!snd_soc_dai_stream_valid(dai, substream->stream)) - continue; - - snd_soc_dai_hw_free(dai, substream); - } - - mutex_unlock(&rtd->card->pcm_mutex); - return 0; -} - static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { int ret = -EINVAL; -- cgit v1.2.3 From 918ad772c4e47f26bc1b5040a79336b7063626cf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 29 Sep 2020 13:31:25 +0900 Subject: ASoC: soc-link: add mark for snd_soc_link_hw_params/free() soc_pcm_hw_params() does rollback when failed (A), but, it is almost same as soc_pcm_hw_free(). static int soc_pcm_hw_params(xxx) { ... if (ret < 0) goto xxx_err; ... return ret; ^ component_err: | ... | interface_err: (A) ... | codec_err: | ... v return ret; } The difference is soc_pcm_hw_free() is for all dai/component/substream, rollback is for succeeded part only. This kind of duplicated code can be a hotbed of bugs, thus, we want to share soc_pcm_hw_free() and rollback. Now, soc_pcm_hw_params/free() are handling => 1) snd_soc_link_hw_params/free() 2) snd_soc_pcm_component_hw_params/free() 3) snd_soc_dai_hw_params/free() This patch is for 1) snd_soc_link_hw_params/free(). The idea of having bit-flag or counter is not enough for this purpose. For example if one DAI is used for 2xPlaybacks for some reasons, and if 1st Playback was succeeded but 2nd Playback was failed, 2nd Playback rollback doesn't need to call shutdown. But it has succeeded bit-flag or counter via 1st Playback, thus, 2nd Playback rollback will call unneeded shutdown. And 1st Playback's necessary shutdown will not be called, because bit-flag or counter was cleared by wrong 2nd Playback rollback. To avoid such case, this patch marks substream pointer when hw_params() was succeeded. If rollback needed, it will check rollback flag and marked substream pointer. One note here ist that it cares *previous* hw_params() only now, but we might want to check *whole* marked substream in the future. This patch is using macro named "push/pop", so that it can be easily update. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfgtgqba.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-link.h | 3 ++- include/sound/soc.h | 1 + sound/soc/soc-link.c | 12 +++++++++++- sound/soc/soc-pcm.c | 4 ++-- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-link.h b/include/sound/soc-link.h index dac6c0ce6ede..eff34fc7d3d3 100644 --- a/include/sound/soc-link.h +++ b/include/sound/soc-link.h @@ -19,7 +19,8 @@ void snd_soc_link_shutdown(struct snd_pcm_substream *substream, int snd_soc_link_prepare(struct snd_pcm_substream *substream); int snd_soc_link_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); -void snd_soc_link_hw_free(struct snd_pcm_substream *substream); +void snd_soc_link_hw_free(struct snd_pcm_substream *substream, + int rollback); int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd); int snd_soc_link_compr_startup(struct snd_compr_stream *cstream); diff --git a/include/sound/soc.h b/include/sound/soc.h index 7541c71c9eb8..fa6ce936f899 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1161,6 +1161,7 @@ struct snd_soc_pcm_runtime { /* function mark */ struct snd_pcm_substream *mark_startup; + struct snd_pcm_substream *mark_hw_params; /* bit field */ unsigned int pop_wait:1; diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index 2a8881978930..409ae4940da3 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -119,16 +119,26 @@ int snd_soc_link_hw_params(struct snd_pcm_substream *substream, rtd->dai_link->ops->hw_params) ret = rtd->dai_link->ops->hw_params(substream, params); + /* mark substream if succeeded */ + if (ret == 0) + soc_link_mark_push(rtd, substream, hw_params); + return soc_link_ret(rtd, ret); } -void snd_soc_link_hw_free(struct snd_pcm_substream *substream) +void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + if (rollback && !soc_link_mark_match(rtd, substream, hw_params)) + return; + if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) rtd->dai_link->ops->hw_free(substream); + + /* remove marked substream */ + soc_link_mark_pop(rtd, substream, hw_params); } int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 697c9cb4a127..8c69288f1bf5 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -886,7 +886,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) } /* free any machine hw params */ - snd_soc_link_hw_free(substream); + snd_soc_link_hw_free(substream, 0); /* free any component resources */ snd_soc_pcm_component_hw_free(substream, NULL); @@ -1028,7 +1028,7 @@ codec_err: codec_dai->rate = 0; } - snd_soc_link_hw_free(substream); + snd_soc_link_hw_free(substream, 1); mutex_unlock(&rtd->card->pcm_mutex); return ret; -- cgit v1.2.3 From 3a36a64a2de4699ef4a2479a7fb2564b85c8fb4e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 29 Sep 2020 13:31:41 +0900 Subject: ASoC: soc-component: add mark for snd_soc_pcm_component_hw_params/free() soc_pcm_hw_params() does rollback when failed (A), but, it is almost same as soc_pcm_hw_free(). static int soc_pcm_hw_params(xxx) { ... if (ret < 0) goto xxx_err; ... return ret; ^ component_err: | ... | interface_err: (A) ... | codec_err: | ... v return ret; } The difference is soc_pcm_hw_free() is for all dai/component/substream, rollback is for succeeded part only. This kind of duplicated code can be a hotbed of bugs, thus, we want to share soc_pcm_hw_free() and rollback. Now, soc_pcm_hw_params/free() are handling 1) snd_soc_link_hw_params/free() => 2) snd_soc_pcm_component_hw_params/free() 3) snd_soc_dai_hw_params/free() This patch is for 2) snd_soc_pcm_component_hw_params/free(). The idea of having bit-flag or counter is not enough for this purpose. For example if one DAI is used for 2xPlaybacks for some reasons, and if 1st Playback was succeeded but 2nd Playback was failed, 2nd Playback rollback doesn't need to call shutdown. But it has succeeded bit-flag or counter via 1st Playback, thus, 2nd Playback rollback will call unneeded shutdown. And 1st Playback's necessary shutdown will not be called, because bit-flag or counter was cleared by wrong 2nd Playback rollback. To avoid such case, this patch marks substream pointer when hw_params() was succeeded. If rollback needed, it will check rollback flag and marked substream pointer. One note here is that it cares *previous* hw_params() only now, but we might want to check *whole* marked substream in the future. This patch is using macro named "push/pop", so that it can be easily update. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k0wdgqav.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 6 +++--- sound/soc/soc-component.c | 19 ++++++++++--------- sound/soc/soc-pcm.c | 7 +++---- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 2c790ce95259..21f1d120b68e 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -220,6 +220,7 @@ struct snd_soc_component { /* function mark */ struct snd_pcm_substream *mark_module; struct snd_pcm_substream *mark_open; + struct snd_pcm_substream *mark_hw_params; void *mark_pm; #ifdef CONFIG_DEBUG_FS @@ -459,10 +460,9 @@ int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd); void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd); int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream); int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_component **last); + struct snd_pcm_hw_params *params); void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_component *last); + int rollback); int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream, int cmd); int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 728e93f35ffb..6d719c2db92e 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -779,8 +779,7 @@ int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream) } int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_component **last) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component; @@ -790,33 +789,35 @@ int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream, if (component->driver->hw_params) { ret = component->driver->hw_params(component, substream, params); - if (ret < 0) { - *last = component; + if (ret < 0) return soc_component_ret(component, ret); - } } + /* mark substream if succeeded */ + soc_component_mark_push(component, substream, hw_params); } - *last = NULL; return 0; } void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_component *last) + int rollback) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component; int i, ret; for_each_rtd_components(rtd, i, component) { - if (component == last) - break; + if (rollback && !soc_component_mark_match(component, substream, hw_params)) + continue; if (component->driver->hw_free) { ret = component->driver->hw_free(component, substream); if (ret < 0) soc_component_ret(component, ret); } + + /* remove marked substream */ + soc_component_mark_pop(component, substream, hw_params); } } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8c69288f1bf5..6eec0f498090 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -889,7 +889,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) snd_soc_link_hw_free(substream, 0); /* free any component resources */ - snd_soc_pcm_component_hw_free(substream, NULL); + snd_soc_pcm_component_hw_free(substream, 0); /* now free hw params for the DAIs */ for_each_rtd_dais(rtd, i, dai) { @@ -912,7 +912,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_component *component; struct snd_soc_dai *cpu_dai; struct snd_soc_dai *codec_dai; int i, ret = 0; @@ -995,7 +994,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, snd_soc_dapm_update_dai(substream, params, cpu_dai); } - ret = snd_soc_pcm_component_hw_params(substream, params, &component); + ret = snd_soc_pcm_component_hw_params(substream, params); if (ret < 0) goto component_err; @@ -1004,7 +1003,7 @@ out: return ret; component_err: - snd_soc_pcm_component_hw_free(substream, component); + snd_soc_pcm_component_hw_free(substream, 1); i = rtd->num_cpus; -- cgit v1.2.3 From c304c9acb6e60bcc5c4d4b5a72763ca3bdf7d76b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 29 Sep 2020 13:31:53 +0900 Subject: ASoC: soc-dai: add mark for snd_soc_dai_hw_params/free() soc_pcm_hw_params() does rollback when failed (A), but, it is almost same as soc_pcm_hw_free(). static int soc_pcm_hw_params(xxx) { ... if (ret < 0) goto xxx_err; ... return ret; ^ component_err: | ... | interface_err: (A) ... | codec_err: | ... v return ret; } The difference is soc_pcm_hw_free() is for all dai/component/substream, rollback is for succeeded part only. This kind of duplicated code can be a hotbed of bugs, thus, we want to share soc_pcm_hw_free() and rollback. Now, soc_pcm_hw_params/free() are handling 1) snd_soc_link_hw_params/free() 2) snd_soc_pcm_component_hw_params/free() => 3) snd_soc_dai_hw_params/free() This patch is for 3) snd_soc_dai_hw_params/free(). The idea of having bit-flag or counter is not enough for this purpose. For example if one DAI is used for 2xPlaybacks for some reasons, and if 1st Playback was succeeded but 2nd Playback was failed, 2nd Playback rollback doesn't need to call shutdown. But it has succeeded bit-flag or counter via 1st Playback, thus, 2nd Playback rollback will call unneeded shutdown. And 1st Playback's necessary shutdown will not be called, because bit-flag or counter was cleared by wrong 2nd Playback rollback. To avoid such case, this patch marks substream pointer when hw_params() was succeeded. If rollback needed, it will check rollback flag and marked substream pointer. One note here is that it cares *previous* hw_params() only now, but we might want to check *whole* marked substream in the future. This patch is using macro named "push/pop", so that it can be easily update. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87imbxgqai.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 4 +++- sound/soc/soc-dai.c | 13 ++++++++++++- sound/soc/soc-dapm.c | 4 ++-- sound/soc/soc-pcm.c | 6 +++--- 4 files changed, 20 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 2150bd4c7a05..7a85a6f83ca8 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -149,7 +149,8 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); void snd_soc_dai_hw_free(struct snd_soc_dai *dai, - struct snd_pcm_substream *substream); + struct snd_pcm_substream *substream, + int rollback); int snd_soc_dai_startup(struct snd_soc_dai *dai, struct snd_pcm_substream *substream); void snd_soc_dai_shutdown(struct snd_soc_dai *dai, @@ -390,6 +391,7 @@ struct snd_soc_dai { /* function mark */ struct snd_pcm_substream *mark_startup; + struct snd_pcm_substream *mark_hw_params; /* bit field */ unsigned int probed:1; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 4705c3da6280..2686a566649b 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -335,16 +335,27 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai, if (dai->driver->ops && dai->driver->ops->hw_params) ret = dai->driver->ops->hw_params(substream, params, dai); + + /* mark substream if succeeded */ + if (ret == 0) + soc_dai_mark_push(dai, substream, hw_params); end: return soc_dai_ret(dai, ret); } void snd_soc_dai_hw_free(struct snd_soc_dai *dai, - struct snd_pcm_substream *substream) + struct snd_pcm_substream *substream, + int rollback) { + if (rollback && !soc_dai_mark_match(dai, substream, hw_params)) + return; + if (dai->driver->ops && dai->driver->ops->hw_free) dai->driver->ops->hw_free(substream, dai); + + /* remove marked substream */ + soc_dai_mark_pop(dai, substream, hw_params); } int snd_soc_dai_startup(struct snd_soc_dai *dai, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 980f2c330b87..471ac8d9b669 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3955,13 +3955,13 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, substream->stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; - snd_soc_dai_hw_free(source, substream); + snd_soc_dai_hw_free(source, substream, 0); } substream->stream = SNDRV_PCM_STREAM_PLAYBACK; snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; - snd_soc_dai_hw_free(sink, substream); + snd_soc_dai_hw_free(sink, substream, 0); } substream->stream = SNDRV_PCM_STREAM_CAPTURE; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6eec0f498090..d4dd2dc1b00c 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -896,7 +896,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) if (!snd_soc_dai_stream_valid(dai, substream->stream)) continue; - snd_soc_dai_hw_free(dai, substream); + snd_soc_dai_hw_free(dai, substream, 0); } mutex_unlock(&rtd->card->pcm_mutex); @@ -1012,7 +1012,7 @@ interface_err: if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) continue; - snd_soc_dai_hw_free(cpu_dai, substream); + snd_soc_dai_hw_free(cpu_dai, substream, 1); cpu_dai->rate = 0; } @@ -1023,7 +1023,7 @@ codec_err: if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) continue; - snd_soc_dai_hw_free(codec_dai, substream); + snd_soc_dai_hw_free(codec_dai, substream, 1); codec_dai->rate = 0; } -- cgit v1.2.3 From 4662c59688b8db8834aab14f0d37a4f26fc0dd20 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 29 Sep 2020 13:32:01 +0900 Subject: ASoC: soc-pcm: add soc_pcm_hw_clean() and call it from soc_pcm_hw_params/free() soc_pcm_hw_params() does rollback when failed (A), but, it is almost same as soc_pcm_hw_free(). static int soc_pcm_hw_params(xxx) { ... if (ret < 0) goto xxx_err; ... return ret; ^ component_err: | ... | interface_err: (A) ... | codec_err: | ... v return ret; } The difference is soc_pcm_hw_free() is for all dai/component/substream, rollback is for succeeded part only. This kind of duplicated code can be a hotbed of bugs, thus, we want to share soc_pcm_hw_free() and rollback. Now, soc_pcm_hw_params/free() are handling 1) snd_soc_link_hw_params/free() 2) snd_soc_pcm_component_hw_params/free() 3) snd_soc_dai_hw_params/free() Now, 1) to 3) are handled. This patch adds new soc_pcm_hw_clean() and call it from soc_pcm_hw_params() as rollback, and from soc_pcm_hw_free() as normal close handler. Other difference is that soc_pcm_hw_free() handles digital mute if it was last user. Rollback also handles it by this patch. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h7rhgqab.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ---- sound/soc/soc-pcm.c | 56 +++++++++++++++-------------------------------------- 2 files changed, 16 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index fa6ce936f899..5ac578c9340c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1184,14 +1184,10 @@ struct snd_soc_pcm_runtime { for ((i) = 0; \ ((i) < rtd->num_cpus) && ((dai) = asoc_rtd_to_cpu(rtd, i)); \ (i)++) -#define for_each_rtd_cpu_dais_rollback(rtd, i, dai) \ - for (; (--(i) >= 0) && ((dai) = asoc_rtd_to_cpu(rtd, i));) #define for_each_rtd_codec_dais(rtd, i, dai) \ for ((i) = 0; \ ((i) < rtd->num_codecs) && ((dai) = asoc_rtd_to_codec(rtd, i)); \ (i)++) -#define for_each_rtd_codec_dais_rollback(rtd, i, dai) \ - for (; (--(i) >= 0) && ((dai) = asoc_rtd_to_codec(rtd, i));) #define for_each_rtd_dais(rtd, i, dai) \ for ((i) = 0; \ ((i) < (rtd)->num_cpus + (rtd)->num_codecs) && \ diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d4dd2dc1b00c..17ff3a369631 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -860,10 +860,7 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, interval->max = channels; } -/* - * Frees resources allocated by hw_params, can be called multiple times - */ -static int soc_pcm_hw_free(struct snd_pcm_substream *substream) +static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *dai; @@ -886,23 +883,31 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) } /* free any machine hw params */ - snd_soc_link_hw_free(substream, 0); + snd_soc_link_hw_free(substream, rollback); /* free any component resources */ - snd_soc_pcm_component_hw_free(substream, 0); + snd_soc_pcm_component_hw_free(substream, rollback); /* now free hw params for the DAIs */ for_each_rtd_dais(rtd, i, dai) { if (!snd_soc_dai_stream_valid(dai, substream->stream)) continue; - snd_soc_dai_hw_free(dai, substream, 0); + snd_soc_dai_hw_free(dai, substream, rollback); } mutex_unlock(&rtd->card->pcm_mutex); return 0; } +/* + * Frees resources allocated by hw_params, can be called multiple times + */ +static int soc_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return soc_pcm_hw_clean(substream, 0); +} + /* * Called by ALSA when the hardware params are set by application. This * function can also be called multiple times and can allocate buffers @@ -963,7 +968,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_hw_params(codec_dai, substream, &codec_params); if(ret < 0) - goto codec_err; + goto out; codec_dai->rate = params_rate(&codec_params); codec_dai->channels = params_channels(&codec_params); @@ -983,7 +988,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_hw_params(cpu_dai, substream, params); if (ret < 0) - goto interface_err; + goto out; /* store the parameters for each DAI */ cpu_dai->rate = params_rate(params); @@ -995,41 +1000,12 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } ret = snd_soc_pcm_component_hw_params(substream, params); - if (ret < 0) - goto component_err; - out: mutex_unlock(&rtd->card->pcm_mutex); - return ret; -component_err: - snd_soc_pcm_component_hw_free(substream, 1); - - i = rtd->num_cpus; - -interface_err: - for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) { - if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) - continue; - - snd_soc_dai_hw_free(cpu_dai, substream, 1); - cpu_dai->rate = 0; - } - - i = rtd->num_codecs; - -codec_err: - for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) { - if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) - continue; - - snd_soc_dai_hw_free(codec_dai, substream, 1); - codec_dai->rate = 0; - } - - snd_soc_link_hw_free(substream, 1); + if (ret < 0) + soc_pcm_hw_clean(substream, 1); - mutex_unlock(&rtd->card->pcm_mutex); return ret; } -- cgit v1.2.3 From aa2e2785545aab21b6cb2e23f111ae0751cbcca7 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 26 Oct 2020 17:09:47 +0000 Subject: ASoC: qcom: sm8250: add sound card qrb5165-rb5 support Add support to Qualcomm Robotics RB5 Development Kit based on QRB5165 Robotics SoC. This board has 2 WSA881X smart speakers with onboard DMIC connected to internal LPASS codec via WSA and VA macros respectively. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201026170947.10567-3-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 11 +++ sound/soc/qcom/Makefile | 2 + sound/soc/qcom/sm8250.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 sound/soc/qcom/sm8250.c (limited to 'sound') diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 2696ffcba880..484cad31da25 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -127,4 +127,15 @@ config SND_SOC_SDM845 SDM845 SoC-based systems. Say Y if you want to use audio device on this SoCs. +config SND_SOC_SM8250 + tristate "SoC Machine driver for SM8250 boards" + depends on QCOM_APR && SOUNDWIRE + depends on COMMON_CLK + select SND_SOC_QDSP6 + select SND_SOC_QCOM_COMMON + help + To add support for audio on Qualcomm Technologies Inc. + SM8250 SoC-based systems. + Say Y if you want to use audio device on this SoCs. + endif #SND_SOC_QCOM diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index 0bd90d74e3db..effa4b3f58fa 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -19,12 +19,14 @@ snd-soc-storm-objs := storm.o snd-soc-apq8016-sbc-objs := apq8016_sbc.o snd-soc-apq8096-objs := apq8096.o snd-soc-sdm845-objs := sdm845.o +snd-soc-sm8250-objs := sm8250.o snd-soc-qcom-common-objs := common.o obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o +obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o #DSP lib diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c new file mode 100644 index 000000000000..7d43de6d909f --- /dev/null +++ b/sound/soc/qcom/sm8250.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include "qdsp6/q6afe.h" +#include "common.h" + +#define DRIVER_NAME "sm8250" +#define MI2S_BCLK_RATE 1536000 +#define MAX_SDW_STREAMS 16 + +struct sm8250_snd_data { + bool stream_prepared[MAX_SDW_STREAMS]; + struct snd_soc_card *card; + struct sdw_stream_runtime *sruntime[MAX_SDW_STREAMS]; +}; + +static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + return 0; +} + +static int sm8250_snd_startup(struct snd_pcm_substream *substream) +{ + unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + + switch (cpu_dai->id) { + case TERTIARY_MI2S_RX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF; + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + break; + default: + break; + } + return 0; +} + +static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime; + int i; + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + for_each_rtd_codec_dais(rtd, i, codec_dai) { + sruntime = snd_soc_dai_get_sdw_stream(codec_dai, + substream->stream); + if (sruntime != ERR_PTR(-ENOTSUPP)) + pdata->sruntime[cpu_dai->id] = sruntime; + } + break; + } + + return 0; + +} + +static int sm8250_snd_wsa_dma_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + int ret; + + if (!sruntime) + return 0; + + if (data->stream_prepared[cpu_dai->id]) { + sdw_disable_stream(sruntime); + sdw_deprepare_stream(sruntime); + data->stream_prepared[cpu_dai->id] = false; + } + + ret = sdw_prepare_stream(sruntime); + if (ret) + return ret; + + /** + * NOTE: there is a strict hw requirement about the ordering of port + * enables and actual WSA881x PA enable. PA enable should only happen + * after soundwire ports are enabled if not DC on the line is + * accumulated resulting in Click/Pop Noise + * PA enable/mute are handled as part of codec DAPM and digital mute. + */ + + ret = sdw_enable_stream(sruntime); + if (ret) { + sdw_deprepare_stream(sruntime); + return ret; + } + data->stream_prepared[cpu_dai->id] = true; + + return ret; +} + +static int sm8250_snd_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + return sm8250_snd_wsa_dma_prepare(substream); + default: + break; + } + + return 0; +} + +static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; + + switch (cpu_dai->id) { + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + if (sruntime && data->stream_prepared[cpu_dai->id]) { + sdw_disable_stream(sruntime); + sdw_deprepare_stream(sruntime); + data->stream_prepared[cpu_dai->id] = false; + } + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_ops sm8250_be_ops = { + .startup = sm8250_snd_startup, + .hw_params = sm8250_snd_hw_params, + .hw_free = sm8250_snd_hw_free, + .prepare = sm8250_snd_prepare, +}; + +static void sm8250_add_be_ops(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + + for_each_card_prelinks(card, i, link) { + if (link->no_pcm == 1) { + link->be_hw_params_fixup = sm8250_be_hw_params_fixup; + link->ops = &sm8250_be_ops; + } + } +} + +static int sm8250_platform_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct sm8250_snd_data *data; + struct device *dev = &pdev->dev; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + /* Allocate the private data */ + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + card->dev = dev; + dev_set_drvdata(dev, card); + snd_soc_card_set_drvdata(card, data); + ret = qcom_snd_parse_of(card); + if (ret) + return ret; + + card->driver_name = DRIVER_NAME; + sm8250_add_be_ops(card); + return devm_snd_soc_register_card(dev, card); +} + +static const struct of_device_id snd_sm8250_dt_match[] = { + {.compatible = "qcom,sdm8250"}, + {.compatible = "qcom,qrb5165-rb5"}, + {} +}; + +MODULE_DEVICE_TABLE(of, snd_sm8250_dt_match); + +static struct platform_driver snd_sm8250_driver = { + .probe = sm8250_platform_probe, + .driver = { + .name = "snd-sm8250", + .of_match_table = snd_sm8250_dt_match, + }, +}; +module_platform_driver(snd_sm8250_driver); +MODULE_AUTHOR("Srinivas Kandagatla Date: Fri, 23 Oct 2020 11:23:46 +0200 Subject: ASoC: jz4740-i2s: Remove manual DMA peripheral ID assignment All platforms that use the jz4740-i2s driver have been switched to devicetree for a while now and the assignment of the DMA peripheral ID is done in the devicetree. It is no longer necessary to manually assign the peripheral ID in the driver, so remove that. The DMA driver does not even look at the value assigned in the driver anymore and always uses the value provided by the devicetree. Signed-off-by: Lars-Peter Clausen Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20201023092346.5777-1-lars@metafoo.de Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index c7bd20104b20..e8bc7ca5ee5e 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -26,9 +26,6 @@ #include "jz4740-i2s.h" -#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24 -#define JZ4740_DMA_TYPE_AIC_RECEIVE 25 - #define JZ_REG_AIC_CONF 0x00 #define JZ_REG_AIC_CTRL 0x04 #define JZ_REG_AIC_I2S_FMT 0x10 @@ -377,13 +374,11 @@ static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s) /* Playback */ dma_data = &i2s->playback_dma_data; dma_data->maxburst = 16; - dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT; dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; /* Capture */ dma_data = &i2s->capture_dma_data; dma_data->maxburst = 16; - dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE; dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; } -- cgit v1.2.3 From 76b5f68bbf7df9343b69fbee04d5edf50680c231 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 12 Oct 2020 17:19:11 +0300 Subject: ASoC: pcm5102a: Make codec selectable The TI PCM5102A codec driver can be used with the generic sound card drivers, so it should be selectable. For example, with the addition of #sound-dai-cells = <0> property in DT, it can be used with simple/graph card drivers. Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20201012141911.3150996-1-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 34c6dd04b85a..5791b7056af6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1003,7 +1003,7 @@ config SND_SOC_PCM3168A_SPI select REGMAP_SPI config SND_SOC_PCM5102A - tristate + tristate "Texas Instruments PCM5102A CODEC" config SND_SOC_PCM512x tristate -- cgit v1.2.3 From ab589bac553f79d559952aa088480a72258ac5bc Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 19 Oct 2020 13:53:13 +0300 Subject: ASoC: adau1977: remove platform data and move micbias bindings include The change removes the platform_data include/definition. It only contains some values for the MICBIAS. These are moved into 'dt-bindings/sound/adi,adau1977.h' so that they can be used inside device-trees. When moving then, they need to be converted to pre-compiler defines, so that the DT compiler can understand them. The driver then, also needs to include the new 'dt-bindings/sound/adi,adau1977.h' file. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201019105313.24862-1-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- include/dt-bindings/sound/adi,adau1977.h | 15 +++++++++++ include/linux/platform_data/adau1977.h | 44 -------------------------------- sound/soc/codecs/adau1977.c | 9 +++---- 3 files changed, 18 insertions(+), 50 deletions(-) create mode 100644 include/dt-bindings/sound/adi,adau1977.h delete mode 100644 include/linux/platform_data/adau1977.h (limited to 'sound') diff --git a/include/dt-bindings/sound/adi,adau1977.h b/include/dt-bindings/sound/adi,adau1977.h new file mode 100644 index 000000000000..8eebec6570f2 --- /dev/null +++ b/include/dt-bindings/sound/adi,adau1977.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __DT_BINDINGS_ADI_ADAU1977_H__ +#define __DT_BINDINGS_ADI_ADAU1977_H__ + +#define ADAU1977_MICBIAS_5V0 0x0 +#define ADAU1977_MICBIAS_5V5 0x1 +#define ADAU1977_MICBIAS_6V0 0x2 +#define ADAU1977_MICBIAS_6V5 0x3 +#define ADAU1977_MICBIAS_7V0 0x4 +#define ADAU1977_MICBIAS_7V5 0x5 +#define ADAU1977_MICBIAS_8V0 0x6 +#define ADAU1977_MICBIAS_8V5 0x7 +#define ADAU1977_MICBIAS_9V0 0x8 + +#endif /* __DT_BINDINGS_ADI_ADAU1977_H__ */ diff --git a/include/linux/platform_data/adau1977.h b/include/linux/platform_data/adau1977.h deleted file mode 100644 index 86667235077a..000000000000 --- a/include/linux/platform_data/adau1977.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * ADAU1977/ADAU1978/ADAU1979 driver - * - * Copyright 2014 Analog Devices Inc. - * Author: Lars-Peter Clausen - */ - -#ifndef __LINUX_PLATFORM_DATA_ADAU1977_H__ -#define __LINUX_PLATFORM_DATA_ADAU1977_H__ - -/** - * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting - * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V - * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V - * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V - * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V - * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V - * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V - * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V - * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V - * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V - */ -enum adau1977_micbias { - ADAU1977_MICBIAS_5V0 = 0x0, - ADAU1977_MICBIAS_5V5 = 0x1, - ADAU1977_MICBIAS_6V0 = 0x2, - ADAU1977_MICBIAS_6V5 = 0x3, - ADAU1977_MICBIAS_7V0 = 0x4, - ADAU1977_MICBIAS_7V5 = 0x5, - ADAU1977_MICBIAS_8V0 = 0x6, - ADAU1977_MICBIAS_8V5 = 0x7, - ADAU1977_MICBIAS_9V0 = 0x8, -}; - -/** - * struct adau1977_platform_data - Platform configuration data for the ADAU1977 - * @micbias: Specifies the voltage for the MICBIAS pin - */ -struct adau1977_platform_data { - enum adau1977_micbias micbias; -}; - -#endif diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 0a36e523584c..8260f49caa24 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -24,6 +23,8 @@ #include #include +#include + #include "adau1977.h" #define ADAU1977_REG_POWER 0x00 @@ -881,13 +882,9 @@ static const struct snd_soc_component_driver adau1977_component_driver = { static int adau1977_setup_micbias(struct adau1977 *adau1977) { - struct adau1977_platform_data *pdata = adau1977->dev->platform_data; unsigned int micbias; - if (pdata) - micbias = pdata->micbias; - else if (device_property_read_u32(adau1977->dev, "adi,micbias", - &micbias)) + if (device_property_read_u32(adau1977->dev, "adi,micbias", &micbias)) micbias = ADAU1977_MICBIAS_8V5; if (micbias > ADAU1977_MICBIAS_9V0) { -- cgit v1.2.3 From 79405e3e5375875f8edc7dd6c1cf5376b1ded6e7 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 15 Oct 2020 11:27:03 +0100 Subject: ASoC: wm5102: Use get_unaligned_be16() for dac_comp_coeff Replace the two-step copy-and-convert in wm5102_out_comp_coeff_put() with get_unaligned_be16(). Apart from looking nicer, it avoids this sparse warning: wm5102.c:687:35: sparse: sparse: cast to restricted __be16 Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20201015102703.24622-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 2ed3fa67027d..70d353b63fe0 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -682,9 +682,7 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, struct arizona *arizona = dev_get_drvdata(component->dev->parent); mutex_lock(&arizona->dac_comp_lock); - memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data, - sizeof(arizona->dac_comp_coeff)); - arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff); + arizona->dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data); mutex_unlock(&arizona->dac_comp_lock); return 0; -- cgit v1.2.3 From efb38304c550cd7abf1a855074a73dc4a8874aa0 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Fri, 23 Oct 2020 23:37:17 +0530 Subject: ASoC: amd: support other audio modes for raven ACP supports different audio configurations other than I2S. This patch will fix acp driver probe failure for other audio configurations. Tested-by: Prike Liang Reviewed-by: Prike Liang Acked-by: Alex Deucher Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/1603476441-3506-1-git-send-email-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/raven/pci-acp3x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c index 31b797c8bfe6..cd5b097a9402 100644 --- a/sound/soc/amd/raven/pci-acp3x.c +++ b/sound/soc/amd/raven/pci-acp3x.c @@ -231,9 +231,7 @@ static int snd_acp3x_probe(struct pci_dev *pci, } break; default: - dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val); - ret = -ENODEV; - goto disable_msi; + dev_info(&pci->dev, "ACP audio mode : %d\n", val); } pm_runtime_set_autosuspend_delay(&pci->dev, 2000); pm_runtime_use_autosuspend(&pci->dev); -- cgit v1.2.3 From 516232e3609f485be04445b03723fbaed64a5321 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 15 Oct 2020 13:28:48 +0800 Subject: ASoC: fsl_spdif: Add support for i.MX8QM platform On i.MX8QM, there are separate interrupts for TX and RX. As the EDMA can't be configured to swing back to first FIFO after writing the second FIFO, so we need to force the burst size to be 2 on i.MX8QM. And EDMA don't support to shift the data from S24_LE to S16_LE, so the supported TX format is also different on i.MX8QM. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/1602739728-4433-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 57 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index b0f643fefe1e..e494ad6ec7d7 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -49,10 +49,18 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; * @imx: for imx platform * @shared_root_clock: flag of sharing a clock source with others; * so the driver shouldn't set root clock rate + * @interrupts: interrupt number + * @tx_burst: tx maxburst size + * @rx_burst: rx maxburst size + * @tx_formats: tx supported data format */ struct fsl_spdif_soc_data { bool imx; bool shared_root_clock; + u32 interrupts; + u32 tx_burst; + u32 rx_burst; + u64 tx_formats; }; /* @@ -128,16 +136,38 @@ struct fsl_spdif_priv { static struct fsl_spdif_soc_data fsl_spdif_vf610 = { .imx = false, .shared_root_clock = false, + .interrupts = 1, + .tx_burst = FSL_SPDIF_TXFIFO_WML, + .rx_burst = FSL_SPDIF_RXFIFO_WML, + .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK, }; static struct fsl_spdif_soc_data fsl_spdif_imx35 = { .imx = true, .shared_root_clock = false, + .interrupts = 1, + .tx_burst = FSL_SPDIF_TXFIFO_WML, + .rx_burst = FSL_SPDIF_RXFIFO_WML, + .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK, }; static struct fsl_spdif_soc_data fsl_spdif_imx6sx = { .imx = true, .shared_root_clock = true, + .interrupts = 1, + .tx_burst = FSL_SPDIF_TXFIFO_WML, + .rx_burst = FSL_SPDIF_RXFIFO_WML, + .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK, + +}; + +static struct fsl_spdif_soc_data fsl_spdif_imx8qm = { + .imx = true, + .shared_root_clock = true, + .interrupts = 2, + .tx_burst = 2, /* Applied for EDMA */ + .rx_burst = 2, /* Applied for EDMA */ + .tx_formats = SNDRV_PCM_FMTBIT_S24_LE, /* Applied for EDMA */ }; /* Check if clk is a root clock that does not share clock source with others */ @@ -1273,6 +1303,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) /* Initialize this copy of the CPU DAI driver structure */ memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev); + spdif_priv->cpu_dai_drv.playback.formats = + spdif_priv->soc->tx_formats; /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1287,15 +1319,19 @@ static int fsl_spdif_probe(struct platform_device *pdev) return PTR_ERR(spdif_priv->regmap); } - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + for (i = 0; i < spdif_priv->soc->interrupts; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + return irq; + } - ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, - dev_name(&pdev->dev), spdif_priv); - if (ret) { - dev_err(&pdev->dev, "could not claim irq %u\n", irq); - return ret; + ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, + dev_name(&pdev->dev), spdif_priv); + if (ret) { + dev_err(&pdev->dev, "could not claim irq %u\n", irq); + return ret; + } } /* Get system clock for rx clock rate calculation */ @@ -1344,8 +1380,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) spdif_priv->dpll_locked = false; - spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML; - spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML; + spdif_priv->dma_params_tx.maxburst = spdif_priv->soc->tx_burst; + spdif_priv->dma_params_rx.maxburst = spdif_priv->soc->rx_burst; spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL; spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL; @@ -1458,6 +1494,7 @@ static const struct of_device_id fsl_spdif_dt_ids[] = { { .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, }, { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, }, { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, }, + { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, }, {} }; MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); -- cgit v1.2.3 From 1bfa3eaa4511256ab14555ab2573e6e75194b1fa Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 13 Oct 2020 10:49:20 +0800 Subject: ASoC: fsl_spdif: Add support for higher sample rates Add 88200Hz and 176400Hz sample rates support for TX. Add 88200Hz, 176400Hz, 192000Hz sample rates support for RX. Signed-off-by: Viorel Suman Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Reviewed-by: Daniel Baluta Link: https://lore.kernel.org/r/1602557360-18795-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 16 +++++++++++++--- sound/soc/fsl/fsl_spdif.h | 9 ++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index e494ad6ec7d7..5fa178f3f497 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -459,10 +459,18 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, rate = SPDIF_TXRATE_48000; csfs = IEC958_AES3_CON_FS_48000; break; + case 88200: + rate = SPDIF_TXRATE_88200; + csfs = IEC958_AES3_CON_FS_88200; + break; case 96000: rate = SPDIF_TXRATE_96000; csfs = IEC958_AES3_CON_FS_96000; break; + case 176400: + rate = SPDIF_TXRATE_176400; + csfs = IEC958_AES3_CON_FS_176400; + break; case 192000: rate = SPDIF_TXRATE_192000; csfs = IEC958_AES3_CON_FS_192000; @@ -857,7 +865,7 @@ static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 16000; - uinfo->value.integer.max = 96000; + uinfo->value.integer.max = 192000; return 0; } @@ -1175,7 +1183,8 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, struct clk *clk, u64 savesub, enum spdif_txrate index, bool round) { - static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; + static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400, + 192000, }; bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); u64 rate_ideal, rate_actual, sub; u32 arate; @@ -1235,7 +1244,8 @@ out: static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index) { - static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; + static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400, + 192000, }; struct platform_device *pdev = spdif_priv->pdev; struct device *dev = &pdev->dev; u64 savesub = 100000, ret; diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h index e6c61e07bc1a..d5f1dfd58740 100644 --- a/sound/soc/fsl/fsl_spdif.h +++ b/sound/soc/fsl/fsl_spdif.h @@ -163,7 +163,9 @@ enum spdif_txrate { SPDIF_TXRATE_32000 = 0, SPDIF_TXRATE_44100, SPDIF_TXRATE_48000, + SPDIF_TXRATE_88200, SPDIF_TXRATE_96000, + SPDIF_TXRATE_176400, SPDIF_TXRATE_192000, }; #define SPDIF_TXRATE_MAX (SPDIF_TXRATE_192000 + 1) @@ -177,15 +179,20 @@ enum spdif_txrate { #define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \ SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | \ SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | \ SNDRV_PCM_RATE_192000) #define FSL_SPDIF_RATES_CAPTURE (SNDRV_PCM_RATE_16000 | \ SNDRV_PCM_RATE_32000 | \ SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | \ SNDRV_PCM_RATE_64000 | \ - SNDRV_PCM_RATE_96000) + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000) #define FSL_SPDIF_FORMATS_PLAYBACK (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \ -- cgit v1.2.3 From 9e3ecb5b16818abd0bc5f3997cf4d641a710f837 Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Tue, 27 Oct 2020 11:22:34 +0800 Subject: ASoC: qcom: sc7180: Add machine driver for sound card registration Add new driver to register sound card on sc7180 trogdor board and do the required configuration for lpass cpu dai and external codecs connected over MI2S interfaces. Signed-off-by: Ajit Pandey Signed-off-by: Cheng-Yi Chiang Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201027032234.1705835-3-cychiang@chromium.org Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 12 +++ sound/soc/qcom/Makefile | 2 + sound/soc/qcom/sc7180.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+) create mode 100644 sound/soc/qcom/sc7180.c (limited to 'sound') diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 484cad31da25..41cb08bd5588 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -138,4 +138,16 @@ config SND_SOC_SM8250 SM8250 SoC-based systems. Say Y if you want to use audio device on this SoCs. +config SND_SOC_SC7180 + tristate "SoC Machine driver for SC7180 boards" + depends on I2C + select SND_SOC_QCOM_COMMON + select SND_SOC_LPASS_SC7180 + select SND_SOC_MAX98357A + select SND_SOC_RT5682_I2C + help + To add support for audio on Qualcomm Technologies Inc. + SC7180 SoC-based systems. + Say Y if you want to use audio device on this SoCs. + endif #SND_SOC_QCOM diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index effa4b3f58fa..1600ae55bd34 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o snd-soc-storm-objs := storm.o snd-soc-apq8016-sbc-objs := apq8016_sbc.o snd-soc-apq8096-objs := apq8096.o +snd-soc-sc7180-objs := sc7180.o snd-soc-sdm845-objs := sdm845.o snd-soc-sm8250-objs := sm8250.o snd-soc-qcom-common-objs := common.o @@ -25,6 +26,7 @@ snd-soc-qcom-common-objs := common.o obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o +obj-$(CONFIG_SND_SOC_SC7180) += snd-soc-sc7180.o obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c new file mode 100644 index 000000000000..b391f64c3a80 --- /dev/null +++ b/sound/soc/qcom/sc7180.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright (c) 2020, The Linux Foundation. All rights reserved. +// +// sc7180.c -- ALSA SoC Machine driver for SC7180 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../codecs/rt5682.h" +#include "common.h" +#include "lpass.h" + +#define DEFAULT_MCLK_RATE 19200000 +#define RT5682_PLL1_FREQ (48000 * 512) + +#define DRIVER_NAME "SC7180" + +struct sc7180_snd_data { + struct snd_soc_card card; + u32 pri_mi2s_clk_count; + struct snd_soc_jack hs_jack; + struct snd_soc_jack hdmi_jack; +}; + +static void sc7180_jack_free(struct snd_jack *jack) +{ + struct snd_soc_component *component = jack->private_data; + + snd_soc_component_set_jack(component, NULL, NULL); +} + +static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + struct snd_jack *jack; + int rval; + + rval = snd_soc_card_jack_new( + card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_HEADPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pdata->hs_jack, NULL, 0); + + if (rval < 0) { + dev_err(card->dev, "Unable to add Headset Jack\n"); + return rval; + } + + jack = pdata->hs_jack.jack; + + snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + jack->private_data = component; + jack->private_free = sc7180_jack_free; + + return snd_soc_component_set_jack(component, &pdata->hs_jack, NULL); +} + +static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + struct snd_jack *jack; + int rval; + + rval = snd_soc_card_jack_new( + card, "HDMI Jack", + SND_JACK_LINEOUT, + &pdata->hdmi_jack, NULL, 0); + + if (rval < 0) { + dev_err(card->dev, "Unable to add HDMI Jack\n"); + return rval; + } + + jack = pdata->hdmi_jack.jack; + jack->private_data = component; + jack->private_free = sc7180_jack_free; + + return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL); +} + +static int sc7180_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case MI2S_PRIMARY: + return sc7180_headset_init(rtd); + case MI2S_SECONDARY: + return 0; + case LPASS_DP_RX: + return sc7180_hdmi_init(rtd); + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + return -EINVAL; + } + return 0; +} + +static int sc7180_snd_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + + switch (cpu_dai->id) { + case MI2S_PRIMARY: + if (++data->pri_mi2s_clk_count == 1) { + snd_soc_dai_set_sysclk(cpu_dai, + LPASS_MCLK0, + DEFAULT_MCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); + } + + snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S); + + /* Configure PLL1 for codec */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK, + DEFAULT_MCLK_RATE, RT5682_PLL1_FREQ); + if (ret) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + } + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, + RT5682_PLL1_FREQ, + SND_SOC_CLOCK_IN); + if (ret) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", + ret); + + break; + case MI2S_SECONDARY: + break; + case LPASS_DP_RX: + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + return -EINVAL; + } + return 0; +} + +static void sc7180_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case MI2S_PRIMARY: + if (--data->pri_mi2s_clk_count == 0) { + snd_soc_dai_set_sysclk(cpu_dai, + LPASS_MCLK0, + 0, + SNDRV_PCM_STREAM_PLAYBACK); + } + break; + case MI2S_SECONDARY: + break; + case LPASS_DP_RX: + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + break; + } +} + +static const struct snd_soc_ops sc7180_ops = { + .startup = sc7180_snd_startup, + .shutdown = sc7180_snd_shutdown, +}; + +static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static void sc7180_add_ops(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + + for_each_card_prelinks(card, i, link) { + link->ops = &sc7180_ops; + link->init = sc7180_init; + } +} + +static int sc7180_snd_platform_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct sc7180_snd_data *data; + struct device *dev = &pdev->dev; + int ret; + + /* Allocate the private data */ + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + card = &data->card; + snd_soc_card_set_drvdata(card, data); + + card->owner = THIS_MODULE; + card->driver_name = DRIVER_NAME; + card->dev = dev; + card->dapm_widgets = sc7180_snd_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets); + + ret = qcom_snd_parse_of(card); + if (ret) + return ret; + + sc7180_add_ops(card); + + return devm_snd_soc_register_card(dev, card); +} + +static const struct of_device_id sc7180_snd_device_id[] = { + { .compatible = "google,sc7180-trogdor"}, + {}, +}; +MODULE_DEVICE_TABLE(of, sc7180_snd_device_id); + +static struct platform_driver sc7180_snd_driver = { + .probe = sc7180_snd_platform_probe, + .driver = { + .name = "msm-snd-sc7180", + .of_match_table = sc7180_snd_device_id, + }, +}; +module_platform_driver(sc7180_snd_driver); + +MODULE_DESCRIPTION("sc7180 ASoC Machine Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 023e1b1f1164a5e2da2ad20588cf164de9ef67bb Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 27 Oct 2020 11:15:26 +0000 Subject: ASoC: qcom: qdsp6: make use of devm_of_platform_populate make use of devm_of_platform_populate to remove some redundant code! Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201027111526.12326-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6adm.c | 10 +--------- sound/soc/qcom/qdsp6/q6afe.c | 10 +--------- sound/soc/qcom/qdsp6/q6asm.c | 10 +--------- 3 files changed, 3 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c index 72f29720398c..1855b805eba2 100644 --- a/sound/soc/qcom/qdsp6/q6adm.c +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -601,14 +601,7 @@ static int q6adm_probe(struct apr_device *adev) INIT_LIST_HEAD(&adm->copps_list); spin_lock_init(&adm->copps_list_lock); - return of_platform_populate(dev->of_node, NULL, NULL, dev); -} - -static int q6adm_remove(struct apr_device *adev) -{ - of_platform_depopulate(&adev->dev); - - return 0; + return devm_of_platform_populate(dev); } #ifdef CONFIG_OF @@ -621,7 +614,6 @@ MODULE_DEVICE_TABLE(of, q6adm_device_id); static struct apr_driver qcom_q6adm_driver = { .probe = q6adm_probe, - .remove = q6adm_remove, .callback = q6adm_callback, .driver = { .name = "qcom-q6adm", diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 0ca1e4aae518..daa58b5f941e 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -1740,14 +1740,7 @@ static int q6afe_probe(struct apr_device *adev) dev_set_drvdata(dev, afe); - return of_platform_populate(dev->of_node, NULL, NULL, dev); -} - -static int q6afe_remove(struct apr_device *adev) -{ - of_platform_depopulate(&adev->dev); - - return 0; + return devm_of_platform_populate(dev); } #ifdef CONFIG_OF @@ -1760,7 +1753,6 @@ MODULE_DEVICE_TABLE(of, q6afe_device_id); static struct apr_driver qcom_q6afe_driver = { .probe = q6afe_probe, - .remove = q6afe_remove, .callback = q6afe_callback, .driver = { .name = "qcom-q6afe", diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index c547c560cb24..a6618efe22f2 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -1727,14 +1727,7 @@ static int q6asm_probe(struct apr_device *adev) spin_lock_init(&q6asm->slock); dev_set_drvdata(dev, q6asm); - return of_platform_populate(dev->of_node, NULL, NULL, dev); -} - -static int q6asm_remove(struct apr_device *adev) -{ - of_platform_depopulate(&adev->dev); - - return 0; + return devm_of_platform_populate(dev); } #ifdef CONFIG_OF @@ -1747,7 +1740,6 @@ MODULE_DEVICE_TABLE(of, q6asm_device_id); static struct apr_driver qcom_q6asm_driver = { .probe = q6asm_probe, - .remove = q6asm_remove, .callback = q6asm_srvc_callback, .driver = { .name = "qcom-q6asm", -- cgit v1.2.3 From 7c91d02068c342918003606bf378b259f37b31ba Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 28 Oct 2020 14:20:01 +0000 Subject: ASoC: qcom: sm8250: Fix array out of bounds access Static analysis Coverity had detected a potential array out-of-bounds write issue due to the fact that MAX AFE port Id was set to 16 instead of using AFE_PORT_MAX macro. Fix this by properly using AFE_PORT_MAX macro. Fixes: aa2e2785545a ("ASoC: qcom: sm8250: add sound card qrb5165-rb5 support") Reported-by: Colin Ian King Signed-off-by: Srinivas Kandagatla Reviewed-by: Colin Ian King Link: https://lore.kernel.org/r/20201028142001.22431-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 7d43de6d909f..52c40512102f 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -13,12 +13,11 @@ #define DRIVER_NAME "sm8250" #define MI2S_BCLK_RATE 1536000 -#define MAX_SDW_STREAMS 16 struct sm8250_snd_data { - bool stream_prepared[MAX_SDW_STREAMS]; + bool stream_prepared[AFE_PORT_MAX]; struct snd_soc_card *card; - struct sdw_stream_runtime *sruntime[MAX_SDW_STREAMS]; + struct sdw_stream_runtime *sruntime[AFE_PORT_MAX]; }; static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, -- cgit v1.2.3 From bcc96dc3cf8048c80af7c487af17e19be27ac57d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Oct 2020 11:51:12 +0000 Subject: ASoC: qcom: fix unsigned int bitwidth compared to less than zero The check for an error return from the call to snd_pcm_format_width is never true as the unsigned int bitwidth can never be less than zero. Fix this by making bitwidth an int. Fixes: 7cb37b7bd0d3 ("ASoC: qcom: Add support for lpass hdmi driver") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20201028115112.109017-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c index 172952d3a5d6..abfb8737a89f 100644 --- a/sound/soc/qcom/lpass-hdmi.c +++ b/sound/soc/qcom/lpass-hdmi.c @@ -24,7 +24,7 @@ static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream, unsigned int rate = params_rate(params); unsigned int channels = params_channels(params); unsigned int ret; - unsigned int bitwidth; + int bitwidth; unsigned int word_length; unsigned int ch_sts_buf0; unsigned int ch_sts_buf1; -- cgit v1.2.3 From bbc4e1bb5fd6577ed668e7c2ba0705dff1783bce Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 29 Oct 2020 10:15:50 +0000 Subject: ASoC: qcom: sm8250: update compatible with new bindings Update compatible string as board compatible and device compatible should not be same!. Make the driver inline with the new bindings. Fixes: aa2e2785545a ("ASoC: qcom: sm8250: add sound card qrb5165-rb5 support") Reported-by: Rob Herring Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201029101550.31695-2-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 52c40512102f..315ed6ccb7c4 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -207,8 +207,8 @@ static int sm8250_platform_probe(struct platform_device *pdev) } static const struct of_device_id snd_sm8250_dt_match[] = { - {.compatible = "qcom,sdm8250"}, - {.compatible = "qcom,qrb5165-rb5"}, + {.compatible = "qcom,sm8250-sndcard"}, + {.compatible = "qcom,qrb5165-rb5-sndcard"}, {} }; -- cgit v1.2.3 From ec6869b096f10526df14d9972a60ebffef72f0b9 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Wed, 28 Oct 2020 23:48:05 +0100 Subject: ASoC: tegra20-spdif: remove "default m" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make tegra20-spdif default to N as all other drivers do. Signed-off-by: Michał Mirosław Fixes: 774fec338bfc ("ASoC: Tegra: Implement SPDIF CPU DAI") Link: https://lore.kernel.org/r/8756eb5aac561173aa222c9cb64dd314ab1b1f9b.1603925200.git.mirq-linux@rere.qmqm.pl Signed-off-by: Mark Brown --- sound/soc/tegra/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 3d91bd3e59cd..a62cc87551ac 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -39,7 +39,6 @@ config SND_SOC_TEGRA20_I2S config SND_SOC_TEGRA20_SPDIF tristate "Tegra20 SPDIF interface" depends on SND_SOC_TEGRA - default m help Say Y or M if you want to add support for the Tegra20 SPDIF interface. You will also need to select the individual machine drivers to support -- cgit v1.2.3 From 93c0210671d8f3ec2262da703fab93a1497158a8 Mon Sep 17 00:00:00 2001 From: Clément Péron Date: Fri, 30 Oct 2020 15:46:34 +0100 Subject: ASoC: sun4i-i2s: Fix lrck_period computation for I2S justified mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Left and Right justified mode are computed using the same formula as DSP_A and DSP_B mode. Which is wrong and the user manual explicitly says: LRCK_PERDIOD: PCM Mode: Number of BCLKs within (Left + Right) channel width. I2S/Left-Justified/Right-Justified Mode: Number of BCLKs within each individual channel width(Left or Right) Fix this by using the same formula as the I2S mode. Fixes: 7ae7834ec446 ("ASoC: sun4i-i2s: Add support for DSP formats") Signed-off-by: Clément Péron Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/20201030144648.397824-2-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index f23ff29e7c1d..a994b5cf87b3 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -450,11 +450,11 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: - case SND_SOC_DAIFMT_LEFT_J: - case SND_SOC_DAIFMT_RIGHT_J: lrck_period = params_physical_width(params) * slots; break; + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_I2S: lrck_period = params_physical_width(params); break; -- cgit v1.2.3 From c779e2de0ac6156bea63e759481ee383587336cc Mon Sep 17 00:00:00 2001 From: Clément Péron Date: Fri, 30 Oct 2020 15:46:35 +0100 Subject: ASoC: sun4i-i2s: Change set_chan_cfg() params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As slots and slot_width can be set manually using set_tdm(). These values are then kept in sun4i_i2s struct. So we need to check if these values are set or not. This is not done actually and will trigger a bug. For example, if we set to the simple soundcard in the device-tree dai-tdm-slot-width = <32> and then start a stream using S16_LE, currently we would calculate BCLK for 32-bit slots, but program lrck_period for 16-bit slots, making the sample rate double what we expected. To fix this, we need to check if these values are set or not but as this logic is already done by the caller. Avoid duplicating this logic and just pass the required values as params to set_chan_cfg(). Suggested-by: Samuel Holland Acked-by: Maxime Ripard Signed-off-by: Clément Péron Link: https://lore.kernel.org/r/20201030144648.397824-3-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index a994b5cf87b3..4ff2068779fd 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -162,8 +162,15 @@ struct sun4i_i2s_quirks { unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); - int (*set_chan_cfg)(const struct sun4i_i2s *, - const struct snd_pcm_hw_params *); + + /* + * In the set_chan_cfg() function pointer: + * @slots: channels per frame + padding slots, regardless of format + * @slot_width: bits per sample + padding bits, regardless of format + */ + int (*set_chan_cfg)(const struct sun4i_i2s *i2s, + unsigned int channels, unsigned int slots, + unsigned int slot_width); int (*set_fmt)(const struct sun4i_i2s *, unsigned int); }; @@ -399,10 +406,9 @@ static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width) } static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, - const struct snd_pcm_hw_params *params) + unsigned int channels, unsigned int slots, + unsigned int slot_width) { - unsigned int channels = params_channels(params); - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); @@ -419,15 +425,11 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, } static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, - const struct snd_pcm_hw_params *params) + unsigned int channels, unsigned int slots, + unsigned int slot_width) { - unsigned int channels = params_channels(params); - unsigned int slots = channels; unsigned int lrck_period; - if (i2s->slots) - slots = i2s->slots; - /* Map the channels for playback and capture */ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210); @@ -450,13 +452,13 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: - lrck_period = params_physical_width(params) * slots; + lrck_period = slot_width * slots; break; case SND_SOC_DAIFMT_LEFT_J: case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_I2S: - lrck_period = params_physical_width(params); + lrck_period = slot_width; break; default: @@ -482,7 +484,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, unsigned int word_size = params_width(params); unsigned int slot_width = params_physical_width(params); unsigned int channels = params_channels(params); + unsigned int slots = channels; + int ret, sr, wss; u32 width; @@ -492,7 +496,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, if (i2s->slot_width) slot_width = i2s->slot_width; - ret = i2s->variant->set_chan_cfg(i2s, params); + ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width); if (ret < 0) { dev_err(dai->dev, "Invalid channel configuration\n"); return ret; -- cgit v1.2.3 From 73adf87b7a5882408b0a17da59e69df4be12a968 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Fri, 30 Oct 2020 15:46:36 +0100 Subject: ASoC: sun4i-i2s: Add support for H6 I2S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit H6 I2S is very similar to that in H3, except it supports up to 16 channels. Signed-off-by: Jernej Skrabec Signed-off-by: Marcus Cooper Reviewed-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Clément Péron Link: https://lore.kernel.org/r/20201030144648.397824-4-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 222 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 4ff2068779fd..24b3137afbc2 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -124,6 +124,21 @@ #define SUN8I_I2S_RX_CHAN_SEL_REG 0x54 #define SUN8I_I2S_RX_CHAN_MAP_REG 0x58 +/* Defines required for sun50i-h6 support */ +#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK GENMASK(21, 20) +#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset) ((offset) << 20) +#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK GENMASK(19, 16) +#define SUN50I_H6_I2S_TX_CHAN_SEL(chan) ((chan - 1) << 16) +#define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(15, 0) +#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1)) + +#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG 0x44 +#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG 0x48 + +#define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64 +#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68 +#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG 0x6C + struct sun4i_i2s; /** @@ -476,6 +491,60 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, return 0; } +static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + unsigned int channels, unsigned int slots, + unsigned int slot_width) +{ + unsigned int lrck_period; + + /* Map the channels for playback and capture */ + regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0xFEDCBA98); + regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210); + regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98); + regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210); + + /* Configure the channels */ + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN50I_H6_I2S_TX_CHAN_SEL_MASK, + SUN50I_H6_I2S_TX_CHAN_SEL(channels)); + regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG, + SUN50I_H6_I2S_TX_CHAN_SEL_MASK, + SUN50I_H6_I2S_TX_CHAN_SEL(channels)); + + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); + + switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + lrck_period = slot_width * slots; + break; + + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_I2S: + lrck_period = slot_width; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, + SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); + + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN50I_H6_I2S_TX_CHAN_EN_MASK, + SUN50I_H6_I2S_TX_CHAN_EN(channels)); + + return 0; +} + static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -703,6 +772,108 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, return 0; } +static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) +{ + u32 mode, val; + u8 offset; + + /* + * DAI clock polarity + * + * The setup for LRCK contradicts the datasheet, but under a + * scope it's clear that the LRCK polarity is reversed + * compared to the expected polarity on the bus. + */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + val = 0; + break; + case SND_SOC_DAIFMT_NB_NF: + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, + val); + + /* DAI Mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + mode = SUN8I_I2S_CTRL_MODE_PCM; + offset = 1; + break; + + case SND_SOC_DAIFMT_DSP_B: + mode = SUN8I_I2S_CTRL_MODE_PCM; + offset = 0; + break; + + case SND_SOC_DAIFMT_I2S: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 1; + break; + + case SND_SOC_DAIFMT_LEFT_J: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 0; + break; + + case SND_SOC_DAIFMT_RIGHT_J: + mode = SUN8I_I2S_CTRL_MODE_RIGHT; + offset = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_MODE_MASK, mode); + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK, + SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG, + SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK, + SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, + val); + + return 0; +} + static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); @@ -983,6 +1154,22 @@ static const struct reg_default sun8i_i2s_reg_defaults[] = { { SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 }, }; +static const struct reg_default sun50i_h6_i2s_reg_defaults[] = { + { SUN4I_I2S_CTRL_REG, 0x00060000 }, + { SUN4I_I2S_FMT0_REG, 0x00000033 }, + { SUN4I_I2S_FMT1_REG, 0x00000030 }, + { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, + { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, + { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, + { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 }, + { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 }, + { SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 }, + { SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 }, + { SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 }, + { SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 }, + { SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 }, +}; + static const struct regmap_config sun4i_i2s_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1010,6 +1197,19 @@ static const struct regmap_config sun8i_i2s_regmap_config = { .volatile_reg = sun8i_i2s_volatile_reg, }; +static const struct regmap_config sun50i_h6_i2s_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN50I_H6_I2S_RX_CHAN_MAP1_REG, + .cache_type = REGCACHE_FLAT, + .reg_defaults = sun50i_h6_i2s_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(sun50i_h6_i2s_reg_defaults), + .writeable_reg = sun4i_i2s_wr_reg, + .readable_reg = sun8i_i2s_rd_reg, + .volatile_reg = sun8i_i2s_volatile_reg, +}; + static int sun4i_i2s_runtime_resume(struct device *dev) { struct sun4i_i2s *i2s = dev_get_drvdata(dev); @@ -1168,6 +1368,24 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .set_fmt = sun4i_i2s_set_soc_fmt, }; +static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = { + .has_reset = true, + .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, + .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config, + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, + .get_sr = sun8i_i2s_get_sr_wss, + .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun50i_h6_i2s_set_chan_cfg, + .set_fmt = sun50i_h6_i2s_set_soc_fmt, +}; + static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1337,6 +1555,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun50i-a64-codec-i2s", .data = &sun50i_a64_codec_i2s_quirks, }, + { + .compatible = "allwinner,sun50i-h6-i2s", + .data = &sun50i_h6_i2s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); -- cgit v1.2.3 From 9c2d255f0e63f8e54bd8345f9c59c4060cf4bbd4 Mon Sep 17 00:00:00 2001 From: Clément Péron Date: Fri, 30 Oct 2020 15:46:37 +0100 Subject: ASoC: sun4i-i2s: Change get_sr() and get_wss() to be more explicit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are actually using a complex formula to just return a bunch of simple values. Also this formula is wrong for sun4i when calling get_wss() the function return 4 instead of 3. Replace this with a simpler switch case. Also drop the i2s params which is unused and return a simple int as returning an error code could be out of range for an s8 and there is no optim to return a s8 here. Fixes: 619c15f7fac9 ("ASoC: sun4i-i2s: Change SR and WSS computation") Reviewed-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Clément Péron Link: https://lore.kernel.org/r/20201030144648.397824-5-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 69 +++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 24b3137afbc2..6ee9c2995b4f 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -175,8 +175,8 @@ struct sun4i_i2s_quirks { unsigned int num_mclk_dividers; unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); - s8 (*get_sr)(const struct sun4i_i2s *, int); - s8 (*get_wss)(const struct sun4i_i2s *, int); + int (*get_sr)(unsigned int width); + int (*get_wss)(unsigned int width); /* * In the set_chan_cfg() function pointer: @@ -387,37 +387,56 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return 0; } -static s8 sun4i_i2s_get_sr(const struct sun4i_i2s *i2s, int width) +static int sun4i_i2s_get_sr(unsigned int width) { - if (width < 16 || width > 24) - return -EINVAL; - - if (width % 4) - return -EINVAL; + switch (width) { + case 16: + return 0; + case 20: + return 1; + case 24: + return 2; + } - return (width - 16) / 4; + return -EINVAL; } -static s8 sun4i_i2s_get_wss(const struct sun4i_i2s *i2s, int width) +static int sun4i_i2s_get_wss(unsigned int width) { - if (width < 16 || width > 32) - return -EINVAL; - - if (width % 4) - return -EINVAL; + switch (width) { + case 16: + return 0; + case 20: + return 1; + case 24: + return 2; + case 32: + return 3; + } - return (width - 16) / 4; + return -EINVAL; } -static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width) +static int sun8i_i2s_get_sr_wss(unsigned int width) { - if (width % 4) - return -EINVAL; - - if (width < 8 || width > 32) - return -EINVAL; + switch (width) { + case 8: + return 1; + case 12: + return 2; + case 16: + return 3; + case 20: + return 4; + case 24: + return 5; + case 28: + return 6; + case 32: + return 7; + } - return (width - 8) / 4 + 1; + return -EINVAL; } static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, @@ -582,11 +601,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, } i2s->playback_dma_data.addr_width = width; - sr = i2s->variant->get_sr(i2s, word_size); + sr = i2s->variant->get_sr(word_size); if (sr < 0) return -EINVAL; - wss = i2s->variant->get_wss(i2s, slot_width); + wss = i2s->variant->get_wss(slot_width); if (wss < 0) return -EINVAL; -- cgit v1.2.3 From d8659dd9a13ce7a92c017c352aea1c390f300937 Mon Sep 17 00:00:00 2001 From: Marcus Cooper Date: Fri, 30 Oct 2020 15:46:38 +0100 Subject: ASoC: sun4i-i2s: Set sign extend sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the newer SoCs such as the H3 and A64 this is set by default to transfer a 0 after each sample in each slot. However the A10 and A20 SoCs that this driver was developed on had a default setting where it padded the audio gain with zeros. This isn't a problem while we have only support for 16bit audio but with larger sample resolution rates in the pipeline then SEXT bits should be cleared so that they also pad at the LSB. Without this the audio gets distorted. Set sign extend sample for all the sunxi generations even if they are not affected. This will keep consistency and avoid relying on default. Signed-off-by: Marcus Cooper Reviewed-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Clément Péron Link: https://lore.kernel.org/r/20201030144648.397824-6-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 6ee9c2995b4f..46e4da18c27f 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -48,6 +48,9 @@ #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) #define SUN4I_I2S_FMT1_REG 0x08 +#define SUN4I_I2S_FMT1_REG_SEXT_MASK BIT(8) +#define SUN4I_I2S_FMT1_REG_SEXT(sext) ((sext) << 8) + #define SUN4I_I2S_FIFO_TX_REG 0x0c #define SUN4I_I2S_FIFO_RX_REG 0x10 @@ -105,6 +108,9 @@ #define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) #define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7) +#define SUN8I_I2S_FMT1_REG_SEXT_MASK GENMASK(5, 4) +#define SUN8I_I2S_FMT1_REG_SEXT(sext) ((sext) << 4) + #define SUN8I_I2S_INT_STA_REG 0x0c #define SUN8I_I2S_FIFO_TX_REG 0x20 @@ -686,6 +692,7 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, } regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, SUN4I_I2S_CTRL_MODE_MASK, val); + return 0; } @@ -788,6 +795,11 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, val); + /* Set sign extension to pad out LSB with 0 */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG, + SUN8I_I2S_FMT1_REG_SEXT_MASK, + SUN8I_I2S_FMT1_REG_SEXT(0)); + return 0; } @@ -890,6 +902,11 @@ static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, val); + /* Set sign extension to pad out LSB with 0 */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG, + SUN8I_I2S_FMT1_REG_SEXT_MASK, + SUN8I_I2S_FMT1_REG_SEXT(0)); + return 0; } -- cgit v1.2.3 From 6ad7ca6297f8679162ee62ed672b603e8d004146 Mon Sep 17 00:00:00 2001 From: Marcus Cooper Date: Fri, 30 Oct 2020 15:46:39 +0100 Subject: ASoC: sun4i-i2s: Add 20 and 24 bit support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the functionality of the driver to include support of 20 and 24 bits per sample. Signed-off-by: Marcus Cooper Acked-by: Maxime Ripard Reviewed-by: Chen-Yu Tsai Signed-off-by: Clément Péron Link: https://lore.kernel.org/r/20201030144648.397824-7-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 46e4da18c27f..786731191d90 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -600,6 +600,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, case 16: width = DMA_SLAVE_BUSWIDTH_2_BYTES; break; + case 32: + width = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; default: dev_err(dai->dev, "Unsupported physical sample width: %d\n", params_physical_width(params)); @@ -1081,6 +1084,10 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +#define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + static struct snd_soc_dai_driver sun4i_i2s_dai = { .probe = sun4i_i2s_dai_probe, .capture = { @@ -1088,14 +1095,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = { .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SUN4I_FORMATS, }, .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SUN4I_FORMATS, }, .ops = &sun4i_i2s_dai_ops, .symmetric_rates = 1, -- cgit v1.2.3 From 64359246abe4421ad409be5b0bc9a534caa18b7d Mon Sep 17 00:00:00 2001 From: Clément Péron Date: Fri, 30 Oct 2020 15:46:40 +0100 Subject: ASoC: sun4i-i2s: Fix sun8i volatile regs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FIFO TX reg is volatile and sun8i i2s register mapping is different from sun4i. Even if in this case it's doesn't create an issue, Avoid setting some regs that are undefined in sun8i. Acked-by: Maxime Ripard Reviewed-by: Chen-Yu Tsai Signed-off-by: Clément Péron Link: https://lore.kernel.org/r/20201030144648.397824-8-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 786731191d90..003610c0badf 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1162,12 +1162,19 @@ static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg) static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg) { - if (reg == SUN8I_I2S_INT_STA_REG) + switch (reg) { + case SUN4I_I2S_FIFO_CTRL_REG: + case SUN4I_I2S_FIFO_RX_REG: + case SUN4I_I2S_FIFO_STA_REG: + case SUN4I_I2S_RX_CNT_REG: + case SUN4I_I2S_TX_CNT_REG: + case SUN8I_I2S_FIFO_TX_REG: + case SUN8I_I2S_INT_STA_REG: return true; - if (reg == SUN8I_I2S_FIFO_TX_REG) - return false; - return sun4i_i2s_volatile_reg(dev, reg); + default: + return false; + } } static const struct reg_default sun4i_i2s_reg_defaults[] = { -- cgit v1.2.3 From 38d7adc0a003298013786cfffe5f4cc907009d30 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Fri, 30 Oct 2020 15:46:41 +0100 Subject: ASoC: sun4i-i2s: Fix setting of FIFO modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because SUN4I_I2S_FIFO_CTRL_REG is volatile, writes done while the regmap is cache-only are ignored. To work around this, move the configuration to a callback that runs while the ASoC core has a runtime PM reference to the device. Signed-off-by: Samuel Holland Reviewed-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Clément Péron Link: https://lore.kernel.org/r/20201030144648.397824-9-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 003610c0badf..4f5cd850752d 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -596,6 +596,13 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, return ret; } + /* Set significant bits in our FIFOs */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, + SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK | + SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, + SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | + SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); + switch (params_physical_width(params)) { case 16: width = DMA_SLAVE_BUSWIDTH_2_BYTES; @@ -924,13 +931,6 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return ret; } - /* Set significant bits in our FIFOs */ - regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, - SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK | - SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, - SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | - SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); - i2s->format = fmt; return 0; -- cgit v1.2.3 From 08c7b7d546fddce76d500e5e5767aa08836f7cae Mon Sep 17 00:00:00 2001 From: Clément Péron Date: Fri, 30 Oct 2020 15:46:42 +0100 Subject: ASoC: sun4i-i2s: fix coding-style for callback definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checkpatch script produces warning: WARNING: function definition argument 'const struct sun4i_i2s *' should also have an identifier name. Let's fix this by adding identifier name to get_bclk_parent_rate() and set_fmt() callback definition. Acked-by: Maxime Ripard Signed-off-by: Clément Péron Link: https://lore.kernel.org/r/20201030144648.397824-10-peron.clem@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 4f5cd850752d..4b8ca5be0a29 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -180,7 +180,7 @@ struct sun4i_i2s_quirks { const struct sun4i_i2s_clk_div *mclk_dividers; unsigned int num_mclk_dividers; - unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); + unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *i2s); int (*get_sr)(unsigned int width); int (*get_wss)(unsigned int width); @@ -192,7 +192,7 @@ struct sun4i_i2s_quirks { int (*set_chan_cfg)(const struct sun4i_i2s *i2s, unsigned int channels, unsigned int slots, unsigned int slot_width); - int (*set_fmt)(const struct sun4i_i2s *, unsigned int); + int (*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt); }; struct sun4i_i2s { -- cgit v1.2.3 From 35249a5684fd01377bb40e20b8a604774cb073d8 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Sat, 31 Oct 2020 01:05:58 +0800 Subject: ASoC: intel: sof_rt5682: Add support for cml_rt1015_rt5682 This patch adds the driver data and updates quirk info for cml with rt1015 speaker amp and rt5682 headset codec. Due to different mclk frequency on JSL and CML, we need to use 4 slot TDM 100fs to avoid the SSP m/n counter. Signed-off-by: Brent Lu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201030170559.20370-2-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 47 ++++++++++++++++++++--- sound/soc/intel/common/soc-acpi-intel-cml-match.c | 13 +++++++ 2 files changed, 55 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index ddbb9fe7cc06..7701957e0eb7 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -42,8 +42,9 @@ #define SOF_RT5682_NUM_HDMIDEV(quirk) \ ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK) #define SOF_RT1015_SPEAKER_AMP_PRESENT BIT(13) -#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(14) -#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(15) +#define SOF_RT1015_SPEAKER_AMP_100FS BIT(14) +#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15) +#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -291,21 +292,26 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct snd_soc_dai *codec_dai; - int i, ret; + int i, fs, ret; if (!snd_soc_card_get_codec_dai(card, "rt1015-aif")) return 0; + if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_100FS) + fs = 100; + else + fs = 64; + for_each_rtd_codec_dais(rtd, i, codec_dai) { /* Set tdm/i2s1 master bclk ratio */ - ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); + ret = snd_soc_dai_set_bclk_ratio(codec_dai, fs); if (ret < 0) { dev_err(card->dev, "failed to set bclk ratio\n"); return ret; } ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, - params_rate(params) * 64, + params_rate(params) * fs, params_rate(params) * 256); if (ret < 0) { dev_err(card->dev, "failed to set pll\n"); @@ -319,6 +325,26 @@ static int sof_rt1015_hw_params(struct snd_pcm_substream *substream, dev_err(card->dev, "failed to set sysclk\n"); return ret; } + + if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_100FS) { + if (!strcmp(codec_dai->component->name, "i2c-10EC1015:00")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x0, 0x1, 4, 24); + if (ret < 0) { + dev_err(card->dev, "failed to set tdm slot\n"); + return ret; + } + } + + if (!strcmp(codec_dai->component->name, "i2c-10EC1015:01")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x0, 0x2, 4, 24); + if (ret < 0) { + dev_err(card->dev, "failed to set tdm slot\n"); + return ret; + } + } + } } return 0; @@ -875,6 +901,16 @@ static const struct platform_device_id board_ids[] = { SOF_MAX98360A_SPEAKER_AMP_PRESENT | SOF_RT5682_SSP_AMP(1)), }, + { + .name = "cml_rt1015_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT1015_SPEAKER_AMP_PRESENT | + SOF_RT1015_SPEAKER_AMP_100FS | + SOF_RT5682_SSP_AMP(1)), + }, { } }; @@ -898,3 +934,4 @@ MODULE_ALIAS("platform:tgl_max98357a_rt5682"); MODULE_ALIAS("platform:jsl_rt5682_rt1015"); MODULE_ALIAS("platform:tgl_max98373_rt5682"); MODULE_ALIAS("platform:jsl_rt5682_max98360a"); +MODULE_ALIAS("platform:cml_rt1015_rt5682"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index 26dde88bb227..adddc91918df 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -14,6 +14,11 @@ static struct snd_soc_acpi_codecs rt1011_spk_codecs = { .codecs = {"10EC1011"} }; +static struct snd_soc_acpi_codecs rt1015_spk_codecs = { + .num_codecs = 1, + .codecs = {"10EC1015"} +}; + static struct snd_soc_acpi_codecs max98357a_spk_codecs = { .num_codecs = 1, .codecs = {"MX98357A"} @@ -38,6 +43,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", }, + { + .id = "10EC5682", + .drv_name = "cml_rt1015_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rt1015_spk_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", + }, { .id = "10EC5682", .drv_name = "sof_rt5682", -- cgit v1.2.3 From bdd088ce5bfd32b95ab1bd90b49405e7c1f1fff5 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Sat, 31 Oct 2020 01:05:59 +0800 Subject: ASoC: intel: sof_rt5682: Add quirk for Dooly This DMI product family string of this board is "Google_Hatch" so the DMI quirk will take place. However, this board is using rt1015 speaker amp instead of max98357a specified in the quirk. Therefore, we need an new DMI quirk for this board. Signed-off-by: Brent Lu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201030170559.20370-3-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 7701957e0eb7..e7d9a82ca70d 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -100,6 +100,24 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { SOF_RT5682_MCLK_24MHZ | SOF_RT5682_SSP_CODEC(1)), }, + { + /* + * Dooly is hatch family but using rt1015 amp so it + * requires a quirk before "Google_Hatch". + */ + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "Dooly"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT1015_SPEAKER_AMP_PRESENT | + SOF_RT1015_SPEAKER_AMP_100FS | + SOF_RT5682_SSP_AMP(1)), + }, { .callback = sof_rt5682_quirk_cb, .matches = { -- cgit v1.2.3 From 46713ed258695e2de00ab2738160f89220c0a976 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 1 Nov 2020 08:00:37 -0800 Subject: ASoC: bcm2835-i2s: remove unneeded semicolon A semicolon is not needed after a switch statement. Signed-off-by: Tom Rix Link: https://lore.kernel.org/r/20201101160037.2295512-1-trix@redhat.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index dc34fe1559c6..c2f7631e8705 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -797,7 +797,7 @@ static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg) @@ -807,7 +807,7 @@ static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static const struct regmap_config bcm2835_regmap_config = { -- cgit v1.2.3 From ff3cfccba4dd87bb89ca185b58b38b9a74260138 Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 29 Oct 2020 08:25:13 +0000 Subject: ASoC: ti: davinci-evm: Remove redundant null check before clk_disable_unprepare Because clk_disable_unprepare() already checked NULL clock parameter, so the additional check is unnecessary, just remove it. Signed-off-by: Xu Wang Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201029082513.28233-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/ti/davinci-evm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index 105e56ab9cdc..b043a0070d20 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -46,8 +46,7 @@ static void evm_shutdown(struct snd_pcm_substream *substream) struct snd_soc_card_drvdata_davinci *drvdata = snd_soc_card_get_drvdata(soc_card); - if (drvdata->mclk) - clk_disable_unprepare(drvdata->mclk); + clk_disable_unprepare(drvdata->mclk); } static int evm_hw_params(struct snd_pcm_substream *substream, -- cgit v1.2.3 From c1af06a28a0176ceb1fc71408b32aabf53db4470 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 1 Nov 2020 09:19:43 -0800 Subject: ASoC: Intel: remove unneeded semicolon A semicolon is not needed after a switch statement. Signed-off-by: Tom Rix Acked-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201101171943.2305030-1-trix@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 2 +- sound/soc/intel/catpt/loader.c | 2 +- sound/soc/intel/catpt/pcm.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index e90590559185..e21e11dac000 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -186,7 +186,7 @@ int sst_driver_ops(struct intel_sst_drv *sst) "SST Driver capabilities missing for dev_id: %x", sst->dev_id); return -EINVAL; - }; + } } void sst_process_pending_msg(struct work_struct *work) diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index 8a5f20abcadb..40c22e4bb263 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -304,7 +304,7 @@ static int catpt_load_block(struct catpt_dev *cdev, default: sram = &cdev->dram; break; - }; + } dst_addr = sram->start + blk->ram_offset; if (alloc) { diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index ba653ebea7d1..1775540ac92b 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -92,7 +92,7 @@ catpt_get_stream_template(struct snd_pcm_substream *substream) break; default: break; - }; + } return catpt_topology[type]; } @@ -419,7 +419,7 @@ static int catpt_dai_apply_usettings(struct snd_soc_dai *dai, break; default: return 0; - }; + } list_for_each_entry(pos, &component->card->snd_card->controls, list) { if (pos->private_data == component && -- cgit v1.2.3 From f4bf1f4d1385b7cb61a3fc811bb4912d49aa394a Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Tue, 3 Nov 2020 12:05:54 +0200 Subject: ASoC: atmel-i2s: do not warn if muxclk is missing Besides the fact that muxclk is optional, muxclk can be set using assigned-clocks, removing the need to set it in driver. The warning is thus unneeded, so we can transform it in a debug print, eventually to just reflect that muxclk was not set by the driver. Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20201103100554.1307190-1-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index bbe2b638abb5..232300dda548 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -563,8 +563,8 @@ static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev, err = PTR_ERR(muxclk); if (err == -EPROBE_DEFER) return -EPROBE_DEFER; - dev_warn(dev->dev, - "failed to get the I2S clock control: %d\n", err); + dev_dbg(dev->dev, + "failed to get the I2S clock control: %d\n", err); return 0; } -- cgit v1.2.3 From 99503469bdb54868fc9566480f1897c85dddd256 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 1 Nov 2020 09:17:42 -0800 Subject: ASoC: TSCS454: remove unneeded semicolon A semicolon is not needed after a switch statement. Signed-off-by: Tom Rix Link: https://lore.kernel.org/r/20201101171742.2304458-1-trix@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/tscs454.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index d0af16b4db2f..cd1f1a592386 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -177,7 +177,7 @@ static bool tscs454_volatile(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool tscs454_writable(struct device *dev, unsigned int reg) @@ -197,7 +197,7 @@ static bool tscs454_writable(struct device *dev, unsigned int reg) return false; default: return true; - }; + } } static bool tscs454_readable(struct device *dev, unsigned int reg) @@ -217,7 +217,7 @@ static bool tscs454_readable(struct device *dev, unsigned int reg) return false; default: return true; - }; + } } static bool tscs454_precious(struct device *dev, unsigned int reg) @@ -246,7 +246,7 @@ static bool tscs454_precious(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static const struct regmap_range_cfg tscs454_regmap_range_cfg = { -- cgit v1.2.3 From 19f6e424d6150b5eede2277dbc6dfd3bf42e994f Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Mon, 2 Nov 2020 18:34:28 +0800 Subject: ASoC: ti: davinci-mcasp: remove always zero of davinci_mcasp_get_dt_params davinci_mcasp_get_dt_params alway return zero, and its return value could be ignored by the caller. So make it 'void' type to avoid the check its return value. Fixes: 764958f2b5239 ("ASoC: ti: davinci-mcasp: Support for auxclk-fs-ratio") Signed-off-by: Zhang Qilong Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201102103428.32678-1-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index a6b72ad53b43..9df8194a2c22 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2110,20 +2110,18 @@ static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) } #endif /* CONFIG_GPIOLIB */ -static int davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp) +static void davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp) { struct device_node *np = mcasp->dev->of_node; int ret; u32 val; if (!np) - return 0; + return; ret = of_property_read_u32(np, "auxclk-fs-ratio", &val); if (ret >= 0) mcasp->auxclk_fs_ratio = val; - - return 0; } static int davinci_mcasp_probe(struct platform_device *pdev) @@ -2359,9 +2357,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret) goto err; - ret = davinci_mcasp_get_dt_params(mcasp); - if (ret) - return -EINVAL; + davinci_mcasp_get_dt_params(mcasp); ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, -- cgit v1.2.3 From 0246c6cb246f36ffcac0b843da179ab6510e139b Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 1 Nov 2020 09:24:12 -0800 Subject: ASoC: tegra: remove unneeded semicolon A semicolon is not needed after a switch statement. Signed-off-by: Tom Rix Acked-by: Sameer Pujar Link: https://lore.kernel.org/r/20201101172412.2306144-1-trix@redhat.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra186_dspk.c | 6 +++--- sound/soc/tegra/tegra210_dmic.c | 6 +++--- sound/soc/tegra/tegra210_i2s.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index 0cbe31e2c7e9..7d9948fb2ca7 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -310,7 +310,7 @@ static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg) @@ -326,7 +326,7 @@ static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg) @@ -339,7 +339,7 @@ static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static const struct regmap_config tegra186_dspk_regmap = { diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index a661f40bc41c..ead2c99bf72e 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -322,7 +322,7 @@ static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg) @@ -338,7 +338,7 @@ static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg) @@ -353,7 +353,7 @@ static bool tegra210_dmic_volatile_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static const struct regmap_config tegra210_dmic_regmap_config = { diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index a383bd5c51cd..ca31ec92e508 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -662,7 +662,7 @@ static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg) @@ -682,7 +682,7 @@ static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg) @@ -701,7 +701,7 @@ static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static const struct regmap_config tegra210_i2s_regmap_config = { -- cgit v1.2.3 From 3d13ea9b8db71515d8f4795ec7a044e75999bd83 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 3 Nov 2020 13:18:53 +0300 Subject: ASoC: qcom: sc7180: Fix some indenting in sc7180_lpass_alloc_dma_channel() This code is correct, but it should be indented one more tab. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20201103101853.GD1127762@mwanda Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-sc7180.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index c6292f9e613f..61a208fe6875 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -96,8 +96,8 @@ static int sc7180_lpass_alloc_dma_channel(struct lpass_data *drvdata, chan = find_first_zero_bit(&drvdata->dma_ch_bit_map, v->rdma_channels); - if (chan >= v->rdma_channels) - return -EBUSY; + if (chan >= v->rdma_channels) + return -EBUSY; } else { chan = find_next_zero_bit(&drvdata->dma_ch_bit_map, v->wrdma_channel_start + -- cgit v1.2.3 From 32c5dca18be7ad88629c33f51ba7f05ae97930fa Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 1 Nov 2020 08:03:12 -0800 Subject: ASoC: TSCS42xx: remove unneeded semicolon A semicolon is not needed after a switch statement. Signed-off-by: Tom Rix Link: https://lore.kernel.org/r/20201101160312.2296146-1-trix@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/tscs42xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index 3265d3e8cb28..6200fab7896f 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -66,7 +66,7 @@ static bool tscs42xx_volatile(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool tscs42xx_precious(struct device *dev, unsigned int reg) @@ -81,7 +81,7 @@ static bool tscs42xx_precious(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static const struct regmap_config tscs42xx_regmap = { @@ -1294,7 +1294,7 @@ static int part_is_valid(struct tscs42xx *tscs42xx) return true; default: return false; - }; + } } static int set_sysclk(struct snd_soc_component *component) -- cgit v1.2.3 From 1a6a071f51a5373de21edd34f9b79610be2d02e3 Mon Sep 17 00:00:00 2001 From: Yu Hao Date: Tue, 3 Nov 2020 14:33:35 -0800 Subject: ALSA: seq: remove useless function The function snd_seq_queue_client_termination() is only called from the function seq_free_client1(). The function seq_free_client1() calls the function snd_seq_queue_client_leave() and the function snd_seq_queue_client_termination() together. Because the function snd_seq_queue_client_leave() does all things, so the function snd_seq_queue_client_termination() is a useless function. Signed-off-by: Yu Hao Link: https://lore.kernel.org/r/20201103223335.21831-1-yuhaobehappy@gmail.com Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 1 - sound/core/seq/seq_queue.c | 27 --------------------------- sound/core/seq/seq_queue.h | 3 --- 3 files changed, 31 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index cc93157fa950..f9f2fea58b32 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -279,7 +279,6 @@ static int seq_free_client1(struct snd_seq_client *client) snd_seq_delete_all_ports(client); snd_seq_queue_client_leave(client->number); snd_use_lock_sync(&client->use_lock); - snd_seq_queue_client_termination(client->number); if (client->pool) snd_seq_pool_delete(&client->pool); spin_lock_irq(&clients_lock); diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 71a6ea62c3be..13cfc2d47fa7 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -537,33 +537,6 @@ int snd_seq_queue_is_used(int queueid, int client) /*----------------------------------------------------------------*/ -/* notification that client has left the system - - * stop the timer on all queues owned by this client - */ -void snd_seq_queue_client_termination(int client) -{ - unsigned long flags; - int i; - struct snd_seq_queue *q; - bool matched; - - for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { - if ((q = queueptr(i)) == NULL) - continue; - spin_lock_irqsave(&q->owner_lock, flags); - matched = (q->owner == client); - if (matched) - q->klocked = 1; - spin_unlock_irqrestore(&q->owner_lock, flags); - if (matched) { - if (q->timer->running) - snd_seq_timer_stop(q->timer); - snd_seq_timer_reset(q->timer); - } - queuefree(q); - } -} - /* final stage notification - * remove cells for no longer exist client (for non-owned queue) * or delete this queue (for owned queue) diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h index 9254c8dbe5e3..1c3a8d3254d9 100644 --- a/sound/core/seq/seq_queue.h +++ b/sound/core/seq/seq_queue.h @@ -59,9 +59,6 @@ struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int f /* delete queue (destructor) */ int snd_seq_queue_delete(int client, int queueid); -/* notification that client has left the system */ -void snd_seq_queue_client_termination(int client); - /* final stage */ void snd_seq_queue_client_leave(int client); -- cgit v1.2.3 From 841fb1096713bdd85cb2484557623136e10041d2 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 30 Oct 2020 10:54:22 -0400 Subject: ASoC: topology: Remove unused functions from topology API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Topology API exposes snd_soc_tplg_widget_remove and snd_soc_tplg_widget_remove_all, but both are nowhere used. All current users load and unload topology as a whole. As following commits introduce resource managed memory, remove them to simplify code and reduce maintenance burden. Reviewed-by: Guennadi Liakhovetski Signed-off-by: Amadeusz Sławiński Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201030145427.3497990-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 5 ----- sound/soc/soc-topology.c | 37 +------------------------------------ 2 files changed, 1 insertion(+), 41 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 5223896de26f..b1ac5df82dba 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -185,11 +185,6 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, u32 index); int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index); -/* Widget removal - widgets also removed wth component API */ -void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w); -void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm, - u32 index); - /* Binds event handlers to dynamic widgets */ int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w, const struct snd_soc_tplg_widget_events *events, int num_events, diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index c5ef432a023b..7919097c162f 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1725,7 +1725,7 @@ widget: return 0; ready_err: - snd_soc_tplg_widget_remove(widget); + remove_widget(widget->dapm->component, &widget->dobj, SOC_TPLG_PASS_WIDGET); snd_soc_dapm_free_widget(widget); hdr_err: kfree(template.sname); @@ -2834,41 +2834,6 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, } EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load); -/* remove this dynamic widget */ -void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w) -{ - /* make sure we are a widget */ - if (w->dobj.type != SND_SOC_DOBJ_WIDGET) - return; - - remove_widget(w->dapm->component, &w->dobj, SOC_TPLG_PASS_WIDGET); -} -EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove); - -/* remove all dynamic widgets from this DAPM context */ -void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm, - u32 index) -{ - struct snd_soc_dapm_widget *w, *next_w; - - for_each_card_widgets_safe(dapm->card, w, next_w) { - - /* make sure we are a widget with correct context */ - if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm) - continue; - - /* match ID */ - if (w->dobj.index != index && - w->dobj.index != SND_SOC_TPLG_INDEX_ALL) - continue; - /* check and free and dynamic widget kcontrols */ - snd_soc_tplg_widget_remove(w); - snd_soc_dapm_free_widget(w); - } - snd_soc_dapm_reset_cache(dapm); -} -EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all); - /* remove dynamic controls from the component driver */ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) { -- cgit v1.2.3 From a5b8f71c5477f4327c66a085d9714fe298510819 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 30 Oct 2020 10:54:23 -0400 Subject: ASoC: topology: Remove multistep topology loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In theory topology can be loaded in multiple steps by providing index to snd_soc_tplg_component_load, however, from usability point of view it doesn't make sense, as can be seen from all current users loading topology in one go. Remove the unnecessary parameter. Reviewed-by: Guennadi Liakhovetski Signed-off-by: Amadeusz Sławiński Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201030145427.3497990-3-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 8 ++------ sound/soc/intel/skylake/skl-topology.c | 9 ++------- sound/soc/soc-topology.c | 18 +++--------------- sound/soc/sof/pcm.c | 2 +- sound/soc/sof/topology.c | 4 +--- 5 files changed, 9 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index b1ac5df82dba..328cf763d9b4 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -31,9 +31,6 @@ struct snd_soc_dai_driver; struct snd_soc_dai; struct snd_soc_dapm_route; -/* object scan be loaded and unloaded in groups with identfying indexes */ -#define SND_SOC_TPLG_INDEX_ALL 0 /* ID that matches all FW objects */ - /* dynamic object type */ enum snd_soc_dobj_type { SND_SOC_DOBJ_NONE = 0, /* object is not dynamic */ @@ -181,9 +178,8 @@ static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr) /* Dynamic Object loading and removal for component drivers */ int snd_soc_tplg_component_load(struct snd_soc_component *comp, - struct snd_soc_tplg_ops *ops, const struct firmware *fw, - u32 index); -int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index); + struct snd_soc_tplg_ops *ops, const struct firmware *fw); +int snd_soc_tplg_component_remove(struct snd_soc_component *comp); /* Binds event handlers to dynamic widgets */ int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 40bee10b0c65..ae466cd59292 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3742,12 +3742,7 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) } component_load: - - /* - * The complete tplg for SKL is loaded as index 0, we don't use - * any other index - */ - ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0); + ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw); if (ret < 0) { dev_err(bus->dev, "tplg component load failed%d\n", ret); goto err; @@ -3777,5 +3772,5 @@ void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) list_del(&ppl->node); /* clean up topology */ - snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); + snd_soc_tplg_component_remove(component); } diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 7919097c162f..2a71cec7277e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -64,7 +64,6 @@ struct soc_tplg { struct device *dev; struct snd_soc_component *comp; u32 index; /* current block index */ - u32 req_index; /* required index, only loaded/free matching blocks */ /* vendor specific kcontrol operations */ const struct snd_soc_tplg_kcontrol_ops *io_ops; @@ -2680,11 +2679,6 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr); - /* check for matching ID */ - if (le32_to_cpu(hdr->index) != tplg->req_index && - tplg->req_index != SND_SOC_TPLG_INDEX_ALL) - return 0; - tplg->index = le32_to_cpu(hdr->index); switch (le32_to_cpu(hdr->type)) { @@ -2804,7 +2798,7 @@ static int soc_tplg_load(struct soc_tplg *tplg) /* load audio component topology from "firmware" file */ int snd_soc_tplg_component_load(struct snd_soc_component *comp, - struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id) + struct snd_soc_tplg_ops *ops, const struct firmware *fw) { struct soc_tplg tplg; int ret; @@ -2819,7 +2813,6 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, tplg.dev = comp->dev; tplg.comp = comp; tplg.ops = ops; - tplg.req_index = id; tplg.io_ops = ops->io_ops; tplg.io_ops_count = ops->io_ops_count; tplg.bytes_ext_ops = ops->bytes_ext_ops; @@ -2828,14 +2821,14 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, ret = soc_tplg_load(&tplg); /* free the created components if fail to load topology */ if (ret) - snd_soc_tplg_component_remove(comp, SND_SOC_TPLG_INDEX_ALL); + snd_soc_tplg_component_remove(comp); return ret; } EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load); /* remove dynamic controls from the component driver */ -int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) +int snd_soc_tplg_component_remove(struct snd_soc_component *comp) { struct snd_soc_dobj *dobj, *next_dobj; int pass = SOC_TPLG_PASS_END; @@ -2847,11 +2840,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list, list) { - /* match index */ - if (dobj->index != index && - index != SND_SOC_TPLG_INDEX_ALL) - continue; - switch (dobj->type) { case SND_SOC_DOBJ_MIXER: remove_mixer(comp, dobj, pass); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index cbac6f17c52f..0a70e685f826 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -780,7 +780,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) static void sof_pcm_remove(struct snd_soc_component *component) { /* remove topology */ - snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); + snd_soc_tplg_component_remove(component); } void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 523a386fce4b..44fddeda6043 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3734,9 +3734,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) return ret; } - ret = snd_soc_tplg_component_load(scomp, - &sof_tplg_ops, fw, - SND_SOC_TPLG_INDEX_ALL); + ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw); if (ret < 0) { dev_err(scomp->dev, "error: tplg component load failed %d\n", ret); -- cgit v1.2.3 From e59db12b8df3ab07dcfe3540ecdf782d4272f263 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 30 Oct 2020 10:54:24 -0400 Subject: ASoC: topology: Unify all device references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In few places tplg->comp->dev is used, while everywhere else tplg->dev is being used. Unify those uses towards tplg->dev, as it is being set to comp->dev during initialization anyway. Reviewed-by: Guennadi Liakhovetski Signed-off-by: Amadeusz Sławiński Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201030145427.3497990-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 2a71cec7277e..9d95c1b01c5a 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1865,7 +1865,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); if (ret < 0) { - dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); + dev_err(tplg->dev, "ASoC: DAI loading failed\n"); goto err; } @@ -1875,7 +1875,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list); /* register the DAI to the component */ - dai = devm_snd_soc_register_dai(tplg->comp->dev, tplg->comp, dai_drv, false); + dai = devm_snd_soc_register_dai(tplg->dev, tplg->comp, dai_drv, false); if (!dai) return -ENOMEM; @@ -1982,13 +1982,13 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, /* pass control to component driver for optional further init */ ret = soc_tplg_dai_link_load(tplg, link, NULL); if (ret < 0) { - dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n"); + dev_err(tplg->dev, "ASoC: FE link loading failed\n"); goto err; } ret = snd_soc_add_pcm_runtime(tplg->comp->card, link); if (ret < 0) { - dev_err(tplg->comp->dev, "ASoC: adding FE link failed\n"); + dev_err(tplg->dev, "ASoC: adding FE link failed\n"); goto err; } @@ -2493,7 +2493,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai); if (ret < 0) { - dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); + dev_err(tplg->dev, "ASoC: DAI loading failed\n"); goto err; } -- cgit v1.2.3 From ff922622443767b27232eb01bae1d9a8d42df073 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 30 Oct 2020 10:54:25 -0400 Subject: ASoC: topology: Change allocations to resource managed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order for topology to be resource managed, change all allocations to be resource managed: k*alloc -> devm_k*alloc kstrdup -> devm_kstrdup Exceptions where non resource managed allocation is left is soc_tplg_dapm_widget_create(), as it uses pointer to memory locally and frees it up after use, as well as soc_tplg_dapm_graph_elems_load(), which has temporary pointer to table of routes. After conversion all redundant calls in error and clean up paths were removed. Also removed some variables which become unneeded when there is no calls using them. Reviewed-by: Guennadi Liakhovetski Signed-off-by: Amadeusz Sławiński Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201030145427.3497990-5-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 171 +++++++++++------------------------------------ 1 file changed, 40 insertions(+), 131 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 9d95c1b01c5a..6ef508f56a5f 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -359,9 +359,6 @@ static void remove_mixer(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) { struct snd_card *card = comp->card->snd_card; - struct soc_mixer_control *sm = - container_of(dobj, struct soc_mixer_control, dobj); - const unsigned int *p = NULL; if (pass != SOC_TPLG_PASS_MIXER) return; @@ -369,12 +366,8 @@ static void remove_mixer(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - if (dobj->control.kcontrol->tlv.p) - p = dobj->control.kcontrol->tlv.p; snd_ctl_remove(card, dobj->control.kcontrol); list_del(&dobj->list); - kfree(sm); - kfree(p); } /* remove an enum kcontrol */ @@ -395,7 +388,6 @@ static void remove_enum(struct snd_soc_component *comp, soc_tplg_denum_remove_values(se); soc_tplg_denum_remove_texts(se); - kfree(se); } /* remove a byte kcontrol */ @@ -403,8 +395,6 @@ static void remove_bytes(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) { struct snd_card *card = comp->card->snd_card; - struct soc_bytes_ext *sb = - container_of(dobj, struct soc_bytes_ext, dobj); if (pass != SOC_TPLG_PASS_MIXER) return; @@ -414,16 +404,12 @@ static void remove_bytes(struct snd_soc_component *comp, snd_ctl_remove(card, dobj->control.kcontrol); list_del(&dobj->list); - kfree(sb); } /* remove a route */ static void remove_route(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) { - struct snd_soc_dapm_route *route = - container_of(dobj, struct snd_soc_dapm_route, dobj); - if (pass != SOC_TPLG_PASS_GRAPH) return; @@ -431,7 +417,6 @@ static void remove_route(struct snd_soc_component *comp, dobj->ops->dapm_route_unload(comp, dobj); list_del(&dobj->list); - kfree(route); } /* remove a widget and it's kcontrols - routes must be removed first */ @@ -469,30 +454,17 @@ static void remove_widget(struct snd_soc_component *comp, soc_tplg_denum_remove_values(se); soc_tplg_denum_remove_texts(se); - kfree(se); - kfree(w->kcontrol_news[i].name); } } else { /* volume mixer or bytes controls */ for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) { struct snd_kcontrol *kcontrol = w->kcontrols[i]; - if (dobj->widget.kcontrol_type - == SND_SOC_TPLG_TYPE_MIXER) - kfree(kcontrol->tlv.p); - - /* Private value is used as struct soc_mixer_control - * for volume mixers or soc_bytes_ext for bytes - * controls. - */ - kfree((void *)kcontrol->private_value); snd_ctl_remove(card, kcontrol); - kfree(w->kcontrol_news[i].name); } } free_news: - kfree(w->kcontrol_news); list_del(&dobj->list); @@ -517,11 +489,7 @@ static void remove_dai(struct snd_soc_component *comp, if (dai->driver == dai_drv) dai->driver = NULL; - kfree(dai_drv->playback.stream_name); - kfree(dai_drv->capture.stream_name); - kfree(dai_drv->name); list_del(&dobj->list); - kfree(dai_drv); } /* remove link configurations */ @@ -540,11 +508,6 @@ static void remove_link(struct snd_soc_component *comp, list_del(&dobj->list); snd_soc_remove_pcm_runtime(comp->card, snd_soc_get_pcm_runtime(comp->card, link)); - - kfree(link->name); - kfree(link->stream_name); - kfree(link->cpus->dai_name); - kfree(link); } /* unload dai link */ @@ -699,7 +662,7 @@ static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg, unsigned int item_len = 2 * sizeof(unsigned int); unsigned int *p; - p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL); + p = devm_kzalloc(tplg->dev, item_len + 2 * sizeof(unsigned int), GFP_KERNEL); if (!p) return -ENOMEM; @@ -743,7 +706,6 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg, static inline void soc_tplg_free_tlv(struct soc_tplg *tplg, struct snd_kcontrol_new *kc) { - kfree(kc->tlv.p); } static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, @@ -771,7 +733,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) return -EINVAL; - sbe = kzalloc(sizeof(*sbe), GFP_KERNEL); + sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); if (sbe == NULL) return -ENOMEM; @@ -797,7 +759,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg); if (err) { soc_control_err(tplg, &be->hdr, be->hdr.name); - kfree(sbe); break; } @@ -807,7 +768,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", be->hdr.name); - kfree(sbe); break; } @@ -817,7 +777,6 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, if (err < 0) { dev_err(tplg->dev, "ASoC: failed to add %s\n", be->hdr.name); - kfree(sbe); break; } @@ -853,7 +812,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) return -EINVAL; - sm = kzalloc(sizeof(*sm), GFP_KERNEL); + sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); if (sm == NULL) return -ENOMEM; tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + @@ -892,7 +851,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg); if (err) { soc_control_err(tplg, &mc->hdr, mc->hdr.name); - kfree(sm); break; } @@ -901,7 +859,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, if (err < 0) { dev_err(tplg->dev, "ASoC: failed to create TLV %s\n", mc->hdr.name); - kfree(sm); break; } @@ -912,7 +869,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); soc_tplg_free_tlv(tplg, &kc); - kfree(sm); break; } @@ -923,7 +879,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, dev_err(tplg->dev, "ASoC: failed to add %s\n", mc->hdr.name); soc_tplg_free_tlv(tplg, &kc); - kfree(sm); break; } @@ -933,13 +888,13 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, return err; } -static int soc_tplg_denum_create_texts(struct soc_enum *se, - struct snd_soc_tplg_enum_control *ec) +static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *se, + struct snd_soc_tplg_enum_control *ec) { int i, ret; se->dobj.control.dtexts = - kcalloc(le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL); + devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL); if (se->dobj.control.dtexts == NULL) return -ENOMEM; @@ -951,7 +906,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se, goto err; } - se->dobj.control.dtexts[i] = kstrdup(ec->texts[i], GFP_KERNEL); + se->dobj.control.dtexts[i] = devm_kstrdup(tplg->dev, ec->texts[i], GFP_KERNEL); if (!se->dobj.control.dtexts[i]) { ret = -ENOMEM; goto err; @@ -970,22 +925,17 @@ err: static inline void soc_tplg_denum_remove_texts(struct soc_enum *se) { - int i = se->items; - - for (--i; i >= 0; i--) - kfree(se->dobj.control.dtexts[i]); - kfree(se->dobj.control.dtexts); } -static int soc_tplg_denum_create_values(struct soc_enum *se, - struct snd_soc_tplg_enum_control *ec) +static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *se, + struct snd_soc_tplg_enum_control *ec) { int i; if (le32_to_cpu(ec->items) > sizeof(*ec->values)) return -EINVAL; - se->dobj.control.dvalues = kzalloc(le32_to_cpu(ec->items) * + se->dobj.control.dvalues = devm_kzalloc(tplg->dev, le32_to_cpu(ec->items) * sizeof(u32), GFP_KERNEL); if (!se->dobj.control.dvalues) @@ -1001,7 +951,6 @@ static int soc_tplg_denum_create_values(struct soc_enum *se, static inline void soc_tplg_denum_remove_values(struct soc_enum *se) { - kfree(se->dobj.control.dvalues); } static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, @@ -1030,7 +979,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) return -EINVAL; - se = kzalloc((sizeof(*se)), GFP_KERNEL); + se = devm_kzalloc(tplg->dev, (sizeof(*se)), GFP_KERNEL); if (se == NULL) return -ENOMEM; @@ -1061,7 +1010,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, switch (le32_to_cpu(ec->hdr.ops.info)) { case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: case SND_SOC_TPLG_CTL_ENUM_VALUE: - err = soc_tplg_denum_create_values(se, ec); + err = soc_tplg_denum_create_values(tplg, se, ec); if (err < 0) { dev_err(tplg->dev, "ASoC: could not create values for %s\n", @@ -1072,7 +1021,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - err = soc_tplg_denum_create_texts(se, ec); + err = soc_tplg_denum_create_texts(tplg, se, ec); if (err < 0) { dev_err(tplg->dev, "ASoC: could not create texts for %s\n", @@ -1118,7 +1067,6 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, return 0; err_denum: - kfree(se); return err; } @@ -1195,7 +1143,7 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; struct snd_soc_tplg_dapm_graph_elem *elem; struct snd_soc_dapm_route **routes; - int count, i, j; + int count, i; int ret = 0; count = le32_to_cpu(hdr->count); @@ -1224,15 +1172,9 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, * each route can be freed when it is removed in remove_route(). */ for (i = 0; i < count; i++) { - routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL); - if (!routes[i]) { - /* free previously allocated memory */ - for (j = 0; j < i; j++) - kfree(routes[j]); - - kfree(routes); + routes[i] = devm_kzalloc(tplg->dev, sizeof(*routes[i]), GFP_KERNEL); + if (!routes[i]) return -ENOMEM; - } } for (i = 0; i < count; i++) { @@ -1289,15 +1231,6 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, snd_soc_dapm_add_routes(dapm, routes[i], 1); } - /* - * free memory allocated for all dapm routes not added to the - * list in case of error - */ - if (ret < 0) { - while (i < count) - kfree(routes[i++]); - } - /* * free pointer to array of dapm routes as this is no longer needed. * The memory allocated for each dapm route will be freed @@ -1316,7 +1249,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( struct snd_soc_tplg_mixer_control *mc; int i, err; - kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL); + kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL); if (kc == NULL) return NULL; @@ -1328,7 +1261,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( SNDRV_CTL_ELEM_ID_NAME_MAXLEN) goto err_sm; - sm = kzalloc(sizeof(*sm), GFP_KERNEL); + sm = devm_kzalloc(tplg->dev, sizeof(*sm), GFP_KERNEL); if (sm == NULL) goto err_sm; @@ -1339,7 +1272,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( mc->hdr.name, i); kc[i].private_value = (long)sm; - kc[i].name = kstrdup(mc->hdr.name, GFP_KERNEL); + kc[i].name = devm_kstrdup(tplg->dev, mc->hdr.name, GFP_KERNEL); if (kc[i].name == NULL) goto err_sm; kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -1391,11 +1324,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( err_sm: for (; i >= 0; i--) { soc_tplg_free_tlv(tplg, &kc[i]); - sm = (struct soc_mixer_control *)kc[i].private_value; - kfree(sm); - kfree(kc[i].name); } - kfree(kc); return NULL; } @@ -1408,7 +1337,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( struct soc_enum *se; int i, err; - kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL); + kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL); if (kc == NULL) return NULL; @@ -1419,7 +1348,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( SNDRV_CTL_ELEM_ID_NAME_MAXLEN) goto err_se; - se = kzalloc(sizeof(*se), GFP_KERNEL); + se = devm_kzalloc(tplg->dev, sizeof(*se), GFP_KERNEL); if (se == NULL) goto err_se; @@ -1430,7 +1359,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( ec->hdr.name); kc[i].private_value = (long)se; - kc[i].name = kstrdup(ec->hdr.name, GFP_KERNEL); + kc[i].name = devm_kstrdup(tplg->dev, ec->hdr.name, GFP_KERNEL); if (kc[i].name == NULL) goto err_se; kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -1450,7 +1379,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( switch (le32_to_cpu(ec->hdr.ops.info)) { case SND_SOC_TPLG_CTL_ENUM_VALUE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - err = soc_tplg_denum_create_values(se, ec); + err = soc_tplg_denum_create_values(tplg, se, ec); if (err < 0) { dev_err(tplg->dev, "ASoC: could not create values for %s\n", ec->hdr.name); @@ -1460,7 +1389,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - err = soc_tplg_denum_create_texts(se, ec); + err = soc_tplg_denum_create_texts(tplg, se, ec); if (err < 0) { dev_err(tplg->dev, "ASoC: could not create texts for %s\n", ec->hdr.name); @@ -1502,10 +1431,7 @@ err_se: soc_tplg_denum_remove_texts(se); } - kfree(se); - kfree(kc[i].name); } - kfree(kc); return NULL; } @@ -1518,7 +1444,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( struct snd_kcontrol_new *kc; int i, err; - kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL); + kc = devm_kcalloc(tplg->dev, num_kcontrols, sizeof(*kc), GFP_KERNEL); if (!kc) return NULL; @@ -1530,7 +1456,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( SNDRV_CTL_ELEM_ID_NAME_MAXLEN) goto err_sbe; - sbe = kzalloc(sizeof(*sbe), GFP_KERNEL); + sbe = devm_kzalloc(tplg->dev, sizeof(*sbe), GFP_KERNEL); if (sbe == NULL) goto err_sbe; @@ -1542,7 +1468,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( be->hdr.name, be->hdr.access); kc[i].private_value = (long)sbe; - kc[i].name = kstrdup(be->hdr.name, GFP_KERNEL); + kc[i].name = devm_kstrdup(tplg->dev, be->hdr.name, GFP_KERNEL); if (kc[i].name == NULL) goto err_sbe; kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -1571,12 +1497,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( return kc; err_sbe: - for (; i >= 0; i--) { - sbe = (struct soc_bytes_ext *)kc[i].private_value; - kfree(sbe); - kfree(kc[i].name); - } - kfree(kc); return NULL; } @@ -1783,10 +1703,10 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg) return 0; } -static int set_stream_info(struct snd_soc_pcm_stream *stream, - struct snd_soc_tplg_stream_caps *caps) +static int set_stream_info(struct soc_tplg *tplg, struct snd_soc_pcm_stream *stream, + struct snd_soc_tplg_stream_caps *caps) { - stream->stream_name = kstrdup(caps->name, GFP_KERNEL); + stream->stream_name = devm_kstrdup(tplg->dev, caps->name, GFP_KERNEL); if (!stream->stream_name) return -ENOMEM; @@ -1830,12 +1750,12 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, snd_soc_component_get_dapm(tplg->comp); int ret; - dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL); + dai_drv = devm_kzalloc(tplg->dev, sizeof(struct snd_soc_dai_driver), GFP_KERNEL); if (dai_drv == NULL) return -ENOMEM; if (strlen(pcm->dai_name)) { - dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL); + dai_drv->name = devm_kstrdup(tplg->dev, pcm->dai_name, GFP_KERNEL); if (!dai_drv->name) { ret = -ENOMEM; goto err; @@ -1846,7 +1766,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, if (pcm->playback) { stream = &dai_drv->playback; caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; - ret = set_stream_info(stream, caps); + ret = set_stream_info(tplg, stream, caps); if (ret < 0) goto err; } @@ -1854,7 +1774,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, if (pcm->capture) { stream = &dai_drv->capture; caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE]; - ret = set_stream_info(stream, caps); + ret = set_stream_info(tplg, stream, caps); if (ret < 0) goto err; } @@ -1889,11 +1809,6 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, return 0; err: - kfree(dai_drv->playback.stream_name); - kfree(dai_drv->capture.stream_name); - kfree(dai_drv->name); - kfree(dai_drv); - return ret; } @@ -1929,7 +1844,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, int ret; /* link + cpu + codec + platform */ - link = kzalloc(sizeof(*link) + (3 * sizeof(*dlc)), GFP_KERNEL); + link = devm_kzalloc(tplg->dev, sizeof(*link) + (3 * sizeof(*dlc)), GFP_KERNEL); if (link == NULL) return -ENOMEM; @@ -1948,8 +1863,8 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, link->dobj.type = SND_SOC_DOBJ_DAI_LINK; if (strlen(pcm->pcm_name)) { - link->name = kstrdup(pcm->pcm_name, GFP_KERNEL); - link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL); + link->name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL); + link->stream_name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL); if (!link->name || !link->stream_name) { ret = -ENOMEM; goto err; @@ -1958,7 +1873,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, link->id = le32_to_cpu(pcm->pcm_id); if (strlen(pcm->dai_name)) { - link->cpus->dai_name = kstrdup(pcm->dai_name, GFP_KERNEL); + link->cpus->dai_name = devm_kstrdup(tplg->dev, pcm->dai_name, GFP_KERNEL); if (!link->cpus->dai_name) { ret = -ENOMEM; goto err; @@ -1996,10 +1911,6 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, return 0; err: - kfree(link->name); - kfree(link->stream_name); - kfree(link->cpus->dai_name); - kfree(link); return ret; } @@ -2472,7 +2383,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, if (d->playback) { stream = &dai_drv->playback; caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; - ret = set_stream_info(stream, caps); + ret = set_stream_info(tplg, stream, caps); if (ret < 0) goto err; } @@ -2480,7 +2391,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, if (d->capture) { stream = &dai_drv->capture; caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE]; - ret = set_stream_info(stream, caps); + ret = set_stream_info(tplg, stream, caps); if (ret < 0) goto err; } @@ -2500,8 +2411,6 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, return 0; err: - kfree(dai_drv->playback.stream_name); - kfree(dai_drv->capture.stream_name); return ret; } -- cgit v1.2.3 From 033df362ea3635179d1defed2230be69ed632c05 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 30 Oct 2020 10:54:26 -0400 Subject: ASoC: topology: Remove empty functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After changing memory management to resource managed one, some of the functions became no ops, remove them as they are no longer needed. Reviewed-by: Guennadi Liakhovetski Signed-off-by: Amadeusz Sławiński Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201030145427.3497990-6-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 44 -------------------------------------------- 1 file changed, 44 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6ef508f56a5f..4f632aeeeb5e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -79,8 +79,6 @@ struct soc_tplg { static int soc_tplg_process_headers(struct soc_tplg *tplg); static void soc_tplg_complete(struct soc_tplg *tplg); -static void soc_tplg_denum_remove_texts(struct soc_enum *se); -static void soc_tplg_denum_remove_values(struct soc_enum *se); /* check we dont overflow the data for this control chunk */ static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size, @@ -375,7 +373,6 @@ static void remove_enum(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) { struct snd_card *card = comp->card->snd_card; - struct soc_enum *se = container_of(dobj, struct soc_enum, dobj); if (pass != SOC_TPLG_PASS_MIXER) return; @@ -385,9 +382,6 @@ static void remove_enum(struct snd_soc_component *comp, snd_ctl_remove(card, dobj->control.kcontrol); list_del(&dobj->list); - - soc_tplg_denum_remove_values(se); - soc_tplg_denum_remove_texts(se); } /* remove a byte kcontrol */ @@ -445,15 +439,9 @@ static void remove_widget(struct snd_soc_component *comp, /* enumerated widget mixer */ for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) { struct snd_kcontrol *kcontrol = w->kcontrols[i]; - struct soc_enum *se = - (struct soc_enum *)kcontrol->private_value; snd_ctl_remove(card, kcontrol); - /* free enum kcontrol's dvalues and dtexts */ - soc_tplg_denum_remove_values(se); - soc_tplg_denum_remove_texts(se); - } } else { /* volume mixer or bytes controls */ @@ -703,11 +691,6 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg, return 0; } -static inline void soc_tplg_free_tlv(struct soc_tplg *tplg, - struct snd_kcontrol_new *kc) -{ -} - static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, size_t size) { @@ -868,7 +851,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); - soc_tplg_free_tlv(tplg, &kc); break; } @@ -878,7 +860,6 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, if (err < 0) { dev_err(tplg->dev, "ASoC: failed to add %s\n", mc->hdr.name); - soc_tplg_free_tlv(tplg, &kc); break; } @@ -918,15 +899,9 @@ static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *s return 0; err: - se->items = i; - soc_tplg_denum_remove_texts(se); return ret; } -static inline void soc_tplg_denum_remove_texts(struct soc_enum *se) -{ -} - static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *se, struct snd_soc_tplg_enum_control *ec) { @@ -949,10 +924,6 @@ static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum * return 0; } -static inline void soc_tplg_denum_remove_values(struct soc_enum *se) -{ -} - static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, size_t size) { @@ -1322,10 +1293,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( return kc; err_sm: - for (; i >= 0; i--) { - soc_tplg_free_tlv(tplg, &kc[i]); - } - return NULL; } @@ -1422,17 +1389,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( return kc; err_se: - for (; i >= 0; i--) { - /* free values and texts */ - se = (struct soc_enum *)kc[i].private_value; - - if (se) { - soc_tplg_denum_remove_values(se); - soc_tplg_denum_remove_texts(se); - } - - } - return NULL; } -- cgit v1.2.3 From 8d456654839cd4fd10225ffa9c70c64784615f95 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 30 Oct 2020 10:54:27 -0400 Subject: ASoC: topology: Simplify remove_widget function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that enum and mixer kcontrols are freed by resource management framework, removing kcontrol becomes one function call, so simplify code in remove_widget. Reviewed-by: Guennadi Liakhovetski Signed-off-by: Amadeusz Sławiński Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201030145427.3497990-7-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 4f632aeeeb5e..07c60187e9ea 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -431,26 +431,8 @@ static void remove_widget(struct snd_soc_component *comp, if (!w->kcontrols) goto free_news; - /* - * Dynamic Widgets either have 1..N enum kcontrols or mixers. - * The enum may either have an array of values or strings. - */ - if (dobj->widget.kcontrol_type == SND_SOC_TPLG_TYPE_ENUM) { - /* enumerated widget mixer */ - for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) { - struct snd_kcontrol *kcontrol = w->kcontrols[i]; - - snd_ctl_remove(card, kcontrol); - - } - } else { - /* volume mixer or bytes controls */ - for (i = 0; w->kcontrols != NULL && i < w->num_kcontrols; i++) { - struct snd_kcontrol *kcontrol = w->kcontrols[i]; - - snd_ctl_remove(card, kcontrol); - } - } + for (i = 0; w->kcontrols && i < w->num_kcontrols; i++) + snd_ctl_remove(card, w->kcontrols[i]); free_news: -- cgit v1.2.3 From 682c5a72a2bb0745da73211bed5f47ccccd84025 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Tue, 3 Nov 2020 15:59:30 +0800 Subject: ASoC: mediatek: mt6359: add the calibration functions Add the calibraion functions for initializing the codec when registering the machine driver. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1604390378-23993-2-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/mt6359.h | 7 +++ 2 files changed, 117 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index 81aafb553bdd..d20c59a87524 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -68,6 +68,38 @@ static void mt6359_reset_capture_gpio(struct mt6359_priv *priv) 0x3 << 0, 0x0); } +/* use only when doing mtkaif calibraiton at the boot time */ +static void mt6359_set_dcxo(struct mt6359_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6359_DCXO_CW12, + 0x1 << RG_XO_AUDIO_EN_M_SFT, + (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT); +} + +/* use only when doing mtkaif calibraiton at the boot time */ +static void mt6359_set_clksq(struct mt6359_priv *priv, bool enable) +{ + /* Enable/disable CLKSQ 26MHz */ + regmap_update_bits(priv->regmap, MT6359_AUDENC_ANA_CON23, + RG_CLKSQ_EN_MASK_SFT, + (enable ? 1 : 0) << RG_CLKSQ_EN_SFT); +} + +/* use only when doing mtkaif calibraiton at the boot time */ +static void mt6359_set_aud_global_bias(struct mt6359_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON13, + RG_AUDGLB_PWRDN_VA32_MASK_SFT, + (enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA32_SFT); +} + +/* use only when doing mtkaif calibraiton at the boot time */ +static void mt6359_set_topck(struct mt6359_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6359_AUD_TOP_CKPDN_CON0, + 0x0066, enable ? 0x0 : 0x66); +} + static void mt6359_set_decoder_clk(struct mt6359_priv *priv, bool enable) { regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON13, @@ -122,6 +154,84 @@ static void mt6359_mtkaif_tx_disable(struct mt6359_priv *priv) 0xff00, 0x3000); } +void mt6359_set_mtkaif_protocol(struct snd_soc_component *cmpnt, + int mtkaif_protocol) +{ + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + priv->mtkaif_protocol = mtkaif_protocol; +} +EXPORT_SYMBOL_GPL(mt6359_set_mtkaif_protocol); + +void mt6359_mtkaif_calibration_enable(struct snd_soc_component *cmpnt) +{ + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + mt6359_set_playback_gpio(priv); + mt6359_set_capture_gpio(priv); + mt6359_mtkaif_tx_enable(priv); + + mt6359_set_dcxo(priv, true); + mt6359_set_aud_global_bias(priv, true); + mt6359_set_clksq(priv, true); + mt6359_set_topck(priv, true); + + /* set dat_miso_loopback on */ + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT, + 1 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT, + 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1, + RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_MASK_SFT, + 1 << RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_SFT); +} +EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_enable); + +void mt6359_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) +{ + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + /* set dat_miso_loopback off */ + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT, + 0 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT, + 0 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1, + RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_MASK_SFT, + 0 << RG_AUD_PAD_TOP_DAT_MISO3_LOOPBACK_SFT); + + mt6359_set_topck(priv, false); + mt6359_set_clksq(priv, false); + mt6359_set_aud_global_bias(priv, false); + mt6359_set_dcxo(priv, false); + + mt6359_mtkaif_tx_disable(priv); + mt6359_reset_playback_gpio(priv); + mt6359_reset_capture_gpio(priv); +} +EXPORT_SYMBOL_GPL(mt6359_mtkaif_calibration_disable); + +void mt6359_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, + int phase_1, int phase_2, int phase_3) +{ + struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT, + phase_1 << RG_AUD_PAD_TOP_PHASE_MODE_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT, + phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); + regmap_update_bits(priv->regmap, MT6359_AUDIO_DIG_CFG1, + RG_AUD_PAD_TOP_PHASE_MODE3_MASK_SFT, + phase_3 << RG_AUD_PAD_TOP_PHASE_MODE3_SFT); +} +EXPORT_SYMBOL_GPL(mt6359_set_mtkaif_calibration_phase); + static void zcd_disable(struct mt6359_priv *priv) { regmap_write(priv->regmap, MT6359_ZCD_CON0, 0x0000); diff --git a/sound/soc/codecs/mt6359.h b/sound/soc/codecs/mt6359.h index 3792e534a91b..af6f07fbc4fd 100644 --- a/sound/soc/codecs/mt6359.h +++ b/sound/soc/codecs/mt6359.h @@ -2637,4 +2637,11 @@ struct mt6359_priv { (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \ (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE) +void mt6359_set_mtkaif_protocol(struct snd_soc_component *cmpnt, + int mtkaif_protocol); +void mt6359_mtkaif_calibration_enable(struct snd_soc_component *cmpnt); +void mt6359_mtkaif_calibration_disable(struct snd_soc_component *cmpnt); +void mt6359_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, + int phase_1, int phase_2, int phase_3); + #endif/* end _MT6359_H_ */ -- cgit v1.2.3 From 125ab5d588b0b3b842064c4d53a666ca74521ae8 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Tue, 3 Nov 2020 15:59:31 +0800 Subject: ASoC: mediatek: mt8192: add platform driver This patch adds mt8192 platform and affiliated drivers. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1604390378-23993-3-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 10 + sound/soc/mediatek/Makefile | 1 + sound/soc/mediatek/common/mtk-afe-fe-dai.c | 13 +- sound/soc/mediatek/common/mtk-base-afe.h | 1 + sound/soc/mediatek/mt8192/Makefile | 14 + sound/soc/mediatek/mt8192/mt8192-afe-clk.c | 669 +++++ sound/soc/mediatek/mt8192/mt8192-afe-clk.h | 244 ++ sound/soc/mediatek/mt8192/mt8192-afe-common.h | 170 ++ sound/soc/mediatek/mt8192/mt8192-afe-control.c | 163 + sound/soc/mediatek/mt8192/mt8192-afe-gpio.c | 306 ++ sound/soc/mediatek/mt8192/mt8192-afe-gpio.h | 19 + sound/soc/mediatek/mt8192/mt8192-afe-pcm.c | 2389 +++++++++++++++ sound/soc/mediatek/mt8192/mt8192-interconnection.h | 65 + sound/soc/mediatek/mt8192/mt8192-reg.h | 3131 ++++++++++++++++++++ 14 files changed, 7191 insertions(+), 4 deletions(-) create mode 100644 sound/soc/mediatek/mt8192/Makefile create mode 100644 sound/soc/mediatek/mt8192/mt8192-afe-clk.c create mode 100644 sound/soc/mediatek/mt8192/mt8192-afe-clk.h create mode 100644 sound/soc/mediatek/mt8192/mt8192-afe-common.h create mode 100644 sound/soc/mediatek/mt8192/mt8192-afe-control.c create mode 100644 sound/soc/mediatek/mt8192/mt8192-afe-gpio.c create mode 100644 sound/soc/mediatek/mt8192/mt8192-afe-gpio.h create mode 100644 sound/soc/mediatek/mt8192/mt8192-afe-pcm.c create mode 100644 sound/soc/mediatek/mt8192/mt8192-interconnection.h create mode 100644 sound/soc/mediatek/mt8192/mt8192-reg.h (limited to 'sound') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 76e055d1dfb2..9de1be4a32f5 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -158,3 +158,13 @@ config SND_SOC_MTK_BTCVSD BT encoded data to/from BT firmware. Select Y if you have such device. If unsure select "N". + +config SND_SOC_MT8192 + tristate "ASoC support for Mediatek MT8192 chip" + depends on ARCH_MEDIATEK + select SND_SOC_MEDIATEK + help + This adds ASoC platform driver support for Mediatek MT8192 chip + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 76032cae6d51..f6cb6b8508e3 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ +obj-$(CONFIG_SND_SOC_MT8192) += mt8192/ diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index 882cdf86c8bf..3cb2adf420bb 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -542,8 +542,13 @@ int mtk_memif_set_format(struct mtk_base_afe *afe, break; case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_U32_LE: - hd_audio = 1; - hd_align = 1; + if (afe->memif_32bit_supported) { + hd_audio = 2; + hd_align = 0; + } else { + hd_audio = 1; + hd_align = 1; + } break; case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_U24_LE: @@ -556,10 +561,10 @@ int mtk_memif_set_format(struct mtk_base_afe *afe, } mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, - 1, hd_audio, memif->data->hd_shift); + 0x3, hd_audio, memif->data->hd_shift); mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg, - 1, hd_align, memif->data->hd_align_mshift); + 0x1, hd_align, memif->data->hd_align_mshift); return 0; } diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h index a8cf44d98244..a6f68c68581c 100644 --- a/sound/soc/mediatek/common/mtk-base-afe.h +++ b/sound/soc/mediatek/common/mtk-base-afe.h @@ -91,6 +91,7 @@ struct mtk_base_afe { int memif_size; struct mtk_base_afe_irq *irqs; int irqs_size; + int memif_32bit_supported; struct list_head sub_dais; struct snd_soc_dai_driver *dai_drivers; diff --git a/sound/soc/mediatek/mt8192/Makefile b/sound/soc/mediatek/mt8192/Makefile new file mode 100644 index 000000000000..dd1848688170 --- /dev/null +++ b/sound/soc/mediatek/mt8192/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 + +# platform driver +snd-soc-mt8192-afe-objs := \ + mt8192-afe-pcm.o \ + mt8192-afe-clk.o \ + mt8192-afe-gpio.o \ + mt8192-dai-adda.o \ + mt8192-afe-control.o \ + mt8192-dai-i2s.o \ + mt8192-dai-pcm.o \ + mt8192-dai-tdm.o + +obj-$(CONFIG_SND_SOC_MT8192) += snd-soc-mt8192-afe.o diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-clk.c b/sound/soc/mediatek/mt8192/mt8192-afe-clk.c new file mode 100644 index 000000000000..bba5f3056e8f --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-afe-clk.c @@ -0,0 +1,669 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8192-afe-clk.c -- Mediatek 8192 afe clock ctrl +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Shane Chien +// + +#include +#include +#include +#include + +#include "mt8192-afe-clk.h" +#include "mt8192-afe-common.h" + +static const char *aud_clks[CLK_NUM] = { + [CLK_AFE] = "aud_afe_clk", + [CLK_TML] = "aud_tml_clk", + [CLK_APLL22M] = "aud_apll22m_clk", + [CLK_APLL24M] = "aud_apll24m_clk", + [CLK_APLL1_TUNER] = "aud_apll1_tuner_clk", + [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk", + [CLK_NLE] = "aud_nle", + [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk", + [CLK_INFRA_AUDIO_26M] = "aud_infra_26m_clk", + [CLK_MUX_AUDIO] = "top_mux_audio", + [CLK_MUX_AUDIOINTBUS] = "top_mux_audio_int", + [CLK_TOP_MAINPLL_D4_D4] = "top_mainpll_d4_d4", + [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1", + [CLK_TOP_APLL1_CK] = "top_apll1_ck", + [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2", + [CLK_TOP_APLL2_CK] = "top_apll2_ck", + [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1", + [CLK_TOP_APLL1_D4] = "top_apll1_d4", + [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2", + [CLK_TOP_APLL2_D4] = "top_apll2_d4", + [CLK_TOP_MUX_AUDIO_H] = "top_mux_audio_h", + [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel", + [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel", + [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel", + [CLK_TOP_I2S3_M_SEL] = "top_i2s3_m_sel", + [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel", + [CLK_TOP_I2S5_M_SEL] = "top_i2s5_m_sel", + [CLK_TOP_I2S6_M_SEL] = "top_i2s6_m_sel", + [CLK_TOP_I2S7_M_SEL] = "top_i2s7_m_sel", + [CLK_TOP_I2S8_M_SEL] = "top_i2s8_m_sel", + [CLK_TOP_I2S9_M_SEL] = "top_i2s9_m_sel", + [CLK_TOP_APLL12_DIV0] = "top_apll12_div0", + [CLK_TOP_APLL12_DIV1] = "top_apll12_div1", + [CLK_TOP_APLL12_DIV2] = "top_apll12_div2", + [CLK_TOP_APLL12_DIV3] = "top_apll12_div3", + [CLK_TOP_APLL12_DIV4] = "top_apll12_div4", + [CLK_TOP_APLL12_DIVB] = "top_apll12_divb", + [CLK_TOP_APLL12_DIV5] = "top_apll12_div5", + [CLK_TOP_APLL12_DIV6] = "top_apll12_div6", + [CLK_TOP_APLL12_DIV7] = "top_apll12_div7", + [CLK_TOP_APLL12_DIV8] = "top_apll12_div8", + [CLK_TOP_APLL12_DIV9] = "top_apll12_div9", + [CLK_CLK26M] = "top_clk26m_clk", +}; + +int mt8192_set_audio_int_bus_parent(struct mtk_base_afe *afe, + int clk_id) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS], + afe_priv->clk[clk_id]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], + aud_clks[clk_id], ret); + } + + return ret; +} + +static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_TOP_APLL1_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_TOP_APLL1_CK], ret); + goto EXIT; + } + + /* 180.6336 / 4 = 45.1584MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_TOP_APLL1_D4]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_TOP_APLL1_D4], ret); + goto EXIT; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + } + +EXIT: + return ret; +} + +static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_TOP_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_TOP_APLL2_CK], ret); + goto EXIT; + } + + /* 196.608 / 4 = 49.152MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_TOP_APLL2_D4]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_TOP_APLL2_D4], ret); + goto EXIT; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + } + +EXIT: + return ret; +} + +int mt8192_afe_enable_clock(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int ret; + + dev_info(afe->dev, "%s()\n", __func__); + + ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret); + goto EXIT; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_AUDIO_26M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_INFRA_AUDIO_26M], ret); + goto EXIT; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], ret); + goto EXIT; + } + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto EXIT; + } + + ret = mt8192_set_audio_int_bus_parent(afe, CLK_CLK26M); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUDIO_H], + afe_priv->clk[CLK_TOP_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUDIO_H], + aud_clks[CLK_TOP_APLL2_CK], ret); + goto EXIT; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_AFE], ret); + goto EXIT; + } + +EXIT: + return ret; +} + +void mt8192_afe_disable_clock(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + dev_info(afe->dev, "%s()\n", __func__); + + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); + mt8192_set_audio_int_bus_parent(afe, CLK_CLK26M); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]); + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); +} + +int mt8192_apll1_enable(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll1_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL22M], ret); + goto EXIT; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL1_TUNER], ret); + goto EXIT; + } + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, + 0x0000FFF7, 0x00000832); + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, + 0x1 << AFE_22M_ON_SFT); + +EXIT: + return ret; +} + +void mt8192_apll1_disable(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, + 0x0 << AFE_22M_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); + + apll1_mux_setting(afe, false); +} + +int mt8192_apll2_enable(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll2_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL24M], ret); + goto EXIT; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL2_TUNER], ret); + goto EXIT; + } + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, + 0x0000FFF7, 0x00000634); + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, + 0x1 << AFE_24M_ON_SFT); + +EXIT: + return ret; +} + +void mt8192_apll2_disable(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, + 0x0 << AFE_24M_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); + + apll2_mux_setting(afe, false); +} + +int mt8192_get_apll_rate(struct mtk_base_afe *afe, int apll) +{ + return (apll == MT8192_APLL1) ? 180633600 : 196608000; +} + +int mt8192_get_apll_by_rate(struct mtk_base_afe *afe, int rate) +{ + return ((rate % 8000) == 0) ? MT8192_APLL2 : MT8192_APLL1; +} + +int mt8192_get_apll_by_name(struct mtk_base_afe *afe, const char *name) +{ + if (strcmp(name, APLL1_W_NAME) == 0) + return MT8192_APLL1; + else + return MT8192_APLL2; +} + +/* mck */ +struct mt8192_mck_div { + int m_sel_id; + int div_clk_id; + /* below will be deprecated */ + int div_pdn_reg; + int div_pdn_mask_sft; + int div_reg; + int div_mask_sft; + int div_mask; + int div_sft; + int div_apll_sel_reg; + int div_apll_sel_mask_sft; + int div_apll_sel_sft; +}; + +static const struct mt8192_mck_div mck_div[MT8192_MCK_NUM] = { + [MT8192_I2S0_MCK] = { + .m_sel_id = CLK_TOP_I2S0_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV0, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV0_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_2, + .div_mask_sft = APLL12_CK_DIV0_MASK_SFT, + .div_mask = APLL12_CK_DIV0_MASK, + .div_sft = APLL12_CK_DIV0_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S0_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S0_MCK_SEL_SFT, + }, + [MT8192_I2S1_MCK] = { + .m_sel_id = CLK_TOP_I2S1_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV1, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV1_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_2, + .div_mask_sft = APLL12_CK_DIV1_MASK_SFT, + .div_mask = APLL12_CK_DIV1_MASK, + .div_sft = APLL12_CK_DIV1_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S1_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S1_MCK_SEL_SFT, + }, + [MT8192_I2S2_MCK] = { + .m_sel_id = CLK_TOP_I2S2_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV2, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV2_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_2, + .div_mask_sft = APLL12_CK_DIV2_MASK_SFT, + .div_mask = APLL12_CK_DIV2_MASK, + .div_sft = APLL12_CK_DIV2_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S2_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S2_MCK_SEL_SFT, + }, + [MT8192_I2S3_MCK] = { + .m_sel_id = CLK_TOP_I2S3_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV3, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV3_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_2, + .div_mask_sft = APLL12_CK_DIV3_MASK_SFT, + .div_mask = APLL12_CK_DIV3_MASK, + .div_sft = APLL12_CK_DIV3_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S3_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S3_MCK_SEL_SFT, + }, + [MT8192_I2S4_MCK] = { + .m_sel_id = CLK_TOP_I2S4_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV4, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV4_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_3, + .div_mask_sft = APLL12_CK_DIV4_MASK_SFT, + .div_mask = APLL12_CK_DIV4_MASK, + .div_sft = APLL12_CK_DIV4_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S4_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S4_MCK_SEL_SFT, + }, + [MT8192_I2S4_BCK] = { + .m_sel_id = -1, + .div_clk_id = CLK_TOP_APLL12_DIVB, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIVB_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_2, + .div_mask_sft = APLL12_CK_DIVB_MASK_SFT, + .div_mask = APLL12_CK_DIVB_MASK, + .div_sft = APLL12_CK_DIVB_SFT, + }, + [MT8192_I2S5_MCK] = { + .m_sel_id = CLK_TOP_I2S5_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV5, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV5_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_3, + .div_mask_sft = APLL12_CK_DIV5_MASK_SFT, + .div_mask = APLL12_CK_DIV5_MASK, + .div_sft = APLL12_CK_DIV5_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S5_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S5_MCK_SEL_SFT, + }, + [MT8192_I2S6_MCK] = { + .m_sel_id = CLK_TOP_I2S6_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV6, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV6_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_3, + .div_mask_sft = APLL12_CK_DIV6_MASK_SFT, + .div_mask = APLL12_CK_DIV6_MASK, + .div_sft = APLL12_CK_DIV6_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S6_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S6_MCK_SEL_SFT, + }, + [MT8192_I2S7_MCK] = { + .m_sel_id = CLK_TOP_I2S7_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV7, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV7_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_4, + .div_mask_sft = APLL12_CK_DIV7_MASK_SFT, + .div_mask = APLL12_CK_DIV7_MASK, + .div_sft = APLL12_CK_DIV7_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S7_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S7_MCK_SEL_SFT, + }, + [MT8192_I2S8_MCK] = { + .m_sel_id = CLK_TOP_I2S8_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV8, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV8_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_4, + .div_mask_sft = APLL12_CK_DIV8_MASK_SFT, + .div_mask = APLL12_CK_DIV8_MASK, + .div_sft = APLL12_CK_DIV8_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S8_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S8_MCK_SEL_SFT, + }, + [MT8192_I2S9_MCK] = { + .m_sel_id = CLK_TOP_I2S9_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV9, + .div_pdn_reg = CLK_AUDDIV_0, + .div_pdn_mask_sft = APLL12_DIV9_PDN_MASK_SFT, + .div_reg = CLK_AUDDIV_4, + .div_mask_sft = APLL12_CK_DIV9_MASK_SFT, + .div_mask = APLL12_CK_DIV9_MASK, + .div_sft = APLL12_CK_DIV9_SFT, + .div_apll_sel_reg = CLK_AUDDIV_0, + .div_apll_sel_mask_sft = APLL_I2S9_MCK_SEL_MASK_SFT, + .div_apll_sel_sft = APLL_I2S9_MCK_SEL_SFT, + }, +}; + +int mt8192_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int apll = mt8192_get_apll_by_rate(afe, rate); + int apll_clk_id = apll == MT8192_APLL1 ? + CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + int ret; + + /* select apll */ + if (m_sel_id >= 0) { + ret = clk_prepare_enable(afe_priv->clk[m_sel_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[m_sel_id], ret); + return ret; + } + ret = clk_set_parent(afe_priv->clk[m_sel_id], + afe_priv->clk[apll_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[m_sel_id], + aud_clks[apll_clk_id], ret); + return ret; + } + } + + /* enable div, set rate */ + ret = clk_prepare_enable(afe_priv->clk[div_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[div_clk_id], ret); + return ret; + } + ret = clk_set_rate(afe_priv->clk[div_clk_id], rate); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n", + __func__, aud_clks[div_clk_id], + rate, ret); + return ret; + } + + return 0; +} + +void mt8192_mck_disable(struct mtk_base_afe *afe, int mck_id) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + + clk_disable_unprepare(afe_priv->clk[div_clk_id]); + if (m_sel_id >= 0) + clk_disable_unprepare(afe_priv->clk[m_sel_id]); +} + +int mt8192_init_clock(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + struct device_node *of_node = afe->dev->of_node; + int i = 0; + + afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk), + GFP_KERNEL); + if (!afe_priv->clk) + return -ENOMEM; + + for (i = 0; i < CLK_NUM; i++) { + afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]); + if (IS_ERR(afe_priv->clk[i])) { + dev_warn(afe->dev, "%s devm_clk_get %s fail, ret %ld\n", + __func__, + aud_clks[i], PTR_ERR(afe_priv->clk[i])); + afe_priv->clk[i] = NULL; + } + } + + afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,apmixedsys"); + if (IS_ERR(afe_priv->apmixedsys)) { + dev_err(afe->dev, "%s() Cannot find apmixedsys controller: %ld\n", + __func__, PTR_ERR(afe_priv->apmixedsys)); + return PTR_ERR(afe_priv->apmixedsys); + } + + afe_priv->topckgen = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,topckgen"); + if (IS_ERR(afe_priv->topckgen)) { + dev_err(afe->dev, "%s() Cannot find topckgen controller: %ld\n", + __func__, PTR_ERR(afe_priv->topckgen)); + return PTR_ERR(afe_priv->topckgen); + } + + afe_priv->infracfg = syscon_regmap_lookup_by_phandle(of_node, + "mediatek,infracfg"); + if (IS_ERR(afe_priv->infracfg)) { + dev_err(afe->dev, "%s() Cannot find infracfg: %ld\n", + __func__, PTR_ERR(afe_priv->infracfg)); + return PTR_ERR(afe_priv->infracfg); + } + + return 0; +} diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-clk.h b/sound/soc/mediatek/mt8192/mt8192-afe-clk.h new file mode 100644 index 000000000000..3adaf027af83 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-afe-clk.h @@ -0,0 +1,244 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8192-afe-clk.h -- Mediatek 8192 afe clock ctrl definition + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Shane Chien + */ + +#ifndef _MT8192_AFE_CLOCK_CTRL_H_ +#define _MT8192_AFE_CLOCK_CTRL_H_ + +#define AP_PLL_CON3 0x0014 +#define APLL1_CON0 0x0318 +#define APLL1_CON1 0x031c +#define APLL1_CON2 0x0320 +#define APLL1_CON4 0x0328 +#define APLL1_TUNER_CON0 0x0040 + +#define APLL2_CON0 0x032c +#define APLL2_CON1 0x0330 +#define APLL2_CON2 0x0334 +#define APLL2_CON4 0x033c +#define APLL2_TUNER_CON0 0x0044 + +#define CLK_CFG_7 0x0080 +#define CLK_CFG_8 0x0090 +#define CLK_CFG_11 0x00c0 +#define CLK_CFG_12 0x00d0 +#define CLK_CFG_13 0x00e0 +#define CLK_CFG_15 0x0100 + +#define CLK_AUDDIV_0 0x0320 +#define CLK_AUDDIV_2 0x0328 +#define CLK_AUDDIV_3 0x0334 +#define CLK_AUDDIV_4 0x0338 +#define CKSYS_AUD_TOP_CFG 0x032c +#define CKSYS_AUD_TOP_MON 0x0330 + +#define PERI_BUS_DCM_CTRL 0x0074 +#define MODULE_SW_CG_1_STA 0x0094 +#define MODULE_SW_CG_2_STA 0x00ac + +/* CLK_AUDDIV_0 */ +#define APLL12_DIV0_PDN_SFT 0 +#define APLL12_DIV0_PDN_MASK 0x1 +#define APLL12_DIV0_PDN_MASK_SFT (0x1 << 0) +#define APLL12_DIV1_PDN_SFT 1 +#define APLL12_DIV1_PDN_MASK 0x1 +#define APLL12_DIV1_PDN_MASK_SFT (0x1 << 1) +#define APLL12_DIV2_PDN_SFT 2 +#define APLL12_DIV2_PDN_MASK 0x1 +#define APLL12_DIV2_PDN_MASK_SFT (0x1 << 2) +#define APLL12_DIV3_PDN_SFT 3 +#define APLL12_DIV3_PDN_MASK 0x1 +#define APLL12_DIV3_PDN_MASK_SFT (0x1 << 3) +#define APLL12_DIV4_PDN_SFT 4 +#define APLL12_DIV4_PDN_MASK 0x1 +#define APLL12_DIV4_PDN_MASK_SFT (0x1 << 4) +#define APLL12_DIVB_PDN_SFT 5 +#define APLL12_DIVB_PDN_MASK 0x1 +#define APLL12_DIVB_PDN_MASK_SFT (0x1 << 5) +#define APLL12_DIV5_PDN_SFT 6 +#define APLL12_DIV5_PDN_MASK 0x1 +#define APLL12_DIV5_PDN_MASK_SFT (0x1 << 6) +#define APLL12_DIV6_PDN_SFT 7 +#define APLL12_DIV6_PDN_MASK 0x1 +#define APLL12_DIV6_PDN_MASK_SFT (0x1 << 7) +#define APLL12_DIV7_PDN_SFT 8 +#define APLL12_DIV7_PDN_MASK 0x1 +#define APLL12_DIV7_PDN_MASK_SFT (0x1 << 8) +#define APLL12_DIV8_PDN_SFT 9 +#define APLL12_DIV8_PDN_MASK 0x1 +#define APLL12_DIV8_PDN_MASK_SFT (0x1 << 9) +#define APLL12_DIV9_PDN_SFT 10 +#define APLL12_DIV9_PDN_MASK 0x1 +#define APLL12_DIV9_PDN_MASK_SFT (0x1 << 10) +#define APLL_I2S0_MCK_SEL_SFT 16 +#define APLL_I2S0_MCK_SEL_MASK 0x1 +#define APLL_I2S0_MCK_SEL_MASK_SFT (0x1 << 16) +#define APLL_I2S1_MCK_SEL_SFT 17 +#define APLL_I2S1_MCK_SEL_MASK 0x1 +#define APLL_I2S1_MCK_SEL_MASK_SFT (0x1 << 17) +#define APLL_I2S2_MCK_SEL_SFT 18 +#define APLL_I2S2_MCK_SEL_MASK 0x1 +#define APLL_I2S2_MCK_SEL_MASK_SFT (0x1 << 18) +#define APLL_I2S3_MCK_SEL_SFT 19 +#define APLL_I2S3_MCK_SEL_MASK 0x1 +#define APLL_I2S3_MCK_SEL_MASK_SFT (0x1 << 19) +#define APLL_I2S4_MCK_SEL_SFT 20 +#define APLL_I2S4_MCK_SEL_MASK 0x1 +#define APLL_I2S4_MCK_SEL_MASK_SFT (0x1 << 20) +#define APLL_I2S5_MCK_SEL_SFT 21 +#define APLL_I2S5_MCK_SEL_MASK 0x1 +#define APLL_I2S5_MCK_SEL_MASK_SFT (0x1 << 21) +#define APLL_I2S6_MCK_SEL_SFT 22 +#define APLL_I2S6_MCK_SEL_MASK 0x1 +#define APLL_I2S6_MCK_SEL_MASK_SFT (0x1 << 22) +#define APLL_I2S7_MCK_SEL_SFT 23 +#define APLL_I2S7_MCK_SEL_MASK 0x1 +#define APLL_I2S7_MCK_SEL_MASK_SFT (0x1 << 23) +#define APLL_I2S8_MCK_SEL_SFT 24 +#define APLL_I2S8_MCK_SEL_MASK 0x1 +#define APLL_I2S8_MCK_SEL_MASK_SFT (0x1 << 24) +#define APLL_I2S9_MCK_SEL_SFT 25 +#define APLL_I2S9_MCK_SEL_MASK 0x1 +#define APLL_I2S9_MCK_SEL_MASK_SFT (0x1 << 25) + +/* CLK_AUDDIV_2 */ +#define APLL12_CK_DIV0_SFT 0 +#define APLL12_CK_DIV0_MASK 0xff +#define APLL12_CK_DIV0_MASK_SFT (0xff << 0) +#define APLL12_CK_DIV1_SFT 8 +#define APLL12_CK_DIV1_MASK 0xff +#define APLL12_CK_DIV1_MASK_SFT (0xff << 8) +#define APLL12_CK_DIV2_SFT 16 +#define APLL12_CK_DIV2_MASK 0xff +#define APLL12_CK_DIV2_MASK_SFT (0xff << 16) +#define APLL12_CK_DIV3_SFT 24 +#define APLL12_CK_DIV3_MASK 0xff +#define APLL12_CK_DIV3_MASK_SFT (0xff << 24) + +/* CLK_AUDDIV_3 */ +#define APLL12_CK_DIV4_SFT 0 +#define APLL12_CK_DIV4_MASK 0xff +#define APLL12_CK_DIV4_MASK_SFT (0xff << 0) +#define APLL12_CK_DIVB_SFT 8 +#define APLL12_CK_DIVB_MASK 0xff +#define APLL12_CK_DIVB_MASK_SFT (0xff << 8) +#define APLL12_CK_DIV5_SFT 16 +#define APLL12_CK_DIV5_MASK 0xff +#define APLL12_CK_DIV5_MASK_SFT (0xff << 16) +#define APLL12_CK_DIV6_SFT 24 +#define APLL12_CK_DIV6_MASK 0xff +#define APLL12_CK_DIV6_MASK_SFT (0xff << 24) + +/* CLK_AUDDIV_4 */ +#define APLL12_CK_DIV7_SFT 0 +#define APLL12_CK_DIV7_MASK 0xff +#define APLL12_CK_DIV7_MASK_SFT (0xff << 0) +#define APLL12_CK_DIV8_SFT 8 +#define APLL12_CK_DIV8_MASK 0xff +#define APLL12_CK_DIV8_MASK_SFT (0xff << 0) +#define APLL12_CK_DIV9_SFT 16 +#define APLL12_CK_DIV9_MASK 0xff +#define APLL12_CK_DIV9_MASK_SFT (0xff << 0) + +/* AUD_TOP_CFG */ +#define AUD_TOP_CFG_SFT 0 +#define AUD_TOP_CFG_MASK 0xffffffff +#define AUD_TOP_CFG_MASK_SFT (0xffffffff << 0) + +/* AUD_TOP_MON */ +#define AUD_TOP_MON_SFT 0 +#define AUD_TOP_MON_MASK 0xffffffff +#define AUD_TOP_MON_MASK_SFT (0xffffffff << 0) + +/* CLK_AUDDIV_3 */ +#define APLL12_CK_DIV5_MSB_SFT 0 +#define APLL12_CK_DIV5_MSB_MASK 0xf +#define APLL12_CK_DIV5_MSB_MASK_SFT (0xf << 0) +#define RESERVED0_SFT 4 +#define RESERVED0_MASK 0xfffffff +#define RESERVED0_MASK_SFT (0xfffffff << 4) + +/* APLL */ +#define APLL1_W_NAME "APLL1" +#define APLL2_W_NAME "APLL2" +enum { + MT8192_APLL1 = 0, + MT8192_APLL2, +}; + +enum { + CLK_AFE = 0, + CLK_TML, + CLK_APLL22M, + CLK_APLL24M, + CLK_APLL1_TUNER, + CLK_APLL2_TUNER, + CLK_NLE, + CLK_INFRA_SYS_AUDIO, + CLK_INFRA_AUDIO_26M, + CLK_MUX_AUDIO, + CLK_MUX_AUDIOINTBUS, + CLK_TOP_MAINPLL_D4_D4, + /* apll related mux */ + CLK_TOP_MUX_AUD_1, + CLK_TOP_APLL1_CK, + CLK_TOP_MUX_AUD_2, + CLK_TOP_APLL2_CK, + CLK_TOP_MUX_AUD_ENG1, + CLK_TOP_APLL1_D4, + CLK_TOP_MUX_AUD_ENG2, + CLK_TOP_APLL2_D4, + CLK_TOP_MUX_AUDIO_H, + CLK_TOP_I2S0_M_SEL, + CLK_TOP_I2S1_M_SEL, + CLK_TOP_I2S2_M_SEL, + CLK_TOP_I2S3_M_SEL, + CLK_TOP_I2S4_M_SEL, + CLK_TOP_I2S5_M_SEL, + CLK_TOP_I2S6_M_SEL, + CLK_TOP_I2S7_M_SEL, + CLK_TOP_I2S8_M_SEL, + CLK_TOP_I2S9_M_SEL, + CLK_TOP_APLL12_DIV0, + CLK_TOP_APLL12_DIV1, + CLK_TOP_APLL12_DIV2, + CLK_TOP_APLL12_DIV3, + CLK_TOP_APLL12_DIV4, + CLK_TOP_APLL12_DIVB, + CLK_TOP_APLL12_DIV5, + CLK_TOP_APLL12_DIV6, + CLK_TOP_APLL12_DIV7, + CLK_TOP_APLL12_DIV8, + CLK_TOP_APLL12_DIV9, + CLK_CLK26M, + CLK_NUM +}; + +struct mtk_base_afe; + +int mt8192_init_clock(struct mtk_base_afe *afe); +int mt8192_afe_enable_clock(struct mtk_base_afe *afe); +void mt8192_afe_disable_clock(struct mtk_base_afe *afe); + +int mt8192_apll1_enable(struct mtk_base_afe *afe); +void mt8192_apll1_disable(struct mtk_base_afe *afe); + +int mt8192_apll2_enable(struct mtk_base_afe *afe); +void mt8192_apll2_disable(struct mtk_base_afe *afe); + +int mt8192_get_apll_rate(struct mtk_base_afe *afe, int apll); +int mt8192_get_apll_by_rate(struct mtk_base_afe *afe, int rate); +int mt8192_get_apll_by_name(struct mtk_base_afe *afe, const char *name); + +/* these will be replaced by using CCF */ +int mt8192_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate); +void mt8192_mck_disable(struct mtk_base_afe *afe, int mck_id); + +int mt8192_set_audio_int_bus_parent(struct mtk_base_afe *afe, + int clk_id); + +#endif diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-common.h b/sound/soc/mediatek/mt8192/mt8192-afe-common.h new file mode 100644 index 000000000000..d55eff46cc7f --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-afe-common.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8192-afe-common.h -- Mediatek 8192 audio driver definitions + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Shane Chien + */ + +#ifndef _MT_8192_AFE_COMMON_H_ +#define _MT_8192_AFE_COMMON_H_ + +#include +#include +#include + +#include "../common/mtk-base-afe.h" +#include "mt8192-reg.h" + +enum { + MT8192_MEMIF_DL1, + MT8192_MEMIF_DL12, + MT8192_MEMIF_DL2, + MT8192_MEMIF_DL3, + MT8192_MEMIF_DL4, + MT8192_MEMIF_DL5, + MT8192_MEMIF_DL6, + MT8192_MEMIF_DL7, + MT8192_MEMIF_DL8, + MT8192_MEMIF_DL9, + MT8192_MEMIF_DAI, + MT8192_MEMIF_DAI2, + MT8192_MEMIF_MOD_DAI, + MT8192_MEMIF_VUL12, + MT8192_MEMIF_VUL2, + MT8192_MEMIF_VUL3, + MT8192_MEMIF_VUL4, + MT8192_MEMIF_VUL5, + MT8192_MEMIF_VUL6, + MT8192_MEMIF_AWB, + MT8192_MEMIF_AWB2, + MT8192_MEMIF_HDMI, + MT8192_MEMIF_NUM, + MT8192_DAI_ADDA = MT8192_MEMIF_NUM, + MT8192_DAI_ADDA_CH34, + MT8192_DAI_AP_DMIC, + MT8192_DAI_AP_DMIC_CH34, + MT8192_DAI_VOW, + MT8192_DAI_CONNSYS_I2S, + MT8192_DAI_I2S_0, + MT8192_DAI_I2S_1, + MT8192_DAI_I2S_2, + MT8192_DAI_I2S_3, + MT8192_DAI_I2S_5, + MT8192_DAI_I2S_6, + MT8192_DAI_I2S_7, + MT8192_DAI_I2S_8, + MT8192_DAI_I2S_9, + MT8192_DAI_HW_GAIN_1, + MT8192_DAI_HW_GAIN_2, + MT8192_DAI_SRC_1, + MT8192_DAI_SRC_2, + MT8192_DAI_PCM_1, + MT8192_DAI_PCM_2, + MT8192_DAI_TDM, + MT8192_DAI_NUM, +}; + +enum { + MT8192_IRQ_0, + MT8192_IRQ_1, + MT8192_IRQ_2, + MT8192_IRQ_3, + MT8192_IRQ_4, + MT8192_IRQ_5, + MT8192_IRQ_6, + MT8192_IRQ_7, + MT8192_IRQ_8, + MT8192_IRQ_9, + MT8192_IRQ_10, + MT8192_IRQ_11, + MT8192_IRQ_12, + MT8192_IRQ_13, + MT8192_IRQ_14, + MT8192_IRQ_15, + MT8192_IRQ_16, + MT8192_IRQ_17, + MT8192_IRQ_18, + MT8192_IRQ_19, + MT8192_IRQ_20, + MT8192_IRQ_21, + MT8192_IRQ_22, + MT8192_IRQ_23, + MT8192_IRQ_24, + MT8192_IRQ_25, + MT8192_IRQ_26, + MT8192_IRQ_31, /* used only for TDM */ + MT8192_IRQ_NUM, +}; + +enum { + MTKAIF_PROTOCOL_1 = 0, + MTKAIF_PROTOCOL_2, + MTKAIF_PROTOCOL_2_CLK_P2, +}; + +enum { + MTK_AFE_ADDA_DL_GAIN_MUTE = 0, + MTK_AFE_ADDA_DL_GAIN_NORMAL = 0xf74f, + /* SA suggest apply -0.3db to audio/speech path */ +}; + +/* MCLK */ +enum { + MT8192_I2S0_MCK = 0, + MT8192_I2S1_MCK, + MT8192_I2S2_MCK, + MT8192_I2S3_MCK, + MT8192_I2S4_MCK, + MT8192_I2S4_BCK, + MT8192_I2S5_MCK, + MT8192_I2S6_MCK, + MT8192_I2S7_MCK, + MT8192_I2S8_MCK, + MT8192_I2S9_MCK, + MT8192_MCK_NUM, +}; + +struct clk; + +struct mt8192_afe_private { + struct clk **clk; + struct regmap *topckgen; + struct regmap *apmixedsys; + struct regmap *infracfg; + int stf_positive_gain_db; + int pm_runtime_bypass_reg_ctl; + + /* dai */ + bool dai_on[MT8192_DAI_NUM]; + void *dai_priv[MT8192_DAI_NUM]; + + /* adda */ + int mtkaif_protocol; + int mtkaif_chosen_phase[4]; + int mtkaif_phase_cycle[4]; + int mtkaif_calibration_num_phase; + int mtkaif_dmic; + int mtkaif_dmic_ch34; + int mtkaif_adda6_only; + + /* mck */ + int mck_rate[MT8192_MCK_NUM]; +}; + +int mt8192_dai_adda_register(struct mtk_base_afe *afe); +int mt8192_dai_i2s_register(struct mtk_base_afe *afe); +int mt8192_dai_hw_gain_register(struct mtk_base_afe *afe); +int mt8192_dai_src_register(struct mtk_base_afe *afe); +int mt8192_dai_pcm_register(struct mtk_base_afe *afe); +int mt8192_dai_tdm_register(struct mtk_base_afe *afe); + +unsigned int mt8192_general_rate_transform(struct device *dev, + unsigned int rate); +unsigned int mt8192_rate_transform(struct device *dev, + unsigned int rate, int aud_blk); + +int mt8192_dai_set_priv(struct mtk_base_afe *afe, int id, + int priv_size, const void *priv_data); + +#endif diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-control.c b/sound/soc/mediatek/mt8192/mt8192-afe-control.c new file mode 100644 index 000000000000..9163e05e54e1 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-afe-control.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio Control +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Shane Chien +// + +#include + +#include "mt8192-afe-common.h" + +enum { + MTK_AFE_RATE_8K = 0, + MTK_AFE_RATE_11K = 1, + MTK_AFE_RATE_12K = 2, + MTK_AFE_RATE_384K = 3, + MTK_AFE_RATE_16K = 4, + MTK_AFE_RATE_22K = 5, + MTK_AFE_RATE_24K = 6, + MTK_AFE_RATE_352K = 7, + MTK_AFE_RATE_32K = 8, + MTK_AFE_RATE_44K = 9, + MTK_AFE_RATE_48K = 10, + MTK_AFE_RATE_88K = 11, + MTK_AFE_RATE_96K = 12, + MTK_AFE_RATE_176K = 13, + MTK_AFE_RATE_192K = 14, + MTK_AFE_RATE_260K = 15, +}; + +enum { + MTK_AFE_DAI_MEMIF_RATE_8K = 0, + MTK_AFE_DAI_MEMIF_RATE_16K = 1, + MTK_AFE_DAI_MEMIF_RATE_32K = 2, + MTK_AFE_DAI_MEMIF_RATE_48K = 3, +}; + +enum { + MTK_AFE_PCM_RATE_8K = 0, + MTK_AFE_PCM_RATE_16K = 1, + MTK_AFE_PCM_RATE_32K = 2, + MTK_AFE_PCM_RATE_48K = 3, +}; + +unsigned int mt8192_general_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_RATE_8K; + case 11025: + return MTK_AFE_RATE_11K; + case 12000: + return MTK_AFE_RATE_12K; + case 16000: + return MTK_AFE_RATE_16K; + case 22050: + return MTK_AFE_RATE_22K; + case 24000: + return MTK_AFE_RATE_24K; + case 32000: + return MTK_AFE_RATE_32K; + case 44100: + return MTK_AFE_RATE_44K; + case 48000: + return MTK_AFE_RATE_48K; + case 88200: + return MTK_AFE_RATE_88K; + case 96000: + return MTK_AFE_RATE_96K; + case 176400: + return MTK_AFE_RATE_176K; + case 192000: + return MTK_AFE_RATE_192K; + case 260000: + return MTK_AFE_RATE_260K; + case 352800: + return MTK_AFE_RATE_352K; + case 384000: + return MTK_AFE_RATE_384K; + default: + dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, + rate, MTK_AFE_RATE_48K); + return MTK_AFE_RATE_48K; + } +} + +static unsigned int dai_memif_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_DAI_MEMIF_RATE_8K; + case 16000: + return MTK_AFE_DAI_MEMIF_RATE_16K; + case 32000: + return MTK_AFE_DAI_MEMIF_RATE_32K; + case 48000: + return MTK_AFE_DAI_MEMIF_RATE_48K; + default: + dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, + rate, MTK_AFE_DAI_MEMIF_RATE_16K); + return MTK_AFE_DAI_MEMIF_RATE_16K; + } +} + +static unsigned int pcm_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_PCM_RATE_8K; + case 16000: + return MTK_AFE_PCM_RATE_16K; + case 32000: + return MTK_AFE_PCM_RATE_32K; + case 48000: + return MTK_AFE_PCM_RATE_48K; + default: + dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, + rate, MTK_AFE_PCM_RATE_32K); + return MTK_AFE_PCM_RATE_32K; + } +} + +unsigned int mt8192_rate_transform(struct device *dev, + unsigned int rate, int aud_blk) +{ + switch (aud_blk) { + case MT8192_MEMIF_DAI: + case MT8192_MEMIF_MOD_DAI: + return dai_memif_rate_transform(dev, rate); + case MT8192_DAI_PCM_1: + case MT8192_DAI_PCM_2: + return pcm_rate_transform(dev, rate); + default: + return mt8192_general_rate_transform(dev, rate); + } +} + +int mt8192_dai_set_priv(struct mtk_base_afe *afe, int id, + int priv_size, const void *priv_data) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + void *temp_data; + + temp_data = devm_kzalloc(afe->dev, + priv_size, + GFP_KERNEL); + if (!temp_data) + return -ENOMEM; + + if (priv_data) + memcpy(temp_data, priv_data, priv_size); + + afe_priv->dai_priv[id] = temp_data; + + return 0; +} diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c new file mode 100644 index 000000000000..ea000888c9e8 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8192-afe-gpio.c -- Mediatek 8192 afe gpio ctrl +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Shane Chien +// + +#include +#include + +#include "mt8192-afe-common.h" +#include "mt8192-afe-gpio.h" + +struct pinctrl *aud_pinctrl; + +enum mt8192_afe_gpio { + MT8192_AFE_GPIO_DAT_MISO_OFF, + MT8192_AFE_GPIO_DAT_MISO_ON, + MT8192_AFE_GPIO_DAT_MOSI_OFF, + MT8192_AFE_GPIO_DAT_MOSI_ON, + MT8192_AFE_GPIO_DAT_MISO_CH34_OFF, + MT8192_AFE_GPIO_DAT_MISO_CH34_ON, + MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF, + MT8192_AFE_GPIO_DAT_MOSI_CH34_ON, + MT8192_AFE_GPIO_I2S0_OFF, + MT8192_AFE_GPIO_I2S0_ON, + MT8192_AFE_GPIO_I2S1_OFF, + MT8192_AFE_GPIO_I2S1_ON, + MT8192_AFE_GPIO_I2S2_OFF, + MT8192_AFE_GPIO_I2S2_ON, + MT8192_AFE_GPIO_I2S3_OFF, + MT8192_AFE_GPIO_I2S3_ON, + MT8192_AFE_GPIO_I2S5_OFF, + MT8192_AFE_GPIO_I2S5_ON, + MT8192_AFE_GPIO_I2S6_OFF, + MT8192_AFE_GPIO_I2S6_ON, + MT8192_AFE_GPIO_I2S7_OFF, + MT8192_AFE_GPIO_I2S7_ON, + MT8192_AFE_GPIO_I2S8_OFF, + MT8192_AFE_GPIO_I2S8_ON, + MT8192_AFE_GPIO_I2S9_OFF, + MT8192_AFE_GPIO_I2S9_ON, + MT8192_AFE_GPIO_VOW_DAT_OFF, + MT8192_AFE_GPIO_VOW_DAT_ON, + MT8192_AFE_GPIO_VOW_CLK_OFF, + MT8192_AFE_GPIO_VOW_CLK_ON, + MT8192_AFE_GPIO_CLK_MOSI_OFF, + MT8192_AFE_GPIO_CLK_MOSI_ON, + MT8192_AFE_GPIO_TDM_OFF, + MT8192_AFE_GPIO_TDM_ON, + MT8192_AFE_GPIO_GPIO_NUM +}; + +struct audio_gpio_attr { + const char *name; + bool gpio_prepare; + struct pinctrl_state *gpioctrl; +}; + +static struct audio_gpio_attr aud_gpios[MT8192_AFE_GPIO_GPIO_NUM] = { + [MT8192_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL}, + [MT8192_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL}, + [MT8192_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL}, + [MT8192_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL}, + [MT8192_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL}, + [MT8192_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL}, + [MT8192_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL}, + [MT8192_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL}, + [MT8192_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL}, + [MT8192_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL}, + [MT8192_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL}, + [MT8192_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL}, + [MT8192_AFE_GPIO_I2S5_OFF] = {"aud_gpio_i2s5_off", false, NULL}, + [MT8192_AFE_GPIO_I2S5_ON] = {"aud_gpio_i2s5_on", false, NULL}, + [MT8192_AFE_GPIO_I2S6_OFF] = {"aud_gpio_i2s6_off", false, NULL}, + [MT8192_AFE_GPIO_I2S6_ON] = {"aud_gpio_i2s6_on", false, NULL}, + [MT8192_AFE_GPIO_I2S7_OFF] = {"aud_gpio_i2s7_off", false, NULL}, + [MT8192_AFE_GPIO_I2S7_ON] = {"aud_gpio_i2s7_on", false, NULL}, + [MT8192_AFE_GPIO_I2S8_OFF] = {"aud_gpio_i2s8_off", false, NULL}, + [MT8192_AFE_GPIO_I2S8_ON] = {"aud_gpio_i2s8_on", false, NULL}, + [MT8192_AFE_GPIO_I2S9_OFF] = {"aud_gpio_i2s9_off", false, NULL}, + [MT8192_AFE_GPIO_I2S9_ON] = {"aud_gpio_i2s9_on", false, NULL}, + [MT8192_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL}, + [MT8192_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL}, + [MT8192_AFE_GPIO_VOW_DAT_OFF] = {"vow_dat_miso_off", false, NULL}, + [MT8192_AFE_GPIO_VOW_DAT_ON] = {"vow_dat_miso_on", false, NULL}, + [MT8192_AFE_GPIO_VOW_CLK_OFF] = {"vow_clk_miso_off", false, NULL}, + [MT8192_AFE_GPIO_VOW_CLK_ON] = {"vow_clk_miso_on", false, NULL}, + [MT8192_AFE_GPIO_DAT_MISO_CH34_OFF] = {"aud_dat_miso_ch34_off", + false, NULL}, + [MT8192_AFE_GPIO_DAT_MISO_CH34_ON] = {"aud_dat_miso_ch34_on", + false, NULL}, + [MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF] = {"aud_dat_mosi_ch34_off", + false, NULL}, + [MT8192_AFE_GPIO_DAT_MOSI_CH34_ON] = {"aud_dat_mosi_ch34_on", + false, NULL}, + [MT8192_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL}, + [MT8192_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL}, +}; + +static DEFINE_MUTEX(gpio_request_mutex); + +static int mt8192_afe_gpio_select(struct device *dev, + enum mt8192_afe_gpio type) +{ + int ret; + + if (type < 0 || type >= MT8192_AFE_GPIO_GPIO_NUM) { + dev_err(dev, "%s(), error, invalid gpio type %d\n", + __func__, type); + return -EINVAL; + } + + if (!aud_gpios[type].gpio_prepare) { + dev_warn(dev, "%s(), error, gpio type %d not prepared\n", + __func__, type); + return -EIO; + } + + ret = pinctrl_select_state(aud_pinctrl, + aud_gpios[type].gpioctrl); + if (ret) { + dev_dbg(dev, "%s(), error, can not set gpio type %d\n", + __func__, type); + } + + return ret; +} + +int mt8192_afe_gpio_init(struct device *dev) +{ + int i, ret; + + aud_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(aud_pinctrl)) { + ret = PTR_ERR(aud_pinctrl); + dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n", + __func__, ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) { + aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl, + aud_gpios[i].name); + if (IS_ERR(aud_gpios[i].gpioctrl)) { + ret = PTR_ERR(aud_gpios[i].gpioctrl); + dev_dbg(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n", + __func__, aud_gpios[i].name, ret); + } else { + aud_gpios[i].gpio_prepare = true; + } + } + + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_CLK_MOSI_ON); + + /* gpio status init */ + mt8192_afe_gpio_request(dev, false, MT8192_DAI_ADDA, 0); + mt8192_afe_gpio_request(dev, false, MT8192_DAI_ADDA, 1); + + return 0; +} + +static int mt8192_afe_gpio_adda_dl(struct device *dev, bool enable) +{ + if (enable) { + return mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_DAT_MOSI_ON); + } else { + return mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_DAT_MOSI_OFF); + } +} + +static int mt8192_afe_gpio_adda_ul(struct device *dev, bool enable) +{ + if (enable) { + return mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_DAT_MISO_ON); + } else { + return mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_DAT_MISO_OFF); + } +} + +static int mt8192_afe_gpio_adda_ch34_dl(struct device *dev, bool enable) +{ + if (enable) { + return mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_DAT_MOSI_CH34_ON); + } else { + return mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_DAT_MOSI_CH34_OFF); + } +} + +static int mt8192_afe_gpio_adda_ch34_ul(struct device *dev, bool enable) +{ + if (enable) { + return mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_DAT_MISO_CH34_ON); + } else { + return mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_DAT_MISO_CH34_OFF); + } +} + +int mt8192_afe_gpio_request(struct device *dev, bool enable, + int dai, int uplink) +{ + mutex_lock(&gpio_request_mutex); + switch (dai) { + case MT8192_DAI_ADDA: + if (uplink) + mt8192_afe_gpio_adda_ul(dev, enable); + else + mt8192_afe_gpio_adda_dl(dev, enable); + break; + case MT8192_DAI_ADDA_CH34: + if (uplink) + mt8192_afe_gpio_adda_ch34_ul(dev, enable); + else + mt8192_afe_gpio_adda_ch34_dl(dev, enable); + break; + case MT8192_DAI_I2S_0: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S0_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S0_OFF); + break; + case MT8192_DAI_I2S_1: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S1_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S1_OFF); + break; + case MT8192_DAI_I2S_2: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S2_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S2_OFF); + break; + case MT8192_DAI_I2S_3: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S3_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S3_OFF); + break; + case MT8192_DAI_I2S_5: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S5_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S5_OFF); + break; + case MT8192_DAI_I2S_6: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S6_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S6_OFF); + break; + case MT8192_DAI_I2S_7: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S7_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S7_OFF); + break; + case MT8192_DAI_I2S_8: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S8_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S8_OFF); + break; + case MT8192_DAI_I2S_9: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S9_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_I2S9_OFF); + break; + case MT8192_DAI_TDM: + if (enable) + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_TDM_ON); + else + mt8192_afe_gpio_select(dev, MT8192_AFE_GPIO_TDM_OFF); + break; + case MT8192_DAI_VOW: + if (enable) { + mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_VOW_CLK_ON); + mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_VOW_DAT_ON); + } else { + mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_VOW_CLK_OFF); + mt8192_afe_gpio_select(dev, + MT8192_AFE_GPIO_VOW_DAT_OFF); + } + break; + default: + mutex_unlock(&gpio_request_mutex); + dev_warn(dev, "%s(), invalid dai %d\n", __func__, dai); + return -EINVAL; + } + mutex_unlock(&gpio_request_mutex); + + return 0; +} diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.h b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.h new file mode 100644 index 000000000000..5d29469da1c1 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8192-afe-gpio.h -- Mediatek 8192 afe gpio ctrl definition + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Shane Chien + */ + +#ifndef _MT8192_AFE_GPIO_H_ +#define _MT8192_AFE_GPIO_H_ + +struct device; + +int mt8192_afe_gpio_init(struct device *dev); + +int mt8192_afe_gpio_request(struct device *dev, bool enable, + int dai, int uplink); + +#endif diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c new file mode 100644 index 000000000000..4a4729f254ed --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c @@ -0,0 +1,2389 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Mediatek ALSA SoC AFE platform driver for 8192 +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Shane Chien +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/mtk-afe-fe-dai.h" +#include "../common/mtk-afe-platform-driver.h" + +#include "mt8192-afe-common.h" +#include "mt8192-afe-clk.h" +#include "mt8192-afe-gpio.h" +#include "mt8192-interconnection.h" + +static const struct snd_pcm_hardware mt8192_afe_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + .period_bytes_min = 96, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 4 * 48 * 1024, + .fifo_size = 0, +}; + +static int mt8192_memif_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + int id = asoc_rtd_to_cpu(rtd, 0)->id; + + return mt8192_rate_transform(afe->dev, rate, id); +} + +static int mt8192_get_dai_fs(struct mtk_base_afe *afe, + int dai_id, unsigned int rate) +{ + return mt8192_rate_transform(afe->dev, rate, dai_id); +} + +static int mt8192_irq_fs(struct snd_pcm_substream *substream, unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt8192_general_rate_transform(afe->dev, rate); +} + +int mt8192_get_memif_pbuf_size(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + if ((runtime->period_size * 1000) / runtime->rate > 10) + return MT8192_MEMIF_PBUF_SIZE_256_BYTES; + else + return MT8192_MEMIF_PBUF_SIZE_32_BYTES; +} + +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mt8192_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT8192_MEMIF_DL1, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL12", + .id = MT8192_MEMIF_DL12, + .playback = { + .stream_name = "DL12", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL2", + .id = MT8192_MEMIF_DL2, + .playback = { + .stream_name = "DL2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL3", + .id = MT8192_MEMIF_DL3, + .playback = { + .stream_name = "DL3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL4", + .id = MT8192_MEMIF_DL4, + .playback = { + .stream_name = "DL4", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL5", + .id = MT8192_MEMIF_DL5, + .playback = { + .stream_name = "DL5", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL6", + .id = MT8192_MEMIF_DL6, + .playback = { + .stream_name = "DL6", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL7", + .id = MT8192_MEMIF_DL7, + .playback = { + .stream_name = "DL7", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL8", + .id = MT8192_MEMIF_DL8, + .playback = { + .stream_name = "DL8", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL9", + .id = MT8192_MEMIF_DL9, + .playback = { + .stream_name = "DL9", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL1", + .id = MT8192_MEMIF_VUL12, + .capture = { + .stream_name = "UL1", + .channels_min = 1, + .channels_max = 4, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL2", + .id = MT8192_MEMIF_AWB, + .capture = { + .stream_name = "UL2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL3", + .id = MT8192_MEMIF_VUL2, + .capture = { + .stream_name = "UL3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL4", + .id = MT8192_MEMIF_AWB2, + .capture = { + .stream_name = "UL4", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL5", + .id = MT8192_MEMIF_VUL3, + .capture = { + .stream_name = "UL5", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL6", + .id = MT8192_MEMIF_VUL4, + .capture = { + .stream_name = "UL6", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL7", + .id = MT8192_MEMIF_VUL5, + .capture = { + .stream_name = "UL7", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL8", + .id = MT8192_MEMIF_VUL6, + .capture = { + .stream_name = "UL8", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL_MONO_1", + .id = MT8192_MEMIF_MOD_DAI, + .capture = { + .stream_name = "UL_MONO_1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_DAI_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL_MONO_2", + .id = MT8192_MEMIF_DAI, + .capture = { + .stream_name = "UL_MONO_2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_DAI_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL_MONO_3", + .id = MT8192_MEMIF_DAI2, + .capture = { + .stream_name = "UL_MONO_3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_DAI_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "HDMI", + .id = MT8192_MEMIF_HDMI, + .playback = { + .stream_name = "HDMI", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, +}; + +static int ul_tinyconn_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg_shift; + unsigned int reg_mask_shift; + + dev_info(afe->dev, "%s(), event 0x%x\n", __func__, event); + + if (strstr(w->name, "UL1")) { + reg_shift = VUL1_USE_TINY_SFT; + reg_mask_shift = VUL1_USE_TINY_MASK_SFT; + } else if (strstr(w->name, "UL2")) { + reg_shift = VUL2_USE_TINY_SFT; + reg_mask_shift = VUL2_USE_TINY_MASK_SFT; + } else if (strstr(w->name, "UL3")) { + reg_shift = VUL12_USE_TINY_SFT; + reg_mask_shift = VUL12_USE_TINY_MASK_SFT; + } else if (strstr(w->name, "UL4")) { + reg_shift = AWB2_USE_TINY_SFT; + reg_mask_shift = AWB2_USE_TINY_MASK_SFT; + } else { + reg_shift = AWB2_USE_TINY_SFT; + reg_mask_shift = AWB2_USE_TINY_MASK_SFT; + dev_warn(afe->dev, "%s(), err widget name %s, default use UL4", + __func__, w->name); + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(afe->regmap, AFE_MEMIF_CONN, reg_mask_shift, + 0x1 << reg_shift); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(afe->regmap, AFE_MEMIF_CONN, reg_mask_shift, + 0x0 << reg_shift); + break; + default: + break; + } + + return 0; +} + +/* dma widget & routes*/ +static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN21, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN21, + I_ADDA_UL_CH3, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN22, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN22, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN22, + I_ADDA_UL_CH4, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul1_ch3_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN9, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN9, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN9, + I_ADDA_UL_CH3, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul1_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN10, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN10, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN10, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4", AFE_CONN10, + I_ADDA_UL_CH4, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN5, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN5, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN5, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN5, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN5_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN5_1, + I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN5_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN5, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN5, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN5, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S6_CH1", AFE_CONN5_1, + I_I2S6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S8_CH1", AFE_CONN5_1, + I_I2S8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1", AFE_CONN5_1, + I_CONNSYS_I2S_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1", AFE_CONN5_1, + I_SRC_1_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN6, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN6, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN6, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN6, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN6_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN6_1, + I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN6_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN6, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN6, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN6, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S6_CH2", AFE_CONN6_1, + I_I2S6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S8_CH2", AFE_CONN6_1, + I_I2S8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2", AFE_CONN6_1, + I_CONNSYS_I2S_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2", AFE_CONN6_1, + I_SRC_1_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1", AFE_CONN32_1, + I_CONNSYS_I2S_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN32, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN32, + I_DL2_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2", AFE_CONN33_1, + I_CONNSYS_I2S_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN38, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN38, + I_I2S0_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN39, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN39, + I_I2S0_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul5_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN44, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul5_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN45, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul6_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN46, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN46, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN46, + I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN46_1, + I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN46, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN46, + I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN46_1, + I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN46, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN46, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul6_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN47, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN47, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN47, + I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN47_1, + I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN47, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN47, + I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN47_1, + I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN47, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN47, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul7_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN48, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul7_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN49, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul8_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN50, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul8_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN51, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul_mono_1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN12, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN12, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul_mono_2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN11, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul_mono_3_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN35, + I_ADDA_UL_CH1, 1, 0), +}; + +/* TINYCONN MUX */ +enum { + TINYCONN_CH1_MUX_I2S0 = 0x14, + TINYCONN_CH2_MUX_I2S0 = 0x15, + TINYCONN_CH1_MUX_I2S6 = 0x1a, + TINYCONN_CH2_MUX_I2S6 = 0x1b, + TINYCONN_CH1_MUX_I2S8 = 0x1c, + TINYCONN_CH2_MUX_I2S8 = 0x1d, + TINYCONN_MUX_NONE = 0x1f, +}; + +static const char * const tinyconn_mux_map[] = { + "NONE", + "I2S0_CH1", + "I2S0_CH2", + "I2S6_CH1", + "I2S6_CH2", + "I2S8_CH1", + "I2S8_CH2", +}; + +static int tinyconn_mux_map_value[] = { + TINYCONN_MUX_NONE, + TINYCONN_CH1_MUX_I2S0, + TINYCONN_CH2_MUX_I2S0, + TINYCONN_CH1_MUX_I2S6, + TINYCONN_CH2_MUX_I2S6, + TINYCONN_CH1_MUX_I2S8, + TINYCONN_CH2_MUX_I2S8, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(ul4_tinyconn_ch1_mux_map_enum, + AFE_TINY_CONN0, + O_2_CFG_SFT, + O_2_CFG_MASK, + tinyconn_mux_map, + tinyconn_mux_map_value); +static SOC_VALUE_ENUM_SINGLE_DECL(ul4_tinyconn_ch2_mux_map_enum, + AFE_TINY_CONN0, + O_3_CFG_SFT, + O_3_CFG_MASK, + tinyconn_mux_map, + tinyconn_mux_map_value); + +static const struct snd_kcontrol_new ul4_tinyconn_ch1_mux_control = + SOC_DAPM_ENUM("UL4_TINYCONN_CH1_MUX", ul4_tinyconn_ch1_mux_map_enum); +static const struct snd_kcontrol_new ul4_tinyconn_ch2_mux_control = + SOC_DAPM_ENUM("UL4_TINYCONN_CH2_MUX", ul4_tinyconn_ch2_mux_map_enum); + +static const struct snd_soc_dapm_widget mt8192_memif_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0, + memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)), + SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0, + memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)), + SND_SOC_DAPM_MIXER("UL1_CH3", SND_SOC_NOPM, 0, 0, + memif_ul1_ch3_mix, ARRAY_SIZE(memif_ul1_ch3_mix)), + SND_SOC_DAPM_MIXER("UL1_CH4", SND_SOC_NOPM, 0, 0, + memif_ul1_ch4_mix, ARRAY_SIZE(memif_ul1_ch4_mix)), + + SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0, + memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)), + SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0, + memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0, + memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)), + SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0, + memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0, + memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)), + SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0, + memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)), + SND_SOC_DAPM_MUX_E("UL4_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0, + &ul4_tinyconn_ch1_mux_control, + ul_tinyconn_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX_E("UL4_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0, + &ul4_tinyconn_ch2_mux_control, + ul_tinyconn_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MIXER("UL5_CH1", SND_SOC_NOPM, 0, 0, + memif_ul5_ch1_mix, ARRAY_SIZE(memif_ul5_ch1_mix)), + SND_SOC_DAPM_MIXER("UL5_CH2", SND_SOC_NOPM, 0, 0, + memif_ul5_ch2_mix, ARRAY_SIZE(memif_ul5_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL6_CH1", SND_SOC_NOPM, 0, 0, + memif_ul6_ch1_mix, ARRAY_SIZE(memif_ul6_ch1_mix)), + SND_SOC_DAPM_MIXER("UL6_CH2", SND_SOC_NOPM, 0, 0, + memif_ul6_ch2_mix, ARRAY_SIZE(memif_ul6_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL7_CH1", SND_SOC_NOPM, 0, 0, + memif_ul7_ch1_mix, ARRAY_SIZE(memif_ul7_ch1_mix)), + SND_SOC_DAPM_MIXER("UL7_CH2", SND_SOC_NOPM, 0, 0, + memif_ul7_ch2_mix, ARRAY_SIZE(memif_ul7_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL8_CH1", SND_SOC_NOPM, 0, 0, + memif_ul8_ch1_mix, ARRAY_SIZE(memif_ul8_ch1_mix)), + SND_SOC_DAPM_MIXER("UL8_CH2", SND_SOC_NOPM, 0, 0, + memif_ul8_ch2_mix, ARRAY_SIZE(memif_ul8_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL_MONO_1_CH1", SND_SOC_NOPM, 0, 0, + memif_ul_mono_1_mix, + ARRAY_SIZE(memif_ul_mono_1_mix)), + + SND_SOC_DAPM_MIXER("UL_MONO_2_CH1", SND_SOC_NOPM, 0, 0, + memif_ul_mono_2_mix, + ARRAY_SIZE(memif_ul_mono_2_mix)), + + SND_SOC_DAPM_MIXER("UL_MONO_3_CH1", SND_SOC_NOPM, 0, 0, + memif_ul_mono_3_mix, + ARRAY_SIZE(memif_ul_mono_3_mix)), + + SND_SOC_DAPM_INPUT("UL1_VIRTUAL_INPUT"), + SND_SOC_DAPM_INPUT("UL2_VIRTUAL_INPUT"), + SND_SOC_DAPM_INPUT("UL6_VIRTUAL_INPUT"), +}; + +static const struct snd_soc_dapm_route mt8192_memif_routes[] = { + {"UL1", NULL, "UL1_CH1"}, + {"UL1", NULL, "UL1_CH2"}, + {"UL1", NULL, "UL1_CH3"}, + {"UL1", NULL, "UL1_CH4"}, + {"UL1_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL1_CH1", "ADDA_UL_CH2", "ADDA_UL_Mux"}, + {"UL1_CH1", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"}, + {"UL1_CH2", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL1_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"}, + {"UL1_CH2", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"}, + {"UL1_CH2", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"}, + {"UL1_CH3", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL1_CH3", "ADDA_UL_CH2", "ADDA_UL_Mux"}, + {"UL1_CH3", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"}, + {"UL1_CH4", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL1_CH4", "ADDA_UL_CH2", "ADDA_UL_Mux"}, + {"UL1_CH4", "ADDA_UL_CH3", "ADDA_CH34_UL_Mux"}, + {"UL1_CH4", "ADDA_UL_CH4", "ADDA_CH34_UL_Mux"}, + + {"UL2", NULL, "UL2_CH1"}, + {"UL2", NULL, "UL2_CH2"}, + {"UL2_CH1", "I2S0_CH1", "I2S0"}, + {"UL2_CH2", "I2S0_CH2", "I2S0"}, + {"UL2_CH1", "I2S2_CH1", "I2S2"}, + {"UL2_CH2", "I2S2_CH2", "I2S2"}, + {"UL2_CH1", "I2S6_CH1", "I2S6"}, + {"UL2_CH2", "I2S6_CH2", "I2S6"}, + {"UL2_CH1", "I2S8_CH1", "I2S8"}, + {"UL2_CH2", "I2S8_CH2", "I2S8"}, + + {"UL2_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"}, + {"UL2_CH2", "PCM_1_CAP_CH1", "PCM 1 Capture"}, + {"UL2_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"}, + {"UL2_CH2", "PCM_2_CAP_CH1", "PCM 2 Capture"}, + + {"UL_MONO_1", NULL, "UL_MONO_1_CH1"}, + {"UL_MONO_1_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"}, + {"UL_MONO_1_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"}, + + {"UL_MONO_2", NULL, "UL_MONO_2_CH1"}, + {"UL_MONO_2_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + + {"UL_MONO_3", NULL, "UL_MONO_3_CH1"}, + {"UL_MONO_3_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + + {"UL2_CH1", "CONNSYS_I2S_CH1", "Connsys I2S"}, + {"UL2_CH2", "CONNSYS_I2S_CH2", "Connsys I2S"}, + + {"UL3", NULL, "UL3_CH1"}, + {"UL3", NULL, "UL3_CH2"}, + {"UL3_CH1", "CONNSYS_I2S_CH1", "Connsys I2S"}, + {"UL3_CH2", "CONNSYS_I2S_CH2", "Connsys I2S"}, + + {"UL4", NULL, "UL4_CH1"}, + {"UL4", NULL, "UL4_CH2"}, + {"UL4", NULL, "UL4_TINYCONN_CH1_MUX"}, + {"UL4", NULL, "UL4_TINYCONN_CH2_MUX"}, + {"UL4_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL4_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"}, + {"UL4_CH1", "I2S0_CH1", "I2S0"}, + {"UL4_CH2", "I2S0_CH2", "I2S0"}, + {"UL4_TINYCONN_CH1_MUX", "I2S0_CH1", "I2S0"}, + {"UL4_TINYCONN_CH2_MUX", "I2S0_CH2", "I2S0"}, + + {"UL5", NULL, "UL5_CH1"}, + {"UL5", NULL, "UL5_CH2"}, + {"UL5_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL5_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"}, + + {"UL6", NULL, "UL6_CH1"}, + {"UL6", NULL, "UL6_CH2"}, + + {"UL6_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL6_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"}, + {"UL6_CH1", "PCM_1_CAP_CH1", "PCM 1 Capture"}, + {"UL6_CH2", "PCM_1_CAP_CH1", "PCM 1 Capture"}, + {"UL6_CH1", "PCM_2_CAP_CH1", "PCM 2 Capture"}, + {"UL6_CH2", "PCM_2_CAP_CH1", "PCM 2 Capture"}, + + {"UL7", NULL, "UL7_CH1"}, + {"UL7", NULL, "UL7_CH2"}, + {"UL7_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL7_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"}, + + {"UL8", NULL, "UL8_CH1"}, + {"UL8", NULL, "UL8_CH2"}, + {"UL8_CH1", "ADDA_UL_CH1", "ADDA_UL_Mux"}, + {"UL8_CH2", "ADDA_UL_CH2", "ADDA_UL_Mux"}, +}; + +static const struct mtk_base_memif_data memif_data[MT8192_MEMIF_NUM] = { + [MT8192_MEMIF_DL1] = { + .name = "DL1", + .id = MT8192_MEMIF_DL1, + .reg_ofs_base = AFE_DL1_BASE, + .reg_ofs_cur = AFE_DL1_CUR, + .reg_ofs_end = AFE_DL1_END, + .reg_ofs_base_msb = AFE_DL1_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL1_CUR_MSB, + .reg_ofs_end_msb = AFE_DL1_END_MSB, + .fs_reg = AFE_DL1_CON0, + .fs_shift = DL1_MODE_SFT, + .fs_maskbit = DL1_MODE_MASK, + .mono_reg = AFE_DL1_CON0, + .mono_shift = DL1_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL1_ON_SFT, + .hd_reg = AFE_DL1_CON0, + .hd_shift = DL1_HD_MODE_SFT, + .hd_align_reg = AFE_DL1_CON0, + .hd_align_mshift = DL1_HALIGN_SFT, + .pbuf_reg = AFE_DL1_CON0, + .pbuf_shift = DL1_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL1_CON0, + .minlen_shift = DL1_MINLEN_SFT, + }, + [MT8192_MEMIF_DL12] = { + .name = "DL12", + .id = MT8192_MEMIF_DL12, + .reg_ofs_base = AFE_DL12_BASE, + .reg_ofs_cur = AFE_DL12_CUR, + .reg_ofs_end = AFE_DL12_END, + .reg_ofs_base_msb = AFE_DL12_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL12_CUR_MSB, + .reg_ofs_end_msb = AFE_DL12_END_MSB, + .fs_reg = AFE_DL12_CON0, + .fs_shift = DL12_MODE_SFT, + .fs_maskbit = DL12_MODE_MASK, + .mono_reg = AFE_DL12_CON0, + .mono_shift = DL12_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL12_ON_SFT, + .hd_reg = AFE_DL12_CON0, + .hd_shift = DL12_HD_MODE_SFT, + .hd_align_reg = AFE_DL12_CON0, + .hd_align_mshift = DL12_HALIGN_SFT, + .pbuf_reg = AFE_DL12_CON0, + .pbuf_shift = DL12_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL12_CON0, + .minlen_shift = DL12_MINLEN_SFT, + }, + [MT8192_MEMIF_DL2] = { + .name = "DL2", + .id = MT8192_MEMIF_DL2, + .reg_ofs_base = AFE_DL2_BASE, + .reg_ofs_cur = AFE_DL2_CUR, + .reg_ofs_end = AFE_DL2_END, + .reg_ofs_base_msb = AFE_DL2_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL2_CUR_MSB, + .reg_ofs_end_msb = AFE_DL2_END_MSB, + .fs_reg = AFE_DL2_CON0, + .fs_shift = DL2_MODE_SFT, + .fs_maskbit = DL2_MODE_MASK, + .mono_reg = AFE_DL2_CON0, + .mono_shift = DL2_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL2_ON_SFT, + .hd_reg = AFE_DL2_CON0, + .hd_shift = DL2_HD_MODE_SFT, + .hd_align_reg = AFE_DL2_CON0, + .hd_align_mshift = DL2_HALIGN_SFT, + .pbuf_reg = AFE_DL2_CON0, + .pbuf_shift = DL2_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL2_CON0, + .minlen_shift = DL2_MINLEN_SFT, + }, + [MT8192_MEMIF_DL3] = { + .name = "DL3", + .id = MT8192_MEMIF_DL3, + .reg_ofs_base = AFE_DL3_BASE, + .reg_ofs_cur = AFE_DL3_CUR, + .reg_ofs_end = AFE_DL3_END, + .reg_ofs_base_msb = AFE_DL3_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL3_CUR_MSB, + .reg_ofs_end_msb = AFE_DL3_END_MSB, + .fs_reg = AFE_DL3_CON0, + .fs_shift = DL3_MODE_SFT, + .fs_maskbit = DL3_MODE_MASK, + .mono_reg = AFE_DL3_CON0, + .mono_shift = DL3_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL3_ON_SFT, + .hd_reg = AFE_DL3_CON0, + .hd_shift = DL3_HD_MODE_SFT, + .hd_align_reg = AFE_DL3_CON0, + .hd_align_mshift = DL3_HALIGN_SFT, + .pbuf_reg = AFE_DL3_CON0, + .pbuf_shift = DL3_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL3_CON0, + .minlen_shift = DL3_MINLEN_SFT, + }, + [MT8192_MEMIF_DL4] = { + .name = "DL4", + .id = MT8192_MEMIF_DL4, + .reg_ofs_base = AFE_DL4_BASE, + .reg_ofs_cur = AFE_DL4_CUR, + .reg_ofs_end = AFE_DL4_END, + .reg_ofs_base_msb = AFE_DL4_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL4_CUR_MSB, + .reg_ofs_end_msb = AFE_DL4_END_MSB, + .fs_reg = AFE_DL4_CON0, + .fs_shift = DL4_MODE_SFT, + .fs_maskbit = DL4_MODE_MASK, + .mono_reg = AFE_DL4_CON0, + .mono_shift = DL4_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL4_ON_SFT, + .hd_reg = AFE_DL4_CON0, + .hd_shift = DL4_HD_MODE_SFT, + .hd_align_reg = AFE_DL4_CON0, + .hd_align_mshift = DL4_HALIGN_SFT, + .pbuf_reg = AFE_DL4_CON0, + .pbuf_shift = DL4_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL4_CON0, + .minlen_shift = DL4_MINLEN_SFT, + }, + [MT8192_MEMIF_DL5] = { + .name = "DL5", + .id = MT8192_MEMIF_DL5, + .reg_ofs_base = AFE_DL5_BASE, + .reg_ofs_cur = AFE_DL5_CUR, + .reg_ofs_end = AFE_DL5_END, + .reg_ofs_base_msb = AFE_DL5_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL5_CUR_MSB, + .reg_ofs_end_msb = AFE_DL5_END_MSB, + .fs_reg = AFE_DL5_CON0, + .fs_shift = DL5_MODE_SFT, + .fs_maskbit = DL5_MODE_MASK, + .mono_reg = AFE_DL5_CON0, + .mono_shift = DL5_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL5_ON_SFT, + .hd_reg = AFE_DL5_CON0, + .hd_shift = DL5_HD_MODE_SFT, + .hd_align_reg = AFE_DL5_CON0, + .hd_align_mshift = DL5_HALIGN_SFT, + .pbuf_reg = AFE_DL5_CON0, + .pbuf_shift = DL5_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL5_CON0, + .minlen_shift = DL5_MINLEN_SFT, + }, + [MT8192_MEMIF_DL6] = { + .name = "DL6", + .id = MT8192_MEMIF_DL6, + .reg_ofs_base = AFE_DL6_BASE, + .reg_ofs_cur = AFE_DL6_CUR, + .reg_ofs_end = AFE_DL6_END, + .reg_ofs_base_msb = AFE_DL6_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL6_CUR_MSB, + .reg_ofs_end_msb = AFE_DL6_END_MSB, + .fs_reg = AFE_DL6_CON0, + .fs_shift = DL6_MODE_SFT, + .fs_maskbit = DL6_MODE_MASK, + .mono_reg = AFE_DL6_CON0, + .mono_shift = DL6_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL6_ON_SFT, + .hd_reg = AFE_DL6_CON0, + .hd_shift = DL6_HD_MODE_SFT, + .hd_align_reg = AFE_DL6_CON0, + .hd_align_mshift = DL6_HALIGN_SFT, + .pbuf_reg = AFE_DL6_CON0, + .pbuf_shift = DL6_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL6_CON0, + .minlen_shift = DL6_MINLEN_SFT, + }, + [MT8192_MEMIF_DL7] = { + .name = "DL7", + .id = MT8192_MEMIF_DL7, + .reg_ofs_base = AFE_DL7_BASE, + .reg_ofs_cur = AFE_DL7_CUR, + .reg_ofs_end = AFE_DL7_END, + .reg_ofs_base_msb = AFE_DL7_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL7_CUR_MSB, + .reg_ofs_end_msb = AFE_DL7_END_MSB, + .fs_reg = AFE_DL7_CON0, + .fs_shift = DL7_MODE_SFT, + .fs_maskbit = DL7_MODE_MASK, + .mono_reg = AFE_DL7_CON0, + .mono_shift = DL7_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL7_ON_SFT, + .hd_reg = AFE_DL7_CON0, + .hd_shift = DL7_HD_MODE_SFT, + .hd_align_reg = AFE_DL7_CON0, + .hd_align_mshift = DL7_HALIGN_SFT, + .pbuf_reg = AFE_DL7_CON0, + .pbuf_shift = DL7_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL7_CON0, + .minlen_shift = DL7_MINLEN_SFT, + }, + [MT8192_MEMIF_DL8] = { + .name = "DL8", + .id = MT8192_MEMIF_DL8, + .reg_ofs_base = AFE_DL8_BASE, + .reg_ofs_cur = AFE_DL8_CUR, + .reg_ofs_end = AFE_DL8_END, + .reg_ofs_base_msb = AFE_DL8_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL8_CUR_MSB, + .reg_ofs_end_msb = AFE_DL8_END_MSB, + .fs_reg = AFE_DL8_CON0, + .fs_shift = DL8_MODE_SFT, + .fs_maskbit = DL8_MODE_MASK, + .mono_reg = AFE_DL8_CON0, + .mono_shift = DL8_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL8_ON_SFT, + .hd_reg = AFE_DL8_CON0, + .hd_shift = DL8_HD_MODE_SFT, + .hd_align_reg = AFE_DL8_CON0, + .hd_align_mshift = DL8_HALIGN_SFT, + .pbuf_reg = AFE_DL8_CON0, + .pbuf_shift = DL8_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL8_CON0, + .minlen_shift = DL8_MINLEN_SFT, + }, + [MT8192_MEMIF_DL9] = { + .name = "DL9", + .id = MT8192_MEMIF_DL9, + .reg_ofs_base = AFE_DL9_BASE, + .reg_ofs_cur = AFE_DL9_CUR, + .reg_ofs_end = AFE_DL9_END, + .reg_ofs_base_msb = AFE_DL9_BASE_MSB, + .reg_ofs_cur_msb = AFE_DL9_CUR_MSB, + .reg_ofs_end_msb = AFE_DL9_END_MSB, + .fs_reg = AFE_DL9_CON0, + .fs_shift = DL9_MODE_SFT, + .fs_maskbit = DL9_MODE_MASK, + .mono_reg = AFE_DL9_CON0, + .mono_shift = DL9_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL9_ON_SFT, + .hd_reg = AFE_DL9_CON0, + .hd_shift = DL9_HD_MODE_SFT, + .hd_align_reg = AFE_DL9_CON0, + .hd_align_mshift = DL9_HALIGN_SFT, + .pbuf_reg = AFE_DL9_CON0, + .pbuf_shift = DL9_PBUF_SIZE_SFT, + .minlen_reg = AFE_DL9_CON0, + .minlen_shift = DL9_MINLEN_SFT, + }, + [MT8192_MEMIF_DAI] = { + .name = "DAI", + .id = MT8192_MEMIF_DAI, + .reg_ofs_base = AFE_DAI_BASE, + .reg_ofs_cur = AFE_DAI_CUR, + .reg_ofs_end = AFE_DAI_END, + .reg_ofs_base_msb = AFE_DAI_BASE_MSB, + .reg_ofs_cur_msb = AFE_DAI_CUR_MSB, + .reg_ofs_end_msb = AFE_DAI_END_MSB, + .fs_reg = AFE_DAI_CON0, + .fs_shift = DAI_MODE_SFT, + .fs_maskbit = DAI_MODE_MASK, + .mono_reg = AFE_DAI_CON0, + .mono_shift = DAI_DUPLICATE_WR_SFT, + .mono_invert = 1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DAI_ON_SFT, + .hd_reg = AFE_DAI_CON0, + .hd_shift = DAI_HD_MODE_SFT, + .hd_align_reg = AFE_DAI_CON0, + .hd_align_mshift = DAI_HALIGN_SFT, + }, + [MT8192_MEMIF_MOD_DAI] = { + .name = "MOD_DAI", + .id = MT8192_MEMIF_MOD_DAI, + .reg_ofs_base = AFE_MOD_DAI_BASE, + .reg_ofs_cur = AFE_MOD_DAI_CUR, + .reg_ofs_end = AFE_MOD_DAI_END, + .reg_ofs_base_msb = AFE_MOD_DAI_BASE_MSB, + .reg_ofs_cur_msb = AFE_MOD_DAI_CUR_MSB, + .reg_ofs_end_msb = AFE_MOD_DAI_END_MSB, + .fs_reg = AFE_MOD_DAI_CON0, + .fs_shift = MOD_DAI_MODE_SFT, + .fs_maskbit = MOD_DAI_MODE_MASK, + .mono_reg = AFE_MOD_DAI_CON0, + .mono_shift = MOD_DAI_DUPLICATE_WR_SFT, + .mono_invert = 1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = MOD_DAI_ON_SFT, + .hd_reg = AFE_MOD_DAI_CON0, + .hd_shift = MOD_DAI_HD_MODE_SFT, + .hd_align_reg = AFE_MOD_DAI_CON0, + .hd_align_mshift = MOD_DAI_HALIGN_SFT, + }, + [MT8192_MEMIF_DAI2] = { + .name = "DAI2", + .id = MT8192_MEMIF_DAI2, + .reg_ofs_base = AFE_DAI2_BASE, + .reg_ofs_cur = AFE_DAI2_CUR, + .reg_ofs_end = AFE_DAI2_END, + .reg_ofs_base_msb = AFE_DAI2_BASE_MSB, + .reg_ofs_cur_msb = AFE_DAI2_CUR_MSB, + .reg_ofs_end_msb = AFE_DAI2_END_MSB, + .fs_reg = AFE_DAI2_CON0, + .fs_shift = DAI2_MODE_SFT, + .fs_maskbit = DAI2_MODE_MASK, + .mono_reg = AFE_DAI2_CON0, + .mono_shift = DAI2_DUPLICATE_WR_SFT, + .mono_invert = 1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DAI2_ON_SFT, + .hd_reg = AFE_DAI2_CON0, + .hd_shift = DAI2_HD_MODE_SFT, + .hd_align_reg = AFE_DAI2_CON0, + .hd_align_mshift = DAI2_HALIGN_SFT, + }, + [MT8192_MEMIF_VUL12] = { + .name = "VUL12", + .id = MT8192_MEMIF_VUL12, + .reg_ofs_base = AFE_VUL12_BASE, + .reg_ofs_cur = AFE_VUL12_CUR, + .reg_ofs_end = AFE_VUL12_END, + .reg_ofs_base_msb = AFE_VUL12_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL12_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL12_END_MSB, + .fs_reg = AFE_VUL12_CON0, + .fs_shift = VUL12_MODE_SFT, + .fs_maskbit = VUL12_MODE_MASK, + .mono_reg = AFE_VUL12_CON0, + .mono_shift = VUL12_MONO_SFT, + .quad_ch_reg = AFE_VUL12_CON0, + .quad_ch_shift = VUL12_4CH_EN_SFT, + .quad_ch_mask = VUL12_4CH_EN_MASK, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL12_ON_SFT, + .hd_reg = AFE_VUL12_CON0, + .hd_shift = VUL12_HD_MODE_SFT, + .hd_align_reg = AFE_VUL12_CON0, + .hd_align_mshift = VUL12_HALIGN_SFT, + }, + [MT8192_MEMIF_VUL2] = { + .name = "VUL2", + .id = MT8192_MEMIF_VUL2, + .reg_ofs_base = AFE_VUL2_BASE, + .reg_ofs_cur = AFE_VUL2_CUR, + .reg_ofs_end = AFE_VUL2_END, + .reg_ofs_base_msb = AFE_VUL2_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL2_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL2_END_MSB, + .fs_reg = AFE_VUL2_CON0, + .fs_shift = VUL2_MODE_SFT, + .fs_maskbit = VUL2_MODE_MASK, + .mono_reg = AFE_VUL2_CON0, + .mono_shift = VUL2_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL2_ON_SFT, + .hd_reg = AFE_VUL2_CON0, + .hd_shift = VUL2_HD_MODE_SFT, + .hd_align_reg = AFE_VUL2_CON0, + .hd_align_mshift = VUL2_HALIGN_SFT, + }, + [MT8192_MEMIF_AWB] = { + .name = "AWB", + .id = MT8192_MEMIF_AWB, + .reg_ofs_base = AFE_AWB_BASE, + .reg_ofs_cur = AFE_AWB_CUR, + .reg_ofs_end = AFE_AWB_END, + .reg_ofs_base_msb = AFE_AWB_BASE_MSB, + .reg_ofs_cur_msb = AFE_AWB_CUR_MSB, + .reg_ofs_end_msb = AFE_AWB_END_MSB, + .fs_reg = AFE_AWB_CON0, + .fs_shift = AWB_MODE_SFT, + .fs_maskbit = AWB_MODE_MASK, + .mono_reg = AFE_AWB_CON0, + .mono_shift = AWB_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = AWB_ON_SFT, + .hd_reg = AFE_AWB_CON0, + .hd_shift = AWB_HD_MODE_SFT, + .hd_align_reg = AFE_AWB_CON0, + .hd_align_mshift = AWB_HALIGN_SFT, + }, + [MT8192_MEMIF_AWB2] = { + .name = "AWB2", + .id = MT8192_MEMIF_AWB2, + .reg_ofs_base = AFE_AWB2_BASE, + .reg_ofs_cur = AFE_AWB2_CUR, + .reg_ofs_end = AFE_AWB2_END, + .reg_ofs_base_msb = AFE_AWB2_BASE_MSB, + .reg_ofs_cur_msb = AFE_AWB2_CUR_MSB, + .reg_ofs_end_msb = AFE_AWB2_END_MSB, + .fs_reg = AFE_AWB2_CON0, + .fs_shift = AWB2_MODE_SFT, + .fs_maskbit = AWB2_MODE_MASK, + .mono_reg = AFE_AWB2_CON0, + .mono_shift = AWB2_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = AWB2_ON_SFT, + .hd_reg = AFE_AWB2_CON0, + .hd_shift = AWB2_HD_MODE_SFT, + .hd_align_reg = AFE_AWB2_CON0, + .hd_align_mshift = AWB2_HALIGN_SFT, + }, + [MT8192_MEMIF_VUL3] = { + .name = "VUL3", + .id = MT8192_MEMIF_VUL3, + .reg_ofs_base = AFE_VUL3_BASE, + .reg_ofs_cur = AFE_VUL3_CUR, + .reg_ofs_end = AFE_VUL3_END, + .reg_ofs_base_msb = AFE_VUL3_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL3_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL3_END_MSB, + .fs_reg = AFE_VUL3_CON0, + .fs_shift = VUL3_MODE_SFT, + .fs_maskbit = VUL3_MODE_MASK, + .mono_reg = AFE_VUL3_CON0, + .mono_shift = VUL3_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL3_ON_SFT, + .hd_reg = AFE_VUL3_CON0, + .hd_shift = VUL3_HD_MODE_SFT, + .hd_align_reg = AFE_VUL3_CON0, + .hd_align_mshift = VUL3_HALIGN_SFT, + }, + [MT8192_MEMIF_VUL4] = { + .name = "VUL4", + .id = MT8192_MEMIF_VUL4, + .reg_ofs_base = AFE_VUL4_BASE, + .reg_ofs_cur = AFE_VUL4_CUR, + .reg_ofs_end = AFE_VUL4_END, + .reg_ofs_base_msb = AFE_VUL4_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL4_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL4_END_MSB, + .fs_reg = AFE_VUL4_CON0, + .fs_shift = VUL4_MODE_SFT, + .fs_maskbit = VUL4_MODE_MASK, + .mono_reg = AFE_VUL4_CON0, + .mono_shift = VUL4_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL4_ON_SFT, + .hd_reg = AFE_VUL4_CON0, + .hd_shift = VUL4_HD_MODE_SFT, + .hd_align_reg = AFE_VUL4_CON0, + .hd_align_mshift = VUL4_HALIGN_SFT, + }, + [MT8192_MEMIF_VUL5] = { + .name = "VUL5", + .id = MT8192_MEMIF_VUL5, + .reg_ofs_base = AFE_VUL5_BASE, + .reg_ofs_cur = AFE_VUL5_CUR, + .reg_ofs_end = AFE_VUL5_END, + .reg_ofs_base_msb = AFE_VUL5_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL5_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL5_END_MSB, + .fs_reg = AFE_VUL5_CON0, + .fs_shift = VUL5_MODE_SFT, + .fs_maskbit = VUL5_MODE_MASK, + .mono_reg = AFE_VUL5_CON0, + .mono_shift = VUL5_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL5_ON_SFT, + .hd_reg = AFE_VUL5_CON0, + .hd_shift = VUL5_HD_MODE_SFT, + .hd_align_reg = AFE_VUL5_CON0, + .hd_align_mshift = VUL5_HALIGN_SFT, + }, + [MT8192_MEMIF_VUL6] = { + .name = "VUL6", + .id = MT8192_MEMIF_VUL6, + .reg_ofs_base = AFE_VUL6_BASE, + .reg_ofs_cur = AFE_VUL6_CUR, + .reg_ofs_end = AFE_VUL6_END, + .reg_ofs_base_msb = AFE_VUL6_BASE_MSB, + .reg_ofs_cur_msb = AFE_VUL6_CUR_MSB, + .reg_ofs_end_msb = AFE_VUL6_END_MSB, + .fs_reg = AFE_VUL6_CON0, + .fs_shift = VUL6_MODE_SFT, + .fs_maskbit = VUL6_MODE_MASK, + .mono_reg = AFE_VUL6_CON0, + .mono_shift = VUL6_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL6_ON_SFT, + .hd_reg = AFE_VUL6_CON0, + .hd_shift = VUL6_HD_MODE_SFT, + .hd_align_reg = AFE_VUL6_CON0, + .hd_align_mshift = VUL6_HALIGN_SFT, + }, + [MT8192_MEMIF_HDMI] = { + .name = "HDMI", + .id = MT8192_MEMIF_HDMI, + .reg_ofs_base = AFE_HDMI_OUT_BASE, + .reg_ofs_cur = AFE_HDMI_OUT_CUR, + .reg_ofs_end = AFE_HDMI_OUT_END, + .reg_ofs_base_msb = AFE_HDMI_OUT_BASE_MSB, + .reg_ofs_cur_msb = AFE_HDMI_OUT_CUR_MSB, + .reg_ofs_end_msb = AFE_HDMI_OUT_END_MSB, + .fs_reg = -1, + .fs_shift = -1, + .fs_maskbit = -1, + .mono_reg = -1, + .mono_shift = -1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = HDMI_OUT_ON_SFT, + .hd_reg = AFE_HDMI_OUT_CON0, + .hd_shift = HDMI_OUT_HD_MODE_SFT, + .hd_align_reg = AFE_HDMI_OUT_CON0, + .hd_align_mshift = HDMI_OUT_HALIGN_SFT, + .pbuf_reg = AFE_HDMI_OUT_CON0, + .minlen_reg = AFE_HDMI_OUT_CON0, + .minlen_shift = HDMI_OUT_MINLEN_SFT, + }, +}; + +static const struct mtk_base_irq_data irq_data[MT8192_IRQ_NUM] = { + [MT8192_IRQ_0] = { + .id = MT8192_IRQ_0, + .irq_cnt_reg = AFE_IRQ_MCU_CNT0, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ0_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ0_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ0_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ0_MCU_CLR_SFT, + }, + [MT8192_IRQ_1] = { + .id = MT8192_IRQ_1, + .irq_cnt_reg = AFE_IRQ_MCU_CNT1, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ1_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ1_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ1_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ1_MCU_CLR_SFT, + }, + [MT8192_IRQ_2] = { + .id = MT8192_IRQ_2, + .irq_cnt_reg = AFE_IRQ_MCU_CNT2, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ2_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ2_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ2_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ2_MCU_CLR_SFT, + }, + [MT8192_IRQ_3] = { + .id = MT8192_IRQ_3, + .irq_cnt_reg = AFE_IRQ_MCU_CNT3, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ3_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ3_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ3_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ3_MCU_CLR_SFT, + }, + [MT8192_IRQ_4] = { + .id = MT8192_IRQ_4, + .irq_cnt_reg = AFE_IRQ_MCU_CNT4, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ4_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ4_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ4_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ4_MCU_CLR_SFT, + }, + [MT8192_IRQ_5] = { + .id = MT8192_IRQ_5, + .irq_cnt_reg = AFE_IRQ_MCU_CNT5, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ5_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ5_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ5_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ5_MCU_CLR_SFT, + }, + [MT8192_IRQ_6] = { + .id = MT8192_IRQ_6, + .irq_cnt_reg = AFE_IRQ_MCU_CNT6, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ6_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ6_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ6_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ6_MCU_CLR_SFT, + }, + [MT8192_IRQ_7] = { + .id = MT8192_IRQ_7, + .irq_cnt_reg = AFE_IRQ_MCU_CNT7, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ7_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ7_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ7_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ7_MCU_CLR_SFT, + }, + [MT8192_IRQ_8] = { + .id = MT8192_IRQ_8, + .irq_cnt_reg = AFE_IRQ_MCU_CNT8, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ8_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ8_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ8_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ8_MCU_CLR_SFT, + }, + [MT8192_IRQ_9] = { + .id = MT8192_IRQ_9, + .irq_cnt_reg = AFE_IRQ_MCU_CNT9, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ9_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ9_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ9_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ9_MCU_CLR_SFT, + }, + [MT8192_IRQ_10] = { + .id = MT8192_IRQ_10, + .irq_cnt_reg = AFE_IRQ_MCU_CNT10, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ10_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ10_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ10_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ10_MCU_CLR_SFT, + }, + [MT8192_IRQ_11] = { + .id = MT8192_IRQ_11, + .irq_cnt_reg = AFE_IRQ_MCU_CNT11, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ11_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ11_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ11_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ11_MCU_CLR_SFT, + }, + [MT8192_IRQ_12] = { + .id = MT8192_IRQ_12, + .irq_cnt_reg = AFE_IRQ_MCU_CNT12, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ12_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ12_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ12_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ12_MCU_CLR_SFT, + }, + [MT8192_IRQ_13] = { + .id = MT8192_IRQ_13, + .irq_cnt_reg = AFE_IRQ_MCU_CNT13, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ13_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ13_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ13_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ13_MCU_CLR_SFT, + }, + [MT8192_IRQ_14] = { + .id = MT8192_IRQ_14, + .irq_cnt_reg = AFE_IRQ_MCU_CNT14, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ14_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ14_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ14_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ14_MCU_CLR_SFT, + }, + [MT8192_IRQ_15] = { + .id = MT8192_IRQ_15, + .irq_cnt_reg = AFE_IRQ_MCU_CNT15, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ15_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ15_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ15_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ15_MCU_CLR_SFT, + }, + [MT8192_IRQ_16] = { + .id = MT8192_IRQ_16, + .irq_cnt_reg = AFE_IRQ_MCU_CNT16, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ16_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ16_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ16_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ16_MCU_CLR_SFT, + }, + [MT8192_IRQ_17] = { + .id = MT8192_IRQ_17, + .irq_cnt_reg = AFE_IRQ_MCU_CNT17, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ17_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ17_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ17_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ17_MCU_CLR_SFT, + }, + [MT8192_IRQ_18] = { + .id = MT8192_IRQ_18, + .irq_cnt_reg = AFE_IRQ_MCU_CNT18, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ18_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ18_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ18_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ18_MCU_CLR_SFT, + }, + [MT8192_IRQ_19] = { + .id = MT8192_IRQ_19, + .irq_cnt_reg = AFE_IRQ_MCU_CNT19, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ19_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ19_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ19_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ19_MCU_CLR_SFT, + }, + [MT8192_IRQ_20] = { + .id = MT8192_IRQ_20, + .irq_cnt_reg = AFE_IRQ_MCU_CNT20, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ20_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ20_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ20_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ20_MCU_CLR_SFT, + }, + [MT8192_IRQ_21] = { + .id = MT8192_IRQ_21, + .irq_cnt_reg = AFE_IRQ_MCU_CNT21, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ21_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ21_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ21_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ21_MCU_CLR_SFT, + }, + [MT8192_IRQ_22] = { + .id = MT8192_IRQ_22, + .irq_cnt_reg = AFE_IRQ_MCU_CNT22, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ22_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ22_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ22_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ22_MCU_CLR_SFT, + }, + [MT8192_IRQ_23] = { + .id = MT8192_IRQ_23, + .irq_cnt_reg = AFE_IRQ_MCU_CNT23, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON3, + .irq_fs_shift = IRQ23_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ23_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ23_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ23_MCU_CLR_SFT, + }, + [MT8192_IRQ_24] = { + .id = MT8192_IRQ_24, + .irq_cnt_reg = AFE_IRQ_MCU_CNT24, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON4, + .irq_fs_shift = IRQ24_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ24_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ24_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ24_MCU_CLR_SFT, + }, + [MT8192_IRQ_25] = { + .id = MT8192_IRQ_25, + .irq_cnt_reg = AFE_IRQ_MCU_CNT25, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON4, + .irq_fs_shift = IRQ25_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ25_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ25_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ25_MCU_CLR_SFT, + }, + [MT8192_IRQ_26] = { + .id = MT8192_IRQ_26, + .irq_cnt_reg = AFE_IRQ_MCU_CNT26, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = AFE_IRQ_MCU_CON4, + .irq_fs_shift = IRQ26_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ26_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ26_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ26_MCU_CLR_SFT, + }, + [MT8192_IRQ_31] = { + .id = MT8192_IRQ_31, + .irq_cnt_reg = AFE_IRQ_MCU_CNT31, + .irq_cnt_shift = AFE_IRQ_CNT_SHIFT, + .irq_cnt_maskbit = AFE_IRQ_CNT_MASK, + .irq_fs_reg = -1, + .irq_fs_shift = -1, + .irq_fs_maskbit = -1, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ31_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ31_MCU_CLR_SFT, + }, +}; + +static const int memif_irq_usage[MT8192_MEMIF_NUM] = { + [MT8192_MEMIF_DL1] = MT8192_IRQ_0, + [MT8192_MEMIF_DL2] = MT8192_IRQ_1, + [MT8192_MEMIF_DL3] = MT8192_IRQ_2, + [MT8192_MEMIF_DL4] = MT8192_IRQ_3, + [MT8192_MEMIF_DL5] = MT8192_IRQ_4, + [MT8192_MEMIF_DL6] = MT8192_IRQ_5, + [MT8192_MEMIF_DL7] = MT8192_IRQ_6, + [MT8192_MEMIF_DL8] = MT8192_IRQ_7, + [MT8192_MEMIF_DL9] = MT8192_IRQ_8, + [MT8192_MEMIF_DL12] = MT8192_IRQ_9, + [MT8192_MEMIF_DAI] = MT8192_IRQ_10, + [MT8192_MEMIF_MOD_DAI] = MT8192_IRQ_11, + [MT8192_MEMIF_DAI2] = MT8192_IRQ_12, + [MT8192_MEMIF_VUL12] = MT8192_IRQ_13, + [MT8192_MEMIF_VUL2] = MT8192_IRQ_14, + [MT8192_MEMIF_AWB] = MT8192_IRQ_15, + [MT8192_MEMIF_AWB2] = MT8192_IRQ_16, + [MT8192_MEMIF_VUL3] = MT8192_IRQ_17, + [MT8192_MEMIF_VUL4] = MT8192_IRQ_18, + [MT8192_MEMIF_VUL5] = MT8192_IRQ_19, + [MT8192_MEMIF_VUL6] = MT8192_IRQ_20, + [MT8192_MEMIF_HDMI] = MT8192_IRQ_31, +}; + +static bool mt8192_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* these auto-gen reg has read-only bit, so put it as volatile */ + /* volatile reg cannot be cached, so cannot be set when power off */ + switch (reg) { + case AUDIO_TOP_CON0: /* reg bit controlled by CCF */ + case AUDIO_TOP_CON1: /* reg bit controlled by CCF */ + case AUDIO_TOP_CON2: + case AUDIO_TOP_CON3: + case AFE_DL1_CUR_MSB: + case AFE_DL1_CUR: + case AFE_DL1_END: + case AFE_DL2_CUR_MSB: + case AFE_DL2_CUR: + case AFE_DL2_END: + case AFE_DL3_CUR_MSB: + case AFE_DL3_CUR: + case AFE_DL3_END: + case AFE_DL4_CUR_MSB: + case AFE_DL4_CUR: + case AFE_DL4_END: + case AFE_DL12_CUR_MSB: + case AFE_DL12_CUR: + case AFE_DL12_END: + case AFE_ADDA_SRC_DEBUG_MON0: + case AFE_ADDA_SRC_DEBUG_MON1: + case AFE_ADDA_UL_SRC_MON0: + case AFE_ADDA_UL_SRC_MON1: + case AFE_SECURE_CON0: + case AFE_SRAM_BOUND: + case AFE_SECURE_CON1: + case AFE_VUL_CUR_MSB: + case AFE_VUL_CUR: + case AFE_VUL_END: + case AFE_ADDA_3RD_DAC_DL_SDM_FIFO_MON: + case AFE_ADDA_3RD_DAC_DL_SRC_LCH_MON: + case AFE_ADDA_3RD_DAC_DL_SRC_RCH_MON: + case AFE_ADDA_3RD_DAC_DL_SDM_OUT_MON: + case AFE_SIDETONE_MON: + case AFE_SIDETONE_CON0: + case AFE_SIDETONE_COEFF: + case AFE_VUL2_CUR_MSB: + case AFE_VUL2_CUR: + case AFE_VUL2_END: + case AFE_VUL3_CUR_MSB: + case AFE_VUL3_CUR: + case AFE_VUL3_END: + case AFE_I2S_MON: + case AFE_DAC_MON: + case AFE_IRQ0_MCU_CNT_MON: + case AFE_IRQ6_MCU_CNT_MON: + case AFE_VUL4_CUR_MSB: + case AFE_VUL4_CUR: + case AFE_VUL4_END: + case AFE_VUL12_CUR_MSB: + case AFE_VUL12_CUR: + case AFE_VUL12_END: + case AFE_IRQ3_MCU_CNT_MON: + case AFE_IRQ4_MCU_CNT_MON: + case AFE_IRQ_MCU_STATUS: + case AFE_IRQ_MCU_CLR: + case AFE_IRQ_MCU_MON2: + case AFE_IRQ1_MCU_CNT_MON: + case AFE_IRQ2_MCU_CNT_MON: + case AFE_IRQ5_MCU_CNT_MON: + case AFE_IRQ7_MCU_CNT_MON: + case AFE_IRQ_MCU_MISS_CLR: + case AFE_GAIN1_CUR: + case AFE_GAIN2_CUR: + case AFE_SRAM_DELSEL_CON1: + case PCM_INTF_CON2: + case FPGA_CFG0: + case FPGA_CFG1: + case FPGA_CFG2: + case FPGA_CFG3: + case AUDIO_TOP_DBG_MON0: + case AUDIO_TOP_DBG_MON1: + case AFE_IRQ8_MCU_CNT_MON: + case AFE_IRQ11_MCU_CNT_MON: + case AFE_IRQ12_MCU_CNT_MON: + case AFE_IRQ9_MCU_CNT_MON: + case AFE_IRQ10_MCU_CNT_MON: + case AFE_IRQ13_MCU_CNT_MON: + case AFE_IRQ14_MCU_CNT_MON: + case AFE_IRQ15_MCU_CNT_MON: + case AFE_IRQ16_MCU_CNT_MON: + case AFE_IRQ17_MCU_CNT_MON: + case AFE_IRQ18_MCU_CNT_MON: + case AFE_IRQ19_MCU_CNT_MON: + case AFE_IRQ20_MCU_CNT_MON: + case AFE_IRQ21_MCU_CNT_MON: + case AFE_IRQ22_MCU_CNT_MON: + case AFE_IRQ23_MCU_CNT_MON: + case AFE_IRQ24_MCU_CNT_MON: + case AFE_IRQ25_MCU_CNT_MON: + case AFE_IRQ26_MCU_CNT_MON: + case AFE_IRQ31_MCU_CNT_MON: + case AFE_CBIP_MON0: + case AFE_CBIP_SLV_MUX_MON0: + case AFE_CBIP_SLV_DECODER_MON0: + case AFE_ADDA6_MTKAIF_MON0: + case AFE_ADDA6_MTKAIF_MON1: + case AFE_AWB_CUR_MSB: + case AFE_AWB_CUR: + case AFE_AWB_END: + case AFE_AWB2_CUR_MSB: + case AFE_AWB2_CUR: + case AFE_AWB2_END: + case AFE_DAI_CUR_MSB: + case AFE_DAI_CUR: + case AFE_DAI_END: + case AFE_DAI2_CUR_MSB: + case AFE_DAI2_CUR: + case AFE_DAI2_END: + case AFE_ADDA6_SRC_DEBUG_MON0: + case AFE_ADD6A_UL_SRC_MON0: + case AFE_ADDA6_UL_SRC_MON1: + case AFE_MOD_DAI_CUR_MSB: + case AFE_MOD_DAI_CUR: + case AFE_MOD_DAI_END: + case AFE_HDMI_OUT_CUR_MSB: + case AFE_HDMI_OUT_CUR: + case AFE_HDMI_OUT_END: + case AFE_AWB_RCH_MON: + case AFE_AWB_LCH_MON: + case AFE_VUL_RCH_MON: + case AFE_VUL_LCH_MON: + case AFE_VUL12_RCH_MON: + case AFE_VUL12_LCH_MON: + case AFE_VUL2_RCH_MON: + case AFE_VUL2_LCH_MON: + case AFE_DAI_DATA_MON: + case AFE_MOD_DAI_DATA_MON: + case AFE_DAI2_DATA_MON: + case AFE_AWB2_RCH_MON: + case AFE_AWB2_LCH_MON: + case AFE_VUL3_RCH_MON: + case AFE_VUL3_LCH_MON: + case AFE_VUL4_RCH_MON: + case AFE_VUL4_LCH_MON: + case AFE_VUL5_RCH_MON: + case AFE_VUL5_LCH_MON: + case AFE_VUL6_RCH_MON: + case AFE_VUL6_LCH_MON: + case AFE_DL1_RCH_MON: + case AFE_DL1_LCH_MON: + case AFE_DL2_RCH_MON: + case AFE_DL2_LCH_MON: + case AFE_DL12_RCH1_MON: + case AFE_DL12_LCH1_MON: + case AFE_DL12_RCH2_MON: + case AFE_DL12_LCH2_MON: + case AFE_DL3_RCH_MON: + case AFE_DL3_LCH_MON: + case AFE_DL4_RCH_MON: + case AFE_DL4_LCH_MON: + case AFE_DL5_RCH_MON: + case AFE_DL5_LCH_MON: + case AFE_DL6_RCH_MON: + case AFE_DL6_LCH_MON: + case AFE_DL7_RCH_MON: + case AFE_DL7_LCH_MON: + case AFE_DL8_RCH_MON: + case AFE_DL8_LCH_MON: + case AFE_VUL5_CUR_MSB: + case AFE_VUL5_CUR: + case AFE_VUL5_END: + case AFE_VUL6_CUR_MSB: + case AFE_VUL6_CUR: + case AFE_VUL6_END: + case AFE_ADDA_DL_SDM_FIFO_MON: + case AFE_ADDA_DL_SRC_LCH_MON: + case AFE_ADDA_DL_SRC_RCH_MON: + case AFE_ADDA_DL_SDM_OUT_MON: + case AFE_CONNSYS_I2S_MON: + case AFE_ASRC_2CH_CON0: + case AFE_ASRC_2CH_CON2: + case AFE_ASRC_2CH_CON3: + case AFE_ASRC_2CH_CON4: + case AFE_ASRC_2CH_CON5: + case AFE_ASRC_2CH_CON7: + case AFE_ASRC_2CH_CON8: + case AFE_ASRC_2CH_CON12: + case AFE_ASRC_2CH_CON13: + case AFE_DL9_CUR_MSB: + case AFE_DL9_CUR: + case AFE_DL9_END: + case AFE_ADDA_MTKAIF_MON0: + case AFE_ADDA_MTKAIF_MON1: + case AFE_DL_NLE_R_MON0: + case AFE_DL_NLE_R_MON1: + case AFE_DL_NLE_R_MON2: + case AFE_DL_NLE_L_MON0: + case AFE_DL_NLE_L_MON1: + case AFE_DL_NLE_L_MON2: + case AFE_GENERAL1_ASRC_2CH_CON0: + case AFE_GENERAL1_ASRC_2CH_CON2: + case AFE_GENERAL1_ASRC_2CH_CON3: + case AFE_GENERAL1_ASRC_2CH_CON4: + case AFE_GENERAL1_ASRC_2CH_CON5: + case AFE_GENERAL1_ASRC_2CH_CON7: + case AFE_GENERAL1_ASRC_2CH_CON8: + case AFE_GENERAL1_ASRC_2CH_CON12: + case AFE_GENERAL1_ASRC_2CH_CON13: + case AFE_GENERAL2_ASRC_2CH_CON0: + case AFE_GENERAL2_ASRC_2CH_CON2: + case AFE_GENERAL2_ASRC_2CH_CON3: + case AFE_GENERAL2_ASRC_2CH_CON4: + case AFE_GENERAL2_ASRC_2CH_CON5: + case AFE_GENERAL2_ASRC_2CH_CON7: + case AFE_GENERAL2_ASRC_2CH_CON8: + case AFE_GENERAL2_ASRC_2CH_CON12: + case AFE_GENERAL2_ASRC_2CH_CON13: + case AFE_DL9_RCH_MON: + case AFE_DL9_LCH_MON: + case AFE_DL5_CUR_MSB: + case AFE_DL5_CUR: + case AFE_DL5_END: + case AFE_DL6_CUR_MSB: + case AFE_DL6_CUR: + case AFE_DL6_END: + case AFE_DL7_CUR_MSB: + case AFE_DL7_CUR: + case AFE_DL7_END: + case AFE_DL8_CUR_MSB: + case AFE_DL8_CUR: + case AFE_DL8_END: + case AFE_PROT_SIDEBAND_MON: + case AFE_DOMAIN_SIDEBAND0_MON: + case AFE_DOMAIN_SIDEBAND1_MON: + case AFE_DOMAIN_SIDEBAND2_MON: + case AFE_DOMAIN_SIDEBAND3_MON: + case AFE_APLL1_TUNER_CFG: /* [20:31] is monitor */ + case AFE_APLL2_TUNER_CFG: /* [20:31] is monitor */ + case AFE_DAC_CON0: + case AFE_IRQ_MCU_CON0: + case AFE_IRQ_MCU_EN: + return true; + default: + return false; + }; +} + +static const struct regmap_config mt8192_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .volatile_reg = mt8192_is_volatile_reg, + .max_register = AFE_MAX_REGISTER, + .num_reg_defaults_raw = AFE_MAX_REGISTER, + .cache_type = REGCACHE_FLAT, +}; + +static irqreturn_t mt8192_afe_irq_handler(int irq_id, void *dev) +{ + struct mtk_base_afe *afe = dev; + struct mtk_base_afe_irq *irq; + unsigned int status; + unsigned int status_mcu; + unsigned int mcu_en; + int ret; + int i; + + /* get irq that is sent to MCU */ + regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en); + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status); + /* only care IRQ which is sent to MCU */ + status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS; + + if (ret || status_mcu == 0) { + dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n", + __func__, ret, status, mcu_en); + + goto err_irq; + } + + for (i = 0; i < MT8192_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + + if (!memif->substream) + continue; + + if (memif->irq_usage < 0) + continue; + + irq = &afe->irqs[memif->irq_usage]; + + if (status_mcu & (1 << irq->irq_data->irq_en_shift)) + snd_pcm_period_elapsed(memif->substream); + } + +err_irq: + /* clear irq */ + regmap_write(afe->regmap, + AFE_IRQ_MCU_CLR, + status_mcu); + + return IRQ_HANDLED; +} + +static int mt8192_afe_runtime_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + unsigned int value; + int ret; + + dev_info(afe->dev, "%s()\n", __func__); + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + /* disable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x0); + + ret = regmap_read_poll_timeout(afe->regmap, + AFE_DAC_MON, + value, + (value & AFE_ON_RETM_MASK_SFT) == 0, + 20, + 1 * 1000 * 1000); + if (ret) + dev_warn(afe->dev, "%s(), ret %d\n", __func__, ret); + + /* make sure all irq status are cleared */ + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff); + regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff); + + /* reset sgen */ + regmap_write(afe->regmap, AFE_SINEGEN_CON0, 0x0); + regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2, + INNER_LOOP_BACK_MODE_MASK_SFT, + 0x3f << INNER_LOOP_BACK_MODE_SFT); + + /* cache only */ + regcache_cache_only(afe->regmap, true); + regcache_mark_dirty(afe->regmap); + +skip_regmap: + mt8192_afe_disable_clock(afe); + return 0; +} + +static int mt8192_afe_runtime_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int ret; + + dev_info(afe->dev, "%s()\n", __func__); + + ret = mt8192_afe_enable_clock(afe); + if (ret) + return ret; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + regcache_cache_only(afe->regmap, false); + regcache_sync(afe->regmap); + + /* enable audio sys DCM for power saving */ + regmap_update_bits(afe_priv->infracfg, + PERI_BUS_DCM_CTRL, 0x1 << 29, 0x1 << 29); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, 0x1 << 29, 0x1 << 29); + + /* force cpu use 8_24 format when writing 32bit data */ + regmap_update_bits(afe->regmap, AFE_MEMIF_CON0, + CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT); + + /* set all output port to 24bit */ + regmap_write(afe->regmap, AFE_CONN_24BIT, 0xffffffff); + regmap_write(afe->regmap, AFE_CONN_24BIT_1, 0xffffffff); + + /* enable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x1); + +skip_regmap: + return 0; +} + +static int mt8192_afe_component_probe(struct snd_soc_component *component) +{ + return mtk_afe_add_sub_dai_control(component); +} + +const struct snd_soc_component_driver mt8192_afe_component = { + .name = AFE_PCM_NAME, + .probe = mt8192_afe_component_probe, + .pointer = mtk_afe_pcm_pointer, + .pcm_construct = mtk_afe_pcm_new, +}; + +static const struct snd_soc_component_driver mt8192_afe_pcm_component = { + .name = "mt8192-afe-pcm-dai", +}; + +static int mt8192_dai_memif_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mt8192_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt8192_memif_dai_driver); + + dai->dapm_widgets = mt8192_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt8192_memif_widgets); + dai->dapm_routes = mt8192_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt8192_memif_routes); + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt8192_dai_adda_register, + mt8192_dai_i2s_register, + mt8192_dai_pcm_register, + mt8192_dai_tdm_register, + mt8192_dai_memif_register, +}; + +static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev) +{ + struct mtk_base_afe *afe; + struct mt8192_afe_private *afe_priv; + struct device *dev; + struct reset_control *rstc; + int i, ret, irq_id; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); + if (ret) + return ret; + + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), + GFP_KERNEL); + if (!afe->platform_priv) + return -ENOMEM; + afe_priv = afe->platform_priv; + + afe->dev = &pdev->dev; + dev = afe->dev; + + /* init audio related clock */ + ret = mt8192_init_clock(afe); + if (ret) { + dev_err(dev, "init clock error\n"); + return ret; + } + + /* reset controller to reset audio regs before regmap cache */ + rstc = devm_reset_control_get_exclusive(dev, "audiosys"); + if (IS_ERR(rstc)) { + ret = PTR_ERR(rstc); + dev_err(dev, "could not get audiosys reset:%d\n", ret); + return ret; + } + + ret = reset_control_reset(rstc); + if (ret) { + dev_err(dev, "failed to trigger audio reset:%d\n", ret); + return ret; + } + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) + goto err_pm_disable; + + /* regmap init */ + afe->regmap = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(afe->regmap)) { + dev_err(dev, "could not get regmap from parent\n"); + return PTR_ERR(afe->regmap); + } + ret = regmap_attach_dev(dev, afe->regmap, &mt8192_afe_regmap_config); + if (ret) { + dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret); + return ret; + } + + /* enable clock for regcache get default value from hw */ + afe_priv->pm_runtime_bypass_reg_ctl = true; + pm_runtime_get_sync(&pdev->dev); + + ret = regmap_reinit_cache(afe->regmap, &mt8192_afe_regmap_config); + if (ret) { + dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret); + return ret; + } + + pm_runtime_put_sync(&pdev->dev); + afe_priv->pm_runtime_bypass_reg_ctl = false; + + regcache_cache_only(afe->regmap, true); + regcache_mark_dirty(afe->regmap); + + /* init memif */ + afe->memif_size = MT8192_MEMIF_NUM; + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), + GFP_KERNEL); + if (!afe->memif) + return -ENOMEM; + + for (i = 0; i < afe->memif_size; i++) { + afe->memif[i].data = &memif_data[i]; + afe->memif[i].irq_usage = memif_irq_usage[i]; + afe->memif[i].const_irq = 1; + } + + mutex_init(&afe->irq_alloc_lock); /* needed when dynamic irq */ + + /* init irq */ + afe->irqs_size = MT8192_IRQ_NUM; + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), + GFP_KERNEL); + if (!afe->irqs) + return -ENOMEM; + + for (i = 0; i < afe->irqs_size; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + /* request irq */ + irq_id = platform_get_irq(pdev, 0); + if (irq_id < 0) + return irq_id; + + ret = devm_request_irq(dev, irq_id, mt8192_afe_irq_handler, + IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); + if (ret) { + dev_err(dev, "could not request_irq for Afe_ISR_Handle\n"); + return ret; + } + + /* init sub_dais */ + INIT_LIST_HEAD(&afe->sub_dais); + + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { + ret = dai_register_cbs[i](afe); + if (ret) { + dev_warn(afe->dev, "dai register i %d fail, ret %d\n", + i, ret); + goto err_pm_disable; + } + } + + /* init dai_driver and component_driver */ + ret = mtk_afe_combine_sub_dai(afe); + if (ret) { + dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n", + ret); + goto err_pm_disable; + } + + /* others */ + afe->mtk_afe_hardware = &mt8192_afe_hardware; + afe->memif_fs = mt8192_memif_fs; + afe->irq_fs = mt8192_irq_fs; + afe->get_dai_fs = mt8192_get_dai_fs; + afe->get_memif_pbuf_size = mt8192_get_memif_pbuf_size; + afe->memif_32bit_supported = 1; + + afe->runtime_resume = mt8192_afe_runtime_resume; + afe->runtime_suspend = mt8192_afe_runtime_suspend; + + /* register platform */ + ret = devm_snd_soc_register_component(&pdev->dev, + &mt8192_afe_component, NULL, 0); + if (ret) { + dev_warn(dev, "err_platform\n"); + goto err_pm_disable; + } + + ret = devm_snd_soc_register_component(&pdev->dev, + &mt8192_afe_pcm_component, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) { + dev_warn(dev, "err_dai_component\n"); + goto err_pm_disable; + } + + return 0; + +err_pm_disable: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int mt8192_afe_pcm_dev_remove(struct platform_device *pdev) +{ + struct mtk_base_afe *afe = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mt8192_afe_runtime_suspend(&pdev->dev); + + /* disable afe clock */ + mt8192_afe_disable_clock(afe); + return 0; +} + +static const struct of_device_id mt8192_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt8192-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt8192_afe_pcm_dt_match); + +static const struct dev_pm_ops mt8192_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt8192_afe_runtime_suspend, + mt8192_afe_runtime_resume, NULL) +}; + +static struct platform_driver mt8192_afe_pcm_driver = { + .driver = { + .name = "mt8192-audio", + .of_match_table = mt8192_afe_pcm_dt_match, +#ifdef CONFIG_PM + .pm = &mt8192_afe_pm_ops, +#endif + }, + .probe = mt8192_afe_pcm_dev_probe, + .remove = mt8192_afe_pcm_dev_remove, +}; + +module_platform_driver(mt8192_afe_pcm_driver); + +MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8192"); +MODULE_AUTHOR("Shane Chien "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/mediatek/mt8192/mt8192-interconnection.h b/sound/soc/mediatek/mt8192/mt8192-interconnection.h new file mode 100644 index 000000000000..6a1bc7c1a862 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-interconnection.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Mediatek MT8192 audio driver interconnection definition + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Shane Chien + */ + +#ifndef _MT8192_INTERCONNECTION_H_ +#define _MT8192_INTERCONNECTION_H_ + +/* in port define */ +#define I_I2S0_CH1 0 +#define I_I2S0_CH2 1 +#define I_ADDA_UL_CH1 3 +#define I_ADDA_UL_CH2 4 +#define I_DL1_CH1 5 +#define I_DL1_CH2 6 +#define I_DL2_CH1 7 +#define I_DL2_CH2 8 +#define I_PCM_1_CAP_CH1 9 +#define I_GAIN1_OUT_CH1 10 +#define I_GAIN1_OUT_CH2 11 +#define I_GAIN2_OUT_CH1 12 +#define I_GAIN2_OUT_CH2 13 +#define I_PCM_2_CAP_CH1 14 +#define I_ADDA_UL_CH3 17 +#define I_ADDA_UL_CH4 18 +#define I_DL12_CH1 19 +#define I_DL12_CH2 20 +#define I_PCM_2_CAP_CH2 21 +#define I_PCM_1_CAP_CH2 22 +#define I_DL3_CH1 23 +#define I_DL3_CH2 24 +#define I_I2S2_CH1 25 +#define I_I2S2_CH2 26 +#define I_I2S2_CH3 27 +#define I_I2S2_CH4 28 + +/* in port define >= 32 */ +#define I_32_OFFSET 32 +#define I_CONNSYS_I2S_CH1 (34 - I_32_OFFSET) +#define I_CONNSYS_I2S_CH2 (35 - I_32_OFFSET) +#define I_SRC_1_OUT_CH1 (36 - I_32_OFFSET) +#define I_SRC_1_OUT_CH2 (37 - I_32_OFFSET) +#define I_SRC_2_OUT_CH1 (38 - I_32_OFFSET) +#define I_SRC_2_OUT_CH2 (39 - I_32_OFFSET) +#define I_DL4_CH1 (40 - I_32_OFFSET) +#define I_DL4_CH2 (41 - I_32_OFFSET) +#define I_DL5_CH1 (42 - I_32_OFFSET) +#define I_DL5_CH2 (43 - I_32_OFFSET) +#define I_DL6_CH1 (44 - I_32_OFFSET) +#define I_DL6_CH2 (45 - I_32_OFFSET) +#define I_DL7_CH1 (46 - I_32_OFFSET) +#define I_DL7_CH2 (47 - I_32_OFFSET) +#define I_DL8_CH1 (48 - I_32_OFFSET) +#define I_DL8_CH2 (49 - I_32_OFFSET) +#define I_DL9_CH1 (50 - I_32_OFFSET) +#define I_DL9_CH2 (51 - I_32_OFFSET) +#define I_I2S6_CH1 (52 - I_32_OFFSET) +#define I_I2S6_CH2 (53 - I_32_OFFSET) +#define I_I2S8_CH1 (54 - I_32_OFFSET) +#define I_I2S8_CH2 (55 - I_32_OFFSET) + +#endif diff --git a/sound/soc/mediatek/mt8192/mt8192-reg.h b/sound/soc/mediatek/mt8192/mt8192-reg.h new file mode 100644 index 000000000000..562f25c79c34 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-reg.h @@ -0,0 +1,3131 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8192-reg.h -- Mediatek 8192 audio driver reg definition + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Shane Chien + */ + +#ifndef _MT8192_REG_H_ +#define _MT8192_REG_H_ + +/* reg bit enum */ +enum { + MT8192_MEMIF_PBUF_SIZE_32_BYTES, + MT8192_MEMIF_PBUF_SIZE_64_BYTES, + MT8192_MEMIF_PBUF_SIZE_128_BYTES, + MT8192_MEMIF_PBUF_SIZE_256_BYTES, + MT8192_MEMIF_PBUF_SIZE_NUM, +}; + +/***************************************************************************** + * R E G I S T E R D E F I N I T I O N + *****************************************************************************/ +/* AFE_DAC_CON0 */ +#define VUL12_ON_SFT 31 +#define VUL12_ON_MASK 0x1 +#define VUL12_ON_MASK_SFT (0x1 << 31) +#define MOD_DAI_ON_SFT 30 +#define MOD_DAI_ON_MASK 0x1 +#define MOD_DAI_ON_MASK_SFT (0x1 << 30) +#define DAI_ON_SFT 29 +#define DAI_ON_MASK 0x1 +#define DAI_ON_MASK_SFT (0x1 << 29) +#define DAI2_ON_SFT 28 +#define DAI2_ON_MASK 0x1 +#define DAI2_ON_MASK_SFT (0x1 << 28) +#define VUL6_ON_SFT 23 +#define VUL6_ON_MASK 0x1 +#define VUL6_ON_MASK_SFT (0x1 << 23) +#define VUL5_ON_SFT 22 +#define VUL5_ON_MASK 0x1 +#define VUL5_ON_MASK_SFT (0x1 << 22) +#define VUL4_ON_SFT 21 +#define VUL4_ON_MASK 0x1 +#define VUL4_ON_MASK_SFT (0x1 << 21) +#define VUL3_ON_SFT 20 +#define VUL3_ON_MASK 0x1 +#define VUL3_ON_MASK_SFT (0x1 << 20) +#define VUL2_ON_SFT 19 +#define VUL2_ON_MASK 0x1 +#define VUL2_ON_MASK_SFT (0x1 << 19) +#define VUL_ON_SFT 18 +#define VUL_ON_MASK 0x1 +#define VUL_ON_MASK_SFT (0x1 << 18) +#define AWB2_ON_SFT 17 +#define AWB2_ON_MASK 0x1 +#define AWB2_ON_MASK_SFT (0x1 << 17) +#define AWB_ON_SFT 16 +#define AWB_ON_MASK 0x1 +#define AWB_ON_MASK_SFT (0x1 << 16) +#define DL12_ON_SFT 15 +#define DL12_ON_MASK 0x1 +#define DL12_ON_MASK_SFT (0x1 << 15) +#define DL9_ON_SFT 12 +#define DL9_ON_MASK 0x1 +#define DL9_ON_MASK_SFT (0x1 << 12) +#define DL8_ON_SFT 11 +#define DL8_ON_MASK 0x1 +#define DL8_ON_MASK_SFT (0x1 << 11) +#define DL7_ON_SFT 10 +#define DL7_ON_MASK 0x1 +#define DL7_ON_MASK_SFT (0x1 << 10) +#define DL6_ON_SFT 9 +#define DL6_ON_MASK 0x1 +#define DL6_ON_MASK_SFT (0x1 << 9) +#define DL5_ON_SFT 8 +#define DL5_ON_MASK 0x1 +#define DL5_ON_MASK_SFT (0x1 << 8) +#define DL4_ON_SFT 7 +#define DL4_ON_MASK 0x1 +#define DL4_ON_MASK_SFT (0x1 << 7) +#define DL3_ON_SFT 6 +#define DL3_ON_MASK 0x1 +#define DL3_ON_MASK_SFT (0x1 << 6) +#define DL2_ON_SFT 5 +#define DL2_ON_MASK 0x1 +#define DL2_ON_MASK_SFT (0x1 << 5) +#define DL1_ON_SFT 4 +#define DL1_ON_MASK 0x1 +#define DL1_ON_MASK_SFT (0x1 << 4) +#define HDMI_OUT_ON_SFT 1 +#define HDMI_OUT_ON_MASK 0x1 +#define HDMI_OUT_ON_MASK_SFT (0x1 << 1) +#define AFE_ON_SFT 0 +#define AFE_ON_MASK 0x1 +#define AFE_ON_MASK_SFT (0x1 << 0) + +/* AFE_DAC_MON */ +#define AFE_ON_RETM_SFT 0 +#define AFE_ON_RETM_MASK 0x1 +#define AFE_ON_RETM_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON */ +#define BCK_NEG_EG_LATCH_SFT 30 +#define BCK_NEG_EG_LATCH_MASK 0x1 +#define BCK_NEG_EG_LATCH_MASK_SFT (0x1 << 30) +#define BCK_INV_SFT 29 +#define BCK_INV_MASK 0x1 +#define BCK_INV_MASK_SFT (0x1 << 29) +#define I2SIN_PAD_SEL_SFT 28 +#define I2SIN_PAD_SEL_MASK 0x1 +#define I2SIN_PAD_SEL_MASK_SFT (0x1 << 28) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK 0x1 +#define I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S1_HD_EN_SFT 12 +#define I2S1_HD_EN_MASK 0x1 +#define I2S1_HD_EN_MASK_SFT (0x1 << 12) +#define I2S_OUT_MODE_SFT 8 +#define I2S_OUT_MODE_MASK 0xf +#define I2S_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_PAD_CTRL_SFT 7 +#define INV_PAD_CTRL_MASK 0x1 +#define INV_PAD_CTRL_MASK_SFT (0x1 << 7) +#define I2S_BYPSRC_SFT 6 +#define I2S_BYPSRC_MASK 0x1 +#define I2S_BYPSRC_MASK_SFT (0x1 << 6) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S_FMT_SFT 3 +#define I2S_FMT_MASK 0x1 +#define I2S_FMT_MASK_SFT (0x1 << 3) +#define I2S_SRC_SFT 2 +#define I2S_SRC_MASK 0x1 +#define I2S_SRC_MASK_SFT (0x1 << 2) +#define I2S_WLEN_SFT 1 +#define I2S_WLEN_MASK 0x1 +#define I2S_WLEN_MASK_SFT (0x1 << 1) +#define I2S_EN_SFT 0 +#define I2S_EN_MASK 0x1 +#define I2S_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON1 */ +#define I2S2_LR_SWAP_SFT 31 +#define I2S2_LR_SWAP_MASK 0x1 +#define I2S2_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S2_SEL_O19_O20_SFT 18 +#define I2S2_SEL_O19_O20_MASK 0x1 +#define I2S2_SEL_O19_O20_MASK_SFT (0x1 << 18) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S2_SEL_O03_O04_SFT 16 +#define I2S2_SEL_O03_O04_MASK 0x1 +#define I2S2_SEL_O03_O04_MASK_SFT (0x1 << 16) +#define I2S2_32BIT_EN_SFT 13 +#define I2S2_32BIT_EN_MASK 0x1 +#define I2S2_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S2_HD_EN_SFT 12 +#define I2S2_HD_EN_MASK 0x1 +#define I2S2_HD_EN_MASK_SFT (0x1 << 12) +#define I2S2_OUT_MODE_SFT 8 +#define I2S2_OUT_MODE_MASK 0xf +#define I2S2_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S2_FMT_SFT 3 +#define I2S2_FMT_MASK 0x1 +#define I2S2_FMT_MASK_SFT (0x1 << 3) +#define I2S2_WLEN_SFT 1 +#define I2S2_WLEN_MASK 0x1 +#define I2S2_WLEN_MASK_SFT (0x1 << 1) +#define I2S2_EN_SFT 0 +#define I2S2_EN_MASK 0x1 +#define I2S2_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON2 */ +#define I2S3_LR_SWAP_SFT 31 +#define I2S3_LR_SWAP_MASK 0x1 +#define I2S3_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S3_UPDATE_WORD_SFT 24 +#define I2S3_UPDATE_WORD_MASK 0x1f +#define I2S3_UPDATE_WORD_MASK_SFT (0x1f << 24) +#define I2S3_BCK_INV_SFT 23 +#define I2S3_BCK_INV_MASK 0x1 +#define I2S3_BCK_INV_MASK_SFT (0x1 << 23) +#define I2S3_FPGA_BIT_TEST_SFT 22 +#define I2S3_FPGA_BIT_TEST_MASK 0x1 +#define I2S3_FPGA_BIT_TEST_MASK_SFT (0x1 << 22) +#define I2S3_FPGA_BIT_SFT 21 +#define I2S3_FPGA_BIT_MASK 0x1 +#define I2S3_FPGA_BIT_MASK_SFT (0x1 << 21) +#define I2S3_LOOPBACK_SFT 20 +#define I2S3_LOOPBACK_MASK 0x1 +#define I2S3_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S3_HD_EN_SFT 12 +#define I2S3_HD_EN_MASK 0x1 +#define I2S3_HD_EN_MASK_SFT (0x1 << 12) +#define I2S3_OUT_MODE_SFT 8 +#define I2S3_OUT_MODE_MASK 0xf +#define I2S3_OUT_MODE_MASK_SFT (0xf << 8) +#define I2S3_FMT_SFT 3 +#define I2S3_FMT_MASK 0x1 +#define I2S3_FMT_MASK_SFT (0x1 << 3) +#define I2S3_WLEN_SFT 1 +#define I2S3_WLEN_MASK 0x1 +#define I2S3_WLEN_MASK_SFT (0x1 << 1) +#define I2S3_EN_SFT 0 +#define I2S3_EN_MASK 0x1 +#define I2S3_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON3 */ +#define I2S4_LR_SWAP_SFT 31 +#define I2S4_LR_SWAP_MASK 0x1 +#define I2S4_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S4_32BIT_EN_SFT 13 +#define I2S4_32BIT_EN_MASK 0x1 +#define I2S4_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S4_HD_EN_SFT 12 +#define I2S4_HD_EN_MASK 0x1 +#define I2S4_HD_EN_MASK_SFT (0x1 << 12) +#define I2S4_OUT_MODE_SFT 8 +#define I2S4_OUT_MODE_MASK 0xf +#define I2S4_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S4_FMT_SFT 3 +#define I2S4_FMT_MASK 0x1 +#define I2S4_FMT_MASK_SFT (0x1 << 3) +#define I2S4_WLEN_SFT 1 +#define I2S4_WLEN_MASK 0x1 +#define I2S4_WLEN_MASK_SFT (0x1 << 1) +#define I2S4_EN_SFT 0 +#define I2S4_EN_MASK 0x1 +#define I2S4_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON4 */ +#define I2S5_LR_SWAP_SFT 31 +#define I2S5_LR_SWAP_MASK 0x1 +#define I2S5_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK 0x1 +#define I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S5_32BIT_EN_SFT 13 +#define I2S5_32BIT_EN_MASK 0x1 +#define I2S5_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S5_HD_EN_SFT 12 +#define I2S5_HD_EN_MASK 0x1 +#define I2S5_HD_EN_MASK_SFT (0x1 << 12) +#define I2S5_OUT_MODE_SFT 8 +#define I2S5_OUT_MODE_MASK 0xf +#define I2S5_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S5_FMT_SFT 3 +#define I2S5_FMT_MASK 0x1 +#define I2S5_FMT_MASK_SFT (0x1 << 3) +#define I2S5_WLEN_SFT 1 +#define I2S5_WLEN_MASK 0x1 +#define I2S5_WLEN_MASK_SFT (0x1 << 1) +#define I2S5_EN_SFT 0 +#define I2S5_EN_MASK 0x1 +#define I2S5_EN_MASK_SFT (0x1 << 0) + +/* AFE_CONNSYS_I2S_CON */ +#define BCK_NEG_EG_LATCH_SFT 30 +#define BCK_NEG_EG_LATCH_MASK 0x1 +#define BCK_NEG_EG_LATCH_MASK_SFT (0x1 << 30) +#define BCK_INV_SFT 29 +#define BCK_INV_MASK 0x1 +#define BCK_INV_MASK_SFT (0x1 << 29) +#define I2SIN_PAD_SEL_SFT 28 +#define I2SIN_PAD_SEL_MASK 0x1 +#define I2SIN_PAD_SEL_MASK_SFT (0x1 << 28) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK 0x1 +#define I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S_MODE_SFT 8 +#define I2S_MODE_MASK 0xf +#define I2S_MODE_MASK_SFT (0xf << 8) +#define INV_PAD_CTRL_SFT 7 +#define INV_PAD_CTRL_MASK 0x1 +#define INV_PAD_CTRL_MASK_SFT (0x1 << 7) +#define I2S_BYPSRC_SFT 6 +#define I2S_BYPSRC_MASK 0x1 +#define I2S_BYPSRC_MASK_SFT (0x1 << 6) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S_FMT_SFT 3 +#define I2S_FMT_MASK 0x1 +#define I2S_FMT_MASK_SFT (0x1 << 3) +#define I2S_SRC_SFT 2 +#define I2S_SRC_MASK 0x1 +#define I2S_SRC_MASK_SFT (0x1 << 2) +#define I2S_WLEN_SFT 1 +#define I2S_WLEN_MASK 0x1 +#define I2S_WLEN_MASK_SFT (0x1 << 1) +#define I2S_EN_SFT 0 +#define I2S_EN_MASK 0x1 +#define I2S_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON6 */ +#define BCK_NEG_EG_LATCH_SFT 30 +#define BCK_NEG_EG_LATCH_MASK 0x1 +#define BCK_NEG_EG_LATCH_MASK_SFT (0x1 << 30) +#define BCK_INV_SFT 29 +#define BCK_INV_MASK 0x1 +#define BCK_INV_MASK_SFT (0x1 << 29) +#define I2S6_LOOPBACK_SFT 20 +#define I2S6_LOOPBACK_MASK 0x1 +#define I2S6_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S6_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S6_HD_EN_SFT 12 +#define I2S6_HD_EN_MASK 0x1 +#define I2S6_HD_EN_MASK_SFT (0x1 << 12) +#define I2S6_OUT_MODE_SFT 8 +#define I2S6_OUT_MODE_MASK 0xf +#define I2S6_OUT_MODE_MASK_SFT (0xf << 8) +#define I2S6_BYPSRC_SFT 6 +#define I2S6_BYPSRC_MASK 0x1 +#define I2S6_BYPSRC_MASK_SFT (0x1 << 6) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S6_FMT_SFT 3 +#define I2S6_FMT_MASK 0x1 +#define I2S6_FMT_MASK_SFT (0x1 << 3) +#define I2S6_SRC_SFT 2 +#define I2S6_SRC_MASK 0x1 +#define I2S6_SRC_MASK_SFT (0x1 << 2) +#define I2S6_WLEN_SFT 1 +#define I2S6_WLEN_MASK 0x1 +#define I2S6_WLEN_MASK_SFT (0x1 << 1) +#define I2S6_EN_SFT 0 +#define I2S6_EN_MASK 0x1 +#define I2S6_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON7 */ +#define I2S7_LR_SWAP_SFT 31 +#define I2S7_LR_SWAP_MASK 0x1 +#define I2S7_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S7_32BIT_EN_SFT 13 +#define I2S7_32BIT_EN_MASK 0x1 +#define I2S7_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S7_HD_EN_SFT 12 +#define I2S7_HD_EN_MASK 0x1 +#define I2S7_HD_EN_MASK_SFT (0x1 << 12) +#define I2S7_OUT_MODE_SFT 8 +#define I2S7_OUT_MODE_MASK 0xf +#define I2S7_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S7_FMT_SFT 3 +#define I2S7_FMT_MASK 0x1 +#define I2S7_FMT_MASK_SFT (0x1 << 3) +#define I2S7_WLEN_SFT 1 +#define I2S7_WLEN_MASK 0x1 +#define I2S7_WLEN_MASK_SFT (0x1 << 1) +#define I2S7_EN_SFT 0 +#define I2S7_EN_MASK 0x1 +#define I2S7_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON8 */ +#define BCK_NEG_EG_LATCH_SFT 30 +#define BCK_NEG_EG_LATCH_MASK 0x1 +#define BCK_NEG_EG_LATCH_MASK_SFT (0x1 << 30) +#define BCK_INV_SFT 29 +#define BCK_INV_MASK 0x1 +#define BCK_INV_MASK_SFT (0x1 << 29) +#define I2S8_LOOPBACK_SFT 20 +#define I2S8_LOOPBACK_MASK 0x1 +#define I2S8_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S8_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S8_HD_EN_SFT 12 +#define I2S8_HD_EN_MASK 0x1 +#define I2S8_HD_EN_MASK_SFT (0x1 << 12) +#define I2S8_OUT_MODE_SFT 8 +#define I2S8_OUT_MODE_MASK 0xf +#define I2S8_OUT_MODE_MASK_SFT (0xf << 8) +#define I2S8_BYPSRC_SFT 6 +#define I2S8_BYPSRC_MASK 0x1 +#define I2S8_BYPSRC_MASK_SFT (0x1 << 6) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S8_FMT_SFT 3 +#define I2S8_FMT_MASK 0x1 +#define I2S8_FMT_MASK_SFT (0x1 << 3) +#define I2S8_SRC_SFT 2 +#define I2S8_SRC_MASK 0x1 +#define I2S8_SRC_MASK_SFT (0x1 << 2) +#define I2S8_WLEN_SFT 1 +#define I2S8_WLEN_MASK 0x1 +#define I2S8_WLEN_MASK_SFT (0x1 << 1) +#define I2S8_EN_SFT 0 +#define I2S8_EN_MASK 0x1 +#define I2S8_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON9 */ +#define I2S9_LR_SWAP_SFT 31 +#define I2S9_LR_SWAP_MASK 0x1 +#define I2S9_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S9_32BIT_EN_SFT 13 +#define I2S9_32BIT_EN_MASK 0x1 +#define I2S9_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S9_HD_EN_SFT 12 +#define I2S9_HD_EN_MASK 0x1 +#define I2S9_HD_EN_MASK_SFT (0x1 << 12) +#define I2S9_OUT_MODE_SFT 8 +#define I2S9_OUT_MODE_MASK 0xf +#define I2S9_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S9_FMT_SFT 3 +#define I2S9_FMT_MASK 0x1 +#define I2S9_FMT_MASK_SFT (0x1 << 3) +#define I2S9_WLEN_SFT 1 +#define I2S9_WLEN_MASK 0x1 +#define I2S9_WLEN_MASK_SFT (0x1 << 1) +#define I2S9_EN_SFT 0 +#define I2S9_EN_MASK 0x1 +#define I2S9_EN_MASK_SFT (0x1 << 0) + +/* AFE_ASRC_2CH_CON2 */ +#define CHSET_O16BIT_SFT 19 +#define CHSET_O16BIT_MASK 0x1 +#define CHSET_O16BIT_MASK_SFT (0x1 << 19) +#define CHSET_CLR_IIR_HISTORY_SFT 17 +#define CHSET_CLR_IIR_HISTORY_MASK 0x1 +#define CHSET_CLR_IIR_HISTORY_MASK_SFT (0x1 << 17) +#define CHSET_IS_MONO_SFT 16 +#define CHSET_IS_MONO_MASK 0x1 +#define CHSET_IS_MONO_MASK_SFT (0x1 << 16) +#define CHSET_IIR_EN_SFT 11 +#define CHSET_IIR_EN_MASK 0x1 +#define CHSET_IIR_EN_MASK_SFT (0x1 << 11) +#define CHSET_IIR_STAGE_SFT 8 +#define CHSET_IIR_STAGE_MASK 0x7 +#define CHSET_IIR_STAGE_MASK_SFT (0x7 << 8) +#define CHSET_STR_CLR_SFT 5 +#define CHSET_STR_CLR_MASK 0x1 +#define CHSET_STR_CLR_MASK_SFT (0x1 << 5) +#define CHSET_ON_SFT 2 +#define CHSET_ON_MASK 0x1 +#define CHSET_ON_MASK_SFT (0x1 << 2) +#define COEFF_SRAM_CTRL_SFT 1 +#define COEFF_SRAM_CTRL_MASK 0x1 +#define COEFF_SRAM_CTRL_MASK_SFT (0x1 << 1) +#define ASM_ON_SFT 0 +#define ASM_ON_MASK 0x1 +#define ASM_ON_MASK_SFT (0x1 << 0) + +/* AFE_GAIN1_CON0 */ +#define GAIN1_SAMPLE_PER_STEP_SFT 8 +#define GAIN1_SAMPLE_PER_STEP_MASK 0xff +#define GAIN1_SAMPLE_PER_STEP_MASK_SFT (0xff << 8) +#define GAIN1_MODE_SFT 4 +#define GAIN1_MODE_MASK 0xf +#define GAIN1_MODE_MASK_SFT (0xf << 4) +#define GAIN1_ON_SFT 0 +#define GAIN1_ON_MASK 0x1 +#define GAIN1_ON_MASK_SFT (0x1 << 0) + +/* AFE_GAIN1_CON1 */ +#define GAIN1_TARGET_SFT 0 +#define GAIN1_TARGET_MASK 0xfffffff +#define GAIN1_TARGET_MASK_SFT (0xfffffff << 0) + +/* AFE_GAIN2_CON0 */ +#define GAIN2_SAMPLE_PER_STEP_SFT 8 +#define GAIN2_SAMPLE_PER_STEP_MASK 0xff +#define GAIN2_SAMPLE_PER_STEP_MASK_SFT (0xff << 8) +#define GAIN2_MODE_SFT 4 +#define GAIN2_MODE_MASK 0xf +#define GAIN2_MODE_MASK_SFT (0xf << 4) +#define GAIN2_ON_SFT 0 +#define GAIN2_ON_MASK 0x1 +#define GAIN2_ON_MASK_SFT (0x1 << 0) + +/* AFE_GAIN2_CON1 */ +#define GAIN2_TARGET_SFT 0 +#define GAIN2_TARGET_MASK 0xfffffff +#define GAIN2_TARGET_MASK_SFT (0xfffffff << 0) + +/* AFE_GAIN1_CUR */ +#define AFE_GAIN1_CUR_SFT 0 +#define AFE_GAIN1_CUR_MASK 0xfffffff +#define AFE_GAIN1_CUR_MASK_SFT (0xfffffff << 0) + +/* AFE_GAIN2_CUR */ +#define AFE_GAIN2_CUR_SFT 0 +#define AFE_GAIN2_CUR_MASK 0xfffffff +#define AFE_GAIN2_CUR_MASK_SFT (0xfffffff << 0) + +/* PCM_INTF_CON1 */ +#define PCM_FIX_VALUE_SEL_SFT 31 +#define PCM_FIX_VALUE_SEL_MASK 0x1 +#define PCM_FIX_VALUE_SEL_MASK_SFT (0x1 << 31) +#define PCM_BUFFER_LOOPBACK_SFT 30 +#define PCM_BUFFER_LOOPBACK_MASK 0x1 +#define PCM_BUFFER_LOOPBACK_MASK_SFT (0x1 << 30) +#define PCM_PARALLEL_LOOPBACK_SFT 29 +#define PCM_PARALLEL_LOOPBACK_MASK 0x1 +#define PCM_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 29) +#define PCM_SERIAL_LOOPBACK_SFT 28 +#define PCM_SERIAL_LOOPBACK_MASK 0x1 +#define PCM_SERIAL_LOOPBACK_MASK_SFT (0x1 << 28) +#define PCM_DAI_PCM_LOOPBACK_SFT 27 +#define PCM_DAI_PCM_LOOPBACK_MASK 0x1 +#define PCM_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 27) +#define PCM_I2S_PCM_LOOPBACK_SFT 26 +#define PCM_I2S_PCM_LOOPBACK_MASK 0x1 +#define PCM_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 26) +#define PCM_SYNC_DELSEL_SFT 25 +#define PCM_SYNC_DELSEL_MASK 0x1 +#define PCM_SYNC_DELSEL_MASK_SFT (0x1 << 25) +#define PCM_TX_LR_SWAP_SFT 24 +#define PCM_TX_LR_SWAP_MASK 0x1 +#define PCM_TX_LR_SWAP_MASK_SFT (0x1 << 24) +#define PCM_SYNC_OUT_INV_SFT 23 +#define PCM_SYNC_OUT_INV_MASK 0x1 +#define PCM_SYNC_OUT_INV_MASK_SFT (0x1 << 23) +#define PCM_BCLK_OUT_INV_SFT 22 +#define PCM_BCLK_OUT_INV_MASK 0x1 +#define PCM_BCLK_OUT_INV_MASK_SFT (0x1 << 22) +#define PCM_SYNC_IN_INV_SFT 21 +#define PCM_SYNC_IN_INV_MASK 0x1 +#define PCM_SYNC_IN_INV_MASK_SFT (0x1 << 21) +#define PCM_BCLK_IN_INV_SFT 20 +#define PCM_BCLK_IN_INV_MASK 0x1 +#define PCM_BCLK_IN_INV_MASK_SFT (0x1 << 20) +#define PCM_TX_LCH_RPT_SFT 19 +#define PCM_TX_LCH_RPT_MASK 0x1 +#define PCM_TX_LCH_RPT_MASK_SFT (0x1 << 19) +#define PCM_VBT_16K_MODE_SFT 18 +#define PCM_VBT_16K_MODE_MASK 0x1 +#define PCM_VBT_16K_MODE_MASK_SFT (0x1 << 18) +#define PCM_EXT_MODEM_SFT 17 +#define PCM_EXT_MODEM_MASK 0x1 +#define PCM_EXT_MODEM_MASK_SFT (0x1 << 17) +#define PCM_24BIT_SFT 16 +#define PCM_24BIT_MASK 0x1 +#define PCM_24BIT_MASK_SFT (0x1 << 16) +#define PCM_WLEN_SFT 14 +#define PCM_WLEN_MASK 0x3 +#define PCM_WLEN_MASK_SFT (0x3 << 14) +#define PCM_SYNC_LENGTH_SFT 9 +#define PCM_SYNC_LENGTH_MASK 0x1f +#define PCM_SYNC_LENGTH_MASK_SFT (0x1f << 9) +#define PCM_SYNC_TYPE_SFT 8 +#define PCM_SYNC_TYPE_MASK 0x1 +#define PCM_SYNC_TYPE_MASK_SFT (0x1 << 8) +#define PCM_BT_MODE_SFT 7 +#define PCM_BT_MODE_MASK 0x1 +#define PCM_BT_MODE_MASK_SFT (0x1 << 7) +#define PCM_BYP_ASRC_SFT 6 +#define PCM_BYP_ASRC_MASK 0x1 +#define PCM_BYP_ASRC_MASK_SFT (0x1 << 6) +#define PCM_SLAVE_SFT 5 +#define PCM_SLAVE_MASK 0x1 +#define PCM_SLAVE_MASK_SFT (0x1 << 5) +#define PCM_MODE_SFT 3 +#define PCM_MODE_MASK 0x3 +#define PCM_MODE_MASK_SFT (0x3 << 3) +#define PCM_FMT_SFT 1 +#define PCM_FMT_MASK 0x3 +#define PCM_FMT_MASK_SFT (0x3 << 1) +#define PCM_EN_SFT 0 +#define PCM_EN_MASK 0x1 +#define PCM_EN_MASK_SFT (0x1 << 0) + +/* PCM_INTF_CON2 */ +#define PCM1_TX_FIFO_OV_SFT 31 +#define PCM1_TX_FIFO_OV_MASK 0x1 +#define PCM1_TX_FIFO_OV_MASK_SFT (0x1 << 31) +#define PCM1_RX_FIFO_OV_SFT 30 +#define PCM1_RX_FIFO_OV_MASK 0x1 +#define PCM1_RX_FIFO_OV_MASK_SFT (0x1 << 30) +#define PCM2_TX_FIFO_OV_SFT 29 +#define PCM2_TX_FIFO_OV_MASK 0x1 +#define PCM2_TX_FIFO_OV_MASK_SFT (0x1 << 29) +#define PCM2_RX_FIFO_OV_SFT 28 +#define PCM2_RX_FIFO_OV_MASK 0x1 +#define PCM2_RX_FIFO_OV_MASK_SFT (0x1 << 28) +#define PCM1_SYNC_GLITCH_SFT 27 +#define PCM1_SYNC_GLITCH_MASK 0x1 +#define PCM1_SYNC_GLITCH_MASK_SFT (0x1 << 27) +#define PCM2_SYNC_GLITCH_SFT 26 +#define PCM2_SYNC_GLITCH_MASK 0x1 +#define PCM2_SYNC_GLITCH_MASK_SFT (0x1 << 26) +#define TX3_RCH_DBG_MODE_SFT 17 +#define TX3_RCH_DBG_MODE_MASK 0x1 +#define TX3_RCH_DBG_MODE_MASK_SFT (0x1 << 17) +#define PCM1_PCM2_LOOPBACK_SFT 16 +#define PCM1_PCM2_LOOPBACK_MASK 0x1 +#define PCM1_PCM2_LOOPBACK_MASK_SFT (0x1 << 16) +#define DAI_PCM_LOOPBACK_CH_SFT 14 +#define DAI_PCM_LOOPBACK_CH_MASK 0x3 +#define DAI_PCM_LOOPBACK_CH_MASK_SFT (0x3 << 14) +#define I2S_PCM_LOOPBACK_CH_SFT 12 +#define I2S_PCM_LOOPBACK_CH_MASK 0x3 +#define I2S_PCM_LOOPBACK_CH_MASK_SFT (0x3 << 12) +#define TX_FIX_VALUE_SFT 0 +#define TX_FIX_VALUE_MASK 0xff +#define TX_FIX_VALUE_MASK_SFT (0xff << 0) + +/* PCM2_INTF_CON */ +#define PCM2_TX_FIX_VALUE_SFT 24 +#define PCM2_TX_FIX_VALUE_MASK 0xff +#define PCM2_TX_FIX_VALUE_MASK_SFT (0xff << 24) +#define PCM2_FIX_VALUE_SEL_SFT 23 +#define PCM2_FIX_VALUE_SEL_MASK 0x1 +#define PCM2_FIX_VALUE_SEL_MASK_SFT (0x1 << 23) +#define PCM2_BUFFER_LOOPBACK_SFT 22 +#define PCM2_BUFFER_LOOPBACK_MASK 0x1 +#define PCM2_BUFFER_LOOPBACK_MASK_SFT (0x1 << 22) +#define PCM2_PARALLEL_LOOPBACK_SFT 21 +#define PCM2_PARALLEL_LOOPBACK_MASK 0x1 +#define PCM2_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 21) +#define PCM2_SERIAL_LOOPBACK_SFT 20 +#define PCM2_SERIAL_LOOPBACK_MASK 0x1 +#define PCM2_SERIAL_LOOPBACK_MASK_SFT (0x1 << 20) +#define PCM2_DAI_PCM_LOOPBACK_SFT 19 +#define PCM2_DAI_PCM_LOOPBACK_MASK 0x1 +#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 19) +#define PCM2_I2S_PCM_LOOPBACK_SFT 18 +#define PCM2_I2S_PCM_LOOPBACK_MASK 0x1 +#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 18) +#define PCM2_SYNC_DELSEL_SFT 17 +#define PCM2_SYNC_DELSEL_MASK 0x1 +#define PCM2_SYNC_DELSEL_MASK_SFT (0x1 << 17) +#define PCM2_TX_LR_SWAP_SFT 16 +#define PCM2_TX_LR_SWAP_MASK 0x1 +#define PCM2_TX_LR_SWAP_MASK_SFT (0x1 << 16) +#define PCM2_SYNC_IN_INV_SFT 15 +#define PCM2_SYNC_IN_INV_MASK 0x1 +#define PCM2_SYNC_IN_INV_MASK_SFT (0x1 << 15) +#define PCM2_BCLK_IN_INV_SFT 14 +#define PCM2_BCLK_IN_INV_MASK 0x1 +#define PCM2_BCLK_IN_INV_MASK_SFT (0x1 << 14) +#define PCM2_TX_LCH_RPT_SFT 13 +#define PCM2_TX_LCH_RPT_MASK 0x1 +#define PCM2_TX_LCH_RPT_MASK_SFT (0x1 << 13) +#define PCM2_VBT_16K_MODE_SFT 12 +#define PCM2_VBT_16K_MODE_MASK 0x1 +#define PCM2_VBT_16K_MODE_MASK_SFT (0x1 << 12) +#define PCM2_LOOPBACK_CH_SEL_SFT 10 +#define PCM2_LOOPBACK_CH_SEL_MASK 0x3 +#define PCM2_LOOPBACK_CH_SEL_MASK_SFT (0x3 << 10) +#define PCM2_TX2_BT_MODE_SFT 8 +#define PCM2_TX2_BT_MODE_MASK 0x1 +#define PCM2_TX2_BT_MODE_MASK_SFT (0x1 << 8) +#define PCM2_BT_MODE_SFT 7 +#define PCM2_BT_MODE_MASK 0x1 +#define PCM2_BT_MODE_MASK_SFT (0x1 << 7) +#define PCM2_AFIFO_SFT 6 +#define PCM2_AFIFO_MASK 0x1 +#define PCM2_AFIFO_MASK_SFT (0x1 << 6) +#define PCM2_WLEN_SFT 5 +#define PCM2_WLEN_MASK 0x1 +#define PCM2_WLEN_MASK_SFT (0x1 << 5) +#define PCM2_MODE_SFT 3 +#define PCM2_MODE_MASK 0x3 +#define PCM2_MODE_MASK_SFT (0x3 << 3) +#define PCM2_FMT_SFT 1 +#define PCM2_FMT_MASK 0x3 +#define PCM2_FMT_MASK_SFT (0x3 << 1) +#define PCM2_EN_SFT 0 +#define PCM2_EN_MASK 0x1 +#define PCM2_EN_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_CFG0 */ +#define MTKAIF_RXIF_CLKINV_ADC_SFT 31 +#define MTKAIF_RXIF_CLKINV_ADC_MASK 0x1 +#define MTKAIF_RXIF_CLKINV_ADC_MASK_SFT (0x1 << 31) +#define MTKAIF_RXIF_BYPASS_SRC_SFT 17 +#define MTKAIF_RXIF_BYPASS_SRC_MASK 0x1 +#define MTKAIF_RXIF_BYPASS_SRC_MASK_SFT (0x1 << 17) +#define MTKAIF_RXIF_PROTOCOL2_SFT 16 +#define MTKAIF_RXIF_PROTOCOL2_MASK 0x1 +#define MTKAIF_RXIF_PROTOCOL2_MASK_SFT (0x1 << 16) +#define MTKAIF_TXIF_BYPASS_SRC_SFT 5 +#define MTKAIF_TXIF_BYPASS_SRC_MASK 0x1 +#define MTKAIF_TXIF_BYPASS_SRC_MASK_SFT (0x1 << 5) +#define MTKAIF_TXIF_PROTOCOL2_SFT 4 +#define MTKAIF_TXIF_PROTOCOL2_MASK 0x1 +#define MTKAIF_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4) +#define MTKAIF_TXIF_8TO5_SFT 2 +#define MTKAIF_TXIF_8TO5_MASK 0x1 +#define MTKAIF_TXIF_8TO5_MASK_SFT (0x1 << 2) +#define MTKAIF_RXIF_8TO5_SFT 1 +#define MTKAIF_RXIF_8TO5_MASK 0x1 +#define MTKAIF_RXIF_8TO5_MASK_SFT (0x1 << 1) +#define MTKAIF_IF_LOOPBACK1_SFT 0 +#define MTKAIF_IF_LOOPBACK1_MASK 0x1 +#define MTKAIF_IF_LOOPBACK1_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_RX_CFG2 */ +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 16 +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK 0x1 +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT (0x1 << 16) +#define MTKAIF_RXIF_DELAY_CYCLE_SFT 12 +#define MTKAIF_RXIF_DELAY_CYCLE_MASK 0xf +#define MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT (0xf << 12) +#define MTKAIF_RXIF_DELAY_DATA_SFT 8 +#define MTKAIF_RXIF_DELAY_DATA_MASK 0x1 +#define MTKAIF_RXIF_DELAY_DATA_MASK_SFT (0x1 << 8) +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4 +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK 0x7 +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT (0x7 << 4) + +/* AFE_ADDA_DL_SRC2_CON0 */ +#define DL_2_INPUT_MODE_CTL_SFT 28 +#define DL_2_INPUT_MODE_CTL_MASK 0xf +#define DL_2_INPUT_MODE_CTL_MASK_SFT (0xf << 28) +#define DL_2_CH1_SATURATION_EN_CTL_SFT 27 +#define DL_2_CH1_SATURATION_EN_CTL_MASK 0x1 +#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT (0x1 << 27) +#define DL_2_CH2_SATURATION_EN_CTL_SFT 26 +#define DL_2_CH2_SATURATION_EN_CTL_MASK 0x1 +#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT (0x1 << 26) +#define DL_2_OUTPUT_SEL_CTL_SFT 24 +#define DL_2_OUTPUT_SEL_CTL_MASK 0x3 +#define DL_2_OUTPUT_SEL_CTL_MASK_SFT (0x3 << 24) +#define DL_2_FADEIN_0START_EN_SFT 16 +#define DL_2_FADEIN_0START_EN_MASK 0x3 +#define DL_2_FADEIN_0START_EN_MASK_SFT (0x3 << 16) +#define DL_DISABLE_HW_CG_CTL_SFT 15 +#define DL_DISABLE_HW_CG_CTL_MASK 0x1 +#define DL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 15) +#define C_DATA_EN_SEL_CTL_PRE_SFT 14 +#define C_DATA_EN_SEL_CTL_PRE_MASK 0x1 +#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT (0x1 << 14) +#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT 13 +#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK 0x1 +#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT (0x1 << 13) +#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT 12 +#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK 0x1 +#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT (0x1 << 12) +#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT 11 +#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK 0x1 +#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT (0x1 << 11) +#define DL2_ARAMPSP_CTL_PRE_SFT 9 +#define DL2_ARAMPSP_CTL_PRE_MASK 0x3 +#define DL2_ARAMPSP_CTL_PRE_MASK_SFT (0x3 << 9) +#define DL_2_IIRMODE_CTL_PRE_SFT 6 +#define DL_2_IIRMODE_CTL_PRE_MASK 0x7 +#define DL_2_IIRMODE_CTL_PRE_MASK_SFT (0x7 << 6) +#define DL_2_VOICE_MODE_CTL_PRE_SFT 5 +#define DL_2_VOICE_MODE_CTL_PRE_MASK 0x1 +#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT (0x1 << 5) +#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT 4 +#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK 0x1 +#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT (0x1 << 4) +#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT 3 +#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK 0x1 +#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT (0x1 << 3) +#define DL_2_IIR_ON_CTL_PRE_SFT 2 +#define DL_2_IIR_ON_CTL_PRE_MASK 0x1 +#define DL_2_IIR_ON_CTL_PRE_MASK_SFT (0x1 << 2) +#define DL_2_GAIN_ON_CTL_PRE_SFT 1 +#define DL_2_GAIN_ON_CTL_PRE_MASK 0x1 +#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT (0x1 << 1) +#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK 0x1 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_DL_SRC2_CON1 */ +#define DL_2_GAIN_CTL_PRE_SFT 16 +#define DL_2_GAIN_CTL_PRE_MASK 0xffff +#define DL_2_GAIN_CTL_PRE_MASK_SFT (0xffff << 16) +#define DL_2_GAIN_MODE_CTL_SFT 0 +#define DL_2_GAIN_MODE_CTL_MASK 0x1 +#define DL_2_GAIN_MODE_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_SRC_CON0 */ +#define ULCF_CFG_EN_CTL_SFT 31 +#define ULCF_CFG_EN_CTL_MASK 0x1 +#define ULCF_CFG_EN_CTL_MASK_SFT (0x1 << 31) +#define UL_DMIC_PHASE_SEL_CH1_SFT 27 +#define UL_DMIC_PHASE_SEL_CH1_MASK 0x7 +#define UL_DMIC_PHASE_SEL_CH1_MASK_SFT (0x7 << 27) +#define UL_DMIC_PHASE_SEL_CH2_SFT 24 +#define UL_DMIC_PHASE_SEL_CH2_MASK 0x7 +#define UL_DMIC_PHASE_SEL_CH2_MASK_SFT (0x7 << 24) +#define UL_MODE_3P25M_CH2_CTL_SFT 22 +#define UL_MODE_3P25M_CH2_CTL_MASK 0x1 +#define UL_MODE_3P25M_CH2_CTL_MASK_SFT (0x1 << 22) +#define UL_MODE_3P25M_CH1_CTL_SFT 21 +#define UL_MODE_3P25M_CH1_CTL_MASK 0x1 +#define UL_MODE_3P25M_CH1_CTL_MASK_SFT (0x1 << 21) +#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17 +#define UL_VOICE_MODE_CH1_CH2_CTL_MASK 0x7 +#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT (0x7 << 17) +#define UL_AP_DMIC_ON_SFT 16 +#define UL_AP_DMIC_ON_MASK 0x1 +#define UL_AP_DMIC_ON_MASK_SFT (0x1 << 16) +#define DMIC_LOW_POWER_MODE_CTL_SFT 14 +#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3 +#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14) +#define UL_DISABLE_HW_CG_CTL_SFT 12 +#define UL_DISABLE_HW_CG_CTL_MASK 0x1 +#define UL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 12) +#define UL_IIR_ON_TMP_CTL_SFT 10 +#define UL_IIR_ON_TMP_CTL_MASK 0x1 +#define UL_IIR_ON_TMP_CTL_MASK_SFT (0x1 << 10) +#define UL_IIRMODE_CTL_SFT 7 +#define UL_IIRMODE_CTL_MASK 0x7 +#define UL_IIRMODE_CTL_MASK_SFT (0x7 << 7) +#define DIGMIC_4P33M_SEL_SFT 6 +#define DIGMIC_4P33M_SEL_MASK 0x1 +#define DIGMIC_4P33M_SEL_MASK_SFT (0x1 << 6) +#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5) +#define UL_LOOP_BACK_MODE_CTL_SFT 2 +#define UL_LOOP_BACK_MODE_CTL_MASK 0x1 +#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2) +#define UL_SDM_3_LEVEL_CTL_SFT 1 +#define UL_SDM_3_LEVEL_CTL_MASK 0x1 +#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1) +#define UL_SRC_ON_TMP_CTL_SFT 0 +#define UL_SRC_ON_TMP_CTL_MASK 0x1 +#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_SRC_CON1 */ +#define C_DAC_EN_CTL_SFT 27 +#define C_DAC_EN_CTL_MASK 0x1 +#define C_DAC_EN_CTL_MASK_SFT (0x1 << 27) +#define C_MUTE_SW_CTL_SFT 26 +#define C_MUTE_SW_CTL_MASK 0x1 +#define C_MUTE_SW_CTL_MASK_SFT (0x1 << 26) +#define ASDM_SRC_SEL_CTL_SFT 25 +#define ASDM_SRC_SEL_CTL_MASK 0x1 +#define ASDM_SRC_SEL_CTL_MASK_SFT (0x1 << 25) +#define C_AMP_DIV_CH2_CTL_SFT 21 +#define C_AMP_DIV_CH2_CTL_MASK 0x7 +#define C_AMP_DIV_CH2_CTL_MASK_SFT (0x7 << 21) +#define C_FREQ_DIV_CH2_CTL_SFT 16 +#define C_FREQ_DIV_CH2_CTL_MASK 0x1f +#define C_FREQ_DIV_CH2_CTL_MASK_SFT (0x1f << 16) +#define C_SINE_MODE_CH2_CTL_SFT 12 +#define C_SINE_MODE_CH2_CTL_MASK 0xf +#define C_SINE_MODE_CH2_CTL_MASK_SFT (0xf << 12) +#define C_AMP_DIV_CH1_CTL_SFT 9 +#define C_AMP_DIV_CH1_CTL_MASK 0x7 +#define C_AMP_DIV_CH1_CTL_MASK_SFT (0x7 << 9) +#define C_FREQ_DIV_CH1_CTL_SFT 4 +#define C_FREQ_DIV_CH1_CTL_MASK 0x1f +#define C_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 4) +#define C_SINE_MODE_CH1_CTL_SFT 0 +#define C_SINE_MODE_CH1_CTL_MASK 0xf +#define C_SINE_MODE_CH1_CTL_MASK_SFT (0xf << 0) + +/* AFE_ADDA_TOP_CON0 */ +#define C_LOOP_BACK_MODE_CTL_SFT 12 +#define C_LOOP_BACK_MODE_CTL_MASK 0xf +#define C_LOOP_BACK_MODE_CTL_MASK_SFT (0xf << 12) +#define ADDA_UL_GAIN_MODE_SFT 8 +#define ADDA_UL_GAIN_MODE_MASK 0x3 +#define ADDA_UL_GAIN_MODE_MASK_SFT (0x3 << 8) +#define C_EXT_ADC_CTL_SFT 0 +#define C_EXT_ADC_CTL_MASK 0x1 +#define C_EXT_ADC_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_DL_CON0 */ +#define AFE_ADDA_UL_LR_SWAP_SFT 31 +#define AFE_ADDA_UL_LR_SWAP_MASK 0x1 +#define AFE_ADDA_UL_LR_SWAP_MASK_SFT (0x1 << 31) +#define AFE_ADDA_CKDIV_RST_SFT 30 +#define AFE_ADDA_CKDIV_RST_MASK 0x1 +#define AFE_ADDA_CKDIV_RST_MASK_SFT (0x1 << 30) +#define AFE_ADDA_FIFO_AUTO_RST_SFT 29 +#define AFE_ADDA_FIFO_AUTO_RST_MASK 0x1 +#define AFE_ADDA_FIFO_AUTO_RST_MASK_SFT (0x1 << 29) +#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_SFT 21 +#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK 0x3 +#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK_SFT (0x3 << 21) +#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 20 +#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK 0x1 +#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT (0x1 << 20) +#define AFE_ADDA6_UL_LR_SWAP_SFT 15 +#define AFE_ADDA6_UL_LR_SWAP_MASK 0x1 +#define AFE_ADDA6_UL_LR_SWAP_MASK_SFT (0x1 << 15) +#define AFE_ADDA6_CKDIV_RST_SFT 14 +#define AFE_ADDA6_CKDIV_RST_MASK 0x1 +#define AFE_ADDA6_CKDIV_RST_MASK_SFT (0x1 << 14) +#define AFE_ADDA6_FIFO_AUTO_RST_SFT 13 +#define AFE_ADDA6_FIFO_AUTO_RST_MASK 0x1 +#define AFE_ADDA6_FIFO_AUTO_RST_MASK_SFT (0x1 << 13) +#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_SFT 5 +#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK 0x3 +#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK_SFT (0x3 << 5) +#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 4 +#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK 0x1 +#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT (0x1 << 4) +#define ADDA_AFE_ON_SFT 0 +#define ADDA_AFE_ON_MASK 0x1 +#define ADDA_AFE_ON_MASK_SFT (0x1 << 0) + +/* AFE_SIDETONE_CON0 */ +#define R_RDY_SFT 30 +#define R_RDY_MASK 0x1 +#define R_RDY_MASK_SFT (0x1 << 30) +#define W_RDY_SFT 29 +#define W_RDY_MASK 0x1 +#define W_RDY_MASK_SFT (0x1 << 29) +#define R_W_EN_SFT 25 +#define R_W_EN_MASK 0x1 +#define R_W_EN_MASK_SFT (0x1 << 25) +#define R_W_SEL_SFT 24 +#define R_W_SEL_MASK 0x1 +#define R_W_SEL_MASK_SFT (0x1 << 24) +#define SEL_CH2_SFT 23 +#define SEL_CH2_MASK 0x1 +#define SEL_CH2_MASK_SFT (0x1 << 23) +#define SIDE_TONE_COEFFICIENT_ADDR_SFT 16 +#define SIDE_TONE_COEFFICIENT_ADDR_MASK 0x1f +#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT (0x1f << 16) +#define SIDE_TONE_COEFFICIENT_SFT 0 +#define SIDE_TONE_COEFFICIENT_MASK 0xffff +#define SIDE_TONE_COEFFICIENT_MASK_SFT (0xffff << 0) + +/* AFE_SIDETONE_COEFF */ +#define SIDE_TONE_COEFF_SFT 0 +#define SIDE_TONE_COEFF_MASK 0xffff +#define SIDE_TONE_COEFF_MASK_SFT (0xffff << 0) + +/* AFE_SIDETONE_CON1 */ +#define STF_BYPASS_MODE_SFT 31 +#define STF_BYPASS_MODE_MASK 0x1 +#define STF_BYPASS_MODE_MASK_SFT (0x1 << 31) +#define STF_BYPASS_MODE_O28_O29_SFT 30 +#define STF_BYPASS_MODE_O28_O29_MASK 0x1 +#define STF_BYPASS_MODE_O28_O29_MASK_SFT (0x1 << 30) +#define STF_BYPASS_MODE_I2S4_SFT 29 +#define STF_BYPASS_MODE_I2S4_MASK 0x1 +#define STF_BYPASS_MODE_I2S4_MASK_SFT (0x1 << 29) +#define STF_BYPASS_MODE_I2S5_SFT 28 +#define STF_BYPASS_MODE_I2S5_MASK 0x1 +#define STF_BYPASS_MODE_I2S5_MASK_SFT (0x1 << 28) +#define STF_BYPASS_MODE_DL3_SFT 27 +#define STF_BYPASS_MODE_DL3_MASK 0x1 +#define STF_BYPASS_MODE_DL3_MASK_SFT (0x1 << 27) +#define STF_BYPASS_MODE_I2S7_SFT 26 +#define STF_BYPASS_MODE_I2S7_MASK 0x1 +#define STF_BYPASS_MODE_I2S7_MASK_SFT (0x1 << 26) +#define STF_BYPASS_MODE_I2S9_SFT 25 +#define STF_BYPASS_MODE_I2S9_MASK 0x1 +#define STF_BYPASS_MODE_I2S9_MASK_SFT (0x1 << 25) +#define STF_O19O20_OUT_EN_SEL_SFT 13 +#define STF_O19O20_OUT_EN_SEL_MASK 0x1 +#define STF_O19O20_OUT_EN_SEL_MASK_SFT (0x1 << 13) +#define STF_SOURCE_FROM_O19O20_SFT 12 +#define STF_SOURCE_FROM_O19O20_MASK 0x1 +#define STF_SOURCE_FROM_O19O20_MASK_SFT (0x1 << 12) +#define SIDE_TONE_ON_SFT 8 +#define SIDE_TONE_ON_MASK 0x1 +#define SIDE_TONE_ON_MASK_SFT (0x1 << 8) +#define SIDE_TONE_HALF_TAP_NUM_SFT 0 +#define SIDE_TONE_HALF_TAP_NUM_MASK 0x3f +#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT (0x3f << 0) + +/* AFE_SIDETONE_GAIN */ +#define POSITIVE_GAIN_SFT 16 +#define POSITIVE_GAIN_MASK 0x7 +#define POSITIVE_GAIN_MASK_SFT (0x7 << 16) +#define SIDE_TONE_GAIN_SFT 0 +#define SIDE_TONE_GAIN_MASK 0xffff +#define SIDE_TONE_GAIN_MASK_SFT (0xffff << 0) + +/* AFE_ADDA_DL_SDM_DCCOMP_CON */ +#define USE_3RD_SDM_SFT 28 +#define USE_3RD_SDM_MASK 0x1 +#define USE_3RD_SDM_MASK_SFT (0x1 << 28) +#define DL_FIFO_START_POINT_SFT 24 +#define DL_FIFO_START_POINT_MASK 0x7 +#define DL_FIFO_START_POINT_MASK_SFT (0x7 << 24) +#define DL_FIFO_SWAP_SFT 20 +#define DL_FIFO_SWAP_MASK 0x1 +#define DL_FIFO_SWAP_MASK_SFT (0x1 << 20) +#define C_AUDSDM1ORDSELECT_CTL_SFT 19 +#define C_AUDSDM1ORDSELECT_CTL_MASK 0x1 +#define C_AUDSDM1ORDSELECT_CTL_MASK_SFT (0x1 << 19) +#define C_SDM7BITSEL_CTL_SFT 18 +#define C_SDM7BITSEL_CTL_MASK 0x1 +#define C_SDM7BITSEL_CTL_MASK_SFT (0x1 << 18) +#define GAIN_AT_SDM_RST_PRE_CTL_SFT 15 +#define GAIN_AT_SDM_RST_PRE_CTL_MASK 0x1 +#define GAIN_AT_SDM_RST_PRE_CTL_MASK_SFT (0x1 << 15) +#define DL_DCM_AUTO_IDLE_EN_SFT 14 +#define DL_DCM_AUTO_IDLE_EN_MASK 0x1 +#define DL_DCM_AUTO_IDLE_EN_MASK_SFT (0x1 << 14) +#define AFE_DL_SRC_DCM_EN_SFT 13 +#define AFE_DL_SRC_DCM_EN_MASK 0x1 +#define AFE_DL_SRC_DCM_EN_MASK_SFT (0x1 << 13) +#define AFE_DL_POST_SRC_DCM_EN_SFT 12 +#define AFE_DL_POST_SRC_DCM_EN_MASK 0x1 +#define AFE_DL_POST_SRC_DCM_EN_MASK_SFT (0x1 << 12) +#define AUD_SDM_MONO_SFT 9 +#define AUD_SDM_MONO_MASK 0x1 +#define AUD_SDM_MONO_MASK_SFT (0x1 << 9) +#define AUD_DC_COMP_EN_SFT 8 +#define AUD_DC_COMP_EN_MASK 0x1 +#define AUD_DC_COMP_EN_MASK_SFT (0x1 << 8) +#define ATTGAIN_CTL_SFT 0 +#define ATTGAIN_CTL_MASK 0x3f +#define ATTGAIN_CTL_MASK_SFT (0x3f << 0) + +/* AFE_SINEGEN_CON0 */ +#define DAC_EN_SFT 26 +#define DAC_EN_MASK 0x1 +#define DAC_EN_MASK_SFT (0x1 << 26) +#define MUTE_SW_CH2_SFT 25 +#define MUTE_SW_CH2_MASK 0x1 +#define MUTE_SW_CH2_MASK_SFT (0x1 << 25) +#define MUTE_SW_CH1_SFT 24 +#define MUTE_SW_CH1_MASK 0x1 +#define MUTE_SW_CH1_MASK_SFT (0x1 << 24) +#define SINE_MODE_CH2_SFT 20 +#define SINE_MODE_CH2_MASK 0xf +#define SINE_MODE_CH2_MASK_SFT (0xf << 20) +#define AMP_DIV_CH2_SFT 17 +#define AMP_DIV_CH2_MASK 0x7 +#define AMP_DIV_CH2_MASK_SFT (0x7 << 17) +#define FREQ_DIV_CH2_SFT 12 +#define FREQ_DIV_CH2_MASK 0x1f +#define FREQ_DIV_CH2_MASK_SFT (0x1f << 12) +#define SINE_MODE_CH1_SFT 8 +#define SINE_MODE_CH1_MASK 0xf +#define SINE_MODE_CH1_MASK_SFT (0xf << 8) +#define AMP_DIV_CH1_SFT 5 +#define AMP_DIV_CH1_MASK 0x7 +#define AMP_DIV_CH1_MASK_SFT (0x7 << 5) +#define FREQ_DIV_CH1_SFT 0 +#define FREQ_DIV_CH1_MASK 0x1f +#define FREQ_DIV_CH1_MASK_SFT (0x1f << 0) + +/* AFE_SINEGEN_CON2 */ +#define INNER_LOOP_BACK_MODE_SFT 0 +#define INNER_LOOP_BACK_MODE_MASK 0x3f +#define INNER_LOOP_BACK_MODE_MASK_SFT (0x3f << 0) + +/* AFE_HD_ENGEN_ENABLE */ +#define AFE_24M_ON_SFT 1 +#define AFE_24M_ON_MASK 0x1 +#define AFE_24M_ON_MASK_SFT (0x1 << 1) +#define AFE_22M_ON_SFT 0 +#define AFE_22M_ON_MASK 0x1 +#define AFE_22M_ON_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_DL_NLE_FIFO_MON */ +#define DL_NLE_FIFO_WBIN_SFT 8 +#define DL_NLE_FIFO_WBIN_MASK 0xf +#define DL_NLE_FIFO_WBIN_MASK_SFT (0xf << 8) +#define DL_NLE_FIFO_RBIN_SFT 4 +#define DL_NLE_FIFO_RBIN_MASK 0xf +#define DL_NLE_FIFO_RBIN_MASK_SFT (0xf << 4) +#define DL_NLE_FIFO_RDACTIVE_SFT 3 +#define DL_NLE_FIFO_RDACTIVE_MASK 0x1 +#define DL_NLE_FIFO_RDACTIVE_MASK_SFT (0x1 << 3) +#define DL_NLE_FIFO_STARTRD_SFT 2 +#define DL_NLE_FIFO_STARTRD_MASK 0x1 +#define DL_NLE_FIFO_STARTRD_MASK_SFT (0x1 << 2) +#define DL_NLE_FIFO_RD_EMPTY_SFT 1 +#define DL_NLE_FIFO_RD_EMPTY_MASK 0x1 +#define DL_NLE_FIFO_RD_EMPTY_MASK_SFT (0x1 << 1) +#define DL_NLE_FIFO_WR_FULL_SFT 0 +#define DL_NLE_FIFO_WR_FULL_MASK 0x1 +#define DL_NLE_FIFO_WR_FULL_MASK_SFT (0x1 << 0) + +/* AFE_DL1_CON0 */ +#define DL1_MODE_SFT 24 +#define DL1_MODE_MASK 0xf +#define DL1_MODE_MASK_SFT (0xf << 24) +#define DL1_MINLEN_SFT 20 +#define DL1_MINLEN_MASK 0xf +#define DL1_MINLEN_MASK_SFT (0xf << 20) +#define DL1_MAXLEN_SFT 16 +#define DL1_MAXLEN_MASK 0xf +#define DL1_MAXLEN_MASK_SFT (0xf << 16) +#define DL1_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL1_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL1_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL1_PBUF_SIZE_SFT 12 +#define DL1_PBUF_SIZE_MASK 0x3 +#define DL1_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL1_MONO_SFT 8 +#define DL1_MONO_MASK 0x1 +#define DL1_MONO_MASK_SFT (0x1 << 8) +#define DL1_NORMAL_MODE_SFT 5 +#define DL1_NORMAL_MODE_MASK 0x1 +#define DL1_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL1_HALIGN_SFT 4 +#define DL1_HALIGN_MASK 0x1 +#define DL1_HALIGN_MASK_SFT (0x1 << 4) +#define DL1_HD_MODE_SFT 0 +#define DL1_HD_MODE_MASK 0x3 +#define DL1_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL2_CON0 */ +#define DL2_MODE_SFT 24 +#define DL2_MODE_MASK 0xf +#define DL2_MODE_MASK_SFT (0xf << 24) +#define DL2_MINLEN_SFT 20 +#define DL2_MINLEN_MASK 0xf +#define DL2_MINLEN_MASK_SFT (0xf << 20) +#define DL2_MAXLEN_SFT 16 +#define DL2_MAXLEN_MASK 0xf +#define DL2_MAXLEN_MASK_SFT (0xf << 16) +#define DL2_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL2_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL2_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL2_PBUF_SIZE_SFT 12 +#define DL2_PBUF_SIZE_MASK 0x3 +#define DL2_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL2_MONO_SFT 8 +#define DL2_MONO_MASK 0x1 +#define DL2_MONO_MASK_SFT (0x1 << 8) +#define DL2_NORMAL_MODE_SFT 5 +#define DL2_NORMAL_MODE_MASK 0x1 +#define DL2_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL2_HALIGN_SFT 4 +#define DL2_HALIGN_MASK 0x1 +#define DL2_HALIGN_MASK_SFT (0x1 << 4) +#define DL2_HD_MODE_SFT 0 +#define DL2_HD_MODE_MASK 0x3 +#define DL2_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL3_CON0 */ +#define DL3_MODE_SFT 24 +#define DL3_MODE_MASK 0xf +#define DL3_MODE_MASK_SFT (0xf << 24) +#define DL3_MINLEN_SFT 20 +#define DL3_MINLEN_MASK 0xf +#define DL3_MINLEN_MASK_SFT (0xf << 20) +#define DL3_MAXLEN_SFT 16 +#define DL3_MAXLEN_MASK 0xf +#define DL3_MAXLEN_MASK_SFT (0xf << 16) +#define DL3_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL3_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL3_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL3_PBUF_SIZE_SFT 12 +#define DL3_PBUF_SIZE_MASK 0x3 +#define DL3_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL3_MONO_SFT 8 +#define DL3_MONO_MASK 0x1 +#define DL3_MONO_MASK_SFT (0x1 << 8) +#define DL3_NORMAL_MODE_SFT 5 +#define DL3_NORMAL_MODE_MASK 0x1 +#define DL3_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL3_HALIGN_SFT 4 +#define DL3_HALIGN_MASK 0x1 +#define DL3_HALIGN_MASK_SFT (0x1 << 4) +#define DL3_HD_MODE_SFT 0 +#define DL3_HD_MODE_MASK 0x3 +#define DL3_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL4_CON0 */ +#define DL4_MODE_SFT 24 +#define DL4_MODE_MASK 0xf +#define DL4_MODE_MASK_SFT (0xf << 24) +#define DL4_MINLEN_SFT 20 +#define DL4_MINLEN_MASK 0xf +#define DL4_MINLEN_MASK_SFT (0xf << 20) +#define DL4_MAXLEN_SFT 16 +#define DL4_MAXLEN_MASK 0xf +#define DL4_MAXLEN_MASK_SFT (0xf << 16) +#define DL4_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL4_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL4_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL4_PBUF_SIZE_SFT 12 +#define DL4_PBUF_SIZE_MASK 0x3 +#define DL4_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL4_MONO_SFT 8 +#define DL4_MONO_MASK 0x1 +#define DL4_MONO_MASK_SFT (0x1 << 8) +#define DL4_NORMAL_MODE_SFT 5 +#define DL4_NORMAL_MODE_MASK 0x1 +#define DL4_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL4_HALIGN_SFT 4 +#define DL4_HALIGN_MASK 0x1 +#define DL4_HALIGN_MASK_SFT (0x1 << 4) +#define DL4_HD_MODE_SFT 0 +#define DL4_HD_MODE_MASK 0x3 +#define DL4_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL5_CON0 */ +#define DL5_MODE_SFT 24 +#define DL5_MODE_MASK 0xf +#define DL5_MODE_MASK_SFT (0xf << 24) +#define DL5_MINLEN_SFT 20 +#define DL5_MINLEN_MASK 0xf +#define DL5_MINLEN_MASK_SFT (0xf << 20) +#define DL5_MAXLEN_SFT 16 +#define DL5_MAXLEN_MASK 0xf +#define DL5_MAXLEN_MASK_SFT (0xf << 16) +#define DL5_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL5_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL5_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL5_PBUF_SIZE_SFT 12 +#define DL5_PBUF_SIZE_MASK 0x3 +#define DL5_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL5_MONO_SFT 8 +#define DL5_MONO_MASK 0x1 +#define DL5_MONO_MASK_SFT (0x1 << 8) +#define DL5_NORMAL_MODE_SFT 5 +#define DL5_NORMAL_MODE_MASK 0x1 +#define DL5_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL5_HALIGN_SFT 4 +#define DL5_HALIGN_MASK 0x1 +#define DL5_HALIGN_MASK_SFT (0x1 << 4) +#define DL5_HD_MODE_SFT 0 +#define DL5_HD_MODE_MASK 0x3 +#define DL5_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL6_CON0 */ +#define DL6_MODE_SFT 24 +#define DL6_MODE_MASK 0xf +#define DL6_MODE_MASK_SFT (0xf << 24) +#define DL6_MINLEN_SFT 20 +#define DL6_MINLEN_MASK 0xf +#define DL6_MINLEN_MASK_SFT (0xf << 20) +#define DL6_MAXLEN_SFT 16 +#define DL6_MAXLEN_MASK 0xf +#define DL6_MAXLEN_MASK_SFT (0xf << 16) +#define DL6_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL6_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL6_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL6_PBUF_SIZE_SFT 12 +#define DL6_PBUF_SIZE_MASK 0x3 +#define DL6_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL6_MONO_SFT 8 +#define DL6_MONO_MASK 0x1 +#define DL6_MONO_MASK_SFT (0x1 << 8) +#define DL6_NORMAL_MODE_SFT 5 +#define DL6_NORMAL_MODE_MASK 0x1 +#define DL6_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL6_HALIGN_SFT 4 +#define DL6_HALIGN_MASK 0x1 +#define DL6_HALIGN_MASK_SFT (0x1 << 4) +#define DL6_HD_MODE_SFT 0 +#define DL6_HD_MODE_MASK 0x3 +#define DL6_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL7_CON0 */ +#define DL7_MODE_SFT 24 +#define DL7_MODE_MASK 0xf +#define DL7_MODE_MASK_SFT (0xf << 24) +#define DL7_MINLEN_SFT 20 +#define DL7_MINLEN_MASK 0xf +#define DL7_MINLEN_MASK_SFT (0xf << 20) +#define DL7_MAXLEN_SFT 16 +#define DL7_MAXLEN_MASK 0xf +#define DL7_MAXLEN_MASK_SFT (0xf << 16) +#define DL7_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL7_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL7_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL7_PBUF_SIZE_SFT 12 +#define DL7_PBUF_SIZE_MASK 0x3 +#define DL7_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL7_MONO_SFT 8 +#define DL7_MONO_MASK 0x1 +#define DL7_MONO_MASK_SFT (0x1 << 8) +#define DL7_NORMAL_MODE_SFT 5 +#define DL7_NORMAL_MODE_MASK 0x1 +#define DL7_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL7_HALIGN_SFT 4 +#define DL7_HALIGN_MASK 0x1 +#define DL7_HALIGN_MASK_SFT (0x1 << 4) +#define DL7_HD_MODE_SFT 0 +#define DL7_HD_MODE_MASK 0x3 +#define DL7_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL8_CON0 */ +#define DL8_MODE_SFT 24 +#define DL8_MODE_MASK 0xf +#define DL8_MODE_MASK_SFT (0xf << 24) +#define DL8_MINLEN_SFT 20 +#define DL8_MINLEN_MASK 0xf +#define DL8_MINLEN_MASK_SFT (0xf << 20) +#define DL8_MAXLEN_SFT 16 +#define DL8_MAXLEN_MASK 0xf +#define DL8_MAXLEN_MASK_SFT (0xf << 16) +#define DL8_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL8_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL8_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL8_PBUF_SIZE_SFT 12 +#define DL8_PBUF_SIZE_MASK 0x3 +#define DL8_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL8_MONO_SFT 8 +#define DL8_MONO_MASK 0x1 +#define DL8_MONO_MASK_SFT (0x1 << 8) +#define DL8_NORMAL_MODE_SFT 5 +#define DL8_NORMAL_MODE_MASK 0x1 +#define DL8_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL8_HALIGN_SFT 4 +#define DL8_HALIGN_MASK 0x1 +#define DL8_HALIGN_MASK_SFT (0x1 << 4) +#define DL8_HD_MODE_SFT 0 +#define DL8_HD_MODE_MASK 0x3 +#define DL8_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL9_CON0 */ +#define DL9_MODE_SFT 24 +#define DL9_MODE_MASK 0xf +#define DL9_MODE_MASK_SFT (0xf << 24) +#define DL9_MINLEN_SFT 20 +#define DL9_MINLEN_MASK 0xf +#define DL9_MINLEN_MASK_SFT (0xf << 20) +#define DL9_MAXLEN_SFT 16 +#define DL9_MAXLEN_MASK 0xf +#define DL9_MAXLEN_MASK_SFT (0xf << 16) +#define DL9_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL9_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL9_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL9_PBUF_SIZE_SFT 12 +#define DL9_PBUF_SIZE_MASK 0x3 +#define DL9_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL9_MONO_SFT 8 +#define DL9_MONO_MASK 0x1 +#define DL9_MONO_MASK_SFT (0x1 << 8) +#define DL9_NORMAL_MODE_SFT 5 +#define DL9_NORMAL_MODE_MASK 0x1 +#define DL9_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL9_HALIGN_SFT 4 +#define DL9_HALIGN_MASK 0x1 +#define DL9_HALIGN_MASK_SFT (0x1 << 4) +#define DL9_HD_MODE_SFT 0 +#define DL9_HD_MODE_MASK 0x3 +#define DL9_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DL12_CON0 */ +#define DL12_MODE_SFT 24 +#define DL12_MODE_MASK 0xf +#define DL12_MODE_MASK_SFT (0xf << 24) +#define DL12_MINLEN_SFT 20 +#define DL12_MINLEN_MASK 0xf +#define DL12_MINLEN_MASK_SFT (0xf << 20) +#define DL12_MAXLEN_SFT 16 +#define DL12_MAXLEN_MASK 0xf +#define DL12_MAXLEN_MASK_SFT (0xf << 16) +#define DL12_SW_CLEAR_BUF_EMPTY_SFT 15 +#define DL12_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define DL12_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define DL12_PBUF_SIZE_SFT 12 +#define DL12_PBUF_SIZE_MASK 0x3 +#define DL12_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define DL12_4CH_EN_SFT 11 +#define DL12_4CH_EN_MASK 0x1 +#define DL12_4CH_EN_MASK_SFT (0x1 << 11) +#define DL12_MONO_SFT 8 +#define DL12_MONO_MASK 0x1 +#define DL12_MONO_MASK_SFT (0x1 << 8) +#define DL12_NORMAL_MODE_SFT 5 +#define DL12_NORMAL_MODE_MASK 0x1 +#define DL12_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DL12_HALIGN_SFT 4 +#define DL12_HALIGN_MASK 0x1 +#define DL12_HALIGN_MASK_SFT (0x1 << 4) +#define DL12_HD_MODE_SFT 0 +#define DL12_HD_MODE_MASK 0x3 +#define DL12_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_AWB_CON0 */ +#define AWB_MODE_SFT 24 +#define AWB_MODE_MASK 0xf +#define AWB_MODE_MASK_SFT (0xf << 24) +#define AWB_SW_CLEAR_BUF_FULL_SFT 15 +#define AWB_SW_CLEAR_BUF_FULL_MASK 0x1 +#define AWB_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define AWB_R_MONO_SFT 9 +#define AWB_R_MONO_MASK 0x1 +#define AWB_R_MONO_MASK_SFT (0x1 << 9) +#define AWB_MONO_SFT 8 +#define AWB_MONO_MASK 0x1 +#define AWB_MONO_MASK_SFT (0x1 << 8) +#define AWB_WR_SIGN_SFT 6 +#define AWB_WR_SIGN_MASK 0x1 +#define AWB_WR_SIGN_MASK_SFT (0x1 << 6) +#define AWB_NORMAL_MODE_SFT 5 +#define AWB_NORMAL_MODE_MASK 0x1 +#define AWB_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define AWB_HALIGN_SFT 4 +#define AWB_HALIGN_MASK 0x1 +#define AWB_HALIGN_MASK_SFT (0x1 << 4) +#define AWB_HD_MODE_SFT 0 +#define AWB_HD_MODE_MASK 0x3 +#define AWB_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_AWB2_CON0 */ +#define AWB2_MODE_SFT 24 +#define AWB2_MODE_MASK 0xf +#define AWB2_MODE_MASK_SFT (0xf << 24) +#define AWB2_SW_CLEAR_BUF_FULL_SFT 15 +#define AWB2_SW_CLEAR_BUF_FULL_MASK 0x1 +#define AWB2_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define AWB2_R_MONO_SFT 9 +#define AWB2_R_MONO_MASK 0x1 +#define AWB2_R_MONO_MASK_SFT (0x1 << 9) +#define AWB2_MONO_SFT 8 +#define AWB2_MONO_MASK 0x1 +#define AWB2_MONO_MASK_SFT (0x1 << 8) +#define AWB2_WR_SIGN_SFT 6 +#define AWB2_WR_SIGN_MASK 0x1 +#define AWB2_WR_SIGN_MASK_SFT (0x1 << 6) +#define AWB2_NORMAL_MODE_SFT 5 +#define AWB2_NORMAL_MODE_MASK 0x1 +#define AWB2_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define AWB2_HALIGN_SFT 4 +#define AWB2_HALIGN_MASK 0x1 +#define AWB2_HALIGN_MASK_SFT (0x1 << 4) +#define AWB2_HD_MODE_SFT 0 +#define AWB2_HD_MODE_MASK 0x3 +#define AWB2_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL_CON0 */ +#define VUL_MODE_SFT 24 +#define VUL_MODE_MASK 0xf +#define VUL_MODE_MASK_SFT (0xf << 24) +#define VUL_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define VUL_R_MONO_SFT 9 +#define VUL_R_MONO_MASK 0x1 +#define VUL_R_MONO_MASK_SFT (0x1 << 9) +#define VUL_MONO_SFT 8 +#define VUL_MONO_MASK 0x1 +#define VUL_MONO_MASK_SFT (0x1 << 8) +#define VUL_WR_SIGN_SFT 6 +#define VUL_WR_SIGN_MASK 0x1 +#define VUL_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL_NORMAL_MODE_SFT 5 +#define VUL_NORMAL_MODE_MASK 0x1 +#define VUL_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define VUL_HALIGN_SFT 4 +#define VUL_HALIGN_MASK 0x1 +#define VUL_HALIGN_MASK_SFT (0x1 << 4) +#define VUL_HD_MODE_SFT 0 +#define VUL_HD_MODE_MASK 0x3 +#define VUL_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL12_CON0 */ +#define VUL12_MODE_SFT 24 +#define VUL12_MODE_MASK 0xf +#define VUL12_MODE_MASK_SFT (0xf << 24) +#define VUL12_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL12_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL12_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define VUL12_4CH_EN_SFT 11 +#define VUL12_4CH_EN_MASK 0x1 +#define VUL12_4CH_EN_MASK_SFT (0x1 << 11) +#define VUL12_R_MONO_SFT 9 +#define VUL12_R_MONO_MASK 0x1 +#define VUL12_R_MONO_MASK_SFT (0x1 << 9) +#define VUL12_MONO_SFT 8 +#define VUL12_MONO_MASK 0x1 +#define VUL12_MONO_MASK_SFT (0x1 << 8) +#define VUL12_WR_SIGN_SFT 6 +#define VUL12_WR_SIGN_MASK 0x1 +#define VUL12_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL12_NORMAL_MODE_SFT 5 +#define VUL12_NORMAL_MODE_MASK 0x1 +#define VUL12_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define VUL12_HALIGN_SFT 4 +#define VUL12_HALIGN_MASK 0x1 +#define VUL12_HALIGN_MASK_SFT (0x1 << 4) +#define VUL12_HD_MODE_SFT 0 +#define VUL12_HD_MODE_MASK 0x3 +#define VUL12_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL2_CON0 */ +#define VUL2_MODE_SFT 24 +#define VUL2_MODE_MASK 0xf +#define VUL2_MODE_MASK_SFT (0xf << 24) +#define VUL2_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL2_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL2_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define VUL2_R_MONO_SFT 9 +#define VUL2_R_MONO_MASK 0x1 +#define VUL2_R_MONO_MASK_SFT (0x1 << 9) +#define VUL2_MONO_SFT 8 +#define VUL2_MONO_MASK 0x1 +#define VUL2_MONO_MASK_SFT (0x1 << 8) +#define VUL2_WR_SIGN_SFT 6 +#define VUL2_WR_SIGN_MASK 0x1 +#define VUL2_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL2_NORMAL_MODE_SFT 5 +#define VUL2_NORMAL_MODE_MASK 0x1 +#define VUL2_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define VUL2_HALIGN_SFT 4 +#define VUL2_HALIGN_MASK 0x1 +#define VUL2_HALIGN_MASK_SFT (0x1 << 4) +#define VUL2_HD_MODE_SFT 0 +#define VUL2_HD_MODE_MASK 0x3 +#define VUL2_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL3_CON0 */ +#define VUL3_MODE_SFT 24 +#define VUL3_MODE_MASK 0xf +#define VUL3_MODE_MASK_SFT (0xf << 24) +#define VUL3_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL3_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL3_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define VUL3_R_MONO_SFT 9 +#define VUL3_R_MONO_MASK 0x1 +#define VUL3_R_MONO_MASK_SFT (0x1 << 9) +#define VUL3_MONO_SFT 8 +#define VUL3_MONO_MASK 0x1 +#define VUL3_MONO_MASK_SFT (0x1 << 8) +#define VUL3_WR_SIGN_SFT 6 +#define VUL3_WR_SIGN_MASK 0x1 +#define VUL3_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL3_NORMAL_MODE_SFT 5 +#define VUL3_NORMAL_MODE_MASK 0x1 +#define VUL3_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define VUL3_HALIGN_SFT 4 +#define VUL3_HALIGN_MASK 0x1 +#define VUL3_HALIGN_MASK_SFT (0x1 << 4) +#define VUL3_HD_MODE_SFT 0 +#define VUL3_HD_MODE_MASK 0x3 +#define VUL3_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL4_CON0 */ +#define VUL4_MODE_SFT 24 +#define VUL4_MODE_MASK 0xf +#define VUL4_MODE_MASK_SFT (0xf << 24) +#define VUL4_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL4_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL4_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define VUL4_R_MONO_SFT 9 +#define VUL4_R_MONO_MASK 0x1 +#define VUL4_R_MONO_MASK_SFT (0x1 << 9) +#define VUL4_MONO_SFT 8 +#define VUL4_MONO_MASK 0x1 +#define VUL4_MONO_MASK_SFT (0x1 << 8) +#define VUL4_WR_SIGN_SFT 6 +#define VUL4_WR_SIGN_MASK 0x1 +#define VUL4_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL4_NORMAL_MODE_SFT 5 +#define VUL4_NORMAL_MODE_MASK 0x1 +#define VUL4_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define VUL4_HALIGN_SFT 4 +#define VUL4_HALIGN_MASK 0x1 +#define VUL4_HALIGN_MASK_SFT (0x1 << 4) +#define VUL4_HD_MODE_SFT 0 +#define VUL4_HD_MODE_MASK 0x3 +#define VUL4_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL5_CON0 */ +#define VUL5_MODE_SFT 24 +#define VUL5_MODE_MASK 0xf +#define VUL5_MODE_MASK_SFT (0xf << 24) +#define VUL5_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL5_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL5_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define VUL5_R_MONO_SFT 9 +#define VUL5_R_MONO_MASK 0x1 +#define VUL5_R_MONO_MASK_SFT (0x1 << 9) +#define VUL5_MONO_SFT 8 +#define VUL5_MONO_MASK 0x1 +#define VUL5_MONO_MASK_SFT (0x1 << 8) +#define VUL5_WR_SIGN_SFT 6 +#define VUL5_WR_SIGN_MASK 0x1 +#define VUL5_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL5_NORMAL_MODE_SFT 5 +#define VUL5_NORMAL_MODE_MASK 0x1 +#define VUL5_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define VUL5_HALIGN_SFT 4 +#define VUL5_HALIGN_MASK 0x1 +#define VUL5_HALIGN_MASK_SFT (0x1 << 4) +#define VUL5_HD_MODE_SFT 0 +#define VUL5_HD_MODE_MASK 0x3 +#define VUL5_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_VUL6_CON0 */ +#define VUL6_MODE_SFT 24 +#define VUL6_MODE_MASK 0xf +#define VUL6_MODE_MASK_SFT (0xf << 24) +#define VUL6_SW_CLEAR_BUF_FULL_SFT 15 +#define VUL6_SW_CLEAR_BUF_FULL_MASK 0x1 +#define VUL6_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define VUL6_R_MONO_SFT 9 +#define VUL6_R_MONO_MASK 0x1 +#define VUL6_R_MONO_MASK_SFT (0x1 << 9) +#define VUL6_MONO_SFT 8 +#define VUL6_MONO_MASK 0x1 +#define VUL6_MONO_MASK_SFT (0x1 << 8) +#define VUL6_WR_SIGN_SFT 6 +#define VUL6_WR_SIGN_MASK 0x1 +#define VUL6_WR_SIGN_MASK_SFT (0x1 << 6) +#define VUL6_NORMAL_MODE_SFT 5 +#define VUL6_NORMAL_MODE_MASK 0x1 +#define VUL6_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define VUL6_HALIGN_SFT 4 +#define VUL6_HALIGN_MASK 0x1 +#define VUL6_HALIGN_MASK_SFT (0x1 << 4) +#define VUL6_HD_MODE_SFT 0 +#define VUL6_HD_MODE_MASK 0x3 +#define VUL6_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DAI_CON0 */ +#define DAI_MODE_SFT 24 +#define DAI_MODE_MASK 0x3 +#define DAI_MODE_MASK_SFT (0x3 << 24) +#define DAI_SW_CLEAR_BUF_FULL_SFT 15 +#define DAI_SW_CLEAR_BUF_FULL_MASK 0x1 +#define DAI_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define DAI_DUPLICATE_WR_SFT 10 +#define DAI_DUPLICATE_WR_MASK 0x1 +#define DAI_DUPLICATE_WR_MASK_SFT (0x1 << 10) +#define DAI_MONO_SFT 8 +#define DAI_MONO_MASK 0x1 +#define DAI_MONO_MASK_SFT (0x1 << 8) +#define DAI_WR_SIGN_SFT 6 +#define DAI_WR_SIGN_MASK 0x1 +#define DAI_WR_SIGN_MASK_SFT (0x1 << 6) +#define DAI_NORMAL_MODE_SFT 5 +#define DAI_NORMAL_MODE_MASK 0x1 +#define DAI_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DAI_HALIGN_SFT 4 +#define DAI_HALIGN_MASK 0x1 +#define DAI_HALIGN_MASK_SFT (0x1 << 4) +#define DAI_HD_MODE_SFT 0 +#define DAI_HD_MODE_MASK 0x3 +#define DAI_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_MOD_DAI_CON0 */ +#define MOD_DAI_MODE_SFT 24 +#define MOD_DAI_MODE_MASK 0x3 +#define MOD_DAI_MODE_MASK_SFT (0x3 << 24) +#define MOD_DAI_SW_CLEAR_BUF_FULL_SFT 15 +#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK 0x1 +#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define MOD_DAI_DUPLICATE_WR_SFT 10 +#define MOD_DAI_DUPLICATE_WR_MASK 0x1 +#define MOD_DAI_DUPLICATE_WR_MASK_SFT (0x1 << 10) +#define MOD_DAI_MONO_SFT 8 +#define MOD_DAI_MONO_MASK 0x1 +#define MOD_DAI_MONO_MASK_SFT (0x1 << 8) +#define MOD_DAI_WR_SIGN_SFT 6 +#define MOD_DAI_WR_SIGN_MASK 0x1 +#define MOD_DAI_WR_SIGN_MASK_SFT (0x1 << 6) +#define MOD_DAI_NORMAL_MODE_SFT 5 +#define MOD_DAI_NORMAL_MODE_MASK 0x1 +#define MOD_DAI_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define MOD_DAI_HALIGN_SFT 4 +#define MOD_DAI_HALIGN_MASK 0x1 +#define MOD_DAI_HALIGN_MASK_SFT (0x1 << 4) +#define MOD_DAI_HD_MODE_SFT 0 +#define MOD_DAI_HD_MODE_MASK 0x3 +#define MOD_DAI_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_DAI2_CON0 */ +#define DAI2_MODE_SFT 24 +#define DAI2_MODE_MASK 0xf +#define DAI2_MODE_MASK_SFT (0xf << 24) +#define DAI2_SW_CLEAR_BUF_FULL_SFT 15 +#define DAI2_SW_CLEAR_BUF_FULL_MASK 0x1 +#define DAI2_SW_CLEAR_BUF_FULL_MASK_SFT (0x1 << 15) +#define DAI2_DUPLICATE_WR_SFT 10 +#define DAI2_DUPLICATE_WR_MASK 0x1 +#define DAI2_DUPLICATE_WR_MASK_SFT (0x1 << 10) +#define DAI2_MONO_SFT 8 +#define DAI2_MONO_MASK 0x1 +#define DAI2_MONO_MASK_SFT (0x1 << 8) +#define DAI2_WR_SIGN_SFT 6 +#define DAI2_WR_SIGN_MASK 0x1 +#define DAI2_WR_SIGN_MASK_SFT (0x1 << 6) +#define DAI2_NORMAL_MODE_SFT 5 +#define DAI2_NORMAL_MODE_MASK 0x1 +#define DAI2_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define DAI2_HALIGN_SFT 4 +#define DAI2_HALIGN_MASK 0x1 +#define DAI2_HALIGN_MASK_SFT (0x1 << 4) +#define DAI2_HD_MODE_SFT 0 +#define DAI2_HD_MODE_MASK 0x3 +#define DAI2_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_MEMIF_CON0 */ +#define CPU_COMPACT_MODE_SFT 2 +#define CPU_COMPACT_MODE_MASK 0x1 +#define CPU_COMPACT_MODE_MASK_SFT (0x1 << 2) +#define CPU_HD_ALIGN_SFT 1 +#define CPU_HD_ALIGN_MASK 0x1 +#define CPU_HD_ALIGN_MASK_SFT (0x1 << 1) +#define SYSRAM_SIGN_SFT 0 +#define SYSRAM_SIGN_MASK 0x1 +#define SYSRAM_SIGN_MASK_SFT (0x1 << 0) + +/* AFE_HDMI_OUT_CON0 */ +#define HDMI_CH_NUM_SFT 24 +#define HDMI_CH_NUM_MASK 0xf +#define HDMI_CH_NUM_MASK_SFT (0xf << 24) +#define HDMI_OUT_MINLEN_SFT 20 +#define HDMI_OUT_MINLEN_MASK 0xf +#define HDMI_OUT_MINLEN_MASK_SFT (0xf << 20) +#define HDMI_OUT_MAXLEN_SFT 16 +#define HDMI_OUT_MAXLEN_MASK 0xf +#define HDMI_OUT_MAXLEN_MASK_SFT (0xf << 16) +#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_SFT 15 +#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_MASK 0x1 +#define HDMI_OUT_SW_CLEAR_BUF_EMPTY_MASK_SFT (0x1 << 15) +#define HDMI_OUT_PBUF_SIZE_SFT 12 +#define HDMI_OUT_PBUF_SIZE_MASK 0x3 +#define HDMI_OUT_PBUF_SIZE_MASK_SFT (0x3 << 12) +#define HDMI_OUT_NORMAL_MODE_SFT 5 +#define HDMI_OUT_NORMAL_MODE_MASK 0x1 +#define HDMI_OUT_NORMAL_MODE_MASK_SFT (0x1 << 5) +#define HDMI_OUT_HALIGN_SFT 4 +#define HDMI_OUT_HALIGN_MASK 0x1 +#define HDMI_OUT_HALIGN_MASK_SFT (0x1 << 4) +#define HDMI_OUT_HD_MODE_SFT 0 +#define HDMI_OUT_HD_MODE_MASK 0x3 +#define HDMI_OUT_HD_MODE_MASK_SFT (0x3 << 0) + +/* AFE_IRQ_MCU_CON0 */ +#define IRQ31_MCU_ON_SFT 31 +#define IRQ31_MCU_ON_MASK 0x1 +#define IRQ31_MCU_ON_MASK_SFT (0x1 << 31) +#define IRQ26_MCU_ON_SFT 26 +#define IRQ26_MCU_ON_MASK 0x1 +#define IRQ26_MCU_ON_MASK_SFT (0x1 << 26) +#define IRQ25_MCU_ON_SFT 25 +#define IRQ25_MCU_ON_MASK 0x1 +#define IRQ25_MCU_ON_MASK_SFT (0x1 << 25) +#define IRQ24_MCU_ON_SFT 24 +#define IRQ24_MCU_ON_MASK 0x1 +#define IRQ24_MCU_ON_MASK_SFT (0x1 << 24) +#define IRQ23_MCU_ON_SFT 23 +#define IRQ23_MCU_ON_MASK 0x1 +#define IRQ23_MCU_ON_MASK_SFT (0x1 << 23) +#define IRQ22_MCU_ON_SFT 22 +#define IRQ22_MCU_ON_MASK 0x1 +#define IRQ22_MCU_ON_MASK_SFT (0x1 << 22) +#define IRQ21_MCU_ON_SFT 21 +#define IRQ21_MCU_ON_MASK 0x1 +#define IRQ21_MCU_ON_MASK_SFT (0x1 << 21) +#define IRQ20_MCU_ON_SFT 20 +#define IRQ20_MCU_ON_MASK 0x1 +#define IRQ20_MCU_ON_MASK_SFT (0x1 << 20) +#define IRQ19_MCU_ON_SFT 19 +#define IRQ19_MCU_ON_MASK 0x1 +#define IRQ19_MCU_ON_MASK_SFT (0x1 << 19) +#define IRQ18_MCU_ON_SFT 18 +#define IRQ18_MCU_ON_MASK 0x1 +#define IRQ18_MCU_ON_MASK_SFT (0x1 << 18) +#define IRQ17_MCU_ON_SFT 17 +#define IRQ17_MCU_ON_MASK 0x1 +#define IRQ17_MCU_ON_MASK_SFT (0x1 << 17) +#define IRQ16_MCU_ON_SFT 16 +#define IRQ16_MCU_ON_MASK 0x1 +#define IRQ16_MCU_ON_MASK_SFT (0x1 << 16) +#define IRQ15_MCU_ON_SFT 15 +#define IRQ15_MCU_ON_MASK 0x1 +#define IRQ15_MCU_ON_MASK_SFT (0x1 << 15) +#define IRQ14_MCU_ON_SFT 14 +#define IRQ14_MCU_ON_MASK 0x1 +#define IRQ14_MCU_ON_MASK_SFT (0x1 << 14) +#define IRQ13_MCU_ON_SFT 13 +#define IRQ13_MCU_ON_MASK 0x1 +#define IRQ13_MCU_ON_MASK_SFT (0x1 << 13) +#define IRQ12_MCU_ON_SFT 12 +#define IRQ12_MCU_ON_MASK 0x1 +#define IRQ12_MCU_ON_MASK_SFT (0x1 << 12) +#define IRQ11_MCU_ON_SFT 11 +#define IRQ11_MCU_ON_MASK 0x1 +#define IRQ11_MCU_ON_MASK_SFT (0x1 << 11) +#define IRQ10_MCU_ON_SFT 10 +#define IRQ10_MCU_ON_MASK 0x1 +#define IRQ10_MCU_ON_MASK_SFT (0x1 << 10) +#define IRQ9_MCU_ON_SFT 9 +#define IRQ9_MCU_ON_MASK 0x1 +#define IRQ9_MCU_ON_MASK_SFT (0x1 << 9) +#define IRQ8_MCU_ON_SFT 8 +#define IRQ8_MCU_ON_MASK 0x1 +#define IRQ8_MCU_ON_MASK_SFT (0x1 << 8) +#define IRQ7_MCU_ON_SFT 7 +#define IRQ7_MCU_ON_MASK 0x1 +#define IRQ7_MCU_ON_MASK_SFT (0x1 << 7) +#define IRQ6_MCU_ON_SFT 6 +#define IRQ6_MCU_ON_MASK 0x1 +#define IRQ6_MCU_ON_MASK_SFT (0x1 << 6) +#define IRQ5_MCU_ON_SFT 5 +#define IRQ5_MCU_ON_MASK 0x1 +#define IRQ5_MCU_ON_MASK_SFT (0x1 << 5) +#define IRQ4_MCU_ON_SFT 4 +#define IRQ4_MCU_ON_MASK 0x1 +#define IRQ4_MCU_ON_MASK_SFT (0x1 << 4) +#define IRQ3_MCU_ON_SFT 3 +#define IRQ3_MCU_ON_MASK 0x1 +#define IRQ3_MCU_ON_MASK_SFT (0x1 << 3) +#define IRQ2_MCU_ON_SFT 2 +#define IRQ2_MCU_ON_MASK 0x1 +#define IRQ2_MCU_ON_MASK_SFT (0x1 << 2) +#define IRQ1_MCU_ON_SFT 1 +#define IRQ1_MCU_ON_MASK 0x1 +#define IRQ1_MCU_ON_MASK_SFT (0x1 << 1) +#define IRQ0_MCU_ON_SFT 0 +#define IRQ0_MCU_ON_MASK 0x1 +#define IRQ0_MCU_ON_MASK_SFT (0x1 << 0) + +/* AFE_IRQ_MCU_CON1 */ +#define IRQ7_MCU_MODE_SFT 28 +#define IRQ7_MCU_MODE_MASK 0xf +#define IRQ7_MCU_MODE_MASK_SFT (0xf << 28) +#define IRQ6_MCU_MODE_SFT 24 +#define IRQ6_MCU_MODE_MASK 0xf +#define IRQ6_MCU_MODE_MASK_SFT (0xf << 24) +#define IRQ5_MCU_MODE_SFT 20 +#define IRQ5_MCU_MODE_MASK 0xf +#define IRQ5_MCU_MODE_MASK_SFT (0xf << 20) +#define IRQ4_MCU_MODE_SFT 16 +#define IRQ4_MCU_MODE_MASK 0xf +#define IRQ4_MCU_MODE_MASK_SFT (0xf << 16) +#define IRQ3_MCU_MODE_SFT 12 +#define IRQ3_MCU_MODE_MASK 0xf +#define IRQ3_MCU_MODE_MASK_SFT (0xf << 12) +#define IRQ2_MCU_MODE_SFT 8 +#define IRQ2_MCU_MODE_MASK 0xf +#define IRQ2_MCU_MODE_MASK_SFT (0xf << 8) +#define IRQ1_MCU_MODE_SFT 4 +#define IRQ1_MCU_MODE_MASK 0xf +#define IRQ1_MCU_MODE_MASK_SFT (0xf << 4) +#define IRQ0_MCU_MODE_SFT 0 +#define IRQ0_MCU_MODE_MASK 0xf +#define IRQ0_MCU_MODE_MASK_SFT (0xf << 0) + +/* AFE_IRQ_MCU_CON2 */ +#define IRQ15_MCU_MODE_SFT 28 +#define IRQ15_MCU_MODE_MASK 0xf +#define IRQ15_MCU_MODE_MASK_SFT (0xf << 28) +#define IRQ14_MCU_MODE_SFT 24 +#define IRQ14_MCU_MODE_MASK 0xf +#define IRQ14_MCU_MODE_MASK_SFT (0xf << 24) +#define IRQ13_MCU_MODE_SFT 20 +#define IRQ13_MCU_MODE_MASK 0xf +#define IRQ13_MCU_MODE_MASK_SFT (0xf << 20) +#define IRQ12_MCU_MODE_SFT 16 +#define IRQ12_MCU_MODE_MASK 0xf +#define IRQ12_MCU_MODE_MASK_SFT (0xf << 16) +#define IRQ11_MCU_MODE_SFT 12 +#define IRQ11_MCU_MODE_MASK 0xf +#define IRQ11_MCU_MODE_MASK_SFT (0xf << 12) +#define IRQ10_MCU_MODE_SFT 8 +#define IRQ10_MCU_MODE_MASK 0xf +#define IRQ10_MCU_MODE_MASK_SFT (0xf << 8) +#define IRQ9_MCU_MODE_SFT 4 +#define IRQ9_MCU_MODE_MASK 0xf +#define IRQ9_MCU_MODE_MASK_SFT (0xf << 4) +#define IRQ8_MCU_MODE_SFT 0 +#define IRQ8_MCU_MODE_MASK 0xf +#define IRQ8_MCU_MODE_MASK_SFT (0xf << 0) + +/* AFE_IRQ_MCU_CON3 */ +#define IRQ23_MCU_MODE_SFT 28 +#define IRQ23_MCU_MODE_MASK 0xf +#define IRQ23_MCU_MODE_MASK_SFT (0xf << 28) +#define IRQ22_MCU_MODE_SFT 24 +#define IRQ22_MCU_MODE_MASK 0xf +#define IRQ22_MCU_MODE_MASK_SFT (0xf << 24) +#define IRQ21_MCU_MODE_SFT 20 +#define IRQ21_MCU_MODE_MASK 0xf +#define IRQ21_MCU_MODE_MASK_SFT (0xf << 20) +#define IRQ20_MCU_MODE_SFT 16 +#define IRQ20_MCU_MODE_MASK 0xf +#define IRQ20_MCU_MODE_MASK_SFT (0xf << 16) +#define IRQ19_MCU_MODE_SFT 12 +#define IRQ19_MCU_MODE_MASK 0xf +#define IRQ19_MCU_MODE_MASK_SFT (0xf << 12) +#define IRQ18_MCU_MODE_SFT 8 +#define IRQ18_MCU_MODE_MASK 0xf +#define IRQ18_MCU_MODE_MASK_SFT (0xf << 8) +#define IRQ17_MCU_MODE_SFT 4 +#define IRQ17_MCU_MODE_MASK 0xf +#define IRQ17_MCU_MODE_MASK_SFT (0xf << 4) +#define IRQ16_MCU_MODE_SFT 0 +#define IRQ16_MCU_MODE_MASK 0xf +#define IRQ16_MCU_MODE_MASK_SFT (0xf << 0) + +/* AFE_IRQ_MCU_CON4 */ +#define IRQ26_MCU_MODE_SFT 8 +#define IRQ26_MCU_MODE_MASK 0xf +#define IRQ26_MCU_MODE_MASK_SFT (0xf << 8) +#define IRQ25_MCU_MODE_SFT 4 +#define IRQ25_MCU_MODE_MASK 0xf +#define IRQ25_MCU_MODE_MASK_SFT (0xf << 4) +#define IRQ24_MCU_MODE_SFT 0 +#define IRQ24_MCU_MODE_MASK 0xf +#define IRQ24_MCU_MODE_MASK_SFT (0xf << 0) + +/* AFE_IRQ_MCU_CLR */ +#define IRQ31_MCU_CLR_SFT 31 +#define IRQ31_MCU_CLR_MASK 0x1 +#define IRQ31_MCU_CLR_MASK_SFT (0x1 << 31) +#define IRQ26_MCU_CLR_SFT 26 +#define IRQ26_MCU_CLR_MASK 0x1 +#define IRQ26_MCU_CLR_MASK_SFT (0x1 << 26) +#define IRQ25_MCU_CLR_SFT 25 +#define IRQ25_MCU_CLR_MASK 0x1 +#define IRQ25_MCU_CLR_MASK_SFT (0x1 << 25) +#define IRQ24_MCU_CLR_SFT 24 +#define IRQ24_MCU_CLR_MASK 0x1 +#define IRQ24_MCU_CLR_MASK_SFT (0x1 << 24) +#define IRQ23_MCU_CLR_SFT 23 +#define IRQ23_MCU_CLR_MASK 0x1 +#define IRQ23_MCU_CLR_MASK_SFT (0x1 << 23) +#define IRQ22_MCU_CLR_SFT 22 +#define IRQ22_MCU_CLR_MASK 0x1 +#define IRQ22_MCU_CLR_MASK_SFT (0x1 << 22) +#define IRQ21_MCU_CLR_SFT 21 +#define IRQ21_MCU_CLR_MASK 0x1 +#define IRQ21_MCU_CLR_MASK_SFT (0x1 << 21) +#define IRQ20_MCU_CLR_SFT 20 +#define IRQ20_MCU_CLR_MASK 0x1 +#define IRQ20_MCU_CLR_MASK_SFT (0x1 << 20) +#define IRQ19_MCU_CLR_SFT 19 +#define IRQ19_MCU_CLR_MASK 0x1 +#define IRQ19_MCU_CLR_MASK_SFT (0x1 << 19) +#define IRQ18_MCU_CLR_SFT 18 +#define IRQ18_MCU_CLR_MASK 0x1 +#define IRQ18_MCU_CLR_MASK_SFT (0x1 << 18) +#define IRQ17_MCU_CLR_SFT 17 +#define IRQ17_MCU_CLR_MASK 0x1 +#define IRQ17_MCU_CLR_MASK_SFT (0x1 << 17) +#define IRQ16_MCU_CLR_SFT 16 +#define IRQ16_MCU_CLR_MASK 0x1 +#define IRQ16_MCU_CLR_MASK_SFT (0x1 << 16) +#define IRQ15_MCU_CLR_SFT 15 +#define IRQ15_MCU_CLR_MASK 0x1 +#define IRQ15_MCU_CLR_MASK_SFT (0x1 << 15) +#define IRQ14_MCU_CLR_SFT 14 +#define IRQ14_MCU_CLR_MASK 0x1 +#define IRQ14_MCU_CLR_MASK_SFT (0x1 << 14) +#define IRQ13_MCU_CLR_SFT 13 +#define IRQ13_MCU_CLR_MASK 0x1 +#define IRQ13_MCU_CLR_MASK_SFT (0x1 << 13) +#define IRQ12_MCU_CLR_SFT 12 +#define IRQ12_MCU_CLR_MASK 0x1 +#define IRQ12_MCU_CLR_MASK_SFT (0x1 << 12) +#define IRQ11_MCU_CLR_SFT 11 +#define IRQ11_MCU_CLR_MASK 0x1 +#define IRQ11_MCU_CLR_MASK_SFT (0x1 << 11) +#define IRQ10_MCU_CLR_SFT 10 +#define IRQ10_MCU_CLR_MASK 0x1 +#define IRQ10_MCU_CLR_MASK_SFT (0x1 << 10) +#define IRQ9_MCU_CLR_SFT 9 +#define IRQ9_MCU_CLR_MASK 0x1 +#define IRQ9_MCU_CLR_MASK_SFT (0x1 << 9) +#define IRQ8_MCU_CLR_SFT 8 +#define IRQ8_MCU_CLR_MASK 0x1 +#define IRQ8_MCU_CLR_MASK_SFT (0x1 << 8) +#define IRQ7_MCU_CLR_SFT 7 +#define IRQ7_MCU_CLR_MASK 0x1 +#define IRQ7_MCU_CLR_MASK_SFT (0x1 << 7) +#define IRQ6_MCU_CLR_SFT 6 +#define IRQ6_MCU_CLR_MASK 0x1 +#define IRQ6_MCU_CLR_MASK_SFT (0x1 << 6) +#define IRQ5_MCU_CLR_SFT 5 +#define IRQ5_MCU_CLR_MASK 0x1 +#define IRQ5_MCU_CLR_MASK_SFT (0x1 << 5) +#define IRQ4_MCU_CLR_SFT 4 +#define IRQ4_MCU_CLR_MASK 0x1 +#define IRQ4_MCU_CLR_MASK_SFT (0x1 << 4) +#define IRQ3_MCU_CLR_SFT 3 +#define IRQ3_MCU_CLR_MASK 0x1 +#define IRQ3_MCU_CLR_MASK_SFT (0x1 << 3) +#define IRQ2_MCU_CLR_SFT 2 +#define IRQ2_MCU_CLR_MASK 0x1 +#define IRQ2_MCU_CLR_MASK_SFT (0x1 << 2) +#define IRQ1_MCU_CLR_SFT 1 +#define IRQ1_MCU_CLR_MASK 0x1 +#define IRQ1_MCU_CLR_MASK_SFT (0x1 << 1) +#define IRQ0_MCU_CLR_SFT 0 +#define IRQ0_MCU_CLR_MASK 0x1 +#define IRQ0_MCU_CLR_MASK_SFT (0x1 << 0) + +/* AFE_IRQ_MCU_EN */ +#define IRQ31_MCU_EN_SFT 31 +#define IRQ30_MCU_EN_SFT 30 +#define IRQ29_MCU_EN_SFT 29 +#define IRQ28_MCU_EN_SFT 28 +#define IRQ27_MCU_EN_SFT 27 +#define IRQ26_MCU_EN_SFT 26 +#define IRQ25_MCU_EN_SFT 25 +#define IRQ24_MCU_EN_SFT 24 +#define IRQ23_MCU_EN_SFT 23 +#define IRQ22_MCU_EN_SFT 22 +#define IRQ21_MCU_EN_SFT 21 +#define IRQ20_MCU_EN_SFT 20 +#define IRQ19_MCU_EN_SFT 19 +#define IRQ18_MCU_EN_SFT 18 +#define IRQ17_MCU_EN_SFT 17 +#define IRQ16_MCU_EN_SFT 16 +#define IRQ15_MCU_EN_SFT 15 +#define IRQ14_MCU_EN_SFT 14 +#define IRQ13_MCU_EN_SFT 13 +#define IRQ12_MCU_EN_SFT 12 +#define IRQ11_MCU_EN_SFT 11 +#define IRQ10_MCU_EN_SFT 10 +#define IRQ9_MCU_EN_SFT 9 +#define IRQ8_MCU_EN_SFT 8 +#define IRQ7_MCU_EN_SFT 7 +#define IRQ6_MCU_EN_SFT 6 +#define IRQ5_MCU_EN_SFT 5 +#define IRQ4_MCU_EN_SFT 4 +#define IRQ3_MCU_EN_SFT 3 +#define IRQ2_MCU_EN_SFT 2 +#define IRQ1_MCU_EN_SFT 1 +#define IRQ0_MCU_EN_SFT 0 + +/* AFE_IRQ_MCU_SCP_EN */ +#define IRQ31_MCU_SCP_EN_SFT 31 +#define IRQ30_MCU_SCP_EN_SFT 30 +#define IRQ29_MCU_SCP_EN_SFT 29 +#define IRQ28_MCU_SCP_EN_SFT 28 +#define IRQ27_MCU_SCP_EN_SFT 27 +#define IRQ26_MCU_SCP_EN_SFT 26 +#define IRQ25_MCU_SCP_EN_SFT 25 +#define IRQ24_MCU_SCP_EN_SFT 24 +#define IRQ23_MCU_SCP_EN_SFT 23 +#define IRQ22_MCU_SCP_EN_SFT 22 +#define IRQ21_MCU_SCP_EN_SFT 21 +#define IRQ20_MCU_SCP_EN_SFT 20 +#define IRQ19_MCU_SCP_EN_SFT 19 +#define IRQ18_MCU_SCP_EN_SFT 18 +#define IRQ17_MCU_SCP_EN_SFT 17 +#define IRQ16_MCU_SCP_EN_SFT 16 +#define IRQ15_MCU_SCP_EN_SFT 15 +#define IRQ14_MCU_SCP_EN_SFT 14 +#define IRQ13_MCU_SCP_EN_SFT 13 +#define IRQ12_MCU_SCP_EN_SFT 12 +#define IRQ11_MCU_SCP_EN_SFT 11 +#define IRQ10_MCU_SCP_EN_SFT 10 +#define IRQ9_MCU_SCP_EN_SFT 9 +#define IRQ8_MCU_SCP_EN_SFT 8 +#define IRQ7_MCU_SCP_EN_SFT 7 +#define IRQ6_MCU_SCP_EN_SFT 6 +#define IRQ5_MCU_SCP_EN_SFT 5 +#define IRQ4_MCU_SCP_EN_SFT 4 +#define IRQ3_MCU_SCP_EN_SFT 3 +#define IRQ2_MCU_SCP_EN_SFT 2 +#define IRQ1_MCU_SCP_EN_SFT 1 +#define IRQ0_MCU_SCP_EN_SFT 0 + +/* AFE_TDM_CON1 */ +#define TDM_EN_SFT 0 +#define TDM_EN_MASK 0x1 +#define TDM_EN_MASK_SFT (0x1 << 0) +#define BCK_INVERSE_SFT 1 +#define BCK_INVERSE_MASK 0x1 +#define BCK_INVERSE_MASK_SFT (0x1 << 1) +#define LRCK_INVERSE_SFT 2 +#define LRCK_INVERSE_MASK 0x1 +#define LRCK_INVERSE_MASK_SFT (0x1 << 2) +#define DELAY_DATA_SFT 3 +#define DELAY_DATA_MASK 0x1 +#define DELAY_DATA_MASK_SFT (0x1 << 3) +#define LEFT_ALIGN_SFT 4 +#define LEFT_ALIGN_MASK 0x1 +#define LEFT_ALIGN_MASK_SFT (0x1 << 4) +#define WLEN_SFT 8 +#define WLEN_MASK 0x3 +#define WLEN_MASK_SFT (0x3 << 8) +#define CHANNEL_NUM_SFT 10 +#define CHANNEL_NUM_MASK 0x3 +#define CHANNEL_NUM_MASK_SFT (0x3 << 10) +#define CHANNEL_BCK_CYCLES_SFT 12 +#define CHANNEL_BCK_CYCLES_MASK 0x3 +#define CHANNEL_BCK_CYCLES_MASK_SFT (0x3 << 12) +#define DAC_BIT_NUM_SFT 16 +#define DAC_BIT_NUM_MASK 0x1f +#define DAC_BIT_NUM_MASK_SFT (0x1f << 16) +#define LRCK_TDM_WIDTH_SFT 24 +#define LRCK_TDM_WIDTH_MASK 0xff +#define LRCK_TDM_WIDTH_MASK_SFT (0xff << 24) + +/* AFE_TDM_CON2 */ +#define ST_CH_PAIR_SOUT0_SFT 0 +#define ST_CH_PAIR_SOUT0_MASK 0x7 +#define ST_CH_PAIR_SOUT0_MASK_SFT (0x7 << 0) +#define ST_CH_PAIR_SOUT1_SFT 4 +#define ST_CH_PAIR_SOUT1_MASK 0x7 +#define ST_CH_PAIR_SOUT1_MASK_SFT (0x7 << 4) +#define ST_CH_PAIR_SOUT2_SFT 8 +#define ST_CH_PAIR_SOUT2_MASK 0x7 +#define ST_CH_PAIR_SOUT2_MASK_SFT (0x7 << 8) +#define ST_CH_PAIR_SOUT3_SFT 12 +#define ST_CH_PAIR_SOUT3_MASK 0x7 +#define ST_CH_PAIR_SOUT3_MASK_SFT (0x7 << 12) +#define TDM_FIX_VALUE_SEL_SFT 16 +#define TDM_FIX_VALUE_SEL_MASK 0x1 +#define TDM_FIX_VALUE_SEL_MASK_SFT (0x1 << 16) +#define TDM_I2S_LOOPBACK_SFT 20 +#define TDM_I2S_LOOPBACK_MASK 0x1 +#define TDM_I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define TDM_I2S_LOOPBACK_CH_SFT 21 +#define TDM_I2S_LOOPBACK_CH_MASK 0x3 +#define TDM_I2S_LOOPBACK_CH_MASK_SFT (0x3 << 21) +#define TDM_FIX_VALUE_SFT 24 +#define TDM_FIX_VALUE_MASK 0xff +#define TDM_FIX_VALUE_MASK_SFT (0xff << 24) + +/* AFE_HDMI_CONN0 */ +#define HDMI_O_7_SFT 21 +#define HDMI_O_7_MASK 0x7 +#define HDMI_O_7_MASK_SFT (0x7 << 21) +#define HDMI_O_6_SFT 18 +#define HDMI_O_6_MASK 0x7 +#define HDMI_O_6_MASK_SFT (0x7 << 18) +#define HDMI_O_5_SFT 15 +#define HDMI_O_5_MASK 0x7 +#define HDMI_O_5_MASK_SFT (0x7 << 15) +#define HDMI_O_4_SFT 12 +#define HDMI_O_4_MASK 0x7 +#define HDMI_O_4_MASK_SFT (0x7 << 12) +#define HDMI_O_3_SFT 9 +#define HDMI_O_3_MASK 0x7 +#define HDMI_O_3_MASK_SFT (0x7 << 9) +#define HDMI_O_2_SFT 6 +#define HDMI_O_2_MASK 0x7 +#define HDMI_O_2_MASK_SFT (0x7 << 6) +#define HDMI_O_1_SFT 3 +#define HDMI_O_1_MASK 0x7 +#define HDMI_O_1_MASK_SFT (0x7 << 3) +#define HDMI_O_0_SFT 0 +#define HDMI_O_0_MASK 0x7 +#define HDMI_O_0_MASK_SFT (0x7 << 0) + +/* AFE_AUD_PAD_TOP */ +#define AUD_PAD_TOP_MON_SFT 15 +#define AUD_PAD_TOP_MON_MASK 0x1ffff +#define AUD_PAD_TOP_MON_MASK_SFT (0x1ffff << 15) +#define AUD_PAD_TOP_FIFO_RSP_SFT 4 +#define AUD_PAD_TOP_FIFO_RSP_MASK 0xf +#define AUD_PAD_TOP_FIFO_RSP_MASK_SFT (0xf << 4) +#define RG_RX_PROTOCOL2_SFT 3 +#define RG_RX_PROTOCOL2_MASK 0x1 +#define RG_RX_PROTOCOL2_MASK_SFT (0x1 << 3) +#define RESERVDED_01_SFT 1 +#define RESERVDED_01_MASK 0x3 +#define RESERVDED_01_MASK_SFT (0x3 << 1) +#define RG_RX_FIFO_ON_SFT 0 +#define RG_RX_FIFO_ON_MASK 0x1 +#define RG_RX_FIFO_ON_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_SYNCWORD_CFG */ +#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT 23 +#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK 0x1 +#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK_SFT (0x1 << 23) + +/* AFE_ADDA_MTKAIF_RX_CFG0 */ +#define MTKAIF_RXIF_VOICE_MODE_SFT 20 +#define MTKAIF_RXIF_VOICE_MODE_MASK 0xf +#define MTKAIF_RXIF_VOICE_MODE_MASK_SFT (0xf << 20) +#define MTKAIF_RXIF_DETECT_ON_SFT 16 +#define MTKAIF_RXIF_DETECT_ON_MASK 0x1 +#define MTKAIF_RXIF_DETECT_ON_MASK_SFT (0x1 << 16) +#define MTKAIF_RXIF_DATA_BIT_SFT 8 +#define MTKAIF_RXIF_DATA_BIT_MASK 0x7 +#define MTKAIF_RXIF_DATA_BIT_MASK_SFT (0x7 << 8) +#define MTKAIF_RXIF_FIFO_RSP_SFT 4 +#define MTKAIF_RXIF_FIFO_RSP_MASK 0x7 +#define MTKAIF_RXIF_FIFO_RSP_MASK_SFT (0x7 << 4) +#define MTKAIF_RXIF_DATA_MODE_SFT 0 +#define MTKAIF_RXIF_DATA_MODE_MASK 0x1 +#define MTKAIF_RXIF_DATA_MODE_MASK_SFT (0x1 << 0) + +/* GENERAL_ASRC_MODE */ +#define GENERAL2_ASRCOUT_MODE_SFT 12 +#define GENERAL2_ASRCOUT_MODE_MASK 0xf +#define GENERAL2_ASRCOUT_MODE_MASK_SFT (0xf << 12) +#define GENERAL2_ASRCIN_MODE_SFT 8 +#define GENERAL2_ASRCIN_MODE_MASK 0xf +#define GENERAL2_ASRCIN_MODE_MASK_SFT (0xf << 8) +#define GENERAL1_ASRCOUT_MODE_SFT 4 +#define GENERAL1_ASRCOUT_MODE_MASK 0xf +#define GENERAL1_ASRCOUT_MODE_MASK_SFT (0xf << 4) +#define GENERAL1_ASRCIN_MODE_SFT 0 +#define GENERAL1_ASRCIN_MODE_MASK 0xf +#define GENERAL1_ASRCIN_MODE_MASK_SFT (0xf << 0) + +/* GENERAL_ASRC_EN_ON */ +#define GENERAL2_ASRC_EN_ON_SFT 1 +#define GENERAL2_ASRC_EN_ON_MASK 0x1 +#define GENERAL2_ASRC_EN_ON_MASK_SFT (0x1 << 1) +#define GENERAL1_ASRC_EN_ON_SFT 0 +#define GENERAL1_ASRC_EN_ON_MASK 0x1 +#define GENERAL1_ASRC_EN_ON_MASK_SFT (0x1 << 0) + +/* AFE_GENERAL1_ASRC_2CH_CON0 */ +#define G_SRC_CHSET_STR_CLR_SFT 4 +#define G_SRC_CHSET_STR_CLR_MASK 0x1 +#define G_SRC_CHSET_STR_CLR_MASK_SFT (0x1 << 4) +#define G_SRC_CHSET_ON_SFT 2 +#define G_SRC_CHSET_ON_MASK 0x1 +#define G_SRC_CHSET_ON_MASK_SFT (0x1 << 2) +#define G_SRC_COEFF_SRAM_CTRL_SFT 1 +#define G_SRC_COEFF_SRAM_CTRL_MASK 0x1 +#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT (0x1 << 1) +#define G_SRC_ASM_ON_SFT 0 +#define G_SRC_ASM_ON_MASK 0x1 +#define G_SRC_ASM_ON_MASK_SFT (0x1 << 0) + +/* AFE_GENERAL1_ASRC_2CH_CON3 */ +#define G_SRC_ASM_FREQ_4_SFT 0 +#define G_SRC_ASM_FREQ_4_MASK 0xffffff +#define G_SRC_ASM_FREQ_4_MASK_SFT (0xffffff << 0) + +/* AFE_GENERAL1_ASRC_2CH_CON4 */ +#define G_SRC_ASM_FREQ_5_SFT 0 +#define G_SRC_ASM_FREQ_5_MASK 0xffffff +#define G_SRC_ASM_FREQ_5_MASK_SFT (0xffffff << 0) + +/* AFE_GENERAL1_ASRC_2CH_CON13 */ +#define G_SRC_COEFF_SRAM_ADR_SFT 0 +#define G_SRC_COEFF_SRAM_ADR_MASK 0x3f +#define G_SRC_COEFF_SRAM_ADR_MASK_SFT (0x3f << 0) + +/* AFE_GENERAL1_ASRC_2CH_CON2 */ +#define G_SRC_CHSET_O16BIT_SFT 19 +#define G_SRC_CHSET_O16BIT_MASK 0x1 +#define G_SRC_CHSET_O16BIT_MASK_SFT (0x1 << 19) +#define G_SRC_CHSET_CLR_IIR_HISTORY_SFT 17 +#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK 0x1 +#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK_SFT (0x1 << 17) +#define G_SRC_CHSET_IS_MONO_SFT 16 +#define G_SRC_CHSET_IS_MONO_MASK 0x1 +#define G_SRC_CHSET_IS_MONO_MASK_SFT (0x1 << 16) +#define G_SRC_CHSET_IIR_EN_SFT 11 +#define G_SRC_CHSET_IIR_EN_MASK 0x1 +#define G_SRC_CHSET_IIR_EN_MASK_SFT (0x1 << 11) +#define G_SRC_CHSET_IIR_STAGE_SFT 8 +#define G_SRC_CHSET_IIR_STAGE_MASK 0x7 +#define G_SRC_CHSET_IIR_STAGE_MASK_SFT (0x7 << 8) +#define G_SRC_CHSET_STR_CLR_RU_SFT 5 +#define G_SRC_CHSET_STR_CLR_RU_MASK 0x1 +#define G_SRC_CHSET_STR_CLR_RU_MASK_SFT (0x1 << 5) +#define G_SRC_CHSET_ON_SFT 2 +#define G_SRC_CHSET_ON_MASK 0x1 +#define G_SRC_CHSET_ON_MASK_SFT (0x1 << 2) +#define G_SRC_COEFF_SRAM_CTRL_SFT 1 +#define G_SRC_COEFF_SRAM_CTRL_MASK 0x1 +#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT (0x1 << 1) +#define G_SRC_ASM_ON_SFT 0 +#define G_SRC_ASM_ON_MASK 0x1 +#define G_SRC_ASM_ON_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_DL_SDM_AUTO_RESET_CON */ +#define ADDA_SDM_AUTO_RESET_ONOFF_SFT 31 +#define ADDA_SDM_AUTO_RESET_ONOFF_MASK 0x1 +#define ADDA_SDM_AUTO_RESET_ONOFF_MASK_SFT (0x1 << 31) + +/* AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON */ +#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_SFT 31 +#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK 0x1 +#define ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK_SFT (0x1 << 31) + +/* AFE_TINY_CONN0 */ +#define O_3_CFG_SFT 24 +#define O_3_CFG_MASK 0x1f +#define O_3_CFG_MASK_SFT (0x1f << 24) +#define O_2_CFG_SFT 16 +#define O_2_CFG_MASK 0x1f +#define O_2_CFG_MASK_SFT (0x1f << 16) +#define O_1_CFG_SFT 8 +#define O_1_CFG_MASK 0x1f +#define O_1_CFG_MASK_SFT (0x1f << 8) +#define O_0_CFG_SFT 0 +#define O_0_CFG_MASK 0x1f +#define O_0_CFG_MASK_SFT (0x1f << 0) + +/* AFE_TINY_CONN5 */ +#define O_23_CFG_SFT 24 +#define O_23_CFG_MASK 0x1f +#define O_23_CFG_MASK_SFT (0x1f << 24) +#define O_22_CFG_SFT 16 +#define O_22_CFG_MASK 0x1f +#define O_22_CFG_MASK_SFT (0x1f << 16) +#define O_21_CFG_SFT 8 +#define O_21_CFG_MASK 0x1f +#define O_21_CFG_MASK_SFT (0x1f << 8) +#define O_20_CFG_SFT 0 +#define O_20_CFG_MASK 0x1f +#define O_20_CFG_MASK_SFT (0x1f << 0) + +/* AFE_MEMIF_CONN */ +#define VUL6_USE_TINY_SFT 8 +#define VUL6_USE_TINY_MASK 1 +#define VUL6_USE_TINY_MASK_SFT (0x1 << 8) +#define VUL5_USE_TINY_SFT 7 +#define VUL5_USE_TINY_MASK 1 +#define VUL5_USE_TINY_MASK_SFT (0x1 << 7) +#define VUL4_USE_TINY_SFT 6 +#define VUL4_USE_TINY_MASK 1 +#define VUL4_USE_TINY_MASK_SFT (0x1 << 6) +#define VUL3_USE_TINY_SFT 5 +#define VUL3_USE_TINY_MASK 1 +#define VUL3_USE_TINY_MASK_SFT (0x1 << 5) +#define AWB2_USE_TINY_SFT 4 +#define AWB2_USE_TINY_MASK 1 +#define AWB2_USE_TINY_MASK_SFT (0x1 << 4) +#define AWB_USE_TINY_SFT 3 +#define AWB_USE_TINY_MASK 1 +#define AWB_USE_TINY_MASK_SFT (0x1 << 3) +#define VUL12_USE_TINY_SFT 2 +#define VUL12_USE_TINY_MASK 1 +#define VUL12_USE_TINY_MASK_SFT (0x1 << 2) +#define VUL2_USE_TINY_SFT 1 +#define VUL2_USE_TINY_MASK 1 +#define VUL2_USE_TINY_MASK_SFT (0x1 << 1) +#define VUL1_USE_TINY_SFT 0 +#define VUL1_USE_TINY_MASK 1 +#define VUL1_USE_TINY_MASK_SFT (0x1 << 0) + +/* AFE_ASRC_2CH_CON0 */ +#define CON0_CHSET_STR_CLR_SFT 4 +#define CON0_CHSET_STR_CLR_MASK 1 +#define CON0_CHSET_STR_CLR_MASK_SFT (0x1 << 4) +#define CON0_ASM_ON_SFT 0 +#define CON0_ASM_ON_MASK 1 +#define CON0_ASM_ON_MASK_SFT (0x1 << 0) + +/* AFE_ASRC_2CH_CON5 */ +#define CALI_EN_SFT 0 +#define CALI_EN_MASK 1 +#define CALI_EN_MASK_SFT (0x1 << 0) + +#define AUDIO_TOP_CON0 0x0000 +#define AUDIO_TOP_CON1 0x0004 +#define AUDIO_TOP_CON2 0x0008 +#define AUDIO_TOP_CON3 0x000c +#define AFE_DAC_CON0 0x0010 +#define AFE_I2S_CON 0x0018 +#define AFE_CONN0 0x0020 +#define AFE_CONN1 0x0024 +#define AFE_CONN2 0x0028 +#define AFE_CONN3 0x002c +#define AFE_CONN4 0x0030 +#define AFE_I2S_CON1 0x0034 +#define AFE_I2S_CON2 0x0038 +#define AFE_I2S_CON3 0x0040 +#define AFE_CONN5 0x0044 +#define AFE_CONN_24BIT 0x0048 +#define AFE_DL1_CON0 0x004c +#define AFE_DL1_BASE_MSB 0x0050 +#define AFE_DL1_BASE 0x0054 +#define AFE_DL1_CUR_MSB 0x0058 +#define AFE_DL1_CUR 0x005c +#define AFE_DL1_END_MSB 0x0060 +#define AFE_DL1_END 0x0064 +#define AFE_DL2_CON0 0x0068 +#define AFE_DL2_BASE_MSB 0x006c +#define AFE_DL2_BASE 0x0070 +#define AFE_DL2_CUR_MSB 0x0074 +#define AFE_DL2_CUR 0x0078 +#define AFE_DL2_END_MSB 0x007c +#define AFE_DL2_END 0x0080 +#define AFE_DL3_CON0 0x0084 +#define AFE_DL3_BASE_MSB 0x0088 +#define AFE_DL3_BASE 0x008c +#define AFE_DL3_CUR_MSB 0x0090 +#define AFE_DL3_CUR 0x0094 +#define AFE_DL3_END_MSB 0x0098 +#define AFE_DL3_END 0x009c +#define AFE_CONN6 0x00bc +#define AFE_DL4_CON0 0x00cc +#define AFE_DL4_BASE_MSB 0x00d0 +#define AFE_DL4_BASE 0x00d4 +#define AFE_DL4_CUR_MSB 0x00d8 +#define AFE_DL4_CUR 0x00dc +#define AFE_DL4_END_MSB 0x00e0 +#define AFE_DL4_END 0x00e4 +#define AFE_DL12_CON0 0x00e8 +#define AFE_DL12_BASE_MSB 0x00ec +#define AFE_DL12_BASE 0x00f0 +#define AFE_DL12_CUR_MSB 0x00f4 +#define AFE_DL12_CUR 0x00f8 +#define AFE_DL12_END_MSB 0x00fc +#define AFE_DL12_END 0x0100 +#define AFE_ADDA_DL_SRC2_CON0 0x0108 +#define AFE_ADDA_DL_SRC2_CON1 0x010c +#define AFE_ADDA_UL_SRC_CON0 0x0114 +#define AFE_ADDA_UL_SRC_CON1 0x0118 +#define AFE_ADDA_TOP_CON0 0x0120 +#define AFE_ADDA_UL_DL_CON0 0x0124 +#define AFE_ADDA_SRC_DEBUG 0x012c +#define AFE_ADDA_SRC_DEBUG_MON0 0x0130 +#define AFE_ADDA_SRC_DEBUG_MON1 0x0134 +#define AFE_ADDA_UL_SRC_MON0 0x0148 +#define AFE_ADDA_UL_SRC_MON1 0x014c +#define AFE_SECURE_CON0 0x0150 +#define AFE_SRAM_BOUND 0x0154 +#define AFE_SECURE_CON1 0x0158 +#define AFE_SECURE_CONN0 0x015c +#define AFE_VUL_CON0 0x0170 +#define AFE_VUL_BASE_MSB 0x0174 +#define AFE_VUL_BASE 0x0178 +#define AFE_VUL_CUR_MSB 0x017c +#define AFE_VUL_CUR 0x0180 +#define AFE_VUL_END_MSB 0x0184 +#define AFE_VUL_END 0x0188 +#define AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON 0x018c +#define AFE_ADDA_3RD_DAC_DL_SRC2_CON0 0x0190 +#define AFE_ADDA_3RD_DAC_DL_SRC2_CON1 0x0194 +#define AFE_ADDA_3RD_DAC_PREDIS_CON0 0x01a0 +#define AFE_ADDA_3RD_DAC_PREDIS_CON1 0x01a4 +#define AFE_ADDA_3RD_DAC_PREDIS_CON2 0x01a8 +#define AFE_ADDA_3RD_DAC_PREDIS_CON3 0x01ac +#define AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON 0x01b0 +#define AFE_ADDA_3RD_DAC_DL_SDM_TEST 0x01b4 +#define AFE_ADDA_3RD_DAC_DL_DC_COMP_CFG0 0x01b8 +#define AFE_ADDA_3RD_DAC_DL_DC_COMP_CFG1 0x01bc +#define AFE_ADDA_3RD_DAC_DL_SDM_FIFO_MON 0x01c0 +#define AFE_ADDA_3RD_DAC_DL_SRC_LCH_MON 0x01c4 +#define AFE_ADDA_3RD_DAC_DL_SRC_RCH_MON 0x01c8 +#define AFE_ADDA_3RD_DAC_DL_SDM_OUT_MON 0x01cc +#define AFE_SIDETONE_DEBUG 0x01d0 +#define AFE_SIDETONE_MON 0x01d4 +#define AFE_ADDA_3RD_DAC_DL_SDM_DITHER_CON 0x01d8 +#define AFE_SINEGEN_CON2 0x01dc +#define AFE_SIDETONE_CON0 0x01e0 +#define AFE_SIDETONE_COEFF 0x01e4 +#define AFE_SIDETONE_CON1 0x01e8 +#define AFE_SIDETONE_GAIN 0x01ec +#define AFE_SINEGEN_CON0 0x01f0 +#define AFE_I2S_MON2 0x01f8 +#define AFE_SINEGEN_CON_TDM 0x01fc +#define AFE_TOP_CON0 0x0200 +#define AFE_VUL2_CON0 0x020c +#define AFE_VUL2_BASE_MSB 0x0210 +#define AFE_VUL2_BASE 0x0214 +#define AFE_VUL2_CUR_MSB 0x0218 +#define AFE_VUL2_CUR 0x021c +#define AFE_VUL2_END_MSB 0x0220 +#define AFE_VUL2_END 0x0224 +#define AFE_VUL3_CON0 0x0228 +#define AFE_VUL3_BASE_MSB 0x022c +#define AFE_VUL3_BASE 0x0230 +#define AFE_VUL3_CUR_MSB 0x0234 +#define AFE_VUL3_CUR 0x0238 +#define AFE_VUL3_END_MSB 0x023c +#define AFE_VUL3_END 0x0240 +#define AFE_BUSY 0x0244 +#define AFE_BUS_CFG 0x0250 +#define AFE_ADDA_PREDIS_CON0 0x0260 +#define AFE_ADDA_PREDIS_CON1 0x0264 +#define AFE_I2S_MON 0x027c +#define AFE_ADDA_IIR_COEF_02_01 0x0290 +#define AFE_ADDA_IIR_COEF_04_03 0x0294 +#define AFE_ADDA_IIR_COEF_06_05 0x0298 +#define AFE_ADDA_IIR_COEF_08_07 0x029c +#define AFE_ADDA_IIR_COEF_10_09 0x02a0 +#define AFE_IRQ_MCU_CON1 0x02e4 +#define AFE_IRQ_MCU_CON2 0x02e8 +#define AFE_DAC_MON 0x02ec +#define AFE_IRQ_MCU_CON3 0x02f0 +#define AFE_IRQ_MCU_CON4 0x02f4 +#define AFE_IRQ_MCU_CNT0 0x0300 +#define AFE_IRQ_MCU_CNT6 0x0304 +#define AFE_IRQ_MCU_CNT8 0x0308 +#define AFE_IRQ_MCU_DSP2_EN 0x030c +#define AFE_IRQ0_MCU_CNT_MON 0x0310 +#define AFE_IRQ6_MCU_CNT_MON 0x0314 +#define AFE_VUL4_CON0 0x0358 +#define AFE_VUL4_BASE_MSB 0x035c +#define AFE_VUL4_BASE 0x0360 +#define AFE_VUL4_CUR_MSB 0x0364 +#define AFE_VUL4_CUR 0x0368 +#define AFE_VUL4_END_MSB 0x036c +#define AFE_VUL4_END 0x0370 +#define AFE_VUL12_CON0 0x0374 +#define AFE_VUL12_BASE_MSB 0x0378 +#define AFE_VUL12_BASE 0x037c +#define AFE_VUL12_CUR_MSB 0x0380 +#define AFE_VUL12_CUR 0x0384 +#define AFE_VUL12_END_MSB 0x0388 +#define AFE_VUL12_END 0x038c +#define AFE_HDMI_CONN0 0x0390 +#define AFE_IRQ3_MCU_CNT_MON 0x0398 +#define AFE_IRQ4_MCU_CNT_MON 0x039c +#define AFE_IRQ_MCU_CON0 0x03a0 +#define AFE_IRQ_MCU_STATUS 0x03a4 +#define AFE_IRQ_MCU_CLR 0x03a8 +#define AFE_IRQ_MCU_CNT1 0x03ac +#define AFE_IRQ_MCU_CNT2 0x03b0 +#define AFE_IRQ_MCU_EN 0x03b4 +#define AFE_IRQ_MCU_MON2 0x03b8 +#define AFE_IRQ_MCU_CNT5 0x03bc +#define AFE_IRQ1_MCU_CNT_MON 0x03c0 +#define AFE_IRQ2_MCU_CNT_MON 0x03c4 +#define AFE_IRQ5_MCU_CNT_MON 0x03cc +#define AFE_IRQ_MCU_DSP_EN 0x03d0 +#define AFE_IRQ_MCU_SCP_EN 0x03d4 +#define AFE_IRQ_MCU_CNT7 0x03dc +#define AFE_IRQ7_MCU_CNT_MON 0x03e0 +#define AFE_IRQ_MCU_CNT3 0x03e4 +#define AFE_IRQ_MCU_CNT4 0x03e8 +#define AFE_IRQ_MCU_CNT11 0x03ec +#define AFE_APLL1_TUNER_CFG 0x03f0 +#define AFE_APLL2_TUNER_CFG 0x03f4 +#define AFE_IRQ_MCU_MISS_CLR 0x03f8 +#define AFE_CONN33 0x0408 +#define AFE_IRQ_MCU_CNT12 0x040c +#define AFE_GAIN1_CON0 0x0410 +#define AFE_GAIN1_CON1 0x0414 +#define AFE_GAIN1_CON2 0x0418 +#define AFE_GAIN1_CON3 0x041c +#define AFE_CONN7 0x0420 +#define AFE_GAIN1_CUR 0x0424 +#define AFE_GAIN2_CON0 0x0428 +#define AFE_GAIN2_CON1 0x042c +#define AFE_GAIN2_CON2 0x0430 +#define AFE_GAIN2_CON3 0x0434 +#define AFE_CONN8 0x0438 +#define AFE_GAIN2_CUR 0x043c +#define AFE_CONN9 0x0440 +#define AFE_CONN10 0x0444 +#define AFE_CONN11 0x0448 +#define AFE_CONN12 0x044c +#define AFE_CONN13 0x0450 +#define AFE_CONN14 0x0454 +#define AFE_CONN15 0x0458 +#define AFE_CONN16 0x045c +#define AFE_CONN17 0x0460 +#define AFE_CONN18 0x0464 +#define AFE_CONN19 0x0468 +#define AFE_CONN20 0x046c +#define AFE_CONN21 0x0470 +#define AFE_CONN22 0x0474 +#define AFE_CONN23 0x0478 +#define AFE_CONN24 0x047c +#define AFE_CONN_RS 0x0494 +#define AFE_CONN_DI 0x0498 +#define AFE_CONN25 0x04b0 +#define AFE_CONN26 0x04b4 +#define AFE_CONN27 0x04b8 +#define AFE_CONN28 0x04bc +#define AFE_CONN29 0x04c0 +#define AFE_CONN30 0x04c4 +#define AFE_CONN31 0x04c8 +#define AFE_CONN32 0x04cc +#define AFE_SRAM_DELSEL_CON1 0x04f4 +#define AFE_CONN56 0x0500 +#define AFE_CONN57 0x0504 +#define AFE_CONN56_1 0x0510 +#define AFE_CONN57_1 0x0514 +#define AFE_TINY_CONN2 0x0520 +#define AFE_TINY_CONN3 0x0524 +#define AFE_TINY_CONN4 0x0528 +#define AFE_TINY_CONN5 0x052c +#define PCM_INTF_CON1 0x0530 +#define PCM_INTF_CON2 0x0538 +#define PCM2_INTF_CON 0x053c +#define AFE_TDM_CON1 0x0548 +#define AFE_TDM_CON2 0x054c +#define AFE_I2S_CON6 0x0564 +#define AFE_I2S_CON7 0x0568 +#define AFE_I2S_CON8 0x056c +#define AFE_I2S_CON9 0x0570 +#define AFE_CONN34 0x0580 +#define FPGA_CFG0 0x05b0 +#define FPGA_CFG1 0x05b4 +#define FPGA_CFG2 0x05c0 +#define FPGA_CFG3 0x05c4 +#define AUDIO_TOP_DBG_CON 0x05c8 +#define AUDIO_TOP_DBG_MON0 0x05cc +#define AUDIO_TOP_DBG_MON1 0x05d0 +#define AFE_IRQ8_MCU_CNT_MON 0x05e4 +#define AFE_IRQ11_MCU_CNT_MON 0x05e8 +#define AFE_IRQ12_MCU_CNT_MON 0x05ec +#define AFE_IRQ_MCU_CNT9 0x0600 +#define AFE_IRQ_MCU_CNT10 0x0604 +#define AFE_IRQ_MCU_CNT13 0x0608 +#define AFE_IRQ_MCU_CNT14 0x060c +#define AFE_IRQ_MCU_CNT15 0x0610 +#define AFE_IRQ_MCU_CNT16 0x0614 +#define AFE_IRQ_MCU_CNT17 0x0618 +#define AFE_IRQ_MCU_CNT18 0x061c +#define AFE_IRQ_MCU_CNT19 0x0620 +#define AFE_IRQ_MCU_CNT20 0x0624 +#define AFE_IRQ_MCU_CNT21 0x0628 +#define AFE_IRQ_MCU_CNT22 0x062c +#define AFE_IRQ_MCU_CNT23 0x0630 +#define AFE_IRQ_MCU_CNT24 0x0634 +#define AFE_IRQ_MCU_CNT25 0x0638 +#define AFE_IRQ_MCU_CNT26 0x063c +#define AFE_IRQ_MCU_CNT31 0x0640 +#define AFE_TINY_CONN6 0x0650 +#define AFE_TINY_CONN7 0x0654 +#define AFE_IRQ9_MCU_CNT_MON 0x0660 +#define AFE_IRQ10_MCU_CNT_MON 0x0664 +#define AFE_IRQ13_MCU_CNT_MON 0x0668 +#define AFE_IRQ14_MCU_CNT_MON 0x066c +#define AFE_IRQ15_MCU_CNT_MON 0x0670 +#define AFE_IRQ16_MCU_CNT_MON 0x0674 +#define AFE_IRQ17_MCU_CNT_MON 0x0678 +#define AFE_IRQ18_MCU_CNT_MON 0x067c +#define AFE_IRQ19_MCU_CNT_MON 0x0680 +#define AFE_IRQ20_MCU_CNT_MON 0x0684 +#define AFE_IRQ21_MCU_CNT_MON 0x0688 +#define AFE_IRQ22_MCU_CNT_MON 0x068c +#define AFE_IRQ23_MCU_CNT_MON 0x0690 +#define AFE_IRQ24_MCU_CNT_MON 0x0694 +#define AFE_IRQ25_MCU_CNT_MON 0x0698 +#define AFE_IRQ26_MCU_CNT_MON 0x069c +#define AFE_IRQ31_MCU_CNT_MON 0x06a0 +#define AFE_GENERAL_REG0 0x0800 +#define AFE_GENERAL_REG1 0x0804 +#define AFE_GENERAL_REG2 0x0808 +#define AFE_GENERAL_REG3 0x080c +#define AFE_GENERAL_REG4 0x0810 +#define AFE_GENERAL_REG5 0x0814 +#define AFE_GENERAL_REG6 0x0818 +#define AFE_GENERAL_REG7 0x081c +#define AFE_GENERAL_REG8 0x0820 +#define AFE_GENERAL_REG9 0x0824 +#define AFE_GENERAL_REG10 0x0828 +#define AFE_GENERAL_REG11 0x082c +#define AFE_GENERAL_REG12 0x0830 +#define AFE_GENERAL_REG13 0x0834 +#define AFE_GENERAL_REG14 0x0838 +#define AFE_GENERAL_REG15 0x083c +#define AFE_CBIP_CFG0 0x0840 +#define AFE_CBIP_MON0 0x0844 +#define AFE_CBIP_SLV_MUX_MON0 0x0848 +#define AFE_CBIP_SLV_DECODER_MON0 0x084c +#define AFE_ADDA6_MTKAIF_MON0 0x0854 +#define AFE_ADDA6_MTKAIF_MON1 0x0858 +#define AFE_AWB_CON0 0x085c +#define AFE_AWB_BASE_MSB 0x0860 +#define AFE_AWB_BASE 0x0864 +#define AFE_AWB_CUR_MSB 0x0868 +#define AFE_AWB_CUR 0x086c +#define AFE_AWB_END_MSB 0x0870 +#define AFE_AWB_END 0x0874 +#define AFE_AWB2_CON0 0x0878 +#define AFE_AWB2_BASE_MSB 0x087c +#define AFE_AWB2_BASE 0x0880 +#define AFE_AWB2_CUR_MSB 0x0884 +#define AFE_AWB2_CUR 0x0888 +#define AFE_AWB2_END_MSB 0x088c +#define AFE_AWB2_END 0x0890 +#define AFE_DAI_CON0 0x0894 +#define AFE_DAI_BASE_MSB 0x0898 +#define AFE_DAI_BASE 0x089c +#define AFE_DAI_CUR_MSB 0x08a0 +#define AFE_DAI_CUR 0x08a4 +#define AFE_DAI_END_MSB 0x08a8 +#define AFE_DAI_END 0x08ac +#define AFE_DAI2_CON0 0x08b0 +#define AFE_DAI2_BASE_MSB 0x08b4 +#define AFE_DAI2_BASE 0x08b8 +#define AFE_DAI2_CUR_MSB 0x08bc +#define AFE_DAI2_CUR 0x08c0 +#define AFE_DAI2_END_MSB 0x08c4 +#define AFE_DAI2_END 0x08c8 +#define AFE_MEMIF_CON0 0x08cc +#define AFE_CONN0_1 0x0900 +#define AFE_CONN1_1 0x0904 +#define AFE_CONN2_1 0x0908 +#define AFE_CONN3_1 0x090c +#define AFE_CONN4_1 0x0910 +#define AFE_CONN5_1 0x0914 +#define AFE_CONN6_1 0x0918 +#define AFE_CONN7_1 0x091c +#define AFE_CONN8_1 0x0920 +#define AFE_CONN9_1 0x0924 +#define AFE_CONN10_1 0x0928 +#define AFE_CONN11_1 0x092c +#define AFE_CONN12_1 0x0930 +#define AFE_CONN13_1 0x0934 +#define AFE_CONN14_1 0x0938 +#define AFE_CONN15_1 0x093c +#define AFE_CONN16_1 0x0940 +#define AFE_CONN17_1 0x0944 +#define AFE_CONN18_1 0x0948 +#define AFE_CONN19_1 0x094c +#define AFE_CONN20_1 0x0950 +#define AFE_CONN21_1 0x0954 +#define AFE_CONN22_1 0x0958 +#define AFE_CONN23_1 0x095c +#define AFE_CONN24_1 0x0960 +#define AFE_CONN25_1 0x0964 +#define AFE_CONN26_1 0x0968 +#define AFE_CONN27_1 0x096c +#define AFE_CONN28_1 0x0970 +#define AFE_CONN29_1 0x0974 +#define AFE_CONN30_1 0x0978 +#define AFE_CONN31_1 0x097c +#define AFE_CONN32_1 0x0980 +#define AFE_CONN33_1 0x0984 +#define AFE_CONN34_1 0x0988 +#define AFE_CONN_RS_1 0x098c +#define AFE_CONN_DI_1 0x0990 +#define AFE_CONN_24BIT_1 0x0994 +#define AFE_CONN_REG 0x0998 +#define AFE_CONN35 0x09a0 +#define AFE_CONN36 0x09a4 +#define AFE_CONN37 0x09a8 +#define AFE_CONN38 0x09ac +#define AFE_CONN35_1 0x09b0 +#define AFE_CONN36_1 0x09b4 +#define AFE_CONN37_1 0x09b8 +#define AFE_CONN38_1 0x09bc +#define AFE_CONN39 0x09c0 +#define AFE_CONN40 0x09c4 +#define AFE_CONN41 0x09c8 +#define AFE_CONN42 0x09cc +#define AFE_SGEN_CON_SGEN32 0x09d0 +#define AFE_CONN39_1 0x09e0 +#define AFE_CONN40_1 0x09e4 +#define AFE_CONN41_1 0x09e8 +#define AFE_CONN42_1 0x09ec +#define AFE_I2S_CON4 0x09f8 +#define AFE_ADDA6_TOP_CON0 0x0a80 +#define AFE_ADDA6_UL_SRC_CON0 0x0a84 +#define AFE_ADDA6_UL_SRC_CON1 0x0a88 +#define AFE_ADDA6_SRC_DEBUG 0x0a8c +#define AFE_ADDA6_SRC_DEBUG_MON0 0x0a90 +#define AFE_ADDA6_ULCF_CFG_02_01 0x0aa0 +#define AFE_ADDA6_ULCF_CFG_04_03 0x0aa4 +#define AFE_ADDA6_ULCF_CFG_06_05 0x0aa8 +#define AFE_ADDA6_ULCF_CFG_08_07 0x0aac +#define AFE_ADDA6_ULCF_CFG_10_09 0x0ab0 +#define AFE_ADDA6_ULCF_CFG_12_11 0x0ab4 +#define AFE_ADDA6_ULCF_CFG_14_13 0x0ab8 +#define AFE_ADDA6_ULCF_CFG_16_15 0x0abc +#define AFE_ADDA6_ULCF_CFG_18_17 0x0ac0 +#define AFE_ADDA6_ULCF_CFG_20_19 0x0ac4 +#define AFE_ADDA6_ULCF_CFG_22_21 0x0ac8 +#define AFE_ADDA6_ULCF_CFG_24_23 0x0acc +#define AFE_ADDA6_ULCF_CFG_26_25 0x0ad0 +#define AFE_ADDA6_ULCF_CFG_28_27 0x0ad4 +#define AFE_ADDA6_ULCF_CFG_30_29 0x0ad8 +#define AFE_ADD6A_UL_SRC_MON0 0x0ae4 +#define AFE_ADDA6_UL_SRC_MON1 0x0ae8 +#define AFE_TINY_CONN0 0x0af0 +#define AFE_TINY_CONN1 0x0af4 +#define AFE_CONN43 0x0af8 +#define AFE_CONN43_1 0x0afc +#define AFE_MOD_DAI_CON0 0x0b00 +#define AFE_MOD_DAI_BASE_MSB 0x0b04 +#define AFE_MOD_DAI_BASE 0x0b08 +#define AFE_MOD_DAI_CUR_MSB 0x0b0c +#define AFE_MOD_DAI_CUR 0x0b10 +#define AFE_MOD_DAI_END_MSB 0x0b14 +#define AFE_MOD_DAI_END 0x0b18 +#define AFE_HDMI_OUT_CON0 0x0b1c +#define AFE_HDMI_OUT_BASE_MSB 0x0b20 +#define AFE_HDMI_OUT_BASE 0x0b24 +#define AFE_HDMI_OUT_CUR_MSB 0x0b28 +#define AFE_HDMI_OUT_CUR 0x0b2c +#define AFE_HDMI_OUT_END_MSB 0x0b30 +#define AFE_HDMI_OUT_END 0x0b34 +#define AFE_AWB_RCH_MON 0x0b70 +#define AFE_AWB_LCH_MON 0x0b74 +#define AFE_VUL_RCH_MON 0x0b78 +#define AFE_VUL_LCH_MON 0x0b7c +#define AFE_VUL12_RCH_MON 0x0b80 +#define AFE_VUL12_LCH_MON 0x0b84 +#define AFE_VUL2_RCH_MON 0x0b88 +#define AFE_VUL2_LCH_MON 0x0b8c +#define AFE_DAI_DATA_MON 0x0b90 +#define AFE_MOD_DAI_DATA_MON 0x0b94 +#define AFE_DAI2_DATA_MON 0x0b98 +#define AFE_AWB2_RCH_MON 0x0b9c +#define AFE_AWB2_LCH_MON 0x0ba0 +#define AFE_VUL3_RCH_MON 0x0ba4 +#define AFE_VUL3_LCH_MON 0x0ba8 +#define AFE_VUL4_RCH_MON 0x0bac +#define AFE_VUL4_LCH_MON 0x0bb0 +#define AFE_VUL5_RCH_MON 0x0bb4 +#define AFE_VUL5_LCH_MON 0x0bb8 +#define AFE_VUL6_RCH_MON 0x0bbc +#define AFE_VUL6_LCH_MON 0x0bc0 +#define AFE_DL1_RCH_MON 0x0bc4 +#define AFE_DL1_LCH_MON 0x0bc8 +#define AFE_DL2_RCH_MON 0x0bcc +#define AFE_DL2_LCH_MON 0x0bd0 +#define AFE_DL12_RCH1_MON 0x0bd4 +#define AFE_DL12_LCH1_MON 0x0bd8 +#define AFE_DL12_RCH2_MON 0x0bdc +#define AFE_DL12_LCH2_MON 0x0be0 +#define AFE_DL3_RCH_MON 0x0be4 +#define AFE_DL3_LCH_MON 0x0be8 +#define AFE_DL4_RCH_MON 0x0bec +#define AFE_DL4_LCH_MON 0x0bf0 +#define AFE_DL5_RCH_MON 0x0bf4 +#define AFE_DL5_LCH_MON 0x0bf8 +#define AFE_DL6_RCH_MON 0x0bfc +#define AFE_DL6_LCH_MON 0x0c00 +#define AFE_DL7_RCH_MON 0x0c04 +#define AFE_DL7_LCH_MON 0x0c08 +#define AFE_DL8_RCH_MON 0x0c0c +#define AFE_DL8_LCH_MON 0x0c10 +#define AFE_VUL5_CON0 0x0c14 +#define AFE_VUL5_BASE_MSB 0x0c18 +#define AFE_VUL5_BASE 0x0c1c +#define AFE_VUL5_CUR_MSB 0x0c20 +#define AFE_VUL5_CUR 0x0c24 +#define AFE_VUL5_END_MSB 0x0c28 +#define AFE_VUL5_END 0x0c2c +#define AFE_VUL6_CON0 0x0c30 +#define AFE_VUL6_BASE_MSB 0x0c34 +#define AFE_VUL6_BASE 0x0c38 +#define AFE_VUL6_CUR_MSB 0x0c3c +#define AFE_VUL6_CUR 0x0c40 +#define AFE_VUL6_END_MSB 0x0c44 +#define AFE_VUL6_END 0x0c48 +#define AFE_ADDA_DL_SDM_DCCOMP_CON 0x0c50 +#define AFE_ADDA_DL_SDM_TEST 0x0c54 +#define AFE_ADDA_DL_DC_COMP_CFG0 0x0c58 +#define AFE_ADDA_DL_DC_COMP_CFG1 0x0c5c +#define AFE_ADDA_DL_SDM_FIFO_MON 0x0c60 +#define AFE_ADDA_DL_SRC_LCH_MON 0x0c64 +#define AFE_ADDA_DL_SRC_RCH_MON 0x0c68 +#define AFE_ADDA_DL_SDM_OUT_MON 0x0c6c +#define AFE_ADDA_DL_SDM_DITHER_CON 0x0c70 +#define AFE_ADDA_DL_SDM_AUTO_RESET_CON 0x0c74 +#define AFE_CONNSYS_I2S_CON 0x0c78 +#define AFE_CONNSYS_I2S_MON 0x0c7c +#define AFE_ASRC_2CH_CON0 0x0c80 +#define AFE_ASRC_2CH_CON1 0x0c84 +#define AFE_ASRC_2CH_CON2 0x0c88 +#define AFE_ASRC_2CH_CON3 0x0c8c +#define AFE_ASRC_2CH_CON4 0x0c90 +#define AFE_ASRC_2CH_CON5 0x0c94 +#define AFE_ASRC_2CH_CON6 0x0c98 +#define AFE_ASRC_2CH_CON7 0x0c9c +#define AFE_ASRC_2CH_CON8 0x0ca0 +#define AFE_ASRC_2CH_CON9 0x0ca4 +#define AFE_ASRC_2CH_CON10 0x0ca8 +#define AFE_ASRC_2CH_CON12 0x0cb0 +#define AFE_ASRC_2CH_CON13 0x0cb4 +#define AFE_ADDA6_IIR_COEF_02_01 0x0ce0 +#define AFE_ADDA6_IIR_COEF_04_03 0x0ce4 +#define AFE_ADDA6_IIR_COEF_06_05 0x0ce8 +#define AFE_ADDA6_IIR_COEF_08_07 0x0cec +#define AFE_ADDA6_IIR_COEF_10_09 0x0cf0 +#define AFE_SE_PROT_SIDEBAND 0x0d38 +#define AFE_SE_DOMAIN_SIDEBAND0 0x0d3c +#define AFE_ADDA_PREDIS_CON2 0x0d40 +#define AFE_ADDA_PREDIS_CON3 0x0d44 +#define AFE_MEMIF_CONN 0x0d50 +#define AFE_SE_DOMAIN_SIDEBAND1 0x0d54 +#define AFE_SE_DOMAIN_SIDEBAND2 0x0d58 +#define AFE_SE_DOMAIN_SIDEBAND3 0x0d5c +#define AFE_CONN44 0x0d70 +#define AFE_CONN45 0x0d74 +#define AFE_CONN46 0x0d78 +#define AFE_CONN47 0x0d7c +#define AFE_CONN44_1 0x0d80 +#define AFE_CONN45_1 0x0d84 +#define AFE_CONN46_1 0x0d88 +#define AFE_CONN47_1 0x0d8c +#define AFE_DL9_CUR_MSB 0x0dc0 +#define AFE_DL9_CUR 0x0dc4 +#define AFE_DL9_END_MSB 0x0dc8 +#define AFE_DL9_END 0x0dcc +#define AFE_HD_ENGEN_ENABLE 0x0dd0 +#define AFE_ADDA_DL_NLE_FIFO_MON 0x0dfc +#define AFE_ADDA_MTKAIF_CFG0 0x0e00 +#define AFE_ADDA_MTKAIF_SYNCWORD_CFG 0x0e14 +#define AFE_ADDA_MTKAIF_RX_CFG0 0x0e20 +#define AFE_ADDA_MTKAIF_RX_CFG1 0x0e24 +#define AFE_ADDA_MTKAIF_RX_CFG2 0x0e28 +#define AFE_ADDA_MTKAIF_MON0 0x0e34 +#define AFE_ADDA_MTKAIF_MON1 0x0e38 +#define AFE_AUD_PAD_TOP 0x0e40 +#define AFE_DL_NLE_R_CFG0 0x0e44 +#define AFE_DL_NLE_R_CFG1 0x0e48 +#define AFE_DL_NLE_L_CFG0 0x0e4c +#define AFE_DL_NLE_L_CFG1 0x0e50 +#define AFE_DL_NLE_R_MON0 0x0e54 +#define AFE_DL_NLE_R_MON1 0x0e58 +#define AFE_DL_NLE_R_MON2 0x0e5c +#define AFE_DL_NLE_L_MON0 0x0e60 +#define AFE_DL_NLE_L_MON1 0x0e64 +#define AFE_DL_NLE_L_MON2 0x0e68 +#define AFE_DL_NLE_GAIN_CFG0 0x0e6c +#define AFE_ADDA6_MTKAIF_CFG0 0x0e70 +#define AFE_ADDA6_MTKAIF_RX_CFG0 0x0e74 +#define AFE_ADDA6_MTKAIF_RX_CFG1 0x0e78 +#define AFE_ADDA6_MTKAIF_RX_CFG2 0x0e7c +#define AFE_GENERAL1_ASRC_2CH_CON0 0x0e80 +#define AFE_GENERAL1_ASRC_2CH_CON1 0x0e84 +#define AFE_GENERAL1_ASRC_2CH_CON2 0x0e88 +#define AFE_GENERAL1_ASRC_2CH_CON3 0x0e8c +#define AFE_GENERAL1_ASRC_2CH_CON4 0x0e90 +#define AFE_GENERAL1_ASRC_2CH_CON5 0x0e94 +#define AFE_GENERAL1_ASRC_2CH_CON6 0x0e98 +#define AFE_GENERAL1_ASRC_2CH_CON7 0x0e9c +#define AFE_GENERAL1_ASRC_2CH_CON8 0x0ea0 +#define AFE_GENERAL1_ASRC_2CH_CON9 0x0ea4 +#define AFE_GENERAL1_ASRC_2CH_CON10 0x0ea8 +#define AFE_GENERAL1_ASRC_2CH_CON12 0x0eb0 +#define AFE_GENERAL1_ASRC_2CH_CON13 0x0eb4 +#define GENERAL_ASRC_MODE 0x0eb8 +#define GENERAL_ASRC_EN_ON 0x0ebc +#define AFE_CONN48 0x0ec0 +#define AFE_CONN49 0x0ec4 +#define AFE_CONN50 0x0ec8 +#define AFE_CONN51 0x0ecc +#define AFE_CONN52 0x0ed0 +#define AFE_CONN53 0x0ed4 +#define AFE_CONN54 0x0ed8 +#define AFE_CONN55 0x0edc +#define AFE_CONN48_1 0x0ee0 +#define AFE_CONN49_1 0x0ee4 +#define AFE_CONN50_1 0x0ee8 +#define AFE_CONN51_1 0x0eec +#define AFE_CONN52_1 0x0ef0 +#define AFE_CONN53_1 0x0ef4 +#define AFE_CONN54_1 0x0ef8 +#define AFE_CONN55_1 0x0efc +#define AFE_GENERAL2_ASRC_2CH_CON0 0x0f00 +#define AFE_GENERAL2_ASRC_2CH_CON1 0x0f04 +#define AFE_GENERAL2_ASRC_2CH_CON2 0x0f08 +#define AFE_GENERAL2_ASRC_2CH_CON3 0x0f0c +#define AFE_GENERAL2_ASRC_2CH_CON4 0x0f10 +#define AFE_GENERAL2_ASRC_2CH_CON5 0x0f14 +#define AFE_GENERAL2_ASRC_2CH_CON6 0x0f18 +#define AFE_GENERAL2_ASRC_2CH_CON7 0x0f1c +#define AFE_GENERAL2_ASRC_2CH_CON8 0x0f20 +#define AFE_GENERAL2_ASRC_2CH_CON9 0x0f24 +#define AFE_GENERAL2_ASRC_2CH_CON10 0x0f28 +#define AFE_GENERAL2_ASRC_2CH_CON12 0x0f30 +#define AFE_GENERAL2_ASRC_2CH_CON13 0x0f34 +#define AFE_DL9_RCH_MON 0x0f38 +#define AFE_DL9_LCH_MON 0x0f3c +#define AFE_DL5_CON0 0x0f4c +#define AFE_DL5_BASE_MSB 0x0f50 +#define AFE_DL5_BASE 0x0f54 +#define AFE_DL5_CUR_MSB 0x0f58 +#define AFE_DL5_CUR 0x0f5c +#define AFE_DL5_END_MSB 0x0f60 +#define AFE_DL5_END 0x0f64 +#define AFE_DL6_CON0 0x0f68 +#define AFE_DL6_BASE_MSB 0x0f6c +#define AFE_DL6_BASE 0x0f70 +#define AFE_DL6_CUR_MSB 0x0f74 +#define AFE_DL6_CUR 0x0f78 +#define AFE_DL6_END_MSB 0x0f7c +#define AFE_DL6_END 0x0f80 +#define AFE_DL7_CON0 0x0f84 +#define AFE_DL7_BASE_MSB 0x0f88 +#define AFE_DL7_BASE 0x0f8c +#define AFE_DL7_CUR_MSB 0x0f90 +#define AFE_DL7_CUR 0x0f94 +#define AFE_DL7_END_MSB 0x0f98 +#define AFE_DL7_END 0x0f9c +#define AFE_DL8_CON0 0x0fa0 +#define AFE_DL8_BASE_MSB 0x0fa4 +#define AFE_DL8_BASE 0x0fa8 +#define AFE_DL8_CUR_MSB 0x0fac +#define AFE_DL8_CUR 0x0fb0 +#define AFE_DL8_END_MSB 0x0fb4 +#define AFE_DL8_END 0x0fb8 +#define AFE_DL9_CON0 0x0fbc +#define AFE_DL9_BASE_MSB 0x0fc0 +#define AFE_DL9_BASE 0x0fc4 +#define AFE_SE_SECURE_CON 0x1004 +#define AFE_PROT_SIDEBAND_MON 0x1008 +#define AFE_DOMAIN_SIDEBAND0_MON 0x100c +#define AFE_DOMAIN_SIDEBAND1_MON 0x1010 +#define AFE_DOMAIN_SIDEBAND2_MON 0x1014 +#define AFE_DOMAIN_SIDEBAND3_MON 0x1018 +#define AFE_SECURE_MASK_CONN0 0x1020 +#define AFE_SECURE_MASK_CONN1 0x1024 +#define AFE_SECURE_MASK_CONN2 0x1028 +#define AFE_SECURE_MASK_CONN3 0x102c +#define AFE_SECURE_MASK_CONN4 0x1030 +#define AFE_SECURE_MASK_CONN5 0x1034 +#define AFE_SECURE_MASK_CONN6 0x1038 +#define AFE_SECURE_MASK_CONN7 0x103c +#define AFE_SECURE_MASK_CONN8 0x1040 +#define AFE_SECURE_MASK_CONN9 0x1044 +#define AFE_SECURE_MASK_CONN10 0x1048 +#define AFE_SECURE_MASK_CONN11 0x104c +#define AFE_SECURE_MASK_CONN12 0x1050 +#define AFE_SECURE_MASK_CONN13 0x1054 +#define AFE_SECURE_MASK_CONN14 0x1058 +#define AFE_SECURE_MASK_CONN15 0x105c +#define AFE_SECURE_MASK_CONN16 0x1060 +#define AFE_SECURE_MASK_CONN17 0x1064 +#define AFE_SECURE_MASK_CONN18 0x1068 +#define AFE_SECURE_MASK_CONN19 0x106c +#define AFE_SECURE_MASK_CONN20 0x1070 +#define AFE_SECURE_MASK_CONN21 0x1074 +#define AFE_SECURE_MASK_CONN22 0x1078 +#define AFE_SECURE_MASK_CONN23 0x107c +#define AFE_SECURE_MASK_CONN24 0x1080 +#define AFE_SECURE_MASK_CONN25 0x1084 +#define AFE_SECURE_MASK_CONN26 0x1088 +#define AFE_SECURE_MASK_CONN27 0x108c +#define AFE_SECURE_MASK_CONN28 0x1090 +#define AFE_SECURE_MASK_CONN29 0x1094 +#define AFE_SECURE_MASK_CONN30 0x1098 +#define AFE_SECURE_MASK_CONN31 0x109c +#define AFE_SECURE_MASK_CONN32 0x10a0 +#define AFE_SECURE_MASK_CONN33 0x10a4 +#define AFE_SECURE_MASK_CONN34 0x10a8 +#define AFE_SECURE_MASK_CONN35 0x10ac +#define AFE_SECURE_MASK_CONN36 0x10b0 +#define AFE_SECURE_MASK_CONN37 0x10b4 +#define AFE_SECURE_MASK_CONN38 0x10b8 +#define AFE_SECURE_MASK_CONN39 0x10bc +#define AFE_SECURE_MASK_CONN40 0x10c0 +#define AFE_SECURE_MASK_CONN41 0x10c4 +#define AFE_SECURE_MASK_CONN42 0x10c8 +#define AFE_SECURE_MASK_CONN43 0x10cc +#define AFE_SECURE_MASK_CONN44 0x10d0 +#define AFE_SECURE_MASK_CONN45 0x10d4 +#define AFE_SECURE_MASK_CONN46 0x10d8 +#define AFE_SECURE_MASK_CONN47 0x10dc +#define AFE_SECURE_MASK_CONN48 0x10e0 +#define AFE_SECURE_MASK_CONN49 0x10e4 +#define AFE_SECURE_MASK_CONN50 0x10e8 +#define AFE_SECURE_MASK_CONN51 0x10ec +#define AFE_SECURE_MASK_CONN52 0x10f0 +#define AFE_SECURE_MASK_CONN53 0x10f4 +#define AFE_SECURE_MASK_CONN54 0x10f8 +#define AFE_SECURE_MASK_CONN55 0x10fc +#define AFE_SECURE_MASK_CONN56 0x1100 +#define AFE_SECURE_MASK_CONN57 0x1104 +#define AFE_SECURE_MASK_CONN0_1 0x1108 +#define AFE_SECURE_MASK_CONN1_1 0x110c +#define AFE_SECURE_MASK_CONN2_1 0x1110 +#define AFE_SECURE_MASK_CONN3_1 0x1114 +#define AFE_SECURE_MASK_CONN4_1 0x1118 +#define AFE_SECURE_MASK_CONN5_1 0x111c +#define AFE_SECURE_MASK_CONN6_1 0x1120 +#define AFE_SECURE_MASK_CONN7_1 0x1124 +#define AFE_SECURE_MASK_CONN8_1 0x1128 +#define AFE_SECURE_MASK_CONN9_1 0x112c +#define AFE_SECURE_MASK_CONN10_1 0x1130 +#define AFE_SECURE_MASK_CONN11_1 0x1134 +#define AFE_SECURE_MASK_CONN12_1 0x1138 +#define AFE_SECURE_MASK_CONN13_1 0x113c +#define AFE_SECURE_MASK_CONN14_1 0x1140 +#define AFE_SECURE_MASK_CONN15_1 0x1144 +#define AFE_SECURE_MASK_CONN16_1 0x1148 +#define AFE_SECURE_MASK_CONN17_1 0x114c +#define AFE_SECURE_MASK_CONN18_1 0x1150 +#define AFE_SECURE_MASK_CONN19_1 0x1154 +#define AFE_SECURE_MASK_CONN20_1 0x1158 +#define AFE_SECURE_MASK_CONN21_1 0x115c +#define AFE_SECURE_MASK_CONN22_1 0x1160 +#define AFE_SECURE_MASK_CONN23_1 0x1164 +#define AFE_SECURE_MASK_CONN24_1 0x1168 +#define AFE_SECURE_MASK_CONN25_1 0x116c +#define AFE_SECURE_MASK_CONN26_1 0x1170 +#define AFE_SECURE_MASK_CONN27_1 0x1174 +#define AFE_SECURE_MASK_CONN28_1 0x1178 +#define AFE_SECURE_MASK_CONN29_1 0x117c +#define AFE_SECURE_MASK_CONN30_1 0x1180 +#define AFE_SECURE_MASK_CONN31_1 0x1184 +#define AFE_SECURE_MASK_CONN32_1 0x1188 +#define AFE_SECURE_MASK_CONN33_1 0x118c +#define AFE_SECURE_MASK_CONN34_1 0x1190 +#define AFE_SECURE_MASK_CONN35_1 0x1194 +#define AFE_SECURE_MASK_CONN36_1 0x1198 +#define AFE_SECURE_MASK_CONN37_1 0x119c +#define AFE_SECURE_MASK_CONN38_1 0x11a0 +#define AFE_SECURE_MASK_CONN39_1 0x11a4 +#define AFE_SECURE_MASK_CONN40_1 0x11a8 +#define AFE_SECURE_MASK_CONN41_1 0x11ac +#define AFE_SECURE_MASK_CONN42_1 0x11b0 +#define AFE_SECURE_MASK_CONN43_1 0x11b4 +#define AFE_SECURE_MASK_CONN44_1 0x11b8 +#define AFE_SECURE_MASK_CONN45_1 0x11bc +#define AFE_SECURE_MASK_CONN46_1 0x11c0 +#define AFE_SECURE_MASK_CONN47_1 0x11c4 +#define AFE_SECURE_MASK_CONN48_1 0x11c8 +#define AFE_SECURE_MASK_CONN49_1 0x11cc +#define AFE_SECURE_MASK_CONN50_1 0x11d0 +#define AFE_SECURE_MASK_CONN51_1 0x11d4 +#define AFE_SECURE_MASK_CONN52_1 0x11d8 +#define AFE_SECURE_MASK_CONN53_1 0x11dc +#define AFE_SECURE_MASK_CONN54_1 0x11e0 +#define AFE_SECURE_MASK_CONN55_1 0x11e4 +#define AFE_SECURE_MASK_CONN56_1 0x11e8 +#define AFE_SECURE_MASK_TINY_CONN0 0x1200 +#define AFE_SECURE_MASK_TINY_CONN1 0x1204 +#define AFE_SECURE_MASK_TINY_CONN2 0x1208 +#define AFE_SECURE_MASK_TINY_CONN3 0x120c +#define AFE_SECURE_MASK_TINY_CONN4 0x1210 +#define AFE_SECURE_MASK_TINY_CONN5 0x1214 +#define AFE_SECURE_MASK_TINY_CONN6 0x1218 +#define AFE_SECURE_MASK_TINY_CONN7 0x121c + +#define AFE_MAX_REGISTER AFE_SECURE_MASK_TINY_CONN7 + +#define AFE_IRQ_STATUS_BITS 0x87FFFFFF +#define AFE_IRQ_CNT_SHIFT 0 +#define AFE_IRQ_CNT_MASK 0x3ffff + +#endif -- cgit v1.2.3 From 2c37b4ed730bc45e936794031a2fa13d75fb4572 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Tue, 3 Nov 2020 15:59:32 +0800 Subject: ASoC: mediatek: mt8192: support i2s in platform driver This patch adds mt8192 i2s dai driver. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1604390378-23993-4-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-dai-i2s.c | 2110 ++++++++++++++++++++++++++++ 1 file changed, 2110 insertions(+) create mode 100644 sound/soc/mediatek/mt8192/mt8192-dai-i2s.c (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c new file mode 100644 index 000000000000..53c560ea4aae --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c @@ -0,0 +1,2110 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Shane Chien +// + +#include +#include +#include + +#include "mt8192-afe-clk.h" +#include "mt8192-afe-common.h" +#include "mt8192-afe-gpio.h" +#include "mt8192-interconnection.h" + +enum { + I2S_FMT_EIAJ = 0, + I2S_FMT_I2S = 1, +}; + +enum { + I2S_WLEN_16_BIT = 0, + I2S_WLEN_32_BIT = 1, +}; + +enum { + I2S_HD_NORMAL = 0, + I2S_HD_LOW_JITTER = 1, +}; + +enum { + I2S1_SEL_O28_O29 = 0, + I2S1_SEL_O03_O04 = 1, +}; + +enum { + I2S_IN_PAD_CONNSYS = 0, + I2S_IN_PAD_IO_MUX = 1, +}; + +struct mtk_afe_i2s_priv { + int id; + int rate; /* for determine which apll to use */ + int low_jitter_en; + + const char *share_property_name; + int share_i2s_id; + + int mclk_id; + int mclk_rate; + int mclk_apll; +}; + +static unsigned int get_i2s_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + I2S_WLEN_16_BIT : I2S_WLEN_32_BIT; +} + +#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux" +#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux" +#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux" +#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux" +#define MTK_AFE_I2S5_KCONTROL_NAME "I2S5_HD_Mux" +#define MTK_AFE_I2S6_KCONTROL_NAME "I2S6_HD_Mux" +#define MTK_AFE_I2S7_KCONTROL_NAME "I2S7_HD_Mux" +#define MTK_AFE_I2S8_KCONTROL_NAME "I2S8_HD_Mux" +#define MTK_AFE_I2S9_KCONTROL_NAME "I2S9_HD_Mux" + +#define I2S0_HD_EN_W_NAME "I2S0_HD_EN" +#define I2S1_HD_EN_W_NAME "I2S1_HD_EN" +#define I2S2_HD_EN_W_NAME "I2S2_HD_EN" +#define I2S3_HD_EN_W_NAME "I2S3_HD_EN" +#define I2S5_HD_EN_W_NAME "I2S5_HD_EN" +#define I2S6_HD_EN_W_NAME "I2S6_HD_EN" +#define I2S7_HD_EN_W_NAME "I2S7_HD_EN" +#define I2S8_HD_EN_W_NAME "I2S8_HD_EN" +#define I2S9_HD_EN_W_NAME "I2S9_HD_EN" + +#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN" +#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN" +#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN" +#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN" +#define I2S5_MCLK_EN_W_NAME "I2S5_MCLK_EN" +#define I2S6_MCLK_EN_W_NAME "I2S6_MCLK_EN" +#define I2S7_MCLK_EN_W_NAME "I2S7_MCLK_EN" +#define I2S8_MCLK_EN_W_NAME "I2S8_MCLK_EN" +#define I2S9_MCLK_EN_W_NAME "I2S9_MCLK_EN" + +static int get_i2s_id_by_name(struct mtk_base_afe *afe, + const char *name) +{ + if (strncmp(name, "I2S0", 4) == 0) + return MT8192_DAI_I2S_0; + else if (strncmp(name, "I2S1", 4) == 0) + return MT8192_DAI_I2S_1; + else if (strncmp(name, "I2S2", 4) == 0) + return MT8192_DAI_I2S_2; + else if (strncmp(name, "I2S3", 4) == 0) + return MT8192_DAI_I2S_3; + else if (strncmp(name, "I2S5", 4) == 0) + return MT8192_DAI_I2S_5; + else if (strncmp(name, "I2S6", 4) == 0) + return MT8192_DAI_I2S_6; + else if (strncmp(name, "I2S7", 4) == 0) + return MT8192_DAI_I2S_7; + else if (strncmp(name, "I2S8", 4) == 0) + return MT8192_DAI_I2S_8; + else if (strncmp(name, "I2S9", 4) == 0) + return MT8192_DAI_I2S_9; + else + return -EINVAL; +} + +static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_i2s_id_by_name(afe, name); + + if (dai_id < 0) + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + +/* low jitter control */ +static const char * const mt8192_i2s_hd_str[] = { + "Normal", "Low_Jitter" +}; + +static SOC_ENUM_SINGLE_EXT_DECL(mt8192_i2s_enum, mt8192_i2s_hd_str); + +static int mt8192_i2s_hd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en; + + return 0; +} + +static int mt8192_i2s_hd_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int hd_en; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + hd_en = ucontrol->value.integer.value[0]; + + dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", + __func__, kcontrol->id.name, hd_en); + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + i2s_priv->low_jitter_en = hd_en; + + return 0; +} + +static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = { + SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S5_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S6_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S7_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S8_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S9_KCONTROL_NAME, mt8192_i2s_enum, + mt8192_i2s_hd_get, mt8192_i2s_hd_set), +}; + +/* dai component */ +/* i2s virtual mux to output widget */ +static const char * const i2s_mux_map[] = { + "Normal", "Dummy_Widget", +}; + +static int i2s_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum, + SND_SOC_NOPM, + 0, + 1, + i2s_mux_map, + i2s_mux_map_value); + +static const struct snd_kcontrol_new i2s0_in_mux_control = + SOC_DAPM_ENUM("I2S0 In Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s8_in_mux_control = + SOC_DAPM_ENUM("I2S8 In Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s1_out_mux_control = + SOC_DAPM_ENUM("I2S1 Out Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s3_out_mux_control = + SOC_DAPM_ENUM("I2S3 Out Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s5_out_mux_control = + SOC_DAPM_ENUM("I2S5 Out Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s7_out_mux_control = + SOC_DAPM_ENUM("I2S7 Out Select", i2s_mux_map_enum); + +static const struct snd_kcontrol_new i2s9_out_mux_control = + SOC_DAPM_ENUM("I2S9 Out Select", i2s_mux_map_enum); + +/* Tinyconn Mux */ +enum { + TINYCONN_CH1_MUX_DL1 = 0x0, + TINYCONN_CH2_MUX_DL1 = 0x1, + TINYCONN_CH1_MUX_DL12 = 0x2, + TINYCONN_CH2_MUX_DL12 = 0x3, + TINYCONN_CH1_MUX_DL2 = 0x4, + TINYCONN_CH2_MUX_DL2 = 0x5, + TINYCONN_CH1_MUX_DL3 = 0x6, + TINYCONN_CH2_MUX_DL3 = 0x7, + TINYCONN_MUX_NONE = 0x1f, +}; + +static const char * const tinyconn_mux_map[] = { + "NONE", + "DL1_CH1", + "DL1_CH2", + "DL12_CH1", + "DL12_CH2", + "DL2_CH1", + "DL2_CH2", + "DL3_CH1", + "DL3_CH2", +}; + +static int tinyconn_mux_map_value[] = { + TINYCONN_MUX_NONE, + TINYCONN_CH1_MUX_DL1, + TINYCONN_CH2_MUX_DL1, + TINYCONN_CH1_MUX_DL12, + TINYCONN_CH2_MUX_DL12, + TINYCONN_CH1_MUX_DL2, + TINYCONN_CH2_MUX_DL2, + TINYCONN_CH1_MUX_DL3, + TINYCONN_CH2_MUX_DL3, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(i2s1_tinyconn_ch1_mux_map_enum, + AFE_TINY_CONN5, + O_20_CFG_SFT, + O_20_CFG_MASK, + tinyconn_mux_map, + tinyconn_mux_map_value); +static const struct snd_kcontrol_new i2s1_tinyconn_ch1_mux_control = + SOC_DAPM_ENUM("i2s1 ch1 tinyconn Select", + i2s1_tinyconn_ch1_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(i2s1_tinyconn_ch2_mux_map_enum, + AFE_TINY_CONN5, + O_21_CFG_SFT, + O_21_CFG_MASK, + tinyconn_mux_map, + tinyconn_mux_map_value); +static const struct snd_kcontrol_new i2s1_tinyconn_ch2_mux_control = + SOC_DAPM_ENUM("i2s1 ch2 tinyconn Select", + i2s1_tinyconn_ch2_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(i2s3_tinyconn_ch1_mux_map_enum, + AFE_TINY_CONN5, + O_22_CFG_SFT, + O_22_CFG_MASK, + tinyconn_mux_map, + tinyconn_mux_map_value); +static const struct snd_kcontrol_new i2s3_tinyconn_ch1_mux_control = + SOC_DAPM_ENUM("i2s3 ch1 tinyconn Select", + i2s3_tinyconn_ch1_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(i2s3_tinyconn_ch2_mux_map_enum, + AFE_TINY_CONN5, + O_23_CFG_SFT, + O_23_CFG_MASK, + tinyconn_mux_map, + tinyconn_mux_map_value); +static const struct snd_kcontrol_new i2s3_tinyconn_ch2_mux_control = + SOC_DAPM_ENUM("i2s3 ch2 tinyconn Select", + i2s3_tinyconn_ch2_mux_map_enum); + +/* i2s in lpbk */ +static const char * const i2s_lpbk_mux_map[] = { + "Normal", "Lpbk", +}; + +static int i2s_lpbk_mux_map_value[] = { + 0, 1, +}; + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s0_lpbk_mux_map_enum, + AFE_I2S_CON, + I2S_LOOPBACK_SFT, + 1, + i2s_lpbk_mux_map, + i2s_lpbk_mux_map_value); + +static const struct snd_kcontrol_new i2s0_lpbk_mux_control = + SOC_DAPM_ENUM("I2S Lpbk Select", i2s0_lpbk_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s2_lpbk_mux_map_enum, + AFE_I2S_CON2, + I2S3_LOOPBACK_SFT, + 1, + i2s_lpbk_mux_map, + i2s_lpbk_mux_map_value); + +static const struct snd_kcontrol_new i2s2_lpbk_mux_control = + SOC_DAPM_ENUM("I2S Lpbk Select", i2s2_lpbk_mux_map_enum); + +/* interconnection */ +static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN0, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN0, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN0, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN0, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN0_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN0_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN0_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN0_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN0_1, I_DL9_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN0, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN0, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN0, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN0, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN0, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN1, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN1, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN1, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN1, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN1_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN1_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN1_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN1_1, I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN1_1, I_DL9_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN1, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN1, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN1, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN1, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN1, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN1, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN1, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN1, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN28, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN28, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN28, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN28, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN28_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN28_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN28_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN28_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN28_1, I_DL9_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN28, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN28, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN28, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN28, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN29, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN29, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN29, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN29, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN29_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN29_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN29_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN29_1, I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN29_1, I_DL9_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN29, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN29, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN29, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN29, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN29, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN29, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s5_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN30, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN30, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN30, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN30, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN30_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN30_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN30_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN30_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN30_1, I_DL9_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN30, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN30, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN30, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN30, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s5_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN31, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN31, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN31, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN31, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN31_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN31_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN31_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN31_1, I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN31_1, I_DL9_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN31, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN31, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN31, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN31, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN31, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN31, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s7_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN54, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN54, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN54, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN54, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN54_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN54_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN54_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN54_1, I_DL9_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN54, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN54, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN54, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN54, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s7_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN55, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN55, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN55, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN55, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN55_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN55_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN55_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN55_1, I_DL9_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN55, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN55, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN55, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN55, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN55, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN55, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s9_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN56, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN56, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN56, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN56, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN56_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN56_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN56_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN56_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH1", AFE_CONN56_1, I_DL9_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN56, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN56, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN56, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN56, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s9_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN57, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN57, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN57, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN57, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN57_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN57_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN57_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN57_1, I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL9_CH2", AFE_CONN57_1, I_DL9_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN57, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN57, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN57, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN57, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN57, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN57, + I_PCM_2_CAP_CH2, 1, 0), +}; + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_I2S_MCLK_EN, + SUPPLY_SEQ_I2S_HD_EN, + SUPPLY_SEQ_I2S_EN, +}; + +static int mtk_i2s_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_afe_gpio_request(afe->dev, true, i2s_priv->id, 0); + break; + case SND_SOC_DAPM_POST_PMD: + mt8192_afe_gpio_request(afe->dev, false, i2s_priv->id, 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_apll_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8192_apll1_enable(afe); + else + mt8192_apll2_enable(afe); + break; + case SND_SOC_DAPM_POST_PMD: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8192_apll1_disable(afe); + else + mt8192_apll2_disable(afe); + break; + default: + break; + } + + return 0; +} + +static int i2s_out_tinyconn_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg; + unsigned int reg_shift; + unsigned int reg_mask_shift; + + dev_dbg(afe->dev, "%s(), event 0x%x\n", __func__, event); + + if (strstr(w->name, "I2S1")) { + reg = AFE_I2S_CON1; + reg_shift = I2S2_32BIT_EN_SFT; + reg_mask_shift = I2S2_32BIT_EN_MASK_SFT; + } else if (strstr(w->name, "I2S3")) { + reg = AFE_I2S_CON3; + reg_shift = I2S4_32BIT_EN_SFT; + reg_mask_shift = I2S4_32BIT_EN_MASK_SFT; + } else if (strstr(w->name, "I2S5")) { + reg = AFE_I2S_CON4; + reg_shift = I2S5_32BIT_EN_SFT; + reg_mask_shift = I2S5_32BIT_EN_MASK_SFT; + } else if (strstr(w->name, "I2S7")) { + reg = AFE_I2S_CON7; + reg_shift = I2S7_32BIT_EN_SFT; + reg_mask_shift = I2S7_32BIT_EN_MASK_SFT; + } else if (strstr(w->name, "I2S9")) { + reg = AFE_I2S_CON9; + reg_shift = I2S9_32BIT_EN_SFT; + reg_mask_shift = I2S9_32BIT_EN_MASK_SFT; + } else { + reg = AFE_I2S_CON1; + reg_shift = I2S2_32BIT_EN_SFT; + reg_mask_shift = I2S2_32BIT_EN_MASK_SFT; + dev_warn(afe->dev, "%s(), error widget name %s, use i2s1\n", + __func__, w->name); + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(afe->regmap, reg, reg_mask_shift, + 0x1 << reg_shift); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(afe->regmap, reg, reg_mask_shift, + 0x0 << reg_shift); + break; + default: + break; + } + + return 0; +} + +static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + i2s_priv->mclk_rate = 0; + mt8192_mck_disable(afe, i2s_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = { + SND_SOC_DAPM_INPUT("CONNSYS"), + + SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch1_mix, + ARRAY_SIZE(mtk_i2s1_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch2_mix, + ARRAY_SIZE(mtk_i2s1_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch1_mix, + ARRAY_SIZE(mtk_i2s3_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch2_mix, + ARRAY_SIZE(mtk_i2s3_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S5_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s5_ch1_mix, + ARRAY_SIZE(mtk_i2s5_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S5_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s5_ch2_mix, + ARRAY_SIZE(mtk_i2s5_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S7_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s7_ch1_mix, + ARRAY_SIZE(mtk_i2s7_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S7_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s7_ch2_mix, + ARRAY_SIZE(mtk_i2s7_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S9_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s9_ch1_mix, + ARRAY_SIZE(mtk_i2s9_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S9_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s9_ch2_mix, + ARRAY_SIZE(mtk_i2s9_ch2_mix)), + + SND_SOC_DAPM_MUX_E("I2S1_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0, + &i2s1_tinyconn_ch1_mux_control, + i2s_out_tinyconn_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX_E("I2S1_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0, + &i2s1_tinyconn_ch2_mux_control, + i2s_out_tinyconn_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX_E("I2S3_TINYCONN_CH1_MUX", SND_SOC_NOPM, 0, 0, + &i2s3_tinyconn_ch1_mux_control, + i2s_out_tinyconn_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX_E("I2S3_TINYCONN_CH2_MUX", SND_SOC_NOPM, 0, 0, + &i2s3_tinyconn_ch2_mux_control, + i2s_out_tinyconn_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + /* i2s en*/ + SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON1, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON2, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON3, I2S_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S5_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON4, I2S5_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S6_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON6, I2S6_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S7_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON7, I2S7_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S8_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON8, I2S8_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("I2S9_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON9, I2S9_EN_SFT, 0, + mtk_i2s_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* i2s hd en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON, I2S1_HD_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON1, I2S2_HD_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON2, I2S3_HD_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON3, I2S4_HD_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S5_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON4, I2S5_HD_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S6_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON6, I2S6_HD_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S7_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON7, I2S7_HD_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S8_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON8, I2S8_HD_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S9_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON9, I2S9_HD_EN_SFT, 0, NULL, 0), + + /* i2s mclk en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S5_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S6_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S7_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S8_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S9_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* apll */ + SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* allow i2s on without codec on */ + SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"), + SND_SOC_DAPM_MUX("I2S1_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s1_out_mux_control), + SND_SOC_DAPM_MUX("I2S3_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s3_out_mux_control), + SND_SOC_DAPM_MUX("I2S5_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s5_out_mux_control), + SND_SOC_DAPM_MUX("I2S7_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s7_out_mux_control), + SND_SOC_DAPM_MUX("I2S9_Out_Mux", + SND_SOC_NOPM, 0, 0, &i2s9_out_mux_control), + + SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"), + SND_SOC_DAPM_MUX("I2S0_In_Mux", + SND_SOC_NOPM, 0, 0, &i2s0_in_mux_control), + SND_SOC_DAPM_MUX("I2S8_In_Mux", + SND_SOC_NOPM, 0, 0, &i2s8_in_mux_control), + + /* i2s in lpbk */ + SND_SOC_DAPM_MUX("I2S0_Lpbk_Mux", + SND_SOC_NOPM, 0, 0, &i2s0_lpbk_mux_control), + SND_SOC_DAPM_MUX("I2S2_Lpbk_Mux", + SND_SOC_NOPM, 0, 0, &i2s2_lpbk_mux_control), +}; + +static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (i2s_priv->share_i2s_id < 0) + return 0; + + return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name); +} + +static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + /* check if share i2s need hd en */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + return 0; +} + +static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + int i2s_need_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8192_get_apll_by_name(afe, source->name); + + /* choose APLL from i2s rate */ + i2s_need_apll = mt8192_get_apll_by_rate(afe, i2s_priv->rate); + + if (i2s_need_apll == cur_apll) + return 1; + + return 0; +} + +static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + /* check if share i2s need mclk */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + return 0; +} + +static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8192_get_apll_by_name(afe, source->name); + + if (i2s_priv->mclk_apll == cur_apll) + return 1; + + return 0; +} + +static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { + {"Connsys I2S", NULL, "CONNSYS"}, + + /* i2s0 */ + {"I2S0", NULL, "I2S0_EN"}, + {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S6_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S7_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S8_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S9_EN", mtk_afe_i2s_share_connect}, + + {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s1 */ + {"I2S1_CH1", "DL1_CH1", "DL1"}, + {"I2S1_CH2", "DL1_CH2", "DL1"}, + {"I2S1_TINYCONN_CH1_MUX", "DL1_CH1", "DL1"}, + {"I2S1_TINYCONN_CH2_MUX", "DL1_CH2", "DL1"}, + + {"I2S1_CH1", "DL2_CH1", "DL2"}, + {"I2S1_CH2", "DL2_CH2", "DL2"}, + {"I2S1_TINYCONN_CH1_MUX", "DL2_CH1", "DL2"}, + {"I2S1_TINYCONN_CH2_MUX", "DL2_CH2", "DL2"}, + + {"I2S1_CH1", "DL3_CH1", "DL3"}, + {"I2S1_CH2", "DL3_CH2", "DL3"}, + {"I2S1_TINYCONN_CH1_MUX", "DL3_CH1", "DL3"}, + {"I2S1_TINYCONN_CH2_MUX", "DL3_CH2", "DL3"}, + + {"I2S1_CH1", "DL12_CH1", "DL12"}, + {"I2S1_CH2", "DL12_CH2", "DL12"}, + {"I2S1_TINYCONN_CH1_MUX", "DL12_CH1", "DL12"}, + {"I2S1_TINYCONN_CH2_MUX", "DL12_CH2", "DL12"}, + + {"I2S1_CH1", "DL4_CH1", "DL4"}, + {"I2S1_CH2", "DL4_CH2", "DL4"}, + + {"I2S1_CH1", "DL5_CH1", "DL5"}, + {"I2S1_CH2", "DL5_CH2", "DL5"}, + + {"I2S1_CH1", "DL6_CH1", "DL6"}, + {"I2S1_CH2", "DL6_CH2", "DL6"}, + + {"I2S1_CH1", "DL8_CH1", "DL8"}, + {"I2S1_CH2", "DL8_CH2", "DL8"}, + + {"I2S1", NULL, "I2S1_CH1"}, + {"I2S1", NULL, "I2S1_CH2"}, + {"I2S1", NULL, "I2S3_TINYCONN_CH1_MUX"}, + {"I2S1", NULL, "I2S3_TINYCONN_CH2_MUX"}, + + {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S1_EN"}, + {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S6_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S7_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S8_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S9_EN", mtk_afe_i2s_share_connect}, + + {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s2 */ + {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S2_EN"}, + {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S6_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S7_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S8_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S9_EN", mtk_afe_i2s_share_connect}, + + {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s3 */ + {"I2S3_CH1", "DL1_CH1", "DL1"}, + {"I2S3_CH2", "DL1_CH2", "DL1"}, + {"I2S3_TINYCONN_CH1_MUX", "DL1_CH1", "DL1"}, + {"I2S3_TINYCONN_CH2_MUX", "DL1_CH2", "DL1"}, + + {"I2S3_CH1", "DL2_CH1", "DL2"}, + {"I2S3_CH2", "DL2_CH2", "DL2"}, + {"I2S3_TINYCONN_CH1_MUX", "DL2_CH1", "DL2"}, + {"I2S3_TINYCONN_CH2_MUX", "DL2_CH2", "DL2"}, + + {"I2S3_CH1", "DL3_CH1", "DL3"}, + {"I2S3_CH2", "DL3_CH2", "DL3"}, + {"I2S3_TINYCONN_CH1_MUX", "DL3_CH1", "DL3"}, + {"I2S3_TINYCONN_CH2_MUX", "DL3_CH2", "DL3"}, + + {"I2S3_CH1", "DL12_CH1", "DL12"}, + {"I2S3_CH2", "DL12_CH2", "DL12"}, + {"I2S3_TINYCONN_CH1_MUX", "DL12_CH1", "DL12"}, + {"I2S3_TINYCONN_CH2_MUX", "DL12_CH2", "DL12"}, + + {"I2S3_CH1", "DL4_CH1", "DL4"}, + {"I2S3_CH2", "DL4_CH2", "DL4"}, + + {"I2S3_CH1", "DL5_CH1", "DL5"}, + {"I2S3_CH2", "DL5_CH2", "DL5"}, + + {"I2S3_CH1", "DL6_CH1", "DL6"}, + {"I2S3_CH2", "DL6_CH2", "DL6"}, + + {"I2S3_CH1", "DL8_CH1", "DL8"}, + {"I2S3_CH2", "DL8_CH2", "DL8"}, + + {"I2S3", NULL, "I2S3_CH1"}, + {"I2S3", NULL, "I2S3_CH2"}, + {"I2S3", NULL, "I2S3_TINYCONN_CH1_MUX"}, + {"I2S3", NULL, "I2S3_TINYCONN_CH2_MUX"}, + + {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S3_EN"}, + {"I2S3", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S6_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S7_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S8_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S9_EN", mtk_afe_i2s_share_connect}, + + {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s5 */ + {"I2S5_CH1", "DL1_CH1", "DL1"}, + {"I2S5_CH2", "DL1_CH2", "DL1"}, + + {"I2S5_CH1", "DL2_CH1", "DL2"}, + {"I2S5_CH2", "DL2_CH2", "DL2"}, + + {"I2S5_CH1", "DL3_CH1", "DL3"}, + {"I2S5_CH2", "DL3_CH2", "DL3"}, + + {"I2S5_CH1", "DL12_CH1", "DL12"}, + {"I2S5_CH2", "DL12_CH2", "DL12"}, + + {"I2S5_CH1", "DL4_CH1", "DL4"}, + {"I2S5_CH2", "DL4_CH2", "DL4"}, + + {"I2S5_CH1", "DL5_CH1", "DL5"}, + {"I2S5_CH2", "DL5_CH2", "DL5"}, + + {"I2S5_CH1", "DL6_CH1", "DL6"}, + {"I2S5_CH2", "DL6_CH2", "DL6"}, + + {"I2S5_CH1", "DL8_CH1", "DL8"}, + {"I2S5_CH2", "DL8_CH2", "DL8"}, + + {"I2S5", NULL, "I2S5_CH1"}, + {"I2S5", NULL, "I2S5_CH2"}, + + {"I2S5", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S5_EN"}, + {"I2S5", NULL, "I2S6_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S7_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S8_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S9_EN", mtk_afe_i2s_share_connect}, + + {"I2S5", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S5_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S5_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S5", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S5_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S5_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s6 */ + {"I2S6", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S6", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S6", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S6", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S6", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + {"I2S6", NULL, "I2S6_EN"}, + {"I2S6", NULL, "I2S7_EN", mtk_afe_i2s_share_connect}, + {"I2S6", NULL, "I2S8_EN", mtk_afe_i2s_share_connect}, + {"I2S6", NULL, "I2S9_EN", mtk_afe_i2s_share_connect}, + + {"I2S6", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S6", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S6", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S6", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S6", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S6", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S6", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S6", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S6", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S6_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S6_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S6", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S6", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S6", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S6", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S6", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S6", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S6", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S6", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S6", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S6_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S6_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s7 */ + {"I2S7", NULL, "I2S7_CH1"}, + {"I2S7", NULL, "I2S7_CH2"}, + + {"I2S7", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S7", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S7", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S7", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S7", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + {"I2S7", NULL, "I2S6_EN", mtk_afe_i2s_share_connect}, + {"I2S7", NULL, "I2S7_EN"}, + {"I2S7", NULL, "I2S8_EN", mtk_afe_i2s_share_connect}, + {"I2S7", NULL, "I2S9_EN", mtk_afe_i2s_share_connect}, + + {"I2S7", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S7", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S7", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S7", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S7", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S7", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S7", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S7", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S7", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S7_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S7_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S7", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S7", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S7", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S7", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S7", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S7", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S7", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S7", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S7", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S7_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S7_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s8 */ + {"I2S8", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S8", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S8", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S8", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S8", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + {"I2S8", NULL, "I2S6_EN", mtk_afe_i2s_share_connect}, + {"I2S8", NULL, "I2S7_EN", mtk_afe_i2s_share_connect}, + {"I2S8", NULL, "I2S8_EN"}, + {"I2S8", NULL, "I2S9_EN", mtk_afe_i2s_share_connect}, + + {"I2S8", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S8", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S8", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S8", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S8", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S8", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S8", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S8", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S8", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S8_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S8_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S8", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S8", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S8", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S8", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S8", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S8", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S8", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S8", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S8", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S8_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S8_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s9 */ + {"I2S9_CH1", "DL1_CH1", "DL1"}, + {"I2S9_CH2", "DL1_CH2", "DL1"}, + + {"I2S9_CH1", "DL2_CH1", "DL2"}, + {"I2S9_CH2", "DL2_CH2", "DL2"}, + + {"I2S9_CH1", "DL3_CH1", "DL3"}, + {"I2S9_CH2", "DL3_CH2", "DL3"}, + + {"I2S9_CH1", "DL12_CH1", "DL12"}, + {"I2S9_CH2", "DL12_CH2", "DL12"}, + + {"I2S9_CH1", "DL4_CH1", "DL4"}, + {"I2S9_CH2", "DL4_CH2", "DL4"}, + + {"I2S9_CH1", "DL5_CH1", "DL5"}, + {"I2S9_CH2", "DL5_CH2", "DL5"}, + + {"I2S9_CH1", "DL6_CH1", "DL6"}, + {"I2S9_CH2", "DL6_CH2", "DL6"}, + + {"I2S9_CH1", "DL8_CH1", "DL8"}, + {"I2S9_CH2", "DL8_CH2", "DL8"}, + + {"I2S9_CH1", "DL9_CH1", "DL9"}, + {"I2S9_CH2", "DL9_CH2", "DL9"}, + + {"I2S9", NULL, "I2S9_CH1"}, + {"I2S9", NULL, "I2S9_CH2"}, + + {"I2S9", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S9", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S9", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S9", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S9", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + {"I2S9", NULL, "I2S6_EN", mtk_afe_i2s_share_connect}, + {"I2S9", NULL, "I2S7_EN", mtk_afe_i2s_share_connect}, + {"I2S9", NULL, "I2S8_EN", mtk_afe_i2s_share_connect}, + {"I2S9", NULL, "I2S9_EN"}, + + {"I2S9", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S9", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S9", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S9", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S9", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S9", NULL, I2S6_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S9", NULL, I2S7_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S9", NULL, I2S8_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S9", NULL, I2S9_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S9_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S9_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S9", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S9", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S9", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S9", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S9", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S9", NULL, I2S6_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S9", NULL, I2S7_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S9", NULL, I2S8_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S9", NULL, I2S9_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S9_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S9_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* allow i2s on without codec on */ + {"I2S0", NULL, "I2S0_In_Mux"}, + {"I2S0_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"}, + + {"I2S8", NULL, "I2S8_In_Mux"}, + {"I2S8_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"}, + + {"I2S1_Out_Mux", "Dummy_Widget", "I2S1"}, + {"I2S_DUMMY_OUT", NULL, "I2S1_Out_Mux"}, + + {"I2S3_Out_Mux", "Dummy_Widget", "I2S3"}, + {"I2S_DUMMY_OUT", NULL, "I2S3_Out_Mux"}, + + {"I2S5_Out_Mux", "Dummy_Widget", "I2S5"}, + {"I2S_DUMMY_OUT", NULL, "I2S5_Out_Mux"}, + + {"I2S7_Out_Mux", "Dummy_Widget", "I2S7"}, + {"I2S_DUMMY_OUT", NULL, "I2S7_Out_Mux"}, + + {"I2S9_Out_Mux", "Dummy_Widget", "I2S9"}, + {"I2S_DUMMY_OUT", NULL, "I2S9_Out_Mux"}, + + /* i2s in lpbk */ + {"I2S0_Lpbk_Mux", "Lpbk", "I2S3"}, + {"I2S2_Lpbk_Mux", "Lpbk", "I2S1"}, + {"I2S0", NULL, "I2S0_Lpbk_Mux"}, + {"I2S2", NULL, "I2S2_Lpbk_Mux"}, +}; + +/* dai ops */ +static int mtk_dai_connsys_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8192_rate_transform(afe->dev, + rate, dai->id); + unsigned int i2s_con = 0; + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, dai->id, substream->stream, rate); + + /* non-inverse, i2s mode, proxy mode, 16bits, from connsys */ + i2s_con |= 0 << INV_PAD_CTRL_SFT; + i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT; + i2s_con |= 1 << I2S_SRC_SFT; + i2s_con |= get_i2s_wlen(SNDRV_PCM_FORMAT_S16_LE) << I2S_WLEN_SFT; + i2s_con |= 0 << I2SIN_PAD_SEL_SFT; + regmap_write(afe->regmap, AFE_CONNSYS_I2S_CON, i2s_con); + + /* use asrc */ + regmap_update_bits(afe->regmap, + AFE_CONNSYS_I2S_CON, + I2S_BYPSRC_MASK_SFT, + 0x0 << I2S_BYPSRC_SFT); + + /* proxy mode, set i2s for asrc */ + regmap_update_bits(afe->regmap, + AFE_CONNSYS_I2S_CON, + I2S_MODE_MASK_SFT, + rate_reg << I2S_MODE_SFT); + + switch (rate) { + case 32000: + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x140000); + break; + case 44100: + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x001B9000); + break; + default: + regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x001E0000); + break; + } + + /* Calibration setting */ + regmap_write(afe->regmap, AFE_ASRC_2CH_CON4, 0x00140000); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON9, 0x00036000); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON10, 0x0002FC00); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON6, 0x00007EF4); + regmap_write(afe->regmap, AFE_ASRC_2CH_CON5, 0x00FF5986); + + /* 0:Stereo 1:Mono */ + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON2, + CHSET_IS_MONO_MASK_SFT, + 0x0 << CHSET_IS_MONO_SFT); + + return 0; +} + +static int mtk_dai_connsys_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s(), cmd %d, stream %d\n", + __func__, cmd, substream->stream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* i2s enable */ + regmap_update_bits(afe->regmap, + AFE_CONNSYS_I2S_CON, + I2S_EN_MASK_SFT, + 0x1 << I2S_EN_SFT); + + /* calibrator enable */ + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON5, + CALI_EN_MASK_SFT, + 0x1 << CALI_EN_SFT); + + /* asrc enable */ + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON0, + CON0_CHSET_STR_CLR_MASK_SFT, + 0x1 << CON0_CHSET_STR_CLR_SFT); + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON0, + CON0_ASM_ON_MASK_SFT, + 0x1 << CON0_ASM_ON_SFT); + + afe_priv->dai_on[dai->id] = true; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON0, + CON0_ASM_ON_MASK_SFT, + 0 << CON0_ASM_ON_SFT); + regmap_update_bits(afe->regmap, + AFE_ASRC_2CH_CON5, + CALI_EN_MASK_SFT, + 0 << CALI_EN_SFT); + + /* i2s disable */ + regmap_update_bits(afe->regmap, + AFE_CONNSYS_I2S_CON, + I2S_EN_MASK_SFT, + 0x0 << I2S_EN_SFT); + + /* bypass asrc */ + regmap_update_bits(afe->regmap, + AFE_CONNSYS_I2S_CON, + I2S_BYPSRC_MASK_SFT, + 0x1 << I2S_BYPSRC_SFT); + + afe_priv->dai_on[dai->id] = false; + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_connsys_i2s_ops = { + .hw_params = mtk_dai_connsys_i2s_hw_params, + .trigger = mtk_dai_connsys_i2s_trigger, +}; + +/* i2s */ +static int mtk_dai_i2s_config(struct mtk_base_afe *afe, + struct snd_pcm_hw_params *params, + int i2s_id) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id]; + + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8192_rate_transform(afe->dev, + rate, i2s_id); + snd_pcm_format_t format = params_format(params); + unsigned int i2s_con = 0; + int ret = 0; + + dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n", + __func__, i2s_id, rate, format); + + if (i2s_priv) + i2s_priv->rate = rate; + else + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + + switch (i2s_id) { + case MT8192_DAI_I2S_0: + i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT; + i2s_con |= rate_reg << I2S_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON, + 0xffffeffe, i2s_con); + break; + case MT8192_DAI_I2S_1: + i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT; + i2s_con |= rate_reg << I2S2_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON1, + 0xffffeffe, i2s_con); + break; + case MT8192_DAI_I2S_2: + i2s_con = 8 << I2S3_UPDATE_WORD_SFT; + i2s_con |= rate_reg << I2S3_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON2, + 0xffffeffe, i2s_con); + break; + case MT8192_DAI_I2S_3: + i2s_con = rate_reg << I2S4_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON3, + 0xffffeffe, i2s_con); + break; + case MT8192_DAI_I2S_5: + i2s_con = rate_reg << I2S5_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S5_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S5_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON4, + 0xffffeffe, i2s_con); + break; + case MT8192_DAI_I2S_6: + i2s_con = rate_reg << I2S6_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S6_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S6_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON6, + 0xffffeffe, i2s_con); + break; + case MT8192_DAI_I2S_7: + i2s_con = rate_reg << I2S7_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S7_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S7_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON7, + 0xffffeffe, i2s_con); + break; + case MT8192_DAI_I2S_8: + i2s_con = rate_reg << I2S8_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S8_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S8_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON8, + 0xffffeffe, i2s_con); + break; + case MT8192_DAI_I2S_9: + i2s_con = rate_reg << I2S9_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S9_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S9_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON9, + 0xffffeffe, i2s_con); + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, i2s_id); + return -EINVAL; + } + + /* set share i2s */ + if (i2s_priv && i2s_priv->share_i2s_id >= 0) + ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id); + + return ret; +} + +static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + return mtk_dai_i2s_config(afe, params, dai->id); +} + +static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id]; + int apll; + int apll_rate; + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq); + + apll = mt8192_get_apll_by_rate(afe, freq); + apll_rate = mt8192_get_apll_rate(afe, apll); + + if (freq > apll_rate) { + dev_warn(afe->dev, "%s(), freq > apll rate", __func__); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_warn(afe->dev, "%s(), APLL can't gen freq Hz", __func__); + return -EINVAL; + } + + i2s_priv->mclk_rate = freq; + i2s_priv->mclk_apll = apll; + + if (i2s_priv->share_i2s_id > 0) { + struct mtk_afe_i2s_priv *share_i2s_priv; + + share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id]; + if (!share_i2s_priv) { + dev_warn(afe->dev, "%s(), share_i2s_priv = NULL", + __func__); + return -EINVAL; + } + + share_i2s_priv->mclk_rate = i2s_priv->mclk_rate; + share_i2s_priv->mclk_apll = i2s_priv->mclk_apll; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_i2s_ops = { + .hw_params = mtk_dai_i2s_hw_params, + .set_sysclk = mtk_dai_i2s_set_sysclk, +}; + +/* dai driver */ +#define MTK_CONNSYS_I2S_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = { + { + .name = "CONNSYS_I2S", + .id = MT8192_DAI_CONNSYS_I2S, + .capture = { + .stream_name = "Connsys I2S", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_CONNSYS_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_connsys_i2s_ops, + }, + { + .name = "I2S0", + .id = MT8192_DAI_I2S_0, + .capture = { + .stream_name = "I2S0", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S1", + .id = MT8192_DAI_I2S_1, + .playback = { + .stream_name = "I2S1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S2", + .id = MT8192_DAI_I2S_2, + .capture = { + .stream_name = "I2S2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S3", + .id = MT8192_DAI_I2S_3, + .playback = { + .stream_name = "I2S3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S5", + .id = MT8192_DAI_I2S_5, + .playback = { + .stream_name = "I2S5", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S6", + .id = MT8192_DAI_I2S_6, + .capture = { + .stream_name = "I2S6", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S7", + .id = MT8192_DAI_I2S_7, + .playback = { + .stream_name = "I2S7", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S8", + .id = MT8192_DAI_I2S_8, + .capture = { + .stream_name = "I2S8", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S9", + .id = MT8192_DAI_I2S_9, + .playback = { + .stream_name = "I2S9", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + } +}; + +/* this enum is merely for mtk_afe_i2s_priv declare */ +enum { + DAI_I2S0 = 0, + DAI_I2S1, + DAI_I2S2, + DAI_I2S3, + DAI_I2S5, + DAI_I2S6, + DAI_I2S7, + DAI_I2S8, + DAI_I2S9, + DAI_I2S_NUM, +}; + +static const struct mtk_afe_i2s_priv mt8192_i2s_priv[DAI_I2S_NUM] = { + [DAI_I2S0] = { + .id = MT8192_DAI_I2S_0, + .mclk_id = MT8192_I2S0_MCK, + .share_property_name = "i2s0-share", + .share_i2s_id = -1, + }, + [DAI_I2S1] = { + .id = MT8192_DAI_I2S_1, + .mclk_id = MT8192_I2S1_MCK, + .share_property_name = "i2s1-share", + .share_i2s_id = -1, + }, + [DAI_I2S2] = { + .id = MT8192_DAI_I2S_2, + .mclk_id = MT8192_I2S2_MCK, + .share_property_name = "i2s2-share", + .share_i2s_id = -1, + }, + [DAI_I2S3] = { + .id = MT8192_DAI_I2S_3, + .mclk_id = MT8192_I2S3_MCK, + .share_property_name = "i2s3-share", + .share_i2s_id = -1, + }, + [DAI_I2S5] = { + .id = MT8192_DAI_I2S_5, + .mclk_id = MT8192_I2S5_MCK, + .share_property_name = "i2s5-share", + .share_i2s_id = -1, + }, + [DAI_I2S6] = { + .id = MT8192_DAI_I2S_6, + .mclk_id = MT8192_I2S6_MCK, + .share_property_name = "i2s6-share", + .share_i2s_id = -1, + }, + [DAI_I2S7] = { + .id = MT8192_DAI_I2S_7, + .mclk_id = MT8192_I2S7_MCK, + .share_property_name = "i2s7-share", + .share_i2s_id = -1, + }, + [DAI_I2S8] = { + .id = MT8192_DAI_I2S_8, + .mclk_id = MT8192_I2S8_MCK, + .share_property_name = "i2s8-share", + .share_i2s_id = -1, + }, + [DAI_I2S9] = { + .id = MT8192_DAI_I2S_9, + .mclk_id = MT8192_I2S9_MCK, + .share_property_name = "i2s9-share", + .share_i2s_id = -1, + }, +}; + +int mt8192_dai_i2s_get_share(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + const struct device_node *of_node = afe->dev->of_node; + const char *of_str; + const char *property_name; + struct mtk_afe_i2s_priv *i2s_priv; + int i; + + for (i = 0; i < DAI_I2S_NUM; i++) { + i2s_priv = afe_priv->dai_priv[mt8192_i2s_priv[i].id]; + property_name = mt8192_i2s_priv[i].share_property_name; + if (of_property_read_string(of_node, property_name, &of_str)) + continue; + i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str); + } + + return 0; +} + +int mt8192_dai_i2s_set_priv(struct mtk_base_afe *afe) +{ + int i; + int ret; + + for (i = 0; i < DAI_I2S_NUM; i++) { + ret = mt8192_dai_set_priv(afe, mt8192_i2s_priv[i].id, + sizeof(struct mtk_afe_i2s_priv), + &mt8192_i2s_priv[i]); + if (ret) + return ret; + } + + return 0; +} + +int mt8192_dai_i2s_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + int ret; + + dev_dbg(afe->dev, "%s()\n", __func__); + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_i2s_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver); + + dai->controls = mtk_dai_i2s_controls; + dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls); + dai->dapm_widgets = mtk_dai_i2s_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets); + dai->dapm_routes = mtk_dai_i2s_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes); + + /* set all dai i2s private data */ + ret = mt8192_dai_i2s_set_priv(afe); + if (ret) + return ret; + + /* parse share i2s */ + ret = mt8192_dai_i2s_get_share(afe); + if (ret) + return ret; + + return 0; +} -- cgit v1.2.3 From 607ac48595640d549a769f0dde0732e69c3a6c03 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Tue, 3 Nov 2020 15:59:33 +0800 Subject: ASoC: mediatek: mt8192: support adda in platform driver This patch adds mt8192 adda dai driver. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1604390378-23993-5-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-dai-adda.c | 1471 +++++++++++++++++++++++++++ 1 file changed, 1471 insertions(+) create mode 100644 sound/soc/mediatek/mt8192/mt8192-dai-adda.c (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c new file mode 100644 index 000000000000..f040dce85da5 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c @@ -0,0 +1,1471 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI ADDA Control +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Shane Chien +// + +#include +#include + +#include "mt8192-afe-clk.h" +#include "mt8192-afe-common.h" +#include "mt8192-afe-gpio.h" +#include "mt8192-interconnection.h" + +enum { + UL_IIR_SW = 0, + UL_IIR_5HZ, + UL_IIR_10HZ, + UL_IIR_25HZ, + UL_IIR_50HZ, + UL_IIR_75HZ, +}; + +enum { + AUDIO_SDM_LEVEL_MUTE = 0, + AUDIO_SDM_LEVEL_NORMAL = 0x1d, + /* if you change level normal */ + /* you need to change formula of hp impedance and dc trim too */ +}; + +enum { + AUDIO_SDM_2ND = 0, + AUDIO_SDM_3RD, +}; + +enum { + DELAY_DATA_MISO1 = 0, + DELAY_DATA_MISO2, +}; + +enum { + MTK_AFE_ADDA_DL_RATE_8K = 0, + MTK_AFE_ADDA_DL_RATE_11K = 1, + MTK_AFE_ADDA_DL_RATE_12K = 2, + MTK_AFE_ADDA_DL_RATE_16K = 3, + MTK_AFE_ADDA_DL_RATE_22K = 4, + MTK_AFE_ADDA_DL_RATE_24K = 5, + MTK_AFE_ADDA_DL_RATE_32K = 6, + MTK_AFE_ADDA_DL_RATE_44K = 7, + MTK_AFE_ADDA_DL_RATE_48K = 8, + MTK_AFE_ADDA_DL_RATE_96K = 9, + MTK_AFE_ADDA_DL_RATE_192K = 10, +}; + +enum { + MTK_AFE_ADDA_UL_RATE_8K = 0, + MTK_AFE_ADDA_UL_RATE_16K = 1, + MTK_AFE_ADDA_UL_RATE_32K = 2, + MTK_AFE_ADDA_UL_RATE_48K = 3, + MTK_AFE_ADDA_UL_RATE_96K = 4, + MTK_AFE_ADDA_UL_RATE_192K = 5, + MTK_AFE_ADDA_UL_RATE_48K_HD = 6, +}; + +#define SDM_AUTO_RESET_THRESHOLD 0x190000 + +static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_DL_RATE_8K; + case 11025: + return MTK_AFE_ADDA_DL_RATE_11K; + case 12000: + return MTK_AFE_ADDA_DL_RATE_12K; + case 16000: + return MTK_AFE_ADDA_DL_RATE_16K; + case 22050: + return MTK_AFE_ADDA_DL_RATE_22K; + case 24000: + return MTK_AFE_ADDA_DL_RATE_24K; + case 32000: + return MTK_AFE_ADDA_DL_RATE_32K; + case 44100: + return MTK_AFE_ADDA_DL_RATE_44K; + case 48000: + return MTK_AFE_ADDA_DL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_DL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_DL_RATE_192K; + default: + dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_DL_RATE_48K; + } +} + +static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_UL_RATE_8K; + case 16000: + return MTK_AFE_ADDA_UL_RATE_16K; + case 32000: + return MTK_AFE_ADDA_UL_RATE_32K; + case 48000: + return MTK_AFE_ADDA_UL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_UL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_UL_RATE_192K; + default: + dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_UL_RATE_48K; + } +} + +/* dai component */ +static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN3, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN3_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN3_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN3_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1", AFE_CONN3_1, I_DL8_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN3, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN3, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1", AFE_CONN3_1, + I_SRC_1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH1", AFE_CONN3_1, + I_SRC_2_OUT_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN4, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN4_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN4_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN4_1, I_DL6_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2", AFE_CONN4_1, I_DL8_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN4, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN4, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4, + I_PCM_2_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2", AFE_CONN4_1, + I_SRC_1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH2", AFE_CONN4_1, + I_SRC_2_OUT_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch3_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN52, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1", AFE_CONN52, I_DL12_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN52, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN52, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN52_1, I_DL4_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1", AFE_CONN52_1, I_DL5_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1", AFE_CONN52_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN52, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN52, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN52, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1", AFE_CONN52, + I_GAIN1_OUT_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN52, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN52, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN53, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN53, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2", AFE_CONN53, I_DL12_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN53, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN53, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN53, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN53, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN53_1, I_DL4_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2", AFE_CONN53_1, I_DL5_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2", AFE_CONN53_1, I_DL6_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN53, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN53, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN53, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2", AFE_CONN53, + I_GAIN1_OUT_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN53, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN53, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN53, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN53, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_stf_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN19, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_stf_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN20, + I_ADDA_UL_CH2, 1, 0), +}; + +enum { + SUPPLY_SEQ_ADDA_AFE_ON, + SUPPLY_SEQ_ADDA_DL_ON, + SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + SUPPLY_SEQ_ADDA_MTKAIF_CFG, + SUPPLY_SEQ_ADDA6_MTKAIF_CFG, + SUPPLY_SEQ_ADDA_FIFO, + SUPPLY_SEQ_ADDA_AP_DMIC, + SUPPLY_SEQ_ADDA_UL_ON, +}; + +static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id) +{ + unsigned int reg; + + switch (id) { + case MT8192_DAI_ADDA: + case MT8192_DAI_AP_DMIC: + reg = AFE_ADDA_UL_SRC_CON0; + break; + case MT8192_DAI_ADDA_CH34: + case MT8192_DAI_AP_DMIC_CH34: + reg = AFE_ADDA6_UL_SRC_CON0; + break; + default: + return -EINVAL; + } + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, reg, + DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT, + 0x0); + regmap_update_bits(afe->regmap, reg, + DMIC_LOW_POWER_MODE_CTL_MASK_SFT, + 0x0); + + /* turn on dmic, ch1, ch2 */ + regmap_update_bits(afe->regmap, reg, + UL_SDM_3_LEVEL_CTL_MASK_SFT, + 0x1 << UL_SDM_3_LEVEL_CTL_SFT); + regmap_update_bits(afe->regmap, reg, + UL_MODE_3P25M_CH1_CTL_MASK_SFT, + 0x1 << UL_MODE_3P25M_CH1_CTL_SFT); + regmap_update_bits(afe->regmap, reg, + UL_MODE_3P25M_CH2_CTL_MASK_SFT, + 0x1 << UL_MODE_3P25M_CH2_CTL_SFT); + return 0; +} + +static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int mtkaif_dmic = afe_priv->mtkaif_dmic; + + dev_info(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n", + __func__, w->name, event, mtkaif_dmic); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 1); + + /* update setting to dmic */ + if (mtkaif_dmic) { + /* mtkaif_rxif_data_mode = 1, dmic */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + 0x1, 0x1); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + MTKAIF_RXIF_VOICE_MODE_MASK_SFT, + 0x0); + mtk_adda_ul_src_dmic(afe, MT8192_DAI_ADDA); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 1); + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_ch34_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int mtkaif_dmic = afe_priv->mtkaif_dmic_ch34; + int mtkaif_adda6_only = afe_priv->mtkaif_adda6_only; + + dev_info(afe->dev, + "%s(), name %s, event 0x%x, mtkaif_dmic %d, mtkaif_adda6_only %d\n", + __func__, w->name, event, mtkaif_dmic, mtkaif_adda6_only); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, + 1); + + /* update setting to dmic */ + if (mtkaif_dmic) { + /* mtkaif_rxif_data_mode = 1, dmic */ + regmap_update_bits(afe->regmap, + AFE_ADDA6_MTKAIF_RX_CFG0, + 0x1, 0x1); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, + AFE_ADDA6_MTKAIF_RX_CFG0, + MTKAIF_RXIF_VOICE_MODE_MASK_SFT, + 0x0); + mtk_adda_ul_src_dmic(afe, MT8192_DAI_ADDA_CH34); + } + + /* when using adda6 without adda enabled, + * RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT need to be set or + * data cannot be received. + */ + if (mtkaif_adda6_only) { + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_SYNCWORD_CFG, + 0x1 << 23, 0x1 << 23); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, + 1); + + /* reset dmic */ + afe_priv->mtkaif_dmic_ch34 = 0; + + if (mtkaif_adda6_only) { + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_SYNCWORD_CFG, + 0x1 << 23, 0x0 << 23); + } + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x38); + else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30); + else + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x30); + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int delay_data; + int delay_cycle; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) { + /* set protocol 2 */ + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + 0x00010000); + regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0, + 0x00010000); + + if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0 && + (afe_priv->mtkaif_chosen_phase[0] < 0 || + afe_priv->mtkaif_chosen_phase[1] < 0)) { + dev_warn(afe->dev, + "%s(), mtkaif_chosen_phase[0/1]:%d/%d\n", + __func__, + afe_priv->mtkaif_chosen_phase[0], + afe_priv->mtkaif_chosen_phase[1]); + break; + } else if (strcmp(w->name, "ADDA6_MTKAIF_CFG") == 0 && + afe_priv->mtkaif_chosen_phase[2] < 0) { + dev_warn(afe->dev, + "%s(), mtkaif_chosen_phase[2]:%d\n", + __func__, + afe_priv->mtkaif_chosen_phase[2]); + break; + } + + /* mtkaif_rxif_clkinv_adc inverse for calibration */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + MTKAIF_RXIF_CLKINV_ADC_MASK_SFT, + 0x1 << MTKAIF_RXIF_CLKINV_ADC_SFT); + regmap_update_bits(afe->regmap, AFE_ADDA6_MTKAIF_CFG0, + MTKAIF_RXIF_CLKINV_ADC_MASK_SFT, + 0x1 << MTKAIF_RXIF_CLKINV_ADC_SFT); + + /* set delay for ch12 */ + if (afe_priv->mtkaif_phase_cycle[0] >= + afe_priv->mtkaif_phase_cycle[1]) { + delay_data = DELAY_DATA_MISO1; + delay_cycle = afe_priv->mtkaif_phase_cycle[0] - + afe_priv->mtkaif_phase_cycle[1]; + } else { + delay_data = DELAY_DATA_MISO2; + delay_cycle = afe_priv->mtkaif_phase_cycle[1] - + afe_priv->mtkaif_phase_cycle[0]; + } + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_DATA_MASK_SFT, + delay_data << + MTKAIF_RXIF_DELAY_DATA_SFT); + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT, + delay_cycle << + MTKAIF_RXIF_DELAY_CYCLE_SFT); + + /* set delay between ch3 and ch2 */ + if (afe_priv->mtkaif_phase_cycle[2] >= + afe_priv->mtkaif_phase_cycle[1]) { + delay_data = DELAY_DATA_MISO1; /* ch3 */ + delay_cycle = afe_priv->mtkaif_phase_cycle[2] - + afe_priv->mtkaif_phase_cycle[1]; + } else { + delay_data = DELAY_DATA_MISO2; /* ch2 */ + delay_cycle = afe_priv->mtkaif_phase_cycle[1] - + afe_priv->mtkaif_phase_cycle[2]; + } + + regmap_update_bits(afe->regmap, + AFE_ADDA6_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_DATA_MASK_SFT, + delay_data << + MTKAIF_RXIF_DELAY_DATA_SFT); + regmap_update_bits(afe->regmap, + AFE_ADDA6_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT, + delay_cycle << + MTKAIF_RXIF_DELAY_CYCLE_SFT); + } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) { + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + 0x00010000); + regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0, + 0x00010000); + } else { + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x0); + regmap_write(afe->regmap, AFE_ADDA6_MTKAIF_CFG0, 0x0); + } + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_info(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 0); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_adda_ch34_dl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_info(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, + 0); + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, + 0); + break; + default: + break; + } + + return 0; +} + +/* stf */ +static int stf_positive_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->stf_positive_gain_db; + return 0; +} + +static int stf_positive_gain_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int gain_db = ucontrol->value.integer.value[0]; + + afe_priv->stf_positive_gain_db = gain_db; + + if (gain_db >= 0 && gain_db <= 24) { + regmap_update_bits(afe->regmap, + AFE_SIDETONE_GAIN, + POSITIVE_GAIN_MASK_SFT, + (gain_db / 6) << POSITIVE_GAIN_SFT); + } else { + dev_warn(afe->dev, "%s(), gain_db %d invalid\n", + __func__, gain_db); + } + return 0; +} + +static int mt8192_adda_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic; + return 0; +} + +static int mt8192_adda_dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int dmic_on; + + dmic_on = ucontrol->value.integer.value[0]; + + dev_info(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n", + __func__, kcontrol->id.name, dmic_on); + + afe_priv->mtkaif_dmic = dmic_on; + afe_priv->mtkaif_dmic_ch34 = dmic_on; + return 0; +} + +static int mt8192_adda6_only_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->mtkaif_adda6_only; + return 0; +} + +static int mt8192_adda6_only_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int mtkaif_adda6_only; + + mtkaif_adda6_only = ucontrol->value.integer.value[0]; + + dev_info(afe->dev, "%s(), kcontrol name %s, mtkaif_adda6_only %d\n", + __func__, kcontrol->id.name, mtkaif_adda6_only); + + afe_priv->mtkaif_adda6_only = mtkaif_adda6_only; + return 0; +} + +static const struct snd_kcontrol_new mtk_adda_controls[] = { + SOC_SINGLE("Sidetone_Gain", AFE_SIDETONE_GAIN, + SIDE_TONE_GAIN_SFT, SIDE_TONE_GAIN_MASK, 0), + SOC_SINGLE_EXT("Sidetone_Positive_Gain_dB", SND_SOC_NOPM, 0, 100, 0, + stf_positive_gain_get, stf_positive_gain_set), + SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1, + DL_2_GAIN_CTL_PRE_SFT, DL_2_GAIN_CTL_PRE_MASK, 0), + SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0, + mt8192_adda_dmic_get, mt8192_adda_dmic_set), + SOC_SINGLE_BOOL_EXT("MTKAIF_ADDA6_ONLY Switch", 0, + mt8192_adda6_only_get, mt8192_adda6_only_set), +}; + +static const struct snd_kcontrol_new stf_ctl = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const u16 stf_coeff_table_16k[] = { + 0x049C, 0x09E8, 0x09E0, 0x089C, + 0xFF54, 0xF488, 0xEAFC, 0xEBAC, + 0xfA40, 0x17AC, 0x3D1C, 0x6028, + 0x7538 +}; + +static const u16 stf_coeff_table_32k[] = { + 0xFE52, 0x0042, 0x00C5, 0x0194, + 0x029A, 0x03B7, 0x04BF, 0x057D, + 0x05BE, 0x0555, 0x0426, 0x0230, + 0xFF92, 0xFC89, 0xF973, 0xF6C6, + 0xF500, 0xF49D, 0xF603, 0xF970, + 0xFEF3, 0x065F, 0x0F4F, 0x1928, + 0x2329, 0x2C80, 0x345E, 0x3A0D, + 0x3D08 +}; + +static const u16 stf_coeff_table_48k[] = { + 0x0401, 0xFFB0, 0xFF5A, 0xFECE, + 0xFE10, 0xFD28, 0xFC21, 0xFB08, + 0xF9EF, 0xF8E8, 0xF80A, 0xF76C, + 0xF724, 0xF746, 0xF7E6, 0xF90F, + 0xFACC, 0xFD1E, 0xFFFF, 0x0364, + 0x0737, 0x0B62, 0x0FC1, 0x1431, + 0x188A, 0x1CA4, 0x2056, 0x237D, + 0x25F9, 0x27B0, 0x2890 +}; + +static int mtk_stf_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + size_t half_tap_num; + const u16 *stf_coeff_table; + unsigned int ul_rate, reg_value; + size_t coef_addr; + + regmap_read(afe->regmap, AFE_ADDA_UL_SRC_CON0, &ul_rate); + ul_rate = ul_rate >> UL_VOICE_MODE_CH1_CH2_CTL_SFT; + ul_rate = ul_rate & UL_VOICE_MODE_CH1_CH2_CTL_MASK; + + if (ul_rate == MTK_AFE_ADDA_UL_RATE_48K) { + half_tap_num = ARRAY_SIZE(stf_coeff_table_48k); + stf_coeff_table = stf_coeff_table_48k; + } else if (ul_rate == MTK_AFE_ADDA_UL_RATE_32K) { + half_tap_num = ARRAY_SIZE(stf_coeff_table_32k); + stf_coeff_table = stf_coeff_table_32k; + } else { + half_tap_num = ARRAY_SIZE(stf_coeff_table_16k); + stf_coeff_table = stf_coeff_table_16k; + } + + regmap_read(afe->regmap, AFE_SIDETONE_CON1, ®_value); + + dev_info(afe->dev, "%s(), name %s, event 0x%x, ul_rate 0x%x, AFE_SIDETONE_CON1 0x%x\n", + __func__, w->name, event, ul_rate, reg_value); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* set side tone gain = 0 */ + regmap_update_bits(afe->regmap, + AFE_SIDETONE_GAIN, + SIDE_TONE_GAIN_MASK_SFT, + 0); + regmap_update_bits(afe->regmap, + AFE_SIDETONE_GAIN, + POSITIVE_GAIN_MASK_SFT, + 0); + /* don't bypass stf */ + regmap_update_bits(afe->regmap, + AFE_SIDETONE_CON1, + 0x1f << 27, + 0x0); + /* set stf half tap num */ + regmap_update_bits(afe->regmap, + AFE_SIDETONE_CON1, + SIDE_TONE_HALF_TAP_NUM_MASK_SFT, + half_tap_num << SIDE_TONE_HALF_TAP_NUM_SFT); + + /* set side tone coefficient */ + regmap_read(afe->regmap, AFE_SIDETONE_CON0, ®_value); + for (coef_addr = 0; coef_addr < half_tap_num; coef_addr++) { + bool old_w_ready = (reg_value >> W_RDY_SFT) & 0x1; + bool new_w_ready = 0; + int try_cnt = 0; + + regmap_update_bits(afe->regmap, + AFE_SIDETONE_CON0, + 0x39FFFFF, + (1 << R_W_EN_SFT) | + (1 << R_W_SEL_SFT) | + (0 << SEL_CH2_SFT) | + (coef_addr << + SIDE_TONE_COEFFICIENT_ADDR_SFT) | + stf_coeff_table[coef_addr]); + + /* wait until flag write_ready changed */ + for (try_cnt = 0; try_cnt < 10; try_cnt++) { + regmap_read(afe->regmap, + AFE_SIDETONE_CON0, ®_value); + new_w_ready = (reg_value >> W_RDY_SFT) & 0x1; + + /* flip => ok */ + if (new_w_ready == old_w_ready) { + udelay(3); + if (try_cnt == 9) { + dev_warn(afe->dev, + "%s(), write coeff not ready", + __func__); + } + } else { + break; + } + } + /* need write -> read -> write to write next coeff */ + regmap_update_bits(afe->regmap, + AFE_SIDETONE_CON0, + R_W_SEL_MASK_SFT, + 0x0); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* bypass stf */ + regmap_update_bits(afe->regmap, + AFE_SIDETONE_CON1, + 0x1f << 27, + 0x1f << 27); + + /* set side tone gain = 0 */ + regmap_update_bits(afe->regmap, + AFE_SIDETONE_GAIN, + SIDE_TONE_GAIN_MASK_SFT, + 0); + regmap_update_bits(afe->regmap, + AFE_SIDETONE_GAIN, + POSITIVE_GAIN_MASK_SFT, + 0); + break; + default: + break; + } + + return 0; +} + +/* stf mux */ +enum { + STF_SRC_ADDA_ADDA6 = 0, + STF_SRC_O19O20, +}; + +static const char *const stf_o19o20_mux_map[] = { + "ADDA_ADDA6", + "O19O20", +}; + +static int stf_o19o20_mux_map_value[] = { + STF_SRC_ADDA_ADDA6, + STF_SRC_O19O20, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(stf_o19o20_mux_map_enum, + AFE_SIDETONE_CON1, + STF_SOURCE_FROM_O19O20_SFT, + STF_SOURCE_FROM_O19O20_MASK, + stf_o19o20_mux_map, + stf_o19o20_mux_map_value); + +static const struct snd_kcontrol_new stf_o19O20_mux_control = + SOC_DAPM_ENUM("STF_O19O20_MUX", stf_o19o20_mux_map_enum); + +enum { + STF_SRC_ADDA = 0, + STF_SRC_ADDA6, +}; + +static const char *const stf_adda_mux_map[] = { + "ADDA", + "ADDA6", +}; + +static int stf_adda_mux_map_value[] = { + STF_SRC_ADDA, + STF_SRC_ADDA6, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(stf_adda_mux_map_enum, + AFE_SIDETONE_CON1, + STF_O19O20_OUT_EN_SEL_SFT, + STF_O19O20_OUT_EN_SEL_MASK, + stf_adda_mux_map, + stf_adda_mux_map_value); + +static const struct snd_kcontrol_new stf_adda_mux_control = + SOC_DAPM_ENUM("STF_ADDA_MUX", stf_adda_mux_map_enum); + +/* ADDA UL MUX */ +enum { + ADDA_UL_MUX_MTKAIF = 0, + ADDA_UL_MUX_AP_DMIC, + ADDA_UL_MUX_MASK = 0x1, +}; + +static const char * const adda_ul_mux_map[] = { + "MTKAIF", "AP_DMIC" +}; + +static int adda_ul_map_value[] = { + ADDA_UL_MUX_MTKAIF, + ADDA_UL_MUX_AP_DMIC, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum, + SND_SOC_NOPM, + 0, + ADDA_UL_MUX_MASK, + adda_ul_mux_map, + adda_ul_map_value); + +static const struct snd_kcontrol_new adda_ul_mux_control = + SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum); + +static const struct snd_kcontrol_new adda_ch34_ul_mux_control = + SOC_DAPM_ENUM("ADDA_CH34_UL_MUX Select", adda_ul_mux_map_enum); + +static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch1_mix, + ARRAY_SIZE(mtk_adda_dl_ch1_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch2_mix, + ARRAY_SIZE(mtk_adda_dl_ch2_mix)), + + SND_SOC_DAPM_MIXER("ADDA_DL_CH3", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch3_mix, + ARRAY_SIZE(mtk_adda_dl_ch3_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH4", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch4_mix, + ARRAY_SIZE(mtk_adda_dl_ch4_mix)), + + SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON, + AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON, + AFE_ADDA_DL_SRC2_CON0, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, + mtk_adda_dl_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Playback Enable", + SUPPLY_SEQ_ADDA_DL_ON, + AFE_ADDA_3RD_DAC_DL_SRC2_CON0, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, + mtk_adda_ch34_dl_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA_UL_SRC_CON0, + UL_SRC_ON_TMP_CTL_SFT, 0, + mtk_adda_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("ADDA CH34 Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA6_UL_SRC_CON0, + UL_SRC_ON_TMP_CTL_SFT, 0, + mtk_adda_ch34_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP, + AFE_AUD_PAD_TOP, + RG_RX_FIFO_ON_SFT, 0, + mtk_adda_pad_top_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG, + SND_SOC_NOPM, 0, 0, + mtk_adda_mtkaif_cfg_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("ADDA6_MTKAIF_CFG", SUPPLY_SEQ_ADDA6_MTKAIF_CFG, + SND_SOC_NOPM, 0, 0, + mtk_adda_mtkaif_cfg_event, + SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC, + AFE_ADDA_UL_SRC_CON0, + UL_AP_DMIC_ON_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AP_DMIC_CH34_EN", SUPPLY_SEQ_ADDA_AP_DMIC, + AFE_ADDA6_UL_SRC_CON0, + UL_AP_DMIC_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO, + AFE_ADDA_UL_DL_CON0, + AFE_ADDA_FIFO_AUTO_RST_SFT, 1, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADDA_CH34_FIFO", SUPPLY_SEQ_ADDA_FIFO, + AFE_ADDA_UL_DL_CON0, + AFE_ADDA6_FIFO_AUTO_RST_SFT, 1, + NULL, 0), + + SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0, + &adda_ul_mux_control), + SND_SOC_DAPM_MUX("ADDA_CH34_UL_Mux", SND_SOC_NOPM, 0, 0, + &adda_ch34_ul_mux_control), + + SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"), + SND_SOC_DAPM_INPUT("AP_DMIC_CH34_INPUT"), + + /* stf */ + SND_SOC_DAPM_SWITCH_E("Sidetone Filter", + AFE_SIDETONE_CON1, SIDE_TONE_ON_SFT, 0, + &stf_ctl, + mtk_stf_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("STF_O19O20_MUX", SND_SOC_NOPM, 0, 0, + &stf_o19O20_mux_control), + SND_SOC_DAPM_MUX("STF_ADDA_MUX", SND_SOC_NOPM, 0, 0, + &stf_adda_mux_control), + SND_SOC_DAPM_MIXER("STF_CH1", SND_SOC_NOPM, 0, 0, + mtk_stf_ch1_mix, + ARRAY_SIZE(mtk_stf_ch1_mix)), + SND_SOC_DAPM_MIXER("STF_CH2", SND_SOC_NOPM, 0, 0, + mtk_stf_ch2_mix, + ARRAY_SIZE(mtk_stf_ch2_mix)), + SND_SOC_DAPM_OUTPUT("STF_OUTPUT"), + + /* clock */ + SND_SOC_DAPM_CLOCK_SUPPLY("top_mux_audio_h"), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_3rd_dac_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_3rd_dac_predis_clk"), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_adda6_adc_clk"), +}; + +static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { + /* playback */ + {"ADDA_DL_CH1", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH2", "DL1"}, + + {"ADDA_DL_CH1", "DL12_CH1", "DL12"}, + {"ADDA_DL_CH2", "DL12_CH2", "DL12"}, + + {"ADDA_DL_CH1", "DL6_CH1", "DL6"}, + {"ADDA_DL_CH2", "DL6_CH2", "DL6"}, + + {"ADDA_DL_CH1", "DL8_CH1", "DL8"}, + {"ADDA_DL_CH2", "DL8_CH2", "DL8"}, + + {"ADDA_DL_CH1", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH2", "DL2"}, + + {"ADDA_DL_CH1", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH2", "DL3"}, + + {"ADDA_DL_CH1", "DL4_CH1", "DL4"}, + {"ADDA_DL_CH2", "DL4_CH2", "DL4"}, + + {"ADDA_DL_CH1", "DL5_CH1", "DL5"}, + {"ADDA_DL_CH2", "DL5_CH2", "DL5"}, + + {"ADDA Playback", NULL, "ADDA_DL_CH1"}, + {"ADDA Playback", NULL, "ADDA_DL_CH2"}, + + {"ADDA Playback", NULL, "ADDA Enable"}, + {"ADDA Playback", NULL, "ADDA Playback Enable"}, + + {"ADDA_DL_CH3", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH4", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH4", "DL1_CH2", "DL1"}, + + {"ADDA_DL_CH3", "DL12_CH1", "DL12"}, + {"ADDA_DL_CH4", "DL12_CH2", "DL12"}, + + {"ADDA_DL_CH3", "DL6_CH1", "DL6"}, + {"ADDA_DL_CH4", "DL6_CH2", "DL6"}, + + {"ADDA_DL_CH3", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH4", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH4", "DL2_CH2", "DL2"}, + + {"ADDA_DL_CH3", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH4", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH4", "DL3_CH2", "DL3"}, + + {"ADDA_DL_CH3", "DL4_CH1", "DL4"}, + {"ADDA_DL_CH4", "DL4_CH2", "DL4"}, + + {"ADDA_DL_CH3", "DL5_CH1", "DL5"}, + {"ADDA_DL_CH4", "DL5_CH2", "DL5"}, + + {"ADDA CH34 Playback", NULL, "ADDA_DL_CH3"}, + {"ADDA CH34 Playback", NULL, "ADDA_DL_CH4"}, + + {"ADDA CH34 Playback", NULL, "ADDA Enable"}, + {"ADDA CH34 Playback", NULL, "ADDA CH34 Playback Enable"}, + + /* capture */ + {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"}, + {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"}, + + {"ADDA_CH34_UL_Mux", "MTKAIF", "ADDA CH34 Capture"}, + {"ADDA_CH34_UL_Mux", "AP_DMIC", "AP DMIC CH34 Capture"}, + + {"ADDA Capture", NULL, "ADDA Enable"}, + {"ADDA Capture", NULL, "ADDA Capture Enable"}, + {"ADDA Capture", NULL, "AUD_PAD_TOP"}, + {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"}, + + {"AP DMIC Capture", NULL, "ADDA Enable"}, + {"AP DMIC Capture", NULL, "ADDA Capture Enable"}, + {"AP DMIC Capture", NULL, "ADDA_FIFO"}, + {"AP DMIC Capture", NULL, "AP_DMIC_EN"}, + + {"ADDA CH34 Capture", NULL, "ADDA Enable"}, + {"ADDA CH34 Capture", NULL, "ADDA CH34 Capture Enable"}, + {"ADDA CH34 Capture", NULL, "AUD_PAD_TOP"}, + {"ADDA CH34 Capture", NULL, "ADDA6_MTKAIF_CFG"}, + + {"AP DMIC CH34 Capture", NULL, "ADDA Enable"}, + {"AP DMIC CH34 Capture", NULL, "ADDA CH34 Capture Enable"}, + {"AP DMIC CH34 Capture", NULL, "ADDA_CH34_FIFO"}, + {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_EN"}, + + {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"}, + {"AP DMIC CH34 Capture", NULL, "AP_DMIC_CH34_INPUT"}, + + /* sidetone filter */ + {"STF_ADDA_MUX", "ADDA", "ADDA_UL_Mux"}, + {"STF_ADDA_MUX", "ADDA6", "ADDA_CH34_UL_Mux"}, + + {"STF_O19O20_MUX", "ADDA_ADDA6", "STF_ADDA_MUX"}, + {"STF_O19O20_MUX", "O19O20", "STF_CH1"}, + {"STF_O19O20_MUX", "O19O20", "STF_CH2"}, + + {"Sidetone Filter", "Switch", "STF_O19O20_MUX"}, + {"STF_OUTPUT", NULL, "Sidetone Filter"}, + {"ADDA Playback", NULL, "Sidetone Filter"}, + {"ADDA CH34 Playback", NULL, "Sidetone Filter"}, + + /* clk */ + {"ADDA Playback", NULL, "aud_dac_clk"}, + {"ADDA Playback", NULL, "aud_dac_predis_clk"}, + + {"ADDA CH34 Playback", NULL, "aud_3rd_dac_clk"}, + {"ADDA CH34 Playback", NULL, "aud_3rd_dac_predis_clk"}, + + {"ADDA Capture Enable", NULL, "aud_adc_clk"}, + {"ADDA CH34 Capture Enable", NULL, "aud_adda6_adc_clk"}, +}; + +/* dai ops */ +static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + int id = dai->id; + + dev_info(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, + id, + substream->stream, + rate); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + unsigned int dl_src2_con0 = 0; + unsigned int dl_src2_con1 = 0; + + /* set sampling rate */ + dl_src2_con0 = adda_dl_rate_transform(afe, rate) << + DL_2_INPUT_MODE_CTL_SFT; + + /* set output mode, UP_SAMPLING_RATE_X8 */ + dl_src2_con0 |= (0x3 << DL_2_OUTPUT_SEL_CTL_SFT); + + /* turn off mute function */ + dl_src2_con0 |= (0x01 << DL_2_MUTE_CH2_OFF_CTL_PRE_SFT); + dl_src2_con0 |= (0x01 << DL_2_MUTE_CH1_OFF_CTL_PRE_SFT); + + /* set voice input data if input sample rate is 8k or 16k */ + if (rate == 8000 || rate == 16000) + dl_src2_con0 |= 0x01 << DL_2_VOICE_MODE_CTL_PRE_SFT; + + /* SA suggest apply -0.3db to audio/speech path */ + dl_src2_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL << + DL_2_GAIN_CTL_PRE_SFT; + + /* turn on down-link gain */ + dl_src2_con0 |= (0x01 << DL_2_GAIN_ON_CTL_PRE_SFT); + + if (id == MT8192_DAI_ADDA) { + /* clean predistortion */ + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0); + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0); + + regmap_write(afe->regmap, + AFE_ADDA_DL_SRC2_CON0, dl_src2_con0); + regmap_write(afe->regmap, + AFE_ADDA_DL_SRC2_CON1, dl_src2_con1); + + /* set sdm gain */ + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DCCOMP_CON, + ATTGAIN_CTL_MASK_SFT, + AUDIO_SDM_LEVEL_NORMAL << + ATTGAIN_CTL_SFT); + + /* 2nd sdm */ + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DCCOMP_CON, + USE_3RD_SDM_MASK_SFT, + AUDIO_SDM_2ND << USE_3RD_SDM_SFT); + + /* sdm auto reset */ + regmap_write(afe->regmap, + AFE_ADDA_DL_SDM_AUTO_RESET_CON, + SDM_AUTO_RESET_THRESHOLD); + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_AUTO_RESET_CON, + ADDA_SDM_AUTO_RESET_ONOFF_MASK_SFT, + 0x1 << ADDA_SDM_AUTO_RESET_ONOFF_SFT); + } else { + /* clean predistortion */ + regmap_write(afe->regmap, + AFE_ADDA_3RD_DAC_PREDIS_CON0, 0); + regmap_write(afe->regmap, + AFE_ADDA_3RD_DAC_PREDIS_CON1, 0); + + regmap_write(afe->regmap, AFE_ADDA_3RD_DAC_DL_SRC2_CON0, + dl_src2_con0); + regmap_write(afe->regmap, AFE_ADDA_3RD_DAC_DL_SRC2_CON1, + dl_src2_con1); + + /* set sdm gain */ + regmap_update_bits(afe->regmap, + AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON, + ATTGAIN_CTL_MASK_SFT, + AUDIO_SDM_LEVEL_NORMAL << + ATTGAIN_CTL_SFT); + + /* 2nd sdm */ + regmap_update_bits(afe->regmap, + AFE_ADDA_3RD_DAC_DL_SDM_DCCOMP_CON, + USE_3RD_SDM_MASK_SFT, + AUDIO_SDM_2ND << USE_3RD_SDM_SFT); + + /* sdm auto reset */ + regmap_write(afe->regmap, + AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON, + SDM_AUTO_RESET_THRESHOLD); + regmap_update_bits(afe->regmap, + AFE_ADDA_3RD_DAC_DL_SDM_AUTO_RESET_CON, + ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_MASK_SFT, + 0x1 << ADDA_3RD_DAC_SDM_AUTO_RESET_ONOFF_SFT); + } + } else { + unsigned int voice_mode = 0; + unsigned int ul_src_con0 = 0; /* default value */ + + voice_mode = adda_ul_rate_transform(afe, rate); + + ul_src_con0 |= (voice_mode << 17) & (0x7 << 17); + + /* enable iir */ + ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) & + UL_IIR_ON_TMP_CTL_MASK_SFT; + ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) & + UL_IIRMODE_CTL_MASK_SFT; + + switch (id) { + case MT8192_DAI_ADDA: + case MT8192_DAI_AP_DMIC: + /* 35Hz @ 48k */ + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_02_01, 0x00000000); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_04_03, 0x00003FB8); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_06_05, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_08_07, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA_IIR_COEF_10_09, 0x0000C048); + + regmap_write(afe->regmap, + AFE_ADDA_UL_SRC_CON0, ul_src_con0); + + /* Using Internal ADC */ + regmap_update_bits(afe->regmap, + AFE_ADDA_TOP_CON0, + 0x1 << 0, + 0x0 << 0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG0, + 0x1 << 0, + 0x0 << 0); + break; + case MT8192_DAI_ADDA_CH34: + case MT8192_DAI_AP_DMIC_CH34: + /* 35Hz @ 48k */ + regmap_write(afe->regmap, + AFE_ADDA6_IIR_COEF_02_01, 0x00000000); + regmap_write(afe->regmap, + AFE_ADDA6_IIR_COEF_04_03, 0x00003FB8); + regmap_write(afe->regmap, + AFE_ADDA6_IIR_COEF_06_05, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA6_IIR_COEF_08_07, 0x3FB80000); + regmap_write(afe->regmap, + AFE_ADDA6_IIR_COEF_10_09, 0x0000C048); + + regmap_write(afe->regmap, + AFE_ADDA6_UL_SRC_CON0, ul_src_con0); + + /* Using Internal ADC */ + regmap_update_bits(afe->regmap, + AFE_ADDA6_TOP_CON0, + 0x1 << 0, + 0x0 << 0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, + AFE_ADDA6_MTKAIF_RX_CFG0, + 0x1 << 0, + 0x0 << 0); + break; + default: + break; + } + + /* ap dmic */ + switch (id) { + case MT8192_DAI_AP_DMIC: + case MT8192_DAI_AP_DMIC_CH34: + mtk_adda_ul_src_dmic(afe, id); + break; + default: + break; + } + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_adda_ops = { + .hw_params = mtk_dai_adda_hw_params, +}; + +/* dai driver */ +#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { + { + .name = "ADDA", + .id = MT8192_DAI_ADDA, + .playback = { + .stream_name = "ADDA Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_PLAYBACK_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .capture = { + .stream_name = "ADDA Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "ADDA_CH34", + .id = MT8192_DAI_ADDA_CH34, + .playback = { + .stream_name = "ADDA CH34 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_PLAYBACK_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .capture = { + .stream_name = "ADDA CH34 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "AP_DMIC", + .id = MT8192_DAI_AP_DMIC, + .capture = { + .stream_name = "AP DMIC Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, + { + .name = "AP_DMIC_CH34", + .id = MT8192_DAI_AP_DMIC_CH34, + .capture = { + .stream_name = "AP DMIC CH34 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, +}; + +int mt8192_dai_adda_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + dev_info(afe->dev, "%s()\n", __func__); + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_adda_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); + + dai->controls = mtk_adda_controls; + dai->num_controls = ARRAY_SIZE(mtk_adda_controls); + dai->dapm_widgets = mtk_dai_adda_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); + dai->dapm_routes = mtk_dai_adda_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); + + /* ap dmic priv share with adda */ + afe_priv->dai_priv[MT8192_DAI_AP_DMIC] = + afe_priv->dai_priv[MT8192_DAI_ADDA]; + afe_priv->dai_priv[MT8192_DAI_AP_DMIC_CH34] = + afe_priv->dai_priv[MT8192_DAI_ADDA_CH34]; + + return 0; +} -- cgit v1.2.3 From c63b7866011e63038d32bc37f3abd0deabbc34f6 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Tue, 3 Nov 2020 15:59:34 +0800 Subject: ASoC: mediatek: mt8192: support pcm in platform driver This patch adds mt8192 pcm dai driver. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1604390378-23993-6-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-dai-pcm.c | 409 +++++++++++++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 sound/soc/mediatek/mt8192/mt8192-dai-pcm.c (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c b/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c new file mode 100644 index 000000000000..6e94cfdf06fc --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Shane Chien +// + +#include +#include + +#include "mt8192-afe-common.h" +#include "mt8192-interconnection.h" + +enum AUD_TX_LCH_RPT { + AUD_TX_LCH_RPT_NO_REPEAT = 0, + AUD_TX_LCH_RPT_REPEAT = 1 +}; + +enum AUD_VBT_16K_MODE { + AUD_VBT_16K_MODE_DISABLE = 0, + AUD_VBT_16K_MODE_ENABLE = 1 +}; + +enum AUD_EXT_MODEM { + AUD_EXT_MODEM_SELECT_INTERNAL = 0, + AUD_EXT_MODEM_SELECT_EXTERNAL = 1 +}; + +enum AUD_PCM_SYNC_TYPE { + /* bck sync length = 1 */ + AUD_PCM_ONE_BCK_CYCLE_SYNC = 0, + /* bck sync length = PCM_INTF_CON1[9:13] */ + AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1 +}; + +enum AUD_BT_MODE { + AUD_BT_MODE_DUAL_MIC_ON_TX = 0, + AUD_BT_MODE_SINGLE_MIC_ON_TX = 1 +}; + +enum AUD_PCM_AFIFO_SRC { + /* slave mode & external modem uses different crystal */ + AUD_PCM_AFIFO_ASRC = 0, + /* slave mode & external modem uses the same crystal */ + AUD_PCM_AFIFO_AFIFO = 1 +}; + +enum AUD_PCM_CLOCK_SOURCE { + AUD_PCM_CLOCK_MASTER_MODE = 0, + AUD_PCM_CLOCK_SLAVE_MODE = 1 +}; + +enum AUD_PCM_WLEN { + AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0, + AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1 +}; + +enum AUD_PCM_MODE { + AUD_PCM_MODE_PCM_MODE_8K = 0, + AUD_PCM_MODE_PCM_MODE_16K = 1, + AUD_PCM_MODE_PCM_MODE_32K = 2, + AUD_PCM_MODE_PCM_MODE_48K = 3, +}; + +enum AUD_PCM_FMT { + AUD_PCM_FMT_I2S = 0, + AUD_PCM_FMT_EIAJ = 1, + AUD_PCM_FMT_PCM_MODE_A = 2, + AUD_PCM_FMT_PCM_MODE_B = 3 +}; + +enum AUD_BCLK_OUT_INV { + AUD_BCLK_OUT_INV_NO_INVERSE = 0, + AUD_BCLK_OUT_INV_INVERSE = 1 +}; + +enum AUD_PCM_EN { + AUD_PCM_EN_DISABLE = 0, + AUD_PCM_EN_ENABLE = 1 +}; + +/* dai component */ +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN7_1, + I_DL4_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN8_1, + I_DL4_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN27, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN27, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN27, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN27, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN27_1, + I_DL4_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN17, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN17, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN17_1, + I_DL4_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN18, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN18, + I_ADDA_UL_CH3, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN18_1, + I_DL4_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch3_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN23, + I_ADDA_UL_CH3, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN24, + I_I2S0_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN24, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN24, + I_I2S2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN24, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN24_1, + I_DL4_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch5_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN25, + I_I2S0_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN25, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN25, + I_I2S2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN25_1, + I_DL4_CH2, 1, 0), +}; + +static int mtk_pcm_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_info(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch1_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)), + SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch2_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)), + SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch4_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch1_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch2_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH3", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch3_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch3_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch4_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH5", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch5_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch5_mix)), + + SND_SOC_DAPM_SUPPLY("PCM_1_EN", + PCM_INTF_CON1, PCM_EN_SFT, 0, + mtk_pcm_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("PCM_2_EN", + PCM2_INTF_CON, PCM2_EN_SFT, 0, + mtk_pcm_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("MD1_TO_AFE"), + SND_SOC_DAPM_INPUT("MD2_TO_AFE"), + SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"), + SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"), +}; + +static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { + {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"}, + {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"}, + {"PCM 1 Playback", NULL, "PCM_1_PB_CH4"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH1"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH2"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH3"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH4"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH5"}, + + {"PCM 1 Playback", NULL, "PCM_1_EN"}, + {"PCM 2 Playback", NULL, "PCM_2_EN"}, + {"PCM 1 Capture", NULL, "PCM_1_EN"}, + {"PCM 2 Capture", NULL, "PCM_2_EN"}, + + {"AFE_TO_MD1", NULL, "PCM 2 Playback"}, + {"AFE_TO_MD2", NULL, "PCM 1 Playback"}, + {"PCM 2 Capture", NULL, "MD1_TO_AFE"}, + {"PCM 1 Capture", NULL, "MD2_TO_AFE"}, + + {"PCM_1_PB_CH1", "DL2_CH1", "DL2"}, + {"PCM_1_PB_CH2", "DL2_CH2", "DL2"}, + {"PCM_1_PB_CH4", "DL1_CH1", "DL1"}, + {"PCM_2_PB_CH1", "DL2_CH1", "DL2"}, + {"PCM_2_PB_CH2", "DL2_CH2", "DL2"}, + {"PCM_2_PB_CH4", "DL1_CH1", "DL1"}, + + {"PCM_1_PB_CH1", "DL4_CH1", "DL4"}, + {"PCM_1_PB_CH2", "DL4_CH2", "DL4"}, + {"PCM_1_PB_CH4", "DL4_CH1", "DL4"}, + {"PCM_2_PB_CH1", "DL4_CH1", "DL4"}, + {"PCM_2_PB_CH2", "DL4_CH2", "DL4"}, + {"PCM_2_PB_CH4", "DL4_CH1", "DL4"}, + {"PCM_1_PB_CH4", "I2S0_CH1", "I2S0"}, + {"PCM_2_PB_CH4", "I2S2_CH1", "I2S2"}, + {"PCM_2_PB_CH5", "DL1_CH2", "DL1"}, + {"PCM_2_PB_CH5", "DL4_CH2", "DL4"}, + {"PCM_2_PB_CH5", "I2S0_CH2", "I2S0"}, + {"PCM_2_PB_CH5", "I2S2_CH2", "I2S2"}, +}; + +/* dai ops */ +static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8192_rate_transform(afe->dev, rate, dai->id); + unsigned int pcm_con = 0; + + dev_info(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n", + __func__, + dai->id, + substream->stream, + rate, + rate_reg, + dai->playback_widget->active, + dai->capture_widget->active); + + if (dai->playback_widget->active || dai->capture_widget->active) + return 0; + + switch (dai->id) { + case MT8192_DAI_PCM_1: + pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT; + pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT; + pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT; + pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT; + pcm_con |= 0 << PCM_SYNC_LENGTH_SFT; + pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT; + pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT; + pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT; + pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT; + pcm_con |= rate_reg << PCM_MODE_SFT; + pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT; + + regmap_update_bits(afe->regmap, PCM_INTF_CON1, + 0xfffffffe, pcm_con); + break; + case MT8192_DAI_PCM_2: + pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT; + pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT; + pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT; + pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT; + pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT; + pcm_con |= rate_reg << PCM2_MODE_SFT; + pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT; + + regmap_update_bits(afe->regmap, PCM2_INTF_CON, + 0xfffffffe, pcm_con); + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, dai->id); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_pcm_ops = { + .hw_params = mtk_dai_pcm_hw_params, +}; + +/* dai driver */ +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = { + { + .name = "PCM 1", + .id = MT8192_DAI_PCM_1, + .playback = { + .stream_name = "PCM 1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .capture = { + .stream_name = "PCM 1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_dai_pcm_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "PCM 2", + .id = MT8192_DAI_PCM_2, + .playback = { + .stream_name = "PCM 2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .capture = { + .stream_name = "PCM 2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_dai_pcm_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, +}; + +int mt8192_dai_pcm_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dev_info(afe->dev, "%s()\n", __func__); + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_pcm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver); + + dai->dapm_widgets = mtk_dai_pcm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets); + dai->dapm_routes = mtk_dai_pcm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes); + return 0; +} -- cgit v1.2.3 From 52fcd65414abfcf31206d9d8ac6dba9cc1cbbf85 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Tue, 3 Nov 2020 15:59:35 +0800 Subject: ASoC: mediatek: mt8192: support tdm in platform driver This patch adds mt8192 tdm dai driver. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1604390378-23993-7-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-dai-tdm.c | 778 +++++++++++++++++++++++++++++ 1 file changed, 778 insertions(+) create mode 100644 sound/soc/mediatek/mt8192/mt8192-dai-tdm.c (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c new file mode 100644 index 000000000000..8383536b7ae0 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-dai-tdm.c @@ -0,0 +1,778 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI TDM Control +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Shane Chien + +#include +#include + +#include "mt8192-afe-clk.h" +#include "mt8192-afe-common.h" +#include "mt8192-afe-gpio.h" +#include "mt8192-interconnection.h" + +struct mtk_afe_tdm_priv { + int id; + int bck_id; + int bck_rate; + int tdm_out_mode; + int bck_invert; + int lck_invert; + int mclk_id; + int mclk_multiple; /* according to sample rate */ + int mclk_rate; + int mclk_apll; +}; + +enum { + TDM_OUT_I2S = 0, + TDM_OUT_DSP_A = 1, + TDM_OUT_DSP_B = 2, +}; + +enum { + TDM_BCK_NON_INV = 0, + TDM_BCK_INV = 1, +}; + +enum { + TDM_LCK_NON_INV = 0, + TDM_LCK_INV = 1, +}; + +enum { + TDM_WLEN_16_BIT = 1, + TDM_WLEN_32_BIT = 2, +}; + +enum { + TDM_CHANNEL_BCK_16 = 0, + TDM_CHANNEL_BCK_24 = 1, + TDM_CHANNEL_BCK_32 = 2, +}; + +enum { + TDM_CHANNEL_NUM_2 = 0, + TDM_CHANNEL_NUM_4 = 1, + TDM_CHANNEL_NUM_8 = 2, +}; + +enum { + TDM_CH_START_O30_O31 = 0, + TDM_CH_START_O32_O33, + TDM_CH_START_O34_O35, + TDM_CH_START_O36_O37, + TDM_CH_ZERO, +}; + +static unsigned int get_tdm_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + TDM_WLEN_16_BIT : TDM_WLEN_32_BIT; +} + +static unsigned int get_tdm_channel_bck(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32; +} + +static unsigned int get_tdm_lrck_width(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) - 1; +} + +static unsigned int get_tdm_ch(unsigned int ch) +{ + switch (ch) { + case 1: + case 2: + return TDM_CHANNEL_NUM_2; + case 3: + case 4: + return TDM_CHANNEL_NUM_4; + case 5: + case 6: + case 7: + case 8: + default: + return TDM_CHANNEL_NUM_8; + } +} + +static unsigned int get_tdm_ch_fixup(unsigned int channels) +{ + if (channels > 4) + return 8; + else if (channels > 2) + return 4; + else + return 2; +} + +static unsigned int get_tdm_ch_per_sdata(unsigned int mode, + unsigned int channels) +{ + if (mode == TDM_OUT_DSP_A || mode == TDM_OUT_DSP_B) + return get_tdm_ch_fixup(channels); + else + return 2; +} + +/* interconnection */ +enum { + HDMI_CONN_CH0 = 0, + HDMI_CONN_CH1, + HDMI_CONN_CH2, + HDMI_CONN_CH3, + HDMI_CONN_CH4, + HDMI_CONN_CH5, + HDMI_CONN_CH6, + HDMI_CONN_CH7, +}; + +static const char *const hdmi_conn_mux_map[] = { + "CH0", "CH1", "CH2", "CH3", + "CH4", "CH5", "CH6", "CH7", +}; + +static int hdmi_conn_mux_map_value[] = { + HDMI_CONN_CH0, + HDMI_CONN_CH1, + HDMI_CONN_CH2, + HDMI_CONN_CH3, + HDMI_CONN_CH4, + HDMI_CONN_CH5, + HDMI_CONN_CH6, + HDMI_CONN_CH7, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_0_SFT, + HDMI_O_0_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch0_mux_control = + SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_1_SFT, + HDMI_O_1_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch1_mux_control = + SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_2_SFT, + HDMI_O_2_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch2_mux_control = + SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_3_SFT, + HDMI_O_3_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch3_mux_control = + SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_4_SFT, + HDMI_O_4_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch4_mux_control = + SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_5_SFT, + HDMI_O_5_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch5_mux_control = + SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_6_SFT, + HDMI_O_6_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch6_mux_control = + SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_7_SFT, + HDMI_O_7_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch7_mux_control = + SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum); + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_TDM_MCK_EN, + SUPPLY_SEQ_TDM_BCK_EN, + SUPPLY_SEQ_TDM_EN, +}; + +static int get_tdm_id_by_name(const char *name) +{ + return MT8192_DAI_TDM; +} + +static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_afe_gpio_request(afe->dev, true, tdm_priv->id, 0); + break; + case SND_SOC_DAPM_POST_PMD: + mt8192_afe_gpio_request(afe->dev, false, tdm_priv->id, 0); + break; + default: + break; + } + + return 0; +} + +static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n", + __func__, w->name, event, dai_id); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate); + break; + case SND_SOC_DAPM_POST_PMD: + mt8192_mck_disable(afe, tdm_priv->bck_id); + break; + default: + break; + } + + return 0; +} + +static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n", + __func__, w->name, event, dai_id); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8192_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + tdm_priv->mclk_rate = 0; + mt8192_mck_disable(afe, tdm_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = { + SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch0_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch1_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch2_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch3_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch4_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch5_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch6_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch7_mux_control), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"), + + SND_SOC_DAPM_SUPPLY_S("TDM_EN", SUPPLY_SEQ_TDM_EN, + AFE_TDM_CON1, TDM_EN_SFT, 0, + mtk_tdm_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_bck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_mck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_tdm_id_by_name(w->name); + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; + int cur_apll; + + /* which apll */ + cur_apll = mt8192_get_apll_by_name(afe, source->name); + + return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = { + {"HDMI_CH0_MUX", "CH0", "HDMI"}, + {"HDMI_CH0_MUX", "CH1", "HDMI"}, + {"HDMI_CH0_MUX", "CH2", "HDMI"}, + {"HDMI_CH0_MUX", "CH3", "HDMI"}, + {"HDMI_CH0_MUX", "CH4", "HDMI"}, + {"HDMI_CH0_MUX", "CH5", "HDMI"}, + {"HDMI_CH0_MUX", "CH6", "HDMI"}, + {"HDMI_CH0_MUX", "CH7", "HDMI"}, + + {"HDMI_CH1_MUX", "CH0", "HDMI"}, + {"HDMI_CH1_MUX", "CH1", "HDMI"}, + {"HDMI_CH1_MUX", "CH2", "HDMI"}, + {"HDMI_CH1_MUX", "CH3", "HDMI"}, + {"HDMI_CH1_MUX", "CH4", "HDMI"}, + {"HDMI_CH1_MUX", "CH5", "HDMI"}, + {"HDMI_CH1_MUX", "CH6", "HDMI"}, + {"HDMI_CH1_MUX", "CH7", "HDMI"}, + + {"HDMI_CH2_MUX", "CH0", "HDMI"}, + {"HDMI_CH2_MUX", "CH1", "HDMI"}, + {"HDMI_CH2_MUX", "CH2", "HDMI"}, + {"HDMI_CH2_MUX", "CH3", "HDMI"}, + {"HDMI_CH2_MUX", "CH4", "HDMI"}, + {"HDMI_CH2_MUX", "CH5", "HDMI"}, + {"HDMI_CH2_MUX", "CH6", "HDMI"}, + {"HDMI_CH2_MUX", "CH7", "HDMI"}, + + {"HDMI_CH3_MUX", "CH0", "HDMI"}, + {"HDMI_CH3_MUX", "CH1", "HDMI"}, + {"HDMI_CH3_MUX", "CH2", "HDMI"}, + {"HDMI_CH3_MUX", "CH3", "HDMI"}, + {"HDMI_CH3_MUX", "CH4", "HDMI"}, + {"HDMI_CH3_MUX", "CH5", "HDMI"}, + {"HDMI_CH3_MUX", "CH6", "HDMI"}, + {"HDMI_CH3_MUX", "CH7", "HDMI"}, + + {"HDMI_CH4_MUX", "CH0", "HDMI"}, + {"HDMI_CH4_MUX", "CH1", "HDMI"}, + {"HDMI_CH4_MUX", "CH2", "HDMI"}, + {"HDMI_CH4_MUX", "CH3", "HDMI"}, + {"HDMI_CH4_MUX", "CH4", "HDMI"}, + {"HDMI_CH4_MUX", "CH5", "HDMI"}, + {"HDMI_CH4_MUX", "CH6", "HDMI"}, + {"HDMI_CH4_MUX", "CH7", "HDMI"}, + + {"HDMI_CH5_MUX", "CH0", "HDMI"}, + {"HDMI_CH5_MUX", "CH1", "HDMI"}, + {"HDMI_CH5_MUX", "CH2", "HDMI"}, + {"HDMI_CH5_MUX", "CH3", "HDMI"}, + {"HDMI_CH5_MUX", "CH4", "HDMI"}, + {"HDMI_CH5_MUX", "CH5", "HDMI"}, + {"HDMI_CH5_MUX", "CH6", "HDMI"}, + {"HDMI_CH5_MUX", "CH7", "HDMI"}, + + {"HDMI_CH6_MUX", "CH0", "HDMI"}, + {"HDMI_CH6_MUX", "CH1", "HDMI"}, + {"HDMI_CH6_MUX", "CH2", "HDMI"}, + {"HDMI_CH6_MUX", "CH3", "HDMI"}, + {"HDMI_CH6_MUX", "CH4", "HDMI"}, + {"HDMI_CH6_MUX", "CH5", "HDMI"}, + {"HDMI_CH6_MUX", "CH6", "HDMI"}, + {"HDMI_CH6_MUX", "CH7", "HDMI"}, + + {"HDMI_CH7_MUX", "CH0", "HDMI"}, + {"HDMI_CH7_MUX", "CH1", "HDMI"}, + {"HDMI_CH7_MUX", "CH2", "HDMI"}, + {"HDMI_CH7_MUX", "CH3", "HDMI"}, + {"HDMI_CH7_MUX", "CH4", "HDMI"}, + {"HDMI_CH7_MUX", "CH5", "HDMI"}, + {"HDMI_CH7_MUX", "CH6", "HDMI"}, + {"HDMI_CH7_MUX", "CH7", "HDMI"}, + + {"TDM", NULL, "HDMI_CH0_MUX"}, + {"TDM", NULL, "HDMI_CH1_MUX"}, + {"TDM", NULL, "HDMI_CH2_MUX"}, + {"TDM", NULL, "HDMI_CH3_MUX"}, + {"TDM", NULL, "HDMI_CH4_MUX"}, + {"TDM", NULL, "HDMI_CH5_MUX"}, + {"TDM", NULL, "HDMI_CH6_MUX"}, + {"TDM", NULL, "HDMI_CH7_MUX"}, + + {"TDM", NULL, "aud_tdm_clk"}, + {"TDM", NULL, "TDM_BCK"}, + {"TDM", NULL, "TDM_EN"}, + {"TDM_BCK", NULL, "TDM_MCK"}, + {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, + {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, +}; + +/* dai ops */ +static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe, + struct mtk_afe_tdm_priv *tdm_priv, + int freq) +{ + int apll; + int apll_rate; + + apll = mt8192_get_apll_by_rate(afe, freq); + apll_rate = mt8192_get_apll_rate(afe, apll); + + if (!freq || freq > apll_rate) { + dev_warn(afe->dev, + "%s(), freq(%d Hz) invalid\n", __func__, freq); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_warn(afe->dev, + "%s(), APLL cannot generate %d Hz", __func__, freq); + return -EINVAL; + } + + tdm_priv->mclk_rate = freq; + tdm_priv->mclk_apll = apll; + + return 0; +} + +static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int tdm_id = dai->id; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id]; + unsigned int tdm_out_mode = tdm_priv->tdm_out_mode; + unsigned int rate = params_rate(params); + unsigned int channels = params_channels(params); + unsigned int out_channels_per_sdata = + get_tdm_ch_per_sdata(tdm_out_mode, channels); + snd_pcm_format_t format = params_format(params); + unsigned int tdm_con = 0; + + /* calculate mclk_rate, if not set explicitly */ + if (!tdm_priv->mclk_rate) { + tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple; + mtk_dai_tdm_cal_mclk(afe, + tdm_priv, + tdm_priv->mclk_rate); + } + + /* calculate bck */ + tdm_priv->bck_rate = rate * + out_channels_per_sdata * + snd_pcm_format_physical_width(format); + + if (tdm_priv->bck_rate > tdm_priv->mclk_rate) + dev_warn(afe->dev, "%s(), bck_rate > mclk_rate rate", __func__); + + if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0) + dev_warn(afe->dev, "%s(), bck cannot generate", __func__); + + dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n", + __func__, + tdm_id, rate, channels, format, + tdm_priv->mclk_rate, tdm_priv->bck_rate); + + dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n", + __func__, out_channels_per_sdata); + + /* set tdm */ + if (tdm_priv->bck_invert) + tdm_con |= 1 << BCK_INVERSE_SFT; + + if (tdm_priv->lck_invert) + tdm_con |= 1 << LRCK_INVERSE_SFT; + + if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) { + tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; + } else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_A) { + tdm_con |= 0 << DELAY_DATA_SFT; + tdm_con |= 0 << LRCK_TDM_WIDTH_SFT; + } else if (tdm_priv->tdm_out_mode == TDM_OUT_DSP_B) { + tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= 0 << LRCK_TDM_WIDTH_SFT; + } + + tdm_con |= 1 << LEFT_ALIGN_SFT; + tdm_con |= get_tdm_wlen(format) << WLEN_SFT; + tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT; + tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT; + regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con); + + if (out_channels_per_sdata == 2) { + switch (channels) { + case 1: + case 2: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 3: + case 4: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 5: + case 6: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 7: + case 8: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; + break; + default: + tdm_con = 0; + } + } else { + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + } + + regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con); + + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + HDMI_CH_NUM_MASK_SFT, + channels << HDMI_CH_NUM_SFT); + return 0; +} + +static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_info(afe->dev, "%s(), freq %d\n", __func__, freq); + + return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); +} + +static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + /* DAI mode*/ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + tdm_priv->tdm_out_mode = TDM_OUT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + tdm_priv->tdm_out_mode = TDM_OUT_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + tdm_priv->tdm_out_mode = TDM_OUT_DSP_B; + break; + default: + tdm_priv->tdm_out_mode = TDM_OUT_I2S; + } + + /* DAI clock inversion*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + default: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { + .hw_params = mtk_dai_tdm_hw_params, + .set_sysclk = mtk_dai_tdm_set_sysclk, + .set_fmt = mtk_dai_tdm_set_fmt, +}; + +/* dai driver */ +#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = { + { + .name = "TDM", + .id = MT8192_DAI_TDM, + .playback = { + .stream_name = "TDM", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_TDM_RATES, + .formats = MTK_TDM_FORMATS, + }, + .ops = &mtk_dai_tdm_ops, + }, +}; + +static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe) +{ + struct mtk_afe_tdm_priv *tdm_priv; + + tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv), + GFP_KERNEL); + if (!tdm_priv) + return NULL; + + tdm_priv->mclk_multiple = 128; + tdm_priv->bck_id = MT8192_I2S4_BCK; + tdm_priv->mclk_id = MT8192_I2S4_MCK; + tdm_priv->id = MT8192_DAI_TDM; + + return tdm_priv; +} + +int mt8192_dai_tdm_register(struct mtk_base_afe *afe) +{ + struct mt8192_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv; + struct mtk_base_afe_dai *dai; + + dev_info(afe->dev, "%s()\n", __func__); + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_tdm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver); + + dai->dapm_widgets = mtk_dai_tdm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets); + dai->dapm_routes = mtk_dai_tdm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes); + + tdm_priv = init_tdm_priv_data(afe); + if (!tdm_priv) + return -ENOMEM; + + afe_priv->dai_priv[MT8192_DAI_TDM] = tdm_priv; + + return 0; +} -- cgit v1.2.3 From 18b13ff23fab34a9d35cec60ed19aceab61dc3f9 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Tue, 3 Nov 2020 15:59:37 +0800 Subject: ASoC: mediatek: mt8192: add machine driver with mt6359, rt1015 and rt5682 This patch adds support for the machine board with mt6359, rt1015 and rt5682. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1604390378-23993-9-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 13 + sound/soc/mediatek/mt8192/Makefile | 2 + .../mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 1058 ++++++++++++++++++++ 3 files changed, 1073 insertions(+) create mode 100644 sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c (limited to 'sound') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 9de1be4a32f5..d4532400ff13 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -168,3 +168,16 @@ config SND_SOC_MT8192 that can be used with other codecs. Select Y if you have such device. If unsure select "N". + +config SND_SOC_MT8192_MT6359_RT1015_RT5682 + tristate "ASoC Audio driver for MT8192 with MT6359 RT1015 RT5682 codec" + depends on I2C + depends on SND_SOC_MT8192 + select SND_SOC_MT6359 + select SND_SOC_RT1015 + select SND_SOC_RT5682_I2C + help + This adds ASoC driver for Mediatek MT8192 boards + with the MT6359 RT1015 RT5682 audio codec. + Select Y if you have such device. + If unsure select "N". diff --git a/sound/soc/mediatek/mt8192/Makefile b/sound/soc/mediatek/mt8192/Makefile index dd1848688170..8b27d82626ea 100644 --- a/sound/soc/mediatek/mt8192/Makefile +++ b/sound/soc/mediatek/mt8192/Makefile @@ -12,3 +12,5 @@ snd-soc-mt8192-afe-objs := \ mt8192-dai-tdm.o obj-$(CONFIG_SND_SOC_MT8192) += snd-soc-mt8192-afe.o +obj-$(CONFIG_SND_SOC_MT8192_MT6359_RT1015_RT5682) += \ + mt8192-mt6359-rt1015-rt5682.o diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c new file mode 100644 index 000000000000..41d8a8567bb3 --- /dev/null +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -0,0 +1,1058 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8192-mt6359-rt1015-rt5682.c -- +// MT8192-MT6359-RT1015-RT6358 ALSA SoC machine driver +// +// Copyright (c) 2020 MediaTek Inc. +// Author: Jiaxin Yu +// + +#include +#include +#include +#include +#include +#include +#include + +#include "../../codecs/mt6359.h" +#include "../../codecs/rt1015.h" +#include "../../codecs/rt5682.h" +#include "../common/mtk-afe-platform-driver.h" +#include "mt8192-afe-common.h" +#include "mt8192-afe-clk.h" +#include "mt8192-afe-gpio.h" + +#define RT1015_CODEC_DAI "rt1015-aif" +#define RT1015_DEV0_NAME "rt1015.1-0028" +#define RT1015_DEV1_NAME "rt1015.1-0029" + +#define RT5682_CODEC_DAI "rt5682-aif1" +#define RT5682_DEV0_NAME "rt5682.1-001a" + +static struct snd_soc_jack headset_jack; + +static const struct snd_soc_dapm_widget +mt8192_mt6359_rt1015_rt5682_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Left SPO" }, + { "Right Spk", NULL, "Right SPO" }, + /* headset */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + { "IN1P", NULL, "Headset Mic" }, +}; + +static const struct snd_kcontrol_new mt8192_mt6359_rt1015_rt5682_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai; + unsigned int rate = params_rate(params); + unsigned int mclk_fs_ratio = 128; + unsigned int mclk_fs = rate * mclk_fs_ratio; + int ret, i; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); + if (ret) { + dev_err(card->dev, "failed to set bclk ratio\n"); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT1015_PLL_S_BCLK, + params_rate(params) * 64, + params_rate(params) * 256); + if (ret) { + dev_err(card->dev, "failed to set pll\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT1015_SCLK_S_PLL, + params_rate(params) * 256, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "failed to set sysclk\n"); + return ret; + } + } + + return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT); +} + +static int mt8192_rt5682_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + unsigned int rate = params_rate(params); + unsigned int mclk_fs_ratio = 128; + unsigned int mclk_fs = rate * mclk_fs_ratio; + int bitwidth; + int ret; + + bitwidth = snd_pcm_format_width(params_format(params)); + if (bitwidth < 0) { + dev_err(card->dev, "invalid bit width: %d\n", bitwidth); + return bitwidth; + } + + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth); + if (ret) { + dev_err(card->dev, "failed to set tdm slot\n"); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, + RT5682_PLL1_S_BCLK1, + params_rate(params) * 64, + params_rate(params) * 512); + if (ret) { + dev_err(card->dev, "failed to set pll\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT5682_SCLK_S_PLL1, + params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "failed to set sysclk\n"); + return ret; + } + + return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT); +} + +static const struct snd_soc_ops mt8192_rt1015_i2s_ops = { + .hw_params = mt8192_rt1015_i2s_hw_params, +}; + +static const struct snd_soc_ops mt8192_rt5682_i2s_ops = { + .hw_params = mt8192_rt5682_i2s_hw_params, +}; + +static int mt8192_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *cmpnt_afe = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + int phase; + unsigned int monitor; + int test_done_1, test_done_2, test_done_3; + int cycle_1, cycle_2, cycle_3; + int prev_cycle_1, prev_cycle_2, prev_cycle_3; + int chosen_phase_1, chosen_phase_2, chosen_phase_3; + int counter; + int mtkaif_calib_ok; + + dev_info(afe->dev, "%s(), start\n", __func__); + + pm_runtime_get_sync(afe->dev); + mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 1); + mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA, 0); + mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, 1); + mt8192_afe_gpio_request(afe->dev, true, MT8192_DAI_ADDA_CH34, 0); + + mt6359_mtkaif_calibration_enable(cmpnt_codec); + + /* set clock protocol 2 */ + regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x38); + regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x39); + + /* set test type to synchronizer pulse */ + regmap_update_bits(afe_priv->topckgen, + CKSYS_AUD_TOP_CFG, 0xffff, 0x4); + + mtkaif_calib_ok = true; + afe_priv->mtkaif_calibration_num_phase = 42; /* mt6359: 0 ~ 42 */ + afe_priv->mtkaif_chosen_phase[0] = -1; + afe_priv->mtkaif_chosen_phase[1] = -1; + afe_priv->mtkaif_chosen_phase[2] = -1; + + for (phase = 0; + phase <= afe_priv->mtkaif_calibration_num_phase && + mtkaif_calib_ok; + phase++) { + mt6359_set_mtkaif_calibration_phase(cmpnt_codec, + phase, phase, phase); + + regmap_update_bits(afe_priv->topckgen, + CKSYS_AUD_TOP_CFG, 0x1, 0x1); + + test_done_1 = 0; + test_done_2 = 0; + test_done_3 = 0; + cycle_1 = -1; + cycle_2 = -1; + cycle_3 = -1; + counter = 0; + while (test_done_1 == 0 || + test_done_2 == 0 || + test_done_3 == 0) { + regmap_read(afe_priv->topckgen, + CKSYS_AUD_TOP_MON, &monitor); + + test_done_1 = (monitor >> 28) & 0x1; + test_done_2 = (monitor >> 29) & 0x1; + test_done_3 = (monitor >> 30) & 0x1; + if (test_done_1 == 1) + cycle_1 = monitor & 0xf; + + if (test_done_2 == 1) + cycle_2 = (monitor >> 4) & 0xf; + + if (test_done_3 == 1) + cycle_3 = (monitor >> 8) & 0xf; + + /* handle if never test done */ + if (++counter > 10000) { + dev_err(afe->dev, "%s(), test fail, cycle_1 %d, cycle_2 %d, cycle_3 %d, monitor 0x%x\n", + __func__, + cycle_1, cycle_2, cycle_3, monitor); + mtkaif_calib_ok = false; + break; + } + } + + if (phase == 0) { + prev_cycle_1 = cycle_1; + prev_cycle_2 = cycle_2; + prev_cycle_3 = cycle_3; + } + + if (cycle_1 != prev_cycle_1 && + afe_priv->mtkaif_chosen_phase[0] < 0) { + afe_priv->mtkaif_chosen_phase[0] = phase - 1; + afe_priv->mtkaif_phase_cycle[0] = prev_cycle_1; + } + + if (cycle_2 != prev_cycle_2 && + afe_priv->mtkaif_chosen_phase[1] < 0) { + afe_priv->mtkaif_chosen_phase[1] = phase - 1; + afe_priv->mtkaif_phase_cycle[1] = prev_cycle_2; + } + + if (cycle_3 != prev_cycle_3 && + afe_priv->mtkaif_chosen_phase[2] < 0) { + afe_priv->mtkaif_chosen_phase[2] = phase - 1; + afe_priv->mtkaif_phase_cycle[2] = prev_cycle_3; + } + + regmap_update_bits(afe_priv->topckgen, + CKSYS_AUD_TOP_CFG, 0x1, 0x0); + + if (afe_priv->mtkaif_chosen_phase[0] >= 0 && + afe_priv->mtkaif_chosen_phase[1] >= 0 && + afe_priv->mtkaif_chosen_phase[2] >= 0) + break; + } + + if (afe_priv->mtkaif_chosen_phase[0] < 0) + chosen_phase_1 = 0; + else + chosen_phase_1 = afe_priv->mtkaif_chosen_phase[0]; + + if (afe_priv->mtkaif_chosen_phase[1] < 0) + chosen_phase_2 = 0; + else + chosen_phase_2 = afe_priv->mtkaif_chosen_phase[1]; + + if (afe_priv->mtkaif_chosen_phase[2] < 0) + chosen_phase_3 = 0; + else + chosen_phase_3 = afe_priv->mtkaif_chosen_phase[2]; + + mt6359_set_mtkaif_calibration_phase(cmpnt_codec, + chosen_phase_1, + chosen_phase_2, + chosen_phase_3); + + /* disable rx fifo */ + regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP, 0xff, 0x38); + + mt6359_mtkaif_calibration_disable(cmpnt_codec); + + mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 1); + mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA, 0); + mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, 1); + mt8192_afe_gpio_request(afe->dev, false, MT8192_DAI_ADDA_CH34, 0); + pm_runtime_put(afe->dev); + + dev_info(afe->dev, "%s(), mtkaif_chosen_phase[0/1/2]:%d/%d/%d\n", + __func__, + afe_priv->mtkaif_chosen_phase[0], + afe_priv->mtkaif_chosen_phase[1], + afe_priv->mtkaif_chosen_phase[2]); + + return 0; +} + +static int mt8192_mt6359_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *cmpnt_afe = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe); + struct mt8192_afe_private *afe_priv = afe->platform_priv; + + /* set mtkaif protocol */ + mt6359_set_mtkaif_protocol(cmpnt_codec, + MT6359_MTKAIF_PROTOCOL_2_CLK_P2); + afe_priv->mtkaif_protocol = MTKAIF_PROTOCOL_2_CLK_P2; + + /* mtkaif calibration */ + mt8192_mt6359_mtkaif_calibration(rtd); + + return 0; +} + +static int mt8192_rt5682_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *cmpnt_codec = + asoc_rtd_to_codec(rtd, 0)->component; + struct snd_soc_jack *jack = &headset_jack; + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + ret = snd_soc_component_set_jack(cmpnt_codec, jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack set failed: %d\n", ret); + return ret; + } + + return 0; +}; + +static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + /* fix BE i2s format to 32bit, clean param mask first */ + snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), + 0, SNDRV_PCM_FORMAT_LAST); + + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int +mt8192_mt6359_rt1015_rt5682_cap1_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + int ret; + + static const unsigned int channels[] = { + 1, 2, 4 + }; + static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, + }; + static const unsigned int rates[] = { + 8000, 16000, 32000, 48000, 96000, 192000 + }; + static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, + }; + + struct snd_pcm_runtime *runtime = substream->runtime; + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + if (ret < 0) { + dev_err(afe->dev, "hw_constraint_list channels failed\n"); + return ret; + } + + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + if (ret < 0) { + dev_err(afe->dev, "hw_constraint_list rate failed\n"); + return ret; + } + + return 0; +} + +static const struct snd_soc_ops mt8192_mt6359_rt1015_rt5682_capture1_ops = { + .startup = mt8192_mt6359_rt1015_rt5682_cap1_startup, +}; + +/* FE */ +SND_SOC_DAILINK_DEFS(playback1, + DAILINK_COMP_ARRAY(COMP_CPU("DL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback12, + DAILINK_COMP_ARRAY(COMP_CPU("DL12")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback2, + DAILINK_COMP_ARRAY(COMP_CPU("DL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback3, + DAILINK_COMP_ARRAY(COMP_CPU("DL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback4, + DAILINK_COMP_ARRAY(COMP_CPU("DL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback5, + DAILINK_COMP_ARRAY(COMP_CPU("DL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback6, + DAILINK_COMP_ARRAY(COMP_CPU("DL6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback7, + DAILINK_COMP_ARRAY(COMP_CPU("DL7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback8, + DAILINK_COMP_ARRAY(COMP_CPU("DL8")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback9, + DAILINK_COMP_ARRAY(COMP_CPU("DL9")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture1, + DAILINK_COMP_ARRAY(COMP_CPU("UL1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture2, + DAILINK_COMP_ARRAY(COMP_CPU("UL2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture3, + DAILINK_COMP_ARRAY(COMP_CPU("UL3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture4, + DAILINK_COMP_ARRAY(COMP_CPU("UL4")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture5, + DAILINK_COMP_ARRAY(COMP_CPU("UL5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture6, + DAILINK_COMP_ARRAY(COMP_CPU("UL6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture7, + DAILINK_COMP_ARRAY(COMP_CPU("UL7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture8, + DAILINK_COMP_ARRAY(COMP_CPU("UL8")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture_mono1, + DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture_mono2, + DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(capture_mono3, + DAILINK_COMP_ARRAY(COMP_CPU("UL_MONO_3")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(playback_hdmi, + DAILINK_COMP_ARRAY(COMP_CPU("HDMI")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +/* BE */ +SND_SOC_DAILINK_DEFS(primary_codec, + DAILINK_COMP_ARRAY(COMP_CPU("ADDA")), + DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound", + "mt6359-snd-codec-aif1")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(primary_codec_ch34, + DAILINK_COMP_ARRAY(COMP_CPU("ADDA_CH34")), + DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound", + "mt6359-snd-codec-aif2")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(ap_dmic, + DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(ap_dmic_ch34, + DAILINK_COMP_ARRAY(COMP_CPU("AP_DMIC_CH34")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s0, + DAILINK_COMP_ARRAY(COMP_CPU("I2S0")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s1, + DAILINK_COMP_ARRAY(COMP_CPU("I2S1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s2, + DAILINK_COMP_ARRAY(COMP_CPU("I2S2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s3, + DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), + DAILINK_COMP_ARRAY(COMP_CODEC(RT1015_DEV0_NAME, + RT1015_CODEC_DAI), + COMP_CODEC(RT1015_DEV1_NAME, + RT1015_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s5, + DAILINK_COMP_ARRAY(COMP_CPU("I2S5")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s6, + DAILINK_COMP_ARRAY(COMP_CPU("I2S6")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s7, + DAILINK_COMP_ARRAY(COMP_CPU("I2S7")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s8, + DAILINK_COMP_ARRAY(COMP_CPU("I2S8")), + DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, + RT5682_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(i2s9, + DAILINK_COMP_ARRAY(COMP_CPU("I2S9")), + DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, + RT5682_CODEC_DAI)), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(connsys_i2s, + DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(pcm1, + DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(pcm2, + DAILINK_COMP_ARRAY(COMP_CPU("PCM 2")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +SND_SOC_DAILINK_DEFS(tdm, + DAILINK_COMP_ARRAY(COMP_CPU("TDM")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + +static struct snd_soc_dai_link mt8192_mt6359_rt1015_rt5682_dai_links[] = { + /* Front End DAI links */ + { + .name = "Playback_1", + .stream_name = "Playback_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback1), + }, + { + .name = "Playback_12", + .stream_name = "Playback_12", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback12), + }, + { + .name = "Playback_2", + .stream_name = "Playback_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback2), + }, + { + .name = "Playback_3", + .stream_name = "Playback_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback3), + }, + { + .name = "Playback_4", + .stream_name = "Playback_4", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback4), + }, + { + .name = "Playback_5", + .stream_name = "Playback_5", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback5), + }, + { + .name = "Playback_6", + .stream_name = "Playback_6", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback6), + }, + { + .name = "Playback_7", + .stream_name = "Playback_7", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback7), + }, + { + .name = "Playback_8", + .stream_name = "Playback_8", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback8), + }, + { + .name = "Playback_9", + .stream_name = "Playback_9", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback9), + }, + { + .name = "Capture_1", + .stream_name = "Capture_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + .ops = &mt8192_mt6359_rt1015_rt5682_capture1_ops, + SND_SOC_DAILINK_REG(capture1), + }, + { + .name = "Capture_2", + .stream_name = "Capture_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture2), + }, + { + .name = "Capture_3", + .stream_name = "Capture_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture3), + }, + { + .name = "Capture_4", + .stream_name = "Capture_4", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture4), + }, + { + .name = "Capture_5", + .stream_name = "Capture_5", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture5), + }, + { + .name = "Capture_6", + .stream_name = "Capture_6", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture6), + }, + { + .name = "Capture_7", + .stream_name = "Capture_7", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture7), + }, + { + .name = "Capture_8", + .stream_name = "Capture_8", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture8), + }, + { + .name = "Capture_Mono_1", + .stream_name = "Capture_Mono_1", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture_mono1), + }, + { + .name = "Capture_Mono_2", + .stream_name = "Capture_Mono_2", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture_mono2), + }, + { + .name = "Capture_Mono_3", + .stream_name = "Capture_Mono_3", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(capture_mono3), + }, + { + .name = "playback_hdmi", + .stream_name = "Playback_HDMI", + .trigger = {SND_SOC_DPCM_TRIGGER_PRE, + SND_SOC_DPCM_TRIGGER_PRE}, + .dynamic = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(playback_hdmi), + }, + /* Back End DAI links */ + { + .name = "Primary Codec", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .init = mt8192_mt6359_init, + SND_SOC_DAILINK_REG(primary_codec), + }, + { + .name = "Primary Codec CH34", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(primary_codec_ch34), + }, + { + .name = "AP_DMIC", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(ap_dmic), + }, + { + .name = "AP_DMIC_CH34", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(ap_dmic_ch34), + }, + { + .name = "I2S0", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s0), + }, + { + .name = "I2S1", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s1), + }, + { + .name = "I2S2", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s2), + }, + { + .name = "I2S3", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s3), + .ops = &mt8192_rt1015_i2s_ops, + }, + { + .name = "I2S5", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s5), + }, + { + .name = "I2S6", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s6), + }, + { + .name = "I2S7", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s7), + }, + { + .name = "I2S8", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + .init = mt8192_rt5682_init, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s8), + .ops = &mt8192_rt5682_i2s_ops, + }, + { + .name = "I2S9", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, + SND_SOC_DAILINK_REG(i2s9), + .ops = &mt8192_rt5682_i2s_ops, + }, + { + .name = "CONNSYS_I2S", + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(connsys_i2s), + }, + { + .name = "PCM 1", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pcm1), + }, + { + .name = "PCM 2", + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(pcm2), + }, + { + .name = "TDM", + .no_pcm = 1, + .dpcm_playback = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(tdm), + }, +}; + +static struct snd_soc_codec_conf rt1015_amp_conf[] = { + { + .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(RT1015_DEV1_NAME), + .name_prefix = "Right", + }, +}; + +static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_soc_card = { + .name = "mt8192_mt6359_rt1015_rt5682", + .owner = THIS_MODULE, + .dai_link = mt8192_mt6359_rt1015_rt5682_dai_links, + .num_links = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_dai_links), + .controls = mt8192_mt6359_rt1015_rt5682_controls, + .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_controls), + .dapm_widgets = mt8192_mt6359_rt1015_rt5682_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_widgets), + .dapm_routes = mt8192_mt6359_rt1015_rt5682_routes, + .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_routes), + .codec_conf = rt1015_amp_conf, + .num_configs = ARRAY_SIZE(rt1015_amp_conf), +}; + +static int mt8192_mt6359_rt1015_rt5682_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt8192_mt6359_rt1015_rt5682_soc_card; + struct device_node *platform_node; + int ret, i; + struct snd_soc_dai_link *dai_link; + + card->dev = &pdev->dev; + + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + if (!dai_link->platforms->name) + dai_link->platforms->of_node = platform_node; + } + + ret = mt8192_afe_gpio_init(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "init gpio error %d\n", ret); + return ret; + } + + return devm_snd_soc_register_card(&pdev->dev, card); +} + +#ifdef CONFIG_OF +static const struct of_device_id mt8192_mt6359_rt1015_rt5682_dt_match[] = { + {.compatible = "mediatek,mt8192_mt6359_rt1015_rt5682",}, + {} +}; +#endif + +static const struct dev_pm_ops mt8192_mt6359_rt1015_rt5682_pm_ops = { + .poweroff = snd_soc_poweroff, + .restore = snd_soc_resume, +}; + +static struct platform_driver mt8192_mt6359_rt1015_rt5682_driver = { + .driver = { + .name = "mt8192_mt6359_rt1015_rt5682", +#ifdef CONFIG_OF + .of_match_table = mt8192_mt6359_rt1015_rt5682_dt_match, +#endif + .pm = &mt8192_mt6359_rt1015_rt5682_pm_ops, + }, + .probe = mt8192_mt6359_rt1015_rt5682_dev_probe, +}; + +module_platform_driver(mt8192_mt6359_rt1015_rt5682_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8192-MT6359-RT1015-RT5682 ALSA SoC machine driver"); +MODULE_AUTHOR("Jiaxin Yu "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("mt8192_mt6359_rt1015_rt5682 soc card"); -- cgit v1.2.3 From 7e9a2387c5fdfb3121249b216382ec28e36d5612 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 4 Nov 2020 17:20:05 +0800 Subject: ASoC: rt1015: support TDM slot configuration Add TDM slot callback function to support TDM configuration Signed-off-by: Shuming Fan Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201104092005.2227-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt1015.h | 42 +++++++++++++++++++ 2 files changed, 143 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 25fe2ddedd54..a9cd6ad0bf5a 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -944,6 +944,106 @@ static int rt1015_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) return 0; } +static int rt1015_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; + unsigned int val = 0, rx_slotnum, tx_slotnum; + int ret = 0, first_bit; + + switch (slots) { + case 2: + val |= RT1015_I2S_TX_2CH; + break; + case 4: + val |= RT1015_I2S_TX_4CH; + break; + case 6: + val |= RT1015_I2S_TX_6CH; + break; + case 8: + val |= RT1015_I2S_TX_8CH; + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + switch (slot_width) { + case 16: + val |= RT1015_I2S_CH_TX_LEN_16B; + break; + case 20: + val |= RT1015_I2S_CH_TX_LEN_20B; + break; + case 24: + val |= RT1015_I2S_CH_TX_LEN_24B; + break; + case 32: + val |= RT1015_I2S_CH_TX_LEN_32B; + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + /* Rx slot configuration */ + rx_slotnum = hweight_long(rx_mask); + if (rx_slotnum != 1) { + ret = -EINVAL; + dev_err(component->dev, "too many rx slots or zero slot\n"); + goto _set_tdm_err_; + } + + /* This is an assumption that the system sends stereo audio to the amplifier typically. + * And the stereo audio is placed in slot 0/2/4/6 as the starting slot. + * The users could select the channel from L/R/L+R by "Mono LR Select" control. + */ + first_bit = __ffs(rx_mask); + switch (first_bit) { + case 0: + case 2: + case 4: + case 6: + snd_soc_component_update_bits(component, + RT1015_TDM1_4, + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, + (first_bit << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | + ((first_bit+1) << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + case 1: + case 3: + case 5: + case 7: + snd_soc_component_update_bits(component, + RT1015_TDM1_4, + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, + ((first_bit-1) << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | + (first_bit << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + /* Tx slot configuration */ + tx_slotnum = hweight_long(tx_mask); + if (tx_slotnum) { + ret = -EINVAL; + dev_err(component->dev, "doesn't need to support tx slots\n"); + goto _set_tdm_err_; + } + + snd_soc_component_update_bits(component, RT1015_TDM1_1, + RT1015_I2S_CH_TX_MASK | RT1015_I2S_CH_RX_MASK | + RT1015_I2S_CH_TX_LEN_MASK | RT1015_I2S_CH_RX_LEN_MASK, val); + +_set_tdm_err_: + return ret; +} + static int rt1015_probe(struct snd_soc_component *component) { struct rt1015_priv *rt1015 = @@ -975,6 +1075,7 @@ static struct snd_soc_dai_ops rt1015_aif_dai_ops = { .hw_params = rt1015_hw_params, .set_fmt = rt1015_set_dai_fmt, .set_bclk_ratio = rt1015_set_bclk_ratio, + .set_tdm_slot = rt1015_set_tdm_slot, }; static struct snd_soc_dai_driver rt1015_dai[] = { diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h index d3fdd30aca6d..ad8274c80990 100644 --- a/sound/soc/codecs/rt1015.h +++ b/sound/soc/codecs/rt1015.h @@ -213,6 +213,12 @@ #define RT1015_ID_VERA 0x0 #define RT1015_ID_VERB 0x1 +/* 0x00f2 */ +#define RT1015_MONO_LR_SEL_MASK (0x3 << 4) +#define RT1015_MONO_L_CHANNEL (0x0 << 4) +#define RT1015_MONO_R_CHANNEL (0x1 << 4) +#define RT1015_MONO_LR_MIX_CHANNEL (0x2 << 4) + /* 0x0102 */ #define RT1015_DAC_VOL_MASK (0x7f << 9) #define RT1015_DAC_VOL_SFT 9 @@ -275,6 +281,42 @@ #define RT1015_TDM_INV_BCLK_MASK (0x1 << 15) #define RT1015_TDM_INV_BCLK_SFT 15 #define RT1015_TDM_INV_BCLK (0x1 << 15) +#define RT1015_I2S_CH_TX_MASK (0x3 << 10) +#define RT1015_I2S_CH_TX_SFT 10 +#define RT1015_I2S_TX_2CH (0x0 << 10) +#define RT1015_I2S_TX_4CH (0x1 << 10) +#define RT1015_I2S_TX_6CH (0x2 << 10) +#define RT1015_I2S_TX_8CH (0x3 << 10) +#define RT1015_I2S_CH_RX_MASK (0x3 << 8) +#define RT1015_I2S_CH_RX_SFT 8 +#define RT1015_I2S_RX_2CH (0x0 << 8) +#define RT1015_I2S_RX_4CH (0x1 << 8) +#define RT1015_I2S_RX_6CH (0x2 << 8) +#define RT1015_I2S_RX_8CH (0x3 << 8) +#define RT1015_I2S_LR_CH_SEL_MASK (0x1 << 7) +#define RT1015_I2S_LR_CH_SEL_SFT 7 +#define RT1015_I2S_LEFT_CH_SEL (0x0 << 7) +#define RT1015_I2S_RIGHT_CH_SEL (0x1 << 7) +#define RT1015_I2S_CH_TX_LEN_MASK (0x7 << 4) +#define RT1015_I2S_CH_TX_LEN_SFT 4 +#define RT1015_I2S_CH_TX_LEN_16B (0x0 << 4) +#define RT1015_I2S_CH_TX_LEN_20B (0x1 << 4) +#define RT1015_I2S_CH_TX_LEN_24B (0x2 << 4) +#define RT1015_I2S_CH_TX_LEN_32B (0x3 << 4) +#define RT1015_I2S_CH_TX_LEN_8B (0x4 << 4) +#define RT1015_I2S_CH_RX_LEN_MASK (0x7 << 0) +#define RT1015_I2S_CH_RX_LEN_SFT 0 +#define RT1015_I2S_CH_RX_LEN_16B (0x0 << 0) +#define RT1015_I2S_CH_RX_LEN_20B (0x1 << 0) +#define RT1015_I2S_CH_RX_LEN_24B (0x2 << 0) +#define RT1015_I2S_CH_RX_LEN_32B (0x3 << 0) +#define RT1015_I2S_CH_RX_LEN_8B (0x4 << 0) + +/* TDM1 Setting-4 (0x011a) */ +#define RT1015_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 12) +#define RT1015_TDM_I2S_TX_R_DAC1_1_MASK (0x7 << 8) +#define RT1015_TDM_I2S_TX_L_DAC1_1_SFT 12 +#define RT1015_TDM_I2S_TX_R_DAC1_1_SFT 8 /* 0x0330 */ #define RT1015_ABST_AUTO_EN_MASK (0x1 << 13) -- cgit v1.2.3 From 20f64a1db8a06fdf4ed03375546f8d3555cb6cc9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 5 Nov 2020 11:41:00 +0000 Subject: ASoC: qcom: lpass-cpu: fix warning on symbol scope This patch fixes below warning when module is compiled with W=1 C=1 lpass-cpu.c:677:22: warning: symbol 'lpass_hdmi_regmap_config' was not declared. Should it be static? Fixes: 7cb37b7bd0d3 ("ASoC: qcom: Add support for lpass hdmi driver") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201105114100.18647-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index ba2aca301a9b..0c64deaf9374 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -668,7 +668,7 @@ static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg) return false; } -struct regmap_config lpass_hdmi_regmap_config = { +static struct regmap_config lpass_hdmi_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, -- cgit v1.2.3 From 8bfe8c967546dc05385b52bac49ad972fea5887c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 5 Nov 2020 12:47:47 +0000 Subject: ASoC: mediatek: mt8192: Fix build failure A build of arm64 allmodconfig with next-20201105 fails with the error: ERROR: modpost: "mt8192_afe_gpio_request" undefined! ERROR: modpost: "mt8192_afe_gpio_init" undefined! Export the symbols so that mt8192-mt6359-rt1015-rt5682.ko finds it. Signed-off-by: Sudip Mukherjee Link: https://lore.kernel.org/r/20201105124747.18383-1-sudipm.mukherjee@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-afe-gpio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c index ea000888c9e8..fbbe9ed9adb3 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c @@ -160,6 +160,7 @@ int mt8192_afe_gpio_init(struct device *dev) return 0; } +EXPORT_SYMBOL(mt8192_afe_gpio_init); static int mt8192_afe_gpio_adda_dl(struct device *dev, bool enable) { @@ -304,3 +305,4 @@ int mt8192_afe_gpio_request(struct device *dev, bool enable, return 0; } +EXPORT_SYMBOL(mt8192_afe_gpio_request); -- cgit v1.2.3 From df3d6390fa0ad48eecbe0b48acb4d364a70cd378 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Thu, 5 Nov 2020 20:28:07 +0800 Subject: ASoC: mediatek: mt8192: Make some symbols static Fix the following sparse warnings: ./mt8192-dai-i2s.c:2040:5: warning: symbol 'mt8192_dai_i2s_get_share' was not declared. Should it be static? ./mt8192-dai-i2s.c:2060:5: warning: symbol 'mt8192_dai_i2s_set_priv' was not declared. Should it be static? ./mt8192-afe-gpio.c:15:16: warning: symbol 'aud_pinctrl' was not declared. Should it be static? ./mt8192-afe-pcm.c:70:5: warning: symbol 'mt8192_get_memif_pbuf_size' was not declared. Should it be static? ./mt8192-afe-pcm.c:2137:39: warning: symbol 'mt8192_afe_component' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: Zou Wei Acked-by: Jiaxin Yu Link: https://lore.kernel.org/r/1604579287-25251-1-git-send-email-zou_wei@huawei.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8192/mt8192-afe-gpio.c | 2 +- sound/soc/mediatek/mt8192/mt8192-afe-pcm.c | 4 ++-- sound/soc/mediatek/mt8192/mt8192-dai-i2s.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c index fbbe9ed9adb3..165663a78e36 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-gpio.c @@ -12,7 +12,7 @@ #include "mt8192-afe-common.h" #include "mt8192-afe-gpio.h" -struct pinctrl *aud_pinctrl; +static struct pinctrl *aud_pinctrl; enum mt8192_afe_gpio { MT8192_AFE_GPIO_DAT_MISO_OFF, diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c index 4a4729f254ed..e7fec2d75e3d 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c @@ -67,7 +67,7 @@ static int mt8192_irq_fs(struct snd_pcm_substream *substream, unsigned int rate) return mt8192_general_rate_transform(afe->dev, rate); } -int mt8192_get_memif_pbuf_size(struct snd_pcm_substream *substream) +static int mt8192_get_memif_pbuf_size(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2134,7 +2134,7 @@ static int mt8192_afe_component_probe(struct snd_soc_component *component) return mtk_afe_add_sub_dai_control(component); } -const struct snd_soc_component_driver mt8192_afe_component = { +static const struct snd_soc_component_driver mt8192_afe_component = { .name = AFE_PCM_NAME, .probe = mt8192_afe_component_probe, .pointer = mtk_afe_pcm_pointer, diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c index 53c560ea4aae..5b29340f9516 100644 --- a/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c +++ b/sound/soc/mediatek/mt8192/mt8192-dai-i2s.c @@ -2037,7 +2037,7 @@ static const struct mtk_afe_i2s_priv mt8192_i2s_priv[DAI_I2S_NUM] = { }, }; -int mt8192_dai_i2s_get_share(struct mtk_base_afe *afe) +static int mt8192_dai_i2s_get_share(struct mtk_base_afe *afe) { struct mt8192_afe_private *afe_priv = afe->platform_priv; const struct device_node *of_node = afe->dev->of_node; @@ -2057,7 +2057,7 @@ int mt8192_dai_i2s_get_share(struct mtk_base_afe *afe) return 0; } -int mt8192_dai_i2s_set_priv(struct mtk_base_afe *afe) +static int mt8192_dai_i2s_set_priv(struct mtk_base_afe *afe) { int i; int ret; -- cgit v1.2.3 From 4c22b80f61540ea99d9b4af0127315338755f05b Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 26 Oct 2020 11:01:29 +0100 Subject: ASoC: pcm: DRAIN support reactivation soc-pcm's dpcm_fe_dai_do_trigger() supported DRAIN commnad up to kernel v5.4 where explicit switch(cmd) has been introduced which takes into account all SNDRV_PCM_TRIGGER_xxx but SNDRV_PCM_TRIGGER_DRAIN. Update switch statement to reactive support for it. As DRAIN is somewhat unique by lacking negative/stop counterpart, bring behaviour of dpcm_fe_dai_do_trigger() for said command back to its pre-v5.4 state by adding it to START/RESUME/PAUSE_RELEASE group. Fixes: acbf27746ecf ("ASoC: pcm: update FE/BE trigger order based on the command") Signed-off-by: Cezary Rojewski Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201026100129.8216-1-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 17ff3a369631..2a39f355b3a4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2206,6 +2206,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_DRAIN: ret = dpcm_dai_trigger_fe_be(substream, cmd, true); break; case SNDRV_PCM_TRIGGER_STOP: @@ -2223,6 +2224,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_DRAIN: ret = dpcm_dai_trigger_fe_be(substream, cmd, false); break; case SNDRV_PCM_TRIGGER_STOP: -- cgit v1.2.3 From ee5d28e735082a5676c85bdc578653097e4e29e2 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 5 Nov 2020 11:44:35 +0000 Subject: ASoC: q6afe-clocks: fix warning on symbol scope This patch fixes below warning when module is compiled with W=1 C=1 sound/soc/qcom/qdsp6/q6afe-clocks.c:122:18: warning: symbol 'q6afe_clks' was not declared. Should it be static? Fixes: 520a1c396d196 ("ASoC: q6afe-clocks: add q6afe clock controller") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201105114435.22860-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe-clocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/qdsp6/q6afe-clocks.c b/sound/soc/qcom/qdsp6/q6afe-clocks.c index 2efc2eaa0424..87e4633afe2c 100644 --- a/sound/soc/qcom/qdsp6/q6afe-clocks.c +++ b/sound/soc/qcom/qdsp6/q6afe-clocks.c @@ -119,7 +119,7 @@ static const struct clk_ops clk_vote_q6afe_ops = { .unprepare = clk_unvote_q6afe_block, }; -struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = { +static struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = { [LPASS_CLK_ID_PRI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT), [LPASS_CLK_ID_PRI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT), [LPASS_CLK_ID_SEC_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT), -- cgit v1.2.3 From ec4177c83456b9e84d796ed0bc7656fd922937cb Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 29 Oct 2020 08:41:37 +0000 Subject: ASoC: samsung: i2s: Remove redundant null check before clk_disable_unprepare Because clk_disable_unprepare() already checked NULL clock parameter, so the additional check is unnecessary, just remove it. Signed-off-by: Xu Wang Link: https://lore.kernel.org/r/20201029084137.28771-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index df53d4ea808f..36969f0a3f9a 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1212,8 +1212,7 @@ static int i2s_runtime_suspend(struct device *dev) priv->suspend_i2scon = readl(priv->addr + I2SCON); priv->suspend_i2spsr = readl(priv->addr + I2SPSR); - if (priv->op_clk) - clk_disable_unprepare(priv->op_clk); + clk_disable_unprepare(priv->op_clk); clk_disable_unprepare(priv->clk); return 0; -- cgit v1.2.3 From b8f94957765629e6a0d89abb4ff7e06e6565f61f Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 29 Oct 2020 09:01:04 +0000 Subject: ASoC: pxa: pxa-ssp: Remove redundant null check before clk_prepare_enable/clk_disable_unprepare ecause clk_prepare_enable() and clk_disable_unprepare() already checked NULL clock parameter, so the additional checks are unnecessary, just remove them. Signed-off-by: Xu Wang Link: https://lore.kernel.org/r/20201029090104.29552-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index c4e7307a4437..b941adcbb8f9 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -99,8 +99,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, pxa_ssp_disable(ssp); } - if (priv->extclk) - clk_prepare_enable(priv->extclk); + clk_prepare_enable(priv->extclk); dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL); if (!dma) @@ -124,8 +123,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(ssp->clk); } - if (priv->extclk) - clk_disable_unprepare(priv->extclk); + clk_disable_unprepare(priv->extclk); kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); -- cgit v1.2.3 From 8a24c834c053ef1b0cdefbd9c5bcb487cbc5068f Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 2 Nov 2020 09:52:27 +0800 Subject: ASoC: fsl_aud2htx: Add aud2htx module driver The AUD2HTX is a digital module that provides a bridge between the Audio Subsystem and the HDMI RTX Subsystem. This module includes intermediate storage to queue SDMA transactions prior to being synchronized and passed to the HDMI RTX Subsystem over the Audio Link. The AUD2HTX contains a DMA request routed to the SDMA module. This DMA request is controlled based on the watermark level in the 32-entry sample buffer. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/1604281947-26874-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 5 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_aud2htx.c | 311 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_aud2htx.h | 67 ++++++++++ 4 files changed, 385 insertions(+) create mode 100644 sound/soc/fsl/fsl_aud2htx.c create mode 100644 sound/soc/fsl/fsl_aud2htx.h (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index d04b64d32dc1..52a562215008 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -105,6 +105,11 @@ config SND_SOC_FSL_XCVR iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC, HDMI1.4 ARC and SPDIF. +config SND_SOC_FSL_AUD2HTX + tristate "AUDIO TO HDMI TX module support" + help + Say Y if you want to add AUDIO TO HDMI TX support for NXP. + config SND_SOC_FSL_UTILS tristate diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 1d2231f9cc47..2181b7f9f677 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -26,6 +26,7 @@ snd-soc-fsl-dma-objs := fsl_dma.o snd-soc-fsl-mqs-objs := fsl_mqs.o snd-soc-fsl-easrc-objs := fsl_easrc.o snd-soc-fsl-xcvr-objs := fsl_xcvr.o +snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o @@ -40,6 +41,7 @@ obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o +obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o # MPC5200 Platform Support obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c new file mode 100644 index 000000000000..124aeb70f24e --- /dev/null +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2020 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_aud2htx.h" +#include "imx-pcm.h" + +static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct fsl_aud2htx *aud2htx = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL, + AUD2HTX_CTRL_EN, AUD2HTX_CTRL_EN); + regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT, + AUD2HTX_CTRE_DE, AUD2HTX_CTRE_DE); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT, + AUD2HTX_CTRE_DE, 0); + regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL, + AUD2HTX_CTRL_EN, 0); + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = { + .trigger = fsl_aud2htx_trigger, +}; + +static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai) +{ + struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev); + + /* DMA request when number of entries < WTMK_LOW */ + regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT, + AUD2HTX_CTRE_DT_MASK, 0); + + /* Disable interrupts*/ + regmap_update_bits(aud2htx->regmap, AUD2HTX_IRQ_MASK, + AUD2HTX_WM_HIGH_IRQ_MASK | + AUD2HTX_WM_LOW_IRQ_MASK | + AUD2HTX_OVF_MASK, + AUD2HTX_WM_HIGH_IRQ_MASK | + AUD2HTX_WM_LOW_IRQ_MASK | + AUD2HTX_OVF_MASK); + + /* Configure watermark */ + regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT, + AUD2HTX_CTRE_WL_MASK, + AUD2HTX_WTMK_LOW << AUD2HTX_CTRE_WL_SHIFT); + regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT, + AUD2HTX_CTRE_WH_MASK, + AUD2HTX_WTMK_HIGH << AUD2HTX_CTRE_WH_SHIFT); + + snd_soc_dai_init_dma_data(cpu_dai, &aud2htx->dma_params_tx, + &aud2htx->dma_params_rx); + + return 0; +} + +static struct snd_soc_dai_driver fsl_aud2htx_dai = { + .probe = fsl_aud2htx_dai_probe, + .playback = { + .stream_name = "CPU-Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = FSL_AUD2HTX_FORMATS, + }, + .ops = &fsl_aud2htx_dai_ops, +}; + +static const struct snd_soc_component_driver fsl_aud2htx_component = { + .name = "fsl-aud2htx", +}; + +static const struct reg_default fsl_aud2htx_reg_defaults[] = { + {AUD2HTX_CTRL, 0x00000000}, + {AUD2HTX_CTRL_EXT, 0x00000000}, + {AUD2HTX_WR, 0x00000000}, + {AUD2HTX_STATUS, 0x00000000}, + {AUD2HTX_IRQ_NOMASK, 0x00000000}, + {AUD2HTX_IRQ_MASKED, 0x00000000}, + {AUD2HTX_IRQ_MASK, 0x00000000}, +}; + +static bool fsl_aud2htx_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AUD2HTX_CTRL: + case AUD2HTX_CTRL_EXT: + case AUD2HTX_STATUS: + case AUD2HTX_IRQ_NOMASK: + case AUD2HTX_IRQ_MASKED: + case AUD2HTX_IRQ_MASK: + return true; + default: + return false; + } +} + +static bool fsl_aud2htx_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AUD2HTX_CTRL: + case AUD2HTX_CTRL_EXT: + case AUD2HTX_WR: + case AUD2HTX_IRQ_NOMASK: + case AUD2HTX_IRQ_MASKED: + case AUD2HTX_IRQ_MASK: + return true; + default: + return false; + } +} + +static bool fsl_aud2htx_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AUD2HTX_STATUS: + case AUD2HTX_IRQ_NOMASK: + case AUD2HTX_IRQ_MASKED: + return true; + default: + return false; + } +} + +static const struct regmap_config fsl_aud2htx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .max_register = AUD2HTX_IRQ_MASK, + .reg_defaults = fsl_aud2htx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(fsl_aud2htx_reg_defaults), + .readable_reg = fsl_aud2htx_readable_reg, + .volatile_reg = fsl_aud2htx_volatile_reg, + .writeable_reg = fsl_aud2htx_writeable_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct of_device_id fsl_aud2htx_dt_ids[] = { + { .compatible = "fsl,imx8mp-aud2htx",}, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_aud2htx_dt_ids); + +static irqreturn_t fsl_aud2htx_isr(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +static int fsl_aud2htx_probe(struct platform_device *pdev) +{ + struct fsl_aud2htx *aud2htx; + struct resource *res; + void __iomem *regs; + int ret, irq; + + aud2htx = devm_kzalloc(&pdev->dev, sizeof(*aud2htx), GFP_KERNEL); + if (!aud2htx) + return -ENOMEM; + + aud2htx->pdev = pdev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "failed ioremap\n"); + return PTR_ERR(regs); + } + + aud2htx->regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &fsl_aud2htx_regmap_config); + if (IS_ERR(aud2htx->regmap)) { + dev_err(&pdev->dev, "failed to init regmap"); + return PTR_ERR(aud2htx->regmap); + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for node %s\n", + dev_name(&pdev->dev)); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, fsl_aud2htx_isr, 0, + dev_name(&pdev->dev), aud2htx); + if (ret) { + dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); + return ret; + } + + aud2htx->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(aud2htx->bus_clk)) { + dev_err(&pdev->dev, "failed to get mem clock\n"); + return PTR_ERR(aud2htx->bus_clk); + } + + aud2htx->dma_params_tx.chan_name = "tx"; + aud2htx->dma_params_tx.maxburst = AUD2HTX_MAXBURST; + aud2htx->dma_params_tx.addr = res->start + AUD2HTX_WR; + + platform_set_drvdata(pdev, aud2htx); + pm_runtime_enable(&pdev->dev); + + regcache_cache_only(aud2htx->regmap, true); + + ret = devm_snd_soc_register_component(&pdev->dev, + &fsl_aud2htx_component, + &fsl_aud2htx_dai, 1); + if (ret) { + dev_err(&pdev->dev, "failed to register ASoC DAI\n"); + return ret; + } + + ret = imx_pcm_dma_init(pdev, IMX_DEFAULT_DMABUF_SIZE); + if (ret) + dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret); + + return ret; +} + +static int fsl_aud2htx_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int fsl_aud2htx_runtime_suspend(struct device *dev) +{ + struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev); + + regcache_cache_only(aud2htx->regmap, true); + clk_disable_unprepare(aud2htx->bus_clk); + + return 0; +} + +static int fsl_aud2htx_runtime_resume(struct device *dev) +{ + struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(aud2htx->bus_clk); + if (ret) + return ret; + + regcache_cache_only(aud2htx->regmap, false); + regcache_mark_dirty(aud2htx->regmap); + regcache_sync(aud2htx->regmap); + + return 0; +} + +static const struct dev_pm_ops fsl_aud2htx_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend, + fsl_aud2htx_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver fsl_aud2htx_driver = { + .probe = fsl_aud2htx_probe, + .remove = fsl_aud2htx_remove, + .driver = { + .name = "fsl-aud2htx", + .pm = &fsl_aud2htx_pm_ops, + .of_match_table = fsl_aud2htx_dt_ids, + }, +}; +module_platform_driver(fsl_aud2htx_driver); + +MODULE_AUTHOR("Shengjiu Wang "); +MODULE_DESCRIPTION("NXP AUD2HTX driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_aud2htx.h b/sound/soc/fsl/fsl_aud2htx.h new file mode 100644 index 000000000000..ad70d6a7694c --- /dev/null +++ b/sound/soc/fsl/fsl_aud2htx.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2020 NXP + */ + +#ifndef _FSL_AUD2HTX_H +#define _FSL_AUD2HTX_H + +#define FSL_AUD2HTX_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* AUD2HTX Register Map */ +#define AUD2HTX_CTRL 0x0 /* AUD2HTX Control Register */ +#define AUD2HTX_CTRL_EXT 0x4 /* AUD2HTX Control Extended Register */ +#define AUD2HTX_WR 0x8 /* AUD2HTX Write Register */ +#define AUD2HTX_STATUS 0xC /* AUD2HTX Status Register */ +#define AUD2HTX_IRQ_NOMASK 0x10 /* AUD2HTX Nonmasked Interrupt Flags Register */ +#define AUD2HTX_IRQ_MASKED 0x14 /* AUD2HTX Masked Interrupt Flags Register */ +#define AUD2HTX_IRQ_MASK 0x18 /* AUD2HTX IRQ Masks Register */ + +/* AUD2HTX Control Register */ +#define AUD2HTX_CTRL_EN BIT(0) + +/* AUD2HTX Control Extended Register */ +#define AUD2HTX_CTRE_DE BIT(0) +#define AUD2HTX_CTRE_DT_SHIFT 0x1 +#define AUD2HTX_CTRE_DT_WIDTH 0x2 +#define AUD2HTX_CTRE_DT_MASK ((BIT(AUD2HTX_CTRE_DT_WIDTH) - 1) \ + << AUD2HTX_CTRE_DT_SHIFT) +#define AUD2HTX_CTRE_WL_SHIFT 16 +#define AUD2HTX_CTRE_WL_WIDTH 5 +#define AUD2HTX_CTRE_WL_MASK ((BIT(AUD2HTX_CTRE_WL_WIDTH) - 1) \ + << AUD2HTX_CTRE_WL_SHIFT) +#define AUD2HTX_CTRE_WH_SHIFT 24 +#define AUD2HTX_CTRE_WH_WIDTH 5 +#define AUD2HTX_CTRE_WH_MASK ((BIT(AUD2HTX_CTRE_WH_WIDTH) - 1) \ + << AUD2HTX_CTRE_WH_SHIFT) + +/* AUD2HTX IRQ Masks Register */ +#define AUD2HTX_WM_HIGH_IRQ_MASK BIT(2) +#define AUD2HTX_WM_LOW_IRQ_MASK BIT(1) +#define AUD2HTX_OVF_MASK BIT(0) + +#define AUD2HTX_FIFO_DEPTH 0x20 +#define AUD2HTX_WTMK_LOW 0x10 +#define AUD2HTX_WTMK_HIGH 0x10 +#define AUD2HTX_MAXBURST 0x10 + +/** + * fsl_aud2htx: AUD2HTX private data + * + * @pdev: platform device pointer + * @regmap: regmap handler + * @bus_clk: clock source to access register + * @dma_params_rx: DMA parameters for receive channel + * @dma_params_tx: DMA parameters for transmit channel + */ +struct fsl_aud2htx { + struct platform_device *pdev; + struct regmap *regmap; + struct clk *bus_clk; + + struct snd_dmaengine_dai_dma_data dma_params_rx; + struct snd_dmaengine_dai_dma_data dma_params_tx; +}; + +#endif /* _FSL_AUD2HTX_H */ -- cgit v1.2.3 From 372c4bd11de1793667e11d19c29fffc80495eeca Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 6 Nov 2020 09:25:48 +0200 Subject: ASoC: ti: davinci-mcasp: Use platform_get_irq_byname_optional Depending on the integration of McASP either the 'common' or the 'rx' and 'tx' or only the 'tx' interrupt number is valid, provided. By switching to platform_get_irq_byname_optional() we can clean up the bootlog from messages like: davinci-mcasp 2ba0000.mcasp: IRQ common not found The irq number == 0 is not valid, fix the check at the same time. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201106072551.689-2-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 9df8194a2c22..20a7c37d4bdf 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2202,8 +2202,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->dev = &pdev->dev; - irq = platform_get_irq_byname(pdev, "common"); - if (irq >= 0) { + irq = platform_get_irq_byname_optional(pdev, "common"); + if (irq > 0) { irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common", dev_name(&pdev->dev)); if (!irq_name) { @@ -2223,8 +2223,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; } - irq = platform_get_irq_byname(pdev, "rx"); - if (irq >= 0) { + irq = platform_get_irq_byname_optional(pdev, "rx"); + if (irq > 0) { irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx", dev_name(&pdev->dev)); if (!irq_name) { @@ -2242,8 +2242,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; } - irq = platform_get_irq_byname(pdev, "tx"); - if (irq >= 0) { + irq = platform_get_irq_byname_optional(pdev, "tx"); + if (irq > 0) { irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx", dev_name(&pdev->dev)); if (!irq_name) { -- cgit v1.2.3 From db8793a39b293d5a8983e1713a70a76cb039c2fe Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 6 Nov 2020 09:25:49 +0200 Subject: ASoC: ti: davinci-mcasp: Remove legacy dma_request parsing The legacy dma_request (which was holding the DMA request number) is no longer in use for a long time. All legacy platforms has been converted to dma_slave_map. Remove it along with the DT parsing to get tx_dma_channel and rx_dma_channel. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201106072551.689-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 57 +++----------------------------------------- 1 file changed, 3 insertions(+), 54 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 20a7c37d4bdf..90b05a879214 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -94,7 +94,6 @@ struct davinci_mcasp { u8 bclk_div; int streams; u32 irq_request[2]; - int dma_request[2]; int sysclk_freq; bool bclk_master; @@ -1755,7 +1754,6 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( struct davinci_mcasp_pdata *pdata = NULL; const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev); - struct of_phandle_args dma_spec; const u32 *of_serial_dir32; u32 val; @@ -1810,31 +1808,6 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( pdata->serial_dir = of_serial_dir; } - ret = of_property_match_string(np, "dma-names", "tx"); - if (ret < 0) - goto nodata; - - ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, - &dma_spec); - if (ret < 0) - goto nodata; - - pdata->tx_dma_channel = dma_spec.args[0]; - - /* RX is not valid in DIT mode */ - if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) { - ret = of_property_match_string(np, "dma-names", "rx"); - if (ret < 0) - goto nodata; - - ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret, - &dma_spec); - if (ret < 0) - goto nodata; - - pdata->rx_dma_channel = dma_spec.args[0]; - } - ret = of_property_read_u32(np, "tx-num-evt", &val); if (ret >= 0) pdata->txnumevt = val; @@ -2127,11 +2100,10 @@ static void davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp) static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; - struct resource *mem, *res, *dat; + struct resource *mem, *dat; struct davinci_mcasp_pdata *pdata; struct davinci_mcasp *mcasp; char *irq_name; - int *dma; int irq; int ret; @@ -2266,45 +2238,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->dat_port = true; dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; + dma_data->filter_data = "tx"; if (dat) dma_data->addr = dat->start; else dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata); - dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (res) - *dma = res->start; - else - *dma = pdata->tx_dma_channel; - - /* dmaengine filter data for DT and non-DT boot */ - if (pdev->dev.of_node) - dma_data->filter_data = "tx"; - else - dma_data->filter_data = dma; /* RX is not valid in DIT mode */ if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE]; + dma_data->filter_data = "rx"; if (dat) dma_data->addr = dat->start; else dma_data->addr = mem->start + davinci_mcasp_rxdma_offset(pdata); - - dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE]; - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (res) - *dma = res->start; - else - *dma = pdata->rx_dma_channel; - - /* dmaengine filter data for DT and non-DT boot */ - if (pdev->dev.of_node) - dma_data->filter_data = "rx"; - else - dma_data->filter_data = dma; } if (mcasp->version < MCASP_VERSION_3) { -- cgit v1.2.3 From 1125d925990b8d8166c45396c9281e2a705c97f8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 6 Nov 2020 09:25:50 +0200 Subject: ASoC: ti: davinci-mcasp: Simplify the configuration parameter handling Replace the davinci_mcasp_set_pdata_from_of() function which returned a pdata pointer with davinci_mcasp_get_config() to return an actual error code and handle all pdata validation and private mcasp struct setup in there. Drop the unused ram-size-playback and sram-size-capture query from DT at the same time. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201106072551.689-4-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 164 ++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 104 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 90b05a879214..5aa6a647dfdc 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -76,6 +76,7 @@ struct davinci_mcasp_ruledata { struct davinci_mcasp { struct snd_dmaengine_dai_dma_data dma_data[2]; + struct davinci_mcasp_pdata *pdata; void __iomem *base; u32 fifo_base; struct device *dev; @@ -1747,44 +1748,37 @@ err1: return ret; } -static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( - struct platform_device *pdev) +static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp, + struct platform_device *pdev) { + const struct of_device_id *match = of_match_device(mcasp_dt_ids, &pdev->dev); struct device_node *np = pdev->dev.of_node; struct davinci_mcasp_pdata *pdata = NULL; - const struct of_device_id *match = - of_match_device(mcasp_dt_ids, &pdev->dev); - const u32 *of_serial_dir32; u32 val; - int i, ret = 0; + int i; if (pdev->dev.platform_data) { pdata = pdev->dev.platform_data; pdata->dismod = DISMOD_LOW; - return pdata; + goto out; } else if (match) { pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata), GFP_KERNEL); if (!pdata) - return NULL; + return -ENOMEM; } else { - /* control shouldn't reach here. something is wrong */ - ret = -EINVAL; - goto nodata; + dev_err(&pdev->dev, "No compatible match found\n"); + return -EINVAL; } - ret = of_property_read_u32(np, "op-mode", &val); - if (ret >= 0) + if (of_property_read_u32(np, "op-mode", &val) == 0) pdata->op_mode = val; - ret = of_property_read_u32(np, "tdm-slots", &val); - if (ret >= 0) { + if (of_property_read_u32(np, "tdm-slots", &val) == 0) { if (val < 2 || val > 32) { - dev_err(&pdev->dev, - "tdm-slots must be in rage [2-32]\n"); - ret = -EINVAL; - goto nodata; + dev_err(&pdev->dev, "tdm-slots must be in rage [2-32]\n"); + return -EINVAL; } pdata->tdm_slots = val; @@ -1796,10 +1790,8 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( u8 *of_serial_dir = devm_kzalloc(&pdev->dev, (sizeof(*of_serial_dir) * val), GFP_KERNEL); - if (!of_serial_dir) { - ret = -ENOMEM; - goto nodata; - } + if (!of_serial_dir) + return -ENOMEM; for (i = 0; i < val; i++) of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); @@ -1808,24 +1800,16 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( pdata->serial_dir = of_serial_dir; } - ret = of_property_read_u32(np, "tx-num-evt", &val); - if (ret >= 0) + if (of_property_read_u32(np, "tx-num-evt", &val) == 0) pdata->txnumevt = val; - ret = of_property_read_u32(np, "rx-num-evt", &val); - if (ret >= 0) + if (of_property_read_u32(np, "rx-num-evt", &val) == 0) pdata->rxnumevt = val; - ret = of_property_read_u32(np, "sram-size-playback", &val); - if (ret >= 0) - pdata->sram_size_playback = val; - - ret = of_property_read_u32(np, "sram-size-capture", &val); - if (ret >= 0) - pdata->sram_size_capture = val; + if (of_property_read_u32(np, "auxclk-fs-ratio", &val) == 0) + mcasp->auxclk_fs_ratio = val; - ret = of_property_read_u32(np, "dismod", &val); - if (ret >= 0) { + if (of_property_read_u32(np, "dismod", &val) == 0) { if (val == 0 || val == 2 || val == 3) { pdata->dismod = DISMOD_VAL(val); } else { @@ -1836,15 +1820,40 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( pdata->dismod = DISMOD_LOW; } - return pdata; +out: + mcasp->pdata = pdata; -nodata: - if (ret < 0) { - dev_err(&pdev->dev, "Error populating platform data, err %d\n", - ret); - pdata = NULL; + mcasp->op_mode = pdata->op_mode; + /* sanity check for tdm slots parameter */ + if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { + if (pdata->tdm_slots < 2) { + dev_warn(&pdev->dev, "invalid tdm slots: %d\n", + pdata->tdm_slots); + mcasp->tdm_slots = 2; + } else if (pdata->tdm_slots > 32) { + dev_warn(&pdev->dev, "invalid tdm slots: %d\n", + pdata->tdm_slots); + mcasp->tdm_slots = 32; + } else { + mcasp->tdm_slots = pdata->tdm_slots; + } } - return pdata; + + mcasp->num_serializer = pdata->num_serializer; +#ifdef CONFIG_PM + mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev, + mcasp->num_serializer, sizeof(u32), + GFP_KERNEL); + if (!mcasp->context.xrsr_regs) + return -ENOMEM; +#endif + mcasp->serial_dir = pdata->serial_dir; + mcasp->version = pdata->version; + mcasp->txnumevt = pdata->txnumevt; + mcasp->rxnumevt = pdata->rxnumevt; + mcasp->dismod = pdata->dismod; + + return 0; } enum { @@ -2083,25 +2092,10 @@ static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) } #endif /* CONFIG_GPIOLIB */ -static void davinci_mcasp_get_dt_params(struct davinci_mcasp *mcasp) -{ - struct device_node *np = mcasp->dev->of_node; - int ret; - u32 val; - - if (!np) - return; - - ret = of_property_read_u32(np, "auxclk-fs-ratio", &val); - if (ret >= 0) - mcasp->auxclk_fs_ratio = val; -} - static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; struct resource *mem, *dat; - struct davinci_mcasp_pdata *pdata; struct davinci_mcasp *mcasp; char *irq_name; int irq; @@ -2117,11 +2111,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (!mcasp) return -ENOMEM; - pdata = davinci_mcasp_set_pdata_from_of(pdev); - if (!pdata) { - dev_err(&pdev->dev, "no platform data\n"); - return -EINVAL; - } + mcasp->dev = &pdev->dev; + ret = davinci_mcasp_get_config(mcasp, pdev); + if (ret) + return ret; mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); if (!mem) { @@ -2140,40 +2133,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - mcasp->op_mode = pdata->op_mode; - /* sanity check for tdm slots parameter */ - if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { - if (pdata->tdm_slots < 2) { - dev_err(&pdev->dev, "invalid tdm slots: %d\n", - pdata->tdm_slots); - mcasp->tdm_slots = 2; - } else if (pdata->tdm_slots > 32) { - dev_err(&pdev->dev, "invalid tdm slots: %d\n", - pdata->tdm_slots); - mcasp->tdm_slots = 32; - } else { - mcasp->tdm_slots = pdata->tdm_slots; - } - } - - mcasp->num_serializer = pdata->num_serializer; -#ifdef CONFIG_PM - mcasp->context.xrsr_regs = devm_kcalloc(&pdev->dev, - mcasp->num_serializer, sizeof(u32), - GFP_KERNEL); - if (!mcasp->context.xrsr_regs) { - ret = -ENOMEM; - goto err; - } -#endif - mcasp->serial_dir = pdata->serial_dir; - mcasp->version = pdata->version; - mcasp->txnumevt = pdata->txnumevt; - mcasp->rxnumevt = pdata->rxnumevt; - mcasp->dismod = pdata->dismod; - - mcasp->dev = &pdev->dev; - irq = platform_get_irq_byname_optional(pdev, "common"); if (irq > 0) { irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common", @@ -2242,7 +2201,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (dat) dma_data->addr = dat->start; else - dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata); + dma_data->addr = mem->start + davinci_mcasp_txdma_offset(mcasp->pdata); /* RX is not valid in DIT mode */ @@ -2253,7 +2212,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->addr = dat->start; else dma_data->addr = - mem->start + davinci_mcasp_rxdma_offset(pdata); + mem->start + davinci_mcasp_rxdma_offset(mcasp->pdata); } if (mcasp->version < MCASP_VERSION_3) { @@ -2306,11 +2265,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret) goto err; - davinci_mcasp_get_dt_params(mcasp); - - ret = devm_snd_soc_register_component(&pdev->dev, - &davinci_mcasp_component, - &davinci_mcasp_dai[pdata->op_mode], 1); + ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, + &davinci_mcasp_dai[mcasp->op_mode], 1); if (ret != 0) goto err; -- cgit v1.2.3 From 1b4fb70e5b28a477478417a7958e0228460ffe68 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 6 Nov 2020 09:25:51 +0200 Subject: ASoC: ti: davinci-mcasp: Handle missing required DT properties McASP needs three required properties to be usable for audio: op-mode, tdm-slots and the serial-dir array. Instead of probing the driver even without the needed information we should make sure that all the parameters are provided for operation. The fact that McASP can act as a GPIO controller for it's pins complicates this a bit, but as a general rule we can: - we fail the probe if McASP is not configured to be used as gpiochip - we will not register the DAI (and PCM) if gpiochip is defined Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201106072551.689-5-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 77 +++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 5aa6a647dfdc..7eab8351177a 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -83,6 +83,9 @@ struct davinci_mcasp { struct snd_pcm_substream *substreams[2]; unsigned int dai_fmt; + /* Audio can not be enabled due to missing parameter(s) */ + bool missing_audio_param; + /* McASP specific data */ int tdm_slots; u32 tdm_mask[2]; @@ -1748,6 +1751,17 @@ err1: return ret; } +static bool davinci_mcasp_have_gpiochip(struct davinci_mcasp *mcasp) +{ +#ifdef CONFIG_OF_GPIO + if (mcasp->dev->of_node && + of_property_read_bool(mcasp->dev->of_node, "gpio-controller")) + return true; +#endif + + return false; +} + static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp, struct platform_device *pdev) { @@ -1772,8 +1786,12 @@ static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp, return -EINVAL; } - if (of_property_read_u32(np, "op-mode", &val) == 0) + if (of_property_read_u32(np, "op-mode", &val) == 0) { pdata->op_mode = val; + } else { + mcasp->missing_audio_param = true; + goto out; + } if (of_property_read_u32(np, "tdm-slots", &val) == 0) { if (val < 2 || val > 32) { @@ -1782,6 +1800,9 @@ static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp, } pdata->tdm_slots = val; + } else if (pdata->op_mode == DAVINCI_MCASP_IIS_MODE) { + mcasp->missing_audio_param = true; + goto out; } of_serial_dir32 = of_get_property(np, "serial-dir", &val); @@ -1798,6 +1819,9 @@ static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp, pdata->num_serializer = val; pdata->serial_dir = of_serial_dir; + } else { + mcasp->missing_audio_param = true; + goto out; } if (of_property_read_u32(np, "tx-num-evt", &val) == 0) @@ -1823,6 +1847,16 @@ static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp, out: mcasp->pdata = pdata; + if (mcasp->missing_audio_param) { + if (davinci_mcasp_have_gpiochip(mcasp)) { + dev_dbg(&pdev->dev, "Missing DT parameter(s) for audio\n"); + return 0; + } + + dev_err(&pdev->dev, "Insufficient DT parameter(s)\n"); + return -ENODEV; + } + mcasp->op_mode = pdata->op_mode; /* sanity check for tdm slots parameter */ if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { @@ -2072,7 +2106,7 @@ static const struct gpio_chip davinci_mcasp_template_chip = { static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) { - if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller")) + if (!davinci_mcasp_have_gpiochip(mcasp)) return 0; mcasp->gpio_chip = davinci_mcasp_template_chip; @@ -2111,11 +2145,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (!mcasp) return -ENOMEM; - mcasp->dev = &pdev->dev; - ret = davinci_mcasp_get_config(mcasp, pdev); - if (ret) - return ret; - mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); if (!mem) { dev_warn(&pdev->dev, @@ -2131,8 +2160,23 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (IS_ERR(mcasp->base)) return PTR_ERR(mcasp->base); + dev_set_drvdata(&pdev->dev, mcasp); pm_runtime_enable(&pdev->dev); + mcasp->dev = &pdev->dev; + ret = davinci_mcasp_get_config(mcasp, pdev); + if (ret) + goto err; + + /* All PINS as McASP */ + pm_runtime_get_sync(mcasp->dev); + mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); + pm_runtime_put(mcasp->dev); + + /* Skip audio related setup code if the configuration is not adequat */ + if (mcasp->missing_audio_param) + goto no_audio; + irq = platform_get_irq_byname_optional(pdev, "common"); if (irq > 0) { irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common", @@ -2252,19 +2296,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret) goto err; - dev_set_drvdata(&pdev->dev, mcasp); - mcasp_reparent_fck(pdev); - /* All PINS as McASP */ - pm_runtime_get_sync(mcasp->dev); - mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); - pm_runtime_put(mcasp->dev); - - ret = davinci_mcasp_init_gpiochip(mcasp); - if (ret) - goto err; - ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[mcasp->op_mode], 1); @@ -2294,8 +2327,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev) goto err; } - return 0; +no_audio: + ret = davinci_mcasp_init_gpiochip(mcasp); + if (ret) { + dev_err(&pdev->dev, "gpiochip registration failed: %d\n", ret); + goto err; + } + return 0; err: pm_runtime_disable(&pdev->dev); return ret; -- cgit v1.2.3 From 95370acdb87d73b12a0e6895fa422a6409d14a01 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 9 Nov 2020 14:29:58 +0800 Subject: ASoC: rt1015: modification for calibration to get better performance Modification for calibration to get better performance. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20201109062958.16917-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015.c | 101 ++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 53 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index a9cd6ad0bf5a..db45ec60dd09 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -492,18 +492,40 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015) snd_soc_dapm_mutex_lock(&component->dapm); regcache_cache_bypass(regmap, true); - regmap_write(regmap, RT1015_PWR1, 0xd7df); - regmap_write(regmap, RT1015_PWR4, 0x00b2); - regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2008); + regmap_write(regmap, RT1015_PWR9, 0xAA60); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0089); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008A); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008C); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008D); + regmap_write(regmap, RT1015_PWR4, 0x80B2); + regmap_write(regmap, RT1015_CLASSD_SEQ, 0x5797); + regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2100); + regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0100); + regmap_write(regmap, RT1015_PWR5, 0x2175); + regmap_write(regmap, RT1015_MIXER1, 0x005D); + regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1); + regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12F7); + regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x1205); + msleep(200); + regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2000); + regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0180); + regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x00A1); + regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x0A05); + msleep(200); + regmap_write(regmap, RT1015_PWR4, 0x00B2); + regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2028); regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140); - regmap_write(regmap, RT1015_GAT_BOOST, 0x0efe); - regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000d); - regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000e); - regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a00); - regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a01); - regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a05); - msleep(500); - regmap_write(regmap, RT1015_PWR1, 0x0); + regmap_write(regmap, RT1015_PWR5, 0x0175); + regmap_write(regmap, RT1015_CLSD_INTERNAL1, 0x1721); + regmap_write(regmap, RT1015_CLASSD_SEQ, 0x570E); + regmap_write(regmap, RT1015_MIXER1, 0x203D); + regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5A01); + regmap_write(regmap, RT1015_CLSD_INTERNAL2, 0x12FF); + regmap_write(regmap, RT1015_GAT_BOOST, 0x0eFE); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x008E); + regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0088); + regmap_write(regmap, RT1015_SYS_RST1, 0x05F5); + regmap_write(regmap, RT1015_SYS_RST2, 0x0b9a); regcache_cache_bypass(regmap, false); regcache_mark_dirty(regmap); @@ -598,6 +620,8 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, if (rt1015->bypass_boost == RT1015_Enable_Boost) { snd_soc_component_write(component, RT1015_SYS_RST1, 0x05f7); + snd_soc_component_write(component, + RT1015_SYS_RST2, 0x0b0a); snd_soc_component_write(component, RT1015_GAT_BOOST, 0xacfe); snd_soc_component_write(component, @@ -605,10 +629,14 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, snd_soc_component_write(component, RT1015_GAT_BOOST, 0xecfe); } else { + snd_soc_component_write(component, + 0x032d, 0xaa60); snd_soc_component_write(component, RT1015_SYS_RST1, 0x05f7); snd_soc_component_write(component, - RT1015_PWR_STATE_CTRL, 0x026e); + RT1015_SYS_RST2, 0x0b0a); + snd_soc_component_write(component, + RT1015_PWR_STATE_CTRL, 0x008e); } break; @@ -622,11 +650,17 @@ static int r1015_dac_event(struct snd_soc_dapm_widget *w, RT1015_PWR9, 0xa800); snd_soc_component_write(component, RT1015_SYS_RST1, 0x05f5); + snd_soc_component_write(component, + RT1015_SYS_RST2, 0x0b9a); } else { snd_soc_component_write(component, - RT1015_PWR_STATE_CTRL, 0x0268); + 0x032d, 0xaa60); + snd_soc_component_write(component, + RT1015_PWR_STATE_CTRL, 0x0088); snd_soc_component_write(component, RT1015_SYS_RST1, 0x05f5); + snd_soc_component_write(component, + RT1015_SYS_RST2, 0x0b9a); } rt1015->dac_is_used = 0; @@ -658,38 +692,12 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = { - SND_SOC_DAPM_SUPPLY("LDO2", RT1015_PWR1, RT1015_PWR_LDO2_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("INT RC CLK", RT1015_PWR1, RT1015_PWR_INTCLK_BIT, - 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ISENSE", RT1015_PWR1, RT1015_PWR_ISENSE_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("VSENSE", RT1015_PWR1, RT1015_PWR_VSENSE_BIT, 0, - NULL, 0), SND_SOC_DAPM_SUPPLY("PLL", RT1015_PWR1, RT1015_PWR_PLL_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("BG1 BG2", RT1015_PWR1, RT1015_PWR_BG_1_2_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("MBIAS BG", RT1015_PWR1, RT1015_PWR_MBIAS_BG_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("VBAT", RT1015_PWR1, RT1015_PWR_VBAT_BIT, 0, NULL, - 0), - SND_SOC_DAPM_SUPPLY("MBIAS", RT1015_PWR1, RT1015_PWR_MBIAS_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("ADCV", RT1015_PWR1, RT1015_PWR_ADCV_BIT, 0, NULL, - 0), - SND_SOC_DAPM_SUPPLY("MIXERV", RT1015_PWR1, RT1015_PWR_MIXERV_BIT, 0, - NULL, 0), - SND_SOC_DAPM_SUPPLY("SUMV", RT1015_PWR1, RT1015_PWR_SUMV_BIT, 0, NULL, - 0), - SND_SOC_DAPM_SUPPLY("VREFLV", RT1015_PWR1, RT1015_PWR_VREFLV_BIT, 0, - NULL, 0), - SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC_E("DAC", NULL, RT1015_PWR1, RT1015_PWR_DAC_BIT, 0, + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, rt1015_amp_drv_event, SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_OUTPUT("SPO"), @@ -697,19 +705,7 @@ static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = { static const struct snd_soc_dapm_route rt1015_dapm_routes[] = { { "DAC", NULL, "AIFRX" }, - { "DAC", NULL, "LDO2" }, { "DAC", NULL, "PLL", rt1015_is_sys_clk_from_pll}, - { "DAC", NULL, "INT RC CLK" }, - { "DAC", NULL, "ISENSE" }, - { "DAC", NULL, "VSENSE" }, - { "DAC", NULL, "BG1 BG2" }, - { "DAC", NULL, "MBIAS BG" }, - { "DAC", NULL, "VBAT" }, - { "DAC", NULL, "MBIAS" }, - { "DAC", NULL, "ADCV" }, - { "DAC", NULL, "MIXERV" }, - { "DAC", NULL, "SUMV" }, - { "DAC", NULL, "VREFLV" }, { "Amp Drv", NULL, "DAC" }, { "SPO", NULL, "Amp Drv" }, }; @@ -1052,7 +1048,6 @@ static int rt1015_probe(struct snd_soc_component *component) rt1015->component = component; rt1015->bclk_ratio = 0; rt1015->cali_done = 0; - snd_soc_component_write(component, RT1015_BAT_RPO_STEP1, 0x061c); INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work); -- cgit v1.2.3 From b2fc3029308dd1bace4c11c733eca2ef941b0e29 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Mon, 9 Nov 2020 18:34:15 +0800 Subject: ASoC: qcom: sc7180: Add missing PM ops Use PM ops snd_soc_pm_ops to handle suspend/resume like other machine drivers. Signed-off-by: Cheng-Yi Chiang Link: https://lore.kernel.org/r/20201109103415.607495-1-cychiang@chromium.org Signed-off-by: Mark Brown --- sound/soc/qcom/sc7180.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index b391f64c3a80..42e366ecc689 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -258,6 +258,7 @@ static struct platform_driver sc7180_snd_driver = { .driver = { .name = "msm-snd-sc7180", .of_match_table = sc7180_snd_device_id, + .pm = &snd_soc_pm_ops, }, }; module_platform_driver(sc7180_snd_driver); -- cgit v1.2.3 From 1cc3245b2c7464b6d6ad210b0e333781676de519 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Sat, 7 Nov 2020 10:20:43 +0800 Subject: ASoC: fsl_aud2htx: Remove dev_err() usage after platform_get_irq() platform_get_irq() would print error message internally, so dev_err() after platform_get_irq() is not needed Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/1604715643-29507-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_aud2htx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 124aeb70f24e..4091ccc7c3e9 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -211,11 +211,8 @@ static int fsl_aud2htx_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", - dev_name(&pdev->dev)); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, fsl_aud2htx_isr, 0, dev_name(&pdev->dev), aud2htx); -- cgit v1.2.3 From 8461352ddf076712350eeded350c13385c80ff38 Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Sun, 8 Nov 2020 00:13:31 +0800 Subject: ALSA: firewire: fix comparison to bool warning Fix the following coccicheck warning: ./sound/firewire/amdtp-stream.h:273:6-19: WARNING: Comparison to bool Reported-by: Tosk Robot Signed-off-by: Kaixu Xia Link: https://lore.kernel.org/r/1604765611-8209-1-git-send-email-kaixuxia@tencent.com Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 2ceb57d1d58e..a3daa1f2c1c4 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -270,7 +270,7 @@ static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s, unsigned int timeout) { return wait_event_timeout(s->callback_wait, - s->callbacked == true, + s->callbacked, msecs_to_jiffies(timeout)) > 0; } -- cgit v1.2.3 From 64a70744b77898a15d7a5b2b4dc0fa9523a75cde Mon Sep 17 00:00:00 2001 From: "Shane.Chien" Date: Tue, 10 Nov 2020 10:31:31 +0800 Subject: ASoC: Fix vaud18 power leakage of mt6359 vaud18 is power of mt6359 audio path. It should only enable when audio is used, instead of in boot up stage. Once mt6359 audio path is enabled or disabled, vaud18 is controlled by regulator supply widget "LDO_VAUD18". Due to vaud18 is controlled by regulator dapm macro instead of regmap, the macro MT6359_LDO_VAUD18_CON0 and variable avdd_reg is no used and removed from mt6359.h. Signed-off-by: Shane.Chien Link: https://lore.kernel.org/r/1604975492-6142-2-git-send-email-shane.chien@mediatek.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359.c | 25 +------------------------ sound/soc/codecs/mt6359.h | 8 -------- 2 files changed, 1 insertion(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index d20c59a87524..ecdfd5732075 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -1943,9 +1943,7 @@ static const struct snd_soc_dapm_widget mt6359_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF, MT6359_DCXO_CW12, RG_XO_AUDIO_EN_M_SFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY_S("LDO_VAUD18", SUPPLY_SEQ_LDO_VAUD18, - MT6359_LDO_VAUD18_CON0, - RG_LDO_VAUD18_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_REGULATOR_SUPPLY("LDO_VAUD18", 0, 0), SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB, MT6359_AUDDEC_ANA_CON13, RG_AUDGLB_PWRDN_VA32_SFT, 1, NULL, 0), @@ -2807,20 +2805,6 @@ static int mt6359_platform_driver_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, priv); priv->dev = &pdev->dev; - priv->avdd_reg = devm_regulator_get(&pdev->dev, "vaud18"); - if (IS_ERR(priv->avdd_reg)) { - dev_err(&pdev->dev, "%s(), have no vaud18 supply: %ld", - __func__, PTR_ERR(priv->avdd_reg)); - return PTR_ERR(priv->avdd_reg); - } - - ret = regulator_enable(priv->avdd_reg); - if (ret) { - dev_err(&pdev->dev, "%s(), failed to enable regulator!\n", - __func__); - return ret; - } - ret = mt6359_parse_dt(priv); if (ret) { dev_warn(&pdev->dev, "%s() failed to parse dts\n", __func__); @@ -2841,13 +2825,6 @@ static int mt6359_platform_driver_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s(), dev name %s\n", __func__, dev_name(&pdev->dev)); - ret = regulator_disable(priv->avdd_reg); - if (ret) { - dev_err(&pdev->dev, "%s(), failed to disable regulator!\n", - __func__); - return ret; - } - return 0; } diff --git a/sound/soc/codecs/mt6359.h b/sound/soc/codecs/mt6359.h index af6f07fbc4fd..35f806b7396d 100644 --- a/sound/soc/codecs/mt6359.h +++ b/sound/soc/codecs/mt6359.h @@ -135,11 +135,6 @@ /* MT6359_DCXO_CW12 */ #define RG_XO_AUDIO_EN_M_SFT 13 -/* LDO_VAUD18_CON0 */ -#define RG_LDO_VAUD18_EN_SFT 0 -#define RG_LDO_VAUD18_EN_MASK 0x1 -#define RG_LDO_VAUD18_EN_MASK_SFT (0x1 << 0) - /* AUD_TOP_CKPDN_CON0 */ #define RG_VOW13M_CK_PDN_SFT 13 #define RG_VOW13M_CK_PDN_MASK 0x1 @@ -2132,7 +2127,6 @@ #define MT6359_DCXO_CW11 0x7a6 #define MT6359_DCXO_CW12 0x7a8 -#define MT6359_LDO_VAUD18_CON0 0x1c98 #define MT6359_GPIO_MODE0 0xcc #define MT6359_GPIO_MODE0_SET 0xce @@ -2469,7 +2463,6 @@ enum { enum { /* common */ SUPPLY_SEQ_CLK_BUF, - SUPPLY_SEQ_LDO_VAUD18, SUPPLY_SEQ_AUD_GLB, SUPPLY_SEQ_HP_PULL_DOWN, SUPPLY_SEQ_CLKSQ, @@ -2629,7 +2622,6 @@ struct mt6359_priv { int hp_gain_ctl; int hp_hifi_mode; int mtkaif_protocol; - struct regulator *avdd_reg; }; #define CODEC_MT6359_NAME "mtk-codec-mt6359" -- cgit v1.2.3 From 3cfbf07c6d2779d24a6f5b999a91f400256b1d4e Mon Sep 17 00:00:00 2001 From: Ajye Huang Date: Fri, 6 Nov 2020 14:14:33 +0800 Subject: ASoC: qcom: sc7180: Modify machine driver for 2mic In addition, having mixer control to switch between DMICs by using "dmic-gpios" property. Refer to this one as an example, commit b7a742cff3f6 ("ASoC: AMD: Use mixer control to switch between DMICs") Signed-off-by: Ajye Huang Reviewed-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201106061433.1483129-3-ajye_huang@compal.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc7180.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index 42e366ecc689..878fd0169aab 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -5,6 +5,8 @@ // sc7180.c -- ALSA SoC Machine driver for SC7180 #include +#include +#include #include #include #include @@ -28,6 +30,8 @@ struct sc7180_snd_data { u32 pri_mi2s_clk_count; struct snd_soc_jack hs_jack; struct snd_soc_jack hdmi_jack; + struct gpio_desc *dmic_sel; + int dmic_switch; }; static void sc7180_jack_free(struct snd_jack *jack) @@ -169,6 +173,27 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) return 0; } +static int dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card); + + ucontrol->value.integer.value[0] = data->dmic_switch; + return 0; +} + +static int dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card); + + data->dmic_switch = ucontrol->value.integer.value[0]; + gpiod_set_value(data->dmic_sel, data->dmic_switch); + return 0; +} + static void sc7180_snd_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -206,6 +231,30 @@ static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), }; +static const char * const dmic_mux_text[] = { + "Front Mic", + "Rear Mic", +}; + +static SOC_ENUM_SINGLE_DECL(sc7180_dmic_enum, + SND_SOC_NOPM, 0, dmic_mux_text); + +static const struct snd_kcontrol_new sc7180_dmic_mux_control = + SOC_DAPM_ENUM_EXT("DMIC Select Mux", sc7180_dmic_enum, + dmic_get, dmic_set); + +static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("DMIC", NULL), + SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control), +}; + +static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = { + {"Dmic Mux", "Front Mic", "DMIC"}, + {"Dmic Mux", "Rear Mic", "DMIC"}, +}; + static void sc7180_add_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; @@ -238,6 +287,18 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) card->dapm_widgets = sc7180_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets); + if (of_property_read_bool(dev->of_node, "dmic-gpios")) { + card->dapm_widgets = sc7180_snd_dual_mic_widgets, + card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets), + card->dapm_routes = sc7180_snd_dual_mic_audio_route, + card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route), + data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW); + if (IS_ERR(data->dmic_sel)) { + dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n", PTR_ERR(data->dmic_sel)); + return PTR_ERR(data->dmic_sel); + } + } + ret = qcom_snd_parse_of(card); if (ret) return ret; -- cgit v1.2.3 From eb84959ab8c0ca2897e69575110bdaaf2d532eb7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 30 Oct 2020 10:01:15 +0900 Subject: ASoC: soc-compress: tidyup STREAM vs COMPRESS snd_soc_runtime_activate() and snd_soc_dai_digital_mute() need SNDRV_PCM_STREAM_xxx instead of SND_COMPRESS_xxx. These are bug but nothing happen because these are same value. enum { SNDRV_PCM_STREAM_PLAYBACK = 0, SNDRV_PCM_STREAM_CAPTURE, ... }; enum snd_compr_direction { SND_COMPRESS_PLAYBACK = 0, SND_COMPRESS_CAPTURE }; This patch tidyup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874kmcmsyn.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 3a6a60215e81..52544a85725d 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -75,8 +75,14 @@ static int soc_compr_open(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component = NULL; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int stream; int ret; + if (cstream->direction == SND_COMPRESS_PLAYBACK) + stream = SNDRV_PCM_STREAM_PLAYBACK; + else + stream = SNDRV_PCM_STREAM_CAPTURE; + ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream); if (ret < 0) goto pm_err; @@ -95,7 +101,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) if (ret < 0) goto machine_err; - snd_soc_runtime_activate(rtd, cstream->direction); + snd_soc_runtime_activate(rtd, stream); mutex_unlock(&rtd->card->pcm_mutex); @@ -208,7 +214,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) snd_soc_runtime_deactivate(rtd, stream); - snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); + snd_soc_dai_digital_mute(codec_dai, 1, stream); if (!snd_soc_dai_active(cpu_dai)) cpu_dai->rate = 0; @@ -304,10 +310,16 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int stream; int ret; mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + if (cstream->direction == SND_COMPRESS_PLAYBACK) + stream = SNDRV_PCM_STREAM_PLAYBACK; + else + stream = SNDRV_PCM_STREAM_CAPTURE; + ret = soc_compr_components_trigger(cstream, cmd); if (ret < 0) goto out; @@ -318,10 +330,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction); + snd_soc_dai_digital_mute(codec_dai, 0, stream); break; case SNDRV_PCM_TRIGGER_STOP: - snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); + snd_soc_dai_digital_mute(codec_dai, 1, stream); break; } -- cgit v1.2.3 From 7428d8c8bd7936840b4615df674cee5fce1eb385 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 30 Oct 2020 10:01:22 +0900 Subject: ASoC: soc-compress: assume SNDRV_PCM_STREAM_xxx and SND_COMPRESS_xxx are same soc-compress.c is using both SND_COMPRESS_xxx and SND_PCM_STREAM_xxx. These are defined as UAPI, and has same value. enum { SNDRV_PCM_STREAM_PLAYBACK = 0, SNDRV_PCM_STREAM_CAPTURE, ... }; enum snd_compr_direction { SND_COMPRESS_PLAYBACK = 0, SND_COMPRESS_CAPTURE }; Essentially both COMPRESS and PCM_STREAM definitions are identical, and can be never different because of ABI compatibility, which means it's safe to mix both variants in the code. This patch checks it by BUILD_BUG_ON(), and merge to use. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87361wmsyg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 67 ++++++++++++++---------------------------------- 1 file changed, 19 insertions(+), 48 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 52544a85725d..c7ad52a21a29 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -75,14 +75,9 @@ static int soc_compr_open(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component = NULL; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - int stream; + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ int ret; - if (cstream->direction == SND_COMPRESS_PLAYBACK) - stream = SNDRV_PCM_STREAM_PLAYBACK; - else - stream = SNDRV_PCM_STREAM_CAPTURE; - ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream); if (ret < 0) goto pm_err; @@ -128,14 +123,9 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list; - int stream; + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ int ret; - if (cstream->direction == SND_COMPRESS_PLAYBACK) - stream = SNDRV_PCM_STREAM_PLAYBACK; - else - stream = SNDRV_PCM_STREAM_CAPTURE; - mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); fe->dpcm[stream].runtime = fe_substream->runtime; @@ -203,15 +193,10 @@ static int soc_compr_free(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int stream; + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - if (cstream->direction == SND_COMPRESS_PLAYBACK) - stream = SNDRV_PCM_STREAM_PLAYBACK; - else - stream = SNDRV_PCM_STREAM_CAPTURE; - snd_soc_runtime_deactivate(rtd, stream); snd_soc_dai_digital_mute(codec_dai, 1, stream); @@ -242,15 +227,11 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); struct snd_soc_dpcm *dpcm; - int stream, ret; + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ + int ret; mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - if (cstream->direction == SND_COMPRESS_PLAYBACK) - stream = SNDRV_PCM_STREAM_PLAYBACK; - else - stream = SNDRV_PCM_STREAM_CAPTURE; - snd_soc_runtime_deactivate(fe, stream); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -310,16 +291,11 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - int stream; + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ int ret; mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - if (cstream->direction == SND_COMPRESS_PLAYBACK) - stream = SNDRV_PCM_STREAM_PLAYBACK; - else - stream = SNDRV_PCM_STREAM_CAPTURE; - ret = soc_compr_components_trigger(cstream, cmd); if (ret < 0) goto out; @@ -346,17 +322,13 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) { struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); - int ret, stream; + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ + int ret; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || cmd == SND_COMPR_TRIGGER_DRAIN) return soc_compr_components_trigger(cstream, cmd); - if (cstream->direction == SND_COMPRESS_PLAYBACK) - stream = SNDRV_PCM_STREAM_PLAYBACK; - else - stream = SNDRV_PCM_STREAM_CAPTURE; - mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); ret = snd_soc_dai_compr_trigger(cpu_dai, cstream, cmd); @@ -418,6 +390,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ int ret; mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); @@ -441,12 +414,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, if (ret < 0) goto err; - if (cstream->direction == SND_COMPRESS_PLAYBACK) - snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, - SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, - SND_SOC_DAPM_STREAM_START); + snd_soc_dapm_stream_event(rtd, stream, SND_SOC_DAPM_STREAM_START); /* cancel any delayed stream shutdown that is pending */ rtd->pop_wait = 0; @@ -468,12 +436,8 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_pcm_substream *fe_substream = fe->pcm->streams[cstream->direction].substream; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); - int ret, stream; - - if (cstream->direction == SND_COMPRESS_PLAYBACK) - stream = SNDRV_PCM_STREAM_PLAYBACK; - else - stream = SNDRV_PCM_STREAM_CAPTURE; + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ + int ret; mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); @@ -771,6 +735,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) int playback = 0, capture = 0; int i; + /* + * make sure these are same value, + * and then use these as equally + */ + BUILD_BUG_ON((int)SNDRV_PCM_STREAM_PLAYBACK != (int)SND_COMPRESS_PLAYBACK); + BUILD_BUG_ON((int)SNDRV_PCM_STREAM_CAPTURE != (int)SND_COMPRESS_CAPTURE); + if (rtd->num_cpus > 1 || rtd->num_codecs > 1) { dev_err(rtd->card->dev, -- cgit v1.2.3 From 4d1a9952dda649284413e6ff12b81db3a2bc4115 Mon Sep 17 00:00:00 2001 From: David Lin Date: Mon, 2 Nov 2020 10:32:13 +0800 Subject: ASoC: nau8315: add codec driver Add codec driver for Nuvoton NAU8315. Signed-off-by: David Lin Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201102023212.594137-1-CTLIN0@nuvoton.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/nau8315.txt | 18 +++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/nau8315.c | 166 +++++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nau8315.txt create mode 100644 sound/soc/codecs/nau8315.c (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/nau8315.txt b/Documentation/devicetree/bindings/sound/nau8315.txt new file mode 100644 index 000000000000..6eaec46f384c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nau8315.txt @@ -0,0 +1,18 @@ +Nuvoton NAU8315 Mono Class-D Amplifier + +Required properties: +- compatible : "nuvoton,nau8315" + +Optional properties: +- enable-gpios : GPIO specifier for the chip's device enable input(EN) pin. + If this option is not specified then driver does not manage + the pin state (e.g. chip is always on). + +Example: + +#include + +nau8315 { + compatible = "nuvoton,nau8315"; + enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5791b7056af6..2b6eceb3573c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -130,6 +130,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_MT6358 imply SND_SOC_MT6359 imply SND_SOC_MT6660 + imply SND_SOC_NAU8315 imply SND_SOC_NAU8540 imply SND_SOC_NAU8810 imply SND_SOC_NAU8822 @@ -1760,6 +1761,10 @@ config SND_SOC_MT6660 Select N if you don't have MT6660 on board. Select M to build this as module. +config SND_SOC_NAU8315 + tristate "Nuvoton Technology Corporation NAU8315 CODEC" + depends on GPIOLIB + config SND_SOC_NAU8540 tristate "Nuvoton Technology Corporation NAU85L40 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 11ce98c25d6c..144d9256d4d5 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -129,6 +129,7 @@ snd-soc-mt6351-objs := mt6351.o snd-soc-mt6358-objs := mt6358.o snd-soc-mt6359-objs := mt6359.o snd-soc-mt6660-objs := mt6660.o +snd-soc-nau8315-objs := nau8315.o snd-soc-nau8540-objs := nau8540.o snd-soc-nau8810-objs := nau8810.o snd-soc-nau8822-objs := nau8822.o @@ -438,6 +439,7 @@ obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o +obj-$(CONFIG_SND_SOC_NAU8315) += snd-soc-nau8315.o obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c new file mode 100644 index 000000000000..e6bc5c0a5036 --- /dev/null +++ b/sound/soc/codecs/nau8315.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// nau8315.c -- NAU8315 ALSA SoC Audio Amplifier Driver +// +// Copyright 2020 Nuvoton Technology Crop. +// +// Author: David Lin +// +// Based on MAX98357A.c + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct nau8315_priv { + struct gpio_desc *enable; + int enpin_switch; +}; + +static int nau8315_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct nau8315_priv *nau8315 = + snd_soc_component_get_drvdata(component); + + if (!nau8315->enable) + return 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (nau8315->enpin_switch) { + gpiod_set_value(nau8315->enable, 1); + dev_dbg(component->dev, "set enable to 1"); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + gpiod_set_value(nau8315->enable, 0); + dev_dbg(component->dev, "set enable to 0"); + break; + } + + return 0; +} + +static int nau8315_enpin_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct nau8315_priv *nau8315 = + snd_soc_component_get_drvdata(component); + + if (event & SND_SOC_DAPM_POST_PMU) + nau8315->enpin_switch = 1; + else if (event & SND_SOC_DAPM_POST_PMD) + nau8315->enpin_switch = 0; + + return 0; +} + +static const struct snd_soc_dapm_widget nau8315_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("Speaker"), + SND_SOC_DAPM_OUT_DRV_E("EN_Pin", SND_SOC_NOPM, 0, 0, NULL, 0, + nau8315_enpin_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route nau8315_dapm_routes[] = { + {"EN_Pin", NULL, "HiFi Playback"}, + {"Speaker", NULL, "EN_Pin"}, +}; + +static const struct snd_soc_component_driver nau8315_component_driver = { + .dapm_widgets = nau8315_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(nau8315_dapm_widgets), + .dapm_routes = nau8315_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(nau8315_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct snd_soc_dai_ops nau8315_dai_ops = { + .trigger = nau8315_daiops_trigger, +}; + +#define NAU8315_RATES SNDRV_PCM_RATE_8000_96000 +#define NAU8315_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE) + +static struct snd_soc_dai_driver nau8315_dai_driver = { + .name = "nau8315-hifi", + .playback = { + .stream_name = "HiFi Playback", + .formats = NAU8315_FORMATS, + .rates = NAU8315_RATES, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &nau8315_dai_ops, +}; + +static int nau8315_platform_probe(struct platform_device *pdev) +{ + struct nau8315_priv *nau8315; + + nau8315 = devm_kzalloc(&pdev->dev, sizeof(*nau8315), GFP_KERNEL); + if (!nau8315) + return -ENOMEM; + + nau8315->enable = devm_gpiod_get_optional(&pdev->dev, + "enable", GPIOD_OUT_LOW); + if (IS_ERR(nau8315->enable)) + return PTR_ERR(nau8315->enable); + + dev_set_drvdata(&pdev->dev, nau8315); + + return devm_snd_soc_register_component(&pdev->dev, + &nau8315_component_driver, + &nau8315_dai_driver, 1); +} + +#ifdef CONFIG_OF +static const struct of_device_id nau8315_device_id[] = { + { .compatible = "nuvoton,nau8315" }, + {} +}; +MODULE_DEVICE_TABLE(of, nau8315_device_id); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id nau8315_acpi_match[] = { + { "NVTN2010", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, nau8315_acpi_match); +#endif + +static struct platform_driver nau8315_platform_driver = { + .driver = { + .name = "nau8315", + .of_match_table = of_match_ptr(nau8315_device_id), + .acpi_match_table = ACPI_PTR(nau8315_acpi_match), + }, + .probe = nau8315_platform_probe, +}; +module_platform_driver(nau8315_platform_driver); + +MODULE_DESCRIPTION("ASoC NAU8315 Mono Class-D Amplifier Driver"); +MODULE_AUTHOR("David Lin "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 9352d45a6e4588b8c7ddded871e08d89e0e6b79f Mon Sep 17 00:00:00 2001 From: David Lin Date: Tue, 10 Nov 2020 17:58:25 +0800 Subject: ASoC: nau8315: revise the power event of EN_PIN dapm widget for symmetry This patch is to revise the power event of EN_PIN dapm widget for symmetry. Signed-off-by: David Lin Link: https://lore.kernel.org/r/20201110095823.3512447-1-CTLIN0@nuvoton.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8315.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/nau8315.c b/sound/soc/codecs/nau8315.c index e6bc5c0a5036..2b66e3f7a8b7 100644 --- a/sound/soc/codecs/nau8315.c +++ b/sound/soc/codecs/nau8315.c @@ -65,7 +65,7 @@ static int nau8315_enpin_event(struct snd_soc_dapm_widget *w, struct nau8315_priv *nau8315 = snd_soc_component_get_drvdata(component); - if (event & SND_SOC_DAPM_POST_PMU) + if (event & SND_SOC_DAPM_PRE_PMU) nau8315->enpin_switch = 1; else if (event & SND_SOC_DAPM_POST_PMD) nau8315->enpin_switch = 0; @@ -77,7 +77,7 @@ static const struct snd_soc_dapm_widget nau8315_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("Speaker"), SND_SOC_DAPM_OUT_DRV_E("EN_Pin", SND_SOC_NOPM, 0, 0, NULL, 0, nau8315_enpin_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route nau8315_dapm_routes[] = { -- cgit v1.2.3 From 3256ef984b016fc8491f34cad594168b4b500317 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 2 Nov 2020 20:40:08 +0530 Subject: ASoC: soc-core: Fix component name_prefix parsing The "prefix" can be defined in DAI link node or it can be specified as part of the component node itself. Currently "sound-name-prefix" defined in a component is not taking effect. Actually the property is not getting parsed. It can be fixed by parsing "sound-name-prefix" property whenever "prefix" is missing in DAI link Codec node. Signed-off-by: Sameer Pujar Link: https://lore.kernel.org/r/1604329814-24779-2-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ea3986a46c12..cb7333da58f1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1124,7 +1124,8 @@ static void soc_set_name_prefix(struct snd_soc_card *card, for (i = 0; i < card->num_configs; i++) { struct snd_soc_codec_conf *map = &card->codec_conf[i]; - if (snd_soc_is_matching_component(&map->dlc, component)) { + if (snd_soc_is_matching_component(&map->dlc, component) && + map->name_prefix) { component->name_prefix = map->name_prefix; return; } -- cgit v1.2.3 From aa293777bfeb75fb8872565ef99cc0e8b98b5c7d Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 2 Nov 2020 20:40:09 +0530 Subject: ASoC: soc-pcm: Get all BEs along DAPM path dpcm_end_walk_at_be() stops the graph walk when first BE is found for the given FE component. In a component model we may want to connect multiple DAIs from different components. A new flag is introduced in 'snd_soc_card', which when set allows DAI/component chaining. Later PCM operations can be called for all these listed components for a valid DAPM path. Signed-off-by: Sameer Pujar Link: https://lore.kernel.org/r/1604329814-24779-3-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/soc-pcm.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 5ac578c9340c..4a9958b9b532 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1084,6 +1084,7 @@ struct snd_soc_card { unsigned int fully_routed:1; unsigned int disable_route_checks:1; unsigned int probed:1; + unsigned int component_chaining:1; void *drvdata; }; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2a39f355b3a4..aaab5cfe986b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1259,7 +1259,8 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe, /* get number of valid DAI paths and their widgets */ paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list, - dpcm_end_walk_at_be); + fe->card->component_chaining ? + NULL : dpcm_end_walk_at_be); dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, stream ? "capture" : "playback"); -- cgit v1.2.3 From e6aeb375d25dba56c4089b1d6aa0a77fe218ef3b Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 2 Nov 2020 20:40:10 +0530 Subject: ASoC: audio-graph: Use of_node and DAI for DPCM DAI link names For multiple instances of components, using DAI name alone for DAI links is causing conflicts. Components can define multiple DAIs and hence using just a device name won't help either. Thus DT device node reference and DAI names are used to uniquely represent DAI link names. Signed-off-by: Sameer Pujar Acked-by: Kuninori Morimoto Link: https://lore.kernel.org/r/1604329814-24779-4-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 97b4f5480a31..1e205629e89a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -253,7 +253,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, goto out_put_node; ret = asoc_simple_set_dailink_name(dev, dai_link, - "fe.%s", + "fe.%pOFP.%s", + cpus->of_node, cpus->dai_name); if (ret < 0) goto out_put_node; @@ -287,7 +288,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, goto out_put_node; ret = asoc_simple_set_dailink_name(dev, dai_link, - "be.%s", + "be.%pOFP.%s", + codecs->of_node, codecs->dai_name); if (ret < 0) goto out_put_node; -- cgit v1.2.3 From c21cbb526c0a105d582299839a9c4244dd6bf38a Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 2 Nov 2020 20:40:11 +0530 Subject: ASoC: audio-graph: Identify 'no_pcm' DAI links for DPCM PCM devices are created for FE dai links with 'no-pcm' flag as '0'. Such DAI links have CPU component which implement either pcm_construct() or pcm_new() at component or dai level respectively. Based on this, current patch exposes a helper function to identify such components and populate 'no_pcm' flag for DPCM DAI link. This helps to have BE<->BE component links where PCM devices need not be created for CPU component involved in such links. Signed-off-by: Sameer Pujar Cc: Kuninori Morimoto Link: https://lore.kernel.org/r/1604329814-24779-5-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'sound') diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 1e205629e89a..9b0684173a35 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -111,6 +111,17 @@ static int graph_get_dai_id(struct device_node *ep) return id; } +static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc) +{ + struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc); + + if (dai && (dai->component->driver->pcm_construct || + dai->driver->pcm_new)) + return true; + + return false; +} + static int asoc_simple_parse_dai(struct device_node *ep, struct snd_soc_dai_link_component *dlc, int *is_single_link) @@ -205,6 +216,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, int dup_codec) { struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_card *card = simple_priv_to_card(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; @@ -259,6 +271,19 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (ret < 0) goto out_put_node; + /* + * In BE<->BE connections it is not required to create + * PCM devices at CPU end of the dai link and thus 'no_pcm' + * flag needs to be set. It is useful when there are many + * BE components and some of these have to be connected to + * form a valid audio path. + * + * For example: FE <-> BE1 <-> BE2 <-> ... <-> BEn where + * there are 'n' BE components in the path. + */ + if (card->component_chaining && !soc_component_is_pcm(cpus)) + dai_link->no_pcm = 1; + /* card->num_links includes Codec */ asoc_simple_canonicalize_cpu(dai_link, is_single_links); } else { -- cgit v1.2.3 From 930dd47d74023e7c94a7c256279e12924c14475d Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 2 Nov 2020 20:40:12 +0530 Subject: ASoC: audio-graph: Support empty Codec endpoint For open platforms, which can support pluggable audio cards, Codec endpoint is not fixed always. It actually depends on the compatible HW module that is going to be connected. From SoC side the given I/O interface is always available. Hence such links have fixed CPU endpoint but no Codec endpoint. This patch helps to support such links where user can populate Codec endpoint only and its fields in Platform DT depending on the plugged HW. Signed-off-by: Sameer Pujar Cc: Kuninori Morimoto Link: https://lore.kernel.org/r/1604329814-24779-6-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 9b0684173a35..0ba50be9ccdb 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -229,6 +229,14 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; + /* + * Codec endpoint can be NULL for pluggable audio HW. + * Platform DT can populate the Codec endpoint depending on the + * plugged HW. + */ + if (!li->cpu && !codec_ep) + return 0; + /* Do it all CPU endpoint, and 1st Codec endpoint */ if (!li->cpu && dup_codec) return 0; @@ -565,7 +573,7 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, li->link++; /* 1xCPU-dummy */ li->dais++; /* 1xCPU */ - if (!dup_codec) { + if (!dup_codec && codec_ep) { li->link++; /* 1xdummy-Codec */ li->conf++; /* 1xdummy-Codec */ li->dais++; /* 1xCodec */ -- cgit v1.2.3 From d09c774f2f9ff25817866b70f1fb9603e5196971 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 2 Nov 2020 20:40:13 +0530 Subject: ASoC: audio-graph: Expose new members for asoc_simple_priv Add new members in struct 'asoc_simple_priv'. Idea is to leverage simple or graph card driver as much as possible and vendor can maintain a thin driver to control the behavior by populating these newly exposed members. Following are the members added in 'asoc_simple_priv': - 'ops' struct: In some cases SoC vendor drivers may want to implement 'snd_soc_ops' callbacks differently. In such cases custom callbacks would be used. - 'force_dpcm' flag: Right now simple or graph card drivers detect DAI links as DPCM links if: * The dpcm_selectable is set AND * Codec is connected to multiple CPU endpoints or aconvert property is used for rate/channels. So there is no way to directly specify usage of DPCM alone. So a flag is exposed to mark all links as DPCM. Vendor driver can set this if required. - 'dpcm_selectable': Currently simple or audio graph drivers provide a way to enable this for specific compatibles. However vendor driver may want to define some additional info. Thus expose this variable where vendor drivers can set this if required. Audio graph driver is updated to consider above flags or callbacks. Subsequent patches in the series illustrate usage for above. Signed-off-by: Sameer Pujar Cc: Kuninori Morimoto Link: https://lore.kernel.org/r/1604329814-24779-7-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 3 +++ sound/soc/generic/audio-graph-card.c | 41 ++++++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 86a1e956991e..ba4a3e1897b9 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -56,6 +56,9 @@ struct asoc_simple_priv { struct asoc_simple_dai *dais; struct snd_soc_codec_conf *codec_conf; struct gpio_desc *pa_gpio; + const struct snd_soc_ops *ops; + unsigned int dpcm_selectable:1; + unsigned int force_dpcm:1; }; #define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0ba50be9ccdb..4db9c0e5445d 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -355,6 +355,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, snd_soc_dai_link_set_capabilities(dai_link); dai_link->ops = &graph_ops; + + /* Use custom snd_soc_ops callbacks if available */ + if (priv->ops) + dai_link->ops = priv->ops; + dai_link->init = asoc_simple_dai_init; out_put_node: @@ -439,6 +444,28 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, return 0; } +static inline bool parse_as_dpcm_link(struct asoc_simple_priv *priv, + struct device_node *codec_port, + struct asoc_simple_data *adata) +{ + if (priv->force_dpcm) + return true; + + if (!priv->dpcm_selectable) + return false; + + /* + * It is DPCM + * if Codec port has many endpoints, + * or has convert-xxx property + */ + if ((of_get_child_count(codec_port) > 1) || + (adata->convert_rate || adata->convert_channels)) + return true; + + return false; +} + static int graph_for_each_link(struct asoc_simple_priv *priv, struct link_info *li, int (*func_noml)(struct asoc_simple_priv *priv, @@ -459,7 +486,6 @@ static int graph_for_each_link(struct asoc_simple_priv *priv, struct device_node *codec_port; struct device_node *codec_port_old = NULL; struct asoc_simple_data adata; - uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev); int rc, ret; /* loop for all listed CPU port */ @@ -482,14 +508,8 @@ static int graph_for_each_link(struct asoc_simple_priv *priv, graph_parse_convert(dev, codec_ep, &adata); graph_parse_convert(dev, cpu_ep, &adata); - /* - * It is DPCM - * if Codec port has many endpoints, - * or has convert-xxx property - */ - if (dpcm_selectable && - ((of_get_child_count(codec_port) > 1) || - adata.convert_rate || adata.convert_channels)) + /* check if link requires DPCM parsing */ + if (parse_as_dpcm_link(priv, codec_port, &adata)) ret = func_dpcm(priv, cpu_ep, codec_ep, li, (codec_port_old == codec_port)); /* else normal sound */ @@ -678,6 +698,9 @@ static int graph_probe(struct platform_device *pdev) card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets); card->probe = graph_card_probe; + if (of_device_get_match_data(dev)) + priv->dpcm_selectable = 1; + memset(&li, 0, sizeof(li)); graph_get_dais_count(priv, &li); if (!li.link || !li.dais) -- cgit v1.2.3 From e32b100bc6ecbc390aae728fc7d2a3e247faa8a7 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 2 Nov 2020 20:40:14 +0530 Subject: ASoC: audio-graph: Expose helpers from audio graph This commit exposes following functions which can be used by a sound card driver based on generic audio graph driver. Idea is vendors can have a thin driver and re-use common stuff from audio graph driver. - graph_card_probe() - graph_parse_of() In doing so a new header file is added for above. The graph_probe() function is simplified by moving more common stuff to graph_parse_of(). Signed-off-by: Sameer Pujar Cc: Kuninori Morimoto Link: https://lore.kernel.org/r/1604329814-24779-8-git-send-email-spujar@nvidia.com Signed-off-by: Mark Brown --- include/sound/graph_card.h | 16 ++++++ sound/soc/generic/audio-graph-card.c | 95 +++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 45 deletions(-) create mode 100644 include/sound/graph_card.h (limited to 'sound') diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h new file mode 100644 index 000000000000..bbb5a137855c --- /dev/null +++ b/include/sound/graph_card.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * ASoC audio graph card support + * + */ + +#ifndef __GRAPH_CARD_H +#define __GRAPH_CARD_H + +#include + +int graph_card_probe(struct snd_soc_card *card); + +int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev); + +#endif /* __GRAPH_CARD_H */ diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 4db9c0e5445d..16a04a678828 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #define DPCM_SELECTABLE 1 @@ -529,12 +529,34 @@ static int graph_for_each_link(struct asoc_simple_priv *priv, return 0; } -static int graph_parse_of(struct asoc_simple_priv *priv) +static void graph_get_dais_count(struct asoc_simple_priv *priv, + struct link_info *li); + +int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) { struct snd_soc_card *card = simple_priv_to_card(priv); struct link_info li; int ret; + card->owner = THIS_MODULE; + card->dev = dev; + + memset(&li, 0, sizeof(li)); + graph_get_dais_count(priv, &li); + if (!li.link || !li.dais) + return -EINVAL; + + ret = asoc_simple_init_priv(priv, &li); + if (ret < 0) + return ret; + + priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); + if (IS_ERR(priv->pa_gpio)) { + ret = PTR_ERR(priv->pa_gpio); + dev_err(dev, "failed to get amplifier gpio: %d\n", ret); + return ret; + } + ret = asoc_simple_parse_widgets(card, NULL); if (ret < 0) return ret; @@ -561,11 +583,32 @@ static int graph_parse_of(struct asoc_simple_priv *priv) graph_dai_link_of, graph_dai_link_of_dpcm); if (ret < 0) - return ret; + goto err; } - return asoc_simple_parse_card_name(card, NULL); + ret = asoc_simple_parse_card_name(card, NULL); + if (ret < 0) + goto err; + + snd_soc_card_set_drvdata(card, priv); + + asoc_simple_debug_info(priv); + + ret = devm_snd_soc_register_card(dev, card); + if (ret < 0) + goto err; + + return 0; + +err: + asoc_simple_clean_reference(card); + + if (ret != -EPROBE_DEFER) + dev_err(dev, "parse error %d\n", ret); + + return ret; } +EXPORT_SYMBOL_GPL(graph_parse_of); static int graph_count_noml(struct asoc_simple_priv *priv, struct device_node *cpu_ep, @@ -662,7 +705,7 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv, li->link, li->dais, li->conf); } -static int graph_card_probe(struct snd_soc_card *card) +int graph_card_probe(struct snd_soc_card *card) { struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); int ret; @@ -677,14 +720,13 @@ static int graph_card_probe(struct snd_soc_card *card) return 0; } +EXPORT_SYMBOL_GPL(graph_card_probe); static int graph_probe(struct platform_device *pdev) { struct asoc_simple_priv *priv; struct device *dev = &pdev->dev; struct snd_soc_card *card; - struct link_info li; - int ret; /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -692,8 +734,6 @@ static int graph_probe(struct platform_device *pdev) return -ENOMEM; card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; card->dapm_widgets = graph_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets); card->probe = graph_card_probe; @@ -701,42 +741,7 @@ static int graph_probe(struct platform_device *pdev) if (of_device_get_match_data(dev)) priv->dpcm_selectable = 1; - memset(&li, 0, sizeof(li)); - graph_get_dais_count(priv, &li); - if (!li.link || !li.dais) - return -EINVAL; - - ret = asoc_simple_init_priv(priv, &li); - if (ret < 0) - return ret; - - priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); - if (IS_ERR(priv->pa_gpio)) { - ret = PTR_ERR(priv->pa_gpio); - dev_err(dev, "failed to get amplifier gpio: %d\n", ret); - return ret; - } - - ret = graph_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - asoc_simple_debug_info(priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_clean_reference(card); - - return ret; + return graph_parse_of(priv, dev); } static int graph_remove(struct platform_device *pdev) -- cgit v1.2.3 From 048751de568816de52dedf0fa967cceada7885f1 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Mon, 2 Nov 2020 18:18:10 +0200 Subject: ASoC: fsl_xcvr: fix break condition The break condition copied by mistake as same as loop condition in the previous version, but must be the opposite. So fix it. Signed-off-by: Viorel Suman Link: https://lore.kernel.org/r/20201102161810.902464-1-viorel.suman@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_xcvr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c055179e6d11..2a28810d0e29 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -247,7 +247,7 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy) regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx); ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val, - (val & idx) != ((val & tidx) >> 1), + (val & idx) == ((val & tidx) >> 1), 10, 10000); if (ret) dev_err(dev, "AI timeout: failed to set %s reg 0x%02x=0x%08x\n", -- cgit v1.2.3 From 4e59dd249cd513a211e2ecce2cb31f4e29a5ce5b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Nov 2020 15:51:54 +0300 Subject: ASoC: qcom: common: Fix refcounting in qcom_snd_parse_of() There are two issues in this function. 1) We can't drop the refrences on "cpu", "codec" and "platform" before we take the reference. This doesn't cause a problem on the first iteration because those pointers start as NULL so the of_node_put() is a no-op. But on the subsequent iterations, it will lead to a use after free. 2) If the devm_kzalloc() allocation failed then the code returned directly instead of cleaning up. Fixes: c1e6414cdc37 ("ASoC: qcom: common: Fix refcount imbalance on error") Fixes: 1e36ea360ab9 ("ASoC: qcom: common: use modern dai_link style") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20201105125154.GA176426@mwanda Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 54660f126d09..09af00700700 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -58,7 +58,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL); if (!dlc) { ret = -ENOMEM; - goto err; + goto err_put_np; } link->cpus = &dlc[0]; @@ -70,7 +70,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ret = of_property_read_string(np, "link-name", &link->name); if (ret) { dev_err(card->dev, "error getting codec dai_link name\n"); - goto err; + goto err_put_np; } cpu = of_get_child_by_name(np, "cpu"); @@ -130,8 +130,10 @@ int qcom_snd_parse_of(struct snd_soc_card *card) } else { /* DPCM frontend */ dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL); - if (!dlc) - return -ENOMEM; + if (!dlc) { + ret = -ENOMEM; + goto err; + } link->codecs = dlc; link->num_codecs = 1; @@ -158,10 +160,11 @@ int qcom_snd_parse_of(struct snd_soc_card *card) return 0; err: - of_node_put(np); of_node_put(cpu); of_node_put(codec); of_node_put(platform); +err_put_np: + of_node_put(np); return ret; } EXPORT_SYMBOL(qcom_snd_parse_of); -- cgit v1.2.3 From b8161cbe55a1892a19a318eaebbda92438fa708c Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Wed, 11 Nov 2020 12:13:24 +0800 Subject: ASoC: wm8994: Fix PM disable depth imbalance on error The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. Fixes: 57e265c8d71fb ("ASoC: wm8994: Move runtime PM init to platform device init") Signed-off-by: Zhang Qilong Reviewed-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20201111041326.1257558-2-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index fc9ea198ac79..f57884113406 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4645,8 +4645,12 @@ static int wm8994_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8994, + ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8994, wm8994_dai, ARRAY_SIZE(wm8994_dai)); + if (ret < 0) + pm_runtime_disable(&pdev->dev); + + return ret; } static int wm8994_remove(struct platform_device *pdev) -- cgit v1.2.3 From 193aa0a043645220d2a2f783ba06ae13d4601078 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Wed, 11 Nov 2020 12:13:26 +0800 Subject: ASoC: wm8998: Fix PM disable depth imbalance on error The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. Fixes: 31833ead95c2c ("ASoC: arizona: Move request of speaker IRQs into bus probe") Signed-off-by: Zhang Qilong Reviewed-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20201111041326.1257558-4-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8998.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index f6c5cc80c970..5413254295b7 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1375,7 +1375,7 @@ static int wm8998_probe(struct platform_device *pdev) ret = arizona_init_spk_irqs(arizona); if (ret < 0) - return ret; + goto err_pm_disable; ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8998, @@ -1390,6 +1390,8 @@ static int wm8998_probe(struct platform_device *pdev) err_spk_irqs: arizona_free_spk_irqs(arizona); +err_pm_disable: + pm_runtime_disable(&pdev->dev); return ret; } -- cgit v1.2.3 From 34d3daba23399440dedddd0f9ccd6c1057314139 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 11 Nov 2020 10:32:45 +0000 Subject: ASoC: tegra: Don't warn on probe deferral Deferred probe is an expected return value for snd_soc_register_card(). Given that the driver deals with it properly, there's no need to output a warning that may potentially confuse users. Signed-off-by: Jon Hunter Link: https://lore.kernel.org/r/20201111103245.152189-1-jonathanh@nvidia.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_alc5632.c | 4 ++-- sound/soc/tegra/tegra_max98090.c | 8 +++----- sound/soc/tegra/tegra_rt5640.c | 8 +++----- sound/soc/tegra/tegra_rt5677.c | 4 ++-- sound/soc/tegra/tegra_sgtl5000.c | 4 ++-- sound/soc/tegra/tegra_wm8753.c | 8 +++----- sound/soc/tegra/tegra_wm8903.c | 8 +++----- sound/soc/tegra/tegra_wm9712.c | 4 ++-- sound/soc/tegra/trimslice.c | 8 +++----- 9 files changed, 23 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 8661877bf4c6..0a0efd24e4b0 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -203,8 +203,8 @@ static int tegra_alc5632_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); + dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); goto err_put_cpu_of_node; } diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index 9d8e16473ab9..00c19704057b 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -247,11 +247,9 @@ static int tegra_max98090_probe(struct platform_device *pdev) return ret; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); return 0; } diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index c73bd23b3d67..9afba37a3b08 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -193,11 +193,9 @@ static int tegra_rt5640_probe(struct platform_device *pdev) return ret; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); return 0; } diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c index 7504507dd8b8..d30f8b6deda4 100644 --- a/sound/soc/tegra/tegra_rt5677.c +++ b/sound/soc/tegra/tegra_rt5677.c @@ -268,8 +268,8 @@ static int tegra_rt5677_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); + dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); goto err_put_cpu_of_node; } diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c index e1dc8e7d337a..885332170c77 100644 --- a/sound/soc/tegra/tegra_sgtl5000.c +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -154,8 +154,8 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); + dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); goto err_put_cpu_of_node; } diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index fa41fa366daf..efd793886689 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -156,11 +156,9 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev) return ret; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); return 0; } diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index ef6652aaac9b..e4863fa37b0c 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -352,11 +352,9 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev) return ret; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(&pdev->dev, "devm_snd_soc_register_card failed (%d)\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); return 0; } diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c index 726edfa21a29..4f09a178049d 100644 --- a/sound/soc/tegra/tegra_wm9712.c +++ b/sound/soc/tegra/tegra_wm9712.c @@ -117,8 +117,8 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); + dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); goto codec_unregister; } diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index baae4cce7fc6..6c1cc3d0ac33 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -144,11 +144,9 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev) return ret; ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card failed\n"); return 0; } -- cgit v1.2.3 From 6b0e12a5c668c6b77c3e6d6c55c3ae7ed8bf5bd5 Mon Sep 17 00:00:00 2001 From: "Shane.Chien" Date: Wed, 11 Nov 2020 12:14:56 +0800 Subject: ASoC: Remove mt6359_platform_driver_remove remove mt6359_platform_driver_remove due to it is useless. Signed-off-by: Shane.Chien Link: https://lore.kernel.org/r/1605068096-12587-1-git-send-email-shane.chien@mediatek.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index ecdfd5732075..d37dbd2b50c2 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -2817,23 +2817,11 @@ static int mt6359_platform_driver_probe(struct platform_device *pdev) ARRAY_SIZE(mt6359_dai_driver)); } -static int mt6359_platform_driver_remove(struct platform_device *pdev) -{ - struct mt6359_priv *priv = dev_get_drvdata(&pdev->dev); - int ret; - - dev_dbg(&pdev->dev, "%s(), dev name %s\n", - __func__, dev_name(&pdev->dev)); - - return 0; -} - static struct platform_driver mt6359_platform_driver = { .driver = { .name = "mt6359-sound", }, .probe = mt6359_platform_driver_probe, - .remove = mt6359_platform_driver_remove, }; module_platform_driver(mt6359_platform_driver) -- cgit v1.2.3 From 2aff94e47da2e2006ceb53c00247218ea8a72770 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Wed, 11 Nov 2020 10:45:22 +0800 Subject: ASoC: mediatek: mt8192: skip first time data at the beginning of DMIC recording We can choose to drop away any length of data from the beginning according to project needs. Some projects don't want to throw away any data, because they want to use recorded data to do echo cancellation, so they have to make sure that they are aligned with the reference data as much as possible. Or there are other algorithms in the upper layer to eliminate this noise. Or some projects want to eliminate this noise form the kernel layer. However, the minimum recommended value is 50ms to skip pop noise. Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1605062722-8711-1-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 1 + sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index d4532400ff13..49772dfc92c7 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -176,6 +176,7 @@ config SND_SOC_MT8192_MT6359_RT1015_RT5682 select SND_SOC_MT6359 select SND_SOC_RT1015 select SND_SOC_RT5682_I2C + select SND_SOC_DMIC help This adds ASoC driver for Mediatek MT8192 boards with the MT6359 RT1015 RT5682 audio codec. diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 41d8a8567bb3..b7f42a530d06 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -540,7 +540,9 @@ SND_SOC_DAILINK_DEFS(playback_hdmi, SND_SOC_DAILINK_DEFS(primary_codec, DAILINK_COMP_ARRAY(COMP_CPU("ADDA")), DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound", - "mt6359-snd-codec-aif1")), + "mt6359-snd-codec-aif1"), + COMP_CODEC("dmic-codec", + "dmic-hifi")), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(primary_codec_ch34, -- cgit v1.2.3 From 5e7aace13df24ff72511f29c14ebbfe638ef733c Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Wed, 11 Nov 2020 21:09:20 +0800 Subject: ASoC: arizona: Fix a wrong free in wm8997_probe In the normal path, we should not free the arizona, we should return immediately. It will be free when call remove operation. Fixes: 31833ead95c2c ("ASoC: arizona: Move request of speaker IRQs into bus probe") Reported-by: Richard Fitzgerald Signed-off-by: Zhang Qilong Acked-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20201111130923.220186-2-zhangqilong3@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8997.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 37e4bb3dbd8a..229f2986cd96 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1177,6 +1177,8 @@ static int wm8997_probe(struct platform_device *pdev) goto err_spk_irqs; } + return ret; + err_spk_irqs: arizona_free_spk_irqs(arizona); -- cgit v1.2.3 From e936619b7ce784c808a8e2524f712a89ef245920 Mon Sep 17 00:00:00 2001 From: xuyuqing Date: Thu, 12 Nov 2020 09:43:28 +0800 Subject: ASoC: qcom: sc7180: Modify machine driver for sound card Bypass set jack because there is no jack on coachz. Create route for dmic. Signed-off-by: xuyuqing Link: https://lore.kernel.org/r/20201112014328.695232-3-xuyuqing@huaqin.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 1 + sound/soc/qcom/sc7180.c | 86 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 41cb08bd5588..27f93006be96 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -145,6 +145,7 @@ config SND_SOC_SC7180 select SND_SOC_LPASS_SC7180 select SND_SOC_MAX98357A select SND_SOC_RT5682_I2C + select SND_SOC_ADAU7002 help To add support for audio on Qualcomm Technologies Inc. SC7180 SoC-based systems. diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index 878fd0169aab..e2e6567566af 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -221,16 +221,69 @@ static void sc7180_snd_shutdown(struct snd_pcm_substream *substream) } } +static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case MI2S_PRIMARY: + return 0; + case MI2S_SECONDARY: + return 0; + case LPASS_DP_RX: + return sc7180_hdmi_init(rtd); + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + return -EINVAL; + } + return 0; +} + +static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + + switch (cpu_dai->id) { + case MI2S_PRIMARY: + snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S); + + break; + case MI2S_SECONDARY: + break; + case LPASS_DP_RX: + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + return -EINVAL; + } + return 0; +} + static const struct snd_soc_ops sc7180_ops = { .startup = sc7180_snd_startup, .shutdown = sc7180_snd_shutdown, }; +static const struct snd_soc_ops sc7180_adau7002_ops = { + .startup = sc7180_adau7002_snd_startup, +}; + static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), }; +static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = { + SND_SOC_DAPM_MIC("DMIC", NULL), +}; + static const char * const dmic_mux_text[] = { "Front Mic", "Rear Mic", @@ -255,23 +308,15 @@ static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = { {"Dmic Mux", "Rear Mic", "DMIC"}, }; -static void sc7180_add_ops(struct snd_soc_card *card) -{ - struct snd_soc_dai_link *link; - int i; - - for_each_card_prelinks(card, i, link) { - link->ops = &sc7180_ops; - link->init = sc7180_init; - } -} - static int sc7180_snd_platform_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct sc7180_snd_data *data; struct device *dev = &pdev->dev; + struct snd_soc_dai_link *link; int ret; + int i; + bool no_headphone; /* Allocate the private data */ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); @@ -299,17 +344,32 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) } } + if (of_device_is_compatible(dev->of_node, "google,sc7180-coachz")) { + no_headphone = true; + card->dapm_widgets = sc7180_adau7002_snd_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sc7180_adau7002_snd_widgets); + } + ret = qcom_snd_parse_of(card); if (ret) return ret; - sc7180_add_ops(card); + for_each_card_prelinks(card, i, link) { + if (no_headphone) { + link->ops = &sc7180_adau7002_ops; + link->init = sc7180_adau7002_init; + } else { + link->ops = &sc7180_ops; + link->init = sc7180_init; + } + } return devm_snd_soc_register_card(dev, card); } static const struct of_device_id sc7180_snd_device_id[] = { - { .compatible = "google,sc7180-trogdor"}, + {.compatible = "google,sc7180-trogdor"}, + {.compatible = "google,sc7180-coachz"}, {}, }; MODULE_DEVICE_TABLE(of, sc7180_snd_device_id); -- cgit v1.2.3 From 488cdbd8931fe4bc7f374a8b429e81d0e4b7ac76 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Nov 2020 15:43:15 -0600 Subject: ASoC: Intel: sof_sdw: add quirk for new TigerLake-SDCA device Add quirks for jack detection, rt715 DAI and number of speakers. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20201111214318.150529-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b29946eb4355..ca968901ac96 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -48,6 +48,16 @@ static int sof_sdw_quirk_cb(const struct dmi_system_id *id) } static const struct dmi_system_id sof_sdw_quirk_table[] = { + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32") + }, + .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | + SOF_RT715_DAI_ID_FIX | + SOF_SDW_FOUR_SPK), + }, { .callback = sof_sdw_quirk_cb, .matches = { -- cgit v1.2.3 From 4a55000722d74e4ad1ea4700a423e21fab0d53ba Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Nov 2020 15:43:16 -0600 Subject: ASoC: codecs: rt*.c: remove useless pointer cast Pointer cast is not necessary, remove. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20201111214318.150529-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308-sdw.c | 2 +- sound/soc/codecs/rt5682-sdw.c | 2 +- sound/soc/codecs/rt700.c | 2 +- sound/soc/codecs/rt711.c | 2 +- sound/soc/codecs/rt715.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index c2621b0afe6c..ec5564f780e8 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -475,7 +475,7 @@ static int rt1308_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, if (!stream) return -ENOMEM; - stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + stream->sdw_stream = sdw_stream; /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ if (direction == SNDRV_PCM_STREAM_PLAYBACK) diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 58fb13132602..4d707e854875 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -103,7 +103,7 @@ static int rt5682_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, if (!stream) return -ENOMEM; - stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + stream->sdw_stream = sdw_stream; /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ if (direction == SNDRV_PCM_STREAM_PLAYBACK) diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 687ac2153666..66ec395dbbcd 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -867,7 +867,7 @@ static int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, if (!stream) return -ENOMEM; - stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + stream->sdw_stream = sdw_stream; /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ if (direction == SNDRV_PCM_STREAM_PLAYBACK) diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 65b59dbfb43c..5771c02c3459 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -913,7 +913,7 @@ static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, if (!stream) return -ENOMEM; - stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + stream->sdw_stream = sdw_stream; /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ if (direction == SNDRV_PCM_STREAM_PLAYBACK) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 532c5303e7ab..9a7d393d424a 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -537,7 +537,7 @@ static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, if (!stream) return -ENOMEM; - stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + stream->sdw_stream = sdw_stream; /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ if (direction == SNDRV_PCM_STREAM_PLAYBACK) -- cgit v1.2.3 From 17f6433192d858e49a40d1fa939bf61cc493a3b7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Nov 2020 15:43:17 -0600 Subject: ASoC: rt711: remove warnings cppcheck complains, use separate loop variable for sink and source ports sound/soc/codecs/rt711-sdw.c:382:4: style: Variable 'i' is reassigned a value before the old one has been used. [redundantAssignment] i = 0; ^ sound/soc/codecs/rt711-sdw.c:371:4: note: i is assigned i++; ^ sound/soc/codecs/rt711-sdw.c:382:4: note: i is overwritten i = 0; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20201111214318.150529-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdw.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index f0a0691bd31c..fc7df79c3b91 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -338,7 +338,8 @@ static int rt711_update_status(struct sdw_slave *slave, static int rt711_read_prop(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; - int nval, i; + int nval; + int i, j; u32 bit; unsigned long addr; struct sdw_dpn_prop *dpn; @@ -379,15 +380,15 @@ static int rt711_read_prop(struct sdw_slave *slave) if (!prop->sink_dpn_prop) return -ENOMEM; - i = 0; + j = 0; dpn = prop->sink_dpn_prop; addr = prop->sink_ports; for_each_set_bit(bit, &addr, 32) { - dpn[i].num = bit; - dpn[i].type = SDW_DPN_FULL; - dpn[i].simple_ch_prep_sm = true; - dpn[i].ch_prep_timeout = 10; - i++; + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; } /* set the timeout values */ -- cgit v1.2.3 From f184892613dddcc12a1880c3b406314ec81498c7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Nov 2020 15:43:18 -0600 Subject: ASoC: codecs: max98373-sdw: align regmap use with other codecs It's not clear why this driver has an additional call to regmap_mark_dirty(), remove to align with others. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20201111214318.150529-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98373-sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index fa589d834f9a..ec2e79c57357 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -247,7 +247,7 @@ static __maybe_unused int max98373_suspend(struct device *dev) struct max98373_priv *max98373 = dev_get_drvdata(dev); regcache_cache_only(max98373->regmap, true); - regcache_mark_dirty(max98373->regmap); + return 0; } -- cgit v1.2.3 From e7ee770a3f9004a5b4ddaa28ff9efe3ff3382268 Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Mon, 9 Nov 2020 13:09:58 -0800 Subject: ASoC: Intel: Boards: tgl_max98373: add dpcm_capture flag for speaker_smart_amp Smart_amp_speaker device has the playback stream and capture stream associated to it. Hence add the dpcm_capture = 1 flag while dailink creation. This patches fixes: ERR kernel [timestamp] SSP1-Codec: ASoC: no backend capture stream Reviewed-by: Pierre-Louis Bossart Signed-off-by: Dharageswari R Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201109210958.84198-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index e7d9a82ca70d..891f908659f5 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -734,6 +734,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_codecs = ARRAY_SIZE(max_98373_components); links[id].init = max98373_spk_codec_init; links[id].ops = &max_98373_ops; + /* feedback stream */ + links[id].dpcm_capture = 1; } else if (sof_rt5682_quirk & SOF_MAX98360A_SPEAKER_AMP_PRESENT) { links[id].codecs = max98360a_component; -- cgit v1.2.3 From 0c7f946d6b10ea240743cdcd8a502f82a6148b10 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 11 Nov 2020 19:33:21 +0200 Subject: ASoC: SOF: loader: do not warn about unknown firmware headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The firmware extended data IPC and manifest structures are designed to be extendable without breaking the driver-firmware ABI. Driver should not raise a warning in case a new header type is detected at firmware boot. There are already checks for IPC ABI compatibility in snd_sof_ipc_valid() and if the versions are deemed compatible, extra fields in IPC messages should not trigger warnings. Signed-off-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Karol Trzciński Link: https://lore.kernel.org/r/20201111173321.1933452-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index ba9ed66f98bc..ce68d708fc6f 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -124,7 +124,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) /* They are supported but we don't do anything here */ break; default: - dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n", + dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n", ext_hdr->type, ext_hdr->hdr.size); ret = 0; break; @@ -280,7 +280,7 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev, ret = ext_man_get_dbg_abi_info(sdev, elem_hdr); break; default: - dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n", + dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n", elem_hdr->type, elem_hdr->size); break; } -- cgit v1.2.3 From 724d53f6a0f318390630a50ee713fa19a927fa23 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Nov 2020 10:44:22 -0600 Subject: ASoC: SOF: imx: fix Kconfig punctuation Add periods at the end of sentences in help text. Signed-off-by: Randy Dunlap Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112164425.25603-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 48f998a19ddb..49d605cb09a5 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -17,7 +17,7 @@ config SND_SOC_SOF_IMX_OF select SND_SOC_SOF_IMX8M if SND_SOC_SOF_IMX8M_SUPPORT help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_IMX_COMMON tristate @@ -30,7 +30,7 @@ config SND_SOC_SOF_IMX8_SUPPORT depends on IMX_SCU=y || IMX_SCU=SND_SOC_SOF_IMX_OF depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_IMX_OF help - This adds support for Sound Open Firmware for NXP i.MX8 platforms + This adds support for Sound Open Firmware for NXP i.MX8 platforms. Say Y if you have such a device. If unsure select "N". @@ -40,13 +40,13 @@ config SND_SOC_SOF_IMX8 select SND_SOC_SOF_XTENSA help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_IMX8M_SUPPORT bool "SOF support for i.MX8M" depends on IMX_DSP=y || IMX_DSP=SND_SOC_SOF_OF help - This adds support for Sound Open Firmware for NXP i.MX8M platforms + This adds support for Sound Open Firmware for NXP i.MX8M platforms. Say Y if you have such a device. If unsure select "N". @@ -56,6 +56,6 @@ config SND_SOC_SOF_IMX8M select SND_SOC_SOF_XTENSA help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL -- cgit v1.2.3 From aff581aee84079b89e796d6ab26560c88d1dcd7a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Nov 2020 10:44:23 -0600 Subject: ASoC: SOF: Kconfig: fix Kconfig punctuation and wording Add periods at the end of sentences in help text. Drop "a" in one place where it is not needed. Fix a verb. Add some capitalization. Signed-off-by: Randy Dunlap Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112164425.25603-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 8c1f0829de40..031dad5fc4c7 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -2,7 +2,7 @@ config SND_SOC_SOF_TOPLEVEL bool "Sound Open Firmware Support" help - This adds support for Sound Open Firmware (SOF). SOF is a free and + This adds support for Sound Open Firmware (SOF). SOF is free and generic open source audio DSP firmware for multiple devices. Say Y if you have such a device that is supported by SOF. If unsure select "N". @@ -16,8 +16,8 @@ config SND_SOC_SOF_PCI select SND_SOC_ACPI if ACPI help This adds support for PCI enumeration. This option is - required to enable Intel Skylake+ devices - Say Y if you need this option + required to enable Intel Skylake+ devices. + Say Y if you need this option. If unsure select "N". config SND_SOC_SOF_ACPI @@ -28,8 +28,8 @@ config SND_SOC_SOF_ACPI select IOSF_MBI if X86 && PCI help This adds support for ACPI enumeration. This option is required - to enable Intel Broadwell/Baytrail/Cherrytrail devices - Say Y if you need this option + to enable Intel Broadwell/Baytrail/Cherrytrail devices. + Say Y if you need this option. If unsure select "N". config SND_SOC_SOF_OF @@ -54,12 +54,12 @@ config SND_SOC_SOF_DEVELOPER_SUPPORT bool "SOF developer options support" depends on EXPERT help - This option unlock SOF developer options for debug/performance/ + This option unlocks SOF developer options for debug/performance/ code hardening. Distributions should not select this option, only SOF development teams should select it. - Say Y if you are involved in SOF development and need this option - If not, select N + Say Y if you are involved in SOF development and need this option. + If not, select N. if SND_SOC_SOF_DEVELOPER_SUPPORT @@ -72,13 +72,13 @@ config SND_SOC_SOF_NOCODEC_SUPPORT This adds support for a dummy/nocodec machine driver fallback option if no known codec is detected. This is typically only enabled for developers or devices where the sound card is - controlled externally - This option is mutually exclusive with the Intel HDAudio support, - selecting it may have negative impacts and prevent e.g. microphone + controlled externally. + This option is mutually exclusive with the Intel HDAudio support. + Selecting it may have negative impacts and prevent e.g. microphone functionality from being enabled on Intel CoffeeLake and later platforms. Distributions should not select this option! - Say Y if you need this nocodec fallback option + Say Y if you need this nocodec fallback option. If unsure select "N". config SND_SOC_SOF_STRICT_ABI_CHECKS @@ -92,8 +92,8 @@ config SND_SOC_SOF_STRICT_ABI_CHECKS is invoked. This option will stop topology creation and firmware load upfront. It is intended for SOF CI/releases and not for users or distros. - Say Y if you want strict ABI checks for an SOF release - If you are not involved in SOF releases and CI development + Say Y if you want strict ABI checks for an SOF release. + If you are not involved in SOF releases and CI development, select "N". config SND_SOC_SOF_DEBUG @@ -114,8 +114,8 @@ config SND_SOC_SOF_FORCE_NOCODEC_MODE though there is a codec detected on the real platform. This is typically only enabled for developers for debug purposes, before codec/machine driver is ready, or to exclude the impact of those - drivers - Say Y if you need this force nocodec mode option + drivers. + Say Y if you need this force nocodec mode option. If unsure select "N". config SND_SOC_SOF_DEBUG_XRUN_STOP @@ -137,12 +137,12 @@ config SND_SOC_SOF_DEBUG_VERBOSE_IPC config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION bool "SOF force to use IPC for position update on SKL+" help - This option force to handle stream position update IPCs and run pcm + This option forces to handle stream position update IPCs and run PCM elapse to inform ALSA about that, on platforms (e.g. Intel SKL+) that with other approach (e.g. HDAC DPIB/posbuf) to elapse PCM. On platforms (e.g. Intel SKL-) where position update IPC is the only one choice, this setting won't impact anything. - if you are trying to debug pointer update with position IPCs or where + If you are trying to debug pointer update with position IPCs or where DPIB/posbuf is not ready, select "Y". If unsure select "N". @@ -161,7 +161,7 @@ config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE help The firmware trace can be enabled either at build-time with this option, or dynamically by setting flags in the SOF core - module parameter (similar to dynamic debug) + module parameter (similar to dynamic debug). If unsure, select "N". config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST @@ -190,7 +190,7 @@ config SND_SOC_SOF select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. The selection is made at the top level and does not exactly follow module dependencies but since the module or built-in type is decided at the top level it doesn't matter. @@ -199,7 +199,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE bool help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. When selected, the probe is handled in two steps, for example to avoid lockdeps if request_module is used in the probe. -- cgit v1.2.3 From 66e1b65128c2bf884d39589a8308dd115c5eba67 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Nov 2020 10:44:24 -0600 Subject: ASoC: SOF: Intel: fix Kconfig punctuation and wording Add periods at the end of sentences in help text. Insert a "not" in one place. Fix help text indentation. Remove a duplicate "Intel(R)" in one place. Signed-off-by: Randy Dunlap Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112164425.25603-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 62 ++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index a066e08860cb..75018e61fdda 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -15,7 +15,7 @@ config SND_SOC_SOF_INTEL_ACPI select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_INTEL_PCI def_tristate SND_SOC_SOF_PCI @@ -31,13 +31,13 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_JASPERLAKE_SUPPORT help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_INTEL_HIFI_EP_IPC tristate help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_INTEL_ATOM_HIFI_EP tristate @@ -45,7 +45,7 @@ config SND_SOC_SOF_INTEL_ATOM_HIFI_EP select SND_SOC_SOF_INTEL_HIFI_EP_IPC help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_INTEL_COMMON tristate @@ -55,7 +55,7 @@ config SND_SOC_SOF_INTEL_COMMON select SND_SOC_ACPI if ACPI help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. if SND_SOC_SOF_INTEL_ACPI @@ -72,7 +72,7 @@ config SND_SOC_SOF_BAYTRAIL_SUPPORT recommended for distros. At some point all legacy drivers will be deprecated but not before all userspace firmware/topology/UCM files are made available to downstream distros. - Say Y if you want to enable SOF on Baytrail/Cherrytrail + Say Y if you want to enable SOF on Baytrail/Cherrytrail. If unsure select "N". config SND_SOC_SOF_BAYTRAIL @@ -80,7 +80,7 @@ config SND_SOC_SOF_BAYTRAIL select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_BROADWELL_SUPPORT bool "SOF support for Broadwell" @@ -91,11 +91,11 @@ config SND_SOC_SOF_BROADWELL_SUPPORT This option is mutually exclusive with the Haswell/Broadwell legacy driver. If you want to enable SOF on Broadwell you need to deselect the legacy driver first. - SOF does fully support Broadwell yet, so this option is not + SOF does not fully support Broadwell yet, so this option is not recommended for distros. At some point all legacy drivers will be deprecated but not before all userspace firmware/topology/UCM files are made available to downstream distros. - Say Y if you want to enable SOF on Broadwell + Say Y if you want to enable SOF on Broadwell. If unsure select "N". config SND_SOC_SOF_BROADWELL @@ -104,7 +104,7 @@ config SND_SOC_SOF_BROADWELL select SND_SOC_SOF_INTEL_HIFI_EP_IPC help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. endif ## SND_SOC_SOF_INTEL_ACPI @@ -123,7 +123,7 @@ config SND_SOC_SOF_MERRIFIELD select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_APOLLOLAKE_SUPPORT bool "SOF support for Apollolake" @@ -138,7 +138,7 @@ config SND_SOC_SOF_APOLLOLAKE select SND_SOC_SOF_HDA_COMMON help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_GEMINILAKE_SUPPORT bool "SOF support for GeminiLake" @@ -153,7 +153,7 @@ config SND_SOC_SOF_GEMINILAKE select SND_SOC_SOF_HDA_COMMON help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_CANNONLAKE_SUPPORT bool "SOF support for Cannonlake" @@ -169,7 +169,7 @@ config SND_SOC_SOF_CANNONLAKE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_COFFEELAKE_SUPPORT bool "SOF support for CoffeeLake" @@ -185,7 +185,7 @@ config SND_SOC_SOF_COFFEELAKE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_ICELAKE_SUPPORT bool "SOF support for Icelake" @@ -201,7 +201,7 @@ config SND_SOC_SOF_ICELAKE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_COMETLAKE tristate @@ -209,7 +209,7 @@ config SND_SOC_SOF_COMETLAKE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_COMETLAKE_SUPPORT bool @@ -236,7 +236,7 @@ config SND_SOC_SOF_TIGERLAKE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_ELKHARTLAKE_SUPPORT bool "SOF support for ElkhartLake" @@ -252,7 +252,7 @@ config SND_SOC_SOF_ELKHARTLAKE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_JASPERLAKE_SUPPORT bool "SOF support for JasperLake" @@ -267,7 +267,7 @@ config SND_SOC_SOF_JASPERLAKE select SND_SOC_SOF_HDA_COMMON help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_HDA_COMMON tristate @@ -275,7 +275,7 @@ config SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_HDA_LINK_BASELINE help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. if SND_SOC_SOF_HDA_COMMON @@ -285,7 +285,7 @@ config SND_SOC_SOF_HDA_LINK select SND_SOC_SOF_PROBE_WORK_QUEUE help This adds support for HDA links(HDA/HDMI) with Sound Open Firmware - for Intel(R) platforms. + for Intel(R) platforms. Say Y if you want to enable HDA links with SOF. If unsure select "N". @@ -294,7 +294,7 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC depends on SND_SOC_SOF_HDA_LINK help This adds support for HDAudio codecs with Sound Open Firmware - for Intel(R) platforms. + for Intel(R) platforms. Say Y if you want to enable HDAudio codecs with SOF. If unsure select "N". @@ -302,8 +302,8 @@ config SND_SOC_SOF_HDA_PROBES bool "SOF enable probes over HDA" depends on SND_SOC_SOF_DEBUG_PROBES help - This option enables the data probing for Intel(R). - Intel(R) Skylake and newer platforms. + This option enables the data probing for Intel(R) + Skylake and newer platforms. Say Y if you want to enable probes. If unsure, select "N". @@ -314,7 +314,7 @@ config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1 and disables known workarounds for specific HDAudio platforms. Only use to look into power optimizations on platforms not affected by DMI L1 issues. This option is not recommended. - Say Y if you want to enable DMI Link L1 + Say Y if you want to enable DMI Link L1. If unsure, select "N". endif ## SND_SOC_SOF_HDA_COMMON @@ -324,7 +324,7 @@ config SND_SOC_SOF_HDA_LINK_BASELINE select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_HDA tristate @@ -333,14 +333,14 @@ config SND_SOC_SOF_HDA select SND_INTEL_DSP_CONFIG help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK bool "SOF support for SoundWire" depends on SOUNDWIRE && ACPI help This adds support for SoundWire with Sound Open Firmware - for Intel(R) platforms. + for Intel(R) platforms. Say Y if you want to enable SoundWire links with SOF. If unsure select "N". @@ -349,14 +349,14 @@ config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE select SND_SOC_SOF_INTEL_SOUNDWIRE if SND_SOC_SOF_INTEL_SOUNDWIRE_LINK help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. config SND_SOC_SOF_INTEL_SOUNDWIRE tristate select SOUNDWIRE_INTEL help This option is not user-selectable but automagically handled by - 'select' statements at a higher level + 'select' statements at a higher level. endif ## SND_SOC_SOF_INTEL_PCI -- cgit v1.2.3 From 358f0ac1f2791c80c19cc26706cf34664c9fd756 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:44:25 -0600 Subject: ASoC: SOF: Intel: fix Kconfig dependency for SND_INTEL_DSP_CONFIG SND_INTEL_DSP_CONFIG is selected by the HDaudio, Skylake and SOF drivers. When the HDaudio link is not selected as a option, this Kconfig option is not touched and will default to whatever other drivers selected. In the case e.g. where HDaudio is compiled as built-in, the linker will complain: ld: sound/soc/sof/sof-pci-dev.o: in function `sof_pci_probe': sof-pci-dev.c:(.text+0x5c): undefined reference to `snd_intel_dsp_driver_probe' Adding the select for all HDaudio platforms, regardless of whether they rely on the HDaudio link or not, solves the problem. Reported-by: Randy Dunlap Acked-by: Randy Dunlap Fixes: 82d9d54a6c0ee ('ALSA: hda: add Intel DSP configuration / probe code') Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201112164425.25603-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 75018e61fdda..b233302f05e4 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -271,6 +271,7 @@ config SND_SOC_SOF_JASPERLAKE config SND_SOC_SOF_HDA_COMMON tristate + select SND_INTEL_DSP_CONFIG select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_HDA_LINK_BASELINE help @@ -330,7 +331,6 @@ config SND_SOC_SOF_HDA tristate select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_INTEL_DSP_CONFIG help This option is not user-selectable but automagically handled by 'select' statements at a higher level. -- cgit v1.2.3 From 9c9fd07eb481cbfc89efa7820b3bb2b4a55eb303 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 10 Nov 2020 17:39:32 -0300 Subject: ASoC: wm1133-ev1: Remove unused driver Since commit c93197b0041d ("ARM: imx: Remove i.MX31 board files"), the MACH_MX31ADS_WM1133_EV1 non-DT platform is no longer supported, so get rid of its machine audio driver too. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20201110203937.25684-1-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 11 -- sound/soc/fsl/Makefile | 2 - sound/soc/fsl/wm1133-ev1.c | 289 --------------------------------------------- 3 files changed, 302 deletions(-) delete mode 100644 sound/soc/fsl/wm1133-ev1.c (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 52a562215008..3ad547193df8 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -239,17 +239,6 @@ config SND_SOC_IMX_SSI comment "SoC Audio support for Freescale i.MX boards:" -config SND_MXC_SOC_WM1133_EV1 - tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted" - depends on MACH_MX31ADS_WM1133_EV1 - select SND_SOC_WM8350 - select SND_SOC_IMX_PCM_FIQ - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_SSI - help - Enable support for audio on the i.MX31ADS with the WM1133-EV1 - PMIC board with WM8835x fitted. - config SND_SOC_MX27VIS_AIC32X4 tristate "SoC audio support for Visstrim M10 boards" depends on MACH_IMX27_VISSTRIM_M10 && I2C diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 2181b7f9f677..8d3e40415050 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -65,7 +65,6 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o snd-soc-phycore-ac97-objs := phycore-ac97.o snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o -snd-soc-wm1133-ev1-objs := wm1133-ev1.o snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-spdif-objs := imx-spdif.o @@ -75,7 +74,6 @@ snd-soc-imx-audmix-objs := imx-audmix.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o -obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c deleted file mode 100644 index 99611a037ada..000000000000 --- a/sound/soc/fsl/wm1133-ev1.c +++ /dev/null @@ -1,289 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// wm1133-ev1.c - Audio for WM1133-EV1 on i.MX31ADS -// -// Copyright (c) 2010 Wolfson Microelectronics plc -// Author: Mark Brown -// -// Based on an earlier driver for the same hardware by Liam Girdwood. - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "imx-ssi.h" -#include "../codecs/wm8350.h" -#include "imx-audmux.h" - -/* There is a silicon mic on the board optionally connected via a solder pad - * SP1. Define this to enable it. - */ -#undef USE_SIMIC - -struct _wm8350_audio { - unsigned int channels; - snd_pcm_format_t format; - unsigned int rate; - unsigned int sysclk; - unsigned int bclkdiv; - unsigned int clkdiv; - unsigned int lr_rate; -}; - -/* in order of power consumption per rate (lowest first) */ -static const struct _wm8350_audio wm8350_audio[] = { - /* 16bit mono modes */ - {1, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000 >> 1, - WM8350_BCLK_DIV_48, WM8350_DACDIV_3, 16,}, - - /* 16 bit stereo modes */ - {2, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000, - WM8350_BCLK_DIV_48, WM8350_DACDIV_6, 32,}, - {2, SNDRV_PCM_FORMAT_S16_LE, 16000, 12288000, - WM8350_BCLK_DIV_24, WM8350_DACDIV_3, 32,}, - {2, SNDRV_PCM_FORMAT_S16_LE, 32000, 12288000, - WM8350_BCLK_DIV_12, WM8350_DACDIV_1_5, 32,}, - {2, SNDRV_PCM_FORMAT_S16_LE, 48000, 12288000, - WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,}, - {2, SNDRV_PCM_FORMAT_S16_LE, 96000, 24576000, - WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,}, - {2, SNDRV_PCM_FORMAT_S16_LE, 11025, 11289600, - WM8350_BCLK_DIV_32, WM8350_DACDIV_4, 32,}, - {2, SNDRV_PCM_FORMAT_S16_LE, 22050, 11289600, - WM8350_BCLK_DIV_16, WM8350_DACDIV_2, 32,}, - {2, SNDRV_PCM_FORMAT_S16_LE, 44100, 11289600, - WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,}, - {2, SNDRV_PCM_FORMAT_S16_LE, 88200, 22579200, - WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,}, - - /* 24bit stereo modes */ - {2, SNDRV_PCM_FORMAT_S24_LE, 48000, 12288000, - WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,}, - {2, SNDRV_PCM_FORMAT_S24_LE, 96000, 24576000, - WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,}, - {2, SNDRV_PCM_FORMAT_S24_LE, 44100, 11289600, - WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,}, - {2, SNDRV_PCM_FORMAT_S24_LE, 88200, 22579200, - WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,}, -}; - -static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - int i, found = 0; - snd_pcm_format_t format = params_format(params); - unsigned int rate = params_rate(params); - unsigned int channels = params_channels(params); - - /* find the correct audio parameters */ - for (i = 0; i < ARRAY_SIZE(wm8350_audio); i++) { - if (rate == wm8350_audio[i].rate && - format == wm8350_audio[i].format && - channels == wm8350_audio[i].channels) { - found = 1; - break; - } - } - if (!found) - return -EINVAL; - - /* codec FLL input is 14.75 MHz from MCLK */ - snd_soc_dai_set_pll(codec_dai, 0, 0, 14750000, wm8350_audio[i].sysclk); - - /* TODO: The SSI driver should figure this out for us */ - switch (channels) { - case 2: - snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0); - break; - case 1: - snd_soc_dai_set_tdm_slot(cpu_dai, 0x1, 0x1, 1, 0); - break; - default: - return -EINVAL; - } - - /* set MCLK as the codec system clock for DAC and ADC */ - snd_soc_dai_set_sysclk(codec_dai, WM8350_MCLK_SEL_PLL_MCLK, - wm8350_audio[i].sysclk, SND_SOC_CLOCK_IN); - - /* set codec BCLK division for sample rate */ - snd_soc_dai_set_clkdiv(codec_dai, WM8350_BCLK_CLKDIV, - wm8350_audio[i].bclkdiv); - - /* DAI is synchronous and clocked with DAC LRCLK & ADC LRC */ - snd_soc_dai_set_clkdiv(codec_dai, - WM8350_DACLR_CLKDIV, wm8350_audio[i].lr_rate); - snd_soc_dai_set_clkdiv(codec_dai, - WM8350_ADCLR_CLKDIV, wm8350_audio[i].lr_rate); - - /* now configure DAC and ADC clocks */ - snd_soc_dai_set_clkdiv(codec_dai, - WM8350_DAC_CLKDIV, wm8350_audio[i].clkdiv); - - snd_soc_dai_set_clkdiv(codec_dai, - WM8350_ADC_CLKDIV, wm8350_audio[i].clkdiv); - - return 0; -} - -static const struct snd_soc_ops wm1133_ev1_ops = { - .hw_params = wm1133_ev1_hw_params, -}; - -static const struct snd_soc_dapm_widget wm1133_ev1_widgets[] = { -#ifdef USE_SIMIC - SND_SOC_DAPM_MIC("SiMIC", NULL), -#endif - SND_SOC_DAPM_MIC("Mic1 Jack", NULL), - SND_SOC_DAPM_MIC("Mic2 Jack", NULL), - SND_SOC_DAPM_LINE("Line In Jack", NULL), - SND_SOC_DAPM_LINE("Line Out Jack", NULL), - SND_SOC_DAPM_HP("Headphone Jack", NULL), -}; - -/* imx32ads soc_card audio map */ -static const struct snd_soc_dapm_route wm1133_ev1_map[] = { - -#ifdef USE_SIMIC - /* SiMIC --> IN1LN (with automatic bias) via SP1 */ - { "IN1LN", NULL, "Mic Bias" }, - { "Mic Bias", NULL, "SiMIC" }, -#endif - - /* Mic 1 Jack --> IN1LN and IN1LP (with automatic bias) */ - { "IN1LN", NULL, "Mic Bias" }, - { "IN1LP", NULL, "Mic1 Jack" }, - { "Mic Bias", NULL, "Mic1 Jack" }, - - /* Mic 2 Jack --> IN1RN and IN1RP (with automatic bias) */ - { "IN1RN", NULL, "Mic Bias" }, - { "IN1RP", NULL, "Mic2 Jack" }, - { "Mic Bias", NULL, "Mic2 Jack" }, - - /* Line in Jack --> AUX (L+R) */ - { "IN3R", NULL, "Line In Jack" }, - { "IN3L", NULL, "Line In Jack" }, - - /* Out1 --> Headphone Jack */ - { "Headphone Jack", NULL, "OUT1R" }, - { "Headphone Jack", NULL, "OUT1L" }, - - /* Out1 --> Line Out Jack */ - { "Line Out Jack", NULL, "OUT2R" }, - { "Line Out Jack", NULL, "OUT2L" }, -}; - -static struct snd_soc_jack hp_jack; - -static struct snd_soc_jack_pin hp_jack_pins[] = { - { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE }, -}; - -static struct snd_soc_jack mic_jack; - -static struct snd_soc_jack_pin mic_jack_pins[] = { - { .pin = "Mic1 Jack", .mask = SND_JACK_MICROPHONE }, - { .pin = "Mic2 Jack", .mask = SND_JACK_MICROPHONE }, -}; - -static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; - - /* Headphone jack detection */ - snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE, - &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins)); - wm8350_hp_jack_detect(component, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE); - - /* Microphone jack detection */ - snd_soc_card_jack_new(rtd->card, "Microphone", - SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack, - mic_jack_pins, ARRAY_SIZE(mic_jack_pins)); - wm8350_mic_jack_detect(component, &mic_jack, SND_JACK_MICROPHONE, - SND_JACK_BTN_0); - - snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias"); - - return 0; -} - - -SND_SOC_DAILINK_DEFS(ev1, - DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")), - DAILINK_COMP_ARRAY(COMP_CODEC("wm8350-codec.0-0x1a", "wm8350-hifi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0"))); - -static struct snd_soc_dai_link wm1133_ev1_dai = { - .name = "WM1133-EV1", - .stream_name = "Audio", - .init = wm1133_ev1_init, - .ops = &wm1133_ev1_ops, - .symmetric_rates = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, - SND_SOC_DAILINK_REG(ev1), -}; - -static struct snd_soc_card wm1133_ev1 = { - .name = "WM1133-EV1", - .owner = THIS_MODULE, - .dai_link = &wm1133_ev1_dai, - .num_links = 1, - - .dapm_widgets = wm1133_ev1_widgets, - .num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets), - .dapm_routes = wm1133_ev1_map, - .num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map), -}; - -static struct platform_device *wm1133_ev1_snd_device; - -static int __init wm1133_ev1_audio_init(void) -{ - int ret; - unsigned int ptcr, pdcr; - - /* SSI0 mastered by port 5 */ - ptcr = IMX_AUDMUX_V2_PTCR_SYN | - IMX_AUDMUX_V2_PTCR_TFSDIR | - IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) | - IMX_AUDMUX_V2_PTCR_TCLKDIR | - IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5); - pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5); - imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr); - - ptcr = IMX_AUDMUX_V2_PTCR_SYN; - pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0); - imx_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr); - - wm1133_ev1_snd_device = platform_device_alloc("soc-audio", -1); - if (!wm1133_ev1_snd_device) - return -ENOMEM; - - platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1); - ret = platform_device_add(wm1133_ev1_snd_device); - - if (ret) - platform_device_put(wm1133_ev1_snd_device); - - return ret; -} -module_init(wm1133_ev1_audio_init); - -static void __exit wm1133_ev1_audio_exit(void) -{ - platform_device_unregister(wm1133_ev1_snd_device); -} -module_exit(wm1133_ev1_audio_exit); - -MODULE_AUTHOR("Mark Brown "); -MODULE_DESCRIPTION("Audio for WM1133-EV1 on i.MX31ADS"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3fbb01fb583fd3ddd319f5a547bf10e322301a3f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 10 Nov 2020 17:39:33 -0300 Subject: ASoC: mx27vis-aic32x4: Remove unused driver Since commit 879c0e5e0ac7 ("ARM: imx: Remove i.MX27 board files"), the MACH_IMX27_VISSTRIM_M10 non-DT platform is no longer supported, so get rid of its machine audio driver too. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20201110203937.25684-2-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 11 --- sound/soc/fsl/Makefile | 2 - sound/soc/fsl/mx27vis-aic32x4.c | 214 ---------------------------------------- 3 files changed, 227 deletions(-) delete mode 100644 sound/soc/fsl/mx27vis-aic32x4.c (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 3ad547193df8..c18ec9310aa7 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -239,17 +239,6 @@ config SND_SOC_IMX_SSI comment "SoC Audio support for Freescale i.MX boards:" -config SND_SOC_MX27VIS_AIC32X4 - tristate "SoC audio support for Visstrim M10 boards" - depends on MACH_IMX27_VISSTRIM_M10 && I2C - select SND_SOC_TLV320AIC32X4 - select SND_SOC_IMX_PCM_DMA - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_SSI - help - Say Y if you want to add support for SoC audio on Visstrim SM10 - board with TLV320AIC32X4 codec. - config SND_SOC_PHYCORE_AC97 tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" depends on MACH_PCM043 || MACH_PCA100 diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8d3e40415050..5c6058f414be 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -64,7 +64,6 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o snd-soc-phycore-ac97-objs := phycore-ac97.o -snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-spdif-objs := imx-spdif.o @@ -73,7 +72,6 @@ snd-soc-imx-audmix-objs := imx-audmix.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o -obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c deleted file mode 100644 index 8d3b1897370b..000000000000 --- a/sound/soc/fsl/mx27vis-aic32x4.c +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// mx27vis-aic32x4.c -// -// Copyright 2011 Vista Silicon S.L. -// -// Author: Javier Martin - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../codecs/tlv320aic32x4.h" -#include "imx-ssi.h" -#include "imx-audmux.h" - -#define MX27VIS_AMP_GAIN 0 -#define MX27VIS_AMP_MUTE 1 - -static int mx27vis_amp_gain; -static int mx27vis_amp_mute; -static int mx27vis_amp_gain0_gpio; -static int mx27vis_amp_gain1_gpio; -static int mx27vis_amp_mutel_gpio; -static int mx27vis_amp_muter_gpio; - -static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, 0, - 25000000, SND_SOC_CLOCK_OUT); - if (ret) { - pr_err("%s: failed setting codec sysclk\n", __func__); - return ret; - } - - ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, - SND_SOC_CLOCK_IN); - if (ret) { - pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); - return ret; - } - - return 0; -} - -static const struct snd_soc_ops mx27vis_aic32x4_snd_ops = { - .hw_params = mx27vis_aic32x4_hw_params, -}; - -static int mx27vis_amp_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int value = ucontrol->value.integer.value[0]; - unsigned int reg = mc->reg; - int max = mc->max; - - if (value > max) - return -EINVAL; - - switch (reg) { - case MX27VIS_AMP_GAIN: - gpio_set_value(mx27vis_amp_gain0_gpio, value & 1); - gpio_set_value(mx27vis_amp_gain1_gpio, value >> 1); - mx27vis_amp_gain = value; - break; - case MX27VIS_AMP_MUTE: - gpio_set_value(mx27vis_amp_mutel_gpio, value & 1); - gpio_set_value(mx27vis_amp_muter_gpio, value >> 1); - mx27vis_amp_mute = value; - break; - } - return 0; -} - -static int mx27vis_amp_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - - switch (reg) { - case MX27VIS_AMP_GAIN: - ucontrol->value.integer.value[0] = mx27vis_amp_gain; - break; - case MX27VIS_AMP_MUTE: - ucontrol->value.integer.value[0] = mx27vis_amp_mute; - break; - } - return 0; -} - -/* From 6dB to 24dB in steps of 6dB */ -static const DECLARE_TLV_DB_SCALE(mx27vis_amp_tlv, 600, 600, 0); - -static const struct snd_kcontrol_new mx27vis_aic32x4_controls[] = { - SOC_DAPM_PIN_SWITCH("External Mic"), - SOC_SINGLE_EXT_TLV("LO Ext Boost", MX27VIS_AMP_GAIN, 0, 3, 0, - mx27vis_amp_get, mx27vis_amp_set, mx27vis_amp_tlv), - SOC_DOUBLE_EXT("LO Ext Mute Switch", MX27VIS_AMP_MUTE, 0, 1, 1, 0, - mx27vis_amp_get, mx27vis_amp_set), -}; - -static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { - SND_SOC_DAPM_MIC("External Mic", NULL), -}; - -static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { - {"Mic Bias", NULL, "External Mic"}, - {"IN1_R", NULL, "Mic Bias"}, - {"IN2_R", NULL, "Mic Bias"}, - {"IN3_R", NULL, "Mic Bias"}, - {"IN1_L", NULL, "Mic Bias"}, - {"IN2_L", NULL, "Mic Bias"}, - {"IN3_L", NULL, "Mic Bias"}, -}; - -SND_SOC_DAILINK_DEFS(hifi, - DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")), - DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic32x4.0-0018", - "tlv320aic32x4-hifi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0"))); - -static struct snd_soc_dai_link mx27vis_aic32x4_dai = { - .name = "tlv320aic32x4", - .stream_name = "TLV320AIC32X4", - .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, - .ops = &mx27vis_aic32x4_snd_ops, - SND_SOC_DAILINK_REG(hifi), -}; - -static struct snd_soc_card mx27vis_aic32x4 = { - .name = "visstrim_m10-audio", - .owner = THIS_MODULE, - .dai_link = &mx27vis_aic32x4_dai, - .num_links = 1, - .controls = mx27vis_aic32x4_controls, - .num_controls = ARRAY_SIZE(mx27vis_aic32x4_controls), - .dapm_widgets = aic32x4_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets), - .dapm_routes = aic32x4_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), -}; - -static int mx27vis_aic32x4_probe(struct platform_device *pdev) -{ - struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data; - int ret; - - if (!pdata) { - dev_err(&pdev->dev, "No platform data supplied\n"); - return -EINVAL; - } - - mx27vis_amp_gain0_gpio = pdata->amp_gain0_gpio; - mx27vis_amp_gain1_gpio = pdata->amp_gain1_gpio; - mx27vis_amp_mutel_gpio = pdata->amp_mutel_gpio; - mx27vis_amp_muter_gpio = pdata->amp_muter_gpio; - - mx27vis_aic32x4.dev = &pdev->dev; - ret = devm_snd_soc_register_card(&pdev->dev, &mx27vis_aic32x4); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - return ret; - } - - /* Connect SSI0 as clock slave to SSI1 external pins */ - imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, - IMX_AUDMUX_V1_PCR_SYN | - IMX_AUDMUX_V1_PCR_TFSDIR | - IMX_AUDMUX_V1_PCR_TCLKDIR | - IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) | - IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) - ); - imx_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1, - IMX_AUDMUX_V1_PCR_SYN | - IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) - ); - - return ret; -} - -static struct platform_driver mx27vis_aic32x4_audio_driver = { - .driver = { - .name = "mx27vis", - }, - .probe = mx27vis_aic32x4_probe, -}; - -module_platform_driver(mx27vis_aic32x4_audio_driver); - -MODULE_AUTHOR("Javier Martin "); -MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:mx27vis"); -- cgit v1.2.3 From 440534a0ecfd20235a091fb2a98c2c3adf86834e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 10 Nov 2020 17:39:34 -0300 Subject: ASoC: phycore-ac97: Remove unused driver Since commit e1324ece2af4 ("ARM: imx: Remove i.MX35 board files"), the MACH_PCM043 and MACH_PCA100 non-DT platform are no longer supported, so get rid of their machine audio driver too. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20201110203937.25684-3-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 12 ----- sound/soc/fsl/Makefile | 2 - sound/soc/fsl/phycore-ac97.c | 121 ------------------------------------------- 3 files changed, 135 deletions(-) delete mode 100644 sound/soc/fsl/phycore-ac97.c (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index c18ec9310aa7..63be2bf5b509 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -239,18 +239,6 @@ config SND_SOC_IMX_SSI comment "SoC Audio support for Freescale i.MX boards:" -config SND_SOC_PHYCORE_AC97 - tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" - depends on MACH_PCM043 || MACH_PCA100 - select SND_SOC_AC97_BUS - select SND_SOC_WM9712 - select SND_SOC_IMX_PCM_FIQ - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_SSI - help - Say Y if you want to add support for SoC audio on Phytec phyCORE - and phyCARD boards in AC97 mode - config SND_SOC_EUKREA_TLV320 tristate "Eukrea TLV320" depends on ARCH_MXC && !ARM64 && I2C diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 5c6058f414be..12755058f877 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -63,7 +63,6 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o -snd-soc-phycore-ac97-objs := phycore-ac97.o snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-spdif-objs := imx-spdif.o @@ -71,7 +70,6 @@ snd-soc-imx-mc13783-objs := imx-mc13783.o snd-soc-imx-audmix-objs := imx-audmix.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o -obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o diff --git a/sound/soc/fsl/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c deleted file mode 100644 index e561f7ff1699..000000000000 --- a/sound/soc/fsl/phycore-ac97.c +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// phycore-ac97.c -- SoC audio for imx_phycore in AC97 mode -// -// Copyright 2009 Sascha Hauer, Pengutronix - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "imx-audmux.h" - -static struct snd_soc_card imx_phycore; - -static const struct snd_soc_ops imx_phycore_hifi_ops = { -}; - -SND_SOC_DAILINK_DEFS(hifi, - DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")), - DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0"))); - -static struct snd_soc_dai_link imx_phycore_dai_ac97[] = { - { - .name = "HiFi", - .stream_name = "HiFi", - .ops = &imx_phycore_hifi_ops, - SND_SOC_DAILINK_REG(hifi), - }, -}; - -static struct snd_soc_card imx_phycore = { - .name = "PhyCORE-ac97-audio", - .owner = THIS_MODULE, - .dai_link = imx_phycore_dai_ac97, - .num_links = ARRAY_SIZE(imx_phycore_dai_ac97), -}; - -static struct platform_device *imx_phycore_snd_ac97_device; -static struct platform_device *imx_phycore_snd_device; - -static int __init imx_phycore_init(void) -{ - int ret; - - if (machine_is_pca100()) { - imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, - IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */ - IMX_AUDMUX_V1_PCR_TFCSEL(3) | - IMX_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */ - IMX_AUDMUX_V1_PCR_RXDSEL(3)); - imx_audmux_v1_configure_port(3, - IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */ - IMX_AUDMUX_V1_PCR_TFCSEL(0) | - IMX_AUDMUX_V1_PCR_TFSDIR | - IMX_AUDMUX_V1_PCR_RXDSEL(0)); - } else if (machine_is_pcm043()) { - imx_audmux_v2_configure_port(3, - IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */ - IMX_AUDMUX_V2_PTCR_TFSEL(0) | - IMX_AUDMUX_V2_PTCR_TFSDIR, - IMX_AUDMUX_V2_PDCR_RXDSEL(0)); - imx_audmux_v2_configure_port(0, - IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */ - IMX_AUDMUX_V2_PTCR_TCSEL(3) | - IMX_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */ - IMX_AUDMUX_V2_PDCR_RXDSEL(3)); - } else { - /* return happy. We might run on a totally different machine */ - return 0; - } - - imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!imx_phycore_snd_ac97_device) - return -ENOMEM; - - platform_set_drvdata(imx_phycore_snd_ac97_device, &imx_phycore); - ret = platform_device_add(imx_phycore_snd_ac97_device); - if (ret) - goto fail1; - - imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1); - if (!imx_phycore_snd_device) { - ret = -ENOMEM; - goto fail2; - } - ret = platform_device_add(imx_phycore_snd_device); - - if (ret) { - printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - goto fail3; - } - - return 0; - -fail3: - platform_device_put(imx_phycore_snd_device); -fail2: - platform_device_del(imx_phycore_snd_ac97_device); -fail1: - platform_device_put(imx_phycore_snd_ac97_device); - return ret; -} - -static void __exit imx_phycore_exit(void) -{ - platform_device_unregister(imx_phycore_snd_device); - platform_device_unregister(imx_phycore_snd_ac97_device); -} - -late_initcall(imx_phycore_init); -module_exit(imx_phycore_exit); - -MODULE_AUTHOR("Sascha Hauer "); -MODULE_DESCRIPTION("PhyCORE ALSA SoC driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 83e7e2278680207f1650949db11ba0e1b6fbc3f5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 10 Nov 2020 17:39:35 -0300 Subject: ASoC: imx-mc13783: Remove unused driver The imx-mc13783 was used on imx27-pdk and imx31-pdk non-DT platforms. Since 5.10-rc1, i.MX has been converted to a DT-only platform and all board files are gone. Remove the imx-mc13783 audio machine driver as there is no user at all. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20201110203937.25684-4-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 8 --- sound/soc/fsl/Makefile | 2 - sound/soc/fsl/imx-mc13783.c | 156 -------------------------------------------- 3 files changed, 166 deletions(-) delete mode 100644 sound/soc/fsl/imx-mc13783.c (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 63be2bf5b509..1536c6d411fa 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -283,14 +283,6 @@ config SND_SOC_IMX_SPDIF Say Y if you want to add support for SoC audio on an i.MX board with a S/DPDIF. -config SND_SOC_IMX_MC13783 - tristate "SoC Audio support for I.MX boards with mc13783" - depends on MFD_MC13XXX && ARM - select SND_SOC_IMX_SSI - select SND_SOC_IMX_AUDMUX - select SND_SOC_MC13783 - select SND_SOC_IMX_PCM_DMA - config SND_SOC_FSL_ASOC_CARD tristate "Generic ASoC Sound Card with ASRC support" depends on OF && I2C diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 12755058f877..5637ebbe8ab2 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -66,12 +66,10 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-spdif-objs := imx-spdif.o -snd-soc-imx-mc13783-objs := imx-mc13783.o snd-soc-imx-audmix-objs := imx-audmix.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o -obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c deleted file mode 100644 index d9dca7bbcae3..000000000000 --- a/sound/soc/fsl/imx-mc13783.c +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// imx-mc13783.c -- SoC audio for imx based boards with mc13783 codec -// -// Copyright 2012 Philippe Retornaz, -// -// Heavly based on phycore-mc13783: -// Copyright 2009 Sascha Hauer, Pengutronix - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../codecs/mc13783.h" -#include "imx-ssi.h" -#include "imx-audmux.h" - -#define FMT_SSI (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \ - SND_SOC_DAIFMT_CBM_CFM) - -static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 4, 16); - if (ret) - return ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0); - if (ret) - return ret; - - return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16); -} - -static const struct snd_soc_ops imx_mc13783_hifi_ops = { - .hw_params = imx_mc13783_hifi_hw_params, -}; - -SND_SOC_DAILINK_DEFS(hifi, - DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")), - DAILINK_COMP_ARRAY(COMP_CODEC("mc13783-codec", "mc13783-hifi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0"))); - -static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = { - { - .name = "MC13783", - .stream_name = "Sound", - .ops = &imx_mc13783_hifi_ops, - .symmetric_rates = 1, - .dai_fmt = FMT_SSI, - SND_SOC_DAILINK_REG(hifi), - }, -}; - -static const struct snd_soc_dapm_widget imx_mc13783_widget[] = { - SND_SOC_DAPM_MIC("Mic", NULL), - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_soc_dapm_route imx_mc13783_routes[] = { - {"Speaker", NULL, "LSP"}, - {"Headphone", NULL, "HSL"}, - {"Headphone", NULL, "HSR"}, - - {"MC1LIN", NULL, "MC1 Bias"}, - {"MC2IN", NULL, "MC2 Bias"}, - {"MC1 Bias", NULL, "Mic"}, - {"MC2 Bias", NULL, "Mic"}, -}; - -static struct snd_soc_card imx_mc13783 = { - .name = "imx_mc13783", - .owner = THIS_MODULE, - .dai_link = imx_mc13783_dai_mc13783, - .num_links = ARRAY_SIZE(imx_mc13783_dai_mc13783), - .dapm_widgets = imx_mc13783_widget, - .num_dapm_widgets = ARRAY_SIZE(imx_mc13783_widget), - .dapm_routes = imx_mc13783_routes, - .num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes), -}; - -static int imx_mc13783_probe(struct platform_device *pdev) -{ - int ret; - - imx_mc13783.dev = &pdev->dev; - - ret = devm_snd_soc_register_card(&pdev->dev, &imx_mc13783); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", - ret); - return ret; - } - - if (machine_is_mx31_3ds() || machine_is_mx31moboard()) { - imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4, - IMX_AUDMUX_V2_PTCR_SYN, - IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) | - IMX_AUDMUX_V2_PDCR_MODE(1) | - IMX_AUDMUX_V2_PDCR_INMMASK(0xfc)); - imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, - IMX_AUDMUX_V2_PTCR_SYN | - IMX_AUDMUX_V2_PTCR_TFSDIR | - IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | - IMX_AUDMUX_V2_PTCR_TCLKDIR | - IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | - IMX_AUDMUX_V2_PTCR_RFSDIR | - IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | - IMX_AUDMUX_V2_PTCR_RCLKDIR | - IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4), - IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4)); - } else if (machine_is_mx27_3ds()) { - imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, - IMX_AUDMUX_V1_PCR_SYN | - IMX_AUDMUX_V1_PCR_TFSDIR | - IMX_AUDMUX_V1_PCR_TCLKDIR | - IMX_AUDMUX_V1_PCR_RFSDIR | - IMX_AUDMUX_V1_PCR_RCLKDIR | - IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | - IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | - IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) - ); - imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4, - IMX_AUDMUX_V1_PCR_SYN | - IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) - ); - } - - return ret; -} - -static struct platform_driver imx_mc13783_audio_driver = { - .driver = { - .name = "imx_mc13783", - }, - .probe = imx_mc13783_probe, -}; - -module_platform_driver(imx_mc13783_audio_driver); - -MODULE_AUTHOR("Sascha Hauer "); -MODULE_AUTHOR("Philippe Retornaz Date: Tue, 10 Nov 2020 17:39:36 -0300 Subject: ASoC: fsl: eukrea: Remove the SND_SOC_IMX_SSI selection SND_SOC_IMX_SSI was only used by i.MX non-DT platforms. SND_SOC_EUKREA_TLV320 already selects the SND_SOC_FSL_SSI symbol, which is enough. Remove the unneeded SND_SOC_IMX_SSI selection. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20201110203937.25684-5-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 1536c6d411fa..31897fff6c71 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -244,7 +244,6 @@ config SND_SOC_EUKREA_TLV320 depends on ARCH_MXC && !ARM64 && I2C select SND_SOC_TLV320AIC23_I2C select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_SSI select SND_SOC_FSL_SSI select SND_SOC_IMX_PCM_DMA help -- cgit v1.2.3 From c31da0b196f99c7d95c69bab96e709b72a30f509 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 10 Nov 2020 17:39:37 -0300 Subject: ASoC: imx-ssi: Remove unused driver The imx-ssi driver was only used by i.MX non-DT platforms. Since 5.10-rc1, i.MX has been converted to a DT-only platform and all board files are gone. Remove the imx-ssi audio driver as there are no more users at all. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20201110203937.25684-6-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 6 +- sound/soc/fsl/Makefile | 2 - sound/soc/fsl/imx-ssi.c | 651 ------------------------------------------------ 3 files changed, 1 insertion(+), 658 deletions(-) delete mode 100644 sound/soc/fsl/imx-ssi.c (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 31897fff6c71..a299f61e529e 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -228,15 +228,11 @@ endif # SND_POWERPC_SOC config SND_SOC_IMX_PCM_FIQ tristate - default y if SND_SOC_IMX_SSI=y && (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC) + default y if (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC) select FIQ if SND_IMX_SOC -config SND_SOC_IMX_SSI - tristate - select SND_SOC_FSL_UTILS - comment "SoC Audio support for Freescale i.MX boards:" config SND_SOC_EUKREA_TLV320 diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 5637ebbe8ab2..0b20e038b65b 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -53,9 +53,7 @@ obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o # i.MX Platform Support -snd-soc-imx-ssi-objs := imx-ssi.o snd-soc-imx-audmux-objs := imx-audmux.o -obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c deleted file mode 100644 index f8488e8f5f5b..000000000000 --- a/sound/soc/fsl/imx-ssi.c +++ /dev/null @@ -1,651 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// imx-ssi.c -- ALSA Soc Audio Layer -// -// Copyright 2009 Sascha Hauer -// -// This code is based on code copyrighted by Freescale, -// Liam Girdwood, Javier Martin and probably others. -// -// The i.MX SSI core has some nasty limitations in AC97 mode. While most -// sane processor vendors have a FIFO per AC97 slot, the i.MX has only -// one FIFO which combines all valid receive slots. We cannot even select -// which slots we want to receive. The WM9712 with which this driver -// was developed with always sends GPIO status data in slot 12 which -// we receive in our (PCM-) data stream. The only chance we have is to -// manually skip this data in the FIQ handler. With sampling rates different -// from 48000Hz not every frame has valid receive data, so the ratio -// between pcm data and GPIO status data changes. Our FIQ handler is not -// able to handle this, hence this driver only works with 48000Hz sampling -// rate. -// Reading and writing AC97 registers is another challenge. The core -// provides us status bits when the read register is updated with *another* -// value. When we read the same register two times (and the register still -// contains the same value) these status bits are not set. We work -// around this by not polling these bits but only wait a fixed delay. - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "imx-ssi.h" -#include "fsl_utils.h" - -#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV) - -/* - * SSI Network Mode or TDM slots configuration. - * Should only be called when port is inactive (i.e. SSIEN = 0). - */ -static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, - unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) -{ - struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); - u32 sccr; - - sccr = readl(ssi->base + SSI_STCCR); - sccr &= ~SSI_STCCR_DC_MASK; - sccr |= SSI_STCCR_DC(slots - 1); - writel(sccr, ssi->base + SSI_STCCR); - - sccr = readl(ssi->base + SSI_SRCCR); - sccr &= ~SSI_STCCR_DC_MASK; - sccr |= SSI_STCCR_DC(slots - 1); - writel(sccr, ssi->base + SSI_SRCCR); - - writel(~tx_mask, ssi->base + SSI_STMSK); - writel(~rx_mask, ssi->base + SSI_SRMSK); - - return 0; -} - -/* - * SSI DAI format configuration. - * Should only be called when port is inactive (i.e. SSIEN = 0). - */ -static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) -{ - struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); - u32 strcr = 0, scr; - - scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET); - - /* DAI mode */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - /* data on rising edge of bclk, frame low 1clk before data */ - strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI | - SSI_STCR_TEFS; - scr |= SSI_SCR_NET; - if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) { - scr &= ~SSI_I2S_MODE_MASK; - scr |= SSI_SCR_I2S_MODE_SLAVE; - } - break; - case SND_SOC_DAIFMT_LEFT_J: - /* data on rising edge of bclk, frame high with data */ - strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP; - break; - case SND_SOC_DAIFMT_DSP_B: - /* data on rising edge of bclk, frame high with data */ - strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL; - break; - case SND_SOC_DAIFMT_DSP_A: - /* data on rising edge of bclk, frame high 1clk before data */ - strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL | - SSI_STCR_TEFS; - break; - } - - /* DAI clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_IF: - strcr ^= SSI_STCR_TSCKP | SSI_STCR_TFSI; - break; - case SND_SOC_DAIFMT_IB_NF: - strcr ^= SSI_STCR_TSCKP; - break; - case SND_SOC_DAIFMT_NB_IF: - strcr ^= SSI_STCR_TFSI; - break; - case SND_SOC_DAIFMT_NB_NF: - break; - } - - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - break; - default: - /* Master mode not implemented, needs handling of clocks. */ - return -EINVAL; - } - - strcr |= SSI_STCR_TFEN0; - - if (ssi->flags & IMX_SSI_NET) - scr |= SSI_SCR_NET; - if (ssi->flags & IMX_SSI_SYN) - scr |= SSI_SCR_SYN; - - writel(strcr, ssi->base + SSI_STCR); - writel(strcr, ssi->base + SSI_SRCR); - writel(scr, ssi->base + SSI_SCR); - - return 0; -} - -/* - * SSI system clock configuration. - * Should only be called when port is inactive (i.e. SSIEN = 0). - */ -static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); - u32 scr; - - scr = readl(ssi->base + SSI_SCR); - - switch (clk_id) { - case IMX_SSP_SYS_CLK: - if (dir == SND_SOC_CLOCK_OUT) - scr |= SSI_SCR_SYS_CLK_EN; - else - scr &= ~SSI_SCR_SYS_CLK_EN; - break; - default: - return -EINVAL; - } - - writel(scr, ssi->base + SSI_SCR); - - return 0; -} - -/* - * SSI Clock dividers - * Should only be called when port is inactive (i.e. SSIEN = 0). - */ -static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); - u32 stccr, srccr; - - stccr = readl(ssi->base + SSI_STCCR); - srccr = readl(ssi->base + SSI_SRCCR); - - switch (div_id) { - case IMX_SSI_TX_DIV_2: - stccr &= ~SSI_STCCR_DIV2; - stccr |= div; - break; - case IMX_SSI_TX_DIV_PSR: - stccr &= ~SSI_STCCR_PSR; - stccr |= div; - break; - case IMX_SSI_TX_DIV_PM: - stccr &= ~0xff; - stccr |= SSI_STCCR_PM(div); - break; - case IMX_SSI_RX_DIV_2: - stccr &= ~SSI_STCCR_DIV2; - stccr |= div; - break; - case IMX_SSI_RX_DIV_PSR: - stccr &= ~SSI_STCCR_PSR; - stccr |= div; - break; - case IMX_SSI_RX_DIV_PM: - stccr &= ~0xff; - stccr |= SSI_STCCR_PM(div); - break; - default: - return -EINVAL; - } - - writel(stccr, ssi->base + SSI_STCCR); - writel(srccr, ssi->base + SSI_SRCCR); - - return 0; -} - -/* - * Should only be called when port is inactive (i.e. SSIEN = 0), - * although can be called multiple times by upper layers. - */ -static int imx_ssi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *cpu_dai) -{ - struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai); - u32 reg, sccr; - - /* Tx/Rx config */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - reg = SSI_STCCR; - else - reg = SSI_SRCCR; - - if (ssi->flags & IMX_SSI_SYN) - reg = SSI_STCCR; - - sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; - - /* DAI data (word) size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - sccr |= SSI_SRCCR_WL(16); - break; - case SNDRV_PCM_FORMAT_S20_3LE: - sccr |= SSI_SRCCR_WL(20); - break; - case SNDRV_PCM_FORMAT_S24_LE: - sccr |= SSI_SRCCR_WL(24); - break; - } - - writel(sccr, ssi->base + reg); - - return 0; -} - -static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai); - unsigned int sier_bits, sier; - unsigned int scr; - - scr = readl(ssi->base + SSI_SCR); - sier = readl(ssi->base + SSI_SIER); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (ssi->flags & IMX_SSI_DMA) - sier_bits = SSI_SIER_TDMAE; - else - sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN; - } else { - if (ssi->flags & IMX_SSI_DMA) - sier_bits = SSI_SIER_RDMAE; - else - sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN; - } - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - scr |= SSI_SCR_TE; - else - scr |= SSI_SCR_RE; - sier |= sier_bits; - - scr |= SSI_SCR_SSIEN; - - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - scr &= ~SSI_SCR_TE; - else - scr &= ~SSI_SCR_RE; - sier &= ~sier_bits; - - if (!(scr & (SSI_SCR_TE | SSI_SCR_RE))) - scr &= ~SSI_SCR_SSIEN; - - break; - default: - return -EINVAL; - } - - if (!(ssi->flags & IMX_SSI_USE_AC97)) - /* rx/tx are always enabled to access ac97 registers */ - writel(scr, ssi->base + SSI_SCR); - - writel(sier, ssi->base + SSI_SIER); - - return 0; -} - -static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { - .hw_params = imx_ssi_hw_params, - .set_fmt = imx_ssi_set_dai_fmt, - .set_clkdiv = imx_ssi_set_dai_clkdiv, - .set_sysclk = imx_ssi_set_dai_sysclk, - .set_tdm_slot = imx_ssi_set_dai_tdm_slot, - .trigger = imx_ssi_trigger, -}; - -static int imx_ssi_dai_probe(struct snd_soc_dai *dai) -{ - struct imx_ssi *ssi = dev_get_drvdata(dai->dev); - uint32_t val; - - snd_soc_dai_set_drvdata(dai, ssi); - - val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) | - SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst); - writel(val, ssi->base + SSI_SFCSR); - - /* Tx/Rx config */ - dai->playback_dma_data = &ssi->dma_params_tx; - dai->capture_dma_data = &ssi->dma_params_rx; - - return 0; -} - -static struct snd_soc_dai_driver imx_ssi_dai = { - .probe = imx_ssi_dai_probe, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &imx_ssi_pcm_dai_ops, -}; - -static struct snd_soc_dai_driver imx_ac97_dai = { - .probe = imx_ssi_dai_probe, - .playback = { - .stream_name = "AC97 Playback", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "AC97 Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &imx_ssi_pcm_dai_ops, -}; - -static const struct snd_soc_component_driver imx_component = { - .name = DRV_NAME, -}; - -static void setup_channel_to_ac97(struct imx_ssi *imx_ssi) -{ - void __iomem *base = imx_ssi->base; - - writel(0x0, base + SSI_SCR); - writel(0x0, base + SSI_STCR); - writel(0x0, base + SSI_SRCR); - - writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR); - - writel(SSI_SFCSR_RFWM0(8) | - SSI_SFCSR_TFWM0(8) | - SSI_SFCSR_RFWM1(8) | - SSI_SFCSR_TFWM1(8), base + SSI_SFCSR); - - writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR); - writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR); - - writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR); - writel(SSI_SOR_WAIT(3), base + SSI_SOR); - - writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN | - SSI_SCR_TE | SSI_SCR_RE, - base + SSI_SCR); - - writel(SSI_SACNT_DEFAULT, base + SSI_SACNT); - writel(0xff, base + SSI_SACCDIS); - writel(0x300, base + SSI_SACCEN); -} - -static struct imx_ssi *ac97_ssi; - -static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - struct imx_ssi *imx_ssi = ac97_ssi; - void __iomem *base = imx_ssi->base; - unsigned int lreg; - unsigned int lval; - - if (reg > 0x7f) - return; - - pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val); - - lreg = reg << 12; - writel(lreg, base + SSI_SACADD); - - lval = val << 4; - writel(lval , base + SSI_SACDAT); - - writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT); - udelay(100); -} - -static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - struct imx_ssi *imx_ssi = ac97_ssi; - void __iomem *base = imx_ssi->base; - - unsigned short val = -1; - unsigned int lreg; - - lreg = (reg & 0x7f) << 12 ; - writel(lreg, base + SSI_SACADD); - writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT); - - udelay(100); - - val = (readl(base + SSI_SACDAT) >> 4) & 0xffff; - - pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val); - - return val; -} - -static void imx_ssi_ac97_reset(struct snd_ac97 *ac97) -{ - struct imx_ssi *imx_ssi = ac97_ssi; - - if (imx_ssi->ac97_reset) - imx_ssi->ac97_reset(ac97); - /* First read sometimes fails, do a dummy read */ - imx_ssi_ac97_read(ac97, 0); -} - -static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97) -{ - struct imx_ssi *imx_ssi = ac97_ssi; - - if (imx_ssi->ac97_warm_reset) - imx_ssi->ac97_warm_reset(ac97); - - /* First read sometimes fails, do a dummy read */ - imx_ssi_ac97_read(ac97, 0); -} - -static struct snd_ac97_bus_ops imx_ssi_ac97_ops = { - .read = imx_ssi_ac97_read, - .write = imx_ssi_ac97_write, - .reset = imx_ssi_ac97_reset, - .warm_reset = imx_ssi_ac97_warm_reset -}; - -static int imx_ssi_probe(struct platform_device *pdev) -{ - struct resource *res; - struct imx_ssi *ssi; - struct imx_ssi_platform_data *pdata = pdev->dev.platform_data; - int ret = 0; - struct snd_soc_dai_driver *dai; - - ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); - if (!ssi) - return -ENOMEM; - dev_set_drvdata(&pdev->dev, ssi); - - if (pdata) { - ssi->ac97_reset = pdata->ac97_reset; - ssi->ac97_warm_reset = pdata->ac97_warm_reset; - ssi->flags = pdata->flags; - } - - ssi->irq = platform_get_irq(pdev, 0); - if (ssi->irq < 0) - return ssi->irq; - - ssi->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(ssi->clk)) { - ret = PTR_ERR(ssi->clk); - dev_err(&pdev->dev, "Cannot get the clock: %d\n", - ret); - goto failed_clk; - } - ret = clk_prepare_enable(ssi->clk); - if (ret) - goto failed_clk; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ssi->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ssi->base)) { - ret = PTR_ERR(ssi->base); - goto failed_register; - } - - if (ssi->flags & IMX_SSI_USE_AC97) { - if (ac97_ssi) { - dev_err(&pdev->dev, "AC'97 SSI already registered\n"); - ret = -EBUSY; - goto failed_register; - } - ac97_ssi = ssi; - setup_channel_to_ac97(ssi); - dai = &imx_ac97_dai; - } else - dai = &imx_ssi_dai; - - writel(0x0, ssi->base + SSI_SIER); - - ssi->dma_params_rx.addr = res->start + SSI_SRX0; - ssi->dma_params_tx.addr = res->start + SSI_STX0; - - ssi->dma_params_tx.maxburst = 6; - ssi->dma_params_rx.maxburst = 4; - - ssi->dma_params_tx.filter_data = &ssi->filter_data_tx; - ssi->dma_params_rx.filter_data = &ssi->filter_data_rx; - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); - if (res) { - imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start, - IMX_DMATYPE_SSI); - } - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0"); - if (res) { - imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start, - IMX_DMATYPE_SSI); - } - - platform_set_drvdata(pdev, ssi); - - ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret); - goto failed_register; - } - - ret = snd_soc_register_component(&pdev->dev, &imx_component, - dai, 1); - if (ret) { - dev_err(&pdev->dev, "register DAI failed\n"); - goto failed_register; - } - - ssi->fiq_params.irq = ssi->irq; - ssi->fiq_params.base = ssi->base; - ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx; - ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx; - - ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params); - ssi->dma_init = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE); - - if (ssi->fiq_init && ssi->dma_init) { - ret = ssi->fiq_init; - goto failed_pcm; - } - - return 0; - -failed_pcm: - snd_soc_unregister_component(&pdev->dev); -failed_register: - clk_disable_unprepare(ssi->clk); -failed_clk: - snd_soc_set_ac97_ops(NULL); - - return ret; -} - -static int imx_ssi_remove(struct platform_device *pdev) -{ - struct imx_ssi *ssi = platform_get_drvdata(pdev); - - if (!ssi->fiq_init) - imx_pcm_fiq_exit(pdev); - - snd_soc_unregister_component(&pdev->dev); - - if (ssi->flags & IMX_SSI_USE_AC97) - ac97_ssi = NULL; - - clk_disable_unprepare(ssi->clk); - snd_soc_set_ac97_ops(NULL); - - return 0; -} - -static struct platform_driver imx_ssi_driver = { - .probe = imx_ssi_probe, - .remove = imx_ssi_remove, - - .driver = { - .name = "imx-ssi", - }, -}; - -module_platform_driver(imx_ssi_driver); - -/* Module information */ -MODULE_AUTHOR("Sascha Hauer, "); -MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-ssi"); -- cgit v1.2.3 From f026c123001bcc15b78311495cec79a8b73c3cf2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:30:57 -0600 Subject: ASoC: topology: use inclusive language for bclk and fsync Mirror suggested changes in alsa-lib. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201112163100.5081-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 32 ++++++++++++++++++++------------ include/uapi/sound/asoc.h | 22 ++++++++++++++-------- sound/soc/soc-topology.c | 24 ++++++++++++------------ sound/soc/sof/topology.c | 6 +++--- 4 files changed, 49 insertions(+), 35 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 7a85a6f83ca8..4bf759f025d2 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -72,21 +72,29 @@ struct snd_compr_stream; #define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */ /* - * DAI hardware clock masters. + * DAI hardware clock providers/consumers * * This is wrt the codec, the inverse is true for the interface - * i.e. if the codec is clk and FRM master then the interface is - * clk and frame secondary. + * i.e. if the codec is clk and FRM provider then the interface is + * clk and frame consumer. */ -#define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */ -#define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk secondary & FRM master */ -#define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame secondary */ -#define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM secondary */ - -#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f -#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 -#define SND_SOC_DAIFMT_INV_MASK 0x0f00 -#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 +#define SND_SOC_DAIFMT_CBP_CFP (1 << 12) /* codec clk provider & frame provider */ +#define SND_SOC_DAIFMT_CBC_CFP (2 << 12) /* codec clk consumer & frame provider */ +#define SND_SOC_DAIFMT_CBP_CFC (3 << 12) /* codec clk provider & frame consumer */ +#define SND_SOC_DAIFMT_CBC_CFC (4 << 12) /* codec clk consumer & frame follower */ + +/* previous definitions kept for backwards-compatibility, do not use in new contributions */ +#define SND_SOC_DAIFMT_CBM_CFM SND_SOC_DAIFMT_CBP_CFP +#define SND_SOC_DAIFMT_CBS_CFM SND_SOC_DAIFMT_CBC_CFP +#define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC +#define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC + +#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f +#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 +#define SND_SOC_DAIFMT_INV_MASK 0x0f00 +#define SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK 0xf000 + +#define SND_SOC_DAIFMT_MASTER_MASK SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK /* * Master Clock Directions diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index a74ca232f1fc..da61398b1f8f 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -170,16 +170,22 @@ #define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3) /* DAI topology BCLK parameter - * For the backwards capability, by default codec is bclk master + * For the backwards capability, by default codec is bclk provider */ -#define SND_SOC_TPLG_BCLK_CM 0 /* codec is bclk master */ -#define SND_SOC_TPLG_BCLK_CS 1 /* codec is bclk slave */ +#define SND_SOC_TPLG_BCLK_CP 0 /* codec is bclk provider */ +#define SND_SOC_TPLG_BCLK_CC 1 /* codec is bclk consumer */ +/* keep previous definitions for compatibility */ +#define SND_SOC_TPLG_BCLK_CM SND_SOC_TPLG_BCLK_CP +#define SND_SOC_TPLG_BCLK_CS SND_SOC_TPLG_BCLK_CC /* DAI topology FSYNC parameter - * For the backwards capability, by default codec is fsync master + * For the backwards capability, by default codec is fsync provider */ -#define SND_SOC_TPLG_FSYNC_CM 0 /* codec is fsync master */ -#define SND_SOC_TPLG_FSYNC_CS 1 /* codec is fsync slave */ +#define SND_SOC_TPLG_FSYNC_CP 0 /* codec is fsync provider */ +#define SND_SOC_TPLG_FSYNC_CC 1 /* codec is fsync consumer */ +/* keep previous definitions for compatibility */ +#define SND_SOC_TPLG_FSYNC_CM SND_SOC_TPLG_FSYNC_CP +#define SND_SOC_TPLG_FSYNC_CS SND_SOC_TPLG_FSYNC_CC /* * Block Header. @@ -336,8 +342,8 @@ struct snd_soc_tplg_hw_config { __u8 clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - __u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */ - __u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + __u8 bclk_provider; /* SND_SOC_TPLG_BCLK_ value */ + __u8 fsync_provider; /* SND_SOC_TPLG_FSYNC_ value */ __u8 mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ __le16 reserved; /* for 32bit alignment */ __le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 07c60187e9ea..eb2633dd6454 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2017,7 +2017,7 @@ static void set_link_hw_format(struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg) { struct snd_soc_tplg_hw_config *hw_config; - unsigned char bclk_master, fsync_master; + unsigned char bclk_provider, fsync_provider; unsigned char invert_bclk, invert_fsync; int i; @@ -2057,18 +2057,18 @@ static void set_link_hw_format(struct snd_soc_dai_link *link, link->dai_fmt |= SND_SOC_DAIFMT_IB_IF; /* clock masters */ - bclk_master = (hw_config->bclk_master == - SND_SOC_TPLG_BCLK_CM); - fsync_master = (hw_config->fsync_master == - SND_SOC_TPLG_FSYNC_CM); - if (bclk_master && fsync_master) - link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; - else if (!bclk_master && fsync_master) - link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; - else if (bclk_master && !fsync_master) - link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; + bclk_provider = (hw_config->bclk_provider == + SND_SOC_TPLG_BCLK_CP); + fsync_provider = (hw_config->fsync_provider == + SND_SOC_TPLG_FSYNC_CP); + if (bclk_provider && fsync_provider) + link->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; + else if (!bclk_provider && fsync_provider) + link->dai_fmt |= SND_SOC_DAIFMT_CBC_CFP; + else if (bclk_provider && !fsync_provider) + link->dai_fmt |= SND_SOC_DAIFMT_CBP_CFC; else - link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + link->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; } } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 44fddeda6043..d708c640e7b5 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2777,15 +2777,15 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, struct sof_ipc_dai_config *config) { /* clock directions wrt codec */ - if (hw_config->bclk_master == SND_SOC_TPLG_BCLK_CM) { + if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CM) { /* codec is bclk master */ - if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM) + if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CM) config->format |= SOF_DAI_FMT_CBM_CFM; else config->format |= SOF_DAI_FMT_CBM_CFS; } else { /* codec is bclk slave */ - if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM) + if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CM) config->format |= SOF_DAI_FMT_CBS_CFM; else config->format |= SOF_DAI_FMT_CBS_CFS; -- cgit v1.2.3 From df132fa9daf4828598dbba553e1b2bb5cf36a715 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:30:58 -0600 Subject: ASoC: SOF: use inclusive language for bclk and fsync Mirror alsa-lib definitions w/ codec_provider (CP) and codec_consumer (CC). Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201112163100.5081-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/dai.h | 16 +++++++++++----- sound/soc/sof/topology.c | 18 +++++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 34f135adf8ec..6bb403e8c5ee 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -34,15 +34,21 @@ #define SOF_DAI_FMT_IB_NF (3 << 8) /**< invert BCLK + nor FRM */ #define SOF_DAI_FMT_IB_IF (4 << 8) /**< invert BCLK + FRM */ -#define SOF_DAI_FMT_CBM_CFM (0 << 12) /**< codec clk & FRM master */ -#define SOF_DAI_FMT_CBS_CFM (2 << 12) /**< codec clk slave & FRM master */ -#define SOF_DAI_FMT_CBM_CFS (3 << 12) /**< codec clk master & frame slave */ -#define SOF_DAI_FMT_CBS_CFS (4 << 12) /**< codec clk & FRM slave */ +#define SOF_DAI_FMT_CBP_CFP (0 << 12) /**< codec bclk provider & frame provider */ +#define SOF_DAI_FMT_CBC_CFP (2 << 12) /**< codec bclk consumer & frame provider */ +#define SOF_DAI_FMT_CBP_CFC (3 << 12) /**< codec bclk provider & frame consumer */ +#define SOF_DAI_FMT_CBC_CFC (4 << 12) /**< codec bclk consumer & frame consumer */ + +/* keep old definitions for backwards compatibility */ +#define SOF_DAI_FMT_CBM_CFM SOF_DAI_FMT_CBP_CFP +#define SOF_DAI_FMT_CBS_CFM SOF_DAI_FMT_CBC_CFP +#define SOF_DAI_FMT_CBM_CFS SOF_DAI_FMT_CBP_CFC +#define SOF_DAI_FMT_CBS_CFS SOF_DAI_FMT_CBC_CFC #define SOF_DAI_FMT_FORMAT_MASK 0x000f #define SOF_DAI_FMT_CLOCK_MASK 0x00f0 #define SOF_DAI_FMT_INV_MASK 0x0f00 -#define SOF_DAI_FMT_MASTER_MASK 0xf000 +#define SOF_DAI_FMT_CLOCK_PROVIDER_MASK 0xf000 /** \brief Types of DAI */ enum sof_ipc_dai_type { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d708c640e7b5..430d274722ae 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2777,18 +2777,18 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, struct sof_ipc_dai_config *config) { /* clock directions wrt codec */ - if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CM) { - /* codec is bclk master */ - if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CM) - config->format |= SOF_DAI_FMT_CBM_CFM; + if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) { + /* codec is bclk provider */ + if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP) + config->format |= SOF_DAI_FMT_CBP_CFP; else - config->format |= SOF_DAI_FMT_CBM_CFS; + config->format |= SOF_DAI_FMT_CBP_CFC; } else { - /* codec is bclk slave */ - if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CM) - config->format |= SOF_DAI_FMT_CBS_CFM; + /* codec is bclk consumer */ + if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP) + config->format |= SOF_DAI_FMT_CBC_CFP; else - config->format |= SOF_DAI_FMT_CBS_CFS; + config->format |= SOF_DAI_FMT_CBC_CFC; } /* inverted clocks ? */ -- cgit v1.2.3 From 84b53a366ebc45027e64f2e37001e4e602a93464 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:30:59 -0600 Subject: ASoC: Intel: atom: use inclusive language for SSP bclk/fsync Use 'provider' and 'consumer' terms. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201112163100.5081-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 12 ++++++------ sound/soc/intel/atom/sst-atom-controls.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 6b5a34a15acb..335c32732994 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -827,14 +827,14 @@ static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt) { int format; - format = (fmt & SND_SOC_DAIFMT_MASTER_MASK); + format = (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK); dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); switch (format) { - case SND_SOC_DAIFMT_CBS_CFS: - return SSP_MODE_MASTER; - case SND_SOC_DAIFMT_CBM_CFM: - return SSP_MODE_SLAVE; + case SND_SOC_DAIFMT_CBC_CFC: + return SSP_MODE_PROVIDER; + case SND_SOC_DAIFMT_CBP_CFP: + return SSP_MODE_CONSUMER; default: dev_err(dai->dev, "Invalid ssp protocol: %d\n", format); } @@ -905,7 +905,7 @@ static const struct sst_ssp_config sst_ssp_configs = { .ssp_id = SSP_CODEC, .bits_per_slot = 24, .slots = 4, - .ssp_mode = SSP_MODE_MASTER, + .ssp_mode = SSP_MODE_PROVIDER, .pcm_mode = SSP_PCM_MODE_NETWORK, .duplex = SSP_DUPLEX, .ssp_protocol = SSP_MODE_PCM, diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index 620b48d2a064..23bf37544a8d 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h @@ -439,8 +439,8 @@ struct sst_cmd_tone_stop { } __packed; enum sst_ssp_mode { - SSP_MODE_MASTER = 0, - SSP_MODE_SLAVE = 1, + SSP_MODE_PROVIDER = 0, + SSP_MODE_CONSUMER = 1, }; enum sst_ssp_pcm_mode { -- cgit v1.2.3 From a6e9717a71fd825b6d18a532954d1f9daadcd875 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:31:00 -0600 Subject: ASoC: Intel: keembay: use inclusive language for bclk and fsync Use 'clock provider' and 'clock consumer' terms. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201112163100.5081-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/keembay/kmb_platform.c | 22 +++++++++++----------- sound/soc/intel/keembay/kmb_platform.h | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index f54b710ee1c2..3441e69ced04 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -358,7 +358,7 @@ static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s, kmb_i2s_irq_trigger(kmb_i2s, substream->stream, config->chan_nr, true); - if (kmb_i2s->master) + if (kmb_i2s->clock_provider) writel(1, kmb_i2s->i2s_base + CER); else writel(0, kmb_i2s->i2s_base + CER); @@ -393,13 +393,13 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - kmb_i2s->master = false; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + kmb_i2s->clock_provider = false; ret = 0; break; - case SND_SOC_DAIFMT_CBS_CFS: - writel(MASTER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0); + case SND_SOC_DAIFMT_CBC_CFC: + writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0); ret = clk_prepare_enable(kmb_i2s->clk_i2s); if (ret < 0) @@ -410,7 +410,7 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) if (ret) return ret; - kmb_i2s->master = true; + kmb_i2s->clock_provider = true; break; default: return -EINVAL; @@ -510,7 +510,7 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream, * Platform is not capable of providing clocks for * multi channel audio */ - if (kmb_i2s->master) + if (kmb_i2s->clock_provider) return -EINVAL; write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) | @@ -524,12 +524,12 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream, * Platform is only capable of providing clocks need for * 2 channel master mode */ - if (!(kmb_i2s->master)) + if (!(kmb_i2s->clock_provider)) return -EINVAL; write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) | (config->data_width << DATA_WIDTH_CONFIG_BIT) | - MASTER_MODE | I2S_OPERATION; + CLOCK_PROVIDER_MODE | I2S_OPERATION; writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0); break; @@ -544,7 +544,7 @@ static int kmb_dai_hw_params(struct snd_pcm_substream *substream, config->sample_rate = params_rate(hw_params); - if (kmb_i2s->master) { + if (kmb_i2s->clock_provider) { /* Only 2 ch supported in Master mode */ u32 bitclk = config->sample_rate * config->data_width * 2; diff --git a/sound/soc/intel/keembay/kmb_platform.h b/sound/soc/intel/keembay/kmb_platform.h index 9756b132c12f..0c393e5916b6 100644 --- a/sound/soc/intel/keembay/kmb_platform.h +++ b/sound/soc/intel/keembay/kmb_platform.h @@ -58,7 +58,7 @@ #define PSS_CPR_CLK_CLR 0x000 #define PSS_CPR_AUX_RST_EN 0x070 -#define MASTER_MODE BIT(13) +#define CLOCK_PROVIDER_MODE BIT(13) /* Interrupt Flag */ #define TX_INT_FLAG GENMASK(5, 4) @@ -99,8 +99,8 @@ #define DWC_I2S_PLAY BIT(0) #define DWC_I2S_RECORD BIT(1) -#define DW_I2S_SLAVE BIT(2) -#define DW_I2S_MASTER BIT(3) +#define DW_I2S_CONSUMER BIT(2) +#define DW_I2S_PROVIDER BIT(3) #define I2S_RXDMA 0x01C0 #define I2S_TXDMA 0x01C8 @@ -130,7 +130,7 @@ struct kmb_i2s_info { u32 ccr; u32 xfer_resolution; u32 fifo_th; - bool master; + bool clock_provider; struct i2s_clk_config_data config; int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); -- cgit v1.2.3 From 7416f6bc5fcb1fe6700391c94b59ac1c744ad9d1 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Fri, 13 Nov 2020 13:53:59 +0800 Subject: ASoC: rt5682: Add a new property for the DMIC clock driving The patch adds a new property to set the DMIC clock driving. Signed-off-by: Oder Chiou Link: https://lore.kernel.org/r/20201113055400.11242-1-oder_chiou@realtek.com Signed-off-by: Mark Brown --- include/sound/rt5682.h | 1 + sound/soc/codecs/rt5682-i2c.c | 5 +++++ sound/soc/codecs/rt5682.c | 3 +++ sound/soc/codecs/rt5682.h | 14 ++++++++++++++ 4 files changed, 23 insertions(+) (limited to 'sound') diff --git a/include/sound/rt5682.h b/include/sound/rt5682.h index e1f790561ac1..3900a07e3935 100644 --- a/include/sound/rt5682.h +++ b/include/sound/rt5682.h @@ -40,6 +40,7 @@ struct rt5682_platform_data { unsigned int btndet_delay; unsigned int dmic_clk_rate; unsigned int dmic_delay; + bool dmic_clk_driving_high; const char *dai_clk_names[RT5682_DAI_NUM_CLKS]; }; diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 6b4e0eb30c89..37d13120f5ba 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -221,6 +221,11 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, case RT5682_DMIC1_CLK_GPIO3: /* share with BCLK2 */ regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1, RT5682_GP3_PIN_MASK, RT5682_GP3_PIN_DMIC_CLK); + if (rt5682->pdata.dmic_clk_driving_high) + regmap_update_bits(rt5682->regmap, + RT5682_PAD_DRIVING_CTRL, + RT5682_PAD_DRV_GP3_MASK, + 2 << RT5682_PAD_DRV_GP3_SFT); break; default: diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index a9acce7b6cca..f299b30f4f59 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2989,6 +2989,9 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) rt5682->pdata.dai_clk_names[RT5682_DAI_WCLK_IDX], rt5682->pdata.dai_clk_names[RT5682_DAI_BCLK_IDX]); + rt5682->pdata.dmic_clk_driving_high = device_property_read_bool(dev, + "realtek,dmic-clk-driving-high"); + return 0; } EXPORT_SYMBOL_GPL(rt5682_parse_dt); diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 354acd735ef4..99b85cfe6248 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1271,6 +1271,20 @@ #define RT5682_CP_CLK_HP_300KHZ (0x2 << 4) #define RT5682_CP_CLK_HP_600KHZ (0x3 << 4) +/* Pad Driving Control (0x0136) */ +#define RT5682_PAD_DRV_GP1_MASK (0x3 << 14) +#define RT5682_PAD_DRV_GP1_SFT 14 +#define RT5682_PAD_DRV_GP2_MASK (0x3 << 12) +#define RT5682_PAD_DRV_GP2_SFT 12 +#define RT5682_PAD_DRV_GP3_MASK (0x3 << 10) +#define RT5682_PAD_DRV_GP3_SFT 10 +#define RT5682_PAD_DRV_GP4_MASK (0x3 << 8) +#define RT5682_PAD_DRV_GP4_SFT 8 +#define RT5682_PAD_DRV_GP5_MASK (0x3 << 6) +#define RT5682_PAD_DRV_GP5_SFT 6 +#define RT5682_PAD_DRV_GP6_MASK (0x3 << 4) +#define RT5682_PAD_DRV_GP6_SFT 4 + /* Chopper and Clock control for DAC (0x013a)*/ #define RT5682_CKXEN_DAC1_MASK (0x1 << 13) #define RT5682_CKXEN_DAC1_SFT 13 -- cgit v1.2.3 From 6feaaa7c19bde25595e03bf883953f85711e4ac8 Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Sun, 15 Nov 2020 13:23:03 +0100 Subject: ASoC: pcm512x: Fix not setting word length if DAIFMT_CBS_CFS In `pcm512x_hw_params()`, the following switch-case: ~~~~ switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: ~~~~ returns 0, which was preventing word length from being written into codecs register. Fixed by writing it into register before checking `SND_SOC_DAIFMT_MASTER_MASK`. Tested with Raspberry Pi + sound card `hifiberry_dacplus` in CBS_CFS format Signed-off-by: Kirill Marinushkin Cc: Mark Brown Cc: Takashi Iwai Cc: Liam Girdwood Cc: Matthias Reichl Cc: Kuninori Morimoto Cc: Peter Ujfalusi Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201115122306.18164-2-kmarinushkin@birdec.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 8153d3d01654..db3dc6a40feb 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1195,6 +1195,13 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1, + PCM512x_ALEN, alen); + if (ret != 0) { + dev_err(component->dev, "Failed to set frame size: %d\n", ret); + return ret; + } + switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: ret = regmap_update_bits(pcm512x->regmap, @@ -1229,13 +1236,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1, - PCM512x_ALEN, alen); - if (ret != 0) { - dev_err(component->dev, "Failed to set frame size: %d\n", ret); - return ret; - } - if (pcm512x->pll_out) { ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11); if (ret != 0) { -- cgit v1.2.3 From 798714b6121d833c8abe4161761a94fdd1e73a90 Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Sun, 15 Nov 2020 13:23:04 +0100 Subject: ASoC: pcm512x: Rearrange operations in `hw_params()` This commit is a preparation for the next patch in the series. It's goal is to make format check easy-to-move-out. Theoretically, more butifications are possile in `hw_params()` func, but my intention in this commit is to keep behaviour unchanged. Signed-off-by: Kirill Marinushkin Cc: Mark Brown Cc: Takashi Iwai Cc: Liam Girdwood Cc: Matthias Reichl Cc: Kuninori Morimoto Cc: Peter Ujfalusi Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201115122306.18164-3-kmarinushkin@birdec.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 49 +++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index db3dc6a40feb..aa55a477a28f 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1204,16 +1204,8 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - ret = regmap_update_bits(pcm512x->regmap, - PCM512x_BCLK_LRCLK_CFG, - PCM512x_BCKP - | PCM512x_BCKO | PCM512x_LRKO, - 0); - if (ret != 0) { - dev_err(component->dev, - "Failed to enable slave mode: %d\n", ret); - return ret; - } + clock_output = 0; + master_mode = 0; ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, PCM512x_DCAS, 0); @@ -1223,7 +1215,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, ret); return ret; } - return 0; + goto skip_pll; case SND_SOC_DAIFMT_CBM_CFM: clock_output = PCM512x_BCKO | PCM512x_LRKO; master_mode = PCM512x_RLRK | PCM512x_RBCK; @@ -1316,25 +1308,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, dev_err(component->dev, "Failed to enable pll: %d\n", ret); return ret; } - } - - ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG, - PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO, - clock_output); - if (ret != 0) { - dev_err(component->dev, "Failed to enable clock output: %d\n", ret); - return ret; - } - ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE, - PCM512x_RLRK | PCM512x_RBCK, - master_mode); - if (ret != 0) { - dev_err(component->dev, "Failed to enable master mode: %d\n", ret); - return ret; - } - - if (pcm512x->pll_out) { gpio = PCM512x_G1OE << (pcm512x->pll_out - 1); ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN, gpio, gpio); @@ -1368,6 +1342,23 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, return ret; } +skip_pll: + ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG, + PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO, + clock_output); + if (ret != 0) { + dev_err(component->dev, "Failed to enable clock output: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE, + PCM512x_RLRK | PCM512x_RBCK, + master_mode); + if (ret != 0) { + dev_err(component->dev, "Failed to enable master mode: %d\n", ret); + return ret; + } + return 0; } -- cgit v1.2.3 From 26b97d95a05d0346e1ad6096deedac3f24a4607b Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Sun, 15 Nov 2020 13:23:05 +0100 Subject: ASoC: pcm512x: Move format check into `set_fmt()` I would like to describe the reasoning by quoting Peter Ujfalusi from his review of this patch series v1 [1]: > When you bind a link you will use set_fmt for the two sides to see if > they can agree, that both can support what has been asked. > > The pcm512x driver just saves the fmt and say back to that card: > whatever, I'm fine with it. But runtime during hw_params it can fail due > to unsupported bus format, which it actually acked to be ok. > > This is the difference. > > Sure, some device have constraint based on the fmt towards the hw_params > and it is perfectly OK to do such a checks and rejections or build > rules/constraints based on fmt, but failing hw_params just because > set_fmt did not checked that the bus format is not even supported is not > a nice thing to do. [1] https://patchwork.kernel.org/project/alsa-devel/patch/ 20201109212133.25869-1-kmarinushkin@birdec.com/ Signed-off-by: Kirill Marinushkin Cc: Mark Brown Cc: Takashi Iwai Cc: Liam Girdwood Cc: Matthias Reichl Cc: Kuninori Morimoto Cc: Peter Ujfalusi Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201115122306.18164-4-kmarinushkin@birdec.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 55 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index aa55a477a28f..22ef77955a28 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1168,8 +1168,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); int alen; int gpio; - int clock_output; - int master_mode; int ret; dev_dbg(component->dev, "hw_params %u Hz, %u channels\n", @@ -1202,11 +1200,8 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, return ret; } - switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - clock_output = 0; - master_mode = 0; - + if ((pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) == + SND_SOC_DAIFMT_CBS_CFS) { ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, PCM512x_DCAS, 0); if (ret != 0) { @@ -1216,16 +1211,6 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, return ret; } goto skip_pll; - case SND_SOC_DAIFMT_CBM_CFM: - clock_output = PCM512x_BCKO | PCM512x_LRKO; - master_mode = PCM512x_RLRK | PCM512x_RBCK; - break; - case SND_SOC_DAIFMT_CBM_CFS: - clock_output = PCM512x_BCKO; - master_mode = PCM512x_RBCK; - break; - default: - return -EINVAL; } if (pcm512x->pll_out) { @@ -1343,6 +1328,34 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, } skip_pll: + return 0; +} + +static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + int clock_output; + int master_mode; + int ret; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + clock_output = 0; + master_mode = 0; + break; + case SND_SOC_DAIFMT_CBM_CFM: + clock_output = PCM512x_BCKO | PCM512x_LRKO; + master_mode = PCM512x_RLRK | PCM512x_RBCK; + break; + case SND_SOC_DAIFMT_CBM_CFS: + clock_output = PCM512x_BCKO; + master_mode = PCM512x_RBCK; + break; + default: + return -EINVAL; + } + ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG, PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO, clock_output); @@ -1359,14 +1372,6 @@ skip_pll: return ret; } - return 0; -} - -static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct snd_soc_component *component = dai->component; - struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); - pcm512x->fmt = fmt; return 0; -- cgit v1.2.3 From 25d27c4f68d2040c4772d586be3e02ee99eb71af Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Sun, 15 Nov 2020 13:23:06 +0100 Subject: ASoC: pcm512x: Add support for more data formats Currently, pcm512x driver supports only I2S data format. This commit adds RJ, LJ, DSP_A and DSP_B as well. I don't expect regression WRT existing sound cards, because: * default value in corresponding register of pcm512x codec is 0 == I2S * existing in-tree sound cards with pcm512x codec are configured for I2S * i don't see how existing off-tree sound cards with pcm512x codec could be configured differently - it would not work * tested explicitly, that there is no regression with Raspberry Pi + sound card `sound/soc/bcm/hifiberry_dacplus.c` Signed-off-by: Kirill Marinushkin Cc: Mark Brown Cc: Takashi Iwai Cc: Liam Girdwood Cc: Matthias Reichl Cc: Kuninori Morimoto Cc: Peter Ujfalusi Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20201115122306.18164-5-kmarinushkin@birdec.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 22ef77955a28..4dc844f3c1fc 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1335,6 +1335,8 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + int afmt; + int offset = 0; int clock_output; int master_mode; int ret; @@ -1372,6 +1374,42 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return ret; } + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + afmt = PCM512x_AFMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + afmt = PCM512x_AFMT_RTJ; + break; + case SND_SOC_DAIFMT_LEFT_J: + afmt = PCM512x_AFMT_LTJ; + break; + case SND_SOC_DAIFMT_DSP_A: + offset = 1; + fallthrough; + case SND_SOC_DAIFMT_DSP_B: + afmt = PCM512x_AFMT_DSP; + break; + default: + dev_err(component->dev, "unsupported DAI format: 0x%x\n", + pcm512x->fmt); + return -EINVAL; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1, + PCM512x_AFMT, afmt); + if (ret != 0) { + dev_err(component->dev, "Failed to set data format: %d\n", ret); + return ret; + } + + ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_2, + 0xFF, offset); + if (ret != 0) { + dev_err(component->dev, "Failed to set data offset: %d\n", ret); + return ret; + } + pcm512x->fmt = fmt; return 0; -- cgit v1.2.3 From 768a3a3b327da88c2fa6856806d32852a90e75d5 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 16 Nov 2020 14:33:30 +0100 Subject: ASoC: Intel: catpt: Optimize applying user settings Initial user settings such as volume control need to be applied only once after stream is allocated. As prepare() operation can be invoked multiple times during the stream's lifetime, relocate catpt_dai_apply_usettings() and call it directly within catpt_dai_hw_params() rather than on every catpt_dai_prepare(). catpt_dai_apply_usettings() remains unchanged. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201116133332.8530-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/pcm.c | 104 ++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 52 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 2061978b6cb9..52f63131209d 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -324,6 +324,54 @@ static void catpt_dai_shutdown(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, NULL); } +static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol); + +static int catpt_dai_apply_usettings(struct snd_soc_dai *dai, + struct catpt_stream_runtime *stream) +{ + struct catpt_dev *cdev = dev_get_drvdata(dai->dev); + struct snd_soc_component *component = dai->component; + struct snd_kcontrol *pos, *kctl = NULL; + const char *name; + int ret; + u32 id = stream->info.stream_hw_id; + + /* only selected streams have individual controls */ + switch (id) { + case CATPT_PIN_ID_OFFLOAD1: + name = "Media0 Playback Volume"; + break; + case CATPT_PIN_ID_OFFLOAD2: + name = "Media1 Playback Volume"; + break; + case CATPT_PIN_ID_CAPTURE1: + name = "Mic Capture Volume"; + break; + case CATPT_PIN_ID_REFERENCE: + name = "Loopback Mute"; + break; + default: + return 0; + }; + + list_for_each_entry(pos, &component->card->snd_card->controls, list) { + if (pos->private_data == component && + !strncmp(name, pos->id.name, sizeof(pos->id.name))) { + kctl = pos; + break; + } + } + if (!kctl) + return -ENOENT; + + if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK) + return catpt_set_dspvol(cdev, id, (long *)kctl->private_value); + ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value); + if (ret) + return CATPT_IPC_ERROR(ret); + return 0; +} + static int catpt_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -370,6 +418,10 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, if (ret) return CATPT_IPC_ERROR(ret); + ret = catpt_dai_apply_usettings(dai, stream); + if (ret) + return ret; + stream->allocated = true; return 0; } @@ -391,54 +443,6 @@ static int catpt_dai_hw_free(struct snd_pcm_substream *substream, return 0; } -static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol); - -static int catpt_dai_apply_usettings(struct snd_soc_dai *dai, - struct catpt_stream_runtime *stream) -{ - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); - struct snd_soc_component *component = dai->component; - struct snd_kcontrol *pos, *kctl = NULL; - const char *name; - int ret; - u32 id = stream->info.stream_hw_id; - - /* only selected streams have individual controls */ - switch (id) { - case CATPT_PIN_ID_OFFLOAD1: - name = "Media0 Playback Volume"; - break; - case CATPT_PIN_ID_OFFLOAD2: - name = "Media1 Playback Volume"; - break; - case CATPT_PIN_ID_CAPTURE1: - name = "Mic Capture Volume"; - break; - case CATPT_PIN_ID_REFERENCE: - name = "Loopback Mute"; - break; - default: - return 0; - }; - - list_for_each_entry(pos, &component->card->snd_card->controls, list) { - if (pos->private_data == component && - !strncmp(name, pos->id.name, sizeof(pos->id.name))) { - kctl = pos; - break; - } - } - if (!kctl) - return -ENOENT; - - if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK) - return catpt_set_dspvol(cdev, id, (long *)kctl->private_value); - ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value); - if (ret) - return CATPT_IPC_ERROR(ret); - return 0; -} - static int catpt_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -458,10 +462,6 @@ static int catpt_dai_prepare(struct snd_pcm_substream *substream, if (ret) return CATPT_IPC_ERROR(ret); - ret = catpt_dai_apply_usettings(dai, stream); - if (ret) - return ret; - stream->prepared = true; return 0; } -- cgit v1.2.3 From c440c72474e12fcf79bbe716d4796d16b7201031 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 16 Nov 2020 14:33:31 +0100 Subject: ASoC: Intel: catpt: Streamline power routines across LPT and WPT There is no need for separate power on/off routines for LPT and WPT as as the protocol is shared for both platforms. Make WPT routines generic and reuse them in LPT case too. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201116133332.8530-5-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/core.h | 6 ++++-- sound/soc/intel/catpt/device.c | 18 +++++++++--------- sound/soc/intel/catpt/dsp.c | 10 +++++----- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h index 88dc3fb6306f..693dc4a4b621 100644 --- a/sound/soc/intel/catpt/core.h +++ b/sound/soc/intel/catpt/core.h @@ -80,6 +80,8 @@ struct catpt_spec { u32 host_ssp_offset[CATPT_SSP_COUNT]; u32 dram_mask; u32 iram_mask; + u32 d3srampgd_bit; + u32 d3pgd_bit; void (*pll_shutdown)(struct catpt_dev *cdev, bool enable); int (*power_up)(struct catpt_dev *cdev); int (*power_down)(struct catpt_dev *cdev); @@ -128,8 +130,8 @@ void lpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable); void wpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable); int lpt_dsp_power_up(struct catpt_dev *cdev); int lpt_dsp_power_down(struct catpt_dev *cdev); -int wpt_dsp_power_up(struct catpt_dev *cdev); -int wpt_dsp_power_down(struct catpt_dev *cdev); +int catpt_dsp_power_up(struct catpt_dev *cdev); +int catpt_dsp_power_down(struct catpt_dev *cdev); int catpt_dsp_stall(struct catpt_dev *cdev, bool stall); void catpt_dsp_update_srampge(struct catpt_dev *cdev, struct resource *sram, unsigned long mask); diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index a70179959795..b1d380868d8c 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -69,7 +69,7 @@ release_dma_chan: dma_release_channel(chan); if (ret) return ret; - return cdev->spec->power_down(cdev); + return catpt_dsp_power_down(cdev); } static int __maybe_unused catpt_resume(struct device *dev) @@ -77,7 +77,7 @@ static int __maybe_unused catpt_resume(struct device *dev) struct catpt_dev *cdev = dev_get_drvdata(dev); int ret, i; - ret = cdev->spec->power_up(cdev); + ret = catpt_dsp_power_up(cdev); if (ret) return ret; @@ -162,7 +162,7 @@ static int catpt_probe_components(struct catpt_dev *cdev) { int ret; - ret = cdev->spec->power_up(cdev); + ret = catpt_dsp_power_up(cdev); if (ret) return ret; @@ -204,7 +204,7 @@ err_reg_board: err_boot_fw: catpt_dmac_remove(cdev); err_dmac_probe: - cdev->spec->power_down(cdev); + catpt_dsp_power_down(cdev); return ret; } @@ -293,7 +293,7 @@ static int catpt_acpi_remove(struct platform_device *pdev) snd_soc_unregister_component(cdev->dev); catpt_dmac_remove(cdev); - cdev->spec->power_down(cdev); + catpt_dsp_power_down(cdev); catpt_sram_free(&cdev->iram); catpt_sram_free(&cdev->dram); @@ -311,9 +311,9 @@ static struct catpt_spec lpt_desc = { .host_ssp_offset = { 0x0E8000, 0x0E9000 }, .dram_mask = LPT_VDRTCTL0_DSRAMPGE_MASK, .iram_mask = LPT_VDRTCTL0_ISRAMPGE_MASK, + .d3srampgd_bit = LPT_VDRTCTL0_D3SRAMPGD, + .d3pgd_bit = LPT_VDRTCTL0_D3PGD, .pll_shutdown = lpt_dsp_pll_shutdown, - .power_up = lpt_dsp_power_up, - .power_down = lpt_dsp_power_down, }; static struct catpt_spec wpt_desc = { @@ -326,9 +326,9 @@ static struct catpt_spec wpt_desc = { .host_ssp_offset = { 0x0FC000, 0x0FD000 }, .dram_mask = WPT_VDRTCTL0_DSRAMPGE_MASK, .iram_mask = WPT_VDRTCTL0_ISRAMPGE_MASK, + .d3srampgd_bit = WPT_VDRTCTL0_D3SRAMPGD, + .d3pgd_bit = WPT_VDRTCTL0_D3PGD, .pll_shutdown = wpt_dsp_pll_shutdown, - .power_up = wpt_dsp_power_up, - .power_down = wpt_dsp_power_down, }; static const struct acpi_device_id catpt_ids[] = { diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c index 7d2968571951..aee72b97a046 100644 --- a/sound/soc/intel/catpt/dsp.c +++ b/sound/soc/intel/catpt/dsp.c @@ -387,7 +387,7 @@ int lpt_dsp_power_up(struct catpt_dev *cdev) return 0; } -int wpt_dsp_power_down(struct catpt_dev *cdev) +int catpt_dsp_power_down(struct catpt_dev *cdev) { u32 mask, val; @@ -417,8 +417,8 @@ int wpt_dsp_power_down(struct catpt_dev *cdev) cdev->spec->dram_mask); catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, cdev->spec->iram_mask); - mask = WPT_VDRTCTL0_D3SRAMPGD | WPT_VDRTCTL0_D3PGD; - catpt_updatel_pci(cdev, VDRTCTL0, mask, WPT_VDRTCTL0_D3PGD); + mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit; + catpt_updatel_pci(cdev, VDRTCTL0, mask, cdev->spec->d3pgd_bit); catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot); /* give hw time to drop off */ @@ -432,7 +432,7 @@ int wpt_dsp_power_down(struct catpt_dev *cdev) return 0; } -int wpt_dsp_power_up(struct catpt_dev *cdev) +int catpt_dsp_power_up(struct catpt_dev *cdev) { u32 mask, val; @@ -447,7 +447,7 @@ int wpt_dsp_power_up(struct catpt_dev *cdev) catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0); /* SRAM power gating none */ - mask = WPT_VDRTCTL0_D3SRAMPGD | WPT_VDRTCTL0_D3PGD; + mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit; catpt_updatel_pci(cdev, VDRTCTL0, mask, mask); catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0); catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0); -- cgit v1.2.3 From 3d32489838bbf3119bb1ea59cdbed0077d7dbf3c Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 16 Nov 2020 14:33:32 +0100 Subject: ASoC: Intel: catpt: Cleanup after power routines streamlining With LPT switching to WPT-based power on/off routines, functions that have been previously used by it are rendered redundant so remove them. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201116133332.8530-6-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/core.h | 4 ---- sound/soc/intel/catpt/dsp.c | 46 -------------------------------------------- 2 files changed, 50 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h index 693dc4a4b621..0f53a0d43254 100644 --- a/sound/soc/intel/catpt/core.h +++ b/sound/soc/intel/catpt/core.h @@ -83,8 +83,6 @@ struct catpt_spec { u32 d3srampgd_bit; u32 d3pgd_bit; void (*pll_shutdown)(struct catpt_dev *cdev, bool enable); - int (*power_up)(struct catpt_dev *cdev); - int (*power_down)(struct catpt_dev *cdev); }; struct catpt_dev { @@ -128,8 +126,6 @@ int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan, void lpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable); void wpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable); -int lpt_dsp_power_up(struct catpt_dev *cdev); -int lpt_dsp_power_down(struct catpt_dev *cdev); int catpt_dsp_power_up(struct catpt_dev *cdev); int catpt_dsp_power_down(struct catpt_dev *cdev); int catpt_dsp_stall(struct catpt_dev *cdev, bool stall); diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c index aee72b97a046..6ac69c58c059 100644 --- a/sound/soc/intel/catpt/dsp.c +++ b/sound/soc/intel/catpt/dsp.c @@ -341,52 +341,6 @@ static void catpt_dsp_set_regs_defaults(struct catpt_dev *cdev) } } -int lpt_dsp_power_down(struct catpt_dev *cdev) -{ - catpt_dsp_reset(cdev, true); - - /* set 24Mhz clock for both SSPs */ - catpt_updatel_shim(cdev, CS1, CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1), - CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1)); - catpt_dsp_select_lpclock(cdev, true, false); - - /* DRAM power gating all */ - catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, - cdev->spec->dram_mask); - catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, - cdev->spec->iram_mask); - - catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot); - /* give hw time to drop off */ - udelay(50); - - return 0; -} - -int lpt_dsp_power_up(struct catpt_dev *cdev) -{ - /* SRAM power gating none */ - catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0); - catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0); - - catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0); - /* give hw time to wake up */ - udelay(100); - - catpt_dsp_select_lpclock(cdev, false, false); - catpt_updatel_shim(cdev, CS1, - CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1), - CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1)); - /* stagger DSP reset after clock selection */ - udelay(50); - - catpt_dsp_reset(cdev, false); - /* generate int deassert msg to fix inversed int logic */ - catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB | CATPT_IMC_IPCCD, 0); - - return 0; -} - int catpt_dsp_power_down(struct catpt_dev *cdev) { u32 mask, val; -- cgit v1.2.3 From 7141f25f14e03a0b049ffb2010b12abf652a10f3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 16 Nov 2020 15:59:50 +0300 Subject: ASoC: qcom: sc7180: initialize the "no_headphone" variable The "no_headphone" variable is never set to "false" so it could be uninitialized. Fixes: e936619b7ce7 ("ASoC: qcom: sc7180: Modify machine driver for sound card") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/20201116125950.GA44063@mwanda Signed-off-by: Mark Brown --- sound/soc/qcom/sc7180.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index e2e6567566af..de70fa792aea 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -316,7 +316,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) struct snd_soc_dai_link *link; int ret; int i; - bool no_headphone; + bool no_headphone = false; /* Allocate the private data */ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -- cgit v1.2.3 From 299fe9937dbd1a4d9a1da6a2b6f222298534ca57 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 16 Nov 2020 18:24:23 +0100 Subject: ASoC: meson: fix COMPILE_TEST error When compiled with CONFIG_HAVE_CLK, the kernel need to get provider for the clock API. This is usually selected by the platform and the sound drivers should not really care about this. However COMPILE_TEST is special and the platform required may not have been selected, leading to this type of error: > aiu-encoder-spdif.c:(.text+0x3a0): undefined reference to `clk_set_parent' Since we need a sane provider of the API with COMPILE_TEST, depends on COMMON_CLK. Fixes: 6dc4fa179fb8 ("ASoC: meson: add axg fifo base driver") Reported-by: kernel test robot Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20201116172423.546855-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 363dc3b1bbe4..ce0cbdc69b2e 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "ASoC support for Amlogic platforms" - depends on ARCH_MESON || COMPILE_TEST + depends on ARCH_MESON || (COMPILE_TEST && COMMON_CLK) config SND_MESON_AIU tristate "Amlogic AIU" -- cgit v1.2.3 From 6c2b6bb0d34319ea8390dc8b46465332b1dae025 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 16 Nov 2020 16:26:42 +0200 Subject: ASoC: SOF: Intel: initial support for Alderlake-S Add Kconfig entries, PCI ID and chip info for Alderlake-S product. Signed-off-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201116142642.2106067-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/intel/tgl.c | 16 ++++++++++++++++ sound/soc/sof/sof-pci-dev.c | 21 +++++++++++++++++++++ 4 files changed, 54 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index b233302f05e4..b607dba5fb2a 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -29,6 +29,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT select SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_JASPERLAKE_SUPPORT + select SND_SOC_SOF_ALDERLAKE if SND_SOC_SOF_ALDERLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level. @@ -269,6 +270,21 @@ config SND_SOC_SOF_JASPERLAKE This option is not user-selectable but automagically handled by 'select' statements at a higher level. +config SND_SOC_SOF_ALDERLAKE_SUPPORT + bool "SOF support for Alderlake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Alderlake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_ALDERLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate select SND_INTEL_DSP_CONFIG diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 1bc4dabdd394..75954e642c5e 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -742,6 +742,7 @@ extern const struct sof_intel_dsp_desc tgl_chip_info; extern const struct sof_intel_dsp_desc tglh_chip_info; extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; +extern const struct sof_intel_dsp_desc adls_chip_info; /* machine driver select */ void hda_machine_select(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 0278b67de1ec..bdcc66d0df78 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -151,3 +151,19 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); + +const struct sof_intel_dsp_desc adls_chip_info = { + /* Alderlake-S */ + .cores_num = 2, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 8f62e3487dc1..f2a107481336 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -284,6 +284,23 @@ static const struct sof_dev_desc jsl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) +static const struct sof_dev_desc adls_desc = { + .machines = snd_soc_acpi_intel_hda_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &adls_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-adl-s.ri", + .nocodec_tplg_filename = "sof-adl-nocodec.tplg", + .ops = &sof_tgl_ops, +}; +#endif + static const struct dev_pm_ops sof_pci_pm = { .prepare = snd_sof_prepare, .complete = snd_sof_complete, @@ -490,6 +507,10 @@ static const struct pci_device_id sof_pci_ids[] = { .driver_data = (unsigned long)&ehl_desc}, { PCI_DEVICE(0x8086, 0x4b58), .driver_data = (unsigned long)&ehl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) + { PCI_DEVICE(0x8086, 0x7ad0), + .driver_data = (unsigned long)&adls_desc}, #endif { 0, } }; -- cgit v1.2.3 From 313ebec48dedcac351557b5a84b8b2239951c238 Mon Sep 17 00:00:00 2001 From: V Sujith Kumar Reddy Date: Mon, 16 Nov 2020 13:19:15 +0530 Subject: ASoC: qcom: lpass-sc7180: Add 32 bit format support for capture Add 32 bit format support for capture in lpass-sc7180 snd_soc_dai_driver capabilities. Need to add contstraints in machine driver so that only specific format allowed. Signed-off-by: V Sujith Kumar Reddy Signed-off-by: Srinivasa Rao Manidadapu Link: https://lore.kernel.org/r/1605512955-7017-1-git-send-email-srivasam@codeaurora.org Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-sc7180.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 61a208fe6875..da1d051622fb 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -34,7 +34,8 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { }, .capture = { .stream_name = "Primary Capture", - .formats = SNDRV_PCM_FMTBIT_S16, + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S32, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, -- cgit v1.2.3 From 60a973862f3c41bc8d4b7a74bd45eda220e248e8 Mon Sep 17 00:00:00 2001 From: V Sujith Kumar Reddy Date: Sat, 14 Nov 2020 00:08:22 +0530 Subject: ASoC: qcom: sc7180: Register shutdown handler for lpass platform Register shutdown handler to stop sc7180 lpass platform driver and to disable audio clocks. Signed-off-by: V Sujith Kumar Reddy Signed-off-by: Srinivasa Rao Mandadapu Link: https://lore.kernel.org/r/1605292702-25046-1-git-send-email-srivasam@codeaurora.org Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 10 ++++++++++ sound/soc/qcom/lpass-sc7180.c | 1 + sound/soc/qcom/lpass.h | 1 + 3 files changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 0c64deaf9374..0d9ff23d7463 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -908,5 +908,15 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove); +void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + + if (drvdata->variant->exit) + drvdata->variant->exit(pdev); + +} +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown); + MODULE_DESCRIPTION("QTi LPASS CPU Driver"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index da1d051622fb..238069e293bf 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -298,6 +298,7 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = { }, .probe = asoc_qcom_lpass_cpu_platform_probe, .remove = asoc_qcom_lpass_cpu_platform_remove, + .shutdown = asoc_qcom_lpass_cpu_platform_shutdown, }; module_platform_driver(sc7180_lpass_cpu_platform_driver); diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index b4830f353796..32a68c4fc238 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -255,6 +255,7 @@ struct lpass_variant { /* register the platform driver from the CPU DAI driver */ int asoc_qcom_lpass_platform_register(struct platform_device *); int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); +void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; -- cgit v1.2.3 From e1ade4c55ae3559b082faf9f5207cc6caba1c546 Mon Sep 17 00:00:00 2001 From: Bogdan Togorean Date: Tue, 10 Nov 2020 17:22:13 +0200 Subject: ASoc: adi: Kconfig: Remove depends on for ADI reference designs Audio ADI reference designs are also used on some ZynqMP boards, and can also be used on Intel FPGA boards and also on some more complex FPGA combinations (FPGA cards connected through PCIe). This change removes the dependency on Microblaze and Zynq architectures to allow the usage of this driver for the systems described above. Signed-off-by: Bogdan Togorean Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201110152213.37811-1-alexandru.ardelean@analog.com Signed-off-by: Mark Brown --- sound/soc/adi/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/adi/Kconfig b/sound/soc/adi/Kconfig index e321e3b672da..0236dc5b4e9f 100644 --- a/sound/soc/adi/Kconfig +++ b/sound/soc/adi/Kconfig @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config SND_SOC_ADI tristate "Audio support for Analog Devices reference designs" - depends on MICROBLAZE || ARCH_ZYNQ || COMPILE_TEST help Audio support for various reference designs by Analog Devices. -- cgit v1.2.3 From 674226db62ec758c4575bcdb933a2410f1a29bbf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Nov 2020 15:51:20 +0100 Subject: ASoC: fsl: SND_SOC_FSL_AUD2HTX should depend on ARCH_MXC The Freescale/NXP AUDIO TO HDMI TX module is only present on NXP i.MX 8 Series SoCs. Hence add a dependency on ARCH_MXC, to prevent asking the user about this driver when configuring a kernel without i.MX 8 platform support. Fixes: 8a24c834c053ef1b ("ASoC: fsl_aud2htx: Add aud2htx module driver") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20201110145120.3280658-1-geert+renesas@glider.be Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index a299f61e529e..06a2d225d644 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -107,6 +107,7 @@ config SND_SOC_FSL_XCVR config SND_SOC_FSL_AUD2HTX tristate "AUDIO TO HDMI TX module support" + depends on CONFIG_ARCH_MXC || COMPILE_TEST help Say Y if you want to add AUDIO TO HDMI TX support for NXP. -- cgit v1.2.3 From 9a207228bdf0a4933b794c944d7111564353ea94 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Nov 2020 15:50:01 +0100 Subject: ASoC: intel: SND_SOC_INTEL_KEEMBAY should depend on ARCH_KEEMBAY The Intel Keem Bay audio module is only present on Intel Keem Bay SoCs. Hence add a dependency on ARCH_KEEMBAY, to prevent asking the user about this driver when configuring a kernel without Intel Keem Bay platform support. Fixes: c544912bcc2dc806 ("ASoC: Intel: Add makefiles and kconfig changes for KeemBay") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20201110145001.3280479-1-geert+renesas@glider.be Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a5b446d5af19..c1bf69a0bcfe 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -198,7 +198,7 @@ endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_INTEL_KEEMBAY tristate "Keembay Platforms" - depends on ARM64 || COMPILE_TEST + depends on ARCH_KEEMBAY || COMPILE_TEST depends on COMMON_CLK help If you have a Intel Keembay platform then enable this option -- cgit v1.2.3 From 5268e0bf7123c422892fec362f5be2bcae9bbb95 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Nov 2020 18:49:04 +0100 Subject: ASoC: Fix 7/8 spaces indentation in Kconfig Some entries used 7 or 8 spaces instead if a single TAB. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20201110174904.3413846-1-geert@linux-m68k.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 18 +++++++++--------- sound/soc/generic/Kconfig | 2 +- sound/soc/intel/boards/Kconfig | 2 +- sound/soc/meson/Kconfig | 2 +- sound/soc/pxa/Kconfig | 14 +++++++------- 5 files changed, 19 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 2b6eceb3573c..b4ca5208fed6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -518,7 +518,7 @@ config SND_SOC_AK5558 select REGMAP_I2C config SND_SOC_ALC5623 - tristate "Realtek ALC5623 CODEC" + tristate "Realtek ALC5623 CODEC" depends on I2C config SND_SOC_ALC5632 @@ -729,7 +729,7 @@ config SND_SOC_JZ4770_CODEC will be called snd-soc-jz4770-codec. config SND_SOC_L3 - tristate + tristate config SND_SOC_DA7210 tristate @@ -769,10 +769,10 @@ config SND_SOC_HDMI_CODEC select HDMI config SND_SOC_ES7134 - tristate "Everest Semi ES7134 CODEC" + tristate "Everest Semi ES7134 CODEC" config SND_SOC_ES7241 - tristate "Everest Semi ES7241 CODEC" + tristate "Everest Semi ES7241 CODEC" config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" @@ -971,10 +971,10 @@ config SND_SOC_PCM186X_SPI select REGMAP_SPI config SND_SOC_PCM3008 - tristate + tristate config SND_SOC_PCM3060 - tristate + tristate config SND_SOC_PCM3060_I2C tristate "Texas Instruments PCM3060 CODEC - I2C" @@ -1437,7 +1437,7 @@ config SND_SOC_UDA1334 rate) and mute. config SND_SOC_UDA134X - tristate + tristate config SND_SOC_UDA1380 tristate @@ -1766,8 +1766,8 @@ config SND_SOC_NAU8315 depends on GPIOLIB config SND_SOC_NAU8540 - tristate "Nuvoton Technology Corporation NAU85L40 CODEC" - depends on I2C + tristate "Nuvoton Technology Corporation NAU85L40 CODEC" + depends on I2C config SND_SOC_NAU8810 tristate "Nuvoton Technology Corporation NAU88C10 CODEC" diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index a90c3b28bce5..4cafcf0e2bbf 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config SND_SIMPLE_CARD_UTILS - tristate + tristate config SND_SIMPLE_CARD tristate "ASoC Simple sound card support" diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index c10c37803c67..dddb672a6d55 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -552,7 +552,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT5682_SDW select SND_SOC_DMIC - help + help Add support for Intel SoundWire-based platforms connected to MAX98373, RT700, RT711, RT1308 and RT715 If unsure select "N". diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index ce0cbdc69b2e..b93ea33739f2 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -98,7 +98,7 @@ config SND_MESON_AXG_PDM in the Amlogic AXG SoC family config SND_MESON_CARD_UTILS - tristate + tristate config SND_MESON_CODEC_GLUE tristate diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 0ac85eada75c..9d40e8a206d1 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -221,13 +221,13 @@ config SND_PXA2XX_SOC_MIOA701 MIO A701. config SND_PXA2XX_SOC_IMOTE2 - tristate "SoC Audio support for IMote 2" - depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 && I2C - select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8940 - help - Say Y if you want to add support for SoC audio on the - IMote 2. + tristate "SoC Audio support for IMote 2" + depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 && I2C + select SND_PXA2XX_SOC_I2S + select SND_SOC_WM8940 + help + Say Y if you want to add support for SoC audio on the + IMote 2. config SND_MMP_SOC_BROWNSTONE tristate "SoC Audio support for Marvell Brownstone" -- cgit v1.2.3 From a4e427c59a266dc3eb0eb5d52879b067a6f6e73b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:15:20 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_open() component related function should be implemented at soc-component.c. This patch moves soc-compress soc_compr_components_open() to soc-component as snd_soc_component_compr_open(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87ft5d7v7x.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 23 +++++++++++++++++++++++ sound/soc/soc-compress.c | 31 ++----------------------------- 3 files changed, 27 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 21f1d120b68e..0d79a0b30aba 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -444,6 +444,8 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, struct of_phandle_args *args, const char **dai_name); +int snd_soc_component_compr_open(struct snd_compr_stream *cstream, + struct snd_soc_component **last); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 6d719c2db92e..a711bee11712 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -421,6 +421,29 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); #endif +int snd_soc_component_compr_open(struct snd_compr_stream *cstream, + struct snd_soc_component **last) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret; + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->open) { + ret = component->driver->compress_ops->open(component, cstream); + if (ret < 0) { + *last = component; + return soc_component_ret(component, ret); + } + } + } + + *last = NULL; + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_open); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index c7ad52a21a29..d55ea0db7901 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -22,33 +22,6 @@ #include #include -static int soc_compr_components_open(struct snd_compr_stream *cstream, - struct snd_soc_component **last) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret; - - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->open) - continue; - - ret = component->driver->compress_ops->open(component, cstream); - if (ret < 0) { - dev_err(component->dev, - "Compress ASoC: can't open platform %s: %d\n", - component->name, ret); - - *last = component; - return ret; - } - } - - *last = NULL; - return 0; -} - static int soc_compr_components_free(struct snd_compr_stream *cstream, struct snd_soc_component *last) { @@ -88,7 +61,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) if (ret < 0) goto out; - ret = soc_compr_components_open(cstream, &component); + ret = snd_soc_component_compr_open(cstream, &component); if (ret < 0) goto machine_err; @@ -156,7 +129,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) if (ret < 0) goto out; - ret = soc_compr_components_open(cstream, &component); + ret = snd_soc_component_compr_open(cstream, &component); if (ret < 0) goto open_err; -- cgit v1.2.3 From dbde5e21140cd2ad9d9e8eeeb104755f5294ce9f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:15:26 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_free() component related function should be implemented at soc-component.c. This patch moves soc-compress soc_compr_components_free() to soc-component as snd_soc_component_compr_free(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87eekx7v7r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 18 ++++++++++++++++++ sound/soc/soc-compress.c | 29 ++++------------------------- 3 files changed, 24 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 0d79a0b30aba..1b2ed4a463b2 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -446,6 +446,8 @@ int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, const char **dai_name); int snd_soc_component_compr_open(struct snd_compr_stream *cstream, struct snd_soc_component **last); +void snd_soc_component_compr_free(struct snd_compr_stream *cstream, + struct snd_soc_component *last); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index a711bee11712..5dcbdfe411f6 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -444,6 +444,24 @@ int snd_soc_component_compr_open(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_open); +void snd_soc_component_compr_free(struct snd_compr_stream *cstream, + struct snd_soc_component *last) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i; + + for_each_rtd_components(rtd, i, component) { + if (component == last) + break; + + if (component->driver->compress_ops && + component->driver->compress_ops->free) + component->driver->compress_ops->free(component, cstream); + } +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_free); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d55ea0db7901..4517baf0e62c 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -22,27 +22,6 @@ #include #include -static int soc_compr_components_free(struct snd_compr_stream *cstream, - struct snd_soc_component *last) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i; - - for_each_rtd_components(rtd, i, component) { - if (component == last) - break; - - if (!component->driver->compress_ops || - !component->driver->compress_ops->free) - continue; - - component->driver->compress_ops->free(component, cstream); - } - - return 0; -} - static int soc_compr_open(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -76,7 +55,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) return 0; machine_err: - soc_compr_components_free(cstream, component); + snd_soc_component_compr_free(cstream, component); snd_soc_dai_compr_shutdown(cpu_dai, cstream); out: @@ -150,7 +129,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) return 0; machine_err: - soc_compr_components_free(cstream, component); + snd_soc_component_compr_free(cstream, component); open_err: snd_soc_dai_compr_shutdown(cpu_dai, cstream); out: @@ -182,7 +161,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) snd_soc_link_compr_shutdown(cstream); - soc_compr_components_free(cstream, NULL); + snd_soc_component_compr_free(cstream, NULL); snd_soc_dai_compr_shutdown(cpu_dai, cstream); @@ -230,7 +209,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) snd_soc_link_compr_shutdown(cstream); - soc_compr_components_free(cstream, NULL); + snd_soc_component_compr_free(cstream, NULL); snd_soc_dai_compr_shutdown(cpu_dai, cstream); -- cgit v1.2.3 From 08aee25114426ba988ccb27af057dcf7faaa61ac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:15:33 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_trigger() component related function should be implemented at soc-component.c. This patch moves soc-compress soc_compr_components_trigger() to soc-component as snd_soc_component_compr_trigger(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87d00h7v7k.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 20 ++++++++++++++++++++ sound/soc/soc-compress.c | 27 +++------------------------ 3 files changed, 24 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 1b2ed4a463b2..6cb4a6a0bc39 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -448,6 +448,7 @@ int snd_soc_component_compr_open(struct snd_compr_stream *cstream, struct snd_soc_component **last); void snd_soc_component_compr_free(struct snd_compr_stream *cstream, struct snd_soc_component *last); +int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 5dcbdfe411f6..cf34545f4108 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -462,6 +462,26 @@ void snd_soc_component_compr_free(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_free); +int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret; + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->trigger) { + ret = component->driver->compress_ops->trigger( + component, cstream, cmd); + if (ret < 0) + return soc_component_ret(component, ret); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_trigger); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 4517baf0e62c..d85bd1d1c119 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -217,27 +217,6 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) return 0; } -static int soc_compr_components_trigger(struct snd_compr_stream *cstream, - int cmd) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret; - - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->trigger) - continue; - - ret = component->driver->compress_ops->trigger( - component, cstream, cmd); - if (ret < 0) - return ret; - } - - return 0; -} - static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -248,7 +227,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - ret = soc_compr_components_trigger(cstream, cmd); + ret = snd_soc_component_compr_trigger(cstream, cmd); if (ret < 0) goto out; @@ -279,7 +258,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || cmd == SND_COMPR_TRIGGER_DRAIN) - return soc_compr_components_trigger(cstream, cmd); + return snd_soc_component_compr_trigger(cstream, cmd); mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); @@ -287,7 +266,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) if (ret < 0) goto out; - ret = soc_compr_components_trigger(cstream, cmd); + ret = snd_soc_component_compr_trigger(cstream, cmd); if (ret < 0) goto out; -- cgit v1.2.3 From ff08cf80addacbf42d419c2ef5561562f765bda3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:15:49 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_set_params() component related function should be implemented at soc-component.c. This patch moves soc-compress soc_compr_components_set_params() to soc-component as snd_soc_component_compr_set_params(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87blg17v74.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 21 +++++++++++++++++++++ sound/soc/soc-compress.c | 25 ++----------------------- 3 files changed, 25 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 6cb4a6a0bc39..d18a16a0881b 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -449,6 +449,8 @@ int snd_soc_component_compr_open(struct snd_compr_stream *cstream, void snd_soc_component_compr_free(struct snd_compr_stream *cstream, struct snd_soc_component *last); int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd); +int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index cf34545f4108..4afd63223724 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -482,6 +482,27 @@ int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd) } EXPORT_SYMBOL_GPL(snd_soc_component_compr_trigger); +int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret; + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->set_params) { + ret = component->driver->compress_ops->set_params( + component, cstream, params); + if (ret < 0) + return soc_component_ret(component, ret); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_params); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d85bd1d1c119..437ccd121b99 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -295,27 +295,6 @@ out: return ret; } -static int soc_compr_components_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret; - - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->set_params) - continue; - - ret = component->driver->compress_ops->set_params( - component, cstream, params); - if (ret < 0) - return ret; - } - - return 0; -} - static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *params) { @@ -337,7 +316,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, if (ret < 0) goto err; - ret = soc_compr_components_set_params(cstream, params); + ret = snd_soc_component_compr_set_params(cstream, params); if (ret < 0) goto err; @@ -394,7 +373,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, if (ret < 0) goto out; - ret = soc_compr_components_set_params(cstream, params); + ret = snd_soc_component_compr_set_params(cstream, params); if (ret < 0) goto out; -- cgit v1.2.3 From 77c221ecfed8762f65d17f3a6ee7b4f2cec61ae4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:15:56 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_get_params() component related function should be implemented at soc-component.c. This patch adds snd_soc_component_compr_get_params(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87a6vl7v6x.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 20 ++++++++++++++++++++ sound/soc/soc-compress.c | 14 ++------------ 3 files changed, 24 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index d18a16a0881b..6841c3037548 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -451,6 +451,8 @@ void snd_soc_component_compr_free(struct snd_compr_stream *cstream, int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd); int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *params); +int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream, + struct snd_codec *params); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 4afd63223724..f87071c6edb0 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -503,6 +503,26 @@ int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_params); +int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream, + struct snd_codec *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret; + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->get_params) { + ret = component->driver->compress_ops->get_params( + component, cstream, params); + return soc_component_ret(component, ret); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_params); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 437ccd121b99..a98defdecad7 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -394,9 +394,8 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_codec *params) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - int i, ret = 0; + int ret = 0; mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); @@ -404,16 +403,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, if (ret < 0) goto err; - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->get_params) - continue; - - ret = component->driver->compress_ops->get_params( - component, cstream, params); - break; - } - + ret = snd_soc_component_compr_get_params(cstream, params); err: mutex_unlock(&rtd->card->pcm_mutex); return ret; -- cgit v1.2.3 From d67fcb2d8f15df6f98698f411d9cb8c221ab6c91 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:16:03 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_get_caps() component related function should be implemented at soc-component.c. This patch adds snd_soc_component_compr_get_caps(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/878sb57v6q.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 24 ++++++++++++++++++++++++ sound/soc/soc-compress.c | 27 ++------------------------- 3 files changed, 28 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 6841c3037548..7fd45462963e 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -453,6 +453,8 @@ int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *params); int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream, struct snd_codec *params); +int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream, + struct snd_compr_caps *caps); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index f87071c6edb0..b885e96cc8ae 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -523,6 +523,30 @@ int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_params); +int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream, + struct snd_compr_caps *caps) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret = 0; + + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->get_caps) { + ret = component->driver->compress_ops->get_caps( + component, cstream, caps); + break; + } + } + + mutex_unlock(&rtd->card->pcm_mutex); + + return soc_component_ret(component, ret); +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_caps); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index a98defdecad7..e7530712ab91 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -409,29 +409,6 @@ err: return ret; } -static int soc_compr_get_caps(struct snd_compr_stream *cstream, - struct snd_compr_caps *caps) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret = 0; - - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->get_caps) - continue; - - ret = component->driver->compress_ops->get_caps( - component, cstream, caps); - break; - } - - mutex_unlock(&rtd->card->pcm_mutex); - return ret; -} - static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_compr_codec_caps *codec) { @@ -596,7 +573,7 @@ static struct snd_compr_ops soc_compr_ops = { .trigger = soc_compr_trigger, .pointer = soc_compr_pointer, .ack = soc_compr_ack, - .get_caps = soc_compr_get_caps, + .get_caps = snd_soc_component_compr_get_caps, .get_codec_caps = soc_compr_get_codec_caps }; @@ -611,7 +588,7 @@ static struct snd_compr_ops soc_compr_dyn_ops = { .trigger = soc_compr_trigger_fe, .pointer = soc_compr_pointer, .ack = soc_compr_ack, - .get_caps = soc_compr_get_caps, + .get_caps = snd_soc_component_compr_get_caps, .get_codec_caps = soc_compr_get_codec_caps }; -- cgit v1.2.3 From 0f6fe09720a3f307ab9f218f052d40b7d4e42b4c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:16:11 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_get_codec_caps() component related function should be implemented at soc-component.c. This patch adds snd_soc_component_compr_get_codec_caps(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/877dqp7v6i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 24 ++++++++++++++++++++++++ sound/soc/soc-compress.c | 27 ++------------------------- 3 files changed, 28 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 7fd45462963e..d91e0eb1546d 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -455,6 +455,8 @@ int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream, struct snd_codec *params); int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream, struct snd_compr_caps *caps); +int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream, + struct snd_compr_codec_caps *codec); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index b885e96cc8ae..8fba1a395f1e 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -547,6 +547,30 @@ int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_caps); +int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream, + struct snd_compr_codec_caps *codec) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret = 0; + + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->get_codec_caps) { + ret = component->driver->compress_ops->get_codec_caps( + component, cstream, codec); + break; + } + } + + mutex_unlock(&rtd->card->pcm_mutex); + + return soc_component_ret(component, ret); +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_codec_caps); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index e7530712ab91..a82bd02d5519 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -409,29 +409,6 @@ err: return ret; } -static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, - struct snd_compr_codec_caps *codec) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret = 0; - - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->get_codec_caps) - continue; - - ret = component->driver->compress_ops->get_codec_caps( - component, cstream, codec); - break; - } - - mutex_unlock(&rtd->card->pcm_mutex); - return ret; -} - static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -574,7 +551,7 @@ static struct snd_compr_ops soc_compr_ops = { .pointer = soc_compr_pointer, .ack = soc_compr_ack, .get_caps = snd_soc_component_compr_get_caps, - .get_codec_caps = soc_compr_get_codec_caps + .get_codec_caps = snd_soc_component_compr_get_codec_caps, }; /* ASoC Dynamic Compress operations */ @@ -589,7 +566,7 @@ static struct snd_compr_ops soc_compr_dyn_ops = { .pointer = soc_compr_pointer, .ack = soc_compr_ack, .get_caps = snd_soc_component_compr_get_caps, - .get_codec_caps = soc_compr_get_codec_caps + .get_codec_caps = snd_soc_component_compr_get_codec_caps, }; /** -- cgit v1.2.3 From 0506b88503645e71c18152693caee9cfa1dbf093 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:16:17 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_ack() component related function should be implemented at soc-component.c. This patch adds snd_soc_component_compr_ack(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/875z697v6c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-component.c | 20 ++++++++++++++++++++ sound/soc/soc-compress.c | 15 ++------------- 3 files changed, 23 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index d91e0eb1546d..ba0eb49f8885 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -457,6 +457,7 @@ int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream, struct snd_compr_caps *caps); int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_compr_codec_caps *codec); +int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 8fba1a395f1e..832177e5094e 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -571,6 +571,26 @@ int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_codec_caps); +int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret; + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->ack) { + ret = component->driver->compress_ops->ack( + component, cstream, bytes); + if (ret < 0) + return soc_component_ret(component, ret); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_ack); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index a82bd02d5519..234e1506ed43 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -412,9 +412,8 @@ err: static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - int i, ret = 0; + int ret; mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); @@ -422,17 +421,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) if (ret < 0) goto err; - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->ack) - continue; - - ret = component->driver->compress_ops->ack( - component, cstream, bytes); - if (ret < 0) - goto err; - } - + ret = snd_soc_component_compr_ack(cstream, bytes); err: mutex_unlock(&rtd->card->pcm_mutex); return ret; -- cgit v1.2.3 From 03ecea64e0ae26d7a8b53bce05a39b78022e1312 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:16:24 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_pointer() component related function should be implemented at soc-component.c. This patch adds snd_soc_component_compr_pointer(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/874klt7v65.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 20 ++++++++++++++++++++ sound/soc/soc-compress.c | 13 ++----------- 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index ba0eb49f8885..d4e396cc75c2 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -458,6 +458,8 @@ int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream, int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_compr_codec_caps *codec); int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes); +int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 832177e5094e..3ff2f227b99e 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -591,6 +591,26 @@ int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes) } EXPORT_SYMBOL_GPL(snd_soc_component_compr_ack); +int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret; + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->pointer) { + ret = component->driver->compress_ops->pointer( + component, cstream, tstamp); + return soc_component_ret(component, ret); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_pointer); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 234e1506ed43..eb5cb2f1823e 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -431,8 +431,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, struct snd_compr_tstamp *tstamp) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret = 0; + int ret; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); @@ -441,15 +440,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, if (ret < 0) goto out; - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->pointer) - continue; - - ret = component->driver->compress_ops->pointer( - component, cstream, tstamp); - break; - } + ret = snd_soc_component_compr_pointer(cstream, tstamp); out: mutex_unlock(&rtd->card->pcm_mutex); return ret; -- cgit v1.2.3 From b5852e66b115172dc3a88cb476b99c21ac6ffed8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:16:30 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_copy() component related function should be implemented at soc-component.c. This patch adds snd_soc_component_compr_copy(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87361d7v5z.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 24 ++++++++++++++++++++++++ sound/soc/soc-compress.c | 25 +------------------------ 3 files changed, 27 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index d4e396cc75c2..535f22502e1e 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -460,6 +460,8 @@ int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream, int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes); int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream, struct snd_compr_tstamp *tstamp); +int snd_soc_component_compr_copy(struct snd_compr_stream *cstream, + char __user *buf, size_t count); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 3ff2f227b99e..77fcb6fc42fb 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -611,6 +611,30 @@ int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_pointer); +int snd_soc_component_compr_copy(struct snd_compr_stream *cstream, + char __user *buf, size_t count) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret = 0; + + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->copy) { + ret = component->driver->compress_ops->copy( + component, cstream, buf, count); + break; + } + } + + mutex_unlock(&rtd->card->pcm_mutex); + + return soc_component_ret(component, ret); +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_copy); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index eb5cb2f1823e..4a202478a8d6 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -446,29 +446,6 @@ out: return ret; } -static int soc_compr_copy(struct snd_compr_stream *cstream, - char __user *buf, size_t count) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret = 0; - - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->copy) - continue; - - ret = component->driver->compress_ops->copy( - component, cstream, buf, count); - break; - } - - mutex_unlock(&rtd->card->pcm_mutex); - return ret; -} - static int soc_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata) { @@ -649,7 +626,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) !component->driver->compress_ops->copy) continue; - compr->ops->copy = soc_compr_copy; + compr->ops->copy = snd_soc_component_compr_copy; break; } -- cgit v1.2.3 From 1b308fb138eba8dd57198b25235d8369a42af293 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:16:36 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_set_metadata() component related function should be implemented at soc-component.c. This patch adds snd_soc_component_compr_set_metadata(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/871rgx7v5t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 21 +++++++++++++++++++++ sound/soc/soc-compress.c | 16 ++-------------- 3 files changed, 25 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 535f22502e1e..d23ebd5ce617 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -462,6 +462,8 @@ int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream, struct snd_compr_tstamp *tstamp); int snd_soc_component_compr_copy(struct snd_compr_stream *cstream, char __user *buf, size_t count); +int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 77fcb6fc42fb..ef2b97631748 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -635,6 +635,27 @@ int snd_soc_component_compr_copy(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_copy); +int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret; + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->set_metadata) { + ret = component->driver->compress_ops->set_metadata( + component, cstream, metadata); + if (ret < 0) + return soc_component_ret(component, ret); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_metadata); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 4a202478a8d6..3d29b41cf96f 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -450,26 +450,14 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - int i, ret; + int ret; ret = snd_soc_dai_compr_set_metadata(cpu_dai, cstream, metadata); if (ret < 0) return ret; - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->set_metadata) - continue; - - ret = component->driver->compress_ops->set_metadata( - component, cstream, metadata); - if (ret < 0) - return ret; - } - - return 0; + return snd_soc_component_compr_set_metadata(cstream, metadata); } static int soc_compr_get_metadata(struct snd_compr_stream *cstream, -- cgit v1.2.3 From bab78c238025c89df771631c54f6229f6c56fb26 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 13 Nov 2020 13:16:41 +0900 Subject: ASoC: soc-component: add snd_soc_component_compr_get_metadata() component related function should be implemented at soc-component.c. This patch adds snd_soc_component_compr_get_metadata(). Signed-off-by: Kuninori Morimoto Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87zh3l6gl8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 2 ++ sound/soc/soc-component.c | 20 ++++++++++++++++++++ sound/soc/soc-compress.c | 14 ++------------ 3 files changed, 24 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index d23ebd5ce617..984dd7353066 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -464,6 +464,8 @@ int snd_soc_component_compr_copy(struct snd_compr_stream *cstream, char __user *buf, size_t count); int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata); +int snd_soc_component_compr_get_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata); int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index ef2b97631748..5d3a8dcd8d49 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -656,6 +656,26 @@ int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream, } EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_metadata); +int snd_soc_component_compr_get_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i, ret; + + for_each_rtd_components(rtd, i, component) { + if (component->driver->compress_ops && + component->driver->compress_ops->get_metadata) { + ret = component->driver->compress_ops->get_metadata( + component, cstream, metadata); + return soc_component_ret(component, ret); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_metadata); + static unsigned int soc_component_read_no_lock( struct snd_soc_component *component, unsigned int reg) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 3d29b41cf96f..5a751d5d3847 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -464,24 +464,14 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, struct snd_compr_metadata *metadata) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - int i, ret; + int ret; ret = snd_soc_dai_compr_get_metadata(cpu_dai, cstream, metadata); if (ret < 0) return ret; - for_each_rtd_components(rtd, i, component) { - if (!component->driver->compress_ops || - !component->driver->compress_ops->get_metadata) - continue; - - return component->driver->compress_ops->get_metadata( - component, cstream, metadata); - } - - return 0; + return snd_soc_component_compr_get_metadata(cstream, metadata); } /* ASoC Compress operations */ -- cgit v1.2.3 From a5ec7c9e007b1095d04146eb94bac3863d35a69d Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Fri, 6 Nov 2020 16:53:36 +0800 Subject: ASoC: wcd9335: Remove unnecessary conversion to bool The '>=' expression itself is bool, no need to convert it to bool. Fix the following coccicheck warning: ./sound/soc/codecs/wcd9335.c:3982:25-30: WARNING: conversion to bool not needed here Reported-by: Tosk Robot Signed-off-by: Kaixu Xia Link: https://lore.kernel.org/r/1604652816-1330-1-git-send-email-kaixuxia@tencent.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index f2d9d52ee171..843c311ea79e 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -3979,7 +3979,7 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) } for_each_set_bit(j, &status, 32) { - tx = (j >= 16 ? true : false); + tx = (j >= 16); port_id = (tx ? j - 16 : j); regmap_read(wcd->if_regmap, WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val); -- cgit v1.2.3 From b88b31f4fa0abcd698045362d4aefcddc50cba59 Mon Sep 17 00:00:00 2001 From: Kyle Russell Date: Fri, 6 Nov 2020 09:59:05 -0500 Subject: ASoC: mmp-sspa: clear transmit phase bit for non-stereo formats The transmit phase register value is never cleared during hw params. So once hw params sets this bit to handle a two channel format, it remains configured for dual-phase, which is not desirable for mono playback. Signed-off-by: Kyle Russell Link: https://lore.kernel.org/r/20201106145905.365903-1-bkylerussell@gmail.com Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-sspa.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 4255851c71c1..52d4d8ace1c3 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -239,6 +239,7 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + sspa_ctrl &= ~SSPA_CTL_XPH; if (dev->of_node || params_channels(params) == 2) sspa_ctrl |= SSPA_CTL_XPH; -- cgit v1.2.3 From 45f366ec7941932d1a14576f3bd73d831fe9da95 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Mon, 16 Nov 2020 20:29:00 +0800 Subject: ASoC: samsung: fix platform_no_drv_owner.cocci warnings ./sound/soc/samsung/midas_wm1811.c:534:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Zou Wei Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/1605529740-68757-1-git-send-email-zou_wei@huawei.com Signed-off-by: Mark Brown --- sound/soc/samsung/midas_wm1811.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index d03340ce49a2..1f9a553edf19 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -531,7 +531,6 @@ static struct platform_driver midas_driver = { .driver = { .name = "midas-audio", .of_match_table = midas_of_match, - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, }, .probe = midas_probe, -- cgit v1.2.3 From 809bcbcecebff86003e13f07444d21b9d6652a64 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 5 Nov 2020 11:34:54 +0000 Subject: ASoC: codecs: lpass-wsa-macro: Add support to WSA Macro Qualcomm LPASS (Low Power Audio SubSystem) has internal codec WSA macro block which is used for connecting with WSA Smart speakers over soundwire. This patch adds support to the codec part of the WSA Macro block. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201105113458.12360-3-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/lpass-wsa-macro.c | 1383 ++++++++++++++++++++++++++++++++++++ sound/soc/codecs/lpass-wsa-macro.h | 17 + 4 files changed, 1406 insertions(+) create mode 100644 sound/soc/codecs/lpass-wsa-macro.c create mode 100644 sound/soc/codecs/lpass-wsa-macro.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b4ca5208fed6..d5ce46d7c718 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1789,4 +1789,8 @@ config SND_SOC_TPA6130A2 tristate "Texas Instruments TPA6130A2 headphone amplifier" depends on I2C +config SND_SOC_LPASS_WSA_MACRO + depends on COMMON_CLK + tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)" + endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 144d9256d4d5..d3322e9d5fc0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -103,6 +103,7 @@ snd-soc-l3-objs := l3.o snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o snd-soc-lochnagar-sc-objs := lochnagar-sc.o +snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o snd-soc-madera-objs := madera.o snd-soc-max9759-objs := max9759.o snd-soc-max9768-objs := max9768.o @@ -615,3 +616,4 @@ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o +obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO) += snd-soc-lpass-wsa-macro.o diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c new file mode 100644 index 000000000000..76873d582eff --- /dev/null +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -0,0 +1,1383 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lpass-wsa-macro.h" + +#define CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL (0x0000) +#define CDC_WSA_MCLK_EN_MASK BIT(0) +#define CDC_WSA_MCLK_ENABLE BIT(0) +#define CDC_WSA_MCLK_DISABLE 0 +#define CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL (0x0004) +#define CDC_WSA_FS_CNT_EN_MASK BIT(0) +#define CDC_WSA_FS_CNT_ENABLE BIT(0) +#define CDC_WSA_FS_CNT_DISABLE 0 +#define CDC_WSA_CLK_RST_CTRL_SWR_CONTROL (0x0008) +#define CDC_WSA_SWR_CLK_EN_MASK BIT(0) +#define CDC_WSA_SWR_CLK_ENABLE BIT(0) +#define CDC_WSA_SWR_RST_EN_MASK BIT(1) +#define CDC_WSA_SWR_RST_ENABLE BIT(1) +#define CDC_WSA_SWR_RST_DISABLE 0 +#define CDC_WSA_TOP_TOP_CFG0 (0x0080) +#define CDC_WSA_TOP_TOP_CFG1 (0x0084) +#define CDC_WSA_TOP_FREQ_MCLK (0x0088) +#define CDC_WSA_TOP_DEBUG_BUS_SEL (0x008C) +#define CDC_WSA_TOP_DEBUG_EN0 (0x0090) +#define CDC_WSA_TOP_DEBUG_EN1 (0x0094) +#define CDC_WSA_TOP_DEBUG_DSM_LB (0x0098) +#define CDC_WSA_TOP_RX_I2S_CTL (0x009C) +#define CDC_WSA_TOP_TX_I2S_CTL (0x00A0) +#define CDC_WSA_TOP_I2S_CLK (0x00A4) +#define CDC_WSA_TOP_I2S_RESET (0x00A8) +#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 (0x0100) +#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK GENMASK(5, 3) +#define CDC_WSA_RX_INTX_2_SEL_MASK GENMASK(2, 0) +#define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1 (0x0104) +#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG0 (0x0108) +#define CDC_WSA_RX_INP_MUX_RX_INT1_CFG1 (0x010C) +#define CDC_WSA_RX_INP_MUX_RX_MIX_CFG0 (0x0110) +#define CDC_WSA_RX_MIX_TX1_SEL_MASK GENMASK(5, 3) +#define CDC_WSA_RX_MIX_TX1_SEL_SHFT 3 +#define CDC_WSA_RX_MIX_TX0_SEL_MASK GENMASK(2, 0) +#define CDC_WSA_RX_INP_MUX_RX_EC_CFG0 (0x0114) +#define CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0 (0x0118) +#define CDC_WSA_TX0_SPKR_PROT_PATH_CTL (0x0244) +#define CDC_WSA_TX_SPKR_PROT_RESET_MASK BIT(5) +#define CDC_WSA_TX_SPKR_PROT_RESET BIT(5) +#define CDC_WSA_TX_SPKR_PROT_NO_RESET 0 +#define CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK BIT(4) +#define CDC_WSA_TX_SPKR_PROT_CLK_ENABLE BIT(4) +#define CDC_WSA_TX_SPKR_PROT_CLK_DISABLE 0 +#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK GENMASK(3, 0) +#define CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K 0 +#define CDC_WSA_TX0_SPKR_PROT_PATH_CFG0 (0x0248) +#define CDC_WSA_TX1_SPKR_PROT_PATH_CTL (0x0264) +#define CDC_WSA_TX1_SPKR_PROT_PATH_CFG0 (0x0268) +#define CDC_WSA_TX2_SPKR_PROT_PATH_CTL (0x0284) +#define CDC_WSA_TX2_SPKR_PROT_PATH_CFG0 (0x0288) +#define CDC_WSA_TX3_SPKR_PROT_PATH_CTL (0x02A4) +#define CDC_WSA_TX3_SPKR_PROT_PATH_CFG0 (0x02A8) +#define CDC_WSA_INTR_CTRL_CFG (0x0340) +#define CDC_WSA_INTR_CTRL_CLR_COMMIT (0x0344) +#define CDC_WSA_INTR_CTRL_PIN1_MASK0 (0x0360) +#define CDC_WSA_INTR_CTRL_PIN1_STATUS0 (0x0368) +#define CDC_WSA_INTR_CTRL_PIN1_CLEAR0 (0x0370) +#define CDC_WSA_INTR_CTRL_PIN2_MASK0 (0x0380) +#define CDC_WSA_INTR_CTRL_PIN2_STATUS0 (0x0388) +#define CDC_WSA_INTR_CTRL_PIN2_CLEAR0 (0x0390) +#define CDC_WSA_INTR_CTRL_LEVEL0 (0x03C0) +#define CDC_WSA_INTR_CTRL_BYPASS0 (0x03C8) +#define CDC_WSA_INTR_CTRL_SET0 (0x03D0) +#define CDC_WSA_RX0_RX_PATH_CTL (0x0400) +#define CDC_WSA_RX_PATH_CLK_EN_MASK BIT(5) +#define CDC_WSA_RX_PATH_CLK_ENABLE BIT(5) +#define CDC_WSA_RX_PATH_CLK_DISABLE 0 +#define CDC_WSA_RX_PATH_PGA_MUTE_EN_MASK BIT(4) +#define CDC_WSA_RX_PATH_PGA_MUTE_ENABLE BIT(4) +#define CDC_WSA_RX_PATH_PGA_MUTE_DISABLE 0 +#define CDC_WSA_RX0_RX_PATH_CFG0 (0x0404) +#define CDC_WSA_RX_PATH_COMP_EN_MASK BIT(1) +#define CDC_WSA_RX_PATH_COMP_ENABLE BIT(1) +#define CDC_WSA_RX_PATH_HD2_EN_MASK BIT(2) +#define CDC_WSA_RX_PATH_HD2_ENABLE BIT(2) +#define CDC_WSA_RX_PATH_SPKR_RATE_MASK BIT(3) +#define CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072 BIT(3) +#define CDC_WSA_RX0_RX_PATH_CFG1 (0x0408) +#define CDC_WSA_RX_PATH_SMART_BST_EN_MASK BIT(0) +#define CDC_WSA_RX_PATH_SMART_BST_ENABLE BIT(0) +#define CDC_WSA_RX_PATH_SMART_BST_DISABLE 0 +#define CDC_WSA_RX0_RX_PATH_CFG2 (0x040C) +#define CDC_WSA_RX0_RX_PATH_CFG3 (0x0410) +#define CDC_WSA_RX_DC_DCOEFF_MASK GENMASK(1, 0) +#define CDC_WSA_RX0_RX_VOL_CTL (0x0414) +#define CDC_WSA_RX0_RX_PATH_MIX_CTL (0x0418) +#define CDC_WSA_RX_PATH_MIX_CLK_EN_MASK BIT(5) +#define CDC_WSA_RX_PATH_MIX_CLK_ENABLE BIT(5) +#define CDC_WSA_RX_PATH_MIX_CLK_DISABLE 0 +#define CDC_WSA_RX0_RX_PATH_MIX_CFG (0x041C) +#define CDC_WSA_RX0_RX_VOL_MIX_CTL (0x0420) +#define CDC_WSA_RX0_RX_PATH_SEC0 (0x0424) +#define CDC_WSA_RX0_RX_PATH_SEC1 (0x0428) +#define CDC_WSA_RX_PGA_HALF_DB_MASK BIT(0) +#define CDC_WSA_RX_PGA_HALF_DB_ENABLE BIT(0) +#define CDC_WSA_RX_PGA_HALF_DB_DISABLE 0 +#define CDC_WSA_RX0_RX_PATH_SEC2 (0x042C) +#define CDC_WSA_RX0_RX_PATH_SEC3 (0x0430) +#define CDC_WSA_RX_PATH_HD2_SCALE_MASK GENMASK(1, 0) +#define CDC_WSA_RX_PATH_HD2_ALPHA_MASK GENMASK(5, 2) +#define CDC_WSA_RX0_RX_PATH_SEC5 (0x0438) +#define CDC_WSA_RX0_RX_PATH_SEC6 (0x043C) +#define CDC_WSA_RX0_RX_PATH_SEC7 (0x0440) +#define CDC_WSA_RX0_RX_PATH_MIX_SEC0 (0x0444) +#define CDC_WSA_RX0_RX_PATH_MIX_SEC1 (0x0448) +#define CDC_WSA_RX0_RX_PATH_DSMDEM_CTL (0x044C) +#define CDC_WSA_RX_DSMDEM_CLK_EN_MASK BIT(0) +#define CDC_WSA_RX_DSMDEM_CLK_ENABLE BIT(0) +#define CDC_WSA_RX1_RX_PATH_CTL (0x0480) +#define CDC_WSA_RX1_RX_PATH_CFG0 (0x0484) +#define CDC_WSA_RX1_RX_PATH_CFG1 (0x0488) +#define CDC_WSA_RX1_RX_PATH_CFG2 (0x048C) +#define CDC_WSA_RX1_RX_PATH_CFG3 (0x0490) +#define CDC_WSA_RX1_RX_VOL_CTL (0x0494) +#define CDC_WSA_RX1_RX_PATH_MIX_CTL (0x0498) +#define CDC_WSA_RX1_RX_PATH_MIX_CFG (0x049C) +#define CDC_WSA_RX1_RX_VOL_MIX_CTL (0x04A0) +#define CDC_WSA_RX1_RX_PATH_SEC0 (0x04A4) +#define CDC_WSA_RX1_RX_PATH_SEC1 (0x04A8) +#define CDC_WSA_RX1_RX_PATH_SEC2 (0x04AC) +#define CDC_WSA_RX1_RX_PATH_SEC3 (0x04B0) +#define CDC_WSA_RX1_RX_PATH_SEC5 (0x04B8) +#define CDC_WSA_RX1_RX_PATH_SEC6 (0x04BC) +#define CDC_WSA_RX1_RX_PATH_SEC7 (0x04C0) +#define CDC_WSA_RX1_RX_PATH_MIX_SEC0 (0x04C4) +#define CDC_WSA_RX1_RX_PATH_MIX_SEC1 (0x04C8) +#define CDC_WSA_RX1_RX_PATH_DSMDEM_CTL (0x04CC) +#define CDC_WSA_BOOST0_BOOST_PATH_CTL (0x0500) +#define CDC_WSA_BOOST_PATH_CLK_EN_MASK BIT(4) +#define CDC_WSA_BOOST_PATH_CLK_ENABLE BIT(4) +#define CDC_WSA_BOOST_PATH_CLK_DISABLE 0 +#define CDC_WSA_BOOST0_BOOST_CTL (0x0504) +#define CDC_WSA_BOOST0_BOOST_CFG1 (0x0508) +#define CDC_WSA_BOOST0_BOOST_CFG2 (0x050C) +#define CDC_WSA_BOOST1_BOOST_PATH_CTL (0x0540) +#define CDC_WSA_BOOST1_BOOST_CTL (0x0544) +#define CDC_WSA_BOOST1_BOOST_CFG1 (0x0548) +#define CDC_WSA_BOOST1_BOOST_CFG2 (0x054C) +#define CDC_WSA_COMPANDER0_CTL0 (0x0580) +#define CDC_WSA_COMPANDER_CLK_EN_MASK BIT(0) +#define CDC_WSA_COMPANDER_CLK_ENABLE BIT(0) +#define CDC_WSA_COMPANDER_SOFT_RST_MASK BIT(1) +#define CDC_WSA_COMPANDER_SOFT_RST_ENABLE BIT(1) +#define CDC_WSA_COMPANDER_HALT_MASK BIT(2) +#define CDC_WSA_COMPANDER_HALT BIT(2) +#define CDC_WSA_COMPANDER0_CTL1 (0x0584) +#define CDC_WSA_COMPANDER0_CTL2 (0x0588) +#define CDC_WSA_COMPANDER0_CTL3 (0x058C) +#define CDC_WSA_COMPANDER0_CTL4 (0x0590) +#define CDC_WSA_COMPANDER0_CTL5 (0x0594) +#define CDC_WSA_COMPANDER0_CTL6 (0x0598) +#define CDC_WSA_COMPANDER0_CTL7 (0x059C) +#define CDC_WSA_COMPANDER1_CTL0 (0x05C0) +#define CDC_WSA_COMPANDER1_CTL1 (0x05C4) +#define CDC_WSA_COMPANDER1_CTL2 (0x05C8) +#define CDC_WSA_COMPANDER1_CTL3 (0x05CC) +#define CDC_WSA_COMPANDER1_CTL4 (0x05D0) +#define CDC_WSA_COMPANDER1_CTL5 (0x05D4) +#define CDC_WSA_COMPANDER1_CTL6 (0x05D8) +#define CDC_WSA_COMPANDER1_CTL7 (0x05DC) +#define CDC_WSA_SOFTCLIP0_CRC (0x0600) +#define CDC_WSA_SOFTCLIP_CLK_EN_MASK BIT(0) +#define CDC_WSA_SOFTCLIP_CLK_ENABLE BIT(0) +#define CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL (0x0604) +#define CDC_WSA_SOFTCLIP_EN_MASK BIT(0) +#define CDC_WSA_SOFTCLIP_ENABLE BIT(0) +#define CDC_WSA_SOFTCLIP1_CRC (0x0640) +#define CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL (0x0644) +#define CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL (0x0680) +#define CDC_WSA_EC_HQ_EC_CLK_EN_MASK BIT(0) +#define CDC_WSA_EC_HQ_EC_CLK_ENABLE BIT(0) +#define CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 (0x0684) +#define CDC_WSA_EC_HQ_EC_REF_PCM_RATE_MASK GENMASK(4, 1) +#define CDC_WSA_EC_HQ_EC_REF_PCM_RATE_48K BIT(3) +#define CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL (0x06C0) +#define CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0 (0x06C4) +#define CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL (0x0700) +#define CDC_WSA_SPLINE_ASRC0_CTL0 (0x0704) +#define CDC_WSA_SPLINE_ASRC0_CTL1 (0x0708) +#define CDC_WSA_SPLINE_ASRC0_FIFO_CTL (0x070C) +#define CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB (0x0710) +#define CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB (0x0714) +#define CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB (0x0718) +#define CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB (0x071C) +#define CDC_WSA_SPLINE_ASRC0_STATUS_FIFO (0x0720) +#define CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL (0x0740) +#define CDC_WSA_SPLINE_ASRC1_CTL0 (0x0744) +#define CDC_WSA_SPLINE_ASRC1_CTL1 (0x0748) +#define CDC_WSA_SPLINE_ASRC1_FIFO_CTL (0x074C) +#define CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB (0x0750) +#define CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB (0x0754) +#define CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB (0x0758) +#define CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB (0x075C) +#define CDC_WSA_SPLINE_ASRC1_STATUS_FIFO (0x0760) +#define WSA_MAX_OFFSET (0x0760) + +#define WSA_MACRO_RX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define WSA_MACRO_RX_MIX_RATES (SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define WSA_MACRO_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define WSA_MACRO_ECHO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_48000) +#define WSA_MACRO_ECHO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define NUM_INTERPOLATORS 2 +#define WSA_NUM_CLKS_MAX 5 +#define WSA_MACRO_MCLK_FREQ 19200000 +#define WSA_MACRO_MUX_INP_SHFT 0x3 +#define WSA_MACRO_MUX_INP_MASK1 0x07 +#define WSA_MACRO_MUX_INP_MASK2 0x38 +#define WSA_MACRO_MUX_CFG_OFFSET 0x8 +#define WSA_MACRO_MUX_CFG1_OFFSET 0x4 +#define WSA_MACRO_RX_COMP_OFFSET 0x40 +#define WSA_MACRO_RX_SOFTCLIP_OFFSET 0x40 +#define WSA_MACRO_RX_PATH_OFFSET 0x80 +#define WSA_MACRO_RX_PATH_CFG3_OFFSET 0x10 +#define WSA_MACRO_RX_PATH_DSMDEM_OFFSET 0x4C +#define WSA_MACRO_FS_RATE_MASK 0x0F +#define WSA_MACRO_EC_MIX_TX0_MASK 0x03 +#define WSA_MACRO_EC_MIX_TX1_MASK 0x18 +#define WSA_MACRO_MAX_DMA_CH_PER_PORT 0x2 + +enum { + WSA_MACRO_GAIN_OFFSET_M1P5_DB, + WSA_MACRO_GAIN_OFFSET_0_DB, +}; +enum { + WSA_MACRO_RX0 = 0, + WSA_MACRO_RX1, + WSA_MACRO_RX_MIX, + WSA_MACRO_RX_MIX0 = WSA_MACRO_RX_MIX, + WSA_MACRO_RX_MIX1, + WSA_MACRO_RX_MAX, +}; + +enum { + WSA_MACRO_TX0 = 0, + WSA_MACRO_TX1, + WSA_MACRO_TX_MAX, +}; + +enum { + WSA_MACRO_EC0_MUX = 0, + WSA_MACRO_EC1_MUX, + WSA_MACRO_EC_MUX_MAX, +}; + +enum { + WSA_MACRO_COMP1, /* SPK_L */ + WSA_MACRO_COMP2, /* SPK_R */ + WSA_MACRO_COMP_MAX +}; + +enum { + WSA_MACRO_SOFTCLIP0, /* RX0 */ + WSA_MACRO_SOFTCLIP1, /* RX1 */ + WSA_MACRO_SOFTCLIP_MAX +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +static struct interp_sample_rate int_prim_sample_rate_val[] = { + {8000, 0x0}, /* 8K */ + {16000, 0x1}, /* 16K */ + {24000, -EINVAL},/* 24K */ + {32000, 0x3}, /* 32K */ + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ + {384000, 0x7}, /* 384K */ + {44100, 0x8}, /* 44.1K */ +}; + +static struct interp_sample_rate int_mix_sample_rate_val[] = { + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ +}; + +enum { + WSA_MACRO_AIF_INVALID = 0, + WSA_MACRO_AIF1_PB, + WSA_MACRO_AIF_MIX1_PB, + WSA_MACRO_AIF_VI, + WSA_MACRO_AIF_ECHO, + WSA_MACRO_MAX_DAIS, +}; + +struct wsa_macro { + struct device *dev; + int comp_enabled[WSA_MACRO_COMP_MAX]; + int ec_hq[WSA_MACRO_RX1 + 1]; + u16 prim_int_users[WSA_MACRO_RX1 + 1]; + u16 wsa_mclk_users; + bool reset_swr; + unsigned long active_ch_mask[WSA_MACRO_MAX_DAIS]; + unsigned long active_ch_cnt[WSA_MACRO_MAX_DAIS]; + int rx_port_value[WSA_MACRO_RX_MAX]; + int ear_spkr_gain; + int spkr_gain_offset; + int spkr_mode; + int is_softclip_on[WSA_MACRO_SOFTCLIP_MAX]; + int softclip_clk_users[WSA_MACRO_SOFTCLIP_MAX]; + struct regmap *regmap; + struct clk_bulk_data clks[WSA_NUM_CLKS_MAX]; + struct clk_hw hw; +}; +#define to_wsa_macro(_hw) container_of(_hw, struct wsa_macro, hw) + +static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); + +static const char * const wsa_macro_ear_spkr_pa_gain_text[] = { + "G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB", + "G_4_DB", "G_5_DB", "G_6_DB" +}; + +static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum, + wsa_macro_ear_spkr_pa_gain_text); + +static const struct reg_default wsa_defaults[] = { + /* WSA Macro */ + { CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { CDC_WSA_TOP_TOP_CFG0, 0x00}, + { CDC_WSA_TOP_TOP_CFG1, 0x00}, + { CDC_WSA_TOP_FREQ_MCLK, 0x00}, + { CDC_WSA_TOP_DEBUG_BUS_SEL, 0x00}, + { CDC_WSA_TOP_DEBUG_EN0, 0x00}, + { CDC_WSA_TOP_DEBUG_EN1, 0x00}, + { CDC_WSA_TOP_DEBUG_DSM_LB, 0x88}, + { CDC_WSA_TOP_RX_I2S_CTL, 0x0C}, + { CDC_WSA_TOP_TX_I2S_CTL, 0x0C}, + { CDC_WSA_TOP_I2S_CLK, 0x02}, + { CDC_WSA_TOP_I2S_RESET, 0x00}, + { CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, 0x00}, + { CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, 0x00}, + { CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, 0x00}, + { CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, 0x00}, + { CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, 0x00}, + { CDC_WSA_RX_INP_MUX_RX_EC_CFG0, 0x00}, + { CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, 0x00}, + { CDC_WSA_TX0_SPKR_PROT_PATH_CTL, 0x02}, + { CDC_WSA_TX0_SPKR_PROT_PATH_CFG0, 0x00}, + { CDC_WSA_TX1_SPKR_PROT_PATH_CTL, 0x02}, + { CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x00}, + { CDC_WSA_TX2_SPKR_PROT_PATH_CTL, 0x02}, + { CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x00}, + { CDC_WSA_TX3_SPKR_PROT_PATH_CTL, 0x02}, + { CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x00}, + { CDC_WSA_INTR_CTRL_CFG, 0x00}, + { CDC_WSA_INTR_CTRL_CLR_COMMIT, 0x00}, + { CDC_WSA_INTR_CTRL_PIN1_MASK0, 0xFF}, + { CDC_WSA_INTR_CTRL_PIN1_STATUS0, 0x00}, + { CDC_WSA_INTR_CTRL_PIN1_CLEAR0, 0x00}, + { CDC_WSA_INTR_CTRL_PIN2_MASK0, 0xFF}, + { CDC_WSA_INTR_CTRL_PIN2_STATUS0, 0x00}, + { CDC_WSA_INTR_CTRL_PIN2_CLEAR0, 0x00}, + { CDC_WSA_INTR_CTRL_LEVEL0, 0x00}, + { CDC_WSA_INTR_CTRL_BYPASS0, 0x00}, + { CDC_WSA_INTR_CTRL_SET0, 0x00}, + { CDC_WSA_RX0_RX_PATH_CTL, 0x04}, + { CDC_WSA_RX0_RX_PATH_CFG0, 0x00}, + { CDC_WSA_RX0_RX_PATH_CFG1, 0x64}, + { CDC_WSA_RX0_RX_PATH_CFG2, 0x8F}, + { CDC_WSA_RX0_RX_PATH_CFG3, 0x00}, + { CDC_WSA_RX0_RX_VOL_CTL, 0x00}, + { CDC_WSA_RX0_RX_PATH_MIX_CTL, 0x04}, + { CDC_WSA_RX0_RX_PATH_MIX_CFG, 0x7E}, + { CDC_WSA_RX0_RX_VOL_MIX_CTL, 0x00}, + { CDC_WSA_RX0_RX_PATH_SEC0, 0x04}, + { CDC_WSA_RX0_RX_PATH_SEC1, 0x08}, + { CDC_WSA_RX0_RX_PATH_SEC2, 0x00}, + { CDC_WSA_RX0_RX_PATH_SEC3, 0x00}, + { CDC_WSA_RX0_RX_PATH_SEC5, 0x00}, + { CDC_WSA_RX0_RX_PATH_SEC6, 0x00}, + { CDC_WSA_RX0_RX_PATH_SEC7, 0x00}, + { CDC_WSA_RX0_RX_PATH_MIX_SEC0, 0x08}, + { CDC_WSA_RX0_RX_PATH_MIX_SEC1, 0x00}, + { CDC_WSA_RX0_RX_PATH_DSMDEM_CTL, 0x00}, + { CDC_WSA_RX1_RX_PATH_CFG0, 0x00}, + { CDC_WSA_RX1_RX_PATH_CFG1, 0x64}, + { CDC_WSA_RX1_RX_PATH_CFG2, 0x8F}, + { CDC_WSA_RX1_RX_PATH_CFG3, 0x00}, + { CDC_WSA_RX1_RX_VOL_CTL, 0x00}, + { CDC_WSA_RX1_RX_PATH_MIX_CTL, 0x04}, + { CDC_WSA_RX1_RX_PATH_MIX_CFG, 0x7E}, + { CDC_WSA_RX1_RX_VOL_MIX_CTL, 0x00}, + { CDC_WSA_RX1_RX_PATH_SEC0, 0x04}, + { CDC_WSA_RX1_RX_PATH_SEC1, 0x08}, + { CDC_WSA_RX1_RX_PATH_SEC2, 0x00}, + { CDC_WSA_RX1_RX_PATH_SEC3, 0x00}, + { CDC_WSA_RX1_RX_PATH_SEC5, 0x00}, + { CDC_WSA_RX1_RX_PATH_SEC6, 0x00}, + { CDC_WSA_RX1_RX_PATH_SEC7, 0x00}, + { CDC_WSA_RX1_RX_PATH_MIX_SEC0, 0x08}, + { CDC_WSA_RX1_RX_PATH_MIX_SEC1, 0x00}, + { CDC_WSA_RX1_RX_PATH_DSMDEM_CTL, 0x00}, + { CDC_WSA_BOOST0_BOOST_PATH_CTL, 0x00}, + { CDC_WSA_BOOST0_BOOST_CTL, 0xD0}, + { CDC_WSA_BOOST0_BOOST_CFG1, 0x89}, + { CDC_WSA_BOOST0_BOOST_CFG2, 0x04}, + { CDC_WSA_BOOST1_BOOST_PATH_CTL, 0x00}, + { CDC_WSA_BOOST1_BOOST_CTL, 0xD0}, + { CDC_WSA_BOOST1_BOOST_CFG1, 0x89}, + { CDC_WSA_BOOST1_BOOST_CFG2, 0x04}, + { CDC_WSA_COMPANDER0_CTL0, 0x60}, + { CDC_WSA_COMPANDER0_CTL1, 0xDB}, + { CDC_WSA_COMPANDER0_CTL2, 0xFF}, + { CDC_WSA_COMPANDER0_CTL3, 0x35}, + { CDC_WSA_COMPANDER0_CTL4, 0xFF}, + { CDC_WSA_COMPANDER0_CTL5, 0x00}, + { CDC_WSA_COMPANDER0_CTL6, 0x01}, + { CDC_WSA_COMPANDER0_CTL7, 0x28}, + { CDC_WSA_COMPANDER1_CTL0, 0x60}, + { CDC_WSA_COMPANDER1_CTL1, 0xDB}, + { CDC_WSA_COMPANDER1_CTL2, 0xFF}, + { CDC_WSA_COMPANDER1_CTL3, 0x35}, + { CDC_WSA_COMPANDER1_CTL4, 0xFF}, + { CDC_WSA_COMPANDER1_CTL5, 0x00}, + { CDC_WSA_COMPANDER1_CTL6, 0x01}, + { CDC_WSA_COMPANDER1_CTL7, 0x28}, + { CDC_WSA_SOFTCLIP0_CRC, 0x00}, + { CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL, 0x38}, + { CDC_WSA_SOFTCLIP1_CRC, 0x00}, + { CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL, 0x38}, + { CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL, 0x00}, + { CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0, 0x01}, + { CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL, 0x00}, + { CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0, 0x01}, + { CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL, 0x00}, + { CDC_WSA_SPLINE_ASRC0_CTL0, 0x00}, + { CDC_WSA_SPLINE_ASRC0_CTL1, 0x00}, + { CDC_WSA_SPLINE_ASRC0_FIFO_CTL, 0xA8}, + { CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00}, + { CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00}, + { CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00}, + { CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00}, + { CDC_WSA_SPLINE_ASRC0_STATUS_FIFO, 0x00}, + { CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL, 0x00}, + { CDC_WSA_SPLINE_ASRC1_CTL0, 0x00}, + { CDC_WSA_SPLINE_ASRC1_CTL1, 0x00}, + { CDC_WSA_SPLINE_ASRC1_FIFO_CTL, 0xA8}, + { CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00}, + { CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00}, + { CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00}, + { CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00}, + { CDC_WSA_SPLINE_ASRC1_STATUS_FIFO, 0x00}, +}; + +static bool wsa_is_wronly_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case CDC_WSA_INTR_CTRL_CLR_COMMIT: + case CDC_WSA_INTR_CTRL_PIN1_CLEAR0: + case CDC_WSA_INTR_CTRL_PIN2_CLEAR0: + return true; + } + + return false; +} + +static bool wsa_is_rw_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL: + case CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL: + case CDC_WSA_CLK_RST_CTRL_SWR_CONTROL: + case CDC_WSA_TOP_TOP_CFG0: + case CDC_WSA_TOP_TOP_CFG1: + case CDC_WSA_TOP_FREQ_MCLK: + case CDC_WSA_TOP_DEBUG_BUS_SEL: + case CDC_WSA_TOP_DEBUG_EN0: + case CDC_WSA_TOP_DEBUG_EN1: + case CDC_WSA_TOP_DEBUG_DSM_LB: + case CDC_WSA_TOP_RX_I2S_CTL: + case CDC_WSA_TOP_TX_I2S_CTL: + case CDC_WSA_TOP_I2S_CLK: + case CDC_WSA_TOP_I2S_RESET: + case CDC_WSA_RX_INP_MUX_RX_INT0_CFG0: + case CDC_WSA_RX_INP_MUX_RX_INT0_CFG1: + case CDC_WSA_RX_INP_MUX_RX_INT1_CFG0: + case CDC_WSA_RX_INP_MUX_RX_INT1_CFG1: + case CDC_WSA_RX_INP_MUX_RX_MIX_CFG0: + case CDC_WSA_RX_INP_MUX_RX_EC_CFG0: + case CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0: + case CDC_WSA_TX0_SPKR_PROT_PATH_CTL: + case CDC_WSA_TX0_SPKR_PROT_PATH_CFG0: + case CDC_WSA_TX1_SPKR_PROT_PATH_CTL: + case CDC_WSA_TX1_SPKR_PROT_PATH_CFG0: + case CDC_WSA_TX2_SPKR_PROT_PATH_CTL: + case CDC_WSA_TX2_SPKR_PROT_PATH_CFG0: + case CDC_WSA_TX3_SPKR_PROT_PATH_CTL: + case CDC_WSA_TX3_SPKR_PROT_PATH_CFG0: + case CDC_WSA_INTR_CTRL_CFG: + case CDC_WSA_INTR_CTRL_PIN1_MASK0: + case CDC_WSA_INTR_CTRL_PIN2_MASK0: + case CDC_WSA_INTR_CTRL_LEVEL0: + case CDC_WSA_INTR_CTRL_BYPASS0: + case CDC_WSA_INTR_CTRL_SET0: + case CDC_WSA_RX0_RX_PATH_CTL: + case CDC_WSA_RX0_RX_PATH_CFG0: + case CDC_WSA_RX0_RX_PATH_CFG1: + case CDC_WSA_RX0_RX_PATH_CFG2: + case CDC_WSA_RX0_RX_PATH_CFG3: + case CDC_WSA_RX0_RX_VOL_CTL: + case CDC_WSA_RX0_RX_PATH_MIX_CTL: + case CDC_WSA_RX0_RX_PATH_MIX_CFG: + case CDC_WSA_RX0_RX_VOL_MIX_CTL: + case CDC_WSA_RX0_RX_PATH_SEC0: + case CDC_WSA_RX0_RX_PATH_SEC1: + case CDC_WSA_RX0_RX_PATH_SEC2: + case CDC_WSA_RX0_RX_PATH_SEC3: + case CDC_WSA_RX0_RX_PATH_SEC5: + case CDC_WSA_RX0_RX_PATH_SEC6: + case CDC_WSA_RX0_RX_PATH_SEC7: + case CDC_WSA_RX0_RX_PATH_MIX_SEC0: + case CDC_WSA_RX0_RX_PATH_MIX_SEC1: + case CDC_WSA_RX0_RX_PATH_DSMDEM_CTL: + case CDC_WSA_RX1_RX_PATH_CTL: + case CDC_WSA_RX1_RX_PATH_CFG0: + case CDC_WSA_RX1_RX_PATH_CFG1: + case CDC_WSA_RX1_RX_PATH_CFG2: + case CDC_WSA_RX1_RX_PATH_CFG3: + case CDC_WSA_RX1_RX_VOL_CTL: + case CDC_WSA_RX1_RX_PATH_MIX_CTL: + case CDC_WSA_RX1_RX_PATH_MIX_CFG: + case CDC_WSA_RX1_RX_VOL_MIX_CTL: + case CDC_WSA_RX1_RX_PATH_SEC0: + case CDC_WSA_RX1_RX_PATH_SEC1: + case CDC_WSA_RX1_RX_PATH_SEC2: + case CDC_WSA_RX1_RX_PATH_SEC3: + case CDC_WSA_RX1_RX_PATH_SEC5: + case CDC_WSA_RX1_RX_PATH_SEC6: + case CDC_WSA_RX1_RX_PATH_SEC7: + case CDC_WSA_RX1_RX_PATH_MIX_SEC0: + case CDC_WSA_RX1_RX_PATH_MIX_SEC1: + case CDC_WSA_RX1_RX_PATH_DSMDEM_CTL: + case CDC_WSA_BOOST0_BOOST_PATH_CTL: + case CDC_WSA_BOOST0_BOOST_CTL: + case CDC_WSA_BOOST0_BOOST_CFG1: + case CDC_WSA_BOOST0_BOOST_CFG2: + case CDC_WSA_BOOST1_BOOST_PATH_CTL: + case CDC_WSA_BOOST1_BOOST_CTL: + case CDC_WSA_BOOST1_BOOST_CFG1: + case CDC_WSA_BOOST1_BOOST_CFG2: + case CDC_WSA_COMPANDER0_CTL0: + case CDC_WSA_COMPANDER0_CTL1: + case CDC_WSA_COMPANDER0_CTL2: + case CDC_WSA_COMPANDER0_CTL3: + case CDC_WSA_COMPANDER0_CTL4: + case CDC_WSA_COMPANDER0_CTL5: + case CDC_WSA_COMPANDER0_CTL7: + case CDC_WSA_COMPANDER1_CTL0: + case CDC_WSA_COMPANDER1_CTL1: + case CDC_WSA_COMPANDER1_CTL2: + case CDC_WSA_COMPANDER1_CTL3: + case CDC_WSA_COMPANDER1_CTL4: + case CDC_WSA_COMPANDER1_CTL5: + case CDC_WSA_COMPANDER1_CTL7: + case CDC_WSA_SOFTCLIP0_CRC: + case CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL: + case CDC_WSA_SOFTCLIP1_CRC: + case CDC_WSA_SOFTCLIP1_SOFTCLIP_CTRL: + case CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL: + case CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0: + case CDC_WSA_EC_HQ1_EC_REF_HQ_PATH_CTL: + case CDC_WSA_EC_HQ1_EC_REF_HQ_CFG0: + case CDC_WSA_SPLINE_ASRC0_CLK_RST_CTL: + case CDC_WSA_SPLINE_ASRC0_CTL0: + case CDC_WSA_SPLINE_ASRC0_CTL1: + case CDC_WSA_SPLINE_ASRC0_FIFO_CTL: + case CDC_WSA_SPLINE_ASRC1_CLK_RST_CTL: + case CDC_WSA_SPLINE_ASRC1_CTL0: + case CDC_WSA_SPLINE_ASRC1_CTL1: + case CDC_WSA_SPLINE_ASRC1_FIFO_CTL: + return true; + } + + return false; +} + +static bool wsa_is_writeable_register(struct device *dev, unsigned int reg) +{ + bool ret; + + ret = wsa_is_rw_register(dev, reg); + if (!ret) + return wsa_is_wronly_register(dev, reg); + + return ret; +} + +static bool wsa_is_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_WSA_INTR_CTRL_CLR_COMMIT: + case CDC_WSA_INTR_CTRL_PIN1_CLEAR0: + case CDC_WSA_INTR_CTRL_PIN2_CLEAR0: + case CDC_WSA_INTR_CTRL_PIN1_STATUS0: + case CDC_WSA_INTR_CTRL_PIN2_STATUS0: + case CDC_WSA_COMPANDER0_CTL6: + case CDC_WSA_COMPANDER1_CTL6: + case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB: + case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB: + case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB: + case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB: + case CDC_WSA_SPLINE_ASRC0_STATUS_FIFO: + case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB: + case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB: + case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB: + case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB: + case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO: + return true; + } + + return wsa_is_rw_register(dev, reg); +} + +static bool wsa_is_volatile_register(struct device *dev, unsigned int reg) +{ + /* Update volatile list for rx/tx macros */ + switch (reg) { + case CDC_WSA_INTR_CTRL_PIN1_STATUS0: + case CDC_WSA_INTR_CTRL_PIN2_STATUS0: + case CDC_WSA_COMPANDER0_CTL6: + case CDC_WSA_COMPANDER1_CTL6: + case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_LSB: + case CDC_WSA_SPLINE_ASRC0_STATUS_FMIN_CNTR_MSB: + case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_LSB: + case CDC_WSA_SPLINE_ASRC0_STATUS_FMAX_CNTR_MSB: + case CDC_WSA_SPLINE_ASRC0_STATUS_FIFO: + case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_LSB: + case CDC_WSA_SPLINE_ASRC1_STATUS_FMIN_CNTR_MSB: + case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_LSB: + case CDC_WSA_SPLINE_ASRC1_STATUS_FMAX_CNTR_MSB: + case CDC_WSA_SPLINE_ASRC1_STATUS_FIFO: + return true; + } + return false; +} + +static const struct regmap_config wsa_regmap_config = { + .name = "wsa_macro", + .reg_bits = 16, + .val_bits = 32, /* 8 but with 32 bit read/write */ + .reg_stride = 4, + .cache_type = REGCACHE_FLAT, + .reg_defaults = wsa_defaults, + .num_reg_defaults = ARRAY_SIZE(wsa_defaults), + .max_register = WSA_MAX_OFFSET, + .writeable_reg = wsa_is_writeable_register, + .volatile_reg = wsa_is_volatile_register, + .readable_reg = wsa_is_readable_register, +}; + +/** + * wsa_macro_set_spkr_mode - Configures speaker compander and smartboost + * settings based on speaker mode. + * + * @component: codec instance + * @mode: Indicates speaker configuration mode. + * + * Returns 0 on success or -EINVAL on error. + */ +int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode) +{ + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + wsa->spkr_mode = mode; + + switch (mode) { + case WSA_MACRO_SPKR_MODE_1: + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00); + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x00); + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00); + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x00); + snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x44); + snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x44); + break; + default: + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80); + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80); + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01); + snd_soc_component_update_bits(component, CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01); + snd_soc_component_update_bits(component, CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x58); + snd_soc_component_update_bits(component, CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x58); + break; + } + return 0; +} +EXPORT_SYMBOL(wsa_macro_set_spkr_mode); + +static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 int_prim_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp; + u32 j, port; + u16 int_mux_cfg0, int_mux_cfg1; + u16 int_fs_reg; + u8 int_mux_cfg0_val, int_mux_cfg1_val; + u8 inp0_sel, inp1_sel, inp2_sel; + struct snd_soc_component *component = dai->component; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + for_each_set_bit(port, &wsa->active_ch_mask[dai->id], WSA_MACRO_RX_MAX) { + int_1_mix1_inp = port; + if ((int_1_mix1_inp < WSA_MACRO_RX0) || (int_1_mix1_inp > WSA_MACRO_RX_MIX1)) { + dev_err(component->dev, "%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the cdc_dma rx port + * is connected + */ + for (j = 0; j < NUM_INTERPOLATORS; j++) { + int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET; + int_mux_cfg0_val = snd_soc_component_read(component, + int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1; + inp1_sel = (int_mux_cfg0_val >> WSA_MACRO_MUX_INP_SHFT) & + WSA_MACRO_MUX_INP_MASK1; + inp2_sel = (int_mux_cfg1_val >> WSA_MACRO_MUX_INP_SHFT) & + WSA_MACRO_MUX_INP_MASK1; + if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || + (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) { + int_fs_reg = CDC_WSA_RX0_RX_PATH_CTL + + WSA_MACRO_RX_PATH_OFFSET * j; + /* sample_rate is in Hz */ + snd_soc_component_update_bits(component, int_fs_reg, + WSA_MACRO_FS_RATE_MASK, + int_prim_fs_rate_reg_val); + } + int_mux_cfg0 += WSA_MACRO_MUX_CFG_OFFSET; + } + } + + return 0; +} + +static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 int_mix_fs_rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp; + u32 j, port; + u16 int_mux_cfg1, int_fs_reg; + u8 int_mux_cfg1_val; + struct snd_soc_component *component = dai->component; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + for_each_set_bit(port, &wsa->active_ch_mask[dai->id], WSA_MACRO_RX_MAX) { + int_2_inp = port; + if ((int_2_inp < WSA_MACRO_RX0) || (int_2_inp > WSA_MACRO_RX_MIX1)) { + dev_err(component->dev, "%s: Invalid RX port, Dai ID is %d\n", + __func__, dai->id); + return -EINVAL; + } + + int_mux_cfg1 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < NUM_INTERPOLATORS; j++) { + int_mux_cfg1_val = snd_soc_component_read(component, + int_mux_cfg1) & + WSA_MACRO_MUX_INP_MASK1; + if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) { + int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL + + WSA_MACRO_RX_PATH_OFFSET * j; + + snd_soc_component_update_bits(component, + int_fs_reg, + WSA_MACRO_FS_RATE_MASK, + int_mix_fs_rate_reg_val); + } + int_mux_cfg1 += WSA_MACRO_MUX_CFG_OFFSET; + } + } + return 0; +} + +static int wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + int rate_val = 0; + int i, ret; + + /* set mixing path rate */ + for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) { + if (sample_rate == int_mix_sample_rate_val[i].sample_rate) { + rate_val = int_mix_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) || (rate_val < 0)) + goto prim_rate; + + ret = wsa_macro_set_mix_interpolator_rate(dai, (u8) rate_val, sample_rate); +prim_rate: + /* set primary path sample rate */ + for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) { + if (sample_rate == int_prim_sample_rate_val[i].sample_rate) { + rate_val = int_prim_sample_rate_val[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) || (rate_val < 0)) + return -EINVAL; + + ret = wsa_macro_set_prim_interpolator_rate(dai, (u8) rate_val, sample_rate); + + return ret; +} + +static int wsa_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + int ret; + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = wsa_macro_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err(component->dev, + "%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + break; + default: + break; + } + return 0; +} + +static int wsa_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + u16 val, mask = 0, cnt = 0, temp; + + switch (dai->id) { + case WSA_MACRO_AIF_VI: + *tx_slot = wsa->active_ch_mask[dai->id]; + *tx_num = wsa->active_ch_cnt[dai->id]; + break; + case WSA_MACRO_AIF1_PB: + case WSA_MACRO_AIF_MIX1_PB: + for_each_set_bit(temp, &wsa->active_ch_mask[dai->id], + WSA_MACRO_RX_MAX) { + mask |= (1 << temp); + if (++cnt == WSA_MACRO_MAX_DMA_CH_PER_PORT) + break; + } + if (mask & 0x0C) + mask = mask >> 0x2; + *rx_slot = mask; + *rx_num = cnt; + break; + case WSA_MACRO_AIF_ECHO: + val = snd_soc_component_read(component, CDC_WSA_RX_INP_MUX_RX_MIX_CFG0); + if (val & WSA_MACRO_EC_MIX_TX1_MASK) { + mask |= 0x2; + cnt++; + } + if (val & WSA_MACRO_EC_MIX_TX0_MASK) { + mask |= 0x1; + cnt++; + } + *tx_slot = mask; + *tx_num = cnt; + break; + default: + dev_err(component->dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static struct snd_soc_dai_ops wsa_macro_dai_ops = { + .hw_params = wsa_macro_hw_params, + .get_channel_map = wsa_macro_get_channel_map, +}; + +static struct snd_soc_dai_driver wsa_macro_dai[] = { + { + .name = "wsa_macro_rx1", + .id = WSA_MACRO_AIF1_PB, + .playback = { + .stream_name = "WSA_AIF1 Playback", + .rates = WSA_MACRO_RX_RATES, + .formats = WSA_MACRO_RX_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_rx_mix", + .id = WSA_MACRO_AIF_MIX1_PB, + .playback = { + .stream_name = "WSA_AIF_MIX1 Playback", + .rates = WSA_MACRO_RX_MIX_RATES, + .formats = WSA_MACRO_RX_FORMATS, + .rate_max = 192000, + .rate_min = 48000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_vifeedback", + .id = WSA_MACRO_AIF_VI, + .capture = { + .stream_name = "WSA_AIF_VI Capture", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000, + .formats = WSA_MACRO_RX_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wsa_macro_dai_ops, + }, + { + .name = "wsa_macro_echo", + .id = WSA_MACRO_AIF_ECHO, + .capture = { + .stream_name = "WSA_AIF_ECHO Capture", + .rates = WSA_MACRO_ECHO_RATES, + .formats = WSA_MACRO_ECHO_FORMATS, + .rate_max = 48000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wsa_macro_dai_ops, + }, +}; + +static void wsa_macro_mclk_enable(struct wsa_macro *wsa, bool mclk_enable) +{ + struct regmap *regmap = wsa->regmap; + + if (mclk_enable) { + if (wsa->wsa_mclk_users == 0) { + regcache_mark_dirty(regmap); + regcache_sync(regmap); + /* 9.6MHz MCLK, set value 0x00 if other frequency */ + regmap_update_bits(regmap, CDC_WSA_TOP_FREQ_MCLK, 0x01, 0x01); + regmap_update_bits(regmap, + CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, + CDC_WSA_MCLK_EN_MASK, + CDC_WSA_MCLK_ENABLE); + regmap_update_bits(regmap, + CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + CDC_WSA_FS_CNT_EN_MASK, + CDC_WSA_FS_CNT_ENABLE); + } + wsa->wsa_mclk_users++; + } else { + if (wsa->wsa_mclk_users <= 0) { + dev_err(wsa->dev, "clock already disabled\n"); + wsa->wsa_mclk_users = 0; + return; + } + wsa->wsa_mclk_users--; + if (wsa->wsa_mclk_users == 0) { + regmap_update_bits(regmap, + CDC_WSA_CLK_RST_CTRL_FS_CNT_CONTROL, + CDC_WSA_FS_CNT_EN_MASK, + CDC_WSA_FS_CNT_DISABLE); + regmap_update_bits(regmap, + CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, + CDC_WSA_MCLK_EN_MASK, + CDC_WSA_MCLK_DISABLE); + } + } +} + +static int wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + int ec_tx = ((struct soc_mixer_control *) kcontrol->private_value)->shift; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wsa->ec_hq[ec_tx]; + + return 0; +} + +static int wsa_macro_set_ec_hq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + int ec_tx = ((struct soc_mixer_control *) kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + wsa->ec_hq[ec_tx] = value; + + return 0; +} + +static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wsa->comp_enabled[comp]; + return 0; +} + +static int wsa_macro_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + wsa->comp_enabled[comp] = value; + + return 0; +} + +static int wsa_macro_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wsa->ear_spkr_gain; + + return 0; +} + +static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + wsa->ear_spkr_gain = ucontrol->value.integer.value[0]; + + return 0; +} + +static int wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + int path = ((struct soc_mixer_control *)kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = wsa->is_softclip_on[path]; + + return 0; +} + +static int wsa_macro_soft_clip_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + int path = ((struct soc_mixer_control *) kcontrol->private_value)->shift; + + wsa->is_softclip_on[path] = ucontrol->value.integer.value[0]; + + return 0; +} + +static const struct snd_kcontrol_new wsa_macro_snd_controls[] = { + SOC_ENUM_EXT("EAR SPKR PA Gain", wsa_macro_ear_spkr_pa_gain_enum, + wsa_macro_ear_spkr_pa_gain_get, + wsa_macro_ear_spkr_pa_gain_put), + SOC_SINGLE_EXT("WSA_Softclip0 Enable", SND_SOC_NOPM, + WSA_MACRO_SOFTCLIP0, 1, 0, + wsa_macro_soft_clip_enable_get, + wsa_macro_soft_clip_enable_put), + SOC_SINGLE_EXT("WSA_Softclip1 Enable", SND_SOC_NOPM, + WSA_MACRO_SOFTCLIP1, 1, 0, + wsa_macro_soft_clip_enable_get, + wsa_macro_soft_clip_enable_put), + + SOC_SINGLE_S8_TLV("WSA_RX0 Digital Volume", CDC_WSA_RX0_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("WSA_RX1 Digital Volume", CDC_WSA_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + + SOC_SINGLE("WSA_RX0 Digital Mute", CDC_WSA_RX0_RX_PATH_CTL, 4, 1, 0), + SOC_SINGLE("WSA_RX1 Digital Mute", CDC_WSA_RX1_RX_PATH_CTL, 4, 1, 0), + SOC_SINGLE("WSA_RX0_MIX Digital Mute", CDC_WSA_RX0_RX_PATH_MIX_CTL, 4, + 1, 0), + SOC_SINGLE("WSA_RX1_MIX Digital Mute", CDC_WSA_RX1_RX_PATH_MIX_CTL, 4, + 1, 0), + SOC_SINGLE_EXT("WSA_COMP1 Switch", SND_SOC_NOPM, WSA_MACRO_COMP1, 1, 0, + wsa_macro_get_compander, wsa_macro_set_compander), + SOC_SINGLE_EXT("WSA_COMP2 Switch", SND_SOC_NOPM, WSA_MACRO_COMP2, 1, 0, + wsa_macro_get_compander, wsa_macro_set_compander), + SOC_SINGLE_EXT("WSA_RX0 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX0, 1, 0, + wsa_macro_get_ec_hq, wsa_macro_set_ec_hq), + SOC_SINGLE_EXT("WSA_RX1 EC_HQ Switch", SND_SOC_NOPM, WSA_MACRO_RX1, 1, 0, + wsa_macro_get_ec_hq, wsa_macro_set_ec_hq), +}; + +static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) +{ + struct regmap *regmap = wsa->regmap; + + if (enable) { + wsa_macro_mclk_enable(wsa, true); + + /* reset swr ip */ + if (wsa->reset_swr) + regmap_update_bits(regmap, + CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + CDC_WSA_SWR_RST_EN_MASK, + CDC_WSA_SWR_RST_ENABLE); + + regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + CDC_WSA_SWR_CLK_EN_MASK, + CDC_WSA_SWR_CLK_ENABLE); + + /* Bring out of reset */ + if (wsa->reset_swr) + regmap_update_bits(regmap, + CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + CDC_WSA_SWR_RST_EN_MASK, + CDC_WSA_SWR_RST_DISABLE); + wsa->reset_swr = false; + } else { + regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, + CDC_WSA_SWR_CLK_EN_MASK, 0); + wsa_macro_mclk_enable(wsa, false); + } + + return 0; +} + +static int wsa_macro_component_probe(struct snd_soc_component *comp) +{ + struct wsa_macro *wsa = snd_soc_component_get_drvdata(comp); + + snd_soc_component_init_regmap(comp, wsa->regmap); + + wsa->spkr_gain_offset = WSA_MACRO_GAIN_OFFSET_M1P5_DB; + + /* set SPKR rate to FS_2P4_3P072 */ + snd_soc_component_update_bits(comp, CDC_WSA_RX0_RX_PATH_CFG1, + CDC_WSA_RX_PATH_SPKR_RATE_MASK, + CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072); + + snd_soc_component_update_bits(comp, CDC_WSA_RX1_RX_PATH_CFG1, + CDC_WSA_RX_PATH_SPKR_RATE_MASK, + CDC_WSA_RX_PATH_SPKR_RATE_FS_2P4_3P072); + + wsa_macro_set_spkr_mode(comp, WSA_MACRO_SPKR_MODE_1); + + return 0; +} + +static int swclk_gate_enable(struct clk_hw *hw) +{ + return wsa_swrm_clock(to_wsa_macro(hw), true); +} + +static void swclk_gate_disable(struct clk_hw *hw) +{ + wsa_swrm_clock(to_wsa_macro(hw), false); +} + +static int swclk_gate_is_enabled(struct clk_hw *hw) +{ + struct wsa_macro *wsa = to_wsa_macro(hw); + int ret, val; + + regmap_read(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, &val); + ret = val & BIT(0); + + return ret; +} + +static unsigned long swclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate / 2; +} + +static const struct clk_ops swclk_gate_ops = { + .prepare = swclk_gate_enable, + .unprepare = swclk_gate_disable, + .is_enabled = swclk_gate_is_enabled, + .recalc_rate = swclk_recalc_rate, +}; + +static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa) +{ + struct device *dev = wsa->dev; + struct device_node *np = dev->of_node; + const char *parent_clk_name; + const char *clk_name = "mclk"; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + parent_clk_name = __clk_get_name(wsa->clks[2].clk); + + init.name = clk_name; + init.ops = &swclk_gate_ops; + init.flags = 0; + init.parent_names = &parent_clk_name; + init.num_parents = 1; + wsa->hw.init = &init; + hw = &wsa->hw; + ret = clk_hw_register(wsa->dev, hw); + if (ret) + return ERR_PTR(ret); + + of_clk_add_provider(np, of_clk_src_simple_get, hw->clk); + + return NULL; +} + +static const struct snd_soc_component_driver wsa_macro_component_drv = { + .name = "WSA MACRO", + .probe = wsa_macro_component_probe, + .controls = wsa_macro_snd_controls, + .num_controls = ARRAY_SIZE(wsa_macro_snd_controls), +}; + +static int wsa_macro_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct wsa_macro *wsa; + void __iomem *base; + int ret; + + wsa = devm_kzalloc(dev, sizeof(*wsa), GFP_KERNEL); + if (!wsa) + return -ENOMEM; + + wsa->clks[0].id = "macro"; + wsa->clks[1].id = "dcodec"; + wsa->clks[2].id = "mclk"; + wsa->clks[3].id = "npl"; + wsa->clks[4].id = "fsgen"; + + ret = devm_clk_bulk_get(dev, WSA_NUM_CLKS_MAX, wsa->clks); + if (ret) { + dev_err(dev, "Error getting WSA Clocks (%d)\n", ret); + return ret; + } + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + wsa->regmap = devm_regmap_init_mmio(dev, base, &wsa_regmap_config); + + dev_set_drvdata(dev, wsa); + + wsa->reset_swr = true; + wsa->dev = dev; + + /* set MCLK and NPL rates */ + clk_set_rate(wsa->clks[2].clk, WSA_MACRO_MCLK_FREQ); + clk_set_rate(wsa->clks[3].clk, WSA_MACRO_MCLK_FREQ); + + ret = clk_bulk_prepare_enable(WSA_NUM_CLKS_MAX, wsa->clks); + if (ret) + return ret; + + wsa_macro_register_mclk_output(wsa); + + ret = devm_snd_soc_register_component(dev, &wsa_macro_component_drv, + wsa_macro_dai, + ARRAY_SIZE(wsa_macro_dai)); + if (ret) + goto err; + + return ret; +err: + clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks); + + return ret; + +} + +static int wsa_macro_remove(struct platform_device *pdev) +{ + struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev); + + of_clk_del_provider(pdev->dev.of_node); + + clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks); + + return 0; +} + +static const struct of_device_id wsa_macro_dt_match[] = { + {.compatible = "qcom,sm8250-lpass-wsa-macro"}, + {} +}; +MODULE_DEVICE_TABLE(of, wsa_macro_dt_match); + +static struct platform_driver wsa_macro_driver = { + .driver = { + .name = "wsa_macro", + .of_match_table = wsa_macro_dt_match, + }, + .probe = wsa_macro_probe, + .remove = wsa_macro_remove, +}; + +module_platform_driver(wsa_macro_driver); +MODULE_DESCRIPTION("WSA macro driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/lpass-wsa-macro.h b/sound/soc/codecs/lpass-wsa-macro.h new file mode 100644 index 000000000000..d3d62b3f6500 --- /dev/null +++ b/sound/soc/codecs/lpass-wsa-macro.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LPASS_WSA_MACRO_H__ +#define __LPASS_WSA_MACRO_H__ + +/* + * Selects compander and smart boost settings + * for a given speaker mode + */ +enum { + WSA_MACRO_SPKR_MODE_DEFAULT, + WSA_MACRO_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */ +}; + +int wsa_macro_set_spkr_mode(struct snd_soc_component *component, int mode); + +#endif /* __LPASS_WSA_MACRO_H__ */ -- cgit v1.2.3 From 2c4066e5d428d47a28f87407b3d73ebe40c06fd4 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 5 Nov 2020 11:34:55 +0000 Subject: ASoC: codecs: lpass-wsa-macro: add dapm widgets and route This patch adds dapm widgets and routes on this codec Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201105113458.12360-4-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 1081 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1081 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 76873d582eff..25f1df214ca5 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -354,6 +354,26 @@ struct wsa_macro { static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); +static const char *const rx_text[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "DEC0", "DEC1" +}; + +static const char *const rx_mix_text[] = { + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1" +}; + +static const char *const rx_mix_ec_text[] = { + "ZERO", "RX_MIX_TX0", "RX_MIX_TX1" +}; + +static const char *const rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF_MIX1_PB" +}; + +static const char *const rx_sidetone_mix_text[] = { + "ZERO", "SRC0" +}; + static const char * const wsa_macro_ear_spkr_pa_gain_text[] = { "G_DEFAULT", "G_0_DB", "G_1_DB", "G_2_DB", "G_3_DB", "G_4_DB", "G_5_DB", "G_6_DB" @@ -362,6 +382,84 @@ static const char * const wsa_macro_ear_spkr_pa_gain_text[] = { static SOC_ENUM_SINGLE_EXT_DECL(wsa_macro_ear_spkr_pa_gain_enum, wsa_macro_ear_spkr_pa_gain_text); +/* RX INT0 */ +static const struct soc_enum rx0_prim_inp0_chain_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 0, 7, rx_text); + +static const struct soc_enum rx0_prim_inp1_chain_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG0, + 3, 7, rx_text); + +static const struct soc_enum rx0_prim_inp2_chain_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 3, 7, rx_text); + +static const struct soc_enum rx0_mix_chain_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT0_CFG1, + 0, 5, rx_mix_text); + +static const struct soc_enum rx0_sidetone_mix_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text); + +static const struct snd_kcontrol_new rx0_prim_inp0_mux = + SOC_DAPM_ENUM("WSA_RX0 INP0 Mux", rx0_prim_inp0_chain_enum); + +static const struct snd_kcontrol_new rx0_prim_inp1_mux = + SOC_DAPM_ENUM("WSA_RX0 INP1 Mux", rx0_prim_inp1_chain_enum); + +static const struct snd_kcontrol_new rx0_prim_inp2_mux = + SOC_DAPM_ENUM("WSA_RX0 INP2 Mux", rx0_prim_inp2_chain_enum); + +static const struct snd_kcontrol_new rx0_mix_mux = + SOC_DAPM_ENUM("WSA_RX0 MIX Mux", rx0_mix_chain_enum); + +static const struct snd_kcontrol_new rx0_sidetone_mix_mux = + SOC_DAPM_ENUM("WSA_RX0 SIDETONE MIX Mux", rx0_sidetone_mix_enum); + +/* RX INT1 */ +static const struct soc_enum rx1_prim_inp0_chain_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 0, 7, rx_text); + +static const struct soc_enum rx1_prim_inp1_chain_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG0, + 3, 7, rx_text); + +static const struct soc_enum rx1_prim_inp2_chain_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 3, 7, rx_text); + +static const struct soc_enum rx1_mix_chain_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_INT1_CFG1, + 0, 5, rx_mix_text); + +static const struct snd_kcontrol_new rx1_prim_inp0_mux = + SOC_DAPM_ENUM("WSA_RX1 INP0 Mux", rx1_prim_inp0_chain_enum); + +static const struct snd_kcontrol_new rx1_prim_inp1_mux = + SOC_DAPM_ENUM("WSA_RX1 INP1 Mux", rx1_prim_inp1_chain_enum); + +static const struct snd_kcontrol_new rx1_prim_inp2_mux = + SOC_DAPM_ENUM("WSA_RX1 INP2 Mux", rx1_prim_inp2_chain_enum); + +static const struct snd_kcontrol_new rx1_mix_mux = + SOC_DAPM_ENUM("WSA_RX1 MIX Mux", rx1_mix_chain_enum); + +static const struct soc_enum rx_mix_ec0_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, + 0, 3, rx_mix_ec_text); + +static const struct soc_enum rx_mix_ec1_enum = + SOC_ENUM_SINGLE(CDC_WSA_RX_INP_MUX_RX_MIX_CFG0, + 3, 3, rx_mix_ec_text); + +static const struct snd_kcontrol_new rx_mix_ec0_mux = + SOC_DAPM_ENUM("WSA RX_MIX EC0_Mux", rx_mix_ec0_enum); + +static const struct snd_kcontrol_new rx_mix_ec1_mux = + SOC_DAPM_ENUM("WSA RX_MIX EC1_Mux", rx_mix_ec1_enum); + static const struct reg_default wsa_defaults[] = { /* WSA Macro */ { CDC_WSA_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, @@ -1038,6 +1136,613 @@ static void wsa_macro_mclk_enable(struct wsa_macro *wsa, bool mclk_enable) } } +static int wsa_macro_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + wsa_macro_mclk_enable(wsa, event == SND_SOC_DAPM_PRE_PMU); + return 0; +} + +static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + u32 tx_reg0, tx_reg1; + + if (test_bit(WSA_MACRO_TX0, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + tx_reg0 = CDC_WSA_TX0_SPKR_PROT_PATH_CTL; + tx_reg1 = CDC_WSA_TX1_SPKR_PROT_PATH_CTL; + } else if (test_bit(WSA_MACRO_TX1, &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + tx_reg0 = CDC_WSA_TX2_SPKR_PROT_PATH_CTL; + tx_reg1 = CDC_WSA_TX3_SPKR_PROT_PATH_CTL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Enable V&I sensing */ + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_RESET); + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_RESET); + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK, + CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K); + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_PCM_RATE_MASK, + CDC_WSA_TX_SPKR_PROT_PCM_RATE_8K); + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK, + CDC_WSA_TX_SPKR_PROT_CLK_ENABLE); + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK, + CDC_WSA_TX_SPKR_PROT_CLK_ENABLE); + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_NO_RESET); + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_NO_RESET); + break; + case SND_SOC_DAPM_POST_PMD: + /* Disable V&I sensing */ + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_RESET); + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_RESET_MASK, + CDC_WSA_TX_SPKR_PROT_RESET); + snd_soc_component_update_bits(component, tx_reg0, + CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK, + CDC_WSA_TX_SPKR_PROT_CLK_DISABLE); + snd_soc_component_update_bits(component, tx_reg1, + CDC_WSA_TX_SPKR_PROT_CLK_EN_MASK, + CDC_WSA_TX_SPKR_PROT_CLK_DISABLE); + break; + } + + return 0; +} + +static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + int val; + + switch (w->reg) { + case CDC_WSA_RX0_RX_PATH_MIX_CTL: + gain_reg = CDC_WSA_RX0_RX_VOL_MIX_CTL; + break; + case CDC_WSA_RX1_RX_PATH_MIX_CTL: + gain_reg = CDC_WSA_RX1_RX_VOL_MIX_CTL; + break; + default: + return 0; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = snd_soc_component_read(component, gain_reg); + snd_soc_component_write(component, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, w->reg, + CDC_WSA_RX_PATH_MIX_CLK_EN_MASK, + CDC_WSA_RX_PATH_MIX_CLK_DISABLE); + break; + } + + return 0; +} + +static void wsa_macro_hd2_control(struct snd_soc_component *component, + u16 reg, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg; + + if (reg == CDC_WSA_RX0_RX_PATH_CTL) { + hd2_scale_reg = CDC_WSA_RX0_RX_PATH_SEC3; + hd2_enable_reg = CDC_WSA_RX0_RX_PATH_CFG0; + } + if (reg == CDC_WSA_RX1_RX_PATH_CTL) { + hd2_scale_reg = CDC_WSA_RX1_RX_PATH_SEC3; + hd2_enable_reg = CDC_WSA_RX1_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + CDC_WSA_RX_PATH_HD2_ALPHA_MASK, + 0x10); + snd_soc_component_update_bits(component, hd2_scale_reg, + CDC_WSA_RX_PATH_HD2_SCALE_MASK, + 0x1); + snd_soc_component_update_bits(component, hd2_enable_reg, + CDC_WSA_RX_PATH_HD2_EN_MASK, + CDC_WSA_RX_PATH_HD2_ENABLE); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + CDC_WSA_RX_PATH_HD2_EN_MASK, 0); + snd_soc_component_update_bits(component, hd2_scale_reg, + CDC_WSA_RX_PATH_HD2_SCALE_MASK, + 0); + snd_soc_component_update_bits(component, hd2_scale_reg, + CDC_WSA_RX_PATH_HD2_ALPHA_MASK, + 0); + } +} + +static int wsa_macro_config_compander(struct snd_soc_component *component, + int comp, int event) +{ + u16 comp_ctl0_reg, rx_path_cfg0_reg; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + if (!wsa->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = CDC_WSA_COMPANDER0_CTL0 + + (comp * WSA_MACRO_RX_COMP_OFFSET); + rx_path_cfg0_reg = CDC_WSA_RX0_RX_PATH_CFG0 + + (comp * WSA_MACRO_RX_PATH_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + CDC_WSA_COMPANDER_CLK_EN_MASK, + CDC_WSA_COMPANDER_CLK_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + CDC_WSA_COMPANDER_SOFT_RST_MASK, + CDC_WSA_COMPANDER_SOFT_RST_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + CDC_WSA_COMPANDER_SOFT_RST_MASK, + 0); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + CDC_WSA_RX_PATH_COMP_EN_MASK, + CDC_WSA_RX_PATH_COMP_ENABLE); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + CDC_WSA_COMPANDER_HALT_MASK, + CDC_WSA_COMPANDER_HALT); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + CDC_WSA_RX_PATH_COMP_EN_MASK, 0); + snd_soc_component_update_bits(component, comp_ctl0_reg, + CDC_WSA_COMPANDER_SOFT_RST_MASK, + CDC_WSA_COMPANDER_SOFT_RST_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + CDC_WSA_COMPANDER_SOFT_RST_MASK, + 0); + snd_soc_component_update_bits(component, comp_ctl0_reg, + CDC_WSA_COMPANDER_CLK_EN_MASK, 0); + snd_soc_component_update_bits(component, comp_ctl0_reg, + CDC_WSA_COMPANDER_HALT_MASK, 0); + } + + return 0; +} + +static void wsa_macro_enable_softclip_clk(struct snd_soc_component *component, + struct wsa_macro *wsa, + int path, + bool enable) +{ + u16 softclip_clk_reg = CDC_WSA_SOFTCLIP0_CRC + + (path * WSA_MACRO_RX_SOFTCLIP_OFFSET); + u8 softclip_mux_mask = (1 << path); + u8 softclip_mux_value = (1 << path); + + if (enable) { + if (wsa->softclip_clk_users[path] == 0) { + snd_soc_component_update_bits(component, + softclip_clk_reg, + CDC_WSA_SOFTCLIP_CLK_EN_MASK, + CDC_WSA_SOFTCLIP_CLK_ENABLE); + snd_soc_component_update_bits(component, + CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, + softclip_mux_mask, softclip_mux_value); + } + wsa->softclip_clk_users[path]++; + } else { + wsa->softclip_clk_users[path]--; + if (wsa->softclip_clk_users[path] == 0) { + snd_soc_component_update_bits(component, + softclip_clk_reg, + CDC_WSA_SOFTCLIP_CLK_EN_MASK, + 0); + snd_soc_component_update_bits(component, + CDC_WSA_RX_INP_MUX_SOFTCLIP_CFG0, + softclip_mux_mask, 0x00); + } + } +} + +static int wsa_macro_config_softclip(struct snd_soc_component *component, + int path, int event) +{ + u16 softclip_ctrl_reg; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + int softclip_path = 0; + + if (path == WSA_MACRO_COMP1) + softclip_path = WSA_MACRO_SOFTCLIP0; + else if (path == WSA_MACRO_COMP2) + softclip_path = WSA_MACRO_SOFTCLIP1; + + if (!wsa->is_softclip_on[softclip_path]) + return 0; + + softclip_ctrl_reg = CDC_WSA_SOFTCLIP0_SOFTCLIP_CTRL + + (softclip_path * WSA_MACRO_RX_SOFTCLIP_OFFSET); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Softclip clock and mux */ + wsa_macro_enable_softclip_clk(component, wsa, softclip_path, + true); + /* Enable Softclip control */ + snd_soc_component_update_bits(component, softclip_ctrl_reg, + CDC_WSA_SOFTCLIP_EN_MASK, + CDC_WSA_SOFTCLIP_ENABLE); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, softclip_ctrl_reg, + CDC_WSA_SOFTCLIP_EN_MASK, 0); + wsa_macro_enable_softclip_clk(component, wsa, softclip_path, + false); + } + + return 0; +} + +static bool wsa_macro_adie_lb(struct snd_soc_component *component, + int interp_idx) +{ + u16 int_mux_cfg0, int_mux_cfg1; + u8 int_mux_cfg0_val, int_mux_cfg1_val; + u8 int_n_inp0, int_n_inp1, int_n_inp2; + + int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; + int_mux_cfg1 = int_mux_cfg0 + 4; + int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1); + + int_n_inp0 = int_mux_cfg0_val & 0x0F; + if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || + int_n_inp0 == INTn_1_INP_SEL_DEC1) + return true; + + int_n_inp1 = int_mux_cfg0_val >> 4; + if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || + int_n_inp1 == INTn_1_INP_SEL_DEC1) + return true; + + int_n_inp2 = int_mux_cfg1_val >> 4; + if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || + int_n_inp2 == INTn_1_INP_SEL_DEC1) + return true; + + return false; +} + +static int wsa_macro_enable_main_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u16 reg; + + reg = CDC_WSA_RX0_RX_PATH_CTL + WSA_MACRO_RX_PATH_OFFSET * w->shift; + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wsa_macro_adie_lb(component, w->shift)) { + snd_soc_component_update_bits(component, reg, + CDC_WSA_RX_PATH_CLK_EN_MASK, + CDC_WSA_RX_PATH_CLK_ENABLE); + } + break; + default: + break; + } + return 0; +} + +static int wsa_macro_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg = 0; + + switch (reg) { + case CDC_WSA_RX0_RX_PATH_CTL: + case CDC_WSA_RX0_RX_PATH_MIX_CTL: + prim_int_reg = CDC_WSA_RX0_RX_PATH_CTL; + *ind = 0; + break; + case CDC_WSA_RX1_RX_PATH_CTL: + case CDC_WSA_RX1_RX_PATH_MIX_CTL: + prim_int_reg = CDC_WSA_RX1_RX_PATH_CTL; + *ind = 1; + break; + } + + return prim_int_reg; +} + +static int wsa_macro_enable_prim_interpolator(struct snd_soc_component *component, + u16 reg, int event) +{ + u16 prim_int_reg; + u16 ind = 0; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + prim_int_reg = wsa_macro_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wsa->prim_int_users[ind]++; + if (wsa->prim_int_users[ind] == 1) { + snd_soc_component_update_bits(component, + prim_int_reg + WSA_MACRO_RX_PATH_CFG3_OFFSET, + CDC_WSA_RX_DC_DCOEFF_MASK, + 0x3); + snd_soc_component_update_bits(component, prim_int_reg, + CDC_WSA_RX_PATH_PGA_MUTE_EN_MASK, + CDC_WSA_RX_PATH_PGA_MUTE_ENABLE); + wsa_macro_hd2_control(component, prim_int_reg, event); + snd_soc_component_update_bits(component, + prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET, + CDC_WSA_RX_DSMDEM_CLK_EN_MASK, + CDC_WSA_RX_DSMDEM_CLK_ENABLE); + } + if ((reg != prim_int_reg) && + ((snd_soc_component_read( + component, prim_int_reg)) & 0x10)) + snd_soc_component_update_bits(component, reg, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + wsa->prim_int_users[ind]--; + if (wsa->prim_int_users[ind] == 0) { + snd_soc_component_update_bits(component, + prim_int_reg + WSA_MACRO_RX_PATH_DSMDEM_OFFSET, + CDC_WSA_RX_DSMDEM_CLK_EN_MASK, 0); + wsa_macro_hd2_control(component, prim_int_reg, event); + } + break; + } + + return 0; +} + +static int wsa_macro_config_ear_spkr_gain(struct snd_soc_component *component, + struct wsa_macro *wsa, + int event, int gain_reg) +{ + int comp_gain_offset, val; + + switch (wsa->spkr_mode) { + /* Compander gain in WSA_MACRO_SPKR_MODE1 case is 12 dB */ + case WSA_MACRO_SPKR_MODE_1: + comp_gain_offset = -12; + break; + /* Default case compander gain is 15 dB */ + default: + comp_gain_offset = -15; + break; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Apply ear spkr gain only if compander is enabled */ + if (wsa->comp_enabled[WSA_MACRO_COMP1] && + (gain_reg == CDC_WSA_RX0_RX_VOL_CTL) && + (wsa->ear_spkr_gain != 0)) { + /* For example, val is -8(-12+5-1) for 4dB of gain */ + val = comp_gain_offset + wsa->ear_spkr_gain - 1; + snd_soc_component_write(component, gain_reg, val); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* + * Reset RX0 volume to 0 dB if compander is enabled and + * ear_spkr_gain is non-zero. + */ + if (wsa->comp_enabled[WSA_MACRO_COMP1] && + (gain_reg == CDC_WSA_RX0_RX_VOL_CTL) && + (wsa->ear_spkr_gain != 0)) { + snd_soc_component_write(component, gain_reg, 0x0); + } + break; + } + + return 0; +} + +static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + u16 reg; + int val; + int offset_val = 0; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + if (w->shift == WSA_MACRO_COMP1) { + reg = CDC_WSA_RX0_RX_PATH_CTL; + gain_reg = CDC_WSA_RX0_RX_VOL_CTL; + } else if (w->shift == WSA_MACRO_COMP2) { + reg = CDC_WSA_RX1_RX_PATH_CTL; + gain_reg = CDC_WSA_RX1_RX_VOL_CTL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reset if needed */ + wsa_macro_enable_prim_interpolator(component, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + wsa_macro_config_compander(component, w->shift, event); + wsa_macro_config_softclip(component, w->shift, event); + /* apply gain after int clk is enabled */ + if ((wsa->spkr_gain_offset == WSA_MACRO_GAIN_OFFSET_M1P5_DB) && + (wsa->comp_enabled[WSA_MACRO_COMP1] || + wsa->comp_enabled[WSA_MACRO_COMP2])) { + snd_soc_component_update_bits(component, + CDC_WSA_RX0_RX_PATH_SEC1, + CDC_WSA_RX_PGA_HALF_DB_MASK, + CDC_WSA_RX_PGA_HALF_DB_ENABLE); + snd_soc_component_update_bits(component, + CDC_WSA_RX0_RX_PATH_MIX_SEC0, + CDC_WSA_RX_PGA_HALF_DB_MASK, + CDC_WSA_RX_PGA_HALF_DB_ENABLE); + snd_soc_component_update_bits(component, + CDC_WSA_RX1_RX_PATH_SEC1, + CDC_WSA_RX_PGA_HALF_DB_MASK, + CDC_WSA_RX_PGA_HALF_DB_ENABLE); + snd_soc_component_update_bits(component, + CDC_WSA_RX1_RX_PATH_MIX_SEC0, + CDC_WSA_RX_PGA_HALF_DB_MASK, + CDC_WSA_RX_PGA_HALF_DB_ENABLE); + offset_val = -2; + } + val = snd_soc_component_read(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + wsa_macro_config_ear_spkr_gain(component, wsa, + event, gain_reg); + break; + case SND_SOC_DAPM_POST_PMD: + wsa_macro_config_compander(component, w->shift, event); + wsa_macro_config_softclip(component, w->shift, event); + wsa_macro_enable_prim_interpolator(component, reg, event); + if ((wsa->spkr_gain_offset == WSA_MACRO_GAIN_OFFSET_M1P5_DB) && + (wsa->comp_enabled[WSA_MACRO_COMP1] || + wsa->comp_enabled[WSA_MACRO_COMP2])) { + snd_soc_component_update_bits(component, + CDC_WSA_RX0_RX_PATH_SEC1, + CDC_WSA_RX_PGA_HALF_DB_MASK, + CDC_WSA_RX_PGA_HALF_DB_DISABLE); + snd_soc_component_update_bits(component, + CDC_WSA_RX0_RX_PATH_MIX_SEC0, + CDC_WSA_RX_PGA_HALF_DB_MASK, + CDC_WSA_RX_PGA_HALF_DB_DISABLE); + snd_soc_component_update_bits(component, + CDC_WSA_RX1_RX_PATH_SEC1, + CDC_WSA_RX_PGA_HALF_DB_MASK, + CDC_WSA_RX_PGA_HALF_DB_DISABLE); + snd_soc_component_update_bits(component, + CDC_WSA_RX1_RX_PATH_MIX_SEC0, + CDC_WSA_RX_PGA_HALF_DB_MASK, + CDC_WSA_RX_PGA_HALF_DB_DISABLE); + offset_val = 2; + val = snd_soc_component_read(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + } + wsa_macro_config_ear_spkr_gain(component, wsa, + event, gain_reg); + break; + } + + return 0; +} + +static int wsa_macro_spk_boost_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u16 boost_path_ctl, boost_path_cfg1; + u16 reg, reg_mix; + + if (!strcmp(w->name, "WSA_RX INT0 CHAIN")) { + boost_path_ctl = CDC_WSA_BOOST0_BOOST_PATH_CTL; + boost_path_cfg1 = CDC_WSA_RX0_RX_PATH_CFG1; + reg = CDC_WSA_RX0_RX_PATH_CTL; + reg_mix = CDC_WSA_RX0_RX_PATH_MIX_CTL; + } else if (!strcmp(w->name, "WSA_RX INT1 CHAIN")) { + boost_path_ctl = CDC_WSA_BOOST1_BOOST_PATH_CTL; + boost_path_cfg1 = CDC_WSA_RX1_RX_PATH_CFG1; + reg = CDC_WSA_RX1_RX_PATH_CTL; + reg_mix = CDC_WSA_RX1_RX_PATH_MIX_CTL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, boost_path_cfg1, + CDC_WSA_RX_PATH_SMART_BST_EN_MASK, + CDC_WSA_RX_PATH_SMART_BST_ENABLE); + snd_soc_component_update_bits(component, boost_path_ctl, + CDC_WSA_BOOST_PATH_CLK_EN_MASK, + CDC_WSA_BOOST_PATH_CLK_ENABLE); + if ((snd_soc_component_read(component, reg_mix)) & 0x10) + snd_soc_component_update_bits(component, reg_mix, + 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(component, reg, 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, boost_path_ctl, + CDC_WSA_BOOST_PATH_CLK_EN_MASK, + CDC_WSA_BOOST_PATH_CLK_DISABLE); + snd_soc_component_update_bits(component, boost_path_cfg1, + CDC_WSA_RX_PATH_SMART_BST_EN_MASK, + CDC_WSA_RX_PATH_SMART_BST_DISABLE); + break; + } + + return 0; +} + +static int wsa_macro_enable_echo(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + u16 val, ec_tx, ec_hq_reg; + + val = snd_soc_component_read(component, CDC_WSA_RX_INP_MUX_RX_MIX_CFG0); + + switch (w->shift) { + case WSA_MACRO_EC0_MUX: + val = val & CDC_WSA_RX_MIX_TX0_SEL_MASK; + ec_tx = val - 1; + break; + case WSA_MACRO_EC1_MUX: + val = val & CDC_WSA_RX_MIX_TX1_SEL_MASK; + ec_tx = (val >> CDC_WSA_RX_MIX_TX1_SEL_SHFT) - 1; + break; + } + + if (wsa->ec_hq[ec_tx]) { + ec_hq_reg = CDC_WSA_EC_HQ0_EC_REF_HQ_PATH_CTL + 0x40 * ec_tx; + snd_soc_component_update_bits(component, ec_hq_reg, + CDC_WSA_EC_HQ_EC_CLK_EN_MASK, + CDC_WSA_EC_HQ_EC_CLK_ENABLE); + ec_hq_reg = CDC_WSA_EC_HQ0_EC_REF_HQ_CFG0 + 0x40 * ec_tx; + /* default set to 48k */ + snd_soc_component_update_bits(component, ec_hq_reg, + CDC_WSA_EC_HQ_EC_REF_PCM_RATE_MASK, + CDC_WSA_EC_HQ_EC_REF_PCM_RATE_48K); + } + + return 0; +} + static int wsa_macro_get_ec_hq(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1111,6 +1816,75 @@ static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol, return 0; } +static int wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = + wsa->rx_port_value[widget->shift]; + return 0; +} + +static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 rx_port_value = ucontrol->value.integer.value[0]; + u32 bit_input; + u32 aif_rst; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + + aif_rst = wsa->rx_port_value[widget->shift]; + if (!rx_port_value) { + if (aif_rst == 0) { + dev_err(component->dev, "%s: AIF reset already\n", __func__); + return 0; + } + if (aif_rst >= WSA_MACRO_RX_MAX) { + dev_err(component->dev, "%s: Invalid AIF reset\n", __func__); + return 0; + } + } + wsa->rx_port_value[widget->shift] = rx_port_value; + + bit_input = widget->shift; + + switch (rx_port_value) { + case 0: + if (wsa->active_ch_cnt[aif_rst]) { + clear_bit(bit_input, + &wsa->active_ch_mask[aif_rst]); + wsa->active_ch_cnt[aif_rst]--; + } + break; + case 1: + case 2: + set_bit(bit_input, + &wsa->active_ch_mask[rx_port_value]); + wsa->active_ch_cnt[rx_port_value]++; + break; + default: + dev_err(component->dev, + "%s: Invalid AIF_ID for WSA RX MUX %d\n", + __func__, rx_port_value); + return -EINVAL; + } + + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + rx_port_value, e, update); + return 0; +} + static int wsa_macro_soft_clip_enable_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1169,6 +1943,309 @@ static const struct snd_kcontrol_new wsa_macro_snd_controls[] = { wsa_macro_get_ec_hq, wsa_macro_set_ec_hq), }; +static const struct soc_enum rx_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_mux_text), rx_mux_text); + +static const struct snd_kcontrol_new rx_mux[WSA_MACRO_RX_MAX] = { + SOC_DAPM_ENUM_EXT("WSA RX0 Mux", rx_mux_enum, + wsa_macro_rx_mux_get, wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX1 Mux", rx_mux_enum, + wsa_macro_rx_mux_get, wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX_MIX0 Mux", rx_mux_enum, + wsa_macro_rx_mux_get, wsa_macro_rx_mux_put), + SOC_DAPM_ENUM_EXT("WSA RX_MIX1 Mux", rx_mux_enum, + wsa_macro_rx_mux_get, wsa_macro_rx_mux_put), +}; + +static int wsa_macro_vi_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm); + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + u32 spk_tx_id = mixer->shift; + u32 dai_id = widget->shift; + + if (test_bit(spk_tx_id, &wsa->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int wsa_macro_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm); + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); + u32 enable = ucontrol->value.integer.value[0]; + u32 spk_tx_id = mixer->shift; + + if (enable) { + if (spk_tx_id == WSA_MACRO_TX0 && + !test_bit(WSA_MACRO_TX0, + &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + set_bit(WSA_MACRO_TX0, + &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); + wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++; + } + if (spk_tx_id == WSA_MACRO_TX1 && + !test_bit(WSA_MACRO_TX1, + &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + set_bit(WSA_MACRO_TX1, + &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); + wsa->active_ch_cnt[WSA_MACRO_AIF_VI]++; + } + } else { + if (spk_tx_id == WSA_MACRO_TX0 && + test_bit(WSA_MACRO_TX0, + &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + clear_bit(WSA_MACRO_TX0, + &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); + wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--; + } + if (spk_tx_id == WSA_MACRO_TX1 && + test_bit(WSA_MACRO_TX1, + &wsa->active_ch_mask[WSA_MACRO_AIF_VI])) { + clear_bit(WSA_MACRO_TX1, + &wsa->active_ch_mask[WSA_MACRO_AIF_VI]); + wsa->active_ch_cnt[WSA_MACRO_AIF_VI]--; + } + } + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + +static const struct snd_kcontrol_new aif_vi_mixer[] = { + SOC_SINGLE_EXT("WSA_SPKR_VI_1", SND_SOC_NOPM, WSA_MACRO_TX0, 1, 0, + wsa_macro_vi_feed_mixer_get, + wsa_macro_vi_feed_mixer_put), + SOC_SINGLE_EXT("WSA_SPKR_VI_2", SND_SOC_NOPM, WSA_MACRO_TX1, 1, 0, + wsa_macro_vi_feed_mixer_get, + wsa_macro_vi_feed_mixer_put), +}; + +static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("WSA AIF1 PB", "WSA_AIF1 Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("WSA AIF_MIX1 PB", "WSA_AIF_MIX1 Playback", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT_E("WSA AIF_VI", "WSA_AIF_VI Capture", 0, + SND_SOC_NOPM, WSA_MACRO_AIF_VI, 0, + wsa_macro_enable_vi_feedback, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT("WSA AIF_ECHO", "WSA_AIF_ECHO Capture", 0, + SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MIXER("WSA_AIF_VI Mixer", SND_SOC_NOPM, WSA_MACRO_AIF_VI, + 0, aif_vi_mixer, ARRAY_SIZE(aif_vi_mixer)), + SND_SOC_DAPM_MUX_E("WSA RX_MIX EC0_MUX", SND_SOC_NOPM, + WSA_MACRO_EC0_MUX, 0, + &rx_mix_ec0_mux, wsa_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("WSA RX_MIX EC1_MUX", SND_SOC_NOPM, + WSA_MACRO_EC1_MUX, 0, + &rx_mix_ec1_mux, wsa_macro_enable_echo, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("WSA RX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX0, 0, + &rx_mux[WSA_MACRO_RX0]), + SND_SOC_DAPM_MUX("WSA RX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX1, 0, + &rx_mux[WSA_MACRO_RX1]), + SND_SOC_DAPM_MUX("WSA RX_MIX0 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX0, 0, + &rx_mux[WSA_MACRO_RX_MIX0]), + SND_SOC_DAPM_MUX("WSA RX_MIX1 MUX", SND_SOC_NOPM, WSA_MACRO_RX_MIX1, 0, + &rx_mux[WSA_MACRO_RX_MIX1]), + + SND_SOC_DAPM_MIXER("WSA RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX_MIX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA RX_MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux), + SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux), + SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux), + SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", CDC_WSA_RX0_RX_PATH_MIX_CTL, + 0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux), + SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux), + SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux), + SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", CDC_WSA_RX1_RX_PATH_MIX_CTL, + 0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0, + wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 MIX", SND_SOC_NOPM, 1, 0, NULL, 0, + wsa_macro_enable_main_path, SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_MIXER("WSA_RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("WSA_RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("WSA_RX0 INT0 SIDETONE MIX", CDC_WSA_RX0_RX_PATH_CFG1, + 4, 0, &rx0_sidetone_mix_mux), + + SND_SOC_DAPM_INPUT("WSA SRC0_INP"), + SND_SOC_DAPM_INPUT("WSA_TX DEC0_INP"), + SND_SOC_DAPM_INPUT("WSA_TX DEC1_INP"), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 INTERP", SND_SOC_NOPM, + WSA_MACRO_COMP1, 0, NULL, 0, + wsa_macro_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 INTERP", SND_SOC_NOPM, + WSA_MACRO_COMP2, 0, NULL, 0, + wsa_macro_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT0 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, wsa_macro_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("WSA_RX INT1 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, wsa_macro_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("VIINPUT_WSA"), + SND_SOC_DAPM_OUTPUT("WSA_SPK1 OUT"), + SND_SOC_DAPM_OUTPUT("WSA_SPK2 OUT"), + + SND_SOC_DAPM_SUPPLY("WSA_RX0_CLK", CDC_WSA_RX0_RX_PATH_CTL, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("WSA_RX1_CLK", CDC_WSA_RX1_RX_PATH_CTL, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("WSA_RX_MIX0_CLK", CDC_WSA_RX0_RX_PATH_MIX_CTL, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("WSA_RX_MIX1_CLK", CDC_WSA_RX1_RX_PATH_MIX_CTL, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("WSA_MCLK", 0, SND_SOC_NOPM, 0, 0, + wsa_macro_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route wsa_audio_map[] = { + /* VI Feedback */ + {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_1", "VIINPUT_WSA"}, + {"WSA_AIF_VI Mixer", "WSA_SPKR_VI_2", "VIINPUT_WSA"}, + {"WSA AIF_VI", NULL, "WSA_AIF_VI Mixer"}, + {"WSA AIF_VI", NULL, "WSA_MCLK"}, + + {"WSA RX_MIX EC0_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"}, + {"WSA RX_MIX EC1_MUX", "RX_MIX_TX0", "WSA_RX INT0 SEC MIX"}, + {"WSA RX_MIX EC0_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"}, + {"WSA RX_MIX EC1_MUX", "RX_MIX_TX1", "WSA_RX INT1 SEC MIX"}, + {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC0_MUX"}, + {"WSA AIF_ECHO", NULL, "WSA RX_MIX EC1_MUX"}, + {"WSA AIF_ECHO", NULL, "WSA_MCLK"}, + + {"WSA AIF1 PB", NULL, "WSA_MCLK"}, + {"WSA AIF_MIX1 PB", NULL, "WSA_MCLK"}, + + {"WSA RX0 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX1 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX_MIX0 MUX", "AIF1_PB", "WSA AIF1 PB"}, + {"WSA RX_MIX1 MUX", "AIF1_PB", "WSA AIF1 PB"}, + + {"WSA RX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX_MIX0 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + {"WSA RX_MIX1 MUX", "AIF_MIX1_PB", "WSA AIF_MIX1 PB"}, + + {"WSA RX0", NULL, "WSA RX0 MUX"}, + {"WSA RX1", NULL, "WSA RX1 MUX"}, + {"WSA RX_MIX0", NULL, "WSA RX_MIX0 MUX"}, + {"WSA RX_MIX1", NULL, "WSA RX_MIX1 MUX"}, + + {"WSA RX0", NULL, "WSA_RX0_CLK"}, + {"WSA RX1", NULL, "WSA_RX1_CLK"}, + {"WSA RX_MIX0", NULL, "WSA_RX_MIX0_CLK"}, + {"WSA RX_MIX1", NULL, "WSA_RX_MIX1_CLK"}, + + {"WSA_RX0 INP0", "RX0", "WSA RX0"}, + {"WSA_RX0 INP0", "RX1", "WSA RX1"}, + {"WSA_RX0 INP0", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP0", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP0", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP0", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP0"}, + + {"WSA_RX0 INP1", "RX0", "WSA RX0"}, + {"WSA_RX0 INP1", "RX1", "WSA RX1"}, + {"WSA_RX0 INP1", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP1", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP1", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP1", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP1"}, + + {"WSA_RX0 INP2", "RX0", "WSA RX0"}, + {"WSA_RX0 INP2", "RX1", "WSA RX1"}, + {"WSA_RX0 INP2", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 INP2", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX0 INP2", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX0 INP2", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT0 MIX", NULL, "WSA_RX0 INP2"}, + + {"WSA_RX0 MIX INP", "RX0", "WSA RX0"}, + {"WSA_RX0 MIX INP", "RX1", "WSA RX1"}, + {"WSA_RX0 MIX INP", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX0 MIX INP", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX0 MIX INP"}, + + {"WSA_RX INT0 SEC MIX", NULL, "WSA_RX INT0 MIX"}, + {"WSA_RX INT0 INTERP", NULL, "WSA_RX INT0 SEC MIX"}, + {"WSA_RX0 INT0 SIDETONE MIX", "SRC0", "WSA SRC0_INP"}, + {"WSA_RX INT0 INTERP", NULL, "WSA_RX0 INT0 SIDETONE MIX"}, + {"WSA_RX INT0 CHAIN", NULL, "WSA_RX INT0 INTERP"}, + + {"WSA_SPK1 OUT", NULL, "WSA_RX INT0 CHAIN"}, + {"WSA_SPK1 OUT", NULL, "WSA_MCLK"}, + + {"WSA_RX1 INP0", "RX0", "WSA RX0"}, + {"WSA_RX1 INP0", "RX1", "WSA RX1"}, + {"WSA_RX1 INP0", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP0", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP0", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP0", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP0"}, + + {"WSA_RX1 INP1", "RX0", "WSA RX0"}, + {"WSA_RX1 INP1", "RX1", "WSA RX1"}, + {"WSA_RX1 INP1", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP1", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP1", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP1", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP1"}, + + {"WSA_RX1 INP2", "RX0", "WSA RX0"}, + {"WSA_RX1 INP2", "RX1", "WSA RX1"}, + {"WSA_RX1 INP2", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 INP2", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX1 INP2", "DEC0", "WSA_TX DEC0_INP"}, + {"WSA_RX1 INP2", "DEC1", "WSA_TX DEC1_INP"}, + {"WSA_RX INT1 MIX", NULL, "WSA_RX1 INP2"}, + + {"WSA_RX1 MIX INP", "RX0", "WSA RX0"}, + {"WSA_RX1 MIX INP", "RX1", "WSA RX1"}, + {"WSA_RX1 MIX INP", "RX_MIX0", "WSA RX_MIX0"}, + {"WSA_RX1 MIX INP", "RX_MIX1", "WSA RX_MIX1"}, + {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX1 MIX INP"}, + + {"WSA_RX INT1 SEC MIX", NULL, "WSA_RX INT1 MIX"}, + {"WSA_RX INT1 INTERP", NULL, "WSA_RX INT1 SEC MIX"}, + + {"WSA_RX INT1 CHAIN", NULL, "WSA_RX INT1 INTERP"}, + {"WSA_SPK2 OUT", NULL, "WSA_RX INT1 CHAIN"}, + {"WSA_SPK2 OUT", NULL, "WSA_MCLK"}, +}; + static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) { struct regmap *regmap = wsa->regmap; @@ -1292,6 +2369,10 @@ static const struct snd_soc_component_driver wsa_macro_component_drv = { .probe = wsa_macro_component_probe, .controls = wsa_macro_snd_controls, .num_controls = ARRAY_SIZE(wsa_macro_snd_controls), + .dapm_widgets = wsa_macro_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wsa_macro_dapm_widgets), + .dapm_routes = wsa_audio_map, + .num_dapm_routes = ARRAY_SIZE(wsa_audio_map), }; static int wsa_macro_probe(struct platform_device *pdev) -- cgit v1.2.3 From 908e6b1df26efc9d2df70c9a7bf4f5eae5c5702f Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 5 Nov 2020 11:34:57 +0000 Subject: ASoC: codecs: lpass-va-macro: Add support to VA Macro Qualcomm LPASS (Low Power Audio SubSystem) has internal codec VA macro block which is used for connecting with DMICs. This patch adds support to the codec part of the VA Macro block Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201105113458.12360-6-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/lpass-va-macro.c | 883 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 889 insertions(+) create mode 100644 sound/soc/codecs/lpass-va-macro.c (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d5ce46d7c718..3edd6495f0c8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1793,4 +1793,8 @@ config SND_SOC_LPASS_WSA_MACRO depends on COMMON_CLK tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)" +config SND_SOC_LPASS_VA_MACRO + depends on COMMON_CLK + tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)" + endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d3322e9d5fc0..915e54f7f1a4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -104,6 +104,7 @@ snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o snd-soc-lochnagar-sc-objs := lochnagar-sc.o snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o +snd-soc-lpass-va-macro-objs := lpass-va-macro.o snd-soc-madera-objs := madera.o snd-soc-max9759-objs := max9759.o snd-soc-max9768-objs := max9768.o @@ -617,3 +618,4 @@ obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO) += snd-soc-lpass-wsa-macro.o +obj-$(CONFIG_SND_SOC_LPASS_VA_MACRO) += snd-soc-lpass-va-macro.o diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c new file mode 100644 index 000000000000..e7590e70f2c0 --- /dev/null +++ b/sound/soc/codecs/lpass-va-macro.c @@ -0,0 +1,883 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* VA macro registers */ +#define CDC_VA_CLK_RST_CTRL_MCLK_CONTROL (0x0000) +#define CDC_VA_MCLK_CONTROL_EN BIT(0) +#define CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL (0x0004) +#define CDC_VA_FS_CONTROL_EN BIT(0) +#define CDC_VA_CLK_RST_CTRL_SWR_CONTROL (0x0008) +#define CDC_VA_TOP_CSR_TOP_CFG0 (0x0080) +#define CDC_VA_FS_BROADCAST_EN BIT(1) +#define CDC_VA_TOP_CSR_DMIC0_CTL (0x0084) +#define CDC_VA_TOP_CSR_DMIC1_CTL (0x0088) +#define CDC_VA_TOP_CSR_DMIC2_CTL (0x008C) +#define CDC_VA_TOP_CSR_DMIC3_CTL (0x0090) +#define CDC_VA_DMIC_CLK_SEL_MASK GENMASK(3, 1) +#define CDC_VA_DMIC_CLK_SEL_SHFT 1 +#define CDC_VA_DMIC_CLK_SEL_DIV0 0x0 +#define CDC_VA_DMIC_CLK_SEL_DIV1 0x2 +#define CDC_VA_DMIC_CLK_SEL_DIV2 0x4 +#define CDC_VA_DMIC_CLK_SEL_DIV3 0x6 +#define CDC_VA_DMIC_CLK_SEL_DIV4 0x8 +#define CDC_VA_DMIC_CLK_SEL_DIV5 0xa +#define CDC_VA_TOP_CSR_DMIC_CFG (0x0094) +#define CDC_VA_RESET_ALL_DMICS_MASK BIT(7) +#define CDC_VA_RESET_ALL_DMICS_RESET BIT(7) +#define CDC_VA_RESET_ALL_DMICS_DISABLE 0 +#define CDC_VA_DMIC3_FREQ_CHANGE_MASK BIT(3) +#define CDC_VA_DMIC3_FREQ_CHANGE_EN BIT(3) +#define CDC_VA_DMIC2_FREQ_CHANGE_MASK BIT(2) +#define CDC_VA_DMIC2_FREQ_CHANGE_EN BIT(2) +#define CDC_VA_DMIC1_FREQ_CHANGE_MASK BIT(1) +#define CDC_VA_DMIC1_FREQ_CHANGE_EN BIT(1) +#define CDC_VA_DMIC0_FREQ_CHANGE_MASK BIT(0) +#define CDC_VA_DMIC0_FREQ_CHANGE_EN BIT(0) +#define CDC_VA_DMIC_FREQ_CHANGE_DISABLE 0 +#define CDC_VA_TOP_CSR_DEBUG_BUS (0x009C) +#define CDC_VA_TOP_CSR_DEBUG_EN (0x00A0) +#define CDC_VA_TOP_CSR_TX_I2S_CTL (0x00A4) +#define CDC_VA_TOP_CSR_I2S_CLK (0x00A8) +#define CDC_VA_TOP_CSR_I2S_RESET (0x00AC) +#define CDC_VA_TOP_CSR_CORE_ID_0 (0x00C0) +#define CDC_VA_TOP_CSR_CORE_ID_1 (0x00C4) +#define CDC_VA_TOP_CSR_CORE_ID_2 (0x00C8) +#define CDC_VA_TOP_CSR_CORE_ID_3 (0x00CC) +#define CDC_VA_TOP_CSR_SWR_MIC_CTL0 (0x00D0) +#define CDC_VA_TOP_CSR_SWR_MIC_CTL1 (0x00D4) +#define CDC_VA_TOP_CSR_SWR_MIC_CTL2 (0x00D8) +#define CDC_VA_TOP_CSR_SWR_CTRL (0x00DC) +#define CDC_VA_INP_MUX_ADC_MUX0_CFG0 (0x0100) +#define CDC_VA_INP_MUX_ADC_MUX0_CFG1 (0x0104) +#define CDC_VA_INP_MUX_ADC_MUX1_CFG0 (0x0108) +#define CDC_VA_INP_MUX_ADC_MUX1_CFG1 (0x010C) +#define CDC_VA_INP_MUX_ADC_MUX2_CFG0 (0x0110) +#define CDC_VA_INP_MUX_ADC_MUX2_CFG1 (0x0114) +#define CDC_VA_INP_MUX_ADC_MUX3_CFG0 (0x0118) +#define CDC_VA_INP_MUX_ADC_MUX3_CFG1 (0x011C) +#define CDC_VA_TX0_TX_PATH_CTL (0x0400) +#define CDC_VA_TX_PATH_CLK_EN_MASK BIT(5) +#define CDC_VA_TX_PATH_CLK_EN BIT(5) +#define CDC_VA_TX_PATH_CLK_DISABLE 0 +#define CDC_VA_TX_PATH_PGA_MUTE_EN_MASK BIT(4) +#define CDC_VA_TX_PATH_PGA_MUTE_EN BIT(4) +#define CDC_VA_TX_PATH_PGA_MUTE_DISABLE 0 +#define CDC_VA_TX0_TX_PATH_CFG0 (0x0404) +#define CDC_VA_ADC_MODE_MASK GENMASK(2, 1) +#define CDC_VA_ADC_MODE_SHIFT 1 +#define TX_HPF_CUT_OFF_FREQ_MASK GENMASK(6, 5) +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 +#define CDC_VA_TX0_TX_PATH_CFG1 (0x0408) +#define CDC_VA_TX0_TX_VOL_CTL (0x040C) +#define CDC_VA_TX0_TX_PATH_SEC0 (0x0410) +#define CDC_VA_TX0_TX_PATH_SEC1 (0x0414) +#define CDC_VA_TX0_TX_PATH_SEC2 (0x0418) +#define CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK BIT(1) +#define CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_REQ BIT(1) +#define CDC_VA_TX_HPF_ZERO_GATE_MASK BIT(0) +#define CDC_VA_TX_HPF_ZERO_NO_GATE BIT(0) +#define CDC_VA_TX_HPF_ZERO_GATE 0 +#define CDC_VA_TX0_TX_PATH_SEC3 (0x041C) +#define CDC_VA_TX0_TX_PATH_SEC4 (0x0420) +#define CDC_VA_TX0_TX_PATH_SEC5 (0x0424) +#define CDC_VA_TX0_TX_PATH_SEC6 (0x0428) +#define CDC_VA_TX0_TX_PATH_SEC7 (0x042C) +#define CDC_VA_TX1_TX_PATH_CTL (0x0480) +#define CDC_VA_TX1_TX_PATH_CFG0 (0x0484) +#define CDC_VA_TX1_TX_PATH_CFG1 (0x0488) +#define CDC_VA_TX1_TX_VOL_CTL (0x048C) +#define CDC_VA_TX1_TX_PATH_SEC0 (0x0490) +#define CDC_VA_TX1_TX_PATH_SEC1 (0x0494) +#define CDC_VA_TX1_TX_PATH_SEC2 (0x0498) +#define CDC_VA_TX1_TX_PATH_SEC3 (0x049C) +#define CDC_VA_TX1_TX_PATH_SEC4 (0x04A0) +#define CDC_VA_TX1_TX_PATH_SEC5 (0x04A4) +#define CDC_VA_TX1_TX_PATH_SEC6 (0x04A8) +#define CDC_VA_TX2_TX_PATH_CTL (0x0500) +#define CDC_VA_TX2_TX_PATH_CFG0 (0x0504) +#define CDC_VA_TX2_TX_PATH_CFG1 (0x0508) +#define CDC_VA_TX2_TX_VOL_CTL (0x050C) +#define CDC_VA_TX2_TX_PATH_SEC0 (0x0510) +#define CDC_VA_TX2_TX_PATH_SEC1 (0x0514) +#define CDC_VA_TX2_TX_PATH_SEC2 (0x0518) +#define CDC_VA_TX2_TX_PATH_SEC3 (0x051C) +#define CDC_VA_TX2_TX_PATH_SEC4 (0x0520) +#define CDC_VA_TX2_TX_PATH_SEC5 (0x0524) +#define CDC_VA_TX2_TX_PATH_SEC6 (0x0528) +#define CDC_VA_TX3_TX_PATH_CTL (0x0580) +#define CDC_VA_TX3_TX_PATH_CFG0 (0x0584) +#define CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK BIT(7) +#define CDC_VA_TX_PATH_ADC_DMIC_SEL_DMIC BIT(7) +#define CDC_VA_TX_PATH_ADC_DMIC_SEL_ADC 0 +#define CDC_VA_TX3_TX_PATH_CFG1 (0x0588) +#define CDC_VA_TX3_TX_VOL_CTL (0x058C) +#define CDC_VA_TX3_TX_PATH_SEC0 (0x0590) +#define CDC_VA_TX3_TX_PATH_SEC1 (0x0594) +#define CDC_VA_TX3_TX_PATH_SEC2 (0x0598) +#define CDC_VA_TX3_TX_PATH_SEC3 (0x059C) +#define CDC_VA_TX3_TX_PATH_SEC4 (0x05A0) +#define CDC_VA_TX3_TX_PATH_SEC5 (0x05A4) +#define CDC_VA_TX3_TX_PATH_SEC6 (0x05A8) + +#define VA_MAX_OFFSET (0x07A8) + +#define VA_MACRO_NUM_DECIMATORS 4 +#define VA_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define VA_MACRO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define VA_MACRO_MCLK_FREQ 9600000 +#define VA_MACRO_TX_PATH_OFFSET 0x80 +#define VA_MACRO_SWR_MIC_MUX_SEL_MASK 0xF +#define VA_MACRO_ADC_MUX_CFG_OFFSET 0x8 + +static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400); + +enum { + VA_MACRO_AIF_INVALID = 0, + VA_MACRO_AIF1_CAP, + VA_MACRO_AIF2_CAP, + VA_MACRO_AIF3_CAP, + VA_MACRO_MAX_DAIS, +}; + +enum { + VA_MACRO_DEC0, + VA_MACRO_DEC1, + VA_MACRO_DEC2, + VA_MACRO_DEC3, + VA_MACRO_DEC4, + VA_MACRO_DEC5, + VA_MACRO_DEC6, + VA_MACRO_DEC7, + VA_MACRO_DEC_MAX, +}; + +enum { + VA_MACRO_CLK_DIV_2, + VA_MACRO_CLK_DIV_3, + VA_MACRO_CLK_DIV_4, + VA_MACRO_CLK_DIV_6, + VA_MACRO_CLK_DIV_8, + VA_MACRO_CLK_DIV_16, +}; + +#define VA_NUM_CLKS_MAX 3 + +struct va_macro { + struct device *dev; + unsigned long active_ch_mask[VA_MACRO_MAX_DAIS]; + unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS]; + unsigned long active_decimator[VA_MACRO_MAX_DAIS]; + u16 dmic_clk_div; + + int dec_mode[VA_MACRO_NUM_DECIMATORS]; + struct regmap *regmap; + struct clk_bulk_data clks[VA_NUM_CLKS_MAX]; + struct clk_hw hw; + + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + s32 dmic_6_7_clk_cnt; + u8 dmic_0_1_clk_div; + u8 dmic_2_3_clk_div; + u8 dmic_4_5_clk_div; + u8 dmic_6_7_clk_div; +}; + +#define to_va_macro(_hw) container_of(_hw, struct va_macro, hw) + +static bool va_is_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_VA_TOP_CSR_CORE_ID_0: + case CDC_VA_TOP_CSR_CORE_ID_1: + case CDC_VA_TOP_CSR_CORE_ID_2: + case CDC_VA_TOP_CSR_CORE_ID_3: + case CDC_VA_TOP_CSR_DMIC0_CTL: + case CDC_VA_TOP_CSR_DMIC1_CTL: + case CDC_VA_TOP_CSR_DMIC2_CTL: + case CDC_VA_TOP_CSR_DMIC3_CTL: + return true; + } + return false; +} + +static const struct reg_default va_defaults[] = { + /* VA macro */ + { CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, 0x00}, + { CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, 0x00}, + { CDC_VA_CLK_RST_CTRL_SWR_CONTROL, 0x00}, + { CDC_VA_TOP_CSR_TOP_CFG0, 0x00}, + { CDC_VA_TOP_CSR_DMIC0_CTL, 0x00}, + { CDC_VA_TOP_CSR_DMIC1_CTL, 0x00}, + { CDC_VA_TOP_CSR_DMIC2_CTL, 0x00}, + { CDC_VA_TOP_CSR_DMIC3_CTL, 0x00}, + { CDC_VA_TOP_CSR_DMIC_CFG, 0x80}, + { CDC_VA_TOP_CSR_DEBUG_BUS, 0x00}, + { CDC_VA_TOP_CSR_DEBUG_EN, 0x00}, + { CDC_VA_TOP_CSR_TX_I2S_CTL, 0x0C}, + { CDC_VA_TOP_CSR_I2S_CLK, 0x00}, + { CDC_VA_TOP_CSR_I2S_RESET, 0x00}, + { CDC_VA_TOP_CSR_CORE_ID_0, 0x00}, + { CDC_VA_TOP_CSR_CORE_ID_1, 0x00}, + { CDC_VA_TOP_CSR_CORE_ID_2, 0x00}, + { CDC_VA_TOP_CSR_CORE_ID_3, 0x00}, + { CDC_VA_TOP_CSR_SWR_MIC_CTL0, 0xEE}, + { CDC_VA_TOP_CSR_SWR_MIC_CTL1, 0xEE}, + { CDC_VA_TOP_CSR_SWR_MIC_CTL2, 0xEE}, + { CDC_VA_TOP_CSR_SWR_CTRL, 0x06}, + + /* VA core */ + { CDC_VA_INP_MUX_ADC_MUX0_CFG0, 0x00}, + { CDC_VA_INP_MUX_ADC_MUX0_CFG1, 0x00}, + { CDC_VA_INP_MUX_ADC_MUX1_CFG0, 0x00}, + { CDC_VA_INP_MUX_ADC_MUX1_CFG1, 0x00}, + { CDC_VA_INP_MUX_ADC_MUX2_CFG0, 0x00}, + { CDC_VA_INP_MUX_ADC_MUX2_CFG1, 0x00}, + { CDC_VA_INP_MUX_ADC_MUX3_CFG0, 0x00}, + { CDC_VA_INP_MUX_ADC_MUX3_CFG1, 0x00}, + { CDC_VA_TX0_TX_PATH_CTL, 0x04}, + { CDC_VA_TX0_TX_PATH_CFG0, 0x10}, + { CDC_VA_TX0_TX_PATH_CFG1, 0x0B}, + { CDC_VA_TX0_TX_VOL_CTL, 0x00}, + { CDC_VA_TX0_TX_PATH_SEC0, 0x00}, + { CDC_VA_TX0_TX_PATH_SEC1, 0x00}, + { CDC_VA_TX0_TX_PATH_SEC2, 0x01}, + { CDC_VA_TX0_TX_PATH_SEC3, 0x3C}, + { CDC_VA_TX0_TX_PATH_SEC4, 0x20}, + { CDC_VA_TX0_TX_PATH_SEC5, 0x00}, + { CDC_VA_TX0_TX_PATH_SEC6, 0x00}, + { CDC_VA_TX0_TX_PATH_SEC7, 0x25}, + { CDC_VA_TX1_TX_PATH_CTL, 0x04}, + { CDC_VA_TX1_TX_PATH_CFG0, 0x10}, + { CDC_VA_TX1_TX_PATH_CFG1, 0x0B}, + { CDC_VA_TX1_TX_VOL_CTL, 0x00}, + { CDC_VA_TX1_TX_PATH_SEC0, 0x00}, + { CDC_VA_TX1_TX_PATH_SEC1, 0x00}, + { CDC_VA_TX1_TX_PATH_SEC2, 0x01}, + { CDC_VA_TX1_TX_PATH_SEC3, 0x3C}, + { CDC_VA_TX1_TX_PATH_SEC4, 0x20}, + { CDC_VA_TX1_TX_PATH_SEC5, 0x00}, + { CDC_VA_TX1_TX_PATH_SEC6, 0x00}, + { CDC_VA_TX2_TX_PATH_CTL, 0x04}, + { CDC_VA_TX2_TX_PATH_CFG0, 0x10}, + { CDC_VA_TX2_TX_PATH_CFG1, 0x0B}, + { CDC_VA_TX2_TX_VOL_CTL, 0x00}, + { CDC_VA_TX2_TX_PATH_SEC0, 0x00}, + { CDC_VA_TX2_TX_PATH_SEC1, 0x00}, + { CDC_VA_TX2_TX_PATH_SEC2, 0x01}, + { CDC_VA_TX2_TX_PATH_SEC3, 0x3C}, + { CDC_VA_TX2_TX_PATH_SEC4, 0x20}, + { CDC_VA_TX2_TX_PATH_SEC5, 0x00}, + { CDC_VA_TX2_TX_PATH_SEC6, 0x00}, + { CDC_VA_TX3_TX_PATH_CTL, 0x04}, + { CDC_VA_TX3_TX_PATH_CFG0, 0x10}, + { CDC_VA_TX3_TX_PATH_CFG1, 0x0B}, + { CDC_VA_TX3_TX_VOL_CTL, 0x00}, + { CDC_VA_TX3_TX_PATH_SEC0, 0x00}, + { CDC_VA_TX3_TX_PATH_SEC1, 0x00}, + { CDC_VA_TX3_TX_PATH_SEC2, 0x01}, + { CDC_VA_TX3_TX_PATH_SEC3, 0x3C}, + { CDC_VA_TX3_TX_PATH_SEC4, 0x20}, + { CDC_VA_TX3_TX_PATH_SEC5, 0x00}, + { CDC_VA_TX3_TX_PATH_SEC6, 0x00}, +}; + +static bool va_is_rw_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_VA_CLK_RST_CTRL_MCLK_CONTROL: + case CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL: + case CDC_VA_CLK_RST_CTRL_SWR_CONTROL: + case CDC_VA_TOP_CSR_TOP_CFG0: + case CDC_VA_TOP_CSR_DMIC0_CTL: + case CDC_VA_TOP_CSR_DMIC1_CTL: + case CDC_VA_TOP_CSR_DMIC2_CTL: + case CDC_VA_TOP_CSR_DMIC3_CTL: + case CDC_VA_TOP_CSR_DMIC_CFG: + case CDC_VA_TOP_CSR_DEBUG_BUS: + case CDC_VA_TOP_CSR_DEBUG_EN: + case CDC_VA_TOP_CSR_TX_I2S_CTL: + case CDC_VA_TOP_CSR_I2S_CLK: + case CDC_VA_TOP_CSR_I2S_RESET: + case CDC_VA_INP_MUX_ADC_MUX0_CFG0: + case CDC_VA_INP_MUX_ADC_MUX0_CFG1: + case CDC_VA_INP_MUX_ADC_MUX1_CFG0: + case CDC_VA_INP_MUX_ADC_MUX1_CFG1: + case CDC_VA_INP_MUX_ADC_MUX2_CFG0: + case CDC_VA_INP_MUX_ADC_MUX2_CFG1: + case CDC_VA_INP_MUX_ADC_MUX3_CFG0: + case CDC_VA_INP_MUX_ADC_MUX3_CFG1: + case CDC_VA_TX0_TX_PATH_CTL: + case CDC_VA_TX0_TX_PATH_CFG0: + case CDC_VA_TX0_TX_PATH_CFG1: + case CDC_VA_TX0_TX_VOL_CTL: + case CDC_VA_TX0_TX_PATH_SEC0: + case CDC_VA_TX0_TX_PATH_SEC1: + case CDC_VA_TX0_TX_PATH_SEC2: + case CDC_VA_TX0_TX_PATH_SEC3: + case CDC_VA_TX0_TX_PATH_SEC4: + case CDC_VA_TX0_TX_PATH_SEC5: + case CDC_VA_TX0_TX_PATH_SEC6: + case CDC_VA_TX0_TX_PATH_SEC7: + case CDC_VA_TX1_TX_PATH_CTL: + case CDC_VA_TX1_TX_PATH_CFG0: + case CDC_VA_TX1_TX_PATH_CFG1: + case CDC_VA_TX1_TX_VOL_CTL: + case CDC_VA_TX1_TX_PATH_SEC0: + case CDC_VA_TX1_TX_PATH_SEC1: + case CDC_VA_TX1_TX_PATH_SEC2: + case CDC_VA_TX1_TX_PATH_SEC3: + case CDC_VA_TX1_TX_PATH_SEC4: + case CDC_VA_TX1_TX_PATH_SEC5: + case CDC_VA_TX1_TX_PATH_SEC6: + case CDC_VA_TX2_TX_PATH_CTL: + case CDC_VA_TX2_TX_PATH_CFG0: + case CDC_VA_TX2_TX_PATH_CFG1: + case CDC_VA_TX2_TX_VOL_CTL: + case CDC_VA_TX2_TX_PATH_SEC0: + case CDC_VA_TX2_TX_PATH_SEC1: + case CDC_VA_TX2_TX_PATH_SEC2: + case CDC_VA_TX2_TX_PATH_SEC3: + case CDC_VA_TX2_TX_PATH_SEC4: + case CDC_VA_TX2_TX_PATH_SEC5: + case CDC_VA_TX2_TX_PATH_SEC6: + case CDC_VA_TX3_TX_PATH_CTL: + case CDC_VA_TX3_TX_PATH_CFG0: + case CDC_VA_TX3_TX_PATH_CFG1: + case CDC_VA_TX3_TX_VOL_CTL: + case CDC_VA_TX3_TX_PATH_SEC0: + case CDC_VA_TX3_TX_PATH_SEC1: + case CDC_VA_TX3_TX_PATH_SEC2: + case CDC_VA_TX3_TX_PATH_SEC3: + case CDC_VA_TX3_TX_PATH_SEC4: + case CDC_VA_TX3_TX_PATH_SEC5: + case CDC_VA_TX3_TX_PATH_SEC6: + return true; + } + + return false; +} + +static bool va_is_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CDC_VA_TOP_CSR_CORE_ID_0: + case CDC_VA_TOP_CSR_CORE_ID_1: + case CDC_VA_TOP_CSR_CORE_ID_2: + case CDC_VA_TOP_CSR_CORE_ID_3: + return true; + } + + return va_is_rw_register(dev, reg); +} + +static const struct regmap_config va_regmap_config = { + .name = "va_macro", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .cache_type = REGCACHE_FLAT, + .reg_defaults = va_defaults, + .num_reg_defaults = ARRAY_SIZE(va_defaults), + .max_register = VA_MAX_OFFSET, + .volatile_reg = va_is_volatile_register, + .readable_reg = va_is_readable_register, + .writeable_reg = va_is_rw_register, +}; + +static int va_clk_rsc_fs_gen_request(struct va_macro *va, bool enable) +{ + struct regmap *regmap = va->regmap; + + if (enable) { + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, + CDC_VA_MCLK_CONTROL_EN, + CDC_VA_MCLK_CONTROL_EN); + + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, + CDC_VA_FS_CONTROL_EN, + CDC_VA_FS_CONTROL_EN); + + regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0, + CDC_VA_FS_BROADCAST_EN, + CDC_VA_FS_BROADCAST_EN); + } else { + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_MCLK_CONTROL, + CDC_VA_MCLK_CONTROL_EN, 0x0); + + regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_FS_CNT_CONTROL, + CDC_VA_FS_CONTROL_EN, 0x0); + + regmap_update_bits(regmap, CDC_VA_TOP_CSR_TOP_CFG0, + CDC_VA_FS_BROADCAST_EN, 0x0); + } + + return 0; +} + +static int va_macro_mclk_enable(struct va_macro *va, bool mclk_enable) +{ + struct regmap *regmap = va->regmap; + + if (mclk_enable) { + va_clk_rsc_fs_gen_request(va, true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, 0x0, VA_MAX_OFFSET); + } else { + va_clk_rsc_fs_gen_request(va, false); + } + + return 0; +} + +static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct va_macro *va = snd_soc_component_get_drvdata(comp); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int path = e->shift_l; + + ucontrol->value.integer.value[0] = va->dec_mode[path]; + + return 0; +} + +static int va_macro_dec_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + int value = ucontrol->value.integer.value[0]; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int path = e->shift_l; + struct va_macro *va = snd_soc_component_get_drvdata(comp); + + va->dec_mode[path] = value; + + return 0; +} + +static int va_macro_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int tx_fs_rate; + struct snd_soc_component *component = dai->component; + u32 decimator, sample_rate; + u16 tx_fs_reg; + struct device *va_dev = component->dev; + struct va_macro *va = snd_soc_component_get_drvdata(component); + + sample_rate = params_rate(params); + switch (sample_rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err(va_dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + } + + for_each_set_bit(decimator, &va->active_ch_mask[dai->id], + VA_MACRO_DEC_MAX) { + if (decimator >= 0) { + tx_fs_reg = CDC_VA_TX0_TX_PATH_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + snd_soc_component_update_bits(component, tx_fs_reg, + 0x0F, tx_fs_rate); + } else { + dev_err(va_dev, + "%s: ERROR: Invalid decimator: %d\n", + __func__, decimator); + return -EINVAL; + } + } + return 0; +} + +static int va_macro_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct snd_soc_component *component = dai->component; + struct device *va_dev = component->dev; + struct va_macro *va = snd_soc_component_get_drvdata(component); + + switch (dai->id) { + case VA_MACRO_AIF1_CAP: + case VA_MACRO_AIF2_CAP: + case VA_MACRO_AIF3_CAP: + *tx_slot = va->active_ch_mask[dai->id]; + *tx_num = va->active_ch_cnt[dai->id]; + break; + default: + dev_err(va_dev, "%s: Invalid AIF\n", __func__); + break; + } + return 0; +} + +static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct va_macro *va = snd_soc_component_get_drvdata(component); + u16 tx_vol_ctl_reg, decimator; + + decimator = va->active_decimator[dai->id]; + + tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + if (mute) + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + CDC_VA_TX_PATH_PGA_MUTE_EN_MASK, + CDC_VA_TX_PATH_PGA_MUTE_EN); + else + snd_soc_component_update_bits(component, tx_vol_ctl_reg, + CDC_VA_TX_PATH_PGA_MUTE_EN_MASK, + CDC_VA_TX_PATH_PGA_MUTE_DISABLE); + + return 0; +} + +static struct snd_soc_dai_ops va_macro_dai_ops = { + .hw_params = va_macro_hw_params, + .get_channel_map = va_macro_get_channel_map, + .mute_stream = va_macro_digital_mute, +}; + +static struct snd_soc_dai_driver va_macro_dais[] = { + { + .name = "va_macro_tx1", + .id = VA_MACRO_AIF1_CAP, + .capture = { + .stream_name = "VA_AIF1 Capture", + .rates = VA_MACRO_RATES, + .formats = VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &va_macro_dai_ops, + }, + { + .name = "va_macro_tx2", + .id = VA_MACRO_AIF2_CAP, + .capture = { + .stream_name = "VA_AIF2 Capture", + .rates = VA_MACRO_RATES, + .formats = VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &va_macro_dai_ops, + }, + { + .name = "va_macro_tx3", + .id = VA_MACRO_AIF3_CAP, + .capture = { + .stream_name = "VA_AIF3 Capture", + .rates = VA_MACRO_RATES, + .formats = VA_MACRO_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 8, + }, + .ops = &va_macro_dai_ops, + }, +}; + +static const char * const dec_mode_mux_text[] = { + "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF", +}; + +static const struct soc_enum dec_mode_mux_enum[] = { + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(dec_mode_mux_text), + dec_mode_mux_text), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(dec_mode_mux_text), + dec_mode_mux_text), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(dec_mode_mux_text), + dec_mode_mux_text), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(dec_mode_mux_text), + dec_mode_mux_text), +}; + +static const struct snd_kcontrol_new va_macro_snd_controls[] = { + SOC_SINGLE_S8_TLV("VA_DEC0 Volume", CDC_VA_TX0_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC1 Volume", CDC_VA_TX1_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC2 Volume", CDC_VA_TX2_TX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC3 Volume", CDC_VA_TX3_TX_VOL_CTL, + -84, 40, digital_gain), + + SOC_ENUM_EXT("VA_DEC0 MODE", dec_mode_mux_enum[0], + va_macro_dec_mode_get, va_macro_dec_mode_put), + SOC_ENUM_EXT("VA_DEC1 MODE", dec_mode_mux_enum[1], + va_macro_dec_mode_get, va_macro_dec_mode_put), + SOC_ENUM_EXT("VA_DEC2 MODE", dec_mode_mux_enum[2], + va_macro_dec_mode_get, va_macro_dec_mode_put), + SOC_ENUM_EXT("VA_DEC3 MODE", dec_mode_mux_enum[3], + va_macro_dec_mode_get, va_macro_dec_mode_put), +}; + +static int va_macro_component_probe(struct snd_soc_component *component) +{ + struct va_macro *va = snd_soc_component_get_drvdata(component); + + snd_soc_component_init_regmap(component, va->regmap); + + return 0; +} + +static const struct snd_soc_component_driver va_macro_component_drv = { + .name = "VA MACRO", + .probe = va_macro_component_probe, + .controls = va_macro_snd_controls, + .num_controls = ARRAY_SIZE(va_macro_snd_controls), +}; + +static int fsgen_gate_enable(struct clk_hw *hw) +{ + return va_macro_mclk_enable(to_va_macro(hw), true); +} + +static void fsgen_gate_disable(struct clk_hw *hw) +{ + va_macro_mclk_enable(to_va_macro(hw), false); +} + +static int fsgen_gate_is_enabled(struct clk_hw *hw) +{ + struct va_macro *va = to_va_macro(hw); + int val; + + regmap_read(va->regmap, CDC_VA_TOP_CSR_TOP_CFG0, &val); + + return !!(val & CDC_VA_FS_BROADCAST_EN); +} + +static const struct clk_ops fsgen_gate_ops = { + .prepare = fsgen_gate_enable, + .unprepare = fsgen_gate_disable, + .is_enabled = fsgen_gate_is_enabled, +}; + +static int va_macro_register_fsgen_output(struct va_macro *va) +{ + struct clk *parent = va->clks[2].clk; + struct device *dev = va->dev; + struct device_node *np = dev->of_node; + const char *parent_clk_name; + const char *clk_name = "fsgen"; + struct clk_init_data init; + int ret; + + parent_clk_name = __clk_get_name(parent); + + of_property_read_string(np, "clock-output-names", &clk_name); + + init.name = clk_name; + init.ops = &fsgen_gate_ops; + init.flags = 0; + init.parent_names = &parent_clk_name; + init.num_parents = 1; + va->hw.init = &init; + ret = devm_clk_hw_register(va->dev, &va->hw); + if (ret) + return ret; + + return of_clk_add_provider(np, of_clk_src_simple_get, va->hw.clk); +} + +static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate, + struct va_macro *va) +{ + u32 div_factor; + u32 mclk_rate = VA_MACRO_MCLK_FREQ; + + if (!dmic_sample_rate || mclk_rate % dmic_sample_rate != 0) + goto undefined_rate; + + div_factor = mclk_rate / dmic_sample_rate; + + switch (div_factor) { + case 2: + va->dmic_clk_div = VA_MACRO_CLK_DIV_2; + break; + case 3: + va->dmic_clk_div = VA_MACRO_CLK_DIV_3; + break; + case 4: + va->dmic_clk_div = VA_MACRO_CLK_DIV_4; + break; + case 6: + va->dmic_clk_div = VA_MACRO_CLK_DIV_6; + break; + case 8: + va->dmic_clk_div = VA_MACRO_CLK_DIV_8; + break; + case 16: + va->dmic_clk_div = VA_MACRO_CLK_DIV_16; + break; + default: + /* Any other DIV factor is invalid */ + goto undefined_rate; + } + + return dmic_sample_rate; + +undefined_rate: + dev_err(va->dev, "%s: Invalid rate %d, for mclk %d\n", + __func__, dmic_sample_rate, mclk_rate); + dmic_sample_rate = 0; + + return dmic_sample_rate; +} + +static int va_macro_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct va_macro *va; + void __iomem *base; + u32 sample_rate = 0; + int ret; + + va = devm_kzalloc(dev, sizeof(*va), GFP_KERNEL); + if (!va) + return -ENOMEM; + + va->dev = dev; + va->clks[0].id = "macro"; + va->clks[1].id = "dcodec"; + va->clks[2].id = "mclk"; + + ret = devm_clk_bulk_get(dev, VA_NUM_CLKS_MAX, va->clks); + if (ret) { + dev_err(dev, "Error getting VA Clocks (%d)\n", ret); + return ret; + } + + ret = of_property_read_u32(dev->of_node, "qcom,dmic-sample-rate", + &sample_rate); + if (ret) { + dev_err(dev, "qcom,dmic-sample-rate dt entry missing\n"); + va->dmic_clk_div = VA_MACRO_CLK_DIV_2; + } else { + ret = va_macro_validate_dmic_sample_rate(sample_rate, va); + if (!ret) + return -EINVAL; + } + + /* mclk rate */ + clk_set_rate(va->clks[1].clk, VA_MACRO_MCLK_FREQ); + ret = clk_bulk_prepare_enable(VA_NUM_CLKS_MAX, va->clks); + if (ret) + return ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto err; + } + + va->regmap = devm_regmap_init_mmio(dev, base, &va_regmap_config); + if (IS_ERR(va->regmap)) { + ret = -EINVAL; + goto err; + } + + dev_set_drvdata(dev, va); + ret = va_macro_register_fsgen_output(va); + if (ret) + goto err; + + ret = devm_snd_soc_register_component(dev, &va_macro_component_drv, + va_macro_dais, + ARRAY_SIZE(va_macro_dais)); + if (ret) + goto soc_err; + + return ret; + +soc_err: + of_clk_del_provider(pdev->dev.of_node); +err: + clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks); + + return ret; +} + +static int va_macro_remove(struct platform_device *pdev) +{ + struct va_macro *va = dev_get_drvdata(&pdev->dev); + + of_clk_del_provider(pdev->dev.of_node); + clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks); + + return 0; +} + +static const struct of_device_id va_macro_dt_match[] = { + { .compatible = "qcom,sm8250-lpass-va-macro" }, + {} +}; + +static struct platform_driver va_macro_driver = { + .driver = { + .name = "va_macro", + .of_match_table = va_macro_dt_match, + .suppress_bind_attrs = true, + }, + .probe = va_macro_probe, + .remove = va_macro_remove, +}; + +module_platform_driver(va_macro_driver); +MODULE_DESCRIPTION("VA macro driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 58aad93015b9dc7cb8966c1dc775ec69f0280b79 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 5 Nov 2020 11:34:58 +0000 Subject: ASoC: codecs: lpass-va-macro: add dapm widgets and routes Add dapm widgets and routes for this codec. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201105113458.12360-7-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-va-macro.c | 620 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 620 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index e7590e70f2c0..b604de07e650 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -27,6 +27,8 @@ #define CDC_VA_TOP_CSR_DMIC1_CTL (0x0088) #define CDC_VA_TOP_CSR_DMIC2_CTL (0x008C) #define CDC_VA_TOP_CSR_DMIC3_CTL (0x0090) +#define CDC_VA_DMIC_EN_MASK BIT(0) +#define CDC_VA_DMIC_ENABLE BIT(0) #define CDC_VA_DMIC_CLK_SEL_MASK GENMASK(3, 1) #define CDC_VA_DMIC_CLK_SEL_SHFT 1 #define CDC_VA_DMIC_CLK_SEL_DIV0 0x0 @@ -452,6 +454,327 @@ static int va_macro_mclk_enable(struct va_macro *va, bool mclk_enable) return 0; } +static int va_macro_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct va_macro *va = snd_soc_component_get_drvdata(comp); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return va_macro_mclk_enable(va, true); + case SND_SOC_DAPM_POST_PMD: + return va_macro_mclk_enable(va, false); + } + + return 0; +} + +static int va_macro_put_dec_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + u16 mic_sel_reg; + + val = ucontrol->value.enumerated.item[0]; + + switch (e->reg) { + case CDC_VA_INP_MUX_ADC_MUX0_CFG0: + mic_sel_reg = CDC_VA_TX0_TX_PATH_CFG0; + break; + case CDC_VA_INP_MUX_ADC_MUX1_CFG0: + mic_sel_reg = CDC_VA_TX1_TX_PATH_CFG0; + break; + case CDC_VA_INP_MUX_ADC_MUX2_CFG0: + mic_sel_reg = CDC_VA_TX2_TX_PATH_CFG0; + break; + case CDC_VA_INP_MUX_ADC_MUX3_CFG0: + mic_sel_reg = CDC_VA_TX3_TX_PATH_CFG0; + break; + default: + dev_err(component->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + + if (val != 0) + snd_soc_component_update_bits(component, mic_sel_reg, + CDC_VA_TX_PATH_ADC_DMIC_SEL_MASK, + CDC_VA_TX_PATH_ADC_DMIC_SEL_DMIC); + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int va_macro_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u32 dai_id = widget->shift; + u32 dec_id = mc->shift; + struct va_macro *va = snd_soc_component_get_drvdata(component); + + if (test_bit(dec_id, &va->active_ch_mask[dai_id])) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *component = + snd_soc_dapm_to_component(widget->dapm); + struct snd_soc_dapm_update *update = NULL; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u32 dai_id = widget->shift; + u32 dec_id = mc->shift; + u32 enable = ucontrol->value.integer.value[0]; + struct va_macro *va = snd_soc_component_get_drvdata(component); + + if (enable) { + set_bit(dec_id, &va->active_ch_mask[dai_id]); + va->active_ch_cnt[dai_id]++; + va->active_decimator[dai_id] = dec_id; + } else { + clear_bit(dec_id, &va->active_ch_mask[dai_id]); + va->active_ch_cnt[dai_id]--; + va->active_decimator[dai_id] = -1; + } + + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static int va_dmic_clk_enable(struct snd_soc_component *component, + u32 dmic, bool enable) +{ + struct va_macro *va = snd_soc_component_get_drvdata(component); + u16 dmic_clk_reg; + s32 *dmic_clk_cnt; + u8 *dmic_clk_div; + u8 freq_change_mask; + u8 clk_div; + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(va->dmic_0_1_clk_cnt); + dmic_clk_div = &(va->dmic_0_1_clk_div); + dmic_clk_reg = CDC_VA_TOP_CSR_DMIC0_CTL; + freq_change_mask = CDC_VA_DMIC0_FREQ_CHANGE_MASK; + break; + case 2: + case 3: + dmic_clk_cnt = &(va->dmic_2_3_clk_cnt); + dmic_clk_div = &(va->dmic_2_3_clk_div); + dmic_clk_reg = CDC_VA_TOP_CSR_DMIC1_CTL; + freq_change_mask = CDC_VA_DMIC1_FREQ_CHANGE_MASK; + break; + case 4: + case 5: + dmic_clk_cnt = &(va->dmic_4_5_clk_cnt); + dmic_clk_div = &(va->dmic_4_5_clk_div); + dmic_clk_reg = CDC_VA_TOP_CSR_DMIC2_CTL; + freq_change_mask = CDC_VA_DMIC2_FREQ_CHANGE_MASK; + break; + case 6: + case 7: + dmic_clk_cnt = &(va->dmic_6_7_clk_cnt); + dmic_clk_div = &(va->dmic_6_7_clk_div); + dmic_clk_reg = CDC_VA_TOP_CSR_DMIC3_CTL; + freq_change_mask = CDC_VA_DMIC3_FREQ_CHANGE_MASK; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + } + + if (enable) { + clk_div = va->dmic_clk_div; + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(component, + CDC_VA_TOP_CSR_DMIC_CFG, + CDC_VA_RESET_ALL_DMICS_MASK, + CDC_VA_RESET_ALL_DMICS_DISABLE); + snd_soc_component_update_bits(component, dmic_clk_reg, + CDC_VA_DMIC_CLK_SEL_MASK, + clk_div << CDC_VA_DMIC_CLK_SEL_SHFT); + snd_soc_component_update_bits(component, dmic_clk_reg, + CDC_VA_DMIC_EN_MASK, + CDC_VA_DMIC_ENABLE); + } else { + if (*dmic_clk_div > clk_div) { + snd_soc_component_update_bits(component, + CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, + freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + CDC_VA_DMIC_CLK_SEL_MASK, + clk_div << CDC_VA_DMIC_CLK_SEL_SHFT); + snd_soc_component_update_bits(component, + CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, + CDC_VA_DMIC_FREQ_CHANGE_DISABLE); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } else { + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(component, dmic_clk_reg, + CDC_VA_DMIC_EN_MASK, 0); + clk_div = 0; + snd_soc_component_update_bits(component, dmic_clk_reg, + CDC_VA_DMIC_CLK_SEL_MASK, + clk_div << CDC_VA_DMIC_CLK_SEL_SHFT); + } else { + clk_div = va->dmic_clk_div; + if (*dmic_clk_div > clk_div) { + clk_div = va->dmic_clk_div; + snd_soc_component_update_bits(component, + CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, + freq_change_mask); + snd_soc_component_update_bits(component, dmic_clk_reg, + CDC_VA_DMIC_CLK_SEL_MASK, + clk_div << CDC_VA_DMIC_CLK_SEL_SHFT); + snd_soc_component_update_bits(component, + CDC_VA_TOP_CSR_DMIC_CFG, + freq_change_mask, + CDC_VA_DMIC_FREQ_CHANGE_DISABLE); + } else { + clk_div = *dmic_clk_div; + } + } + *dmic_clk_div = clk_div; + } + + return 0; +} + +static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + unsigned int dmic = w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + va_dmic_clk_enable(comp, dmic, true); + break; + case SND_SOC_DAPM_POST_PMD: + va_dmic_clk_enable(comp, dmic, false); + break; + } + + return 0; +} + +static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + unsigned int decimator; + u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + u8 hpf_cut_off_freq; + + struct va_macro *va = snd_soc_component_get_drvdata(comp); + + decimator = w->shift; + + tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + hpf_gate_reg = CDC_VA_TX0_TX_PATH_SEC2 + + VA_MACRO_TX_PATH_OFFSET * decimator; + dec_cfg_reg = CDC_VA_TX0_TX_PATH_CFG0 + + VA_MACRO_TX_PATH_OFFSET * decimator; + tx_gain_ctl_reg = CDC_VA_TX0_TX_VOL_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(comp, + dec_cfg_reg, CDC_VA_ADC_MODE_MASK, + va->dec_mode[decimator] << CDC_VA_ADC_MODE_SHIFT); + /* Enable TX PGA Mute */ + break; + case SND_SOC_DAPM_POST_PMU: + /* Enable TX CLK */ + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, + CDC_VA_TX_PATH_CLK_EN_MASK, + CDC_VA_TX_PATH_CLK_EN); + snd_soc_component_update_bits(comp, hpf_gate_reg, + CDC_VA_TX_HPF_ZERO_GATE_MASK, + CDC_VA_TX_HPF_ZERO_GATE); + + usleep_range(1000, 1010); + hpf_cut_off_freq = (snd_soc_component_read(comp, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(comp, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + + snd_soc_component_update_bits(comp, hpf_gate_reg, + CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK, + CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_REQ); + + /* + * Minimum 1 clk cycle delay is required as per HW spec + */ + usleep_range(1000, 1010); + + snd_soc_component_update_bits(comp, + hpf_gate_reg, + CDC_VA_TX_HPF_CUTOFF_FREQ_CHANGE_MASK, + 0x0); + } + + + usleep_range(1000, 1010); + snd_soc_component_update_bits(comp, hpf_gate_reg, + CDC_VA_TX_HPF_ZERO_GATE_MASK, + CDC_VA_TX_HPF_ZERO_NO_GATE); + /* + * 6ms delay is required as per HW spec + */ + usleep_range(6000, 6010); + /* apply gain after decimator is enabled */ + snd_soc_component_write(comp, tx_gain_ctl_reg, + snd_soc_component_read(comp, tx_gain_ctl_reg)); + break; + case SND_SOC_DAPM_POST_PMD: + /* Disable TX CLK */ + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, + CDC_VA_TX_PATH_CLK_EN_MASK, + CDC_VA_TX_PATH_CLK_DISABLE); + break; + } + return 0; +} + static int va_macro_dec_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -631,6 +954,299 @@ static struct snd_soc_dai_driver va_macro_dais[] = { }, }; +static const char * const adc_mux_text[] = { + "VA_DMIC", "SWR_MIC" +}; + +static SOC_ENUM_SINGLE_DECL(va_dec0_enum, CDC_VA_INP_MUX_ADC_MUX0_CFG1, + 0, adc_mux_text); +static SOC_ENUM_SINGLE_DECL(va_dec1_enum, CDC_VA_INP_MUX_ADC_MUX1_CFG1, + 0, adc_mux_text); +static SOC_ENUM_SINGLE_DECL(va_dec2_enum, CDC_VA_INP_MUX_ADC_MUX2_CFG1, + 0, adc_mux_text); +static SOC_ENUM_SINGLE_DECL(va_dec3_enum, CDC_VA_INP_MUX_ADC_MUX3_CFG1, + 0, adc_mux_text); + +static const struct snd_kcontrol_new va_dec0_mux = SOC_DAPM_ENUM("va_dec0", + va_dec0_enum); +static const struct snd_kcontrol_new va_dec1_mux = SOC_DAPM_ENUM("va_dec1", + va_dec1_enum); +static const struct snd_kcontrol_new va_dec2_mux = SOC_DAPM_ENUM("va_dec2", + va_dec2_enum); +static const struct snd_kcontrol_new va_dec3_mux = SOC_DAPM_ENUM("va_dec3", + va_dec3_enum); + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", + "DMIC4", "DMIC5", "DMIC6", "DMIC7" +}; + +static SOC_ENUM_SINGLE_DECL(va_dmic0_enum, CDC_VA_INP_MUX_ADC_MUX0_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(va_dmic1_enum, CDC_VA_INP_MUX_ADC_MUX1_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(va_dmic2_enum, CDC_VA_INP_MUX_ADC_MUX2_CFG0, + 4, dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL(va_dmic3_enum, CDC_VA_INP_MUX_ADC_MUX3_CFG0, + 4, dmic_mux_text); + +static const struct snd_kcontrol_new va_dmic0_mux = SOC_DAPM_ENUM_EXT("va_dmic0", + va_dmic0_enum, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_dmic1_mux = SOC_DAPM_ENUM_EXT("va_dmic1", + va_dmic1_enum, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_dmic2_mux = SOC_DAPM_ENUM_EXT("va_dmic2", + va_dmic2_enum, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_dmic3_mux = SOC_DAPM_ENUM_EXT("va_dmic3", + va_dmic3_enum, snd_soc_dapm_get_enum_double, + va_macro_put_dec_enum); + +static const struct snd_kcontrol_new va_aif1_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif2_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_kcontrol_new va_aif3_cap_mixer[] = { + SOC_SINGLE_EXT("DEC0", SND_SOC_NOPM, VA_MACRO_DEC0, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC1", SND_SOC_NOPM, VA_MACRO_DEC1, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC2", SND_SOC_NOPM, VA_MACRO_DEC2, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC3", SND_SOC_NOPM, VA_MACRO_DEC3, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC4", SND_SOC_NOPM, VA_MACRO_DEC4, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC5", SND_SOC_NOPM, VA_MACRO_DEC5, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC6", SND_SOC_NOPM, VA_MACRO_DEC6, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), + SOC_SINGLE_EXT("DEC7", SND_SOC_NOPM, VA_MACRO_DEC7, 1, 0, + va_macro_tx_mixer_get, va_macro_tx_mixer_put), +}; + +static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT("VA_AIF1 CAP", "VA_AIF1 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF1_CAP, 0), + + SND_SOC_DAPM_AIF_OUT("VA_AIF2 CAP", "VA_AIF2 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF2_CAP, 0), + + SND_SOC_DAPM_AIF_OUT("VA_AIF3 CAP", "VA_AIF3 Capture", 0, + SND_SOC_NOPM, VA_MACRO_AIF3_CAP, 0), + + SND_SOC_DAPM_MIXER("VA_AIF1_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF1_CAP, 0, + va_aif1_cap_mixer, ARRAY_SIZE(va_aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("VA_AIF2_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF2_CAP, 0, + va_aif2_cap_mixer, ARRAY_SIZE(va_aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("VA_AIF3_CAP Mixer", SND_SOC_NOPM, + VA_MACRO_AIF3_CAP, 0, + va_aif3_cap_mixer, ARRAY_SIZE(va_aif3_cap_mixer)), + + SND_SOC_DAPM_MUX("VA DMIC MUX0", SND_SOC_NOPM, 0, 0, &va_dmic0_mux), + SND_SOC_DAPM_MUX("VA DMIC MUX1", SND_SOC_NOPM, 0, 0, &va_dmic1_mux), + SND_SOC_DAPM_MUX("VA DMIC MUX2", SND_SOC_NOPM, 0, 0, &va_dmic2_mux), + SND_SOC_DAPM_MUX("VA DMIC MUX3", SND_SOC_NOPM, 0, 0, &va_dmic3_mux), + + SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micb", 0, 0), + SND_SOC_DAPM_INPUT("DMIC0 Pin"), + SND_SOC_DAPM_INPUT("DMIC1 Pin"), + SND_SOC_DAPM_INPUT("DMIC2 Pin"), + SND_SOC_DAPM_INPUT("DMIC3 Pin"), + SND_SOC_DAPM_INPUT("DMIC4 Pin"), + SND_SOC_DAPM_INPUT("DMIC5 Pin"), + SND_SOC_DAPM_INPUT("DMIC6 Pin"), + SND_SOC_DAPM_INPUT("DMIC7 Pin"), + + SND_SOC_DAPM_ADC_E("VA DMIC0", NULL, SND_SOC_NOPM, 0, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC1", NULL, SND_SOC_NOPM, 1, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC2", NULL, SND_SOC_NOPM, 2, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC3", NULL, SND_SOC_NOPM, 3, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC4", NULL, SND_SOC_NOPM, 4, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC5", NULL, SND_SOC_NOPM, 5, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC6", NULL, SND_SOC_NOPM, 6, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("VA DMIC7", NULL, SND_SOC_NOPM, 7, 0, + va_macro_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_INPUT("VA SWR_ADC0"), + SND_SOC_DAPM_INPUT("VA SWR_ADC1"), + SND_SOC_DAPM_INPUT("VA SWR_ADC2"), + SND_SOC_DAPM_INPUT("VA SWR_ADC3"), + SND_SOC_DAPM_INPUT("VA SWR_MIC0"), + SND_SOC_DAPM_INPUT("VA SWR_MIC1"), + SND_SOC_DAPM_INPUT("VA SWR_MIC2"), + SND_SOC_DAPM_INPUT("VA SWR_MIC3"), + SND_SOC_DAPM_INPUT("VA SWR_MIC4"), + SND_SOC_DAPM_INPUT("VA SWR_MIC5"), + SND_SOC_DAPM_INPUT("VA SWR_MIC6"), + SND_SOC_DAPM_INPUT("VA SWR_MIC7"), + + SND_SOC_DAPM_MUX_E("VA DEC0 MUX", SND_SOC_NOPM, VA_MACRO_DEC0, 0, + &va_dec0_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC1 MUX", SND_SOC_NOPM, VA_MACRO_DEC1, 0, + &va_dec1_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC2 MUX", SND_SOC_NOPM, VA_MACRO_DEC2, 0, + &va_dec2_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("VA DEC3 MUX", SND_SOC_NOPM, VA_MACRO_DEC3, 0, + &va_dec3_mux, va_macro_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0, + va_macro_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route va_audio_map[] = { + {"VA_AIF1 CAP", NULL, "VA_MCLK"}, + {"VA_AIF2 CAP", NULL, "VA_MCLK"}, + {"VA_AIF3 CAP", NULL, "VA_MCLK"}, + + {"VA_AIF1 CAP", NULL, "VA_AIF1_CAP Mixer"}, + {"VA_AIF2 CAP", NULL, "VA_AIF2_CAP Mixer"}, + {"VA_AIF3 CAP", NULL, "VA_AIF3_CAP Mixer"}, + + {"VA_AIF1_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF1_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA_AIF2_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF2_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA_AIF3_CAP Mixer", "DEC0", "VA DEC0 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC1", "VA DEC1 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC2", "VA DEC2 MUX"}, + {"VA_AIF3_CAP Mixer", "DEC3", "VA DEC3 MUX"}, + + {"VA DEC0 MUX", "VA_DMIC", "VA DMIC MUX0"}, + {"VA DMIC MUX0", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX0", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX0", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX0", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX0", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX0", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX0", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX0", "DMIC7", "VA DMIC7"}, + + {"VA DEC1 MUX", "VA_DMIC", "VA DMIC MUX1"}, + {"VA DMIC MUX1", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX1", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX1", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX1", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX1", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX1", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX1", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX1", "DMIC7", "VA DMIC7"}, + + {"VA DEC2 MUX", "VA_DMIC", "VA DMIC MUX2"}, + {"VA DMIC MUX2", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX2", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX2", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX2", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX2", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX2", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX2", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX2", "DMIC7", "VA DMIC7"}, + + {"VA DEC3 MUX", "VA_DMIC", "VA DMIC MUX3"}, + {"VA DMIC MUX3", "DMIC0", "VA DMIC0"}, + {"VA DMIC MUX3", "DMIC1", "VA DMIC1"}, + {"VA DMIC MUX3", "DMIC2", "VA DMIC2"}, + {"VA DMIC MUX3", "DMIC3", "VA DMIC3"}, + {"VA DMIC MUX3", "DMIC4", "VA DMIC4"}, + {"VA DMIC MUX3", "DMIC5", "VA DMIC5"}, + {"VA DMIC MUX3", "DMIC6", "VA DMIC6"}, + {"VA DMIC MUX3", "DMIC7", "VA DMIC7"}, + + { "VA DMIC0", NULL, "DMIC0 Pin" }, + { "VA DMIC1", NULL, "DMIC1 Pin" }, + { "VA DMIC2", NULL, "DMIC2 Pin" }, + { "VA DMIC3", NULL, "DMIC3 Pin" }, + { "VA DMIC4", NULL, "DMIC4 Pin" }, + { "VA DMIC5", NULL, "DMIC5 Pin" }, + { "VA DMIC6", NULL, "DMIC6 Pin" }, + { "VA DMIC7", NULL, "DMIC7 Pin" }, +}; + static const char * const dec_mode_mux_text[] = { "ADC_DEFAULT", "ADC_LOW_PWR", "ADC_HIGH_PERF", }; @@ -680,6 +1296,10 @@ static const struct snd_soc_component_driver va_macro_component_drv = { .probe = va_macro_component_probe, .controls = va_macro_snd_controls, .num_controls = ARRAY_SIZE(va_macro_snd_controls), + .dapm_widgets = va_macro_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(va_macro_dapm_widgets), + .dapm_routes = va_audio_map, + .num_dapm_routes = ARRAY_SIZE(va_audio_map), }; static int fsgen_gate_enable(struct clk_hw *hw) -- cgit v1.2.3 From 7998c168a94de9c593ab07455924e827ad5f1bd7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:12 -0600 Subject: ASoC: Intel: broadwell: add missing pm_ops For some reason this ops is missing in 2 out of the 3 broadwell drivers. Add to make sure ASoC takes care of power management. Tested-by: Cezary Rojewski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/broadwell.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 77c85f17aca6..69e0b13b47f4 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -318,6 +318,7 @@ static struct platform_driver broadwell_audio = { .remove = broadwell_audio_remove, .driver = { .name = "broadwell-audio", + .pm = &snd_soc_pm_ops }, }; -- cgit v1.2.3 From cf7f4a5320cda6fc533ae96601b4ce767d1af0f8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:13 -0600 Subject: ASoC: Intel: bdw-rt5677: add missing pm_ops For some reason this ops is missing in 2 out of the 3 broadwell drivers. Add to make sure ASoC takes care of power management. Tested-by: Cezary Rojewski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5677.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 7a3e773d0a1c..9cdd4164e1fb 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -446,6 +446,7 @@ static struct platform_driver bdw_rt5677_audio = { .probe = bdw_rt5677_probe, .driver = { .name = "bdw-rt5677", + .pm = &snd_soc_pm_ops }, }; -- cgit v1.2.3 From 61349f0f2715d08f9ab4448bc9004810fc74b531 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 18 Nov 2020 21:14:20 +0100 Subject: ASoC: sunxi: do not select COMMON_CLK to fix builds COMMON_CLK is a user-selectable option with its own dependencies. The most important dependency is !HAVE_LEGACY_CLK. User-selectable drivers should not select COMMON_CLK because they will create a dependency cycle and build failures. For example on MIPS a configuration with COMMON_CLK (selected by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (selected by SOC_RT305X) is possible: WARNING: unmet direct dependencies detected for COMMON_CLK Depends on [n]: !HAVE_LEGACY_CLK [=y] Selected by [y]: - SND_SUN8I_CODEC [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && (ARCH_SUNXI || COMPILE_TEST [=y]) && OF [=y] && (MACH_SUN8I || ARM64 && ARCH_SUNXI || COMPILE_TEST [=y]) /usr/bin/mips-linux-gnu-ld: drivers/clk/clk.o: in function `clk_set_rate': (.text+0xaeb4): multiple definition of `clk_set_rate'; arch/mips/ralink/clk.o:(.text+0x88): first defined here Signed-off-by: Krzysztof Kozlowski Reviewed-by: Samuel Holland Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/20201118201420.4878-1-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 69b9d8515335..ddcaaa98d3cb 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -14,7 +14,7 @@ config SND_SUN8I_CODEC tristate "Allwinner SUN8I audio codec" depends on OF depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST - select COMMON_CLK + depends on COMMON_CLK select REGMAP_MMIO help This option enables the digital part of the internal audio codec for -- cgit v1.2.3 From 53233e40c142b1e0e1df9d9ac0ffc0945cfffbc9 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 19 Nov 2020 14:40:38 +0800 Subject: ASoC: fsl_sai: Correct the clock source for mclk0 On VF610, mclk0 = bus_clk; On i.MX6SX/6UL/6ULL/7D, mclk0 = mclk1; On i.MX7ULP, mclk0 = bus_clk; On i.MX8QM/8QXP, mclk0 = bus_clk; On i.MX8MQ/8MN/8MM/8MP, mclk0 = bus_clk; So add variable mclk0_is_mclk1 in fsl_sai_soc_data to distinguish these platforms. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/1605768038-4582-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 20 ++++++++++++++++++-- sound/soc/fsl/fsl_sai.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 3e5c1eaccd5e..f3d3d20d35d7 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -359,7 +359,14 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) if (sai->is_slave_mode) return 0; - for (id = 0; id < FSL_SAI_MCLK_MAX; id++) { + /* + * There is no point in polling MCLK0 if it is identical to MCLK1. + * And given that MQS use case has to use MCLK1 though two clocks + * are the same, we simply skip MCLK0 and start to find from MCLK1. + */ + id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0; + + for (; id < FSL_SAI_MCLK_MAX; id++) { clk_rate = clk_get_rate(sai->mclk_clk[id]); if (!clk_rate) continue; @@ -1040,7 +1047,6 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->bus_clk = NULL; } - sai->mclk_clk[0] = sai->bus_clk; for (i = 1; i < FSL_SAI_MCLK_MAX; i++) { sprintf(tmp, "mclk%d", i); sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); @@ -1051,6 +1057,11 @@ static int fsl_sai_probe(struct platform_device *pdev) } } + if (sai->soc_data->mclk0_is_mclk1) + sai->mclk_clk[0] = sai->mclk_clk[1]; + else + sai->mclk_clk[0] = sai->bus_clk; + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -1165,6 +1176,7 @@ static const struct fsl_sai_soc_data fsl_sai_vf610_data = { .use_edma = false, .fifo_depth = 32, .reg_offset = 0, + .mclk0_is_mclk1 = false, }; static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { @@ -1172,6 +1184,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { .use_edma = false, .fifo_depth = 32, .reg_offset = 0, + .mclk0_is_mclk1 = true, }; static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { @@ -1179,6 +1192,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { .use_edma = false, .fifo_depth = 16, .reg_offset = 8, + .mclk0_is_mclk1 = false, }; static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { @@ -1186,6 +1200,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { .use_edma = false, .fifo_depth = 128, .reg_offset = 8, + .mclk0_is_mclk1 = false, }; static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { @@ -1193,6 +1208,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { .use_edma = true, .fifo_depth = 64, .reg_offset = 0, + .mclk0_is_mclk1 = false, }; static const struct of_device_id fsl_sai_ids[] = { diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 4bbcd0dbe8f1..ff2619f1b214 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -219,6 +219,7 @@ struct fsl_sai_soc_data { bool use_imx_pcm; bool use_edma; + bool mclk0_is_mclk1; unsigned int fifo_depth; unsigned int reg_offset; }; -- cgit v1.2.3 From 73ea3a5dbbefa792746e258e267a1e066a6ac855 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Tue, 17 Nov 2020 15:52:23 +0100 Subject: ASoC: Intel: catpt: select WANT_DEV_COREDUMP Select WANT_DEV_COREDUMP for catpt driver. Signed-off-by: Piotr Maziarz Signed-off-by: Gustaw Lewandowski -- Changes in v2: - change should be added to catpt only Acked-by: Cezary Rojewski Link: https://lore.kernel.org/r/20201117145223.21222-1-gustaw.lewandowski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c1bf69a0bcfe..e2247c4fe8ad 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -24,6 +24,7 @@ config SND_SOC_INTEL_CATPT depends on DMADEVICES && SND_DMA_SGBUF select DW_DMAC_CORE select SND_SOC_ACPI_INTEL_MATCH + select WANT_DEV_COREDUMP help Enable support for Intel(R) Haswell and Broadwell platforms with I2S codec present. This is a recommended option. -- cgit v1.2.3 From 9983ac49b7db34258facf47439463e96522e1d5a Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 18 Nov 2020 16:05:44 +0200 Subject: ASoC: SOF: relax PCM period and buffer size constraints Current SOF implementation limits period and buffer sizes to multiples of period_min. Period_min is defined in topology, but is in practise set to align with the SOF DSP timer tick (typically 1ms). While this approach helps user-space to avoid period sizes, which are not aligned to the DSP timer tick, it causes problems to applications which want to align data processing size to that of ALSA period size. One example is JACK audio server, which limits period sizes to power of two values. Other ALSA drivers where audio data transfer is driven by a timer tick, like USB, do not constraint period and buffer sizes to exact multiple of the timer tick. To align SOF to follow the same behaviour, drop the additional alignment constraints. As a side-effect, this patch can cause irregularity to period wakeup timing. This happens when application chooses settings which were previously forbidden. For example, if application configures period size to 2^14 bytes and audio config of S32_LE/2ch/48000Hz, one period represents 42.667ms of audio. Without this patch, this configuration is not allowed by SOF. With the patch applied, configuration is allowed but the wakeups are paced by the DSP timer tick, which is typically 1ms. Application will see period wakeups with a 42/43/42/43ms repeating pattern. Both approaches are valid within ALSA context, but relaxing the constraints is better aligned with existing applications and other ALSA drivers like USB audio. Signed-off-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201118140545.2138895-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 0a70e685f826..37d12162e448 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -478,17 +478,10 @@ static int sof_pcm_open(struct snd_soc_component *component, caps = &spcm->pcm.caps[substream->stream]; - /* set any runtime constraints based on topology */ - snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - le32_to_cpu(caps->period_size_min)); - snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - le32_to_cpu(caps->period_size_min)); - /* set runtime config */ runtime->hw.info = ops->hw_info; /* platform-specific */ + /* set any runtime constraints based on topology */ runtime->hw.formats = le64_to_cpu(caps->formats); runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min); runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max); -- cgit v1.2.3 From caebea04b9125c677e6e747793fbc7fab077727b Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 18 Nov 2020 16:05:45 +0200 Subject: ASoC: SOF: Intel: add hw specific PCM constraints Part of PCM constraints are set based on DSP topology, but rest should be set based on hardware capabilities. Add PCM constraints for Intel platforms: - Add constraint for the period count to be integer. This avoids wrap-arounds of the DMA circular buffer in middle of a period. - Align period size to dword/32bit as per HDA spec. Both constraints are aligned with current implementation in snd-hda-intel driver. Signed-off-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201118140545.2138895-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-pcm.c | 7 +++++++ sound/soc/sof/intel/intel-ipc.c | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index b527d5958ae5..5d35bb18660a 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -225,6 +225,13 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, return -ENODEV; } + /* minimum as per HDA spec */ + snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); + + /* avoid circular buffer wrap in middle of period */ + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + /* binding pcm substream to hda stream */ substream->runtime->private_data = &dsp_stream->hstream; return 0; diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c index 310f9168c124..de66f8a82a07 100644 --- a/sound/soc/sof/intel/intel-ipc.c +++ b/sound/soc/sof/intel/intel-ipc.c @@ -73,6 +73,13 @@ int intel_pcm_open(struct snd_sof_dev *sdev, /* binding pcm substream to hda stream */ substream->runtime->private_data = stream; + /* align to DMA minimum transfer size */ + snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); + + /* avoid circular buffer wrap in middle of period */ + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + return 0; } EXPORT_SYMBOL_NS(intel_pcm_open, SND_SOC_SOF_INTEL_HIFI_EP_IPC); -- cgit v1.2.3 From a27b421f1d04b201c474a15ee1591919c81fb413 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 17 Nov 2020 13:50:01 -0800 Subject: ASoC: pcm: call snd_soc_dapm_stream_stop() in soc_pcm_hw_clean Currently, the SND_SOC_DAPM_STREAM_START event is sent during pcm_prepare() but the SND_SOC_DAPM_STREAM_STOP event is sent only in dpcm_fe_dai_shutdown() after soc_pcm_close(). This results in an imbalance between when the DAPM widgets receive the PRE/POST_PMU/PMD events. So call snd_soc_dapm_stream_stop() in soc_pcm_hw_clean() before the snd_soc_pcm_component_hw_free() to keep the stream_stop DAPM event balanced with the stream_start event in soc_pm_prepare(). Also, in order to prevent duplicate DAPM stream events, remove the call for DAPM STREAM_START event in dpcm_fe_dai_prepare() and the call for DAPM STREAM_STOP event in dpcm_fe_dai_shutdown(). Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201117215001.163107-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index aaab5cfe986b..5250124dc8f5 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -662,8 +662,6 @@ static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback) soc_pcm_components_close(substream, rollback); - if (!rollback) - snd_soc_dapm_stream_stop(rtd, substream->stream); mutex_unlock(&rtd->card->pcm_mutex); @@ -882,6 +880,9 @@ static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback) snd_soc_dai_digital_mute(dai, 1, substream->stream); } + /* run the stream event */ + snd_soc_dapm_stream_stop(rtd, substream->stream); + /* free any machine hw params */ snd_soc_link_hw_free(substream, rollback); @@ -1859,9 +1860,6 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) /* now shutdown the frontend */ soc_pcm_close(substream); - /* run the stream event for each BE */ - dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); - fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); return 0; @@ -2363,8 +2361,6 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) goto out; } - /* run the stream event for each BE */ - dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; out: -- cgit v1.2.3 From b5682305297db24b456e55ba209574cb8f9318f9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:14 -0600 Subject: ALSA: hda: intel-dsp-config: add helper for ACPI DSP driver selection Mirror capabilities provided for PCI devices, so that distributions can select which ACPI driver is loaded at run-time with kernel parameters and DMI tables instead of forcing a build-time selection. The "legacy" option supported for HDaudio has no meaning here and will be ignored. The 'SST' driver based on closed-source firmware has the priority to avoid any impact on users, and the choice to use SOF is strictly opt-in. This may change at some point when the 'SST' driver is deprecated on Baytrail/Cherrytrail. Signed-off-by: Pierre-Louis Bossart Acked-by: Takashi Iwai Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/intel-dsp-config.h | 7 ++++ sound/hda/intel-dsp-config.c | 77 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) (limited to 'sound') diff --git a/include/sound/intel-dsp-config.h b/include/sound/intel-dsp-config.h index c36622bee3f8..d4609077c258 100644 --- a/include/sound/intel-dsp-config.h +++ b/include/sound/intel-dsp-config.h @@ -21,6 +21,7 @@ enum { #if IS_ENABLED(CONFIG_SND_INTEL_DSP_CONFIG) int snd_intel_dsp_driver_probe(struct pci_dev *pci); +int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]); #else @@ -29,6 +30,12 @@ static inline int snd_intel_dsp_driver_probe(struct pci_dev *pci) return SND_INTEL_DSP_DRIVER_ANY; } +static inline +int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]) +{ + return SND_INTEL_DSP_DRIVER_ANY; +} + #endif #endif diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 1c5114dedda9..7e6b8571c138 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -29,6 +29,7 @@ MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=lega struct config_entry { u32 flags; u16 device; + u8 acpi_hid[ACPI_ID_LEN]; const struct dmi_system_id *dmi_table; }; @@ -433,6 +434,82 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) } EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); +/* + * configuration table + * - the order of similar ACPI ID entries is important! + * - the first successful match will win + */ +static const struct config_entry acpi_config_table[] = { +/* BayTrail */ +#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) + { + .flags = FLAG_SST, + .acpi_hid = "80860F28", + }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + { + .flags = FLAG_SOF, + .acpi_hid = "80860F28", + }, +#endif +/* CherryTrail */ +#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) + { + .flags = FLAG_SST, + .acpi_hid = "808622A8", + }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + { + .flags = FLAG_SOF, + .acpi_hid = "808622A8", + }, +#endif +}; + +static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN], + const struct config_entry *table, + u32 len) +{ + for (; len > 0; len--, table++) { + if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN)) + continue; + if (table->dmi_table && !dmi_check_system(table->dmi_table)) + continue; + return table; + } + return NULL; +} + +int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]) +{ + const struct config_entry *cfg; + + if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) + return dsp_driver; + + if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) { + dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n", + SND_INTEL_DSP_DRIVER_LEGACY); + } + + /* find the configuration for the specific device */ + cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table, + ARRAY_SIZE(acpi_config_table)); + if (!cfg) + return SND_INTEL_DSP_DRIVER_ANY; + + if (cfg->flags & FLAG_SST) + return SND_INTEL_DSP_DRIVER_SST; + + if (cfg->flags & FLAG_SOF) + return SND_INTEL_DSP_DRIVER_SOF; + + return SND_INTEL_DSP_DRIVER_SST; +} +EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel DSP config driver"); MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); -- cgit v1.2.3 From 41656c3dc2acfe2aef3d7c4e1cd2b92f49b6e3a7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:16 -0600 Subject: ASoC: Intel: boards: byt/cht: set card and driver name at run time To avoid hard-coded variations between SOF and SST drivers, set the card name and driver dynamically depending on the parent type. This is the first pass required to let distributions select which drivers to use with kernel parameters instead of build-time selection. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_cx2072x.c | 20 +++++++++++++----- sound/soc/intel/boards/bytcht_da7213.c | 20 +++++++++++++----- sound/soc/intel/boards/bytcht_es8316.c | 22 +++++++++++++------- sound/soc/intel/boards/bytcr_rt5640.c | 22 +++++++++++++------- sound/soc/intel/boards/bytcr_rt5651.c | 20 +++++++++++++----- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 22 +++++++++++++------- sound/soc/intel/boards/cht_bsw_nau8824.c | 22 +++++++++++++------- sound/soc/intel/boards/cht_bsw_rt5645.c | 31 +++++++++++++++++++--------- sound/soc/intel/boards/cht_bsw_rt5672.c | 22 +++++++++++++------- 9 files changed, 141 insertions(+), 60 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 0b50b3646d55..762f09190f10 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -205,14 +205,12 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht cx2072x" /* card name will be 'sof-bytcht cx2072x' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcht-cx2072x" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card byt_cht_cx2072x_card = { @@ -236,6 +234,7 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; struct acpi_device *adev; int dai_index = 0; + bool sof_parent; int i, ret; byt_cht_cx2072x_card.dev = &pdev->dev; @@ -265,6 +264,17 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) if (ret) return ret; + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + byt_cht_cx2072x_card.name = SOF_CARD_NAME; + byt_cht_cx2072x_card.driver_name = SOF_DRIVER_NAME; + } else { + byt_cht_cx2072x_card.name = CARD_NAME; + byt_cht_cx2072x_card.driver_name = DRIVER_NAME; + } + return devm_snd_soc_register_card(&pdev->dev, &byt_cht_cx2072x_card); } diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index e1e46b4bbac5..ef6682226a85 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -205,14 +205,12 @@ static struct snd_soc_dai_link dailink[] = { }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht da7213" /* card name will be 'sof-bytcht da7213' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcht-da7213" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card bytcht_da7213_card = { @@ -237,6 +235,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; const char *platform_name; struct acpi_device *adev; + bool sof_parent; int dai_index = 0; int ret_val = 0; int i; @@ -269,6 +268,17 @@ static int bytcht_da7213_probe(struct platform_device *pdev) if (ret_val) return ret_val; + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + bytcht_da7213_card.name = SOF_CARD_NAME; + bytcht_da7213_card.driver_name = SOF_DRIVER_NAME; + } else { + bytcht_da7213_card.name = CARD_NAME; + bytcht_da7213_card.driver_name = DRIVER_NAME; + } + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 7ed869bf1a92..fbb62bab9dcc 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -406,18 +406,14 @@ static int byt_cht_es8316_resume(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcht-es8316" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif static struct snd_soc_card byt_cht_es8316_card = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = byt_cht_es8316_dais, .num_links = ARRAY_SIZE(byt_cht_es8316_dais), @@ -472,6 +468,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) const char *platform_name; struct acpi_device *adev; struct device *codec_dev; + bool sof_parent; unsigned int cnt = 0; int dai_index = 0; int i; @@ -590,6 +587,17 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_card.long_name = long_name; #endif + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + byt_cht_es8316_card.name = SOF_CARD_NAME; + byt_cht_es8316_card.driver_name = SOF_DRIVER_NAME; + } else { + byt_cht_es8316_card.name = CARD_NAME; + byt_cht_es8316_card.driver_name = DRIVER_NAME; + } + /* register the soc card */ snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 9dadf6561444..574b489a3283 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1136,18 +1136,14 @@ static int byt_rt5640_resume(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht rt5640" /* card name will be 'sof-bytcht rt5640' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht rt5640" /* card name will be 'sof-bytcht rt5640' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcr-rt5640" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif static struct snd_soc_card byt_rt5640_card = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = byt_rt5640_dais, .num_links = ARRAY_SIZE(byt_rt5640_dais), @@ -1173,6 +1169,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; const char *platform_name; struct acpi_device *adev; + bool sof_parent; int ret_val = 0; int dai_index = 0; int i; @@ -1336,6 +1333,17 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) if (ret_val) return ret_val; + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + byt_rt5640_card.name = SOF_CARD_NAME; + byt_rt5640_card.driver_name = SOF_DRIVER_NAME; + } else { + byt_rt5640_card.name = CARD_NAME; + byt_rt5640_card.driver_name = DRIVER_NAME; + } + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) { diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 64d3fc4a3225..69e1d84e4de3 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -827,14 +827,12 @@ static int byt_rt5651_resume(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht rt5651" /* card name will be 'sof-bytcht rt5651' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht rt5651" /* card name will be 'sof-bytcht rt5651' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bytcr-rt5651" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif static struct snd_soc_card byt_rt5651_card = { .name = CARD_NAME, @@ -876,6 +874,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) const char *platform_name; struct acpi_device *adev; struct device *codec_dev; + bool sof_parent; bool is_bytcr = false; int ret_val = 0; int dai_index = 0; @@ -1093,6 +1092,17 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) if (ret_val) return ret_val; + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + byt_rt5651_card.name = SOF_CARD_NAME; + byt_rt5651_card.driver_name = SOF_DRIVER_NAME; + } else { + byt_rt5651_card.name = CARD_NAME; + byt_rt5651_card.driver_name = DRIVER_NAME; + } + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); if (ret_val) { diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 835e9bd6b52d..a1d456d7a9c2 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -382,19 +382,15 @@ static struct snd_soc_dai_link cht_dailink[] = { }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "chtmax98090" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -540,6 +536,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *mclk_name; struct snd_soc_acpi_mach *mach; const char *platform_name; + bool sof_parent; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) @@ -602,6 +599,17 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } } + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + snd_soc_card_cht.name = SOF_CARD_NAME; + snd_soc_card_cht.driver_name = SOF_DRIVER_NAME; + } else { + snd_soc_card_cht.name = CARD_NAME; + snd_soc_card_cht.driver_name = DRIVER_NAME; + } + ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { dev_err(&pdev->dev, diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 3e12bff15fed..f173793d867b 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -231,19 +231,15 @@ static struct snd_soc_dai_link cht_dailink[] = { }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht nau8824" /* card name will be 'sof-bytcht nau8824 */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "chtnau8824" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -260,6 +256,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) struct cht_mc_private *drv; struct snd_soc_acpi_mach *mach; const char *platform_name; + bool sof_parent; int ret_val; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -277,6 +274,17 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (ret_val) return ret_val; + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + snd_soc_card_cht.name = SOF_CARD_NAME; + snd_soc_card_cht.driver_name = SOF_DRIVER_NAME; + } else { + snd_soc_card_cht.name = CARD_NAME; + snd_soc_card_cht.driver_name = DRIVER_NAME; + } + /* register the soc card */ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index b53c02481749..bdaf8d00fc6b 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -479,21 +479,17 @@ static struct snd_soc_dai_link cht_dailink[] = { }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_RT5645_NAME "bytcht rt5645" /* card name 'sof-bytcht rt5645' */ -#define CARD_RT5650_NAME "bytcht rt5650" /* card name 'sof-bytcht rt5650' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_RT5645_NAME "bytcht rt5645" /* card name 'sof-bytcht rt5645' */ +#define SOF_CARD_RT5650_NAME "bytcht rt5650" /* card name 'sof-bytcht rt5650' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_RT5645_NAME "chtrt5645" #define CARD_RT5650_NAME "chtrt5650" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card snd_soc_card_chtrt5645 = { - .name = CARD_RT5645_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -506,8 +502,6 @@ static struct snd_soc_card snd_soc_card_chtrt5645 = { }; static struct snd_soc_card snd_soc_card_chtrt5650 = { - .name = CARD_RT5650_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -541,6 +535,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *platform_name; struct cht_mc_private *drv; struct acpi_device *adev; + bool sof_parent; bool found = false; bool is_bytcr = false; int dai_index = 0; @@ -680,6 +675,22 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } snd_soc_card_set_drvdata(card, drv); + + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + snd_soc_card_chtrt5645.name = SOF_CARD_RT5645_NAME; + snd_soc_card_chtrt5645.driver_name = SOF_DRIVER_NAME; + snd_soc_card_chtrt5650.name = SOF_CARD_RT5650_NAME; + snd_soc_card_chtrt5650.driver_name = SOF_DRIVER_NAME; + } else { + snd_soc_card_chtrt5645.name = CARD_RT5645_NAME; + snd_soc_card_chtrt5645.driver_name = DRIVER_NAME; + snd_soc_card_chtrt5650.name = CARD_RT5650_NAME; + snd_soc_card_chtrt5650.driver_name = DRIVER_NAME; + } + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 8442be93eb1c..6c46bfc43b50 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -382,19 +382,15 @@ static int cht_resume_post(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "cht-bsw-rt5672" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = cht_dailink, .num_links = ARRAY_SIZE(cht_dailink), @@ -417,6 +413,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; const char *platform_name; struct acpi_device *adev; + bool sof_parent; int i; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -458,6 +455,17 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + sof_parent = snd_soc_acpi_sof_parent(&pdev->dev); + + /* set card and driver name */ + if (sof_parent) { + snd_soc_card_cht.name = SOF_CARD_NAME; + snd_soc_card_cht.driver_name = SOF_DRIVER_NAME; + } else { + snd_soc_card_cht.name = CARD_NAME; + snd_soc_card_cht.driver_name = DRIVER_NAME; + } + /* register the soc card */ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { -- cgit v1.2.3 From 05ff312badb6079f18c0b05d89e21733a9dafe32 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:17 -0600 Subject: ASoC: Intel: byt/cht: set pm ops dynamically The Atom/SST driver does not rely on ASoC power management, but the SOF driver does. Rather than using a hard-coded build-time assignment, we can set this pm_ops dynamically depending on what the parent is. That will remove the last build-time dependency and allow for coexistence of both SST and SOF drivers for Baytrail/Cherrytrail. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_cx2072x.c | 7 ++++--- sound/soc/intel/boards/bytcht_da7213.c | 7 ++++--- sound/soc/intel/boards/bytcht_es8316.c | 7 ++++--- sound/soc/intel/boards/bytcr_rt5640.c | 8 +++++--- sound/soc/intel/boards/bytcr_rt5651.c | 7 ++++--- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 7 ++++--- sound/soc/intel/boards/cht_bsw_nau8824.c | 7 ++++--- sound/soc/intel/boards/cht_bsw_rt5645.c | 7 ++++--- sound/soc/intel/boards/cht_bsw_rt5672.c | 7 ++++--- 9 files changed, 37 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 762f09190f10..2bfe3e4c696f 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -275,15 +275,16 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) byt_cht_cx2072x_card.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + return devm_snd_soc_register_card(&pdev->dev, &byt_cht_cx2072x_card); } static struct platform_driver snd_byt_cht_cx2072x_driver = { .driver = { .name = "bytcht_cx2072x", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_byt_cht_cx2072x_probe, }; diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index ef6682226a85..cfeba27252ba 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -279,6 +279,10 @@ static int bytcht_da7213_probe(struct platform_device *pdev) bytcht_da7213_card.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, @@ -292,9 +296,6 @@ static int bytcht_da7213_probe(struct platform_device *pdev) static struct platform_driver bytcht_da7213_driver = { .driver = { .name = "bytcht_da7213", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = bytcht_da7213_probe, }; diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index fbb62bab9dcc..892cf684216e 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -598,6 +598,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_card.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + dev->driver->pm = &snd_soc_pm_ops; + /* register the soc card */ snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); @@ -623,9 +627,6 @@ static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) static struct platform_driver snd_byt_cht_es8316_mc_driver = { .driver = { .name = "bytcht_es8316", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_byt_cht_es8316_mc_probe, .remove = snd_byt_cht_es8316_mc_remove, diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 574b489a3283..18f668fbc64c 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1163,6 +1163,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; @@ -1344,6 +1345,10 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) byt_rt5640_card.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + dev->driver->pm = &snd_soc_pm_ops; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) { @@ -1358,9 +1363,6 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) static struct platform_driver snd_byt_rt5640_mc_driver = { .driver = { .name = "bytcr_rt5640", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_byt_rt5640_mc_probe, }; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 69e1d84e4de3..f289ec8563a1 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -1103,6 +1103,10 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) byt_rt5651_card.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); if (ret_val) { @@ -1117,9 +1121,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) static struct platform_driver snd_byt_rt5651_mc_driver = { .driver = { .name = "bytcr_rt5651", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_byt_rt5651_mc_probe, }; diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index a1d456d7a9c2..131882378a59 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -610,6 +610,10 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_cht.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + dev->driver->pm = &snd_soc_pm_ops; + ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { dev_err(&pdev->dev, @@ -634,9 +638,6 @@ static int snd_cht_mc_remove(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-max98090", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_cht_mc_probe, .remove = snd_cht_mc_remove, diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index f173793d867b..8131af1730f7 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -285,6 +285,10 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_cht.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + /* register the soc card */ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { @@ -300,9 +304,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-nau8824", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_cht_mc_probe, }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index bdaf8d00fc6b..6fea554cfed5 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -691,6 +691,10 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_chtrt5650.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, @@ -704,9 +708,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-rt5645", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_cht_mc_probe, }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 6c46bfc43b50..10c88ef2f85d 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -466,6 +466,10 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_cht.driver_name = DRIVER_NAME; } + /* set pm ops */ + if (sof_parent) + pdev->dev.driver->pm = &snd_soc_pm_ops; + /* register the soc card */ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { @@ -480,9 +484,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-rt5672", -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - .pm = &snd_soc_pm_ops, -#endif }, .probe = snd_cht_mc_probe, }; -- cgit v1.2.3 From f7313f9fc28781ad0801d8b9c692222445e664ca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:18 -0600 Subject: ASoC: SOF: acpi: add dynamic selection of DSP driver Follow PCI example and stop the probe when another driver is desired for the same ACPI HID. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 1 + sound/soc/sof/sof-acpi-dev.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index b607dba5fb2a..7005fc67ca42 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -79,6 +79,7 @@ config SND_SOC_SOF_BAYTRAIL_SUPPORT config SND_SOC_SOF_BAYTRAIL tristate select SND_SOC_SOF_INTEL_ATOM_HIFI_EP + select SND_INTEL_DSP_CONFIG help This option is not user-selectable but automagically handled by 'select' statements at a higher level. diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index a78b76ef37b2..2a369c2c6551 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -120,12 +121,23 @@ static void sof_acpi_probe_complete(struct device *dev) static int sof_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const struct acpi_device_id *id; const struct sof_dev_desc *desc; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; int ret; - dev_dbg(&pdev->dev, "ACPI DSP detected"); + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + ret = snd_intel_acpi_dsp_driver_probe(dev, id->id); + if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) { + dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n"); + return -ENODEV; + } + + dev_dbg(dev, "ACPI DSP detected"); sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); if (!sof_pdata) -- cgit v1.2.3 From df5f5edaef4b653fa731dcf3753e71766f95c2cd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:19 -0600 Subject: ASoC: Intel: Atom: add dynamic selection of DSP driver Follow PCI example and stop the probe when another driver is desired for the same ACPI HID. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/atom/sst/sst_acpi.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c1bf69a0bcfe..25ce4f6ed4b8 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -55,6 +55,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI depends on X86 && ACPI && PCI select SND_SST_ATOM_HIFI2_PLATFORM select SND_SOC_ACPI_INTEL_MATCH + select SND_INTEL_DSP_CONFIG select IOSF_MBI help If you have a Intel Baytrail or Cherrytrail platform with an I2S diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index f943a0884976..2c1b8a2e3506 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -246,6 +247,13 @@ static int sst_acpi_probe(struct platform_device *pdev) id = acpi_match_device(dev->driver->acpi_match_table, dev); if (!id) return -ENODEV; + + ret = snd_intel_acpi_dsp_driver_probe(dev, id->id); + if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SST) { + dev_dbg(dev, "SST ACPI driver not selected, aborting probe\n"); + return -ENODEV; + } + dev_dbg(dev, "for %s\n", id->id); mach = (struct snd_soc_acpi_mach *)id->driver_data; -- cgit v1.2.3 From b405b4318c77db061fdf1c8c4b9329ea30e807ee Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:20 -0600 Subject: ASoC: SOF: Intel: allow for coexistence between SOF and Atom/SST drivers Now that we have all the support needed for coexistence between ACPI drivers for Baytrail and Cherrytrail, remove mutual exclusion in the Kconfig file. The selection is done by playing with the snd_intel_dsp module parameter. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 7005fc67ca42..d554888043ac 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -62,17 +62,16 @@ if SND_SOC_SOF_INTEL_ACPI config SND_SOC_SOF_BAYTRAIL_SUPPORT bool "SOF support for Baytrail, Braswell and Cherrytrail" - depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI=n help This adds support for Sound Open Firmware for Intel(R) platforms using the Baytrail, Braswell or Cherrytrail processors. - This option is mutually exclusive with the Atom/SST and Baytrail - legacy drivers. If you want to enable SOF on Baytrail/Cherrytrail, - you need to deselect those options first. - SOF does not support Baytrail-CR for now, so this option is not - recommended for distros. At some point all legacy drivers will be - deprecated but not before all userspace firmware/topology/UCM files - are made available to downstream distros. + This option can coexist in the same build with the Atom legacy + drivers, currently the default but which will be deprecated + at some point. + Existing firmware/topology binaries and UCM configurations + typically located in the root file system are already + compatible with both SOF or Atom/SST legacy drivers. + This is a recommended option for distributions. Say Y if you want to enable SOF on Baytrail/Cherrytrail. If unsure select "N". -- cgit v1.2.3 From 803e591337e6f7953350e0f56284ebbabb600808 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:21 -0600 Subject: ALSA: hda: intel-dsp-config: add Broadwell ACPI DSP driver selection Add ACPI IDs for Broadwell (and Haswell for consistency). This addition is required for dynamic selection of drivers on those devices. Signed-off-by: Pierre-Louis Bossart Acked-by: Takashi Iwai Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/hda/intel-dsp-config.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'sound') diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 7e6b8571c138..0dc079ba02ff 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -466,6 +466,26 @@ static const struct config_entry acpi_config_table[] = { .acpi_hid = "808622A8", }, #endif +/* Broadwell */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) + { + .flags = FLAG_SST, + .acpi_hid = "INT3438" + }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) + { + .flags = FLAG_SOF, + .acpi_hid = "INT3438" + }, +#endif +/* Haswell - not supported by SOF but added for consistency */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) + { + .flags = FLAG_SST, + .acpi_hid = "INT33C8" + }, +#endif }; static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN], -- cgit v1.2.3 From 8643e85aab878fe0d8031ae4622b40cfb78d4172 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:22 -0600 Subject: ASoC: Intel: broadwell: set card and driver name dynamically Remove last hard-coded build-time dependency Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5650.c | 17 ++++++++++++----- sound/soc/intel/boards/bdw-rt5677.c | 17 ++++++++++++----- sound/soc/intel/boards/broadwell.c | 19 ++++++++++++------- 3 files changed, 36 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index aa420b201848..c5122d3b0e6c 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -262,14 +262,12 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { }, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bdw rt5650" /* card name will be 'sof-bdw rt5650' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bdw rt5650" /* card name will be 'sof-bdw rt5650' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bdw-rt5650" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* ASoC machine driver for Broadwell DSP + RT5650 */ static struct snd_soc_card bdw_rt5650_card = { @@ -309,6 +307,15 @@ static int bdw_rt5650_probe(struct platform_device *pdev) if (ret) return ret; + /* set card and driver name */ + if (snd_soc_acpi_sof_parent(&pdev->dev)) { + bdw_rt5650_card.name = SOF_CARD_NAME; + bdw_rt5650_card.driver_name = SOF_DRIVER_NAME; + } else { + bdw_rt5650_card.name = CARD_NAME; + bdw_rt5650_card.driver_name = DRIVER_NAME; + } + snd_soc_card_set_drvdata(&bdw_rt5650_card, bdw_rt5650); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5650_card); diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 9cdd4164e1fb..021bc59aac80 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -387,14 +387,12 @@ static int bdw_rt5677_resume_post(struct snd_soc_card *card) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "bdw-rt5677" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* ASoC machine driver for Broadwell DSP + RT5677 */ static struct snd_soc_card bdw_rt5677_card = { @@ -437,6 +435,15 @@ static int bdw_rt5677_probe(struct platform_device *pdev) if (ret) return ret; + /* set card and driver name */ + if (snd_soc_acpi_sof_parent(&pdev->dev)) { + bdw_rt5677_card.name = SOF_CARD_NAME; + bdw_rt5677_card.driver_name = SOF_DRIVER_NAME; + } else { + bdw_rt5677_card.name = CARD_NAME; + bdw_rt5677_card.driver_name = DRIVER_NAME; + } + snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 69e0b13b47f4..3c3aff9c61cc 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -262,19 +262,15 @@ static int broadwell_resume(struct snd_soc_card *card){ return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) /* use space before codec name to simplify card ID, and simplify driver name */ -#define CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */ -#define DRIVER_NAME "SOF" -#else +#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */ +#define SOF_DRIVER_NAME "SOF" + #define CARD_NAME "broadwell-rt286" #define DRIVER_NAME NULL /* card name will be used for driver name */ -#endif /* broadwell audio machine driver for WPT + RT286S */ static struct snd_soc_card broadwell_rt286 = { - .name = CARD_NAME, - .driver_name = DRIVER_NAME, .owner = THIS_MODULE, .dai_link = broadwell_rt286_dais, .num_links = ARRAY_SIZE(broadwell_rt286_dais), @@ -303,6 +299,15 @@ static int broadwell_audio_probe(struct platform_device *pdev) if (ret) return ret; + /* set card and driver name */ + if (snd_soc_acpi_sof_parent(&pdev->dev)) { + broadwell_rt286.name = SOF_CARD_NAME; + broadwell_rt286.driver_name = SOF_DRIVER_NAME; + } else { + broadwell_rt286.name = CARD_NAME; + broadwell_rt286.driver_name = DRIVER_NAME; + } + return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); } -- cgit v1.2.3 From ec8a15d3a7c7d6e9acd2e0637d2020ac17fb7820 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:23 -0600 Subject: ASoC: Intel: catpt: add dynamic selection of DSP driver Follow PCI example and stop the probe when another driver is desired for the same ACPI HID. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/catpt/device.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 25ce4f6ed4b8..998c4a2601ac 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -24,6 +24,7 @@ config SND_SOC_INTEL_CATPT depends on DMADEVICES && SND_DMA_SGBUF select DW_DMAC_CORE select SND_SOC_ACPI_INTEL_MATCH + select SND_INTEL_DSP_CONFIG help Enable support for Intel(R) Haswell and Broadwell platforms with I2S codec present. This is a recommended option. diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index b1d380868d8c..85a34e37316d 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -239,9 +240,20 @@ static int catpt_acpi_probe(struct platform_device *pdev) const struct catpt_spec *spec; struct catpt_dev *cdev; struct device *dev = &pdev->dev; + const struct acpi_device_id *id; struct resource *res; int ret; + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + ret = snd_intel_acpi_dsp_driver_probe(dev, id->id); + if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SST) { + dev_dbg(dev, "CATPT ACPI driver not selected, aborting probe\n"); + return -ENODEV; + } + spec = device_get_match_data(dev); if (!spec) return -ENODEV; -- cgit v1.2.3 From 0e5cc22162e55c19255f4e25dadf9fda76eac11c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:25 -0600 Subject: ALSA: hda: intel-dsp-config: ignore dsp_driver parameter for PCI legacy devices On Haswell/Broadwell/Baytrail/Braswell, the DSP is not used for the HDMI/DP interface, and setting the dsp_driver parameter to a value > 1 has the side effect of preventing the HDaudio legacy driver from probing. The DSP driver selection should really only handle cases where a DSP is actually used. This patch traps all known PCI devices and makes sure the HDaudio driver can always be probed. Signed-off-by: Pierre-Louis Bossart Acked-by: Takashi Iwai Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/hda/intel-dsp-config.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 0dc079ba02ff..6a0d070c60c9 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -379,6 +379,20 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) if (pci->vendor != 0x8086) return SND_INTEL_DSP_DRIVER_ANY; + /* + * Legacy devices don't have a PCI-based DSP and use HDaudio + * for HDMI/DP support, ignore kernel parameter + */ + switch (pci->device) { + case 0x160c: /* Broadwell */ + case 0x0a0c: /* Haswell */ + case 0x0c0c: + case 0x0d0c: + case 0x0f04: /* Baytrail */ + case 0x2284: /* Braswell */ + return SND_INTEL_DSP_DRIVER_ANY; + } + if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) return dsp_driver; -- cgit v1.2.3 From d512ef22d77b0779e9b0e9a91a63b291357079f9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 16:38:24 -0600 Subject: ASoC: SOF: Intel: allow for coexistence between SOF and catpt drivers Now that we have all the support needed for coexistence between ACPI drivers for Broadwell, remove mutual exclusion in the Kconfig file. The selection is done by playing with the snd_intel_dspcfg module 'dsp_driver' parameter. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20201112223825.39765-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index d554888043ac..e6302bb03c55 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -85,17 +85,18 @@ config SND_SOC_SOF_BAYTRAIL config SND_SOC_SOF_BROADWELL_SUPPORT bool "SOF support for Broadwell" - depends on SND_SOC_INTEL_HASWELL=n + select SND_INTEL_DSP_CONFIG help This adds support for Sound Open Firmware for Intel(R) platforms using the Broadwell processors. - This option is mutually exclusive with the Haswell/Broadwell legacy - driver. If you want to enable SOF on Broadwell you need to deselect - the legacy driver first. - SOF does not fully support Broadwell yet, so this option is not - recommended for distros. At some point all legacy drivers will be - deprecated but not before all userspace firmware/topology/UCM files - are made available to downstream distros. + This option can coexist in the same build with the default 'catpt' + driver. + Existing firmware/topology binaries and UCM configurations typically + located in the root file system are already compatible with both SOF + or catpt drivers. + SOF does not fully support Broadwell and has limitations related to + DMA and suspend-resume, this is not a recommended option for + distributions. Say Y if you want to enable SOF on Broadwell. If unsure select "N". -- cgit v1.2.3 From 9546c76c73a1ee8b662b09f7308bcb63d2cd0d51 Mon Sep 17 00:00:00 2001 From: Jiaxin Yu Date: Fri, 20 Nov 2020 11:06:12 +0800 Subject: ASoC: mediatek: mt6359: Fix regulator_dev_lookup() fails for id "LDO_VAUD18" Mt6359 platform device is instantiated by mfd_add_devices(). In the case, dev->of_node is NULL so that always fails to get the regulator_dev. Use regualator-name "vaud18" that in dts node instead of "LDO_VAUD19-supply". So that we can get regulator_dev through regulator_lookup_by_name() directly. Fixes: 64a70744b778 ("ASoC: Fix vaud18 power leakage of mt6359") Signed-off-by: Jiaxin Yu Link: https://lore.kernel.org/r/1605841573-1442-2-git-send-email-jiaxin.yu@mediatek.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index d37dbd2b50c2..6de0d744fa9e 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -1943,7 +1943,6 @@ static const struct snd_soc_dapm_widget mt6359_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF, MT6359_DCXO_CW12, RG_XO_AUDIO_EN_M_SFT, 0, NULL, 0), - SND_SOC_DAPM_REGULATOR_SUPPLY("LDO_VAUD18", 0, 0), SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB, MT6359_AUDDEC_ANA_CON13, RG_AUDGLB_PWRDN_VA32_SFT, 1, NULL, 0), @@ -1963,6 +1962,8 @@ static const struct snd_soc_dapm_widget mt6359_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK, MT6359_AUD_TOP_CKPDN_CON0, RG_AUDIF_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_REGULATOR_SUPPLY("vaud18", 0, 0), + /* Digital Clock */ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST, MT6359_AUDIO_TOP_CON0, @@ -2312,7 +2313,7 @@ static int mt_dcc_clk_connect(struct snd_soc_dapm_widget *source, static const struct snd_soc_dapm_route mt6359_dapm_routes[] = { /* Capture */ {"AIFTX_Supply", NULL, "CLK_BUF"}, - {"AIFTX_Supply", NULL, "LDO_VAUD18"}, + {"AIFTX_Supply", NULL, "vaud18"}, {"AIFTX_Supply", NULL, "AUDGLB"}, {"AIFTX_Supply", NULL, "CLKSQ Audio"}, {"AIFTX_Supply", NULL, "AUD_CK"}, @@ -2440,7 +2441,7 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = { /* DL Supply */ {"DL Power Supply", NULL, "CLK_BUF"}, - {"DL Power Supply", NULL, "LDO_VAUD18"}, + {"DL Power Supply", NULL, "vaud18"}, {"DL Power Supply", NULL, "AUDGLB"}, {"DL Power Supply", NULL, "CLKSQ Audio"}, {"DL Power Supply", NULL, "AUDNCP_CK"}, -- cgit v1.2.3 From fca18e62984a0d797da8379a422a6bb644d68244 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Wed, 11 Nov 2020 19:31:05 +0200 Subject: ASoC: SOF: control: override volume info callback ASoC dapm controls currently don't support more than 2 channels. This is a problem for SOF-based devices where individual volume control cannot be provided on the 4 DMIC input path. If we want to provide controls for more than 2 channels, this patch suggests a simple solution based on an override of the info callback. For example, in the case with 4 channel DMIC PGAs, a sof_info callback would be used. Mono and stereo cases will keep using the existing dapm info callback. A longer-term solution would be to remove the limits to 2 channels in ASoC/DAPM/topology. This is a topic Intel is currently looking into, e.g. by removing the use of 'reg' and 'rreg' fields and use arrays instead. Such changes will be rather intrusive and touch multiple codec and platform drivers. Removing restrictions is the right thing to do, but this will need to be done in steps with lots of validation. Signed-off-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201111173105.1927466-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 22 ++++++++++++++++++++++ sound/soc/sof/sof-audio.h | 2 ++ sound/soc/sof/topology.c | 9 +++++++++ 3 files changed, 33 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 056c86ad5a47..a5dd728c580a 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -114,6 +114,28 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, return change; } +int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + unsigned int channels = scontrol->num_channels; + int platform_max; + + if (!sm->platform_max) + sm->platform_max = sm->max; + platform_max = sm->platform_max; + + if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + + uinfo->count = channels; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = platform_max - sm->min; + return 0; +} + int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 9f645a2e5a6c..ddcfd46617f8 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -124,6 +124,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_sof_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *ucontrol); int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_switch_put(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 430d274722ae..b6b32a7a91f8 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1041,6 +1041,15 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, goto out; } + /* + * If control has more than 2 channels we need to override the info. This is because even if + * ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the + * pre-defined dapm control types (and related functions) creating the actual control + * restrict the channels only to mono or stereo. + */ + if (le32_to_cpu(mc->num_channels) > 2) + kc->info = snd_sof_volume_info; + /* init the volume get/put data */ scontrol->size = struct_size(scontrol->control_data, chanv, le32_to_cpu(mc->num_channels)); -- cgit v1.2.3 From 2b3f6f4af95594d8e9c137ddc8d6bec61f04dbb5 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 20 Nov 2020 12:38:13 +0000 Subject: ASoC: codecs: lpass-va-macro: add missing MODULE_DEVICE_TABLE Fix module loading due by adding missing MODULE_DEVICE_TABLE. Fixes: 908e6b1df26e ("ASoC: codecs: lpass-va-macro: Add support to VA Macro") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201120123813.14059-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-va-macro.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index b604de07e650..3e6bbef26dcb 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1487,6 +1487,7 @@ static const struct of_device_id va_macro_dt_match[] = { { .compatible = "qcom,sm8250-lpass-va-macro" }, {} }; +MODULE_DEVICE_TABLE(of, va_macro_dt_match); static struct platform_driver va_macro_driver = { .driver = { -- cgit v1.2.3 From 82d1aeb8a40740cf4208ce864cbcaa5e8bbabf4e Mon Sep 17 00:00:00 2001 From: Kyle Russell Date: Wed, 18 Nov 2020 22:41:06 -0500 Subject: ASoC: mmp-sspa: set phase two word length register If hw params enables dual phase transmission, then the word length for the second phase should be set to match the sample format instead of remaining at the reset default. This matches the configuration already being done for the first phase. This driver already sets the phase two sample size, so this should complete the phase two configuration. Signed-off-by: Kyle Russell Link: https://lore.kernel.org/r/20201119034106.1273906-1-bkylerussell@gmail.com Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-sspa.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 52d4d8ace1c3..4803972ee655 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -246,6 +246,9 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream, sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK; sspa_ctrl |= SSPA_CTL_XWDLEN1(bitval); + sspa_ctrl &= ~SSPA_CTL_XWDLEN2_MASK; + sspa_ctrl |= SSPA_CTL_XWDLEN2(bitval); + sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK; sspa_ctrl |= SSPA_CTL_XSSZ1(bitval); -- cgit v1.2.3 From ddf1c4b3944add7939f6778d8fb71df01e74d45f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 19 Nov 2020 15:31:45 +0300 Subject: ASoC: qcom: sm8250: fix HDMI audio playback Current code does not setup CPU dai (causing -EIO errors on playback) and does not pass SND_SOC_DAIFMT_I2S to codec fmt (causing i2s-hifi errors). Fix both errors to enable HDMI audio playback on SM8250. Tested on RB5 platform. Signed-off-by: Dmitry Baryshkov Fixes: aa2e2785545a ("ASoC: qcom: sm8250: add sound card qrb5165-rb5 support") Cc: Srinivas Kandagatla Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201119123145.709891-1-dmitry.baryshkov@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 315ed6ccb7c4..fe8fd7367e21 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -36,6 +36,7 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int sm8250_snd_startup(struct snd_pcm_substream *substream) { + unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); @@ -43,10 +44,11 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) switch (cpu_dai->id) { case TERTIARY_MI2S_RX: - codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF; + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, fmt); snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; default: -- cgit v1.2.3 From f805e7e09c8f6d56f3e9bd2e7cec729f9d0855d0 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 20 Nov 2020 16:16:53 +0200 Subject: ASoC: SOF: nocodec: modify DAI link definitions The ignore_machine field in the component driver is used to ignore the FE DAI links defined in the machine driver, override BE fixups and set the stream names for the DAI links defined in the machine driver. This is required to make SOF compatible with the legacy machine drivers. In the case of the nocodec machine driver in SOF, there is no need to rely upon this ignore_machine logic in the core. Modify the machine driver to set DAI link stream names and the BE hw_params_fixup callback appropriately. Signed-off-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201120141653.2160134-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 6 ++++-- sound/soc/sof/nocodec.c | 18 ++++++++++++++---- sound/soc/sof/pcm.c | 3 +-- sound/soc/sof/sof-audio.c | 2 +- sound/soc/sof/sof-audio.h | 3 +++ 5 files changed, 23 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/include/sound/sof.h b/include/sound/sof.h index 9aa055289dcc..646a655c3c6b 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -100,6 +100,8 @@ struct sof_dev_desc { const struct snd_sof_dsp_ops *ops; }; -int sof_nocodec_setup(struct device *dev, - const struct snd_sof_dsp_ops *ops); +int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, + int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params)); + #endif diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 9e922df6a710..3b9bb2e83a86 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -10,17 +10,21 @@ #include #include +#include "sof-audio.h" #include "sof-priv.h" static struct snd_soc_card sof_nocodec_card = { .name = "nocodec", /* the sof- prefix is added by the core */ + .topology_shortname = "sof-nocodec", .owner = THIS_MODULE }; static int sof_nocodec_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, struct snd_soc_dai_link *links, - int link_num, struct snd_soc_card *card) + int link_num, struct snd_soc_card *card, + int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params)) { struct snd_soc_dai_link_component *dlc; int i; @@ -39,6 +43,8 @@ static int sof_nocodec_bes_setup(struct device *dev, if (!links[i].name) return -ENOMEM; + links[i].stream_name = links[i].name; + links[i].cpus = &dlc[0]; links[i].codecs = &dlc[1]; links[i].platforms = &dlc[2]; @@ -57,6 +63,8 @@ static int sof_nocodec_bes_setup(struct device *dev, links[i].dpcm_playback = 1; if (ops->drv[i].capture.channels_min) links[i].dpcm_capture = 1; + + links[i].be_hw_params_fixup = pcm_dai_link_fixup; } card->dai_link = links; @@ -65,8 +73,9 @@ static int sof_nocodec_bes_setup(struct device *dev, return 0; } -int sof_nocodec_setup(struct device *dev, - const struct snd_sof_dsp_ops *ops) +int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, + int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params)) { struct snd_soc_dai_link *links; @@ -77,7 +86,7 @@ int sof_nocodec_setup(struct device *dev, return -ENOMEM; return sof_nocodec_bes_setup(dev, ops, links, ops->num_drv, - &sof_nocodec_card); + &sof_nocodec_card, pcm_dai_link_fixup); } EXPORT_SYMBOL(sof_nocodec_setup); @@ -86,6 +95,7 @@ static int sof_nocodec_probe(struct platform_device *pdev) struct snd_soc_card *card = &sof_nocodec_card; card->dev = &pdev->dev; + card->topology_shortname_created = true; return devm_snd_soc_register_card(&pdev->dev, card); } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 37d12162e448..0dc39fbcd81d 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -620,8 +620,7 @@ capture: } /* fixup the BE DAI link to match any values from topology */ -static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) +int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 9a8ce25a8fc8..3277489fee5e 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -468,7 +468,7 @@ int sof_machine_check(struct snd_sof_dev *sdev) mach->drv_name = "sof-nocodec"; sof_pdata->tplg_filename = desc->nocodec_tplg_filename; - ret = sof_nocodec_setup(sdev->dev, desc->ops); + ret = sof_nocodec_setup(sdev->dev, desc->ops, sof_pcm_dai_link_fixup); if (ret < 0) return ret; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index ddcfd46617f8..d00a918b6f39 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -214,6 +214,9 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, enum sof_ipc_ctrl_cmd ctrl_cmd, bool send); +/* DAI link fixup */ +int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); + /* PM */ int sof_restore_pipelines(struct device *dev); int sof_set_hw_params_upon_resume(struct device *dev); -- cgit v1.2.3 From 3371c6f9f4115d8949e093be8299a9c1ebe29137 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Nov 2020 12:23:50 -0600 Subject: ASoC: codecs: Fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix multiple warnings by explicitly adding multiple break statements instead of just letting the code fall through, and also add fallthrough pseudo-keywords in places where the code is intended to fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/d17b4d8300dbb6aff0d055b06b487c96ca264757.1605896059.git.gustavoars@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/adav80x.c | 1 + sound/soc/codecs/arizona.c | 1 + sound/soc/codecs/cs42l52.c | 1 + sound/soc/codecs/cs42l56.c | 1 + sound/soc/codecs/cs47l92.c | 1 + sound/soc/codecs/wm8962.c | 1 + 6 files changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 4fd99280d7db..75a649108106 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -373,6 +373,7 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_CBM_CFM: capture |= ADAV80X_CAPTURE_MODE_MASTER; playback |= ADAV80X_PLAYBACK_MODE_MASTER; + break; case SND_SOC_DAIFMT_CBS_CFS: break; default: diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 1228f2de0297..e32871b3f68a 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1034,6 +1034,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, priv->out_down_delay++; break; } + break; default: break; } diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index f772628f233e..796b894c390f 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -944,6 +944,7 @@ static int cs42l52_beep_event(struct input_dev *dev, unsigned int type, case SND_BELL: if (hz) hz = 261; + break; case SND_TONE: break; default: diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 97024a6ac96d..bb9599cc832b 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1008,6 +1008,7 @@ static int cs42l56_beep_event(struct input_dev *dev, unsigned int type, case SND_BELL: if (hz) hz = 261; + break; case SND_TONE: break; default: diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index 6e34106c268f..52dc29942ec2 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -201,6 +201,7 @@ static int cs47l92_outclk_ev(struct snd_soc_dapm_widget *w, default: break; } + break; default: break; } diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 0bd3bbc2aacf..3af456010b9c 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3203,6 +3203,7 @@ static int wm8962_beep_event(struct input_dev *dev, unsigned int type, case SND_BELL: if (hz) hz = 1000; + fallthrough; case SND_TONE: break; default: -- cgit v1.2.3 From 704cbc4eb314bfe009680f4a5891d6734cf2cea7 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Nov 2020 12:33:52 -0600 Subject: ALSA: hdspm: Fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a break statement instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/3f70182b366fca7e085a3b57cb2eb193be04eed8.1605896059.git.gustavoars@kernel.org Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 3382c069fd3d..04e878a0f773 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6313,6 +6313,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, (statusregister & HDSPM_RX_64ch) ? 1 : 0; /* TODO: Mac driver sets it when f_s>48kHz */ status.card_specific.madi.frame_format = 0; + break; default: break; -- cgit v1.2.3 From 59e3d501cfaa51890f1a712f10065914632e1c91 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Nov 2020 12:34:01 -0600 Subject: ALSA: pcsp: Fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a break statement instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/9705120ac2310bb20035e375862410413359611d.1605896059.git.gustavoars@kernel.org Signed-off-by: Takashi Iwai --- sound/drivers/pcsp/pcsp_input.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/drivers/pcsp/pcsp_input.c b/sound/drivers/pcsp/pcsp_input.c index 52b475b310c3..e79603fe743d 100644 --- a/sound/drivers/pcsp/pcsp_input.c +++ b/sound/drivers/pcsp/pcsp_input.c @@ -54,6 +54,7 @@ static int pcspkr_input_event(struct input_dev *dev, unsigned int type, case SND_BELL: if (value) value = 1000; + break; case SND_TONE: break; default: -- cgit v1.2.3 From 45bbe6c95e427511f8d5a401d886b5261c673e30 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Nov 2020 12:34:12 -0600 Subject: ALSA: sb: Fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a break statement instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/0f6d5b94f1890be2b8f88d6f930fc75779e26345.1605896059.git.gustavoars@kernel.org Signed-off-by: Takashi Iwai --- sound/isa/sb/sb8_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 86d0d2fdf48a..8d01692c4f2a 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -506,6 +506,7 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) } else { runtime->hw.rate_max = 15000; } + break; default: break; } -- cgit v1.2.3 From e714fa93898f3b1050356a16bef72168166ade2a Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sat, 21 Nov 2020 00:10:46 +0100 Subject: ALSA: aloop: Constify ops structs The only usage of the ops field in the loopback_cable struct is to call its members, the field it self is never changed. Make it a pointer to const. This allows us to constify two static loopback_ops structs to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20201120231046.76758-1-rikard.falkeborn@gmail.com Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index c91356326699..702f91b9c60f 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -105,7 +105,7 @@ struct loopback_cable { unsigned int running; unsigned int pause; /* timer specific */ - struct loopback_ops *ops; + const struct loopback_ops *ops; /* If sound timer is used */ struct { int stream; @@ -1021,7 +1021,7 @@ static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm) return 0; } -static struct loopback_ops loopback_jiffies_timer_ops = { +static const struct loopback_ops loopback_jiffies_timer_ops = { .open = loopback_jiffies_timer_open, .start = loopback_jiffies_timer_start, .stop = loopback_jiffies_timer_stop, @@ -1172,7 +1172,7 @@ exit: /* stop_sync() is not required for sound timer because it does not need to be * restarted in loopback_prepare() on Xrun recovery */ -static struct loopback_ops loopback_snd_timer_ops = { +static const struct loopback_ops loopback_snd_timer_ops = { .open = loopback_snd_timer_open, .start = loopback_snd_timer_start, .stop = loopback_snd_timer_stop, -- cgit v1.2.3 From 9ac05523d38d4c2f40c9e41fc1453146fcd74368 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 21 Nov 2020 09:37:47 +0100 Subject: ALSA: emu10k1: Use dma_set_mask_and_coherent to simplify code 'pci_set_dma_mask()' + 'pci_set_consistent_dma_mask()' can be replaced by an equivalent 'dma_set_mask_and_coherent()' which is much less verbose. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/20201121083747.1330299-1-christophe.jaillet@wanadoo.fr Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index def8161cde4c..785ec0cf3933 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -894,8 +894,8 @@ static int snd_emu10k1x_create(struct snd_card *card, if ((err = pci_enable_device(pci)) < 0) return err; - if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 || - pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) { + + if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28)) < 0) { dev_err(card->dev, "error to set 28bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; -- cgit v1.2.3 From bc4e94aa8e72e79598e63a0b73febdcd8aeb541f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:07 +0100 Subject: ALSA: usb-audio: Handle discrete rates properly in hw constraints In the current code, when the device provides the discrete sample rate tables with unusual sample rates, the driver tries to gather the whole values from the audioformat entries and create a hw-constraint rule to restrict with this single rate list. This is rather inefficient and may overlook the rates that are associated only with the certain audioformat entries. This patch improves the hw constraint setup by rewriting the existing hw_rule_rate(). The discrete sample rates (identified by rate_table and nr_rates of format entry) are checked in the existing hw_rule_rate() instead of extra rules; in the case of discrete rates, the function compares with each rate table entry and calculates the min/max values from there. For the contiguous rates, the behavior doesn't change. Along with it, snd_usb_pcm_check_knot() and snb_usb_substream rate_list field become superfluous, thus those are dropped. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.h | 1 - sound/usb/pcm.c | 73 +++++++++++------------------------------------------- sound/usb/stream.c | 1 - 3 files changed, 15 insertions(+), 60 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index 5351d7183b1b..3cc668f98f43 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -157,7 +157,6 @@ struct snd_usb_substream { u64 formats; /* format bitmasks (all or'ed) */ unsigned int num_formats; /* number of supported audio formats (list) */ struct list_head fmt_list; /* format list */ - struct snd_pcm_hw_constraint_list rate_list; /* limited rates */ spinlock_t lock; int last_frame_number; /* stored frame number */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index a860303cc522..3265155df1b5 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1039,27 +1039,31 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_usb_substream *subs = rule->private; struct audioformat *fp; struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - unsigned int rmin, rmax; + unsigned int rmin, rmax, r; int changed; + int i; hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max); - changed = 0; - rmin = rmax = 0; + rmin = UINT_MAX; + rmax = 0; list_for_each_entry(fp, &subs->fmt_list, list) { if (!hw_check_valid_format(subs, params, fp)) continue; - if (changed++) { - if (rmin > fp->rate_min) - rmin = fp->rate_min; - if (rmax < fp->rate_max) - rmax = fp->rate_max; + if (fp->rate_table && fp->nr_rates) { + for (i = 0; i < fp->nr_rates; i++) { + r = fp->rate_table[i]; + if (!snd_interval_test(it, r)) + continue; + rmin = min(rmin, r); + rmax = max(rmax, r); + } } else { - rmin = fp->rate_min; - rmax = fp->rate_max; + rmin = min(rmin, fp->rate_min); + rmax = max(rmax, fp->rate_max); } } - if (!changed) { + if (rmin > rmax) { hwc_debug(" --> get empty\n"); it->empty = 1; return -EINVAL; @@ -1205,50 +1209,6 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params, return changed; } -/* - * If the device supports unusual bit rates, does the request meet these? - */ -static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, - struct snd_usb_substream *subs) -{ - struct audioformat *fp; - int *rate_list; - int count = 0, needs_knot = 0; - int err; - - kfree(subs->rate_list.list); - subs->rate_list.list = NULL; - - list_for_each_entry(fp, &subs->fmt_list, list) { - if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) - return 0; - count += fp->nr_rates; - if (fp->rates & SNDRV_PCM_RATE_KNOT) - needs_knot = 1; - } - if (!needs_knot) - return 0; - - subs->rate_list.list = rate_list = - kmalloc_array(count, sizeof(int), GFP_KERNEL); - if (!subs->rate_list.list) - return -ENOMEM; - subs->rate_list.count = count; - subs->rate_list.mask = 0; - count = 0; - list_for_each_entry(fp, &subs->fmt_list, list) { - int i; - for (i = 0; i < fp->nr_rates; i++) - rate_list[count++] = fp->rate_table[i]; - } - err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &subs->rate_list); - if (err < 0) - return err; - - return 0; -} - /* * set up the runtime hardware information. @@ -1338,9 +1298,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre if (err < 0) return err; } - err = snd_usb_pcm_check_knot(runtime, subs); - if (err < 0) - return err; return snd_usb_autoresume(subs->stream->chip); } diff --git a/sound/usb/stream.c b/sound/usb/stream.c index ca76ba5b5c0b..f17913e0b5b4 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -47,7 +47,6 @@ static void free_substream(struct snd_usb_substream *subs) return; /* not initialized */ list_for_each_entry_safe(fp, n, &subs->fmt_list, list) audioformat_free(fp); - kfree(subs->rate_list.list); kfree(subs->str_pd); snd_media_stream_delete(subs); } -- cgit v1.2.3 From 4974b7950929e4a28d4eaee48e4ad07f168ac132 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:08 +0100 Subject: ALSA: usb-audio: Don't call usb_set_interface() at trigger callback The PCM trigger callback is atomic, hence we must not call a function like usb_set_interface() there. Calling it from there would lead to a kernel Oops. Fix it by moving the usb_set_interface() call to set_sync_endpoint(). Also, apply the snd_usb_set_interface_quirk() for consistency, too. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 3265155df1b5..380d7275d187 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -232,21 +232,6 @@ static int start_endpoints(struct snd_usb_substream *subs) !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { struct snd_usb_endpoint *ep = subs->sync_endpoint; - if (subs->data_endpoint->iface != subs->sync_endpoint->iface || - subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting) { - err = usb_set_interface(subs->dev, - subs->sync_endpoint->iface, - subs->sync_endpoint->altsetting); - if (err < 0) { - clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); - dev_err(&subs->dev->dev, - "%d:%d: cannot set interface (%d)\n", - subs->sync_endpoint->iface, - subs->sync_endpoint->altsetting, err); - return -EIO; - } - } - dev_dbg(&subs->dev->dev, "Starting sync EP @%p\n", ep); ep->sync_slave = subs->data_endpoint; @@ -530,6 +515,19 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, subs->data_endpoint->sync_master = subs->sync_endpoint; + if (subs->data_endpoint->iface != subs->sync_endpoint->iface || + subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting) { + err = usb_set_interface(subs->dev, + subs->sync_endpoint->iface, + subs->sync_endpoint->altsetting); + if (err < 0) + return err; + dev_dbg(&dev->dev, "setting usb interface %d:%d\n", + subs->sync_endpoint->iface, + subs->sync_endpoint->altsetting); + snd_usb_set_interface_quirk(dev); + } + return 0; } -- cgit v1.2.3 From 93db51d06b32227319dae2ac289029ccf1b33181 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:09 +0100 Subject: ALSA: usb-audio: Check valid altsetting at parsing rates for UAC2/3 The current driver code assumes blindly that all found sample rates for the same endpoint from the UAC2 and UAC3 descriptors can be used no matter which altsetting, but actually this was wrong: some devices accept only limited sample rates in each altsetting. For determining which altsetting supports which rate, we need to verify each sample rate and check the validity via UAC2_AS_VAL_ALT_SETTINGS. This control reports back the available altsettings as a bitmap. This patch implements the missing piece above, the verification and reconstructs the sample rate tables based on the result. An open question is how to deal with the altsettings that ended up with no valid sample rates after verification. At least, there is a device that showed this problem although the sample rates did work in the later usage (see bug link). For now, we accept such an altset as is, assuming that it's a firmware bug. Reported-by: Dylan Robinson Tested-by: Keith Milner Tested-by: Dylan Robinson BugLink: https://bugzilla.suse.com/show_bug.cgi?id=1178203 Link: https://lore.kernel.org/r/20201123085347.19667-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/clock.c | 106 ++++++++++++++++++++++++++++++----------------------- sound/usb/clock.h | 4 ++ sound/usb/format.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/usb/clock.c b/sound/usb/clock.c index f3ca59005d91..f174230d07d5 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -560,16 +560,60 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, return le32_to_cpu(data); } +/* + * Try to set the given sample rate: + * + * Return 0 if the clock source is read-only, the actual rate on success, + * or a negative error code. + * + * This function gets called from format.c to validate each sample rate, too. + * Hence no message is shown upon error + */ +int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, + const struct audioformat *fmt, + int clock, int rate) +{ + bool writeable; + u32 bmControls; + __le32 data; + int err; + + if (fmt->protocol == UAC_VERSION_3) { + struct uac3_clock_source_descriptor *cs_desc; + + cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); + bmControls = le32_to_cpu(cs_desc->bmControls); + } else { + struct uac_clock_source_descriptor *cs_desc; + + cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); + bmControls = cs_desc->bmControls; + } + + writeable = uac_v2v3_control_is_writeable(bmControls, + UAC2_CS_CONTROL_SAM_FREQ); + if (!writeable) + return 0; + + data = cpu_to_le32(rate); + err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + UAC2_CS_CONTROL_SAM_FREQ << 8, + snd_usb_ctrl_intf(chip) | (clock << 8), + &data, sizeof(data)); + if (err < 0) + return err; + + return get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock); +} + static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, - struct audioformat *fmt, int rate) + struct usb_host_interface *alts, + struct audioformat *fmt, int rate) { struct usb_device *dev = chip->dev; - __le32 data; - int err, cur_rate, prev_rate; + int cur_rate, prev_rate; int clock; - bool writeable; - u32 bmControls; /* First, try to find a valid clock. This may trigger * automatic clock selection if the current clock is not @@ -592,50 +636,22 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, if (prev_rate == rate) goto validation; - if (fmt->protocol == UAC_VERSION_3) { - struct uac3_clock_source_descriptor *cs_desc; - - cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); - bmControls = le32_to_cpu(cs_desc->bmControls); - } else { - struct uac_clock_source_descriptor *cs_desc; - - cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); - bmControls = cs_desc->bmControls; + cur_rate = snd_usb_set_sample_rate_v2v3(chip, fmt, clock, rate); + if (cur_rate < 0) { + usb_audio_err(chip, + "%d:%d: cannot set freq %d (v2/v3): err %d\n", + iface, fmt->altsetting, rate, cur_rate); + return cur_rate; } - writeable = uac_v2v3_control_is_writeable(bmControls, - UAC2_CS_CONTROL_SAM_FREQ); - if (writeable) { - data = cpu_to_le32(rate); - err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - UAC2_CS_CONTROL_SAM_FREQ << 8, - snd_usb_ctrl_intf(chip) | (clock << 8), - &data, sizeof(data)); - if (err < 0) { - usb_audio_err(chip, - "%d:%d: cannot set freq %d (v2/v3): err %d\n", - iface, fmt->altsetting, rate, err); - return err; - } - - cur_rate = get_sample_rate_v2v3(chip, iface, - fmt->altsetting, clock); - } else { + if (!cur_rate) cur_rate = prev_rate; - } if (cur_rate != rate) { - if (!writeable) { - usb_audio_warn(chip, - "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n", - iface, fmt->altsetting, rate, cur_rate); - return -ENXIO; - } - usb_audio_dbg(chip, - "current rate %d is different from the runtime rate %d\n", - cur_rate, rate); + usb_audio_warn(chip, + "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n", + fmt->iface, fmt->altsetting, rate, cur_rate); + return -ENXIO; } /* Some devices doesn't respond to sample rate changes while the diff --git a/sound/usb/clock.h b/sound/usb/clock.h index 68df0fbe09d0..97597f5a3c18 100644 --- a/sound/usb/clock.h +++ b/sound/usb/clock.h @@ -9,4 +9,8 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, int snd_usb_clock_find_source(struct snd_usb_audio *chip, struct audioformat *fmt, bool validate); +int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, + const struct audioformat *fmt, + int clock, int rate); + #endif /* __USBAUDIO_CLOCK_H */ diff --git a/sound/usb/format.c b/sound/usb/format.c index 3bfead393aa3..3348032daa16 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -417,6 +417,97 @@ static int line6_parse_audio_format_rates_quirk(struct snd_usb_audio *chip, return -ENODEV; } +/* check whether the given altsetting is supported for the already set rate */ +static bool check_valid_altsetting_v2v3(struct snd_usb_audio *chip, int iface, + int altsetting) +{ + struct usb_device *dev = chip->dev; + __le64 raw_data = 0; + u64 data; + int err; + + /* we assume 64bit is enough for any altsettings */ + if (snd_BUG_ON(altsetting >= 64 - 8)) + return false; + + err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_AS_VAL_ALT_SETTINGS << 8, + iface, &raw_data, sizeof(raw_data)); + if (err < 0) + return false; + + data = le64_to_cpu(raw_data); + /* first byte contains the bitmap size */ + if ((data & 0xff) * 8 < altsetting) + return false; + if (data & (1ULL << (altsetting + 8))) + return true; + + return false; +} + +/* + * Validate each sample rate with the altsetting + * Rebuild the rate table if only partial values are valid + */ +static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip, + struct audioformat *fp, + int clock) +{ + struct usb_device *dev = chip->dev; + unsigned int *table; + unsigned int nr_rates; + unsigned int rate_min = 0x7fffffff; + unsigned int rate_max = 0; + unsigned int rates = 0; + int i, err; + + table = kcalloc(fp->nr_rates, sizeof(*table), GFP_KERNEL); + if (!table) + return -ENOMEM; + + /* clear the interface altsetting at first */ + usb_set_interface(dev, fp->iface, 0); + + nr_rates = 0; + for (i = 0; i < fp->nr_rates; i++) { + err = snd_usb_set_sample_rate_v2v3(chip, fp, clock, + fp->rate_table[i]); + if (err < 0) + continue; + + if (check_valid_altsetting_v2v3(chip, fp->iface, fp->altsetting)) { + table[nr_rates++] = fp->rate_table[i]; + if (rate_min > fp->rate_table[i]) + rate_min = fp->rate_table[i]; + if (rate_max < fp->rate_table[i]) + rate_max = fp->rate_table[i]; + rates |= snd_pcm_rate_to_rate_bit(fp->rate_table[i]); + } + } + + if (!nr_rates) { + usb_audio_dbg(chip, + "No valid sample rate available for %d:%d, assuming a firmware bug\n", + fp->iface, fp->altsetting); + nr_rates = fp->nr_rates; /* continue as is */ + } + + if (fp->nr_rates == nr_rates) { + kfree(table); + return 0; + } + + kfree(fp->rate_table); + fp->rate_table = table; + fp->nr_rates = nr_rates; + fp->rate_min = rate_min; + fp->rate_max = rate_max; + fp->rates = rates; + return 0; +} + /* * parse the format descriptor and stores the possible sample rates * on the audioformat table (audio class v2 and v3). @@ -509,6 +600,8 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, * allocated, so the rates will be stored */ parse_uac2_sample_rate_range(chip, fp, nr_triplets, data); + ret = validate_sample_rate_table_v2v3(chip, fp, clock); + err_free: kfree(data); err: -- cgit v1.2.3 From 2e43aae2bf5a4ede98cbe0c85ad104dd7ba5dfd2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:10 +0100 Subject: ALSA: usb-audio: Check implicit feedback EP generically for UAC2 It seems that many UAC2 devices are with the implicit feedback, but they couldn't be probed properly because the assumption the driver takes currently isn't applied: they have the single endpoint for both data and implicit-fb streams, while we checked only the classical sync endpoints assigned to the next altsetting in the same interface. This patch extends the search to match with those typical cases where the implicit fb stream is found in the next interface number. While we're at it, slightly refactor the code, not returning 0/-ERROR but use the standard bool to success/failur, which is more intuitive in this particular case. Reported-by: Dylan Robinson Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 83 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 380d7275d187..2b11c2c837bf 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -272,33 +272,70 @@ static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream) return 0; } -static int search_roland_implicit_fb(struct usb_device *dev, int ifnum, - unsigned int altsetting, - struct usb_host_interface **alts, - unsigned int *ep) +/* Check whether the given iface:altsetting points to an implicit fb source */ +static bool search_generic_implicit_fb(struct usb_device *dev, int ifnum, + unsigned int altsetting, + struct usb_host_interface **altsp, + unsigned int *ep) { struct usb_interface *iface; + struct usb_host_interface *alts; + struct usb_interface_descriptor *altsd; + struct usb_endpoint_descriptor *epd; + + iface = usb_ifnum_to_if(dev, ifnum); + if (!iface) + return false; + alts = usb_altnum_to_altsetting(iface, altsetting); + if (!alts) + return false; + altsd = get_iface_desc(alts); + if (altsd->bInterfaceClass != USB_CLASS_AUDIO || + altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING || + altsd->bInterfaceProtocol != UAC_VERSION_2 || + altsd->bNumEndpoints < 1) + return false; + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_in(epd) || + (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != + USB_ENDPOINT_USAGE_IMPLICIT_FB) + return false; + *ep = epd->bEndpointAddress; + *altsp = alts; + return true; +} + +/* Like the function above, but specific to Roland with vendor class and hack */ +static bool search_roland_implicit_fb(struct usb_device *dev, int ifnum, + unsigned int altsetting, + struct usb_host_interface **altsp, + unsigned int *ep) +{ + struct usb_interface *iface; + struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; struct usb_endpoint_descriptor *epd; iface = usb_ifnum_to_if(dev, ifnum); - if (!iface || iface->num_altsetting < altsetting + 1) - return -ENOENT; - *alts = &iface->altsetting[altsetting]; - altsd = get_iface_desc(*alts); - if (altsd->bAlternateSetting != altsetting || - altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC || + if (!iface) + return false; + alts = usb_altnum_to_altsetting(iface, altsetting); + if (!alts) + return false; + altsd = get_iface_desc(alts); + if (altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC || (altsd->bInterfaceSubClass != 2 && - altsd->bInterfaceProtocol != 2 ) || + altsd->bInterfaceProtocol != 2) || altsd->bNumEndpoints < 1) - return -ENOENT; - epd = get_endpoint(*alts, 0); + return false; + epd = get_endpoint(alts, 0); if (!usb_endpoint_is_isoc_in(epd) || (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != USB_ENDPOINT_USAGE_IMPLICIT_FB) - return -ENOENT; + return false; *ep = epd->bEndpointAddress; - return 0; + *altsp = alts; + return true; } /* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk @@ -375,6 +412,19 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, return 0; } + /* Generic UAC2 implicit feedback */ + if (attr == USB_ENDPOINT_SYNC_ASYNC && + altsd->bInterfaceClass == USB_CLASS_AUDIO && + altsd->bInterfaceProtocol == UAC_VERSION_2 && + altsd->bNumEndpoints == 1) { + ifnum = altsd->bInterfaceNumber + 1; + if (search_generic_implicit_fb(dev, ifnum, + altsd->bAlternateSetting, + &alts, &ep)) + goto add_sync_ep; + } + + /* Roland/BOSS implicit feedback with vendor spec class */ if (attr == USB_ENDPOINT_SYNC_ASYNC && altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && altsd->bInterfaceProtocol == 2 && @@ -382,9 +432,8 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ && search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1, altsd->bAlternateSetting, - &alts, &ep) >= 0) { + &alts, &ep)) goto add_sync_ep; - } /* No quirk */ return 0; -- cgit v1.2.3 From c7474d09777c3d321f9f7f6a416f276204926c54 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:11 +0100 Subject: ALSA: usb-audio: Add snd_usb_get_endpoint() helper Factor out the code to obtain snd_usb_endpoint object matching with the given endpoint. It'll be used in the later patch to add the implicit feedback hw-constraint. No functional change by this patch itself. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 36 +++++++++++++++++++++++++++--------- sound/usb/endpoint.h | 4 ++++ 2 files changed, 31 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index e2f9ce2f5b8b..cf00871fd278 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -439,6 +439,26 @@ exit_clear: clear_bit(ctx->index, &ep->active_mask); } +/* + * Get the existing endpoint object corresponding EP, iface and alt numbers + * Returns NULL if not present. + * Call inside chip->mutex locking for avoiding the race. + */ +struct snd_usb_endpoint * +snd_usb_get_endpoint(struct snd_usb_audio *chip, + int ep_num, int iface, int altsetting) +{ + struct snd_usb_endpoint *ep; + + list_for_each_entry(ep, &chip->ep_list, list) { + if (ep->ep_num == ep_num && + ep->iface == iface && + ep->altsetting == altsetting) + return ep; + } + return NULL; +} + /** * snd_usb_add_endpoint: Add an endpoint to an USB audio chip * @@ -470,15 +490,13 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, mutex_lock(&chip->mutex); - list_for_each_entry(ep, &chip->ep_list, list) { - if (ep->ep_num == ep_num && - ep->iface == alts->desc.bInterfaceNumber && - ep->altsetting == alts->desc.bAlternateSetting) { - usb_audio_dbg(ep->chip, - "Re-using EP %x in iface %d,%d @%p\n", - ep_num, ep->iface, ep->altsetting, ep); - goto __exit_unlock; - } + ep = snd_usb_get_endpoint(chip, ep_num, + alts->desc.bInterfaceNumber, + alts->desc.bAlternateSetting); + if (ep) { + usb_audio_dbg(ep->chip, "Re-using EP %x in iface %d,%d @%p\n", + ep_num, ep->iface, ep->altsetting, ep); + goto __exit_unlock; } usb_audio_dbg(chip, "Creating new %s %s endpoint #%x\n", diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index d23fa0a8c11b..61487095a766 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -5,6 +5,10 @@ #define SND_USB_ENDPOINT_TYPE_DATA 0 #define SND_USB_ENDPOINT_TYPE_SYNC 1 +struct snd_usb_endpoint *snd_usb_get_endpoint(struct snd_usb_audio *chip, + int ep_num, int iface, + int altsetting); + struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, struct usb_host_interface *alts, int ep_num, int direction, int type); -- cgit v1.2.3 From 1803503fe963afe850b26769f5447f871b1c6f83 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:12 +0100 Subject: ALSA: usb-audio: Set and clear sync EP link properly The sync EP setup isn't cleared at stopping the stream but expected to be cleared at the next stream start. This may leave the sync link setup stale and can spoof wrongly when full duplex streams were running in the implicit fb sync. Let's initialize them properly at start and end of the stream. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 2b11c2c837bf..8800ec627a73 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -238,6 +238,7 @@ static int start_endpoints(struct snd_usb_substream *subs) err = snd_usb_endpoint_start(ep); if (err < 0) { clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); + ep->sync_slave = NULL; return err; } } @@ -253,8 +254,10 @@ static void sync_pending_stops(struct snd_usb_substream *subs) static void stop_endpoints(struct snd_usb_substream *subs) { - if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) + if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { snd_usb_endpoint_stop(subs->sync_endpoint); + subs->sync_endpoint->sync_slave = NULL; + } if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) snd_usb_endpoint_stop(subs->data_endpoint); @@ -471,26 +474,10 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, bool implicit_fb; int err; - /* we need a sync pipe in async OUT or adaptive IN mode */ - /* check the number of EP, since some devices have broken - * descriptors which fool us. if it has only one EP, - * assume it as adaptive-out or sync-in. - */ attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; - if ((is_playback && (attr != USB_ENDPOINT_SYNC_ASYNC)) || - (!is_playback && (attr != USB_ENDPOINT_SYNC_ADAPTIVE))) { - - /* - * In these modes the notion of sync_endpoint is irrelevant. - * Reset pointers to avoid using stale data from previously - * used settings, e.g. when configuration and endpoints were - * changed - */ - - subs->sync_endpoint = NULL; - subs->data_endpoint->sync_master = NULL; - } + subs->sync_endpoint = NULL; + subs->data_endpoint->sync_master = NULL; err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr); if (err < 0) @@ -939,6 +926,11 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) sync_pending_stops(subs); snd_usb_endpoint_deactivate(subs->sync_endpoint); snd_usb_endpoint_deactivate(subs->data_endpoint); + if (subs->data_endpoint) { + subs->data_endpoint->sync_master = NULL; + subs->data_endpoint = NULL; + } + subs->sync_endpoint = NULL; snd_usb_unlock_shutdown(subs->stream->chip); } -- cgit v1.2.3 From e93e890e16ef5a0605b7cdc52b3bde50d88d7207 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:13 +0100 Subject: ALSA: usb-audio: Improve some debug prints There are a few rooms for improvements wrt the debug prints: - The EP debug print is shown only at starting, not at stopping - The EP debug print contains useless object addresses - Some helpers show the urb and the EP object addresses, too This patch addresses those shortcomings. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 8 ++++---- sound/usb/pcm.c | 11 ++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index cf00871fd278..8205a64a734e 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -367,8 +367,8 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) err = usb_submit_urb(ctx->urb, GFP_ATOMIC); if (err < 0) usb_audio_err(ep->chip, - "Unable to submit urb #%d: %d (urb %p)\n", - ctx->index, err, ctx->urb); + "Unable to submit urb #%d: %d at %s\n", + ctx->index, err, __func__); else set_bit(ctx->index, &ep->active_mask); } @@ -494,8 +494,8 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, alts->desc.bInterfaceNumber, alts->desc.bAlternateSetting); if (ep) { - usb_audio_dbg(ep->chip, "Re-using EP %x in iface %d,%d @%p\n", - ep_num, ep->iface, ep->altsetting, ep); + usb_audio_dbg(ep->chip, "Re-using EP %x in iface %d,%d\n", + ep_num, ep->iface, ep->altsetting); goto __exit_unlock; } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 8800ec627a73..8f4fe65d5c37 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -218,7 +218,7 @@ static int start_endpoints(struct snd_usb_substream *subs) if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { struct snd_usb_endpoint *ep = subs->data_endpoint; - dev_dbg(&subs->dev->dev, "Starting data EP @%p\n", ep); + dev_dbg(&subs->dev->dev, "Starting data EP 0x%x\n", ep->ep_num); ep->data_subs = subs; err = snd_usb_endpoint_start(ep); @@ -232,7 +232,7 @@ static int start_endpoints(struct snd_usb_substream *subs) !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { struct snd_usb_endpoint *ep = subs->sync_endpoint; - dev_dbg(&subs->dev->dev, "Starting sync EP @%p\n", ep); + dev_dbg(&subs->dev->dev, "Starting sync EP 0x%x\n", ep->ep_num); ep->sync_slave = subs->data_endpoint; err = snd_usb_endpoint_start(ep); @@ -255,12 +255,17 @@ static void sync_pending_stops(struct snd_usb_substream *subs) static void stop_endpoints(struct snd_usb_substream *subs) { if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { + dev_dbg(&subs->dev->dev, "Stopping sync EP 0x%x\n", + subs->sync_endpoint->ep_num); snd_usb_endpoint_stop(subs->sync_endpoint); subs->sync_endpoint->sync_slave = NULL; } - if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) + if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { + dev_dbg(&subs->dev->dev, "Stopping data EP 0x%x\n", + subs->data_endpoint->ep_num); snd_usb_endpoint_stop(subs->data_endpoint); + } } /* PCM sync_stop callback */ -- cgit v1.2.3 From f6581c0e5d297cc1e0d7eb7c2603097f532e629a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:14 +0100 Subject: ALSA: usb-audio: Track implicit fb sync endpoint in audioformat list Instead of parsing and evaluating the sync endpoint and the implicit feedback mode at each time the audio stream is opened, let's parse it once at the probe time, as the all needed information can be obtained statically from the descriptor or from the quirk. This patch extends audioformat struct to record the sync endpoint, interface and altsetting as well as the implicit feedback flag, which are filled at parsing the streams. Then, set_sync_endpoint() is much simplified just to follow the already parsed data. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.h | 4 ++ sound/usb/pcm.c | 149 +++++++++++++++++++++++++++++++++-------------------- sound/usb/pcm.h | 2 + sound/usb/stream.c | 2 + 4 files changed, 100 insertions(+), 57 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index 3cc668f98f43..898a283576df 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -22,6 +22,10 @@ struct audioformat { unsigned char attributes; /* corresponding attributes of cs endpoint */ unsigned char endpoint; /* endpoint */ unsigned char ep_attr; /* endpoint attributes */ + bool implicit_fb; /* implicit feedback endpoint */ + unsigned char sync_ep; /* sync endpoint number */ + unsigned char sync_iface; /* sync EP interface */ + unsigned char sync_altsetting; /* sync EP alternate setting */ unsigned char datainterval; /* log_2 of data packet interval */ unsigned char protocol; /* UAC_VERSION_1/2/3 */ unsigned int maxpacksize; /* max. packet size */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 8f4fe65d5c37..fea2764163b4 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -349,21 +349,18 @@ static bool search_roland_implicit_fb(struct usb_device *dev, int ifnum, /* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk * applies. Returns 1 if a quirk was found. */ -static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, - struct usb_device *dev, - struct usb_interface_descriptor *altsd, - unsigned int attr) +static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_interface *iface, + struct usb_host_interface *alts) { - struct usb_host_interface *alts; - struct usb_interface *iface; + struct usb_device *dev = chip->dev; + struct usb_interface_descriptor *altsd = get_iface_desc(alts); + unsigned int attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; unsigned int ep; unsigned int ifnum; - /* Implicit feedback sync EPs consumers are always playback EPs */ - if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK) - return 0; - - switch (subs->stream->chip->usb_id) { + switch (chip->usb_id) { case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ case USB_ID(0x22f0, 0x0006): /* Allen&Heath Qu-16 */ @@ -437,11 +434,13 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && altsd->bInterfaceProtocol == 2 && altsd->bNumEndpoints == 1 && - USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ && - search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1, - altsd->bAlternateSetting, - &alts, &ep)) - goto add_sync_ep; + USB_ID_VENDOR(chip->usb_id) == 0x0582 /* Roland */) { + ifnum = altsd->bInterfaceNumber + 1; + if (search_roland_implicit_fb(dev, ifnum, + altsd->bAlternateSetting, + &alts, &ep)) + goto add_sync_ep; + } /* No quirk */ return 0; @@ -450,56 +449,59 @@ add_sync_ep_from_ifnum: iface = usb_ifnum_to_if(dev, ifnum); if (!iface || iface->num_altsetting < 2) - return -EINVAL; + return 0; alts = &iface->altsetting[1]; add_sync_ep: - subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, - alts, ep, !subs->direction, - SND_USB_ENDPOINT_TYPE_DATA); - if (!subs->sync_endpoint) - return -EINVAL; - - subs->sync_endpoint->is_implicit_feedback = 1; - - subs->data_endpoint->sync_master = subs->sync_endpoint; + fmt->sync_ep = ep; + fmt->sync_iface = ifnum; + fmt->sync_altsetting = alts->desc.bAlternateSetting; + fmt->implicit_fb = 1; + dev_dbg(&dev->dev, "%d:%d: found implicit_fb sync_ep=%x, iface=%d, alt=%d\n", + fmt->iface, fmt->altsetting, fmt->sync_ep, fmt->sync_iface, + fmt->sync_altsetting); return 1; } -static int set_sync_endpoint(struct snd_usb_substream *subs, - struct audioformat *fmt, - struct usb_device *dev, - struct usb_host_interface *alts, - struct usb_interface_descriptor *altsd) +int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, + struct audioformat *fmt) { - int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; - unsigned int ep, attr; - bool implicit_fb; + struct usb_device *dev = chip->dev; + struct usb_interface *iface; + struct usb_host_interface *alts; + struct usb_interface_descriptor *altsd; + unsigned int ep, attr, sync_attr; + bool is_playback; int err; - attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; - - subs->sync_endpoint = NULL; - subs->data_endpoint->sync_master = NULL; - - err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr); - if (err < 0) - return err; - - /* endpoint set by quirk */ - if (err > 0) + iface = usb_ifnum_to_if(dev, fmt->iface); + if (!iface) + return 0; + alts = usb_altnum_to_altsetting(iface, fmt->altsetting); + if (!alts) return 0; + altsd = get_iface_desc(alts); + + is_playback = !(get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN); + if (is_playback) { + err = audioformat_implicit_fb_quirk(chip, fmt, iface, alts); + if (err > 0) + return 0; + } if (altsd->bNumEndpoints < 2) return 0; + attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; if ((is_playback && (attr == USB_ENDPOINT_SYNC_SYNC || attr == USB_ENDPOINT_SYNC_ADAPTIVE)) || (!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE)) return 0; + sync_attr = get_endpoint(alts, 1)->bmAttributes; + /* * In case of illegal SYNC_NONE for OUT endpoint, we keep going to see * if we don't find a sync endpoint, as on M-Audio Transit. In case of @@ -510,7 +512,7 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, /* ... and check descriptor size before accessing bSynchAddress because there is a version of the SB Audigy 2 NX firmware lacking the audio fields in the endpoint descriptors */ - if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC || + if ((sync_attr & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC || (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && get_endpoint(alts, 1)->bSynchAddress != 0)) { dev_err(&dev->dev, @@ -537,22 +539,57 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, return -EINVAL; } - implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK) - == USB_ENDPOINT_USAGE_IMPLICIT_FB; + fmt->sync_ep = ep; + fmt->sync_iface = altsd->bInterfaceNumber; + fmt->sync_altsetting = altsd->bAlternateSetting; + if ((sync_attr & USB_ENDPOINT_USAGE_MASK) == USB_ENDPOINT_USAGE_IMPLICIT_FB) + fmt->implicit_fb = 1; + + dev_dbg(&dev->dev, "%d:%d: found sync_ep=0x%x, iface=%d, alt=%d, implicit_fb=%d\n", + fmt->iface, fmt->altsetting, fmt->sync_ep, fmt->sync_iface, + fmt->sync_altsetting, fmt->implicit_fb); + + return 0; +} + +static int set_sync_endpoint(struct snd_usb_substream *subs, + struct audioformat *fmt) +{ + struct usb_device *dev = subs->dev; + struct usb_interface *iface; + struct usb_host_interface *alts; + int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int ep; + int err; + + subs->sync_endpoint = NULL; + subs->data_endpoint->sync_master = NULL; + + ep = fmt->sync_ep; + if (!ep) + return 0; + + iface = usb_ifnum_to_if(dev, fmt->sync_iface); + if (!iface) + return 0; + + alts = usb_altnum_to_altsetting(iface, fmt->altsetting); + if (!alts) + return 0; subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, alts, ep, !subs->direction, - implicit_fb ? - SND_USB_ENDPOINT_TYPE_DATA : - SND_USB_ENDPOINT_TYPE_SYNC); - + fmt->implicit_fb ? + SND_USB_ENDPOINT_TYPE_DATA : + SND_USB_ENDPOINT_TYPE_SYNC); if (!subs->sync_endpoint) { - if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) + if (is_playback && + (fmt->ep_attr & USB_ENDPOINT_SYNCTYPE) == USB_ENDPOINT_SYNC_NONE) return 0; return -EINVAL; } - subs->sync_endpoint->is_implicit_feedback = implicit_fb; + subs->sync_endpoint->is_implicit_feedback = fmt->implicit_fb; subs->data_endpoint->sync_master = subs->sync_endpoint; @@ -579,7 +616,6 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) { struct usb_device *dev = subs->dev; struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; struct usb_interface *iface; int err; @@ -589,7 +625,6 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) alts = usb_altnum_to_altsetting(iface, fmt->altsetting); if (WARN_ON(!alts)) return -EINVAL; - altsd = get_iface_desc(alts); if (fmt == subs->cur_audiofmt && !subs->need_setup_fmt) return 0; @@ -639,7 +674,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) if (!subs->data_endpoint) return -EINVAL; - err = set_sync_endpoint(subs, fmt, dev, alts, altsd); + err = set_sync_endpoint(subs, fmt); if (err < 0) return err; diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index 9833627c1eca..362782c2df5c 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -14,5 +14,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, struct audioformat *fmt); void snd_usb_preallocate_buffer(struct snd_usb_substream *subs); +int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, + struct audioformat *fmt); #endif /* __USBAUDIO_PCM_H */ diff --git a/sound/usb/stream.c b/sound/usb/stream.c index f17913e0b5b4..7087ee2c8174 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1193,6 +1193,8 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, continue; } + snd_usb_audioformat_set_sync_ep(chip, fp); + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); if (protocol == UAC_VERSION_3) err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); -- cgit v1.2.3 From 1865211d6789e8404c75278754f0fa4735165600 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:15 +0100 Subject: ALSA: usb-audio: Move snd_usb_autoresume() call out of setup_hw_info() This is a preliminary work for the upcoming hw-constraint change for the implicit feedback mode. Currently snd_usb_autoresume() is called at the end of setup_hwinfo(). It's a bit confusing; because of this implicit refcount usage, the caller side needs to call snd_usb_autosuspend() later in the error path although it's not seen inside the function. Instead, it's clearer to call both snd_usb_autoresume() and suspend() in the very same function. It's only refactoring and no functional changes. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index fea2764163b4..78933b6571d0 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1378,7 +1378,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre return err; } - return snd_usb_autoresume(subs->stream->chip); + return 0; } static int snd_usb_pcm_open(struct snd_pcm_substream *substream) @@ -1402,11 +1402,14 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) subs->dsd_dop.marker = 1; ret = setup_hw_info(runtime, subs); - if (ret == 0) { - ret = snd_media_stream_init(subs, as->pcm, direction); - if (ret) - snd_usb_autosuspend(subs->stream->chip); - } + if (ret < 0) + return ret; + ret = snd_usb_autoresume(subs->stream->chip); + if (ret < 0) + return ret; + ret = snd_media_stream_init(subs, as->pcm, direction); + if (ret < 0) + snd_usb_autosuspend(subs->stream->chip); return ret; } -- cgit v1.2.3 From 5a6c3e11c9c9bc764cd4e2621cdb48cc9afb28a1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:16 +0100 Subject: ALSA: usb-audio: Add hw constraint for implicit fb sync In the current code, there is no check at the stream open time whether the endpoint is being already used by others. In the normal operations, this shouldn't happen, but in the case of the implicit feedback mode, it's a common problem with the full duplex operation, because the capture stream is always opened by the playback stream as an implicit sync source. Although we recently introduced the check of such a conflict of parameters at the PCM hw_params time, it doesn't give any hint at the hw_params itself and just gives the error. This isn't quite comfortable, and it caused problems on many applications. This patch attempts to make the parameter handling easier by introducing the strict hw constraint matching with the counterpart stream that is being used. That said, when an implicit feedback playback stream is running before a capture stream is opened, the capture stream carries the PCM hw-constraint to allow only the same sample rate, format, periods and period frames as the running playback stream. If not opened or there is no conflict of endpoints, the behavior remains as same as before. Note that this kind of "weak link" should work for most cases, but this is no concrete solution; e.g. if an application changes the hw params multiple times while another stream is opened, this would lead to inconsistencies. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.h | 9 ++++ sound/usb/endpoint.c | 72 ++++++++++++++++++------- sound/usb/pcm.c | 148 +++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 175 insertions(+), 54 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index 898a283576df..1f61be98a31d 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -114,6 +114,14 @@ struct snd_usb_endpoint { in a stream */ bool is_implicit_feedback; /* This endpoint is used as implicit feedback */ + /* for hw constraints */ + unsigned int cur_rate; + snd_pcm_format_t cur_format; + unsigned int cur_channels; + unsigned int cur_period_frames; + unsigned int cur_period_bytes; + unsigned int cur_buffer_periods; + spinlock_t lock; struct list_head list; }; @@ -144,6 +152,7 @@ struct snd_usb_substream { unsigned int stream_offset_adj; /* Bytes to drop from beginning of stream (for non-compliant devices) */ unsigned int running: 1; /* running status */ + unsigned int fixed_hw:1; /* fixed hw constraints due to sync EP */ unsigned int hwptr_done; /* processed byte position in the buffer */ unsigned int transfer_done; /* processed frames since last period update */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 8205a64a734e..94490d706013 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -459,6 +459,9 @@ snd_usb_get_endpoint(struct snd_usb_audio *chip, return NULL; } +#define ep_type_name(type) \ + (type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync") + /** * snd_usb_add_endpoint: Add an endpoint to an USB audio chip * @@ -500,9 +503,9 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, } usb_audio_dbg(chip, "Creating new %s %s endpoint #%x\n", - is_playback ? "playback" : "capture", - type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync", - ep_num); + is_playback ? "playback" : "capture", + ep_type_name(type), + ep_num); ep = kzalloc(sizeof(*ep), GFP_KERNEL); if (!ep) @@ -644,13 +647,14 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) * Check data endpoint for format differences */ static bool check_ep_params(struct snd_usb_endpoint *ep, - snd_pcm_format_t pcm_format, - unsigned int channels, - unsigned int period_bytes, - unsigned int frames_per_period, - unsigned int periods_per_buffer, - struct audioformat *fmt, - struct snd_usb_endpoint *sync_ep) + snd_pcm_format_t pcm_format, + unsigned int channels, + unsigned int period_bytes, + unsigned int frames_per_period, + unsigned int periods_per_buffer, + unsigned int rate, + struct audioformat *fmt, + struct snd_usb_endpoint *sync_ep) { unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb; unsigned int max_packs_per_period, urbs_per_period, urb_packs; @@ -660,6 +664,14 @@ static bool check_ep_params(struct snd_usb_endpoint *ep, usb_pipeout(ep->pipe)); bool ret = 1; + /* matching with the saved parameters? */ + if (ep->cur_rate == rate && + ep->cur_format == pcm_format && + ep->cur_channels == channels && + ep->cur_period_frames == frames_per_period && + ep->cur_buffer_periods == periods_per_buffer) + return true; + if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) { /* * When operating in DSD DOP mode, the size of a sample frame @@ -917,7 +929,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, * as their corresponding capture endpoint. */ if (usb_pipein(ep->pipe) || - snd_usb_endpoint_implicit_feedback_sink(ep)) { + ep->is_implicit_feedback || + snd_usb_endpoint_implicit_feedback_sink(ep)) { urb_packs = packs_per_ms; /* @@ -1076,12 +1089,17 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, { int err; + usb_audio_dbg(ep->chip, + "Setting params for ep %x (type %s, count %d), rate=%d, format=%s, channels=%d, period_bytes=%d, periods=%d\n", + ep->ep_num, ep_type_name(ep->type), ep->use_count, + rate, snd_pcm_format_name(pcm_format), channels, + period_bytes, buffer_periods); + if (ep->use_count != 0) { bool check = ep->is_implicit_feedback && - check_ep_params(ep, pcm_format, - channels, period_bytes, - period_frames, buffer_periods, - fmt, sync_ep); + check_ep_params(ep, pcm_format, channels, period_bytes, + period_frames, buffer_periods, rate, + fmt, sync_ep); if (!check) { usb_audio_warn(ep->chip, @@ -1134,11 +1152,22 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, err = -EINVAL; } - usb_audio_dbg(ep->chip, - "Setting params for ep #%x (type %d, %d urbs), ret=%d\n", - ep->ep_num, ep->type, ep->nurbs, err); + usb_audio_dbg(ep->chip, "Set up %d URBS, ret=%d\n", ep->nurbs, err); - return err; + if (err < 0) + return err; + + /* record the current set up in the endpoint (for implicit fb) */ + spin_lock_irq(&ep->lock); + ep->cur_rate = rate; + ep->cur_channels = channels; + ep->cur_format = pcm_format; + ep->cur_period_frames = period_frames; + ep->cur_period_bytes = period_bytes; + ep->cur_buffer_periods = buffer_periods; + spin_unlock_irq(&ep->lock); + + return 0; } /** @@ -1273,6 +1302,11 @@ void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) deactivate_urbs(ep, true); wait_clear_urbs(ep); + + /* clear the saved hw params */ + spin_lock_irq(&ep->lock); + ep->cur_rate = 0; + spin_unlock_irq(&ep->lock); } /** diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 78933b6571d0..6d1f5277cd90 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -81,30 +81,33 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream /* * find a matching audio format */ -static struct audioformat *find_format(struct snd_usb_substream *subs) +static struct audioformat *find_format(struct list_head *fmt_list_head, + snd_pcm_format_t format, + unsigned int rate, + unsigned int channels, + struct snd_usb_substream *subs) { struct audioformat *fp; struct audioformat *found = NULL; int cur_attr = 0, attr; - list_for_each_entry(fp, &subs->fmt_list, list) { - if (!(fp->formats & pcm_format_to_bits(subs->pcm_format))) + list_for_each_entry(fp, fmt_list_head, list) { + if (!(fp->formats & pcm_format_to_bits(format))) continue; - if (fp->channels != subs->channels) + if (fp->channels != channels) continue; - if (subs->cur_rate < fp->rate_min || - subs->cur_rate > fp->rate_max) + if (rate < fp->rate_min || rate > fp->rate_max) continue; - if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { + if (!(fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { unsigned int i; for (i = 0; i < fp->nr_rates; i++) - if (fp->rate_table[i] == subs->cur_rate) + if (fp->rate_table[i] == rate) break; if (i >= fp->nr_rates) continue; } attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE; - if (! found) { + if (!found) { found = fp; cur_attr = attr; continue; @@ -114,7 +117,7 @@ static struct audioformat *find_format(struct snd_usb_substream *subs) * this is a workaround for the case like * M-audio audiophile USB. */ - if (attr != cur_attr) { + if (subs && attr != cur_attr) { if ((attr == USB_ENDPOINT_SYNC_ASYNC && subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || (attr == USB_ENDPOINT_SYNC_ADAPTIVE && @@ -138,6 +141,12 @@ static struct audioformat *find_format(struct snd_usb_substream *subs) return found; } +static struct audioformat *find_substream_format(struct snd_usb_substream *subs) +{ + return find_format(&subs->fmt_list, subs->pcm_format, subs->cur_rate, + subs->channels, subs); +} + static int init_pitch_v1(struct snd_usb_audio *chip, int iface, struct usb_host_interface *alts, struct audioformat *fmt) @@ -744,7 +753,6 @@ static int match_endpoint_audioformats(struct snd_usb_substream *subs, */ static int configure_sync_endpoint(struct snd_usb_substream *subs) { - int ret; struct audioformat *fp; struct audioformat *sync_fp = NULL; int cur_score = 0; @@ -752,16 +760,16 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs) struct snd_usb_substream *sync_subs = &subs->stream->substream[subs->direction ^ 1]; - if (subs->sync_endpoint->type != SND_USB_ENDPOINT_TYPE_DATA || - !subs->stream) - return snd_usb_endpoint_set_params(subs->sync_endpoint, - subs->pcm_format, - subs->channels, - subs->period_bytes, - 0, 0, - subs->cur_rate, - subs->cur_audiofmt, - NULL); + if (subs->fixed_hw || + !subs->sync_endpoint->is_implicit_feedback) { + sync_fp = subs->cur_audiofmt; + goto configure; + } + + sync_fp = find_format(&sync_subs->fmt_list, subs->pcm_format, + subs->cur_rate, subs->channels, NULL); + if (sync_fp) + goto configure; /* Try to find the best matching audioformat. */ list_for_each_entry(fp, &sync_subs->fmt_list, list) { @@ -794,16 +802,16 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs) __func__, subs->period_bytes, sync_period_bytes); } - ret = snd_usb_endpoint_set_params(subs->sync_endpoint, - subs->pcm_format, - sync_fp->channels, - sync_period_bytes, - 0, 0, - subs->cur_rate, - sync_fp, - NULL); - - return ret; + configure: + return snd_usb_endpoint_set_params(subs->sync_endpoint, + subs->pcm_format, + sync_fp->channels, + sync_period_bytes, + subs->period_frames, + subs->buffer_periods, + subs->cur_rate, + sync_fp, + NULL); } /* @@ -912,7 +920,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, subs->channels = params_channels(hw_params); subs->cur_rate = params_rate(hw_params); - fmt = find_format(subs); + fmt = find_substream_format(subs); if (!fmt) { dev_dbg(&subs->dev->dev, "cannot set format: format = %#x, rate = %d, channels = %d\n", @@ -956,12 +964,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, static int snd_usb_hw_free(struct snd_pcm_substream *substream) { struct snd_usb_substream *subs = substream->runtime->private_data; + struct snd_usb_audio *chip = subs->stream->chip; snd_media_stop_pipeline(subs); subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; - if (!snd_usb_lock_shutdown(subs->stream->chip)) { + if (!snd_usb_lock_shutdown(chip)) { stop_endpoints(subs); sync_pending_stops(subs); snd_usb_endpoint_deactivate(subs->sync_endpoint); @@ -971,7 +980,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->data_endpoint = NULL; } subs->sync_endpoint = NULL; - snd_usb_unlock_shutdown(subs->stream->chip); + snd_usb_unlock_shutdown(chip); } return 0; @@ -1288,6 +1297,64 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params, return changed; } +/* apply PCM hw constraints from the concurrent sync EP */ +static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime, + struct snd_usb_substream *subs) +{ + struct snd_usb_audio *chip = subs->stream->chip; + struct snd_usb_endpoint *ep; + struct audioformat *fp; + int err; + + subs->fixed_hw = 0; + list_for_each_entry(fp, &subs->fmt_list, list) { + ep = snd_usb_get_endpoint(chip, fp->endpoint, fp->iface, + fp->altsetting); + if (ep && ep->cur_rate) + goto found; + if (!fp->implicit_fb) + continue; + /* for the implicit fb, check the sync ep as well */ + ep = snd_usb_get_endpoint(chip, fp->sync_ep, fp->sync_iface, + fp->sync_altsetting); + if (ep && ep->cur_rate) + goto found; + } + return 0; + + found: + if (!find_format(&subs->fmt_list, ep->cur_format, ep->cur_rate, + ep->cur_channels, NULL)) { + usb_audio_dbg(chip, "EP 0x%x being used, but not applicable\n", + ep->ep_num); + return 0; + } + + usb_audio_dbg(chip, "EP 0x%x being used, using fixed params:\n", + ep->ep_num); + usb_audio_dbg(chip, "rate=%d, format=%s, channels=%d, period_size=%d, periods=%d\n", + ep->cur_rate, snd_pcm_format_name(ep->cur_format), + ep->cur_channels, ep->cur_period_frames, + ep->cur_buffer_periods); + + runtime->hw.formats = pcm_format_to_bits(ep->cur_format); + runtime->hw.rate_min = runtime->hw.rate_max = ep->cur_rate; + runtime->hw.channels_min = runtime->hw.channels_max = + ep->cur_channels; + runtime->hw.rates = SNDRV_PCM_RATE_KNOT; + runtime->hw.periods_min = runtime->hw.periods_max = + ep->cur_buffer_periods; + subs->fixed_hw = 1; + + err = snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + ep->cur_period_frames, + ep->cur_period_frames); + if (err < 0) + return err; + + return 1; /* notify the finding */ +} /* * set up the runtime hardware information. @@ -1295,11 +1362,20 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params, static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) { + struct snd_usb_audio *chip = subs->stream->chip; struct audioformat *fp; unsigned int pt, ptmin; - int param_period_time_if_needed; + int param_period_time_if_needed = -1; int err; + mutex_lock(&chip->mutex); + err = apply_hw_constraint_from_sync(runtime, subs); + mutex_unlock(&chip->mutex); + if (err < 0) + return err; + if (err > 0) /* found the matching? */ + goto add_extra_rules; + runtime->hw.formats = subs->formats; runtime->hw.rate_min = 0x7fffffff; @@ -1350,6 +1426,8 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre -1); if (err < 0) return err; + +add_extra_rules: err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_channels, subs, SNDRV_PCM_HW_PARAM_FORMAT, -- cgit v1.2.3 From 7726dce14c5e7eaa78567be8c1e417acd6c83415 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:17 +0100 Subject: ALSA: usb-audio: Simplify hw_params rules Several hw_params functions narrows the interval via min/max rule in the very similar way, so factor out those into a helper function and use commonly. No functional changes, just minor code refactoring. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 110 ++++++++++++++++++++------------------------------------ 1 file changed, 38 insertions(+), 72 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 6d1f5277cd90..ecc6bf9b42f0 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1121,6 +1121,36 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, return 1; } +static int apply_hw_params_minmax(struct snd_interval *it, unsigned int rmin, + unsigned int rmax) +{ + int changed; + + if (rmin > rmax) { + hwc_debug(" --> get empty\n"); + it->empty = 1; + return -EINVAL; + } + + changed = 0; + if (it->min < rmin) { + it->min = rmin; + it->openmin = 0; + changed = 1; + } + if (it->max > rmax) { + it->max = rmax; + it->openmax = 0; + changed = 1; + } + if (snd_interval_checkempty(it)) { + it->empty = 1; + return -EINVAL; + } + hwc_debug(" --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); + return changed; +} + static int hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -1128,7 +1158,6 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params, struct audioformat *fp; struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); unsigned int rmin, rmax, r; - int changed; int i; hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max); @@ -1151,29 +1180,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params, } } - if (rmin > rmax) { - hwc_debug(" --> get empty\n"); - it->empty = 1; - return -EINVAL; - } - - changed = 0; - if (it->min < rmin) { - it->min = rmin; - it->openmin = 0; - changed = 1; - } - if (it->max > rmax) { - it->max = rmax; - it->openmax = 0; - changed = 1; - } - if (snd_interval_checkempty(it)) { - it->empty = 1; - return -EINVAL; - } - hwc_debug(" --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); - return changed; + return apply_hw_params_minmax(it, rmin, rmax); } @@ -1184,48 +1191,18 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params, struct audioformat *fp; struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); unsigned int rmin, rmax; - int changed; hwc_debug("hw_rule_channels: (%d,%d)\n", it->min, it->max); - changed = 0; - rmin = rmax = 0; + rmin = UINT_MAX; + rmax = 0; list_for_each_entry(fp, &subs->fmt_list, list) { if (!hw_check_valid_format(subs, params, fp)) continue; - if (changed++) { - if (rmin > fp->channels) - rmin = fp->channels; - if (rmax < fp->channels) - rmax = fp->channels; - } else { - rmin = fp->channels; - rmax = fp->channels; - } + rmin = min(rmin, fp->channels); + rmax = max(rmax, fp->channels); } - if (!changed) { - hwc_debug(" --> get empty\n"); - it->empty = 1; - return -EINVAL; - } - - changed = 0; - if (it->min < rmin) { - it->min = rmin; - it->openmin = 0; - changed = 1; - } - if (it->max > rmax) { - it->max = rmax; - it->openmax = 0; - changed = 1; - } - if (snd_interval_checkempty(it)) { - it->empty = 1; - return -EINVAL; - } - hwc_debug(" --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); - return changed; + return apply_hw_params_minmax(it, rmin, rmax); } static int hw_rule_format(struct snd_pcm_hw_params *params, @@ -1267,7 +1244,6 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params, struct snd_interval *it; unsigned char min_datainterval; unsigned int pmin; - int changed; it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); hwc_debug("hw_rule_period_time: (%u,%u)\n", it->min, it->max); @@ -1283,18 +1259,8 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params, return -EINVAL; } pmin = 125 * (1 << min_datainterval); - changed = 0; - if (it->min < pmin) { - it->min = pmin; - it->openmin = 0; - changed = 1; - } - if (snd_interval_checkempty(it)) { - it->empty = 1; - return -EINVAL; - } - hwc_debug(" --> (%u,%u) (changed = %d)\n", it->min, it->max, changed); - return changed; + + return apply_hw_params_minmax(it, pmin, UINT_MAX); } /* apply PCM hw constraints from the concurrent sync EP */ -- cgit v1.2.3 From 7ec827b9465c427511f05bab02dddbcfdd4ecc53 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:18 +0100 Subject: ALSA: usb-audio: Drop debug.h The file debug.h contains a simple macro for debug prints, and it's used only in two places, the format parser and the hw_params rules. The former actually should print a more informative message instead, so the only users are the hw_parmas rules. This patch moves the contents of debug.h into the hw_params rules local code and remove the unneeded includes. Also, the debug print in the format parser is replaced with the information print with more useful information, and the raw printk() call is replaced with pr_debug(). Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-13-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 1 - sound/usb/debug.h | 16 ---------------- sound/usb/format.c | 5 +++-- sound/usb/pcm.c | 11 ++++++++++- 4 files changed, 13 insertions(+), 20 deletions(-) delete mode 100644 sound/usb/debug.h (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 4457214a3ae6..096dd8e3c64b 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -49,7 +49,6 @@ #include "quirks.h" #include "endpoint.h" #include "helper.h" -#include "debug.h" #include "pcm.h" #include "format.h" #include "power.h" diff --git a/sound/usb/debug.h b/sound/usb/debug.h deleted file mode 100644 index 7dd983c35001..000000000000 --- a/sound/usb/debug.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __USBAUDIO_DEBUG_H -#define __USBAUDIO_DEBUG_H - -/* - * h/w constraints - */ - -#ifdef HW_CONST_DEBUG -#define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args) -#else -#define hwc_debug(fmt, args...) do { } while(0) -#endif - -#endif /* __USBAUDIO_DEBUG_H */ - diff --git a/sound/usb/format.c b/sound/usb/format.c index 3348032daa16..7641716f0c6c 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -16,7 +16,6 @@ #include "card.h" #include "quirks.h" #include "helper.h" -#include "debug.h" #include "clock.h" #include "format.h" @@ -227,7 +226,9 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof fp->nr_rates++; } if (!fp->nr_rates) { - hwc_debug("All rates were zero. Skipping format!\n"); + usb_audio_info(chip, + "%u:%d: All rates were zero\n", + fp->iface, fp->altsetting); return -EINVAL; } } else { diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index ecc6bf9b42f0..d83a6a6ac023 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -17,7 +17,6 @@ #include "usbaudio.h" #include "card.h" #include "quirks.h" -#include "debug.h" #include "endpoint.h" #include "helper.h" #include "pcm.h" @@ -1061,6 +1060,16 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) return ret; } +/* + * h/w constraints + */ + +#ifdef HW_CONST_DEBUG +#define hwc_debug(fmt, args...) pr_debug(fmt, ##args) +#else +#define hwc_debug(fmt, args...) do { } while(0) +#endif + static const struct snd_pcm_hardware snd_usb_hardware = { .info = SNDRV_PCM_INFO_MMAP | -- cgit v1.2.3 From 5fd255f4fe9707b5274e60d94d4aa64536f67ec3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:19 +0100 Subject: ALSA: usb-audio: Avoid doubly initialization for implicit fb The implicit feedback mode initializes both the main data stream and the sync data stream. When a sync stream was already opened, this would result in the doubly initialization and might screw up things. Add the check of already opened sync streams and skip the unnecessary initialization. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-14-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index d83a6a6ac023..8ae7d2fdba0d 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -601,8 +601,9 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, subs->data_endpoint->sync_master = subs->sync_endpoint; - if (subs->data_endpoint->iface != subs->sync_endpoint->iface || - subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting) { + if (!subs->sync_endpoint->use_count && + (subs->data_endpoint->iface != subs->sync_endpoint->iface || + subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting)) { err = usb_set_interface(subs->dev, subs->sync_endpoint->iface, subs->sync_endpoint->altsetting); @@ -625,6 +626,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) struct usb_device *dev = subs->dev; struct usb_host_interface *alts; struct usb_interface *iface; + struct snd_usb_endpoint *ep; int err; iface = usb_ifnum_to_if(dev, fmt->iface); @@ -637,6 +639,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) if (fmt == subs->cur_audiofmt && !subs->need_setup_fmt) return 0; + /* shared EP with implicit fb */ + if (fmt->implicit_fb && !subs->need_setup_fmt) { + ep = snd_usb_get_endpoint(subs->stream->chip, fmt->endpoint, + fmt->iface, fmt->altsetting); + if (ep && ep->use_count > 0) + goto add_data_ep; + } + /* close the old interface */ if (subs->interface >= 0 && (subs->interface != fmt->iface || subs->need_setup_fmt)) { if (!subs->stream->chip->keep_iface) { @@ -673,6 +683,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) snd_usb_set_interface_quirk(dev); } + subs->need_setup_ep = true; + + add_data_ep: subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx; subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, @@ -686,9 +699,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) if (err < 0) return err; - err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt); - if (err < 0) - return err; + if (subs->need_setup_ep) { + err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt); + if (err < 0) + return err; + } subs->cur_audiofmt = fmt; @@ -940,10 +955,6 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto unlock; - subs->interface = fmt->iface; - subs->altset_idx = fmt->altset_idx; - subs->need_setup_ep = true; - unlock: snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) -- cgit v1.2.3 From 54cb31901b831befb4f9347dd002dcc8ff2cc263 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:20 +0100 Subject: ALSA: usb-audio: Create endpoint objects at parsing phase Currently snd_usb_endpoint objects are created at first when the substream is opened and tries to assign the endpoints corresponding to the matching audioformat. But since basically the all endpoints have been already parsed and the information have been obtained, we may create the endpoint objects statically at the init phase. It's easier to manage for the implicit fb case, for example. This patch changes the endpoint object management and lets the parser to create the all endpoint objects. This change shouldn't bring any functional changes. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-15-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 87 ++++++++++++++++++++-------------------------------- sound/usb/endpoint.h | 10 +++--- sound/usb/pcm.c | 27 ++++++++-------- sound/usb/stream.c | 16 ++++++++++ 4 files changed, 67 insertions(+), 73 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 94490d706013..eb459db511f8 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -440,22 +440,19 @@ exit_clear: } /* - * Get the existing endpoint object corresponding EP, iface and alt numbers + * Get the existing endpoint object corresponding EP * Returns NULL if not present. - * Call inside chip->mutex locking for avoiding the race. */ struct snd_usb_endpoint * -snd_usb_get_endpoint(struct snd_usb_audio *chip, - int ep_num, int iface, int altsetting) +snd_usb_get_endpoint(struct snd_usb_audio *chip, int ep_num) { struct snd_usb_endpoint *ep; list_for_each_entry(ep, &chip->ep_list, list) { - if (ep->ep_num == ep_num && - ep->iface == iface && - ep->altsetting == altsetting) + if (ep->ep_num == ep_num) return ep; } + return NULL; } @@ -466,14 +463,13 @@ snd_usb_get_endpoint(struct snd_usb_audio *chip, * snd_usb_add_endpoint: Add an endpoint to an USB audio chip * * @chip: The chip - * @alts: The USB host interface * @ep_num: The number of the endpoint to use - * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC * * If the requested endpoint has not been added to the given chip before, - * a new instance is created. Otherwise, a pointer to the previoulsy - * created instance is returned. In case of any error, NULL is returned. + * a new instance is created. + * + * Returns zero on success or a negative error code. * * New endpoints will be added to chip->ep_list and must be freed by * calling snd_usb_endpoint_free(). @@ -481,74 +477,59 @@ snd_usb_get_endpoint(struct snd_usb_audio *chip, * For SND_USB_ENDPOINT_TYPE_SYNC, the caller needs to guarantee that * bNumEndpoints > 1 beforehand. */ -struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - int ep_num, int direction, int type) +int snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int type) { struct snd_usb_endpoint *ep; - int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK; - - if (WARN_ON(!alts)) - return NULL; + bool is_playback; - mutex_lock(&chip->mutex); - - ep = snd_usb_get_endpoint(chip, ep_num, - alts->desc.bInterfaceNumber, - alts->desc.bAlternateSetting); - if (ep) { - usb_audio_dbg(ep->chip, "Re-using EP %x in iface %d,%d\n", - ep_num, ep->iface, ep->altsetting); - goto __exit_unlock; - } + ep = snd_usb_get_endpoint(chip, ep_num); + if (ep) + return 0; - usb_audio_dbg(chip, "Creating new %s %s endpoint #%x\n", - is_playback ? "playback" : "capture", + usb_audio_dbg(chip, "Creating new %s endpoint #%x\n", ep_type_name(type), ep_num); - ep = kzalloc(sizeof(*ep), GFP_KERNEL); if (!ep) - goto __exit_unlock; + return -ENOMEM; ep->chip = chip; spin_lock_init(&ep->lock); ep->type = type; ep->ep_num = ep_num; - ep->iface = alts->desc.bInterfaceNumber; - ep->altsetting = alts->desc.bAlternateSetting; INIT_LIST_HEAD(&ep->ready_playback_urbs); - ep_num &= USB_ENDPOINT_NUMBER_MASK; + is_playback = ((ep_num & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); + ep_num &= USB_ENDPOINT_NUMBER_MASK; if (is_playback) ep->pipe = usb_sndisocpipe(chip->dev, ep_num); else ep->pipe = usb_rcvisocpipe(chip->dev, ep_num); - if (type == SND_USB_ENDPOINT_TYPE_SYNC) { - if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && - get_endpoint(alts, 1)->bRefresh >= 1 && - get_endpoint(alts, 1)->bRefresh <= 9) - ep->syncinterval = get_endpoint(alts, 1)->bRefresh; + list_add_tail(&ep->list, &chip->ep_list); + return 0; +} + +/* Set up syncinterval and maxsyncsize for a sync EP */ +void snd_usb_endpoint_set_syncinterval(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep, + struct usb_host_interface *alts) +{ + struct usb_endpoint_descriptor *desc = get_endpoint(alts, 1); + + if (ep->type == SND_USB_ENDPOINT_TYPE_SYNC) { + if (desc->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + desc->bRefresh >= 1 && desc->bRefresh <= 9) + ep->syncinterval = desc->bRefresh; else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL) ep->syncinterval = 1; - else if (get_endpoint(alts, 1)->bInterval >= 1 && - get_endpoint(alts, 1)->bInterval <= 16) - ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1; + else if (desc->bInterval >= 1 && desc->bInterval <= 16) + ep->syncinterval = desc->bInterval - 1; else ep->syncinterval = 3; - ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); + ep->syncmaxsize = le16_to_cpu(desc->wMaxPacketSize); } - - list_add_tail(&ep->list, &chip->ep_list); - - ep->is_implicit_feedback = 0; - -__exit_unlock: - mutex_unlock(&chip->mutex); - - return ep; } /* diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 61487095a766..76b6de7de991 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -6,12 +6,9 @@ #define SND_USB_ENDPOINT_TYPE_SYNC 1 struct snd_usb_endpoint *snd_usb_get_endpoint(struct snd_usb_audio *chip, - int ep_num, int iface, - int altsetting); + int ep_num); -struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - int ep_num, int direction, int type); +int snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int type); int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, snd_pcm_format_t pcm_format, @@ -34,6 +31,9 @@ void snd_usb_endpoint_free(struct snd_usb_endpoint *ep); int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep); int snd_usb_endpoint_slave_next_packet_size(struct snd_usb_endpoint *ep); int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep); +void snd_usb_endpoint_set_syncinterval(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep, + struct usb_host_interface *alts); void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, struct snd_usb_endpoint *sender, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 8ae7d2fdba0d..03b1a02bcff4 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -585,11 +585,7 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, if (!alts) return 0; - subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, - alts, ep, !subs->direction, - fmt->implicit_fb ? - SND_USB_ENDPOINT_TYPE_DATA : - SND_USB_ENDPOINT_TYPE_SYNC); + subs->sync_endpoint = snd_usb_get_endpoint(subs->stream->chip, ep); if (!subs->sync_endpoint) { if (is_playback && (fmt->ep_attr & USB_ENDPOINT_SYNCTYPE) == USB_ENDPOINT_SYNC_NONE) @@ -597,10 +593,14 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, return -EINVAL; } + subs->sync_endpoint->iface = fmt->sync_iface; + subs->sync_endpoint->altsetting = fmt->sync_altsetting; subs->sync_endpoint->is_implicit_feedback = fmt->implicit_fb; subs->data_endpoint->sync_master = subs->sync_endpoint; + snd_usb_endpoint_set_syncinterval(subs->stream->chip, subs->sync_endpoint, alts); + if (!subs->sync_endpoint->use_count && (subs->data_endpoint->iface != subs->sync_endpoint->iface || subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting)) { @@ -641,8 +641,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) /* shared EP with implicit fb */ if (fmt->implicit_fb && !subs->need_setup_fmt) { - ep = snd_usb_get_endpoint(subs->stream->chip, fmt->endpoint, - fmt->iface, fmt->altsetting); + ep = snd_usb_get_endpoint(subs->stream->chip, fmt->endpoint); if (ep && ep->use_count > 0) goto add_data_ep; } @@ -688,12 +687,12 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) add_data_ep: subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx; - subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, - alts, fmt->endpoint, subs->direction, - SND_USB_ENDPOINT_TYPE_DATA); - + subs->data_endpoint = snd_usb_get_endpoint(subs->stream->chip, + fmt->endpoint); if (!subs->data_endpoint) return -EINVAL; + subs->data_endpoint->iface = fmt->iface; + subs->data_endpoint->altsetting = fmt->altsetting; err = set_sync_endpoint(subs, fmt); if (err < 0) @@ -1294,15 +1293,13 @@ static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime, subs->fixed_hw = 0; list_for_each_entry(fp, &subs->fmt_list, list) { - ep = snd_usb_get_endpoint(chip, fp->endpoint, fp->iface, - fp->altsetting); + ep = snd_usb_get_endpoint(chip, fp->endpoint); if (ep && ep->cur_rate) goto found; if (!fp->implicit_fb) continue; /* for the implicit fb, check the sync ep as well */ - ep = snd_usb_get_endpoint(chip, fp->sync_ep, fp->sync_iface, - fp->sync_altsetting); + ep = snd_usb_get_endpoint(chip, fp->sync_ep); if (ep && ep->cur_rate) goto found; } diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 7087ee2c8174..816fd3e5aada 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1206,6 +1206,22 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, kfree(pd); return err; } + + /* add endpoints */ + err = snd_usb_add_endpoint(chip, fp->endpoint, + SND_USB_ENDPOINT_TYPE_DATA); + if (err < 0) + return err; + + if (fp->sync_ep) { + err = snd_usb_add_endpoint(chip, fp->sync_ep, + fp->implicit_fb ? + SND_USB_ENDPOINT_TYPE_DATA : + SND_USB_ENDPOINT_TYPE_SYNC); + if (err < 0) + return err; + } + /* try to set the interface... */ usb_set_interface(chip->dev, iface_no, altno); snd_usb_init_pitch(chip, iface_no, alts, fp); -- cgit v1.2.3 From 982150560c7c1310d8826abf73857b76000e7db8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:21 +0100 Subject: ALSA: usb-audio: Drop keep_interface flag again This behavior turned out to be invalid from the USB spec POV and shouldn't be applied. As it's an optional flag that is set only via an card control element that must be hardly used, let's drop it again. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-16-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 46 ---------------------------------------------- sound/usb/pcm.c | 17 +++++++---------- sound/usb/usbaudio.h | 3 --- 3 files changed, 7 insertions(+), 59 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 81e987eaf063..12b15ed59eaa 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -3454,48 +3454,6 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) return 0; } -static int keep_iface_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = mixer->chip->keep_iface; - return 0; -} - -static int keep_iface_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - bool keep_iface = !!ucontrol->value.integer.value[0]; - - if (mixer->chip->keep_iface == keep_iface) - return 0; - mixer->chip->keep_iface = keep_iface; - return 1; -} - -static const struct snd_kcontrol_new keep_iface_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .name = "Keep Interface", - .info = snd_ctl_boolean_mono_info, - .get = keep_iface_ctl_get, - .put = keep_iface_ctl_put, -}; - -static int create_keep_iface_ctl(struct usb_mixer_interface *mixer) -{ - struct snd_kcontrol *kctl = snd_ctl_new1(&keep_iface_ctl, mixer); - - /* need only one control per card */ - if (snd_ctl_find_id(mixer->chip->card, &kctl->id)) { - snd_ctl_free_one(kctl); - return 0; - } - - return snd_ctl_add(mixer->chip->card, kctl); -} - int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error) { @@ -3548,10 +3506,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, if (err < 0) goto _error; - err = create_keep_iface_ctl(mixer); - if (err < 0) - goto _error; - err = snd_usb_mixer_apply_create_quirk(mixer); if (err < 0) goto _error; diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 03b1a02bcff4..392aa1cba61c 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -648,14 +648,12 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) /* close the old interface */ if (subs->interface >= 0 && (subs->interface != fmt->iface || subs->need_setup_fmt)) { - if (!subs->stream->chip->keep_iface) { - err = usb_set_interface(subs->dev, subs->interface, 0); - if (err < 0) { - dev_err(&dev->dev, - "%d:%d: return to setting 0 failed (%d)\n", - fmt->iface, fmt->altsetting, err); - return -EIO; - } + err = usb_set_interface(subs->dev, subs->interface, 0); + if (err < 0) { + dev_err(&dev->dev, + "%d:%d: return to setting 0 failed (%d)\n", + fmt->iface, fmt->altsetting, err); + return -EIO; } subs->interface = -1; subs->altset_idx = 0; @@ -1483,8 +1481,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) snd_media_stop_pipeline(subs); - if (!as->chip->keep_iface && - subs->interface >= 0 && + if (subs->interface >= 0 && !snd_usb_lock_shutdown(subs->stream->chip)) { usb_set_interface(subs->dev, subs->interface, 0); subs->interface = -1; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 0805b7f21272..aa017a93f7bd 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -53,9 +53,6 @@ struct snd_usb_audio { int setup; /* from the 'device_setup' module param */ bool autoclock; /* from the 'autoclock' module param */ - bool keep_iface; /* keep interface/altset after closing - * or parameter change - */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ struct media_device *media_dev; -- cgit v1.2.3 From e42a09bc520e94375501a8f8e769b867d8063d9d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:22 +0100 Subject: ALSA: usb-audio: Add snd_usb_get_host_interface() helper Add a helper function to retrieve the usb_host_interface object from the given interface and altsetting number pair, which is a commonly used procedure in the driver code. No functional changes, just minor code refactoring. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-17-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/helper.c | 10 ++++++++++ sound/usb/helper.h | 3 +++ sound/usb/pcm.c | 38 +++++++++++--------------------------- 3 files changed, 24 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/usb/helper.c b/sound/usb/helper.c index cf92d7110773..a4410267bf70 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -121,3 +121,13 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, return 0; } +struct usb_host_interface * +snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting) +{ + struct usb_interface *iface; + + iface = usb_ifnum_to_if(chip->dev, ifnum); + if (!iface) + return NULL; + return usb_altnum_to_altsetting(iface, altsetting); +} diff --git a/sound/usb/helper.h b/sound/usb/helper.h index f5b4c6647e4d..e2b51ec96ec6 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -14,6 +14,9 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, struct usb_host_interface *alts); +struct usb_host_interface * +snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting); + /* * retrieve usb_interface descriptor from the host interface * (conditional for compatibility with the older API) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 392aa1cba61c..b0961ebd71f4 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -289,20 +289,16 @@ static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream) } /* Check whether the given iface:altsetting points to an implicit fb source */ -static bool search_generic_implicit_fb(struct usb_device *dev, int ifnum, +static bool search_generic_implicit_fb(struct snd_usb_audio *chip, int ifnum, unsigned int altsetting, struct usb_host_interface **altsp, unsigned int *ep) { - struct usb_interface *iface; struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; struct usb_endpoint_descriptor *epd; - iface = usb_ifnum_to_if(dev, ifnum); - if (!iface) - return false; - alts = usb_altnum_to_altsetting(iface, altsetting); + alts = snd_usb_get_host_interface(chip, ifnum, altsetting); if (!alts) return false; altsd = get_iface_desc(alts); @@ -322,20 +318,16 @@ static bool search_generic_implicit_fb(struct usb_device *dev, int ifnum, } /* Like the function above, but specific to Roland with vendor class and hack */ -static bool search_roland_implicit_fb(struct usb_device *dev, int ifnum, +static bool search_roland_implicit_fb(struct snd_usb_audio *chip, int ifnum, unsigned int altsetting, struct usb_host_interface **altsp, unsigned int *ep) { - struct usb_interface *iface; struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; struct usb_endpoint_descriptor *epd; - iface = usb_ifnum_to_if(dev, ifnum); - if (!iface) - return false; - alts = usb_altnum_to_altsetting(iface, altsetting); + alts = snd_usb_get_host_interface(chip, ifnum, altsetting); if (!alts) return false; altsd = get_iface_desc(alts); @@ -359,11 +351,11 @@ static bool search_roland_implicit_fb(struct usb_device *dev, int ifnum, */ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, struct audioformat *fmt, - struct usb_interface *iface, struct usb_host_interface *alts) { struct usb_device *dev = chip->dev; struct usb_interface_descriptor *altsd = get_iface_desc(alts); + struct usb_interface *iface; unsigned int attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; unsigned int ep; unsigned int ifnum; @@ -431,7 +423,7 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, altsd->bInterfaceProtocol == UAC_VERSION_2 && altsd->bNumEndpoints == 1) { ifnum = altsd->bInterfaceNumber + 1; - if (search_generic_implicit_fb(dev, ifnum, + if (search_generic_implicit_fb(chip, ifnum, altsd->bAlternateSetting, &alts, &ep)) goto add_sync_ep; @@ -444,7 +436,7 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, altsd->bNumEndpoints == 1 && USB_ID_VENDOR(chip->usb_id) == 0x0582 /* Roland */) { ifnum = altsd->bInterfaceNumber + 1; - if (search_roland_implicit_fb(dev, ifnum, + if (search_roland_implicit_fb(chip, ifnum, altsd->bAlternateSetting, &alts, &ep)) goto add_sync_ep; @@ -477,24 +469,20 @@ int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, struct audioformat *fmt) { struct usb_device *dev = chip->dev; - struct usb_interface *iface; struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; unsigned int ep, attr, sync_attr; bool is_playback; int err; - iface = usb_ifnum_to_if(dev, fmt->iface); - if (!iface) - return 0; - alts = usb_altnum_to_altsetting(iface, fmt->altsetting); + alts = snd_usb_get_host_interface(chip, fmt->iface, fmt->altsetting); if (!alts) return 0; altsd = get_iface_desc(alts); is_playback = !(get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN); if (is_playback) { - err = audioformat_implicit_fb_quirk(chip, fmt, iface, alts); + err = audioformat_implicit_fb_quirk(chip, fmt, alts); if (err > 0) return 0; } @@ -564,7 +552,6 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, struct audioformat *fmt) { struct usb_device *dev = subs->dev; - struct usb_interface *iface; struct usb_host_interface *alts; int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; unsigned int ep; @@ -577,11 +564,8 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, if (!ep) return 0; - iface = usb_ifnum_to_if(dev, fmt->sync_iface); - if (!iface) - return 0; - - alts = usb_altnum_to_altsetting(iface, fmt->altsetting); + alts = snd_usb_get_host_interface(subs->stream->chip, fmt->sync_iface, + fmt->altsetting); if (!alts) return 0; -- cgit v1.2.3 From c7f902015e1e86117e6cd3dde17d5964d88a9559 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:23 +0100 Subject: ALSA: usb-audio: Don't set altsetting before initializing sample rate Setting the active altsetting at changing sample rate seems unrecommended. The host should deselect the altsetting at first before that, then select it again. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-18-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 816fd3e5aada..4501e042a944 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1223,9 +1223,10 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, } /* try to set the interface... */ - usb_set_interface(chip->dev, iface_no, altno); + usb_set_interface(chip->dev, iface_no, 0); snd_usb_init_pitch(chip, iface_no, alts, fp); snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max); + usb_set_interface(chip->dev, iface_no, altno); } return 0; } -- cgit v1.2.3 From d767aba2023c80ff0247b45526358d9a30af8293 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:24 +0100 Subject: ALSA: usb-audio: Pass snd_usb_audio object to quirk functions A preliminary patch for the later big change. Just a minor code refactoring. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-19-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/clock.c | 4 ++-- sound/usb/pcm.c | 17 +++++++++-------- sound/usb/quirks.c | 10 ++++------ sound/usb/quirks.h | 4 ++-- 4 files changed, 17 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/usb/clock.c b/sound/usb/clock.c index f174230d07d5..3298a654ce96 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -658,9 +658,9 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, * interface is active. */ if (rate != prev_rate) { usb_set_interface(dev, iface, 0); - snd_usb_set_interface_quirk(dev); + snd_usb_set_interface_quirk(chip); usb_set_interface(dev, iface, fmt->altsetting); - snd_usb_set_interface_quirk(dev); + snd_usb_set_interface_quirk(chip); } validation: diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index b0961ebd71f4..2518d4c82ad5 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -553,6 +553,7 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, { struct usb_device *dev = subs->dev; struct usb_host_interface *alts; + struct snd_usb_audio *chip = subs->stream->chip; int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; unsigned int ep; int err; @@ -569,7 +570,7 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, if (!alts) return 0; - subs->sync_endpoint = snd_usb_get_endpoint(subs->stream->chip, ep); + subs->sync_endpoint = snd_usb_get_endpoint(chip, ep); if (!subs->sync_endpoint) { if (is_playback && (fmt->ep_attr & USB_ENDPOINT_SYNCTYPE) == USB_ENDPOINT_SYNC_NONE) @@ -596,7 +597,7 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, dev_dbg(&dev->dev, "setting usb interface %d:%d\n", subs->sync_endpoint->iface, subs->sync_endpoint->altsetting); - snd_usb_set_interface_quirk(dev); + snd_usb_set_interface_quirk(chip); } return 0; @@ -608,6 +609,7 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) { struct usb_device *dev = subs->dev; + struct snd_usb_audio *chip = subs->stream->chip; struct usb_host_interface *alts; struct usb_interface *iface; struct snd_usb_endpoint *ep; @@ -625,7 +627,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) /* shared EP with implicit fb */ if (fmt->implicit_fb && !subs->need_setup_fmt) { - ep = snd_usb_get_endpoint(subs->stream->chip, fmt->endpoint); + ep = snd_usb_get_endpoint(chip, fmt->endpoint); if (ep && ep->use_count > 0) goto add_data_ep; } @@ -648,7 +650,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) /* set interface */ if (iface->cur_altsetting != alts) { - err = snd_usb_select_mode_quirk(subs, fmt); + err = snd_usb_select_mode_quirk(chip, fmt); if (err < 0) return -EIO; @@ -661,7 +663,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) } dev_dbg(&dev->dev, "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting); - snd_usb_set_interface_quirk(dev); + snd_usb_set_interface_quirk(chip); } subs->need_setup_ep = true; @@ -669,8 +671,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) add_data_ep: subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx; - subs->data_endpoint = snd_usb_get_endpoint(subs->stream->chip, - fmt->endpoint); + subs->data_endpoint = snd_usb_get_endpoint(chip, fmt->endpoint); if (!subs->data_endpoint) return -EINVAL; subs->data_endpoint->iface = fmt->iface; @@ -681,7 +682,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) return err; if (subs->need_setup_ep) { - err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt); + err = snd_usb_init_pitch(chip, fmt->iface, alts, fmt); if (err < 0) return err; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index c50be2f75f70..bb4c1ae0a4a7 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1553,13 +1553,13 @@ static bool is_itf_usb_dsd_dac(unsigned int id) return false; } -int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, +int snd_usb_select_mode_quirk(struct snd_usb_audio *chip, struct audioformat *fmt) { - struct usb_device *dev = subs->dev; + struct usb_device *dev = chip->dev; int err; - if (is_itf_usb_dsd_dac(subs->stream->chip->usb_id)) { + if (is_itf_usb_dsd_dac(chip->usb_id)) { /* First switch to alt set 0, otherwise the mode switch cmd * will not be accepted by the DAC */ @@ -1622,10 +1622,8 @@ void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) ep->tenor_fb_quirk = 1; } -void snd_usb_set_interface_quirk(struct usb_device *dev) +void snd_usb_set_interface_quirk(struct snd_usb_audio *chip) { - struct snd_usb_audio *chip = dev_get_drvdata(&dev->dev); - if (!chip) return; /* diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index c76cf24a640a..011f22cf2bf6 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -35,12 +35,12 @@ int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep); -void snd_usb_set_interface_quirk(struct usb_device *dev); +void snd_usb_set_interface_quirk(struct snd_usb_audio *chip); void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size); -int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, +int snd_usb_select_mode_quirk(struct snd_usb_audio *chip, struct audioformat *fmt); u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, -- cgit v1.2.3 From 953a446b50fd6c68f0a40f0cd79a2a903faf3243 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:25 +0100 Subject: ALSA: usb-audio: Simplify snd_usb_init_sample_rate() arguments A preliminary change for the later big changes. This is a minor code refactoring to drop the unnecessary arguments that can be retrieved in a different way. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-20-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/clock.c | 29 +++++++++++++++-------------- sound/usb/clock.h | 3 +-- sound/usb/pcm.c | 2 -- sound/usb/quirks.c | 2 +- sound/usb/stream.c | 2 +- 5 files changed, 18 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 3298a654ce96..f25da11fce3a 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -481,15 +481,18 @@ int snd_usb_clock_find_source(struct snd_usb_audio *chip, } } -static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, +static int set_sample_rate_v1(struct snd_usb_audio *chip, struct audioformat *fmt, int rate) { struct usb_device *dev = chip->dev; + struct usb_host_interface *alts; unsigned int ep; unsigned char data[3]; int err, crate; + alts = snd_usb_get_host_interface(chip, fmt->iface, fmt->altsetting); + if (!alts) + return -EINVAL; if (get_iface_desc(alts)->bNumEndpoints < 1) return -EINVAL; ep = get_endpoint(alts, 0)->bEndpointAddress; @@ -507,7 +510,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, data, sizeof(data)); if (err < 0) { dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", - iface, fmt->altsetting, rate, ep); + fmt->iface, fmt->altsetting, rate, ep); return err; } @@ -525,7 +528,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, data, sizeof(data)); if (err < 0) { dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", - iface, fmt->altsetting, ep); + fmt->iface, fmt->altsetting, ep); chip->sample_rate_read_error++; return 0; /* some devices don't support reading */ } @@ -607,8 +610,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, return get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock); } -static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, +static int set_sample_rate_v2v3(struct snd_usb_audio *chip, struct audioformat *fmt, int rate) { struct usb_device *dev = chip->dev; @@ -632,7 +634,7 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, return clock; } - prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock); + prev_rate = get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock); if (prev_rate == rate) goto validation; @@ -640,7 +642,7 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, if (cur_rate < 0) { usb_audio_err(chip, "%d:%d: cannot set freq %d (v2/v3): err %d\n", - iface, fmt->altsetting, rate, cur_rate); + fmt->iface, fmt->altsetting, rate, cur_rate); return cur_rate; } @@ -657,9 +659,9 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, /* Some devices doesn't respond to sample rate changes while the * interface is active. */ if (rate != prev_rate) { - usb_set_interface(dev, iface, 0); + usb_set_interface(dev, fmt->iface, 0); snd_usb_set_interface_quirk(chip); - usb_set_interface(dev, iface, fmt->altsetting); + usb_set_interface(dev, fmt->iface, fmt->altsetting); snd_usb_set_interface_quirk(chip); } @@ -670,14 +672,13 @@ validation: return 0; } -int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, +int snd_usb_init_sample_rate(struct snd_usb_audio *chip, struct audioformat *fmt, int rate) { switch (fmt->protocol) { case UAC_VERSION_1: default: - return set_sample_rate_v1(chip, iface, alts, fmt, rate); + return set_sample_rate_v1(chip, fmt, rate); case UAC_VERSION_3: if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { @@ -688,7 +689,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, } fallthrough; case UAC_VERSION_2: - return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); + return set_sample_rate_v2v3(chip, fmt, rate); } } diff --git a/sound/usb/clock.h b/sound/usb/clock.h index 97597f5a3c18..8d406ed294d6 100644 --- a/sound/usb/clock.h +++ b/sound/usb/clock.h @@ -2,8 +2,7 @@ #ifndef __USBAUDIO_CLOCK_H #define __USBAUDIO_CLOCK_H -int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, +int snd_usb_init_sample_rate(struct snd_usb_audio *chip, struct audioformat *fmt, int rate); int snd_usb_clock_find_source(struct snd_usb_audio *chip, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 2518d4c82ad5..38b461bdca86 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1017,8 +1017,6 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; ret = snd_usb_init_sample_rate(subs->stream->chip, - subs->cur_audiofmt->iface, - alts, subs->cur_audiofmt, subs->cur_rate); if (ret < 0) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index bb4c1ae0a4a7..018c6f241ffb 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -178,7 +178,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); usb_set_interface(chip->dev, fp->iface, 0); snd_usb_init_pitch(chip, fp->iface, alts, fp); - snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max); + snd_usb_init_sample_rate(chip, fp, fp->rate_max); return 0; error: diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 4501e042a944..23e881985123 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1225,7 +1225,7 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, /* try to set the interface... */ usb_set_interface(chip->dev, iface_no, 0); snd_usb_init_pitch(chip, iface_no, alts, fp); - snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max); + snd_usb_init_sample_rate(chip, fp, fp->rate_max); usb_set_interface(chip->dev, iface_no, altno); } return 0; -- cgit v1.2.3 From 73037c8dc1c8cf994a38fedba4a5af7e6da5e4f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:26 +0100 Subject: ALSA: usb-audio: Simplify snd_usb_init_pitch() arguments A preliminary change for the later big changes. This is a minor code refactoring to drop the unnecessary arguments that can be retrieved in a different way. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-21-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 23 +++++++++-------------- sound/usb/pcm.h | 3 +-- sound/usb/quirks.c | 2 +- sound/usb/stream.c | 2 +- 4 files changed, 12 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 38b461bdca86..0998be109af3 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -146,8 +146,7 @@ static struct audioformat *find_substream_format(struct snd_usb_substream *subs) subs->channels, subs); } -static int init_pitch_v1(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, +static int init_pitch_v1(struct snd_usb_audio *chip, struct audioformat *fmt) { struct usb_device *dev = chip->dev; @@ -155,9 +154,7 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface, unsigned char data[1]; int err; - if (get_iface_desc(alts)->bNumEndpoints < 1) - return -EINVAL; - ep = get_endpoint(alts, 0)->bEndpointAddress; + ep = fmt->endpoint; data[0] = 1; err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, @@ -166,15 +163,14 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface, data, sizeof(data)); if (err < 0) { usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n", - iface, ep); + fmt->iface, ep); return err; } return 0; } -static int init_pitch_v2(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, +static int init_pitch_v2(struct snd_usb_audio *chip, struct audioformat *fmt) { struct usb_device *dev = chip->dev; @@ -188,7 +184,7 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface, data, sizeof(data)); if (err < 0) { usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n", - iface, fmt->altsetting); + fmt->iface, fmt->altsetting); return err; } @@ -198,8 +194,7 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface, /* * initialize the pitch control and sample rate */ -int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, +int snd_usb_init_pitch(struct snd_usb_audio *chip, struct audioformat *fmt) { /* if endpoint doesn't have pitch control, bail out */ @@ -209,10 +204,10 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, switch (fmt->protocol) { case UAC_VERSION_1: default: - return init_pitch_v1(chip, iface, alts, fmt); + return init_pitch_v1(chip, fmt); case UAC_VERSION_2: - return init_pitch_v2(chip, iface, alts, fmt); + return init_pitch_v2(chip, fmt); } } @@ -682,7 +677,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) return err; if (subs->need_setup_ep) { - err = snd_usb_init_pitch(chip, fmt->iface, alts, fmt); + err = snd_usb_init_pitch(chip, fmt); if (err < 0) return err; } diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index 362782c2df5c..a4f784225abc 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -9,8 +9,7 @@ void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); int snd_usb_pcm_suspend(struct snd_usb_stream *as); int snd_usb_pcm_resume(struct snd_usb_stream *as); -int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, +int snd_usb_init_pitch(struct snd_usb_audio *chip, struct audioformat *fmt); void snd_usb_preallocate_buffer(struct snd_usb_substream *subs); diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 018c6f241ffb..013ab93fb640 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -177,7 +177,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, if (fp->maxpacksize == 0) fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); usb_set_interface(chip->dev, fp->iface, 0); - snd_usb_init_pitch(chip, fp->iface, alts, fp); + snd_usb_init_pitch(chip, fp); snd_usb_init_sample_rate(chip, fp, fp->rate_max); return 0; diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 23e881985123..7f58c7625cd4 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -1224,7 +1224,7 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, /* try to set the interface... */ usb_set_interface(chip->dev, iface_no, 0); - snd_usb_init_pitch(chip, iface_no, alts, fp); + snd_usb_init_pitch(chip, fp); snd_usb_init_sample_rate(chip, fp, fp->rate_max); usb_set_interface(chip->dev, iface_no, altno); } -- cgit v1.2.3 From 57234bc1038517437d5c589595caf77b2118529e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:27 +0100 Subject: ALSA: usb-audio: Stop both endpoints properly at error start_endpoints() may leave the data endpoint running if an error happens at starting the sync endpoint. We should stop both streams properly, instead. While we're at it, move the debug prints into the endpoint.c that is a more suitable place. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-22-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 6 ++++++ sound/usb/pcm.c | 39 +++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index eb459db511f8..0cc7e9c01263 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1172,6 +1172,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) if (atomic_read(&ep->chip->shutdown)) return -EBADFD; + usb_audio_dbg(ep->chip, "Starting %s EP 0x%x (count %d)\n", + ep_type_name(ep->type), ep->ep_num, ep->use_count); + /* already running? */ if (++ep->use_count != 1) return 0; @@ -1254,6 +1257,9 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) if (!ep) return; + usb_audio_dbg(ep->chip, "Stopping %s EP 0x%x (count %d)\n", + ep_type_name(ep->type), ep->ep_num, ep->use_count); + if (snd_BUG_ON(ep->use_count == 0)) return; diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0998be109af3..c4e39aa92a84 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -211,6 +211,17 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, } } +static void stop_endpoints(struct snd_usb_substream *subs) +{ + if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { + snd_usb_endpoint_stop(subs->sync_endpoint); + subs->sync_endpoint->sync_slave = NULL; + } + + if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) + snd_usb_endpoint_stop(subs->data_endpoint); +} + static int start_endpoints(struct snd_usb_substream *subs) { int err; @@ -221,13 +232,11 @@ static int start_endpoints(struct snd_usb_substream *subs) if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { struct snd_usb_endpoint *ep = subs->data_endpoint; - dev_dbg(&subs->dev->dev, "Starting data EP 0x%x\n", ep->ep_num); - ep->data_subs = subs; err = snd_usb_endpoint_start(ep); if (err < 0) { clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); - return err; + goto error; } } @@ -235,18 +244,20 @@ static int start_endpoints(struct snd_usb_substream *subs) !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { struct snd_usb_endpoint *ep = subs->sync_endpoint; - dev_dbg(&subs->dev->dev, "Starting sync EP 0x%x\n", ep->ep_num); - ep->sync_slave = subs->data_endpoint; err = snd_usb_endpoint_start(ep); if (err < 0) { clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); ep->sync_slave = NULL; - return err; + goto error; } } return 0; + + error: + stop_endpoints(subs); + return err; } static void sync_pending_stops(struct snd_usb_substream *subs) @@ -255,22 +266,6 @@ static void sync_pending_stops(struct snd_usb_substream *subs) snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); } -static void stop_endpoints(struct snd_usb_substream *subs) -{ - if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { - dev_dbg(&subs->dev->dev, "Stopping sync EP 0x%x\n", - subs->sync_endpoint->ep_num); - snd_usb_endpoint_stop(subs->sync_endpoint); - subs->sync_endpoint->sync_slave = NULL; - } - - if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { - dev_dbg(&subs->dev->dev, "Stopping data EP 0x%x\n", - subs->data_endpoint->ep_num); - snd_usb_endpoint_stop(subs->data_endpoint); - } -} - /* PCM sync_stop callback */ static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream) { -- cgit v1.2.3 From 96e221f379e887f58d29969f10ed330ae1be4d80 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:28 +0100 Subject: ALSA: usb-audio: Set callbacks via snd_usb_endpoint_set_callback() The prepare_data_urb and retire_data_urb fields of the endpoint object are set dynamically at PCM trigger start/stop. Those are evaluated in the endpoint handler, but there can be a race, especially if two different PCM substreams are handling the same endpoint for the implicit feedback case. Also, the data_subs field of the endpoint is set and accessed dynamically, too, which has the same risk. As a slight improvement for the concurrency, this patch introduces the function to set the callbacks and the data in a shot with the memory barrier. In the reader side, it's also fetched with the memory barrier. There is still a room of race if prepare and retire callbacks are set during executing the URB completion. But such an inconsistency may happen only for the implicit fb source, i.e. it's only about the capture stream. And luckily, the capture stream never sets the prepare callback, hence the problem doesn't happen practically. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-23-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 60 +++++++++++++++++++++++++++++++++++----------------- sound/usb/endpoint.h | 7 ++++++ sound/usb/pcm.c | 33 ++++++++++++++++------------- 3 files changed, 66 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 0cc7e9c01263..7012fdafc3d8 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -169,11 +169,20 @@ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) return ret; } +static void call_retire_callback(struct snd_usb_endpoint *ep, + struct urb *urb) +{ + struct snd_usb_substream *data_subs; + + data_subs = READ_ONCE(ep->data_subs); + if (data_subs && ep->retire_data_urb) + ep->retire_data_urb(data_subs, urb); +} + static void retire_outbound_urb(struct snd_usb_endpoint *ep, struct snd_urb_ctx *urb_ctx) { - if (ep->retire_data_urb) - ep->retire_data_urb(ep->data_subs, urb_ctx->urb); + call_retire_callback(ep, urb_ctx->urb); } static void retire_inbound_urb(struct snd_usb_endpoint *ep, @@ -189,8 +198,7 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep, if (ep->sync_slave) snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); - if (ep->retire_data_urb) - ep->retire_data_urb(ep->data_subs, urb); + call_retire_callback(ep, urb); } static void prepare_silent_urb(struct snd_usb_endpoint *ep, @@ -244,17 +252,17 @@ static void prepare_outbound_urb(struct snd_usb_endpoint *ep, { struct urb *urb = ctx->urb; unsigned char *cp = urb->transfer_buffer; + struct snd_usb_substream *data_subs; urb->dev = ep->chip->dev; /* we need to set this at each time */ switch (ep->type) { case SND_USB_ENDPOINT_TYPE_DATA: - if (ep->prepare_data_urb) { - ep->prepare_data_urb(ep->data_subs, urb); - } else { - /* no data provider, so send silence */ + data_subs = READ_ONCE(ep->data_subs); + if (data_subs && ep->prepare_data_urb) + ep->prepare_data_urb(data_subs, urb); + else /* no data provider, so send silence */ prepare_silent_urb(ep, ctx); - } break; case SND_USB_ENDPOINT_TYPE_SYNC: @@ -381,7 +389,7 @@ static void snd_complete_urb(struct urb *urb) { struct snd_urb_ctx *ctx = urb->context; struct snd_usb_endpoint *ep = ctx->ep; - struct snd_pcm_substream *substream; + struct snd_usb_substream *data_subs; unsigned long flags; int err; @@ -430,10 +438,9 @@ static void snd_complete_urb(struct urb *urb) return; usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err); - if (ep->data_subs && ep->data_subs->pcm_substream) { - substream = ep->data_subs->pcm_substream; - snd_pcm_stop_xrun(substream); - } + data_subs = READ_ONCE(ep->data_subs); + if (data_subs && data_subs->pcm_substream) + snd_pcm_stop_xrun(data_subs->pcm_substream); exit_clear: clear_bit(ctx->index, &ep->active_mask); @@ -532,6 +539,24 @@ void snd_usb_endpoint_set_syncinterval(struct snd_usb_audio *chip, } } +/* + * Set data endpoint callbacks and the assigned data stream + * + * Called at PCM trigger and cleanups. + * Pass NULL to deactivate each callback. + */ +void snd_usb_endpoint_set_callback(struct snd_usb_endpoint *ep, + void (*prepare)(struct snd_usb_substream *subs, + struct urb *urb), + void (*retire)(struct snd_usb_substream *subs, + struct urb *urb), + struct snd_usb_substream *data_subs) +{ + ep->prepare_data_urb = prepare; + ep->retire_data_urb = retire; + WRITE_ONCE(ep->data_subs, data_subs); +} + /* * wait until all urbs are processed. */ @@ -554,10 +579,8 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep) alive, ep->ep_num); clear_bit(EP_FLAG_STOPPING, &ep->flags); - ep->data_subs = NULL; ep->sync_slave = NULL; - ep->retire_data_urb = NULL; - ep->prepare_data_urb = NULL; + snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL); return 0; } @@ -607,8 +630,7 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) int i; /* route incoming urbs to nirvana */ - ep->retire_data_urb = NULL; - ep->prepare_data_urb = NULL; + snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL); /* stop urbs */ deactivate_urbs(ep, force); diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 76b6de7de991..e2fddb3dcf7a 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -20,6 +20,13 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, struct audioformat *fmt, struct snd_usb_endpoint *sync_ep); +void snd_usb_endpoint_set_callback(struct snd_usb_endpoint *ep, + void (*prepare)(struct snd_usb_substream *subs, + struct urb *urb), + void (*retire)(struct snd_usb_substream *subs, + struct urb *urb), + struct snd_usb_substream *data_subs); + int snd_usb_endpoint_start(struct snd_usb_endpoint *ep); void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep); void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index c4e39aa92a84..32237623de96 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -232,7 +232,6 @@ static int start_endpoints(struct snd_usb_substream *subs) if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { struct snd_usb_endpoint *ep = subs->data_endpoint; - ep->data_subs = subs; err = snd_usb_endpoint_start(ep); if (err < 0) { clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); @@ -1830,18 +1829,24 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea subs->trigger_tstamp_pending_update = true; fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - subs->data_endpoint->prepare_data_urb = prepare_playback_urb; - subs->data_endpoint->retire_data_urb = retire_playback_urb; + snd_usb_endpoint_set_callback(subs->data_endpoint, + prepare_playback_urb, + retire_playback_urb, + subs); subs->running = 1; return 0; case SNDRV_PCM_TRIGGER_STOP: stop_endpoints(subs); + snd_usb_endpoint_set_callback(subs->data_endpoint, + NULL, NULL, NULL); subs->running = 0; return 0; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - subs->data_endpoint->prepare_data_urb = NULL; /* keep retire_data_urb for delay calculation */ - subs->data_endpoint->retire_data_urb = retire_playback_urb; + snd_usb_endpoint_set_callback(subs->data_endpoint, + NULL, + retire_playback_urb, + subs); subs->running = 0; return 0; case SNDRV_PCM_TRIGGER_SUSPEND: @@ -1867,23 +1872,21 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream err = start_endpoints(subs); if (err < 0) return err; - - subs->data_endpoint->retire_data_urb = retire_capture_urb; + fallthrough; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + snd_usb_endpoint_set_callback(subs->data_endpoint, + NULL, retire_capture_urb, + subs); subs->running = 1; return 0; case SNDRV_PCM_TRIGGER_STOP: stop_endpoints(subs); - subs->data_endpoint->retire_data_urb = NULL; - subs->running = 0; - return 0; + fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - subs->data_endpoint->retire_data_urb = NULL; + snd_usb_endpoint_set_callback(subs->data_endpoint, + NULL, NULL, NULL); subs->running = 0; return 0; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - subs->data_endpoint->retire_data_urb = retire_capture_urb; - subs->running = 1; - return 0; case SNDRV_PCM_TRIGGER_SUSPEND: if (subs->stream->chip->setup_fmt_after_resume_quirk) { stop_endpoints(subs); -- cgit v1.2.3 From 75c16b5147ee42270b18b5f32bc3f17f8b74b5eb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:29 +0100 Subject: ALSA: usb-audio: Always set up the parameters after resume The commit 92adc96f8eec ("ALSA: usb-audio: set the interface format after resume on Dell WD19") introduced the workaround for the broken setup after the resume specifically on a Dell dock model. However, the full setup should have been performed after the resume on all devices, as we can't guarantee the same state. So this patch removes the conditional check and applies the workaround always. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-24-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 20 ++++++-------------- sound/usb/quirks-table.h | 8 -------- sound/usb/quirks.c | 11 ----------- sound/usb/usbaudio.h | 1 - 4 files changed, 6 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 32237623de96..ac6385a4eb70 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1835,6 +1835,9 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea subs); subs->running = 1; return 0; + case SNDRV_PCM_TRIGGER_SUSPEND: + subs->need_setup_fmt = true; + fallthrough; case SNDRV_PCM_TRIGGER_STOP: stop_endpoints(subs); snd_usb_endpoint_set_callback(subs->data_endpoint, @@ -1849,13 +1852,6 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea subs); subs->running = 0; return 0; - case SNDRV_PCM_TRIGGER_SUSPEND: - if (subs->stream->chip->setup_fmt_after_resume_quirk) { - stop_endpoints(subs); - subs->need_setup_fmt = true; - return 0; - } - break; } return -EINVAL; @@ -1879,6 +1875,9 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream subs); subs->running = 1; return 0; + case SNDRV_PCM_TRIGGER_SUSPEND: + subs->need_setup_fmt = true; + fallthrough; case SNDRV_PCM_TRIGGER_STOP: stop_endpoints(subs); fallthrough; @@ -1887,13 +1886,6 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream NULL, NULL, NULL); subs->running = 0; return 0; - case SNDRV_PCM_TRIGGER_SUSPEND: - if (subs->stream->chip->setup_fmt_after_resume_quirk) { - stop_endpoints(subs); - subs->need_setup_fmt = true; - return 0; - } - break; } return -EINVAL; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 3c1697f6b60c..85b99c6d3c61 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3256,14 +3256,6 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } } }, -/* Dell WD19 Dock */ -{ - USB_DEVICE(0x0bda, 0x402e), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_SETUP_FMT_AFTER_RESUME - } -}, /* MOTU Microbook II */ { USB_DEVICE_VENDOR_SPEC(0x07fd, 0x0004), diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 013ab93fb640..7e7f258011ff 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -508,16 +508,6 @@ static int create_standard_mixer_quirk(struct snd_usb_audio *chip, return snd_usb_create_mixer(chip, quirk->ifnum, 0); } - -static int setup_fmt_after_resume_quirk(struct snd_usb_audio *chip, - struct usb_interface *iface, - struct usb_driver *driver, - const struct snd_usb_audio_quirk *quirk) -{ - chip->setup_fmt_after_resume_quirk = 1; - return 1; /* Continue with creating streams and mixer */ -} - static int setup_disable_autosuspend(struct snd_usb_audio *chip, struct usb_interface *iface, struct usb_driver *driver, @@ -565,7 +555,6 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk, [QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk, - [QUIRK_SETUP_FMT_AFTER_RESUME] = setup_fmt_after_resume_quirk, [QUIRK_SETUP_DISABLE_AUTOSUSPEND] = setup_disable_autosuspend, }; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index aa017a93f7bd..cc338e8e2597 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -35,7 +35,6 @@ struct snd_usb_audio { wait_queue_head_t shutdown_wait; unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ unsigned int tx_length_quirk:1; /* Put length specifier in transfers */ - unsigned int setup_fmt_after_resume_quirk:1; /* setup the format to interface after resume */ unsigned int need_delayed_register:1; /* warn for delayed registration */ int num_interfaces; int num_suspended_intf; -- cgit v1.2.3 From 61cc2d775e0941ca61b9666760a656919d80077a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:30 +0100 Subject: ALSA: usb-audio: Fix EP matching for continuous rates The function to evaluate the match of the parameters with an EP assumes only the discrete rate tables and doesn't handle the continuous rates properly. This patch fixes match_endpoint_audioformats() to handle the continuous rates. Also the almost useless debug prints there are dropped. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-25-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index ac6385a4eb70..45a692512d27 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -695,41 +695,30 @@ static int match_endpoint_audioformats(struct snd_usb_substream *subs, struct audioformat *match, int rate, snd_pcm_format_t pcm_format) { - int i; - int score = 0; + int i, score; - if (fp->channels < 1) { - dev_dbg(&subs->dev->dev, - "%s: (fmt @%p) no channels\n", __func__, fp); + if (fp->channels < 1) return 0; - } - if (!(fp->formats & pcm_format_to_bits(pcm_format))) { - dev_dbg(&subs->dev->dev, - "%s: (fmt @%p) no match for format %d\n", __func__, - fp, pcm_format); + if (!(fp->formats & pcm_format_to_bits(pcm_format))) return 0; - } - for (i = 0; i < fp->nr_rates; i++) { - if (fp->rate_table[i] == rate) { - score++; - break; + if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { + if (rate < fp->rate_min || rate > fp->rate_max) + return 0; + } else { + for (i = 0; i < fp->nr_rates; i++) { + if (fp->rate_table[i] == rate) + break; } - } - if (!score) { - dev_dbg(&subs->dev->dev, - "%s: (fmt @%p) no match for rate %d\n", __func__, - fp, rate); - return 0; + if (i >= fp->nr_rates) + return 0; } + score = 1; if (fp->channels == match->channels) score++; - dev_dbg(&subs->dev->dev, - "%s: (fmt @%p) score %d\n", __func__, fp, score); - return score; } -- cgit v1.2.3 From bf6313a0ff766925462e97b4e733d5952de02367 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:31 +0100 Subject: ALSA: usb-audio: Refactor endpoint management This is an intensive surgery for the endpoint and stream management for achieving more robust and clean code. The goals of this patch are: - More clear endpoint resource changes - The interface altsetting control in a single place Below are brief description of the whole changes. First off, most of the endpoint operations are moved into endpoint.c, so that the snd_usb_endpoint object is only referred in other places. The endpoint object is acquired and released via the new functions snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called at PCM hw_params and hw_free callbacks, respectively. Those are ref-counted and EPs can manage the multiple opens. The open callback receives the audioformat and hw_params arguments, and those are used for initializing the EP parameters; especially the endpoint, interface and altset numbers are read from there, as well as the PCM parameters like the format, rate and channels. Those are stored in snd_usb_endpoint object. If it's the secondary open, the function checks whether the given parameters are compatible with the already opened EP setup, too. The coupling with a sync EP (including an implicit feedback sync) is done by the sole snd_usb_endpoint_set_sync() call. The configuration of each endpoint is done in a single shot via snd_usb_endpoint_configure() call. This is the place where most of PCM configurations are done. A few flags and special handling in the snd_usb_substream are dropped along with this change. A significant difference wrt the configuration from the previous code is the order of USB host interface setups. Now the interface is always disabled at beginning and (re-)enabled at the last step of snd_usb_endpoint_configure(), in order to be compliant with the standard UAC2/3. For UAC1, the interface is set before the parameter setups since there seem devices that require it (e.g. Yamaha THR10), just like how it was done in the previous driver code. The start/stop are almost same as before, also single-shots. The URB callbacks need to be set via snd_usb_endpoint_set_callback() like the previous code at the trigger phase, too. Finally, the flag for the re-setup is set at the device suspend through the full EP list, instead of PCM trigger. This catches the overlooked cases where the PCM hasn't been running yet but the device needs the full setup after resume. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 8 +- sound/usb/card.h | 11 +- sound/usb/clock.c | 13 +- sound/usb/endpoint.c | 662 ++++++++++++++++++++++++++------------------------- sound/usb/endpoint.h | 40 ++-- sound/usb/pcm.c | 616 +++++++++++++++++++---------------------------- 6 files changed, 616 insertions(+), 734 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 096dd8e3c64b..58958afcec93 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -980,6 +980,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) { struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_usb_stream *as; + struct snd_usb_endpoint *ep; struct usb_mixer_interface *mixer; struct list_head *p; @@ -987,11 +988,10 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) return 0; if (!chip->num_suspended_intf++) { - list_for_each_entry(as, &chip->pcm_list, list) { + list_for_each_entry(as, &chip->pcm_list, list) snd_usb_pcm_suspend(as); - as->substream[0].need_setup_ep = - as->substream[1].need_setup_ep = true; - } + list_for_each_entry(ep, &chip->ep_list, list) + snd_usb_endpoint_suspend(ep); list_for_each(p, &chip->midi_list) snd_usbmidi_suspend(p); list_for_each_entry(mixer, &chip->mixer_list, list) diff --git a/sound/usb/card.h b/sound/usb/card.h index 1f61be98a31d..66a249ae138f 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -26,6 +26,7 @@ struct audioformat { unsigned char sync_ep; /* sync endpoint number */ unsigned char sync_iface; /* sync EP interface */ unsigned char sync_altsetting; /* sync EP alternate setting */ + unsigned char sync_ep_idx; /* sync EP array index */ unsigned char datainterval; /* log_2 of data packet interval */ unsigned char protocol; /* UAC_VERSION_1/2/3 */ unsigned int maxpacksize; /* max. packet size */ @@ -58,6 +59,7 @@ struct snd_urb_ctx { struct snd_usb_endpoint { struct snd_usb_audio *chip; + int opened; /* open refcount; protect with chip->mutex */ int use_count; int ep_num; /* the referenced endpoint number */ int type; /* SND_USB_ENDPOINT_TYPE_* */ @@ -110,14 +112,18 @@ struct snd_usb_endpoint { unsigned char silence_value; unsigned int stride; int iface, altsetting; + unsigned char ep_idx; /* endpoint array index */ int skip_packets; /* quirks for devices to ignore the first n packets in a stream */ - bool is_implicit_feedback; /* This endpoint is used as implicit feedback */ + bool implicit_fb_sync; /* syncs with implicit feedback */ + bool need_setup; /* (re-)need for configure? */ /* for hw constraints */ + struct audioformat *cur_audiofmt; unsigned int cur_rate; snd_pcm_format_t cur_format; unsigned int cur_channels; + unsigned int cur_frame_bytes; unsigned int cur_period_frames; unsigned int cur_period_bytes; unsigned int cur_buffer_periods; @@ -152,7 +158,6 @@ struct snd_usb_substream { unsigned int stream_offset_adj; /* Bytes to drop from beginning of stream (for non-compliant devices) */ unsigned int running: 1; /* running status */ - unsigned int fixed_hw:1; /* fixed hw constraints due to sync EP */ unsigned int hwptr_done; /* processed byte position in the buffer */ unsigned int transfer_done; /* processed frames since last period update */ @@ -163,8 +168,6 @@ struct snd_usb_substream { struct snd_usb_endpoint *data_endpoint; struct snd_usb_endpoint *sync_endpoint; unsigned long flags; - bool need_setup_ep; /* (re)configure EP at prepare? */ - bool need_setup_fmt; /* (re)configure fmt after resume? */ unsigned int speed; /* USB_SPEED_XXX */ u64 formats; /* format bitmasks (all or'ed) */ diff --git a/sound/usb/clock.c b/sound/usb/clock.c index f25da11fce3a..b869a711afbf 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -613,7 +613,6 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, static int set_sample_rate_v2v3(struct snd_usb_audio *chip, struct audioformat *fmt, int rate) { - struct usb_device *dev = chip->dev; int cur_rate, prev_rate; int clock; @@ -656,15 +655,6 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, return -ENXIO; } - /* Some devices doesn't respond to sample rate changes while the - * interface is active. */ - if (rate != prev_rate) { - usb_set_interface(dev, fmt->iface, 0); - snd_usb_set_interface_quirk(chip); - usb_set_interface(dev, fmt->iface, fmt->altsetting); - snd_usb_set_interface_quirk(chip); - } - validation: /* validate clock after rate change */ if (!uac_clock_source_is_valid(chip, fmt, clock)) @@ -675,6 +665,9 @@ validation: int snd_usb_init_sample_rate(struct snd_usb_audio *chip, struct audioformat *fmt, int rate) { + usb_audio_dbg(chip, "%d:%d Set sample rate %d, clock %d\n", + fmt->iface, fmt->altsetting, rate, fmt->clock); + switch (fmt->protocol) { case UAC_VERSION_1: default: diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 7012fdafc3d8..eee74313603e 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -18,6 +18,7 @@ #include "card.h" #include "endpoint.h" #include "pcm.h" +#include "clock.h" #include "quirks.h" #define EP_FLAG_RUNNING 1 @@ -116,10 +117,7 @@ static const char *usb_error_string(int err) */ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep) { - return ep->sync_master && - ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA && - ep->type == SND_USB_ENDPOINT_TYPE_DATA && - usb_pipeout(ep->pipe); + return ep->implicit_fb_sync && usb_pipeout(ep->pipe); } /* @@ -185,18 +183,24 @@ static void retire_outbound_urb(struct snd_usb_endpoint *ep, call_retire_callback(ep, urb_ctx->urb); } +static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, + struct snd_usb_endpoint *sender, + const struct urb *urb); + static void retire_inbound_urb(struct snd_usb_endpoint *ep, struct snd_urb_ctx *urb_ctx) { struct urb *urb = urb_ctx->urb; + struct snd_usb_endpoint *sync_slave; if (unlikely(ep->skip_packets > 0)) { ep->skip_packets--; return; } - if (ep->sync_slave) - snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); + sync_slave = READ_ONCE(ep->sync_slave); + if (sync_slave) + snd_usb_handle_sync_urb(sync_slave, ep, urb); call_retire_callback(ep, urb); } @@ -518,25 +522,155 @@ int snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int type) } /* Set up syncinterval and maxsyncsize for a sync EP */ -void snd_usb_endpoint_set_syncinterval(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep, - struct usb_host_interface *alts) +static void endpoint_set_syncinterval(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) { - struct usb_endpoint_descriptor *desc = get_endpoint(alts, 1); - - if (ep->type == SND_USB_ENDPOINT_TYPE_SYNC) { - if (desc->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && - desc->bRefresh >= 1 && desc->bRefresh <= 9) - ep->syncinterval = desc->bRefresh; - else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL) - ep->syncinterval = 1; - else if (desc->bInterval >= 1 && desc->bInterval <= 16) - ep->syncinterval = desc->bInterval - 1; - else - ep->syncinterval = 3; + struct usb_host_interface *alts; + struct usb_endpoint_descriptor *desc; + + alts = snd_usb_get_host_interface(chip, ep->iface, ep->altsetting); + if (!alts) + return; + + desc = get_endpoint(alts, ep->ep_idx); + if (desc->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + desc->bRefresh >= 1 && desc->bRefresh <= 9) + ep->syncinterval = desc->bRefresh; + else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL) + ep->syncinterval = 1; + else if (desc->bInterval >= 1 && desc->bInterval <= 16) + ep->syncinterval = desc->bInterval - 1; + else + ep->syncinterval = 3; + + ep->syncmaxsize = le16_to_cpu(desc->wMaxPacketSize); +} + +static bool endpoint_compatible(struct snd_usb_endpoint *ep, + const struct audioformat *fp, + const struct snd_pcm_hw_params *params) +{ + if (!ep->opened) + return false; + if (ep->cur_audiofmt != fp) + return false; + if (ep->cur_rate != params_rate(params) || + ep->cur_format != params_format(params) || + ep->cur_period_frames != params_period_size(params) || + ep->cur_buffer_periods != params_periods(params)) + return false; + return true; +} + +/* + * Check whether the given fp and hw params are compatbile with the current + * setup of the target EP for implicit feedback sync + */ +bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep, + const struct audioformat *fp, + const struct snd_pcm_hw_params *params) +{ + bool ret; + + mutex_lock(&chip->mutex); + ret = endpoint_compatible(ep, fp, params); + mutex_unlock(&chip->mutex); + return ret; +} + +/* + * snd_usb_endpoint_open: Open the endpoint + * + * Called from hw_params to assign the endpoint to the substream. + * It's reference-counted, and only the first opener is allowed to set up + * arbitrary parameters. The later opener must be compatible with the + * former opened parameters. + * The endpoint needs to be closed via snd_usb_endpoint_close() later. + * + * Note that this function doesn't configure the endpoint. The substream + * needs to set it up later via snd_usb_endpoint_configure(). + */ +struct snd_usb_endpoint * +snd_usb_endpoint_open(struct snd_usb_audio *chip, + struct audioformat *fp, + const struct snd_pcm_hw_params *params, + bool is_sync_ep) +{ + struct snd_usb_endpoint *ep; + int ep_num = is_sync_ep ? fp->sync_ep : fp->endpoint; - ep->syncmaxsize = le16_to_cpu(desc->wMaxPacketSize); + mutex_lock(&chip->mutex); + ep = snd_usb_get_endpoint(chip, ep_num); + if (!ep) { + usb_audio_err(chip, "Cannot find EP 0x%x to open\n", ep_num); + goto unlock; } + + if (!ep->opened) { + if (is_sync_ep) { + ep->iface = fp->sync_iface; + ep->altsetting = fp->sync_altsetting; + ep->ep_idx = fp->sync_ep_idx; + } else { + ep->iface = fp->iface; + ep->altsetting = fp->altsetting; + ep->ep_idx = 0; + } + usb_audio_dbg(chip, "Open EP 0x%x, iface=%d:%d, idx=%d\n", + ep_num, ep->iface, ep->altsetting, ep->ep_idx); + + ep->cur_audiofmt = fp; + ep->cur_channels = fp->channels; + ep->cur_rate = params_rate(params); + ep->cur_format = params_format(params); + ep->cur_frame_bytes = snd_pcm_format_physical_width(ep->cur_format) * + ep->cur_channels / 8; + ep->cur_period_frames = params_period_size(params); + ep->cur_period_bytes = ep->cur_period_frames * ep->cur_frame_bytes; + ep->cur_buffer_periods = params_periods(params); + + if (ep->type == SND_USB_ENDPOINT_TYPE_SYNC) + endpoint_set_syncinterval(chip, ep); + + ep->implicit_fb_sync = fp->implicit_fb; + ep->need_setup = true; + + usb_audio_dbg(chip, " channels=%d, rate=%d, format=%s, period_bytes=%d, periods=%d, implicit_fb=%d\n", + ep->cur_channels, ep->cur_rate, + snd_pcm_format_name(ep->cur_format), + ep->cur_period_bytes, ep->cur_buffer_periods, + ep->implicit_fb_sync); + + } else { + if (!endpoint_compatible(ep, fp, params)) { + usb_audio_err(chip, "Incompatible EP setup for 0x%x\n", + ep_num); + ep = NULL; + goto unlock; + } + + usb_audio_dbg(chip, "Reopened EP 0x%x (count %d)\n", + ep_num, ep->opened); + } + + ep->opened++; + + unlock: + mutex_unlock(&chip->mutex); + return ep; +} + +/* + * snd_usb_endpoint_set_sync: Link data and sync endpoints + * + * Pass NULL to sync_ep to unlink again + */ +void snd_usb_endpoint_set_sync(struct snd_usb_audio *chip, + struct snd_usb_endpoint *data_ep, + struct snd_usb_endpoint *sync_ep) +{ + data_ep->sync_master = sync_ep; } /* @@ -557,6 +691,54 @@ void snd_usb_endpoint_set_callback(struct snd_usb_endpoint *ep, WRITE_ONCE(ep->data_subs, data_subs); } +static int endpoint_set_interface(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep, + bool set) +{ + int altset = set ? ep->altsetting : 0; + int err; + + usb_audio_dbg(chip, "Setting usb interface %d:%d for EP 0x%x\n", + ep->iface, altset, ep->ep_num); + err = usb_set_interface(chip->dev, ep->iface, altset); + if (err < 0) { + usb_audio_err(chip, "%d:%d: usb_set_interface failed (%d)\n", + ep->iface, altset, err); + return err; + } + + snd_usb_set_interface_quirk(chip); + return 0; +} + +/* + * snd_usb_endpoint_close: Close the endpoint + * + * Unreference the already opened endpoint via snd_usb_endpoint_open(). + */ +void snd_usb_endpoint_close(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) +{ + mutex_lock(&chip->mutex); + usb_audio_dbg(chip, "Closing EP 0x%x (count %d)\n", + ep->ep_num, ep->opened); + if (!--ep->opened) { + endpoint_set_interface(chip, ep, false); + ep->iface = -1; + ep->altsetting = 0; + ep->cur_audiofmt = NULL; + ep->cur_rate = 0; + usb_audio_dbg(chip, "EP 0x%x closed\n", ep->ep_num); + } + mutex_unlock(&chip->mutex); +} + +/* Prepare for suspening EP, called from the main suspend handler */ +void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep) +{ + ep->need_setup = true; +} + /* * wait until all urbs are processed. */ @@ -646,219 +828,36 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) ep->nurbs = 0; } -/* - * Check data endpoint for format differences - */ -static bool check_ep_params(struct snd_usb_endpoint *ep, - snd_pcm_format_t pcm_format, - unsigned int channels, - unsigned int period_bytes, - unsigned int frames_per_period, - unsigned int periods_per_buffer, - unsigned int rate, - struct audioformat *fmt, - struct snd_usb_endpoint *sync_ep) -{ - unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb; - unsigned int max_packs_per_period, urbs_per_period, urb_packs; - unsigned int max_urbs; - int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels; - int tx_length_quirk = (ep->chip->tx_length_quirk && - usb_pipeout(ep->pipe)); - bool ret = 1; - - /* matching with the saved parameters? */ - if (ep->cur_rate == rate && - ep->cur_format == pcm_format && - ep->cur_channels == channels && - ep->cur_period_frames == frames_per_period && - ep->cur_buffer_periods == periods_per_buffer) - return true; - - if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) { - /* - * When operating in DSD DOP mode, the size of a sample frame - * in hardware differs from the actual physical format width - * because we need to make room for the DOP markers. - */ - frame_bits += channels << 3; - } - - ret = ret && (ep->datainterval == fmt->datainterval); - ret = ret && (ep->stride == frame_bits >> 3); - - switch (pcm_format) { - case SNDRV_PCM_FORMAT_U8: - ret = ret && (ep->silence_value == 0x80); - break; - case SNDRV_PCM_FORMAT_DSD_U8: - case SNDRV_PCM_FORMAT_DSD_U16_LE: - case SNDRV_PCM_FORMAT_DSD_U32_LE: - case SNDRV_PCM_FORMAT_DSD_U16_BE: - case SNDRV_PCM_FORMAT_DSD_U32_BE: - ret = ret && (ep->silence_value == 0x69); - break; - default: - ret = ret && (ep->silence_value == 0); - } - - /* assume max. frequency is 50% higher than nominal */ - ret = ret && (ep->freqmax == ep->freqn + (ep->freqn >> 1)); - /* Round up freqmax to nearest integer in order to calculate maximum - * packet size, which must represent a whole number of frames. - * This is accomplished by adding 0x0.ffff before converting the - * Q16.16 format into integer. - * In order to accurately calculate the maximum packet size when - * the data interval is more than 1 (i.e. ep->datainterval > 0), - * multiply by the data interval prior to rounding. For instance, - * a freqmax of 41 kHz will result in a max packet size of 6 (5.125) - * frames with a data interval of 1, but 11 (10.25) frames with a - * data interval of 2. - * (ep->freqmax << ep->datainterval overflows at 8.192 MHz for the - * maximum datainterval value of 3, at USB full speed, higher for - * USB high speed, noting that ep->freqmax is in units of - * frames per packet in Q16.16 format.) - */ - maxsize = (((ep->freqmax << ep->datainterval) + 0xffff) >> 16) * - (frame_bits >> 3); - if (tx_length_quirk) - maxsize += sizeof(__le32); /* Space for length descriptor */ - /* but wMaxPacketSize might reduce this */ - if (ep->maxpacksize && ep->maxpacksize < maxsize) { - /* whatever fits into a max. size packet */ - unsigned int data_maxsize = maxsize = ep->maxpacksize; - - if (tx_length_quirk) - /* Need to remove the length descriptor to calc freq */ - data_maxsize -= sizeof(__le32); - ret = ret && (ep->freqmax == (data_maxsize / (frame_bits >> 3)) - << (16 - ep->datainterval)); - } - - if (ep->fill_max) - ret = ret && (ep->curpacksize == ep->maxpacksize); - else - ret = ret && (ep->curpacksize == maxsize); - - if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) { - packs_per_ms = 8 >> ep->datainterval; - max_packs_per_urb = MAX_PACKS_HS; - } else { - packs_per_ms = 1; - max_packs_per_urb = MAX_PACKS; - } - if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep)) - max_packs_per_urb = min(max_packs_per_urb, - 1U << sync_ep->syncinterval); - max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval); - - /* - * Capture endpoints need to use small URBs because there's no way - * to tell in advance where the next period will end, and we don't - * want the next URB to complete much after the period ends. - * - * Playback endpoints with implicit sync much use the same parameters - * as their corresponding capture endpoint. - */ - if (usb_pipein(ep->pipe) || - snd_usb_endpoint_implicit_feedback_sink(ep)) { - - urb_packs = packs_per_ms; - /* - * Wireless devices can poll at a max rate of once per 4ms. - * For dataintervals less than 5, increase the packet count to - * allow the host controller to use bursting to fill in the - * gaps. - */ - if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_WIRELESS) { - int interval = ep->datainterval; - - while (interval < 5) { - urb_packs <<= 1; - ++interval; - } - } - /* make capture URBs <= 1 ms and smaller than a period */ - urb_packs = min(max_packs_per_urb, urb_packs); - while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) - urb_packs >>= 1; - ret = ret && (ep->nurbs == MAX_URBS); - - /* - * Playback endpoints without implicit sync are adjusted so that - * a period fits as evenly as possible in the smallest number of - * URBs. The total number of URBs is adjusted to the size of the - * ALSA buffer, subject to the MAX_URBS and MAX_QUEUE limits. - */ - } else { - /* determine how small a packet can be */ - minsize = (ep->freqn >> (16 - ep->datainterval)) * - (frame_bits >> 3); - /* with sync from device, assume it can be 12% lower */ - if (sync_ep) - minsize -= minsize >> 3; - minsize = max(minsize, 1u); - - /* how many packets will contain an entire ALSA period? */ - max_packs_per_period = DIV_ROUND_UP(period_bytes, minsize); - - /* how many URBs will contain a period? */ - urbs_per_period = DIV_ROUND_UP(max_packs_per_period, - max_packs_per_urb); - /* how many packets are needed in each URB? */ - urb_packs = DIV_ROUND_UP(max_packs_per_period, urbs_per_period); - - /* limit the number of frames in a single URB */ - ret = ret && (ep->max_urb_frames == - DIV_ROUND_UP(frames_per_period, urbs_per_period)); - - /* try to use enough URBs to contain an entire ALSA buffer */ - max_urbs = min((unsigned) MAX_URBS, - MAX_QUEUE * packs_per_ms / urb_packs); - ret = ret && (ep->nurbs == min(max_urbs, - urbs_per_period * periods_per_buffer)); - } - - ret = ret && (ep->datainterval == fmt->datainterval); - ret = ret && (ep->maxpacksize == fmt->maxpacksize); - ret = ret && - (ep->fill_max == !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)); - - return ret; -} - /* * configure a data endpoint */ -static int data_ep_set_params(struct snd_usb_endpoint *ep, - snd_pcm_format_t pcm_format, - unsigned int channels, - unsigned int period_bytes, - unsigned int frames_per_period, - unsigned int periods_per_buffer, - struct audioformat *fmt, - struct snd_usb_endpoint *sync_ep) +static int data_ep_set_params(struct snd_usb_endpoint *ep) { + struct snd_usb_audio *chip = ep->chip; unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb; unsigned int max_packs_per_period, urbs_per_period, urb_packs; unsigned int max_urbs, i; - int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels; - int tx_length_quirk = (ep->chip->tx_length_quirk && + const struct audioformat *fmt = ep->cur_audiofmt; + int frame_bits = ep->cur_frame_bytes * 8; + int tx_length_quirk = (chip->tx_length_quirk && usb_pipeout(ep->pipe)); - if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) { + usb_audio_dbg(chip, "Setting params for data EP 0x%x, pipe 0x%x\n", + ep->ep_num, ep->pipe); + + if (ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) { /* * When operating in DSD DOP mode, the size of a sample frame * in hardware differs from the actual physical format width * because we need to make room for the DOP markers. */ - frame_bits += channels << 3; + frame_bits += ep->cur_channels << 3; } ep->datainterval = fmt->datainterval; ep->stride = frame_bits >> 3; - switch (pcm_format) { + switch (ep->cur_format) { case SNDRV_PCM_FORMAT_U8: ep->silence_value = 0x80; break; @@ -911,16 +910,16 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, else ep->curpacksize = maxsize; - if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) { + if (snd_usb_get_speed(chip->dev) != USB_SPEED_FULL) { packs_per_ms = 8 >> ep->datainterval; max_packs_per_urb = MAX_PACKS_HS; } else { packs_per_ms = 1; max_packs_per_urb = MAX_PACKS; } - if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep)) + if (ep->sync_master && !ep->implicit_fb_sync) max_packs_per_urb = min(max_packs_per_urb, - 1U << sync_ep->syncinterval); + 1U << ep->sync_master->syncinterval); max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval); /* @@ -931,9 +930,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, * Playback endpoints with implicit sync much use the same parameters * as their corresponding capture endpoint. */ - if (usb_pipein(ep->pipe) || - ep->is_implicit_feedback || - snd_usb_endpoint_implicit_feedback_sink(ep)) { + if (usb_pipein(ep->pipe) || ep->implicit_fb_sync) { urb_packs = packs_per_ms; /* @@ -942,7 +939,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, * allow the host controller to use bursting to fill in the * gaps. */ - if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_WIRELESS) { + if (snd_usb_get_speed(chip->dev) == USB_SPEED_WIRELESS) { int interval = ep->datainterval; while (interval < 5) { urb_packs <<= 1; @@ -951,7 +948,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, } /* make capture URBs <= 1 ms and smaller than a period */ urb_packs = min(max_packs_per_urb, urb_packs); - while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) + while (urb_packs > 1 && urb_packs * maxsize >= ep->cur_period_bytes) urb_packs >>= 1; ep->nurbs = MAX_URBS; @@ -966,12 +963,12 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, minsize = (ep->freqn >> (16 - ep->datainterval)) * (frame_bits >> 3); /* with sync from device, assume it can be 12% lower */ - if (sync_ep) + if (ep->sync_master) minsize -= minsize >> 3; minsize = max(minsize, 1u); /* how many packets will contain an entire ALSA period? */ - max_packs_per_period = DIV_ROUND_UP(period_bytes, minsize); + max_packs_per_period = DIV_ROUND_UP(ep->cur_period_bytes, minsize); /* how many URBs will contain a period? */ urbs_per_period = DIV_ROUND_UP(max_packs_per_period, @@ -980,13 +977,13 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, urb_packs = DIV_ROUND_UP(max_packs_per_period, urbs_per_period); /* limit the number of frames in a single URB */ - ep->max_urb_frames = DIV_ROUND_UP(frames_per_period, - urbs_per_period); + ep->max_urb_frames = DIV_ROUND_UP(ep->cur_period_frames, + urbs_per_period); /* try to use enough URBs to contain an entire ALSA buffer */ max_urbs = min((unsigned) MAX_URBS, MAX_QUEUE * packs_per_ms / urb_packs); - ep->nurbs = min(max_urbs, urbs_per_period * periods_per_buffer); + ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods); } /* allocate and initialize data urbs */ @@ -1004,7 +1001,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, goto out_of_memory; u->urb->transfer_buffer = - usb_alloc_coherent(ep->chip->dev, u->buffer_size, + usb_alloc_coherent(chip->dev, u->buffer_size, GFP_KERNEL, &u->urb->transfer_dma); if (!u->urb->transfer_buffer) goto out_of_memory; @@ -1028,9 +1025,13 @@ out_of_memory: */ static int sync_ep_set_params(struct snd_usb_endpoint *ep) { + struct snd_usb_audio *chip = ep->chip; int i; - ep->syncbuf = usb_alloc_coherent(ep->chip->dev, SYNC_URBS * 4, + usb_audio_dbg(chip, "Setting params for sync EP 0x%x, pipe 0x%x\n", + ep->ep_num, ep->pipe); + + ep->syncbuf = usb_alloc_coherent(chip->dev, SYNC_URBS * 4, GFP_KERNEL, &ep->sync_dma); if (!ep->syncbuf) return -ENOMEM; @@ -1063,60 +1064,19 @@ out_of_memory: return -ENOMEM; } -/** +/* * snd_usb_endpoint_set_params: configure an snd_usb_endpoint * - * @ep: the snd_usb_endpoint to configure - * @pcm_format: the audio fomat. - * @channels: the number of audio channels. - * @period_bytes: the number of bytes in one alsa period. - * @period_frames: the number of frames in one alsa period. - * @buffer_periods: the number of periods in one alsa buffer. - * @rate: the frame rate. - * @fmt: the USB audio format information - * @sync_ep: the sync endpoint to use, if any - * * Determine the number of URBs to be used on this endpoint. * An endpoint must be configured before it can be started. * An endpoint that is already running can not be reconfigured. */ -int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, - snd_pcm_format_t pcm_format, - unsigned int channels, - unsigned int period_bytes, - unsigned int period_frames, - unsigned int buffer_periods, - unsigned int rate, - struct audioformat *fmt, - struct snd_usb_endpoint *sync_ep) +static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) { + const struct audioformat *fmt = ep->cur_audiofmt; int err; - usb_audio_dbg(ep->chip, - "Setting params for ep %x (type %s, count %d), rate=%d, format=%s, channels=%d, period_bytes=%d, periods=%d\n", - ep->ep_num, ep_type_name(ep->type), ep->use_count, - rate, snd_pcm_format_name(pcm_format), channels, - period_bytes, buffer_periods); - - if (ep->use_count != 0) { - bool check = ep->is_implicit_feedback && - check_ep_params(ep, pcm_format, channels, period_bytes, - period_frames, buffer_periods, rate, - fmt, sync_ep); - - if (!check) { - usb_audio_warn(ep->chip, - "Unable to change format on ep #%x: already in use\n", - ep->ep_num); - return -EBUSY; - } - - usb_audio_dbg(ep->chip, - "Ep #%x already in use as implicit feedback but format not changed\n", - ep->ep_num); - return 0; - } - /* release old buffers, if any */ release_urbs(ep, 0); @@ -1124,17 +1084,17 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, ep->maxpacksize = fmt->maxpacksize; ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX); - if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) { - ep->freqn = get_usb_full_speed_rate(rate); + if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL) { + ep->freqn = get_usb_full_speed_rate(ep->cur_rate); ep->pps = 1000 >> ep->datainterval; } else { - ep->freqn = get_usb_high_speed_rate(rate); + ep->freqn = get_usb_high_speed_rate(ep->cur_rate); ep->pps = 8000 >> ep->datainterval; } - ep->sample_rem = rate % ep->pps; - ep->packsize[0] = rate / ep->pps; - ep->packsize[1] = (rate + (ep->pps - 1)) / ep->pps; + ep->sample_rem = ep->cur_rate % ep->pps; + ep->packsize[0] = ep->cur_rate / ep->pps; + ep->packsize[1] = (ep->cur_rate + (ep->pps - 1)) / ep->pps; /* calculate the frequency in 16.16 format */ ep->freqm = ep->freqn; @@ -1144,9 +1104,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, switch (ep->type) { case SND_USB_ENDPOINT_TYPE_DATA: - err = data_ep_set_params(ep, pcm_format, channels, - period_bytes, period_frames, - buffer_periods, fmt, sync_ep); + err = data_ep_set_params(ep); break; case SND_USB_ENDPOINT_TYPE_SYNC: err = sync_ep_set_params(ep); @@ -1155,24 +1113,92 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, err = -EINVAL; } - usb_audio_dbg(ep->chip, "Set up %d URBS, ret=%d\n", ep->nurbs, err); + usb_audio_dbg(chip, "Set up %d URBS, ret=%d\n", ep->nurbs, err); if (err < 0) return err; - /* record the current set up in the endpoint (for implicit fb) */ - spin_lock_irq(&ep->lock); - ep->cur_rate = rate; - ep->cur_channels = channels; - ep->cur_format = pcm_format; - ep->cur_period_frames = period_frames; - ep->cur_period_bytes = period_bytes; - ep->cur_buffer_periods = buffer_periods; - spin_unlock_irq(&ep->lock); + /* some unit conversions in runtime */ + ep->maxframesize = ep->maxpacksize / ep->cur_frame_bytes; + ep->curframesize = ep->curpacksize / ep->cur_frame_bytes; return 0; } +/* + * snd_usb_endpoint_configure: Configure the endpoint + * + * This function sets up the EP to be fully usable state. + * It's called either from hw_params or prepare callback. + * The function checks need_setup flag, and perfoms nothing unless needed, + * so it's safe to call this multiple times. + * + * This returns zero if unchanged, 1 if the configuration has changed, + * or a negative error code. + */ +int snd_usb_endpoint_configure(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) +{ + bool iface_first; + int err = 0; + + mutex_lock(&chip->mutex); + if (!ep->need_setup) + goto unlock; + + /* No need to (re-)configure the sync EP belonging to the same altset */ + if (ep->ep_idx) { + err = snd_usb_endpoint_set_params(chip, ep); + if (err < 0) + goto unlock; + goto done; + } + + /* Need to deselect altsetting at first */ + endpoint_set_interface(chip, ep, false); + + /* Some UAC1 devices (e.g. Yamaha THR10) need the host interface + * to be set up before parameter setups + */ + iface_first = ep->cur_audiofmt->protocol == UAC_VERSION_1; + if (iface_first) { + err = endpoint_set_interface(chip, ep, true); + if (err < 0) + goto unlock; + } + + err = snd_usb_init_pitch(chip, ep->cur_audiofmt); + if (err < 0) + goto unlock; + + err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, ep->cur_rate); + if (err < 0) + goto unlock; + + err = snd_usb_endpoint_set_params(chip, ep); + if (err < 0) + goto unlock; + + err = snd_usb_select_mode_quirk(chip, ep->cur_audiofmt); + if (err < 0) + goto unlock; + + /* for UAC2/3, enable the interface altset here at last */ + if (!iface_first) { + err = endpoint_set_interface(chip, ep, true); + if (err < 0) + goto unlock; + } + + done: + ep->need_setup = false; + err = 1; + +unlock: + mutex_unlock(&chip->mutex); + return err; +} + /** * snd_usb_endpoint_start: start an snd_usb_endpoint * @@ -1194,6 +1220,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) if (atomic_read(&ep->chip->shutdown)) return -EBADFD; + if (ep->sync_master) + WRITE_ONCE(ep->sync_master->sync_slave, ep); + usb_audio_dbg(ep->chip, "Starting %s EP 0x%x (count %d)\n", ep_type_name(ep->type), ep->ep_num, ep->use_count); @@ -1226,6 +1255,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); } + usb_audio_dbg(ep->chip, "No URB submission due to implicit fb sync\n"); return 0; } @@ -1251,9 +1281,13 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) set_bit(i, &ep->active_mask); } + usb_audio_dbg(ep->chip, "%d URBs submitted for EP 0x%x\n", + ep->nurbs, ep->ep_num); return 0; __error: + if (ep->sync_master) + WRITE_ONCE(ep->sync_master->sync_slave, NULL); clear_bit(EP_FLAG_RUNNING, &ep->flags); ep->use_count--; deactivate_urbs(ep, false); @@ -1285,39 +1319,15 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) if (snd_BUG_ON(ep->use_count == 0)) return; + if (ep->sync_master) + WRITE_ONCE(ep->sync_master->sync_slave, NULL); + if (--ep->use_count == 0) { deactivate_urbs(ep, false); set_bit(EP_FLAG_STOPPING, &ep->flags); } } -/** - * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint - * - * @ep: the endpoint to deactivate - * - * If the endpoint is not currently in use, this functions will - * deactivate its associated URBs. - * - * In case of any active users, this functions does nothing. - */ -void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) -{ - if (!ep) - return; - - if (ep->use_count != 0) - return; - - deactivate_urbs(ep, true); - wait_clear_urbs(ep); - - /* clear the saved hw params */ - spin_lock_irq(&ep->lock); - ep->cur_rate = 0; - spin_unlock_irq(&ep->lock); -} - /** * snd_usb_endpoint_release: Tear down an snd_usb_endpoint * @@ -1343,7 +1353,7 @@ void snd_usb_endpoint_free(struct snd_usb_endpoint *ep) kfree(ep); } -/** +/* * snd_usb_handle_sync_urb: parse an USB sync packet * * @ep: the endpoint to handle the packet @@ -1353,9 +1363,9 @@ void snd_usb_endpoint_free(struct snd_usb_endpoint *ep) * This function is called from the context of an endpoint that received * the packet and is used to let another endpoint object handle the payload. */ -void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, - struct snd_usb_endpoint *sender, - const struct urb *urb) +static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, + struct snd_usb_endpoint *sender, + const struct urb *urb) { int shift; unsigned int f; diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index e2fddb3dcf7a..2bfa6d3e029c 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -10,16 +10,25 @@ struct snd_usb_endpoint *snd_usb_get_endpoint(struct snd_usb_audio *chip, int snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int type); -int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, - snd_pcm_format_t pcm_format, - unsigned int channels, - unsigned int period_bytes, - unsigned int period_frames, - unsigned int buffer_periods, - unsigned int rate, - struct audioformat *fmt, - struct snd_usb_endpoint *sync_ep); - +struct snd_usb_endpoint * +snd_usb_endpoint_open(struct snd_usb_audio *chip, + struct audioformat *fp, + const struct snd_pcm_hw_params *params, + bool is_sync_ep); +void snd_usb_endpoint_close(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep); +int snd_usb_endpoint_configure(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep); +void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep); + +bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep, + const struct audioformat *fp, + const struct snd_pcm_hw_params *params); + +void snd_usb_endpoint_set_sync(struct snd_usb_audio *chip, + struct snd_usb_endpoint *data_ep, + struct snd_usb_endpoint *sync_ep); void snd_usb_endpoint_set_callback(struct snd_usb_endpoint *ep, void (*prepare)(struct snd_usb_substream *subs, struct urb *urb), @@ -27,23 +36,16 @@ void snd_usb_endpoint_set_callback(struct snd_usb_endpoint *ep, struct urb *urb), struct snd_usb_substream *data_subs); -int snd_usb_endpoint_start(struct snd_usb_endpoint *ep); +int snd_usb_endpoint_start(struct snd_usb_endpoint *ep); void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep); void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); +void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep); int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); -void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); void snd_usb_endpoint_release(struct snd_usb_endpoint *ep); void snd_usb_endpoint_free(struct snd_usb_endpoint *ep); int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep); int snd_usb_endpoint_slave_next_packet_size(struct snd_usb_endpoint *ep); int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep); -void snd_usb_endpoint_set_syncinterval(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep, - struct usb_host_interface *alts); - -void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, - struct snd_usb_endpoint *sender, - const struct urb *urb); #endif /* __USBAUDIO_ENDPOINT_H */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 45a692512d27..e80e8cf1e863 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -80,21 +80,22 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream /* * find a matching audio format */ -static struct audioformat *find_format(struct list_head *fmt_list_head, - snd_pcm_format_t format, - unsigned int rate, - unsigned int channels, - struct snd_usb_substream *subs) +static struct audioformat * +find_format(struct list_head *fmt_list_head, snd_pcm_format_t format, + unsigned int rate, unsigned int channels, bool strict_match, + struct snd_usb_substream *subs) { struct audioformat *fp; struct audioformat *found = NULL; int cur_attr = 0, attr; list_for_each_entry(fp, fmt_list_head, list) { - if (!(fp->formats & pcm_format_to_bits(format))) - continue; - if (fp->channels != channels) - continue; + if (strict_match) { + if (!(fp->formats & pcm_format_to_bits(format))) + continue; + if (fp->channels != channels) + continue; + } if (rate < fp->rate_min || rate > fp->rate_max) continue; if (!(fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { @@ -140,38 +141,30 @@ static struct audioformat *find_format(struct list_head *fmt_list_head, return found; } -static struct audioformat *find_substream_format(struct snd_usb_substream *subs) +static struct audioformat * +find_substream_format(struct snd_usb_substream *subs, + const struct snd_pcm_hw_params *params) { - return find_format(&subs->fmt_list, subs->pcm_format, subs->cur_rate, - subs->channels, subs); + return find_format(&subs->fmt_list, params_format(params), + params_rate(params), params_channels(params), + true, subs); } -static int init_pitch_v1(struct snd_usb_audio *chip, - struct audioformat *fmt) +static int init_pitch_v1(struct snd_usb_audio *chip, int ep) { struct usb_device *dev = chip->dev; - unsigned int ep; unsigned char data[1]; int err; - ep = fmt->endpoint; - data[0] = 1; err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, data, sizeof(data)); - if (err < 0) { - usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n", - fmt->iface, ep); - return err; - } - - return 0; + return err; } -static int init_pitch_v2(struct snd_usb_audio *chip, - struct audioformat *fmt) +static int init_pitch_v2(struct snd_usb_audio *chip, int ep) { struct usb_device *dev = chip->dev; unsigned char data[1]; @@ -182,13 +175,7 @@ static int init_pitch_v2(struct snd_usb_audio *chip, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, UAC2_EP_CS_PITCH << 8, 0, data, sizeof(data)); - if (err < 0) { - usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n", - fmt->iface, fmt->altsetting); - return err; - } - - return 0; + return err; } /* @@ -197,29 +184,47 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int snd_usb_init_pitch(struct snd_usb_audio *chip, struct audioformat *fmt) { + int err; + /* if endpoint doesn't have pitch control, bail out */ if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL)) return 0; + usb_audio_dbg(chip, "enable PITCH for EP 0x%x\n", fmt->endpoint); + switch (fmt->protocol) { case UAC_VERSION_1: + err = init_pitch_v1(chip, fmt->endpoint); + break; + case UAC_VERSION_2: + err = init_pitch_v2(chip, fmt->endpoint); + break; default: - return init_pitch_v1(chip, fmt); + return 0; + } - case UAC_VERSION_2: - return init_pitch_v2(chip, fmt); + if (err < 0) { + usb_audio_err(chip, "failed to enable PITCH for EP 0x%x\n", + fmt->endpoint); + return err; } + + return 0; } -static void stop_endpoints(struct snd_usb_substream *subs) +static bool stop_endpoints(struct snd_usb_substream *subs) { + bool stopped = 0; + if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { snd_usb_endpoint_stop(subs->sync_endpoint); - subs->sync_endpoint->sync_slave = NULL; + stopped = true; } - - if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) + if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { snd_usb_endpoint_stop(subs->data_endpoint); + stopped = true; + } + return stopped; } static int start_endpoints(struct snd_usb_substream *subs) @@ -230,9 +235,7 @@ static int start_endpoints(struct snd_usb_substream *subs) return -EINVAL; if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { - struct snd_usb_endpoint *ep = subs->data_endpoint; - - err = snd_usb_endpoint_start(ep); + err = snd_usb_endpoint_start(subs->data_endpoint); if (err < 0) { clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); goto error; @@ -241,13 +244,9 @@ static int start_endpoints(struct snd_usb_substream *subs) if (subs->sync_endpoint && !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { - struct snd_usb_endpoint *ep = subs->sync_endpoint; - - ep->sync_slave = subs->data_endpoint; - err = snd_usb_endpoint_start(ep); + err = snd_usb_endpoint_start(subs->sync_endpoint); if (err < 0) { clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); - ep->sync_slave = NULL; goto error; } } @@ -446,6 +445,7 @@ add_sync_ep: fmt->sync_ep = ep; fmt->sync_iface = ifnum; fmt->sync_altsetting = alts->desc.bAlternateSetting; + fmt->sync_ep_idx = 0; fmt->implicit_fb = 1; dev_dbg(&dev->dev, "%d:%d: found implicit_fb sync_ep=%x, iface=%d, alt=%d\n", fmt->iface, fmt->altsetting, fmt->sync_ep, fmt->sync_iface, @@ -527,6 +527,7 @@ int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, fmt->sync_ep = ep; fmt->sync_iface = altsd->bInterfaceNumber; fmt->sync_altsetting = altsd->bAlternateSetting; + fmt->sync_ep_idx = 1; if ((sync_attr & USB_ENDPOINT_USAGE_MASK) == USB_ENDPOINT_USAGE_IMPLICIT_FB) fmt->implicit_fb = 1; @@ -537,152 +538,6 @@ int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, return 0; } -static int set_sync_endpoint(struct snd_usb_substream *subs, - struct audioformat *fmt) -{ - struct usb_device *dev = subs->dev; - struct usb_host_interface *alts; - struct snd_usb_audio *chip = subs->stream->chip; - int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; - unsigned int ep; - int err; - - subs->sync_endpoint = NULL; - subs->data_endpoint->sync_master = NULL; - - ep = fmt->sync_ep; - if (!ep) - return 0; - - alts = snd_usb_get_host_interface(subs->stream->chip, fmt->sync_iface, - fmt->altsetting); - if (!alts) - return 0; - - subs->sync_endpoint = snd_usb_get_endpoint(chip, ep); - if (!subs->sync_endpoint) { - if (is_playback && - (fmt->ep_attr & USB_ENDPOINT_SYNCTYPE) == USB_ENDPOINT_SYNC_NONE) - return 0; - return -EINVAL; - } - - subs->sync_endpoint->iface = fmt->sync_iface; - subs->sync_endpoint->altsetting = fmt->sync_altsetting; - subs->sync_endpoint->is_implicit_feedback = fmt->implicit_fb; - - subs->data_endpoint->sync_master = subs->sync_endpoint; - - snd_usb_endpoint_set_syncinterval(subs->stream->chip, subs->sync_endpoint, alts); - - if (!subs->sync_endpoint->use_count && - (subs->data_endpoint->iface != subs->sync_endpoint->iface || - subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting)) { - err = usb_set_interface(subs->dev, - subs->sync_endpoint->iface, - subs->sync_endpoint->altsetting); - if (err < 0) - return err; - dev_dbg(&dev->dev, "setting usb interface %d:%d\n", - subs->sync_endpoint->iface, - subs->sync_endpoint->altsetting); - snd_usb_set_interface_quirk(chip); - } - - return 0; -} - -/* - * find a matching format and set up the interface - */ -static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) -{ - struct usb_device *dev = subs->dev; - struct snd_usb_audio *chip = subs->stream->chip; - struct usb_host_interface *alts; - struct usb_interface *iface; - struct snd_usb_endpoint *ep; - int err; - - iface = usb_ifnum_to_if(dev, fmt->iface); - if (WARN_ON(!iface)) - return -EINVAL; - alts = usb_altnum_to_altsetting(iface, fmt->altsetting); - if (WARN_ON(!alts)) - return -EINVAL; - - if (fmt == subs->cur_audiofmt && !subs->need_setup_fmt) - return 0; - - /* shared EP with implicit fb */ - if (fmt->implicit_fb && !subs->need_setup_fmt) { - ep = snd_usb_get_endpoint(chip, fmt->endpoint); - if (ep && ep->use_count > 0) - goto add_data_ep; - } - - /* close the old interface */ - if (subs->interface >= 0 && (subs->interface != fmt->iface || subs->need_setup_fmt)) { - err = usb_set_interface(subs->dev, subs->interface, 0); - if (err < 0) { - dev_err(&dev->dev, - "%d:%d: return to setting 0 failed (%d)\n", - fmt->iface, fmt->altsetting, err); - return -EIO; - } - subs->interface = -1; - subs->altset_idx = 0; - } - - if (subs->need_setup_fmt) - subs->need_setup_fmt = false; - - /* set interface */ - if (iface->cur_altsetting != alts) { - err = snd_usb_select_mode_quirk(chip, fmt); - if (err < 0) - return -EIO; - - err = usb_set_interface(dev, fmt->iface, fmt->altsetting); - if (err < 0) { - dev_err(&dev->dev, - "%d:%d: usb_set_interface failed (%d)\n", - fmt->iface, fmt->altsetting, err); - return -EIO; - } - dev_dbg(&dev->dev, "setting usb interface %d:%d\n", - fmt->iface, fmt->altsetting); - snd_usb_set_interface_quirk(chip); - } - - subs->need_setup_ep = true; - - add_data_ep: - subs->interface = fmt->iface; - subs->altset_idx = fmt->altset_idx; - subs->data_endpoint = snd_usb_get_endpoint(chip, fmt->endpoint); - if (!subs->data_endpoint) - return -EINVAL; - subs->data_endpoint->iface = fmt->iface; - subs->data_endpoint->altsetting = fmt->altsetting; - - err = set_sync_endpoint(subs, fmt); - if (err < 0) - return err; - - if (subs->need_setup_ep) { - err = snd_usb_init_pitch(chip, fmt); - if (err < 0) - return err; - } - - subs->cur_audiofmt = fmt; - - snd_usb_set_format_quirk(subs, fmt); - - return 0; -} - /* * Return the score of matching two audioformats. * Veto the audioformat if: @@ -691,8 +546,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) * - Requested sample rate is not supported. */ static int match_endpoint_audioformats(struct snd_usb_substream *subs, - struct audioformat *fp, - struct audioformat *match, int rate, + const struct audioformat *fp, + int rate, int channels, snd_pcm_format_t pcm_format) { int i, score; @@ -716,108 +571,12 @@ static int match_endpoint_audioformats(struct snd_usb_substream *subs, } score = 1; - if (fp->channels == match->channels) + if (fp->channels == channels) score++; return score; } -/* - * Configure the sync ep using the rate and pcm format of the data ep. - */ -static int configure_sync_endpoint(struct snd_usb_substream *subs) -{ - struct audioformat *fp; - struct audioformat *sync_fp = NULL; - int cur_score = 0; - int sync_period_bytes = subs->period_bytes; - struct snd_usb_substream *sync_subs = - &subs->stream->substream[subs->direction ^ 1]; - - if (subs->fixed_hw || - !subs->sync_endpoint->is_implicit_feedback) { - sync_fp = subs->cur_audiofmt; - goto configure; - } - - sync_fp = find_format(&sync_subs->fmt_list, subs->pcm_format, - subs->cur_rate, subs->channels, NULL); - if (sync_fp) - goto configure; - - /* Try to find the best matching audioformat. */ - list_for_each_entry(fp, &sync_subs->fmt_list, list) { - int score = match_endpoint_audioformats(subs, - fp, subs->cur_audiofmt, - subs->cur_rate, subs->pcm_format); - - if (score > cur_score) { - sync_fp = fp; - cur_score = score; - } - } - - if (unlikely(sync_fp == NULL)) { - dev_err(&subs->dev->dev, - "%s: no valid audioformat for sync ep %x found\n", - __func__, sync_subs->ep_num); - return -EINVAL; - } - - /* - * Recalculate the period bytes if channel number differ between - * data and sync ep audioformat. - */ - if (sync_fp->channels != subs->channels) { - sync_period_bytes = (subs->period_bytes / subs->channels) * - sync_fp->channels; - dev_dbg(&subs->dev->dev, - "%s: adjusted sync ep period bytes (%d -> %d)\n", - __func__, subs->period_bytes, sync_period_bytes); - } - - configure: - return snd_usb_endpoint_set_params(subs->sync_endpoint, - subs->pcm_format, - sync_fp->channels, - sync_period_bytes, - subs->period_frames, - subs->buffer_periods, - subs->cur_rate, - sync_fp, - NULL); -} - -/* - * configure endpoint params - * - * called during initial setup and upon resume - */ -static int configure_endpoint(struct snd_usb_substream *subs) -{ - int ret; - - /* format changed */ - stop_endpoints(subs); - sync_pending_stops(subs); - ret = snd_usb_endpoint_set_params(subs->data_endpoint, - subs->pcm_format, - subs->channels, - subs->period_bytes, - subs->period_frames, - subs->buffer_periods, - subs->cur_rate, - subs->cur_audiofmt, - subs->sync_endpoint); - if (ret < 0) - return ret; - - if (subs->sync_endpoint) - ret = configure_sync_endpoint(subs); - - return ret; -} - static int snd_usb_pcm_change_state(struct snd_usb_substream *subs, int state) { int ret; @@ -866,6 +625,92 @@ int snd_usb_pcm_resume(struct snd_usb_stream *as) return 0; } +static struct snd_usb_substream * +find_matching_substream(struct snd_usb_audio *chip, int stream, int ep_num, + int fmt_type) +{ + struct snd_usb_stream *as; + struct snd_usb_substream *subs; + + list_for_each_entry(as, &chip->pcm_list, list) { + subs = &as->substream[stream]; + if (as->fmt_type == fmt_type && subs->ep_num == ep_num) + return subs; + } + + return NULL; +} + +static struct audioformat * +find_implicit_fb_sync_format(struct snd_usb_audio *chip, + const struct audioformat *target, + const struct snd_pcm_hw_params *params, + int stream) +{ + struct snd_usb_substream *subs; + struct audioformat *fp, *sync_fmt; + int score, high_score; + + subs = find_matching_substream(chip, stream, target->sync_ep, + target->fmt_type); + if (!subs) + return NULL; + + sync_fmt = NULL; + high_score = 0; + list_for_each_entry(fp, &subs->fmt_list, list) { + score = match_endpoint_audioformats(subs, fp, + params_rate(params), + params_channels(params), + params_format(params)); + if (score > high_score) { + sync_fmt = fp; + high_score = score; + } + } + + return sync_fmt; +} + +static void close_endpoints(struct snd_usb_audio *chip, + struct snd_usb_substream *subs) +{ + if (subs->data_endpoint) { + snd_usb_endpoint_set_sync(chip, subs->data_endpoint, NULL); + snd_usb_endpoint_close(chip, subs->data_endpoint); + subs->data_endpoint = NULL; + } + + if (subs->sync_endpoint) { + snd_usb_endpoint_close(chip, subs->sync_endpoint); + subs->sync_endpoint = NULL; + } +} + +static int configure_endpoints(struct snd_usb_audio *chip, + struct snd_usb_substream *subs) +{ + int err; + + if (subs->data_endpoint->need_setup) { + /* stop any running stream beforehand */ + if (stop_endpoints(subs)) + sync_pending_stops(subs); + err = snd_usb_endpoint_configure(chip, subs->data_endpoint); + if (err < 0) + return err; + snd_usb_set_format_quirk(subs, subs->cur_audiofmt); + } + + if (subs->sync_endpoint) { + err = snd_usb_endpoint_configure(chip, subs->sync_endpoint); + if (err < 0) + return err; + } + + return 0; +} + /* * hw_params callback * @@ -880,30 +725,45 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_usb_substream *subs = substream->runtime->private_data; + struct snd_usb_audio *chip = subs->stream->chip; struct audioformat *fmt; + struct audioformat *sync_fmt; int ret; ret = snd_media_start_pipeline(subs); if (ret) return ret; - subs->pcm_format = params_format(hw_params); - subs->period_bytes = params_period_bytes(hw_params); - subs->period_frames = params_period_size(hw_params); - subs->buffer_periods = params_periods(hw_params); - subs->channels = params_channels(hw_params); - subs->cur_rate = params_rate(hw_params); - - fmt = find_substream_format(subs); + fmt = find_substream_format(subs, hw_params); if (!fmt) { - dev_dbg(&subs->dev->dev, - "cannot set format: format = %#x, rate = %d, channels = %d\n", - subs->pcm_format, subs->cur_rate, subs->channels); + usb_audio_dbg(chip, + "cannot find format: format=%s, rate=%d, channels=%d\n", + snd_pcm_format_name(params_format(hw_params)), + params_rate(hw_params), params_channels(hw_params)); ret = -EINVAL; goto stop_pipeline; } - ret = snd_usb_lock_shutdown(subs->stream->chip); + if (fmt->implicit_fb && + (fmt->iface != fmt->sync_iface || + fmt->altsetting != fmt->sync_altsetting)) { + sync_fmt = find_implicit_fb_sync_format(chip, fmt, hw_params, + !substream->stream); + if (!sync_fmt) { + usb_audio_dbg(chip, + "cannot find sync format: ep=0x%x, iface=%d:%d, format=%s, rate=%d, channels=%d\n", + fmt->sync_ep, fmt->sync_iface, + fmt->sync_altsetting, + snd_pcm_format_name(params_format(hw_params)), + params_rate(hw_params), params_channels(hw_params)); + ret = -EINVAL; + goto stop_pipeline; + } + } else { + sync_fmt = fmt; + } + + ret = snd_usb_lock_shutdown(chip); if (ret < 0) goto stop_pipeline; @@ -911,18 +771,56 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto unlock; - ret = set_format(subs, fmt); + if (subs->data_endpoint) { + if (snd_usb_endpoint_compatible(chip, subs->data_endpoint, + fmt, hw_params)) + goto unlock; + close_endpoints(chip, subs); + } + + subs->data_endpoint = snd_usb_endpoint_open(chip, fmt, hw_params, false); + if (!subs->data_endpoint) { + ret = -EINVAL; + goto unlock; + } + + if (fmt->sync_ep) { + subs->sync_endpoint = snd_usb_endpoint_open(chip, sync_fmt, + hw_params, + fmt == sync_fmt); + if (!subs->sync_endpoint) { + ret = -EINVAL; + goto unlock; + } + + snd_usb_endpoint_set_sync(chip, subs->data_endpoint, + subs->sync_endpoint); + } + + subs->interface = fmt->iface; + subs->altset_idx = fmt->altset_idx; + subs->cur_audiofmt = fmt; + + ret = configure_endpoints(chip, subs); if (ret < 0) goto unlock; + subs->pcm_format = params_format(hw_params); + subs->period_bytes = params_period_bytes(hw_params); + subs->period_frames = params_period_size(hw_params); + subs->buffer_periods = params_periods(hw_params); + subs->channels = params_channels(hw_params); + subs->cur_rate = params_rate(hw_params); + unlock: - snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) - goto stop_pipeline; - return ret; + close_endpoints(chip, subs); + snd_usb_unlock_shutdown(chip); stop_pipeline: - snd_media_stop_pipeline(subs); + if (ret < 0) + snd_media_stop_pipeline(subs); + return ret; } @@ -941,15 +839,9 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->cur_rate = 0; subs->period_bytes = 0; if (!snd_usb_lock_shutdown(chip)) { - stop_endpoints(subs); - sync_pending_stops(subs); - snd_usb_endpoint_deactivate(subs->sync_endpoint); - snd_usb_endpoint_deactivate(subs->data_endpoint); - if (subs->data_endpoint) { - subs->data_endpoint->sync_master = NULL; - subs->data_endpoint = NULL; - } - subs->sync_endpoint = NULL; + if (stop_endpoints(subs)) + sync_pending_stops(subs); + close_endpoints(chip, subs); snd_usb_unlock_shutdown(chip); } @@ -965,16 +857,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = runtime->private_data; - struct usb_host_interface *alts; - struct usb_interface *iface; + struct snd_usb_audio *chip = subs->stream->chip; int ret; - if (! subs->cur_audiofmt) { - dev_err(&subs->dev->dev, "no format is specified!\n"); - return -ENXIO; - } - - ret = snd_usb_lock_shutdown(subs->stream->chip); + ret = snd_usb_lock_shutdown(chip); if (ret < 0) return ret; if (snd_BUG_ON(!subs->data_endpoint)) { @@ -982,36 +868,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } - ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); - if (ret < 0) - goto unlock; - - ret = set_format(subs, subs->cur_audiofmt); + ret = configure_endpoints(chip, subs); if (ret < 0) goto unlock; - if (subs->need_setup_ep) { - - iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); - alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; - ret = snd_usb_init_sample_rate(subs->stream->chip, - subs->cur_audiofmt, - subs->cur_rate); - if (ret < 0) - goto unlock; - - ret = configure_endpoint(subs); - if (ret < 0) - goto unlock; - subs->need_setup_ep = false; - } - - /* some unit conversions in runtime */ - subs->data_endpoint->maxframesize = - bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); - subs->data_endpoint->curframesize = - bytes_to_frames(runtime, subs->data_endpoint->curpacksize); - /* reset the pointer */ subs->hwptr_done = 0; subs->transfer_done = 0; @@ -1025,7 +885,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) ret = start_endpoints(subs); unlock: - snd_usb_unlock_shutdown(subs->stream->chip); + snd_usb_unlock_shutdown(chip); return ret; } @@ -1047,6 +907,8 @@ static const struct snd_pcm_hardware snd_usb_hardware = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE, + .channels_min = 1, + .channels_max = 256, .buffer_bytes_max = 1024 * 1024, .period_bytes_min = 64, .period_bytes_max = 512 * 1024, @@ -1250,7 +1112,6 @@ static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime, struct audioformat *fp; int err; - subs->fixed_hw = 0; list_for_each_entry(fp, &subs->fmt_list, list) { ep = snd_usb_get_endpoint(chip, fp->endpoint); if (ep && ep->cur_rate) @@ -1266,7 +1127,7 @@ static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime, found: if (!find_format(&subs->fmt_list, ep->cur_format, ep->cur_rate, - ep->cur_channels, NULL)) { + ep->cur_channels, false, NULL)) { usb_audio_dbg(chip, "EP 0x%x being used, but not applicable\n", ep->ep_num); return 0; @@ -1274,19 +1135,23 @@ static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime, usb_audio_dbg(chip, "EP 0x%x being used, using fixed params:\n", ep->ep_num); - usb_audio_dbg(chip, "rate=%d, format=%s, channels=%d, period_size=%d, periods=%d\n", - ep->cur_rate, snd_pcm_format_name(ep->cur_format), - ep->cur_channels, ep->cur_period_frames, + usb_audio_dbg(chip, "rate=%d, period_size=%d, periods=%d\n", + ep->cur_rate, ep->cur_period_frames, ep->cur_buffer_periods); - runtime->hw.formats = pcm_format_to_bits(ep->cur_format); + runtime->hw.formats = subs->formats; runtime->hw.rate_min = runtime->hw.rate_max = ep->cur_rate; - runtime->hw.channels_min = runtime->hw.channels_max = - ep->cur_channels; runtime->hw.rates = SNDRV_PCM_RATE_KNOT; runtime->hw.periods_min = runtime->hw.periods_max = ep->cur_buffer_periods; - subs->fixed_hw = 1; + + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_channels, subs, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_RATE, + -1); + if (err < 0) + return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, @@ -1442,9 +1307,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) snd_media_stop_pipeline(subs); - if (subs->interface >= 0 && - !snd_usb_lock_shutdown(subs->stream->chip)) { - usb_set_interface(subs->dev, subs->interface, 0); + if (!snd_usb_lock_shutdown(subs->stream->chip)) { subs->interface = -1; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1); snd_usb_unlock_shutdown(subs->stream->chip); @@ -1823,15 +1686,19 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea retire_playback_urb, subs); subs->running = 1; + dev_dbg(&subs->dev->dev, "%d:%d Start Playback PCM\n", + subs->cur_audiofmt->iface, + subs->cur_audiofmt->altsetting); return 0; case SNDRV_PCM_TRIGGER_SUSPEND: - subs->need_setup_fmt = true; - fallthrough; case SNDRV_PCM_TRIGGER_STOP: stop_endpoints(subs); snd_usb_endpoint_set_callback(subs->data_endpoint, NULL, NULL, NULL); subs->running = 0; + dev_dbg(&subs->dev->dev, "%d:%d Stop Playback PCM\n", + subs->cur_audiofmt->iface, + subs->cur_audiofmt->altsetting); return 0; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* keep retire_data_urb for delay calculation */ @@ -1840,6 +1707,9 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea retire_playback_urb, subs); subs->running = 0; + dev_dbg(&subs->dev->dev, "%d:%d Pause Playback PCM\n", + subs->cur_audiofmt->iface, + subs->cur_audiofmt->altsetting); return 0; } @@ -1863,10 +1733,11 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream NULL, retire_capture_urb, subs); subs->running = 1; + dev_dbg(&subs->dev->dev, "%d:%d Start Capture PCM\n", + subs->cur_audiofmt->iface, + subs->cur_audiofmt->altsetting); return 0; case SNDRV_PCM_TRIGGER_SUSPEND: - subs->need_setup_fmt = true; - fallthrough; case SNDRV_PCM_TRIGGER_STOP: stop_endpoints(subs); fallthrough; @@ -1874,6 +1745,9 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream snd_usb_endpoint_set_callback(subs->data_endpoint, NULL, NULL, NULL); subs->running = 0; + dev_dbg(&subs->dev->dev, "%d:%d Stop Capture PCM\n", + subs->cur_audiofmt->iface, + subs->cur_audiofmt->altsetting); return 0; } -- cgit v1.2.3 From c15871e17fc6efb98176b92b4152019876dbec24 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:32 +0100 Subject: ALSA: usb-audio: Fix possible stall of implicit fb packet ring-buffer The implicit feedback mode uses a ring buffer for storing the received packet sizes from the feedback source, and the code has a slight flaw; when a playback stream stalls by some reason and the URBs aren't processed, the next_packet FIFO might become empty, but the driver can't distinguish whether it's empty or full because it's managed with read_poss and write_pos. This patch addresses those by changing the next_packet array management. Instead of keeping read and write positions, now the head position and the queued amount are kept. It's easier to understand about the emptiness. Also, the URB active flag is now cleared before calling queue_pending_output_urbs() for avoiding (theoretically) possible inconsistency. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-27-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.h | 5 ++-- sound/usb/endpoint.c | 83 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index 66a249ae138f..cde492e9581a 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -80,8 +80,9 @@ struct snd_usb_endpoint { uint32_t packet_size[MAX_PACKS_HS]; int packets; } next_packet[MAX_URBS]; - int next_packet_read_pos, next_packet_write_pos; - struct list_head ready_playback_urbs; + unsigned int next_packet_head; /* ring buffer offset to read */ + unsigned int next_packet_queued; /* queued items in the ring buffer */ + struct list_head ready_playback_urbs; /* playback URB FIFO for implicit fb */ unsigned int nurbs; /* # urbs */ unsigned long active_mask; /* bitmask of active urbs */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index eee74313603e..b8f06a75fc2a 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -328,6 +328,39 @@ static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep, } } +/* notify an error as XRUN to the assigned PCM data substream */ +static void notify_xrun(struct snd_usb_endpoint *ep) +{ + struct snd_usb_substream *data_subs; + + data_subs = READ_ONCE(ep->data_subs); + if (data_subs && data_subs->pcm_substream) + snd_pcm_stop_xrun(data_subs->pcm_substream); +} + +static struct snd_usb_packet_info * +next_packet_fifo_enqueue(struct snd_usb_endpoint *ep) +{ + struct snd_usb_packet_info *p; + + p = ep->next_packet + (ep->next_packet_head + ep->next_packet_queued) % + ARRAY_SIZE(ep->next_packet); + ep->next_packet_queued++; + return p; +} + +static struct snd_usb_packet_info * +next_packet_fifo_dequeue(struct snd_usb_endpoint *ep) +{ + struct snd_usb_packet_info *p; + + p = ep->next_packet + ep->next_packet_head; + ep->next_packet_head++; + ep->next_packet_head %= ARRAY_SIZE(ep->next_packet); + ep->next_packet_queued--; + return p; +} + /* * Send output urbs that have been prepared previously. URBs are dequeued * from ep->ready_playback_urbs and in case there aren't any available @@ -352,17 +385,14 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) int err, i; spin_lock_irqsave(&ep->lock, flags); - if (ep->next_packet_read_pos != ep->next_packet_write_pos) { - packet = ep->next_packet + ep->next_packet_read_pos; - ep->next_packet_read_pos++; - ep->next_packet_read_pos %= MAX_URBS; - + if (ep->next_packet_queued > 0 && + !list_empty(&ep->ready_playback_urbs)) { /* take URB out of FIFO */ - if (!list_empty(&ep->ready_playback_urbs)) { - ctx = list_first_entry(&ep->ready_playback_urbs, + ctx = list_first_entry(&ep->ready_playback_urbs, struct snd_urb_ctx, ready_list); - list_del_init(&ctx->ready_list); - } + list_del_init(&ctx->ready_list); + + packet = next_packet_fifo_dequeue(ep); } spin_unlock_irqrestore(&ep->lock, flags); @@ -377,12 +407,15 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) prepare_outbound_urb(ep, ctx); err = usb_submit_urb(ctx->urb, GFP_ATOMIC); - if (err < 0) + if (err < 0) { usb_audio_err(ep->chip, "Unable to submit urb #%d: %d at %s\n", ctx->index, err, __func__); - else - set_bit(ctx->index, &ep->active_mask); + notify_xrun(ep); + return; + } + + set_bit(ctx->index, &ep->active_mask); } } @@ -393,7 +426,6 @@ static void snd_complete_urb(struct urb *urb) { struct snd_urb_ctx *ctx = urb->context; struct snd_usb_endpoint *ep = ctx->ep; - struct snd_usb_substream *data_subs; unsigned long flags; int err; @@ -418,10 +450,10 @@ static void snd_complete_urb(struct urb *urb) if (snd_usb_endpoint_implicit_feedback_sink(ep)) { spin_lock_irqsave(&ep->lock, flags); list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); + clear_bit(ctx->index, &ep->active_mask); spin_unlock_irqrestore(&ep->lock, flags); queue_pending_output_urbs(ep); - - goto exit_clear; + return; } prepare_outbound_urb(ep, ctx); @@ -442,9 +474,7 @@ static void snd_complete_urb(struct urb *urb) return; usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err); - data_subs = READ_ONCE(ep->data_subs); - if (data_subs && data_subs->pcm_substream) - snd_pcm_stop_xrun(data_subs->pcm_substream); + notify_xrun(ep); exit_clear: clear_bit(ctx->index, &ep->active_mask); @@ -789,8 +819,8 @@ static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force) clear_bit(EP_FLAG_RUNNING, &ep->flags); INIT_LIST_HEAD(&ep->ready_playback_urbs); - ep->next_packet_read_pos = 0; - ep->next_packet_write_pos = 0; + ep->next_packet_head = 0; + ep->next_packet_queued = 0; for (i = 0; i < ep->nurbs; i++) { if (test_bit(i, &ep->active_mask)) { @@ -1402,7 +1432,16 @@ static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, return; spin_lock_irqsave(&ep->lock, flags); - out_packet = ep->next_packet + ep->next_packet_write_pos; + if (ep->next_packet_queued >= ARRAY_SIZE(ep->next_packet)) { + spin_unlock_irqrestore(&ep->lock, flags); + usb_audio_err(ep->chip, + "next package FIFO overflow EP 0x%x\n", + ep->ep_num); + notify_xrun(ep); + return; + } + + out_packet = next_packet_fifo_enqueue(ep); /* * Iterate through the inbound packet and prepare the lengths @@ -1423,8 +1462,6 @@ static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, out_packet->packet_size[i] = 0; } - ep->next_packet_write_pos++; - ep->next_packet_write_pos %= MAX_URBS; spin_unlock_irqrestore(&ep->lock, flags); queue_pending_output_urbs(ep); -- cgit v1.2.3 From cab941b7e5cf054502b01f776db724400ee5c1b6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:33 +0100 Subject: ALSA: usb-audio: Constify audioformat pointer references The audioformat is referred in many places but most of usages are read-only. Let's add const prefix in the possible places. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-28-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.h | 4 ++-- sound/usb/clock.c | 16 ++++++++-------- sound/usb/clock.h | 4 ++-- sound/usb/endpoint.c | 2 +- sound/usb/endpoint.h | 2 +- sound/usb/pcm.c | 32 ++++++++++++++++---------------- sound/usb/pcm.h | 2 +- sound/usb/quirks.c | 9 +++++---- sound/usb/quirks.h | 6 +++--- 9 files changed, 39 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index cde492e9581a..53f0ce61f858 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -120,7 +120,7 @@ struct snd_usb_endpoint { bool need_setup; /* (re-)need for configure? */ /* for hw constraints */ - struct audioformat *cur_audiofmt; + const struct audioformat *cur_audiofmt; unsigned int cur_rate; snd_pcm_format_t cur_format; unsigned int cur_channels; @@ -142,7 +142,7 @@ struct snd_usb_substream { int direction; /* playback or capture */ int interface; /* current interface */ int endpoint; /* assigned endpoint */ - struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ + const struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ struct snd_usb_power_domain *str_pd; /* UAC3 Power Domain for streaming path */ snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ unsigned int channels; /* current number of channels (for hw_params callback) */ diff --git a/sound/usb/clock.c b/sound/usb/clock.c index b869a711afbf..e940dcee792b 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -152,7 +152,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i } static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, - struct audioformat *fmt, + const struct audioformat *fmt, int source_id) { bool ret = false; @@ -215,7 +215,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, } static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, - struct audioformat *fmt, + const struct audioformat *fmt, int source_id) { int err; @@ -264,7 +264,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, } static int __uac_clock_find_source(struct snd_usb_audio *chip, - struct audioformat *fmt, int entity_id, + const struct audioformat *fmt, int entity_id, unsigned long *visited, bool validate) { struct uac_clock_source_descriptor *source; @@ -358,7 +358,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, } static int __uac3_clock_find_source(struct snd_usb_audio *chip, - struct audioformat *fmt, int entity_id, + const struct audioformat *fmt, int entity_id, unsigned long *visited, bool validate) { struct uac3_clock_source_descriptor *source; @@ -464,7 +464,7 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, * Returns the clock source UnitID (>=0) on success, or an error. */ int snd_usb_clock_find_source(struct snd_usb_audio *chip, - struct audioformat *fmt, bool validate) + const struct audioformat *fmt, bool validate) { DECLARE_BITMAP(visited, 256); memset(visited, 0, sizeof(visited)); @@ -482,7 +482,7 @@ int snd_usb_clock_find_source(struct snd_usb_audio *chip, } static int set_sample_rate_v1(struct snd_usb_audio *chip, - struct audioformat *fmt, int rate) + const struct audioformat *fmt, int rate) { struct usb_device *dev = chip->dev; struct usb_host_interface *alts; @@ -611,7 +611,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, } static int set_sample_rate_v2v3(struct snd_usb_audio *chip, - struct audioformat *fmt, int rate) + const struct audioformat *fmt, int rate) { int cur_rate, prev_rate; int clock; @@ -663,7 +663,7 @@ validation: } int snd_usb_init_sample_rate(struct snd_usb_audio *chip, - struct audioformat *fmt, int rate) + const struct audioformat *fmt, int rate) { usb_audio_dbg(chip, "%d:%d Set sample rate %d, clock %d\n", fmt->iface, fmt->altsetting, rate, fmt->clock); diff --git a/sound/usb/clock.h b/sound/usb/clock.h index 8d406ed294d6..ed9fc2dc0510 100644 --- a/sound/usb/clock.h +++ b/sound/usb/clock.h @@ -3,10 +3,10 @@ #define __USBAUDIO_CLOCK_H int snd_usb_init_sample_rate(struct snd_usb_audio *chip, - struct audioformat *fmt, int rate); + const struct audioformat *fmt, int rate); int snd_usb_clock_find_source(struct snd_usb_audio *chip, - struct audioformat *fmt, bool validate); + const struct audioformat *fmt, bool validate); int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, const struct audioformat *fmt, diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index b8f06a75fc2a..49fb934ee432 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -623,7 +623,7 @@ bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, */ struct snd_usb_endpoint * snd_usb_endpoint_open(struct snd_usb_audio *chip, - struct audioformat *fp, + const struct audioformat *fp, const struct snd_pcm_hw_params *params, bool is_sync_ep) { diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 2bfa6d3e029c..201011d89659 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -12,7 +12,7 @@ int snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int type); struct snd_usb_endpoint * snd_usb_endpoint_open(struct snd_usb_audio *chip, - struct audioformat *fp, + const struct audioformat *fp, const struct snd_pcm_hw_params *params, bool is_sync_ep); void snd_usb_endpoint_close(struct snd_usb_audio *chip, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index e80e8cf1e863..fc028492dd1a 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -80,13 +80,13 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream /* * find a matching audio format */ -static struct audioformat * +static const struct audioformat * find_format(struct list_head *fmt_list_head, snd_pcm_format_t format, unsigned int rate, unsigned int channels, bool strict_match, struct snd_usb_substream *subs) { - struct audioformat *fp; - struct audioformat *found = NULL; + const struct audioformat *fp; + const struct audioformat *found = NULL; int cur_attr = 0, attr; list_for_each_entry(fp, fmt_list_head, list) { @@ -141,7 +141,7 @@ find_format(struct list_head *fmt_list_head, snd_pcm_format_t format, return found; } -static struct audioformat * +static const struct audioformat * find_substream_format(struct snd_usb_substream *subs, const struct snd_pcm_hw_params *params) { @@ -182,7 +182,7 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int ep) * initialize the pitch control and sample rate */ int snd_usb_init_pitch(struct snd_usb_audio *chip, - struct audioformat *fmt) + const struct audioformat *fmt) { int err; @@ -641,14 +641,14 @@ find_matching_substream(struct snd_usb_audio *chip, int stream, int ep_num, return NULL; } -static struct audioformat * +static const struct audioformat * find_implicit_fb_sync_format(struct snd_usb_audio *chip, const struct audioformat *target, const struct snd_pcm_hw_params *params, int stream) { struct snd_usb_substream *subs; - struct audioformat *fp, *sync_fmt; + const struct audioformat *fp, *sync_fmt; int score, high_score; subs = find_matching_substream(chip, stream, target->sync_ep, @@ -726,8 +726,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, { struct snd_usb_substream *subs = substream->runtime->private_data; struct snd_usb_audio *chip = subs->stream->chip; - struct audioformat *fmt; - struct audioformat *sync_fmt; + const struct audioformat *fmt; + const struct audioformat *sync_fmt; int ret; ret = snd_media_start_pipeline(subs); @@ -918,7 +918,7 @@ static const struct snd_pcm_hardware snd_usb_hardware = static int hw_check_valid_format(struct snd_usb_substream *subs, struct snd_pcm_hw_params *params, - struct audioformat *fp) + const struct audioformat *fp) { struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); @@ -995,7 +995,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_usb_substream *subs = rule->private; - struct audioformat *fp; + const struct audioformat *fp; struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); unsigned int rmin, rmax, r; int i; @@ -1028,7 +1028,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_usb_substream *subs = rule->private; - struct audioformat *fp; + const struct audioformat *fp; struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); unsigned int rmin, rmax; @@ -1049,7 +1049,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_usb_substream *subs = rule->private; - struct audioformat *fp; + const struct audioformat *fp; struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); u64 fbits; u32 oldbits[2]; @@ -1080,7 +1080,7 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_usb_substream *subs = rule->private; - struct audioformat *fp; + const struct audioformat *fp; struct snd_interval *it; unsigned char min_datainterval; unsigned int pmin; @@ -1109,7 +1109,7 @@ static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime, { struct snd_usb_audio *chip = subs->stream->chip; struct snd_usb_endpoint *ep; - struct audioformat *fp; + const struct audioformat *fp; int err; list_for_each_entry(fp, &subs->fmt_list, list) { @@ -1170,7 +1170,7 @@ static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime, static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) { struct snd_usb_audio *chip = subs->stream->chip; - struct audioformat *fp; + const struct audioformat *fp; unsigned int pt, ptmin; int param_period_time_if_needed = -1; int err; diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index a4f784225abc..06c586467d3f 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -10,7 +10,7 @@ int snd_usb_pcm_suspend(struct snd_usb_stream *as); int snd_usb_pcm_resume(struct snd_usb_stream *as); int snd_usb_init_pitch(struct snd_usb_audio *chip, - struct audioformat *fmt); + const struct audioformat *fmt); void snd_usb_preallocate_buffer(struct snd_usb_substream *subs); int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 7e7f258011ff..5510c8a98447 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1375,7 +1375,8 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev, /* * check if the device uses big-endian samples */ -int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp) +int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, + const struct audioformat *fp) { /* it depends on altsetting whether the device is big-endian or not */ switch (chip->usb_id) { @@ -1414,7 +1415,7 @@ enum { }; static void set_format_emu_quirk(struct snd_usb_substream *subs, - struct audioformat *fmt) + const struct audioformat *fmt) { unsigned char emu_samplerate_id = 0; @@ -1476,7 +1477,7 @@ static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs) } void snd_usb_set_format_quirk(struct snd_usb_substream *subs, - struct audioformat *fmt) + const struct audioformat *fmt) { switch (subs->stream->chip->usb_id) { case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ @@ -1543,7 +1544,7 @@ static bool is_itf_usb_dsd_dac(unsigned int id) } int snd_usb_select_mode_quirk(struct snd_usb_audio *chip, - struct audioformat *fmt) + const struct audioformat *fmt) { struct usb_device *dev = chip->dev; int err; diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 011f22cf2bf6..67a02303c820 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -26,12 +26,12 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev, unsigned int usb_id); void snd_usb_set_format_quirk(struct snd_usb_substream *subs, - struct audioformat *fmt); + const struct audioformat *fmt); bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip); int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, - struct audioformat *fp); + const struct audioformat *fp); void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep); @@ -41,7 +41,7 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, __u16 index, void *data, __u16 size); int snd_usb_select_mode_quirk(struct snd_usb_audio *chip, - struct audioformat *fmt); + const struct audioformat *fmt); u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, struct audioformat *fp, -- cgit v1.2.3 From 43b81e84068d26d630b63fa877e682909a0102fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:34 +0100 Subject: ALSA: usb-audio: Use atomic_t for endpoint use_count The endpoint objects may be started/stopped concurrently by different substreams in the case of implicit feedback mode, while the current code handles the reference counter without any protection. This patch changes the refcount to atomic_t for avoiding the inconsistency. We need no reference_t here as the refcount goes only up to 2. Also the name "use_count" is renamed to "running" since this is about actually the running status, not the open refcount. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-29-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.h | 2 +- sound/usb/endpoint.c | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index 53f0ce61f858..f58c3769b058 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -60,7 +60,7 @@ struct snd_usb_endpoint { struct snd_usb_audio *chip; int opened; /* open refcount; protect with chip->mutex */ - int use_count; + atomic_t running; /* running status */ int ep_num; /* the referenced endpoint number */ int type; /* SND_USB_ENDPOINT_TYPE_* */ unsigned long flags; diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 49fb934ee432..4d733b2d8287 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1234,7 +1234,7 @@ unlock: * * @ep: the endpoint to start * - * A call to this function will increment the use count of the endpoint. + * A call to this function will increment the running count of the endpoint. * In case it is not already running, the URBs for this endpoint will be * submitted. Otherwise, this function does nothing. * @@ -1253,11 +1253,12 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) if (ep->sync_master) WRITE_ONCE(ep->sync_master->sync_slave, ep); - usb_audio_dbg(ep->chip, "Starting %s EP 0x%x (count %d)\n", - ep_type_name(ep->type), ep->ep_num, ep->use_count); + usb_audio_dbg(ep->chip, "Starting %s EP 0x%x (running %d)\n", + ep_type_name(ep->type), ep->ep_num, + atomic_read(&ep->running)); /* already running? */ - if (++ep->use_count != 1) + if (atomic_inc_return(&ep->running) != 1) return 0; /* just to be sure */ @@ -1319,7 +1320,7 @@ __error: if (ep->sync_master) WRITE_ONCE(ep->sync_master->sync_slave, NULL); clear_bit(EP_FLAG_RUNNING, &ep->flags); - ep->use_count--; + atomic_dec(&ep->running); deactivate_urbs(ep, false); return -EPIPE; } @@ -1329,7 +1330,7 @@ __error: * * @ep: the endpoint to stop (may be NULL) * - * A call to this function will decrement the use count of the endpoint. + * A call to this function will decrement the running count of the endpoint. * In case the last user has requested the endpoint stop, the URBs will * actually be deactivated. * @@ -1343,16 +1344,17 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) if (!ep) return; - usb_audio_dbg(ep->chip, "Stopping %s EP 0x%x (count %d)\n", - ep_type_name(ep->type), ep->ep_num, ep->use_count); + usb_audio_dbg(ep->chip, "Stopping %s EP 0x%x (running %d)\n", + ep_type_name(ep->type), ep->ep_num, + atomic_read(&ep->running)); - if (snd_BUG_ON(ep->use_count == 0)) + if (snd_BUG_ON(!atomic_read(&ep->running))) return; if (ep->sync_master) WRITE_ONCE(ep->sync_master->sync_slave, NULL); - if (--ep->use_count == 0) { + if (!atomic_dec_return(&ep->running)) { deactivate_urbs(ep, false); set_bit(EP_FLAG_STOPPING, &ep->flags); } @@ -1363,7 +1365,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) * * @ep: the endpoint to release * - * This function does not care for the endpoint's use count but will tear + * This function does not care for the endpoint's running count but will tear * down all the streaming URBs immediately. */ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep) @@ -1410,7 +1412,7 @@ static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, * will take care of them later. */ if (snd_usb_endpoint_implicit_feedback_sink(ep) && - ep->use_count != 0) { + atomic_read(&ep->running)) { /* implicit feedback case */ int i, bytes = 0; -- cgit v1.2.3 From d0f09d1e4a88647695739d2ff4268e9fdcf5b35d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:35 +0100 Subject: ALSA: usb-audio: Refactoring endpoint URB deactivation Minor code refactoring to consolidate the URB deactivation code in endpoint.c. A slight behavior change is that the error handling in snd_usb_endpoint_start() leaves EP_FLAG_STOPPING now. This should be synced with the later PCM sync_stop callback. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-30-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 4d733b2d8287..35c84c2264e1 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -777,6 +777,9 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep) unsigned long end_time = jiffies + msecs_to_jiffies(1000); int alive; + if (!test_bit(EP_FLAG_STOPPING, &ep->flags)) + return 0; + do { alive = bitmap_weight(&ep->active_mask, ep->nurbs); if (!alive) @@ -802,22 +805,31 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep) */ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep) { - if (ep && test_bit(EP_FLAG_STOPPING, &ep->flags)) + if (ep) wait_clear_urbs(ep); } /* - * unlink active urbs. + * Stop and unlink active urbs. + * + * This function checks and clears EP_FLAG_RUNNING state. + * When @wait_sync is set, it waits until all pending URBs are killed. */ -static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force) +static int stop_and_unlink_urbs(struct snd_usb_endpoint *ep, bool force, + bool wait_sync) { unsigned int i; if (!force && atomic_read(&ep->chip->shutdown)) /* to be sure... */ return -EBADFD; - clear_bit(EP_FLAG_RUNNING, &ep->flags); + if (atomic_read(&ep->running)) + return -EBUSY; + + if (!test_and_clear_bit(EP_FLAG_RUNNING, &ep->flags)) + goto out; + set_bit(EP_FLAG_STOPPING, &ep->flags); INIT_LIST_HEAD(&ep->ready_playback_urbs); ep->next_packet_head = 0; ep->next_packet_queued = 0; @@ -831,6 +843,9 @@ static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force) } } + out: + if (wait_sync) + return wait_clear_urbs(ep); return 0; } @@ -845,8 +860,7 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL); /* stop urbs */ - deactivate_urbs(ep, force); - wait_clear_urbs(ep); + stop_and_unlink_urbs(ep, force, true); for (i = 0; i < ep->nurbs; i++) release_urb_ctx(&ep->urb[i]); @@ -1261,9 +1275,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) if (atomic_inc_return(&ep->running) != 1) return 0; - /* just to be sure */ - deactivate_urbs(ep, false); - ep->active_mask = 0; ep->unlink_mask = 0; ep->phase = 0; @@ -1317,11 +1328,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) return 0; __error: - if (ep->sync_master) - WRITE_ONCE(ep->sync_master->sync_slave, NULL); - clear_bit(EP_FLAG_RUNNING, &ep->flags); - atomic_dec(&ep->running); - deactivate_urbs(ep, false); + snd_usb_endpoint_stop(ep); return -EPIPE; } @@ -1354,10 +1361,8 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) if (ep->sync_master) WRITE_ONCE(ep->sync_master->sync_slave, NULL); - if (!atomic_dec_return(&ep->running)) { - deactivate_urbs(ep, false); - set_bit(EP_FLAG_STOPPING, &ep->flags); - } + if (!atomic_dec_return(&ep->running)) + stop_and_unlink_urbs(ep, false, false); } /** -- cgit v1.2.3 From 6aa719d15a1903eb3fd0e052ae53f3b024ad4d05 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:36 +0100 Subject: ALSA: usb-audio: Drop unneeded snd_usb_substream fields Some fields like interface and alt_idx in snd_usb_substream are mostly useless now as they can be referred via either cur_audiofmt or data_endpoint assigned to the substream. Drop those, and also assure the concurrency about the access of cur_audiofmt field. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-31-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 1 - sound/usb/card.h | 8 -------- sound/usb/pcm.c | 24 ++++++------------------ sound/usb/proc.c | 19 +++++++++++++------ sound/usb/quirks.c | 10 +++++----- 5 files changed, 24 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 58958afcec93..7940b3bff5bc 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -124,7 +124,6 @@ static void snd_usb_stream_disconnect(struct snd_usb_stream *as) subs = &as->substream[idx]; if (!subs->num_formats) continue; - subs->interface = -1; subs->data_endpoint = NULL; subs->sync_endpoint = NULL; } diff --git a/sound/usb/card.h b/sound/usb/card.h index f58c3769b058..1dd7a514d1d5 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -140,18 +140,10 @@ struct snd_usb_substream { struct usb_device *dev; struct snd_pcm_substream *pcm_substream; int direction; /* playback or capture */ - int interface; /* current interface */ int endpoint; /* assigned endpoint */ const struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ struct snd_usb_power_domain *str_pd; /* UAC3 Power Domain for streaming path */ - snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ - unsigned int channels; /* current number of channels (for hw_params callback) */ unsigned int channels_max; /* max channels in the all audiofmts */ - unsigned int cur_rate; /* current rate (for hw_params callback) */ - unsigned int period_bytes; /* current period bytes (for hw_params callback) */ - unsigned int period_frames; /* current frames per period */ - unsigned int buffer_periods; /* current periods per buffer */ - unsigned int altset_idx; /* USB data format: index of alternate setting */ unsigned int txfr_quirk:1; /* allow sub-frame alignment */ unsigned int tx_length_quirk:1; /* add length specifier to transfers */ unsigned int fmt_type; /* USB audio format type (1-3) */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index fc028492dd1a..95a6a854dc55 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -797,20 +797,11 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, subs->sync_endpoint); } - subs->interface = fmt->iface; - subs->altset_idx = fmt->altset_idx; + mutex_lock(&chip->mutex); subs->cur_audiofmt = fmt; + mutex_unlock(&chip->mutex); ret = configure_endpoints(chip, subs); - if (ret < 0) - goto unlock; - - subs->pcm_format = params_format(hw_params); - subs->period_bytes = params_period_bytes(hw_params); - subs->period_frames = params_period_size(hw_params); - subs->buffer_periods = params_periods(hw_params); - subs->channels = params_channels(hw_params); - subs->cur_rate = params_rate(hw_params); unlock: if (ret < 0) @@ -835,9 +826,9 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) struct snd_usb_audio *chip = subs->stream->chip; snd_media_stop_pipeline(subs); + mutex_lock(&chip->mutex); subs->cur_audiofmt = NULL; - subs->cur_rate = 0; - subs->period_bytes = 0; + mutex_unlock(&chip->mutex); if (!snd_usb_lock_shutdown(chip)) { if (stop_endpoints(subs)) sync_pending_stops(subs); @@ -1274,8 +1265,6 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) struct snd_usb_substream *subs = &as->substream[direction]; int ret; - subs->interface = -1; - subs->altset_idx = 0; runtime->hw = snd_usb_hardware; runtime->private_data = subs; subs->pcm_substream = substream; @@ -1308,7 +1297,6 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) snd_media_stop_pipeline(subs); if (!snd_usb_lock_shutdown(subs->stream->chip)) { - subs->interface = -1; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1); snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) @@ -1570,10 +1558,10 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, } bytes = frames * ep->stride; - if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && + if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE && subs->cur_audiofmt->dsd_dop)) { fill_playback_urb_dsd_dop(subs, urb, bytes); - } else if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U8 && + } else if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U8 && subs->cur_audiofmt->dsd_bitrev)) { /* bit-reverse the bytes */ u8 *buf = urb->transfer_buffer; diff --git a/sound/usb/proc.c b/sound/usb/proc.c index 889c550c9f29..447ba32e281c 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -175,32 +175,39 @@ static void proc_dump_ep_status(struct snd_usb_substream *subs, } } -static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) +static void proc_dump_substream_status(struct snd_usb_audio *chip, + struct snd_usb_substream *subs, + struct snd_info_buffer *buffer) { + mutex_lock(&chip->mutex); if (subs->running) { snd_iprintf(buffer, " Status: Running\n"); - snd_iprintf(buffer, " Interface = %d\n", subs->interface); - snd_iprintf(buffer, " Altset = %d\n", subs->altset_idx); + if (subs->cur_audiofmt) { + snd_iprintf(buffer, " Interface = %d\n", subs->cur_audiofmt->iface); + snd_iprintf(buffer, " Altset = %d\n", subs->cur_audiofmt->altsetting); + } proc_dump_ep_status(subs, subs->data_endpoint, subs->sync_endpoint, buffer); } else { snd_iprintf(buffer, " Status: Stop\n"); } + mutex_unlock(&chip->mutex); } static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_usb_stream *stream = entry->private_data; + struct snd_usb_audio *chip = stream->chip; - snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name); + snd_iprintf(buffer, "%s : %s\n", chip->card->longname, stream->pcm->name); if (stream->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats) { snd_iprintf(buffer, "\nPlayback:\n"); - proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer); + proc_dump_substream_status(chip, &stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer); proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer); } if (stream->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats) { snd_iprintf(buffer, "\nCapture:\n"); - proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer); + proc_dump_substream_status(chip, &stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer); proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer); } } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 5510c8a98447..02f3f6ed9390 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1424,7 +1424,7 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs, * by playback substream */ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { - if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) + if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].cur_audiofmt) return; } @@ -1459,13 +1459,13 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs, */ static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs) { - + unsigned int cur_rate = subs->data_endpoint->cur_rate; /* Convert sample rate value to little endian */ u8 sr[3]; - sr[0] = subs->cur_rate & 0xff; - sr[1] = (subs->cur_rate >> 8) & 0xff; - sr[2] = (subs->cur_rate >> 16) & 0xff; + sr[0] = cur_rate & 0xff; + sr[1] = (cur_rate >> 8) & 0xff; + sr[2] = (cur_rate >> 16) & 0xff; /* Configure device */ usb_set_interface(subs->dev, 0, 1); -- cgit v1.2.3 From 3d58760f4d0015cc1e7765b580daa007d759d86b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:37 +0100 Subject: ALSA: usb-audio: Unify the code for the next packet size calculation There are two places calculating the next packet size for the playback stream in the exactly same way. Provide the single helper for this purpose and use it from both places gracefully. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-32-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 40 ++++++++++++++++++++++++---------------- sound/usb/endpoint.h | 4 ++-- sound/usb/pcm.c | 8 +------- 3 files changed, 27 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 35c84c2264e1..5d618724bd75 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -121,13 +121,13 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep) } /* - * For streaming based on information derived from sync endpoints, - * prepare_outbound_urb_sizes() will call slave_next_packet_size() to - * determine the number of samples to be sent in the next packet. + * Return the number of samples to be sent in the next packet + * for streaming based on information derived from sync endpoints * - * For implicit feedback, slave_next_packet_size() is unused. + * This won't be used for implicit feedback which takes the packet size + * returned from the sync source */ -int snd_usb_endpoint_slave_next_packet_size(struct snd_usb_endpoint *ep) +static int slave_next_packet_size(struct snd_usb_endpoint *ep) { unsigned long flags; int ret; @@ -145,11 +145,10 @@ int snd_usb_endpoint_slave_next_packet_size(struct snd_usb_endpoint *ep) } /* - * For adaptive and synchronous endpoints, prepare_outbound_urb_sizes() - * will call next_packet_size() to determine the number of samples to be - * sent in the next packet. + * Return the number of samples to be sent in the next packet + * for adaptive and synchronous endpoints */ -int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) +static int next_packet_size(struct snd_usb_endpoint *ep) { int ret; @@ -167,6 +166,21 @@ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) return ret; } +/* + * snd_usb_endpoint_next_packet_size: Return the number of samples to be sent + * in the next packet + */ +int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep, + struct snd_urb_ctx *ctx, int idx) +{ + if (ctx->packet_size[idx]) + return ctx->packet_size[idx]; + else if (ep->sync_master) + return slave_next_packet_size(ep); + else + return next_packet_size(ep); +} + static void call_retire_callback(struct snd_usb_endpoint *ep, struct urb *urb) { @@ -223,13 +237,7 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep, unsigned int length; int counts; - if (ctx->packet_size[i]) - counts = ctx->packet_size[i]; - else if (ep->sync_master) - counts = snd_usb_endpoint_slave_next_packet_size(ep); - else - counts = snd_usb_endpoint_next_packet_size(ep); - + counts = snd_usb_endpoint_next_packet_size(ep, ctx, i); length = counts * ep->stride; /* number of silent bytes */ offset = offs * ep->stride + extra * i; urb->iso_frame_desc[i].offset = offset; diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index 201011d89659..11e3bb839fd7 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -45,7 +45,7 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep); void snd_usb_endpoint_free(struct snd_usb_endpoint *ep); int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep); -int snd_usb_endpoint_slave_next_packet_size(struct snd_usb_endpoint *ep); -int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep); +int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep, + struct snd_urb_ctx *ctx, int idx); #endif /* __USBAUDIO_ENDPOINT_H */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 95a6a854dc55..5953e22a72c5 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1512,13 +1512,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, spin_lock_irqsave(&subs->lock, flags); subs->frame_limit += ep->max_urb_frames; for (i = 0; i < ctx->packets; i++) { - if (ctx->packet_size[i]) - counts = ctx->packet_size[i]; - else if (ep->sync_master) - counts = snd_usb_endpoint_slave_next_packet_size(ep); - else - counts = snd_usb_endpoint_next_packet_size(ep); - + counts = snd_usb_endpoint_next_packet_size(ep, ctx, i); /* set up descriptor */ urb->iso_frame_desc[i].offset = frames * ep->stride; urb->iso_frame_desc[i].length = counts * ep->stride; -- cgit v1.2.3 From 13ee03361fc5c9284067f4bfaaea4ebadbd874cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:38 +0100 Subject: ALSA: usb-audio: Simplify rate_min/max and rates set up There are multiple places in format.c performing the similar code for setting the rate_min, rate_max and rates fields. This patch unifies those in a helper function and calls it at the end of the parser phase so that all rate_table entries have been already determined. No functional changes, just a minor code refactoring. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-33-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/format.c | 53 ++++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/usb/format.c b/sound/usb/format.c index 7641716f0c6c..93459ba228d3 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -164,6 +164,23 @@ static int set_fixed_rate(struct audioformat *fp, int rate, int rate_bits) return 0; } +/* set up rate_min, rate_max and rates from the rate table */ +static void set_rate_table_min_max(struct audioformat *fp) +{ + unsigned int rate; + int i; + + fp->rate_min = INT_MAX; + fp->rate_max = 0; + fp->rates = 0; + for (i = 0; i < fp->nr_rates; i++) { + rate = fp->rate_table[i]; + fp->rate_min = min(fp->rate_min, rate); + fp->rate_max = max(fp->rate_max, rate); + fp->rates |= snd_pcm_rate_to_rate_bit(rate); + } +} + /* * parse the format descriptor and stores the possible sample rates * on the audioformat table (audio class v1). @@ -198,7 +215,6 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof return -ENOMEM; fp->nr_rates = 0; - fp->rate_min = fp->rate_max = 0; for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { unsigned int rate = combine_triple(&fmt[idx]); if (!rate) @@ -217,13 +233,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof chip->usb_id == USB_ID(0x041e, 0x4068))) rate = 8000; - fp->rate_table[fp->nr_rates] = rate; - if (!fp->rate_min || rate < fp->rate_min) - fp->rate_min = rate; - if (!fp->rate_max || rate > fp->rate_max) - fp->rate_max = rate; - fp->rates |= snd_pcm_rate_to_rate_bit(rate); - fp->nr_rates++; + fp->rate_table[fp->nr_rates++] = rate; } if (!fp->nr_rates) { usb_audio_info(chip, @@ -231,6 +241,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof fp->iface, fp->altsetting); return -EINVAL; } + set_rate_table_min_max(fp); } else { /* continuous rates */ fp->rates = SNDRV_PCM_RATE_CONTINUOUS; @@ -336,8 +347,6 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, { int i, nr_rates = 0; - fp->rates = fp->rate_min = fp->rate_max = 0; - for (i = 0; i < nr_triplets; i++) { int min = combine_quad(&data[2 + 12 * i]); int max = combine_quad(&data[6 + 12 * i]); @@ -373,12 +382,6 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, if (fp->rate_table) fp->rate_table[nr_rates] = rate; - if (!fp->rate_min || rate < fp->rate_min) - fp->rate_min = rate; - if (!fp->rate_max || rate > fp->rate_max) - fp->rate_max = rate; - fp->rates |= snd_pcm_rate_to_rate_bit(rate); - nr_rates++; if (nr_rates >= MAX_NR_RATES) { usb_audio_err(chip, "invalid uac2 rates\n"); @@ -459,9 +462,6 @@ static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip, struct usb_device *dev = chip->dev; unsigned int *table; unsigned int nr_rates; - unsigned int rate_min = 0x7fffffff; - unsigned int rate_max = 0; - unsigned int rates = 0; int i, err; table = kcalloc(fp->nr_rates, sizeof(*table), GFP_KERNEL); @@ -478,14 +478,8 @@ static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip, if (err < 0) continue; - if (check_valid_altsetting_v2v3(chip, fp->iface, fp->altsetting)) { + if (check_valid_altsetting_v2v3(chip, fp->iface, fp->altsetting)) table[nr_rates++] = fp->rate_table[i]; - if (rate_min > fp->rate_table[i]) - rate_min = fp->rate_table[i]; - if (rate_max < fp->rate_table[i]) - rate_max = fp->rate_table[i]; - rates |= snd_pcm_rate_to_rate_bit(fp->rate_table[i]); - } } if (!nr_rates) { @@ -503,9 +497,6 @@ static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip, kfree(fp->rate_table); fp->rate_table = table; fp->nr_rates = nr_rates; - fp->rate_min = rate_min; - fp->rate_max = rate_max; - fp->rates = rates; return 0; } @@ -602,6 +593,10 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, parse_uac2_sample_rate_range(chip, fp, nr_triplets, data); ret = validate_sample_rate_table_v2v3(chip, fp, clock); + if (ret < 0) + goto err_free; + + set_rate_table_min_max(fp); err_free: kfree(data); -- cgit v1.2.3 From 53837b4ac2bd33ede5cd799940341ce5ea7b2902 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:39 +0100 Subject: ALSA: usb-audio: Replace slave/master terms Follow the inclusive terminology, just replace sync_master/sync_slave with sync_source/sync_sink. It's also a bit clearer from its meaning, too. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-34-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.h | 4 ++-- sound/usb/endpoint.c | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index 1dd7a514d1d5..3e16b9288693 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -71,8 +71,8 @@ struct snd_usb_endpoint { struct urb *urb); struct snd_usb_substream *data_subs; - struct snd_usb_endpoint *sync_master; - struct snd_usb_endpoint *sync_slave; + struct snd_usb_endpoint *sync_source; + struct snd_usb_endpoint *sync_sink; struct snd_urb_ctx urb[MAX_URBS]; diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 5d618724bd75..5f1d5f1ed8db 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -175,7 +175,7 @@ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep, { if (ctx->packet_size[idx]) return ctx->packet_size[idx]; - else if (ep->sync_master) + else if (ep->sync_source) return slave_next_packet_size(ep); else return next_packet_size(ep); @@ -205,16 +205,16 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep, struct snd_urb_ctx *urb_ctx) { struct urb *urb = urb_ctx->urb; - struct snd_usb_endpoint *sync_slave; + struct snd_usb_endpoint *sync_sink; if (unlikely(ep->skip_packets > 0)) { ep->skip_packets--; return; } - sync_slave = READ_ONCE(ep->sync_slave); - if (sync_slave) - snd_usb_handle_sync_urb(sync_slave, ep, urb); + sync_sink = READ_ONCE(ep->sync_sink); + if (sync_sink) + snd_usb_handle_sync_urb(sync_sink, ep, urb); call_retire_callback(ep, urb); } @@ -708,7 +708,7 @@ void snd_usb_endpoint_set_sync(struct snd_usb_audio *chip, struct snd_usb_endpoint *data_ep, struct snd_usb_endpoint *sync_ep) { - data_ep->sync_master = sync_ep; + data_ep->sync_source = sync_ep; } /* @@ -802,7 +802,7 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep) alive, ep->ep_num); clear_bit(EP_FLAG_STOPPING, &ep->flags); - ep->sync_slave = NULL; + ep->sync_sink = NULL; snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL); return 0; @@ -969,9 +969,9 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep) packs_per_ms = 1; max_packs_per_urb = MAX_PACKS; } - if (ep->sync_master && !ep->implicit_fb_sync) + if (ep->sync_source && !ep->implicit_fb_sync) max_packs_per_urb = min(max_packs_per_urb, - 1U << ep->sync_master->syncinterval); + 1U << ep->sync_source->syncinterval); max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval); /* @@ -1015,7 +1015,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep) minsize = (ep->freqn >> (16 - ep->datainterval)) * (frame_bits >> 3); /* with sync from device, assume it can be 12% lower */ - if (ep->sync_master) + if (ep->sync_source) minsize -= minsize >> 3; minsize = max(minsize, 1u); @@ -1272,8 +1272,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) if (atomic_read(&ep->chip->shutdown)) return -EBADFD; - if (ep->sync_master) - WRITE_ONCE(ep->sync_master->sync_slave, ep); + if (ep->sync_source) + WRITE_ONCE(ep->sync_source->sync_sink, ep); usb_audio_dbg(ep->chip, "Starting %s EP 0x%x (running %d)\n", ep_type_name(ep->type), ep->ep_num, @@ -1366,8 +1366,8 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) if (snd_BUG_ON(!atomic_read(&ep->running))) return; - if (ep->sync_master) - WRITE_ONCE(ep->sync_master->sync_slave, NULL); + if (ep->sync_source) + WRITE_ONCE(ep->sync_source->sync_sink, NULL); if (!atomic_dec_return(&ep->running)) stop_and_unlink_urbs(ep, false, false); -- cgit v1.2.3 From 89fa3f686c10c9edde0f41e5a1c71afa0e43ff87 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:40 +0100 Subject: ALSA: usb-audio: Use unsigned char for iface and altsettings fields Just for consistency, use unsigned char for iface and altsetting in allover places. Also rearrange the field positions of snd_usb_endpiont and tidy up with some comments. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-35-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.h | 11 +++++++---- sound/usb/endpoint.c | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index 3e16b9288693..6a027c349194 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -16,7 +16,7 @@ struct audioformat { unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int fmt_bits; /* number of significant bits */ unsigned int frame_size; /* samples per frame for non-audio */ - int iface; /* interface number */ + unsigned char iface; /* interface number */ unsigned char altsetting; /* corresponding alternate setting */ unsigned char altset_idx; /* array index of altenate setting */ unsigned char attributes; /* corresponding attributes of cs endpoint */ @@ -63,7 +63,12 @@ struct snd_usb_endpoint { atomic_t running; /* running status */ int ep_num; /* the referenced endpoint number */ int type; /* SND_USB_ENDPOINT_TYPE_* */ - unsigned long flags; + + unsigned char iface; /* interface number */ + unsigned char altsetting; /* corresponding alternate setting */ + unsigned char ep_idx; /* endpoint array index */ + + unsigned long flags; /* running bit flags */ void (*prepare_data_urb) (struct snd_usb_substream *subs, struct urb *urb); @@ -112,8 +117,6 @@ struct snd_usb_endpoint { unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ unsigned char silence_value; unsigned int stride; - int iface, altsetting; - unsigned char ep_idx; /* endpoint array index */ int skip_packets; /* quirks for devices to ignore the first n packets in a stream */ bool implicit_fb_sync; /* syncs with implicit feedback */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 5f1d5f1ed8db..162da7a50046 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -762,7 +762,7 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip, ep->ep_num, ep->opened); if (!--ep->opened) { endpoint_set_interface(chip, ep, false); - ep->iface = -1; + ep->iface = 0; ep->altsetting = 0; ep->cur_audiofmt = NULL; ep->cur_rate = 0; -- cgit v1.2.3 From 8ec08b1a5cf8e4de1db8919a27d0e2a801b09d24 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:41 +0100 Subject: ALSA: usb-audio: Show sync endpoint information in proc outputs Now the sync endpoints have been parsed at the beginning and won't be changed dynamically, let's show them in the proc outputs for helping debugging. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-36-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/proc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/proc.c b/sound/usb/proc.c index 447ba32e281c..e9bbaea7b2fa 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -108,7 +108,8 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s snd_pcm_format_name(fmt)); snd_iprintf(buffer, "\n"); snd_iprintf(buffer, " Channels: %d\n", fp->channels); - snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", + snd_iprintf(buffer, " Endpoint: 0x%02x (%d %s) (%s)\n", + fp->endpoint, fp->endpoint & USB_ENDPOINT_NUMBER_MASK, fp->endpoint & USB_DIR_IN ? "IN" : "OUT", sync_types[(fp->ep_attr & USB_ENDPOINT_SYNCTYPE) >> 2]); @@ -150,6 +151,19 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s snd_iprintf(buffer, "\n"); } + if (fp->sync_ep) { + snd_iprintf(buffer, " Sync Endpoint: 0x%02x (%d %s)\n", + fp->sync_ep, + fp->sync_ep & USB_ENDPOINT_NUMBER_MASK, + fp->sync_ep & USB_DIR_IN ? "IN" : "OUT"); + snd_iprintf(buffer, " Sync EP Interface: %d\n", + fp->sync_iface); + snd_iprintf(buffer, " Sync EP Altset: %d\n", + fp->sync_altsetting); + snd_iprintf(buffer, " Implicit Feedback Mode: %s\n", + fp->implicit_fb ? "Yes" : "No"); + } + // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); // snd_iprintf(buffer, " EP Attribute = %#x\n", fp->attributes); } -- cgit v1.2.3 From 6234fdc1cede3c1deda8324bdbb8274c0f4ff192 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:42 +0100 Subject: ALSA: usb-audio: Quirk for BOSS GT-001 The capture stream of BOSS GT-001 seems always requiring to be tied with the playback stream. OTOH, the playback stream of this device doesn't seem working in the implicit fb mode, per se, since the playback must be running before the capture stream. This patch tries to address the points above: - Avoid the implicit fb mode for the playback - Set up a fake sync EP for the capture stream with the hard-coded playback stream using the implicit fb mode Reported-by: Keith Milner Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-37-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 5953e22a72c5..676acc20595b 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -403,6 +403,9 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, case USB_ID(0x0582, 0x01d8): /* BOSS Katana */ /* BOSS Katana amplifiers do not need quirks */ return 0; + case USB_ID(0x0582, 0x01e5): /* BOSS GT-001 */ + /* BOSS GT-001 needs no implicit fb for playback */ + return 0; } /* Generic UAC2 implicit feedback */ @@ -454,6 +457,30 @@ add_sync_ep: return 1; } +static int audioformat_capture_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts) +{ + struct usb_device *dev = chip->dev; + + switch (chip->usb_id) { + case USB_ID(0x0582, 0x01e5): /* BOSS GT-001 */ + if (!snd_usb_get_host_interface(chip, 0x01, 0x01)) + return 0; + fmt->sync_ep = 0x0d; + fmt->sync_iface = 0x01; + fmt->sync_altsetting = 0x01; + fmt->sync_ep_idx = 0; + fmt->implicit_fb = 1; + dev_dbg(&dev->dev, "%d:%d: added fake capture sync sync_ep=%x, iface=%d, alt=%d\n", + fmt->iface, fmt->altsetting, fmt->sync_ep, fmt->sync_iface, + fmt->sync_altsetting); + return 1; + } + return 0; + +} + int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, struct audioformat *fmt) { @@ -474,6 +501,10 @@ int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, err = audioformat_implicit_fb_quirk(chip, fmt, alts); if (err > 0) return 0; + } else { + err = audioformat_capture_quirk(chip, fmt, alts); + if (err > 0) + return 0; } if (altsd->bNumEndpoints < 2) -- cgit v1.2.3 From 9fddc15e803945a744f357a4d1c94301e1ed6681 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:43 +0100 Subject: ALSA: usb-audio: Factor out the implicit feedback quirk code The code dealing with the implicit feedback mode grew recently, and it's becoming messy. As we receive more and more devices that need the similar handling, it's better to be processed through a table instead of the open code. This patch moves the code that is relevant with parsing the implicit feedback mode and some helpers into another file, implicit.c. The detection and the setup of the implicit feedback sync EPs are rewritten to use the ID/class matching table instead. There should be no functional changes. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-38-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/Makefile | 1 + sound/usb/implicit.c | 347 +++++++++++++++++++++++++++++++++++++++++++++++++++ sound/usb/implicit.h | 14 +++ sound/usb/pcm.c | 320 +++-------------------------------------------- 4 files changed, 376 insertions(+), 306 deletions(-) create mode 100644 sound/usb/implicit.c create mode 100644 sound/usb/implicit.h (limited to 'sound') diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 56031026b113..9ccb21a4ff8a 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -8,6 +8,7 @@ snd-usb-audio-objs := card.o \ endpoint.o \ format.o \ helper.o \ + implicit.o \ mixer.o \ mixer_quirks.o \ mixer_scarlett.o \ diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c new file mode 100644 index 000000000000..bc7edecff946 --- /dev/null +++ b/sound/usb/implicit.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Special handling for implicit feedback mode +// + +#include +#include +#include +#include + +#include +#include +#include + +#include "usbaudio.h" +#include "card.h" +#include "helper.h" +#include "implicit.h" + +enum { + IMPLICIT_FB_NONE, + IMPLICIT_FB_FIXED, +}; + +struct snd_usb_implicit_fb_match { + unsigned int id; + unsigned int iface_class; + unsigned int ep_num; + unsigned int iface; + int type; +}; + +#define IMPLICIT_FB_FIXED_DEV(vend, prod, ep, ifnum) \ + { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_FIXED, .ep_num = (ep),\ + .iface = (ifnum) } +#define IMPLICIT_FB_SKIP_DEV(vend, prod) \ + { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_NONE } + +/* Implicit feedback quirk table for playback */ +static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { + /* Fixed EP */ + IMPLICIT_FB_FIXED_DEV(0x1397, 0x0001, 0x81, 1), /* Behringer UFX1604 */ + IMPLICIT_FB_FIXED_DEV(0x1397, 0x0002, 0x81, 1), /* Behringer UFX1204 */ + IMPLICIT_FB_FIXED_DEV(0x0763, 0x2080, 0x81, 2), /* M-Audio FastTrack Ultra */ + IMPLICIT_FB_FIXED_DEV(0x0763, 0x2081, 0x81, 2), /* M-Audio FastTrack Ultra */ + IMPLICIT_FB_FIXED_DEV(0x2466, 0x8010, 0x81, 2), /* Fractal Audio Axe-Fx III */ + IMPLICIT_FB_FIXED_DEV(0x07fd, 0x0008, 0x81, 2), /* MOTU M Series */ + IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0001, 0x81, 2), /* Solid State Logic SSL2 */ + IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */ + IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */ + IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */ + IMPLICIT_FB_FIXED_DEV(0x0763, 0x2030, 0x81, 3), /* M-Audio Fast Track C400 */ + IMPLICIT_FB_FIXED_DEV(0x0763, 0x2031, 0x81, 3), /* M-Audio Fast Track C600 */ + IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */ + IMPLICIT_FB_FIXED_DEV(0x2b73, 0x000a, 0x82, 0), /* Pioneer DJ DJM-900NXS2 */ + IMPLICIT_FB_FIXED_DEV(0x2b73, 0x0017, 0x82, 0), /* Pioneer DJ DJM-250MK2 */ + IMPLICIT_FB_FIXED_DEV(0x1686, 0xf029, 0x82, 2), /* Zoom UAC-2 */ + IMPLICIT_FB_FIXED_DEV(0x2466, 0x8003, 0x86, 2), /* Fractal Audio Axe-Fx II */ + IMPLICIT_FB_FIXED_DEV(0x0499, 0x172a, 0x86, 2), /* Yamaha MODX */ + + /* Special matching */ + { .id = USB_ID(0x07fd, 0x0004), .iface_class = USB_CLASS_AUDIO, + .type = IMPLICIT_FB_NONE }, /* MicroBook IIc */ + /* ep = 0x84, ifnum = 0 */ + { .id = USB_ID(0x07fd, 0x0004), .iface_class = USB_CLASS_VENDOR_SPEC, + .type = IMPLICIT_FB_FIXED, + .ep_num = 0x84, .iface = 0 }, /* MOTU MicroBook II */ + + /* No quirk */ + IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8), /* BOSS Katana */ + + /* No quirk for playback but with capture quirk (see below) */ + IMPLICIT_FB_SKIP_DEV(0x0582, 0x01e5), /* BOSS GT-001 */ + + {} /* terminator */ +}; + +/* Implicit feedback quirk table for capture */ +static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { + IMPLICIT_FB_FIXED_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ + + {} /* terminator */ +}; + +/* set up sync EP information on the audioformat */ +static int add_implicit_fb_sync_ep(struct snd_usb_audio *chip, + struct audioformat *fmt, + int ep, int ifnum, + const struct usb_host_interface *alts) +{ + struct usb_interface *iface; + + if (!alts) { + iface = usb_ifnum_to_if(chip->dev, ifnum); + if (!iface || iface->num_altsetting < 2) + return 0; + alts = &iface->altsetting[1]; + } + + fmt->sync_ep = ep; + fmt->sync_iface = ifnum; + fmt->sync_altsetting = alts->desc.bAlternateSetting; + fmt->sync_ep_idx = 0; + fmt->implicit_fb = 1; + usb_audio_dbg(chip, + "%d:%d: added %s implicit_fb sync_ep %x, iface %d:%d\n", + fmt->iface, fmt->altsetting, + (ep & USB_DIR_IN) ? "playback" : "capture", + fmt->sync_ep, fmt->sync_iface, fmt->sync_altsetting); + return 1; +} + +/* Check whether the given UAC2 iface:altset points to an implicit fb source */ +static int add_generic_uac2_implicit_fb(struct snd_usb_audio *chip, + struct audioformat *fmt, + unsigned int ifnum, + unsigned int altsetting) +{ + struct usb_host_interface *alts; + struct usb_endpoint_descriptor *epd; + + alts = snd_usb_get_host_interface(chip, ifnum, altsetting); + if (!alts) + return 0; + if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || + alts->desc.bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING || + alts->desc.bInterfaceProtocol != UAC_VERSION_2 || + alts->desc.bNumEndpoints < 1) + return 0; + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_in(epd) || + (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != + USB_ENDPOINT_USAGE_IMPLICIT_FB) + return 0; + return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, + ifnum, alts); +} + +/* Like the function above, but specific to Roland with vendor class and hack */ +static int add_roland_implicit_fb(struct snd_usb_audio *chip, + struct audioformat *fmt, + unsigned int ifnum, + unsigned int altsetting) +{ + struct usb_host_interface *alts; + struct usb_endpoint_descriptor *epd; + + alts = snd_usb_get_host_interface(chip, ifnum, altsetting); + if (!alts) + return 0; + if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC || + (alts->desc.bInterfaceSubClass != 2 && + alts->desc.bInterfaceProtocol != 2) || + alts->desc.bNumEndpoints < 1) + return 0; + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_in(epd) || + (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != + USB_ENDPOINT_USAGE_IMPLICIT_FB) + return 0; + return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, + ifnum, alts); +} + +static const struct snd_usb_implicit_fb_match * +find_implicit_fb_entry(struct snd_usb_audio *chip, + const struct snd_usb_implicit_fb_match *match, + const struct usb_host_interface *alts) +{ + for (; match->id; match++) + if (match->id == chip->usb_id && + (!match->iface_class || + (alts->desc.bInterfaceClass == match->iface_class))) + return match; + + return NULL; +} + +/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk + * applies. Returns 1 if a quirk was found. + */ +static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts) +{ + const struct snd_usb_implicit_fb_match *p; + unsigned int attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; + + p = find_implicit_fb_entry(chip, playback_implicit_fb_quirks, alts); + if (p) { + switch (p->type) { + case IMPLICIT_FB_NONE: + return 0; /* No quirk */ + case IMPLICIT_FB_FIXED: + return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, + p->iface, NULL); + } + } + + /* Generic UAC2 implicit feedback */ + if (attr == USB_ENDPOINT_SYNC_ASYNC && + alts->desc.bInterfaceClass == USB_CLASS_AUDIO && + alts->desc.bInterfaceProtocol == UAC_VERSION_2 && + alts->desc.bNumEndpoints == 1) { + if (add_generic_uac2_implicit_fb(chip, fmt, + alts->desc.bInterfaceNumber + 1, + alts->desc.bAlternateSetting)) + return 1; + } + + /* Roland/BOSS implicit feedback with vendor spec class */ + if (attr == USB_ENDPOINT_SYNC_ASYNC && + alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC && + alts->desc.bInterfaceProtocol == 2 && + alts->desc.bNumEndpoints == 1 && + USB_ID_VENDOR(chip->usb_id) == 0x0582 /* Roland */) { + if (add_roland_implicit_fb(chip, fmt, + alts->desc.bInterfaceNumber + 1, + alts->desc.bAlternateSetting)) + return 1; + } + + /* No quirk */ + return 0; +} + +/* same for capture, but only handling FIXED entry */ +static int audioformat_capture_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts) +{ + const struct snd_usb_implicit_fb_match *p; + + p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); + if (p && p->type == IMPLICIT_FB_FIXED) + return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, p->iface, + NULL); + return 0; +} + +/* + * Parse altset and set up implicit feedback endpoint on the audioformat + */ +int snd_usb_parse_implicit_fb_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts) +{ + if (fmt->endpoint & USB_DIR_IN) + return audioformat_capture_quirk(chip, fmt, alts); + else + return audioformat_implicit_fb_quirk(chip, fmt, alts); +} + +/* + * Return the score of matching two audioformats. + * Veto the audioformat if: + * - It has no channels for some reason. + * - Requested PCM format is not supported. + * - Requested sample rate is not supported. + */ +static int match_endpoint_audioformats(struct snd_usb_substream *subs, + const struct audioformat *fp, + int rate, int channels, + snd_pcm_format_t pcm_format) +{ + int i, score; + + if (fp->channels < 1) + return 0; + + if (!(fp->formats & pcm_format_to_bits(pcm_format))) + return 0; + + if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { + if (rate < fp->rate_min || rate > fp->rate_max) + return 0; + } else { + for (i = 0; i < fp->nr_rates; i++) { + if (fp->rate_table[i] == rate) + break; + } + if (i >= fp->nr_rates) + return 0; + } + + score = 1; + if (fp->channels == channels) + score++; + + return score; +} + +static struct snd_usb_substream * +find_matching_substream(struct snd_usb_audio *chip, int stream, int ep_num, + int fmt_type) +{ + struct snd_usb_stream *as; + struct snd_usb_substream *subs; + + list_for_each_entry(as, &chip->pcm_list, list) { + subs = &as->substream[stream]; + if (as->fmt_type == fmt_type && subs->ep_num == ep_num) + return subs; + } + + return NULL; +} + +/* + * Return the audioformat that is suitable for the implicit fb + */ +const struct audioformat * +snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, + const struct audioformat *target, + const struct snd_pcm_hw_params *params, + int stream) +{ + struct snd_usb_substream *subs; + const struct audioformat *fp, *sync_fmt; + int score, high_score; + + /* When sharing the same altset, use the original audioformat */ + if (target->iface == target->sync_iface && + target->altsetting == target->sync_altsetting) + return target; + + subs = find_matching_substream(chip, stream, target->sync_ep, + target->fmt_type); + if (!subs) + return NULL; + + sync_fmt = NULL; + high_score = 0; + list_for_each_entry(fp, &subs->fmt_list, list) { + score = match_endpoint_audioformats(subs, fp, + params_rate(params), + params_channels(params), + params_format(params)); + if (score > high_score) { + sync_fmt = fp; + high_score = score; + } + } + + return sync_fmt; +} + diff --git a/sound/usb/implicit.h b/sound/usb/implicit.h new file mode 100644 index 000000000000..ccb415a0ea86 --- /dev/null +++ b/sound/usb/implicit.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __USBAUDIO_IMPLICIT_H +#define __USBAUDIO_IMPLICIT_H + +int snd_usb_parse_implicit_fb_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts); +const struct audioformat * +snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, + const struct audioformat *target, + const struct snd_pcm_hw_params *params, + int stream); + +#endif /* __USBAUDIO_IMPLICIT_H */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 676acc20595b..56079901769f 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -23,6 +23,7 @@ #include "clock.h" #include "power.h" #include "media.h" +#include "implicit.h" #define SUBSTREAM_FLAG_DATA_EP_STARTED 0 #define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 @@ -276,211 +277,7 @@ static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream) return 0; } -/* Check whether the given iface:altsetting points to an implicit fb source */ -static bool search_generic_implicit_fb(struct snd_usb_audio *chip, int ifnum, - unsigned int altsetting, - struct usb_host_interface **altsp, - unsigned int *ep) -{ - struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; - struct usb_endpoint_descriptor *epd; - - alts = snd_usb_get_host_interface(chip, ifnum, altsetting); - if (!alts) - return false; - altsd = get_iface_desc(alts); - if (altsd->bInterfaceClass != USB_CLASS_AUDIO || - altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING || - altsd->bInterfaceProtocol != UAC_VERSION_2 || - altsd->bNumEndpoints < 1) - return false; - epd = get_endpoint(alts, 0); - if (!usb_endpoint_is_isoc_in(epd) || - (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != - USB_ENDPOINT_USAGE_IMPLICIT_FB) - return false; - *ep = epd->bEndpointAddress; - *altsp = alts; - return true; -} - -/* Like the function above, but specific to Roland with vendor class and hack */ -static bool search_roland_implicit_fb(struct snd_usb_audio *chip, int ifnum, - unsigned int altsetting, - struct usb_host_interface **altsp, - unsigned int *ep) -{ - struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; - struct usb_endpoint_descriptor *epd; - - alts = snd_usb_get_host_interface(chip, ifnum, altsetting); - if (!alts) - return false; - altsd = get_iface_desc(alts); - if (altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC || - (altsd->bInterfaceSubClass != 2 && - altsd->bInterfaceProtocol != 2) || - altsd->bNumEndpoints < 1) - return false; - epd = get_endpoint(alts, 0); - if (!usb_endpoint_is_isoc_in(epd) || - (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != - USB_ENDPOINT_USAGE_IMPLICIT_FB) - return false; - *ep = epd->bEndpointAddress; - *altsp = alts; - return true; -} - -/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk - * applies. Returns 1 if a quirk was found. - */ -static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, - struct audioformat *fmt, - struct usb_host_interface *alts) -{ - struct usb_device *dev = chip->dev; - struct usb_interface_descriptor *altsd = get_iface_desc(alts); - struct usb_interface *iface; - unsigned int attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; - unsigned int ep; - unsigned int ifnum; - - switch (chip->usb_id) { - case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ - case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ - case USB_ID(0x22f0, 0x0006): /* Allen&Heath Qu-16 */ - ep = 0x81; - ifnum = 3; - goto add_sync_ep_from_ifnum; - case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ - case USB_ID(0x0763, 0x2081): - ep = 0x81; - ifnum = 2; - goto add_sync_ep_from_ifnum; - case USB_ID(0x2466, 0x8003): /* Fractal Audio Axe-Fx II */ - case USB_ID(0x0499, 0x172a): /* Yamaha MODX */ - ep = 0x86; - ifnum = 2; - goto add_sync_ep_from_ifnum; - case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx III */ - ep = 0x81; - ifnum = 2; - goto add_sync_ep_from_ifnum; - case USB_ID(0x1686, 0xf029): /* Zoom UAC-2 */ - ep = 0x82; - ifnum = 2; - goto add_sync_ep_from_ifnum; - case USB_ID(0x1397, 0x0001): /* Behringer UFX1604 */ - case USB_ID(0x1397, 0x0002): /* Behringer UFX1204 */ - ep = 0x81; - ifnum = 1; - goto add_sync_ep_from_ifnum; - case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II/IIc */ - /* MicroBook IIc */ - if (altsd->bInterfaceClass == USB_CLASS_AUDIO) - return 0; - - /* MicroBook II */ - ep = 0x84; - ifnum = 0; - goto add_sync_ep_from_ifnum; - case USB_ID(0x07fd, 0x0008): /* MOTU M Series */ - case USB_ID(0x31e9, 0x0001): /* Solid State Logic SSL2 */ - case USB_ID(0x31e9, 0x0002): /* Solid State Logic SSL2+ */ - case USB_ID(0x0499, 0x172f): /* Steinberg UR22C */ - case USB_ID(0x0d9a, 0x00df): /* RTX6001 */ - ep = 0x81; - ifnum = 2; - goto add_sync_ep_from_ifnum; - case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ - case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ - ep = 0x82; - ifnum = 0; - goto add_sync_ep_from_ifnum; - case USB_ID(0x0582, 0x01d8): /* BOSS Katana */ - /* BOSS Katana amplifiers do not need quirks */ - return 0; - case USB_ID(0x0582, 0x01e5): /* BOSS GT-001 */ - /* BOSS GT-001 needs no implicit fb for playback */ - return 0; - } - - /* Generic UAC2 implicit feedback */ - if (attr == USB_ENDPOINT_SYNC_ASYNC && - altsd->bInterfaceClass == USB_CLASS_AUDIO && - altsd->bInterfaceProtocol == UAC_VERSION_2 && - altsd->bNumEndpoints == 1) { - ifnum = altsd->bInterfaceNumber + 1; - if (search_generic_implicit_fb(chip, ifnum, - altsd->bAlternateSetting, - &alts, &ep)) - goto add_sync_ep; - } - - /* Roland/BOSS implicit feedback with vendor spec class */ - if (attr == USB_ENDPOINT_SYNC_ASYNC && - altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && - altsd->bInterfaceProtocol == 2 && - altsd->bNumEndpoints == 1 && - USB_ID_VENDOR(chip->usb_id) == 0x0582 /* Roland */) { - ifnum = altsd->bInterfaceNumber + 1; - if (search_roland_implicit_fb(chip, ifnum, - altsd->bAlternateSetting, - &alts, &ep)) - goto add_sync_ep; - } - - /* No quirk */ - return 0; - -add_sync_ep_from_ifnum: - iface = usb_ifnum_to_if(dev, ifnum); - - if (!iface || iface->num_altsetting < 2) - return 0; - - alts = &iface->altsetting[1]; - -add_sync_ep: - fmt->sync_ep = ep; - fmt->sync_iface = ifnum; - fmt->sync_altsetting = alts->desc.bAlternateSetting; - fmt->sync_ep_idx = 0; - fmt->implicit_fb = 1; - dev_dbg(&dev->dev, "%d:%d: found implicit_fb sync_ep=%x, iface=%d, alt=%d\n", - fmt->iface, fmt->altsetting, fmt->sync_ep, fmt->sync_iface, - fmt->sync_altsetting); - - return 1; -} - -static int audioformat_capture_quirk(struct snd_usb_audio *chip, - struct audioformat *fmt, - struct usb_host_interface *alts) -{ - struct usb_device *dev = chip->dev; - - switch (chip->usb_id) { - case USB_ID(0x0582, 0x01e5): /* BOSS GT-001 */ - if (!snd_usb_get_host_interface(chip, 0x01, 0x01)) - return 0; - fmt->sync_ep = 0x0d; - fmt->sync_iface = 0x01; - fmt->sync_altsetting = 0x01; - fmt->sync_ep_idx = 0; - fmt->implicit_fb = 1; - dev_dbg(&dev->dev, "%d:%d: added fake capture sync sync_ep=%x, iface=%d, alt=%d\n", - fmt->iface, fmt->altsetting, fmt->sync_ep, fmt->sync_iface, - fmt->sync_altsetting); - return 1; - } - return 0; - -} - +/* Set up sync endpoint */ int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, struct audioformat *fmt) { @@ -496,20 +293,18 @@ int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, return 0; altsd = get_iface_desc(alts); - is_playback = !(get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN); - if (is_playback) { - err = audioformat_implicit_fb_quirk(chip, fmt, alts); - if (err > 0) - return 0; - } else { - err = audioformat_capture_quirk(chip, fmt, alts); - if (err > 0) - return 0; - } + err = snd_usb_parse_implicit_fb_quirk(chip, fmt, alts); + if (err > 0) + return 0; /* matched */ + + /* + * Generic sync EP handling + */ if (altsd->bNumEndpoints < 2) return 0; + is_playback = !(get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN); attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; if ((is_playback && (attr == USB_ENDPOINT_SYNC_SYNC || attr == USB_ENDPOINT_SYNC_ADAPTIVE)) || @@ -569,45 +364,6 @@ int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip, return 0; } -/* - * Return the score of matching two audioformats. - * Veto the audioformat if: - * - It has no channels for some reason. - * - Requested PCM format is not supported. - * - Requested sample rate is not supported. - */ -static int match_endpoint_audioformats(struct snd_usb_substream *subs, - const struct audioformat *fp, - int rate, int channels, - snd_pcm_format_t pcm_format) -{ - int i, score; - - if (fp->channels < 1) - return 0; - - if (!(fp->formats & pcm_format_to_bits(pcm_format))) - return 0; - - if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { - if (rate < fp->rate_min || rate > fp->rate_max) - return 0; - } else { - for (i = 0; i < fp->nr_rates; i++) { - if (fp->rate_table[i] == rate) - break; - } - if (i >= fp->nr_rates) - return 0; - } - - score = 1; - if (fp->channels == channels) - score++; - - return score; -} - static int snd_usb_pcm_change_state(struct snd_usb_substream *subs, int state) { int ret; @@ -656,53 +412,6 @@ int snd_usb_pcm_resume(struct snd_usb_stream *as) return 0; } -static struct snd_usb_substream * -find_matching_substream(struct snd_usb_audio *chip, int stream, int ep_num, - int fmt_type) -{ - struct snd_usb_stream *as; - struct snd_usb_substream *subs; - - list_for_each_entry(as, &chip->pcm_list, list) { - subs = &as->substream[stream]; - if (as->fmt_type == fmt_type && subs->ep_num == ep_num) - return subs; - } - - return NULL; -} - -static const struct audioformat * -find_implicit_fb_sync_format(struct snd_usb_audio *chip, - const struct audioformat *target, - const struct snd_pcm_hw_params *params, - int stream) -{ - struct snd_usb_substream *subs; - const struct audioformat *fp, *sync_fmt; - int score, high_score; - - subs = find_matching_substream(chip, stream, target->sync_ep, - target->fmt_type); - if (!subs) - return NULL; - - sync_fmt = NULL; - high_score = 0; - list_for_each_entry(fp, &subs->fmt_list, list) { - score = match_endpoint_audioformats(subs, fp, - params_rate(params), - params_channels(params), - params_format(params)); - if (score > high_score) { - sync_fmt = fp; - high_score = score; - } - } - - return sync_fmt; -} - static void close_endpoints(struct snd_usb_audio *chip, struct snd_usb_substream *subs) { @@ -775,11 +484,10 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, goto stop_pipeline; } - if (fmt->implicit_fb && - (fmt->iface != fmt->sync_iface || - fmt->altsetting != fmt->sync_altsetting)) { - sync_fmt = find_implicit_fb_sync_format(chip, fmt, hw_params, - !substream->stream); + if (fmt->implicit_fb) { + sync_fmt = snd_usb_find_implicit_fb_sync_format(chip, fmt, + hw_params, + !substream->stream); if (!sync_fmt) { usb_audio_dbg(chip, "cannot find sync format: ep=0x%x, iface=%d:%d, format=%s, rate=%d, channels=%d\n", -- cgit v1.2.3 From 83b7dcbc51c930fc2079ab6c6fc9d719768321f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:44 +0100 Subject: ALSA: usb-audio: Add generic implicit fb parsing This patch extends the implicit feedback mode parser code to check the description more generically, so that the quirk entries can be added without the explicit EP and interface numbers. The search is done for the next and the previous interface of the given altset, and if both entries are ASYNC mode and the direction matches, it just takes as the sync endpoint. The generic parser is applicable only for the playback stream. As of now, only a few M-Audio devices have been converted to use this mode. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-39-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index bc7edecff946..16b1fb55b7b9 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -19,6 +19,7 @@ enum { IMPLICIT_FB_NONE, + IMPLICIT_FB_GENERIC, IMPLICIT_FB_FIXED, }; @@ -30,6 +31,8 @@ struct snd_usb_implicit_fb_match { int type; }; +#define IMPLICIT_FB_GENERIC_DEV(vend, prod) \ + { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_GENERIC } #define IMPLICIT_FB_FIXED_DEV(vend, prod, ep, ifnum) \ { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_FIXED, .ep_num = (ep),\ .iface = (ifnum) } @@ -38,19 +41,22 @@ struct snd_usb_implicit_fb_match { /* Implicit feedback quirk table for playback */ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { + /* Generic matching */ + IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2080), /* M-Audio FastTrack Ultra */ + IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2081), /* M-Audio FastTrack Ultra */ + IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2030), /* M-Audio Fast Track C400 */ + IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2031), /* M-Audio Fast Track C600 */ + /* Fixed EP */ + /* FIXME: check the availability of generic matching */ IMPLICIT_FB_FIXED_DEV(0x1397, 0x0001, 0x81, 1), /* Behringer UFX1604 */ IMPLICIT_FB_FIXED_DEV(0x1397, 0x0002, 0x81, 1), /* Behringer UFX1204 */ - IMPLICIT_FB_FIXED_DEV(0x0763, 0x2080, 0x81, 2), /* M-Audio FastTrack Ultra */ - IMPLICIT_FB_FIXED_DEV(0x0763, 0x2081, 0x81, 2), /* M-Audio FastTrack Ultra */ IMPLICIT_FB_FIXED_DEV(0x2466, 0x8010, 0x81, 2), /* Fractal Audio Axe-Fx III */ IMPLICIT_FB_FIXED_DEV(0x07fd, 0x0008, 0x81, 2), /* MOTU M Series */ IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0001, 0x81, 2), /* Solid State Logic SSL2 */ IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */ IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */ IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */ - IMPLICIT_FB_FIXED_DEV(0x0763, 0x2030, 0x81, 3), /* M-Audio Fast Track C400 */ - IMPLICIT_FB_FIXED_DEV(0x0763, 0x2031, 0x81, 3), /* M-Audio Fast Track C600 */ IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */ IMPLICIT_FB_FIXED_DEV(0x2b73, 0x000a, 0x82, 0), /* Pioneer DJ DJM-900NXS2 */ IMPLICIT_FB_FIXED_DEV(0x2b73, 0x0017, 0x82, 0), /* Pioneer DJ DJM-250MK2 */ @@ -75,7 +81,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { {} /* terminator */ }; -/* Implicit feedback quirk table for capture */ +/* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { IMPLICIT_FB_FIXED_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ @@ -162,6 +168,47 @@ static int add_roland_implicit_fb(struct snd_usb_audio *chip, ifnum, alts); } + +static int __add_generic_implicit_fb(struct snd_usb_audio *chip, + struct audioformat *fmt, + int iface, int altset) +{ + struct usb_host_interface *alts; + struct usb_endpoint_descriptor *epd; + + alts = snd_usb_get_host_interface(chip, iface, altset); + if (!alts) + return 0; + + if ((alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC && + alts->desc.bInterfaceClass != USB_CLASS_AUDIO) || + alts->desc.bNumEndpoints < 1) + return 0; + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_in(epd) || + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return 0; + return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, + iface, alts); +} + +/* More generic quirk: look for the sync EP next to the data EP */ +static int add_generic_implicit_fb(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts) +{ + if ((fmt->ep_attr & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return 0; + + if (__add_generic_implicit_fb(chip, fmt, + alts->desc.bInterfaceNumber + 1, + alts->desc.bAlternateSetting)) + return 1; + return __add_generic_implicit_fb(chip, fmt, + alts->desc.bInterfaceNumber - 1, + alts->desc.bAlternateSetting); +} + static const struct snd_usb_implicit_fb_match * find_implicit_fb_entry(struct snd_usb_audio *chip, const struct snd_usb_implicit_fb_match *match, @@ -189,6 +236,8 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, p = find_implicit_fb_entry(chip, playback_implicit_fb_quirks, alts); if (p) { switch (p->type) { + case IMPLICIT_FB_GENERIC: + return add_generic_implicit_fb(chip, fmt, alts); case IMPLICIT_FB_NONE: return 0; /* No quirk */ case IMPLICIT_FB_FIXED: -- cgit v1.2.3 From 62abd092f97b33a33fcdb98c30bc01f2b1c55d04 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:45 +0100 Subject: ALSA: usb-audio: Add implicit_fb module option A new module option, implicit_fb, is added to specify the driver looking for the implicit feedback sync. This can be useful for a device that could be working better in the implicit feed back mode and user wants to test it quickly. When this works, we can add the quirk entry easily. Tested-by: Keith Milner Tested-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-40-tiwai@suse.de Signed-off-by: Takashi Iwai --- Documentation/sound/alsa-configuration.rst | 5 +++++ sound/usb/card.c | 4 ++++ sound/usb/implicit.c | 4 ++++ sound/usb/usbaudio.h | 1 + 4 files changed, 14 insertions(+) (limited to 'sound') diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index c755b1c5e16f..fe52c314b763 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -2227,6 +2227,11 @@ quirk_alias Quirk alias list, pass strings like ``0123abcd:5678beef``, which applies the existing quirk for the device 5678:beef to a new device 0123:abcd. +implicit_fb + Apply the generic implicit feedback sync mode. When this is set + and the playback stream sync mode is ASYNC, the driver tries to + tie an adjacent ASYNC capture stream as the implicit feedback + source. use_vmalloc Use vmalloc() for allocations of the PCM buffers (default: yes). For architectures with non-coherent memory like ARM or MIPS, the diff --git a/sound/usb/card.c b/sound/usb/card.c index 7940b3bff5bc..cb0b6582dfee 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -72,6 +72,7 @@ static bool ignore_ctl_error; static bool autoclock = true; static char *quirk_alias[SNDRV_CARDS]; static char *delayed_register[SNDRV_CARDS]; +static bool implicit_fb[SNDRV_CARDS]; bool snd_usb_use_vmalloc = true; bool snd_usb_skip_validation; @@ -97,6 +98,8 @@ module_param_array(quirk_alias, charp, NULL, 0444); MODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef."); module_param_array(delayed_register, charp, NULL, 0444); MODULE_PARM_DESC(delayed_register, "Quirk for delayed registration, given by id:iface, e.g. 0123abcd:4."); +module_param_array(implicit_fb, bool, NULL, 0444); +MODULE_PARM_DESC(implicit_fb, "Apply generic implicit feedback sync mode."); module_param_named(use_vmalloc, snd_usb_use_vmalloc, bool, 0444); MODULE_PARM_DESC(use_vmalloc, "Use vmalloc for PCM intermediate buffers (default: yes)."); module_param_named(skip_validation, snd_usb_skip_validation, bool, 0444); @@ -596,6 +599,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, chip->dev = dev; chip->card = card; chip->setup = device_setup[idx]; + chip->generic_implicit_fb = implicit_fb[idx]; chip->autoclock = autoclock; atomic_set(&chip->active, 1); /* avoid autopm during probing */ atomic_set(&chip->usage_count, 0); diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 16b1fb55b7b9..1d87fcdae95b 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -269,6 +269,10 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, return 1; } + /* Try the generic implicit fb if available */ + if (chip->generic_implicit_fb) + return add_generic_implicit_fb(chip, fmt, alts); + /* No quirk */ return 0; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index cc338e8e2597..980287aadd36 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -51,6 +51,7 @@ struct snd_usb_audio { struct list_head mixer_list; /* list of mixer interfaces */ int setup; /* from the 'device_setup' module param */ + bool generic_implicit_fb; /* from the 'implicit_fb' module param */ bool autoclock; /* from the 'autoclock' module param */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ -- cgit v1.2.3 From ad0e6a3511824f8fdbe3eb63dbabc0ef35e732b9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Nov 2020 09:53:46 +0100 Subject: ALSA: usb-audio: Fix quirks for other BOSS devices A few other BOSS devices (BR-80, GT-100v2, Katana) seem requiring the same quirk as BOSS GT-001, i.e. no implicit feedback for playback but tying with capture. Add and correct the corresponding quirk table entries for them. Reported-and-tested-by: Keith Milner Link: https://lore.kernel.org/r/20201123085347.19667-41-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 1d87fcdae95b..1f7fb036c5b6 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -72,10 +72,10 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { .type = IMPLICIT_FB_FIXED, .ep_num = 0x84, .iface = 0 }, /* MOTU MicroBook II */ - /* No quirk */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8), /* BOSS Katana */ - /* No quirk for playback but with capture quirk (see below) */ + IMPLICIT_FB_SKIP_DEV(0x0582, 0x0130), /* BOSS BR-80 */ + IMPLICIT_FB_SKIP_DEV(0x0582, 0x0189), /* BOSS GT-100v2 */ + IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8), /* BOSS Katana */ IMPLICIT_FB_SKIP_DEV(0x0582, 0x01e5), /* BOSS GT-001 */ {} /* terminator */ @@ -83,6 +83,9 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ IMPLICIT_FB_FIXED_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ {} /* terminator */ -- cgit v1.2.3 From 29b105d947c661e521bf7b1005868c02441732be Mon Sep 17 00:00:00 2001 From: Dylan Robinson Date: Mon, 23 Nov 2020 09:53:47 +0100 Subject: ALSA: usb-audio: Fix MOTU M-Series quirks Now that the usb audio driver correctly finds implicit feedback endpoints, the implicit feedback quirk for the MOTU M-Series is no longer required. This also removes some unnecessary vendor specific messages from the MOTU M-Series boot quirk. The removed vendor specific messages turned on vendor specific interrupts to the host every 32 samples. The only thing the boot quirk needs to do is wait for 2 seconds. Tested-by: Dylan Robinson Signed-off-by: Dylan Robinson Link: https://lore.kernel.org/r/20201123085347.19667-42-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 1 - sound/usb/quirks.c | 16 ---------------- 2 files changed, 17 deletions(-) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 1f7fb036c5b6..386198b36b87 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -52,7 +52,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { IMPLICIT_FB_FIXED_DEV(0x1397, 0x0001, 0x81, 1), /* Behringer UFX1604 */ IMPLICIT_FB_FIXED_DEV(0x1397, 0x0002, 0x81, 1), /* Behringer UFX1204 */ IMPLICIT_FB_FIXED_DEV(0x2466, 0x8010, 0x81, 2), /* Fractal Audio Axe-Fx III */ - IMPLICIT_FB_FIXED_DEV(0x07fd, 0x0008, 0x81, 2), /* MOTU M Series */ IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0001, 0x81, 2), /* Solid State Logic SSL2 */ IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */ IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 02f3f6ed9390..63cdf3c8c2bc 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1110,24 +1110,8 @@ free_buf: static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev) { - int ret; - - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 1, USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0, 0, NULL, 0, 1000); - - if (ret < 0) - return ret; - msleep(2000); - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 1, USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x20, 0, NULL, 0, 1000); - - if (ret < 0) - return ret; - return 0; } -- cgit v1.2.3 From 25ce4f2b3593fa6bba70ddabbd2ee297b262784f Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Wed, 18 Nov 2020 12:38:52 +0800 Subject: ASoC: hdmi-codec: Get ELD in before reporting plugged event In plugged callback, ELD should be updated from display driver so that user space can query information from ELD immediately after receiving jack plugged event. When jack is unplugged, clear ELD buffer so that user space does not get obsolete information of unplugged HDMI. Signed-off-by: Cheng-Yi Chiang Link: https://lore.kernel.org/r/20201118043852.1338877-1-cychiang@chromium.org Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 403d4c6a49a8..e8410b2433de 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -692,10 +692,16 @@ static void plugged_cb(struct device *dev, bool plugged) { struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); - if (plugged) + if (plugged) { + if (hcp->hcd.ops->get_eld) { + hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data, + hcp->eld, sizeof(hcp->eld)); + } hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); - else + } else { hdmi_codec_jack_report(hcp, 0); + memset(hcp->eld, 0, sizeof(hcp->eld)); + } } static int hdmi_codec_set_jack(struct snd_soc_component *component, -- cgit v1.2.3 From c3d900dc905b78788c94f3a063b769bdbad16a98 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 16 Nov 2020 18:51:31 +0100 Subject: ASoC: sh: depend on COMMON_CLK to fix compile tests The SH4 FSI sound drivers use SuperH clocks thus they cannot be built on platforms without proper clock support (e.g. compile test on MIPS with RALINK and SOC_RT305X): /usr/bin/mips-linux-gnu-ld: sound/soc/sh/fsi.o: in function `fsi_clk_set_rate_external': fsi.c:(.text+0x2714): undefined reference to `clk_set_parent' Reported-by: kernel test robot Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201116175133.402553-2-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index ef8a29b9f641..346c806ba390 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -23,6 +23,7 @@ config SND_SOC_SH4_SSI config SND_SOC_SH4_FSI tristate "SH4 FSI support" + depends on SUPERH || COMMON_CLK select SND_SIMPLE_CARD help This option enables FSI sound support -- cgit v1.2.3 From 82ceffce96336ee9863f3dfde63aef5748ca4ab1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 16 Nov 2020 18:51:32 +0100 Subject: ASoC: stm: depend on COMMON_CLK to fix compile tests The STM32 I2S drivers use Common Clock Framework thus they cannot be built on platforms without it (e.g. compile test on MIPS with RALINK and SOC_RT305X): /usr/bin/mips-linux-gnu-ld: sound/soc/stm/stm32_i2s.o: in function `stm32_i2s_hw_params': stm32_i2s.c:(.text+0x1870): undefined reference to `clk_set_parent' Reported-by: kernel test robot Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201116175133.402553-3-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/stm/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index bbade257fe89..da1f7a16605b 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -15,6 +15,7 @@ config SND_SOC_STM32_SAI config SND_SOC_STM32_I2S tristate "STM32 I2S interface (SPI/I2S block) support" depends on (ARCH_STM32 && OF) || COMPILE_TEST + depends on COMMON_CLK depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO -- cgit v1.2.3 From b3cf78e0dacb7fba50d0c1eb9dfa6f92d31529e2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 16 Nov 2020 18:51:33 +0100 Subject: ASoC: ti: depend on COMMON_CLK to fix compile tests The TI/OMAP sound drivers use Common Clock Framework thus they cannot be built on platforms without it (e.g. compile test on MIPS with RALINK and SOC_RT305X): /usr/bin/mips-linux-gnu-ld: sound/soc/ti/davinci-mcasp.o:davinci-mcasp.c:(.text+0x1c64): more undefined references to `clk_set_parent' follow /usr/bin/mips-linux-gnu-ld: sound/soc/ti/omap-dmic.o: in function `omap_dmic_set_dai_sysclk': omap-dmic.c:(.text+0xa5c): undefined reference to `clk_get_parent' Reported-by: kernel test robot Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201116175133.402553-4-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/ti/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig index 9775393d46b6..698d7bc84dcf 100644 --- a/sound/soc/ti/Kconfig +++ b/sound/soc/ti/Kconfig @@ -26,6 +26,7 @@ config SND_SOC_DAVINCI_ASP config SND_SOC_DAVINCI_MCASP tristate "Multichannel Audio Serial Port (McASP) support" + depends on COMMON_CLK select SND_SOC_TI_EDMA_PCM select SND_SOC_TI_SDMA_PCM select SND_SOC_TI_UDMA_PCM @@ -47,7 +48,7 @@ config SND_SOC_DAVINCI_VCIF config SND_SOC_OMAP_DMIC tristate "Digital Microphone Module (DMIC) support" - depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST + depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST && COMMON_CLK select SND_SOC_TI_SDMA_PCM help Say Y or M here if you want to have support for DMIC IP found in @@ -55,7 +56,7 @@ config SND_SOC_OMAP_DMIC config SND_SOC_OMAP_MCBSP tristate "Multichannel Buffered Serial Port (McBSP) support" - depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST + depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST && COMMON_CLK select SND_SOC_TI_SDMA_PCM help Say Y or M here if you want to have support for McBSP IP found in @@ -99,7 +100,7 @@ config SND_SOC_OMAP3_PANDORA config SND_SOC_OMAP3_TWL4030 tristate "SoC Audio support for OMAP3 based boards with twl4030 codec" - depends on ARCH_OMAP3 || COMPILE_TEST + depends on ARCH_OMAP3 || COMPILE_TEST && COMMON_CLK depends on TWL4030_CORE select SND_SOC_OMAP_MCBSP select SND_SOC_TWL4030 @@ -221,7 +222,7 @@ config SND_SOC_DM365_VOICE_CODEC_MODULE config SND_SOC_J721E_EVM tristate "SoC Audio support for j721e EVM" - depends on ARCH_K3 || COMPILE_TEST + depends on ARCH_K3 || COMPILE_TEST && COMMON_CLK depends on I2C select SND_SOC_PCM3168A_I2C select SND_SOC_DAVINCI_MCASP -- cgit v1.2.3 From 6a8b8b582db13a18235f3b0400f103a0573c7859 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 23 Nov 2020 17:09:17 -0300 Subject: ASoC: imx-audmux: Remove unused .id_table Since 5.10-rc1 i.MX is a devicetree-only platform and the existing .id_table support in this driver was only useful for old non-devicetree platforms. Get rid of the .id_table since it is no longer used. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20201123200917.16447-1-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audmux.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 25c18b9e348f..dfa05d40b276 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -170,22 +170,9 @@ static enum imx_audmux_type { IMX31_AUDMUX, } audmux_type; -static const struct platform_device_id imx_audmux_ids[] = { - { - .name = "imx21-audmux", - .driver_data = IMX21_AUDMUX, - }, { - .name = "imx31-audmux", - .driver_data = IMX31_AUDMUX, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, imx_audmux_ids); - static const struct of_device_id imx_audmux_dt_ids[] = { - { .compatible = "fsl,imx21-audmux", .data = &imx_audmux_ids[0], }, - { .compatible = "fsl,imx31-audmux", .data = &imx_audmux_ids[1], }, + { .compatible = "fsl,imx21-audmux", .data = (void *)IMX21_AUDMUX, }, + { .compatible = "fsl,imx31-audmux", .data = (void *)IMX31_AUDMUX, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids); @@ -300,9 +287,6 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, static int imx_audmux_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(imx_audmux_dt_ids, &pdev->dev); - audmux_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(audmux_base)) return PTR_ERR(audmux_base); @@ -314,9 +298,7 @@ static int imx_audmux_probe(struct platform_device *pdev) audmux_clk = NULL; } - if (of_id) - pdev->id_entry = of_id->data; - audmux_type = pdev->id_entry->driver_data; + audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev); switch (audmux_type) { case IMX31_AUDMUX: @@ -335,8 +317,7 @@ static int imx_audmux_probe(struct platform_device *pdev) if (!regcache) return -ENOMEM; - if (of_id) - imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node); + imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node); return 0; } @@ -386,7 +367,6 @@ static const struct dev_pm_ops imx_audmux_pm = { static struct platform_driver imx_audmux_driver = { .probe = imx_audmux_probe, .remove = imx_audmux_remove, - .id_table = imx_audmux_ids, .driver = { .name = DRIVER_NAME, .pm = &imx_audmux_pm, -- cgit v1.2.3 From 7f09f79d5cb13186b0f422cf2e1c711c88c92195 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 24 Nov 2020 20:00:14 +0200 Subject: ASoC: SOF: ext_manifest: Parse firmware config dictionary Values given in this dictionary describes used firmware configuration, like feature availability, buffer size limits and similar properties. Signed-off-by: Karol Trzcinski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201124180017.2232128-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ext_manifest.h | 19 +++++++++++++++++++ sound/soc/sof/loader.c | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) (limited to 'sound') diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index 342e86e54db5..31da6e611c6e 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -61,6 +61,7 @@ enum sof_ext_man_elem_type { SOF_EXT_MAN_ELEM_WINDOW = SOF_IPC_EXT_WINDOW, SOF_EXT_MAN_ELEM_CC_VERSION = SOF_IPC_EXT_CC_INFO, SOF_EXT_MAN_ELEM_DBG_ABI = SOF_IPC_EXT_USER_ABI_INFO, + SOF_EXT_MAN_ELEM_CONFIG_DATA = 5, /**< ABI3.17 */ }; /* extended manifest element header */ @@ -99,4 +100,22 @@ struct ext_man_dbg_abi { struct sof_ipc_user_abi_version dbg_abi; } __packed; +/* EXT_MAN_ELEM_CONFIG_DATA elements identificators, ABI3.17 */ +enum config_elem_type { + SOF_EXT_MAN_CONFIG_EMPTY = 0, + SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE = 1, +}; + +struct sof_config_elem { + uint32_t token; + uint32_t value; +} __packed; + +/* firmware configuration information */ +struct sof_ext_man_config_data { + struct sof_ext_man_elem_header hdr; + + struct sof_config_elem elems[]; +} __packed; + #endif /* __SOF_FIRMWARE_EXT_MANIFEST_H__ */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index ce68d708fc6f..33d3be774380 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -197,6 +197,44 @@ static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev, return 0; } +static int ext_man_get_config_data(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr) +{ + const struct sof_ext_man_config_data *config = + container_of(hdr, struct sof_ext_man_config_data, hdr); + const struct sof_config_elem *elem; + int elems_counter; + int elems_size; + int i; + + /* calculate elements counter */ + elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header); + elems_counter = elems_size / sizeof(struct sof_config_elem); + + dev_dbg(sdev->dev, "%s can hold up to %d config elements\n", + __func__, elems_counter); + + for (i = 0; i < elems_counter; ++i) { + elem = &config->elems[i]; + dev_dbg(sdev->dev, "%s get index %d token %d val %d\n", + __func__, i, elem->token, elem->value); + switch (elem->token) { + case SOF_EXT_MAN_CONFIG_EMPTY: + /* unused memory space is zero filled - mapped to EMPTY elements */ + break; + case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE: + /* TODO: use ipc msg size from config data */ + break; + default: + dev_info(sdev->dev, "Unknown firmware configuration token %d value %d", + elem->token, elem->value); + break; + } + } + + return 0; +} + static ssize_t snd_sof_ext_man_size(const struct firmware *fw) { const struct sof_ext_man_header *head; @@ -279,6 +317,9 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev, case SOF_EXT_MAN_ELEM_DBG_ABI: ret = ext_man_get_dbg_abi_info(sdev, elem_hdr); break; + case SOF_EXT_MAN_ELEM_CONFIG_DATA: + ret = ext_man_get_config_data(sdev, elem_hdr); + break; default: dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n", elem_hdr->type, elem_hdr->size); -- cgit v1.2.3 From 5b10b62989219aa527ee4fa555d1995a3b70981b Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 24 Nov 2020 20:00:17 +0200 Subject: ASoC: SOF: Add `memory_info` file to debugfs This file content describes memory allocation status at run-time, typically to detect memory leaks. Signed-off-by: Karol Trzcinski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201124180017.2232128-5-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/debug.h | 41 ++++++++++++++ include/sound/sof/ext_manifest.h | 1 + include/sound/sof/header.h | 4 ++ include/uapi/sound/sof/abi.h | 2 +- sound/soc/sof/debug.c | 117 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc.c | 9 +++ sound/soc/sof/loader.c | 10 ++++ sound/soc/sof/sof-priv.h | 2 + 8 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 include/sound/sof/debug.h (limited to 'sound') diff --git a/include/sound/sof/debug.h b/include/sound/sof/debug.h new file mode 100644 index 000000000000..3ecb5793789d --- /dev/null +++ b/include/sound/sof/debug.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + */ + +#ifndef __INCLUDE_SOUND_SOF_DEBUG_H__ +#define __INCLUDE_SOUND_SOF_DEBUG_H__ + +#include + +/** ABI3.18 */ +enum sof_ipc_dbg_mem_zone { + SOF_IPC_MEM_ZONE_SYS = 0, /**< System zone */ + SOF_IPC_MEM_ZONE_SYS_RUNTIME = 1, /**< System-runtime zone */ + SOF_IPC_MEM_ZONE_RUNTIME = 2, /**< Runtime zone */ + SOF_IPC_MEM_ZONE_BUFFER = 3, /**< Buffer zone */ +}; + +/** ABI3.18 */ +struct sof_ipc_dbg_mem_usage_elem { + uint32_t zone; /**< see sof_ipc_dbg_mem_zone */ + uint32_t id; /**< heap index within zone */ + uint32_t used; /**< number of bytes used in zone */ + uint32_t free; /**< number of bytes free to use within zone */ + uint32_t reserved; /**< for future use */ +} __packed; + +/** ABI3.18 */ +struct sof_ipc_dbg_mem_usage { + struct sof_ipc_reply rhdr; /**< generic IPC reply header */ + uint32_t reserved[4]; /**< reserved for future use */ + uint32_t num_elems; /**< elems[] counter */ + struct sof_ipc_dbg_mem_usage_elem elems[]; /**< memory usage information */ +} __packed; + +#endif diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index 31da6e611c6e..e05cb21023e5 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -104,6 +104,7 @@ struct ext_man_dbg_abi { enum config_elem_type { SOF_EXT_MAN_CONFIG_EMPTY = 0, SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE = 1, + SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN = 2, /**< ABI 3.18 */ }; struct sof_config_elem { diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 13256d4fb0dd..c93f08334bbe 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -52,6 +52,7 @@ #define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU) #define SOF_IPC_GLB_TEST_MSG SOF_GLB_TYPE(0xBU) #define SOF_IPC_GLB_PROBE SOF_GLB_TYPE(0xCU) +#define SOF_IPC_GLB_DEBUG SOF_GLB_TYPE(0xDU) /* * DSP Command Message Types @@ -118,6 +119,9 @@ #define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) #define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) +/* debug */ +#define SOF_IPC_DEBUG_MEM_USAGE SOF_CMD_TYPE(0x001) + /* test */ #define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001) diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 6af32f82fb99..fe2cfae94b45 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 17 +#define SOF_ABI_MINOR 18 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 9419a99bab53..143117334ae5 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "sof-priv.h" #include "ops.h" @@ -626,6 +628,121 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, } EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item); +static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_size) +{ + struct sof_ipc_cmd_hdr msg = { + .size = sizeof(struct sof_ipc_cmd_hdr), + .cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE, + }; + struct sof_ipc_dbg_mem_usage *reply; + int len; + int ret; + int i; + + reply = kmalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + if (!reply) + return -ENOMEM; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0 && ret != -EACCES) { + pm_runtime_put_noidle(sdev->dev); + dev_err(sdev->dev, "error: enabling device failed: %d\n", ret); + goto error; + } + + ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE); + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_put_autosuspend(sdev->dev); + if (ret < 0 || reply->rhdr.error < 0) { + ret = min(ret, reply->rhdr.error); + dev_err(sdev->dev, "error: reading memory info failed, %d\n", ret); + goto error; + } + + if (struct_size(reply, elems, reply->num_elems) != reply->rhdr.hdr.size) { + dev_err(sdev->dev, "error: invalid memory info ipc struct size, %d\n", + reply->rhdr.hdr.size); + ret = -EINVAL; + goto error; + } + + for (i = 0, len = 0; i < reply->num_elems; i++) { + ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n", + reply->elems[i].zone, reply->elems[i].id, + reply->elems[i].used, reply->elems[i].free); + if (ret < 0) + goto error; + len += ret; + } + + ret = len; +error: + kfree(reply); + return ret; +} + +static ssize_t memory_info_read(struct file *file, char __user *to, size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + int data_length; + + /* read memory info from FW only once for each file read */ + if (!*ppos) { + dfse->buf_data_size = 0; + data_length = memory_info_update(sdev, dfse->buf, dfse->size); + if (data_length < 0) + return data_length; + dfse->buf_data_size = data_length; + } + + return simple_read_from_buffer(to, count, ppos, dfse->buf, dfse->buf_data_size); +} + +static int memory_info_open(struct inode *inode, struct file *file) +{ + struct snd_sof_dfsentry *dfse = inode->i_private; + struct snd_sof_dev *sdev = dfse->sdev; + + file->private_data = dfse; + + /* allocate buffer memory only in first open run, to save memory when unused */ + if (!dfse->buf) { + dfse->buf = devm_kmalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); + if (!dfse->buf) + return -ENOMEM; + dfse->size = PAGE_SIZE; + } + + return 0; +} + +static const struct file_operations memory_info_fops = { + .open = memory_info_open, + .read = memory_info_read, + .llseek = default_llseek, +}; + +int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev) +{ + struct snd_sof_dfsentry *dfse; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + /* don't allocate buffer before first usage, to save memory when unused */ + dfse->type = SOF_DFSENTRY_TYPE_BUF; + dfse->sdev = sdev; + + debugfs_create_file("memory_info", 0444, sdev->debugfs_root, dfse, &memory_info_fops); + + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); + return 0; +} +EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init); + int snd_sof_dbg_init(struct snd_sof_dev *sdev) { const struct snd_sof_dsp_ops *ops = sof_ops(sdev); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index fd2b96ae4943..fc13bb06dbf3 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -181,6 +181,15 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) str2 = "unknown type"; break; } break; + case SOF_IPC_GLB_DEBUG: + str = "GLB_DEBUG"; + switch (type) { + case SOF_IPC_DEBUG_MEM_USAGE: + str2 = "MEM_USAGE"; break; + default: + str2 = "unknown type"; break; + } + break; default: str = "unknown GLB command"; break; } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 33d3be774380..2a8c9bff9963 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -205,6 +205,7 @@ static int ext_man_get_config_data(struct snd_sof_dev *sdev, const struct sof_config_elem *elem; int elems_counter; int elems_size; + int ret = 0; int i; /* calculate elements counter */ @@ -225,11 +226,20 @@ static int ext_man_get_config_data(struct snd_sof_dev *sdev, case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE: /* TODO: use ipc msg size from config data */ break; + case SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN: + if (sdev->first_boot && elem->value) + ret = snd_sof_dbg_memory_info_init(sdev); + break; default: dev_info(sdev->dev, "Unknown firmware configuration token %d value %d", elem->token, elem->value); break; } + if (ret < 0) { + dev_err(sdev->dev, "error: processing sof_ext_man_config_data failed for token %d value 0x%x, %d\n", + elem->token, elem->value, ret); + return ret; + } } return 0; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0aed2a7ab858..d8bc0178dc89 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -290,6 +290,7 @@ enum sof_debugfs_access_type { /* FS entry for debug files that can expose DSP memories, registers */ struct snd_sof_dfsentry { size_t size; + size_t buf_data_size; /* length of buffered data for file read operation */ enum sof_dfsentry_type type; /* * access_type specifies if the @@ -523,6 +524,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, void *stack, size_t stack_words); int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); +int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev); /* * Platform specific ops. -- cgit v1.2.3 From 373c2cebf42772434c8dd0deffc3b3886ea8f1eb Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Tue, 24 Nov 2020 16:19:57 +0200 Subject: ASoC: fsl_xcvr: fix potential resource leak "fw" variable must be relased before return. Signed-off-by: Viorel Suman Link: https://lore.kernel.org/r/20201124141957.20481-1-viorel.suman@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_xcvr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 2a28810d0e29..3d58c88ea603 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -706,6 +706,7 @@ static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) /* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */ if (rem > 16384) { dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem); + release_firmware(fw); return -ENOMEM; } -- cgit v1.2.3 From 9f34c04057232ca2688d26416d3f0011c5ea5377 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:14 +0100 Subject: ASoC: ak5558: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/codecs/ak5558.c:418:34: warning: ‘ak5558_i2c_dt_ids’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-2-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/ak5558.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 2f076d5ee284..8a32b0139cb0 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -415,7 +415,7 @@ static int ak5558_i2c_remove(struct i2c_client *i2c) return 0; } -static const struct of_device_id ak5558_i2c_dt_ids[] = { +static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = { { .compatible = "asahi-kasei,ak5558"}, { } }; -- cgit v1.2.3 From 1bab2b22675f2e4bd498a7688b681839a7ecece0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:15 +0100 Subject: ASoC: bd28623: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/codecs/bd28623.c:225:34: warning: ‘bd28623_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-3-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/bd28623.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/bd28623.c b/sound/soc/codecs/bd28623.c index 31904ef5c88b..a6267cb86d86 100644 --- a/sound/soc/codecs/bd28623.c +++ b/sound/soc/codecs/bd28623.c @@ -222,7 +222,7 @@ static int bd28623_probe(struct platform_device *pdev) &soc_dai_bd, 1); } -static const struct of_device_id bd28623_of_match[] = { +static const struct of_device_id bd28623_of_match[] __maybe_unused = { { .compatible = "rohm,bd28623", }, {} }; -- cgit v1.2.3 From 03219faf153c3adb93d68355a8ccbaa48e40735f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:16 +0100 Subject: ASoC: gtm601: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/codecs/gtm601.c:90:34: warning: ‘gtm601_codec_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-4-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/gtm601.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index ae9e1c70ca57..e1235e695b0f 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -87,7 +87,7 @@ static int gtm601_platform_probe(struct platform_device *pdev) (struct snd_soc_dai_driver *)dai_driver, 1); } -static const struct of_device_id gtm601_codec_of_match[] = { +static const struct of_device_id gtm601_codec_of_match[] __maybe_unused = { { .compatible = "option,gtm601", .data = (void *)>m601_dai }, { .compatible = "broadmobi,bm818", .data = (void *)&bm818_dai }, {}, -- cgit v1.2.3 From 66b9890634690c71910c8dd41f273e87f9bc4b4a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:17 +0100 Subject: ASoC: inno_rk3036: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/codecs/inno_rk3036.c:470:34: warning: ‘rk3036_codec_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-5-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/inno_rk3036.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index d0e8f0d2fbc1..4dbce24c5f76 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -467,7 +467,7 @@ static int rk3036_codec_platform_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id rk3036_codec_of_match[] = { +static const struct of_device_id rk3036_codec_of_match[] __maybe_unused = { { .compatible = "rockchip,rk3036-codec", }, {} }; -- cgit v1.2.3 From 84902aec0886e1a8fdd26ae6b8a65fb2c26018a8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:18 +0100 Subject: ASoC: rk3328: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/codecs/rk3328_codec.c:502:34: warning: ‘rk3328_codec_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-6-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/rk3328_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 940a2fa933ed..bfefefcc76d8 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -499,7 +499,7 @@ static int rk3328_platform_probe(struct platform_device *pdev) ARRAY_SIZE(rk3328_dai)); } -static const struct of_device_id rk3328_codec_of_match[] = { +static const struct of_device_id rk3328_codec_of_match[] __maybe_unused = { { .compatible = "rockchip,rk3328-codec", }, {}, }; -- cgit v1.2.3 From f38c0b1e8a63439edc234a65bb549d3c6e49e66e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:19 +0100 Subject: ASoC: tas571x: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/codecs/tas571x.c:892:34: warning: ‘tas571x_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-7-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas571x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index 835a723ce5bc..a3e682376946 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -773,7 +773,7 @@ static struct snd_soc_dai_driver tas571x_dai = { .ops = &tas571x_dai_ops, }; -static const struct of_device_id tas571x_of_match[]; +static const struct of_device_id tas571x_of_match[] __maybe_unused; static int tas571x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -889,7 +889,7 @@ static int tas571x_i2c_remove(struct i2c_client *client) return 0; } -static const struct of_device_id tas571x_of_match[] = { +static const struct of_device_id tas571x_of_match[] __maybe_unused = { { .compatible = "ti,tas5707", .data = &tas5707_chip, }, { .compatible = "ti,tas5711", .data = &tas5711_chip, }, { .compatible = "ti,tas5717", .data = &tas5717_chip, }, -- cgit v1.2.3 From d013a59a199e81582c6435a924a23ed393279b07 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:20 +0100 Subject: ASoC: kirkwood: armada-370-db: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/kirkwood/armada-370-db.c:137:34: warning: ‘a370db_dt_ids’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-8-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/kirkwood/armada-370-db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c index 8e44ae37ad1e..81326426da33 100644 --- a/sound/soc/kirkwood/armada-370-db.c +++ b/sound/soc/kirkwood/armada-370-db.c @@ -134,7 +134,7 @@ static int a370db_probe(struct platform_device *pdev) return devm_snd_soc_register_card(card->dev, card); } -static const struct of_device_id a370db_dt_ids[] = { +static const struct of_device_id a370db_dt_ids[] __maybe_unused = { { .compatible = "marvell,a370db-audio" }, { }, }; -- cgit v1.2.3 From b397f02171e6d6ca9b77e4cfec73c0dfe2345562 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:21 +0100 Subject: ASoC: meson: t9015: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/meson/t9015.c:315:34: warning: ‘t9015_ids’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-9-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/meson/t9015.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c index 56d2592c16d5..4c1349dd1e06 100644 --- a/sound/soc/meson/t9015.c +++ b/sound/soc/meson/t9015.c @@ -312,7 +312,7 @@ static int t9015_probe(struct platform_device *pdev) &t9015_dai, 1); } -static const struct of_device_id t9015_ids[] = { +static const struct of_device_id t9015_ids[] __maybe_unused = { { .compatible = "amlogic,t9015", }, { } }; -- cgit v1.2.3 From 377c7b7cc11d80acf85101416d1122135f997dc5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:22 +0100 Subject: ASoC: qcom: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/qcom/lpass-apq8016.c:294:34: warning: ‘apq8016_lpass_cpu_device_id’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-10-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 2 +- sound/soc/qcom/lpass-apq8016.c | 2 +- sound/soc/qcom/lpass-ipq806x.c | 2 +- sound/soc/qcom/lpass-sc7180.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 575e2aefefe3..270986b2f102 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -167,7 +167,7 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev) return devm_snd_soc_register_card(&pdev->dev, card); } -static const struct of_device_id apq8016_sbc_device_id[] = { +static const struct of_device_id apq8016_sbc_device_id[] __maybe_unused = { { .compatible = "qcom,apq8016-sbc-sndcard" }, {}, }; diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 0aedb3a0a798..8507ef8f6679 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -291,7 +291,7 @@ static struct lpass_variant apq8016_data = { .free_dma_channel = apq8016_lpass_free_dma_channel, }; -static const struct of_device_id apq8016_lpass_cpu_device_id[] = { +static const struct of_device_id apq8016_lpass_cpu_device_id[] __maybe_unused = { { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data }, {} }; diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 832a9161484e..92f98b4df47f 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -161,7 +161,7 @@ static struct lpass_variant ipq806x_data = { .free_dma_channel = ipq806x_lpass_free_dma_channel, }; -static const struct of_device_id ipq806x_lpass_cpu_device_id[] = { +static const struct of_device_id ipq806x_lpass_cpu_device_id[] __maybe_unused = { { .compatible = "qcom,lpass-cpu", .data = &ipq806x_data }, {} }; diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 238069e293bf..145d1000a527 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -285,7 +285,7 @@ static struct lpass_variant sc7180_data = { .free_dma_channel = sc7180_lpass_free_dma_channel, }; -static const struct of_device_id sc7180_lpass_cpu_device_id[] = { +static const struct of_device_id sc7180_lpass_cpu_device_id[] __maybe_unused = { {.compatible = "qcom,sc7180-lpass-cpu", .data = &sc7180_data}, {} }; -- cgit v1.2.3 From 3285b6623653befaf97687d418c99531a09037db Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:23 +0100 Subject: ASoC: samsung: smdk_wm8994: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/samsung/smdk_wm8994.c:139:34: warning: ‘samsung_wm8994_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-11-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/samsung/smdk_wm8994.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 64a1a64656ab..28d6eb14d7db 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -136,7 +136,7 @@ static struct snd_soc_card smdk = { .num_links = ARRAY_SIZE(smdk_dai), }; -static const struct of_device_id samsung_wm8994_of_match[] = { +static const struct of_device_id samsung_wm8994_of_match[] __maybe_unused = { { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data }, {}, }; -- cgit v1.2.3 From 56af27ad5f363e030a1191da459460fcb70cf76a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:24 +0100 Subject: ASoC: rockchip: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/rockchip/rockchip_i2s.c:569:34: warning: ‘rockchip_i2s_match’ defined but not used [-Wunused-const-variable=] sound/soc/rockchip/rockchip_pdm.c:463:34: warning: ‘rockchip_pdm_match’ defined but not used [-Wunused-const-variable=] sound/soc/rockchip/rockchip_spdif.c:44:34: warning: ‘rk_spdif_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-12-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 2 +- sound/soc/rockchip/rockchip_pdm.c | 2 +- sound/soc/rockchip/rockchip_spdif.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 593299675b8c..eae287d905eb 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -566,7 +566,7 @@ static const struct rk_i2s_pins rk3399_i2s_pins = { .shift = 11, }; -static const struct of_device_id rockchip_i2s_match[] = { +static const struct of_device_id rockchip_i2s_match[] __maybe_unused = { { .compatible = "rockchip,rk3066-i2s", }, { .compatible = "rockchip,rk3188-i2s", }, { .compatible = "rockchip,rk3288-i2s", }, diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 5adb293d0435..e5f732747f71 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -460,7 +460,7 @@ static const struct regmap_config rockchip_pdm_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static const struct of_device_id rockchip_pdm_match[] = { +static const struct of_device_id rockchip_pdm_match[] __maybe_unused = { { .compatible = "rockchip,pdm", .data = (void *)RK_PDM_RK3229 }, { .compatible = "rockchip,px30-pdm", diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 674810851fbc..ffb4ec306441 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -41,7 +41,7 @@ struct rk_spdif_dev { struct regmap *regmap; }; -static const struct of_device_id rk_spdif_match[] = { +static const struct of_device_id rk_spdif_match[] __maybe_unused = { { .compatible = "rockchip,rk3066-spdif", .data = (void *)RK_SPDIF_RK3066 }, { .compatible = "rockchip,rk3188-spdif", -- cgit v1.2.3 From 4bad6ec57d8045046ae8f8e410a16c1ad9d652f2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:25 +0100 Subject: ASoC: ti: davinci: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/ti/davinci-i2s.c:750:34: warning: ‘davinci_i2s_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-13-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/ti/davinci-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index dd34504c09ba..6dca51862dd7 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -747,7 +747,7 @@ static int davinci_i2s_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id davinci_i2s_match[] = { +static const struct of_device_id davinci_i2s_match[] __maybe_unused = { { .compatible = "ti,da850-mcbsp" }, {}, }; -- cgit v1.2.3 From c0b7cf59971e9f5fd1960774dc8a1728777cd437 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:26 +0100 Subject: ASoC: uniphier: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/uniphier/aio-ld11.c:375:34: warning: ‘uniphier_aio_of_match’ defined but not used [-Wunused-const-variable=] sound/soc/uniphier/evea.c:554:34: warning: ‘evea_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-14-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-ld11.c | 2 +- sound/soc/uniphier/aio-pxs2.c | 2 +- sound/soc/uniphier/evea.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c index 8b44f8dc4970..7b3cf5d751f6 100644 --- a/sound/soc/uniphier/aio-ld11.c +++ b/sound/soc/uniphier/aio-ld11.c @@ -372,7 +372,7 @@ static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = { .addr_ext = 1, }; -static const struct of_device_id uniphier_aio_of_match[] = { +static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = { { .compatible = "socionext,uniphier-ld11-aio", .data = &uniphier_aio_ld11_spec, diff --git a/sound/soc/uniphier/aio-pxs2.c b/sound/soc/uniphier/aio-pxs2.c index a1d05fe9d3c2..899904f7ffd6 100644 --- a/sound/soc/uniphier/aio-pxs2.c +++ b/sound/soc/uniphier/aio-pxs2.c @@ -282,7 +282,7 @@ static const struct uniphier_aio_chip_spec uniphier_aio_pxs2_spec = { .addr_ext = 0, }; -static const struct of_device_id uniphier_aio_of_match[] = { +static const struct of_device_id uniphier_aio_of_match[] __maybe_unused = { { .compatible = "socionext,uniphier-pxs2-aio", .data = &uniphier_aio_pxs2_spec, diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c index d27e9ca07856..96343d19a1e0 100644 --- a/sound/soc/uniphier/evea.c +++ b/sound/soc/uniphier/evea.c @@ -551,7 +551,7 @@ static int evea_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id evea_of_match[] = { +static const struct of_device_id evea_of_match[] __maybe_unused = { { .compatible = "socionext,uniphier-evea", }, {} }; -- cgit v1.2.3 From bda20fb03e54c261b6ff8b0d04344ed9a1812338 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:27 +0100 Subject: ASoC: ak4118: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/ak4118.c:407:34: warning: ‘ak4118_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-15-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/ak4118.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index f44d9a4a8507..5d46ae85566c 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -404,11 +404,13 @@ static int ak4118_i2c_probe(struct i2c_client *i2c, &soc_component_drv_ak4118, &ak4118_dai, 1); } +#ifdef CONFIG_OF static const struct of_device_id ak4118_of_match[] = { { .compatible = "asahi-kasei,ak4118", }, {} }; MODULE_DEVICE_TABLE(of, ak4118_of_match); +#endif static const struct i2c_device_id ak4118_id_table[] = { { "ak4118", 0 }, -- cgit v1.2.3 From d11f8974896817382f8adda8b6c9071387cb2ce0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:28 +0100 Subject: ASoC: alc5623: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/alc5623.c:1071:34: warning: ‘alc5623_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-16-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/alc5623.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 3d1761a531f5..54f489837162 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -1068,11 +1068,13 @@ static const struct i2c_device_id alc5623_i2c_table[] = { }; MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table); +#ifdef CONFIG_OF static const struct of_device_id alc5623_of_match[] = { { .compatible = "realtek,alc5623", }, { } }; MODULE_DEVICE_TABLE(of, alc5623_of_match); +#endif /* i2c codec control layer */ static struct i2c_driver alc5623_i2c_driver = { -- cgit v1.2.3 From 5207e768347dbb3249ee83979e868850b4b9d23b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:29 +0100 Subject: ASoC: alc5632: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/alc5632.c:1170:34: warning: ‘alc5632_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-17-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/alc5632.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 9d6dcd3ffa57..bde5ded67754 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1167,11 +1167,13 @@ static const struct i2c_device_id alc5632_i2c_table[] = { }; MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table); +#ifdef CONFIG_OF static const struct of_device_id alc5632_of_match[] = { { .compatible = "realtek,alc5632", }, { } }; MODULE_DEVICE_TABLE(of, alc5632_of_match); +#endif /* i2c codec control layer */ static struct i2c_driver alc5632_i2c_driver = { -- cgit v1.2.3 From a06cd8cf97a336c87a98c7e64e5692c5391b50e6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:30 +0100 Subject: ASoC: da7218: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/da7218.c:2281:34: warning: ‘da7218_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-18-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/da7218.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 6d78bccb55c3..2bfafbe9e3dc 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -2278,12 +2278,14 @@ static irqreturn_t da7218_irq_thread(int irq, void *data) * DT */ +#ifdef CONFIG_OF static const struct of_device_id da7218_of_match[] = { { .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID }, { .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID }, { } }; MODULE_DEVICE_TABLE(of, da7218_of_match); +#endif static inline int da7218_of_get_id(struct device *dev) { -- cgit v1.2.3 From a7de367daa8412fe854a255c2b4ff5bd4399c00a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:31 +0100 Subject: ASoC: da7219: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/da7219.c:1705:34: warning: ‘da7219_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-19-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 0b3b7909efc9..e9b45daec0ca 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1702,11 +1702,13 @@ static struct snd_soc_dai_driver da7219_dai = { * DT/ACPI */ +#ifdef CONFIG_OF static const struct of_device_id da7219_of_match[] = { { .compatible = "dlg,da7219", }, { } }; MODULE_DEVICE_TABLE(of, da7219_of_match); +#endif #ifdef CONFIG_ACPI static const struct acpi_device_id da7219_acpi_match[] = { -- cgit v1.2.3 From a25b45dc143748354947cbc30b682deacb27978f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:32 +0100 Subject: ASoC: da9055: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/da9055.c:1522:34: warning: ‘da9055_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-20-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/da9055.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index b0d9ca6de685..aed92f615b02 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1519,11 +1519,13 @@ static const struct i2c_device_id da9055_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id da9055_of_match[] = { { .compatible = "dlg,da9055-codec", }, { } }; MODULE_DEVICE_TABLE(of, da9055_of_match); +#endif /* I2C codec control layer */ static struct i2c_driver da9055_i2c_driver = { -- cgit v1.2.3 From 75333af40a25ca33179cbbe68019da0b9a123262 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:33 +0100 Subject: ASoC: es8316: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/es8316.c:837:34: warning: ‘es8316_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-21-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index bd5d230c5df2..f9ec5cf82599 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -834,11 +834,13 @@ static const struct i2c_device_id es8316_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, es8316_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id es8316_of_match[] = { { .compatible = "everest,es8316", }, {}, }; MODULE_DEVICE_TABLE(of, es8316_of_match); +#endif #ifdef CONFIG_ACPI static const struct acpi_device_id es8316_acpi_match[] = { -- cgit v1.2.3 From ac792c0ab3db9392bbbc7023fefb41bc9d467bfc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:34 +0100 Subject: ASoC: max98090: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/max98090.c:2671:34: warning: ‘max98090_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-22-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 945a79e4f3eb..06276ff5f8a3 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2668,12 +2668,14 @@ static const struct i2c_device_id max98090_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id max98090_of_match[] = { { .compatible = "maxim,max98090", }, { .compatible = "maxim,max98091", }, { } }; MODULE_DEVICE_TABLE(of, max98090_of_match); +#endif #ifdef CONFIG_ACPI static const struct acpi_device_id max98090_acpi_match[] = { -- cgit v1.2.3 From a5a196bf0a0b9af14e0170282a3c8d8febe9fe64 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:35 +0100 Subject: ASoC: max98095: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/max98095.c:2151:34: warning: ‘max98095_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-23-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98095.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 9bdc6392382a..736cd70be725 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2148,11 +2148,13 @@ static const struct i2c_device_id max98095_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98095_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id max98095_of_match[] = { { .compatible = "maxim,max98095", }, { } }; MODULE_DEVICE_TABLE(of, max98095_of_match); +#endif static struct i2c_driver max98095_i2c_driver = { .driver = { -- cgit v1.2.3 From e77332c3e741e88ea025c9d0fbb22c833cdb01ad Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:36 +0100 Subject: ASoC: max98371: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/max98371.c:411:34: warning: ‘max98371_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-24-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98371.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index dfee05f985bd..0b438303e1d5 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -408,11 +408,13 @@ static const struct i2c_device_id max98371_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, max98371_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id max98371_of_match[] = { { .compatible = "maxim,max98371", }, { } }; MODULE_DEVICE_TABLE(of, max98371_of_match); +#endif static struct i2c_driver max98371_i2c_driver = { .driver = { -- cgit v1.2.3 From 682e22193120a87a25ed7d7a71bbac682a33e2ee Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:37 +0100 Subject: ASoC: max9867: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/max9867.c:652:34: warning: ‘max9867_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-25-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index aef2746bfb94..512e6f2513d3 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -649,11 +649,13 @@ static const struct i2c_device_id max9867_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max9867_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id max9867_of_match[] = { { .compatible = "maxim,max9867", }, { } }; MODULE_DEVICE_TABLE(of, max9867_of_match); +#endif static struct i2c_driver max9867_i2c_driver = { .driver = { -- cgit v1.2.3 From d39d9cb5a2c9526c19e2d3a0a43465d49143426d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:38 +0100 Subject: ASoC: max98925: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/max98925.c:630:34: warning: ‘max98925_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-26-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98925.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index b3e1a54fff88..e18d0022c3f4 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -627,11 +627,13 @@ static const struct i2c_device_id max98925_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98925_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id max98925_of_match[] = { { .compatible = "maxim,max98925", }, { } }; MODULE_DEVICE_TABLE(of, max98925_of_match); +#endif static struct i2c_driver max98925_i2c_driver = { .driver = { -- cgit v1.2.3 From fff68ff65129525c88d52a05a55cabff5a4b0821 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:39 +0100 Subject: ASoC: max98926: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/max98926.c:574:34: warning: ‘max98926_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-27-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index c4dfa8ab1d49..0977e541326d 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -571,11 +571,13 @@ static const struct i2c_device_id max98926_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98926_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id max98926_of_match[] = { { .compatible = "maxim,max98926", }, { } }; MODULE_DEVICE_TABLE(of, max98926_of_match); +#endif static struct i2c_driver max98926_i2c_driver = { .driver = { -- cgit v1.2.3 From 36cbbf009f229fe27eac869cb279de1f80aa654b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:40 +0100 Subject: ASoC: pcm1789: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/pcm1789-i2c.c:36:34: warning: ‘pcm1789_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-28-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/pcm1789-i2c.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/pcm1789-i2c.c b/sound/soc/codecs/pcm1789-i2c.c index 327ec584f240..7a6be45f8149 100644 --- a/sound/soc/codecs/pcm1789-i2c.c +++ b/sound/soc/codecs/pcm1789-i2c.c @@ -33,11 +33,13 @@ static int pcm1789_i2c_remove(struct i2c_client *client) return pcm1789_common_exit(&client->dev); } +#ifdef CONFIG_OF static const struct of_device_id pcm1789_of_match[] = { { .compatible = "ti,pcm1789", }, { } }; MODULE_DEVICE_TABLE(of, pcm1789_of_match); +#endif static const struct i2c_device_id pcm1789_i2c_ids[] = { { "pcm1789", 0 }, -- cgit v1.2.3 From e2baf7fa3e84a6f1fb930f10547401d9363b4caf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:41 +0100 Subject: ASoC: pcm179x: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/pcm179x-i2c.c:33:34: warning: ‘pcm179x_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-29-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/pcm179x-i2c.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c index 36e01678bef4..34a3d596f288 100644 --- a/sound/soc/codecs/pcm179x-i2c.c +++ b/sound/soc/codecs/pcm179x-i2c.c @@ -30,11 +30,13 @@ static int pcm179x_i2c_probe(struct i2c_client *client, return pcm179x_common_init(&client->dev, regmap); } +#ifdef CONFIG_OF static const struct of_device_id pcm179x_of_match[] = { { .compatible = "ti,pcm1792a", }, { } }; MODULE_DEVICE_TABLE(of, pcm179x_of_match); +#endif static const struct i2c_device_id pcm179x_i2c_ids[] = { { "pcm179x", 0 }, -- cgit v1.2.3 From c7bfb25333526463ffc38b5c3460e6778e474c9d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:42 +0100 Subject: ASoC: rt5660: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/rt5660.c:1238:34: warning: ‘rt5660_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-30-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/rt5660.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 9e3813f7583d..0edf09d3a499 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1235,11 +1235,13 @@ static const struct i2c_device_id rt5660_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id); +#ifdef CONFIG_OF static const struct of_device_id rt5660_of_match[] = { { .compatible = "realtek,rt5660", }, {}, }; MODULE_DEVICE_TABLE(of, rt5660_of_match); +#endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5660_acpi_match[] = { -- cgit v1.2.3 From 68591e8aa122b43e5f9c6eb5cf49c559e5d6300e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:43 +0100 Subject: ASoC: tas2562: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/tas2562.c:805:34: warning: ‘tas2562_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-31-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/tas2562.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index f1ff204e3ad0..19965fabe949 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -802,6 +802,7 @@ static const struct i2c_device_id tas2562_id[] = { }; MODULE_DEVICE_TABLE(i2c, tas2562_id); +#ifdef CONFIG_OF static const struct of_device_id tas2562_of_match[] = { { .compatible = "ti,tas2562", }, { .compatible = "ti,tas2563", }, @@ -810,6 +811,7 @@ static const struct of_device_id tas2562_of_match[] = { { }, }; MODULE_DEVICE_TABLE(of, tas2562_of_match); +#endif static struct i2c_driver tas2562_i2c_driver = { .driver = { -- cgit v1.2.3 From 762e0b8baf63b1bb534254f89148884c873363f3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:44 +0100 Subject: ASoC: tlv320: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/tlv320aic23-i2c.c:38:34: warning: ‘tlv320aic23_of_match’ defined but not used [-Wunused-const-variable=] sound/soc/codecs/tlv320adcx140.c:1076:34: warning: ‘tlv320adcx140_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-32-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adcx140.c | 2 ++ sound/soc/codecs/tlv320aic23-i2c.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 53a80246aee1..3f027c8234a6 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -1073,6 +1073,7 @@ static struct snd_soc_dai_driver adcx140_dai_driver[] = { } }; +#ifdef CONFIG_OF static const struct of_device_id tlv320adcx140_of_match[] = { { .compatible = "ti,tlv320adc3140" }, { .compatible = "ti,tlv320adc5140" }, @@ -1080,6 +1081,7 @@ static const struct of_device_id tlv320adcx140_of_match[] = { {}, }; MODULE_DEVICE_TABLE(of, tlv320adcx140_of_match); +#endif static int adcx140_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c index 5025e5c43783..dbb8f969274c 100644 --- a/sound/soc/codecs/tlv320aic23-i2c.c +++ b/sound/soc/codecs/tlv320aic23-i2c.c @@ -35,11 +35,13 @@ static const struct i2c_device_id tlv320aic23_id[] = { MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); +#ifdef CONFIG_OF static const struct of_device_id tlv320aic23_of_match[] = { { .compatible = "ti,tlv320aic23", }, { } }; MODULE_DEVICE_TABLE(of, tlv320aic23_of_match); +#endif static struct i2c_driver tlv320aic23_i2c_driver = { .driver = { -- cgit v1.2.3 From 62bd3054af54d4d55267a623c4d938fd42f48b59 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:45 +0100 Subject: ASoC: ts3a227e: skip of_device_id table when !CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match by multiple methods. Its of_device_id table is referenced via of_match_ptr() so it will be unused for !CONFIG_OF builds: sound/soc/codecs/ts3a227e.c:369:34: warning: ‘ts3a227e_of_match’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-33-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/ts3a227e.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 3ed3b45fa7ba..962f5d48378a 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -366,11 +366,13 @@ static const struct i2c_device_id ts3a227e_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids); +#ifdef CONFIG_OF static const struct of_device_id ts3a227e_of_match[] = { { .compatible = "ti,ts3a227e", }, { } }; MODULE_DEVICE_TABLE(of, ts3a227e_of_match); +#endif #ifdef CONFIG_ACPI static struct acpi_device_id ts3a227e_acpi_match[] = { -- cgit v1.2.3 From 418fb63003f6e2d99d6f6eb6ba25e1576bf55348 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:46 +0100 Subject: ASoC: es7134: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/codecs/es7134.c:264:33: warning: ‘es7154_chip’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-34-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/es7134.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c index 00518406eb2b..e2b79879354b 100644 --- a/sound/soc/codecs/es7134.c +++ b/sound/soc/codecs/es7134.c @@ -183,7 +183,7 @@ static const struct snd_soc_dapm_route es7134_extra_routes[] = { { "Playback", NULL, "VDD", } }; -static const struct es7134_chip es7134_chip = { +static const struct es7134_chip es7134_chip __maybe_unused = { .dai_drv = &es7134_dai, .modes = es7134_modes, .mode_num = ARRAY_SIZE(es7134_modes), @@ -261,7 +261,7 @@ static const struct snd_soc_dapm_route es7154_extra_routes[] = { { "Playback", NULL, "PVDD", } }; -static const struct es7134_chip es7154_chip = { +static const struct es7134_chip es7154_chip __maybe_unused = { .dai_drv = &es7154_dai, .modes = es7154_modes, .mode_num = ARRAY_SIZE(es7154_modes), -- cgit v1.2.3 From 55c259bf06e5f7a899411e474a48d79cf1a0a2f6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:47 +0100 Subject: ASoC: es7241: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/codecs/es7241.c:206:33: warning: ‘es7241_chip’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-35-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/es7241.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c index 87991bd4acef..2344a0b03518 100644 --- a/sound/soc/codecs/es7241.c +++ b/sound/soc/codecs/es7241.c @@ -203,7 +203,7 @@ static const struct es7241_clock_mode es7241_modes[] = { }, }; -static const struct es7241_chip es7241_chip = { +static const struct es7241_chip es7241_chip __maybe_unused = { .modes = es7241_modes, .mode_num = ARRAY_SIZE(es7241_modes), }; -- cgit v1.2.3 From da773b2b45f9de4f44bd62db8b291e2b0a4c3f5b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:48 +0100 Subject: ASoC: samsung: i2s: mark OF related data as maybe unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can be compile tested with !CONFIG_OF making certain data unused: sound/soc/samsung/i2s.c:1646:42: warning: ‘i2sv5_dai_type_i2s1’ defined but not used [-Wunused-const-variable=] sound/soc/samsung/i2s.c:1639:42: warning: ‘i2sv7_dai_type’ defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Reviewed-by: Sylwester Nawrocki Link: https://lore.kernel.org/r/20201125164452.89239-36-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 36969f0a3f9a..4bdc268fd981 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1621,28 +1621,28 @@ static const struct samsung_i2s_dai_data i2sv3_dai_type = { .i2s_variant_regs = &i2sv3_regs, }; -static const struct samsung_i2s_dai_data i2sv5_dai_type = { +static const struct samsung_i2s_dai_data i2sv5_dai_type __maybe_unused = { .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | QUIRK_SUPPORTS_IDMA, .pcm_rates = SNDRV_PCM_RATE_8000_96000, .i2s_variant_regs = &i2sv3_regs, }; -static const struct samsung_i2s_dai_data i2sv6_dai_type = { +static const struct samsung_i2s_dai_data i2sv6_dai_type __maybe_unused = { .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA, .pcm_rates = SNDRV_PCM_RATE_8000_96000, .i2s_variant_regs = &i2sv6_regs, }; -static const struct samsung_i2s_dai_data i2sv7_dai_type = { +static const struct samsung_i2s_dai_data i2sv7_dai_type __maybe_unused = { .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | QUIRK_SUPPORTS_TDM, .pcm_rates = SNDRV_PCM_RATE_8000_192000, .i2s_variant_regs = &i2sv7_regs, }; -static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = { +static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 __maybe_unused = { .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR, .pcm_rates = SNDRV_PCM_RATE_8000_96000, .i2s_variant_regs = &i2sv5_i2s1_regs, -- cgit v1.2.3 From fe4b501e56af81f88215f943c2caef5eded26920 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:49 +0100 Subject: ASoC: max98371: drop driver pm=NULL assignment There is no point to explicitly set driver .pm field to NULL. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-37-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98371.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index 0b438303e1d5..e424779db02b 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -419,7 +419,6 @@ MODULE_DEVICE_TABLE(of, max98371_of_match); static struct i2c_driver max98371_i2c_driver = { .driver = { .name = "max98371", - .pm = NULL, .of_match_table = of_match_ptr(max98371_of_match), }, .probe = max98371_i2c_probe, -- cgit v1.2.3 From 0eb97389cc4d470b3fdf5384f70f4dc074004843 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:50 +0100 Subject: ASoC: max98925: drop driver pm=NULL assignment There is no point to explicitly set driver .pm field to NULL. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-38-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98925.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index e18d0022c3f4..ddaccc24b0cb 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -639,7 +639,6 @@ static struct i2c_driver max98925_i2c_driver = { .driver = { .name = "max98925", .of_match_table = of_match_ptr(max98925_of_match), - .pm = NULL, }, .probe = max98925_i2c_probe, .id_table = max98925_i2c_id, -- cgit v1.2.3 From c37de70121a03415acd4c7de58a65c4a55ab4c6b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:51 +0100 Subject: ASoC: max98926: drop driver pm=NULL assignment There is no point to explicitly set driver .pm field to NULL. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201125164452.89239-39-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 0977e541326d..f286e572263e 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -583,7 +583,6 @@ static struct i2c_driver max98926_i2c_driver = { .driver = { .name = "max98926", .of_match_table = of_match_ptr(max98926_of_match), - .pm = NULL, }, .probe = max98926_i2c_probe, .id_table = max98926_i2c_id, -- cgit v1.2.3 From 0670c9a7239a478ec9675fa82d7ee0a86ef22fe5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 Nov 2020 17:44:52 +0100 Subject: ASoC: samsung: smdk_wm8994: remove redundant of_match_ptr() of_match_device() already handles properly !CONFIG_OF case, so passing the argument via of_match_ptr() is not needed. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Sylwester Nawrocki Link: https://lore.kernel.org/r/20201125164452.89239-40-krzk@kernel.org Signed-off-by: Mark Brown --- sound/soc/samsung/smdk_wm8994.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 28d6eb14d7db..681b244d5312 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -170,7 +170,7 @@ static int smdk_audio_probe(struct platform_device *pdev) smdk_dai[0].platforms->of_node = smdk_dai[0].cpus->of_node; } - id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev); + id = of_match_device(samsung_wm8994_of_match, &pdev->dev); if (id) *board = *((struct smdk_wm8994_data *)id->data); -- cgit v1.2.3 From 144f836646989783cb018d00fa69f3f8dab58349 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 26 Nov 2020 14:36:48 +0800 Subject: ASoC: hdmi-codec: Add RX support HDMI interface can also be used as receiver, this patch is to add such support. The most difference compare with TX is that RX don't need to get edid information. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1606372608-2329-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index e8410b2433de..d5fcc4db8284 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -282,6 +282,7 @@ struct hdmi_codec_priv { static const struct snd_soc_dapm_widget hdmi_widgets[] = { SND_SOC_DAPM_OUTPUT("TX"), + SND_SOC_DAPM_OUTPUT("RX"), }; enum { @@ -389,6 +390,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; mutex_lock(&hcp->lock); @@ -404,7 +406,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, goto err; } - if (hcp->hcd.ops->get_eld) { + if (tx && hcp->hcd.ops->get_eld) { ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data, hcp->eld, sizeof(hcp->eld)); if (ret) @@ -660,14 +662,20 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) { struct snd_soc_dapm_context *dapm; struct hdmi_codec_daifmt *daifmt; - struct snd_soc_dapm_route route = { - .sink = "TX", - .source = dai->driver->playback.stream_name, + struct snd_soc_dapm_route route[] = { + { + .sink = "TX", + .source = dai->driver->playback.stream_name, + }, + { + .sink = dai->driver->capture.stream_name, + .source = "RX", + }, }; int ret; dapm = snd_soc_component_get_dapm(dai->component); - ret = snd_soc_dapm_add_routes(dapm, &route, 1); + ret = snd_soc_dapm_add_routes(dapm, route, 2); if (ret) return ret; @@ -757,6 +765,14 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .formats = I2S_FORMATS, .sig_bits = 24, }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = HDMI_RATES, + .formats = I2S_FORMATS, + .sig_bits = 24, + }, .ops = &hdmi_codec_i2s_dai_ops, .pcm_new = hdmi_codec_pcm_new, }; @@ -773,6 +789,13 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .rates = HDMI_RATES, .formats = SPDIF_FORMATS, }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = HDMI_RATES, + .formats = SPDIF_FORMATS, + }, .ops = &hdmi_codec_spdif_dai_ops, .pcm_new = hdmi_codec_pcm_new, }; -- cgit v1.2.3 From c61d1142cfd45f58b63bf9d2d59523f91096e873 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 26 Nov 2020 14:14:53 +0800 Subject: ASoC: fsl: Fix config name of CONFIG_ARCH_MXC CONFIG_ARCH_MXC should be ARCH_MXC Fixes: 674226db62ec ("ASoC: fsl: SND_SOC_FSL_AUD2HTX should depend on ARCH_MXC") Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1606371293-29099-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 06a2d225d644..24710decd38a 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -107,7 +107,7 @@ config SND_SOC_FSL_XCVR config SND_SOC_FSL_AUD2HTX tristate "AUDIO TO HDMI TX module support" - depends on CONFIG_ARCH_MXC || COMPILE_TEST + depends on ARCH_MXC || COMPILE_TEST help Say Y if you want to add AUDIO TO HDMI TX support for NXP. -- cgit v1.2.3 From 15a7b8c13653cc88de2db89af486e904aedc75ec Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Nov 2020 08:49:57 +0900 Subject: ASoC: soc-compress: move soc_compr_free() next to soc_compr_open() This patch moves soc_compr_free() next to soc_compr_open(). This is prepare for soc_compr_open() cleanup. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8ju5iwv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 68 ++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 5a751d5d3847..792c2aa1a3c0 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -22,6 +22,40 @@ #include #include +static int soc_compr_free(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ + + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + + snd_soc_runtime_deactivate(rtd, stream); + + snd_soc_dai_digital_mute(codec_dai, 1, stream); + + if (!snd_soc_dai_active(cpu_dai)) + cpu_dai->rate = 0; + + if (!snd_soc_dai_active(codec_dai)) + codec_dai->rate = 0; + + snd_soc_link_compr_shutdown(cstream); + + snd_soc_component_compr_free(cstream, NULL); + + snd_soc_dai_compr_shutdown(cpu_dai, cstream); + + snd_soc_dapm_stream_stop(rtd, stream); + + mutex_unlock(&rtd->card->pcm_mutex); + + snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 0); + + return 0; +} + static int soc_compr_open(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -140,40 +174,6 @@ be_err: return ret; } -static int soc_compr_free(struct snd_compr_stream *cstream) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ - - mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - - snd_soc_runtime_deactivate(rtd, stream); - - snd_soc_dai_digital_mute(codec_dai, 1, stream); - - if (!snd_soc_dai_active(cpu_dai)) - cpu_dai->rate = 0; - - if (!snd_soc_dai_active(codec_dai)) - codec_dai->rate = 0; - - snd_soc_link_compr_shutdown(cstream); - - snd_soc_component_compr_free(cstream, NULL); - - snd_soc_dai_compr_shutdown(cpu_dai, cstream); - - snd_soc_dapm_stream_stop(rtd, stream); - - mutex_unlock(&rtd->card->pcm_mutex); - - snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 0); - - return 0; -} - static int soc_compr_free_fe(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *fe = cstream->private_data; -- cgit v1.2.3 From 1e6a93cf74979e167cef8d29f6689705d9ec6735 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Nov 2020 08:50:04 +0900 Subject: ASoC: soc-dai: add mark for snd_soc_dai_compr_startup/shutdown() soc_compr_open() does rollback when failed (A), but, it is almost same as soc_compr_free(). static int soc_compr_open(xxx) { ... if (ret < 0) goto xxx_err; ... return 0; ^ machine_err: | ... | out: (A) ... | pm_err: | ... v return ret; } The difference is soc_compr_free() is for all dai/component/substream, rollback is for succeeded part only. This kind of duplicated code can be a hotbed of bugs, thus, we want to share soc_compr_free() and rollback. => 1) snd_soc_dai_compr_startup/shutdown() 2) snd_soc_component_compr_open/free() 3) snd_soc_link_compr_startup/shutdown() This patch is for 1) snd_soc_dai_compr_startup/shutdown(), and adds new cstream mark. It will mark cstream when startup() was suceeded. If rollback happen *after* that, it will check rollback flag and marked cstream. It cares *previous* startup() only now, but we might want to check *whole* marked cstream in the future. This patch is using macro so that it can be easily adjust to it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87mtze5iwp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 4 +++- sound/soc/soc-compress.c | 8 ++++---- sound/soc/soc-dai.c | 13 ++++++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 4bf759f025d2..6f54401d3de9 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -196,7 +196,8 @@ int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream, int snd_soc_dai_compr_startup(struct snd_soc_dai *dai, struct snd_compr_stream *cstream); void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai, - struct snd_compr_stream *cstream); + struct snd_compr_stream *cstream, + int rollback); int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai, struct snd_compr_stream *cstream, int cmd); int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai, @@ -400,6 +401,7 @@ struct snd_soc_dai { /* function mark */ struct snd_pcm_substream *mark_startup; struct snd_pcm_substream *mark_hw_params; + struct snd_compr_stream *mark_compr_startup; /* bit field */ unsigned int probed:1; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 792c2aa1a3c0..d85b6b174006 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -45,7 +45,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) snd_soc_component_compr_free(cstream, NULL); - snd_soc_dai_compr_shutdown(cpu_dai, cstream); + snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0); snd_soc_dapm_stream_stop(rtd, stream); @@ -91,7 +91,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) machine_err: snd_soc_component_compr_free(cstream, component); - snd_soc_dai_compr_shutdown(cpu_dai, cstream); + snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); out: mutex_unlock(&rtd->card->pcm_mutex); pm_err: @@ -165,7 +165,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) machine_err: snd_soc_component_compr_free(cstream, component); open_err: - snd_soc_dai_compr_shutdown(cpu_dai, cstream); + snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); out: dpcm_path_put(&list); be_err: @@ -211,7 +211,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) snd_soc_component_compr_free(cstream, NULL); - snd_soc_dai_compr_shutdown(cpu_dai, cstream); + snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0); mutex_unlock(&fe->card->mutex); return 0; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 2686a566649b..9afc6e8c3f9f 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -612,16 +612,27 @@ int snd_soc_dai_compr_startup(struct snd_soc_dai *dai, dai->driver->cops->startup) ret = dai->driver->cops->startup(cstream, dai); + /* mark cstream if succeeded */ + if (ret == 0) + soc_dai_mark_push(dai, cstream, compr_startup); + return soc_dai_ret(dai, ret); } EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup); void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai, - struct snd_compr_stream *cstream) + struct snd_compr_stream *cstream, + int rollback) { + if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup)) + return; + if (dai->driver->cops && dai->driver->cops->shutdown) dai->driver->cops->shutdown(cstream, dai); + + /* remove marked cstream */ + soc_dai_mark_pop(dai, cstream, compr_startup); } EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown); -- cgit v1.2.3 From f94ba9ac20fab9af08240fde3741edf73655411d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Nov 2020 08:50:09 +0900 Subject: ASoC: soc-component: add mark for snd_soc_component_compr_open/free() soc_compr_open() does rollback when failed (A), but, it is almost same as soc_compr_free(). static int soc_compr_open(xxx) { ... if (ret < 0) goto xxx_err; ... return 0; ^ machine_err: | ... | out: (A) ... | pm_err: | ... v return ret; } The difference is soc_compr_free() is for all dai/component/substream, rollback is for succeeded part only. This kind of duplicated code can be a hotbed of bugs, thus, we want to share soc_compr_free() and rollback. 1) snd_soc_dai_compr_startup/shutdown() => 2) snd_soc_component_compr_open/free() 3) snd_soc_link_compr_startup/shutdown() This patch is for 2) snd_soc_component_compr_open/free(), and adds new cstream mark. It will mark cstream when startup() was suceeded. If rollback happen *after* that, it will check rollback flag and marked cstream. It cares *previous* startup() only now, but we might want to check *whole* marked cstream in the future. This patch is using macro so that it can be easily adjust to it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfey5iwk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 6 +++--- sound/soc/soc-component.c | 17 ++++++++--------- sound/soc/soc-compress.c | 14 ++++++-------- 3 files changed, 17 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 984dd7353066..9140b5fa19a4 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -221,6 +221,7 @@ struct snd_soc_component { struct snd_pcm_substream *mark_module; struct snd_pcm_substream *mark_open; struct snd_pcm_substream *mark_hw_params; + struct snd_compr_stream *mark_compr_open; void *mark_pm; #ifdef CONFIG_DEBUG_FS @@ -444,10 +445,9 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, struct of_phandle_args *args, const char **dai_name); -int snd_soc_component_compr_open(struct snd_compr_stream *cstream, - struct snd_soc_component **last); +int snd_soc_component_compr_open(struct snd_compr_stream *cstream); void snd_soc_component_compr_free(struct snd_compr_stream *cstream, - struct snd_soc_component *last); + int rollback); int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd); int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *params); diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 5d3a8dcd8d49..434987a64353 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -421,8 +421,7 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); #endif -int snd_soc_component_compr_open(struct snd_compr_stream *cstream, - struct snd_soc_component **last) +int snd_soc_component_compr_open(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; @@ -432,32 +431,32 @@ int snd_soc_component_compr_open(struct snd_compr_stream *cstream, if (component->driver->compress_ops && component->driver->compress_ops->open) { ret = component->driver->compress_ops->open(component, cstream); - if (ret < 0) { - *last = component; + if (ret < 0) return soc_component_ret(component, ret); - } } + soc_component_mark_push(component, cstream, compr_open); } - *last = NULL; return 0; } EXPORT_SYMBOL_GPL(snd_soc_component_compr_open); void snd_soc_component_compr_free(struct snd_compr_stream *cstream, - struct snd_soc_component *last) + int rollback) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; int i; for_each_rtd_components(rtd, i, component) { - if (component == last) - break; + if (rollback && !soc_component_mark_match(component, cstream, compr_open)) + continue; if (component->driver->compress_ops && component->driver->compress_ops->free) component->driver->compress_ops->free(component, cstream); + + soc_component_mark_pop(component, cstream, compr_open); } } EXPORT_SYMBOL_GPL(snd_soc_component_compr_free); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d85b6b174006..8b6a6bd482d1 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -43,7 +43,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) snd_soc_link_compr_shutdown(cstream); - snd_soc_component_compr_free(cstream, NULL); + snd_soc_component_compr_free(cstream, 0); snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0); @@ -59,7 +59,6 @@ static int soc_compr_free(struct snd_compr_stream *cstream) static int soc_compr_open(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component = NULL; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ int ret; @@ -74,7 +73,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) if (ret < 0) goto out; - ret = snd_soc_component_compr_open(cstream, &component); + ret = snd_soc_component_compr_open(cstream); if (ret < 0) goto machine_err; @@ -89,7 +88,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) return 0; machine_err: - snd_soc_component_compr_free(cstream, component); + snd_soc_component_compr_free(cstream, 1); snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); out: @@ -105,7 +104,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[cstream->direction].substream; - struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list; @@ -142,7 +140,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) if (ret < 0) goto out; - ret = snd_soc_component_compr_open(cstream, &component); + ret = snd_soc_component_compr_open(cstream); if (ret < 0) goto open_err; @@ -163,7 +161,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) return 0; machine_err: - snd_soc_component_compr_free(cstream, component); + snd_soc_component_compr_free(cstream, 1); open_err: snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); out: @@ -209,7 +207,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) snd_soc_link_compr_shutdown(cstream); - snd_soc_component_compr_free(cstream, NULL); + snd_soc_component_compr_free(cstream, 0); snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0); -- cgit v1.2.3 From cd7c7d10e8f4ab1dac0bdb2019abc0fad995a788 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Nov 2020 08:50:14 +0900 Subject: ASoC: soc-component: add mark for snd_soc_link_compr_startup/shutdown() soc_compr_open() does rollback when failed (A), but, it is almost same as soc_compr_free(). static int soc_compr_open(xxx) { ... if (ret < 0) goto xxx_err; ... return 0; ^ machine_err: | ... | out: (A) ... | pm_err: | ... v return ret; } The difference is soc_compr_free() is for all dai/component/substream, rollback is for succeeded part only. This kind of duplicated code can be a hotbed of bugs, thus, we want to share soc_compr_free() and rollback. 1) snd_soc_dai_compr_startup/shutdown() 2) snd_soc_component_compr_open/free() => 3) snd_soc_link_compr_startup/shutdown() This patch is for 3) snd_soc_link_compr_startup/shutdown() and adds new cstream mark. It will mark cstream when startup() was suceeded. If rollback happen *after* that, it will check rollback flag and marked cstream. It cares *previous* startup() only now, but we might want to check *whole* marked cstream in the future. This patch is using macro so that it can be easily adjust to it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k0ui5iwf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-link.h | 3 ++- include/sound/soc.h | 1 + sound/soc/soc-compress.c | 4 ++-- sound/soc/soc-link.c | 11 ++++++++++- 4 files changed, 15 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-link.h b/include/sound/soc-link.h index eff34fc7d3d3..4c68b06d6fe6 100644 --- a/include/sound/soc-link.h +++ b/include/sound/soc-link.h @@ -24,7 +24,8 @@ void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd); int snd_soc_link_compr_startup(struct snd_compr_stream *cstream); -void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream); +void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream, + int rollback); int snd_soc_link_compr_set_params(struct snd_compr_stream *cstream); #endif /* __SOC_LINK_H */ diff --git a/include/sound/soc.h b/include/sound/soc.h index 4a9958b9b532..33c289f6097c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1163,6 +1163,7 @@ struct snd_soc_pcm_runtime { /* function mark */ struct snd_pcm_substream *mark_startup; struct snd_pcm_substream *mark_hw_params; + struct snd_compr_stream *mark_compr_startup; /* bit field */ unsigned int pop_wait:1; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 8b6a6bd482d1..6de22b2f8197 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -41,7 +41,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) if (!snd_soc_dai_active(codec_dai)) codec_dai->rate = 0; - snd_soc_link_compr_shutdown(cstream); + snd_soc_link_compr_shutdown(cstream, 0); snd_soc_component_compr_free(cstream, 0); @@ -205,7 +205,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) fe->dpcm[stream].runtime = NULL; - snd_soc_link_compr_shutdown(cstream); + snd_soc_link_compr_shutdown(cstream, 0); snd_soc_component_compr_free(cstream, 0); diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index 409ae4940da3..26cc60f8dcfb 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -162,17 +162,26 @@ int snd_soc_link_compr_startup(struct snd_compr_stream *cstream) rtd->dai_link->compr_ops->startup) ret = rtd->dai_link->compr_ops->startup(cstream); + if (ret == 0) + soc_link_mark_push(rtd, cstream, compr_startup); + return soc_link_ret(rtd, ret); } EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup); -void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream) +void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream, + int rollback) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; + if (rollback && !soc_link_mark_match(rtd, cstream, compr_startup)) + return; + if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown) rtd->dai_link->compr_ops->shutdown(cstream); + + soc_link_mark_pop(rtd, cstream, compr_startup); } EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown); -- cgit v1.2.3 From 453d32c2f7f7375c223eaf3a0a32efbb71bbd3f3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Nov 2020 08:50:19 +0900 Subject: ASoC: soc-compress: add soc_compr_clean() and call it from soc_compr_open/free() soc_compr_open() does rollback when failed (A), but, it is almost same as soc_compr_free(). static int soc_compr_open(xxx) { ... if (ret < 0) goto xxx_err; ... return 0; ^ machine_err: | ... | out: (A) ... | pm_err: | ... v return ret; } The difference is soc_compr_free() is for all dai/component/substream, rollback is for succeeded part only. This kind of duplicated code can be a hotbed of bugs, thus, we want to share soc_compr_free() and rollback. Now, soc_compr_open/free() are handling 1) snd_soc_dai_compr_startup/shutdown() 2) snd_soc_component_compr_open/free() 3) snd_soc_link_compr_startup/shutdown() Now, 1) to 3) are handled. This patch adds new soc_compr_clean() and call it from soc_compr_open() as rollback, and from soc_compr_free_free() as normal close handler. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ima25iwa.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 6de22b2f8197..246a5e32e22a 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -22,7 +22,7 @@ #include #include -static int soc_compr_free(struct snd_compr_stream *cstream) +static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); @@ -31,7 +31,8 @@ static int soc_compr_free(struct snd_compr_stream *cstream) mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - snd_soc_runtime_deactivate(rtd, stream); + if (!rollback) + snd_soc_runtime_deactivate(rtd, stream); snd_soc_dai_digital_mute(codec_dai, 1, stream); @@ -41,21 +42,27 @@ static int soc_compr_free(struct snd_compr_stream *cstream) if (!snd_soc_dai_active(codec_dai)) codec_dai->rate = 0; - snd_soc_link_compr_shutdown(cstream, 0); + snd_soc_link_compr_shutdown(cstream, rollback); - snd_soc_component_compr_free(cstream, 0); + snd_soc_component_compr_free(cstream, rollback); - snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0); + snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback); - snd_soc_dapm_stream_stop(rtd, stream); + if (!rollback) + snd_soc_dapm_stream_stop(rtd, stream); mutex_unlock(&rtd->card->pcm_mutex); - snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 0); + snd_soc_pcm_component_pm_runtime_put(rtd, cstream, rollback); return 0; } +static int soc_compr_free(struct snd_compr_stream *cstream) +{ + return soc_compr_clean(cstream, 0); +} + static int soc_compr_open(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -65,36 +72,28 @@ static int soc_compr_open(struct snd_compr_stream *cstream) ret = snd_soc_pcm_component_pm_runtime_get(rtd, cstream); if (ret < 0) - goto pm_err; + goto err_no_lock; mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); ret = snd_soc_dai_compr_startup(cpu_dai, cstream); if (ret < 0) - goto out; + goto err; ret = snd_soc_component_compr_open(cstream); if (ret < 0) - goto machine_err; + goto err; ret = snd_soc_link_compr_startup(cstream); if (ret < 0) - goto machine_err; + goto err; snd_soc_runtime_activate(rtd, stream); - - mutex_unlock(&rtd->card->pcm_mutex); - - return 0; - -machine_err: - snd_soc_component_compr_free(cstream, 1); - - snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); -out: +err: mutex_unlock(&rtd->card->pcm_mutex); -pm_err: - snd_soc_pcm_component_pm_runtime_put(rtd, cstream, 1); +err_no_lock: + if (ret < 0) + soc_compr_clean(cstream, 1); return ret; } -- cgit v1.2.3 From 6f4a038b99677f4db737841b81b9d45ed4b54966 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 4 Nov 2020 01:22:24 +0800 Subject: ASoC/SoundWire: rt715-sdca: First version of rt715 sdw sdca codec driver First version of rt715 sdw sdca codec driver. Signed-off-by: Jack Yu Reviewed-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20201103172226.4278-4-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt715-sdca-sdw.c | 278 +++++++++++ sound/soc/codecs/rt715-sdca-sdw.h | 170 +++++++ sound/soc/codecs/rt715-sdca.c | 936 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt715-sdca.h | 124 +++++ 6 files changed, 1517 insertions(+) create mode 100644 sound/soc/codecs/rt715-sdca-sdw.c create mode 100644 sound/soc/codecs/rt715-sdca-sdw.h create mode 100644 sound/soc/codecs/rt715-sdca.c create mode 100644 sound/soc/codecs/rt715-sdca.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 34c6dd04b85a..e7797f08e057 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -177,6 +177,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT700_SDW imply SND_SOC_RT711_SDW imply SND_SOC_RT715_SDW + imply SND_SOC_RT715_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_SGTL5000 imply SND_SOC_SI476X @@ -1216,6 +1217,12 @@ config SND_SOC_RT715_SDW select SND_SOC_RT715 select REGMAP_SOUNDWIRE +config SND_SOC_RT715_SDCA_SDW + tristate "Realtek RT715 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + select REGMAP_SOUNDWIRE_MBQ + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 11ce98c25d6c..b1683403afb3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -188,6 +188,7 @@ snd-soc-rt5682-i2c-objs := rt5682-i2c.o snd-soc-rt700-objs := rt700.o rt700-sdw.o snd-soc-rt711-objs := rt711.o rt711-sdw.o snd-soc-rt715-objs := rt715.o rt715-sdw.o +snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o @@ -498,6 +499,7 @@ obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o +obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c new file mode 100644 index 000000000000..889b6b3b0009 --- /dev/null +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt715-sdca-sdw.c -- rt715 ALSA SoC audio driver +// +// Copyright(c) 2020 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt715-sdca.h" +#include "rt715-sdca-sdw.h" + +static bool rt715_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x201a ... 0x2027: + case 0x2029 ... 0x202a: + case 0x202d ... 0x2034: + case 0x2200 ... 0x2204: + case 0x2206 ... 0x2212: + case 0x2230 ... 0x2239: + case 0x2f5b: + case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): + return true; + default: + return false; + } +} + +static bool rt715_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x201b: + case 0x201c: + case 0x201d: + case 0x201f: + case 0x2021: + case 0x2023: + case 0x2230: + case 0x202d ... 0x202f: /* BRA */ + case 0x2200 ... 0x2212: /* i2c debug */ + case 0x2f07: + case 0x2f1b ... 0x2f1e: + case 0x2f30 ... 0x2f34: + case 0x2f50 ... 0x2f51: + case 0x2f53 ... 0x2f59: + case 0x2f5c ... 0x2f5f: + case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): /* VAD Searching status */ + return true; + default: + return false; + } +} + +static bool rt715_sdca_mbq_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2000000: + case 0x200002b: + case 0x2000036: + case 0x2000037: + case 0x2000039: + case 0x6100000: + return true; + default: + return false; + } +} + +static bool rt715_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2000000: + return true; + default: + return false; + } +} + +static const struct regmap_config rt715_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt715_sdca_readable_register, + .volatile_reg = rt715_sdca_volatile_register, + .max_register = 0x43ffffff, + .reg_defaults = rt715_reg_defaults_sdca, + .num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults_sdca), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct regmap_config rt715_sdca_mbq_regmap = { + .name = "sdw-mbq", + .reg_bits = 32, + .val_bits = 16, + .readable_reg = rt715_sdca_mbq_readable_register, + .volatile_reg = rt715_sdca_mbq_volatile_register, + .max_register = 0x43ffffff, + .reg_defaults = rt715_mbq_reg_defaults_sdca, + .num_reg_defaults = ARRAY_SIZE(rt715_mbq_reg_defaults_sdca), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt715_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt715->status = status; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt715->hw_init || rt715->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt715_io_init(&slave->dev, slave); +} + +static int rt715_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval, i; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x50;/* BITMAP: 01010000 */ + prop->sink_ports = 0x0; /* BITMAP: 00000000 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + dpn = prop->src_dpn_prop; + i = 0; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + return 0; +} + +static struct sdw_slave_ops rt715_sdca_slave_ops = { + .read_prop = rt715_read_prop, + .update_status = rt715_update_status, +}; + +static int rt715_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *mbq_regmap, *regmap; + + slave->ops = &rt715_sdca_slave_ops; + + /* Regmap Initialization */ + mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap); + if (!mbq_regmap) + return -EINVAL; + + regmap = devm_regmap_init_sdw(slave, &rt715_sdca_regmap); + if (!regmap) + return -EINVAL; + + return rt715_init(&slave->dev, mbq_regmap, regmap, slave); +} + +static const struct sdw_device_id rt715_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt715_sdca_id); + +static int __maybe_unused rt715_dev_suspend(struct device *dev) +{ + struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); + + if (!rt715->hw_init) + return 0; + + regcache_cache_only(rt715->regmap, true); + regcache_mark_dirty(rt715->regmap); + regcache_cache_only(rt715->mbq_regmap, true); + regcache_mark_dirty(rt715->mbq_regmap); + + return 0; +} + +#define RT715_PROBE_TIMEOUT 2000 + +static int __maybe_unused rt715_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt715->hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->enumeration_complete, + msecs_to_jiffies(RT715_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt715->regmap, false); + regcache_sync_region(rt715->regmap, + SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL, + CH_00), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00)); + regcache_cache_only(rt715->mbq_regmap, false); + regcache_sync_region(rt715->mbq_regmap, 0x2000000, 0x61020ff); + regcache_sync_region(rt715->mbq_regmap, + SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL, + CH_00), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00)); + + return 0; +} + +static const struct dev_pm_ops rt715_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume) + SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL) +}; + +static struct sdw_driver rt715_sdw_driver = { + .driver = { + .name = "rt715-sdca", + .owner = THIS_MODULE, + .pm = &rt715_pm, + }, + .probe = rt715_sdca_sdw_probe, + .ops = &rt715_sdca_slave_ops, + .id_table = rt715_sdca_id, +}; +module_sdw_driver(rt715_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT715 driver SDW SDCA"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h new file mode 100644 index 000000000000..cd365bb60747 --- /dev/null +++ b/sound/soc/codecs/rt715-sdca-sdw.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt715-sdca-sdw.h -- RT715 ALSA SoC audio driver header + * + * Copyright(c) 2020 Realtek Semiconductor Corp. + */ + +#ifndef __RT715_SDW_SDCA_H__ +#define __RT715_SDW_SDCA_H__ + +#include + +static const struct reg_default rt715_reg_defaults_sdca[] = { + { 0x201a, 0x00 }, + { 0x201e, 0x00 }, + { 0x2020, 0x00 }, + { 0x2021, 0x00 }, + { 0x2022, 0x00 }, + { 0x2023, 0x00 }, + { 0x2024, 0x00 }, + { 0x2025, 0x01 }, + { 0x2026, 0x00 }, + { 0x2027, 0x00 }, + { 0x2029, 0x00 }, + { 0x202a, 0x00 }, + { 0x202d, 0x00 }, + { 0x202e, 0x00 }, + { 0x202f, 0x00 }, + { 0x2030, 0x00 }, + { 0x2031, 0x00 }, + { 0x2032, 0x00 }, + { 0x2033, 0x00 }, + { 0x2034, 0x00 }, + { 0x2230, 0x00 }, + { 0x2231, 0x2f }, + { 0x2232, 0x80 }, + { 0x2233, 0x00 }, + { 0x2234, 0x00 }, + { 0x2235, 0x00 }, + { 0x2236, 0x00 }, + { 0x2237, 0x00 }, + { 0x2238, 0x00 }, + { 0x2239, 0x00 }, + { 0x2f01, 0x00 }, + { 0x2f02, 0x09 }, + { 0x2f03, 0x0b }, + { 0x2f04, 0x00 }, + { 0x2f05, 0x0e }, + { 0x2f06, 0x01 }, + { 0x2f08, 0x00 }, + { 0x2f09, 0x00 }, + { 0x2f0a, 0x00 }, + { 0x2f0b, 0x00 }, + { 0x2f0c, 0x00 }, + { 0x2f0d, 0x00 }, + { 0x2f0e, 0x12 }, + { 0x2f0f, 0x00 }, + { 0x2f10, 0x00 }, + { 0x2f11, 0x00 }, + { 0x2f12, 0x00 }, + { 0x2f13, 0x00 }, + { 0x2f14, 0x00 }, + { 0x2f15, 0x00 }, + { 0x2f16, 0x00 }, + { 0x2f17, 0x00 }, + { 0x2f18, 0x00 }, + { 0x2f19, 0x03 }, + { 0x2f1a, 0x00 }, + { 0x2f1f, 0x10 }, + { 0x2f20, 0x00 }, + { 0x2f21, 0x00 }, + { 0x2f22, 0x00 }, + { 0x2f23, 0x00 }, + { 0x2f24, 0x00 }, + { 0x2f25, 0x00 }, + { 0x2f52, 0x01 }, + { 0x2f5a, 0x02 }, + { 0x2f5b, 0x05 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN, + RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, +}; + +static const struct reg_default rt715_mbq_reg_defaults_sdca[] = { + { 0x200002b, 0x0420 }, + { 0x2000036, 0x0000 }, + { 0x2000037, 0x0000 }, + { 0x2000039, 0xaa81 }, + { 0x6100000, 0x0100 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 }, +}; +#endif /* __RT715_SDW_SDCA_H__ */ diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c new file mode 100644 index 000000000000..b843e47eb25b --- /dev/null +++ b/sound/soc/codecs/rt715-sdca.c @@ -0,0 +1,936 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt715-sdca.c -- rt715 ALSA SoC audio driver +// +// Copyright(c) 2020 Realtek Semiconductor Corp. +// +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt715-sdca.h" + +static int rt715_index_write(struct rt715_sdca_priv *rt715, unsigned int nid, + unsigned int reg, unsigned int value) +{ + struct regmap *regmap = rt715->mbq_regmap; + unsigned int addr; + int ret; + + addr = (nid << 20) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + dev_err(&rt715->slave->dev, + "Failed to set private value: %08x <= %04x %d\n", ret, addr, + value); + + return ret; +} + +static int rt715_index_read(struct rt715_sdca_priv *rt715, + unsigned int nid, unsigned int reg, unsigned int *value) +{ + struct regmap *regmap = rt715->mbq_regmap; + unsigned int addr; + int ret; + + addr = (nid << 20) | reg; + + ret = regmap_read(regmap, addr, value); + if (ret < 0) + dev_err(&rt715->slave->dev, + "Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} + +static int rt715_index_update_bits(struct rt715_sdca_priv *rt715, + unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp; + int ret; + + ret = rt715_index_read(rt715, nid, reg, &tmp); + if (ret < 0) + return ret; + + set_mask_bits(&tmp, mask, val); + + return rt715_index_write(rt715, nid, reg, tmp); +} + +/* SDCA Volume/Boost control */ +static int rt715_set_amp_gain_put_sdca(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int val_l, val_r, gain_l_val, gain_r_val; + int ret; + + /* control value to 2s complement */ + /* L channel */ + gain_l_val = ucontrol->value.integer.value[0]; + if (gain_l_val > mc->max) + gain_l_val = mc->max; + val_l = gain_l_val; + + if (mc->shift == 8) { + gain_l_val = (gain_l_val * 10) << mc->shift; + } else { + gain_l_val = + ((abs(gain_l_val - mc->shift) * RT715_SDCA_DB_STEP) << 8) / 1000; + if (val_l <= mc->shift) { + gain_l_val = ~gain_l_val; + gain_l_val += 1; + } + gain_l_val &= 0xffff; + } + + /* R channel */ + gain_r_val = ucontrol->value.integer.value[1]; + if (gain_r_val > mc->max) + gain_r_val = mc->max; + val_r = gain_r_val; + + if (mc->shift == 8) { + gain_r_val = (gain_r_val * 10) << mc->shift; + } else { + gain_r_val = + ((abs(gain_r_val - mc->shift) * RT715_SDCA_DB_STEP) << 8) / 1000; + if (val_r <= mc->shift) { + gain_r_val = ~gain_r_val; + gain_r_val += 1; + } + gain_r_val &= 0xffff; + } + + /* Lch*/ + ret = regmap_write(rt715->mbq_regmap, mc->reg, gain_l_val); + if (ret != 0) { + dev_err(component->dev, "Failed to write 0x%x=0x%x\n", mc->reg, + gain_l_val); + return ret; + } + /* Rch */ + ret = regmap_write(rt715->mbq_regmap, mc->rreg, gain_r_val); + if (ret != 0) { + dev_err(component->dev, "Failed to write 0x%x=0x%x\n", mc->rreg, + gain_r_val); + return ret; + } + + return 0; +} + +static int rt715_set_amp_gain_get_sdca(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int val_l, val_r, ctl_l, ctl_r, neg_flag = 0; + int ret; + + ret = regmap_read(rt715->mbq_regmap, mc->reg, &val_l); + if (ret < 0) + dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", mc->reg, ret); + ret = regmap_read(rt715->mbq_regmap, mc->rreg, &val_r); + if (ret < 0) + dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", mc->rreg, + ret); + + /* L channel */ + if (mc->shift == 8) { + ctl_l = (val_l >> mc->shift) / 10; + } else { + ctl_l = val_l; + if (ctl_l & BIT(15)) { + ctl_l = ~(val_l - 1) & 0xffff; + neg_flag = 1; + } + ctl_l *= 1000; + ctl_l >>= 8; + if (neg_flag) + ctl_l = mc->shift - ctl_l / RT715_SDCA_DB_STEP; + else + ctl_l = mc->shift + ctl_l / RT715_SDCA_DB_STEP; + } + + neg_flag = 0; + /* R channel */ + if (mc->shift == 8) { + ctl_r = (val_r >> mc->shift) / 10; + } else { + ctl_r = val_r; + if (ctl_r & BIT(15)) { + ctl_r = ~(val_r - 1) & 0xffff; + neg_flag = 1; + } + ctl_r *= 1000; + ctl_r >>= 8; + if (neg_flag) + ctl_r = mc->shift - ctl_r / RT715_SDCA_DB_STEP; + else + ctl_r = mc->shift + ctl_r / RT715_SDCA_DB_STEP; + } + + ucontrol->value.integer.value[0] = ctl_l; + ucontrol->value.integer.value[1] = ctl_r; + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\ + xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_soc_info_volsw, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ + xmax, xinvert) } + +static const struct snd_kcontrol_new rt715_snd_controls_sdca[] = { + /* Capture switch */ + SOC_DOUBLE_R("FU0A Capture Switch", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), + 0, 1, 1), + SOC_DOUBLE_R("FU02 1_2 Capture Switch", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), + 0, 1, 1), + SOC_DOUBLE_R("FU02 3_4 Capture Switch", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_03), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_04), + 0, 1, 1), + SOC_DOUBLE_R("FU06 1_2 Capture Switch", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), + 0, 1, 1), + SOC_DOUBLE_R("FU06 3_4 Capture Switch", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_03), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_04), + 0, 1, 1), + /* Volume Control */ + SOC_DOUBLE_R_EXT_TLV("FU0A Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), + 0x2f, 0x7f, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU02 1_2 Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), + 0x2f, 0x7f, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU02 3_4 Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, + CH_03), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, + CH_04), 0x2f, 0x7f, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU06 1_2 Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, + CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, + CH_02), 0x2f, 0x7f, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU06 3_4 Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, + CH_03), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, + CH_04), 0x2f, 0x7f, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + in_vol_tlv), + /* MIC Boost Control */ + SOC_DOUBLE_R_EXT_TLV("FU0E 1_2 Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_02), 8, 3, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU0E 3_4 Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_03), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_04), 8, 3, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU0E 5_6 Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_05), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_06), 8, 3, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU0E 7_8 Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_07), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_08), 8, 3, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU0C 1_2 Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_02), 8, 3, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU0C 3_4 Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_03), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_04), 8, 3, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU0C 5_6 Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_05), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_06), 8, 3, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU0C 7_8 Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_07), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, + CH_08), 8, 3, 0, + rt715_set_amp_gain_get_sdca, rt715_set_amp_gain_put_sdca, + mic_vol_tlv), +}; + +static int rt715_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int val, mask_sft; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + mask_sft = 12; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + mask_sft = 8; + else if (strstr(ucontrol->id.name, "ADC 24 Mux")) + mask_sft = 4; + else if (strstr(ucontrol->id.name, "ADC 25 Mux")) + mask_sft = 0; + else + return -EINVAL; + + rt715_index_read(rt715, RT715_VENDOR_HDA_CTL, + RT715_HDA_LEGACY_MUX_CTL1, &val); + val = (val >> mask_sft) & 0xf; + + /* + * The first two indices of ADC Mux 24/25 are routed to the same + * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2. + * To have a unique set of inputs, we skip the index1 of the muxes. + */ + if ((strstr(ucontrol->id.name, "ADC 24 Mux") || + strstr(ucontrol->id.name, "ADC 25 Mux")) && val > 0) + val -= 1; + ucontrol->value.enumerated.item[0] = val; + + return 0; +} + +static int rt715_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, mask_sft; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + mask_sft = 12; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + mask_sft = 8; + else if (strstr(ucontrol->id.name, "ADC 24 Mux")) + mask_sft = 4; + else if (strstr(ucontrol->id.name, "ADC 25 Mux")) + mask_sft = 0; + else + return -EINVAL; + + /* Verb ID = 0x701h, nid = e->reg */ + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + rt715_index_read(rt715, RT715_VENDOR_HDA_CTL, + RT715_HDA_LEGACY_MUX_CTL1, &val2); + val2 = (val2 >> mask_sft) & 0xf; + + change = val != val2; + + if (change) + rt715_index_update_bits(rt715, RT715_VENDOR_HDA_CTL, + RT715_HDA_LEGACY_MUX_CTL1, 0xf << mask_sft, val << mask_sft); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); + + return change; +} + +static const char * const adc_22_23_mux_text[] = { + "MIC1", + "MIC2", + "LINE1", + "LINE2", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +/* + * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and + * 1 will be connected to the same dmic source, therefore we skip index 1 to + * avoid misunderstanding on usage of dapm routing. + */ +static int rt715_adc_24_25_values[] = { + 0, + 2, + 3, + 4, + 5, +}; + +static const char * const adc_24_mux_text[] = { + "MIC2", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +static const char * const adc_25_mux_text[] = { + "MIC1", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +static SOC_ENUM_SINGLE_DECL(rt715_adc22_enum, SND_SOC_NOPM, 0, + adc_22_23_mux_text); + +static SOC_ENUM_SINGLE_DECL(rt715_adc23_enum, SND_SOC_NOPM, 0, + adc_22_23_mux_text); + +static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum, + SND_SOC_NOPM, 0, 0xf, + adc_24_mux_text, rt715_adc_24_25_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum, + SND_SOC_NOPM, 0, 0xf, + adc_25_mux_text, rt715_adc_24_25_values); + +static const struct snd_kcontrol_new rt715_adc22_mux = + SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt715_adc22_enum, + rt715_mux_get, rt715_mux_put); + +static const struct snd_kcontrol_new rt715_adc23_mux = + SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt715_adc23_enum, + rt715_mux_get, rt715_mux_put); + +static const struct snd_kcontrol_new rt715_adc24_mux = + SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt715_adc24_enum, + rt715_mux_get, rt715_mux_put); + +static const struct snd_kcontrol_new rt715_adc25_mux = + SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt715_adc25_enum, + rt715_mux_get, rt715_mux_put); + +static int rt715_pde23_24_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN, + RT715_SDCA_REQ_POW_CTRL, + CH_00), 0x00); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN, + RT715_SDCA_REQ_POW_CTRL, + CH_00), 0x03); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt715_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("DMIC3"), + SND_SOC_DAPM_INPUT("DMIC4"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + + SND_SOC_DAPM_SUPPLY("PDE23_24", SND_SOC_NOPM, 0, 0, + rt715_pde23_24_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_ADC("ADC 07", NULL, SND_SOC_NOPM, 4, 0), + SND_SOC_DAPM_ADC("ADC 08", NULL, SND_SOC_NOPM, 4, 0), + SND_SOC_DAPM_ADC("ADC 09", NULL, SND_SOC_NOPM, 4, 0), + SND_SOC_DAPM_ADC("ADC 27", NULL, SND_SOC_NOPM, 4, 0), + SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc22_mux), + SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc23_mux), + SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc24_mux), + SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc25_mux), + SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt715_audio_map[] = { + {"DP6TX", NULL, "ADC 09"}, + {"DP6TX", NULL, "ADC 08"}, + {"DP4TX", NULL, "ADC 07"}, + {"DP4TX", NULL, "ADC 27"}, + {"DP4TX", NULL, "ADC 09"}, + {"DP4TX", NULL, "ADC 08"}, + + {"LINE1", NULL, "PDE23_24"}, + {"LINE2", NULL, "PDE23_24"}, + {"MIC1", NULL, "PDE23_24"}, + {"MIC2", NULL, "PDE23_24"}, + {"DMIC1", NULL, "PDE23_24"}, + {"DMIC2", NULL, "PDE23_24"}, + {"DMIC3", NULL, "PDE23_24"}, + {"DMIC4", NULL, "PDE23_24"}, + + {"ADC 09", NULL, "ADC 22 Mux"}, + {"ADC 08", NULL, "ADC 23 Mux"}, + {"ADC 07", NULL, "ADC 24 Mux"}, + {"ADC 27", NULL, "ADC 25 Mux"}, + {"ADC 22 Mux", "MIC1", "MIC1"}, + {"ADC 22 Mux", "MIC2", "MIC2"}, + {"ADC 22 Mux", "LINE1", "LINE1"}, + {"ADC 22 Mux", "LINE2", "LINE2"}, + {"ADC 22 Mux", "DMIC1", "DMIC1"}, + {"ADC 22 Mux", "DMIC2", "DMIC2"}, + {"ADC 22 Mux", "DMIC3", "DMIC3"}, + {"ADC 22 Mux", "DMIC4", "DMIC4"}, + {"ADC 23 Mux", "MIC1", "MIC1"}, + {"ADC 23 Mux", "MIC2", "MIC2"}, + {"ADC 23 Mux", "LINE1", "LINE1"}, + {"ADC 23 Mux", "LINE2", "LINE2"}, + {"ADC 23 Mux", "DMIC1", "DMIC1"}, + {"ADC 23 Mux", "DMIC2", "DMIC2"}, + {"ADC 23 Mux", "DMIC3", "DMIC3"}, + {"ADC 23 Mux", "DMIC4", "DMIC4"}, + {"ADC 24 Mux", "MIC2", "MIC2"}, + {"ADC 24 Mux", "DMIC1", "DMIC1"}, + {"ADC 24 Mux", "DMIC2", "DMIC2"}, + {"ADC 24 Mux", "DMIC3", "DMIC3"}, + {"ADC 24 Mux", "DMIC4", "DMIC4"}, + {"ADC 25 Mux", "MIC1", "MIC1"}, + {"ADC 25 Mux", "DMIC1", "DMIC1"}, + {"ADC 25 Mux", "DMIC2", "DMIC2"}, + {"ADC 25 Mux", "DMIC3", "DMIC3"}, + {"ADC 25 Mux", "DMIC4", "DMIC4"}, +}; + +static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = { + .controls = rt715_snd_controls_sdca, + .num_controls = ARRAY_SIZE(rt715_snd_controls_sdca), + .dapm_widgets = rt715_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt715_dapm_widgets), + .dapm_routes = rt715_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt715_audio_map), +}; + +static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct rt715_sdw_stream_data *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt715_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + +{ + struct rt715_sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + if (!stream) + return; + + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct rt715_sdw_stream_data *stream; + int retval, port, num_channels; + unsigned int val; + + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt715->slave) + return -EINVAL; + + switch (dai->id) { + case RT715_AIF1: + direction = SDW_DATA_DIR_TX; + port = 6; + rt715_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL, + 0xa500); + break; + case RT715_AIF2: + direction = SDW_DATA_DIR_TX; + port = 4; + rt715_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL, + 0xaf00); + break; + default: + dev_err(component->dev, "Invalid DAI id %d\n", dai->id); + return -EINVAL; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = GENMASK(num_channels - 1, 0); + port_config.num = port; + + retval = sdw_stream_add_slave(rt715->slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(component->dev, "Unable to configure port, retval:%d\n", + retval); + return retval; + } + + switch (params_rate(params)) { + case 8000: + val = 0x1; + break; + case 11025: + val = 0x2; + break; + case 12000: + val = 0x3; + break; + case 16000: + val = 0x4; + break; + case 22050: + val = 0x5; + break; + case 24000: + val = 0x6; + break; + case 32000: + val = 0x7; + break; + case 44100: + val = 0x8; + break; + case 48000: + val = 0x9; + break; + case 88200: + val = 0xa; + break; + case 96000: + val = 0xb; + break; + case 176400: + val = 0xc; + break; + case 192000: + val = 0xd; + break; + case 384000: + val = 0xe; + break; + case 768000: + val = 0xf; + break; + default: + dev_err(component->dev, "Unsupported sample rate %d\n", + params_rate(params)); + return -EINVAL; + } + + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CS_FREQ_IND_EN, + RT715_SDCA_FREQ_IND_CTRL, CH_00), val); + + return 0; +} + +static int rt715_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct rt715_sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt715->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt715->slave, stream->sdw_stream); + return 0; +} + +#define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt715_ops = { + .hw_params = rt715_pcm_hw_params, + .hw_free = rt715_pcm_hw_free, + .set_sdw_stream = rt715_set_sdw_stream, + .shutdown = rt715_shutdown, +}; + +static struct snd_soc_dai_driver rt715_dai[] = { + { + .name = "rt715-aif1", + .id = RT715_AIF1, + .capture = { + .stream_name = "DP6 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT715_STEREO_RATES, + .formats = RT715_FORMATS, + }, + .ops = &rt715_ops, + }, + { + .name = "rt715-aif2", + .id = RT715_AIF2, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT715_STEREO_RATES, + .formats = RT715_FORMATS, + }, + .ops = &rt715_ops, + }, +}; + +/* Bus clock frequency */ +#define RT715_CLK_FREQ_9600000HZ 9600000 +#define RT715_CLK_FREQ_12000000HZ 12000000 +#define RT715_CLK_FREQ_6000000HZ 6000000 +#define RT715_CLK_FREQ_4800000HZ 4800000 +#define RT715_CLK_FREQ_2400000HZ 2400000 +#define RT715_CLK_FREQ_12288000HZ 12288000 + +int rt715_init(struct device *dev, struct regmap *mbq_regmap, + struct regmap *regmap, struct sdw_slave *slave) +{ + struct rt715_sdca_priv *rt715; + int ret; + + rt715 = devm_kzalloc(dev, sizeof(*rt715), GFP_KERNEL); + if (!rt715) + return -ENOMEM; + + dev_set_drvdata(dev, rt715); + rt715->slave = slave; + rt715->regmap = regmap; + rt715->mbq_regmap = mbq_regmap; + rt715->hw_sdw_ver = slave->id.sdw_version; + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt715->hw_init = false; + rt715->first_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_codec_dev_rt715_sdca, + rt715_dai, + ARRAY_SIZE(rt715_dai)); + + return ret; +} + +int rt715_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); + unsigned int hw_ver; + + if (rt715->hw_init) + return 0; + + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + if (!rt715->first_init) { + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + + rt715->first_init = true; + } + + pm_runtime_get_noresume(&slave->dev); + + rt715_index_read(rt715, RT715_VENDOR_REG, + RT715_PRODUCT_NUM, &hw_ver); + hw_ver = hw_ver & 0x000f; + + /* set clock selector = external */ + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN, + RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1); + /* set GPIO_4/5/6 to be 3rd/4th DMIC usage */ + if (hw_ver == 0x0) + rt715_index_update_bits(rt715, RT715_VENDOR_REG, + RT715_AD_FUNC_EN, 0x54, 0x54); + else if (hw_ver == 0x1) { + rt715_index_update_bits(rt715, RT715_VENDOR_REG, + RT715_AD_FUNC_EN, 0x55, 0x55); + rt715_index_update_bits(rt715, RT715_VENDOR_REG, + RT715_REV_1, 0x40, 0x40); + } + /* trigger mode = VAD enable */ + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x2); + /* SMPU-1 interrupt enable mask */ + regmap_update_bits(rt715->regmap, RT715_INT_MASK, 0x1, 0x1); + + /* Mark Slave initialization complete */ + rt715->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + return 0; +} + +MODULE_DESCRIPTION("ASoC rt715 driver SDW SDCA"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt715-sdca.h b/sound/soc/codecs/rt715-sdca.h new file mode 100644 index 000000000000..6326cd8c374e --- /dev/null +++ b/sound/soc/codecs/rt715-sdca.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt715-sdca.h -- RT715 ALSA SoC audio driver header + * + * Copyright(c) 2020 Realtek Semiconductor Corp. + */ + +#ifndef __RT715_SDCA_H__ +#define __RT715_SDCA_H__ + +#include +#include +#include +#include +#include +#include + +struct rt715_sdca_priv { + struct regmap *regmap; + struct regmap *mbq_regmap; + struct snd_soc_codec *codec; + struct sdw_slave *slave; + struct delayed_work adc_mute_work; + int dbg_nid; + int dbg_vid; + int dbg_payload; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_init; + int l_is_unmute; + int r_is_unmute; + int hw_sdw_ver; +}; + +struct rt715_sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +/* MIPI Register */ +#define RT715_INT_CTRL 0x005a +#define RT715_INT_MASK 0x005e + +/* NID */ +#define RT715_AUDIO_FUNCTION_GROUP 0x01 +#define RT715_MIC_ADC 0x07 +#define RT715_LINE_ADC 0x08 +#define RT715_MIX_ADC 0x09 +#define RT715_DMIC1 0x12 +#define RT715_DMIC2 0x13 +#define RT715_MIC1 0x18 +#define RT715_MIC2 0x19 +#define RT715_LINE1 0x1a +#define RT715_LINE2 0x1b +#define RT715_DMIC3 0x1d +#define RT715_DMIC4 0x29 +#define RT715_VENDOR_REG 0x20 +#define RT715_MUX_IN1 0x22 +#define RT715_MUX_IN2 0x23 +#define RT715_MUX_IN3 0x24 +#define RT715_MUX_IN4 0x25 +#define RT715_MIX_ADC2 0x27 +#define RT715_INLINE_CMD 0x55 +#define RT715_VENDOR_HDA_CTL 0x61 + +/* Index (NID:20h) */ +#define RT715_PRODUCT_NUM 0x0 +#define RT715_IRQ_CTRL 0x2b +#define RT715_AD_FUNC_EN 0x36 +#define RT715_REV_1 0x37 +#define RT715_SDW_INPUT_SEL 0x39 +#define RT715_EXT_DMIC_CLK_CTRL2 0x54 + +/* Index (NID:61h) */ +#define RT715_HDA_LEGACY_MUX_CTL1 0x00 + +/* SDCA (Function) */ +#define FUN_JACK_CODEC 0x01 +#define FUN_MIC_ARRAY 0x02 +#define FUN_HID 0x03 +/* SDCA (Entity) */ +#define RT715_SDCA_ST_EN 0x00 +#define RT715_SDCA_CS_FREQ_IND_EN 0x01 +#define RT715_SDCA_FU_ADC8_9_VOL 0x02 +#define RT715_SDCA_SMPU_TRIG_ST_EN 0x05 +#define RT715_SDCA_FU_ADC10_11_VOL 0x06 +#define RT715_SDCA_FU_ADC7_27_VOL 0x0a +#define RT715_SDCA_FU_AMIC_GAIN_EN 0x0c +#define RT715_SDCA_FU_DMIC_GAIN_EN 0x0e +#define RT715_SDCA_CX_CLK_SEL_EN 0x10 +#define RT715_SDCA_CREQ_POW_EN 0x18 +/* SDCA (Control) */ +#define RT715_SDCA_ST_CTRL 0x00 +#define RT715_SDCA_CX_CLK_SEL_CTRL 0x01 +#define RT715_SDCA_REQ_POW_CTRL 0x01 +#define RT715_SDCA_FU_MUTE_CTRL 0x01 +#define RT715_SDCA_FU_VOL_CTRL 0x02 +#define RT715_SDCA_FU_DMIC_GAIN_CTRL 0x0b +#define RT715_SDCA_FREQ_IND_CTRL 0x10 +#define RT715_SDCA_SMPU_TRIG_EN_CTRL 0x10 +#define RT715_SDCA_SMPU_TRIG_ST_CTRL 0x11 +/* SDCA (Channel) */ +#define CH_00 0x00 +#define CH_01 0x01 +#define CH_02 0x02 +#define CH_03 0x03 +#define CH_04 0x04 +#define CH_05 0x05 +#define CH_06 0x06 +#define CH_07 0x07 +#define CH_08 0x08 + +#define RT715_SDCA_DB_STEP 375 + +enum { + RT715_AIF1, + RT715_AIF2, +}; + +int rt715_io_init(struct device *dev, struct sdw_slave *slave); +int rt715_init(struct device *dev, struct regmap *mbq_regmap, + struct regmap *regmap, struct sdw_slave *slave); + +#endif /* __RT715_SDCA_H__ */ -- cgit v1.2.3 From d4c1d9eb6611fee6cd3623e810282342757b57f6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 27 Nov 2020 09:07:35 +0900 Subject: ASoC: soc-core: add soc_playback_digital_mute() snd_soc_suspend() and soc_resume_deferred() are calling same snd_soc_dai_digital_mute() with same logic with different parameter. This patch adds new soc_playback_digital_mute() and share the code. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k0u7ekfv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cb7333da58f1..c03b7107cb77 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -520,13 +520,31 @@ static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) } #ifdef CONFIG_PM_SLEEP +static void soc_playback_digital_mute(struct snd_soc_card *card, int mute) +{ + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *dai; + int playback = SNDRV_PCM_STREAM_PLAYBACK; + int i; + + for_each_card_rtds(card, rtd) { + + if (rtd->dai_link->ignore_suspend) + continue; + + for_each_rtd_dais(rtd, i, dai) { + if (snd_soc_dai_stream_active(dai, playback)) + snd_soc_dai_digital_mute(dai, mute, playback); + } + } +} + /* powers down audio subsystem for suspend */ int snd_soc_suspend(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); struct snd_soc_component *component; struct snd_soc_pcm_runtime *rtd; - int playback = SNDRV_PCM_STREAM_PLAYBACK; int i; /* If the card is not initialized yet there is nothing to do */ @@ -543,17 +561,7 @@ int snd_soc_suspend(struct device *dev) snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); /* mute any active DACs */ - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *dai; - - if (rtd->dai_link->ignore_suspend) - continue; - - for_each_rtd_dais(rtd, i, dai) { - if (snd_soc_dai_stream_active(dai, playback)) - snd_soc_dai_digital_mute(dai, 1, playback); - } - } + soc_playback_digital_mute(card, 1); /* suspend all pcms */ for_each_card_rtds(card, rtd) { @@ -650,7 +658,6 @@ static void soc_resume_deferred(struct work_struct *work) deferred_resume_work); struct snd_soc_pcm_runtime *rtd; struct snd_soc_component *component; - int i; /* * our power state is still SNDRV_CTL_POWER_D3hot from suspend time, @@ -681,18 +688,7 @@ static void soc_resume_deferred(struct work_struct *work) } /* unmute any active DACs */ - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *dai; - int playback = SNDRV_PCM_STREAM_PLAYBACK; - - if (rtd->dai_link->ignore_suspend) - continue; - - for_each_rtd_dais(rtd, i, dai) { - if (snd_soc_dai_stream_active(dai, playback)) - snd_soc_dai_digital_mute(dai, 0, playback); - } - } + soc_playback_digital_mute(card, 0); snd_soc_card_resume_post(card); -- cgit v1.2.3 From baed393e8550fa075512772fad27e98ba9dcb527 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 27 Nov 2020 09:07:40 +0900 Subject: ASoC: soc-core: add soc_dapm_suspend_resume() snd_soc_suspend() and soc_resume_deferred() are calling same snd_soc_dapm_stream_event() with same logic with different parameter. This patch adds new soc_dapm_suspend_resume() and share the code. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87im9rekfp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c03b7107cb77..50b4ce6374a0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -539,6 +539,21 @@ static void soc_playback_digital_mute(struct snd_soc_card *card, int mute) } } +static void soc_dapm_suspend_resume(struct snd_soc_card *card, int event) +{ + struct snd_soc_pcm_runtime *rtd; + int stream; + + for_each_card_rtds(card, rtd) { + + if (rtd->dai_link->ignore_suspend) + continue; + + for_each_pcm_streams(stream) + snd_soc_dapm_stream_event(rtd, stream, event); + } +} + /* powers down audio subsystem for suspend */ int snd_soc_suspend(struct device *dev) { @@ -576,16 +591,7 @@ int snd_soc_suspend(struct device *dev) /* close any waiting streams */ snd_soc_flush_all_delayed_work(card); - for_each_card_rtds(card, rtd) { - int stream; - - if (rtd->dai_link->ignore_suspend) - continue; - - for_each_pcm_streams(stream) - snd_soc_dapm_stream_event(rtd, stream, - SND_SOC_DAPM_STREAM_SUSPEND); - } + soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_SUSPEND); /* Recheck all endpoints too, their state is affected by suspend */ dapm_mark_endpoints_dirty(card); @@ -656,7 +662,6 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_card *card = container_of(work, struct snd_soc_card, deferred_resume_work); - struct snd_soc_pcm_runtime *rtd; struct snd_soc_component *component; /* @@ -676,16 +681,7 @@ static void soc_resume_deferred(struct work_struct *work) snd_soc_component_resume(component); } - for_each_card_rtds(card, rtd) { - int stream; - - if (rtd->dai_link->ignore_suspend) - continue; - - for_each_pcm_streams(stream) - snd_soc_dapm_stream_event(rtd, stream, - SND_SOC_DAPM_STREAM_RESUME); - } + soc_dapm_suspend_resume(card, SND_SOC_DAPM_STREAM_RESUME); /* unmute any active DACs */ soc_playback_digital_mute(card, 0); -- cgit v1.2.3 From 7f2c63d6ae0754e5389c5942cb3bd670ea6cff40 Mon Sep 17 00:00:00 2001 From: xuyuqing Date: Wed, 18 Nov 2020 08:58:58 +0800 Subject: ASoC: qcom: sc7180: fix 32 bit format for adau7002 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the microphone is attached to external codec(adau7002) instead of rt5682.We need to always use 32 bit format on sc7180 to meet the clock requirement of adau7002: The ADAU7002 requires a BCLK rate that is a minimum of 64× the LRCLK sample rate Signed-off-by: xuyuqing Link: https://lore.kernel.org/r/20201118005858.123013-2-xuyuqing@huaqin.corp-partner.google.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc7180.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index de70fa792aea..768566bb57a5 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -245,6 +245,7 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_pcm_runtime *runtime = substream->runtime; switch (cpu_dai->id) { case MI2S_PRIMARY: @@ -252,6 +253,8 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S); + runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 32); break; case MI2S_SECONDARY: -- cgit v1.2.3 From e984f3ef3d2ac4a1896f7a3845b7c89c27841cbe Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Fri, 27 Nov 2020 18:40:18 +0200 Subject: ASoC: SOF: ops: add parse_platform_ext_manifest() op Add parse_platform_ext_manifest() op to parse platform-specific config data in the extended manifest. Signed-off-by: Fred Oh Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201127164022.2498406-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ext_manifest.h | 1 + sound/soc/sof/loader.c | 3 +++ sound/soc/sof/ops.h | 10 ++++++++++ sound/soc/sof/sof-priv.h | 5 +++++ 4 files changed, 19 insertions(+) (limited to 'sound') diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index e05cb21023e5..7abc4f0bd3ad 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -62,6 +62,7 @@ enum sof_ext_man_elem_type { SOF_EXT_MAN_ELEM_CC_VERSION = SOF_IPC_EXT_CC_INFO, SOF_EXT_MAN_ELEM_DBG_ABI = SOF_IPC_EXT_USER_ABI_INFO, SOF_EXT_MAN_ELEM_CONFIG_DATA = 5, /**< ABI3.17 */ + SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA = 6, }; /* extended manifest element header */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 2a8c9bff9963..cbce484b6469 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -330,6 +330,9 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev, case SOF_EXT_MAN_ELEM_CONFIG_DATA: ret = ext_man_get_config_data(sdev, elem_hdr); break; + case SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA: + ret = snd_sof_dsp_parse_platform_ext_manifest(sdev, elem_hdr); + break; default: dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n", elem_hdr->type, elem_hdr->size); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b21632f5511a..77a6ac157d37 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -100,6 +100,16 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } +/* parse platform specific extended manifest */ +static inline int snd_sof_dsp_parse_platform_ext_manifest(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr) +{ + if (sof_ops(sdev)->parse_platform_ext_manifest) + return sof_ops(sdev)->parse_platform_ext_manifest(sdev, hdr); + + return 0; +} + /* misc */ /** diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d8bc0178dc89..32d6ceb41fdd 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -18,6 +18,7 @@ #include #include #include +#include /* debug flags */ #define SOF_DBG_ENABLE_TRACE BIT(0) @@ -208,6 +209,10 @@ struct snd_sof_dsp_ops { int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ + /* parse platform specific extended manifest, optional */ + int (*parse_platform_ext_manifest)(struct snd_sof_dev *sof_dev, + const struct sof_ext_man_elem_header *hdr); + /* DSP PM */ int (*suspend)(struct snd_sof_dev *sof_dev, u32 target_state); /* optional */ -- cgit v1.2.3 From edbaaada5c9b57e243a98bf5b442f3a7a43ed14d Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Fri, 27 Nov 2020 18:40:19 +0200 Subject: ASoC: SOF: Intel: hda: define parse_platform_ext_manifest op Define the parse_platform_ext_manifest() op for HDA platforms to parse the SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO config item to determine if the FW is configured for LPRO. The default clock configuration is assumed to be HPRO in the absence of this item in the extended manifest. New member clk_config_lpro is added to struct sof_intel_hda_dev to store the FW clock config information and that this will be used later to perform platform-specific operations in the post_fw_run op. Signed-off-by: Fred Oh Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201127164022.2498406-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/apl.c | 3 +++ sound/soc/sof/intel/cnl.c | 3 +++ sound/soc/sof/intel/ext_manifest.h | 33 +++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda-loader.c | 35 +++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 7 +++++++ sound/soc/sof/intel/tgl.c | 3 +++ 6 files changed, 84 insertions(+) create mode 100644 sound/soc/sof/intel/ext_manifest.h (limited to 'sound') diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 4eeade2e77f7..fc29b91b8932 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -92,6 +92,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* parse platform specific extended manifest */ + .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, + /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index a5d3258104c0..158c38743731 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -294,6 +294,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* parse platform specific extended manifest */ + .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, + /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, diff --git a/sound/soc/sof/intel/ext_manifest.h b/sound/soc/sof/intel/ext_manifest.h new file mode 100644 index 000000000000..a30e25b4e655 --- /dev/null +++ b/sound/soc/sof/intel/ext_manifest.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + */ + +/* + * Intel extended manifest is a extra place to store Intel cavs specific + * metadata about firmware, for example LPRO/HPRO configuration is + * Intel cavs specific. This part of output binary is not signed. + */ + +#ifndef __INTEL_CAVS_EXT_MANIFEST_H__ +#define __INTEL_CAVS_EXT_MANIFEST_H__ + +#include + +/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements identificators */ +enum sof_cavs_config_elem_type { + SOF_EXT_MAN_CAVS_CONFIG_EMPTY = 0, + SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO = 1, +}; + +/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements */ +struct sof_ext_man_cavs_config_data { + struct sof_ext_man_elem_header hdr; + + struct sof_config_elem elems[]; +} __packed; + +#endif /* __INTEL_CAVS_EXT_MANIFEST_H__ */ diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 2707a16c6a4d..73806223abd1 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -19,6 +19,7 @@ #include #include #include +#include "ext_manifest.h" #include "../ops.h" #include "hda.h" @@ -470,3 +471,37 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) /* re-enable clock gating and power gating */ return hda_dsp_ctrl_clock_power_gating(sdev, true); } + +int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr) +{ + const struct sof_ext_man_cavs_config_data *config_data = + container_of(hdr, struct sof_ext_man_cavs_config_data, hdr); + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + int i, elem_num; + + /* calculate total number of config data elements */ + elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header)) + / sizeof(struct sof_config_elem); + if (elem_num <= 0) { + dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num); + return -EINVAL; + } + + for (i = 0; i < elem_num; i++) + switch (config_data->elems[i].token) { + case SOF_EXT_MAN_CAVS_CONFIG_EMPTY: + /* skip empty token */ + break; + case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO: + hda->clk_config_lpro = config_data->elems[i].value; + dev_dbg(sdev->dev, "FW clock config: %s\n", + hda->clk_config_lpro ? "LPRO" : "HPRO"); + break; + default: + dev_warn(sdev->dev, "unsupported token type: %d\n", + config_data->elems[i].token); + } + + return 0; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 75954e642c5e..d1df579e52aa 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -447,6 +447,9 @@ struct sof_intel_hda_dev { /* sdw context allocated by SoundWire driver */ struct sdw_intel_ctx *sdw; + + /* FW clock config, 0:HPRO, 1:LPRO */ + bool clk_config_lpro; }; static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) @@ -618,6 +621,10 @@ int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); +/* parse platform specific ext manifest ops */ +int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr); + /* * HDA Controller Operations. */ diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index bdcc66d0df78..2252ca38ff4b 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -84,6 +84,9 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* parse platform specific extended manifest */ + .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, + /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, -- cgit v1.2.3 From e3a85dbe30cf4c6904640da10e7dbd18c4ee7be7 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Fri, 27 Nov 2020 18:40:20 +0200 Subject: ASoC: SOF: ext_manifest: parse cavs extra config data elem OUTBOX_SIZE, INBOX_SIZE are defined but not being used yet. Handle these elements to avoid warning about unknown token type. Signed-off-by: Fred Oh Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201127164022.2498406-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/ext_manifest.h | 2 ++ sound/soc/sof/intel/hda-loader.c | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/ext_manifest.h b/sound/soc/sof/intel/ext_manifest.h index a30e25b4e655..2dfae9285d3c 100644 --- a/sound/soc/sof/intel/ext_manifest.h +++ b/sound/soc/sof/intel/ext_manifest.h @@ -21,6 +21,8 @@ enum sof_cavs_config_elem_type { SOF_EXT_MAN_CAVS_CONFIG_EMPTY = 0, SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO = 1, + SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE = 2, + SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE = 3, }; /* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements */ diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 73806223abd1..52101b1a3dac 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -498,8 +498,12 @@ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, dev_dbg(sdev->dev, "FW clock config: %s\n", hda->clk_config_lpro ? "LPRO" : "HPRO"); break; + case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE: + case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE: + /* These elements are defined but not being used yet. No warn is required */ + break; default: - dev_warn(sdev->dev, "unsupported token type: %d\n", + dev_info(sdev->dev, "unsupported token type: %d\n", config_data->elems[i].token); } -- cgit v1.2.3 From a70eb70827b4160ada657649c74647f8bb7768ae Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Fri, 27 Nov 2020 18:40:21 +0200 Subject: ASoC: SOF: ops: modify the signature of stall op Modify the signature of stall op to specify core_mask to stall cores. Signed-off-by: Fred Oh Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201127164022.2498406-5-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ops.h | 4 ++-- sound/soc/sof/sof-priv.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 77a6ac157d37..95e748b36903 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -48,10 +48,10 @@ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) return sof_ops(sdev)->run(sdev); } -static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev) +static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev, unsigned int core_mask) { if (sof_ops(sdev)->stall) - return sof_ops(sdev)->stall(sdev); + return sof_ops(sdev)->stall(sdev, core_mask); return 0; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 32d6ceb41fdd..9ba3e3ceed01 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -101,7 +101,7 @@ struct snd_sof_dsp_ops { /* DSP core boot / reset */ int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */ - int (*stall)(struct snd_sof_dev *sof_dev); /* optional */ + int (*stall)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */ int (*reset)(struct snd_sof_dev *sof_dev); /* optional */ int (*core_power_up)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */ -- cgit v1.2.3 From 0cde3e9f029c25b671402425a01e029952a38c8e Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Fri, 27 Nov 2020 18:40:22 +0200 Subject: ASoC: SOF: Intel: hda: add sof_icl_ops for ICL platforms Separate the dsp ops for ICL ops to specify the use of ICCMAX FW boot sequence in the run op. All other ops are identical with TGL except post_fw_run. The recommended HW programming sequence for ICL is to power up core 3 and keep it in stall if HPRO is enabled. Signed-off-by: Fred Oh Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201127164022.2498406-6-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Makefile | 2 +- sound/soc/sof/intel/cnl.c | 16 ----- sound/soc/sof/intel/hda-loader.c | 61 ++++++++++++++++ sound/soc/sof/intel/hda.h | 4 ++ sound/soc/sof/intel/icl.c | 145 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-pci-dev.c | 2 +- 6 files changed, 212 insertions(+), 18 deletions(-) create mode 100644 sound/soc/sof/intel/icl.c (limited to 'sound') diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 72d85b25df7d..2589111c2fae 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -8,7 +8,7 @@ snd-sof-intel-ipc-objs := intel-ipc.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-bus.o \ - apl.o cnl.o tgl.o + apl.o cnl.o tgl.o icl.o snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o snd-sof-intel-hda-objs := hda-codec.o diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 158c38743731..e38db519f38d 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -349,22 +349,6 @@ const struct sof_intel_dsp_desc cnl_chip_info = { }; EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -const struct sof_intel_dsp_desc icl_chip_info = { - /* Icelake */ - .cores_num = 4, - .init_core_mask = 1, - .host_managed_cores_mask = GENMASK(3, 0), - .ipc_req = CNL_DSP_REG_HIPCIDR, - .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, - .ipc_ack = CNL_DSP_REG_HIPCIDA, - .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, - .ipc_ctl = CNL_DSP_REG_HIPCCTL, - .rom_init_timeout = 300, - .ssp_count = ICL_SSP_COUNT, - .ssp_base_offset = CNL_SSP_BASE_OFFSET, -}; -EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); - const struct sof_intel_dsp_desc ehl_chip_info = { /* Elkhartlake */ .cores_num = 4, diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 52101b1a3dac..02c3ff897274 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -472,6 +472,46 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) return hda_dsp_ctrl_clock_power_gating(sdev, true); } +/* + * post fw run operations for ICL, + * Core 3 will be powered up and in stall when HPRO is enabled + */ +int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + int ret; + + if (sdev->first_boot) { + ret = hda_sdw_startup(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: could not startup SoundWire links\n"); + return ret; + } + } + + hda_sdw_int_enable(sdev, true); + + /* + * The recommended HW programming sequence for ICL is to + * power up core 3 and keep it in stall if HPRO is enabled. + * Major difference between ICL and TGL, on ICL core 3 is managed by + * the host whereas on TGL it is handled by the firmware. + */ + if (!hda->clk_config_lpro) { + ret = snd_sof_dsp_core_power_up(sdev, BIT(3)); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core power up failed on core 3\n"); + return ret; + } + + snd_sof_dsp_stall(sdev, BIT(3)); + } + + /* re-enable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, true); +} + int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, const struct sof_ext_man_elem_header *hdr) { @@ -509,3 +549,24 @@ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, return 0; } + +int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* make sure core_mask in host managed cores */ + core_mask &= chip->host_managed_cores_mask; + if (!core_mask) { + dev_err(sdev->dev, "error: core_mask is not in host managed cores\n"); + return -EINVAL; + } + + /* stall core */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); + + return 0; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d1df579e52aa..9ec8ae0fd649 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -615,11 +615,14 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); */ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev); +int hda_dsp_cl_boot_firmware_iccmax_icl(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); /* pre and post fw run ops */ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); +int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev); +int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask); /* parse platform specific ext manifest ops */ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, @@ -740,6 +743,7 @@ extern struct snd_soc_dai_driver skl_dai[]; extern const struct snd_sof_dsp_ops sof_apl_ops; extern const struct snd_sof_dsp_ops sof_cnl_ops; extern const struct snd_sof_dsp_ops sof_tgl_ops; +extern const struct snd_sof_dsp_ops sof_icl_ops; extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c new file mode 100644 index 000000000000..e9d5a0a58504 --- /dev/null +++ b/sound/soc/sof/intel/icl.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Fred Oh +// + +/* + * Hardware interface for audio DSP on IceLake. + */ + +#include +#include +#include +#include +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" + +static const struct snd_sof_debugfs_map icl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +/* Icelake ops */ +const struct snd_sof_dsp_ops sof_icl_ops = { + /* probe and remove */ + .probe = hda_dsp_probe, + .remove = hda_dsp_remove, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_thread = cnl_ipc_irq_thread, + + /* ipc */ + .send_msg = cnl_ipc_send_msg, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, + + .ipc_msg_data = hda_ipc_msg_data, + .ipc_pcm_params = hda_ipc_pcm_params, + + /* machine driver */ + .machine_select = hda_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = hda_set_mach_params, + + /* debug */ + .debug_map = icl_dsp_debugfs, + .debug_map_count = ARRAY_SIZE(icl_dsp_debugfs), + .dbg_dump = hda_dsp_dump, + .ipc_dump = cnl_ipc_dump, + + /* stream callbacks */ + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_hw_free = hda_dsp_stream_hw_free, + .pcm_trigger = hda_dsp_pcm_trigger, + .pcm_pointer = hda_dsp_pcm_pointer, + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) + /* probe callbacks */ + .probe_assign = hda_probe_compr_assign, + .probe_free = hda_probe_compr_free, + .probe_set_params = hda_probe_compr_set_params, + .probe_trigger = hda_probe_compr_trigger, + .probe_pointer = hda_probe_compr_pointer, +#endif + + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_raw, + + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run_icl, + + /* parse platform specific extended manifest */ + .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, + + /* dsp core power up/down */ + .core_power_up = hda_dsp_enable_core, + .core_power_down = hda_dsp_core_reset_power_down, + + /* firmware run */ + .run = hda_dsp_cl_boot_firmware_iccmax, + .stall = hda_dsp_core_stall_icl, + + /* trace callback */ + .trace_init = hda_dsp_trace_init, + .trace_release = hda_dsp_trace_release, + .trace_trigger = hda_dsp_trace_trigger, + + /* DAI drivers */ + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, + + /* PM */ + .suspend = hda_dsp_suspend, + .resume = hda_dsp_resume, + .runtime_suspend = hda_dsp_runtime_suspend, + .runtime_resume = hda_dsp_runtime_resume, + .runtime_idle = hda_dsp_runtime_idle, + .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + .set_power_state = hda_dsp_set_power_state, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + + .arch_ops = &sof_xtensa_arch_ops, +}; +EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +const struct sof_intel_dsp_desc icl_chip_info = { + /* Icelake */ + .cores_num = 4, + .init_core_mask = 1, + .host_managed_cores_mask = GENMASK(3, 0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index f2a107481336..153d66d5c948 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -209,7 +209,7 @@ static const struct sof_dev_desc icl_desc = { .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-icl.ri", .nocodec_tplg_filename = "sof-icl-nocodec.tplg", - .ops = &sof_cnl_ops, + .ops = &sof_icl_ops, }; #endif -- cgit v1.2.3 From 9be9f2d3d073ef42127475f4fb6a392ab133f629 Mon Sep 17 00:00:00 2001 From: Gyeongtaek Lee Date: Thu, 26 Nov 2020 21:34:52 +0900 Subject: ALSA: compress: allow pause and resume during draining With a stream with low bitrate, user can't pause or resume the stream near the end of the stream because current ALSA doesn't allow it. If the stream has very low bitrate enough to store whole stream into the buffer, user can't do anything except stop the stream and then restart it from the first because most of applications call draining after sending last frame to the kernel. If pause, resume are allowed during draining, user experience can be enhanced. To prevent malfunction in HW drivers which don't support pause during draining, pause during draining will only work if HW driver enable this feature explicitly by calling snd_compr_use_pause_in_draining(). Signed-off-by: Gyeongtaek Lee Acked-by: Vinod Koul Link: https://lore.kernel.org/r/000101d6c3f0$89b312b0$9d193810$@samsung.com Signed-off-by: Takashi Iwai --- include/sound/compress_driver.h | 16 ++++++++++++++++ sound/core/compress_offload.c | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index 70cbc5095e72..277087f635f3 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -67,6 +67,7 @@ struct snd_compr_runtime { * @metadata_set: metadata set flag, true when set * @next_track: has userspace signal next track transition, true when set * @partial_drain: undergoing partial_drain for stream, true when set + * @pause_in_draining: paused during draining state, true when set * @private_data: pointer to DSP private data * @dma_buffer: allocated buffer if any */ @@ -80,6 +81,7 @@ struct snd_compr_stream { bool metadata_set; bool next_track; bool partial_drain; + bool pause_in_draining; void *private_data; struct snd_dma_buffer dma_buffer; }; @@ -142,6 +144,7 @@ struct snd_compr_ops { * @direction: Playback or capture direction * @lock: device lock * @device: device id + * @use_pause_in_draining: allow pause in draining, true when set */ struct snd_compr { const char *name; @@ -152,6 +155,7 @@ struct snd_compr { unsigned int direction; struct mutex lock; int device; + bool use_pause_in_draining; #ifdef CONFIG_SND_VERBOSE_PROCFS /* private: */ char id[64]; @@ -166,6 +170,18 @@ int snd_compress_deregister(struct snd_compr *device); int snd_compress_new(struct snd_card *card, int device, int type, const char *id, struct snd_compr *compr); +/** + * snd_compr_use_pause_in_draining - Allow pause and resume in draining state + * @substream: compress substream to set + * + * Allow pause and resume in draining state. + * Only HW driver supports this transition can call this API. + */ +static inline void snd_compr_use_pause_in_draining(struct snd_compr_stream *substream) +{ + substream->device->use_pause_in_draining = true; +} + /* dsp driver callback apis * For playback: driver should call snd_compress_fragment_elapsed() to let the * framework know that a fragment has been consumed from the ring buffer diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index c1fec932c49d..debc30fcf5b3 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -709,11 +709,22 @@ static int snd_compr_pause(struct snd_compr_stream *stream) { int retval; - if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) + switch (stream->runtime->state) { + case SNDRV_PCM_STATE_RUNNING: + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); + if (!retval) + stream->runtime->state = SNDRV_PCM_STATE_PAUSED; + break; + case SNDRV_PCM_STATE_DRAINING: + if (!stream->device->use_pause_in_draining) + return -EPERM; + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); + if (!retval) + stream->pause_in_draining = true; + break; + default: return -EPERM; - retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); - if (!retval) - stream->runtime->state = SNDRV_PCM_STATE_PAUSED; + } return retval; } @@ -721,11 +732,22 @@ static int snd_compr_resume(struct snd_compr_stream *stream) { int retval; - if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED) + switch (stream->runtime->state) { + case SNDRV_PCM_STATE_PAUSED: + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); + if (!retval) + stream->runtime->state = SNDRV_PCM_STATE_RUNNING; + break; + case SNDRV_PCM_STATE_DRAINING: + if (!stream->pause_in_draining) + return -EPERM; + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); + if (!retval) + stream->pause_in_draining = false; + break; + default: return -EPERM; - retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); - if (!retval) - stream->runtime->state = SNDRV_PCM_STATE_RUNNING; + } return retval; } @@ -768,6 +790,7 @@ static int snd_compr_stop(struct snd_compr_stream *stream) /* clear flags and stop any drain wait */ stream->partial_drain = false; stream->metadata_set = false; + stream->pause_in_draining = false; snd_compr_drain_notify(stream); stream->runtime->total_bytes_available = 0; stream->runtime->total_bytes_transferred = 0; -- cgit v1.2.3 From faba002e5fe91aae09ac591187be71c9e201b8f0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Sep 2020 13:30:08 +0200 Subject: ALSA: hda/ca0132: Move unsol callback setups to parser The setup of unsolicited event callbacks should be done only once at the parser phase, not in the init phase that is called multiple times at each resume. This patch moves the unsol setup code in ca0132 codec driver to the more appropriate place. Reported-by: Hui Wang Link: https://lore.kernel.org/r/20200930113008.9307-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index d8370a417e3d..4fbec4258f58 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -8544,7 +8544,7 @@ static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb) ca0132_select_mic(codec); } -static void ca0132_init_unsol(struct hda_codec *codec) +static void ca0132_setup_unsol(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_hp, hp_callback); @@ -9376,7 +9376,6 @@ static int ca0132_init(struct hda_codec *codec) if (ca0132_quirk(spec) == QUIRK_AE5 || ca0132_quirk(spec) == QUIRK_AE7) ae5_register_set(codec); - ca0132_init_unsol(codec); ca0132_init_params(codec); ca0132_init_flags(codec); @@ -9941,6 +9940,8 @@ static int patch_ca0132(struct hda_codec *codec) if (err < 0) goto error; + ca0132_setup_unsol(codec); + return 0; error: -- cgit v1.2.3 From 83ab7b45a2c24997ce1831f8bc829b29e6b7c890 Mon Sep 17 00:00:00 2001 From: Daniel Martin Date: Sat, 28 Nov 2020 09:40:35 +0100 Subject: ALSA: usb-audio: Add support for Pioneer DJ DDJ-RR controller This patch allows the Pioneer DJ DDJ-RR to be seen as a USB audio device under Linux and therefore usable in such applications as Mixxx. Tested Master Audio out, headphones (both output jacks) and microphone input. All work perfectly. Signed-off-by: Daniel Martin Link: https://lore.kernel.org/r/20201128084035.2958-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 85b99c6d3c61..7454011f6006 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3523,6 +3523,62 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } }, +{ + /* + * PIONEER DJ DDJ-RR + * PCM is 6 channels out & 4 channels in @ 44.1 fixed + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000d), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, //Master, Headphones & Booth + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 44100, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 44100 } + } + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, //2x RCA inputs (CH1 & CH2) + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x82, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_IMPLICIT_FB, + .rates = SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 44100, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 44100 } + } + }, + { + .ifnum = -1 + } + } + } +}, + { /* * Pioneer DJ DJM-900NXS2 -- cgit v1.2.3 From 5c7797022fe9a95a4417c75fa59a1a2bfdc5a3be Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 26 Nov 2020 17:59:49 +0100 Subject: ALSA: ppc: drop if block with always false condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The remove callback is only called for devices that were probed successfully before. As the matching probe function cannot complete without error if dev->match_id != PS3_MATCH_ID_SOUND, we don't have to check this here. Signed-off-by: Uwe Kleine-König Reviewed-by: Geert Uytterhoeven Tested-by: Geoff Levand Link: https://lore.kernel.org/r/20201126165950.2554997-1-u.kleine-koenig@pengutronix.de Signed-off-by: Takashi Iwai --- sound/ppc/snd_ps3.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 58bb49fff184..6ab796a5d936 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -1053,8 +1053,6 @@ static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev) { int ret; pr_info("%s:start id=%d\n", __func__, dev->match_id); - if (dev->match_id != PS3_MATCH_ID_SOUND) - return -ENXIO; /* * ctl and preallocate buffer will be freed in -- cgit v1.2.3 From e4e1d47c7906cf108584c617c0b2ba32ed5428ed Mon Sep 17 00:00:00 2001 From: Leonard Goehrs Date: Fri, 27 Nov 2020 16:22:59 +0100 Subject: ALSA: ppc: remove redundant checks in PS3 driver probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check for the FW_FEATURE_PS3_LV1 firmware feature is already performed in ps3_system_bus_init() before registering the driver. So if the probe function is actually used, this feature is already known to be available. The check for the match id is also superfluous; the condition is always true because the bus' match function (ps3_system_bus_match()) only considers this driver for devices having: dev->match_id == snd_ps3_bus_driver_info.match_id. Suggested-by: Geert Uytterhoeven Signed-off-by: Leonard Goehrs Reviewed-by: Uwe Kleine-König Tested-by: Geoff Levand Link: https://lore.kernel.org/r/20201127152259.1470079-1-l.goehrs@pengutronix.de Signed-off-by: Takashi Iwai --- sound/ppc/snd_ps3.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 6ab796a5d936..966b709ee286 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -896,11 +896,6 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) u64 lpar_addr, lpar_size; static u64 dummy_mask; - if (WARN_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1))) - return -ENODEV; - if (WARN_ON(dev->match_id != PS3_MATCH_ID_SOUND)) - return -ENODEV; - the_card.ps3_dev = dev; ret = ps3_open_hv_device(dev); -- cgit v1.2.3 From 2c854e5c63ac56e7e0633fb6140c1bdf4d3dad96 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Nov 2020 09:37:14 +0100 Subject: ALSA: usb-audio: Add quirk for Pioneer DJ DDJ-SR2 Yet another quirk for Pioneer DJ DDJ-SR2, which is quite similar like other DJ DDJ models but with slightly different EPs or channels. Reported-by: Geraldo Link: https://lore.kernel.org/r/20201130083714.10640-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 7454011f6006..0e11cb96fa8c 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3579,6 +3579,63 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } }, +{ + /* + * PIONEER DJ DDJ-SR2 + * PCM is 4 channels out, 6 channels in @ 44.1 fixed + * The Feedback for the output is the input + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001e), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 44100, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 44100 } + } + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x82, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_IMPLICIT_FB, + .rates = SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 44100, + .nr_rates = 1, + .rate_table = (unsigned int[]) { 44100 } + } + }, + { + .ifnum = -1 + } + } + } +}, + { /* * Pioneer DJ DJM-900NXS2 -- cgit v1.2.3 From 2509bb342e476e740db448cce09c19b92905194e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Nov 2020 15:31:58 +0100 Subject: ASoC: amd: Downgrade print level for invalid ACP mode The acp3x raven driver skips the probing when the given device isn't connected with I2S. This skip behavior itself is fine, but the driver also emits an error message "Invalid ACP audio mode" with KERN_ERR. This isn't nice since it appears on the boot screen even if a boot splash is running, although this itself is no real error. Downgrade the print level to KERN_INFO so that this message won't appear on the console unnecessarily. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20201127143200.16272-2-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/amd/raven/pci-acp3x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c index 31b797c8bfe6..a7de4e607961 100644 --- a/sound/soc/amd/raven/pci-acp3x.c +++ b/sound/soc/amd/raven/pci-acp3x.c @@ -231,7 +231,7 @@ static int snd_acp3x_probe(struct pci_dev *pci, } break; default: - dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val); + dev_info(&pci->dev, "Invalid ACP audio mode : %d\n", val); ret = -ENODEV; goto disable_msi; } -- cgit v1.2.3 From ab5893fdc0693e4f747ef26194b6bbf628bdb044 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Nov 2020 15:31:59 +0100 Subject: ASoC: amd: Return -ENODEV for non-existing ACPI call AMD Renoir driver tries to identify the presence of DMIC by evaluating ACPI _WOV entry, and it returns -EINVAL when the ACPI call failed. This ended up an error message like snd_rn_pci_acp3x: probe of 0000:04:00.5 failed with error -22 although the system is correctly set up. For avoiding such a superfluous error message, change the return value to -ENODEV. Then the driver core just skips to the next one without complaining. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20201127143200.16272-3-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/amd/renoir/rn-pci-acp3x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index b943e59fc302..877350f38a68 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -224,7 +224,7 @@ static int snd_rn_acp_probe(struct pci_dev *pci, handle = ACPI_HANDLE(&pci->dev); ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status); if (ACPI_FAILURE(ret)) { - ret = -EINVAL; + ret = -ENODEV; goto de_init; } if (!dmic_status) { -- cgit v1.2.3 From bbe1f69dce94089943cc407a88325ae7e851d49c Mon Sep 17 00:00:00 2001 From: Lumi Lee Date: Mon, 30 Nov 2020 11:11:15 +0800 Subject: ASoC: mediatek: btcvsd fix tx stream assign Fix tx/rx stream assign in write. Write should use tx instead of rx. Signed-off-by: Lumi Lee Link: https://lore.kernel.org/r/1606705875-1940-1-git-send-email-Lumi.Lee@mediatek.com Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-btcvsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index 668fef3e319a..a554c57b6460 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -808,7 +808,7 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, spin_unlock_irqrestore(&bt->tx_lock, flags); if (!avail) { - int ret = wait_for_bt_irq(bt, bt->rx); + int ret = wait_for_bt_irq(bt, bt->tx); if (ret) return written_size; -- cgit v1.2.3 From 9e8434a0083b135b7fc34bd8fbd7cb99a47b3c08 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2020 08:45:19 +0900 Subject: ASoC: soc-core: tidyup jack.h soc-core.c don't need sound/jack.h anymore, but asoc.h needs it. This patch fixup header magic. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y2iju3zm.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/trace/events/asoc.h | 1 + sound/soc/soc-core.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index 40c300fe704d..4d8ef71090af 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -7,6 +7,7 @@ #include #include +#include #define DAPM_DIRECT "(direct)" #define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-") diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 50b4ce6374a0..4a86e987dcf0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 6cd4c6459e47402ab90802eca61a18b231434053 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 27 Nov 2020 13:30:30 +0100 Subject: ASoC: Add ADAU1372 audio CODEC support Add support for the Analog Devices ADAU1372 audio CODEC. [Alexandre Belloni: allow 32kHz for TDM4 in slave mode] Signed-off-by: Lars-Peter Clausen Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201127123030.1610574-2-alexandre.belloni@bootlin.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 16 + sound/soc/codecs/Makefile | 6 + sound/soc/codecs/adau1372-i2c.c | 40 ++ sound/soc/codecs/adau1372-spi.c | 58 +++ sound/soc/codecs/adau1372.c | 1062 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/adau1372.h | 21 + 6 files changed, 1203 insertions(+) create mode 100644 sound/soc/codecs/adau1372-i2c.c create mode 100644 sound/soc/codecs/adau1372-spi.c create mode 100644 sound/soc/codecs/adau1372.c create mode 100644 sound/soc/codecs/adau1372.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3edd6495f0c8..ec30d700901b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -23,6 +23,8 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AD193X_I2C imply SND_SOC_AD1980 imply SND_SOC_AD73311 + imply SND_SOC_ADAU1372_I2C + imply SND_SOC_ADAU1372_SPI imply SND_SOC_ADAU1373 imply SND_SOC_ADAU1761_I2C imply SND_SOC_ADAU1761_SPI @@ -364,6 +366,20 @@ config SND_SOC_AD73311 config SND_SOC_ADAU_UTILS tristate +config SND_SOC_ADAU1372 + tristate + select SND_SOC_ADAU_UTILS + +config SND_SOC_ADAU1372_I2C + tristate "Analog Devices ADAU1372 CODEC (I2C)" + select SND_SOC_ADAU1372 + select REGMAP_I2C + +config SND_SOC_ADAU1372_SPI + tristate "Analog Devices ADAU1372 CODEC (SPI)" + select SND_SOC_ADAU1372 + select REGMAP_SPI + config SND_SOC_ADAU1373 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 915e54f7f1a4..db00063bb0c0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -9,6 +9,9 @@ snd-soc-ad193x-i2c-objs := ad193x-i2c.o snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-adau-utils-objs := adau-utils.o +snd-soc-adau1372-objs := adau1372.o +snd-soc-adau1372-i2c-objs := adau1372-i2c.o +snd-soc-adau1372-spi-objs := adau1372-spi.o snd-soc-adau1373-objs := adau1373.o snd-soc-adau1701-objs := adau1701.o snd-soc-adau17x1-objs := adau17x1.o @@ -319,6 +322,9 @@ obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_ADAU_UTILS) += snd-soc-adau-utils.o +obj-$(CONFIG_SND_SOC_ADAU1372) += snd-soc-adau1372.o +obj-$(CONFIG_SND_SOC_ADAU1372_I2C) += snd-soc-adau1372-i2c.o +obj-$(CONFIG_SND_SOC_ADAU1372_SPI) += snd-soc-adau1372-spi.o obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c new file mode 100644 index 000000000000..fc87a76ff1ee --- /dev/null +++ b/sound/soc/codecs/adau1372-i2c.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for ADAU1372 codec + * + * Copyright 2016 Analog Devices Inc. + * Author: Lars-Peter Clausen + */ + +#include +#include +#include +#include +#include + +#include "adau1372.h" + +static int adau1372_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + return adau1372_probe(&client->dev, + devm_regmap_init_i2c(client, &adau1372_regmap_config), NULL); +} + +static const struct i2c_device_id adau1372_i2c_ids[] = { + { "adau1372", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adau1372_i2c_ids); + +static struct i2c_driver adau1372_i2c_driver = { + .driver = { + .name = "adau1372", + }, + .probe = adau1372_i2c_probe, + .id_table = adau1372_i2c_ids, +}; +module_i2c_driver(adau1372_i2c_driver); + +MODULE_DESCRIPTION("ASoC ADAU1372 CODEC I2C driver"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/adau1372-spi.c b/sound/soc/codecs/adau1372-spi.c new file mode 100644 index 000000000000..51298e00fbd6 --- /dev/null +++ b/sound/soc/codecs/adau1372-spi.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for ADAU1372 codec + * + * Copyright 2016 Analog Devices Inc. + * Author: Lars-Peter Clausen + */ + +#include +#include +#include +#include +#include + +#include "adau1372.h" + +static void adau1372_spi_switch_mode(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + + /* + * To get the device into SPI mode CLATCH has to be pulled low three + * times. Do this by issuing three dummy reads. + */ + spi_w8r8(spi, 0x00); + spi_w8r8(spi, 0x00); + spi_w8r8(spi, 0x00); +} + +static int adau1372_spi_probe(struct spi_device *spi) +{ + struct regmap_config config; + + config = adau1372_regmap_config; + config.read_flag_mask = 0x1; + + return adau1372_probe(&spi->dev, + devm_regmap_init_spi(spi, &config), adau1372_spi_switch_mode); +} + +static const struct spi_device_id adau1372_spi_id[] = { + { "adau1372", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, adau1372_spi_id); + +static struct spi_driver adau1372_spi_driver = { + .driver = { + .name = "adau1372", + }, + .probe = adau1372_spi_probe, + .id_table = adau1372_spi_id, +}; +module_spi_driver(adau1372_spi_driver); + +MODULE_DESCRIPTION("ASoC ADAU1372 CODEC SPI driver"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c new file mode 100644 index 000000000000..5ccbf1b6bcf5 --- /dev/null +++ b/sound/soc/codecs/adau1372.c @@ -0,0 +1,1062 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices ADAU1372 Audio Codec driver + * + * Copyright 2016 Analog Devices Inc. + * Author: Lars-Peter Clausen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "adau1372.h" +#include "adau-utils.h" + +struct adau1372 { + struct clk *clk; + struct regmap *regmap; + void (*switch_mode)(struct device *dev); + bool use_pll; + bool enabled; + bool master; + + struct snd_pcm_hw_constraint_list rate_constraints; + unsigned int slot_width; + + struct clk *mclk; + struct gpio_desc *pd_gpio; + struct device *dev; +}; + +#define ADAU1372_REG_CLK_CTRL 0x00 +#define ADAU1372_REG_PLL(x) (0x01 + (x)) +#define ADAU1372_REG_DAC_SOURCE 0x11 +#define ADAU1372_REG_SOUT_SOURCE_0_1 0x13 +#define ADAU1372_REG_SOUT_SOURCE_2_3 0x14 +#define ADAU1372_REG_SOUT_SOURCE_4_5 0x15 +#define ADAU1372_REG_SOUT_SOURCE_6_7 0x16 +#define ADAU1372_REG_ADC_SDATA_CH 0x17 +#define ADAU1372_REG_ASRCO_SOURCE_0_1 0x18 +#define ADAU1372_REG_ASRCO_SOURCE_2_3 0x19 +#define ADAU1372_REG_ASRC_MODE 0x1a +#define ADAU1372_REG_ADC_CTRL0 0x1b +#define ADAU1372_REG_ADC_CTRL1 0x1c +#define ADAU1372_REG_ADC_CTRL2 0x1d +#define ADAU1372_REG_ADC_CTRL3 0x1e +#define ADAU1372_REG_ADC_VOL(x) (0x1f + (x)) +#define ADAU1372_REG_PGA_CTRL(x) (0x23 + (x)) +#define ADAU1372_REG_PGA_BOOST 0x28 +#define ADAU1372_REG_MICBIAS 0x2d +#define ADAU1372_REG_DAC_CTRL 0x2e +#define ADAU1372_REG_DAC_VOL(x) (0x2f + (x)) +#define ADAU1372_REG_OP_STAGE_MUTE 0x31 +#define ADAU1372_REG_SAI0 0x32 +#define ADAU1372_REG_SAI1 0x33 +#define ADAU1372_REG_SOUT_CTRL 0x34 +#define ADAU1372_REG_MODE_MP(x) (0x38 + (x)) +#define ADAU1372_REG_OP_STAGE_CTRL 0x43 +#define ADAU1372_REG_DECIM_PWR 0x44 +#define ADAU1372_REG_INTERP_PWR 0x45 +#define ADAU1372_REG_BIAS_CTRL0 0x46 +#define ADAU1372_REG_BIAS_CTRL1 0x47 + +#define ADAU1372_CLK_CTRL_PLL_EN BIT(7) +#define ADAU1372_CLK_CTRL_XTAL_DIS BIT(4) +#define ADAU1372_CLK_CTRL_CLKSRC BIT(3) +#define ADAU1372_CLK_CTRL_CC_MDIV BIT(1) +#define ADAU1372_CLK_CTRL_MCLK_EN BIT(0) + +#define ADAU1372_SAI0_DELAY1 (0x0 << 6) +#define ADAU1372_SAI0_DELAY0 (0x1 << 6) +#define ADAU1372_SAI0_DELAY_MASK (0x3 << 6) +#define ADAU1372_SAI0_SAI_I2S (0x0 << 4) +#define ADAU1372_SAI0_SAI_TDM2 (0x1 << 4) +#define ADAU1372_SAI0_SAI_TDM4 (0x2 << 4) +#define ADAU1372_SAI0_SAI_TDM8 (0x3 << 4) +#define ADAU1372_SAI0_SAI_MASK (0x3 << 4) +#define ADAU1372_SAI0_FS_48 0x0 +#define ADAU1372_SAI0_FS_8 0x1 +#define ADAU1372_SAI0_FS_12 0x2 +#define ADAU1372_SAI0_FS_16 0x3 +#define ADAU1372_SAI0_FS_24 0x4 +#define ADAU1372_SAI0_FS_32 0x5 +#define ADAU1372_SAI0_FS_96 0x6 +#define ADAU1372_SAI0_FS_192 0x7 +#define ADAU1372_SAI0_FS_MASK 0xf + +#define ADAU1372_SAI1_TDM_TS BIT(7) +#define ADAU1372_SAI1_BCLK_TDMC BIT(6) +#define ADAU1372_SAI1_LR_MODE BIT(5) +#define ADAU1372_SAI1_LR_POL BIT(4) +#define ADAU1372_SAI1_BCLKRATE BIT(2) +#define ADAU1372_SAI1_BCLKEDGE BIT(1) +#define ADAU1372_SAI1_MS BIT(0) + +static const unsigned int adau1372_rates[] = { + [ADAU1372_SAI0_FS_8] = 8000, + [ADAU1372_SAI0_FS_12] = 12000, + [ADAU1372_SAI0_FS_16] = 16000, + [ADAU1372_SAI0_FS_24] = 24000, + [ADAU1372_SAI0_FS_32] = 32000, + [ADAU1372_SAI0_FS_48] = 48000, + [ADAU1372_SAI0_FS_96] = 96000, + [ADAU1372_SAI0_FS_192] = 192000, +}; + +/* 8k, 12k, 24k, 48k */ +#define ADAU1372_RATE_MASK_TDM8 0x17 +/* + 16k, 96k */ +#define ADAU1372_RATE_MASK_TDM4_MASTER (ADAU1372_RATE_MASK_TDM8 | 0x48 | 0x20) +/* +32k */ +#define ADAU1372_RATE_MASK_TDM4 (ADAU1372_RATE_MASK_TDM4_MASTER | 0x20) +/* + 192k */ +#define ADAU1372_RATE_MASK_TDM2 (ADAU1372_RATE_MASK_TDM4 | 0x80) + +static const DECLARE_TLV_DB_MINMAX(adau1372_digital_tlv, -9563, 0); +static const DECLARE_TLV_DB_SCALE(adau1372_pga_tlv, -1200, 75, 0); +static const DECLARE_TLV_DB_SCALE(adau1372_pga_boost_tlv, 0, 1000, 0); + +static const char * const adau1372_bias_text[] = { + "Normal operation", "Extreme power saving", "Enhanced performance", + "Power saving", +}; + +static const unsigned int adau1372_bias_adc_values[] = { + 0, 2, 3, +}; + +static const char * const adau1372_bias_adc_text[] = { + "Normal operation", "Enhanced performance", "Power saving", +}; + +static const char * const adau1372_bias_dac_text[] = { + "Normal operation", "Power saving", "Superior performance", + "Enhanced performance", +}; + +static SOC_ENUM_SINGLE_DECL(adau1372_bias_hp_enum, + ADAU1372_REG_BIAS_CTRL0, 6, adau1372_bias_text); +static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe0_1_enum, + ADAU1372_REG_BIAS_CTRL0, 4, adau1372_bias_text); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc2_3_enum, + ADAU1372_REG_BIAS_CTRL0, 2, 0x3, adau1372_bias_adc_text, + adau1372_bias_adc_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_bias_adc0_1_enum, + ADAU1372_REG_BIAS_CTRL0, 0, 0x3, adau1372_bias_adc_text, + adau1372_bias_adc_values); +static SOC_ENUM_SINGLE_DECL(adau1372_bias_afe2_3_enum, + ADAU1372_REG_BIAS_CTRL1, 4, adau1372_bias_text); +static SOC_ENUM_SINGLE_DECL(adau1372_bias_mic_enum, + ADAU1372_REG_BIAS_CTRL1, 2, adau1372_bias_text); +static SOC_ENUM_SINGLE_DECL(adau1372_bias_dac_enum, + ADAU1372_REG_BIAS_CTRL1, 0, adau1372_bias_dac_text); + +static const char * const adau1372_hpf_text[] = { + "Off", + "1 Hz", + "4 Hz", + "8 Hz", +}; + +static SOC_ENUM_SINGLE_DECL(adau1372_hpf0_1_enum, ADAU1372_REG_ADC_CTRL2, 5, + adau1372_hpf_text); +static SOC_ENUM_SINGLE_DECL(adau1372_hpf2_3_enum, ADAU1372_REG_ADC_CTRL3, 5, + adau1372_hpf_text); +static const struct snd_kcontrol_new adau1372_controls[] = { + SOC_SINGLE_TLV("ADC 0 Capture Volume", ADAU1372_REG_ADC_VOL(0), + 0, 0xff, 1, adau1372_digital_tlv), + SOC_SINGLE_TLV("ADC 1 Capture Volume", ADAU1372_REG_ADC_VOL(1), + 0, 0xff, 1, adau1372_digital_tlv), + SOC_SINGLE_TLV("ADC 2 Capture Volume", ADAU1372_REG_ADC_VOL(2), + 0, 0xff, 1, adau1372_digital_tlv), + SOC_SINGLE_TLV("ADC 3 Capture Volume", ADAU1372_REG_ADC_VOL(3), + 0, 0xff, 1, adau1372_digital_tlv), + SOC_SINGLE("ADC 0 Capture Switch", ADAU1372_REG_ADC_CTRL0, 3, 1, 1), + SOC_SINGLE("ADC 1 Capture Switch", ADAU1372_REG_ADC_CTRL0, 4, 1, 1), + SOC_SINGLE("ADC 2 Capture Switch", ADAU1372_REG_ADC_CTRL1, 3, 1, 1), + SOC_SINGLE("ADC 3 Capture Switch", ADAU1372_REG_ADC_CTRL1, 4, 1, 1), + + SOC_ENUM("ADC 0+1 High-Pass-Filter", adau1372_hpf0_1_enum), + SOC_ENUM("ADC 2+3 High-Pass-Filter", adau1372_hpf2_3_enum), + + SOC_SINGLE_TLV("PGA 0 Capture Volume", ADAU1372_REG_PGA_CTRL(0), + 0, 0x3f, 0, adau1372_pga_tlv), + SOC_SINGLE_TLV("PGA 1 Capture Volume", ADAU1372_REG_PGA_CTRL(1), + 0, 0x3f, 0, adau1372_pga_tlv), + SOC_SINGLE_TLV("PGA 2 Capture Volume", ADAU1372_REG_PGA_CTRL(2), + 0, 0x3f, 0, adau1372_pga_tlv), + SOC_SINGLE_TLV("PGA 3 Capture Volume", ADAU1372_REG_PGA_CTRL(3), + 0, 0x3f, 0, adau1372_pga_tlv), + SOC_SINGLE_TLV("PGA 0 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, + 0, 1, 0, adau1372_pga_boost_tlv), + SOC_SINGLE_TLV("PGA 1 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, + 1, 1, 0, adau1372_pga_boost_tlv), + SOC_SINGLE_TLV("PGA 2 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, + 2, 1, 0, adau1372_pga_boost_tlv), + SOC_SINGLE_TLV("PGA 3 Boost Capture Volume", ADAU1372_REG_PGA_BOOST, + 3, 1, 0, adau1372_pga_boost_tlv), + SOC_SINGLE("PGA 0 Capture Switch", ADAU1372_REG_PGA_CTRL(0), 7, 1, 1), + SOC_SINGLE("PGA 1 Capture Switch", ADAU1372_REG_PGA_CTRL(1), 7, 1, 1), + SOC_SINGLE("PGA 2 Capture Switch", ADAU1372_REG_PGA_CTRL(2), 7, 1, 1), + SOC_SINGLE("PGA 3 Capture Switch", ADAU1372_REG_PGA_CTRL(3), 7, 1, 1), + + SOC_SINGLE_TLV("DAC 0 Playback Volume", ADAU1372_REG_DAC_VOL(0), + 0, 0xff, 1, adau1372_digital_tlv), + SOC_SINGLE_TLV("DAC 1 Playback Volume", ADAU1372_REG_DAC_VOL(1), + 0, 0xff, 1, adau1372_digital_tlv), + SOC_SINGLE("DAC 0 Playback Switch", ADAU1372_REG_DAC_CTRL, 3, 1, 1), + SOC_SINGLE("DAC 1 Playback Switch", ADAU1372_REG_DAC_CTRL, 4, 1, 1), + + SOC_ENUM("Headphone Bias", adau1372_bias_hp_enum), + SOC_ENUM("Microphone Bias", adau1372_bias_mic_enum), + SOC_ENUM("AFE 0+1 Bias", adau1372_bias_afe0_1_enum), + SOC_ENUM("AFE 2+3 Bias", adau1372_bias_afe2_3_enum), + SOC_ENUM("ADC 0+1 Bias", adau1372_bias_adc0_1_enum), + SOC_ENUM("ADC 2+3 Bias", adau1372_bias_adc2_3_enum), + SOC_ENUM("DAC 0+1 Bias", adau1372_bias_dac_enum), +}; + +static const char * const adau1372_decimator_mux_text[] = { + "ADC", + "DMIC", +}; + +static SOC_ENUM_SINGLE_DECL(adau1372_decimator0_1_mux_enum, ADAU1372_REG_ADC_CTRL2, + 2, adau1372_decimator_mux_text); + +static const struct snd_kcontrol_new adau1372_decimator0_1_mux_control = + SOC_DAPM_ENUM("Decimator 0+1 Capture Mux", adau1372_decimator0_1_mux_enum); + +static SOC_ENUM_SINGLE_DECL(adau1372_decimator2_3_mux_enum, ADAU1372_REG_ADC_CTRL3, + 2, adau1372_decimator_mux_text); + +static const struct snd_kcontrol_new adau1372_decimator2_3_mux_control = + SOC_DAPM_ENUM("Decimator 2+3 Capture Mux", adau1372_decimator2_3_mux_enum); + +static const unsigned int adau1372_asrco_mux_values[] = { + 4, 5, 6, 7, +}; + +static const char * const adau1372_asrco_mux_text[] = { + "Decimator0", + "Decimator1", + "Decimator2", + "Decimator3", +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco0_mux_enum, ADAU1372_REG_ASRCO_SOURCE_0_1, + 0, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco1_mux_enum, ADAU1372_REG_ASRCO_SOURCE_0_1, + 4, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco2_mux_enum, ADAU1372_REG_ASRCO_SOURCE_2_3, + 0, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_asrco3_mux_enum, ADAU1372_REG_ASRCO_SOURCE_2_3, + 4, 0xf, adau1372_asrco_mux_text, adau1372_asrco_mux_values); + +static const struct snd_kcontrol_new adau1372_asrco0_mux_control = + SOC_DAPM_ENUM("Output ASRC0 Capture Mux", adau1372_asrco0_mux_enum); +static const struct snd_kcontrol_new adau1372_asrco1_mux_control = + SOC_DAPM_ENUM("Output ASRC1 Capture Mux", adau1372_asrco1_mux_enum); +static const struct snd_kcontrol_new adau1372_asrco2_mux_control = + SOC_DAPM_ENUM("Output ASRC2 Capture Mux", adau1372_asrco2_mux_enum); +static const struct snd_kcontrol_new adau1372_asrco3_mux_control = + SOC_DAPM_ENUM("Output ASRC3 Capture Mux", adau1372_asrco3_mux_enum); + +static const unsigned int adau1372_sout_mux_values[] = { + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +static const char * const adau1372_sout_mux_text[] = { + "Output ASRC0", + "Output ASRC1", + "Output ASRC2", + "Output ASRC3", + "Serial Input 0", + "Serial Input 1", + "Serial Input 2", + "Serial Input 3", + "Serial Input 4", + "Serial Input 5", + "Serial Input 6", + "Serial Input 7", +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout0_mux_enum, ADAU1372_REG_SOUT_SOURCE_0_1, + 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout1_mux_enum, ADAU1372_REG_SOUT_SOURCE_0_1, + 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout2_mux_enum, ADAU1372_REG_SOUT_SOURCE_2_3, + 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout3_mux_enum, ADAU1372_REG_SOUT_SOURCE_2_3, + 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout4_mux_enum, ADAU1372_REG_SOUT_SOURCE_4_5, + 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout5_mux_enum, ADAU1372_REG_SOUT_SOURCE_4_5, + 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout6_mux_enum, ADAU1372_REG_SOUT_SOURCE_6_7, + 0, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_sout7_mux_enum, ADAU1372_REG_SOUT_SOURCE_6_7, + 4, 0xf, adau1372_sout_mux_text, adau1372_sout_mux_values); + +static const struct snd_kcontrol_new adau1372_sout0_mux_control = + SOC_DAPM_ENUM("Serial Output 0 Capture Mux", adau1372_sout0_mux_enum); +static const struct snd_kcontrol_new adau1372_sout1_mux_control = + SOC_DAPM_ENUM("Serial Output 1 Capture Mux", adau1372_sout1_mux_enum); +static const struct snd_kcontrol_new adau1372_sout2_mux_control = + SOC_DAPM_ENUM("Serial Output 2 Capture Mux", adau1372_sout2_mux_enum); +static const struct snd_kcontrol_new adau1372_sout3_mux_control = + SOC_DAPM_ENUM("Serial Output 3 Capture Mux", adau1372_sout3_mux_enum); +static const struct snd_kcontrol_new adau1372_sout4_mux_control = + SOC_DAPM_ENUM("Serial Output 4 Capture Mux", adau1372_sout4_mux_enum); +static const struct snd_kcontrol_new adau1372_sout5_mux_control = + SOC_DAPM_ENUM("Serial Output 5 Capture Mux", adau1372_sout5_mux_enum); +static const struct snd_kcontrol_new adau1372_sout6_mux_control = + SOC_DAPM_ENUM("Serial Output 6 Capture Mux", adau1372_sout6_mux_enum); +static const struct snd_kcontrol_new adau1372_sout7_mux_control = + SOC_DAPM_ENUM("Serial Output 7 Capture Mux", adau1372_sout7_mux_enum); + +static const char * const adau1372_asrci_mux_text[] = { + "Serial Input 0+1", + "Serial Input 2+3", + "Serial Input 4+5", + "Serial Input 6+7", +}; + +static SOC_ENUM_SINGLE_DECL(adau1372_asrci_mux_enum, + ADAU1372_REG_ASRC_MODE, 2, adau1372_asrci_mux_text); + +static const struct snd_kcontrol_new adau1372_asrci_mux_control = + SOC_DAPM_ENUM("Input ASRC Playback Mux", adau1372_asrci_mux_enum); + +static const unsigned int adau1372_dac_mux_values[] = { + 12, 13 +}; + +static const char * const adau1372_dac_mux_text[] = { + "Input ASRC0", + "Input ASRC1", +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_dac0_mux_enum, ADAU1372_REG_DAC_SOURCE, + 0, 0xf, adau1372_dac_mux_text, adau1372_dac_mux_values); +static SOC_VALUE_ENUM_SINGLE_DECL(adau1372_dac1_mux_enum, ADAU1372_REG_DAC_SOURCE, + 4, 0xf, adau1372_dac_mux_text, adau1372_dac_mux_values); + +static const struct snd_kcontrol_new adau1372_dac0_mux_control = + SOC_DAPM_ENUM("DAC 0 Playback Mux", adau1372_dac0_mux_enum); +static const struct snd_kcontrol_new adau1372_dac1_mux_control = + SOC_DAPM_ENUM("DAC 1 Playback Mux", adau1372_dac1_mux_enum); + +static const struct snd_soc_dapm_widget adau1372_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("AIN0"), + SND_SOC_DAPM_INPUT("AIN1"), + SND_SOC_DAPM_INPUT("AIN2"), + SND_SOC_DAPM_INPUT("AIN3"), + SND_SOC_DAPM_INPUT("DMIC0_1"), + SND_SOC_DAPM_INPUT("DMIC2_3"), + + SND_SOC_DAPM_SUPPLY("MICBIAS0", ADAU1372_REG_MICBIAS, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS1", ADAU1372_REG_MICBIAS, 5, 0, NULL, 0), + + SND_SOC_DAPM_PGA("PGA0", ADAU1372_REG_PGA_CTRL(0), 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA1", ADAU1372_REG_PGA_CTRL(1), 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA2", ADAU1372_REG_PGA_CTRL(2), 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA3", ADAU1372_REG_PGA_CTRL(3), 6, 0, NULL, 0), + SND_SOC_DAPM_ADC("ADC0", NULL, ADAU1372_REG_ADC_CTRL2, 0, 0), + SND_SOC_DAPM_ADC("ADC1", NULL, ADAU1372_REG_ADC_CTRL2, 1, 0), + SND_SOC_DAPM_ADC("ADC2", NULL, ADAU1372_REG_ADC_CTRL3, 0, 0), + SND_SOC_DAPM_ADC("ADC3", NULL, ADAU1372_REG_ADC_CTRL3, 1, 0), + + SND_SOC_DAPM_SUPPLY("ADC0 Filter", ADAU1372_REG_DECIM_PWR, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 Filter", ADAU1372_REG_DECIM_PWR, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 Filter", ADAU1372_REG_DECIM_PWR, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC3 Filter", ADAU1372_REG_DECIM_PWR, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Output ASRC0 Decimator", ADAU1372_REG_DECIM_PWR, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Output ASRC1 Decimator", ADAU1372_REG_DECIM_PWR, 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Output ASRC2 Decimator", ADAU1372_REG_DECIM_PWR, 6, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Output ASRC3 Decimator", ADAU1372_REG_DECIM_PWR, 7, 0, NULL, 0), + + SND_SOC_DAPM_MUX("Decimator0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator0_1_mux_control), + SND_SOC_DAPM_MUX("Decimator1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator0_1_mux_control), + SND_SOC_DAPM_MUX("Decimator2 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator2_3_mux_control), + SND_SOC_DAPM_MUX("Decimator3 Mux", SND_SOC_NOPM, 0, 0, &adau1372_decimator2_3_mux_control), + + SND_SOC_DAPM_MUX("Output ASRC0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco0_mux_control), + SND_SOC_DAPM_MUX("Output ASRC1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco1_mux_control), + SND_SOC_DAPM_MUX("Output ASRC2 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco2_mux_control), + SND_SOC_DAPM_MUX("Output ASRC3 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrco3_mux_control), + SND_SOC_DAPM_MUX("Serial Output 0 Capture Mux", SND_SOC_NOPM, 0, 0, + &adau1372_sout0_mux_control), + SND_SOC_DAPM_MUX("Serial Output 1 Capture Mux", SND_SOC_NOPM, 0, 0, + &adau1372_sout1_mux_control), + SND_SOC_DAPM_MUX("Serial Output 2 Capture Mux", SND_SOC_NOPM, 0, 0, + &adau1372_sout2_mux_control), + SND_SOC_DAPM_MUX("Serial Output 3 Capture Mux", SND_SOC_NOPM, 0, 0, + &adau1372_sout3_mux_control), + SND_SOC_DAPM_MUX("Serial Output 4 Capture Mux", SND_SOC_NOPM, 0, 0, + &adau1372_sout4_mux_control), + SND_SOC_DAPM_MUX("Serial Output 5 Capture Mux", SND_SOC_NOPM, 0, 0, + &adau1372_sout5_mux_control), + SND_SOC_DAPM_MUX("Serial Output 6 Capture Mux", SND_SOC_NOPM, 0, 0, + &adau1372_sout6_mux_control), + SND_SOC_DAPM_MUX("Serial Output 7 Capture Mux", SND_SOC_NOPM, 0, 0, + &adau1372_sout7_mux_control), + + SND_SOC_DAPM_AIF_IN("Serial Input 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Serial Input 1", NULL, 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Serial Input 2", NULL, 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Serial Input 3", NULL, 3, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Serial Input 4", NULL, 4, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Serial Input 5", NULL, 5, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Serial Input 6", NULL, 6, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Serial Input 7", NULL, 7, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_OUT("Serial Output 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("Serial Output 1", NULL, 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("Serial Output 2", NULL, 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("Serial Output 3", NULL, 3, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("Serial Output 4", NULL, 4, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("Serial Output 5", NULL, 5, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("Serial Output 6", NULL, 6, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("Serial Output 7", NULL, 7, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("Output ASRC Supply", ADAU1372_REG_ASRC_MODE, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Input ASRC Supply", ADAU1372_REG_ASRC_MODE, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC1 Modulator", ADAU1372_REG_INTERP_PWR, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC0 Modulator", ADAU1372_REG_INTERP_PWR, 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Input ASRC1 Interpolator", ADAU1372_REG_INTERP_PWR, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Input ASRC0 Interpolator", ADAU1372_REG_INTERP_PWR, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("Input ASRC0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrci_mux_control), + SND_SOC_DAPM_MUX("Input ASRC1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_asrci_mux_control), + + SND_SOC_DAPM_MUX("DAC 0 Mux", SND_SOC_NOPM, 0, 0, &adau1372_dac0_mux_control), + SND_SOC_DAPM_MUX("DAC 1 Mux", SND_SOC_NOPM, 0, 0, &adau1372_dac1_mux_control), + + SND_SOC_DAPM_DAC("DAC0", NULL, ADAU1372_REG_DAC_CTRL, 0, 0), + SND_SOC_DAPM_DAC("DAC1", NULL, ADAU1372_REG_DAC_CTRL, 1, 0), + + SND_SOC_DAPM_OUT_DRV("OP_STAGE_LP", ADAU1372_REG_OP_STAGE_CTRL, 0, 1, NULL, 0), + SND_SOC_DAPM_OUT_DRV("OP_STAGE_LN", ADAU1372_REG_OP_STAGE_CTRL, 1, 1, NULL, 0), + SND_SOC_DAPM_OUT_DRV("OP_STAGE_RP", ADAU1372_REG_OP_STAGE_CTRL, 2, 1, NULL, 0), + SND_SOC_DAPM_OUT_DRV("OP_STAGE_RN", ADAU1372_REG_OP_STAGE_CTRL, 3, 1, NULL, 0), + + SND_SOC_DAPM_OUTPUT("HPOUTL"), + SND_SOC_DAPM_OUTPUT("HPOUTR"), +}; + +#define ADAU1372_SOUT_ROUTES(x) \ + { "Serial Output " #x " Capture Mux", "Output ASRC0", "Output ASRC0 Mux" }, \ + { "Serial Output " #x " Capture Mux", "Output ASRC1", "Output ASRC1 Mux" }, \ + { "Serial Output " #x " Capture Mux", "Output ASRC2", "Output ASRC2 Mux" }, \ + { "Serial Output " #x " Capture Mux", "Output ASRC3", "Output ASRC3 Mux" }, \ + { "Serial Output " #x " Capture Mux", "Serial Input 0", "Serial Input 0" }, \ + { "Serial Output " #x " Capture Mux", "Serial Input 1", "Serial Input 1" }, \ + { "Serial Output " #x " Capture Mux", "Serial Input 2", "Serial Input 2" }, \ + { "Serial Output " #x " Capture Mux", "Serial Input 3", "Serial Input 3" }, \ + { "Serial Output " #x " Capture Mux", "Serial Input 4", "Serial Input 4" }, \ + { "Serial Output " #x " Capture Mux", "Serial Input 5", "Serial Input 5" }, \ + { "Serial Output " #x " Capture Mux", "Serial Input 6", "Serial Input 6" }, \ + { "Serial Output " #x " Capture Mux", "Serial Input 7", "Serial Input 7" }, \ + { "Serial Output " #x, NULL, "Serial Output " #x " Capture Mux" }, \ + { "Capture", NULL, "Serial Output " #x } + +#define ADAU1372_ASRCO_ROUTES(x) \ + { "Output ASRC" #x " Mux", "Decimator0", "Decimator0 Mux" }, \ + { "Output ASRC" #x " Mux", "Decimator1", "Decimator1 Mux" }, \ + { "Output ASRC" #x " Mux", "Decimator2", "Decimator2 Mux" }, \ + { "Output ASRC" #x " Mux", "Decimator3", "Decimator3 Mux" } + +static const struct snd_soc_dapm_route adau1372_dapm_routes[] = { + { "PGA0", NULL, "AIN0" }, + { "PGA1", NULL, "AIN1" }, + { "PGA2", NULL, "AIN2" }, + { "PGA3", NULL, "AIN3" }, + + { "ADC0", NULL, "PGA0" }, + { "ADC1", NULL, "PGA1" }, + { "ADC2", NULL, "PGA2" }, + { "ADC3", NULL, "PGA3" }, + + { "Decimator0 Mux", "ADC", "ADC0" }, + { "Decimator1 Mux", "ADC", "ADC1" }, + { "Decimator2 Mux", "ADC", "ADC2" }, + { "Decimator3 Mux", "ADC", "ADC3" }, + + { "Decimator0 Mux", "DMIC", "DMIC0_1" }, + { "Decimator1 Mux", "DMIC", "DMIC0_1" }, + { "Decimator2 Mux", "DMIC", "DMIC2_3" }, + { "Decimator3 Mux", "DMIC", "DMIC2_3" }, + + { "Decimator0 Mux", NULL, "ADC0 Filter" }, + { "Decimator1 Mux", NULL, "ADC1 Filter" }, + { "Decimator2 Mux", NULL, "ADC2 Filter" }, + { "Decimator3 Mux", NULL, "ADC3 Filter" }, + + { "Output ASRC0 Mux", NULL, "Output ASRC Supply" }, + { "Output ASRC1 Mux", NULL, "Output ASRC Supply" }, + { "Output ASRC2 Mux", NULL, "Output ASRC Supply" }, + { "Output ASRC3 Mux", NULL, "Output ASRC Supply" }, + { "Output ASRC0 Mux", NULL, "Output ASRC0 Decimator" }, + { "Output ASRC1 Mux", NULL, "Output ASRC1 Decimator" }, + { "Output ASRC2 Mux", NULL, "Output ASRC2 Decimator" }, + { "Output ASRC3 Mux", NULL, "Output ASRC3 Decimator" }, + + ADAU1372_ASRCO_ROUTES(0), + ADAU1372_ASRCO_ROUTES(1), + ADAU1372_ASRCO_ROUTES(2), + ADAU1372_ASRCO_ROUTES(3), + + ADAU1372_SOUT_ROUTES(0), + ADAU1372_SOUT_ROUTES(1), + ADAU1372_SOUT_ROUTES(2), + ADAU1372_SOUT_ROUTES(3), + ADAU1372_SOUT_ROUTES(4), + ADAU1372_SOUT_ROUTES(5), + ADAU1372_SOUT_ROUTES(6), + ADAU1372_SOUT_ROUTES(7), + + { "Serial Input 0", NULL, "Playback" }, + { "Serial Input 1", NULL, "Playback" }, + { "Serial Input 2", NULL, "Playback" }, + { "Serial Input 3", NULL, "Playback" }, + { "Serial Input 4", NULL, "Playback" }, + { "Serial Input 5", NULL, "Playback" }, + { "Serial Input 6", NULL, "Playback" }, + { "Serial Input 7", NULL, "Playback" }, + + { "Input ASRC0 Mux", "Serial Input 0+1", "Serial Input 0" }, + { "Input ASRC1 Mux", "Serial Input 0+1", "Serial Input 1" }, + { "Input ASRC0 Mux", "Serial Input 2+3", "Serial Input 2" }, + { "Input ASRC1 Mux", "Serial Input 2+3", "Serial Input 3" }, + { "Input ASRC0 Mux", "Serial Input 4+5", "Serial Input 4" }, + { "Input ASRC1 Mux", "Serial Input 4+5", "Serial Input 5" }, + { "Input ASRC0 Mux", "Serial Input 6+7", "Serial Input 6" }, + { "Input ASRC1 Mux", "Serial Input 6+7", "Serial Input 7" }, + { "Input ASRC0 Mux", NULL, "Input ASRC Supply" }, + { "Input ASRC1 Mux", NULL, "Input ASRC Supply" }, + { "Input ASRC0 Mux", NULL, "Input ASRC0 Interpolator" }, + { "Input ASRC1 Mux", NULL, "Input ASRC1 Interpolator" }, + + { "DAC 0 Mux", "Input ASRC0", "Input ASRC0 Mux" }, + { "DAC 0 Mux", "Input ASRC1", "Input ASRC1 Mux" }, + { "DAC 1 Mux", "Input ASRC0", "Input ASRC0 Mux" }, + { "DAC 1 Mux", "Input ASRC1", "Input ASRC1 Mux" }, + + { "DAC0", NULL, "DAC 0 Mux" }, + { "DAC1", NULL, "DAC 1 Mux" }, + { "DAC0", NULL, "DAC0 Modulator" }, + { "DAC1", NULL, "DAC1 Modulator" }, + + { "OP_STAGE_LP", NULL, "DAC0" }, + { "OP_STAGE_LN", NULL, "DAC0" }, + { "OP_STAGE_RP", NULL, "DAC1" }, + { "OP_STAGE_RN", NULL, "DAC1" }, + + { "HPOUTL", NULL, "OP_STAGE_LP" }, + { "HPOUTL", NULL, "OP_STAGE_LN" }, + { "HPOUTR", NULL, "OP_STAGE_RP" }, + { "HPOUTR", NULL, "OP_STAGE_RN" }, +}; + +static int adau1372_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); + unsigned int sai0 = 0, sai1 = 0; + bool invert_lrclk = false; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + adau1372->master = true; + sai1 |= ADAU1372_SAI1_MS; + break; + case SND_SOC_DAIFMT_CBS_CFS: + adau1372->master = false; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + invert_lrclk = false; + break; + case SND_SOC_DAIFMT_NB_IF: + invert_lrclk = true; + break; + case SND_SOC_DAIFMT_IB_NF: + invert_lrclk = false; + sai1 |= ADAU1372_SAI1_BCLKEDGE; + break; + case SND_SOC_DAIFMT_IB_IF: + invert_lrclk = true; + sai1 |= ADAU1372_SAI1_BCLKEDGE; + break; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + sai0 |= ADAU1372_SAI0_DELAY1; + break; + case SND_SOC_DAIFMT_LEFT_J: + sai0 |= ADAU1372_SAI0_DELAY0; + invert_lrclk = !invert_lrclk; + break; + case SND_SOC_DAIFMT_DSP_A: + sai0 |= ADAU1372_SAI0_DELAY1; + sai1 |= ADAU1372_SAI1_LR_MODE; + break; + case SND_SOC_DAIFMT_DSP_B: + sai0 |= ADAU1372_SAI0_DELAY0; + sai1 |= ADAU1372_SAI1_LR_MODE; + break; + } + + if (invert_lrclk) + sai1 |= ADAU1372_SAI1_LR_POL; + + regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_DELAY_MASK, sai0); + regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, + ADAU1372_SAI1_MS | ADAU1372_SAI1_BCLKEDGE | + ADAU1372_SAI1_LR_MODE | ADAU1372_SAI1_LR_POL, sai1); + + return 0; +} + +static int adau1372_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int slot_width; + unsigned int sai0, sai1; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adau1372_rates); i++) { + if (rate == adau1372_rates[i]) + break; + } + + if (i == ARRAY_SIZE(adau1372_rates)) + return -EINVAL; + + sai0 = i; + + slot_width = adau1372->slot_width; + if (slot_width == 0) + slot_width = params_width(params); + + switch (slot_width) { + case 16: + sai1 = ADAU1372_SAI1_BCLKRATE; + break; + case 32: + sai1 = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_FS_MASK, sai0); + regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_BCLKRATE, sai1); + + return 0; +} + +static int adau1372_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int width) +{ + struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); + unsigned int sai0, sai1; + + /* I2S mode */ + if (slots == 0) { + /* The other settings dont matter in I2S mode */ + regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, + ADAU1372_SAI0_SAI_MASK, ADAU1372_SAI0_SAI_I2S); + adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2; + adau1372->slot_width = 0; + return 0; + } + + /* We have 8 channels anything outside that is not supported */ + if ((tx_mask & ~0xff) != 0 || (rx_mask & ~0xff) != 0) + return -EINVAL; + + switch (width) { + case 16: + sai1 = ADAU1372_SAI1_BCLK_TDMC; + break; + case 32: + sai1 = 0; + break; + default: + return -EINVAL; + } + + switch (slots) { + case 2: + sai0 = ADAU1372_SAI0_SAI_TDM2; + adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2; + break; + case 4: + sai0 = ADAU1372_SAI0_SAI_TDM4; + if (adau1372->master) + adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4_MASTER; + else + adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM4; + break; + case 8: + sai0 = ADAU1372_SAI0_SAI_TDM8; + adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM8; + break; + default: + return -EINVAL; + } + + adau1372->slot_width = width; + + regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI0, ADAU1372_SAI0_SAI_MASK, sai0); + regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_BCLK_TDMC, sai1); + + /* Mask is inverted in hardware */ + regmap_write(adau1372->regmap, ADAU1372_REG_SOUT_CTRL, ~tx_mask); + + return 0; +} + +static int adau1372_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); + unsigned int sai1; + + if (tristate) + sai1 = ADAU1372_SAI1_TDM_TS; + else + sai1 = 0; + + return regmap_update_bits(adau1372->regmap, ADAU1372_REG_SAI1, ADAU1372_SAI1_TDM_TS, sai1); +} + +static int adau1372_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct adau1372 *adau1372 = snd_soc_dai_get_drvdata(dai); + + snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &adau1372->rate_constraints); + + return 0; +} + +static void adau1372_enable_pll(struct adau1372 *adau1372) +{ + unsigned int val, timeout = 0; + int ret; + + regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL, + ADAU1372_CLK_CTRL_PLL_EN, ADAU1372_CLK_CTRL_PLL_EN); + do { + /* Takes about 1ms to lock */ + usleep_range(1000, 2000); + ret = regmap_read(adau1372->regmap, ADAU1372_REG_PLL(5), &val); + if (ret) + break; + timeout++; + } while (!(val & 1) && timeout < 3); + + if (ret < 0 || !(val & 1)) + dev_err(adau1372->dev, "Failed to lock PLL\n"); +} + +static void adau1372_set_power(struct adau1372 *adau1372, bool enable) +{ + if (adau1372->enabled == enable) + return; + + if (enable) { + unsigned int clk_ctrl = ADAU1372_CLK_CTRL_MCLK_EN; + + clk_prepare_enable(adau1372->mclk); + if (adau1372->pd_gpio) + gpiod_set_value(adau1372->pd_gpio, 0); + + if (adau1372->switch_mode) + adau1372->switch_mode(adau1372->dev); + + regcache_cache_only(adau1372->regmap, false); + + /* + * Clocks needs to be enabled before any other register can be + * accessed. + */ + if (adau1372->use_pll) { + adau1372_enable_pll(adau1372); + clk_ctrl |= ADAU1372_CLK_CTRL_CLKSRC; + } + + regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL, + ADAU1372_CLK_CTRL_MCLK_EN | ADAU1372_CLK_CTRL_CLKSRC, clk_ctrl); + regcache_sync(adau1372->regmap); + } else { + if (adau1372->pd_gpio) { + /* + * This will turn everything off and reset the register + * map. No need to do any register writes to manually + * turn things off. + */ + gpiod_set_value(adau1372->pd_gpio, 1); + regcache_mark_dirty(adau1372->regmap); + } else { + regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL, + ADAU1372_CLK_CTRL_MCLK_EN | ADAU1372_CLK_CTRL_PLL_EN, 0); + } + clk_disable_unprepare(adau1372->mclk); + regcache_cache_only(adau1372->regmap, true); + } + + adau1372->enabled = enable; +} + +static int adau1372_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct adau1372 *adau1372 = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + adau1372_set_power(adau1372, true); + break; + case SND_SOC_BIAS_OFF: + adau1372_set_power(adau1372, false); + break; + } + + return 0; +} + +static const struct snd_soc_component_driver adau1372_driver = { + .set_bias_level = adau1372_set_bias_level, + .controls = adau1372_controls, + .num_controls = ARRAY_SIZE(adau1372_controls), + .dapm_widgets = adau1372_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau1372_dapm_widgets), + .dapm_routes = adau1372_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adau1372_dapm_routes), +}; + +static const struct snd_soc_dai_ops adau1372_dai_ops = { + .set_fmt = adau1372_set_dai_fmt, + .set_tdm_slot = adau1372_set_tdm_slot, + .set_tristate = adau1372_set_tristate, + .hw_params = adau1372_hw_params, + .startup = adau1372_startup, +}; + +#define ADAU1372_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver adau1372_dai_driver = { + .name = "adau1372", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = ADAU1372_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = ADAU1372_FORMATS, + .sig_bits = 24, + }, + .ops = &adau1372_dai_ops, + .symmetric_rates = 1, +}; + +static int adau1372_setup_pll(struct adau1372 *adau1372, unsigned int rate) +{ + u8 regs[5]; + unsigned int i; + int ret; + + ret = adau_calc_pll_cfg(rate, 49152000, regs); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + regmap_write(adau1372->regmap, ADAU1372_REG_PLL(i), regs[i]); + + return 0; +} + +int adau1372_probe(struct device *dev, struct regmap *regmap, + void (*switch_mode)(struct device *dev)) +{ + struct adau1372 *adau1372; + unsigned int clk_ctrl; + unsigned long rate; + int ret; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + adau1372 = devm_kzalloc(dev, sizeof(*adau1372), GFP_KERNEL); + if (!adau1372) + return -ENOMEM; + + adau1372->clk = devm_clk_get(dev, "mclk"); + if (IS_ERR(adau1372->clk)) + return PTR_ERR(adau1372->clk); + + adau1372->pd_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(adau1372->pd_gpio)) + return PTR_ERR(adau1372->pd_gpio); + + adau1372->regmap = regmap; + adau1372->switch_mode = switch_mode; + adau1372->dev = dev; + adau1372->rate_constraints.list = adau1372_rates; + adau1372->rate_constraints.count = ARRAY_SIZE(adau1372_rates); + adau1372->rate_constraints.mask = ADAU1372_RATE_MASK_TDM2; + + dev_set_drvdata(dev, adau1372); + + /* + * The datasheet says that the internal MCLK always needs to run at + * 12.288MHz. Automatically choose a valid configuration from the + * external clock. + */ + rate = clk_get_rate(adau1372->clk); + + switch (rate) { + case 12288000: + clk_ctrl = ADAU1372_CLK_CTRL_CC_MDIV; + break; + case 24576000: + clk_ctrl = 0; + break; + default: + clk_ctrl = 0; + ret = adau1372_setup_pll(adau1372, rate); + if (ret < 0) + return ret; + adau1372->use_pll = true; + break; + } + + /* + * Most of the registers are inaccessible unless the internal clock is + * enabled. + */ + regcache_cache_only(regmap, true); + + regmap_update_bits(regmap, ADAU1372_REG_CLK_CTRL, ADAU1372_CLK_CTRL_CC_MDIV, clk_ctrl); + + /* + * No pinctrl support yet, put the multi-purpose pins in the most + * sensible mode for general purpose CODEC operation. + */ + regmap_write(regmap, ADAU1372_REG_MODE_MP(1), 0x00); /* SDATA OUT */ + regmap_write(regmap, ADAU1372_REG_MODE_MP(6), 0x12); /* CLOCKOUT */ + + regmap_write(regmap, ADAU1372_REG_OP_STAGE_MUTE, 0x0); + + regmap_write(regmap, 0x7, 0x01); /* CLOCK OUT */ + + return devm_snd_soc_register_component(dev, &adau1372_driver, &adau1372_dai_driver, 1); +} +EXPORT_SYMBOL(adau1372_probe); + +static const struct reg_default adau1372_reg_defaults[] = { + { ADAU1372_REG_CLK_CTRL, 0x00 }, + { ADAU1372_REG_PLL(0), 0x00 }, + { ADAU1372_REG_PLL(1), 0x00 }, + { ADAU1372_REG_PLL(2), 0x00 }, + { ADAU1372_REG_PLL(3), 0x00 }, + { ADAU1372_REG_PLL(4), 0x00 }, + { ADAU1372_REG_PLL(5), 0x00 }, + { ADAU1372_REG_DAC_SOURCE, 0x10 }, + { ADAU1372_REG_SOUT_SOURCE_0_1, 0x54 }, + { ADAU1372_REG_SOUT_SOURCE_2_3, 0x76 }, + { ADAU1372_REG_SOUT_SOURCE_4_5, 0x54 }, + { ADAU1372_REG_SOUT_SOURCE_6_7, 0x76 }, + { ADAU1372_REG_ADC_SDATA_CH, 0x04 }, + { ADAU1372_REG_ASRCO_SOURCE_0_1, 0x10 }, + { ADAU1372_REG_ASRCO_SOURCE_2_3, 0x32 }, + { ADAU1372_REG_ASRC_MODE, 0x00 }, + { ADAU1372_REG_ADC_CTRL0, 0x19 }, + { ADAU1372_REG_ADC_CTRL1, 0x19 }, + { ADAU1372_REG_ADC_CTRL2, 0x00 }, + { ADAU1372_REG_ADC_CTRL3, 0x00 }, + { ADAU1372_REG_ADC_VOL(0), 0x00 }, + { ADAU1372_REG_ADC_VOL(1), 0x00 }, + { ADAU1372_REG_ADC_VOL(2), 0x00 }, + { ADAU1372_REG_ADC_VOL(3), 0x00 }, + { ADAU1372_REG_PGA_CTRL(0), 0x40 }, + { ADAU1372_REG_PGA_CTRL(1), 0x40 }, + { ADAU1372_REG_PGA_CTRL(2), 0x40 }, + { ADAU1372_REG_PGA_CTRL(3), 0x40 }, + { ADAU1372_REG_PGA_BOOST, 0x00 }, + { ADAU1372_REG_MICBIAS, 0x00 }, + { ADAU1372_REG_DAC_CTRL, 0x18 }, + { ADAU1372_REG_DAC_VOL(0), 0x00 }, + { ADAU1372_REG_DAC_VOL(1), 0x00 }, + { ADAU1372_REG_OP_STAGE_MUTE, 0x0f }, + { ADAU1372_REG_SAI0, 0x00 }, + { ADAU1372_REG_SAI1, 0x00 }, + { ADAU1372_REG_SOUT_CTRL, 0x00 }, + { ADAU1372_REG_MODE_MP(0), 0x00 }, + { ADAU1372_REG_MODE_MP(1), 0x10 }, + { ADAU1372_REG_MODE_MP(4), 0x00 }, + { ADAU1372_REG_MODE_MP(5), 0x00 }, + { ADAU1372_REG_MODE_MP(6), 0x11 }, + { ADAU1372_REG_OP_STAGE_CTRL, 0x0f }, + { ADAU1372_REG_DECIM_PWR, 0x00 }, + { ADAU1372_REG_INTERP_PWR, 0x00 }, + { ADAU1372_REG_BIAS_CTRL0, 0x00 }, + { ADAU1372_REG_BIAS_CTRL1, 0x00 }, +}; + +static bool adau1372_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg == ADAU1372_REG_PLL(5)) + return true; + + return false; +} + +const struct regmap_config adau1372_regmap_config = { + .val_bits = 8, + .reg_bits = 16, + .max_register = 0x4d, + + .reg_defaults = adau1372_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(adau1372_reg_defaults), + .volatile_reg = adau1372_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(adau1372_regmap_config); + +MODULE_DESCRIPTION("ASoC ADAU1372 CODEC driver"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/adau1372.h b/sound/soc/codecs/adau1372.h new file mode 100644 index 000000000000..a9d2c59b73a9 --- /dev/null +++ b/sound/soc/codecs/adau1372.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * ADAU1372 driver + * + * Copyright 2016 Analog Devices Inc. + * Author: Lars-Peter Clausen + */ + +#ifndef SOUND_SOC_CODECS_ADAU1372_H +#define SOUND_SOC_CODECS_ADAU1372_H + +#include + +struct device; + +int adau1372_probe(struct device *dev, struct regmap *regmap, + void (*switch_mode)(struct device *dev)); + +extern const struct regmap_config adau1372_regmap_config; + +#endif -- cgit v1.2.3 From 0d7f2459ae926a964ab211aac413d72074131727 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Tue, 1 Dec 2020 13:11:50 -0800 Subject: ASoC: Intel: Boards: tgl_max98373: update TDM slot_width Speaker amp's SSP bclk configuration was changed in the topology file to be based on 12.288MHz and dai_ops->hw_params is based on s32le format. But, the TDM slot size remained set to 24 bits. This inconsistency created audible noises and needs to be corrected. This patch updates TDM slot width to 32. Fixes: bc7477fc2ab4 ("ASoC: Intel: Boards: tgl_max98373: Update TDM configuration in hw_params") Signed-off-by: Sathyanarayana Nujella Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201201211150.433472-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_maxim_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index b6e63ea13d64..c2a9757181fe 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -49,11 +49,11 @@ static int max98373_hw_params(struct snd_pcm_substream *substream, for_each_rtd_codec_dais(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { /* DEV0 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 24); + snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); } if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { /* DEV1 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 24); + snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); } } return 0; -- cgit v1.2.3 From a5f8037505cbae5b877dea3e15acce4c29e9e797 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 1 Dec 2020 21:26:09 +0800 Subject: ASoC: mediatek: mt8192: rename common symbols Renames common symbols from "mt8192_mt6359_rt1015_rt5682" to "mt8192_mt6359". They will share between a few machine drivers on MT8192 and MT6359 with some different audio components. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201201132614.1691352-2-tzungbi@google.com Signed-off-by: Mark Brown --- .../mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index b7f42a530d06..253c028c1630 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -631,7 +631,7 @@ SND_SOC_DAILINK_DEFS(tdm, DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); -static struct snd_soc_dai_link mt8192_mt6359_rt1015_rt5682_dai_links[] = { +static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { /* Front End DAI links */ { .name = "Playback_1", @@ -986,8 +986,8 @@ static struct snd_soc_codec_conf rt1015_amp_conf[] = { static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_soc_card = { .name = "mt8192_mt6359_rt1015_rt5682", .owner = THIS_MODULE, - .dai_link = mt8192_mt6359_rt1015_rt5682_dai_links, - .num_links = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_dai_links), + .dai_link = mt8192_mt6359_dai_links, + .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links), .controls = mt8192_mt6359_rt1015_rt5682_controls, .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015_rt5682_controls), .dapm_widgets = mt8192_mt6359_rt1015_rt5682_widgets, @@ -998,7 +998,7 @@ static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_soc_card = { .num_configs = ARRAY_SIZE(rt1015_amp_conf), }; -static int mt8192_mt6359_rt1015_rt5682_dev_probe(struct platform_device *pdev) +static int mt8192_mt6359_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8192_mt6359_rt1015_rt5682_soc_card; struct device_node *platform_node; @@ -1029,32 +1029,32 @@ static int mt8192_mt6359_rt1015_rt5682_dev_probe(struct platform_device *pdev) } #ifdef CONFIG_OF -static const struct of_device_id mt8192_mt6359_rt1015_rt5682_dt_match[] = { +static const struct of_device_id mt8192_mt6359_dt_match[] = { {.compatible = "mediatek,mt8192_mt6359_rt1015_rt5682",}, {} }; #endif -static const struct dev_pm_ops mt8192_mt6359_rt1015_rt5682_pm_ops = { +static const struct dev_pm_ops mt8192_mt6359_pm_ops = { .poweroff = snd_soc_poweroff, .restore = snd_soc_resume, }; -static struct platform_driver mt8192_mt6359_rt1015_rt5682_driver = { +static struct platform_driver mt8192_mt6359_driver = { .driver = { - .name = "mt8192_mt6359_rt1015_rt5682", + .name = "mt8192_mt6359", #ifdef CONFIG_OF - .of_match_table = mt8192_mt6359_rt1015_rt5682_dt_match, + .of_match_table = mt8192_mt6359_dt_match, #endif - .pm = &mt8192_mt6359_rt1015_rt5682_pm_ops, + .pm = &mt8192_mt6359_pm_ops, }, - .probe = mt8192_mt6359_rt1015_rt5682_dev_probe, + .probe = mt8192_mt6359_dev_probe, }; -module_platform_driver(mt8192_mt6359_rt1015_rt5682_driver); +module_platform_driver(mt8192_mt6359_driver); /* Module information */ -MODULE_DESCRIPTION("MT8192-MT6359-RT1015-RT5682 ALSA SoC machine driver"); +MODULE_DESCRIPTION("MT8192-MT6359 ALSA SoC machine driver"); MODULE_AUTHOR("Jiaxin Yu "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("mt8192_mt6359_rt1015_rt5682 soc card"); +MODULE_ALIAS("mt8192_mt6359 soc card"); -- cgit v1.2.3 From 2b53d2e16f735d8f13b77fefe03ce6b43c726beb Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 1 Dec 2020 21:26:10 +0800 Subject: ASoC: mediatek: mt8192: extract rt1015_rt5682 specific DAI link Extracts rt1015_rt5682 specific DAI link from the common one. Fills the DAI link data according to of_match. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201201132614.1691352-3-tzungbi@google.com Signed-off-by: Mark Brown --- .../mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 39 +++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 253c028c1630..e841fd32e8cc 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -576,7 +577,7 @@ SND_SOC_DAILINK_DEFS(i2s2, DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); -SND_SOC_DAILINK_DEFS(i2s3, +SND_SOC_DAILINK_DEFS(i2s3_rt1015, DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), DAILINK_COMP_ARRAY(COMP_CODEC(RT1015_DEV0_NAME, RT1015_CODEC_DAI), @@ -894,8 +895,6 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .dpcm_playback = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, - SND_SOC_DAILINK_REG(i2s3), - .ops = &mt8192_rt1015_i2s_ops, }, { .name = "I2S5", @@ -983,7 +982,7 @@ static struct snd_soc_codec_conf rt1015_amp_conf[] = { }, }; -static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_soc_card = { +static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_card = { .name = "mt8192_mt6359_rt1015_rt5682", .owner = THIS_MODULE, .dai_link = mt8192_mt6359_dai_links, @@ -1000,12 +999,11 @@ static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_soc_card = { static int mt8192_mt6359_dev_probe(struct platform_device *pdev) { - struct snd_soc_card *card = &mt8192_mt6359_rt1015_rt5682_soc_card; + struct snd_soc_card *card; struct device_node *platform_node; int ret, i; struct snd_soc_dai_link *dai_link; - - card->dev = &pdev->dev; + const struct of_device_id *match; platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); @@ -1014,7 +1012,29 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) return -EINVAL; } + match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); + if (!match || !match->data) + return -EINVAL; + + card = (struct snd_soc_card *)match->data; + card->dev = &pdev->dev; + for_each_card_prelinks(card, i, dai_link) { + if (strcmp(dai_link->name, "I2S3") == 0) { + if (card == &mt8192_mt6359_rt1015_rt5682_card) { + dai_link->ops = &mt8192_rt1015_i2s_ops; + dai_link->cpus = i2s3_rt1015_cpus; + dai_link->num_cpus = + ARRAY_SIZE(i2s3_rt1015_cpus); + dai_link->codecs = i2s3_rt1015_codecs; + dai_link->num_codecs = + ARRAY_SIZE(i2s3_rt1015_codecs); + dai_link->platforms = i2s3_rt1015_platforms; + dai_link->num_platforms = + ARRAY_SIZE(i2s3_rt1015_platforms); + } + } + if (!dai_link->platforms->name) dai_link->platforms->of_node = platform_node; } @@ -1030,7 +1050,10 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id mt8192_mt6359_dt_match[] = { - {.compatible = "mediatek,mt8192_mt6359_rt1015_rt5682",}, + { + .compatible = "mediatek,mt8192_mt6359_rt1015_rt5682", + .data = &mt8192_mt6359_rt1015_rt5682_card, + }, {} }; #endif -- cgit v1.2.3 From ba499c36d12bcea9d4eba0b021c508bfe13c515d Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 1 Dec 2020 21:26:11 +0800 Subject: ASoC: mediatek: mt8192: move rt1015_rt5682 specific data Moves rt1015_rt5682 specific data right before the snd_soc_card definition for neat purpose. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201201132614.1691352-4-tzungbi@google.com Signed-off-by: Mark Brown --- .../mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index e841fd32e8cc..0d2cc6800f08 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -33,31 +33,6 @@ static struct snd_soc_jack headset_jack; -static const struct snd_soc_dapm_widget -mt8192_mt6359_rt1015_rt5682_widgets[] = { - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = { - /* speaker */ - { "Left Spk", NULL, "Left SPO" }, - { "Right Spk", NULL, "Right SPO" }, - /* headset */ - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - { "IN1P", NULL, "Headset Mic" }, -}; - -static const struct snd_kcontrol_new mt8192_mt6359_rt1015_rt5682_controls[] = { - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - static int mt8192_rt1015_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -971,6 +946,31 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { }, }; +static const struct snd_soc_dapm_widget +mt8192_mt6359_rt1015_rt5682_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route mt8192_mt6359_rt1015_rt5682_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Left SPO" }, + { "Right Spk", NULL, "Right SPO" }, + /* headset */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + { "IN1P", NULL, "Headset Mic" }, +}; + +static const struct snd_kcontrol_new mt8192_mt6359_rt1015_rt5682_controls[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static struct snd_soc_codec_conf rt1015_amp_conf[] = { { .dlc = COMP_CODEC_CONF(RT1015_DEV0_NAME), -- cgit v1.2.3 From cfd8bb254c9985266e4be7f59042170a72548a8f Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 1 Dec 2020 21:26:14 +0800 Subject: ASoC: mediatek: mt8192: support rt1015p_rt5682 Supports machines with rt1015p and rt5682. Uses new proposed compatible string "mt8192_mt6359_rt1015p_rt5682". Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201201132614.1691352-7-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 1 + .../mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 54 ++++++++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'sound') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 49772dfc92c7..8d3dcfb6a580 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -175,6 +175,7 @@ config SND_SOC_MT8192_MT6359_RT1015_RT5682 depends on SND_SOC_MT8192 select SND_SOC_MT6359 select SND_SOC_RT1015 + select SND_SOC_RT1015P select SND_SOC_RT5682_I2C select SND_SOC_DMIC help diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 0d2cc6800f08..716fbb4126b5 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -560,6 +560,11 @@ SND_SOC_DAILINK_DEFS(i2s3_rt1015, RT1015_CODEC_DAI)), DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s3_rt1015p, + DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), + DAILINK_COMP_ARRAY(COMP_CODEC("rt1015p", "HiFi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + SND_SOC_DAILINK_DEFS(i2s5, DAILINK_COMP_ARRAY(COMP_CPU("I2S5")), DAILINK_COMP_ARRAY(COMP_DUMMY()), @@ -997,6 +1002,41 @@ static struct snd_soc_card mt8192_mt6359_rt1015_rt5682_card = { .num_configs = ARRAY_SIZE(rt1015_amp_conf), }; +static const struct snd_soc_dapm_widget +mt8192_mt6359_rt1015p_rt5682_widgets[] = { + SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route mt8192_mt6359_rt1015p_rt5682_routes[] = { + /* speaker */ + { "Speakers", NULL, "Speaker" }, + /* headset */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + { "IN1P", NULL, "Headset Mic" }, +}; + +static const struct snd_kcontrol_new mt8192_mt6359_rt1015p_rt5682_controls[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682_card = { + .name = "mt8192_mt6359_rt1015p_rt5682", + .owner = THIS_MODULE, + .dai_link = mt8192_mt6359_dai_links, + .num_links = ARRAY_SIZE(mt8192_mt6359_dai_links), + .controls = mt8192_mt6359_rt1015p_rt5682_controls, + .num_controls = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_controls), + .dapm_widgets = mt8192_mt6359_rt1015p_rt5682_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_widgets), + .dapm_routes = mt8192_mt6359_rt1015p_rt5682_routes, + .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682_routes), +}; + static int mt8192_mt6359_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card; @@ -1032,6 +1072,16 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) dai_link->platforms = i2s3_rt1015_platforms; dai_link->num_platforms = ARRAY_SIZE(i2s3_rt1015_platforms); + } else if (card == &mt8192_mt6359_rt1015p_rt5682_card) { + dai_link->cpus = i2s3_rt1015p_cpus; + dai_link->num_cpus = + ARRAY_SIZE(i2s3_rt1015p_cpus); + dai_link->codecs = i2s3_rt1015p_codecs; + dai_link->num_codecs = + ARRAY_SIZE(i2s3_rt1015p_codecs); + dai_link->platforms = i2s3_rt1015p_platforms; + dai_link->num_platforms = + ARRAY_SIZE(i2s3_rt1015p_platforms); } } @@ -1054,6 +1104,10 @@ static const struct of_device_id mt8192_mt6359_dt_match[] = { .compatible = "mediatek,mt8192_mt6359_rt1015_rt5682", .data = &mt8192_mt6359_rt1015_rt5682_card, }, + { + .compatible = "mediatek,mt8192_mt6359_rt1015p_rt5682", + .data = &mt8192_mt6359_rt1015p_rt5682_card, + }, {} }; #endif -- cgit v1.2.3 From 569c167ce3bb145662cbdd37924017f5a3071024 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 2 Dec 2020 10:13:36 +0800 Subject: ASoC: rt715: remove unused parameter Remove unused parameter in rt715.h. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20201202021336.3591-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715.h | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index d0d0fd2a6fdb..009a8266f606 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -207,7 +207,6 @@ struct sdw_stream_data { enum { RT715_AIF1, RT715_AIF2, - RT715_AIFS, }; #define RT715_POWER_UP_DELAY_MS 400 -- cgit v1.2.3 From 4d638b9cc79eff11bad13fb3715c0ef38a9edaec Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 2 Dec 2020 09:51:46 +0300 Subject: ASoC: codecs: lpass-va-macro: remove some dead code The "decimator" variable is in the 0-7 range and it's unsigned so there is no need to check for negative values. Fixes: 908e6b1df26e ("ASoC: codecs: lpass-va-macro: Add support to VA Macro") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/X8c5gjZO7YN/CFsq@mwanda Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-va-macro.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 3e6bbef26dcb..91e6890d6efc 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -844,17 +844,10 @@ static int va_macro_hw_params(struct snd_pcm_substream *substream, for_each_set_bit(decimator, &va->active_ch_mask[dai->id], VA_MACRO_DEC_MAX) { - if (decimator >= 0) { - tx_fs_reg = CDC_VA_TX0_TX_PATH_CTL + - VA_MACRO_TX_PATH_OFFSET * decimator; - snd_soc_component_update_bits(component, tx_fs_reg, - 0x0F, tx_fs_rate); - } else { - dev_err(va_dev, - "%s: ERROR: Invalid decimator: %d\n", - __func__, decimator); - return -EINVAL; - } + tx_fs_reg = CDC_VA_TX0_TX_PATH_CTL + + VA_MACRO_TX_PATH_OFFSET * decimator; + snd_soc_component_update_bits(component, tx_fs_reg, 0x0F, + tx_fs_rate); } return 0; } -- cgit v1.2.3 From adc7d561800997d39abc689ad05cf3cd1270b97a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 30 Nov 2020 22:56:26 +0100 Subject: ASoC: adau1372: add missing dependencies SND_SOC_ADAU1372_I2C and SND_SOC_ADAU1372_SPI prpoerly select the REGMAP config they need but forget to depend on the underlying bus. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201130215626.2400999-1-alexandre.belloni@bootlin.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 97b727a449b3..02e23e802b24 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -373,11 +373,13 @@ config SND_SOC_ADAU1372 config SND_SOC_ADAU1372_I2C tristate "Analog Devices ADAU1372 CODEC (I2C)" + depends on I2C select SND_SOC_ADAU1372 select REGMAP_I2C config SND_SOC_ADAU1372_SPI tristate "Analog Devices ADAU1372 CODEC (SPI)" + depends on SPI select SND_SOC_ADAU1372 select REGMAP_SPI -- cgit v1.2.3 From 5057d108d69a55f97f3e436aefbabb9c4064d9d6 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 2 Dec 2020 22:34:39 -0300 Subject: ASoC: fsl_audmix: Remove unneeded data field The .data field is only used to pass the string name to platform_device_register_data(). Pass the string name directly to make the code simpler. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20201203013439.10617-1-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_audmix.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 7ad5925772e8..8dc44dec7956 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -455,7 +455,6 @@ static const struct regmap_config fsl_audmix_regmap_config = { static const struct of_device_id fsl_audmix_ids[] = { { .compatible = "fsl,imx8qm-audmix", - .data = "imx-audmix", }, { /* sentinel */ } }; @@ -465,17 +464,9 @@ static int fsl_audmix_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fsl_audmix *priv; - const char *mdrv; - const struct of_device_id *of_id; void __iomem *regs; int ret; - of_id = of_match_device(fsl_audmix_ids, dev); - if (!of_id || !of_id->data) - return -EINVAL; - - mdrv = of_id->data; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -510,10 +501,10 @@ static int fsl_audmix_probe(struct platform_device *pdev) goto err_disable_pm; } - priv->pdev = platform_device_register_data(dev, mdrv, 0, NULL, 0); + priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0); if (IS_ERR(priv->pdev)) { ret = PTR_ERR(priv->pdev); - dev_err(dev, "failed to register platform %s: %d\n", mdrv, ret); + dev_err(dev, "failed to register platform: %d\n", ret); goto err_disable_pm; } -- cgit v1.2.3 From 77f1ff751037fcd39c8fc37b3c3796fb139fb388 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 30 Nov 2020 11:57:47 +0800 Subject: ASoC: fsl-asoc-card: Add support for si476x codec The si476x codec is used for FM radio function on i.MX6 auto board, it only supports recording function. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/1606708668-28786-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index a2dd3b6b7fec..f62f81ceab0d 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -131,6 +131,13 @@ static const struct snd_soc_dapm_route audio_map_tx[] = { {"CPU-Playback", NULL, "ASRC-Playback"}, }; +static const struct snd_soc_dapm_route audio_map_rx[] = { + /* 1st half -- Normal DAPM routes */ + {"CPU-Capture", NULL, "Capture"}, + /* 2nd half -- ASRC DAPM routes */ + {"ASRC-Capture", NULL, "CPU-Capture"}, +}; + /* Add all possible widgets into here without being redundant */ static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = { SND_SOC_DAPM_LINE("Line Out Jack", NULL), @@ -653,6 +660,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->cpu_priv.slot_width = 32; priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); + } else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) { + codec_dai_name = "si476x-codec"; + priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + priv->card.dapm_routes = audio_map_rx; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); } else { dev_err(&pdev->dev, "unknown Device Tree compatible\n"); ret = -EINVAL; @@ -869,6 +881,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-wm8960", }, { .compatible = "fsl,imx-audio-mqs", }, { .compatible = "fsl,imx-audio-wm8524", }, + { .compatible = "fsl,imx-audio-si476x", }, {} }; MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids); -- cgit v1.2.3 From 1c1fb2653a0c2e3f310c07eacd8fc3a10e08c97a Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Thu, 3 Dec 2020 22:42:27 +0800 Subject: ASoC: jz4740-i2s: add missed checks for clk_get() jz4740_i2s_set_sysclk() does not check the return values of clk_get(), while the file dereferences the pointers in clk_put(). Add the missed checks to fix it. Fixes: 11bd3dd1b7c2 ("ASoC: Add JZ4740 ASoC support") Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20201203144227.418194-1-hslester96@gmail.com Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index c7bd20104b20..0793e284d0e7 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -312,10 +312,14 @@ static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, switch (clk_id) { case JZ4740_I2S_CLKSRC_EXT: parent = clk_get(NULL, "ext"); + if (IS_ERR(parent)) + return PTR_ERR(parent); clk_set_parent(i2s->clk_i2s, parent); break; case JZ4740_I2S_CLKSRC_PLL: parent = clk_get(NULL, "pll half"); + if (IS_ERR(parent)) + return PTR_ERR(parent); clk_set_parent(i2s->clk_i2s, parent); ret = clk_set_rate(i2s->clk_i2s, freq); break; -- cgit v1.2.3 From 7e20ae1208daaf6dad85c2dcb968fc590b6f3b99 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 4 Dec 2020 16:42:28 +0000 Subject: ASoC: q6afe-clocks: Add missing parent clock rate setting clock rate on child clocks without a parent clock rate will result in zero clk rate for child. This also means that when audio is started dsp will attempt to access registers without enabling clock resulting in board boot up. Fix this by adding the missing parent clock rate. Fixes: 520a1c396d196 ("ASoC: q6afe-clocks: add q6afe clock controller") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201204164228.1826-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe-clocks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/qcom/qdsp6/q6afe-clocks.c b/sound/soc/qcom/qdsp6/q6afe-clocks.c index 2efc2eaa0424..acfc0c698f6a 100644 --- a/sound/soc/qcom/qdsp6/q6afe-clocks.c +++ b/sound/soc/qcom/qdsp6/q6afe-clocks.c @@ -16,6 +16,7 @@ .afe_clk_id = Q6AFE_##id, \ .name = #id, \ .attributes = LPASS_CLK_ATTRIBUTE_COUPLE_NO, \ + .rate = 19200000, \ .hw.init = &(struct clk_init_data) { \ .ops = &clk_q6afe_ops, \ .name = #id, \ -- cgit v1.2.3 From 518a760cc369eafeef0d6c76d8c30a8acab2c921 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Dec 2020 19:03:13 +0200 Subject: ASoC: SOF: control: fix cppcheck warning in snd_sof_volume_info() Fix cppcheck warning: sound/soc/sof/control.c:117:82: style:inconclusive: Function 'snd_sof_volume_info' argument 2 names different: declaration 'ucontrol' definition 'uinfo'. [funcArgNamesDifferent] Fixes: fca18e62984a ("ASoC: SOF: control: override volume info callback") Signed-off-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201204170313.2704499-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index d00a918b6f39..dc930fc2f4b5 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -125,7 +125,7 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *ucontrol); + struct snd_ctl_elem_info *uinfo); int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_switch_put(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 7061b8a52296e044eed47b605d136a48da1a7761 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 3 Dec 2020 23:54:41 +0100 Subject: ASoC: cros_ec_codec: fix uninitialized memory read gcc points out a memory area that is copied to a device but not initialized: sound/soc/codecs/cros_ec_codec.c: In function 'i2s_rx_event': arch/x86/include/asm/string_32.h:83:20: error: '*((void *)&p+4)' may be used uninitialized in this function [-Werror=maybe-uninitialized] 83 | *((int *)to + 1) = *((int *)from + 1); Initialize all the unused fields to zero. Fixes: 727f1c71c780 ("ASoC: cros_ec_codec: refactor I2S RX") Signed-off-by: Arnd Bergmann Acked-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201203225458.1477830-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/cros_ec_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 28f039adfa13..5c3b7e5e55d2 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -332,7 +332,7 @@ static int i2s_rx_event(struct snd_soc_dapm_widget *w, snd_soc_dapm_to_component(w->dapm); struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - struct ec_param_ec_codec_i2s_rx p; + struct ec_param_ec_codec_i2s_rx p = {}; switch (event) { case SND_SOC_DAPM_PRE_PMU: -- cgit v1.2.3 From 29275309b0e32bb838d67158c6b6e687275f43e9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 3 Dec 2020 23:38:05 +0100 Subject: ASoC: atmel: mchp-spdifrx needs COMMON_CLK Compile-testing this driver on an older platform without CONFIG_COMMON_CLK fails with ERROR: modpost: "clk_set_min_rate" [sound/soc/atmel/snd-soc-mchp-spdifrx.ko] undefined! Make this is a strict dependency. Fixes: ef265c55c1ac ("ASoC: mchp-spdifrx: add driver for SPDIF RX") Signed-off-by: Arnd Bergmann Reviewed-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20201203223815.1353451-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index bd8854bfd2ee..142373ec411a 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -148,6 +148,7 @@ config SND_MCHP_SOC_SPDIFTX config SND_MCHP_SOC_SPDIFRX tristate "Microchip ASoC driver for boards using S/PDIF RX" depends on OF && (ARCH_AT91 || COMPILE_TEST) + depends on COMMON_CLK select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help -- cgit v1.2.3 From aa6cc97c0ac31c668afc7027bcf2bdb0fe4610fe Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Thu, 3 Dec 2020 23:40:10 +0800 Subject: ASoC: intel: sof_rt5682: Add support for tgl_rt1011_rt5682 This patch adds the driver data for two rt1011 speaker amplifiers on SSP1 and rt5682 on SSP0 for TGL platform. DAI format for rt1011 is leveraged from cml_rt1011_rt5682 which is 4-slot tdm with 100fs bclk. Signed-off-by: Brent Lu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201203154010.29464-1-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/sof_realtek_common.c | 138 ++++++++++++++++++++++ sound/soc/intel/boards/sof_realtek_common.h | 24 ++++ sound/soc/intel/boards/sof_rt5682.c | 26 +++- sound/soc/intel/common/soc-acpi-intel-tgl-match.c | 17 ++- 6 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 sound/soc/intel/boards/sof_realtek_common.c create mode 100644 sound/soc/intel/boards/sof_realtek_common.h (limited to 'sound') diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index dddb672a6d55..b58b9b60d37e 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -443,6 +443,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) select SND_SOC_MAX98373_I2C + select SND_SOC_RT1011 select SND_SOC_RT1015 select SND_SOC_RT5682_I2C select SND_SOC_DMIC diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index a58e4d22e9c8..5f03e484b215 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -18,7 +18,7 @@ snd-soc-sst-byt-cht-cx2072x-objs := bytcht_cx2072x.o snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o -snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o sof_maxim_common.o +snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o sof_maxim_common.o sof_realtek_common.o snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o hda_dsp_common.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c new file mode 100644 index 000000000000..f3cf73c620ba --- /dev/null +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/rt1011.h" +#include "sof_realtek_common.h" + +/* + * Current only 2-amp configuration is supported for rt1011 + */ +static const struct snd_soc_dapm_route rt1011_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Left SPO" }, + { "Right Spk", NULL, "Right SPO" }, +}; + +/* + * Make sure device's Unique ID follows this configuration: + * + * Two speakers: + * 0: left, 1: right + * Four speakers: + * 0: Woofer left, 1: Woofer right + * 2: Tweeter left, 3: Tweeter right + */ +static struct snd_soc_codec_conf rt1011_codec_confs[] = { + { + .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME), + .name_prefix = "Right", + }, +}; + +static struct snd_soc_dai_link_component rt1011_dai_link_components[] = { + { + .name = RT1011_DEV0_NAME, + .dai_name = RT1011_CODEC_DAI, + }, + { + .name = RT1011_DEV1_NAME, + .dai_name = RT1011_CODEC_DAI, + }, +}; + +static const struct { + unsigned int tx; + unsigned int rx; +} rt1011_tdm_mask[] = { + {.tx = 0x4, .rx = 0x1}, + {.tx = 0x8, .rx = 0x2}, +}; + +static int rt1011_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai; + int srate, i, ret = 0; + + srate = params_rate(params); + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + /* 100 Fs to drive 24 bit data */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK, + 100 * srate, 256 * srate); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set pll, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1, + 256 * srate, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n", + ret); + return ret; + } + + if (i >= ARRAY_SIZE(rt1011_tdm_mask)) { + dev_err(codec_dai->dev, "invalid codec index %d\n", + i); + return -ENODEV; + } + + ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx, + rt1011_tdm_mask[i].rx, 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + } + + return 0; +} + +static const struct snd_soc_ops rt1011_ops = { + .hw_params = rt1011_hw_params, +}; + +static int rt1011_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_dapm_routes, + ARRAY_SIZE(rt1011_dapm_routes)); + if (ret) + dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + return ret; +} + +void sof_rt1011_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = rt1011_dai_link_components; + link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components); + link->init = rt1011_init; + link->ops = &rt1011_ops; +} + +void sof_rt1011_codec_conf(struct snd_soc_card *card) +{ + card->codec_conf = rt1011_codec_confs; + card->num_configs = ARRAY_SIZE(rt1011_codec_confs); +} diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h new file mode 100644 index 000000000000..87cb3812b926 --- /dev/null +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2020 Intel Corporation. + */ + +/* + * This file defines data structures used in Machine Driver for Intel + * platforms with Realtek Codecs. + */ +#ifndef __SOF_REALTEK_COMMON_H +#define __SOF_REALTEK_COMMON_H + +#include + +#define RT1011_CODEC_DAI "rt1011-aif" +#define RT1011_DEV0_NAME "i2c-10EC1011:00" +#define RT1011_DEV1_NAME "i2c-10EC1011:01" +#define RT1011_DEV2_NAME "i2c-10EC1011:02" +#define RT1011_DEV3_NAME "i2c-10EC1011:03" + +void sof_rt1011_dai_link(struct snd_soc_dai_link *link); +void sof_rt1011_codec_conf(struct snd_soc_card *card); + +#endif /* __SOF_REALTEK_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 891f908659f5..8b1ca2da9bb9 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -24,6 +24,7 @@ #include "../common/soc-intel-quirks.h" #include "hda_dsp_common.h" #include "sof_maxim_common.h" +#include "sof_realtek_common.h" #define NAME_SIZE 32 @@ -41,10 +42,11 @@ #define SOF_RT5682_NUM_HDMIDEV_MASK (GENMASK(12, 10)) #define SOF_RT5682_NUM_HDMIDEV(quirk) \ ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK) -#define SOF_RT1015_SPEAKER_AMP_PRESENT BIT(13) -#define SOF_RT1015_SPEAKER_AMP_100FS BIT(14) -#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15) -#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16) +#define SOF_RT1011_SPEAKER_AMP_PRESENT BIT(13) +#define SOF_RT1015_SPEAKER_AMP_PRESENT BIT(14) +#define SOF_RT1015_SPEAKER_AMP_100FS BIT(15) +#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(16) +#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(17) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -741,6 +743,9 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].codecs = max98360a_component; links[id].num_codecs = ARRAY_SIZE(max98360a_component); links[id].init = speaker_codec_init; + } else if (sof_rt5682_quirk & + SOF_RT1011_SPEAKER_AMP_PRESENT) { + sof_rt1011_dai_link(&links[id]); } else { links[id].codecs = max98357a_component; links[id].num_codecs = ARRAY_SIZE(max98357a_component); @@ -851,6 +856,8 @@ static int sof_audio_probe(struct platform_device *pdev) if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) sof_max98373_codec_conf(&sof_audio_card_rt5682); + else if (sof_rt5682_quirk & SOF_RT1011_SPEAKER_AMP_PRESENT) + sof_rt1011_codec_conf(&sof_audio_card_rt5682); dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, dmic_be_num, hdmi_num); @@ -931,6 +938,15 @@ static const struct platform_device_id board_ids[] = { SOF_RT1015_SPEAKER_AMP_100FS | SOF_RT5682_SSP_AMP(1)), }, + { + .name = "tgl_rt1011_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT1011_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, { } }; @@ -948,6 +964,7 @@ module_platform_driver(sof_audio) MODULE_DESCRIPTION("SOF Audio Machine driver"); MODULE_AUTHOR("Bard Liao "); MODULE_AUTHOR("Sathya Prakash M R "); +MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sof_rt5682"); MODULE_ALIAS("platform:tgl_max98357a_rt5682"); @@ -955,3 +972,4 @@ MODULE_ALIAS("platform:jsl_rt5682_rt1015"); MODULE_ALIAS("platform:tgl_max98373_rt5682"); MODULE_ALIAS("platform:jsl_rt5682_max98360a"); MODULE_ALIAS("platform:cml_rt1015_rt5682"); +MODULE_ALIAS("platform:tgl_rt1011_rt5682"); diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 9f243e60b95c..98196e9fad62 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -9,7 +9,7 @@ #include #include -static struct snd_soc_acpi_codecs tgl_codecs = { +static const struct snd_soc_acpi_codecs tgl_codecs = { .num_codecs = 1, .codecs = {"MX98357A"} }; @@ -305,11 +305,16 @@ static const struct snd_soc_acpi_link_adr tgl_3_in_1_sdca[] = { {} }; -static struct snd_soc_acpi_codecs tgl_max98373_amp = { +static const struct snd_soc_acpi_codecs tgl_max98373_amp = { .num_codecs = 1, .codecs = {"MX98373"} }; +static const struct snd_soc_acpi_codecs tgl_rt1011_amp = { + .num_codecs = 1, + .codecs = {"10EC1011"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { .id = "10EC1308", @@ -335,6 +340,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { .sof_fw_filename = "sof-tgl.ri", .sof_tplg_filename = "sof-tgl-max98373-rt5682.tplg", }, + { + .id = "10EC5682", + .drv_name = "tgl_rt1011_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &tgl_rt1011_amp, + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); -- cgit v1.2.3 From 7b153760513cee875515398f4a9ba329a8d426e2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 3 Dec 2020 23:28:47 +0100 Subject: ASoC: fsl_aud2htx: mark PM functions as __maybe_unused When CONFIG_PM is disabled, we get a warning for unused functions: sound/soc/fsl/fsl_aud2htx.c:261:12: error: unused function 'fsl_aud2htx_runtime_suspend' [-Werror,-Wunused-function] static int fsl_aud2htx_runtime_suspend(struct device *dev) sound/soc/fsl/fsl_aud2htx.c:271:12: error: unused function 'fsl_aud2htx_runtime_resume' [-Werror,-Wunused-function] static int fsl_aud2htx_runtime_resume(struct device *dev) Mark these as __maybe_unused to avoid the warning without adding an #ifdef. Fixes: 8a24c834c053 ("ASoC: fsl_aud2htx: Add aud2htx module driver") Signed-off-by: Arnd Bergmann Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20201203222900.1042578-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_aud2htx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 4091ccc7c3e9..d70d5e75a30c 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -258,7 +258,7 @@ static int fsl_aud2htx_remove(struct platform_device *pdev) return 0; } -static int fsl_aud2htx_runtime_suspend(struct device *dev) +static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev) { struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev); @@ -268,7 +268,7 @@ static int fsl_aud2htx_runtime_suspend(struct device *dev) return 0; } -static int fsl_aud2htx_runtime_resume(struct device *dev) +static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev) { struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev); int ret; -- cgit v1.2.3 From b1b8eb1283c90a953089d988930d7b6156418958 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 4 Dec 2020 00:14:18 +0100 Subject: ASoC: qcom: fix QDSP6 dependencies, attempt #3 The previous fix left another warning in randconfig builds: WARNING: unmet direct dependencies detected for SND_SOC_QDSP6 Depends on [n]: SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_QCOM [=y] && QCOM_APR [=y] && COMMON_CLK [=n] Selected by [y]: - SND_SOC_MSM8996 [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_QCOM [=y] && QCOM_APR [=y] Add one more dependency for this one. Fixes: 2bc8831b135c ("ASoC: qcom: fix SDM845 & QDSP6 dependencies more") Signed-off-by: Arnd Bergmann Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20201203231443.1483763-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 27f93006be96..cc7c1de2f1d9 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -106,6 +106,7 @@ config SND_SOC_QDSP6 config SND_SOC_MSM8996 tristate "SoC Machine driver for MSM8996 and APQ8096 boards" depends on QCOM_APR + depends on COMMON_CLK select SND_SOC_QDSP6 select SND_SOC_QCOM_COMMON help -- cgit v1.2.3 From c72b9bfe0f914639cc475585f45722a3eb57a56d Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Sat, 5 Dec 2020 13:11:30 +0800 Subject: ALSA: hda/realtek: make bass spk volume adjustable on a yoga laptop This change could fix 2 issues on this machine: - the bass speaker's output volume can't be adjusted, that is because the bass speaker is routed to the DAC (Nid 0x6) which has no volume control. - after plugging a headset with vol+, vol- and pause buttons on it, press those buttons, nothing happens, this means those buttons don't work at all. This machine has alc287 codec, need to add the codec id to the disable/enable_headset_jack_key(), then the headset button could work. The quirk of ALC285_FIXUP_THINKPAD_HEADSET_JACK could fix both of these 2 issues. Cc: Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20201205051130.8122-1-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8616c5624870..5a905fa1b33a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3104,6 +3104,7 @@ static void alc_disable_headset_jack_key(struct hda_codec *codec) case 0x10ec0215: case 0x10ec0225: case 0x10ec0285: + case 0x10ec0287: case 0x10ec0295: case 0x10ec0289: case 0x10ec0299: @@ -3130,6 +3131,7 @@ static void alc_enable_headset_jack_key(struct hda_codec *codec) case 0x10ec0215: case 0x10ec0225: case 0x10ec0285: + case 0x10ec0287: case 0x10ec0295: case 0x10ec0289: case 0x10ec0299: @@ -8578,6 +8580,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x14, 0x90170110}, {0x19, 0x04a11040}, {0x21, 0x04211020}), + SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_HEADSET_JACK, + {0x14, 0x90170110}, + {0x17, 0x90170111}, + {0x19, 0x03a11030}, + {0x21, 0x03211020}), SND_HDA_PIN_QUIRK(0x10ec0286, 0x1025, "Acer", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE, {0x12, 0x90a60130}, {0x17, 0x90170110}, -- cgit v1.2.3 From 4ebd47037027c4beae99680bff3b20fdee5d7c1e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 6 Dec 2020 09:34:56 +0100 Subject: ALSA: seq: Use bool for snd_seq_queue internal flags The snd_seq_queue struct contains various flags in the bit fields. Those are categorized to two different use cases, both of which are protected by different spinlocks. That implies that there are still potential risks of the bad operations for bit fields by concurrent accesses. For addressing the problem, this patch rearranges those flags to be a standard bool instead of a bit field. Reported-by: syzbot+63cbe31877bb80ef58f5@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20201206083456.21110-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/seq/seq_queue.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h index 1c3a8d3254d9..c69105dc1a10 100644 --- a/sound/core/seq/seq_queue.h +++ b/sound/core/seq/seq_queue.h @@ -26,10 +26,10 @@ struct snd_seq_queue { struct snd_seq_timer *timer; /* time keeper for this queue */ int owner; /* client that 'owns' the timer */ - unsigned int locked:1, /* timer is only accesibble by owner if set */ - klocked:1, /* kernel lock (after START) */ - check_again:1, - check_blocked:1; + bool locked; /* timer is only accesibble by owner if set */ + bool klocked; /* kernel lock (after START) */ + bool check_again; /* concurrent access happened during check */ + bool check_blocked; /* queue being checked */ unsigned int flags; /* status flags */ unsigned int info_flags; /* info for sync */ -- cgit v1.2.3 From 88a06d6fd6b369d88cec46c62db3e2604a2f50d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 6 Dec 2020 09:35:27 +0100 Subject: ALSA: rawmidi: Access runtime->avail always in spinlock The runtime->avail field may be accessed concurrently while some places refer to it without taking the runtime->lock spinlock, as detected by KCSAN. Usually this isn't a big problem, but for consistency and safety, we should take the spinlock at each place referencing this field. Reported-by: syzbot+a23a6f1215c84756577c@syzkaller.appspotmail.com Reported-by: syzbot+3d367d1df1d2b67f5c19@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20201206083527.21163-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index c78720a3299c..257ad5206240 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -95,11 +95,21 @@ static inline unsigned short snd_rawmidi_file_flags(struct file *file) } } -static inline int snd_rawmidi_ready(struct snd_rawmidi_substream *substream) +static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime) +{ + return runtime->avail >= runtime->avail_min; +} + +static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long flags; + bool ready; - return runtime->avail >= runtime->avail_min; + spin_lock_irqsave(&runtime->lock, flags); + ready = __snd_rawmidi_ready(runtime); + spin_unlock_irqrestore(&runtime->lock, flags); + return ready; } static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream, @@ -1019,7 +1029,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, if (result > 0) { if (runtime->event) schedule_work(&runtime->event_work); - else if (snd_rawmidi_ready(substream)) + else if (__snd_rawmidi_ready(runtime)) wake_up(&runtime->sleep); } spin_unlock_irqrestore(&runtime->lock, flags); @@ -1098,7 +1108,7 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun result = 0; while (count > 0) { spin_lock_irq(&runtime->lock); - while (!snd_rawmidi_ready(substream)) { + while (!__snd_rawmidi_ready(runtime)) { wait_queue_entry_t wait; if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { @@ -1115,9 +1125,11 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; - if (!runtime->avail) - return result > 0 ? result : -EIO; spin_lock_irq(&runtime->lock); + if (!runtime->avail) { + spin_unlock_irq(&runtime->lock); + return result > 0 ? result : -EIO; + } } spin_unlock_irq(&runtime->lock); count1 = snd_rawmidi_kernel_read1(substream, @@ -1255,7 +1267,7 @@ int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int coun runtime->avail += count; substream->bytes += count; if (count > 0) { - if (runtime->drain || snd_rawmidi_ready(substream)) + if (runtime->drain || __snd_rawmidi_ready(runtime)) wake_up(&runtime->sleep); } return count; @@ -1444,9 +1456,11 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; - if (!runtime->avail && !timeout) - return result > 0 ? result : -EIO; spin_lock_irq(&runtime->lock); + if (!runtime->avail && !timeout) { + spin_unlock_irq(&runtime->lock); + return result > 0 ? result : -EIO; + } } spin_unlock_irq(&runtime->lock); count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count); @@ -1526,6 +1540,7 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; + unsigned long buffer_size, avail, xruns; rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); @@ -1544,13 +1559,16 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; + spin_lock_irq(&runtime->lock); + buffer_size = runtime->buffer_size; + avail = runtime->avail; + spin_unlock_irq(&runtime->lock); snd_iprintf(buffer, " Mode : %s\n" " Buffer size : %lu\n" " Avail : %lu\n", runtime->oss ? "OSS compatible" : "native", - (unsigned long) runtime->buffer_size, - (unsigned long) runtime->avail); + buffer_size, avail); } } } @@ -1568,13 +1586,16 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; + spin_lock_irq(&runtime->lock); + buffer_size = runtime->buffer_size; + avail = runtime->avail; + xruns = runtime->xruns; + spin_unlock_irq(&runtime->lock); snd_iprintf(buffer, " Buffer size : %lu\n" " Avail : %lu\n" " Overruns : %lu\n", - (unsigned long) runtime->buffer_size, - (unsigned long) runtime->avail, - (unsigned long) runtime->xruns); + buffer_size, avail, xruns); } } } -- cgit v1.2.3 From 5cfca59604e423f720297e30a9dc493eea623493 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Mon, 7 Dec 2020 15:27:55 +0800 Subject: ALSA: hda/realtek - Enable headset mic of ASUS X430UN with ALC256 The ASUS laptop X430UN with ALC256 can't detect the headset microphone until ALC256_FIXUP_ASUS_MIC_NO_PRESENCE quirk applied. Signed-off-by: Chris Chiu Signed-off-by: Jian-Hong Pan Cc: Link: https://lore.kernel.org/r/20201207072755.16210-1-chiu@endlessos.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5a905fa1b33a..81fbcba33a40 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7958,6 +7958,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), -- cgit v1.2.3 From bb9dd3ce6177e1f8cf01b0d45e6bd9b93f656bd0 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 2 Dec 2020 11:33:43 -0800 Subject: ASoC: pcm: send DAPM_STREAM_STOP event in dpcm_fe_dai_shutdown A recent change removed the call to send the DAPM_STREAM_STOP event in dpcm_fe_dai_shutdown. But this causes a regression when a PCM prepare is not paired with a hw_free. So, add the DAPM_STREAM_STOP event back to dpcm_fe_dai_shutdown() to fix this. The new sequence would be: soc_pcm_prepare() -> SND_SOC_DAPM_STREAM_START soc_pcm_hw_free() -> soc_pcm_hw_free() -> SND_SOC_DAPM_STREAM_STOP dpcm_fe_dai_shutdown() -> SND_SOC_DAPM_STREAM_STOP Note that the DAPM_STREAM_STOP will be called twice but it seems harmless. Fixes: a27b421f1d04 ('ASoC: pcm: call snd_soc_dapm_stream_stop() in soc_pcm_hw_clean') Reported-by: Hans de Goede Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Tested-by: Hans de Goede Link: https://lore.kernel.org/r/20201202193343.912942-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 5250124dc8f5..ae062e4d1ce8 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1860,6 +1860,9 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) /* now shutdown the frontend */ soc_pcm_close(substream); + /* run the stream stop event */ + dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); + fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); return 0; -- cgit v1.2.3 From 8f6cfbb6d4272635311b4604194e39172e7719ad Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Fri, 4 Dec 2020 18:50:14 +0200 Subject: ASoC: SOF: trace: Add runtime trace filtering mechanism The "filter" debugfs file defines the log levels used by the firmware and reported by sof-logger. The file contains the formatted entry list, where each entry follows the following syntax in plain text: log_level uuid_id pipe_id comp_id; This file may be updated by userspace applications such sof-logger, or directly by the user during debugging process. An unused (wildcard) pipe_id or comp_id value should be set to -1, uuid_id is hexadecimal value, so when unused then should be set to 0. When the file is modified, an IPC command is sent to FW with new trace levels for selected components in filter elements list. Signed-off-by: Karol Trzcinski Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201204165014.2697903-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/header.h | 1 + include/sound/sof/trace.h | 28 ++++++ sound/soc/sof/trace.c | 224 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+) (limited to 'sound') diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index c93f08334bbe..4c747c52e01b 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -118,6 +118,7 @@ #define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001) #define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) #define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) +#define SOF_IPC_TRACE_FILTER_UPDATE SOF_CMD_TYPE(0x004) /**< ABI3.17 */ /* debug */ #define SOF_IPC_DEBUG_MEM_USAGE SOF_CMD_TYPE(0x001) diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h index c31a94a13ce0..25ea99f62d37 100644 --- a/include/sound/sof/trace.h +++ b/include/sound/sof/trace.h @@ -43,6 +43,34 @@ struct sof_ipc_dma_trace_posn { uint32_t messages; /* total trace messages */ } __packed; +/* Values used in sof_ipc_trace_filter_elem: */ + +/* bits 6..0 */ +#define SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL 0x01 /**< trace level for selected components */ +#define SOF_IPC_TRACE_FILTER_ELEM_BY_UUID 0x02 /**< filter by uuid key */ +#define SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE 0x03 /**< filter by pipeline */ +#define SOF_IPC_TRACE_FILTER_ELEM_BY_COMP 0x04 /**< filter by component id */ + +/* bit 7 */ +#define SOF_IPC_TRACE_FILTER_ELEM_FIN 0x80 /**< mark last filter in set */ + +/* bits 31..8: Unused */ + +/** part of sof_ipc_trace_filter, ABI3.17 */ +struct sof_ipc_trace_filter_elem { + uint32_t key; /**< SOF_IPC_TRACE_FILTER_ELEM_ {LEVEL, UUID, COMP, PIPE} */ + uint32_t value; /**< element value */ +} __packed; + +/** Runtime tracing filtration data - SOF_IPC_TRACE_FILTER_UPDATE, ABI3.17 */ +struct sof_ipc_trace_filter { + struct sof_ipc_cmd_hdr hdr; /**< IPC command header */ + uint32_t elem_cnt; /**< number of entries in elems[] array */ + uint32_t reserved[8]; /**< reserved for future usage */ + /** variable size array with new filtering settings */ + struct sof_ipc_trace_filter_elem elems[]; +} __packed; + /* * Commom debug */ diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 69889241a092..f72a6e83e6af 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -13,6 +13,225 @@ #include "sof-priv.h" #include "ops.h" +#define TRACE_FILTER_ELEMENTS_PER_ENTRY 4 +#define TRACE_FILTER_MAX_CONFIG_STRING_LENGTH 1024 + +static int trace_filter_append_elem(struct snd_sof_dev *sdev, uint32_t key, uint32_t value, + struct sof_ipc_trace_filter_elem *elem_list, + int capacity, int *counter) +{ + if (*counter >= capacity) + return -ENOMEM; + + elem_list[*counter].key = key; + elem_list[*counter].value = value; + ++*counter; + + return 0; +} + +static int trace_filter_parse_entry(struct snd_sof_dev *sdev, const char *line, + struct sof_ipc_trace_filter_elem *elem, + int capacity, int *counter) +{ + int len = strlen(line); + int cnt = *counter; + uint32_t uuid_id; + int log_level; + int pipe_id; + int comp_id; + int read; + int ret; + + /* ignore empty content */ + ret = sscanf(line, " %n", &read); + if (!ret && read == len) + return len; + + ret = sscanf(line, " %d %x %d %d %n", &log_level, &uuid_id, &pipe_id, &comp_id, &read); + if (ret != TRACE_FILTER_ELEMENTS_PER_ENTRY || read != len) { + dev_err(sdev->dev, "error: invalid trace filter entry '%s'\n", line); + return -EINVAL; + } + + if (uuid_id > 0) { + ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_UUID, + uuid_id, elem, capacity, &cnt); + if (ret) + return ret; + } + if (pipe_id >= 0) { + ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_PIPE, + pipe_id, elem, capacity, &cnt); + if (ret) + return ret; + } + if (comp_id >= 0) { + ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_BY_COMP, + comp_id, elem, capacity, &cnt); + if (ret) + return ret; + } + + ret = trace_filter_append_elem(sdev, SOF_IPC_TRACE_FILTER_ELEM_SET_LEVEL | + SOF_IPC_TRACE_FILTER_ELEM_FIN, + log_level, elem, capacity, &cnt); + if (ret) + return ret; + + /* update counter only when parsing whole entry passed */ + *counter = cnt; + + return len; +} + +static int trace_filter_parse(struct snd_sof_dev *sdev, char *string, + int *out_elem_cnt, + struct sof_ipc_trace_filter_elem **out) +{ + static const char entry_delimiter[] = ";"; + char *entry = string; + int capacity = 0; + int entry_len; + int cnt = 0; + + /* + * Each entry contains at least 1, up to TRACE_FILTER_ELEMENTS_PER_ENTRY + * IPC elements, depending on content. Calculate IPC elements capacity + * for the input string where each element is set. + */ + while (entry) { + capacity += TRACE_FILTER_ELEMENTS_PER_ENTRY; + entry = strchr(entry + 1, entry_delimiter[0]); + } + *out = kmalloc(capacity * sizeof(**out), GFP_KERNEL); + if (!*out) + return -ENOMEM; + + /* split input string by ';', and parse each entry separately in trace_filter_parse_entry */ + while ((entry = strsep(&string, entry_delimiter))) { + entry_len = trace_filter_parse_entry(sdev, entry, *out, capacity, &cnt); + if (entry_len < 0) { + dev_err(sdev->dev, "error: %s failed for '%s', %d\n", __func__, entry, + entry_len); + return -EINVAL; + } + } + + *out_elem_cnt = cnt; + + return 0; +} + +static int sof_ipc_trace_update_filter(struct snd_sof_dev *sdev, int num_elems, + struct sof_ipc_trace_filter_elem *elems) +{ + struct sof_ipc_trace_filter *msg; + struct sof_ipc_reply reply; + size_t size; + int ret; + + size = struct_size(msg, elems, num_elems); + if (size > SOF_IPC_MSG_MAX_SIZE) + return -EINVAL; + + msg = kmalloc(size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->hdr.size = size; + msg->hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_FILTER_UPDATE; + msg->elem_cnt = num_elems; + memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems)); + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0 && ret != -EACCES) { + pm_runtime_put_noidle(sdev->dev); + dev_err(sdev->dev, "error: enabling device failed: %d\n", ret); + goto error; + } + ret = sof_ipc_tx_message(sdev->ipc, msg->hdr.cmd, msg, msg->hdr.size, + &reply, sizeof(reply)); + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_put_autosuspend(sdev->dev); + +error: + kfree(msg); + return ret ? ret : reply.error; +} + +static ssize_t sof_dfsentry_trace_filter_write(struct file *file, const char __user *from, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct sof_ipc_trace_filter_elem *elems = NULL; + struct snd_sof_dev *sdev = dfse->sdev; + loff_t pos = 0; + int num_elems; + char *string; + int ret; + + if (count > TRACE_FILTER_MAX_CONFIG_STRING_LENGTH) { + dev_err(sdev->dev, "%s too long input, %zu > %d\n", __func__, count, + TRACE_FILTER_MAX_CONFIG_STRING_LENGTH); + return -EINVAL; + } + + string = kmalloc(count + 1, GFP_KERNEL); + if (!string) + return -ENOMEM; + + /* assert null termination */ + string[count] = 0; + ret = simple_write_to_buffer(string, count, &pos, from, count); + if (ret < 0) + goto error; + + ret = trace_filter_parse(sdev, string, &num_elems, &elems); + if (ret < 0) { + dev_err(sdev->dev, "error: fail in trace_filter_parse, %d\n", ret); + goto error; + } + + if (num_elems) { + ret = sof_ipc_trace_update_filter(sdev, num_elems, elems); + if (ret < 0) { + dev_err(sdev->dev, "error: fail in sof_ipc_trace_update_filter %d\n", ret); + goto error; + } + } + ret = count; +error: + kfree(string); + kfree(elems); + return ret; +} + +static const struct file_operations sof_dfs_trace_filter_fops = { + .open = simple_open, + .write = sof_dfsentry_trace_filter_write, + .llseek = default_llseek, +}; + +static int trace_debugfs_filter_create(struct snd_sof_dev *sdev) +{ + struct snd_sof_dfsentry *dfse; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + dfse->sdev = sdev; + dfse->type = SOF_DFSENTRY_TYPE_BUF; + + debugfs_create_file("filter", 0200, sdev->debugfs_root, dfse, + &sof_dfs_trace_filter_fops); + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); + + return 0; +} + static size_t sof_trace_avail(struct snd_sof_dev *sdev, loff_t pos, size_t buffer_size) { @@ -135,10 +354,15 @@ static const struct file_operations sof_dfs_trace_fops = { static int trace_debugfs_create(struct snd_sof_dev *sdev) { struct snd_sof_dfsentry *dfse; + int ret; if (!sdev) return -EINVAL; + ret = trace_debugfs_filter_create(sdev); + if (ret < 0) + dev_err(sdev->dev, "error: fail in %s, %d", __func__, ret); + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); if (!dfse) return -ENOMEM; -- cgit v1.2.3 From e60ffc48fac4b6ba8f3ec500bd166909f3db03c3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 6 Dec 2020 13:24:35 +0100 Subject: ASoC: Intel: cht_bsw_nau8824: Drop compress-cpu-dai bits When using the snd-soc-sst-acpi driver then the compress-cpu-dai bits are not used, the cht_bsw_nau8824 machine-driver is the only BYT/CHT driver defining them. When using the snd-sof-acpi driver then the presence of the compress-cpu-dai bits breaks things because the sof topology file for by/cht devices does not contain routing info for them. Drop the compress-cpu-dai bits, fixing the snd-sof-acpi driver not working on devices using the cht_bsw_nau8824 machine-driver. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201206122436.13553-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_nau8824.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 8131af1730f7..ac78173d01ec 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -176,9 +176,6 @@ SND_SOC_DAILINK_DEF(media, SND_SOC_DAILINK_DEF(deepbuffer, DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai"))); -SND_SOC_DAILINK_DEF(compress, - DAILINK_COMP_ARRAY(COMP_CPU("compress-cpu-dai"))); - SND_SOC_DAILINK_DEF(ssp2_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port"))); SND_SOC_DAILINK_DEF(ssp2_codec, @@ -209,11 +206,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, - [MERR_DPCM_COMPR] = { - .name = "Compressed Port", - .stream_name = "Compress", - SND_SOC_DAILINK_REG(compress, dummy, platform), - }, /* Back End DAI links */ { /* SSP2 - Codec */ -- cgit v1.2.3 From 748e72e869718db8d735d773040bce95158c98c6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 6 Dec 2020 13:24:36 +0100 Subject: ASoC: Intel: cht_bsw_nau8824: Change SSP2-Codec DAI id to 0 The snd-soc-sst-acpi driver does not care about the id specified for the SSP2-Codec DAI, but it does matter for the snd-sof-acpi driver; and when it is not 0 then the snd-sof-acpi driver does not work. Set the SSP2-Codec DAI id to 0, fixing the snd-sof-acpi driver not working on devices using the cht_bsw_nau8824 machine-driver. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201206122436.13553-3-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_nau8824.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index ac78173d01ec..fd5e25ca05f7 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -210,7 +210,7 @@ static struct snd_soc_dai_link cht_dailink[] = { { /* SSP2 - Codec */ .name = "SSP2-Codec", - .id = 1, + .id = 0, .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS, -- cgit v1.2.3 From 6a5f850aa83a1d844d27e3e53ca2f247e55d438b Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Sun, 6 Dec 2020 18:41:59 +0800 Subject: ASoC: fsl: Add imx-hdmi machine driver The driver is initially designed for sound card using HDMI interface on i.MX platform. There is internal HDMI IP or external HDMI modules connect with SAI or AUD2HTX interface. It supports both transmitter and receiver devices. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/1607251319-5821-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 12 +++ sound/soc/fsl/Makefile | 2 + sound/soc/fsl/imx-hdmi.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 sound/soc/fsl/imx-hdmi.c (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 24710decd38a..84db0b7b9d59 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -305,6 +305,18 @@ config SND_SOC_IMX_AUDMIX Say Y if you want to add support for SoC audio on an i.MX board with an Audio Mixer. +config SND_SOC_IMX_HDMI + tristate "SoC Audio support for i.MX boards with HDMI port" + select SND_SOC_FSL_SAI + select SND_SOC_FSL_AUD2HTX + select SND_SOC_HDMI_CODEC + help + ALSA SoC Audio support with HDMI feature for Freescale SoCs that have + SAI/AUD2HTX and connect with internal HDMI IP or external module + SII902X. + Say Y if you want to add support for SoC audio on an i.MX board with + IMX HDMI. + endif # SND_IMX_SOC endmenu diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 0b20e038b65b..8c5fa8a859c0 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -65,9 +65,11 @@ snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-spdif-objs := imx-spdif.o snd-soc-imx-audmix-objs := imx-audmix.o +snd-soc-imx-hdmi-objs := imx-hdmi.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o +obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c new file mode 100644 index 000000000000..2c2a76a71940 --- /dev/null +++ b/sound/soc/fsl/imx-hdmi.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2017-2020 NXP + +#include +#include +#include +#include +#include +#include "fsl_sai.h" + +/** + * struct cpu_priv - CPU private data + * @sysclk_freq: SYSCLK rates for set_sysclk() + * @sysclk_dir: SYSCLK directions for set_sysclk() + * @sysclk_id: SYSCLK ids for set_sysclk() + * @slot_width: Slot width of each frame + * + * Note: [1] for tx and [0] for rx + */ +struct cpu_priv { + unsigned long sysclk_freq[2]; + u32 sysclk_dir[2]; + u32 sysclk_id[2]; + u32 slot_width; +}; + +struct imx_hdmi_data { + struct snd_soc_dai_link dai; + struct snd_soc_card card; + struct snd_soc_jack hdmi_jack; + struct snd_soc_jack_pin hdmi_jack_pin; + struct cpu_priv cpu_priv; + u32 dai_fmt; +}; + +static int imx_hdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct imx_hdmi_data *data = snd_soc_card_get_drvdata(rtd->card); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_card *card = rtd->card; + struct device *dev = card->dev; + u32 slot_width = data->cpu_priv.slot_width; + int ret; + + /* MCLK always is (256 or 192) * rate. */ + ret = snd_soc_dai_set_sysclk(cpu_dai, data->cpu_priv.sysclk_id[tx], + 8 * slot_width * params_rate(params), + tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set cpu sysclk: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0, 2, slot_width); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret); + return ret; + } + + return 0; +} + +static struct snd_soc_ops imx_hdmi_ops = { + .hw_params = imx_hdmi_hw_params, +}; + +static const struct snd_soc_dapm_widget imx_hdmi_widgets[] = { + SND_SOC_DAPM_LINE("HDMI Jack", NULL), +}; + +static int imx_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + struct imx_hdmi_data *data = snd_soc_card_get_drvdata(card); + int ret; + + data->hdmi_jack_pin.pin = "HDMI Jack"; + data->hdmi_jack_pin.mask = SND_JACK_LINEOUT; + /* enable jack detection */ + ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT, + &data->hdmi_jack, &data->hdmi_jack_pin, 1); + if (ret) { + dev_err(card->dev, "Can't new HDMI Jack %d\n", ret); + return ret; + } + + ret = snd_soc_component_set_jack(component, &data->hdmi_jack, NULL); + if (ret && ret != -EOPNOTSUPP) { + dev_err(card->dev, "Can't set HDMI Jack %d\n", ret); + return ret; + } + + return 0; +}; + +static int imx_hdmi_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + bool hdmi_out = of_property_read_bool(np, "hdmi-out"); + bool hdmi_in = of_property_read_bool(np, "hdmi-in"); + struct snd_soc_dai_link_component *dlc; + struct platform_device *cpu_pdev; + struct device_node *cpu_np; + struct imx_hdmi_data *data; + int ret; + + dlc = devm_kzalloc(&pdev->dev, 3 * sizeof(*dlc), GFP_KERNEL); + if (!dlc) + return -ENOMEM; + + cpu_np = of_parse_phandle(np, "audio-cpu", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + cpu_pdev = of_find_device_by_node(cpu_np); + if (!cpu_pdev) { + dev_err(&pdev->dev, "failed to find SAI platform device\n"); + ret = -EINVAL; + goto fail; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto fail; + } + + data->dai.cpus = &dlc[0]; + data->dai.num_cpus = 1; + data->dai.platforms = &dlc[1]; + data->dai.num_platforms = 1; + data->dai.codecs = &dlc[2]; + data->dai.num_codecs = 1; + + data->dai.name = "i.MX HDMI"; + data->dai.stream_name = "i.MX HDMI"; + data->dai.cpus->dai_name = dev_name(&cpu_pdev->dev); + data->dai.platforms->of_node = cpu_np; + data->dai.ops = &imx_hdmi_ops; + data->dai.playback_only = true; + data->dai.capture_only = false; + data->dai.init = imx_hdmi_init; + + if (of_node_name_eq(cpu_np, "sai")) { + data->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; + data->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; + } + + if (of_device_is_compatible(np, "fsl,imx-audio-sii902x")) { + data->dai_fmt = SND_SOC_DAIFMT_LEFT_J; + data->cpu_priv.slot_width = 24; + } else { + data->dai_fmt = SND_SOC_DAIFMT_I2S; + data->cpu_priv.slot_width = 32; + } + + if ((hdmi_out && hdmi_in) || (!hdmi_out && !hdmi_in)) { + dev_err(&pdev->dev, "Invalid HDMI DAI link\n"); + goto fail; + } + + if (hdmi_out) { + data->dai.playback_only = true; + data->dai.capture_only = false; + data->dai.codecs->dai_name = "i2s-hifi"; + data->dai.codecs->name = "hdmi-audio-codec.1"; + data->dai.dai_fmt = data->dai_fmt | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + } + + if (hdmi_in) { + data->dai.playback_only = false; + data->dai.capture_only = true; + data->dai.codecs->dai_name = "i2s-hifi"; + data->dai.codecs->name = "hdmi-audio-codec.2"; + data->dai.dai_fmt = data->dai_fmt | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + } + + data->card.dapm_widgets = imx_hdmi_widgets; + data->card.num_dapm_widgets = ARRAY_SIZE(imx_hdmi_widgets); + data->card.dev = &pdev->dev; + data->card.owner = THIS_MODULE; + ret = snd_soc_of_parse_card_name(&data->card, "model"); + if (ret) + goto fail; + + data->card.num_links = 1; + data->card.dai_link = &data->dai; + + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + goto fail; + } + +fail: + if (cpu_np) + of_node_put(cpu_np); + + return ret; +} + +static const struct of_device_id imx_hdmi_dt_ids[] = { + { .compatible = "fsl,imx-audio-hdmi", }, + { .compatible = "fsl,imx-audio-sii902x", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); + +static struct platform_driver imx_hdmi_driver = { + .driver = { + .name = "imx-hdmi", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = imx_hdmi_dt_ids, + }, + .probe = imx_hdmi_probe, +}; +module_platform_driver(imx_hdmi_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("Freescale i.MX hdmi audio ASoC machine driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx-hdmi"); -- cgit v1.2.3 From 0d024a8bec084205fdd9fa17479ba91f45f85db3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Dec 2020 14:51:54 +0100 Subject: ASoC: cx2072x: Fix doubly definitions of Playback and Capture streams The cx2072x codec driver defines multiple DAIs with the same stream name "Playback" and "Capture". Although the current code works more or less as is as the secondary streams are never used, it still leads the error message like: debugfs: File 'Playback' in directory 'dapm' already present! debugfs: File 'Capture' in directory 'dapm' already present! Fix it by renaming the secondary streams to unique names. Fixes: a497a4363706 ("ASoC: Add support for Conexant CX2072X CODEC") Cc: Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20201208135154.9188-1-tiwai@suse.de Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 2ad00ed21bec..2f10991a8bdb 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1579,7 +1579,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { .id = CX2072X_DAI_DSP, .probe = cx2072x_dsp_dai_probe, .playback = { - .stream_name = "Playback", + .stream_name = "DSP Playback", .channels_min = 2, .channels_max = 2, .rates = CX2072X_RATES_DSP, @@ -1591,7 +1591,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = { .name = "cx2072x-aec", .id = 3, .capture = { - .stream_name = "Capture", + .stream_name = "AEC Capture", .channels_min = 2, .channels_max = 2, .rates = CX2072X_RATES_DSP, -- cgit v1.2.3 From 95d3befbc5e1ee39fc8a78713924cf7ed2b3cabe Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Fri, 4 Dec 2020 14:36:10 +0800 Subject: ASoC: amd: change clk_get() to devm_clk_get() and add missed checks cz_da7219_init() does not check the return values of clk_get(), while da7219_clk_enable() calls clk_set_rate() to dereference the pointers. Add checks to fix the problems. Also, change clk_get() to devm_clk_get() to avoid data leak after failures. Fixes: bb24a31ed584 ("ASoC: AMD: Configure wclk and bclk of master codec") Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20201204063610.513556-1-hslester96@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index a7702e64ec51..849288d01c6b 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -73,8 +73,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) return ret; } - da7219_dai_wclk = clk_get(component->dev, "da7219-dai-wclk"); - da7219_dai_bclk = clk_get(component->dev, "da7219-dai-bclk"); + da7219_dai_wclk = devm_clk_get(component->dev, "da7219-dai-wclk"); + if (IS_ERR(da7219_dai_wclk)) + return PTR_ERR(da7219_dai_wclk); + + da7219_dai_bclk = devm_clk_get(component->dev, "da7219-dai-bclk"); + if (IS_ERR(da7219_dai_bclk)) + return PTR_ERR(da7219_dai_bclk); ret = snd_soc_card_jack_new(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT | -- cgit v1.2.3 From 19bb4f78c91fa46bdf978e18766118498c3d2e63 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 8 Dec 2020 20:57:36 +0200 Subject: ALSA: hda/proc - print DP-MST connections To help in debugging issues with DisplayPort Multi-Stream Transport (aka DP-MST) support, print information of active connections for each device of a display audio pin widget. Example output with the patch with two monitors connected to a DP-MST hub: Devices: 4 Dev 00: PD = 0, ELDV = 0, IA = 0, Connections [ 0x03* 0x05 0x07 0x09 ] Dev 01: PD = 1, ELDV = 1, IA = 0, Connections [ 0x03* 0x05 0x07 0x09 ] *Dev 02: PD = 1, ELDV = 1, IA = 0, Connections [ 0x03 0x05* 0x07 0x09 ] Dev 03: PD = 0, ELDV = 0, IA = 0, Connections [ 0x03* 0x05 0x07 0x09 ] Connection: 4 0x03 0x05* 0x07 0x09 Format of existing "Connection:" entry is left intact to keep compatibility. Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201208185736.2877541-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 0631f31ef87f..00c2eeb2c472 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -679,6 +679,38 @@ static void print_gpio(struct snd_info_buffer *buffer, print_nid_array(buffer, codec, nid, &codec->nids); } +static void print_dpmst_connections(struct snd_info_buffer *buffer, struct hda_codec *codec, + hda_nid_t nid, int dev_num) +{ + int c, conn_len, curr, dev_id_saved; + hda_nid_t *conn; + + conn_len = snd_hda_get_num_raw_conns(codec, nid); + if (conn_len <= 0) + return; + + conn = kmalloc_array(conn_len, sizeof(hda_nid_t), GFP_KERNEL); + if (!conn) + return; + + dev_id_saved = snd_hda_get_dev_select(codec, nid); + + snd_hda_set_dev_select(codec, nid, dev_num); + curr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); + if (snd_hda_get_raw_connections(codec, nid, conn, conn_len) < 0) + goto out; + + for (c = 0; c < conn_len; c++) { + snd_iprintf(buffer, " 0x%02x", conn[c]); + if (c == curr) + snd_iprintf(buffer, "*"); + } + +out: + kfree(conn); + snd_hda_set_dev_select(codec, nid, dev_id_saved); +} + static void print_device_list(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -702,10 +734,14 @@ static void print_device_list(struct snd_info_buffer *buffer, snd_iprintf(buffer, " "); snd_iprintf(buffer, - "Dev %02d: PD = %d, ELDV = %d, IA = %d\n", i, + "Dev %02d: PD = %d, ELDV = %d, IA = %d, Connections [", i, !!(dev_list[i] & AC_DE_PD), !!(dev_list[i] & AC_DE_ELDV), !!(dev_list[i] & AC_DE_IA)); + + print_dpmst_connections(buffer, codec, nid, i); + + snd_iprintf(buffer, " ]\n"); } } -- cgit v1.2.3 From 7e413528474d5895e3e315c019fb0c43522eb6d9 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Wed, 9 Dec 2020 12:57:30 +0800 Subject: ALSA: hda/realtek - Enable headset mic of ASUS Q524UQK with ALC255 The ASUS laptop Q524UQK with ALC255 codec can't detect the headset microphone until ALC255_FIXUP_ASUS_MIC_NO_PRESENCE quirk applied. Signed-off-by: Chris Chiu Signed-off-by: Jian-Hong Pan Cc: Link: https://lore.kernel.org/r/20201209045730.9972-1-chiu@endlessos.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 81fbcba33a40..f76b70132478 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7979,6 +7979,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), -- cgit v1.2.3 From 1bea2256aa96a2d7b1b576eb74e29d79edc9bea8 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Tue, 8 Dec 2020 14:04:14 +0800 Subject: ASoC: Intel: bytcr_rt5640: Add quirk for ARCHOS Cesium 140 Tha ARCHOS Cesium 140 tablet has problem with the jack-sensing, thus the heaset functions are not working. Add quirk for this model to select the correct input map, jack-detect options and channel map to enable jack sensing and headset microphone. This device uses IN1 for its internal MIC and JD2 for jack-detect. Signed-off-by: Chris Chiu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201208060414.27646-1-chiu@endlessos.org Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index f790514a147d..cd6f7caa43c8 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -421,6 +421,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 140 CESIUM"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- cgit v1.2.3 From 3cea33b6f2d7782d1be17c71509986f33ee93541 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 9 Dec 2020 09:54:51 +0300 Subject: ASoC: max98390: Fix error codes in max98390_dsm_init() These error paths return success but they should return -EINVAL. Fixes: 97ed3e509ee6 ("ASoC: max98390: Fix potential crash during param fw loading") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/X9B0uz4svyNTqeMb@mwanda Signed-off-by: Mark Brown --- sound/soc/codecs/max98390.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index ff5cc9bbec29..bb736c44e68a 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -784,6 +784,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) { dev_err(component->dev, "param fw is invalid.\n"); + ret = -EINVAL; goto err_alloc; } dsm_param = (char *)fw->data; @@ -794,6 +795,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) { dev_err(component->dev, "param fw is invalid.\n"); + ret = -EINVAL; goto err_alloc; } regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80); -- cgit v1.2.3 From 55d8e6a85bce21f748c42eedea63681219f70523 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 8 Dec 2020 19:12:33 +0100 Subject: ASoC: AMD Raven/Renoir - fix the PCI probe (PCI revision) The Raven and Renoir ACP can be distinguished by the PCI revision. Let's do the check very early, otherwise the wrong probe code can be run. Link: https://lore.kernel.org/alsa-devel/2e4587f8-f602-cf23-4845-fd27a32b1cfc@amd.com/ Cc: Cc: Vijendar Mukunda Cc: Mark Brown Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20201208181233.2745726-1-perex@perex.cz Signed-off-by: Mark Brown --- sound/soc/amd/raven/pci-acp3x.c | 4 ++++ sound/soc/amd/renoir/rn-pci-acp3x.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c index a7de4e607961..24d0f955243d 100644 --- a/sound/soc/amd/raven/pci-acp3x.c +++ b/sound/soc/amd/raven/pci-acp3x.c @@ -118,6 +118,10 @@ static int snd_acp3x_probe(struct pci_dev *pci, int ret, i; u32 addr, val; + /* Raven device detection */ + if (pci->revision != 0x00) + return -ENODEV; + if (pci_enable_device(pci)) { dev_err(&pci->dev, "pci_enable_device failed\n"); return -ENODEV; diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index 877350f38a68..d9e6e49bff01 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -176,6 +176,10 @@ static int snd_rn_acp_probe(struct pci_dev *pci, int ret, index; u32 addr; + /* Renoir device check */ + if (pci->revision != 0x01) + return -ENODEV; + if (pci_enable_device(pci)) { dev_err(&pci->dev, "pci_enable_device failed\n"); return -ENODEV; -- cgit v1.2.3 From a9faca15a644ff754a9d6e3c9e81f91cb8ca59bd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Dec 2020 08:51:25 +0900 Subject: ASoC: soc-pcm: remove dpcm_do_trigger() dpcm_be_dai_trigger() is calling dpcm_do_trigger() at each SNDRV_PCM_TRIGGER_xxx (1). int dpcm_be_dai_trigger(...) { for_each_dpcm_be(fe, stream, dpcm) { (B) ... switch (cmd) { case SNDRV_PCM_TRIGGER_START: ... (1) ret = dpcm_do_trigger(...); ... case SNDRV_PCM_TRIGGER_RESUME: ... (1) ret = dpcm_do_trigger(...); ... case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ... (1) ret = dpcm_do_trigger(...); ... case SNDRV_PCM_TRIGGER_STOP: ... (1) ret = dpcm_do_trigger(...); ... case SNDRV_PCM_TRIGGER_SUSPEND: ... (1) ret = dpcm_do_trigger(...); ... case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ... (1) ret = dpcm_do_trigger(...); ... } } } But it is just very verbose and duplicated function. Because We can indicate dev_dbg() (A) at dpcm_be_dai_trigger() (B). And dev_err() (C) is not needed because soc_pcm_trigger() itself indicates error message when error. static int dpcm_do_trigger(...) { int ret; (A) dev_dbg(...); ret = soc_pcm_trigger(substream, cmd); if (ret < 0) (C) dev_err(...); return ret; } This patch replace dpcm_do_trigger() to soc_pcm_trigger(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87blfecssk.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ae062e4d1ce8..707c1a49f6b2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2050,21 +2050,6 @@ out: return ret; } -static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm, - struct snd_pcm_substream *substream, int cmd) -{ - int ret; - - dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n", - dpcm->be->dai_link->name, cmd); - - ret = soc_pcm_trigger(substream, cmd); - if (ret < 0) - dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret); - - return ret; -} - int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd) { @@ -2081,6 +2066,9 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (!snd_soc_dpcm_be_can_update(fe, be, stream)) continue; + dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n", + be->dai_link->name, cmd); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && @@ -2088,7 +2076,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) continue; - ret = dpcm_do_trigger(dpcm, be_substream, cmd); + ret = soc_pcm_trigger(be_substream, cmd); if (ret) return ret; @@ -2098,7 +2086,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) continue; - ret = dpcm_do_trigger(dpcm, be_substream, cmd); + ret = soc_pcm_trigger(be_substream, cmd); if (ret) return ret; @@ -2108,7 +2096,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) continue; - ret = dpcm_do_trigger(dpcm, be_substream, cmd); + ret = soc_pcm_trigger(be_substream, cmd); if (ret) return ret; @@ -2122,7 +2110,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) continue; - ret = dpcm_do_trigger(dpcm, be_substream, cmd); + ret = soc_pcm_trigger(be_substream, cmd); if (ret) return ret; @@ -2135,7 +2123,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) continue; - ret = dpcm_do_trigger(dpcm, be_substream, cmd); + ret = soc_pcm_trigger(be_substream, cmd); if (ret) return ret; @@ -2148,7 +2136,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) continue; - ret = dpcm_do_trigger(dpcm, be_substream, cmd); + ret = soc_pcm_trigger(be_substream, cmd); if (ret) return ret; -- cgit v1.2.3 From 6374f493d93b2232444b94989c380d5aada5b810 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 1 Dec 2020 08:51:33 +0900 Subject: ASoC: soc-pcm: care trigger rollback soc_pcm_trigger() calls DAI/Component/Link trigger, but some of them might be failed. static int soc_pcm_trigger(...) { ... switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ret = snd_soc_link_trigger(substream, cmd); if (ret < 0) break; (*) ret = snd_soc_pcm_component_trigger(substream, cmd); if (ret < 0) break; ret = snd_soc_pcm_dai_trigger(substream, cmd); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ret = snd_soc_pcm_dai_trigger(substream, cmd); if (ret < 0) break; ret = snd_soc_pcm_component_trigger(substream, cmd); if (ret < 0) break; ret = snd_soc_link_trigger(substream, cmd); break; } ... } For example, if soc_pcm_trigger() failed at (*) point, we need to rollback previous succeeded trigger. This patch adds trigger mark for DAI/Component/Link, and do STOP if START/RESUME/PAUSE_RELEASE were failed. Because it need to use new rollback parameter, we need to modify DAI/Component/Link trigger functions in the same time. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a6uycssd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 3 ++- include/sound/soc-dai.h | 4 +++- include/sound/soc-link.h | 3 ++- include/sound/soc.h | 1 + sound/soc/soc-component.c | 45 +++++++++++++++++++++++++++++++++++-------- sound/soc/soc-dai.c | 44 ++++++++++++++++++++++++++++++++++-------- sound/soc/soc-link.c | 30 ++++++++++++++++++++++++++++- sound/soc/soc-pcm.c | 42 +++++++++++++++++++++++++++++++--------- 8 files changed, 143 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 9140b5fa19a4..0bce41fefd30 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -221,6 +221,7 @@ struct snd_soc_component { struct snd_pcm_substream *mark_module; struct snd_pcm_substream *mark_open; struct snd_pcm_substream *mark_hw_params; + struct snd_pcm_substream *mark_trigger; struct snd_compr_stream *mark_compr_open; void *mark_pm; @@ -486,7 +487,7 @@ int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream, void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, int rollback); int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream, - int cmd); + int cmd, int rollback); int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd, void *stream); void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd, diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 6f54401d3de9..34d0dbf73ca9 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -189,7 +189,8 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order); int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order); int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd); int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream); -int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd); +int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd, + int rollback); int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream, int cmd); @@ -401,6 +402,7 @@ struct snd_soc_dai { /* function mark */ struct snd_pcm_substream *mark_startup; struct snd_pcm_substream *mark_hw_params; + struct snd_pcm_substream *mark_trigger; struct snd_compr_stream *mark_compr_startup; /* bit field */ diff --git a/include/sound/soc-link.h b/include/sound/soc-link.h index 4c68b06d6fe6..9314cde1756b 100644 --- a/include/sound/soc-link.h +++ b/include/sound/soc-link.h @@ -21,8 +21,9 @@ int snd_soc_link_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback); -int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd); +int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd, + int rollback); int snd_soc_link_compr_startup(struct snd_compr_stream *cstream); void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream, int rollback); diff --git a/include/sound/soc.h b/include/sound/soc.h index b51e96121fa1..3fa6c40a63b7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1042,6 +1042,7 @@ struct snd_soc_pcm_runtime { /* function mark */ struct snd_pcm_substream *mark_startup; struct snd_pcm_substream *mark_hw_params; + struct snd_pcm_substream *mark_trigger; struct snd_compr_stream *mark_compr_startup; /* bit field */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 434987a64353..760523382f3c 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -1075,22 +1075,51 @@ void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, } } +static int soc_component_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int cmd) +{ + int ret = 0; + + if (component->driver->trigger) + ret = component->driver->trigger(component, substream, cmd); + + return soc_component_ret(component, ret); +} + int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream, - int cmd) + int cmd, int rollback) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component; - int i, ret; - - for_each_rtd_components(rtd, i, component) { - if (component->driver->trigger) { - ret = component->driver->trigger(component, substream, cmd); + int i, r, ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + for_each_rtd_components(rtd, i, component) { + ret = soc_component_trigger(component, substream, cmd); if (ret < 0) - return soc_component_ret(component, ret); + break; + soc_component_mark_push(component, substream, trigger); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + for_each_rtd_components(rtd, i, component) { + if (rollback && !soc_component_mark_match(component, substream, trigger)) + continue; + + r = soc_component_trigger(component, substream, cmd); + if (r < 0) + ret = r; /* use last ret */ + soc_component_mark_pop(component, substream, trigger); } } - return 0; + return ret; } int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 9afc6e8c3f9f..cd3bb9a7983f 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -564,23 +564,51 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream) return 0; } +static int soc_dai_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd) +{ + int ret = 0; + + if (dai->driver->ops && + dai->driver->ops->trigger) + ret = dai->driver->ops->trigger(substream, cmd, dai); + + return soc_dai_ret(dai, ret); +} + int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, - int cmd) + int cmd, int rollback) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *dai; - int i, ret; + int i, r, ret = 0; - for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->ops && - dai->driver->ops->trigger) { - ret = dai->driver->ops->trigger(substream, cmd, dai); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + for_each_rtd_dais(rtd, i, dai) { + ret = soc_dai_trigger(dai, substream, cmd); if (ret < 0) - return soc_dai_ret(dai, ret); + break; + soc_dai_mark_push(dai, substream, trigger); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + for_each_rtd_dais(rtd, i, dai) { + if (rollback && !soc_dai_mark_match(dai, substream, trigger)) + continue; + + r = soc_dai_trigger(dai, substream, cmd); + if (r < 0) + ret = r; /* use last ret */ + soc_dai_mark_pop(dai, substream, trigger); } } - return 0; + return ret; } int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index 26cc60f8dcfb..619664cc9ab9 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -141,7 +141,7 @@ void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback) soc_link_mark_pop(rtd, substream, hw_params); } -int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd) +static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); int ret = 0; @@ -153,6 +153,34 @@ int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd) return soc_link_ret(rtd, ret); } +int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd, + int rollback) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = soc_link_trigger(substream, cmd); + if (ret < 0) + break; + soc_link_mark_push(rtd, substream, trigger); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (rollback && !soc_link_mark_match(rtd, substream, trigger)) + break; + + ret = soc_link_trigger(substream, cmd); + soc_link_mark_pop(rtd, substream, startup); + } + + return ret; +} + int snd_soc_link_compr_startup(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 707c1a49f6b2..ee51dc7fd893 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1012,37 +1012,61 @@ out: static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - int ret = -EINVAL; + int ret = -EINVAL, _ret = 0; + int rollback = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = snd_soc_link_trigger(substream, cmd); + ret = snd_soc_link_trigger(substream, cmd, 0); if (ret < 0) - break; + goto start_err; + + ret = snd_soc_pcm_component_trigger(substream, cmd, 0); + if (ret < 0) + goto start_err; - ret = snd_soc_pcm_component_trigger(substream, cmd); + ret = snd_soc_pcm_dai_trigger(substream, cmd, 0); +start_err: if (ret < 0) + rollback = 1; + } + + if (rollback) { + _ret = ret; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + cmd = SNDRV_PCM_TRIGGER_STOP; + break; + case SNDRV_PCM_TRIGGER_RESUME: + cmd = SNDRV_PCM_TRIGGER_SUSPEND; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH; break; + } + } - ret = snd_soc_pcm_dai_trigger(substream, cmd); - break; + switch (cmd) { case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = snd_soc_pcm_dai_trigger(substream, cmd); + ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback); if (ret < 0) break; - ret = snd_soc_pcm_component_trigger(substream, cmd); + ret = snd_soc_pcm_component_trigger(substream, cmd, rollback); if (ret < 0) break; - ret = snd_soc_link_trigger(substream, cmd); + ret = snd_soc_link_trigger(substream, cmd, rollback); break; } + if (_ret) + ret = _ret; + return ret; } -- cgit v1.2.3 From ad13c835442cdb2a964588fd03327f51dbcd4dfa Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 7 Dec 2020 12:53:33 +0000 Subject: ASoC: codecs/jz47xx: Use regmap_{set,clear}_bits Use regmap_{set,clear}_bits instead of regmap_update_bits, when applicable. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20201207125338.119397-1-paul@crapouillou.net Signed-off-by: Mark Brown --- sound/soc/codecs/jz4725b.c | 26 +++++++------- sound/soc/codecs/jz4740.c | 20 ++++------- sound/soc/codecs/jz4770.c | 85 ++++++++++++++++++++-------------------------- 3 files changed, 55 insertions(+), 76 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index e49374c72e70..5201a8f6d7b6 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -198,15 +198,15 @@ static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR, - BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 0); + return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR, + BIT(REG_IFR_RAMP_UP_DONE_OFFSET)); case SND_SOC_DAPM_POST_PMU: return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR, val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 100000, 500000); case SND_SOC_DAPM_PRE_PMD: - return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR, - BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), 0); + return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR, + BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET)); case SND_SOC_DAPM_POST_PMD: return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR, val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), @@ -303,24 +303,22 @@ static int jz4725b_codec_set_bias_level(struct snd_soc_component *component, switch (level) { case SND_SOC_BIAS_ON: - regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, - BIT(REG_PMR2_SB_SLEEP_OFFSET), 0); + regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_SLEEP_OFFSET)); break; case SND_SOC_BIAS_PREPARE: /* Enable sound hardware */ - regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, - BIT(REG_PMR2_SB_OFFSET), 0); + regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_OFFSET)); msleep(224); break; case SND_SOC_BIAS_STANDBY: - regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, - BIT(REG_PMR2_SB_SLEEP_OFFSET), - BIT(REG_PMR2_SB_SLEEP_OFFSET)); + regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_SLEEP_OFFSET)); break; case SND_SOC_BIAS_OFF: - regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, - BIT(REG_PMR2_SB_OFFSET), - BIT(REG_PMR2_SB_OFFSET)); + regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_OFFSET)); break; } diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index c9900d1cd5c2..5e58bfee2b49 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -219,12 +219,11 @@ static struct snd_soc_dai_driver jz4740_codec_dai = { static void jz4740_codec_wakeup(struct regmap *regmap) { - regmap_update_bits(regmap, JZ4740_REG_CODEC_1, - JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET); + regmap_set_bits(regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_RESET); udelay(2); - regmap_update_bits(regmap, JZ4740_REG_CODEC_1, - JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0); + regmap_clear_bits(regmap, JZ4740_REG_CODEC_1, + JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET); regcache_sync(regmap); } @@ -235,7 +234,6 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component, struct jz4740_codec *jz4740_codec = snd_soc_component_get_drvdata(component); struct regmap *regmap = jz4740_codec->regmap; unsigned int mask; - unsigned int value; switch (level) { case SND_SOC_BIAS_ON: @@ -244,9 +242,8 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component, mask = JZ4740_CODEC_1_VREF_DISABLE | JZ4740_CODEC_1_VREF_AMP_DISABLE | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; - value = 0; - regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); + regmap_clear_bits(regmap, JZ4740_REG_CODEC_1, mask); break; case SND_SOC_BIAS_STANDBY: /* The only way to clear the suspend flag is to reset the codec */ @@ -256,17 +253,12 @@ static int jz4740_codec_set_bias_level(struct snd_soc_component *component, mask = JZ4740_CODEC_1_VREF_DISABLE | JZ4740_CODEC_1_VREF_AMP_DISABLE | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; - value = JZ4740_CODEC_1_VREF_DISABLE | - JZ4740_CODEC_1_VREF_AMP_DISABLE | - JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; - regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); + regmap_set_bits(regmap, JZ4740_REG_CODEC_1, mask); break; case SND_SOC_BIAS_OFF: mask = JZ4740_CODEC_1_SUSPEND; - value = JZ4740_CODEC_1_SUSPEND; - - regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); + regmap_set_bits(regmap, JZ4740_REG_CODEC_1, mask); regcache_mark_dirty(regmap); break; default: diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index 298689a07168..c6b2043f31a9 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -190,18 +190,18 @@ static int jz4770_codec_set_bias_level(struct snd_soc_component *codec, switch (level) { case SND_SOC_BIAS_PREPARE: - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC, - REG_CR_VIC_SB, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_VIC, + REG_CR_VIC_SB); msleep(250); - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC, - REG_CR_VIC_SB_SLEEP, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_VIC, + REG_CR_VIC_SB_SLEEP); msleep(400); break; case SND_SOC_BIAS_STANDBY: - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC, - REG_CR_VIC_SB_SLEEP, REG_CR_VIC_SB_SLEEP); - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC, - REG_CR_VIC_SB, REG_CR_VIC_SB); + regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_VIC, + REG_CR_VIC_SB_SLEEP); + regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_VIC, + REG_CR_VIC_SB); fallthrough; default: break; @@ -292,8 +292,8 @@ static int jz4770_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direc } /* clear GUP/GDO flag */ - regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR, - gain_bit, gain_bit); + regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR, + gain_bit); } return 0; @@ -369,8 +369,8 @@ static int hpout_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: /* set cap-less, unmute HP */ - regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP, - REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE, 0); + regmap_clear_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP, + REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE); break; case SND_SOC_DAPM_POST_PMU: @@ -385,16 +385,15 @@ static int hpout_event(struct snd_soc_dapm_widget *w, } /* clear RUP flag */ - regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR, - REG_IFR_RUP, REG_IFR_RUP); + regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR, + REG_IFR_RUP); break; case SND_SOC_DAPM_POST_PMD: /* set cap-couple, mute HP */ - regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP, - REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE, - REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE); + regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP, + REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE); err = regmap_read_poll_timeout(jz_codec->regmap, JZ4770_CODEC_REG_IFR, @@ -406,8 +405,8 @@ static int hpout_event(struct snd_soc_dapm_widget *w, } /* clear RDO flag */ - regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR, - REG_IFR_RDO, REG_IFR_RDO); + regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR, + REG_IFR_RDO); break; } @@ -592,63 +591,53 @@ static void jz4770_codec_codec_init_regs(struct snd_soc_component *codec) regcache_cache_only(regmap, true); /* default HP output to PCM */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP, - REG_CR_HP_SEL_MASK, REG_CR_HP_SEL_MASK); + regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_HP, REG_CR_HP_SEL_MASK); /* default line output to PCM */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_LO, - REG_CR_LO_SEL_MASK, REG_CR_LO_SEL_MASK); + regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_LO, REG_CR_LO_SEL_MASK); /* Disable stereo mic */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_MIC, - BIT(REG_CR_MIC_STEREO_OFFSET), 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_MIC, + BIT(REG_CR_MIC_STEREO_OFFSET)); /* Set mic 1 as default source for ADC */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_ADC, - REG_CR_ADC_IN_SEL_MASK, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_ADC, + REG_CR_ADC_IN_SEL_MASK); /* ADC/DAC: serial + i2s */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_AICR_ADC, - REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S, - REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S); - regmap_update_bits(regmap, JZ4770_CODEC_REG_AICR_DAC, - REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S, - REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S); + regmap_set_bits(regmap, JZ4770_CODEC_REG_AICR_ADC, + REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S); + regmap_set_bits(regmap, JZ4770_CODEC_REG_AICR_DAC, + REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S); /* The generated IRQ is a high level */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_ICR, - REG_ICR_INT_FORM_MASK, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_ICR, REG_ICR_INT_FORM_MASK); regmap_update_bits(regmap, JZ4770_CODEC_REG_IMR, REG_IMR_ALL_MASK, REG_IMR_JACK_MASK | REG_IMR_RUP_MASK | REG_IMR_RDO_MASK | REG_IMR_GUP_MASK | REG_IMR_GDO_MASK); /* 12M oscillator */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CCR, - REG_CCR_CRYSTAL_MASK, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CCR, REG_CCR_CRYSTAL_MASK); /* 0: 16ohm/220uF, 1: 10kohm/1uF */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP, - REG_CR_HP_LOAD, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_HP, REG_CR_HP_LOAD); /* disable automatic gain */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_AGC1, REG_AGC1_EN, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_AGC1, REG_AGC1_EN); /* Disable DAC lrswap */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_DAC, - REG_CR_DAC_LRSWAP, REG_CR_DAC_LRSWAP); + regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_DAC, REG_CR_DAC_LRSWAP); /* Independent L/R DAC gain control */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_GCR_DACL, - REG_GCR_DACL_RLGOD, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_GCR_DACL, + REG_GCR_DACL_RLGOD); /* Disable ADC lrswap */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_ADC, - REG_CR_ADC_LRSWAP, REG_CR_ADC_LRSWAP); + regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_ADC, REG_CR_ADC_LRSWAP); /* default to cap-less mode(0) */ - regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP, - REG_CR_HP_SB_HPCM, 0); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_HP, REG_CR_HP_SB_HPCM); /* Send collected updates. */ regcache_cache_only(regmap, false); -- cgit v1.2.3 From a346c77836183f6e3e054c5da022e0fde2773683 Mon Sep 17 00:00:00 2001 From: Christophe Branchereau Date: Mon, 7 Dec 2020 12:53:34 +0000 Subject: ASoC: codecs/jz4770: Reset interrupt flags in bias PREPARE In case a poll for RUP times out, we might be left with some IRQ flags that should be cleared before the next power on. Signed-off-by: Christophe Branchereau Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20201207125338.119397-2-paul@crapouillou.net Signed-off-by: Mark Brown --- sound/soc/codecs/jz4770.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index c6b2043f31a9..002f2300e750 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -190,6 +190,9 @@ static int jz4770_codec_set_bias_level(struct snd_soc_component *codec, switch (level) { case SND_SOC_BIAS_PREPARE: + /* Reset all interrupt flags. */ + regmap_write(regmap, JZ4770_CODEC_REG_IFR, REG_IFR_ALL_MASK); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_VIC, REG_CR_VIC_SB); msleep(250); @@ -642,9 +645,6 @@ static void jz4770_codec_codec_init_regs(struct snd_soc_component *codec) /* Send collected updates. */ regcache_cache_only(regmap, false); regcache_sync(regmap); - - /* Reset all interrupt flags. */ - regmap_write(regmap, JZ4770_CODEC_REG_IFR, REG_IFR_ALL_MASK); } static int jz4770_codec_codec_probe(struct snd_soc_component *codec) -- cgit v1.2.3 From 6b4da5374b10a48be18df26288125746f1858507 Mon Sep 17 00:00:00 2001 From: Christophe Branchereau Date: Mon, 7 Dec 2020 12:53:35 +0000 Subject: ASoC: codecs/jz4770: Adjust timeouts for cap-coupled outputs When using cap-coupled outputs, the RUP/RDO can take much longer than the 100ms timeout we used to have. Increase that timeout to one second. Signed-off-by: Christophe Branchereau Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20201207125338.119397-3-paul@crapouillou.net Signed-off-by: Mark Brown --- sound/soc/codecs/jz4770.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index 002f2300e750..0da966785aee 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -287,7 +287,7 @@ static int jz4770_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direc err = regmap_read_poll_timeout(jz_codec->regmap, JZ4770_CODEC_REG_IFR, val, val & gain_bit, - 1000, 100 * USEC_PER_MSEC); + 1000, 1 * USEC_PER_SEC); if (err) { dev_err(jz_codec->dev, "Timeout while setting digital mute: %d", err); @@ -381,7 +381,7 @@ static int hpout_event(struct snd_soc_dapm_widget *w, err = regmap_read_poll_timeout(jz_codec->regmap, JZ4770_CODEC_REG_IFR, val, val & REG_IFR_RUP, - 1000, 100 * USEC_PER_MSEC); + 1000, 1 * USEC_PER_SEC); if (err) { dev_err(jz_codec->dev, "RUP timeout: %d", err); return err; @@ -401,7 +401,7 @@ static int hpout_event(struct snd_soc_dapm_widget *w, err = regmap_read_poll_timeout(jz_codec->regmap, JZ4770_CODEC_REG_IFR, val, val & REG_IFR_RDO, - 1000, 100 * USEC_PER_MSEC); + 1000, 1 * USEC_PER_SEC); if (err) { dev_err(jz_codec->dev, "RDO timeout: %d", err); return err; @@ -803,7 +803,7 @@ static int jz4770_codec_io_wait(struct jz_codec *codec) return readl_poll_timeout(codec->base + ICDC_RGADW_OFFSET, reg, !(reg & ICDC_RGADW_RGWR), - 1000, 10 * USEC_PER_MSEC); + 1000, 1 * USEC_PER_SEC); } static int jz4770_codec_reg_read(void *context, unsigned int reg, -- cgit v1.2.3 From 4f293dfea9f6d23a972be0e38556f5b0c02c2d4e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 7 Dec 2020 12:53:36 +0000 Subject: ASoC: codecs/jz4770: Don't change cap-couple setting in HP PMU/PMD There is simply no reason to do that. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20201207125338.119397-4-paul@crapouillou.net Signed-off-by: Mark Brown --- sound/soc/codecs/jz4770.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index 0da966785aee..909b70e817b4 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -371,9 +371,9 @@ static int hpout_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - /* set cap-less, unmute HP */ + /* unmute HP */ regmap_clear_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP, - REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE); + REG_CR_HP_MUTE); break; case SND_SOC_DAPM_POST_PMU: @@ -394,9 +394,9 @@ static int hpout_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: - /* set cap-couple, mute HP */ + /* mute HP */ regmap_set_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP, - REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE); + REG_CR_HP_MUTE); err = regmap_read_poll_timeout(jz_codec->regmap, JZ4770_CODEC_REG_IFR, -- cgit v1.2.3 From e648e3f1165354f04a4deed1f41152a287b68d59 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 7 Dec 2020 12:53:37 +0000 Subject: ASoC: codecs/jz4770: Add DAPM widget to set HP out to cap-less mode Cap-less mode is useful e.g. if the headphones are used as an antenna for a FM radio, so that the signal is not altered. For everything else, we want the cap-couple mode. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20201207125338.119397-5-paul@crapouillou.net Signed-off-by: Mark Brown --- sound/soc/codecs/jz4770.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index 909b70e817b4..c9fe7f72bfcb 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -98,7 +98,7 @@ enum { #define REG_CR_HP_MUTE BIT(7) #define REG_CR_HP_LOAD BIT(6) #define REG_CR_HP_SB_OFFSET 4 -#define REG_CR_HP_SB_HPCM BIT(3) +#define REG_CR_HP_SB_HPCM_OFFSET 3 #define REG_CR_HP_SEL_OFFSET 0 #define REG_CR_HP_SEL_MASK (0x3 << REG_CR_HP_SEL_OFFSET) @@ -519,6 +519,9 @@ static const struct snd_soc_dapm_widget jz4770_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("MICBIAS", JZ4770_CODEC_REG_CR_MIC, REG_CR_MIC_BIAS_SB_OFFSET, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Cap-less", JZ4770_CODEC_REG_CR_HP, + REG_CR_HP_SB_HPCM_OFFSET, 1, NULL, 0), + SND_SOC_DAPM_INPUT("MIC1P"), SND_SOC_DAPM_INPUT("MIC1N"), SND_SOC_DAPM_INPUT("MIC2P"), @@ -640,7 +643,8 @@ static void jz4770_codec_codec_init_regs(struct snd_soc_component *codec) regmap_set_bits(regmap, JZ4770_CODEC_REG_CR_ADC, REG_CR_ADC_LRSWAP); /* default to cap-less mode(0) */ - regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_HP, REG_CR_HP_SB_HPCM); + regmap_clear_bits(regmap, JZ4770_CODEC_REG_CR_HP, + BIT(REG_CR_HP_SB_HPCM_OFFSET)); /* Send collected updates. */ regcache_cache_only(regmap, false); -- cgit v1.2.3 From 397e089bda327a350c1cb29133cb66795339a5d9 Mon Sep 17 00:00:00 2001 From: Derek Fang Date: Wed, 9 Dec 2020 17:13:08 +0800 Subject: ASoC: rt1015: check the return value of regmap_read during i2c probe In some projects, the device ID register is not read correctly. This patch helps to verify the issue is caused from i2c host or client. Signed-off-by: Derek Fang Link: https://lore.kernel.org/r/20201209091308.2823-1-derek.fang@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index ac4c9f43b338..32e6bcf763d1 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -1207,8 +1207,13 @@ static int rt1015_i2c_probe(struct i2c_client *i2c, rt1015->hw_config = (i2c->addr == 0x29) ? RT1015_HW_29 : RT1015_HW_28; - regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val); - if ((val != RT1015_DEVICE_ID_VAL) && (val != RT1015_DEVICE_ID_VAL2)) { + ret = regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val); + if (ret) { + dev_err(&i2c->dev, + "Failed to read device register: %d\n", ret); + return ret; + } else if ((val != RT1015_DEVICE_ID_VAL) && + (val != RT1015_DEVICE_ID_VAL2)) { dev_err(&i2c->dev, "Device with ID register %x is not rt1015\n", val); return -ENODEV; -- cgit v1.2.3 From 718c406e1ffaca4eac987b957bbb36ce1090797a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 8 Dec 2020 18:12:00 +0100 Subject: ASoC: AMD Renoir - add DMI table to avoid the ACP mic probe (broken BIOS) Users reported that some Lenovo AMD platforms do not have ACP microphone, but the BIOS advertises it via ACPI. This patch create a simple DMI table, where those machines with the broken BIOS can be added. The DMI description for Lenovo IdeaPad 5 and IdeaPad Flex 5 devices are added there. Also describe the dmic_acpi_check kernel module parameter in a more understandable way. Cc: Cc: Vijendar Mukunda Cc: Mark Brown Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20201208171200.2737620-1-perex@perex.cz Signed-off-by: Mark Brown --- sound/soc/amd/renoir/rn-pci-acp3x.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index d9e6e49bff01..fa169bf09886 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -20,14 +21,13 @@ module_param(acp_power_gating, int, 0644); MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating"); /** - * dmic_acpi_check = -1 - Checks ACPI method to know DMIC hardware status runtime - * = 0 - Skips the DMIC device creation and returns probe failure - * = 1 - Assumes that platform has DMIC support and skips ACPI - * method check + * dmic_acpi_check = -1 - Use ACPI/DMI method to detect the DMIC hardware presence at runtime + * = 0 - Skip the DMIC device creation and return probe failure + * = 1 - Force DMIC support */ static int dmic_acpi_check = ACP_DMIC_AUTO; module_param(dmic_acpi_check, bint, 0644); -MODULE_PARM_DESC(dmic_acpi_check, "checks Dmic hardware runtime"); +MODULE_PARM_DESC(dmic_acpi_check, "Digital microphone presence (-1=auto, 0=none, 1=force)"); struct acp_dev_data { void __iomem *acp_base; @@ -163,6 +163,17 @@ static int rn_acp_deinit(void __iomem *acp_base) return 0; } +static const struct dmi_system_id rn_acp_quirk_table[] = { + { + /* Lenovo IdeaPad Flex 5 14ARE05, IdeaPad 5 15ARE05 */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "LNVNB161216"), + } + }, + {} +}; + static int snd_rn_acp_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -172,6 +183,7 @@ static int snd_rn_acp_probe(struct pci_dev *pci, acpi_handle handle; acpi_integer dmic_status; #endif + const struct dmi_system_id *dmi_id; unsigned int irqflags; int ret, index; u32 addr; @@ -236,6 +248,12 @@ static int snd_rn_acp_probe(struct pci_dev *pci, goto de_init; } #endif + dmi_id = dmi_first_match(rn_acp_quirk_table); + if (dmi_id && !dmi_id->driver_data) { + dev_info(&pci->dev, "ACPI settings override using DMI (ACP mic is not present)"); + ret = -ENODEV; + goto de_init; + } } adata->res = devm_kzalloc(&pci->dev, -- cgit v1.2.3 From 4c8a4cab331d53fad39f3c5823428d8cea92d994 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 9 Dec 2020 17:31:01 +0200 Subject: ASoC: Intel: common: add ACPI matching tables for Alder Lake Initial support for ADL w/ RT711 Signed-off-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20201209153102.3028310-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 2 + sound/soc/intel/common/Makefile | 2 +- sound/soc/intel/common/soc-acpi-intel-adl-match.c | 52 +++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-adl-match.c (limited to 'sound') diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 5c49e7d78002..59551b1f22f3 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -29,12 +29,14 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 64468fe9c513..12a205ccdeeb 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -8,7 +8,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-cnl-match.o soc-acpi-intel-cfl-match.o \ soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ - soc-acpi-intel-jsl-match.o \ + soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c new file mode 100644 index 000000000000..06b233d63b73 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-apci-intel-adl-match.c - tables and support for ADL ACPI enumeration. + * + * Copyright (c) 2020, Intel Corporation. + */ + +#include +#include + +static const struct snd_soc_acpi_endpoint single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, +}; + +static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { + { + .adr = 0x000020025D071100, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + +static const struct snd_soc_acpi_link_adr adl_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr_d = rt711_0_adr, + }, + {} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); + +/* this table is used when there is no I2S codec present */ +struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { + { + .link_mask = 0x1, /* link0 required */ + .links = adl_rvp, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-adl.ri", + .sof_tplg_filename = "sof-adl-rt711.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_sdw_machines); -- cgit v1.2.3 From ac6b7bd33ad66fef99579e87bca4af985e3a7715 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 9 Dec 2020 17:31:02 +0200 Subject: ASoC: SOF: Intel: add SoundWire support for ADL-S Expand SOF support for Alder Lake by adding ACPI machine tables for ADL-S systems with SoundWire codecs. Modify kernel config to choose SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE for these platforms. Signed-off-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20201209153102.3028310-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 1 + sound/soc/sof/sof-pci-dev.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index e6302bb03c55..d306c370e5d1 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -282,6 +282,7 @@ config SND_SOC_SOF_ALDERLAKE_SUPPORT config SND_SOC_SOF_ALDERLAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 153d66d5c948..63b989e3ec40 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -286,7 +286,8 @@ static const struct sof_dev_desc jsl_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) static const struct sof_dev_desc adls_desc = { - .machines = snd_soc_acpi_intel_hda_machines, + .machines = snd_soc_acpi_intel_adl_machines, + .alt_machines = snd_soc_acpi_intel_adl_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, -- cgit v1.2.3 From 342fbb7578d1741ff646d7b08e14e8753267b9fa Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 5 Dec 2020 01:15:08 +0100 Subject: ASoC: add simple-mux Add a driver for simple mux driven by gpios. It currently only supports one gpio, muxing one of two inputs to a single output. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201205001508.346439-2-alexandre.belloni@bootlin.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 ++ sound/soc/codecs/Makefile | 5 ++ sound/soc/codecs/simple-mux.c | 124 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 sound/soc/codecs/simple-mux.c (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 02e23e802b24..5e4e68112791 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -185,6 +185,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_SGTL5000 imply SND_SOC_SI476X imply SND_SOC_SIMPLE_AMPLIFIER + imply SND_SOC_SIMPLE_MUX imply SND_SOC_SIRF_AUDIO_CODEC imply SND_SOC_SPDIF imply SND_SOC_SSM2305 @@ -1266,6 +1267,10 @@ config SND_SOC_SIMPLE_AMPLIFIER tristate "Simple Audio Amplifier" select GPIOLIB +config SND_SOC_SIMPLE_MUX + tristate "Simple Audio Mux" + select GPIOLIB + config SND_SOC_SIRF_AUDIO_CODEC tristate "SiRF SoC internal audio codec" select REGMAP_MMIO diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index c9a80c3aeed0..f255ec74333c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -312,6 +312,8 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tas2552-objs := tas2552.o snd-soc-tas2562-objs := tas2562.o snd-soc-tas2764-objs := tas2764.o +# Mux +snd-soc-simple-mux-objs := simple-mux.o obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o @@ -627,3 +629,6 @@ obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO) += snd-soc-lpass-wsa-macro.o obj-$(CONFIG_SND_SOC_LPASS_VA_MACRO) += snd-soc-lpass-va-macro.o + +# Mux +obj-$(CONFIG_SND_SOC_SIMPLE_MUX) += snd-soc-simple-mux.o diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c new file mode 100644 index 000000000000..e0a09dadfa7c --- /dev/null +++ b/sound/soc/codecs/simple-mux.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 Bootlin SA + * Author: Alexandre Belloni + */ + +#include +#include +#include +#include + +struct simple_mux { + struct gpio_desc *gpiod_mux; + unsigned int mux; +}; + +static const char * const simple_mux_texts[] = { + "Input 1", "Input 2" +}; + +static SOC_ENUM_SINGLE_EXT_DECL(simple_mux_enum, simple_mux_texts); + +static int simple_mux_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + + ucontrol->value.enumerated.item[0] = priv->mux; + + return 0; +} + +static int simple_mux_control_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + + if (ucontrol->value.enumerated.item[0] > e->items) + return -EINVAL; + + if (priv->mux == ucontrol->value.enumerated.item[0]) + return 0; + + priv->mux = ucontrol->value.enumerated.item[0]; + + gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux); + + return snd_soc_dapm_mux_update_power(dapm, kcontrol, + ucontrol->value.enumerated.item[0], + e, NULL); +} + +static const struct snd_kcontrol_new simple_mux_mux = + SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put); + +static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("IN1"), + SND_SOC_DAPM_INPUT("IN2"), + SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux), + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route simple_mux_dapm_routes[] = { + { "OUT", NULL, "MUX" }, + { "MUX", "Input 1", "IN1" }, + { "MUX", "Input 2", "IN2" }, +}; + +static const struct snd_soc_component_driver simple_mux_component_driver = { + .dapm_widgets = simple_mux_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(simple_mux_dapm_widgets), + .dapm_routes = simple_mux_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(simple_mux_dapm_routes), +}; + +static int simple_mux_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct simple_mux *priv; + int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + priv->gpiod_mux = devm_gpiod_get(dev, "mux", GPIOD_OUT_LOW); + if (IS_ERR(priv->gpiod_mux)) { + err = PTR_ERR(priv->gpiod_mux); + if (err != -EPROBE_DEFER) + dev_err(dev, "Failed to get 'mux' gpio: %d", err); + return err; + } + + return devm_snd_soc_register_component(dev, &simple_mux_component_driver, NULL, 0); +} + +#ifdef CONFIG_OF +static const struct of_device_id simple_mux_ids[] = { + { .compatible = "simple-audio-mux", }, + { } +}; +MODULE_DEVICE_TABLE(of, simple_mux_ids); +#endif + +static struct platform_driver simple_mux_driver = { + .driver = { + .name = "simple-mux", + .of_match_table = of_match_ptr(simple_mux_ids), + }, + .probe = simple_mux_probe, +}; + +module_platform_driver(simple_mux_driver); + +MODULE_DESCRIPTION("ASoC Simple Audio Mux driver"); +MODULE_AUTHOR("Alexandre Belloni "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 2506318e382c4c7daa77bdc48f80a0ee82804588 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Dec 2020 16:01:19 +0100 Subject: ALSA: hda: Fix regressions on clear and reconfig sysfs It seems that the HD-audio clear and reconfig sysfs don't work any longer after the recent driver core change. There are multiple issues around that: the linked list corruption and the dead device handling. The former issue is fixed by another patch for the driver core itself, while the latter patch needs to be addressed in HD-audio side. This patch corresponds to the latter, it recovers those broken functions by replacing the device detach and attach actions with the standard core API functions, which are almost equivalent with unbind and bind actions. Fixes: 654888327e9f ("driver core: Avoid binding drivers to dead devices") Cc: BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=209207 Link: https://lore.kernel.org/r/20201209150119.7705-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/hda_sysfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4bb58e8b08a8..687216e74526 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1803,7 +1803,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) return -EBUSY; /* OK, let it free */ - snd_hdac_device_unregister(&codec->core); + device_release_driver(hda_codec_dev(codec)); /* allow device access again */ snd_hda_unlock_devices(bus); diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index eb8ec109d7ad..d5ffcba794e5 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -139,7 +139,7 @@ static int reconfig_codec(struct hda_codec *codec) "The codec is being used, can't reconfigure.\n"); goto error; } - err = snd_hda_codec_configure(codec); + err = device_reprobe(hda_codec_dev(codec)); if (err < 0) goto error; err = snd_card_register(codec->card); -- cgit v1.2.3 From c9a867fd845171e6845e6fd665c423fa910083d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Dec 2020 17:18:35 +0100 Subject: ALSA: usb-audio: Add implicit fb support for Steinberg UR22 Steinberg UR22 (with USB ID 0499:1509) requires the implicit feedback for the proper playback, otherwise it causes occasional cracks. This patch adds the corresponding the quirk table entry with the recently added generic implicit fb support. Reported-and-tested-by: Kilian Link: https://lore.kernel.org/r/20201209161835.13625-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 386198b36b87..4e911d200562 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -42,6 +42,7 @@ struct snd_usb_implicit_fb_match { /* Implicit feedback quirk table for playback */ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Generic matching */ + IMPLICIT_FB_GENERIC_DEV(0x0499, 0x1509), /* Steinberg UR22 */ IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2080), /* M-Audio FastTrack Ultra */ IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2081), /* M-Audio FastTrack Ultra */ IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2030), /* M-Audio Fast Track C400 */ -- cgit v1.2.3 From c697ba85a94b8f65bf90dec5ef9af5c39c3e73b2 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 10 Dec 2020 12:35:48 -0500 Subject: ALSA: hda/ca0132 - Fix AE-5 rear headphone pincfg. The Windows driver sets the pincfg for the AE-5's rear-headphone to report as a microphone. This causes issues with Pulseaudio mistakenly believing there is no headphone plugged in. In Linux, we should instead set it to be a headphone. Fixes: a6b0961b39896 ("ALSA: hda/ca0132 - fix AE-5 pincfg") Cc: Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201208195223.424753-1-conmanx360@gmail.com Link: https://lore.kernel.org/r/20201210173550.2968-1-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 4fbec4258f58..e96db73c32f5 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1223,7 +1223,7 @@ static const struct hda_pintbl ae5_pincfgs[] = { { 0x0e, 0x01c510f0 }, /* SPDIF In */ { 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */ { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */ - { 0x11, 0x01a170ff }, /* Port B -- LineMicIn2 / Rear Headphone */ + { 0x11, 0x012170ff }, /* Port B -- LineMicIn2 / Rear Headphone */ { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */ { 0x13, 0x908700f0 }, /* What U Hear In*/ { 0x18, 0x50d000f0 }, /* N/A */ -- cgit v1.2.3 From 7079f785b50055a32b72eddcb7d9ba5688db24d0 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 10 Dec 2020 12:35:49 -0500 Subject: ALSA: hda/ca0132 - Change Input Source enum strings. Change the Input Source enumerated control's strings to make it play nice with pulseaudio. Fixes: 7cb9d94c05de9 ("ALSA: hda/ca0132: add alt_select_in/out for R3Di + SBZ") Cc: Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201208195223.424753-2-conmanx360@gmail.com Link: https://lore.kernel.org/r/20201210173550.2968-2-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index e96db73c32f5..793dc5d501a5 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -95,7 +95,7 @@ enum { }; /* Strings for Input Source Enum Control */ -static const char *const in_src_str[3] = {"Rear Mic", "Line", "Front Mic" }; +static const char *const in_src_str[3] = { "Microphone", "Line In", "Front Microphone" }; #define IN_SRC_NUM_OF_INPUTS 3 enum { REAR_MIC, -- cgit v1.2.3 From b1a5039759cb7bfcb2157f28604dbda0bca58598 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 10 Dec 2020 19:44:45 +0200 Subject: ALSA: hda/hdmi: fix silent stream for first playback to DP A problem exists in enabling silent stream when connection type is DisplayPort. Silent stream programming is completed when a new DP receiver is connected, but infoframe transmission does not actually start until PCM is opened for the first time. This can result in audible gap of multiple seconds. This only affects the first PCM open. Fix the issue by properly assigning a converter to the silent stream, and modifying the required stream ID programming sequence. This change only affects Intel display audio codecs. BugLink: https://github.com/thesofproject/linux/issues/2468 Fixes: 951894cf30f4 ("ALSA: hda/hdmi: Add Intel silent stream support") Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201210174445.3134104-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 98 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index b0068f8ca46d..2ddc27db8c01 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -78,6 +78,7 @@ struct hdmi_spec_per_pin { int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */ int repoll_count; bool setup; /* the stream has been set up by prepare callback */ + bool silent_stream; int channels; /* current number of channels */ bool non_pcm; bool chmap_set; /* channel-map override by ALSA API? */ @@ -979,6 +980,13 @@ static int hdmi_choose_cvt(struct hda_codec *codec, else per_pin = get_pin(spec, pin_idx); + if (per_pin && per_pin->silent_stream) { + cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid); + if (cvt_id) + *cvt_id = cvt_idx; + return 0; + } + /* Dynamically assign converter to stream */ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { per_cvt = get_cvt(spec, cvt_idx); @@ -1642,30 +1650,95 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, snd_hda_power_down_pm(codec); } +#define I915_SILENT_RATE 48000 +#define I915_SILENT_CHANNELS 2 +#define I915_SILENT_FORMAT SNDRV_PCM_FORMAT_S16_LE +#define I915_SILENT_FORMAT_BITS 16 +#define I915_SILENT_FMT_MASK 0xf + static void silent_stream_enable(struct hda_codec *codec, - struct hdmi_spec_per_pin *per_pin) + struct hdmi_spec_per_pin *per_pin) { - unsigned int newval, oldval; - - codec_dbg(codec, "hdmi: enabling silent stream for NID %d\n", - per_pin->pin_nid); + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt; + int cvt_idx, pin_idx, err; + unsigned int format; mutex_lock(&per_pin->lock); - if (!per_pin->channels) - per_pin->channels = 2; + if (per_pin->setup) { + codec_dbg(codec, "hdmi: PCM already open, no silent stream\n"); + goto unlock_out; + } - oldval = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_CONV, 0); - newval = (oldval & 0xF0) | 0xF; - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, newval); + pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id); + err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx); + if (err) { + codec_err(codec, "hdmi: no free converter to enable silent mode\n"); + goto unlock_out; + } + + per_cvt = get_cvt(spec, cvt_idx); + per_cvt->assigned = 1; + per_pin->cvt_nid = per_cvt->cvt_nid; + per_pin->silent_stream = true; + codec_dbg(codec, "hdmi: enabling silent stream pin-NID=0x%x cvt-NID=0x%x\n", + per_pin->pin_nid, per_cvt->cvt_nid); + + snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id); + snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0, + AC_VERB_SET_CONNECT_SEL, + per_pin->mux_idx); + + /* configure unused pins to choose other converters */ + pin_cvt_fixup(codec, per_pin, 0); + + snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid, + per_pin->dev_id, I915_SILENT_RATE); + + /* trigger silent stream generation in hw */ + format = snd_hdac_calc_stream_format(I915_SILENT_RATE, I915_SILENT_CHANNELS, + I915_SILENT_FORMAT, I915_SILENT_FORMAT_BITS, 0); + snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, + I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format); + usleep_range(100, 200); + snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format); + + per_pin->channels = I915_SILENT_CHANNELS; hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + unlock_out: mutex_unlock(&per_pin->lock); } +static void silent_stream_disable(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt; + int cvt_idx; + + mutex_lock(&per_pin->lock); + if (!per_pin->silent_stream) + goto unlock_out; + + codec_dbg(codec, "HDMI: disable silent stream on pin-NID=0x%x cvt-NID=0x%x\n", + per_pin->pin_nid, per_pin->cvt_nid); + + cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid); + if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) { + per_cvt = get_cvt(spec, cvt_idx); + per_cvt->assigned = 0; + } + + per_pin->cvt_nid = 0; + per_pin->silent_stream = false; + + unlock_out: + mutex_unlock(&spec->pcm_lock); +} + /* update ELD and jack state via audio component */ static void sync_eld_via_acomp(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin) @@ -1701,6 +1774,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec, pm_ret); silent_stream_enable(codec, per_pin); } else if (monitor_prev && !monitor_next) { + silent_stream_disable(codec, per_pin); pm_ret = snd_hda_power_down_pm(codec); if (pm_ret < 0) codec_err(codec, -- cgit v1.2.3 From 4a6d3b4e7ae77352fa4bd602ff0c44d8450705aa Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 10 Dec 2020 11:06:53 -0500 Subject: ALSA: hda/ca0132 - Reset codec upon initialization. Reset the codec upon initialization to clear out anything that may have been setup on a previous boot into Windows, or in case of an improper shutdown. Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201210160658.461739-2-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 793dc5d501a5..5ac3227fb579 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -8642,6 +8642,22 @@ static void ca0132_init_chip(struct hda_codec *codec) mutex_init(&spec->chipio_mutex); + /* + * The Windows driver always does this upon startup, which seems to + * clear out any previous configuration. This should help issues where + * a boot into Windows prior to a boot into Linux breaks things. Also, + * Windows always sends the reset twice. + */ + if (ca0132_use_alt_functions(spec)) { + chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0); + chipio_write_no_mutex(codec, 0x18b0a4, 0x000000c2); + + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_CODEC_RESET, 0); + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_CODEC_RESET, 0); + } + spec->cur_out_type = SPEAKER_OUT; if (!ca0132_use_alt_functions(spec)) spec->cur_mic_type = DIGITAL_MIC; @@ -9262,11 +9278,6 @@ static void ae5_register_set(struct hda_codec *codec) if (ca0132_quirk(spec) == QUIRK_AE5) ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); - - chipio_write(codec, 0x18b0a4, 0x000000c2); - - snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00); - snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00); } /* -- cgit v1.2.3 From aedeb64211f0d9ae2f71a0a132e402c26b358cdc Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 10 Dec 2020 11:06:54 -0500 Subject: ALSA: hda/ca0132 - Add stream port remapping function. Add function for remapping a ChipIO stream's ports. Also include some documentation as to how this works. Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201210160658.461739-3-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 208 ++++++++++++++++++++++++++++++++----------- 1 file changed, 156 insertions(+), 52 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 5ac3227fb579..200cc0f8ac0e 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -788,6 +788,40 @@ static const struct ae5_filter_set ae5_filter_presets[] = { } }; +/* + * Data structures for storing audio router remapping data. These are used to + * remap a currently active streams ports. + */ +struct chipio_stream_remap_data { + unsigned int stream_id; + unsigned int count; + + unsigned int offset[16]; + unsigned int value[16]; +}; + +static const struct chipio_stream_remap_data stream_remap_data[] = { + { .stream_id = 0x14, + .count = 0x04, + .offset = { 0x00, 0x04, 0x08, 0x0c }, + .value = { 0x0001f8c0, 0x0001f9c1, 0x0001fac6, 0x0001fbc7 }, + }, + { .stream_id = 0x0c, + .count = 0x0c, + .offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, + 0x20, 0x24, 0x28, 0x2c }, + .value = { 0x0001e0c0, 0x0001e1c1, 0x0001e4c2, 0x0001e5c3, + 0x0001e2c4, 0x0001e3c5, 0x0001e8c6, 0x0001e9c7, + 0x0001ecc8, 0x0001edc9, 0x0001eaca, 0x0001ebcb }, + }, + { .stream_id = 0x0c, + .count = 0x08, + .offset = { 0x08, 0x0c, 0x10, 0x14, 0x20, 0x24, 0x28, 0x2c }, + .value = { 0x000140c2, 0x000141c3, 0x000150c4, 0x000151c5, + 0x000142c8, 0x000143c9, 0x000152ca, 0x000153cb }, + } +}; + enum hda_cmd_vendor_io { /* for DspIO node */ VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, @@ -7423,6 +7457,104 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) } } +/* + * The region of ChipIO memory from 0x190000-0x1903fc is a sort of 'audio + * router', where each entry represents a 48khz audio channel, with a format + * of an 8-bit destination, an 8-bit source, and an unknown 2-bit number + * value. The 2-bit number value is seemingly 0 if inactive, 1 if active, + * and 3 if it's using Sample Rate Converter ports. + * An example is: + * 0x0001f8c0 + * In this case, f8 is the destination, and c0 is the source. The number value + * is 1. + * This region of memory is normally managed internally by the 8051, where + * the region of exram memory from 0x1477-0x1575 has each byte represent an + * entry within the 0x190000 range, and when a range of entries is in use, the + * ending value is overwritten with 0xff. + * 0x1578 in exram is a table of 0x25 entries, corresponding to the ChipIO + * streamID's, where each entry is a starting 0x190000 port offset. + * 0x159d in exram is the same as 0x1578, except it contains the ending port + * offset for the corresponding streamID. + * + * On certain cards, such as the SBZ/ZxR/AE7, these are originally setup by + * the 8051, then manually overwritten to remap the ports to work with the + * new DACs. + * + * Currently known portID's: + * 0x00-0x1f: HDA audio stream input/output ports. + * 0x80-0xbf: Sample rate converter input/outputs. Only valid ports seem to + * have the lower-nibble set to 0x1, 0x2, and 0x9. + * 0xc0-0xdf: DSP DMA input/output ports. Dynamically assigned. + * 0xe0-0xff: DAC/ADC audio input/output ports. + * + * Currently known streamID's: + * 0x03: Mic1 ADC to DSP. + * 0x04: Mic2 ADC to DSP. + * 0x05: HDA node 0x02 audio stream to DSP. + * 0x0f: DSP Mic exit to HDA node 0x07. + * 0x0c: DSP processed audio to DACs. + * 0x14: DAC0, front L/R. + * + * It is possible to route the HDA audio streams directly to the DAC and + * bypass the DSP entirely, with the only downside being that since the DSP + * does volume control, the only volume control you'll get is through PCM on + * the PC side, in the same way volume is handled for optical out. This may be + * useful for debugging. + */ +static void chipio_remap_stream(struct hda_codec *codec, + const struct chipio_stream_remap_data *remap_data) +{ + unsigned int i, stream_offset, tmp; + + /* Get the starting port for the stream to be remapped. */ + tmp = 0x1578 + remap_data->stream_id; + for (i = 0; i < 2; i++) { + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW + i, + ((tmp >> (i * 8)) & 0xff)); + } + + stream_offset = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_READ, 0); + + /* + * Check if the stream's port value is 0xff, because the 8051 may not + * have gotten around to setting up the stream yet. Wait until it's + * setup to remap it's ports. + */ + if (stream_offset == 0xff) { + for (i = 0; i < 5; i++) { + msleep(25); + + stream_offset = snd_hda_codec_read(codec, + WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_READ, 0); + + if (stream_offset != 0xff) + break; + } + } + + if (stream_offset == 0xff) { + codec_info(codec, "%s: Stream 0x%02x ports aren't allocated, remap failed!\n", + __func__, remap_data->stream_id); + return; + } + + /* Offset isn't in bytes, its in 32-bit words, so multiply it by 4. */ + stream_offset *= 0x04; + stream_offset += 0x190000; + + for (i = 0; i < remap_data->count; i++) { + chipio_write_no_mutex(codec, + stream_offset + remap_data->offset[i], + remap_data->value[i]); + } + + /* Update stream map configuration. */ + chipio_write_no_mutex(codec, 0x19042c, 0x00000001); +} + /* * Default speaker tuning values setup for alternative codecs. */ @@ -7570,46 +7702,35 @@ static void sbz_connect_streams(struct hda_codec *codec) */ static void sbz_chipio_startup_data(struct hda_codec *codec) { + const struct chipio_stream_remap_data *dsp_out_remap_data; struct ca0132_spec *spec = codec->spec; mutex_lock(&spec->chipio_mutex); codec_dbg(codec, "Startup Data entered, mutex locked and loaded.\n"); - /* These control audio output */ - chipio_write_no_mutex(codec, 0x190060, 0x0001f8c0); - chipio_write_no_mutex(codec, 0x190064, 0x0001f9c1); - chipio_write_no_mutex(codec, 0x190068, 0x0001fac6); - chipio_write_no_mutex(codec, 0x19006c, 0x0001fbc7); - /* Signal to update I think */ - chipio_write_no_mutex(codec, 0x19042c, 0x00000001); + /* Remap DAC0's output ports. */ + chipio_remap_stream(codec, &stream_remap_data[0]); - chipio_set_stream_channels(codec, 0x0C, 6); - chipio_set_stream_control(codec, 0x0C, 1); - /* No clue what these control */ - if (ca0132_quirk(spec) == QUIRK_SBZ) { - chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0); - chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1); - chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2); - chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3); - chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4); - chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5); - chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6); - chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7); - chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8); - chipio_write_no_mutex(codec, 0x190054, 0x0001edc9); - chipio_write_no_mutex(codec, 0x190058, 0x0001eaca); - chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb); - } else if (ca0132_quirk(spec) == QUIRK_ZXR) { - chipio_write_no_mutex(codec, 0x190038, 0x000140c2); - chipio_write_no_mutex(codec, 0x19003c, 0x000141c3); - chipio_write_no_mutex(codec, 0x190040, 0x000150c4); - chipio_write_no_mutex(codec, 0x190044, 0x000151c5); - chipio_write_no_mutex(codec, 0x190050, 0x000142c8); - chipio_write_no_mutex(codec, 0x190054, 0x000143c9); - chipio_write_no_mutex(codec, 0x190058, 0x000152ca); - chipio_write_no_mutex(codec, 0x19005c, 0x000153cb); + /* Remap DSP audio output stream ports. */ + switch (ca0132_quirk(spec)) { + case QUIRK_SBZ: + dsp_out_remap_data = &stream_remap_data[1]; + break; + + case QUIRK_ZXR: + dsp_out_remap_data = &stream_remap_data[2]; + break; + + default: + dsp_out_remap_data = NULL; + break; } - chipio_write_no_mutex(codec, 0x19042c, 0x00000001); + + chipio_set_stream_channels(codec, 0x0c, 6); + chipio_set_stream_control(codec, 0x0c, 1); + + if (dsp_out_remap_data) + chipio_remap_stream(codec, dsp_out_remap_data); codec_dbg(codec, "Startup Data exited, mutex released.\n"); mutex_unlock(&spec->chipio_mutex); @@ -7842,34 +7963,17 @@ static void ae5_post_dsp_startup_data(struct hda_codec *codec) mutex_unlock(&spec->chipio_mutex); } -static const unsigned int ae7_port_set_data[] = { - 0x0001e0c0, 0x0001e1c1, 0x0001e4c2, 0x0001e5c3, 0x0001e2c4, 0x0001e3c5, - 0x0001e8c6, 0x0001e9c7, 0x0001ecc8, 0x0001edc9, 0x0001eaca, 0x0001ebcb -}; - static void ae7_post_dsp_setup_ports(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - unsigned int i, count, addr; mutex_lock(&spec->chipio_mutex); chipio_set_stream_channels(codec, 0x0c, 6); chipio_set_stream_control(codec, 0x0c, 1); - count = ARRAY_SIZE(ae7_port_set_data); - addr = 0x190030; - for (i = 0; i < count; i++) { - chipio_write_no_mutex(codec, addr, ae7_port_set_data[i]); - - /* Addresses are incremented by 4-bytes. */ - addr += 0x04; - } - - /* - * Port setting always ends with a write of 0x1 to address 0x19042c. - */ - chipio_write_no_mutex(codec, 0x19042c, 0x00000001); + /* Seems to share the same port remapping as the SBZ. */ + chipio_remap_stream(codec, &stream_remap_data[1]); ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00); ca0113_mmio_command_set(codec, 0x48, 0x0d, 0x40); -- cgit v1.2.3 From 799c70639c002436cbf5962dff095692f1c50a70 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 10 Dec 2020 11:06:55 -0500 Subject: ALSA: hda/ca0132 - Add 8051 exram helper functions. Add functions for both reading and writing to the 8051's exram. Also, add a little bit of documentation on how the addresses are segmented. Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201210160658.461739-4-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 137 +++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 58 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 200cc0f8ac0e..f9fafd0f725b 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1901,6 +1901,70 @@ static void chipio_8051_write_direct(struct hda_codec *codec, snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, verb, addr); } +/* + * Writes to the 8051's exram, which has 16-bits of address space. + * Data at addresses 0x2000-0x7fff is mirrored to 0x8000-0xdfff. + * Data at 0x8000-0xdfff can also be used as program memory for the 8051 by + * setting the pmem bank selection SFR. + * 0xe000-0xffff is always mapped as program memory, with only 0xf000-0xffff + * being writable. + */ +static void chipio_8051_set_address(struct hda_codec *codec, unsigned int addr) +{ + unsigned int tmp; + + /* Lower 8-bits. */ + tmp = addr & 0xff; + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, tmp); + + /* Upper 8-bits. */ + tmp = (addr >> 8) & 0xff; + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_HIGH, tmp); +} + +static void chipio_8051_set_data(struct hda_codec *codec, unsigned int data) +{ + /* 8-bits of data. */ + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_WRITE, data & 0xff); +} + +static unsigned int chipio_8051_get_data(struct hda_codec *codec) +{ + return snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_READ, 0); +} + +static void chipio_8051_write_exram(struct hda_codec *codec, + unsigned int addr, unsigned int data) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + + chipio_8051_set_address(codec, addr); + chipio_8051_set_data(codec, data); + + mutex_unlock(&spec->chipio_mutex); +} + +static void chipio_8051_write_exram_no_mutex(struct hda_codec *codec, + unsigned int addr, unsigned int data) +{ + chipio_8051_set_address(codec, addr); + chipio_8051_set_data(codec, data); +} + +/* Readback data from the 8051's exram. No mutex. */ +static void chipio_8051_read_exram(struct hda_codec *codec, + unsigned int addr, unsigned int *data) +{ + chipio_8051_set_address(codec, addr); + *data = chipio_8051_get_data(codec); +} + /* * Enable clocks. */ @@ -7422,18 +7486,10 @@ static void ca0132_init_analog_mic2(struct hda_codec *codec) struct ca0132_spec *spec = codec->spec; mutex_lock(&spec->chipio_mutex); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x20); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_WRITE, 0x00); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x2D); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_WRITE, 0x00); + + chipio_8051_write_exram_no_mutex(codec, 0x1920, 0x00); + chipio_8051_write_exram_no_mutex(codec, 0x192d, 0x00); + mutex_unlock(&spec->chipio_mutex); } @@ -7504,18 +7560,11 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) static void chipio_remap_stream(struct hda_codec *codec, const struct chipio_stream_remap_data *remap_data) { - unsigned int i, stream_offset, tmp; + unsigned int i, stream_offset; /* Get the starting port for the stream to be remapped. */ - tmp = 0x1578 + remap_data->stream_id; - for (i = 0; i < 2; i++) { - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW + i, - ((tmp >> (i * 8)) & 0xff)); - } - - stream_offset = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_READ, 0); + chipio_8051_read_exram(codec, 0x1578 + remap_data->stream_id, + &stream_offset); /* * Check if the stream's port value is 0xff, because the 8051 may not @@ -7526,9 +7575,8 @@ static void chipio_remap_stream(struct hda_codec *codec, for (i = 0; i < 5; i++) { msleep(25); - stream_offset = snd_hda_codec_read(codec, - WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_READ, 0); + chipio_8051_read_exram(codec, 0x1578 + remap_data->stream_id, + &stream_offset); if (stream_offset != 0xff) break; @@ -7863,12 +7911,7 @@ static void ae5_post_dsp_param_setup(struct hda_codec *codec) snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83); chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x92); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0xfa); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_WRITE, 0x22); + chipio_8051_write_exram(codec, 0xfa92, 0x22); } static void ae5_post_dsp_pll_setup(struct hda_codec *codec) @@ -8134,12 +8177,7 @@ static void ae7_post_dsp_asi_setup(struct hda_codec *codec) chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0); snd_hda_codec_write(codec, 0x17, 0, 0x794, 0x00); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x92); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0xfa); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_WRITE, 0x22); + chipio_8051_write_exram(codec, 0xfa92, 0x22); ae7_post_dsp_pll_setup(codec); ae7_post_dsp_asi_stream_setup(codec); @@ -9133,12 +9171,7 @@ static void r3d_pre_dsp_setup(struct hda_codec *codec) { chipio_write(codec, 0x18b0a4, 0x000000c2); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x1E); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x1C); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_WRITE, 0x5B); + chipio_8051_write_exram(codec, 0x1c1e, 0x5b); snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44); @@ -9148,21 +9181,9 @@ static void r3di_pre_dsp_setup(struct hda_codec *codec) { chipio_write(codec, 0x18b0a4, 0x000000c2); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x1E); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x1C); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_WRITE, 0x5B); - - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x20); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_WRITE, 0x00); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_DATA_WRITE, 0x40); + chipio_8051_write_exram(codec, 0x1c1e, 0x5b); + chipio_8051_write_exram(codec, 0x1920, 0x00); + chipio_8051_write_exram(codec, 0x1921, 0x40); snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x04); -- cgit v1.2.3 From 8cb12b94c2e32137ab04b0c4d35582f4ae244622 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 10 Dec 2020 11:06:56 -0500 Subject: ALSA: hda/ca0132 - Ensure DSP is properly setup post-firmware download. Make sure that the DSP has no DMA channels allocated once the firmware is downloaded, and that the default audio streams in use by the DSP are setup in the correct order. Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201210160658.461739-5-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 119 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index f9fafd0f725b..c3ae9e4f715b 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1863,6 +1863,18 @@ static void chipio_set_stream_control(struct hda_codec *codec, CONTROL_PARAM_STREAM_CONTROL, enable); } +/* + * Get ChipIO audio stream's status. + */ +static void chipio_get_stream_control(struct hda_codec *codec, + int streamid, unsigned int *enable) +{ + chipio_set_control_param_no_mutex(codec, + CONTROL_PARAM_STREAM_ID, streamid); + *enable = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PARAM_GET, + CONTROL_PARAM_STREAM_CONTROL); +} /* * Set sampling rate of the connection point. NO MUTEX. @@ -7513,6 +7525,109 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) } } + +/* If there is an active channel for some reason, find it and free it. */ +static void ca0132_alt_free_active_dma_channels(struct hda_codec *codec) +{ + unsigned int i, tmp; + int status; + + /* Read active DSPDMAC channel register. */ + status = chipio_read(codec, DSPDMAC_CHNLSTART_MODULE_OFFSET, &tmp); + if (status >= 0) { + /* AND against 0xfff to get the active channel bits. */ + tmp = tmp & 0xfff; + + /* If there are no active channels, nothing to free. */ + if (!tmp) + return; + } else { + codec_dbg(codec, "%s: Failed to read active DSP DMA channel register.\n", + __func__); + return; + } + + /* + * Check each DSP DMA channel for activity, and if the channel is + * active, free it. + */ + for (i = 0; i < DSPDMAC_DMA_CFG_CHANNEL_COUNT; i++) { + if (dsp_is_dma_active(codec, i)) { + status = dspio_free_dma_chan(codec, i); + if (status < 0) + codec_dbg(codec, "%s: Failed to free active DSP DMA channel %d.\n", + __func__, i); + } + } +} + +/* + * In the case of CT_EXTENSIONS_ENABLE being set to 1, and the DSP being in + * use, audio is no longer routed directly to the DAC/ADC from the HDA stream. + * Instead, audio is now routed through the DSP's DMA controllers, which + * the DSP is tasked with setting up itself. Through debugging, it seems the + * cause of most of the no-audio on startup issues were due to improperly + * configured DSP DMA channels. + * + * Normally, the DSP configures these the first time an HDA audio stream is + * started post DSP firmware download. That is why creating a 'dummy' stream + * worked in fixing the audio in some cases. This works most of the time, but + * sometimes if a stream is started/stopped before the DSP can setup the DMA + * configuration registers, it ends up in a broken state. Issues can also + * arise if streams are started in an unusual order, i.e the audio output dma + * channel being sandwiched between the mic1 and mic2 dma channels. + * + * The solution to this is to make sure that the DSP has no DMA channels + * in use post DSP firmware download, and then to manually start each default + * DSP stream that uses the DMA channels. These are 0x0c, the audio output + * stream, 0x03, analog mic 1, and 0x04, analog mic 2. + */ +static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec) +{ + const unsigned int dsp_dma_stream_ids[] = { 0x0c, 0x03, 0x04 }; + struct ca0132_spec *spec = codec->spec; + unsigned int i, tmp; + + /* + * Check if any of the default streams are active, and if they are, + * stop them. + */ + mutex_lock(&spec->chipio_mutex); + + for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) { + chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp); + + if (tmp) { + chipio_set_stream_control(codec, + dsp_dma_stream_ids[i], 0); + } + } + + mutex_unlock(&spec->chipio_mutex); + + /* + * If all DSP streams are inactive, there should be no active DSP DMA + * channels. Check and make sure this is the case, and if it isn't, + * free any active channels. + */ + ca0132_alt_free_active_dma_channels(codec); + + mutex_lock(&spec->chipio_mutex); + + /* Make sure stream 0x0c is six channels. */ + chipio_set_stream_channels(codec, 0x0c, 6); + + for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) { + chipio_set_stream_control(codec, + dsp_dma_stream_ids[i], 1); + + /* Give the DSP some time to setup the DMA channel. */ + msleep(75); + } + + mutex_unlock(&spec->chipio_mutex); +} + /* * The region of ChipIO memory from 0x190000-0x1903fc is a sort of 'audio * router', where each entry represents a 48khz audio channel, with a format @@ -8250,6 +8365,7 @@ static void r3d_setup_defaults(struct hda_codec *codec) ca0132_alt_dsp_scp_startup(codec); ca0132_alt_init_analog_mics(codec); + ca0132_alt_start_dsp_audio_streams(codec); /*remove DSP headroom*/ tmp = FLOAT_ZERO; @@ -8300,6 +8416,7 @@ static void sbz_setup_defaults(struct hda_codec *codec) ca0132_alt_dsp_scp_startup(codec); ca0132_alt_init_analog_mics(codec); + ca0132_alt_start_dsp_audio_streams(codec); sbz_connect_streams(codec); sbz_chipio_startup_data(codec); @@ -8359,6 +8476,7 @@ static void ae5_setup_defaults(struct hda_codec *codec) ca0132_alt_dsp_scp_startup(codec); ca0132_alt_init_analog_mics(codec); + ca0132_alt_start_dsp_audio_streams(codec); chipio_set_stream_control(codec, 0x03, 1); chipio_set_stream_control(codec, 0x04, 1); @@ -8428,6 +8546,7 @@ static void ae7_setup_defaults(struct hda_codec *codec) ca0132_alt_dsp_scp_startup(codec); ca0132_alt_init_analog_mics(codec); + ca0132_alt_start_dsp_audio_streams(codec); ae7_post_dsp_setup_ports(codec); tmp = FLOAT_ZERO; -- cgit v1.2.3 From 19b5926b68252b36bde1cc7b26fb858bd1b9bebb Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 10 Dec 2020 11:06:57 -0500 Subject: ALSA: hda/ca0132 - Remove now unnecessary DSP setup functions. Now that the DSP's audio configuration is understood, remove previous hacky methods of trying to properly configure it. Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201210160658.461739-6-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 105 ------------------------------------------- 1 file changed, 105 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index c3ae9e4f715b..e9019e840a4d 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2426,13 +2426,6 @@ static int dspio_set_uint_param(struct hda_codec *codec, int mod_id, sizeof(unsigned int)); } -static int dspio_set_uint_param_no_source(struct hda_codec *codec, int mod_id, - int req, const unsigned int data) -{ - return dspio_set_param(codec, mod_id, 0x00, req, &data, - sizeof(unsigned int)); -} - /* * Allocate a DSP DMA channel via an SCP message */ @@ -7780,24 +7773,6 @@ static void ca0132_alt_init_speaker_tuning(struct hda_codec *codec) SPEAKER_TUNING_FRONT_LEFT_DELAY + i, values[i]); } -/* - * Creates a dummy stream to bind the output to. This seems to have to be done - * after changing the main outputs source and destination streams. - */ -static void ca0132_alt_create_dummy_stream(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - unsigned int stream_format; - - stream_format = snd_hdac_calc_stream_format(48000, 2, - SNDRV_PCM_FORMAT_S32_LE, 32, 0); - - snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, - 0, stream_format); - - snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); -} - /* * Initialize mic for non-chromebook ca0132 implementations. */ @@ -7839,9 +7814,6 @@ static void sbz_connect_streams(struct hda_codec *codec) codec_dbg(codec, "Connect Streams entered, mutex locked and loaded.\n"); - chipio_set_stream_channels(codec, 0x0C, 6); - chipio_set_stream_control(codec, 0x0C, 1); - /* This value is 0x43 for 96khz, and 0x83 for 192khz. */ chipio_write_no_mutex(codec, 0x18a020, 0x00000043); @@ -7889,9 +7861,6 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) break; } - chipio_set_stream_channels(codec, 0x0c, 6); - chipio_set_stream_control(codec, 0x0c, 1); - if (dsp_out_remap_data) chipio_remap_stream(codec, dsp_out_remap_data); @@ -7899,57 +7868,6 @@ static void sbz_chipio_startup_data(struct hda_codec *codec) mutex_unlock(&spec->chipio_mutex); } -/* - * Custom DSP SCP commands where the src value is 0x00 instead of 0x20. This is - * done after the DSP is loaded. - */ -static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec) -{ - struct ca0132_spec *spec = codec->spec; - unsigned int tmp, i; - - /* - * Gotta run these twice, or else mic works inconsistently. Not clear - * why this is, but multiple tests have confirmed it. - */ - for (i = 0; i < 2; i++) { - switch (ca0132_quirk(spec)) { - case QUIRK_SBZ: - case QUIRK_AE5: - case QUIRK_AE7: - tmp = 0x00000003; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); - tmp = 0x00000001; - dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); - tmp = 0x00000004; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000005; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - break; - case QUIRK_R3D: - case QUIRK_R3DI: - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); - tmp = 0x00000001; - dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); - tmp = 0x00000004; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000005; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - tmp = 0x00000000; - dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); - break; - default: - break; - } - msleep(100); - } -} - static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; @@ -8067,9 +7985,6 @@ static void ae5_post_dsp_stream_setup(struct hda_codec *codec) chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000); - chipio_set_stream_channels(codec, 0x0C, 6); - chipio_set_stream_control(codec, 0x0C, 1); - chipio_set_stream_source_dest(codec, 0x5, 0x43, 0x0); chipio_set_stream_source_dest(codec, 0x18, 0x9, 0xd0); @@ -8127,9 +8042,6 @@ static void ae7_post_dsp_setup_ports(struct hda_codec *codec) mutex_lock(&spec->chipio_mutex); - chipio_set_stream_channels(codec, 0x0c, 6); - chipio_set_stream_control(codec, 0x0c, 1); - /* Seems to share the same port remapping as the SBZ. */ chipio_remap_stream(codec, &stream_remap_data[1]); @@ -8155,8 +8067,6 @@ static void ae7_post_dsp_asi_stream_setup(struct hda_codec *codec) ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00); chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000); - chipio_set_stream_channels(codec, 0x0c, 6); - chipio_set_stream_control(codec, 0x0c, 1); chipio_set_stream_source_dest(codec, 0x05, 0x43, 0x00); chipio_set_stream_source_dest(codec, 0x18, 0x09, 0xd0); @@ -8363,7 +8273,6 @@ static void r3d_setup_defaults(struct hda_codec *codec) if (spec->dsp_state != DSP_DOWNLOADED) return; - ca0132_alt_dsp_scp_startup(codec); ca0132_alt_init_analog_mics(codec); ca0132_alt_start_dsp_audio_streams(codec); @@ -8414,15 +8323,11 @@ static void sbz_setup_defaults(struct hda_codec *codec) if (spec->dsp_state != DSP_DOWNLOADED) return; - ca0132_alt_dsp_scp_startup(codec); ca0132_alt_init_analog_mics(codec); ca0132_alt_start_dsp_audio_streams(codec); sbz_connect_streams(codec); sbz_chipio_startup_data(codec); - chipio_set_stream_control(codec, 0x03, 1); - chipio_set_stream_control(codec, 0x04, 1); - /* * Sets internal input loopback to off, used to have a switch to * enable input loopback, but turned out to be way too buggy. @@ -8457,8 +8362,6 @@ static void sbz_setup_defaults(struct hda_codec *codec) } ca0132_alt_init_speaker_tuning(codec); - - ca0132_alt_create_dummy_stream(codec); } /* @@ -8474,11 +8377,8 @@ static void ae5_setup_defaults(struct hda_codec *codec) if (spec->dsp_state != DSP_DOWNLOADED) return; - ca0132_alt_dsp_scp_startup(codec); ca0132_alt_init_analog_mics(codec); ca0132_alt_start_dsp_audio_streams(codec); - chipio_set_stream_control(codec, 0x03, 1); - chipio_set_stream_control(codec, 0x04, 1); /* New, unknown SCP req's */ tmp = FLOAT_ZERO; @@ -8527,8 +8427,6 @@ static void ae5_setup_defaults(struct hda_codec *codec) } ca0132_alt_init_speaker_tuning(codec); - - ca0132_alt_create_dummy_stream(codec); } /* @@ -8544,7 +8442,6 @@ static void ae7_setup_defaults(struct hda_codec *codec) if (spec->dsp_state != DSP_DOWNLOADED) return; - ca0132_alt_dsp_scp_startup(codec); ca0132_alt_init_analog_mics(codec); ca0132_alt_start_dsp_audio_streams(codec); ae7_post_dsp_setup_ports(codec); @@ -8613,8 +8510,6 @@ static void ae7_setup_defaults(struct hda_codec *codec) } ca0132_alt_init_speaker_tuning(codec); - - ca0132_alt_create_dummy_stream(codec); } /* -- cgit v1.2.3 From 607184cb1635eaee239fe3fb9648a8b82a5232d7 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 11 Dec 2020 14:17:09 +0800 Subject: ALSA: hda/realtek - Add supported for more Lenovo ALC285 Headset Button Add supported for more Lenovo ALC285 Headset Button. Signed-off-by: Kailang Yang Cc: Link: https://lore.kernel.org/r/bb1f1da1526d460885aa4257be81eb94@realtek.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f76b70132478..41cc64036f22 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8577,6 +8577,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60130}, {0x19, 0x03a11020}, {0x21, 0x0321101f}), + SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, + {0x14, 0x90170110}, + {0x19, 0x04a11040}, + {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE, {0x12, 0x90a60130}, {0x14, 0x90170110}, -- cgit v1.2.3 From 13b1f8aa6569060480dc747e45741581dbc0cfc2 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 11 Dec 2020 14:45:47 +0200 Subject: ALSA: hda/hdmi: always print pin NIDs as hexadecimal The debug prints from patch_hdmi.c are not aligned with HDA common code in hda_codec.c nor with other HDA codec drivers. To align with rest of the codebase, use hexadecimal formatting whenever printing value of a HDA NID. Also refer to NIDs with capital letters in traces as is done other modules. This presentation is also aligned with the formatting used in HDA codec procfs entry. Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201211124547.3243871-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2ddc27db8c01..22f5a29d25f6 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -253,7 +253,7 @@ static int pin_id_to_pin_index(struct hda_codec *codec, return pin_idx; } - codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid); + codec_warn(codec, "HDMI: pin NID 0x%x not registered\n", pin_nid); return -EINVAL; } @@ -313,7 +313,7 @@ static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid) if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid) return cvt_idx; - codec_warn(codec, "HDMI: cvt nid %d not registered\n", cvt_nid); + codec_warn(codec, "HDMI: cvt NID 0x%x not registered\n", cvt_nid); return -EINVAL; } @@ -687,8 +687,7 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, dp_ai->CC02_CT47 = active_channels - 1; dp_ai->CA = ca; } else { - codec_dbg(codec, "HDMI: unknown connection type at pin %d\n", - pin_nid); + codec_dbg(codec, "HDMI: unknown connection type at pin NID 0x%x\n", pin_nid); return; } @@ -701,10 +700,8 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, */ if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, sizeof(ai))) { - codec_dbg(codec, - "hdmi_pin_setup_infoframe: pin=%d channels=%d ca=0x%02x\n", - pin_nid, - active_channels, ca); + codec_dbg(codec, "%s: pin NID=0x%x channels=%d ca=0x%02x\n", + __func__, pin_nid, active_channels, ca); hdmi_stop_infoframe_trans(codec, pin_nid); hdmi_fill_audio_infoframe(codec, pin_nid, ai.bytes, sizeof(ai)); @@ -796,7 +793,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res, jack->jack_dirty = 1; codec_dbg(codec, - "HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n", + "HDMI hot plug event: Codec=%d NID=0x%x Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n", codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA), !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); @@ -874,7 +871,7 @@ static void haswell_verify_D0(struct hda_codec *codec, msleep(40); pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT; - codec_dbg(codec, "Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr); + codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr); } } @@ -1121,8 +1118,8 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec, per_cvt = get_cvt(spec, cvt_idx); if (!per_cvt->assigned) { codec_dbg(codec, - "choose cvt %d for pin nid %d\n", - cvt_idx, nid); + "choose cvt %d for pin NID 0x%x\n", + cvt_idx, nid); snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, cvt_idx); @@ -1320,7 +1317,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { codec_warn(codec, - "HDMI: pin %d wcaps %#x does not support connection list\n", + "HDMI: pin NID 0x%x wcaps %#x does not support connection list\n", pin_nid, get_wcaps(codec, pin_nid)); return -EINVAL; } @@ -1635,7 +1632,7 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, eld->eld_valid = false; codec_dbg(codec, - "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + "HDMI status: Codec=%d NID=0x%x Presence_Detect=%d ELD_Valid=%d\n", codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); if (eld->eld_valid) { @@ -2795,7 +2792,7 @@ static int intel_pin2port(void *audio_ptr, int pin_nid) return i; } - codec_info(codec, "Can't find the HDMI/DP port for pin %d\n", pin_nid); + codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid); return -1; } -- cgit v1.2.3 From c6dde8ffd071aea9d1ce64279178e470977b235c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Dec 2020 14:00:48 +0100 Subject: ALSA: usb-audio: Fix control 'access overflow' errors from chmap The current channel-map control implementation in USB-audio driver may lead to an error message like "control 3:0:0:Playback Channel Map:0: access overflow" when CONFIG_SND_CTL_VALIDATION is set. It's because the chmap get callback clears the whole array no matter which count is set, and rather the false-positive detection. This patch fixes the problem by clearing only the needed array range at usb_chmap_ctl_get(). Cc: Link: https://lore.kernel.org/r/20201211130048.6358-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/stream.c b/sound/usb/stream.c index ca76ba5b5c0b..2f6d39c2ba7c 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -193,16 +193,16 @@ static int usb_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct snd_usb_substream *subs = info->private_data; struct snd_pcm_chmap_elem *chmap = NULL; - int i; + int i = 0; - memset(ucontrol->value.integer.value, 0, - sizeof(ucontrol->value.integer.value)); if (subs->cur_audiofmt) chmap = subs->cur_audiofmt->chmap; if (chmap) { for (i = 0; i < chmap->channels; i++) ucontrol->value.integer.value[i] = chmap->map[i]; } + for (; i < subs->channels_max; i++) + ucontrol->value.integer.value[i] = 0; return 0; } -- cgit v1.2.3 From 85a7555575a0e48f9b73db310d0d762a08a46d63 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 9 Dec 2020 09:54:09 +0300 Subject: ASoC: wm_adsp: remove "ctl" from list on error in wm_adsp_create_control() The error handling frees "ctl" but it's still on the "dsp->ctl_list" list so that could result in a use after free. Remove it from the list before returning. Fixes: 2323736dca72 ("ASoC: wm_adsp: Add basic support for rev 1 firmware file format") Signed-off-by: Dan Carpenter Acked-by: Charles Keepax Link: https://lore.kernel.org/r/X9B0keV/02wrx9Xs@mwanda Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index e61d00486c65..dec8716aa8ef 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1519,7 +1519,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); if (!ctl_work) { ret = -ENOMEM; - goto err_ctl_cache; + goto err_list_del; } ctl_work->dsp = dsp; @@ -1529,7 +1529,8 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, return 0; -err_ctl_cache: +err_list_del: + list_del(&ctl->list); kfree(ctl->cache); err_ctl_subname: kfree(ctl->subname); -- cgit v1.2.3 From 4ab9301710760b99b4229d608eb5599040b2e07e Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 11 Dec 2020 13:12:23 +0800 Subject: ASoC: rt1015p: move SDB control from trigger to DAPM Moves SDB control from DAI ops trigger to DAPM. As long as BCLK and LRCLK are ready, SDB can be toggled earlier. Changes from using gpiod_set_value() to gpiod_set_value_cansleep() because it executes in non-atomic context. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201211051224.2307349-2-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015p.c | 51 ++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c index 59bb60682270..ee9dfa2dbbf0 100644 --- a/sound/soc/codecs/rt1015p.c +++ b/sound/soc/codecs/rt1015p.c @@ -19,60 +19,40 @@ struct rt1015p_priv { struct gpio_desc *sdb; - int sdb_switch; }; -static int rt1015p_daiops_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) +static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_component *component = dai->component; + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); struct rt1015p_priv *rt1015p = snd_soc_component_get_drvdata(component); if (!rt1015p->sdb) return 0; - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (rt1015p->sdb_switch) { - gpiod_set_value(rt1015p->sdb, 1); - dev_dbg(component->dev, "set sdb to 1"); - } + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + gpiod_set_value_cansleep(rt1015p->sdb, 1); + dev_dbg(component->dev, "set sdb to 1"); break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - gpiod_set_value(rt1015p->sdb, 0); + case SND_SOC_DAPM_POST_PMD: + gpiod_set_value_cansleep(rt1015p->sdb, 0); dev_dbg(component->dev, "set sdb to 0"); break; + default: + break; } return 0; } -static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = - snd_soc_dapm_to_component(w->dapm); - struct rt1015p_priv *rt1015p = - snd_soc_component_get_drvdata(component); - - if (event & SND_SOC_DAPM_POST_PMU) - rt1015p->sdb_switch = 1; - else if (event & SND_SOC_DAPM_POST_PMD) - rt1015p->sdb_switch = 0; - - return 0; -} - static const struct snd_soc_dapm_widget rt1015p_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("Speaker"), SND_SOC_DAPM_OUT_DRV_E("SDB", SND_SOC_NOPM, 0, 0, NULL, 0, rt1015p_sdb_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = { @@ -91,10 +71,6 @@ static const struct snd_soc_component_driver rt1015p_component_driver = { .non_legacy_dai_naming = 1, }; -static const struct snd_soc_dai_ops rt1015p_dai_ops = { - .trigger = rt1015p_daiops_trigger, -}; - static struct snd_soc_dai_driver rt1015p_dai_driver = { .name = "HiFi", .playback = { @@ -104,7 +80,6 @@ static struct snd_soc_dai_driver rt1015p_dai_driver = { .channels_min = 1, .channels_max = 2, }, - .ops = &rt1015p_dai_ops, }; static int rt1015p_platform_probe(struct platform_device *pdev) -- cgit v1.2.3 From f102d0d173982be3fc096d0293c1c0245e988ba6 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 11 Dec 2020 13:12:24 +0800 Subject: ASoC: rt1015p: delay 300ms after SDB pulling high for calibration RT1015p needs 300ms delay after SDB pulling high for internal calibration during the power on sequence. Delays 300ms right before data sends out to avoid data truncated. Assuming the calibration state gets lost after system suspend. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201211051224.2307349-3-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015p.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c index ee9dfa2dbbf0..671f2a2130fe 100644 --- a/sound/soc/codecs/rt1015p.c +++ b/sound/soc/codecs/rt1015p.c @@ -4,6 +4,7 @@ // // Copyright 2020 The Linux Foundation. All rights reserved. +#include #include #include #include @@ -19,6 +20,7 @@ struct rt1015p_priv { struct gpio_desc *sdb; + bool calib_done; }; static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w, @@ -36,6 +38,11 @@ static int rt1015p_sdb_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMU: gpiod_set_value_cansleep(rt1015p->sdb, 1); dev_dbg(component->dev, "set sdb to 1"); + + if (!rt1015p->calib_done) { + msleep(300); + rt1015p->calib_done = true; + } break; case SND_SOC_DAPM_POST_PMD: gpiod_set_value_cansleep(rt1015p->sdb, 0); @@ -60,7 +67,20 @@ static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = { {"Speaker", NULL, "SDB"}, }; +#ifdef CONFIG_PM +static int rt1015p_suspend(struct snd_soc_component *component) +{ + struct rt1015p_priv *rt1015p = snd_soc_component_get_drvdata(component); + + rt1015p->calib_done = false; + return 0; +} +#else +#define rt1015p_suspend NULL +#endif + static const struct snd_soc_component_driver rt1015p_component_driver = { + .suspend = rt1015p_suspend, .dapm_widgets = rt1015p_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt1015p_dapm_widgets), .dapm_routes = rt1015p_dapm_routes, -- cgit v1.2.3 From b278fc55b47739da49ea7f95e6ad58d436091ba2 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 11 Dec 2020 12:07:41 +0200 Subject: ASoC: SOF: Intel: hda: remove duplicated status dump Remove the duplicate status dump in case DSP init fails. The core will be powered down in this case and the status dump will be invalid anyway. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201211100743.3188821-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 02c3ff897274..d8fb4e277c19 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -408,10 +408,12 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) * should be ready for code loading and firmware boot */ ret = cl_copy_fw(sdev, stream); - if (!ret) + if (!ret) { dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); - else + } else { + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); + } cleanup: /* @@ -435,9 +437,6 @@ cleanup: if (!ret) return chip_info->init_core_mask; - /* dump dsp registers and disable DSP upon error */ - hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); - /* disable DSP */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, -- cgit v1.2.3 From fbfa22ec4b2b8a1bb1a52c56c376295c7b7e7849 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 11 Dec 2020 12:07:42 +0200 Subject: ASoC: SOF: modify the SOF_DBG flags The SOF_DBG_* macros are used for dual purposes right now, for the sof_core_debug module parameter and for the dbg_dump() ops. So, separate these two types of flags into different types to avoid confusion. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201211100743.3188821-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 2 +- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda-loader.c | 4 ++-- sound/soc/sof/loader.c | 4 ++-- sound/soc/sof/ops.c | 2 +- sound/soc/sof/sof-priv.h | 11 ++++++----- 6 files changed, 13 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 143117334ae5..30213a1beaaa 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -817,7 +817,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) } /* dump vital information to the logs */ - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); snd_sof_ipc_dump(sdev); snd_sof_trace_notify_for_error(sdev); } diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 186736ee5fc2..19260dbecac5 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -336,7 +336,7 @@ static int byt_run(struct snd_sof_dev *sdev) } if (tries < 0) { dev_err(sdev->dev, "error: unable to run DSP firmware\n"); - byt_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + byt_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); return -ENODEV; } diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index d8fb4e277c19..c4dcbe500635 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -175,7 +175,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) __func__); err: - hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); return ret; @@ -411,7 +411,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) if (!ret) { dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); } else { - hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index cbce484b6469..df39f477239a 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -856,8 +856,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) msecs_to_jiffies(sdev->boot_timeout)); if (ret == 0) { dev_err(sdev->dev, "error: firmware boot failure\n"); - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | - SOF_DBG_TEXT | SOF_DBG_PCI); + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | + SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI); sdev->fw_state = SOF_FW_BOOT_FAILED; return -EIO; } diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 1a394b4c6a2f..11ecebd07907 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -157,7 +157,7 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n", sdev->dsp_oops_offset, offset); - snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); snd_sof_trace_notify_for_error(sdev); } EXPORT_SYMBOL(snd_sof_dsp_panic); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 9ba3e3ceed01..ba317d3b8e53 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -22,11 +22,12 @@ /* debug flags */ #define SOF_DBG_ENABLE_TRACE BIT(0) -#define SOF_DBG_REGS BIT(1) -#define SOF_DBG_MBOX BIT(2) -#define SOF_DBG_TEXT BIT(3) -#define SOF_DBG_PCI BIT(4) -#define SOF_DBG_RETAIN_CTX BIT(5) /* prevent DSP D3 on FW exception */ +#define SOF_DBG_RETAIN_CTX BIT(1) /* prevent DSP D3 on FW exception */ + +#define SOF_DBG_DUMP_REGS BIT(0) +#define SOF_DBG_DUMP_MBOX BIT(1) +#define SOF_DBG_DUMP_TEXT BIT(2) +#define SOF_DBG_DUMP_PCI BIT(3) /* global debug state set by SOF_DBG_ flags */ extern int sof_core_debug; -- cgit v1.2.3 From 8f7ef6fca0317fb217d1eef8f30010d7a9c6ae0e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 11 Dec 2020 12:07:43 +0200 Subject: ASoC: SOF: Intel: hda: fix the condition passed to sof_dev_dbg_or_err The condition boot_iteration == HDA_FW_BOOT_ATTEMPTS to determine the log level for the DSP status dump would only work in the case of DSP init failure after maximum number of attempts to initialize the DSP. If DSP init succeeds in less than HDA_FW_BOOT_ATTEMPTS attempts and FW loading fails, the ROM status dump would end up getting logged as debug instead of an error. So, add a new flag, SOF_DBG_DUMP_LOG_ERROR, to explicitly specify the log level for DSP status dump. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201211100743.3188821-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 12 ++++++++++-- sound/soc/sof/intel/hda.c | 10 ++++------ sound/soc/sof/loader.c | 2 +- sound/soc/sof/sof-priv.h | 2 ++ 4 files changed, 17 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index c4dcbe500635..ed773696b495 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -88,6 +88,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; unsigned int status; + u32 flags; int ret; int i; @@ -175,7 +176,13 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) __func__); err: - hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); + flags = SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX; + + /* force error log level after max boot attempts */ + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + flags |= SOF_DBG_DUMP_FORCE_ERR_LEVEL; + + hda_dsp_dump(sdev, flags); hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); return ret; @@ -411,7 +418,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) if (!ret) { dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); } else { - hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); + hda_dsp_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | + SOF_DBG_DUMP_FORCE_ERR_LEVEL); dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index bb4128a72a42..509a9b256423 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -416,9 +416,8 @@ void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags) } /* dump the first 8 dwords representing the extended ROM status */ -static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev) +static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags) { - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; char msg[128]; int len = 0; u32 value; @@ -429,14 +428,13 @@ static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev) len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value); } - sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS, + sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL, "extended rom status: %s", msg); } void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[HDA_DSP_STACK_DUMP_SIZE]; @@ -456,11 +454,11 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); } else { - sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS, + sof_dev_dbg_or_err(sdev->dev, flags & SOF_DBG_DUMP_FORCE_ERR_LEVEL, "status = 0x%8.8x panic = 0x%8.8x\n", status, panic); - hda_dsp_dump_ext_rom_status(sdev); + hda_dsp_dump_ext_rom_status(sdev, flags); hda_dsp_get_status(sdev); } } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index df39f477239a..08a17abb63ff 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -857,7 +857,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) if (ret == 0) { dev_err(sdev->dev, "error: firmware boot failure\n"); snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | - SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI); + SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_FORCE_ERR_LEVEL); sdev->fw_state = SOF_FW_BOOT_FAILED; return -EIO; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ba317d3b8e53..68da8f797403 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -28,6 +28,8 @@ #define SOF_DBG_DUMP_MBOX BIT(1) #define SOF_DBG_DUMP_TEXT BIT(2) #define SOF_DBG_DUMP_PCI BIT(3) +#define SOF_DBG_DUMP_FORCE_ERR_LEVEL BIT(4) /* used to dump dsp status with error log level */ + /* global debug state set by SOF_DBG_ flags */ extern int sof_core_debug; -- cgit v1.2.3 From f5824e5ce1cdba523a357a4d3ffbe0876a27330f Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Thu, 10 Dec 2020 10:25:41 -0500 Subject: ASoC: topology: Add missing size check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we parse "values" we perform check if there is correct number of them. However similar check is missing in case of "texts", add it. Signed-off-by: Amadeusz Sławiński Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201210152541.191728-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index eb2633dd6454..e85b52798bc5 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -856,6 +856,9 @@ static int soc_tplg_denum_create_texts(struct soc_tplg *tplg, struct soc_enum *s { int i, ret; + if (le32_to_cpu(ec->items) > ARRAY_SIZE(ec->texts)) + return -EINVAL; + se->dobj.control.dtexts = devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL); if (se->dobj.control.dtexts == NULL) -- cgit v1.2.3 From 631c78ed72bbf852cc09b24e4e4e412ed88770f2 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Thu, 10 Dec 2020 10:25:40 -0500 Subject: ASoC: topology: Fix wrong size check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dan reported that smatch reports wrong size check and after analysis it is confirmed that we are comparing wrong value: pointer size instead of array size. However the check itself is problematic as in UAPI header there are two fields: struct snd_soc_tplg_enum_control { (...) char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; __le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 4]; the texts field is for names and the values one for values assigned to those named fields, after analysis it becomes clear that there is quite a lot overhead values than we may possibly name. So instead of changing check to ARRAY_SIZE(ec->values), as it was first suggested, use hardcoded value of SND_SOC_TPLG_NUM_TEXTS. Link: https://lore.kernel.org/alsa-devel/X9B0eDcKy+9B6kZl@mwanda/ Reported-by: Dan Carpenter Signed-off-by: Amadeusz Sławiński Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20201210152541.191728-1-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index e85b52798bc5..950c45008e24 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -892,10 +892,16 @@ static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum * { int i; - if (le32_to_cpu(ec->items) > sizeof(*ec->values)) + /* + * Following "if" checks if we have at most SND_SOC_TPLG_NUM_TEXTS + * values instead of using ARRAY_SIZE(ec->values) due to the fact that + * it is oversized for its purpose. Additionally it is done so because + * it is defined in UAPI header where it can't be easily changed. + */ + if (le32_to_cpu(ec->items) > SND_SOC_TPLG_NUM_TEXTS) return -EINVAL; - se->dobj.control.dvalues = devm_kzalloc(tplg->dev, le32_to_cpu(ec->items) * + se->dobj.control.dvalues = devm_kcalloc(tplg->dev, le32_to_cpu(ec->items), sizeof(u32), GFP_KERNEL); if (!se->dobj.control.dvalues) -- cgit v1.2.3 From de96bd7b7e9b4cf855fb6d1c7ce32a15dfbdfd92 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 11 Dec 2020 13:13:34 +0800 Subject: ASoC: mediatek: mt8183: add PM ops to machine drivers Adds PM ops to machine drivers so that they notify components in the sound card when system suspend. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20201211051334.2313899-1-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 1 + sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 1 + 2 files changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 26e7d9a7198f..078e58f1ad0b 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -811,6 +811,7 @@ static struct platform_driver mt8183_da7219_max98357_driver = { #ifdef CONFIG_OF .of_match_table = mt8183_da7219_max98357_dt_match, #endif + .pm = &snd_soc_pm_ops, }, .probe = mt8183_da7219_max98357_dev_probe, }; diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 327dfad41e31..8c8340854859 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -744,6 +744,7 @@ static struct platform_driver mt8183_mt6358_ts3a227_max98357_driver = { #ifdef CONFIG_OF .of_match_table = mt8183_mt6358_ts3a227_max98357_dt_match, #endif + .pm = &snd_soc_pm_ops, }, .probe = mt8183_mt6358_ts3a227_max98357_dev_probe, }; -- cgit v1.2.3 From 1688dbe7a730e1c1ed05b9dde497288494d75ad4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 11 Dec 2020 13:10:11 +0300 Subject: ASoC: mediatek: mt8183: delete some unreachable code This has a goto followed by an unreachable return statement. The goto is correct because it cleans up so the current runtime behavior is fine. Let's delete the unreachable return statement. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/X9NFg3KVm16Gx6Io@mwanda Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-afe-clk.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c index 48e81c5d52fc..cc4f8f4d3dab 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c @@ -584,7 +584,6 @@ int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate) __func__, aud_clks[div_clk_id], rate, ret); goto ERR_SET_MCLK_RATE; - return ret; } return 0; -- cgit v1.2.3 From 45c29d9ae9ae41c38f525fab3546f22da80aefb9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Dec 2020 12:22:55 +0200 Subject: ASoC: SOF: imx: update kernel-doc description Add missing parameters to avoid W=1 error Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Daniel Baluta Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201211102255.3189589-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/imx-common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index 5fee637834c2..8826ef94f04a 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -47,6 +47,8 @@ void imx8_get_registers(struct snd_sof_dev *sdev, /** * imx8_dump() - This function is called when a panic message is * received from the firmware. + * @sdev: SOF device + * @flags: parameter not used but required by ops prototype */ void imx8_dump(struct snd_sof_dev *sdev, u32 flags) { -- cgit v1.2.3 From 46c3bbd9827952f92e250fa6ee30a797a4c4e17e Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 11 Dec 2020 15:16:13 +0200 Subject: ALSA: hda/hdmi: packet buffer index must be set before reading value The check for infoframe transmit status in hdmi_infoframe_uptodate() makes the assumption that packet buffer index is set to zero. Align code with specification and explicitly set the index before AC_VERB_GET_HDMI_DIP_XMIT. The packet index setting affects both DIP-Data and DIP-XmitCtrl verbs. There are no known cases where the old implementation has caused driver to work incorrectly. This change is purely based on code review against the specification (HDA spec rev1.0a). Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20201211131613.3271407-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 22f5a29d25f6..1e4a4b83fbf6 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -638,11 +638,11 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, u8 val; int i; + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0) != AC_DIPXMIT_BEST) return false; - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); for (i = 0; i < size; i++) { val = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_DATA, 0); -- cgit v1.2.3 From c1d8aeed83d9e4b98a31f0c669102d8f2f1e4901 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 11 Dec 2020 17:55:02 -0500 Subject: ALSA: hda/ca0132 - Add 8051 PLL write helper functions. Add helper functions for the 8051 PLL PMU write verbs. Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201211225504.4508-1-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 130 +++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 80 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index e9019e840a4d..9b6b7601a881 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1949,6 +1949,14 @@ static unsigned int chipio_8051_get_data(struct hda_codec *codec) VENDOR_CHIPIO_8051_DATA_READ, 0); } +/* PLL_PMU writes share the lower address register of the 8051 exram writes. */ +static void chipio_8051_set_data_pll(struct hda_codec *codec, unsigned int data) +{ + /* 8-bits of data. */ + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, data & 0xff); +} + static void chipio_8051_write_exram(struct hda_codec *codec, unsigned int addr, unsigned int data) { @@ -1977,6 +1985,26 @@ static void chipio_8051_read_exram(struct hda_codec *codec, *data = chipio_8051_get_data(codec); } +static void chipio_8051_write_pll_pmu(struct hda_codec *codec, + unsigned int addr, unsigned int data) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + + chipio_8051_set_address(codec, addr & 0xff); + chipio_8051_set_data_pll(codec, data); + + mutex_unlock(&spec->chipio_mutex); +} + +static void chipio_8051_write_pll_pmu_no_mutex(struct hda_codec *codec, + unsigned int addr, unsigned int data) +{ + chipio_8051_set_address(codec, addr & 0xff); + chipio_8051_set_data_pll(codec, data); +} + /* * Enable clocks. */ @@ -1985,18 +2013,11 @@ static void chipio_enable_clocks(struct hda_codec *codec) struct ca0132_spec *spec = codec->spec; mutex_lock(&spec->chipio_mutex); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xff); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 5); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0x0b); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 6); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xff); + + chipio_8051_write_pll_pmu_no_mutex(codec, 0x00, 0xff); + chipio_8051_write_pll_pmu_no_mutex(codec, 0x05, 0x0b); + chipio_8051_write_pll_pmu_no_mutex(codec, 0x06, 0xff); + mutex_unlock(&spec->chipio_mutex); } @@ -7904,10 +7925,7 @@ static void ae5_post_dsp_register_set(struct hda_codec *codec) struct ca0132_spec *spec = codec->spec; chipio_8051_write_direct(codec, 0x93, 0x10); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); + chipio_8051_write_pll_pmu(codec, 0x44, 0xc2); writeb(0xff, spec->mem_base + 0x304); writeb(0xff, spec->mem_base + 0x304); @@ -7949,30 +7967,11 @@ static void ae5_post_dsp_param_setup(struct hda_codec *codec) static void ae5_post_dsp_pll_setup(struct hda_codec *codec) { - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x41); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc8); - - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x45); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcc); - - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x40); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcb); - - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); - - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x51); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0x8d); + chipio_8051_write_pll_pmu(codec, 0x41, 0xc8); + chipio_8051_write_pll_pmu(codec, 0x45, 0xcc); + chipio_8051_write_pll_pmu(codec, 0x40, 0xcb); + chipio_8051_write_pll_pmu(codec, 0x43, 0xc7); + chipio_8051_write_pll_pmu(codec, 0x51, 0x8d); } static void ae5_post_dsp_stream_setup(struct hda_codec *codec) @@ -7994,10 +7993,7 @@ static void ae5_post_dsp_stream_setup(struct hda_codec *codec) chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7); ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80); @@ -8090,12 +8086,8 @@ static void ae7_post_dsp_pll_setup(struct hda_codec *codec) }; unsigned int i; - for (i = 0; i < ARRAY_SIZE(addr); i++) { - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, addr[i]); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, data[i]); - } + for (i = 0; i < ARRAY_SIZE(addr); i++) + chipio_8051_write_pll_pmu_no_mutex(codec, addr[i], data[i]); } static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec) @@ -8111,10 +8103,7 @@ static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec) mutex_lock(&spec->chipio_mutex); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7); chipio_write_no_mutex(codec, 0x189000, 0x0001f101); chipio_write_no_mutex(codec, 0x189004, 0x0001f101); @@ -8187,10 +8176,7 @@ static void ae7_post_dsp_asi_setup(struct hda_codec *codec) { chipio_8051_write_direct(codec, 0x93, 0x10); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); + chipio_8051_write_pll_pmu(codec, 0x44, 0xc2); ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83); ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f); @@ -8207,10 +8193,7 @@ static void ae7_post_dsp_asi_setup(struct hda_codec *codec) ae7_post_dsp_pll_setup(codec); ae7_post_dsp_asi_stream_setup(codec); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + chipio_8051_write_pll_pmu(codec, 0x43, 0xc7); ae7_post_dsp_asi_setup_ports(codec); } @@ -9367,18 +9350,11 @@ static void ae5_register_set(struct hda_codec *codec) unsigned int i, cur_addr; unsigned char tmp[3]; - if (ca0132_quirk(spec) == QUIRK_AE7) { - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x41); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc8); - } + if (ca0132_quirk(spec) == QUIRK_AE7) + chipio_8051_write_pll_pmu(codec, 0x41, 0xc8); chipio_8051_write_direct(codec, 0x93, 0x10); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); + chipio_8051_write_pll_pmu(codec, 0x44, 0xc2); if (ca0132_quirk(spec) == QUIRK_AE7) { tmp[0] = 0x03; @@ -9454,10 +9430,7 @@ static void ca0132_alt_init(struct hda_codec *codec) break; case QUIRK_AE5: ca0132_gpio_init(codec); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x49); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0x88); + chipio_8051_write_pll_pmu(codec, 0x49, 0x88); chipio_write(codec, 0x18b030, 0x00000020); snd_hda_sequence_write(codec, spec->chip_init_verbs); snd_hda_sequence_write(codec, spec->desktop_init_verbs); @@ -9465,10 +9438,7 @@ static void ca0132_alt_init(struct hda_codec *codec) break; case QUIRK_AE7: ca0132_gpio_init(codec); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x49); - snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_PLL_PMU_WRITE, 0x88); + chipio_8051_write_pll_pmu(codec, 0x49, 0x88); snd_hda_sequence_write(codec, spec->chip_init_verbs); snd_hda_sequence_write(codec, spec->desktop_init_verbs); chipio_write(codec, 0x18b008, 0x000000f8); -- cgit v1.2.3 From d84489e374f5b9b3ab424a5169e68e06a4329524 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 11 Dec 2020 17:55:03 -0500 Subject: ALSA: hda/ca0132 - Add ZxR surround DAC setup. Add pre-dsp download initialization for the DAC's used in the surround sound configuration. Fixes issues of no audio on surround channels. Fixes: 2e492b8ee5da8 ("ALSA: hda/ca0132 - Add ZxR init commands") Signed-off-by: Connor McAdams Link: https://lore.kernel.org/r/20201211225504.4508-2-conmanx360@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 9b6b7601a881..7e62aed172a9 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -9186,6 +9186,44 @@ static void r3di_pre_dsp_setup(struct hda_codec *codec) AC_VERB_SET_PIN_WIDGET_CONTROL, 0x04); } +/* + * The ZxR seems to use alternative DAC's for the surround channels, which + * require PLL PMU setup for the clock rate, I'm guessing. Without setting + * this up, we get no audio out of the surround jacks. + */ +static void zxr_pre_dsp_setup(struct hda_codec *codec) +{ + static const unsigned int addr[] = { 0x43, 0x40, 0x41, 0x42, 0x45 }; + static const unsigned int data[] = { 0x08, 0x0c, 0x0b, 0x07, 0x0d }; + unsigned int i; + + chipio_write(codec, 0x189000, 0x0001f100); + msleep(50); + chipio_write(codec, 0x18900c, 0x0001f100); + msleep(50); + + /* + * This writes a RET instruction at the entry point of the function at + * 0xfa92 in exram. This function seems to have something to do with + * ASI. Might be some way to prevent the card from reconfiguring the + * ASI stuff itself. + */ + chipio_8051_write_exram(codec, 0xfa92, 0x22); + + chipio_8051_write_pll_pmu(codec, 0x51, 0x98); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x82); + chipio_set_control_param(codec, CONTROL_PARAM_ASI, 3); + + chipio_write(codec, 0x18902c, 0x00000000); + msleep(50); + chipio_write(codec, 0x18902c, 0x00000003); + msleep(50); + + for (i = 0; i < ARRAY_SIZE(addr); i++) + chipio_8051_write_pll_pmu(codec, addr[i], data[i]); +} + /* * These are sent before the DSP is downloaded. Not sure * what they do, or if they're necessary. Could possibly @@ -9447,8 +9485,10 @@ static void ca0132_alt_init(struct hda_codec *codec) ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); break; case QUIRK_ZXR: + chipio_8051_write_pll_pmu(codec, 0x49, 0x88); snd_hda_sequence_write(codec, spec->chip_init_verbs); snd_hda_sequence_write(codec, spec->desktop_init_verbs); + zxr_pre_dsp_setup(codec); break; default: break; -- cgit v1.2.3 From 43d5ca88dfcd35e43010fdd818e067aa9a55f5ba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Dec 2020 09:45:51 +0100 Subject: ALSA: usb-audio: Fix potential out-of-bounds shift syzbot spotted a potential out-of-bounds shift in the USB-audio format parser that receives the arbitrary shift value from the USB descriptor. Add a range check for avoiding the undefined behavior. Reported-by: syzbot+df7dc146ebdd6435eea3@syzkaller.appspotmail.com Cc: Link: https://lore.kernel.org/r/20201209084552.17109-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/format.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/usb/format.c b/sound/usb/format.c index 93459ba228d3..9ebc5d202c87 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -39,6 +39,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, case UAC_VERSION_1: default: { struct uac_format_type_i_discrete_descriptor *fmt = _fmt; + if (format >= 64) + return 0; /* invalid format */ sample_width = fmt->bBitResolution; sample_bytes = fmt->bSubframeSize; format = 1ULL << format; -- cgit v1.2.3 From 175b8d89fe292796811fdee87fa39799a5b6b87a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Dec 2020 09:45:52 +0100 Subject: ALSA: pcm: oss: Fix potential out-of-bounds shift syzbot spotted a potential out-of-bounds shift in the PCM OSS layer where it calculates the buffer size with the arbitrary shift value given via an ioctl. Add a range check for avoiding the undefined behavior. As the value can be treated by a signed integer, the max shift should be 30. Reported-by: syzbot+df7dc146ebdd6435eea3@syzkaller.appspotmail.com Cc: Link: https://lore.kernel.org/r/20201209084552.17109-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 327ec42a36b0..de1917484647 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1935,11 +1935,15 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsigned int val) { struct snd_pcm_runtime *runtime; + int fragshift; runtime = substream->runtime; if (runtime->oss.subdivision || runtime->oss.fragshift) return -EINVAL; - runtime->oss.fragshift = val & 0xffff; + fragshift = val & 0xffff; + if (fragshift >= 31) + return -EINVAL; + runtime->oss.fragshift = fragshift; runtime->oss.maxfrags = (val >> 16) & 0xffff; if (runtime->oss.fragshift < 4) /* < 16 */ runtime->oss.fragshift = 4; -- cgit v1.2.3