summaryrefslogtreecommitdiff
path: root/sound/soc/amd
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2023-02-16 14:32:04 +0100
committerTakashi Iwai <tiwai@suse.de>2023-02-16 14:32:04 +0100
commit1bdb78368f9448cf0de9b11eb1388e887d1b4849 (patch)
tree82a70b8d8502d5078dc36d67fbb7bc315e760d63 /sound/soc/amd
parent5661706efa200252d0e9fea02421b0a5857808c3 (diff)
parent76f5aaabce492aa6991c28c96bb78b00b05d06c5 (diff)
Merge tag 'asoc-v6.3' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next
ASoC: Updates for v6.3 There's been quite a lot of activity this release, but not really one big feature - lots of new devices, plus a lot of cleanup and modernisation work spread throughout the subsystem: - More factoring out of common operations into helper functions by Morimoto-san. - DT schema conversons and stylistic nits. - Continued work on building out the new SOF IPC4 scheme. - Support for Awinc AT88395, Infineon PEB2466, Iron Device SMA1303, Mediatek MT8188, Realtek RT712, Renesas IDT821034, Samsung/Tesla FSD SoC I2S, and TI TAS5720A-Q1.
Diffstat (limited to 'sound/soc/amd')
-rw-r--r--sound/soc/amd/acp/acp-legacy-mach.c13
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c465
-rw-r--r--sound/soc/amd/acp/acp-mach.h4
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c14
-rw-r--r--sound/soc/amd/ps/acp63.h14
-rw-r--r--sound/soc/amd/ps/pci-ps.c211
-rw-r--r--sound/soc/amd/ps/ps-pdm-dma.c40
-rw-r--r--sound/soc/amd/raven/acp3x-i2s.c8
-rw-r--r--sound/soc/amd/renoir/acp3x-pdm-dma.c8
-rw-r--r--sound/soc/amd/renoir/rn_acp3x.h2
-rw-r--r--sound/soc/amd/yc/acp6x-pdm-dma.c8
-rw-r--r--sound/soc/amd/yc/acp6x.h2
12 files changed, 579 insertions, 210 deletions
diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c
index 1f4878ff7d37..676ad50638d0 100644
--- a/sound/soc/amd/acp/acp-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-legacy-mach.c
@@ -16,6 +16,7 @@
#include <sound/pcm_params.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
+#include <linux/dmi.h>
#include <linux/module.h>
#include "acp-mach.h"
@@ -27,6 +28,7 @@ static struct acp_card_drvdata rt5682_rt1019_data = {
.hs_codec_id = RT5682,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
+ .tdm_mode = false,
};
static struct acp_card_drvdata rt5682s_max_data = {
@@ -36,6 +38,7 @@ static struct acp_card_drvdata rt5682s_max_data = {
.hs_codec_id = RT5682S,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
+ .tdm_mode = false,
};
static struct acp_card_drvdata rt5682s_rt1019_data = {
@@ -45,6 +48,7 @@ static struct acp_card_drvdata rt5682s_rt1019_data = {
.hs_codec_id = RT5682S,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
+ .tdm_mode = false,
};
static struct acp_card_drvdata max_nau8825_data = {
@@ -56,6 +60,7 @@ static struct acp_card_drvdata max_nau8825_data = {
.dmic_codec_id = DMIC,
.soc_mclk = true,
.platform = REMBRANDT,
+ .tdm_mode = false,
};
static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
@@ -67,6 +72,7 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
.dmic_codec_id = DMIC,
.soc_mclk = true,
.platform = REMBRANDT,
+ .tdm_mode = false,
};
static const struct snd_kcontrol_new acp_controls[] = {
@@ -90,6 +96,8 @@ static int acp_asoc_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = NULL;
struct device *dev = &pdev->dev;
+ const struct dmi_system_id *dmi_id;
+ struct acp_card_drvdata *acp_card_drvdata;
int ret;
if (!pdev->id_entry)
@@ -108,6 +116,11 @@ static int acp_asoc_probe(struct platform_device *pdev)
card->num_controls = ARRAY_SIZE(acp_controls);
card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
+ acp_card_drvdata = card->drvdata;
+ dmi_id = dmi_first_match(acp_quirk_table);
+ if (dmi_id && dmi_id->driver_data)
+ acp_card_drvdata->tdm_mode = dmi_id->driver_data;
+
acp_legacy_dai_links_create(card);
ret = devm_snd_soc_register_card(&pdev->dev, card);
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index a78cf29387a7..b4dcce4fbae9 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -32,6 +32,20 @@
#define DUAL_CHANNEL 2
#define FOUR_CHANNEL 4
+#define TDM_MODE_ENABLE 1
+
+const struct dmi_system_id acp_quirk_table[] = {
+ {
+ /* Google skyrim proto-0 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"),
+ },
+ .driver_data = (void *)TDM_MODE_ENABLE,
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(acp_quirk_table);
+
static struct snd_soc_jack pco_jack;
static const unsigned int channels[] = {
@@ -54,10 +68,11 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
.mask = 0,
};
-static int acp_clk_enable(struct acp_card_drvdata *drvdata)
+static int acp_clk_enable(struct acp_card_drvdata *drvdata,
+ unsigned int srate, unsigned int bclk_ratio)
{
- clk_set_rate(drvdata->wclk, 48000);
- clk_set_rate(drvdata->bclk, 48000 * 64);
+ clk_set_rate(drvdata->wclk, srate);
+ clk_set_rate(drvdata->bclk, srate * bclk_ratio);
return clk_prepare_enable(drvdata->wclk);
}
@@ -86,34 +101,6 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != RT5682)
return -EINVAL;
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBP_CFP);
- if (ret < 0) {
- dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK,
- PCO_PLAT_CLK, RT5682_PLL_FREQ);
- if (ret < 0) {
- dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
- return ret;
- }
-
- ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2,
- RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
- if (ret < 0) {
- dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
- return ret;
- }
-
- /* Set tdm/i2s1 master bclk ratio */
- ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
- if (ret < 0) {
- dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret);
- return ret;
- }
-
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
@@ -151,10 +138,15 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
int ret;
unsigned int fmt;
+ if (drvdata->tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
if (drvdata->soc_mclk)
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
else
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret < 0) {
@@ -168,16 +160,6 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
- if (strcmp(codec_dai->name, "rt5682s-aif1") && strcmp(codec_dai->name, "rt5682s-aif2")) {
- if (!drvdata->soc_mclk) {
- ret = acp_clk_enable(drvdata);
- if (ret < 0) {
- dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
- return ret;
- }
- }
- }
-
return ret;
}
@@ -191,39 +173,36 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream)
clk_disable_unprepare(drvdata->wclk);
}
-static const struct snd_soc_ops acp_card_rt5682_ops = {
- .startup = acp_card_hs_startup,
- .shutdown = acp_card_shutdown,
-};
-
-/* Define RT5682S CODEC component*/
-SND_SOC_DAILINK_DEF(rt5682s,
- DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1")));
-
-static const struct snd_soc_dapm_route rt5682s_map[] = {
- { "Headphone Jack", NULL, "HPOL" },
- { "Headphone Jack", NULL, "HPOR" },
- { "IN1P", NULL, "Headset Mic" },
-};
-
-static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
+static int acp_card_rt5682_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 acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_component *component = codec_dai->component;
- unsigned int fmt;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int ret;
+ unsigned int fmt, srate, ch, format;
- dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
+ srate = params_rate(params);
+ ch = params_channels(params);
+ format = params_physical_width(params);
- if (drvdata->hs_codec_id != RT5682S)
- return -EINVAL;
+ if (drvdata->tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
if (drvdata->soc_mclk)
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
else
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret < 0) {
@@ -231,14 +210,31 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK,
+ if (drvdata->tdm_mode) {
+ /**
+ * As codec supports slot 0 and slot 1 for playback and capture.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 8, 16);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 8, 16);
+ if (ret < 0) {
+ dev_warn(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK,
PCO_PLAT_CLK, RT5682_PLL_FREQ);
if (ret < 0) {
dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
return ret;
}
- ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2,
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2,
RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
@@ -246,13 +242,53 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
}
/* 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, ch * format);
if (ret < 0) {
dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret);
return ret;
}
if (!drvdata->soc_mclk) {
+ ret = acp_clk_enable(drvdata, srate, ch * format);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops acp_card_rt5682_ops = {
+ .startup = acp_card_hs_startup,
+ .shutdown = acp_card_shutdown,
+ .hw_params = acp_card_rt5682_hw_params,
+};
+
+/* Define RT5682S CODEC component*/
+SND_SOC_DAILINK_DEF(rt5682s,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1")));
+
+static const struct snd_soc_dapm_route rt5682s_map[] = {
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+ { "IN1P", NULL, "Headset Mic" },
+};
+
+static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct acp_card_drvdata *drvdata = card->drvdata;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ int ret;
+
+ dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
+
+ if (drvdata->hs_codec_id != RT5682S)
+ return -EINVAL;
+
+ if (!drvdata->soc_mclk) {
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
}
@@ -281,8 +317,90 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682s_map, ARRAY_SIZE(rt5682s_map));
}
+static int acp_card_rt5682s_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 acp_card_drvdata *drvdata = card->drvdata;
+ 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;
+ unsigned int fmt, srate, ch, format;
+
+ srate = params_rate(params);
+ ch = params_channels(params);
+ format = params_physical_width(params);
+
+ if (drvdata->tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ if (drvdata->soc_mclk)
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ else
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (drvdata->tdm_mode) {
+ /**
+ * As codec supports slot 0 and slot 1 for playback and capture.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 8, 16);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 8, 16);
+ if (ret < 0) {
+ dev_warn(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK,
+ PCO_PLAT_CLK, RT5682_PLL_FREQ);
+ if (ret < 0) {
+ dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2,
+ RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
+ return ret;
+ }
+
+ /* Set tdm/i2s1 master bclk ratio */
+ ret = snd_soc_dai_set_bclk_ratio(codec_dai, ch * format);
+ if (ret < 0) {
+ dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret);
+ return ret;
+ }
+
+ clk_set_rate(drvdata->wclk, srate);
+ clk_set_rate(drvdata->bclk, srate * ch * format);
+
+ return 0;
+}
+
static const struct snd_soc_ops acp_card_rt5682s_ops = {
.startup = acp_card_hs_startup,
+ .hw_params = acp_card_rt5682s_hw_params,
};
static const unsigned int dmic_channels[] = {
@@ -351,19 +469,55 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai;
- int srate, i, ret = 0;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ int i, ret = 0;
+ unsigned int fmt, srate, ch, format;
srate = params_rate(params);
+ ch = params_channels(params);
+ format = params_physical_width(params);
if (drvdata->amp_codec_id != RT1019)
return -EINVAL;
+ if (drvdata->tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ if (drvdata->soc_mclk)
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ else
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (drvdata->tdm_mode) {
+ /**
+ * As codec supports slot 2 and slot 3 for playback.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xC, 0, 8, 16);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+ }
+
for_each_rtd_codec_dais(rtd, i, codec_dai) {
if (strcmp(codec_dai->name, "rt1019-aif"))
continue;
- ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
- 64 * srate, 256 * srate);
+ if (drvdata->tdm_mode)
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
+ TDM_CHANNELS * format * srate, 256 * srate);
+ else
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
+ ch * format * srate, 256 * srate);
+
if (ret < 0)
return ret;
@@ -371,6 +525,41 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
256 * srate, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
+
+ if (drvdata->tdm_mode) {
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A
+ | SND_SOC_DAIFMT_NB_NF);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ /**
+ * As codec supports slot 2 for left channel playback.
+ */
+ if (!strcmp(codec_dai->component->name, "i2c-10EC1019:00")) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x4, 0x4, 8, 16);
+ if (ret < 0)
+ break;
+ }
+
+ /**
+ * As codec supports slot 3 for right channel playback.
+ */
+ if (!strcmp(codec_dai->component->name, "i2c-10EC1019:01")) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x8, 0x8, 8, 16);
+ if (ret < 0)
+ break;
+ }
+ }
+ }
+
+ if (!drvdata->soc_mclk) {
+ ret = acp_clk_enable(drvdata, srate, ch * format);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
+ return ret;
+ }
}
return 0;
@@ -379,10 +568,6 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
static int acp_card_amp_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_card *card = rtd->card;
- struct acp_card_drvdata *drvdata = card->drvdata;
- int ret = 0;
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -390,14 +575,7 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
- if (!drvdata->soc_mclk) {
- ret = acp_clk_enable(drvdata);
- if (ret < 0) {
- dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
- return ret;
- }
- }
- return ret;
+ return 0;
}
static const struct snd_soc_ops acp_card_rt1019_ops = {
@@ -426,9 +604,61 @@ static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
ARRAY_SIZE(max98360a_map));
}
+static int acp_card_maxim_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 acp_card_drvdata *drvdata = card->drvdata;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ unsigned int fmt, srate, ch, format;
+ int ret;
+
+ srate = params_rate(params);
+ ch = params_channels(params);
+ format = params_physical_width(params);
+
+ if (drvdata->tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ if (drvdata->soc_mclk)
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ else
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (drvdata->tdm_mode) {
+ /**
+ * As codec supports slot 2 and slot 3 for playback.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xC, 0, 8, 16);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!drvdata->soc_mclk) {
+ ret = acp_clk_enable(drvdata, srate, ch * format);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
static const struct snd_soc_ops acp_card_maxim_ops = {
.startup = acp_card_amp_startup,
.shutdown = acp_card_shutdown,
+ .hw_params = acp_card_maxim_hw_params,
};
/* Declare nau8825 codec components */
@@ -446,7 +676,6 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
- unsigned int fmt;
int ret;
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
@@ -454,16 +683,6 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != NAU8825)
return -EINVAL;
- if (drvdata->soc_mclk)
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
- else
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
-
- ret = snd_soc_dai_set_fmt(codec_dai, fmt);
- if (ret < 0) {
- dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
- return ret;
- }
ret = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
@@ -492,8 +711,12 @@ static int acp_nau8825_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_card *card = rtd->card;
+ struct acp_card_drvdata *drvdata = card->drvdata;
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;
+ unsigned int fmt;
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS,
(48000 * 256), SND_SOC_CLOCK_IN);
@@ -507,6 +730,44 @@ static int acp_nau8825_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ if (drvdata->tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ if (drvdata->soc_mclk)
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ else
+ fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (drvdata->tdm_mode) {
+ /**
+ * As codec supports slot 4 and slot 5 for playback and slot 6 for capture.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x30, 0xC0, 8, 16);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x40, 0x30, 8, 16);
+ if (ret < 0) {
+ dev_warn(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
return ret;
}
@@ -565,8 +826,12 @@ SND_SOC_DAILINK_DEF(i2s_hs,
DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-hs")));
SND_SOC_DAILINK_DEF(sof_sp,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
+SND_SOC_DAILINK_DEF(sof_sp_virtual,
+ DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp-virtual")));
SND_SOC_DAILINK_DEF(sof_hs,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs")));
+SND_SOC_DAILINK_DEF(sof_hs_virtual,
+ DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs-virtual")));
SND_SOC_DAILINK_DEF(sof_dmic,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
SND_SOC_DAILINK_DEF(pdm_dmic,
@@ -596,8 +861,6 @@ static int acp_rtk_set_bias_level(struct snd_soc_card *card,
switch (level) {
case SND_SOC_BIAS_STANDBY:
if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) {
- clk_set_rate(drvdata->wclk, 48000);
- clk_set_rate(drvdata->bclk, 48000 * 64);
/* Increase bclk's enable_count */
ret = clk_prepare_enable(drvdata->bclk);
@@ -701,8 +964,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
if (drv_data->amp_cpu_id == I2S_SP) {
links[i].name = "acp-amp-codec";
links[i].id = AMP_BE_ID;
- links[i].cpus = sof_sp;
- links[i].num_cpus = ARRAY_SIZE(sof_sp);
+ links[i].cpus = sof_sp_virtual;
+ links[i].num_cpus = ARRAY_SIZE(sof_sp_virtual);
links[i].platforms = sof_component;
links[i].num_platforms = ARRAY_SIZE(sof_component);
links[i].dpcm_playback = 1;
@@ -733,8 +996,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
if (drv_data->amp_cpu_id == I2S_HS) {
links[i].name = "acp-amp-codec";
links[i].id = AMP_BE_ID;
- links[i].cpus = sof_hs;
- links[i].num_cpus = ARRAY_SIZE(sof_hs);
+ links[i].cpus = sof_hs_virtual;
+ links[i].num_cpus = ARRAY_SIZE(sof_hs_virtual);
links[i].platforms = sof_component;
links[i].num_platforms = ARRAY_SIZE(sof_component);
links[i].dpcm_playback = 1;
diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h
index 20583ef902df..165f407697c0 100644
--- a/sound/soc/amd/acp/acp-mach.h
+++ b/sound/soc/amd/acp/acp-mach.h
@@ -18,6 +18,8 @@
#include <linux/module.h>
#include <sound/soc.h>
+#define TDM_CHANNELS 8
+
enum be_id {
HEADSET_BE_ID = 0,
AMP_BE_ID,
@@ -58,9 +60,11 @@ struct acp_card_drvdata {
struct clk *wclk;
struct clk *bclk;
bool soc_mclk;
+ bool tdm_mode;
};
int acp_sofdsp_dai_links_create(struct snd_soc_card *card);
int acp_legacy_dai_links_create(struct snd_soc_card *card);
+extern const struct dmi_system_id acp_quirk_table[];
#endif
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index f19f064a7527..99a7d3879340 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -16,6 +16,7 @@
#include <sound/pcm_params.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
+#include <linux/dmi.h>
#include <linux/module.h>
#include "acp-mach.h"
@@ -27,6 +28,7 @@ static struct acp_card_drvdata sof_rt5682_rt1019_data = {
.hs_codec_id = RT5682,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
+ .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682_max_data = {
@@ -36,6 +38,7 @@ static struct acp_card_drvdata sof_rt5682_max_data = {
.hs_codec_id = RT5682,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
+ .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
@@ -45,6 +48,7 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
.hs_codec_id = RT5682S,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
+ .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_max_data = {
@@ -54,6 +58,7 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
.hs_codec_id = RT5682S,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
+ .tdm_mode = false,
};
static struct acp_card_drvdata sof_nau8825_data = {
@@ -64,6 +69,7 @@ static struct acp_card_drvdata sof_nau8825_data = {
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
.soc_mclk = true,
+ .tdm_mode = false,
};
static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
@@ -74,6 +80,7 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
.soc_mclk = true,
+ .tdm_mode = false,
};
static const struct snd_kcontrol_new acp_controls[] = {
@@ -96,6 +103,8 @@ static int acp_sof_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = NULL;
struct device *dev = &pdev->dev;
+ const struct dmi_system_id *dmi_id;
+ struct acp_card_drvdata *acp_card_drvdata;
int ret;
if (!pdev->id_entry)
@@ -114,6 +123,11 @@ static int acp_sof_probe(struct platform_device *pdev)
card->num_controls = ARRAY_SIZE(acp_controls);
card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
+ acp_card_drvdata = card->drvdata;
+ dmi_id = dmi_first_match(acp_quirk_table);
+ if (dmi_id && dmi_id->driver_data)
+ acp_card_drvdata->tdm_mode = dmi_id->driver_data;
+
acp_sofdsp_dai_links_create(card);
ret = devm_snd_soc_register_card(&pdev->dev, card);
diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h
index 5e7f9c1c1b0e..6bf29b520511 100644
--- a/sound/soc/amd/ps/acp63.h
+++ b/sound/soc/amd/ps/acp63.h
@@ -11,7 +11,6 @@
#define ACP63_REG_START 0x1240000
#define ACP63_REG_END 0x1250200
#define ACP63_DEVS 3
-#define ACP63_PDM_MODE 1
#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001
#define ACP_PGFSM_CNTL_POWER_ON_MASK 1
@@ -30,7 +29,7 @@
#define ACP_ERROR_STAT 29
#define PDM_DECIMATION_FACTOR 2
#define ACP_PDM_CLK_FREQ_MASK 7
-#define ACP_WOV_MISC_CTRL_MASK 0x10
+#define ACP_WOV_GAIN_CONTROL GENMASK(4, 3)
#define ACP_PDM_ENABLE 1
#define ACP_PDM_DISABLE 0
#define ACP_PDM_DMA_EN_STATUS 2
@@ -54,6 +53,11 @@
/* time in ms for runtime suspend delay */
#define ACP_SUSPEND_DELAY_MS 2000
+#define ACP63_DMIC_ADDR 2
+#define ACP63_PDM_MODE_DEVS 3
+#define ACP63_PDM_DEV_MASK 1
+#define ACP_DMIC_DEV 2
+
enum acp_config {
ACP_CONFIG_0 = 0,
ACP_CONFIG_1,
@@ -84,6 +88,7 @@ struct pdm_stream_instance {
struct pdm_dev_data {
u32 pdm_irq;
void __iomem *acp63_base;
+ struct mutex *acp_lock;
struct snd_pcm_substream *capture_stream;
};
@@ -100,6 +105,9 @@ static inline void acp63_writel(u32 val, void __iomem *base_addr)
struct acp63_dev_data {
void __iomem *acp63_base;
struct resource *res;
- bool acp63_audio_mode;
struct platform_device *pdev[ACP63_DEVS];
+ struct mutex acp_lock; /* protect shared registers */
+ u16 pdev_mask;
+ u16 pdev_count;
+ u16 pdm_dev_index;
};
diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c
index 489f01a20699..e86f23d97584 100644
--- a/sound/soc/amd/ps/pci-ps.c
+++ b/sound/soc/amd/ps/pci-ps.c
@@ -116,6 +116,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
struct acp63_dev_data *adata;
struct pdm_dev_data *ps_pdm_data;
u32 val;
+ u16 pdev_index;
adata = dev_id;
if (!adata)
@@ -123,7 +124,8 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
val = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
if (val & BIT(PDM_DMA_STAT)) {
- ps_pdm_data = dev_get_drvdata(&adata->pdev[0]->dev);
+ pdev_index = adata->pdm_dev_index;
+ ps_pdm_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
acp63_writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
if (ps_pdm_data->capture_stream)
snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
@@ -132,17 +134,124 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
+static void get_acp63_device_config(u32 config, struct pci_dev *pci,
+ struct acp63_dev_data *acp_data)
+{
+ struct acpi_device *dmic_dev;
+ const union acpi_object *obj;
+ bool is_dmic_dev = false;
+
+ dmic_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_DMIC_ADDR, 0);
+ if (dmic_dev) {
+ if (!acpi_dev_get_property(dmic_dev, "acp-audio-device-type",
+ ACPI_TYPE_INTEGER, &obj) &&
+ obj->integer.value == ACP_DMIC_DEV)
+ is_dmic_dev = true;
+ }
+
+ switch (config) {
+ case ACP_CONFIG_0:
+ case ACP_CONFIG_1:
+ case ACP_CONFIG_2:
+ case ACP_CONFIG_3:
+ case ACP_CONFIG_9:
+ case ACP_CONFIG_15:
+ dev_dbg(&pci->dev, "Audio Mode %d\n", config);
+ break;
+ default:
+ if (is_dmic_dev) {
+ acp_data->pdev_mask = ACP63_PDM_DEV_MASK;
+ acp_data->pdev_count = ACP63_PDM_MODE_DEVS;
+ }
+ break;
+ }
+}
+
+static void acp63_fill_platform_dev_info(struct platform_device_info *pdevinfo,
+ struct device *parent,
+ struct fwnode_handle *fw_node,
+ char *name, unsigned int id,
+ const struct resource *res,
+ unsigned int num_res,
+ const void *data,
+ size_t size_data)
+{
+ pdevinfo->name = name;
+ pdevinfo->id = id;
+ pdevinfo->parent = parent;
+ pdevinfo->num_res = num_res;
+ pdevinfo->res = res;
+ pdevinfo->data = data;
+ pdevinfo->size_data = size_data;
+ pdevinfo->fwnode = fw_node;
+}
+
+static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data *adata, u32 addr)
+{
+ struct platform_device_info pdevinfo[ACP63_DEVS];
+ struct device *parent;
+ int index;
+ int ret;
+
+ parent = &pci->dev;
+ dev_dbg(&pci->dev,
+ "%s pdev_mask:0x%x pdev_count:0x%x\n", __func__, adata->pdev_mask,
+ adata->pdev_count);
+ if (adata->pdev_mask) {
+ adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL);
+ if (!adata->res) {
+ ret = -ENOMEM;
+ goto de_init;
+ }
+ adata->res->flags = IORESOURCE_MEM;
+ adata->res->start = addr;
+ adata->res->end = addr + (ACP63_REG_END - ACP63_REG_START);
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ }
+
+ switch (adata->pdev_mask) {
+ case ACP63_PDM_DEV_MASK:
+ adata->pdm_dev_index = 0;
+ acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
+ 0, adata->res, 1, &adata->acp_lock,
+ sizeof(adata->acp_lock));
+ acp63_fill_platform_dev_info(&pdevinfo[1], parent, NULL, "dmic-codec",
+ 0, NULL, 0, NULL, 0);
+ acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "acp_ps_mach",
+ 0, NULL, 0, NULL, 0);
+ break;
+ default:
+ dev_dbg(&pci->dev, "No PDM devices found\n");
+ return 0;
+ }
+
+ for (index = 0; index < adata->pdev_count; index++) {
+ adata->pdev[index] = platform_device_register_full(&pdevinfo[index]);
+ if (IS_ERR(adata->pdev[index])) {
+ dev_err(&pci->dev,
+ "cannot register %s device\n", pdevinfo[index].name);
+ ret = PTR_ERR(adata->pdev[index]);
+ goto unregister_devs;
+ }
+ }
+ return 0;
+unregister_devs:
+ for (--index; index >= 0; index--)
+ platform_device_unregister(adata->pdev[index]);
+de_init:
+ if (acp63_deinit(adata->acp63_base, &pci->dev))
+ dev_err(&pci->dev, "ACP de-init failed\n");
+ return ret;
+}
+
static int snd_acp63_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
struct acp63_dev_data *adata;
- struct platform_device_info pdevinfo[ACP63_DEVS];
- int index, ret;
- int val = 0x00;
- struct acpi_device *adev;
- const union acpi_object *obj;
u32 addr;
- unsigned int irqflags;
+ u32 irqflags;
+ int val;
+ int ret;
irqflags = IRQF_SHARED;
/* Pink Sardine device check */
@@ -179,86 +288,28 @@ static int snd_acp63_probe(struct pci_dev *pci,
}
pci_set_master(pci);
pci_set_drvdata(pci, adata);
+ mutex_init(&adata->acp_lock);
ret = acp63_init(adata->acp63_base, &pci->dev);
if (ret)
goto release_regions;
+ ret = devm_request_irq(&pci->dev, pci->irq, acp63_irq_handler,
+ irqflags, "ACP_PCI_IRQ", adata);
+ if (ret) {
+ dev_err(&pci->dev, "ACP PCI IRQ request failed\n");
+ goto de_init;
+ }
val = acp63_readl(adata->acp63_base + ACP_PIN_CONFIG);
- switch (val) {
- case ACP_CONFIG_0:
- case ACP_CONFIG_1:
- case ACP_CONFIG_2:
- case ACP_CONFIG_3:
- case ACP_CONFIG_9:
- case ACP_CONFIG_15:
- dev_info(&pci->dev, "Audio Mode %d\n", val);
- break;
- default:
-
- /* Checking DMIC hardware*/
- adev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), 0x02, 0);
-
- if (!adev)
- break;
-
- if (!acpi_dev_get_property(adev, "acp-audio-device-type",
- ACPI_TYPE_INTEGER, &obj) &&
- obj->integer.value == 2) {
- adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL);
- if (!adata->res) {
- ret = -ENOMEM;
- goto de_init;
- }
-
- adata->res->name = "acp_iomem";
- adata->res->flags = IORESOURCE_MEM;
- adata->res->start = addr;
- adata->res->end = addr + (ACP63_REG_END - ACP63_REG_START);
- adata->acp63_audio_mode = ACP63_PDM_MODE;
-
- memset(&pdevinfo, 0, sizeof(pdevinfo));
- pdevinfo[0].name = "acp_ps_pdm_dma";
- pdevinfo[0].id = 0;
- pdevinfo[0].parent = &pci->dev;
- pdevinfo[0].num_res = 1;
- pdevinfo[0].res = adata->res;
-
- pdevinfo[1].name = "dmic-codec";
- pdevinfo[1].id = 0;
- pdevinfo[1].parent = &pci->dev;
-
- pdevinfo[2].name = "acp_ps_mach";
- pdevinfo[2].id = 0;
- pdevinfo[2].parent = &pci->dev;
-
- for (index = 0; index < ACP63_DEVS; index++) {
- adata->pdev[index] =
- platform_device_register_full(&pdevinfo[index]);
-
- if (IS_ERR(adata->pdev[index])) {
- dev_err(&pci->dev,
- "cannot register %s device\n",
- pdevinfo[index].name);
- ret = PTR_ERR(adata->pdev[index]);
- goto unregister_devs;
- }
- ret = devm_request_irq(&pci->dev, pci->irq, acp63_irq_handler,
- irqflags, "ACP_PCI_IRQ", adata);
- if (ret) {
- dev_err(&pci->dev, "ACP PCI IRQ request failed\n");
- goto unregister_devs;
- }
- }
- }
- break;
+ get_acp63_device_config(val, pci, adata);
+ ret = create_acp63_platform_devs(pci, adata, addr);
+ if (ret < 0) {
+ dev_err(&pci->dev, "ACP platform devices creation failed\n");
+ goto de_init;
}
pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pci->dev);
pm_runtime_put_noidle(&pci->dev);
pm_runtime_allow(&pci->dev);
return 0;
-unregister_devs:
- for (--index; index >= 0; index--)
- platform_device_unregister(adata->pdev[index]);
de_init:
if (acp63_deinit(adata->acp63_base, &pci->dev))
dev_err(&pci->dev, "ACP de-init failed\n");
@@ -305,10 +356,8 @@ static void snd_acp63_remove(struct pci_dev *pci)
int ret, index;
adata = pci_get_drvdata(pci);
- if (adata->acp63_audio_mode == ACP63_PDM_MODE) {
- for (index = 0; index < ACP63_DEVS; index++)
- platform_device_unregister(adata->pdev[index]);
- }
+ for (index = 0; index < adata->pdev_count; index++)
+ platform_device_unregister(adata->pdev[index]);
ret = acp63_deinit(adata->acp63_base, &pci->dev);
if (ret)
dev_err(&pci->dev, "ACP de-init failed\n");
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index eea71a9d2ef1..454dab062e4f 100644
--- a/sound/soc/amd/ps/ps-pdm-dma.c
+++ b/sound/soc/amd/ps/ps-pdm-dma.c
@@ -7,6 +7,7 @@
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/io.h>
#include <sound/pcm_params.h>
@@ -18,6 +19,10 @@
#define DRV_NAME "acp_ps_pdm_dma"
+static int pdm_gain = 3;
+module_param(pdm_gain, int, 0644);
+MODULE_PARM_DESC(pdm_gain, "Gain control (0-3)");
+
static const struct snd_pcm_hardware acp63_pdm_hardware_capture = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -55,26 +60,31 @@ static void acp63_enable_pdm_clock(void __iomem *acp_base)
acp63_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL);
pdm_ctrl = acp63_readl(acp_base + ACP_WOV_MISC_CTRL);
- pdm_ctrl |= ACP_WOV_MISC_CTRL_MASK;
+ pdm_ctrl &= ~ACP_WOV_GAIN_CONTROL;
+ pdm_ctrl |= FIELD_PREP(ACP_WOV_GAIN_CONTROL, clamp(pdm_gain, 0, 3));
acp63_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL);
}
-static void acp63_enable_pdm_interrupts(void __iomem *acp_base)
+static void acp63_enable_pdm_interrupts(struct pdm_dev_data *adata)
{
u32 ext_int_ctrl;
- ext_int_ctrl = acp63_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
+ mutex_lock(adata->acp_lock);
+ ext_int_ctrl = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_CNTL);
ext_int_ctrl |= PDM_DMA_INTR_MASK;
- acp63_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ acp63_writel(ext_int_ctrl, adata->acp63_base + ACP_EXTERNAL_INTR_CNTL);
+ mutex_unlock(adata->acp_lock);
}
-static void acp63_disable_pdm_interrupts(void __iomem *acp_base)
+static void acp63_disable_pdm_interrupts(struct pdm_dev_data *adata)
{
u32 ext_int_ctrl;
- ext_int_ctrl = acp63_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
+ mutex_lock(adata->acp_lock);
+ ext_int_ctrl = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_CNTL);
ext_int_ctrl &= ~PDM_DMA_INTR_MASK;
- acp63_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ acp63_writel(ext_int_ctrl, adata->acp63_base + ACP_EXTERNAL_INTR_CNTL);
+ mutex_unlock(adata->acp_lock);
}
static bool acp63_check_pdm_dma_status(void __iomem *acp_base)
@@ -196,7 +206,7 @@ static int acp63_pdm_dma_open(struct snd_soc_component *component,
return ret;
}
- acp63_enable_pdm_interrupts(adata->acp63_base);
+ acp63_enable_pdm_interrupts(adata);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
adata->capture_stream = substream;
@@ -272,7 +282,7 @@ static int acp63_pdm_dma_close(struct snd_soc_component *component,
struct pdm_dev_data *adata = dev_get_drvdata(component->dev);
struct snd_pcm_runtime *runtime = substream->runtime;
- acp63_disable_pdm_interrupts(adata->acp63_base);
+ acp63_disable_pdm_interrupts(adata);
adata->capture_stream = NULL;
kfree(runtime->private_data);
return 0;
@@ -353,6 +363,10 @@ static int acp63_pdm_audio_probe(struct platform_device *pdev)
struct pdm_dev_data *adata;
int status;
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "platform_data not retrieved\n");
+ return -ENODEV;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
@@ -368,7 +382,7 @@ static int acp63_pdm_audio_probe(struct platform_device *pdev)
return -ENOMEM;
adata->capture_stream = NULL;
-
+ adata->acp_lock = pdev->dev.platform_data;
dev_set_drvdata(&pdev->dev, adata);
status = devm_snd_soc_register_component(&pdev->dev,
&acp63_pdm_component,
@@ -408,7 +422,7 @@ static int __maybe_unused acp63_pdm_resume(struct device *dev)
acp63_init_pdm_ring_buffer(PDM_MEM_WINDOW_START, buffer_len,
period_bytes, adata->acp63_base);
}
- acp63_enable_pdm_interrupts(adata->acp63_base);
+ acp63_enable_pdm_interrupts(adata);
return 0;
}
@@ -417,7 +431,7 @@ static int __maybe_unused acp63_pdm_suspend(struct device *dev)
struct pdm_dev_data *adata;
adata = dev_get_drvdata(dev);
- acp63_disable_pdm_interrupts(adata->acp63_base);
+ acp63_disable_pdm_interrupts(adata);
return 0;
}
@@ -426,7 +440,7 @@ static int __maybe_unused acp63_pdm_runtime_resume(struct device *dev)
struct pdm_dev_data *adata;
adata = dev_get_drvdata(dev);
- acp63_enable_pdm_interrupts(adata->acp63_base);
+ acp63_enable_pdm_interrupts(adata);
return 0;
}
diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c
index aa38cef1776d..4ba83689482a 100644
--- a/sound/soc/amd/raven/acp3x-i2s.c
+++ b/sound/soc/amd/raven/acp3x-i2s.c
@@ -315,16 +315,8 @@ static int acp3x_dai_probe(struct platform_device *pdev)
return 0;
}
-static int acp3x_dai_remove(struct platform_device *pdev)
-{
- /* As we use devm_ memory alloc there is nothing TBD here */
-
- return 0;
-}
-
static struct platform_driver acp3x_dai_driver = {
.probe = acp3x_dai_probe,
- .remove = acp3x_dai_remove,
.driver = {
.name = "acp3x_i2s_playcap",
},
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c
index 7203c6488df0..0d8b693aecc9 100644
--- a/sound/soc/amd/renoir/acp3x-pdm-dma.c
+++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c
@@ -6,6 +6,7 @@
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
@@ -17,6 +18,10 @@
#define DRV_NAME "acp_rn_pdm_dma"
+static int pdm_gain = 3;
+module_param(pdm_gain, int, 0644);
+MODULE_PARM_DESC(pdm_gain, "Gain control (0-3)");
+
static const struct snd_pcm_hardware acp_pdm_hardware_capture = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -80,7 +85,8 @@ static void enable_pdm_clock(void __iomem *acp_base)
rn_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL);
pdm_ctrl = rn_readl(acp_base + ACP_WOV_MISC_CTRL);
- pdm_ctrl |= ACP_WOV_MISC_CTRL_MASK;
+ pdm_ctrl &= ~ACP_WOV_GAIN_CONTROL;
+ pdm_ctrl |= FIELD_PREP(ACP_WOV_GAIN_CONTROL, clamp(pdm_gain, 0, 3));
rn_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL);
}
diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h
index ca586603d720..7d0f4e6a2834 100644
--- a/sound/soc/amd/renoir/rn_acp3x.h
+++ b/sound/soc/amd/renoir/rn_acp3x.h
@@ -34,7 +34,7 @@
#define ACP_ERROR_STAT 29
#define PDM_DECIMATION_FACTOR 0x2
#define ACP_PDM_CLK_FREQ_MASK 0x07
-#define ACP_WOV_MISC_CTRL_MASK 0x10
+#define ACP_WOV_GAIN_CONTROL GENMASK(4, 3)
#define ACP_PDM_ENABLE 0x01
#define ACP_PDM_DISABLE 0x00
#define ACP_PDM_DMA_EN_STATUS 0x02
diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c
index acecd6a4ec4b..294dd7fb43c9 100644
--- a/sound/soc/amd/yc/acp6x-pdm-dma.c
+++ b/sound/soc/amd/yc/acp6x-pdm-dma.c
@@ -7,6 +7,7 @@
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/io.h>
#include <sound/pcm_params.h>
@@ -18,6 +19,10 @@
#define DRV_NAME "acp_yc_pdm_dma"
+static int pdm_gain = 3;
+module_param(pdm_gain, int, 0644);
+MODULE_PARM_DESC(pdm_gain, "Gain control (0-3)");
+
static const struct snd_pcm_hardware acp6x_pdm_hardware_capture = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -55,7 +60,8 @@ static void acp6x_enable_pdm_clock(void __iomem *acp_base)
acp6x_writel(pdm_clk_enable, acp_base + ACP_WOV_CLK_CTRL);
pdm_ctrl = acp6x_readl(acp_base + ACP_WOV_MISC_CTRL);
- pdm_ctrl |= ACP_WOV_MISC_CTRL_MASK;
+ pdm_ctrl &= ~ACP_WOV_GAIN_CONTROL;
+ pdm_ctrl |= FIELD_PREP(ACP_WOV_GAIN_CONTROL, clamp(pdm_gain, 0, 3));
acp6x_writel(pdm_ctrl, acp_base + ACP_WOV_MISC_CTRL);
}
diff --git a/sound/soc/amd/yc/acp6x.h b/sound/soc/amd/yc/acp6x.h
index 74b596e6807a..036207568c04 100644
--- a/sound/soc/amd/yc/acp6x.h
+++ b/sound/soc/amd/yc/acp6x.h
@@ -31,7 +31,7 @@
#define ACP_ERROR_STAT 29
#define PDM_DECIMATION_FACTOR 2
#define ACP_PDM_CLK_FREQ_MASK 7
-#define ACP_WOV_MISC_CTRL_MASK 0x10
+#define ACP_WOV_GAIN_CONTROL GENMASK(4, 3)
#define ACP_PDM_ENABLE 1
#define ACP_PDM_DISABLE 0
#define ACP_PDM_DMA_EN_STATUS 2