[alsa-devel] [RESEND PATCH v5 2/6] ASoC: amd: Refactoring of DAI from DMA driver
Asoc: PCM DMA driver should only have dma ops. So Removed all DAI related functionality.Refactoring the PCM DMA diver code.Added new file containing only DAI ops.
Signed-off-by: Ravulapati Vishnu vardhan rao Vishnuvardhanrao.Ravulapati@amd.com --- sound/soc/amd/raven/Makefile | 2 + sound/soc/amd/raven/acp3x-i2s.c | 272 ++++++++++++++++++++++++++++++++++++ sound/soc/amd/raven/acp3x-pcm-dma.c | 251 +++++---------------------------- sound/soc/amd/raven/acp3x.h | 42 ++++++ 4 files changed, 348 insertions(+), 219 deletions(-) create mode 100644 sound/soc/amd/raven/acp3x-i2s.c
diff --git a/sound/soc/amd/raven/Makefile b/sound/soc/amd/raven/Makefile index 108d1ac..8eef292 100644 --- a/sound/soc/amd/raven/Makefile +++ b/sound/soc/amd/raven/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0+ # Raven Ridge platform Support snd-pci-acp3x-objs := pci-acp3x.o +snd-acp3x-i2s-objs := acp3x-i2s.o snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-pci-acp3x.o +obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-i2s.o obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-pcm-dma.o diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c new file mode 100644 index 0000000..0f27abc --- /dev/null +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// AMD ALSA SoC PCM Driver +// +//Copyright 2016 Advanced Micro Devices, Inc. + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/pm_runtime.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> +#include <linux/dma-mapping.h> + +#include "acp3x.h" + +#define DRV_NAME "acp3x-i2s" + +static int acp3x_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + + struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + + case SND_SOC_DAIFMT_I2S: + adata->tdm_mode = false; + break; + case SND_SOC_DAIFMT_DSP_A: + adata->tdm_mode = true; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int acp3x_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, + u32 rx_mask, int slots, int slot_width) +{ + u32 val; + u16 slot_len; + + struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); + + /* These values are as per Hardware Spec */ + + switch (slot_width) { + case SLOT_WIDTH_8: + slot_len = 8; + break; + case SLOT_WIDTH_16: + slot_len = 16; + break; + case SLOT_WIDTH_24: + slot_len = 24; + break; + case SLOT_WIDTH_32: + slot_len = 0; + break; + default: + return -EINVAL; + } + + val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER); + rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_ITER); + val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER); + rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_IRER); + + val = (FRM_LEN | (slots << 15) | (slot_len << 18)); + rv_writel(val, adata->acp3x_base + mmACP_BTTDM_TXFRMT); + rv_writel(val, adata->acp3x_base + mmACP_BTTDM_RXFRMT); + + adata->tdm_fmt = val; + return 0; +} + +static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + u32 val = 0; + struct i2s_stream_instance *rtd = substream->runtime->private_data; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + rtd->xfer_resolution = 0x0; + break; + case SNDRV_PCM_FORMAT_S16_LE: + rtd->xfer_resolution = 0x02; + break; + case SNDRV_PCM_FORMAT_S24_LE: + rtd->xfer_resolution = 0x04; + break; + case SNDRV_PCM_FORMAT_S32_LE: + rtd->xfer_resolution = 0x05; + break; + default: + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); + val = val | (rtd->xfer_resolution << 3); + rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); + } else { + val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER); + val = val | (rtd->xfer_resolution << 3); + rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); + } + return 0; +} + +static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + int ret = 0; + struct i2s_stream_instance *rtd = substream->runtime->private_data; + u32 val, period_bytes; + + period_bytes = frames_to_bytes(substream->runtime, + substream->runtime->period_size); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + rtd->bytescount = acp_get_byte_count(rtd, + substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rv_writel(period_bytes, rtd->acp3x_base + + mmACP_BT_TX_INTR_WATERMARK_SIZE); + val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); + val = val | BIT(0); + rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); + } else { + rv_writel(period_bytes, rtd->acp3x_base + + mmACP_BT_RX_INTR_WATERMARK_SIZE); + val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER); + val = val | BIT(0); + rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); + } + rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); + val = val & ~BIT(0); + rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); + } else { + val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER); + val = val & ~BIT(0); + rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); + } + rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static struct snd_soc_dai_ops acp3x_i2s_dai_ops = { + .hw_params = acp3x_i2s_hwparams, + .trigger = acp3x_i2s_trigger, + .set_fmt = acp3x_i2s_set_fmt, + .set_tdm_slot = acp3x_i2s_set_tdm_slot, +}; + +static const struct snd_soc_component_driver acp3x_dai_component = { + .name = "acp3x-i2s", +}; + +static struct snd_soc_dai_driver acp3x_i2s_dai = { + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + .ops = &acp3x_i2s_dai_ops, +}; + + +static int acp3x_dai_probe(struct platform_device *pdev) +{ + int status; + struct resource *res; + struct i2s_dev_data *adata; + + adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data), + GFP_KERNEL); + if (!adata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); + goto err; + } + + adata->acp3x_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (IS_ERR(adata->acp3x_base)) + return PTR_ERR(adata->acp3x_base); + + adata->i2s_irq = res->start; + dev_set_drvdata(&pdev->dev, adata); + status = devm_snd_soc_register_component(&pdev->dev, + &acp3x_dai_component, + &acp3x_i2s_dai, 1); + if (status) { + dev_err(&pdev->dev, "Fail to register acp i2s dai\n"); + goto dev_err; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, 10000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + return 0; +err: + kfree(adata); + return -ENOMEM; +dev_err: + kfree(adata->acp3x_base); + kfree(adata); + kfree(res); + return -ENODEV; +} + +static int acp3x_dai_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + return 0; +} +static struct platform_driver acp3x_dai_driver = { + .probe = acp3x_dai_probe, + .remove = acp3x_dai_remove, + .driver = { + .name = "acp3x_i2s_playcap", + }, +}; + +module_platform_driver(acp3x_dai_driver); + +MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com"); +MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 60709e3..8db2812 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -18,24 +18,6 @@
#define DRV_NAME "acp3x-i2s-audio"
-struct i2s_dev_data { - bool tdm_mode; - unsigned int i2s_irq; - u32 tdm_fmt; - void __iomem *acp3x_base; - struct snd_pcm_substream *play_stream; - struct snd_pcm_substream *capture_stream; -}; - -struct i2s_stream_instance { - u16 num_pages; - u16 channels; - u32 xfer_resolution; - u64 bytescount; - dma_addr_t dma_addr; - void __iomem *acp3x_base; -}; - static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -280,6 +262,9 @@ static int acp3x_dma_open(struct snd_soc_component *component, { int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + + component = snd_soc_rtdcom_lookup(prtd, DRV_NAME); struct i2s_dev_data *adata = dev_get_drvdata(component->dev); struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance), GFP_KERNEL); @@ -312,23 +297,6 @@ static int acp3x_dma_open(struct snd_soc_component *component, return 0; }
-static u64 acp_get_byte_count(struct i2s_stream_instance *rtd, int direction) -{ - u64 byte_count; - - if (direction == SNDRV_PCM_STREAM_PLAYBACK) { - byte_count = rv_readl(rtd->acp3x_base + - mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH); - byte_count |= rv_readl(rtd->acp3x_base + - mmACP_BT_TX_LINEARPOSITIONCNTR_LOW); - } else { - byte_count = rv_readl(rtd->acp3x_base + - mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH); - byte_count |= rv_readl(rtd->acp3x_base + - mmACP_BT_RX_LINEARPOSITIONCNTR_LOW); - } - return byte_count; -}
static int acp3x_dma_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, @@ -380,6 +348,7 @@ static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_soc_component *component, static int acp3x_dma_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd) { + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct device *parent = component->dev->parent; snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, parent, MIN_BUFFER, MAX_BUFFER); @@ -402,7 +371,9 @@ static int acp3x_dma_mmap(struct snd_soc_component *component, static int acp3x_dma_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *prtd = substream->private_data; struct i2s_stream_instance *rtd = substream->runtime->private_data; + component = snd_soc_rtdcom_lookup(prtd, DRV_NAME); struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -419,182 +390,6 @@ static int acp3x_dma_close(struct snd_soc_component *component, return 0; }
-static int acp3x_dai_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) -{ - - struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - adata->tdm_mode = false; - break; - case SND_SOC_DAIFMT_DSP_A: - adata->tdm_mode = true; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int acp3x_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, - u32 rx_mask, int slots, int slot_width) -{ - u32 val = 0; - u16 slot_len; - - struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); - - switch (slot_width) { - case SLOT_WIDTH_8: - slot_len = 8; - break; - case SLOT_WIDTH_16: - slot_len = 16; - break; - case SLOT_WIDTH_24: - slot_len = 24; - break; - case SLOT_WIDTH_32: - slot_len = 0; - break; - default: - return -EINVAL; - } - - val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER); - rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_ITER); - val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER); - rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_IRER); - - val = (FRM_LEN | (slots << 15) | (slot_len << 18)); - rv_writel(val, adata->acp3x_base + mmACP_BTTDM_TXFRMT); - rv_writel(val, adata->acp3x_base + mmACP_BTTDM_RXFRMT); - - adata->tdm_fmt = val; - return 0; -} - -static int acp3x_dai_i2s_hwparams(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - u32 val = 0; - struct i2s_stream_instance *rtd = substream->runtime->private_data; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_U8: - case SNDRV_PCM_FORMAT_S8: - rtd->xfer_resolution = 0x0; - break; - case SNDRV_PCM_FORMAT_S16_LE: - rtd->xfer_resolution = 0x02; - break; - case SNDRV_PCM_FORMAT_S24_LE: - rtd->xfer_resolution = 0x04; - break; - case SNDRV_PCM_FORMAT_S32_LE: - rtd->xfer_resolution = 0x05; - break; - default: - return -EINVAL; - } - val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); - val = val | (rtd->xfer_resolution << 3); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); - else - rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); - - return 0; -} - -static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - int ret = 0; - struct i2s_stream_instance *rtd = substream->runtime->private_data; - u32 val, period_bytes; - - period_bytes = frames_to_bytes(substream->runtime, - substream->runtime->period_size); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - rtd->bytescount = acp_get_byte_count(rtd, substream->stream); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - rv_writel(period_bytes, rtd->acp3x_base + - mmACP_BT_TX_INTR_WATERMARK_SIZE); - val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); - val = val | BIT(0); - rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); - } else { - rv_writel(period_bytes, rtd->acp3x_base + - mmACP_BT_RX_INTR_WATERMARK_SIZE); - val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER); - val = val | BIT(0); - rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); - } - rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER); - val = val & ~BIT(0); - rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER); - } else { - val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER); - val = val & ~BIT(0); - rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER); - } - rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static struct snd_soc_dai_ops acp3x_dai_i2s_ops = { - .hw_params = acp3x_dai_i2s_hwparams, - .trigger = acp3x_dai_i2s_trigger, - .set_fmt = acp3x_dai_i2s_set_fmt, - .set_tdm_slot = acp3x_dai_set_tdm_slot, -}; - -static struct snd_soc_dai_driver acp3x_i2s_dai_driver = { - .playback = { - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .channels_min = 2, - .channels_max = 8, - - .rate_min = 8000, - .rate_max = 96000, - }, - .capture = { - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .channels_min = 2, - .channels_max = 2, - .rate_min = 8000, - .rate_max = 48000, - }, - .ops = &acp3x_dai_i2s_ops, -}; - static const struct snd_soc_component_driver acp3x_i2s_component = { .name = DRV_NAME, .open = acp3x_dma_open, @@ -628,31 +423,31 @@ static int acp3x_audio_probe(struct platform_device *pdev)
adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL); if (!adata) - return -ENOMEM; + goto err;
adata->acp3x_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!adata->acp3x_base) + goto base_err;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); - return -ENODEV; + goto io_irq; }
adata->i2s_irq = res->start; - adata->play_stream = NULL; - adata->capture_stream = NULL;
dev_set_drvdata(&pdev->dev, adata); /* Initialize ACP */ status = acp3x_init(adata->acp3x_base); if (status) - return -ENODEV; + goto io_irq; status = devm_snd_soc_register_component(&pdev->dev, &acp3x_i2s_component, - &acp3x_i2s_dai_driver, 1); + NULL, 0); if (status) { - dev_err(&pdev->dev, "Fail to register acp i2s dai\n"); + dev_err(&pdev->dev, "Fail to register acp i2s component\n"); goto dev_err; } status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler, @@ -666,7 +461,24 @@ static int acp3x_audio_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; + +err: + kfree(res); + return -ENOMEM; +base_err: + kfree(res); + kfree(adata); + return -ENOMEM; +io_irq: + kfree(res); + kfree(adata->acp3x_base); + kfree(adata); + return -ENOMEM; + dev_err: + kfree(res); + kfree(adata->acp3x_base); + kfree(adata); status = acp3x_deinit(adata->acp3x_base); if (status) dev_err(&pdev->dev, "ACP de-init failed\n"); @@ -774,13 +586,14 @@ static struct platform_driver acp3x_dma_driver = { .probe = acp3x_audio_probe, .remove = acp3x_audio_remove, .driver = { - .name = "acp3x_rv_i2s", + .name = "acp3x_rv_i2s_dma", .pm = &acp3x_pm_ops, }, };
module_platform_driver(acp3x_dma_driver);
+MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com"); MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver"); diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h index 2f15fe1..72c1a23 100644 --- a/sound/soc/amd/raven/acp3x.h +++ b/sound/soc/amd/raven/acp3x.h @@ -51,6 +51,29 @@ #define SLOT_WIDTH_24 0x18 #define SLOT_WIDTH_32 0x20
+struct acp3x_platform_info { + u16 play_i2s_instance; + u16 cap_i2s_instance; + u16 capture_channel; +}; + +struct i2s_dev_data { + bool tdm_mode; + unsigned int i2s_irq; + u32 tdm_fmt; + void __iomem *acp3x_base; + struct snd_pcm_substream *play_stream; + struct snd_pcm_substream *capture_stream; +}; + +struct i2s_stream_instance { + u16 num_pages; + u16 channels; + u32 xfer_resolution; + u64 bytescount; + dma_addr_t dma_addr; + void __iomem *acp3x_base; +};
static inline u32 rv_readl(void __iomem *base_addr) { @@ -61,3 +84,22 @@ static inline void rv_writel(u32 val, void __iomem *base_addr) { writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS); } + +static inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd, + int direction) +{ + u64 byte_count; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + byte_count = rv_readl(rtd->acp3x_base + + mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH); + byte_count |= rv_readl(rtd->acp3x_base + + mmACP_BT_TX_LINEARPOSITIONCNTR_LOW); + } else { + byte_count = rv_readl(rtd->acp3x_base + + mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH); + byte_count |= rv_readl(rtd->acp3x_base + + mmACP_BT_RX_LINEARPOSITIONCNTR_LOW); + } + return byte_count; +}
- val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
- rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_ITER);
- val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
- rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_IRER);
- val = (FRM_LEN | (slots << 15) | (slot_len << 18));
nit-pick: you have extra parentheses that are not needed for (val | 0x02) and the outer ones on the previous line
+static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
+{
- int ret = 0;
nit-pick: move last, xmas-style
- struct i2s_stream_instance *rtd = substream->runtime->private_data;
- u32 val, period_bytes;
+static int acp3x_dai_probe(struct platform_device *pdev) +{
- int status;
- struct resource *res;
- struct i2s_dev_data *adata;
- adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
GFP_KERNEL);
- if (!adata)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
goto err;
- }
- adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
- if (IS_ERR(adata->acp3x_base))
return PTR_ERR(adata->acp3x_base);
- adata->i2s_irq = res->start;
- dev_set_drvdata(&pdev->dev, adata);
- status = devm_snd_soc_register_component(&pdev->dev,
&acp3x_dai_component,
&acp3x_i2s_dai, 1);
- if (status) {
dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
goto dev_err;
- }
- pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- return 0;
+err:
- kfree(adata);
- return -ENOMEM;
+dev_err:
- kfree(adata->acp3x_base);
- kfree(adata);
- kfree(res);
- return -ENODEV;
this can be improved a bit by using ret = -ENOMEM/-ENODEV before the goto, and organizing the labels and the kfree calls in the reverse order of the initialization/allocation steps.
@@ -666,7 +461,24 @@ static int acp3x_audio_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0;
+err:
- kfree(res);
- return -ENOMEM;
+base_err:
- kfree(res);
- kfree(adata);
- return -ENOMEM;
+io_irq:
- kfree(res);
- kfree(adata->acp3x_base);
- kfree(adata);
- return -ENOMEM;
- dev_err:
- kfree(res);
- kfree(adata->acp3x_base);
- kfree(adata); status = acp3x_deinit(adata->acp3x_base); if (status) dev_err(&pdev->dev, "ACP de-init failed\n");
same here, you should have all the kfrees in the reverse order of the kzalloc, and labels pointing straight at the sequence that needs to be executed. Duplicating the error flow makes it hard to maintain the code and check for memory leaks.
Hi Ravulapati,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on asoc/for-next] [also build test WARNING on next-20191113] [cannot apply to v5.4-rc7] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Ravulapati-Vishnu-vardhan-rao/ASoC-... base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next config: x86_64-randconfig-h001-20191113 (attached as .config) compiler: gcc-7 (Debian 7.4.0-14) 7.4.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64
If you fix the issue, kindly add following tag Reported-by: kbuild test robot lkp@intel.com
All warnings (new ones prefixed by >>):
sound/soc/amd/raven/acp3x-pcm-dma.c: In function 'acp3x_dma_open':
sound/soc/amd/raven/acp3x-pcm-dma.c:268:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
struct i2s_dev_data *adata = dev_get_drvdata(component->dev); ^~~~~~ sound/soc/amd/raven/acp3x-pcm-dma.c: In function 'acp3x_dma_new': sound/soc/amd/raven/acp3x-pcm-dma.c:352:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] struct device *parent = component->dev->parent; ^~~~~~ sound/soc/amd/raven/acp3x-pcm-dma.c: In function 'acp3x_dma_close': sound/soc/amd/raven/acp3x-pcm-dma.c:377:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] struct i2s_dev_data *adata = dev_get_drvdata(component->dev); ^~~~~~
vim +268 sound/soc/amd/raven/acp3x-pcm-dma.c
0b87d6bcd6482b Vijendar Mukunda 2018-11-12 259 f52368f36443b4 Kuninori Morimoto 2019-10-02 260 static int acp3x_dma_open(struct snd_soc_component *component, f52368f36443b4 Kuninori Morimoto 2019-10-02 261 struct snd_pcm_substream *substream) 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 262 { 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 263 int ret = 0; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 264 struct snd_pcm_runtime *runtime = substream->runtime; 74480eceed0f95 Ravulapati Vishnu vardhan rao 2019-11-13 265 struct snd_soc_pcm_runtime *prtd = substream->private_data; 74480eceed0f95 Ravulapati Vishnu vardhan rao 2019-11-13 266 74480eceed0f95 Ravulapati Vishnu vardhan rao 2019-11-13 267 component = snd_soc_rtdcom_lookup(prtd, DRV_NAME); 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 @268 struct i2s_dev_data *adata = dev_get_drvdata(component->dev); 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 269 struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance), 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 270 GFP_KERNEL); 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 271 if (!i2s_data) 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 272 return -EINVAL; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 273 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 274 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 275 runtime->hw = acp3x_pcm_hardware_playback; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 276 else 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 277 runtime->hw = acp3x_pcm_hardware_capture; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 278 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 279 ret = snd_pcm_hw_constraint_integer(runtime, 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 280 SNDRV_PCM_HW_PARAM_PERIODS); 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 281 if (ret < 0) { 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 282 dev_err(component->dev, "set integer constraint failed\n"); 46dce404265975 Colin Ian King 2018-11-14 283 kfree(i2s_data); 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 284 return ret; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 285 } 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 286 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 287 if (!adata->play_stream && !adata->capture_stream) 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 288 rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 289 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 290 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 291 adata->play_stream = substream; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 292 else 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 293 adata->capture_stream = substream; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 294 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 295 i2s_data->acp3x_base = adata->acp3x_base; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 296 runtime->private_data = i2s_data; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 297 return 0; 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 298 } 0b87d6bcd6482b Vijendar Mukunda 2018-11-12 299
:::::: The code at line 268 was first introduced by commit :::::: 0b87d6bcd6482b4502d8fd21561380981dad501f ASoC: amd: add acp3x pcm driver dma ops
:::::: TO: Vijendar Mukunda Vijendar.Mukunda@amd.com :::::: CC: Mark Brown broonie@kernel.org
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
participants (3)
-
kbuild test robot
-
Pierre-Louis Bossart
-
Ravulapati Vishnu vardhan rao