Unverified Commit e8a33a94 authored by V sujith kumar Reddy's avatar V sujith kumar Reddy Committed by Mark Brown
Browse files

ASoC: amd: acp: Add legacy audio driver support for Rembrandt platform



Add i2s and dmic support for Rembrandt platform,
Add machine support for nau8825, max98360 and rt5682s,rt1019 codec
in legacy driver for rembrandt platform.
Here codec is in a slave mode.

Signed-off-by: default avatarV sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
Link: https://lore.kernel.org/r/20220707161142.491034-4-Vsujithkumar.Reddy@amd.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent b24484c1
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -40,6 +40,17 @@ config SND_AMD_ASOC_RENOIR
	help
	  This option enables Renoir I2S support on AMD platform.

config SND_AMD_ASOC_REMBRANDT
	tristate "AMD ACP ASOC Rembrandt Support"
	select SND_SOC_AMD_ACP_PCM
	select SND_SOC_AMD_ACP_I2S
	select SND_SOC_AMD_ACP_PDM
	depends on X86 && PCI
	help
	  This option enables Rembrandt I2S support on AMD platform.
	  Say Y if you want to enable AUDIO on Rembrandt
	  If unsure select "N".

config SND_SOC_AMD_MACH_COMMON
	tristate
	depends on X86 && PCI && I2C
+2 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ snd-acp-pci-objs := acp-pci.o

#platform specific driver
snd-acp-renoir-objs     := acp-renoir.o
snd-acp-rembrandt-objs  := acp-rembrandt.o

#machine specific driver
snd-acp-mach-objs     := acp-mach-common.o
@@ -24,6 +25,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o
obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o

obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o
obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o

obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o
obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o
+136 −1
Original line number Diff line number Diff line
@@ -30,11 +30,14 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
{
	struct device *dev = dai->component->dev;
	struct acp_dev_data *adata;
	struct acp_resource *rsrc;
	u32 val;
	u32 xfer_resolution;
	u32 reg_val;
	u32 lrclk_div_val, bclk_div_val;

	adata = snd_soc_dai_get_drvdata(dai);
	rsrc = adata->rsrc;

	/* These values are as per Hardware Spec */
	switch (params_format(params)) {
@@ -63,6 +66,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
		case I2S_SP_INSTANCE:
			reg_val = ACP_I2STDM_ITER;
			break;
		case I2S_HS_INSTANCE:
			reg_val = ACP_HSTDM_ITER;
			break;
		default:
			dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
			return -EINVAL;
@@ -75,6 +81,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
		case I2S_SP_INSTANCE:
			reg_val = ACP_I2STDM_IRER;
			break;
		case I2S_HS_INSTANCE:
			reg_val = ACP_HSTDM_IRER;
			break;
		default:
			dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
			return -EINVAL;
@@ -86,6 +95,74 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
	val = val | (xfer_resolution  << 3);
	writel(val, adata->acp_base + reg_val);

	if (rsrc->soc_mclk) {
		switch (params_format(params)) {
		case SNDRV_PCM_FORMAT_S16_LE:
			switch (params_rate(params)) {
			case 8000:
				bclk_div_val = 768;
				break;
			case 16000:
				bclk_div_val = 384;
				break;
			case 24000:
				bclk_div_val = 256;
				break;
			case 32000:
				bclk_div_val = 192;
				break;
			case 44100:
			case 48000:
				bclk_div_val = 128;
				break;
			case 88200:
			case 96000:
				bclk_div_val = 64;
				break;
			case 192000:
				bclk_div_val = 32;
				break;
			default:
				return -EINVAL;
			}
			lrclk_div_val = 32;
			break;
		case SNDRV_PCM_FORMAT_S32_LE:
			switch (params_rate(params)) {
			case 8000:
				bclk_div_val = 384;
				break;
			case 16000:
				bclk_div_val = 192;
				break;
			case 24000:
				bclk_div_val = 128;
				break;
			case 32000:
				bclk_div_val = 96;
				break;
			case 44100:
			case 48000:
				bclk_div_val = 64;
				break;
			case 88200:
			case 96000:
				bclk_div_val = 32;
				break;
			case 192000:
				bclk_div_val = 16;
				break;
			default:
				return -EINVAL;
			}
			lrclk_div_val = 64;
			break;
		default:
			return -EINVAL;
		}
		adata->lrclk_div = lrclk_div_val;
		adata->bclk_div = bclk_div_val;
	}
	return 0;
}

@@ -94,6 +171,7 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
	struct acp_stream *stream = substream->runtime->private_data;
	struct device *dev = dai->component->dev;
	struct acp_dev_data *adata = dev_get_drvdata(dev);
	struct acp_resource *rsrc = adata->rsrc;
	u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;

	period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
@@ -118,6 +196,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
				ier_val = ACP_I2STDM_IER;
				buf_reg = ACP_I2S_TX_RINGBUFSIZE;
				break;
			case I2S_HS_INSTANCE:
				water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
				reg_val = ACP_HSTDM_ITER;
				ier_val = ACP_HSTDM_IER;
				buf_reg = ACP_HS_TX_RINGBUFSIZE;
				break;
			default:
				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
				return -EINVAL;
@@ -136,6 +220,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
				ier_val = ACP_I2STDM_IER;
				buf_reg = ACP_I2S_RX_RINGBUFSIZE;
				break;
			case I2S_HS_INSTANCE:
				water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
				reg_val = ACP_HSTDM_IRER;
				ier_val = ACP_HSTDM_IER;
				buf_reg = ACP_HS_RX_RINGBUFSIZE;
				break;
			default:
				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
				return -EINVAL;
@@ -147,6 +237,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
		val = val | BIT(0);
		writel(val, adata->acp_base + reg_val);
		writel(1, adata->acp_base + ier_val);
		if (rsrc->soc_mclk)
			acp_set_i2s_clk(adata, dai->driver->id);
		return 0;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -159,6 +251,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
			case I2S_SP_INSTANCE:
				reg_val = ACP_I2STDM_ITER;
				break;
			case I2S_HS_INSTANCE:
				reg_val = ACP_HSTDM_ITER;
				break;
			default:
				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
				return -EINVAL;
@@ -172,6 +267,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
			case I2S_SP_INSTANCE:
				reg_val = ACP_I2STDM_IRER;
				break;
			case I2S_HS_INSTANCE:
				reg_val = ACP_HSTDM_IRER;
				break;
			default:
				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
				return -EINVAL;
@@ -187,6 +285,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
		if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
		    !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
			writel(0, adata->acp_base + ACP_I2STDM_IER);
		if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&
		    !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))
			writel(0, adata->acp_base + ACP_HSTDM_IER);
		return 0;
	default:
		return -EINVAL;
@@ -247,6 +348,27 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
			writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
		}
		break;
	case I2S_HS_INSTANCE:
		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
			reg_dma_size = ACP_HS_TX_DMA_SIZE;
			acp_fifo_addr = rsrc->sram_pte_offset +
				HS_PB_FIFO_ADDR_OFFSET;
			reg_fifo_addr = ACP_HS_TX_FIFOADDR;
			reg_fifo_size = ACP_HS_TX_FIFOSIZE;

			phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
			writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
		} else {
			reg_dma_size = ACP_HS_RX_DMA_SIZE;
			acp_fifo_addr = rsrc->sram_pte_offset +
					HS_CAPT_FIFO_ADDR_OFFSET;
			reg_fifo_addr = ACP_HS_RX_FIFOADDR;
			reg_fifo_size = ACP_HS_RX_FIFOSIZE;

			phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
			writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
		}
		break;
	default:
		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
		return -EINVAL;
@@ -260,7 +382,9 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
	ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
			BIT(BT_RX_THRESHOLD(rsrc->offset)) |
			BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
			BIT(BT_TX_THRESHOLD(rsrc->offset));
			BIT(BT_TX_THRESHOLD(rsrc->offset)) |
			BIT(HS_RX_THRESHOLD(rsrc->offset)) |
			BIT(HS_TX_THRESHOLD(rsrc->offset));

	writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));

@@ -299,6 +423,17 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
			stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
		}
		break;
	case I2S_HS_INSTANCE:
		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
			irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));
			stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;
			stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;
		} else {
			irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));
			stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;
			stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;
		}
		break;
	default:
		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
		return -EINVAL;
+32 −0
Original line number Diff line number Diff line
@@ -47,6 +47,28 @@ static struct acp_card_drvdata rt5682s_rt1019_data = {
	.dmic_codec_id = DMIC,
};

static struct acp_card_drvdata max_nau8825_data = {
	.hs_cpu_id = I2S_HS,
	.amp_cpu_id = I2S_HS,
	.dmic_cpu_id = DMIC,
	.hs_codec_id = NAU8825,
	.amp_codec_id = MAX98360A,
	.dmic_codec_id = DMIC,
	.soc_mclk = true,
	.platform = REMBRANDT,
};

static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
	.hs_cpu_id = I2S_HS,
	.amp_cpu_id = I2S_HS,
	.dmic_cpu_id = DMIC,
	.hs_codec_id = RT5682S,
	.amp_codec_id = RT1019,
	.dmic_codec_id = DMIC,
	.soc_mclk = true,
	.platform = REMBRANDT,
};

static const struct snd_kcontrol_new acp_controls[] = {
	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
	SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -112,6 +134,14 @@ static const struct platform_device_id board_ids[] = {
		.name = "acp3xalc5682s1019",
		.driver_data = (kernel_ulong_t)&rt5682s_rt1019_data,
	},
	{
		.name = "rmb-nau8825-max",
		.driver_data = (kernel_ulong_t)&max_nau8825_data,
	},
	{
		.name = "rmb-rt5682s-rt1019",
		.driver_data = (kernel_ulong_t)&rt5682s_rt1019_rmb_data,
	},
	{ }
};
static struct platform_driver acp_asoc_audio = {
@@ -130,4 +160,6 @@ MODULE_DESCRIPTION("ACP chrome audio support");
MODULE_ALIAS("platform:acp3xalc56821019");
MODULE_ALIAS("platform:acp3xalc5682sm98360");
MODULE_ALIAS("platform:acp3xalc5682s1019");
MODULE_ALIAS("platform:rmb-nau8825-max");
MODULE_ALIAS("platform:rmb-rt5682s-rt1019");
MODULE_LICENSE("GPL v2");
+84 −2
Original line number Diff line number Diff line
@@ -545,6 +545,12 @@ static struct snd_soc_dai_link_component platform_component[] = {
	}
};

static struct snd_soc_dai_link_component platform_rmb_component[] = {
	{
		.name = "acp_asoc_rembrandt.0",
	}
};

static struct snd_soc_dai_link_component sof_component[] = {
	{
		 .name = "0000:04:00.5",
@@ -553,6 +559,8 @@ static struct snd_soc_dai_link_component sof_component[] = {

SND_SOC_DAILINK_DEF(i2s_sp,
	DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp")));
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_hs,
@@ -774,6 +782,40 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
		i++;
	}

	if (drv_data->hs_cpu_id == I2S_HS) {
		links[i].name = "acp-headset-codec";
		links[i].id = HEADSET_BE_ID;
		links[i].cpus = i2s_hs;
		links[i].num_cpus = ARRAY_SIZE(i2s_hs);
		if (drv_data->platform == REMBRANDT) {
			links[i].platforms = platform_rmb_component;
			links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
		} else {
			links[i].platforms = platform_component;
			links[i].num_platforms = ARRAY_SIZE(platform_component);
		}
		links[i].dpcm_playback = 1;
		links[i].dpcm_capture = 1;
		if (!drv_data->hs_codec_id) {
			/* Use dummy codec if codec id not specified */
			links[i].codecs = dummy_codec;
			links[i].num_codecs = ARRAY_SIZE(dummy_codec);
		}
		if (drv_data->hs_codec_id == NAU8825) {
			links[i].codecs = nau8825;
			links[i].num_codecs = ARRAY_SIZE(nau8825);
			links[i].init = acp_card_nau8825_init;
			links[i].ops = &acp_card_nau8825_ops;
		}
		if (drv_data->hs_codec_id == RT5682S) {
			links[i].codecs = rt5682s;
			links[i].num_codecs = ARRAY_SIZE(rt5682s);
			links[i].init = acp_card_rt5682s_init;
			links[i].ops = &acp_card_rt5682s_ops;
		}
		i++;
	}

	if (drv_data->amp_cpu_id == I2S_SP) {
		links[i].name = "acp-amp-codec";
		links[i].id = AMP_BE_ID;
@@ -804,6 +846,41 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
		i++;
	}

	if (drv_data->amp_cpu_id == I2S_HS) {
		links[i].name = "acp-amp-codec";
		links[i].id = AMP_BE_ID;
		links[i].cpus = i2s_hs;
		links[i].num_cpus = ARRAY_SIZE(i2s_hs);
		if (drv_data->platform == REMBRANDT) {
			links[i].platforms = platform_rmb_component;
			links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
		} else {
			links[i].platforms = platform_component;
			links[i].num_platforms = ARRAY_SIZE(platform_component);
		}
		links[i].dpcm_playback = 1;
		if (!drv_data->amp_codec_id) {
			/* Use dummy codec if codec id not specified */
			links[i].codecs = dummy_codec;
			links[i].num_codecs = ARRAY_SIZE(dummy_codec);
		}
		if (drv_data->amp_codec_id == MAX98360A) {
			links[i].codecs = max98360a;
			links[i].num_codecs = ARRAY_SIZE(max98360a);
			links[i].ops = &acp_card_maxim_ops;
			links[i].init = acp_card_maxim_init;
		}
		if (drv_data->amp_codec_id == RT1019) {
			links[i].codecs = rt1019;
			links[i].num_codecs = ARRAY_SIZE(rt1019);
			links[i].ops = &acp_card_rt1019_ops;
			links[i].init = acp_card_rt1019_init;
			card->codec_conf = rt1019_conf;
			card->num_configs = ARRAY_SIZE(rt1019_conf);
		}
		i++;
	}

	if (drv_data->dmic_cpu_id == DMIC) {
		links[i].name = "acp-dmic-codec";
		links[i].id = DMIC_BE_ID;
@@ -817,8 +894,13 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
		}
		links[i].cpus = pdm_dmic;
		links[i].num_cpus = ARRAY_SIZE(pdm_dmic);
		if (drv_data->platform == REMBRANDT) {
			links[i].platforms = platform_rmb_component;
			links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
		} else {
			links[i].platforms = platform_component;
			links[i].num_platforms = ARRAY_SIZE(platform_component);
		}
		links[i].ops = &acp_card_dmic_ops;
		links[i].dpcm_capture = 1;
	}
Loading