aboutsummaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/Kconfig4
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/amd/Kconfig6
-rw-r--r--sound/soc/amd/Makefile1
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c2
-rw-r--r--sound/soc/amd/acp-pcm-dma.c22
-rw-r--r--sound/soc/amd/acp.h2
-rw-r--r--sound/soc/amd/raven/Makefile6
-rw-r--r--sound/soc/amd/raven/acp3x-pcm-dma.c777
-rw-r--r--sound/soc/amd/raven/acp3x.h58
-rw-r--r--sound/soc/amd/raven/chip_offset_byte.h639
-rw-r--r--sound/soc/amd/raven/pci-acp3x.c156
-rw-r--r--sound/soc/codecs/Kconfig6
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ak4104.c22
-rw-r--r--sound/soc/codecs/ak4118.c438
-rw-r--r--sound/soc/codecs/ak4458.c2
-rw-r--r--sound/soc/codecs/ak5558.c19
-rw-r--r--sound/soc/codecs/cs4270.c23
-rw-r--r--sound/soc/codecs/dmic.c40
-rw-r--r--sound/soc/codecs/hdac_hda.c2
-rw-r--r--sound/soc/codecs/hdac_hdmi.c63
-rw-r--r--sound/soc/codecs/max98373.c35
-rw-r--r--sound/soc/codecs/max9867.c505
-rw-r--r--sound/soc/codecs/max9867.h41
-rw-r--r--sound/soc/codecs/nau8540.c2
-rw-r--r--sound/soc/codecs/nau8822.c26
-rw-r--r--sound/soc/codecs/nau8822.h9
-rw-r--r--sound/soc/codecs/nau8825.c4
-rw-r--r--sound/soc/codecs/pcm3060.c28
-rw-r--r--sound/soc/codecs/pcm3060.h3
-rw-r--r--sound/soc/codecs/pcm3168a.c22
-rw-r--r--sound/soc/codecs/pcm512x.c121
-rw-r--r--sound/soc/codecs/pcm512x.h2
-rw-r--r--sound/soc/codecs/rt5663.c75
-rw-r--r--sound/soc/codecs/simple-amplifier.c4
-rw-r--r--sound/soc/codecs/tas6424.c2
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c2
-rw-r--r--sound/soc/codecs/tlv320aic3x.c10
-rw-r--r--sound/soc/codecs/tlv320dac33.c2
-rw-r--r--sound/soc/codecs/wm8998.c2
-rw-r--r--sound/soc/codecs/wm9705.c10
-rw-r--r--sound/soc/codecs/wm9712.c10
-rw-r--r--sound/soc/codecs/wm9713.c10
-rw-r--r--sound/soc/codecs/wm_adsp.c14
-rw-r--r--sound/soc/davinci/Kconfig106
-rw-r--r--sound/soc/davinci/Makefile16
-rw-r--r--sound/soc/fsl/Kconfig2
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c6
-rw-r--r--sound/soc/fsl/fsl_ssi_dbg.c14
-rw-r--r--sound/soc/generic/Kconfig4
-rw-r--r--sound/soc/generic/audio-graph-card.c465
-rw-r--r--sound/soc/generic/audio-graph-scu-card.c262
-rw-r--r--sound/soc/generic/simple-card-utils.c45
-rw-r--r--sound/soc/generic/simple-card.c402
-rw-r--r--sound/soc/generic/simple-scu-card.c264
-rw-r--r--sound/soc/intel/Kconfig73
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_loader.c8
-rw-r--r--sound/soc/intel/atom/sst/sst_pvt.c4
-rw-r--r--sound/soc/intel/boards/Kconfig26
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c33
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c6
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c6
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c2
-rw-r--r--sound/soc/intel/boards/glk_rt5682_max98357a.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c14
-rw-r--r--sound/soc/intel/boards/kbl_rt5660.c543
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c14
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c10
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c22
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c14
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c14
-rw-r--r--sound/soc/intel/common/Makefile2
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-bxt-match.c36
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-icl-match.c32
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-kbl-match.c10
-rw-r--r--sound/soc/intel/skylake/skl-messages.c8
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c3
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c50
-rw-r--r--sound/soc/intel/skylake/skl.c144
-rw-r--r--sound/soc/intel/skylake/skl.h3
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c2
-rw-r--r--sound/soc/meson/Kconfig9
-rw-r--r--sound/soc/meson/Makefile2
-rw-r--r--sound/soc/meson/axg-fifo.h3
-rw-r--r--sound/soc/meson/axg-spdifin.c521
-rw-r--r--sound/soc/meson/axg-toddr.c15
-rw-r--r--sound/soc/omap/Kconfig129
-rw-r--r--sound/soc/omap/Makefile32
-rw-r--r--sound/soc/omap/am3517evm.c141
-rw-r--r--sound/soc/omap/mcbsp.c1104
-rw-r--r--sound/soc/pxa/Kconfig26
-rw-r--r--sound/soc/pxa/Makefile1
-rw-r--r--sound/soc/pxa/raumfeld.c318
-rw-r--r--sound/soc/qcom/Kconfig2
-rw-r--r--sound/soc/qcom/lpass-platform.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c30
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c4
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c372
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c5
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c9
-rw-r--r--sound/soc/qcom/sdm845.c186
-rw-r--r--sound/soc/sh/rcar/adg.c38
-rw-r--r--sound/soc/sh/rcar/cmd.c11
-rw-r--r--sound/soc/sh/rcar/core.c244
-rw-r--r--sound/soc/sh/rcar/ctu.c138
-rw-r--r--sound/soc/sh/rcar/dma.c84
-rw-r--r--sound/soc/sh/rcar/dvc.c13
-rw-r--r--sound/soc/sh/rcar/gen.c49
-rw-r--r--sound/soc/sh/rcar/mix.c3
-rw-r--r--sound/soc/sh/rcar/rsnd.h382
-rw-r--r--sound/soc/sh/rcar/src.c67
-rw-r--r--sound/soc/sh/rcar/ssi.c269
-rw-r--r--sound/soc/sh/rcar/ssiu.c300
-rw-r--r--sound/soc/soc-core.c13
-rw-r--r--sound/soc/stm/stm32_sai.c8
-rw-r--r--sound/soc/stm/stm32_sai_sub.c3
-rw-r--r--sound/soc/sunxi/sun50i-codec-analog.c2
-rw-r--r--sound/soc/ti/Kconfig209
-rw-r--r--sound/soc/ti/Makefile44
-rw-r--r--sound/soc/ti/ams-delta.c (renamed from sound/soc/omap/ams-delta.c)0
-rw-r--r--sound/soc/ti/davinci-evm.c (renamed from sound/soc/davinci/davinci-evm.c)4
-rw-r--r--sound/soc/ti/davinci-i2s.c (renamed from sound/soc/davinci/davinci-i2s.c)0
-rw-r--r--sound/soc/ti/davinci-i2s.h (renamed from sound/soc/davinci/davinci-i2s.h)0
-rw-r--r--sound/soc/ti/davinci-mcasp.c (renamed from sound/soc/davinci/davinci-mcasp.c)123
-rw-r--r--sound/soc/ti/davinci-mcasp.h (renamed from sound/soc/davinci/davinci-mcasp.h)30
-rw-r--r--sound/soc/ti/davinci-vcif.c (renamed from sound/soc/davinci/davinci-vcif.c)0
-rw-r--r--sound/soc/ti/edma-pcm.c (renamed from sound/soc/davinci/edma-pcm.c)0
-rw-r--r--sound/soc/ti/edma-pcm.h (renamed from sound/soc/davinci/edma-pcm.h)4
-rw-r--r--sound/soc/ti/n810.c (renamed from sound/soc/omap/n810.c)0
-rw-r--r--sound/soc/ti/omap-abe-twl6040.c (renamed from sound/soc/omap/omap-abe-twl6040.c)0
-rw-r--r--sound/soc/ti/omap-dmic.c (renamed from sound/soc/omap/omap-dmic.c)0
-rw-r--r--sound/soc/ti/omap-dmic.h (renamed from sound/soc/omap/omap-dmic.h)0
-rw-r--r--sound/soc/ti/omap-hdmi.c (renamed from sound/soc/omap/omap-hdmi-audio.c)0
-rw-r--r--sound/soc/ti/omap-mcbsp-priv.h (renamed from sound/soc/omap/mcbsp.h)126
-rw-r--r--sound/soc/ti/omap-mcbsp-st.c516
-rw-r--r--sound/soc/ti/omap-mcbsp.c (renamed from sound/soc/omap/omap-mcbsp.c)857
-rw-r--r--sound/soc/ti/omap-mcbsp.h (renamed from sound/soc/omap/omap-mcbsp.h)8
-rw-r--r--sound/soc/ti/omap-mcpdm.c (renamed from sound/soc/omap/omap-mcpdm.c)0
-rw-r--r--sound/soc/ti/omap-mcpdm.h (renamed from sound/soc/omap/omap-mcpdm.h)0
-rw-r--r--sound/soc/ti/omap-twl4030.c (renamed from sound/soc/omap/omap-twl4030.c)0
-rw-r--r--sound/soc/ti/omap3pandora.c (renamed from sound/soc/omap/omap3pandora.c)0
-rw-r--r--sound/soc/ti/osk5912.c (renamed from sound/soc/omap/osk5912.c)0
-rw-r--r--sound/soc/ti/rx51.c (renamed from sound/soc/omap/rx51.c)0
-rw-r--r--sound/soc/ti/sdma-pcm.c (renamed from sound/soc/omap/sdma-pcm.c)0
-rw-r--r--sound/soc/ti/sdma-pcm.h (renamed from sound/soc/omap/sdma-pcm.h)4
-rw-r--r--sound/soc/xilinx/Kconfig8
-rw-r--r--sound/soc/xilinx/Makefile2
-rw-r--r--sound/soc/xilinx/xlnx_i2s.c185
152 files changed, 8754 insertions, 3809 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 1cf11cf51e1d..6592a422a047 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -46,13 +46,11 @@ source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/bcm/Kconfig"
source "sound/soc/cirrus/Kconfig"
-source "sound/soc/davinci/Kconfig"
source "sound/soc/dwc/Kconfig"
source "sound/soc/fsl/Kconfig"
source "sound/soc/hisilicon/Kconfig"
source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig"
-source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/img/Kconfig"
source "sound/soc/intel/Kconfig"
@@ -70,9 +68,11 @@ source "sound/soc/sti/Kconfig"
source "sound/soc/stm/Kconfig"
source "sound/soc/sunxi/Kconfig"
source "sound/soc/tegra/Kconfig"
+source "sound/soc/ti/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/uniphier/Kconfig"
source "sound/soc/ux500/Kconfig"
+source "sound/soc/xilinx/Kconfig"
source "sound/soc/xtensa/Kconfig"
source "sound/soc/zte/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 62a5f87c3cfc..48c48c1c893c 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += bcm/
obj-$(CONFIG_SND_SOC) += cirrus/
-obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += hisilicon/
@@ -41,7 +40,6 @@ obj-$(CONFIG_SND_SOC) += mediatek/
obj-$(CONFIG_SND_SOC) += meson/
obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
-obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += qcom/
@@ -54,8 +52,10 @@ obj-$(CONFIG_SND_SOC) += sti/
obj-$(CONFIG_SND_SOC) += stm/
obj-$(CONFIG_SND_SOC) += sunxi/
obj-$(CONFIG_SND_SOC) += tegra/
+obj-$(CONFIG_SND_SOC) += ti/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += uniphier/
obj-$(CONFIG_SND_SOC) += ux500/
+obj-$(CONFIG_SND_SOC) += xilinx/
obj-$(CONFIG_SND_SOC) += xtensa/
obj-$(CONFIG_SND_SOC) += zte/
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 58c1dcb4d255..33ebec990c2f 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -19,3 +19,9 @@ config SND_SOC_AMD_CZ_RT5645_MACH
depends on SND_SOC_AMD_ACP && I2C
help
This option enables machine driver for rt5645.
+
+config SND_SOC_AMD_ACP3x
+ tristate "AMD Audio Coprocessor-v3.x support"
+ depends on X86 && PCI
+ help
+ This option enables ACP v3.x I2S support on AMD platform
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index 79b0622fa5d3..8e1c571c3161 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -5,3 +5,4 @@ snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
+obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index 3f813ea5210a..a5daad973ce5 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -403,7 +403,7 @@ static struct regulator_config acp_da7219_cfg = {
static struct regulator_ops acp_da7219_ops = {
};
-static struct regulator_desc acp_da7219_desc = {
+static const struct regulator_desc acp_da7219_desc = {
.name = "reg-fixed-1.8V",
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index cdebab2f8ce5..f4011bebc7ec 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -303,11 +303,10 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
}
/* Create page table entries in ACP SRAM for the allocated memory */
-static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
+static void acp_pte_config(void __iomem *acp_mmio, dma_addr_t addr,
u16 num_of_pages, u32 pte_offset)
{
u16 page_idx;
- u64 addr;
u32 low;
u32 high;
u32 offset;
@@ -317,7 +316,6 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
/* Load the low address of page int ACP SRAM through SRBM */
acp_reg_write((offset + (page_idx * 8)),
acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
- addr = page_to_phys(pg);
low = lower_32_bits(addr);
high = upper_32_bits(addr);
@@ -333,7 +331,7 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
/* Move to next physically contiguos page */
- pg++;
+ addr += PAGE_SIZE;
}
}
@@ -343,7 +341,7 @@ static void config_acp_dma(void __iomem *acp_mmio,
{
u16 ch_acp_sysmem, ch_acp_i2s;
- acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
+ acp_pte_config(acp_mmio, rtd->dma_addr, rtd->num_of_pages,
rtd->pte_offset);
if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -850,7 +848,6 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
int status;
uint64_t size;
u32 val = 0;
- struct page *pg;
struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -986,16 +983,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
return status;
memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
- pg = virt_to_page(substream->dma_buffer.area);
- if (pg) {
+ if (substream->dma_buffer.area) {
acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
/* Save for runtime private data */
- rtd->pg = pg;
+ rtd->dma_addr = substream->dma_buffer.addr;
rtd->order = get_order(size);
/* Fill the page table entries in ACP SRAM */
- rtd->pg = pg;
rtd->size = size;
rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
rtd->direction = substream->stream;
@@ -1151,18 +1146,21 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
DRV_NAME);
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
+ struct device *parent = component->dev->parent;
switch (adata->asic_type) {
case CHIP_STONEY:
ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
- NULL, ST_MIN_BUFFER,
+ parent,
+ ST_MIN_BUFFER,
ST_MAX_BUFFER);
break;
default:
ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
- NULL, MIN_BUFFER,
+ parent,
+ MIN_BUFFER,
MAX_BUFFER);
break;
}
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index dbbb1a85638d..e5ab6c6040a6 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -123,7 +123,7 @@ enum acp_dma_priority_level {
};
struct audio_substream_data {
- struct page *pg;
+ dma_addr_t dma_addr;
unsigned int order;
u16 num_of_pages;
u16 i2s_instance;
diff --git a/sound/soc/amd/raven/Makefile b/sound/soc/amd/raven/Makefile
new file mode 100644
index 000000000000..108d1acf189b
--- /dev/null
+++ b/sound/soc/amd/raven/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Raven Ridge platform Support
+snd-pci-acp3x-objs := pci-acp3x.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-pcm-dma.o
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
new file mode 100644
index 000000000000..022a8912c8a2
--- /dev/null
+++ b/sound/soc/amd/raven/acp3x-pcm-dma.c
@@ -0,0 +1,777 @@
+// 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 "acp3x.h"
+
+#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;
+ struct page *pg;
+ void __iomem *acp3x_base;
+};
+
+static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .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,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+ .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+ .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
+ .periods_min = PLAYBACK_MIN_NUM_PERIODS,
+ .periods_max = PLAYBACK_MAX_NUM_PERIODS,
+};
+
+static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .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,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+ .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = CAPTURE_MIN_NUM_PERIODS,
+ .periods_max = CAPTURE_MAX_NUM_PERIODS,
+};
+
+static int acp3x_power_on(void __iomem *acp3x_base, bool on)
+{
+ u16 val, mask;
+ u32 timeout;
+
+ if (on == true) {
+ val = 1;
+ mask = ACP3x_POWER_ON;
+ } else {
+ val = 0;
+ mask = ACP3x_POWER_OFF;
+ }
+
+ rv_writel(val, acp3x_base + mmACP_PGFSM_CONTROL);
+ timeout = 0;
+ while (true) {
+ val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
+ if ((val & ACP3x_POWER_OFF_IN_PROGRESS) == mask)
+ break;
+ if (timeout > 100) {
+ pr_err("ACP3x power state change failure\n");
+ return -ENODEV;
+ }
+ timeout++;
+ cpu_relax();
+ }
+ return 0;
+}
+
+static int acp3x_reset(void __iomem *acp3x_base)
+{
+ u32 val, timeout;
+
+ rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
+ timeout = 0;
+ while (true) {
+ val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
+ if ((val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) ||
+ timeout > 100) {
+ if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
+ break;
+ return -ENODEV;
+ }
+ timeout++;
+ cpu_relax();
+ }
+
+ rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
+ timeout = 0;
+ while (true) {
+ val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
+ if (!val || timeout > 100) {
+ if (!val)
+ break;
+ return -ENODEV;
+ }
+ timeout++;
+ cpu_relax();
+ }
+ return 0;
+}
+
+static int acp3x_init(void __iomem *acp3x_base)
+{
+ int ret;
+
+ /* power on */
+ ret = acp3x_power_on(acp3x_base, true);
+ if (ret) {
+ pr_err("ACP3x power on failed\n");
+ return ret;
+ }
+ /* Reset */
+ ret = acp3x_reset(acp3x_base);
+ if (ret) {
+ pr_err("ACP3x reset failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int acp3x_deinit(void __iomem *acp3x_base)
+{
+ int ret;
+
+ /* Reset */
+ ret = acp3x_reset(acp3x_base);
+ if (ret) {
+ pr_err("ACP3x reset failed\n");
+ return ret;
+ }
+ /* power off */
+ ret = acp3x_power_on(acp3x_base, false);
+ if (ret) {
+ pr_err("ACP3x power off failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
+{
+ u16 play_flag, cap_flag;
+ u32 val;
+ struct i2s_dev_data *rv_i2s_data = dev_id;
+
+ if (!rv_i2s_data)
+ return IRQ_NONE;
+
+ play_flag = 0;
+ cap_flag = 0;
+ val = rv_readl(rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT);
+ if ((val & BIT(BT_TX_THRESHOLD)) && rv_i2s_data->play_stream) {
+ rv_writel(BIT(BT_TX_THRESHOLD), rv_i2s_data->acp3x_base +
+ mmACP_EXTERNAL_INTR_STAT);
+ snd_pcm_period_elapsed(rv_i2s_data->play_stream);
+ play_flag = 1;
+ }
+
+ if ((val & BIT(BT_RX_THRESHOLD)) && rv_i2s_data->capture_stream) {
+ rv_writel(BIT(BT_RX_THRESHOLD), rv_i2s_data->acp3x_base +
+ mmACP_EXTERNAL_INTR_STAT);
+ snd_pcm_period_elapsed(rv_i2s_data->capture_stream);
+ cap_flag = 1;
+ }
+
+ if (play_flag | cap_flag)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
+{
+ u16 page_idx;
+ u64 addr;
+ u32 low, high, val, acp_fifo_addr;
+ struct page *pg = rtd->pg;
+
+ /* 8 scratch registers used to map one 64 bit address */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ val = 0;
+ else
+ val = rtd->num_pages * 8;
+
+ /* Group Enable */
+ rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base +
+ mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
+ rv_writel(PAGE_SIZE_4K_ENABLE, rtd->acp3x_base +
+ mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
+
+ for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
+ /* Load the low address of page int ACP SRAM through SRBM */
+ addr = page_to_phys(pg);
+ low = lower_32_bits(addr);
+ high = upper_32_bits(addr);
+
+ rv_writel(low, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val);
+ high |= BIT(31);
+ rv_writel(high, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val
+ + 4);
+ /* Move to next physically contiguos page */
+ val += 8;
+ pg++;
+ }
+
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* Config ringbuffer */
+ rv_writel(MEM_WINDOW_START, rtd->acp3x_base +
+ mmACP_BT_TX_RINGBUFADDR);
+ rv_writel(MAX_BUFFER, rtd->acp3x_base +
+ mmACP_BT_TX_RINGBUFSIZE);
+ rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_TX_DMA_SIZE);
+
+ /* Config audio fifo */
+ acp_fifo_addr = ACP_SRAM_PTE_OFFSET + (rtd->num_pages * 8)
+ + PLAYBACK_FIFO_ADDR_OFFSET;
+ rv_writel(acp_fifo_addr, rtd->acp3x_base +
+ mmACP_BT_TX_FIFOADDR);
+ rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_TX_FIFOSIZE);
+ } else {
+ /* Config ringbuffer */
+ rv_writel(MEM_WINDOW_START + MAX_BUFFER, rtd->acp3x_base +
+ mmACP_BT_RX_RINGBUFADDR);
+ rv_writel(MAX_BUFFER, rtd->acp3x_base +
+ mmACP_BT_RX_RINGBUFSIZE);
+ rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_RX_DMA_SIZE);
+
+ /* Config audio fifo */
+ acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+ (rtd->num_pages * 8) + CAPTURE_FIFO_ADDR_OFFSET;
+ rv_writel(acp_fifo_addr, rtd->acp3x_base +
+ mmACP_BT_RX_FIFOADDR);
+ rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_RX_FIFOSIZE);
+ }
+
+ /* Enable watermark/period interrupt to host */
+ rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD),
+ rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
+}
+
+static int acp3x_dma_open(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *prtd = substream->private_data;
+ struct snd_soc_component *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);
+ if (!i2s_data)
+ return -EINVAL;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ runtime->hw = acp3x_pcm_hardware_playback;
+ else
+ runtime->hw = acp3x_pcm_hardware_capture;
+
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ dev_err(component->dev, "set integer constraint failed\n");
+ kfree(i2s_data);
+ return ret;
+ }
+
+ if (!adata->play_stream && !adata->capture_stream)
+ rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ adata->play_stream = substream;
+ else
+ adata->capture_stream = substream;
+
+ i2s_data->acp3x_base = adata->acp3x_base;
+ runtime->private_data = i2s_data;
+ return 0;
+}
+
+static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int status;
+ u64 size;
+ struct page *pg;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct i2s_stream_instance *rtd = runtime->private_data;
+
+ if (!rtd)
+ return -EINVAL;
+
+ size = params_buffer_bytes(params);
+ status = snd_pcm_lib_malloc_pages(substream, size);
+ if (status < 0)
+ return status;
+
+ memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+ pg = virt_to_page(substream->dma_buffer.area);
+ if (pg) {
+ rtd->pg = pg;
+ rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
+ config_acp3x_dma(rtd, substream->stream);
+ status = 0;
+ } else {
+ status = -ENOMEM;
+ }
+ return status;
+}
+
+static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
+{
+ u32 pos = 0;
+ struct i2s_stream_instance *rtd = substream->runtime->private_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pos = rv_readl(rtd->acp3x_base +
+ mmACP_BT_TX_LINKPOSITIONCNTR);
+ else
+ pos = rv_readl(rtd->acp3x_base +
+ mmACP_BT_RX_LINKPOSITIONCNTR);
+
+ if (pos >= MAX_BUFFER)
+ pos = 0;
+
+ return bytes_to_frames(substream->runtime, pos);
+}
+
+static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
+{
+ return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+ SNDRV_DMA_TYPE_DEV,
+ NULL, MIN_BUFFER,
+ MAX_BUFFER);
+}
+
+static int acp3x_dma_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int acp3x_dma_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static int acp3x_dma_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *prtd = substream->private_data;
+ struct i2s_stream_instance *rtd = substream->runtime->private_data;
+ struct snd_soc_component *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)
+ adata->play_stream = NULL;
+ else
+ adata->capture_stream = NULL;
+
+ /* Disable ACP irq, when the current stream is being closed and
+ * another stream is also not active.
+ */
+ if (!adata->play_stream && !adata->capture_stream)
+ rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+ kfree(rtd);
+ return 0;
+}
+
+static struct snd_pcm_ops acp3x_dma_ops = {
+ .open = acp3x_dma_open,
+ .close = acp3x_dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = acp3x_dma_hw_params,
+ .hw_free = acp3x_dma_hw_free,
+ .pointer = acp3x_dma_pointer,
+ .mmap = acp3x_dma_mmap,
+};
+
+
+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:
+ 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;
+}
+
+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,
+ .ops = &acp3x_dma_ops,
+ .pcm_new = acp3x_dma_new,
+};
+
+static int acp3x_audio_probe(struct platform_device *pdev)
+{
+ int status;
+ struct resource *res;
+ struct i2s_dev_data *adata;
+ unsigned int irqflags;
+
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "platform_data not retrieved\n");
+ return -ENODEV;
+ }
+ irqflags = *((unsigned int *)(pdev->dev.platform_data));
+
+ adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
+ GFP_KERNEL);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+ return -ENODEV;
+ }
+
+ adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+ return -ENODEV;
+ }
+
+ 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;
+ status = devm_snd_soc_register_component(&pdev->dev,
+ &acp3x_i2s_component,
+ &acp3x_i2s_dai_driver, 1);
+ if (status) {
+ dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
+ goto dev_err;
+ }
+ status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler,
+ irqflags, "ACP3x_I2S_IRQ", adata);
+ if (status) {
+ dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\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;
+dev_err:
+ status = acp3x_deinit(adata->acp3x_base);
+ if (status)
+ dev_err(&pdev->dev, "ACP de-init failed\n");
+ else
+ dev_info(&pdev->dev, "ACP de-initialized\n");
+ /*ignore device status and return driver probe error*/
+ return -ENODEV;
+}
+
+static int acp3x_audio_remove(struct platform_device *pdev)
+{
+ int ret;
+ struct i2s_dev_data *adata = dev_get_drvdata(&pdev->dev);
+
+ ret = acp3x_deinit(adata->acp3x_base);
+ if (ret)
+ dev_err(&pdev->dev, "ACP de-init failed\n");
+ else
+ dev_info(&pdev->dev, "ACP de-initialized\n");
+
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static int acp3x_resume(struct device *dev)
+{
+ int status;
+ u32 val;
+ struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+ status = acp3x_init(adata->acp3x_base);
+ if (status)
+ return -ENODEV;
+
+ if (adata->play_stream && adata->play_stream->runtime) {
+ struct i2s_stream_instance *rtd =
+ adata->play_stream->runtime->private_data;
+ config_acp3x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
+ rv_writel((rtd->xfer_resolution << 3),
+ rtd->acp3x_base + mmACP_BTTDM_ITER);
+ if (adata->tdm_mode == true) {
+ rv_writel(adata->tdm_fmt, adata->acp3x_base +
+ mmACP_BTTDM_TXFRMT);
+ val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
+ rv_writel((val | 0x2), adata->acp3x_base +
+ mmACP_BTTDM_ITER);
+ }
+ }
+
+ if (adata->capture_stream && adata->capture_stream->runtime) {
+ struct i2s_stream_instance *rtd =
+ adata->capture_stream->runtime->private_data;
+ config_acp3x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
+ rv_writel((rtd->xfer_resolution << 3),
+ rtd->acp3x_base + mmACP_BTTDM_IRER);
+ if (adata->tdm_mode == true) {
+ rv_writel(adata->tdm_fmt, adata->acp3x_base +
+ mmACP_BTTDM_RXFRMT);
+ val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
+ rv_writel((val | 0x2), adata->acp3x_base +
+ mmACP_BTTDM_IRER);
+ }
+ }
+
+ rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+ return 0;
+}
+
+
+static int acp3x_pcm_runtime_suspend(struct device *dev)
+{
+ int status;
+ struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+ status = acp3x_deinit(adata->acp3x_base);
+ if (status)
+ dev_err(dev, "ACP de-init failed\n");
+ else
+ dev_info(dev, "ACP de-initialized\n");
+
+ rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+
+ return 0;
+}
+
+static int acp3x_pcm_runtime_resume(struct device *dev)
+{
+ int status;
+ struct i2s_dev_data *adata = dev_get_drvdata(dev);
+
+ status = acp3x_init(adata->acp3x_base);
+ if (status)
+ return -ENODEV;
+ rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
+ return 0;
+}
+
+static const struct dev_pm_ops acp3x_pm_ops = {
+ .runtime_suspend = acp3x_pcm_runtime_suspend,
+ .runtime_resume = acp3x_pcm_runtime_resume,
+ .resume = acp3x_resume,
+};
+
+static struct platform_driver acp3x_dma_driver = {
+ .probe = acp3x_audio_probe,
+ .remove = acp3x_audio_remove,
+ .driver = {
+ .name = "acp3x_rv_i2s",
+ .pm = &acp3x_pm_ops,
+ },
+};
+
+module_platform_driver(acp3x_dma_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_AUTHOR("Vijendar.Mukunda@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.h b/sound/soc/amd/raven/acp3x.h
new file mode 100644
index 000000000000..4f2cadd90a87
--- /dev/null
+++ b/sound/soc/amd/raven/acp3x.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * AMD ALSA SoC PCM Driver
+ *
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ */
+
+#include "chip_offset_byte.h"
+
+#define ACP3x_PHY_BASE_ADDRESS 0x1240000
+#define ACP3x_I2S_MODE 0
+#define ACP3x_REG_START 0x1240000
+#define ACP3x_REG_END 0x1250200
+#define I2S_MODE 0x04
+#define BT_TX_THRESHOLD 26
+#define BT_RX_THRESHOLD 25
+#define ACP3x_POWER_ON 0x00
+#define ACP3x_POWER_ON_IN_PROGRESS 0x01
+#define ACP3x_POWER_OFF 0x02
+#define ACP3x_POWER_OFF_IN_PROGRESS 0x03
+#define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001
+
+#define ACP_SRAM_PTE_OFFSET 0x02050000
+#define PAGE_SIZE_4K_ENABLE 0x2
+#define MEM_WINDOW_START 0x4000000
+#define PLAYBACK_FIFO_ADDR_OFFSET 0x400
+#define CAPTURE_FIFO_ADDR_OFFSET 0x500
+
+#define PLAYBACK_MIN_NUM_PERIODS 2
+#define PLAYBACK_MAX_NUM_PERIODS 8
+#define PLAYBACK_MAX_PERIOD_SIZE 16384
+#define PLAYBACK_MIN_PERIOD_SIZE 4096
+#define CAPTURE_MIN_NUM_PERIODS 2
+#define CAPTURE_MAX_NUM_PERIODS 8
+#define CAPTURE_MAX_PERIOD_SIZE 16384
+#define CAPTURE_MIN_PERIOD_SIZE 4096
+
+#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
+#define MIN_BUFFER MAX_BUFFER
+#define FIFO_SIZE 0x100
+#define DMA_SIZE 0x40
+#define FRM_LEN 0x100
+
+#define SLOT_WIDTH_8 0x08
+#define SLOT_WIDTH_16 0x10
+#define SLOT_WIDTH_24 0x18
+#define SLOT_WIDTH_32 0x20
+
+
+static inline u32 rv_readl(void __iomem *base_addr)
+{
+ return readl(base_addr - ACP3x_PHY_BASE_ADDRESS);
+}
+
+static inline void rv_writel(u32 val, void __iomem *base_addr)
+{
+ writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS);
+}
diff --git a/sound/soc/amd/raven/chip_offset_byte.h b/sound/soc/amd/raven/chip_offset_byte.h
new file mode 100644
index 000000000000..9c1fac58fb2a
--- /dev/null
+++ b/sound/soc/amd/raven/chip_offset_byte.h
@@ -0,0 +1,639 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * AMD ACP 3.0 Register Documentation
+ *
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _acp_ip_OFFSET_HEADER
+#define _acp_ip_OFFSET_HEADER
+// Registers from ACP_DMA block
+
+#define mmACP_DMA_CNTL_0 0x1240000
+#define mmACP_DMA_CNTL_1 0x1240004
+#define mmACP_DMA_CNTL_2 0x1240008
+#define mmACP_DMA_CNTL_3 0x124000C
+#define mmACP_DMA_CNTL_4 0x1240010
+#define mmACP_DMA_CNTL_5 0x1240014
+#define mmACP_DMA_CNTL_6 0x1240018
+#define mmACP_DMA_CNTL_7 0x124001C
+#define mmACP_DMA_DSCR_STRT_IDX_0 0x1240020
+#define mmACP_DMA_DSCR_STRT_IDX_1 0x1240024
+#define mmACP_DMA_DSCR_STRT_IDX_2 0x1240028
+#define mmACP_DMA_DSCR_STRT_IDX_3 0x124002C
+#define mmACP_DMA_DSCR_STRT_IDX_4 0x1240030
+#define mmACP_DMA_DSCR_STRT_IDX_5 0x1240034
+#define mmACP_DMA_DSCR_STRT_IDX_6 0x1240038
+#define mmACP_DMA_DSCR_STRT_IDX_7 0x124003C
+#define mmACP_DMA_DSCR_CNT_0 0x1240040
+#define mmACP_DMA_DSCR_CNT_1 0x1240044
+#define mmACP_DMA_DSCR_CNT_2 0x1240048
+#define mmACP_DMA_DSCR_CNT_3 0x124004C
+#define mmACP_DMA_DSCR_CNT_4 0x1240050
+#define mmACP_DMA_DSCR_CNT_5 0x1240054
+#define mmACP_DMA_DSCR_CNT_6 0x1240058
+#define mmACP_DMA_DSCR_CNT_7 0x124005C
+#define mmACP_DMA_PRIO_0 0x1240060
+#define mmACP_DMA_PRIO_1 0x1240064
+#define mmACP_DMA_PRIO_2 0x1240068
+#define mmACP_DMA_PRIO_3 0x124006C
+#define mmACP_DMA_PRIO_4 0x1240070
+#define mmACP_DMA_PRIO_5 0x1240074
+#define mmACP_DMA_PRIO_6 0x1240078
+#define mmACP_DMA_PRIO_7 0x124007C
+#define mmACP_DMA_CUR_DSCR_0 0x1240080
+#define mmACP_DMA_CUR_DSCR_1 0x1240084
+#define mmACP_DMA_CUR_DSCR_2 0x1240088
+#define mmACP_DMA_CUR_DSCR_3 0x124008C
+#define mmACP_DMA_CUR_DSCR_4 0x1240090
+#define mmACP_DMA_CUR_DSCR_5 0x1240094
+#define mmACP_DMA_CUR_DSCR_6 0x1240098
+#define mmACP_DMA_CUR_DSCR_7 0x124009C
+#define mmACP_DMA_CUR_TRANS_CNT_0 0x12400A0
+#define mmACP_DMA_CUR_TRANS_CNT_1 0x12400A4
+#define mmACP_DMA_CUR_TRANS_CNT_2 0x12400A8
+#define mmACP_DMA_CUR_TRANS_CNT_3 0x12400AC
+#define mmACP_DMA_CUR_TRANS_CNT_4 0x12400B0
+#define mmACP_DMA_CUR_TRANS_CNT_5 0x12400B4
+#define mmACP_DMA_CUR_TRANS_CNT_6 0x12400B8
+#define mmACP_DMA_CUR_TRANS_CNT_7 0x12400BC
+#define mmACP_DMA_ERR_STS_0 0x12400C0
+#define mmACP_DMA_ERR_STS_1 0x12400C4
+#define mmACP_DMA_ERR_STS_2 0x12400C8
+#define mmACP_DMA_ERR_STS_3 0x12400CC
+#define mmACP_DMA_ERR_STS_4 0x12400D0
+#define mmACP_DMA_ERR_STS_5 0x12400D4
+#define mmACP_DMA_ERR_STS_6 0x12400D8
+#define mmACP_DMA_ERR_STS_7 0x12400DC
+#define mmACP_DMA_DESC_BASE_ADDR 0x12400E0
+#define mmACP_DMA_DESC_MAX_NUM_DSCR 0x12400E4
+#define mmACP_DMA_CH_STS 0x12400E8
+#define mmACP_DMA_CH_GROUP 0x12400EC
+#define mmACP_DMA_CH_RST_STS 0x12400F0
+
+
+// Registers from ACP_AXI2AXIATU block
+
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0x1240C00
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0x1240C04
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0x1240C08
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0x1240C0C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0x1240C10
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0x1240C14
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0x1240C18
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0x1240C1C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0x1240C20
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0x1240C24
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0x1240C28
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0x1240C2C
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0x1240C30
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0x1240C34
+#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0x1240C38
+#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0x1240C3C
+#define mmACPAXI2AXI_ATU_CTRL 0x1240C40
+
+
+// Registers from ACP_CLKRST block
+
+#define mmACP_SOFT_RESET 0x1241000
+#define mmACP_CONTROL 0x1241004
+#define mmACP_STATUS 0x1241008
+#define mmACP_DSP0_OCD_HALT_ON_RST 0x124100C
+#define mmACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010
+
+
+// Registers from ACP_MISC block
+
+#define mmACP_EXTERNAL_INTR_ENB 0x1241800
+#define mmACP_EXTERNAL_INTR_CNTL 0x1241804
+#define mmACP_EXTERNAL_INTR_STAT 0x1241808
+#define mmACP_DSP0_INTR_CNTL 0x124180C
+#define mmACP_DSP0_INTR_STAT 0x1241810
+#define mmACP_DSP_SW_INTR_CNTL 0x1241814
+#define mmACP_DSP_SW_INTR_STAT 0x1241818
+#define mmACP_SW_INTR_TRIG 0x124181C
+#define mmACP_SMU_MAILBOX 0x1241820
+#define mmDSP_INTERRUPT_ROUTING_CTRL 0x1241824
+#define mmACP_DSP0_WATCHDOG_TIMER_CNTL 0x1241828
+#define mmACP_DSP0_EXT_TIMER1_CNTL 0x124182C
+#define mmACP_DSP0_EXT_TIMER2_CNTL 0x1241830
+#define mmACP_DSP0_EXT_TIMER3_CNTL 0x1241834
+#define mmACP_DSP0_EXT_TIMER4_CNTL 0x1241838
+#define mmACP_DSP0_EXT_TIMER5_CNTL 0x124183C
+#define mmACP_DSP0_EXT_TIMER6_CNTL 0x1241840
+#define mmACP_DSP0_EXT_TIMER1_CURR_VALUE 0x1241844
+#define mmACP_DSP0_EXT_TIMER2_CURR_VALUE 0x1241848
+#define mmACP_DSP0_EXT_TIMER3_CURR_VALUE 0x124184C
+#define mmACP_DSP0_EXT_TIMER4_CURR_VALUE 0x1241850
+#define mmACP_DSP0_EXT_TIMER5_CURR_VALUE 0x1241854
+#define mmACP_DSP0_EXT_TIMER6_CURR_VALUE 0x1241858
+#define mmACP_FW_STATUS 0x124185C
+#define mmACP_TIMER 0x1241874
+#define mmACP_TIMER_CNTL 0x1241878
+#define mmACP_PGMEM_CTRL 0x12418C0
+#define mmACP_ERROR_STATUS 0x12418C4
+#define mmACP_SW_I2S_ERROR_REASON 0x12418C8
+#define mmACP_MEM_PG_STS 0x12418CC
+
+
+// Registers from ACP_PGFSM block
+
+#define mmACP_I2S_PIN_CONFIG 0x1241400
+#define mmACP_PAD_PULLUP_PULLDOWN_CTRL 0x1241404
+#define mmACP_PAD_DRIVE_STRENGTH_CTRL 0x1241408
+#define mmACP_SW_PAD_KEEPER_EN 0x124140C
+#define mmACP_SW_WAKE_EN 0x1241410
+#define mmACP_I2S_WAKE_EN 0x1241414
+#define mmACP_PME_EN 0x1241418
+#define mmACP_PGFSM_CONTROL 0x124141C
+#define mmACP_PGFSM_STATUS 0x1241420
+
+
+// Registers from ACP_SCRATCH block
+
+#define mmACP_SCRATCH_REG_0 0x1250000
+#define mmACP_SCRATCH_REG_1 0x1250004
+#define mmACP_SCRATCH_REG_2 0x1250008
+#define mmACP_SCRATCH_REG_3 0x125000C
+#define mmACP_SCRATCH_REG_4 0x1250010
+#define mmACP_SCRATCH_REG_5 0x1250014
+#define mmACP_SCRATCH_REG_6 0x1250018
+#define mmACP_SCRATCH_REG_7 0x125001C
+#define mmACP_SCRATCH_REG_8 0x1250020
+#define mmACP_SCRATCH_REG_9 0x1250024
+#define mmACP_SCRATCH_REG_10 0x1250028
+#define mmACP_SCRATCH_REG_11 0x125002C
+#define mmACP_SCRATCH_REG_12 0x1250030
+#define mmACP_SCRATCH_REG_13 0x1250034
+#define mmACP_SCRATCH_REG_14 0x1250038
+#define mmACP_SCRATCH_REG_15 0x125003C
+#define mmACP_SCRATCH_REG_16 0x1250040
+#define mmACP_SCRATCH_REG_17 0x1250044
+#define mmACP_SCRATCH_REG_18 0x1250048
+#define mmACP_SCRATCH_REG_19 0x125004C
+#define mmACP_SCRATCH_REG_20 0x1250050
+#define mmACP_SCRATCH_REG_21 0x1250054
+#define mmACP_SCRATCH_REG_22 0x1250058
+#define mmACP_SCRATCH_REG_23 0x125005C
+#define mmACP_SCRATCH_REG_24 0x1250060
+#define mmACP_SCRATCH_REG_25 0x1250064
+#define mmACP_SCRATCH_REG_26 0x1250068
+#define mmACP_SCRATCH_REG_27 0x125006C
+#define mmACP_SCRATCH_REG_28 0x1250070
+#define mmACP_SCRATCH_REG_29 0x1250074
+#define mmACP_SCRATCH_REG_30 0x1250078
+#define mmACP_SCRATCH_REG_31 0x125007C
+#define mmACP_SCRATCH_REG_32 0x1250080
+#define mmACP_SCRATCH_REG_33 0x1250084
+#define mmACP_SCRATCH_REG_34 0x1250088
+#define mmACP_SCRATCH_REG_35 0x125008C
+#define mmACP_SCRATCH_REG_36 0x1250090
+#define mmACP_SCRATCH_REG_37 0x1250094
+#define mmACP_SCRATCH_REG_38 0x1250098
+#define mmACP_SCRATCH_REG_39 0x125009C
+#define mmACP_SCRATCH_REG_40 0x12500A0
+#define mmACP_SCRATCH_REG_41 0x12500A4
+#define mmACP_SCRATCH_REG_42 0x12500A8
+#define mmACP_SCRATCH_REG_43 0x12500AC
+#define mmACP_SCRATCH_REG_44 0x12500B0
+#define mmACP_SCRATCH_REG_45 0x12500B4
+#define mmACP_SCRATCH_REG_46 0x12500B8
+#define mmACP_SCRATCH_REG_47 0x12500BC
+#define mmACP_SCRATCH_REG_48 0x12500C0
+#define mmACP_SCRATCH_REG_49 0x12500C4
+#define mmACP_SCRATCH_REG_50 0x12500C8
+#define mmACP_SCRATCH_REG_51 0x12500CC
+#define mmACP_SCRATCH_REG_52 0x12500D0
+#define mmACP_SCRATCH_REG_53 0x12500D4
+#define mmACP_SCRATCH_REG_54 0x12500D8
+#define mmACP_SCRATCH_REG_55 0x12500DC
+#define mmACP_SCRATCH_REG_56 0x12500E0
+#define mmACP_SCRATCH_REG_57 0x12500E4
+#define mmACP_SCRATCH_REG_58 0x12500E8
+#define mmACP_SCRATCH_REG_59 0x12500EC
+#define mmACP_SCRATCH_REG_60 0x12500F0
+#define mmACP_SCRATCH_REG_61 0x12500F4
+#define mmACP_SCRATCH_REG_62 0x12500F8
+#define mmACP_SCRATCH_REG_63 0x12500FC
+#define mmACP_SCRATCH_REG_64 0x1250100
+#define mmACP_SCRATCH_REG_65 0x1250104
+#define mmACP_SCRATCH_REG_66 0x1250108
+#define mmACP_SCRATCH_REG_67 0x125010C
+#define mmACP_SCRATCH_REG_68 0x1250110
+#define mmACP_SCRATCH_REG_69 0x1250114
+#define mmACP_SCRATCH_REG_70 0x1250118
+#define mmACP_SCRATCH_REG_71 0x125011C
+#define mmACP_SCRATCH_REG_72 0x1250120
+#define mmACP_SCRATCH_REG_73 0x1250124
+#define mmACP_SCRATCH_REG_74 0x1250128
+#define mmACP_SCRATCH_REG_75 0x125012C
+#define mmACP_SCRATCH_REG_76 0x1250130
+#define mmACP_SCRATCH_REG_77 0x1250134
+#define mmACP_SCRATCH_REG_78 0x1250138
+#define mmACP_SCRATCH_REG_79 0x125013C
+#define mmACP_SCRATCH_REG_80 0x1250140
+#define mmACP_SCRATCH_REG_81 0x1250144
+#define mmACP_SCRATCH_REG_82 0x1250148
+#define mmACP_SCRATCH_REG_83 0x125014C
+#define mmACP_SCRATCH_REG_84 0x1250150
+#define mmACP_SCRATCH_REG_85 0x1250154
+#define mmACP_SCRATCH_REG_86 0x1250158
+#define mmACP_SCRATCH_REG_87 0x125015C
+#define mmACP_SCRATCH_REG_88 0x1250160
+#define mmACP_SCRATCH_REG_89 0x1250164
+#define mmACP_SCRATCH_REG_90 0x1250168
+#define mmACP_SCRATCH_REG_91 0x125016C
+#define mmACP_SCRATCH_REG_92 0x1250170
+#define mmACP_SCRATCH_REG_93 0x1250174
+#define mmACP_SCRATCH_REG_94 0x1250178
+#define mmACP_SCRATCH_REG_95 0x125017C
+#define mmACP_SCRATCH_REG_96 0x1250180
+#define mmACP_SCRATCH_REG_97 0x1250184
+#define mmACP_SCRATCH_REG_98 0x1250188
+#define mmACP_SCRATCH_REG_99 0x125018C
+#define mmACP_SCRATCH_REG_100 0x1250190
+#define mmACP_SCRATCH_REG_101 0x1250194
+#define mmACP_SCRATCH_REG_102 0x1250198
+#define mmACP_SCRATCH_REG_103 0x125019C
+#define mmACP_SCRATCH_REG_104 0x12501A0
+#define mmACP_SCRATCH_REG_105 0x12501A4
+#define mmACP_SCRATCH_REG_106 0x12501A8
+#define mmACP_SCRATCH_REG_107 0x12501AC
+#define mmACP_SCRATCH_REG_108 0x12501B0
+#define mmACP_SCRATCH_REG_109 0x12501B4
+#define mmACP_SCRATCH_REG_110 0x12501B8
+#define mmACP_SCRATCH_REG_111 0x12501BC
+#define mmACP_SCRATCH_REG_112 0x12501C0
+#define mmACP_SCRATCH_REG_113 0x12501C4
+#define mmACP_SCRATCH_REG_114 0x12501C8
+#define mmACP_SCRATCH_REG_115 0x12501CC
+#define mmACP_SCRATCH_REG_116 0x12501D0
+#define mmACP_SCRATCH_REG_117 0x12501D4
+#define mmACP_SCRATCH_REG_118 0x12501D8
+#define mmACP_SCRATCH_REG_119 0x12501DC
+#define mmACP_SCRATCH_REG_120 0x12501E0
+#define mmACP_SCRATCH_REG_121 0x12501E4
+#define mmACP_SCRATCH_REG_122 0x12501E8
+#define mmACP_SCRATCH_REG_123 0x12501EC
+#define mmACP_SCRATCH_REG_124 0x12501F0
+#define mmACP_SCRATCH_REG_125 0x12501F4
+#define mmACP_SCRATCH_REG_126 0x12501F8
+#define mmACP_SCRATCH_REG_127 0x12501FC
+#define mmACP_SCRATCH_REG_128 0x1250200
+
+
+// Registers from ACP_SW_ACLK block
+
+#define mmSW_CORB_Base_Address 0x1243200
+#define mmSW_CORB_Write_Pointer 0x1243204
+#define mmSW_CORB_Read_Pointer 0x1243208
+#define mmSW_CORB_Control 0x124320C
+#define mmSW_CORB_Size 0x1243214
+#define mmSW_RIRB_Base_Address 0x1243218
+#define mmSW_RIRB_Write_Pointer 0x124321C
+#define mmSW_RIRB_Response_Interrupt_Count 0x1243220
+#define mmSW_RIRB_Control 0x1243224
+#define mmSW_RIRB_Size 0x1243228
+#define mmSW_RIRB_FIFO_MIN_THDL 0x124322C
+#define mmSW_imm_cmd_UPPER_WORD 0x1243230
+#define mmSW_imm_cmd_LOWER_QWORD 0x1243234
+#define mmSW_imm_resp_UPPER_WORD 0x1243238
+#define mmSW_imm_resp_LOWER_QWORD 0x124323C
+#define mmSW_imm_cmd_sts 0x1243240
+#define mmSW_BRA_BASE_ADDRESS 0x1243244
+#define mmSW_BRA_TRANSFER_SIZE 0x1243248
+#define mmSW_BRA_DMA_BUSY 0x124324C
+#define mmSW_BRA_RESP 0x1243250
+#define mmSW_BRA_RESP_FRAME_ADDR 0x1243254
+#define mmSW_BRA_CURRENT_TRANSFER_SIZE 0x1243258
+#define mmSW_STATE_CHANGE_STATUS_0TO7 0x124325C
+#define mmSW_STATE_CHANGE_STATUS_8TO11 0x1243260
+#define mmSW_STATE_CHANGE_STATUS_MASK_0to7 0x1243264
+#define mmSW_STATE_CHANGE_STATUS_MASK_8to11 0x1243268
+#define mmSW_CLK_FREQUENCY_CTRL 0x124326C
+#define mmSW_ERROR_INTR_MASK 0x1243270
+#define mmSW_PHY_TEST_MODE_DATA_OFF 0x1243274
+
+
+// Registers from ACP_SW_SWCLK block
+
+#define mmACP_SW_EN 0x1243000
+#define mmACP_SW_EN_STATUS 0x1243004
+#define mmACP_SW_FRAMESIZE 0x1243008
+#define mmACP_SW_SSP_Counter 0x124300C
+#define mmACP_SW_Audio_TX_EN 0x1243010
+#define mmACP_SW_Audio_TX_EN_STATUS 0x1243014
+#define mmACP_SW_Audio_TX_Frame_Format 0x1243018
+#define mmACP_SW_Audio_TX_SampleInterval 0x124301C
+#define mmACP_SW_Audio_TX_Hctrl_DP0 0x1243020
+#define mmACP_SW_Audio_TX_Hctrl_DP1 0x1243024
+#define mmACP_SW_Audio_TX_Hctrl_DP2 0x1243028
+#define mmACP_SW_Audio_TX_Hctrl_DP3 0x124302C
+#define mmACP_SW_Audio_TX_offset_DP0 0x1243030
+#define mmACP_SW_Audio_TX_offset_DP1 0x1243034
+#define mmACP_SW_Audio_TX_offset_DP2 0x1243038
+#define mmACP_SW_Audio_TX_offset_DP3 0x124303C
+#define mmACP_SW_Audio_TX_Channel_Enable_DP0 0x1243040
+#define mmACP_SW_Audio_TX_Channel_Enable_DP1 0x1243044
+#define mmACP_SW_Audio_TX_Channel_Enable_DP2 0x1243048
+#define mmACP_SW_Audio_TX_Channel_Enable_DP3 0x124304C
+#define mmACP_SW_BT_TX_EN 0x1243050
+#define mmACP_SW_BT_TX_EN_STATUS 0x1243054
+#define mmACP_SW_BT_TX_Frame_Format 0x1243058
+#define mmACP_SW_BT_TX_SampleInterval 0x124305C
+#define mmACP_SW_BT_TX_Hctrl 0x1243060
+#define mmACP_SW_BT_TX_offset 0x1243064
+#define mmACP_SW_BT_TX_Channel_Enable_DP0 0x1243068
+#define mmACP_SW_Headset_TX_EN 0x124306C
+#define mmACP_SW_Headset_TX_EN_STATUS 0x1243070
+#define mmACP_SW_Headset_TX_Frame_Format 0x1243074
+#define mmACP_SW_Headset_TX_SampleInterval 0x1243078
+#define mmACP_SW_Headset_TX_Hctrl 0x124307C
+#define mmACP_SW_Headset_TX_offset 0x1243080
+#define mmACP_SW_Headset_TX_Channel_Enable_DP0 0x1243084
+#define mmACP_SW_Audio_RX_EN 0x1243088
+#define mmACP_SW_Audio_RX_EN_STATUS 0x124308C
+#define mmACP_SW_Audio_RX_Frame_Format 0x1243090
+#define mmACP_SW_Audio_RX_SampleInterval 0x1243094
+#define mmACP_SW_Audio_RX_Hctrl_DP0 0x1243098
+#define mmACP_SW_Audio_RX_Hctrl_DP1 0x124309C
+#define mmACP_SW_Audio_RX_Hctrl_DP2 0x1243100
+#define mmACP_SW_Audio_RX_Hctrl_DP3 0x1243104
+#define mmACP_SW_Audio_RX_offset_DP0 0x1243108
+#define mmACP_SW_Audio_RX_offset_DP1 0x124310C
+#define mmACP_SW_Audio_RX_offset_DP2 0x1243110
+#define mmACP_SW_Audio_RX_offset_DP3 0x1243114
+#define mmACP_SW_Audio_RX_Channel_Enable_DP0 0x1243118
+#define mmACP_SW_Audio_RX_Channel_Enable_DP1 0x124311C
+#define mmACP_SW_Audio_RX_Channel_Enable_DP2 0x1243120
+#define mmACP_SW_Audio_RX_Channel_Enable_DP3 0x1243124
+#define mmACP_SW_BT_RX_EN 0x1243128
+#define mmACP_SW_BT_RX_EN_STATUS 0x124312C
+#define mmACP_SW_BT_RX_Frame_Format 0x1243130
+#define mmACP_SW_BT_RX_SampleInterval 0x1243134
+#define mmACP_SW_BT_RX_Hctrl 0x1243138
+#define mmACP_SW_BT_RX_offset 0x124313C
+#define mmACP_SW_BT_RX_Channel_Enable_DP0 0x1243140
+#define mmACP_SW_Headset_RX_EN 0x1243144
+#define mmACP_SW_Headset_RX_EN_STATUS 0x1243148
+#define mmACP_SW_Headset_RX_Frame_Format 0x124314C
+#define mmACP_SW_Headset_RX_SampleInterval 0x1243150
+#define mmACP_SW_Headset_RX_Hctrl 0x1243154
+#define mmACP_SW_Headset_RX_offset 0x1243158
+#define mmACP_SW_Headset_RX_Channel_Enable_DP0 0x124315C
+#define mmACP_SW_BPT_PORT_EN 0x1243160
+#define mmACP_SW_BPT_PORT_EN_STATUS 0x1243164
+#define mmACP_SW_BPT_PORT_Frame_Format 0x1243168
+#define mmACP_SW_BPT_PORT_SampleInterval 0x124316C
+#define mmACP_SW_BPT_PORT_Hctrl 0x1243170
+#define mmACP_SW_BPT_PORT_offset 0x1243174
+#define mmACP_SW_BPT_PORT_Channel_Enable 0x1243178
+#define mmACP_SW_BPT_PORT_First_byte_addr 0x124317C
+#define mmACP_SW_CLK_RESUME_CTRL 0x1243180
+#define mmACP_SW_CLK_RESUME_Delay_Cntr 0x1243184
+#define mmACP_SW_BUS_RESET_CTRL 0x1243188
+#define mmACP_SW_PRBS_ERR_STATUS 0x124318C
+
+
+// Registers from ACP_AUDIO_BUFFERS block
+
+#define mmACP_I2S_RX_RINGBUFADDR 0x1242000
+#define mmACP_I2S_RX_RINGBUFSIZE 0x1242004
+#define mmACP_I2S_RX_LINKPOSITIONCNTR 0x1242008
+#define mmACP_I2S_RX_FIFOADDR 0x124200C
+#define mmACP_I2S_RX_FIFOSIZE 0x1242010
+#define mmACP_I2S_RX_DMA_SIZE 0x1242014
+#define mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x1242018
+#define mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x124201C
+#define mmACP_I2S_RX_INTR_WATERMARK_SIZE 0x1242020
+#define mmACP_I2S_TX_RINGBUFADDR 0x1242024
+#define mmACP_I2S_TX_RINGBUFSIZE 0x1242028
+#define mmACP_I2S_TX_LINKPOSITIONCNTR 0x124202C
+#define mmACP_I2S_TX_FIFOADDR 0x1242030
+#define mmACP_I2S_TX_FIFOSIZE 0x1242034
+#define mmACP_I2S_TX_DMA_SIZE 0x1242038
+#define mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x124203C
+#define mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x1242040
+#define mmACP_I2S_TX_INTR_WATERMARK_SIZE 0x1242044
+#define mmACP_BT_RX_RINGBUFADDR 0x1242048
+#define mmACP_BT_RX_RINGBUFSIZE 0x124204C
+#define mmACP_BT_RX_LINKPOSITIONCNTR 0x1242050
+#define mmACP_BT_RX_FIFOADDR 0x1242054
+#define mmACP_BT_RX_FIFOSIZE 0x1242058
+#define mmACP_BT_RX_DMA_SIZE 0x124205C
+#define mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1242060
+#define mmACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x1242064
+#define mmACP_BT_RX_INTR_WATERMARK_SIZE 0x1242068
+#define mmACP_BT_TX_RINGBUFADDR 0x124206C
+#define mmACP_BT_TX_RINGBUFSIZE 0x1242070
+#define mmACP_BT_TX_LINKPOSITIONCNTR 0x1242074
+#define mmACP_BT_TX_FIFOADDR 0x1242078
+#define mmACP_BT_TX_FIFOSIZE 0x124207C
+#define mmACP_BT_TX_DMA_SIZE 0x1242080
+#define mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1242084
+#define mmACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x1242088
+#define mmACP_BT_TX_INTR_WATERMARK_SIZE 0x124208C
+#define mmACP_HS_RX_RINGBUFADDR 0x1242090
+#define mmACP_HS_RX_RINGBUFSIZE 0x1242094
+#define mmACP_HS_RX_LINKPOSITIONCNTR 0x1242098
+#define mmACP_HS_RX_FIFOADDR 0x124209C
+#define mmACP_HS_RX_FIFOSIZE 0x12420A0
+#define mmACP_HS_RX_DMA_SIZE 0x12420A4
+#define mmACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x12420A8
+#define mmACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x12420AC
+#define mmACP_HS_RX_INTR_WATERMARK_SIZE 0x12420B0
+#define mmACP_HS_TX_RINGBUFADDR 0x12420B4
+#define mmACP_HS_TX_RINGBUFSIZE 0x12420B8
+#define mmACP_HS_TX_LINKPOSITIONCNTR 0x12420BC
+#define mmACP_HS_TX_FIFOADDR 0x12420C0
+#define mmACP_HS_TX_FIFOSIZE 0x12420C4
+#define mmACP_HS_TX_DMA_SIZE 0x12420C8
+#define mmACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x12420CC
+#define mmACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x12420D0
+#define mmACP_HS_TX_INTR_WATERMARK_SIZE 0x12420D4
+
+
+// Registers from ACP_I2S_TDM block
+
+#define mmACP_I2STDM_IER 0x1242400
+#define mmACP_I2STDM_IRER 0x1242404
+#define mmACP_I2STDM_RXFRMT 0x1242408
+#define mmACP_I2STDM_ITER 0x124240C
+#define mmACP_I2STDM_TXFRMT 0x1242410
+
+
+// Registers from ACP_BT_TDM block
+
+#define mmACP_BTTDM_IER 0x1242800
+#define mmACP_BTTDM_IRER 0x1242804
+#define mmACP_BTTDM_RXFRMT 0x1242808
+#define mmACP_BTTDM_ITER 0x124280C
+#define mmACP_BTTDM_TXFRMT 0x1242810
+
+
+// Registers from AZALIA_IP block
+
+#define mmAudio_Az_Global_Capabilities 0x1200000
+#define mmAudio_Az_Minor_Version 0x1200002
+#define mmAudio_Az_Major_Version 0x1200003
+#define mmAudio_Az_Output_Payload_Capability 0x1200004
+#define mmAudio_Az_Input_Payload_Capability 0x1200006
+#define mmAudio_Az_Global_Control 0x1200008
+#define mmAudio_Az_Wake_Enable 0x120000C
+#define mmAudio_Az_State_Change_Status 0x120000E
+#define mmAudio_Az_Global_Status 0x1200010
+#define mmAudio_Az_Linked_List_Capability_Header 0x1200014
+#define mmAudio_Az_Output_Stream_Payload_Capability 0x1200018
+#define mmAudio_Az_Input_Stream_Payload_Capability 0x120001A
+#define mmAudio_Az_Interrupt_Control 0x1200020
+#define mmAudio_Az_Interrupt_Status 0x1200024
+#define mmAudio_Az_Wall_Clock_Counter 0x1200030
+#define mmAudio_Az_Stream_Synchronization 0x1200038
+#define mmAudio_Az_CORB_Lower_Base_Address 0x1200040
+#define mmAudio_Az_CORB_Upper_Base_Address 0x1200044
+#define mmAudio_Az_CORB_Write_Pointer 0x1200048
+#define mmAudio_Az_CORB_Read_Pointer 0x120004A
+#define mmAudio_Az_CORB_Control 0x120004C
+#define mmAudio_Az_CORB_Status 0x120004D
+#define mmAudio_Az_CORB_Size 0x120004E
+#define mmAudio_Az_RIRB_Lower_Base_Address 0x1200050
+#define mmAudio_Az_RIRB_Upper_Base_Address 0x1200054
+#define mmAudio_Az_RIRB_Write_Pointer 0x1200058
+#define mmAudio_Az_RIRB_Response_Interrupt_Count 0x120005A
+#define mmAudio_Az_RIRB_Control 0x120005C
+#define mmAudio_Az_RIRB_Status 0x120005D
+#define mmAudio_Az_RIRB_Size 0x120005E
+#define mmAudio_Az_Immediate_Command_Output_Interface 0x1200060
+#define mmAudio_Az_Immediate_Response_Input_Interface 0x1200064
+#define mmAudio_Az_Immediate_Command_Status 0x1200068
+#define mmAudio_Az_DPLBASE 0x1200070
+#define mmAudio_Az_DPUBASE 0x1200074
+#define mmAudio_Az_Input_SD0CTL_and_STS 0x1200080
+#define mmAudio_Az_Input_SD0LPIB 0x1200084
+#define mmAudio_Az_Input_SD0CBL 0x1200088
+#define mmAudio_Az_Input_SD0LVI 0x120008C
+#define mmAudio_Az_Input_SD0FIFOS 0x1200090
+#define mmAudio_Az_Input_SD0FMT 0x1200092
+#define mmAudio_Az_Input_SD0BDPL 0x1200098
+#define mmAudio_Az_Input_SD0BDPU 0x120009C
+#define mmAudio_Az_Input_SD1CTL_and_STS 0x12000A0
+#define mmAudio_Az_Input_SD1LPIB 0x12000A4
+#define mmAudio_Az_Input_SD1CBL 0x12000A8
+#define mmAudio_Az_Input_SD1LVI 0x12000AC
+#define mmAudio_Az_Input_SD1FIFOS 0x12000B0
+#define mmAudio_Az_Input_SD1FMT 0x12000B2
+#define mmAudio_Az_Input_SD1BDPL 0x12000B8
+#define mmAudio_Az_Input_SD1BDPU 0x12000BC
+#define mmAudio_Az_Input_SD2CTL_and_STS 0x12000C0
+#define mmAudio_Az_Input_SD2LPIB 0x12000C4
+#define mmAudio_Az_Input_SD2CBL 0x12000C8
+#define mmAudio_Az_Input_SD2LVI 0x12000CC
+#define mmAudio_Az_Input_SD2FIFOS 0x12000D0
+#define mmAudio_Az_Input_SD2FMT 0x12000D2
+#define mmAudio_Az_Input_SD2BDPL 0x12000D8
+#define mmAudio_Az_Input_SD2BDPU 0x12000DC
+#define mmAudio_Az_Input_SD3CTL_and_STS 0x12000E0
+#define mmAudio_Az_Input_SD3LPIB 0x12000E4
+#define mmAudio_Az_Input_SD3CBL 0x12000E8
+#define mmAudio_Az_Input_SD3LVI 0x12000EC
+#define mmAudio_Az_Input_SD3FIFOS 0x12000F0
+#define mmAudio_Az_Input_SD3FMT 0x12000F2
+#define mmAudio_Az_Input_SD3BDPL 0x12000F8
+#define mmAudio_Az_Input_SD3BDPU 0x12000FC
+#define mmAudio_Az_Output_SD0CTL_and_STS 0x1200100
+#define mmAudio_Az_Output_SD0LPIB 0x1200104
+#define mmAudio_Az_Output_SD0CBL 0x1200108
+#define mmAudio_Az_Output_SD0LVI 0x120010C
+#define mmAudio_Az_Output_SD0FIFOS 0x1200110
+#define mmAudio_Az_Output_SD0FMT 0x1200112
+#define mmAudio_Az_Output_SD0BDPL 0x1200118
+#define mmAudio_Az_Output_SD0BDPU 0x120011C
+#define mmAudio_Az_Output_SD1CTL_and_STS 0x1200120
+#define mmAudio_Az_Output_SD1LPIB 0x1200124
+#define mmAudio_Az_Output_SD1CBL 0x1200128
+#define mmAudio_Az_Output_SD1LVI 0x120012C
+#define mmAudio_Az_Output_SD1FIFOS 0x1200130
+#define mmAudio_Az_Output_SD1FMT 0x1200132
+#define mmAudio_Az_Output_SD1BDPL 0x1200138
+#define mmAudio_Az_Output_SD1BDPU 0x120013C
+#define mmAudio_Az_Output_SD2CTL_and_STS 0x1200140
+#define mmAudio_Az_Output_SD2LPIB 0x1200144
+#define mmAudio_Az_Output_SD2CBL 0x1200148
+#define mmAudio_Az_Output_SD2LVI 0x120014C
+#define mmAudio_Az_Output_SD2FIFOS 0x1200150
+#define mmAudio_Az_Output_SD2FMT 0x1200152
+#define mmAudio_Az_Output_SD2BDPL 0x1200158
+#define mmAudio_Az_Output_SD2BDPU 0x120015C
+#define mmAudio_Az_Output_SD3CTL_and_STS 0x1200160
+#define mmAudio_Az_Output_SD3LPIB 0x1200164
+#define mmAudio_Az_Output_SD3CBL 0x1200168
+#define mmAudio_Az_Output_SD3LVI 0x120016C
+#define mmAudio_Az_Output_SD3FIFOS 0x1200170
+#define mmAudio_Az_Output_SD3FMT 0x1200172
+#define mmAudio_Az_Output_SD3BDPL 0x1200178
+#define mmAudio_Az_Output_SD3BDPU 0x120017C
+#define mmAudioAZ_Misc_Control_Register_1 0x1200180
+#define mmAudioAZ_Misc_Control_Register_2 0x1200182
+#define mmAudioAZ_Misc_Control_Register_3 0x1200183
+#define mmAudio_AZ_Multiple_Links_Capability_Header 0x1200200
+#define mmAudio_AZ_Multiple_Links_Capability_Declaration 0x1200204
+#define mmAudio_AZ_Link0_Capabilities 0x1200240
+#define mmAudio_AZ_Link0_Control 0x1200244
+#define mmAudio_AZ_Link0_Output_Stream_ID 0x1200248
+#define mmAudio_AZ_Link0_SDI_Identifier 0x120024C
+#define mmAudio_AZ_Link0_Per_Stream_Overhead 0x1200250
+#define mmAudio_AZ_Link0_Wall_Frame_Counter 0x1200258
+#define mmAudio_AZ_Link0_Output_Payload_Capability_L 0x1200260
+#define mmAudio_AZ_Link0_Output_Payload_Capability_U 0x1200264
+#define mmAudio_AZ_Link0_Input_Payload_Capability_L 0x1200270
+#define mmAudio_AZ_Link0_Input_Payload_Capability_U 0x1200274
+#define mmAudio_Az_Input_SD0LICBA 0x1202084
+#define mmAudio_Az_Input_SD1LICBA 0x12020A4
+#define mmAudio_Az_Input_SD2LICBA 0x12020C4
+#define mmAudio_Az_Input_SD3LICBA 0x12020E4
+#define mmAudio_Az_Output_SD0LICBA 0x1202104
+#define mmAudio_Az_Output_SD1LICBA 0x1202124
+#define mmAudio_Az_Output_SD2LICBA 0x1202144
+#define mmAudio_Az_Output_SD3LICBA 0x1202164
+#define mmAUDIO_AZ_POWER_MANAGEMENT_CONTROL 0x1204000
+#define mmAUDIO_AZ_IOC_SOFTRST_CONTROL 0x1204004
+#define mmAUDIO_AZ_IOC_CLKGATE_CONTROL 0x1204008
+
+
+// Registers from ACP_AZALIA block
+
+#define mmACP_AZ_PAGE0_LBASE_ADDR 0x1243800
+#define mmACP_AZ_PAGE0_UBASE_ADDR 0x1243804
+#define mmACP_AZ_PAGE0_PGEN_SIZE 0x1243808
+#define mmACP_AZ_PAGE0_OFFSET 0x124380C
+#define mmACP_AZ_PAGE1_LBASE_ADDR 0x1243810
+#define mmACP_AZ_PAGE1_UBASE_ADDR 0x1243814
+#define mmACP_AZ_PAGE1_PGEN_SIZE 0x1243818
+#define mmACP_AZ_PAGE1_OFFSET 0x124381C
+#define mmACP_AZ_PAGE2_LBASE_ADDR 0x1243820
+#define mmACP_AZ_PAGE2_UBASE_ADDR 0x1243824
+#define mmACP_AZ_PAGE2_PGEN_SIZE 0x1243828
+#define mmACP_AZ_PAGE2_OFFSET 0x124382C
+#define mmACP_AZ_PAGE3_LBASE_ADDR 0x1243830
+#define mmACP_AZ_PAGE3_UBASE_ADDR 0x1243834
+#define mmACP_AZ_PAGE3_PGEN_SIZE 0x1243838
+#define mmACP_AZ_PAGE3_OFFSET 0x124383C
+#define mmACP_AZ_PAGE4_LBASE_ADDR 0x1243840
+#define mmACP_AZ_PAGE4_UBASE_ADDR 0x1243844
+#define mmACP_AZ_PAGE4_PGEN_SIZE 0x1243848
+#define mmACP_AZ_PAGE4_OFFSET 0x124384C
+#define mmACP_AZ_PAGE5_LBASE_ADDR 0x1243850
+#define mmACP_AZ_PAGE5_UBASE_ADDR 0x1243854
+#define mmACP_AZ_PAGE5_PGEN_SIZE 0x1243858
+#define mmACP_AZ_PAGE5_OFFSET 0x124385C
+#define mmACP_AZ_PAGE6_LBASE_ADDR 0x1243860
+#define mmACP_AZ_PAGE6_UBASE_ADDR 0x1243864
+#define mmACP_AZ_PAGE6_PGEN_SIZE 0x1243868
+#define mmACP_AZ_PAGE6_OFFSET 0x124386C
+#define mmACP_AZ_PAGE7_LBASE_ADDR 0x1243870
+#define mmACP_AZ_PAGE7_UBASE_ADDR 0x1243874
+#define mmACP_AZ_PAGE7_PGEN_SIZE 0x1243878
+#define mmACP_AZ_PAGE7_OFFSET 0x124387C
+
+
+#endif
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
new file mode 100644
index 000000000000..facec2472b34
--- /dev/null
+++ b/sound/soc/amd/raven/pci-acp3x.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// AMD ACP PCI Driver
+//
+//Copyright 2016 Advanced Micro Devices, Inc.
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include "acp3x.h"
+
+struct acp3x_dev_data {
+ void __iomem *acp3x_base;
+ bool acp3x_audio_mode;
+ struct resource *res;
+ struct platform_device *pdev;
+};
+
+static int snd_acp3x_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ int ret;
+ u32 addr, val;
+ struct acp3x_dev_data *adata;
+ struct platform_device_info pdevinfo;
+ unsigned int irqflags;
+
+ if (pci_enable_device(pci)) {
+ dev_err(&pci->dev, "pci_enable_device failed\n");
+ return -ENODEV;
+ }
+
+ ret = pci_request_regions(pci, "AMD ACP3x audio");
+ if (ret < 0) {
+ dev_err(&pci->dev, "pci_request_regions failed\n");
+ goto disable_pci;
+ }
+
+ adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data),
+ GFP_KERNEL);
+ if (!adata) {
+ ret = -ENOMEM;
+ goto release_regions;
+ }
+
+ /* check for msi interrupt support */
+ ret = pci_enable_msi(pci);
+ if (ret)
+ /* msi is not enabled */
+ irqflags = IRQF_SHARED;
+ else
+ /* msi is enabled */
+ irqflags = 0;
+
+ addr = pci_resource_start(pci, 0);
+ adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0));
+ if (!adata->acp3x_base) {
+ ret = -ENOMEM;
+ goto release_regions;
+ }
+ pci_set_master(pci);
+ pci_set_drvdata(pci, adata);
+
+ val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
+ switch (val) {
+ case I2S_MODE:
+ adata->res = devm_kzalloc(&pci->dev,
+ sizeof(struct resource) * 2,
+ GFP_KERNEL);
+ if (!adata->res) {
+ ret = -ENOMEM;
+ goto unmap_mmio;
+ }
+
+ adata->res[0].name = "acp3x_i2s_iomem";
+ adata->res[0].flags = IORESOURCE_MEM;
+ adata->res[0].start = addr;
+ adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
+
+ adata->res[1].name = "acp3x_i2s_irq";
+ adata->res[1].flags = IORESOURCE_IRQ;
+ adata->res[1].start = pci->irq;
+ adata->res[1].end = pci->irq;
+
+ adata->acp3x_audio_mode = ACP3x_I2S_MODE;
+
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ pdevinfo.name = "acp3x_rv_i2s";
+ pdevinfo.id = 0;
+ pdevinfo.parent = &pci->dev;
+ pdevinfo.num_res = 2;
+ pdevinfo.res = adata->res;
+ pdevinfo.data = &irqflags;
+ pdevinfo.size_data = sizeof(irqflags);
+
+ adata->pdev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(adata->pdev)) {
+ dev_err(&pci->dev, "cannot register %s device\n",
+ pdevinfo.name);
+ ret = PTR_ERR(adata->pdev);
+ goto unmap_mmio;
+ }
+ break;
+ default:
+ dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
+ ret = -ENODEV;
+ goto unmap_mmio;
+ }
+ return 0;
+
+unmap_mmio:
+ pci_disable_msi(pci);
+ iounmap(adata->acp3x_base);
+release_regions:
+ pci_release_regions(pci);
+disable_pci:
+ pci_disable_device(pci);
+
+ return ret;
+}
+
+static void snd_acp3x_remove(struct pci_dev *pci)
+{
+ struct acp3x_dev_data *adata = pci_get_drvdata(pci);
+
+ platform_device_unregister(adata->pdev);
+ iounmap(adata->acp3x_base);
+
+ pci_disable_msi(pci);
+ pci_release_regions(pci);
+ pci_disable_device(pci);
+}
+
+static const struct pci_device_id snd_acp3x_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2),
+ .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
+ .class_mask = 0xffffff },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, snd_acp3x_ids);
+
+static struct pci_driver acp3x_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = snd_acp3x_ids,
+ .probe = snd_acp3x_probe,
+ .remove = snd_acp3x_remove,
+};
+
+module_pci_driver(acp3x_driver);
+
+MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
+MODULE_DESCRIPTION("AMD ACP3x PCI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9cc4f1848c9b..62bdb7e333b8 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ADAU7002
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
+ select SND_SOC_AK4118 if I2C
select SND_SOC_AK4458 if I2C
select SND_SOC_AK4535 if I2C
select SND_SOC_AK4554
@@ -392,6 +393,11 @@ config SND_SOC_AK4104
tristate "AKM AK4104 CODEC"
depends on SPI_MASTER
+config SND_SOC_AK4118
+ tristate "AKM AK4118 CODEC"
+ depends on I2C
+ select REGMAP_I2C
+
config SND_SOC_AK4458
tristate "AKM AK4458 CODEC"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8ffab8c8dbfa..66f55d185620 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -27,6 +27,7 @@ snd-soc-adav801-objs := adav801.o
snd-soc-adav803-objs := adav803.o
snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
+snd-soc-ak4118-objs := ak4118.o
snd-soc-ak4458-objs := ak4458.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4554-objs := ak4554.o
@@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
+obj-$(CONFIG_SND_SOC_AK4118) += snd-soc-ak4118.o
obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 32bc545c19cf..6dec8a65eafc 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <sound/asoundef.h>
#include <sound/core.h>
@@ -268,8 +268,8 @@ static const struct regmap_config ak4104_regmap = {
static int ak4104_spi_probe(struct spi_device *spi)
{
- struct device_node *np = spi->dev.of_node;
struct ak4104_private *ak4104;
+ struct gpio_desc *reset_gpiod;
unsigned int val;
int ret;
@@ -297,19 +297,11 @@ static int ak4104_spi_probe(struct spi_device *spi)
return ret;
}
- if (np) {
- enum of_gpio_flags flags;
- int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
-
- if (gpio_is_valid(gpio)) {
- ret = devm_gpio_request_one(&spi->dev, gpio,
- flags & OF_GPIO_ACTIVE_LOW ?
- GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
- "ak4104 reset");
- if (ret < 0)
- return ret;
- }
- }
+ reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpiod) &&
+ PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
/* read the 'reserved' register - according to the datasheet, it
* should contain 0x5b. Not a good way to verify the presence of
diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c
new file mode 100644
index 000000000000..238ab29f2bf4
--- /dev/null
+++ b/sound/soc/codecs/ak4118.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ak4118.c -- Asahi Kasei ALSA Soc Audio driver
+ *
+ * Copyright 2018 DEVIALET
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#define AK4118_REG_CLK_PWR_CTL 0x00
+#define AK4118_REG_FORMAT_CTL 0x01
+#define AK4118_REG_IO_CTL0 0x02
+#define AK4118_REG_IO_CTL1 0x03
+#define AK4118_REG_INT0_MASK 0x04
+#define AK4118_REG_INT1_MASK 0x05
+#define AK4118_REG_RCV_STATUS0 0x06
+#define AK4118_REG_RCV_STATUS1 0x07
+#define AK4118_REG_RXCHAN_STATUS0 0x08
+#define AK4118_REG_RXCHAN_STATUS1 0x09
+#define AK4118_REG_RXCHAN_STATUS2 0x0a
+#define AK4118_REG_RXCHAN_STATUS3 0x0b
+#define AK4118_REG_RXCHAN_STATUS4 0x0c
+#define AK4118_REG_TXCHAN_STATUS0 0x0d
+#define AK4118_REG_TXCHAN_STATUS1 0x0e
+#define AK4118_REG_TXCHAN_STATUS2 0x0f
+#define AK4118_REG_TXCHAN_STATUS3 0x10
+#define AK4118_REG_TXCHAN_STATUS4 0x11
+#define AK4118_REG_BURST_PREAMB_PC0 0x12
+#define AK4118_REG_BURST_PREAMB_PC1 0x13
+#define AK4118_REG_BURST_PREAMB_PD0 0x14
+#define AK4118_REG_BURST_PREAMB_PD1 0x15
+#define AK4118_REG_QSUB_CTL 0x16
+#define AK4118_REG_QSUB_TRACK 0x17
+#define AK4118_REG_QSUB_INDEX 0x18
+#define AK4118_REG_QSUB_MIN 0x19
+#define AK4118_REG_QSUB_SEC 0x1a
+#define AK4118_REG_QSUB_FRAME 0x1b
+#define AK4118_REG_QSUB_ZERO 0x1c
+#define AK4118_REG_QSUB_ABS_MIN 0x1d
+#define AK4118_REG_QSUB_ABS_SEC 0x1e
+#define AK4118_REG_QSUB_ABS_FRAME 0x1f
+#define AK4118_REG_GPE 0x20
+#define AK4118_REG_GPDR 0x21
+#define AK4118_REG_GPSCR 0x22
+#define AK4118_REG_GPLR 0x23
+#define AK4118_REG_DAT_MASK_DTS 0x24
+#define AK4118_REG_RX_DETECT 0x25
+#define AK4118_REG_STC_DAT_DETECT 0x26
+#define AK4118_REG_RXCHAN_STATUS5 0x27
+#define AK4118_REG_TXCHAN_STATUS5 0x28
+#define AK4118_REG_MAX 0x29
+
+#define AK4118_REG_FORMAT_CTL_DIF0 (1 << 4)
+#define AK4118_REG_FORMAT_CTL_DIF1 (1 << 5)
+#define AK4118_REG_FORMAT_CTL_DIF2 (1 << 6)
+
+struct ak4118_priv {
+ struct regmap *regmap;
+ struct gpio_desc *reset;
+ struct gpio_desc *irq;
+ struct snd_soc_component *component;
+};
+
+static const struct reg_default ak4118_reg_defaults[] = {
+ {AK4118_REG_CLK_PWR_CTL, 0x43},
+ {AK4118_REG_FORMAT_CTL, 0x6a},
+ {AK4118_REG_IO_CTL0, 0x88},
+ {AK4118_REG_IO_CTL1, 0x48},
+ {AK4118_REG_INT0_MASK, 0xee},
+ {AK4118_REG_INT1_MASK, 0xb5},
+ {AK4118_REG_RCV_STATUS0, 0x00},
+ {AK4118_REG_RCV_STATUS1, 0x10},
+ {AK4118_REG_TXCHAN_STATUS0, 0x00},
+ {AK4118_REG_TXCHAN_STATUS1, 0x00},
+ {AK4118_REG_TXCHAN_STATUS2, 0x00},
+ {AK4118_REG_TXCHAN_STATUS3, 0x00},
+ {AK4118_REG_TXCHAN_STATUS4, 0x00},
+ {AK4118_REG_GPE, 0x77},
+ {AK4118_REG_GPDR, 0x00},
+ {AK4118_REG_GPSCR, 0x00},
+ {AK4118_REG_GPLR, 0x00},
+ {AK4118_REG_DAT_MASK_DTS, 0x3f},
+ {AK4118_REG_RX_DETECT, 0x00},
+ {AK4118_REG_STC_DAT_DETECT, 0x00},
+ {AK4118_REG_TXCHAN_STATUS5, 0x00},
+};
+
+static const char * const ak4118_input_select_txt[] = {
+ "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
+};
+static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0,
+ ak4118_input_select_txt);
+
+static const struct snd_kcontrol_new ak4118_input_mux_controls =
+ SOC_DAPM_ENUM("Input Select", ak4118_insel_enum);
+
+static const char * const ak4118_iec958_fs_txt[] = {
+ "44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200",
+ "8000", "96000", "64000", "176400", "192000",
+};
+
+static const int ak4118_iec958_fs_val[] = {
+ 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1,
+ 0x4, 0x4, ak4118_iec958_fs_txt,
+ ak4118_iec958_fs_val);
+
+static struct snd_kcontrol_new ak4118_iec958_controls[] = {
+ SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0),
+ SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0),
+ SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1),
+ SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0),
+ SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum),
+};
+
+static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("INRX0"),
+ SND_SOC_DAPM_INPUT("INRX1"),
+ SND_SOC_DAPM_INPUT("INRX2"),
+ SND_SOC_DAPM_INPUT("INRX3"),
+ SND_SOC_DAPM_INPUT("INRX4"),
+ SND_SOC_DAPM_INPUT("INRX5"),
+ SND_SOC_DAPM_INPUT("INRX6"),
+ SND_SOC_DAPM_INPUT("INRX7"),
+ SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+ &ak4118_input_mux_controls),
+};
+
+static const struct snd_soc_dapm_route ak4118_dapm_routes[] = {
+ {"Input Mux", "RX0", "INRX0"},
+ {"Input Mux", "RX1", "INRX1"},
+ {"Input Mux", "RX2", "INRX2"},
+ {"Input Mux", "RX3", "INRX3"},
+ {"Input Mux", "RX4", "INRX4"},
+ {"Input Mux", "RX5", "INRX5"},
+ {"Input Mux", "RX6", "INRX6"},
+ {"Input Mux", "RX7", "INRX7"},
+};
+
+
+static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118,
+ unsigned int format)
+{
+ int dif;
+
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ dif = AK4118_REG_FORMAT_CTL_DIF2;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return dif;
+}
+
+static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118,
+ unsigned int format)
+{
+ int dif;
+
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 |
+ AK4118_REG_FORMAT_CTL_DIF2;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return dif;
+}
+
+static int ak4118_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int format)
+{
+ struct snd_soc_component *component = dai->component;
+ struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+ int dif;
+ int ret = 0;
+
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* component is master */
+ dif = ak4118_set_dai_fmt_master(ak4118, format);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /*component is slave */
+ dif = ak4118_set_dai_fmt_slave(ak4118, format);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ /* format not supported */
+ if (dif < 0) {
+ ret = dif;
+ goto exit;
+ }
+
+ ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL,
+ AK4118_REG_FORMAT_CTL_DIF0 |
+ AK4118_REG_FORMAT_CTL_DIF1 |
+ AK4118_REG_FORMAT_CTL_DIF2, dif);
+ if (ret < 0)
+ goto exit;
+
+exit:
+ return ret;
+}
+
+static int ak4118_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+static const struct snd_soc_dai_ops ak4118_dai_ops = {
+ .hw_params = ak4118_hw_params,
+ .set_fmt = ak4118_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver ak4118_dai = {
+ .name = "ak4118-hifi",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_22050 | 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 = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE
+ },
+ .ops = &ak4118_dai_ops,
+};
+
+static irqreturn_t ak4118_irq_handler(int irq, void *data)
+{
+ struct ak4118_priv *ak4118 = data;
+ struct snd_soc_component *component = ak4118->component;
+ struct snd_kcontrol_new *kctl_new;
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_id *id;
+ unsigned int i;
+
+ if (!component)
+ return IRQ_NONE;
+
+ for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
+ kctl_new = &ak4118_iec958_controls[i];
+ kctl = snd_soc_card_get_kcontrol(component->card,
+ kctl_new->name);
+ if (!kctl)
+ continue;
+ id = &kctl->id;
+ snd_ctl_notify(component->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, id);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ak4118_probe(struct snd_soc_component *component)
+{
+ struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ ak4118->component = component;
+
+ /* release reset */
+ gpiod_set_value(ak4118->reset, 0);
+
+ /* unmask all int1 sources */
+ ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "failed to write regmap 0x%x 0x%x: %d\n",
+ AK4118_REG_INT1_MASK, 0x00, ret);
+ return ret;
+ }
+
+ /* rx detect enable on all channels */
+ ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "failed to write regmap 0x%x 0x%x: %d\n",
+ AK4118_REG_RX_DETECT, 0xff, ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_component_controls(component, ak4118_iec958_controls,
+ ARRAY_SIZE(ak4118_iec958_controls));
+ if (ret) {
+ dev_err(component->dev,
+ "failed to add component kcontrols: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ak4118_remove(struct snd_soc_component *component)
+{
+ struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
+
+ /* hold reset */
+ gpiod_set_value(ak4118->reset, 1);
+}
+
+static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
+ .probe = ak4118_probe,
+ .remove = ak4118_remove,
+ .dapm_widgets = ak4118_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ak4118_dapm_widgets),
+ .dapm_routes = ak4118_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ak4118_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static const struct regmap_config ak4118_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .reg_defaults = ak4118_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults),
+
+ .cache_type = REGCACHE_NONE,
+ .max_register = AK4118_REG_MAX - 1,
+};
+
+static int ak4118_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct ak4118_priv *ak4118;
+ int ret;
+
+ ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv),
+ GFP_KERNEL);
+ if (ak4118 == NULL)
+ return -ENOMEM;
+
+ ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap);
+ if (IS_ERR(ak4118->regmap))
+ return PTR_ERR(ak4118->regmap);
+
+ i2c_set_clientdata(i2c, ak4118);
+
+ ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ak4118->reset)) {
+ ret = PTR_ERR(ak4118->reset);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&i2c->dev, "Failed to get reset: %d\n", ret);
+ return ret;
+ }
+
+ ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN);
+ if (IS_ERR(ak4118->irq)) {
+ ret = PTR_ERR(ak4118->irq);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq),
+ NULL, ak4118_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "ak4118-irq", ak4118);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_register_component(&i2c->dev, &soc_component_drv_ak4118,
+ &ak4118_dai, 1);
+}
+
+static int ak4118_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_component(&i2c->dev);
+ return 0;
+}
+
+static const struct of_device_id ak4118_of_match[] = {
+ { .compatible = "asahi-kasei,ak4118", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ak4118_of_match);
+
+static const struct i2c_device_id ak4118_id_table[] = {
+ { "ak4118", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
+
+static struct i2c_driver ak4118_i2c_driver = {
+ .driver = {
+ .name = "ak4118",
+ .of_match_table = of_match_ptr(ak4118_of_match),
+ },
+ .id_table = ak4118_id_table,
+ .probe = ak4118_i2c_probe,
+ .remove = ak4118_i2c_remove,
+};
+
+module_i2c_driver(ak4118_i2c_driver);
+
+MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver");
+MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 299ada4dfaa0..70d4c89bd6fc 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream,
return ret;
}
-static struct snd_soc_dai_ops ak4458_dai_ops = {
+static const struct snd_soc_dai_ops ak4458_dai_ops = {
.startup = ak4458_startup,
.hw_params = ak4458_hw_params,
.set_fmt = ak4458_set_dai_fmt,
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 448bb90c9c8e..8179512129d3 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -130,16 +130,12 @@ static int ak5558_hw_params(struct snd_pcm_substream *substream,
u8 bits;
int pcm_width = max(params_physical_width(params), ak5558->slot_width);
- /* set master/slave audio interface */
- bits = snd_soc_component_read32(component, AK5558_02_CONTROL1);
- bits &= ~AK5558_BITS;
-
switch (pcm_width) {
case 16:
- bits |= AK5558_DIF_24BIT_MODE;
+ bits = AK5558_DIF_24BIT_MODE;
break;
case 32:
- bits |= AK5558_DIF_32BIT_MODE;
+ bits = AK5558_DIF_32BIT_MODE;
break;
default:
return -EINVAL;
@@ -168,18 +164,15 @@ static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
/* set master/slave audio interface */
- format = snd_soc_component_read32(component, AK5558_02_CONTROL1);
- format &= ~AK5558_DIF;
-
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- format |= AK5558_DIF_I2S_MODE;
+ format = AK5558_DIF_I2S_MODE;
break;
case SND_SOC_DAIFMT_LEFT_J:
- format |= AK5558_DIF_MSB_MODE;
+ format = AK5558_DIF_MSB_MODE;
break;
case SND_SOC_DAIFMT_DSP_B:
- format |= AK5558_DIF_MSB_MODE;
+ format = AK5558_DIF_MSB_MODE;
break;
default:
return -EINVAL;
@@ -246,7 +239,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream,
&ak5558_rate_constraints);
}
-static struct snd_soc_dai_ops ak5558_dai_ops = {
+static const struct snd_soc_dai_ops ak5558_dai_ops = {
.startup = ak5558_startup,
.hw_params = ak5558_hw_params,
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 3c266eeb89bf..33d74f163bd7 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -29,8 +29,8 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
/*
* The codec isn't really big-endian or little-endian, since the I2S
@@ -658,8 +658,8 @@ static const struct regmap_config cs4270_regmap = {
static int cs4270_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
- struct device_node *np = i2c_client->dev.of_node;
struct cs4270_private *cs4270;
+ struct gpio_desc *reset_gpiod;
unsigned int val;
int ret, i;
@@ -678,20 +678,11 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
if (ret < 0)
return ret;
- /* See if we have a way to bring the codec out of reset */
- if (np) {
- enum of_gpio_flags flags;
- int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
-
- if (gpio_is_valid(gpio)) {
- ret = devm_gpio_request_one(&i2c_client->dev, gpio,
- flags & OF_GPIO_ACTIVE_LOW ?
- GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
- "cs4270 reset");
- if (ret < 0)
- return ret;
- }
- }
+ reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpiod) &&
+ PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
if (IS_ERR(cs4270->regmap))
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index 71322e0410ee..da921da50ef0 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -30,9 +30,39 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#define MAX_MODESWITCH_DELAY 70
+static int modeswitch_delay;
+module_param(modeswitch_delay, uint, 0644);
+
+static int wakeup_delay;
+module_param(wakeup_delay, uint, 0644);
+
struct dmic {
struct gpio_desc *gpio_en;
int wakeup_delay;
+ /* Delay after DMIC mode switch */
+ int modeswitch_delay;
+};
+
+int dmic_daiops_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct dmic *dmic = snd_soc_component_get_drvdata(component);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (dmic->modeswitch_delay)
+ mdelay(dmic->modeswitch_delay);
+
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+ .trigger = dmic_daiops_trigger,
};
static int dmic_aif_event(struct snd_soc_dapm_widget *w,
@@ -68,6 +98,7 @@ static struct snd_soc_dai_driver dmic_dai = {
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S16_LE,
},
+ .ops = &dmic_dai_ops,
};
static int dmic_component_probe(struct snd_soc_component *component)
@@ -85,6 +116,15 @@ static int dmic_component_probe(struct snd_soc_component *component)
device_property_read_u32(component->dev, "wakeup-delay-ms",
&dmic->wakeup_delay);
+ device_property_read_u32(component->dev, "modeswitch-delay-ms",
+ &dmic->modeswitch_delay);
+ if (wakeup_delay)
+ dmic->wakeup_delay = wakeup_delay;
+ if (modeswitch_delay)
+ dmic->modeswitch_delay = modeswitch_delay;
+
+ if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY)
+ dmic->modeswitch_delay = MAX_MODESWITCH_DELAY;
snd_soc_component_set_drvdata(component, dmic);
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 2aaa83028e55..ffecdaaa8cf2 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
struct snd_soc_dai *dai);
-static struct snd_soc_dai_ops hdac_hda_dai_ops = {
+static const struct snd_soc_dai_ops hdac_hda_dai_ops = {
.startup = hdac_hda_dai_open,
.shutdown = hdac_hda_dai_close,
.prepare = hdac_hda_dai_prepare,
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index e63d6e33df48..db709eeb019c 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map {
struct hdac_hdmi_cvt *cvt;
};
+/*
+ * pin to port mapping table where the value indicate the pin number and
+ * the index indicate the port number with 1 base.
+ */
+static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb};
+
struct hdac_hdmi_drv_data {
unsigned int vendor_nid;
+ const int *port_map; /* pin to port mapping table */
+ int port_num;
};
struct hdac_hdmi_priv {
@@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
return 0;
}
-#define INTEL_VENDOR_NID 0x08
-#define INTEL_GLK_VENDOR_NID 0x0b
+#define INTEL_VENDOR_NID_0x2 0x02
+#define INTEL_VENDOR_NID_0x8 0x08
+#define INTEL_VENDOR_NID_0xb 0x0b
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
-#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
+#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev)
@@ -1538,7 +1547,26 @@ free_widgets:
static int hdac_hdmi_pin2port(void *aptr, int pin)
{
- return pin - 4; /* map NID 0x05 -> port #1 */
+ struct hdac_device *hdev = aptr;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+ const int *map = hdmi->drv_data->port_map;
+ int i;
+
+ if (!hdmi->drv_data->port_num)
+ return pin - 4; /* map NID 0x05 -> port #1 */
+
+ /*
+ * looking for the pin number in the mapping table and return
+ * the index which indicate the port number
+ */
+ for (i = 0; i < hdmi->drv_data->port_num; i++) {
+ if (pin == map[i])
+ return i + 1;
+ }
+
+ /* return -1 if pin number exceeds our expectation */
+ dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin);
+ return -1;
}
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
@@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
struct hdac_hdmi_port *hport = NULL;
struct snd_soc_component *component = hdmi->component;
int i;
-
- /* Don't know how this mapping is derived */
- hda_nid_t pin_nid = port + 0x04;
+ hda_nid_t pin_nid;
+
+ if (!hdmi->drv_data->port_num) {
+ /* for legacy platforms */
+ pin_nid = port + 0x04;
+ } else if (port < hdmi->drv_data->port_num) {
+ /* get pin number from the pin2port mapping table */
+ pin_nid = hdmi->drv_data->port_map[port - 1];
+ } else {
+ dev_err(&hdev->dev, "Can't find the pin for port %d\n", port);
+ return;
+ }
dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
pin_nid, pipe);
@@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
return port->eld.info.spk_alloc;
}
+static struct hdac_hdmi_drv_data intel_icl_drv_data = {
+ .vendor_nid = INTEL_VENDOR_NID_0x2,
+ .port_map = icl_pin2port_map,
+ .port_num = ARRAY_SIZE(icl_pin2port_map),
+};
+
static struct hdac_hdmi_drv_data intel_glk_drv_data = {
- .vendor_nid = INTEL_GLK_VENDOR_NID,
+ .vendor_nid = INTEL_VENDOR_NID_0xb,
};
static struct hdac_hdmi_drv_data intel_drv_data = {
- .vendor_nid = INTEL_VENDOR_NID,
+ .vendor_nid = INTEL_VENDOR_NID_0x8,
};
static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
@@ -2258,6 +2301,8 @@ static const struct hda_device_id hdmi_list[] = {
&intel_glk_drv_data),
HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
&intel_glk_drv_data),
+ HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI",
+ &intel_icl_drv_data),
{}
};
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
index a09d01318f79..9c8616a7b61c 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = {
}
};
+static void max98373_reset(struct max98373_priv *max98373, struct device *dev)
+{
+ int ret, reg, count;
+
+ /* Software Reset */
+ ret = regmap_update_bits(max98373->regmap,
+ MAX98373_R2000_SW_RESET,
+ MAX98373_SOFT_RESET,
+ MAX98373_SOFT_RESET);
+ if (ret)
+ dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
+
+ count = 0;
+ while (count < 3) {
+ usleep_range(10000, 11000);
+ /* Software Reset Verification */
+ ret = regmap_read(max98373->regmap,
+ MAX98373_R21FF_REV_ID, &reg);
+ if (!ret) {
+ dev_info(dev, "Reset completed (retry:%d)\n", count);
+ return;
+ }
+ count++;
+ }
+ dev_err(dev, "Reset failed. (ret:%d)\n", ret);
+}
+
static int max98373_probe(struct snd_soc_component *component)
{
struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
/* Software Reset */
- regmap_write(max98373->regmap,
- MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
- usleep_range(10000, 11000);
+ max98373_reset(max98373, component->dev);
/* IV default slot configuration */
regmap_write(max98373->regmap,
@@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
- regmap_write(max98373->regmap,
- MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
- usleep_range(10000, 11000);
+ max98373_reset(max98373, dev);
regcache_cache_only(max98373->regmap, false);
regcache_sync(max98373->regmap);
return 0;
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 4ea3287162ad..8600c5439e1e 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -1,12 +1,10 @@
-/*
- * max9867.c -- max9867 ALSA SoC Audio driver
- *
- * Copyright 2013-15 Maxim Integrated Products
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// MAX9867 ALSA SoC codec driver
+//
+// Copyright 2013-2015 Maxim Integrated Products
+// Copyright 2018 Ladislav Michl <ladis@linux-mips.org>
+//
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -23,254 +21,237 @@ static const char *const max9867_spmode[] = {
"Stereo Single", "Mono Single",
"Stereo Single Fast", "Mono Single Fast"
};
-static const char *const max9867_sidetone_text[] = {
- "None", "Left", "Right", "LeftRight", "LeftRightDiv2",
-};
static const char *const max9867_filter_text[] = {"IIR", "FIR"};
static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7,
max9867_filter_text);
static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0,
max9867_spmode);
-static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6,
- max9867_sidetone_text);
-static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0);
-static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1);
-static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1);
-static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1);
-static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv,
- 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
- 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv,
+ 0, 2, TLV_DB_SCALE_ITEM(-8600, 200, 1),
+ 3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0),
+ 18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0),
+ 26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0),
+ 35, 40, TLV_DB_SCALE_ITEM( 350, 50, 0),
+);
+static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0);
+static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0);
+static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv,
+ 0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1),
+ 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0),
);
static const struct snd_kcontrol_new max9867_snd_controls[] = {
- SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL,
- MAX9867_RIGHTVOL, 0, 63, 1),
- SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN,
- MAX9867_RIGHTMICGAIN,
- 0, 15, 1, max9860_capture_tlv),
- SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN,
- MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv),
- SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN,
- MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv),
- SOC_ENUM("Digital Sidetone Src", max9867_sidetone),
- SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1),
- SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0),
- SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1),
- SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL,
- 4, 15, 1, max9860_adc_left_tlv),
- SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL,
- 0, 15, 1, max9860_adc_right_tlv),
+ SOC_DOUBLE_R_TLV("Master Playback Volume", MAX9867_LEFTVOL,
+ MAX9867_RIGHTVOL, 0, 41, 1, max9867_master_tlv),
+ SOC_DOUBLE_R_TLV("Line Capture Volume", MAX9867_LEFTLINELVL,
+ MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv),
+ SOC_DOUBLE_R_TLV("Mic Capture Volume", MAX9867_LEFTMICGAIN,
+ MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv),
+ SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", MAX9867_LEFTMICGAIN,
+ MAX9867_RIGHTMICGAIN, 5, 4, 0, max9867_micboost_tlv),
+ SOC_SINGLE("Digital Sidetone Volume", MAX9867_SIDETONE, 0, 31, 1),
+ SOC_SINGLE_TLV("Digital Playback Volume", MAX9867_DACLEVEL, 0, 15, 1,
+ max9867_dac_tlv),
+ SOC_SINGLE_TLV("Digital Boost Playback Volume", MAX9867_DACLEVEL, 4, 3, 0,
+ max9867_dacboost_tlv),
+ SOC_DOUBLE_TLV("Digital Capture Volume", MAX9867_ADCLEVEL, 0, 4, 15, 1,
+ max9867_adc_tlv),
SOC_ENUM("Speaker Mode", max9867_spkmode),
SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0),
- SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0),
+ SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0),
SOC_ENUM("DSP Filter", max9867_filter),
};
-static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"};
+/* Input mixer */
+static const struct snd_kcontrol_new max9867_input_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("Line Capture Switch", MAX9867_INPUTCONFIG, 7, 5, 1, 0),
+ SOC_DAPM_DOUBLE("Mic Capture Switch", MAX9867_INPUTCONFIG, 6, 4, 1, 0),
+};
+
+/* Output mixer */
+static const struct snd_kcontrol_new max9867_output_mixer_controls[] = {
+ SOC_DAPM_DOUBLE_R("Line Bypass Switch",
+ MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1),
+};
-static SOC_ENUM_SINGLE_DECL(max9867_mux_enum,
- MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT,
- max9867_mux);
+/* Sidetone mixer */
+static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("Sidetone Switch", MAX9867_SIDETONE, 6, 7, 1, 0),
+};
-static const struct snd_kcontrol_new max9867_dapm_mux_controls =
- SOC_DAPM_ENUM("Route", max9867_mux_enum);
+/* Line out switch */
+static const struct snd_kcontrol_new max9867_line_out_control =
+ SOC_DAPM_DOUBLE_R("Switch",
+ MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1);
-static const struct snd_kcontrol_new max9867_left_dapm_control =
- SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0);
-static const struct snd_kcontrol_new max9867_right_dapm_control =
- SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0);
-static const struct snd_kcontrol_new max9867_line_dapm_control =
- SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1);
static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = {
- SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0),
- SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0),
- SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_OUTPUT("HPOUT"),
-
- SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
- SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
- SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
- &max9867_dapm_mux_controls),
-
- SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1,
- &max9867_left_dapm_control),
- SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1,
- &max9867_right_dapm_control),
- SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0,
- &max9867_line_dapm_control),
- SND_SOC_DAPM_INPUT("LINE_IN"),
+ SND_SOC_DAPM_INPUT("MICL"),
+ SND_SOC_DAPM_INPUT("MICR"),
+ SND_SOC_DAPM_INPUT("LINL"),
+ SND_SOC_DAPM_INPUT("LINR"),
+
+ SND_SOC_DAPM_PGA("Left Line Input", MAX9867_PWRMAN, 6, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right Line Input", MAX9867_PWRMAN, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
+ max9867_input_mixer_controls,
+ ARRAY_SIZE(max9867_input_mixer_controls)),
+ SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
+ SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
+
+ SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0,
+ max9867_sidetone_mixer_controls,
+ ARRAY_SIZE(max9867_sidetone_mixer_controls)),
+ SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0,
+ max9867_output_mixer_controls,
+ ARRAY_SIZE(max9867_output_mixer_controls)),
+ SND_SOC_DAPM_DAC("DACL", "HiFi Playback", MAX9867_PWRMAN, 3, 0),
+ SND_SOC_DAPM_DAC("DACR", "HiFi Playback", MAX9867_PWRMAN, 2, 0),
+ SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0,
+ &max9867_line_out_control),
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
};
static const struct snd_soc_dapm_route max9867_audio_map[] = {
- {"Left DAC", NULL, "DAI_OUT"},
- {"Right DAC", NULL, "DAI_OUT"},
- {"Output Mixer", NULL, "Left DAC"},
- {"Output Mixer", NULL, "Right DAC"},
- {"HPOUT", NULL, "Output Mixer"},
-
- {"Left ADC", NULL, "DAI_IN"},
- {"Right ADC", NULL, "DAI_IN"},
- {"Input Mixer", NULL, "Left ADC"},
- {"Input Mixer", NULL, "Right ADC"},
- {"Input Mux", "Line", "Input Mixer"},
- {"Input Mux", "Mic", "Input Mixer"},
- {"Input Mux", "Mic_Line", "Input Mixer"},
- {"Right Line", "Switch", "Input Mux"},
- {"Left Line", "Switch", "Input Mux"},
- {"LINE_IN", NULL, "Left Line"},
- {"LINE_IN", NULL, "Right Line"},
+ {"Left Line Input", NULL, "LINL"},
+ {"Right Line Input", NULL, "LINR"},
+ {"Input Mixer", "Mic Capture Switch", "MICL"},
+ {"Input Mixer", "Mic Capture Switch", "MICR"},
+ {"Input Mixer", "Line Capture Switch", "Left Line Input"},
+ {"Input Mixer", "Line Capture Switch", "Right Line Input"},
+ {"ADCL", NULL, "Input Mixer"},
+ {"ADCR", NULL, "Input Mixer"},
+
+ {"Digital", "Sidetone Switch", "ADCL"},
+ {"Digital", "Sidetone Switch", "ADCR"},
+ {"DACL", NULL, "Digital"},
+ {"DACR", NULL, "Digital"},
+
+ {"Output Mixer", "Line Bypass Switch", "Left Line Input"},
+ {"Output Mixer", "Line Bypass Switch", "Right Line Input"},
+ {"Output Mixer", NULL, "DACL"},
+ {"Output Mixer", NULL, "DACR"},
+ {"Master Playback", "Switch", "Output Mixer"},
+ {"LOUT", NULL, "Master Playback"},
+ {"ROUT", NULL, "Master Playback"},
+};
+
+static const unsigned int max9867_rates_44k1[] = {
+ 11025, 22050, 44100,
+};
+
+static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = {
+ .list = max9867_rates_44k1,
+ .count = ARRAY_SIZE(max9867_rates_44k1),
};
-enum rates {
- pcm_rate_8, pcm_rate_16, pcm_rate_24,
- pcm_rate_32, pcm_rate_44,
- pcm_rate_48, max_pcm_rate,
+static const unsigned int max9867_rates_48k[] = {
+ 8000, 16000, 32000, 48000,
};
-static const struct ni_div_rates {
- u32 mclk;
- u16 ni[max_pcm_rate];
-} ni_div[] = {
- {11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} },
- {12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} },
- {12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} },
- {13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} },
- {19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} },
- {24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} },
- {26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} },
- {27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} },
+static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = {
+ .list = max9867_rates_48k,
+ .count = ARRAY_SIZE(max9867_rates_48k),
};
-static inline int get_ni_value(int mclk, int rate)
+struct max9867_priv {
+ struct regmap *regmap;
+ const struct snd_pcm_hw_constraint_list *constraints;
+ unsigned int sysclk, pclk;
+ bool master, dsp_a;
+};
+
+static int max9867_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
{
- int i, ret = 0;
+ struct max9867_priv *max9867 =
+ snd_soc_component_get_drvdata(dai->component);
- /* find the closest rate index*/
- for (i = 0; i < ARRAY_SIZE(ni_div); i++) {
- if (ni_div[i].mclk >= mclk)
- break;
- }
- if (i == ARRAY_SIZE(ni_div))
- return -EINVAL;
+ if (max9867->constraints)
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, max9867->constraints);
- switch (rate) {
- case 8000:
- return ni_div[i].ni[pcm_rate_8];
- case 16000:
- return ni_div[i].ni[pcm_rate_16];
- case 32000:
- return ni_div[i].ni[pcm_rate_32];
- case 44100:
- return ni_div[i].ni[pcm_rate_44];
- case 48000:
- return ni_div[i].ni[pcm_rate_48];
- default:
- pr_err("%s wrong rate %d\n", __func__, rate);
- ret = -EINVAL;
- }
- return ret;
+ return 0;
}
static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
+ int value;
+ unsigned long int rate, ratio;
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
- unsigned int ni_h, ni_l;
- int value;
+ unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params),
+ max9867->pclk);
- value = get_ni_value(max9867->sysclk, params_rate(params));
- if (value < 0)
- return value;
-
- ni_h = (0xFF00 & value) >> 8;
- ni_l = 0x00FF & value;
/* set up the ni value */
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
- MAX9867_NI_HIGH_MASK, ni_h);
+ MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8);
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
- MAX9867_NI_LOW_MASK, ni_l);
- if (!max9867->master) {
- /*
- * digital pll locks on to any externally supplied LRCLK signal
- * and also enable rapid lock mode.
- */
- regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
- MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
- regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
- MAX9867_PLL, MAX9867_PLL);
- } else {
- unsigned long int bclk_rate, pclk_bclk_ratio;
- int bclk_value;
-
- bclk_rate = params_rate(params) * 2 * params_width(params);
- pclk_bclk_ratio = max9867->pclk/bclk_rate;
- switch (params_width(params)) {
- case 8:
- case 16:
- switch (pclk_bclk_ratio) {
- case 2:
- bclk_value = MAX9867_IFC1B_PCLK_2;
- break;
- case 4:
- bclk_value = MAX9867_IFC1B_PCLK_4;
- break;
+ MAX9867_NI_LOW_MASK, 0x00FF & ni);
+ if (max9867->master) {
+ if (max9867->dsp_a) {
+ value = MAX9867_IFC1B_48X;
+ } else {
+ rate = params_rate(params) * 2 * params_width(params);
+ ratio = max9867->pclk / rate;
+ switch (params_width(params)) {
case 8:
- bclk_value = MAX9867_IFC1B_PCLK_8;
- break;
case 16:
- bclk_value = MAX9867_IFC1B_PCLK_16;
+ switch (ratio) {
+ case 2:
+ value = MAX9867_IFC1B_PCLK_2;
+ break;
+ case 4:
+ value = MAX9867_IFC1B_PCLK_4;
+ break;
+ case 8:
+ value = MAX9867_IFC1B_PCLK_8;
+ break;
+ case 16:
+ value = MAX9867_IFC1B_PCLK_16;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case 24:
+ value = MAX9867_IFC1B_48X;
+ break;
+ case 32:
+ value = MAX9867_IFC1B_64X;
break;
default:
- dev_err(component->dev,
- "unsupported sampling rate\n");
return -EINVAL;
}
- break;
- case 24:
- bclk_value = MAX9867_IFC1B_24BIT;
- break;
- case 32:
- bclk_value = MAX9867_IFC1B_32BIT;
- break;
- default:
- dev_err(component->dev, "unsupported sampling rate\n");
- return -EINVAL;
}
regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
- MAX9867_IFC1B_BCLK_MASK, bclk_value);
+ MAX9867_IFC1B_BCLK_MASK, value);
+ } else {
+ /*
+ * digital pll locks on to any externally supplied LRCLK signal
+ * and also enable rapid lock mode.
+ */
+ regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
+ MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
+ regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
+ MAX9867_PLL, MAX9867_PLL);
}
return 0;
}
-static int max9867_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
-
- regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
- MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
- return 0;
-}
-
static int max9867_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
- if (mute)
- regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
- MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK);
- else
- regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
- MAX9867_DAC_MUTE_MASK, 0);
- return 0;
+ return regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
+ 1 << 6, !!mute << 6);
}
static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -283,21 +264,29 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
/* Set the prescaler based on the master clock frequency*/
if (freq >= 10000000 && freq <= 20000000) {
value |= MAX9867_PSCLK_10_20;
- max9867->pclk = freq;
+ max9867->pclk = freq;
} else if (freq >= 20000000 && freq <= 40000000) {
value |= MAX9867_PSCLK_20_40;
- max9867->pclk = freq/2;
+ max9867->pclk = freq / 2;
} else if (freq >= 40000000 && freq <= 60000000) {
value |= MAX9867_PSCLK_40_60;
- max9867->pclk = freq/4;
+ max9867->pclk = freq / 4;
} else {
dev_err(component->dev,
"Invalid clock frequency %uHz (required 10-60MHz)\n",
freq);
return -EINVAL;
}
- value = value << MAX9867_PSCLK_SHIFT;
+ if (freq % 48000 == 0)
+ max9867->constraints = &max9867_constraints_48k;
+ else if (freq % 44100 == 0)
+ max9867->constraints = &max9867_constraints_44k1;
+ else
+ dev_warn(component->dev,
+ "Unable to set exact rate with %uHz clock frequency\n",
+ freq);
max9867->sysclk = freq;
+ value = value << MAX9867_PSCLK_SHIFT;
/* exact integer mode is not supported */
value &= ~MAX9867_FREQ_MASK;
regmap_update_bits(max9867->regmap, MAX9867_SYSCLK,
@@ -310,16 +299,17 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
{
struct snd_soc_component *component = codec_dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
- u8 iface1A = 0, iface1B = 0;
+ u8 iface1A, iface1B;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- max9867->master = 1;
- iface1A |= MAX9867_MASTER;
+ max9867->master = true;
+ iface1A = MAX9867_MASTER;
+ iface1B = MAX9867_IFC1B_48X;
break;
case SND_SOC_DAIFMT_CBS_CFS:
- max9867->master = 0;
- iface1A &= ~MAX9867_MASTER;
+ max9867->master = false;
+ iface1A = iface1B = 0;
break;
default:
return -EINVAL;
@@ -327,9 +317,11 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
+ max9867->dsp_a = false;
iface1A |= MAX9867_I2S_DLY;
break;
case SND_SOC_DAIFMT_DSP_A:
+ max9867->dsp_a = true;
iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ;
break;
default:
@@ -355,21 +347,18 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
+
return 0;
}
static const struct snd_soc_dai_ops max9867_dai_ops = {
- .set_fmt = max9867_dai_set_fmt,
.set_sysclk = max9867_set_dai_sysclk,
- .prepare = max9867_prepare,
+ .set_fmt = max9867_dai_set_fmt,
.digital_mute = max9867_mute,
- .hw_params = max9867_dai_hw_params,
+ .startup = max9867_startup,
+ .hw_params = max9867_dai_hw_params,
};
-#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
-#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
-
static struct snd_soc_dai_driver max9867_dai[] = {
{
.name = "max9867-aif1",
@@ -377,42 +366,74 @@ static struct snd_soc_dai_driver max9867_dai[] = {
.stream_name = "HiFi Playback",
.channels_min = 2,
.channels_max = 2,
- .rates = MAX9867_RATES,
- .formats = MAX9867_FORMATS,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 2,
.channels_max = 2,
- .rates = MAX9867_RATES,
- .formats = MAX9867_FORMATS,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &max9867_dai_ops,
.symmetric_rates = 1,
}
};
-#ifdef CONFIG_PM_SLEEP
-static int max9867_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int max9867_suspend(struct snd_soc_component *component)
{
- struct max9867_priv *max9867 = dev_get_drvdata(dev);
+ snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
- /* Drop down to power saving mode when system is suspended */
- regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
- MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK);
return 0;
}
-static int max9867_resume(struct device *dev)
+static int max9867_resume(struct snd_soc_component *component)
{
- struct max9867_priv *max9867 = dev_get_drvdata(dev);
+ snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
- regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
- MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
return 0;
}
+#else
+#define max9867_suspend NULL
+#define max9867_resume NULL
#endif
+static int max9867_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ int err;
+ struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ err = regcache_sync(max9867->regmap);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+ MAX9867_SHTDOWN, MAX9867_SHTDOWN);
+ if (err)
+ return err;
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
+ MAX9867_SHTDOWN, 0);
+ if (err)
+ return err;
+
+ regcache_mark_dirty(max9867->regmap);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_component_driver max9867_component = {
.controls = max9867_snd_controls,
.num_controls = ARRAY_SIZE(max9867_snd_controls),
@@ -420,6 +441,9 @@ static const struct snd_soc_component_driver max9867_component = {
.num_dapm_routes = ARRAY_SIZE(max9867_audio_map),
.dapm_widgets = max9867_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets),
+ .suspend = max9867_suspend,
+ .resume = max9867_resume,
+ .set_bias_level = max9867_set_bias_level,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
@@ -450,8 +474,8 @@ static const struct reg_default max9867_reg[] = {
{ 0x0B, 0x00 },
{ 0x0C, 0x00 },
{ 0x0D, 0x00 },
- { 0x0E, 0x00 },
- { 0x0F, 0x00 },
+ { 0x0E, 0x40 },
+ { 0x0F, 0x40 },
{ 0x10, 0x00 },
{ 0x11, 0x00 },
{ 0x12, 0x00 },
@@ -476,10 +500,9 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct max9867_priv *max9867;
- int ret = 0, reg;
+ int ret, reg;
- max9867 = devm_kzalloc(&i2c->dev,
- sizeof(*max9867), GFP_KERNEL);
+ max9867 = devm_kzalloc(&i2c->dev, sizeof(*max9867), GFP_KERNEL);
if (!max9867)
return -ENOMEM;
@@ -490,8 +513,7 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
return ret;
}
- ret = regmap_read(max9867->regmap,
- MAX9867_REVISION, &reg);
+ ret = regmap_read(max9867->regmap, MAX9867_REVISION, &reg);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to read: %d\n", ret);
return ret;
@@ -499,10 +521,8 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
dev_info(&i2c->dev, "device revision: %x\n", reg);
ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component,
max9867_dai, ARRAY_SIZE(max9867_dai));
- if (ret < 0) {
+ if (ret < 0)
dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
- return ret;
- }
return ret;
}
@@ -518,15 +538,10 @@ static const struct of_device_id max9867_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max9867_of_match);
-static const struct dev_pm_ops max9867_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume)
-};
-
static struct i2c_driver max9867_i2c_driver = {
.driver = {
.name = "max9867",
.of_match_table = of_match_ptr(max9867_of_match),
- .pm = &max9867_pm_ops,
},
.probe = max9867_i2c_probe,
.id_table = max9867_i2c_id,
@@ -534,6 +549,6 @@ static struct i2c_driver max9867_i2c_driver = {
module_i2c_driver(max9867_i2c_driver);
-MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
-MODULE_DESCRIPTION("ALSA SoC MAX9867 driver");
+MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
+MODULE_DESCRIPTION("ASoC MAX9867 driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h
index 55cd9976ff47..2277798291a1 100644
--- a/sound/soc/codecs/max9867.h
+++ b/sound/soc/codecs/max9867.h
@@ -26,13 +26,11 @@
#define MAX9867_PSCLK_10_20 0x1
#define MAX9867_PSCLK_20_40 0x2
#define MAX9867_PSCLK_40_60 0x3
-#define MAX9867_AUDIOCLKHIGH 0x06
-#define MAX9867_NI_HIGH_WIDTH 0x7
-#define MAX9867_NI_HIGH_MASK 0x7F
-#define MAX9867_NI_LOW_MASK 0x7F
-#define MAX9867_NI_LOW_SHIFT 0x1
-#define MAX9867_PLL (1<<7)
-#define MAX9867_AUDIOCLKLOW 0x07
+#define MAX9867_AUDIOCLKHIGH 0x06
+#define MAX9867_NI_HIGH_MASK 0x7F
+#define MAX9867_NI_LOW_MASK 0xFE
+#define MAX9867_PLL (1<<7)
+#define MAX9867_AUDIOCLKLOW 0x07
#define MAX9867_RAPID_LOCK 0x01
#define MAX9867_IFC1A 0x08
#define MAX9867_MASTER (1<<7)
@@ -43,40 +41,29 @@
#define MAX9867_BCI_MODE (1<<5)
#define MAX9867_IFC1B 0x09
#define MAX9867_IFC1B_BCLK_MASK 7
-#define MAX9867_IFC1B_32BIT 0x01
-#define MAX9867_IFC1B_24BIT 0x02
-#define MAX9867_IFC1B_PCLK_2 4
-#define MAX9867_IFC1B_PCLK_4 5
-#define MAX9867_IFC1B_PCLK_8 6
-#define MAX9867_IFC1B_PCLK_16 7
+#define MAX9867_IFC1B_64X 0x01
+#define MAX9867_IFC1B_48X 0x02
+#define MAX9867_IFC1B_PCLK_2 0x04
+#define MAX9867_IFC1B_PCLK_4 0x05
+#define MAX9867_IFC1B_PCLK_8 0x06
+#define MAX9867_IFC1B_PCLK_16 0x07
#define MAX9867_CODECFLTR 0x0a
-#define MAX9867_DACGAIN 0x0b
+#define MAX9867_SIDETONE 0x0b
#define MAX9867_DACLEVEL 0x0c
-#define MAX9867_DAC_MUTE_SHIFT 0x6
-#define MAX9867_DAC_MUTE_WIDTH 0x1
-#define MAX9867_DAC_MUTE_MASK (0x1<<MAX9867_DAC_MUTE_SHIFT)
#define MAX9867_ADCLEVEL 0x0d
#define MAX9867_LEFTLINELVL 0x0e
-#define MAX9867_RIGTHLINELVL 0x0f
+#define MAX9867_RIGHTLINELVL 0x0f
#define MAX9867_LEFTVOL 0x10
#define MAX9867_RIGHTVOL 0x11
#define MAX9867_LEFTMICGAIN 0x12
#define MAX9867_RIGHTMICGAIN 0x13
#define MAX9867_INPUTCONFIG 0x14
-#define MAX9867_INPUT_SHIFT 0x6
#define MAX9867_MICCONFIG 0x15
#define MAX9867_MODECONFIG 0x16
#define MAX9867_PWRMAN 0x17
-#define MAX9867_SHTDOWN_MASK (1<<7)
+#define MAX9867_SHTDOWN 0x80
#define MAX9867_REVISION 0xff
#define MAX9867_CACHEREGNUM 10
-/* codec private data */
-struct max9867_priv {
- struct regmap *regmap;
- unsigned int sysclk;
- unsigned int pclk;
- unsigned int master;
-};
#endif
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index e3c8cd17daf2..4dd1a609756b 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -585,7 +585,7 @@ static int nau8540_calc_fll_param(unsigned int fll_in,
fvco_max = 0;
fvco_sel = ARRAY_SIZE(mclk_src_scaling);
for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
- fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
+ fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
fvco_max < fvco) {
fvco_max = fvco;
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index 622ce947f134..c6152a044416 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -1,18 +1,14 @@
-/*
- * nau8822.c -- NAU8822 ALSA Soc Audio Codec driver
- *
- * Copyright 2017 Nuvoton Technology Corp.
- *
- * Author: David Lin <ctlin0@nuvoton.com>
- * Co-author: John Hsu <kchsu0@nuvoton.com>
- * Co-author: Seven Li <wtli@nuvoton.com>
- *
- * Based on WM8974.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// nau8822.c -- NAU8822 ALSA Soc Audio driver
+//
+// Copyright 2017 Nuvoton Technology Crop.
+//
+// Author: David Lin <ctlin0@nuvoton.com>
+// Co-author: John Hsu <kchsu0@nuvoton.com>
+// Co-author: Seven Li <wtli@nuvoton.com>
+//
+// Based on WM8974.c
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h
index aa79c969cd44..9c552983a293 100644
--- a/sound/soc/codecs/nau8822.h
+++ b/sound/soc/codecs/nau8822.h
@@ -1,13 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * nau8822.h -- NAU8822 Soc Audio Codec driver
+ * nau8822.h -- NAU8822 ALSA SoC Audio driver
+ *
+ * Copyright 2017 Nuvoton Technology Crop.
*
* Author: David Lin <ctlin0@nuvoton.com>
* Co-author: John Hsu <kchsu0@nuvoton.com>
* Co-author: Seven Li <wtli@nuvoton.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef __NAU8822_H__
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index b9fed99d8b5e..7bbcbf5f05c8 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros)
{
u32 gain, sidetone;
- if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) {
- WARN_ON(1);
+ if (WARN_ON(sig_org == 0 || sig_cros == 0))
return 0;
- }
sig_org = nau8825_intlog10_dec3(sig_org);
sig_cros = nau8825_intlog10_dec3(sig_cros);
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c
index 771b46e1974b..6714aa8d9026 100644
--- a/sound/soc/codecs/pcm3060.c
+++ b/sound/soc/codecs/pcm3060.c
@@ -198,19 +198,25 @@ static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
};
static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64,
+ PCM3060_REG_SHIFT_DAPSV, 1),
+
SND_SOC_DAPM_OUTPUT("OUTL"),
SND_SOC_DAPM_OUTPUT("OUTR"),
SND_SOC_DAPM_INPUT("INL"),
SND_SOC_DAPM_INPUT("INR"),
+
+ SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64,
+ PCM3060_REG_SHIFT_ADPSV, 1),
};
static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
- { "OUTL", NULL, "Playback" },
- { "OUTR", NULL, "Playback" },
+ { "OUTL", NULL, "DAC" },
+ { "OUTR", NULL, "DAC" },
- { "Capture", NULL, "INL" },
- { "Capture", NULL, "INR" },
+ { "ADC", NULL, "INL" },
+ { "ADC", NULL, "INR" },
};
/* soc component */
@@ -270,9 +276,23 @@ EXPORT_SYMBOL(pcm3060_regmap);
/* device */
+static void pcm3060_parse_dt(const struct device_node *np,
+ struct pcm3060_priv *priv)
+{
+ priv->out_se = of_property_read_bool(np, "ti,out-single-ended");
+}
+
int pcm3060_probe(struct device *dev)
{
int rc;
+ struct pcm3060_priv *priv = dev_get_drvdata(dev);
+
+ if (dev->of_node)
+ pcm3060_parse_dt(dev->of_node, priv);
+
+ if (priv->out_se)
+ regmap_update_bits(priv->regmap, PCM3060_REG64,
+ PCM3060_REG_SE, PCM3060_REG_SE);
rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
pcm3060_dai,
diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h
index fd89a68aa8a7..6a027b4a845d 100644
--- a/sound/soc/codecs/pcm3060.h
+++ b/sound/soc/codecs/pcm3060.h
@@ -25,6 +25,7 @@ struct pcm3060_priv_dai {
struct pcm3060_priv {
struct regmap *regmap;
struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM];
+ u8 out_se: 1;
};
int pcm3060_probe(struct device *dev);
@@ -36,7 +37,9 @@ int pcm3060_remove(struct device *dev);
#define PCM3060_REG_MRST 0x80
#define PCM3060_REG_SRST 0x40
#define PCM3060_REG_ADPSV 0x20
+#define PCM3060_REG_SHIFT_ADPSV 0x05
#define PCM3060_REG_DAPSV 0x10
+#define PCM3060_REG_SHIFT_DAPSV 0x04
#define PCM3060_REG_SE 0x01
#define PCM3060_REG65 0x41
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 445d025e1409..08d3fe192e65 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -133,10 +133,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
- SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
- SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
- SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
- SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
@@ -176,9 +172,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
- SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
- SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
- SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
@@ -504,6 +497,10 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
unsigned int fmt;
unsigned int sample_min;
unsigned int channel_max;
+ unsigned int channel_maxs[] = {
+ 6, /* rx */
+ 8 /* tx */
+ };
if (tx)
fmt = pcm3168a->dac_fmt;
@@ -528,18 +525,9 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
channel_max = 2;
break;
case PCM3168A_FMT_LEFT_J:
- sample_min = 24;
- if (tx)
- channel_max = 8;
- else
- channel_max = 6;
- break;
case PCM3168A_FMT_I2S:
sample_min = 24;
- if (tx)
- channel_max = 8;
- else
- channel_max = 6;
+ channel_max = channel_maxs[tx];
break;
default:
sample_min = 24;
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index f0f2d4fd3769..6cb1653be804 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -53,6 +53,8 @@ struct pcm512x_priv {
unsigned long overclock_pll;
unsigned long overclock_dac;
unsigned long overclock_dsp;
+ int mute;
+ struct mutex mutex;
};
/*
@@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds =
SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
pcm512x_ramp_step_text);
+static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
+{
+ return regmap_update_bits(
+ pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR,
+ (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT)
+ | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT));
+}
+
+static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&pcm512x->mutex);
+ ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
+ ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
+ mutex_unlock(&pcm512x->mutex);
+
+ return 0;
+}
+
+static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+ int ret, changed = 0;
+
+ mutex_lock(&pcm512x->mutex);
+
+ if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
+ pcm512x->mute ^= 0x4;
+ changed = 1;
+ }
+ if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) {
+ pcm512x->mute ^= 0x2;
+ changed = 1;
+ }
+
+ if (changed) {
+ ret = pcm512x_update_mute(pcm512x);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to update digital mute: %d\n", ret);
+ mutex_unlock(&pcm512x->mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&pcm512x->mutex);
+
+ return changed;
+}
+
static const struct snd_kcontrol_new pcm512x_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
@@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
-SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
- PCM512x_RQMR_SHIFT, 1, 1),
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Digital Playback Switch",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_ctl_boolean_stereo_info,
+ .get = pcm512x_digital_playback_switch_get,
+ .put = pcm512x_digital_playback_switch_put
+},
SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
SOC_ENUM("DSP Program", pcm512x_dsp_program),
@@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_component *component = dai->component;
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+ int ret;
+ unsigned int mute_det;
+
+ mutex_lock(&pcm512x->mutex);
+
+ if (mute) {
+ pcm512x->mute |= 0x1;
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE,
+ PCM512x_RQML | PCM512x_RQMR,
+ PCM512x_RQML | PCM512x_RQMR);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to set digital mute: %d\n", ret);
+ mutex_unlock(&pcm512x->mutex);
+ return ret;
+ }
+
+ regmap_read_poll_timeout(pcm512x->regmap,
+ PCM512x_ANALOG_MUTE_DET,
+ mute_det, (mute_det & 0x3) == 0,
+ 200, 10000);
+
+ mutex_unlock(&pcm512x->mutex);
+ } else {
+ pcm512x->mute &= ~0x1;
+ ret = pcm512x_update_mute(pcm512x);
+ if (ret != 0) {
+ dev_err(component->dev,
+ "Failed to update digital mute: %d\n", ret);
+ mutex_unlock(&pcm512x->mutex);
+ return ret;
+ }
+
+ regmap_read_poll_timeout(pcm512x->regmap,
+ PCM512x_ANALOG_MUTE_DET,
+ mute_det,
+ (mute_det & 0x3)
+ == ((~pcm512x->mute >> 1) & 0x3),
+ 200, 10000);
+ }
+
+ mutex_unlock(&pcm512x->mutex);
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
.startup = pcm512x_dai_startup,
.hw_params = pcm512x_hw_params,
.set_fmt = pcm512x_set_fmt,
+ .digital_mute = pcm512x_digital_mute,
};
static struct snd_soc_dai_driver pcm512x_dai = {
@@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
if (!pcm512x)
return -ENOMEM;
+ mutex_init(&pcm512x->mutex);
+
dev_set_drvdata(dev, pcm512x);
pcm512x->regmap = regmap;
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
index d70d9c0c2088..9dda8693498e 100644
--- a/sound/soc/codecs/pcm512x.h
+++ b/sound/soc/codecs/pcm512x.h
@@ -112,7 +112,9 @@
#define PCM512x_RQST_SHIFT 4
/* Page 0, Register 3 - mute */
+#define PCM512x_RQMR (1 << 0)
#define PCM512x_RQMR_SHIFT 0
+#define PCM512x_RQML (1 << 4)
#define PCM512x_RQML_SHIFT 4
/* Page 0, Register 4 - PLL */
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index 7eb2cbd39d6e..da6647015708 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
+#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -33,6 +34,9 @@
#define RT5663_DEVICE_ID_2 0x6451
#define RT5663_DEVICE_ID_1 0x6406
+#define RT5663_POWER_ON_DELAY_MS 300
+#define RT5663_SUPPLY_CURRENT_UA 500000
+
enum {
CODEC_VER_1,
CODEC_VER_0,
@@ -48,6 +52,11 @@ struct impedance_mapping_table {
unsigned int dc_offset_r_manual_mic;
};
+static const char *const rt5663_supply_names[] = {
+ "avdd",
+ "cpvdd",
+};
+
struct rt5663_priv {
struct snd_soc_component *component;
struct rt5663_platform_data pdata;
@@ -56,6 +65,7 @@ struct rt5663_priv {
struct snd_soc_jack *hs_jack;
struct timer_list btn_check_timer;
struct impedance_mapping_table *imp_table;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)];
int codec_ver;
int sysclk;
@@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
{
struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5663_priv *rt5663;
- int ret;
+ int ret, i;
unsigned int val;
struct regmap *regmap;
@@ -3500,12 +3510,44 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
else
rt5663_parse_dp(rt5663, &i2c->dev);
+ for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++)
+ rt5663->supplies[i].supply = rt5663_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev,
+ ARRAY_SIZE(rt5663->supplies),
+ rt5663->supplies);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* Set load for regulator. */
+ for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) {
+ ret = regulator_set_load(rt5663->supplies[i].consumer,
+ RT5663_SUPPLY_CURRENT_UA);
+ if (ret < 0) {
+ dev_err(&i2c->dev,
+ "Failed to set regulator load on %s, ret: %d\n",
+ rt5663->supplies[i].supply, ret);
+ return ret;
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies),
+ rt5663->supplies);
+
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+ msleep(RT5663_POWER_ON_DELAY_MS);
+
regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
ret);
- return ret;
+ goto err_enable;
}
ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
@@ -3530,14 +3572,15 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev,
"Device with ID register %#x is not rt5663\n",
val);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_enable;
}
if (IS_ERR(rt5663->regmap)) {
ret = PTR_ERR(rt5663->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
- return ret;
+ goto err_enable;
}
/* reset and calibrate */
@@ -3635,20 +3678,32 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
ret = request_irq(i2c->irq, rt5663_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5663", rt5663);
- if (ret)
+ if (ret) {
dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n",
__func__, ret);
+ goto err_enable;
+ }
}
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5663,
rt5663_dai, ARRAY_SIZE(rt5663_dai));
- if (ret) {
- if (i2c->irq)
- free_irq(i2c->irq, rt5663);
- }
+ if (ret)
+ goto err_enable;
+ return 0;
+
+
+ /*
+ * Error after enabling regulators should goto err_enable
+ * to disable regulators.
+ */
+err_enable:
+ if (i2c->irq)
+ free_irq(i2c->irq, rt5663);
+
+ regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
return ret;
}
@@ -3659,6 +3714,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c)
if (i2c->irq)
free_irq(i2c->irq, rt5663);
+ regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
+
return 0;
}
diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c
index 85524acf3e9c..c07e8a80b4b7 100644
--- a/sound/soc/codecs/simple-amplifier.c
+++ b/sound/soc/codecs/simple-amplifier.c
@@ -19,6 +19,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
+#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#define DRV_NAME "simple-amplifier"
@@ -58,11 +59,14 @@ static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = {
(SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)),
SND_SOC_DAPM_OUTPUT("OUTL"),
SND_SOC_DAPM_OUTPUT("OUTR"),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VCC", 20, 0),
};
static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = {
{ "DRV", NULL, "INL" },
{ "DRV", NULL, "INR" },
+ { "OUTL", NULL, "VCC" },
+ { "OUTR", NULL, "VCC" },
{ "OUTL", NULL, "DRV" },
{ "OUTR", NULL, "DRV" },
};
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index 36aebdb8f55c..aaba39295079 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -378,7 +378,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
.non_legacy_dai_naming = 1,
};
-static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
+static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
.hw_params = tas6424_hw_params,
.set_fmt = tas6424_set_dai_fmt,
.set_tdm_slot = tas6424_set_dai_tdm_slot,
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 608ad49ad978..c6048d95c6d3 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1095,7 +1095,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
if (freq/i > 20000000) {
dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
__func__, freq);
- return -EINVAL;
+ return -EINVAL;
}
aic31xx->p_div = i;
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 6a271e6e6b8f..6aa0edf8c5ef 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1260,6 +1260,16 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
aic3x->master = 0;
iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ aic3x->master = 1;
+ iface_areg |= BIT_CLK_MASTER;
+ iface_areg &= ~WORD_CLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ aic3x->master = 1;
+ iface_areg |= WORD_CLK_MASTER;
+ iface_areg &= ~BIT_CLK_MASTER;
+ break;
default:
return -EINVAL;
}
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index a957eaeb7bc1..32907b1e20cf 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -394,7 +394,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret != 0) {
dev_err(component->dev,
"Failed to enable supplies: %d\n", ret);
- goto exit;
+ goto exit;
}
if (dac33->power_gpio >= 0)
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 61294c787f27..409bed30a4e4 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -60,7 +60,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
dev_warn(component->dev,
"Unsupported ASRC rate1 (%s)\n",
arizona_sample_rate_val_to_name(val));
- return -EINVAL;
+ return -EINVAL;
}
break;
default:
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index ccdf088461b7..54c306707c02 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
if (wm9705->mfd_pdata) {
wm9705->ac97 = wm9705->mfd_pdata->ac97;
regmap = wm9705->mfd_pdata->regmap;
- } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+ } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID,
WM9705_VENDOR_ID_MASK);
if (IS_ERR(wm9705->ac97)) {
@@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9705->ac97);
return PTR_ERR(regmap);
}
-#endif
+ } else {
+ return -ENXIO;
}
snd_soc_component_set_drvdata(component, wm9705->ac97);
@@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
static void wm9705_soc_remove(struct snd_soc_component *component)
{
-#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
- if (!wm9705->mfd_pdata) {
+ if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9705->ac97);
}
-#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9705 = {
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index e873baa9e778..01949eaba4fd 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -642,8 +642,7 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
if (wm9712->mfd_pdata) {
wm9712->ac97 = wm9712->mfd_pdata->ac97;
regmap = wm9712->mfd_pdata->regmap;
- } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+ } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
int ret;
wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
@@ -660,7 +659,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9712->ac97);
return PTR_ERR(regmap);
}
-#endif
+ } else {
+ return -ENXIO;
}
snd_soc_component_init_regmap(component, regmap);
@@ -673,14 +673,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
static void wm9712_soc_remove(struct snd_soc_component *component)
{
-#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
- if (!wm9712->mfd_pdata) {
+ if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9712->ac97);
}
-#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9712 = {
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 643863bb32e0..5a2fdf4f69bf 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
if (wm9713->mfd_pdata) {
wm9713->ac97 = wm9713->mfd_pdata->ac97;
regmap = wm9713->mfd_pdata->regmap;
- } else {
-#ifdef CONFIG_SND_SOC_AC97_BUS
+ } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID,
WM9713_VENDOR_ID_MASK);
if (IS_ERR(wm9713->ac97))
@@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9713->ac97);
return PTR_ERR(regmap);
}
-#endif
+ } else {
+ return -ENXIO;
}
snd_soc_component_init_regmap(component, regmap);
@@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
static void wm9713_soc_remove(struct snd_soc_component *component)
{
-#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
- if (!wm9713->mfd_pdata) {
+ if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9713->ac97);
}
-#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9713 = {
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 66501b8dc46f..1dd291cebe67 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -2419,7 +2419,7 @@ static int wm_adsp_create_name(struct wm_adsp *dsp)
return 0;
}
-int wm_adsp1_init(struct wm_adsp *dsp)
+static int wm_adsp_common_init(struct wm_adsp *dsp)
{
int ret;
@@ -2428,11 +2428,17 @@ int wm_adsp1_init(struct wm_adsp *dsp)
return ret;
INIT_LIST_HEAD(&dsp->alg_regions);
+ INIT_LIST_HEAD(&dsp->ctl_list);
mutex_init(&dsp->pwr_lock);
return 0;
}
+
+int wm_adsp1_init(struct wm_adsp *dsp)
+{
+ return wm_adsp_common_init(dsp);
+}
EXPORT_SYMBOL_GPL(wm_adsp1_init);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
@@ -2917,7 +2923,7 @@ int wm_adsp2_init(struct wm_adsp *dsp)
{
int ret;
- ret = wm_adsp_create_name(dsp);
+ ret = wm_adsp_common_init(dsp);
if (ret)
return ret;
@@ -2939,12 +2945,8 @@ int wm_adsp2_init(struct wm_adsp *dsp)
break;
}
- INIT_LIST_HEAD(&dsp->alg_regions);
- INIT_LIST_HEAD(&dsp->ctl_list);
INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
- mutex_init(&dsp->pwr_lock);
-
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_init);
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
deleted file mode 100644
index 778faff28e0e..000000000000
--- a/sound/soc/davinci/Kconfig
+++ /dev/null
@@ -1,106 +0,0 @@
-config SND_DAVINCI_SOC
- tristate
- depends on ARCH_DAVINCI
- select SND_EDMA_SOC
-
-config SND_EDMA_SOC
- tristate "SoC Audio for Texas Instruments chips using eDMA"
- depends on TI_EDMA
- select SND_SOC_GENERIC_DMAENGINE_PCM
- help
- Say Y or M here if you want audio support for TI SoC which uses eDMA.
- The following line of SoCs are supported by this platform driver:
- - daVinci devices
- - AM335x
- - AM437x/AM438x
- - DRA7xx family
-
-config SND_DAVINCI_SOC_I2S
- tristate "DaVinci Multichannel Buffered Serial Port (McBSP) support"
- depends on SND_EDMA_SOC
- help
- Say Y or M here if you want to have support for McBSP IP found in
- Texas Instruments DaVinci DA850 SoCs.
-
-config SND_DAVINCI_SOC_MCASP
- tristate "Multichannel Audio Serial Port (McASP) support"
- depends on SND_SDMA_SOC || SND_EDMA_SOC
- help
- Say Y or M here if you want to have support for McASP IP found in
- various Texas Instruments SoCs like:
- - daVinci devices
- - Sitara line of SoCs (AM335x, AM438x, etc)
- - DRA7x devices
-
-config SND_DAVINCI_SOC_VCIF
- tristate
-
-config SND_DAVINCI_SOC_GENERIC_EVM
- tristate
- select SND_SOC_TLV320AIC3X
- select SND_DAVINCI_SOC_MCASP
-
-config SND_AM33XX_SOC_EVM
- tristate "SoC Audio for the AM33XX chip based boards"
- depends on SND_EDMA_SOC && SOC_AM33XX && I2C
- select SND_DAVINCI_SOC_GENERIC_EVM
- help
- Say Y or M if you want to add support for SoC audio on AM33XX
- boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
- AM335X-EVMSK, and BeagelBone with AudioCape boards have this
- setup.
-
-config SND_DAVINCI_SOC_EVM
- tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
- depends on SND_EDMA_SOC && I2C
- depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
- select SND_DAVINCI_SOC_GENERIC_EVM
- help
- Say Y if you want to add support for SoC audio on TI
- DaVinci DM6446, DM355 or DM365 EVM platforms.
-
-choice
- prompt "DM365 codec select"
- depends on SND_DAVINCI_SOC_EVM
- depends on MACH_DAVINCI_DM365_EVM
-
-config SND_DM365_AIC3X_CODEC
- tristate "Audio Codec - AIC3101"
- help
- Say Y if you want to add support for AIC3101 audio codec
-
-config SND_DM365_VOICE_CODEC
- tristate "Voice Codec - CQ93VC"
- select MFD_DAVINCI_VOICECODEC
- select SND_DAVINCI_SOC_VCIF
- select SND_SOC_CQ0093VC
- help
- Say Y if you want to add support for SoC On-chip voice codec
-endchoice
-
-config SND_DM6467_SOC_EVM
- tristate "SoC Audio support for DaVinci DM6467 EVM"
- depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C
- select SND_DAVINCI_SOC_GENERIC_EVM
- select SND_SOC_SPDIF
-
- help
- Say Y if you want to add support for SoC audio on TI
-
-config SND_DA830_SOC_EVM
- tristate "SoC Audio support for DA830/OMAP-L137 EVM"
- depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C
- select SND_DAVINCI_SOC_GENERIC_EVM
-
- help
- Say Y if you want to add support for SoC audio on TI
- DA830/OMAP-L137 EVM
-
-config SND_DA850_SOC_EVM
- tristate "SoC Audio support for DA850/OMAP-L138 EVM"
- depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C
- select SND_DAVINCI_SOC_GENERIC_EVM
- help
- Say Y if you want to add support for SoC audio on TI
- DA850/OMAP-L138 EVM
-
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
deleted file mode 100644
index 23c6592eb31a..000000000000
--- a/sound/soc/davinci/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# DAVINCI Platform Support
-snd-soc-edma-objs := edma-pcm.o
-snd-soc-davinci-i2s-objs := davinci-i2s.o
-snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
-snd-soc-davinci-vcif-objs:= davinci-vcif.o
-
-obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
-obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
-obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
-obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
-
-# Generic DAVINCI/AM33xx Machine Support
-snd-soc-evm-objs := davinci-evm.o
-
-obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 6ec19fb4a934..2e75b5bc5f1d 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -221,7 +221,7 @@ config SND_SOC_PHYCORE_AC97
config SND_SOC_EUKREA_TLV320
tristate "Eukrea TLV320"
- depends on ARCH_MXC && I2C
+ depends on ARCH_MXC && !ARM64 && I2C
select SND_SOC_TLV320AIC23_I2C
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_SSI
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 44433b20435c..81f2fe2c6d23 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -571,17 +571,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
/* Common settings for corresponding Freescale CPU DAI driver */
- if (strstr(cpu_np->name, "ssi")) {
+ if (of_node_name_eq(cpu_np, "ssi")) {
/* Only SSI needs to configure AUDMUX */
ret = fsl_asoc_card_audmux_init(np, priv);
if (ret) {
dev_err(&pdev->dev, "failed to init audmux\n");
goto asrc_fail;
}
- } else if (strstr(cpu_np->name, "esai")) {
+ } else if (of_node_name_eq(cpu_np, "esai")) {
priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
- } else if (strstr(cpu_np->name, "sai")) {
+ } else if (of_node_name_eq(cpu_np, "sai")) {
priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
}
diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c
index 1255dfe19eef..6f6294149476 100644
--- a/sound/soc/fsl/fsl_ssi_dbg.c
+++ b/sound/soc/fsl/fsl_ssi_dbg.c
@@ -124,17 +124,7 @@ static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
return 0;
}
-static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
-{
- return single_open(file, fsl_ssi_stats_show, inode->i_private);
-}
-
-static const struct file_operations fsl_ssi_stats_ops = {
- .open = fsl_ssi_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(fsl_ssi_stats);
int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
{
@@ -144,7 +134,7 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444,
ssi_dbg->dbg_dir, ssi_dbg,
- &fsl_ssi_stats_ops);
+ &fsl_ssi_stats_fops);
if (!ssi_dbg->dbg_stats) {
debugfs_remove(ssi_dbg->dbg_dir);
return -ENOMEM;
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index c954be0a0f96..92c2cf06f40a 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -6,6 +6,7 @@ config SND_SIMPLE_CARD
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple sound card support
+ It also support DPCM of multi CPU single Codec ststem.
config SND_SIMPLE_SCU_CARD
tristate "ASoC Simple SCU sound card support"
@@ -20,8 +21,9 @@ config SND_AUDIO_GRAPH_CARD
depends on OF
select SND_SIMPLE_CARD_UTILS
help
- This option enables generic simple simple sound card support
+ This option enables generic simple sound card support
with OF-graph DT bindings.
+ It also support DPCM of multi CPU single Codec ststem.
config SND_AUDIO_GRAPH_SCU_CARD
tristate "ASoC Audio Graph SCU sound card support"
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 25c819e402e1..0d6144560a1e 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -23,19 +23,29 @@
struct graph_card_data {
struct snd_soc_card snd_card;
struct graph_dai_props {
- struct asoc_simple_dai cpu_dai;
- struct asoc_simple_dai codec_dai;
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform;
+ struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
unsigned int mclk_fs;
} *dai_props;
- unsigned int mclk_fs;
struct asoc_simple_jack hp_jack;
struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link;
+ struct asoc_simple_dai *dais;
+ struct snd_soc_codec_conf *codec_conf;
struct gpio_desc *pa_gpio;
};
+#define graph_priv_to_card(priv) (&(priv)->snd_card)
+#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
+#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
+#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
+
+#define PREFIX "audio-graph-card,"
+
static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -63,11 +73,6 @@ static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
};
-#define graph_priv_to_card(priv) (&(priv)->snd_card)
-#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
-#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
-#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
-
static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -75,13 +80,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret;
- ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
+ ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
- ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
+ ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
- asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
@@ -92,9 +97,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
- asoc_simple_card_clk_disable(&dai_props->codec_dai);
+ asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
@@ -108,9 +113,7 @@ static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
unsigned int mclk, mclk_fs = 0;
int ret = 0;
- if (priv->mclk_fs)
- mclk_fs = priv->mclk_fs;
- else if (dai_props->mclk_fs)
+ if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;
if (mclk_fs) {
@@ -139,86 +142,238 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *codec = rtd->codec_dai;
- struct snd_soc_dai *cpu = rtd->cpu_dai;
- struct graph_dai_props *dai_props =
- graph_priv_to_props(priv, rtd->num);
- int ret;
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+ int ret = 0;
- ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
+ ret = asoc_simple_card_init_dai(rtd->codec_dai,
+ dai_props->codec_dai);
if (ret < 0)
return ret;
- ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
+ ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+ dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
-static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
- struct graph_card_data *priv,
- int idx)
+static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+
+ asoc_simple_card_convert_fixup(&dai_props->adata, params);
+
+ return 0;
+}
+
+static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top,
+ struct device_node *cpu_ep,
+ struct device_node *codec_ep,
+ struct graph_card_data *priv,
+ int *dai_idx, int link_idx,
+ int *conf_idx, int is_cpu)
{
struct device *dev = graph_priv_to_dev(priv);
- struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
- struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
- struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
- struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
- struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL);
- struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
- struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
+ struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
+ struct device_node *ep = is_cpu ? cpu_ep : codec_ep;
+ struct device_node *port = of_get_parent(ep);
+ struct device_node *ports = of_get_parent(port);
+ struct device_node *node = of_graph_get_port_parent(ep);
+ struct asoc_simple_dai *dai;
+ struct snd_soc_dai_link_component *codecs = dai_link->codecs;
int ret;
- if (rcpu_ep != cpu_ep) {
- dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n",
- cpu_ep->name, codec_ep->name, rcpu_ep->name);
- ret = -EINVAL;
- goto dai_link_of_err;
+ dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec");
+
+ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs);
+
+ asoc_simple_card_parse_convert(dev, top, NULL, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, ports, NULL, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, port, NULL, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, ep, NULL, &dai_props->adata);
+
+ of_node_put(ports);
+ of_node_put(port);
+
+ if (is_cpu) {
+
+ /* BE is dummy */
+ codecs->of_node = NULL;
+ codecs->dai_name = "snd-soc-dummy-dai";
+ codecs->name = "snd-soc-dummy";
+
+ /* FE settings */
+ dai_link->dynamic = 1;
+ dai_link->dpcm_merged_format = 1;
+
+ dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+
+ ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "fe.%s",
+ dai_link->cpu_dai_name);
+ if (ret < 0)
+ return ret;
+
+ /* card->num_links includes Codec */
+ asoc_simple_card_canonicalize_cpu(dai_link,
+ of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
+ } else {
+ struct snd_soc_codec_conf *cconf;
+
+ /* FE is dummy */
+ dai_link->cpu_of_node = NULL;
+ dai_link->cpu_dai_name = "snd-soc-dummy-dai";
+ dai_link->cpu_name = "snd-soc-dummy";
+
+ /* BE settings */
+ dai_link->no_pcm = 1;
+ dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
+
+ dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
+ cconf =
+ dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
+
+ ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "be.%s",
+ codecs->dai_name);
+ if (ret < 0)
+ return ret;
+
+ /* check "prefix" from top node */
+ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
+ "prefix");
+ snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
+ PREFIX "prefix");
+ snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node,
+ "prefix");
+ snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
+ "prefix");
}
+ ret = asoc_simple_card_of_parse_tdm(ep, dai);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_canonicalize_dailink(dai_link);
+ if (ret < 0)
+ return ret;
+
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
+
+ dai_link->dpcm_playback = 1;
+ dai_link->dpcm_capture = 1;
+ dai_link->ops = &asoc_graph_card_ops;
+ dai_link->init = asoc_graph_card_dai_init;
+
+ return 0;
+}
+
+static int asoc_graph_card_dai_link_of(struct device_node *top,
+ struct device_node *cpu_ep,
+ struct device_node *codec_ep,
+ struct graph_card_data *priv,
+ int *dai_idx, int link_idx)
+{
+ struct device *dev = graph_priv_to_dev(priv);
+ struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
+ struct device_node *cpu_port = of_get_parent(cpu_ep);
+ struct device_node *codec_port = of_get_parent(codec_ep);
+ struct device_node *cpu_ports = of_get_parent(cpu_port);
+ struct device_node *codec_ports = of_get_parent(codec_port);
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
+ int ret;
+
+ dev_dbg(dev, "link_of\n");
+
+ cpu_dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+ codec_dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
- of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
- of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
+ /* Factor to mclk, used in hw_params() */
+ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(cpu_ports, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(codec_port, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
+ of_node_put(cpu_port);
+ of_node_put(cpu_ports);
+ of_node_put(codec_port);
+ of_node_put(codec_ports);
+
+ ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
+ NULL, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"%s-%s",
dai_link->cpu_dai_name,
dai_link->codecs->dai_name);
if (ret < 0)
- goto dai_link_of_err;
+ return ret;
dai_link->ops = &asoc_graph_card_ops;
dai_link->init = asoc_graph_card_dai_init;
@@ -226,12 +381,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
-dai_link_of_err:
- of_node_put(cpu_ep);
- of_node_put(rcpu_ep);
- of_node_put(codec_ep);
-
- return ret;
+ return 0;
}
static int asoc_graph_card_parse_of(struct graph_card_data *priv)
@@ -239,44 +389,173 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct of_phandle_iterator it;
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_card *card = graph_priv_to_card(priv);
- struct device_node *node = dev->of_node;
- int rc, idx = 0;
- int ret;
+ struct device_node *top = dev->of_node;
+ struct device_node *node = top;
+ struct device_node *cpu_port;
+ struct device_node *cpu_ep = NULL;
+ struct device_node *codec_ep = NULL;
+ struct device_node *codec_port = NULL;
+ struct device_node *codec_port_old = NULL;
+ int rc, ret;
+ int link_idx, dai_idx, conf_idx;
+ int cpu;
ret = asoc_simple_card_of_parse_widgets(card, NULL);
if (ret < 0)
return ret;
- ret = asoc_simple_card_of_parse_routing(card, NULL, 1);
+ ret = asoc_simple_card_of_parse_routing(card, NULL);
if (ret < 0)
return ret;
- /* Factor to mclk, used in hw_params() */
- of_property_read_u32(node, "mclk-fs", &priv->mclk_fs);
-
- of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
- ret = asoc_graph_card_dai_link_of(it.node, priv, idx++);
- if (ret < 0) {
- of_node_put(it.node);
-
- return ret;
+ link_idx = 0;
+ dai_idx = 0;
+ conf_idx = 0;
+ codec_port_old = NULL;
+ for (cpu = 1; cpu >= 0; cpu--) {
+ /*
+ * Detect all CPU first, and Detect all Codec 2nd.
+ *
+ * In Normal sound case, all DAIs are detected
+ * as "CPU-Codec".
+ *
+ * In DPCM sound case,
+ * all CPUs are detected as "CPU-dummy", and
+ * all Codecs are detected as "dummy-Codec".
+ * To avoid random sub-device numbering,
+ * detect "dummy-Codec" in last;
+ */
+ of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
+ cpu_port = it.node;
+ cpu_ep = NULL;
+ while (1) {
+ cpu_ep = of_get_next_child(cpu_port, cpu_ep);
+ if (!cpu_ep)
+ break;
+
+ codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+ codec_port = of_get_parent(codec_ep);
+
+ of_node_put(codec_ep);
+ of_node_put(codec_port);
+
+ dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep);
+
+ if (of_get_child_count(codec_port) > 1) {
+ /*
+ * for DPCM sound
+ */
+ if (!cpu) {
+ if (codec_port_old == codec_port)
+ continue;
+ codec_port_old = codec_port;
+ }
+ ret = asoc_graph_card_dai_link_of_dpcm(
+ top, cpu_ep, codec_ep, priv,
+ &dai_idx, link_idx++,
+ &conf_idx, cpu);
+ } else if (cpu) {
+ /*
+ * for Normal sound
+ */
+ ret = asoc_graph_card_dai_link_of(
+ top, cpu_ep, codec_ep, priv,
+ &dai_idx, link_idx++);
+ }
+ if (ret < 0)
+ return ret;
+ }
}
}
return asoc_simple_card_parse_card_name(card, NULL);
}
-static int asoc_graph_get_dais_count(struct device *dev)
+static void asoc_graph_get_dais_count(struct device *dev,
+ int *link_num,
+ int *dais_num,
+ int *ccnf_num)
{
struct of_phandle_iterator it;
struct device_node *node = dev->of_node;
- int count = 0;
+ struct device_node *cpu_port;
+ struct device_node *cpu_ep;
+ struct device_node *codec_ep;
+ struct device_node *codec_port;
+ struct device_node *codec_port_old;
+ struct device_node *codec_port_old2;
int rc;
- of_for_each_phandle(&it, rc, node, "dais", NULL, 0)
- count++;
-
- return count;
+ /*
+ * link_num : number of links.
+ * CPU-Codec / CPU-dummy / dummy-Codec
+ * dais_num : number of DAIs
+ * ccnf_num : number of codec_conf
+ * same number for "dummy-Codec"
+ *
+ * ex1)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 7
+ * CPU2 -/ ccnf : 1
+ * CPU3 --- Codec2
+ *
+ * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+ * => 7 DAIs = 4xCPU + 3xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex2)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 6
+ * CPU2 -/ ccnf : 1
+ * CPU3 -/
+ *
+ * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex3)
+ * CPU0 --- Codec0 link : 6
+ * CPU1 -/ dais : 6
+ * CPU2 --- Codec1 ccnf : 2
+ * CPU3 -/
+ *
+ * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 2 ccnf = 2xdummy-Codec
+ */
+ codec_port_old = NULL;
+ codec_port_old2 = NULL;
+ of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
+ cpu_port = it.node;
+ cpu_ep = NULL;
+ while (1) {
+ cpu_ep = of_get_next_child(cpu_port, cpu_ep);
+ if (!cpu_ep)
+ break;
+
+ codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+ codec_port = of_get_parent(codec_ep);
+
+ of_node_put(codec_ep);
+ of_node_put(codec_port);
+
+ (*link_num)++;
+ (*dais_num)++;
+
+ if (codec_port_old == codec_port) {
+ if (codec_port_old2 != codec_port_old) {
+ (*link_num)++;
+ (*ccnf_num)++;
+ }
+
+ codec_port_old2 = codec_port_old;
+ continue;
+ }
+
+ (*dais_num)++;
+ codec_port_old = codec_port;
+ }
+ }
}
static int asoc_graph_soc_card_probe(struct snd_soc_card *card)
@@ -300,22 +579,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
+ struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
- int num, ret, i;
+ struct snd_soc_codec_conf *cconf;
+ int lnum = 0, dnum = 0, cnum = 0;
+ int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- num = asoc_graph_get_dais_count(dev);
- if (num == 0)
+ asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
+ if (!lnum || !dnum)
return -EINVAL;
- dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
- dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
- if (!dai_props || !dai_link)
+ dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+ dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+ dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
+ cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
+ if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -324,7 +608,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
- for (i = 0; i < num; i++) {
+ for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -339,16 +623,20 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
/* Init snd_soc_card */
card = graph_priv_to_card(priv);
- card->owner = THIS_MODULE;
- card->dev = dev;
- card->dai_link = dai_link;
- card->num_links = num;
- card->dapm_widgets = asoc_graph_card_dapm_widgets;
- card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
- card->probe = asoc_graph_soc_card_probe;
+ card->owner = THIS_MODULE;
+ card->dev = dev;
+ card->dai_link = dai_link;
+ card->num_links = lnum;
+ card->dapm_widgets = asoc_graph_card_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
+ card->probe = asoc_graph_soc_card_probe;
+ card->codec_conf = cconf;
+ card->num_configs = cnum;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {
@@ -379,6 +667,7 @@ static int asoc_graph_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_graph_of_match[] = {
{ .compatible = "audio-graph-card", },
+ { .compatible = "audio-graph-scu-card", },
{},
};
MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c
index b83bb31021a9..e1b192ea147b 100644
--- a/sound/soc/generic/audio-graph-scu-card.c
+++ b/sound/soc/generic/audio-graph-scu-card.c
@@ -24,14 +24,18 @@
struct graph_card_data {
struct snd_soc_card snd_card;
- struct snd_soc_codec_conf codec_conf;
struct graph_dai_props {
- struct asoc_simple_dai dai;
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs;
struct snd_soc_dai_link_component platform;
+ struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
} *dai_props;
struct snd_soc_dai_link *dai_link;
+ struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
@@ -39,13 +43,24 @@ struct graph_card_data {
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
+#define PREFIX "audio-graph-card,"
+
static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+ int ret = 0;
+
+ ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
+ if (ret)
+ return ret;
- return asoc_simple_card_clk_enable(&dai_props->dai);
+ ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
+ if (ret)
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+ return ret;
}
static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
@@ -54,7 +69,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(&dai_props->dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+ asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static const struct snd_soc_ops asoc_graph_card_ops = {
@@ -65,39 +82,49 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai;
- struct snd_soc_dai_link *dai_link;
- struct graph_dai_props *dai_props;
- int num = rtd->num;
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+ int ret = 0;
- dai_link = graph_priv_to_link(priv, num);
- dai_props = graph_priv_to_props(priv, num);
- dai = dai_link->dynamic ?
- rtd->cpu_dai :
- rtd->codec_dai;
+ ret = asoc_simple_card_init_dai(rtd->codec_dai,
+ dai_props->codec_dai);
+ if (ret < 0)
+ return ret;
- return asoc_simple_card_init_dai(dai, &dai_props->dai);
+ ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+ dai_props->cpu_dai);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
+
+ asoc_simple_card_convert_fixup(&dai_props->adata, params);
+ /* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
-static int asoc_graph_card_dai_link_of(struct device_node *ep,
+static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep,
+ struct device_node *codec_ep,
struct graph_card_data *priv,
- unsigned int daifmt,
- int idx, int is_fe)
+ int *dai_idx, int link_idx,
+ int *conf_idx, int is_fe)
{
struct device *dev = graph_priv_to_dev(priv);
- struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
- struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
+ struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
struct snd_soc_card *card = graph_priv_to_card(priv);
+ struct device_node *ep = is_fe ? cpu_ep : codec_ep;
+ struct device_node *node = of_graph_get_port_parent(ep);
+ struct asoc_simple_dai *dai;
int ret;
if (is_fe) {
@@ -113,11 +140,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
+ dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+
ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
if (ret)
return ret;
- ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai);
+ ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
@@ -131,6 +161,8 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
} else {
+ struct snd_soc_codec_conf *cconf;
+
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
@@ -140,11 +172,17 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
+ dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
+ cconf =
+ dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
+
ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
if (ret < 0)
return ret;
- ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai);
+ ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
@@ -154,13 +192,20 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
- snd_soc_of_parse_audio_prefix(card,
- &priv->codec_conf,
+ /* check "prefix" from top node */
+ snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
"prefix");
+ /* check "prefix" from each node if top doesn't have */
+ if (!cconf->of_node)
+ snd_soc_of_parse_node_prefix(node, cconf,
+ dai_link->codecs->of_node,
+ PREFIX "prefix");
}
- ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai);
+ asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
+
+ ret = asoc_simple_card_of_parse_tdm(ep, dai);
if (ret)
return ret;
@@ -168,7 +213,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
- dai_link->dai_fmt = daifmt;
+ ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
+ NULL, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
+
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_graph_card_ops;
@@ -186,11 +235,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct device_node *cpu_port;
struct device_node *cpu_ep;
struct device_node *codec_ep;
- struct device_node *rcpu_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
- unsigned int daifmt = 0;
- int dai_idx, ret;
+ int dai_idx, link_idx, conf_idx, ret;
int rc, codec;
if (!node)
@@ -201,47 +248,20 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
* see simple-card
*/
- ret = asoc_simple_card_of_parse_routing(card, NULL, 0);
+ ret = asoc_simple_card_of_parse_routing(card, NULL);
if (ret < 0)
return ret;
- asoc_simple_card_parse_convert(dev, NULL, &priv->adata);
+ asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata);
/*
* it supports multi CPU, single CODEC only here
* see asoc_graph_get_dais_count
*/
- /* find 1st codec */
- of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
- cpu_port = it.node;
- cpu_ep = of_get_next_child(cpu_port, NULL);
- codec_ep = of_graph_get_remote_endpoint(cpu_ep);
- rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
-
- of_node_put(cpu_ep);
- of_node_put(codec_ep);
- of_node_put(rcpu_ep);
-
- if (!codec_ep)
- continue;
-
- if (rcpu_ep != cpu_ep) {
- dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n",
- cpu_ep->name, codec_ep->name, rcpu_ep->name);
- ret = -EINVAL;
- goto parse_of_err;
- }
-
- ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
- NULL, &daifmt);
- if (ret < 0) {
- of_node_put(cpu_port);
- goto parse_of_err;
- }
- }
-
+ link_idx = 0;
dai_idx = 0;
+ conf_idx = 0;
codec_port_old = NULL;
for (codec = 0; codec < 2; codec++) {
/*
@@ -257,31 +277,23 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
of_node_put(cpu_ep);
of_node_put(codec_ep);
+ of_node_put(cpu_port);
of_node_put(codec_port);
+ it.node = NULL;
if (codec) {
- if (!codec_port)
- continue;
-
if (codec_port_old == codec_port)
continue;
codec_port_old = codec_port;
-
- /* Back-End (= Codec) */
- ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
- if (ret < 0) {
- of_node_put(cpu_port);
- goto parse_of_err;
- }
- } else {
- /* Front-End (= CPU) */
- ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1);
- if (ret < 0) {
- of_node_put(cpu_port);
- goto parse_of_err;
- }
}
+
+ ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep,
+ priv, &dai_idx,
+ link_idx++, &conf_idx,
+ !codec);
+ if (ret < 0)
+ goto parse_of_err;
}
}
@@ -289,13 +301,24 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
if (ret)
goto parse_of_err;
+ if ((card->num_links != link_idx) ||
+ (card->num_configs != conf_idx)) {
+ dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n",
+ card->num_links, link_idx, card->num_configs, conf_idx);
+ ret = -EINVAL;
+ goto parse_of_err;
+ }
+
ret = 0;
parse_of_err:
return ret;
}
-static int asoc_graph_get_dais_count(struct device *dev)
+static void asoc_graph_get_dais_count(struct device *dev,
+ int *link_num,
+ int *dais_num,
+ int *ccnf_num)
{
struct of_phandle_iterator it;
struct device_node *node = dev->of_node;
@@ -304,10 +327,48 @@ static int asoc_graph_get_dais_count(struct device *dev)
struct device_node *codec_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
- int count = 0;
+ struct device_node *codec_port_old2;
int rc;
+ /*
+ * link_num : number of links.
+ * CPU-Codec / CPU-dummy / dummy-Codec
+ * dais_num : number of DAIs
+ * ccnf_num : number of codec_conf
+ * same number for dummy-Codec
+ *
+ * ex1)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 7
+ * CPU2 -/ ccnf : 1
+ * CPU3 --- Codec2
+ *
+ * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+ * => 7 DAIs = 4xCPU + 3xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex2)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 6
+ * CPU2 -/ ccnf : 1
+ * CPU3 -/
+ *
+ * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex3)
+ * CPU0 --- Codec0 link : 6
+ * CPU1 -/ dais : 6
+ * CPU2 --- Codec1 ccnf : 2
+ * CPU3 -/
+ *
+ * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 2 ccnf = 2xdummy-Codec
+ */
codec_port_old = NULL;
+ codec_port_old2 = NULL;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = of_get_next_child(cpu_port, NULL);
@@ -318,20 +379,22 @@ static int asoc_graph_get_dais_count(struct device *dev)
of_node_put(codec_ep);
of_node_put(codec_port);
- if (cpu_ep)
- count++;
+ (*link_num)++;
+ (*dais_num)++;
- if (!codec_port)
- continue;
+ if (codec_port_old == codec_port) {
+ if (codec_port_old2 != codec_port_old) {
+ (*link_num)++;
+ (*ccnf_num)++;
+ }
- if (codec_port_old == codec_port)
+ codec_port_old2 = codec_port_old;
continue;
+ }
- count++;
+ (*dais_num)++;
codec_port_old = codec_port;
}
-
- return count;
}
static int asoc_graph_card_probe(struct platform_device *pdev)
@@ -339,22 +402,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
+ struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
- int num, ret, i;
+ struct snd_soc_codec_conf *cconf;
+ int lnum = 0, dnum = 0, cnum = 0;
+ int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- num = asoc_graph_get_dais_count(dev);
- if (num == 0)
+ asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
+ if (!lnum || !dnum)
return -EINVAL;
- dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
- dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
- if (!dai_props || !dai_link)
+ dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+ dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+ dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
+ cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
+ if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -363,7 +431,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
- for (i = 0; i < num; i++) {
+ for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -371,15 +439,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
/* Init snd_soc_card */
card = graph_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
- card->num_links = num;
- card->codec_conf = &priv->codec_conf;
- card->num_configs = 1;
+ card->num_links = lnum;
+ card->codec_conf = cconf;
+ card->num_configs = cnum;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index f34cc6cddfa2..b807a47515eb 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -32,10 +32,11 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
-void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+void asoc_simple_card_parse_convert(struct device *dev,
+ struct device_node *np,
+ char *prefix,
struct asoc_simple_card_data *data)
{
- struct device_node *np = dev->of_node;
char prop[128];
if (!prefix)
@@ -151,21 +152,19 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
-static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
- struct clk *clk)
-{
- dai->clk = clk;
-}
-
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
{
- return clk_prepare_enable(dai->clk);
+ if (dai)
+ return clk_prepare_enable(dai->clk);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
{
- clk_disable_unprepare(dai->clk);
+ if (dai)
+ clk_disable_unprepare(dai->clk);
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
@@ -200,7 +199,7 @@ int asoc_simple_card_parse_clk(struct device *dev,
if (!IS_ERR(clk)) {
simple_dai->sysclk = clk_get_rate(clk);
- asoc_simple_card_clk_register(simple_dai, clk);
+ simple_dai->clk = clk;
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
simple_dai->sysclk = val;
} else {
@@ -272,13 +271,24 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep)
{
struct device_node *node;
struct device_node *endpoint;
+ struct of_endpoint info;
int i, id;
int ret;
+ /* use driver specified DAI ID if exist */
ret = snd_soc_get_dai_id(ep);
if (ret != -ENOTSUPP)
return ret;
+ /* use endpoint/port reg if exist */
+ ret = of_graph_parse_endpoint(ep, &info);
+ if (ret == 0) {
+ if (info.id)
+ return info.id;
+ if (info.port)
+ return info.port;
+ }
+
node = of_graph_get_port_parent(ep);
/*
@@ -348,6 +358,9 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
{
int ret;
+ if (!simple_dai)
+ return 0;
+
if (simple_dai->sysclk) {
ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
simple_dai->clk_direction);
@@ -415,8 +428,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
- char *prefix,
- int optional)
+ char *prefix)
{
struct device_node *node = card->dev->of_node;
char prop[128];
@@ -426,11 +438,8 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
- if (!of_property_read_bool(node, prop)) {
- if (optional)
- return 0;
- return -EINVAL;
- }
+ if (!of_property_read_bool(node, prop))
+ return 0;
return snd_soc_of_parse_audio_routing(card, prop);
}
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 5a3f59aa4ba5..37e001cf9cd1 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -18,16 +18,19 @@
struct simple_card_data {
struct snd_soc_card snd_card;
struct simple_dai_props {
- struct asoc_simple_dai cpu_dai;
- struct asoc_simple_dai codec_dai;
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform;
+ struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
unsigned int mclk_fs;
} *dai_props;
- unsigned int mclk_fs;
struct asoc_simple_jack hp_jack;
struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link;
+ struct asoc_simple_dai *dais;
+ struct snd_soc_codec_conf *codec_conf;
};
#define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -47,13 +50,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
simple_priv_to_props(priv, rtd->num);
int ret;
- ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
+ ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
- ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
+ ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
- asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
@@ -65,14 +68,17 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(&dai_props->cpu_dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
- asoc_simple_card_clk_disable(&dai_props->codec_dai);
+ asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
unsigned long rate)
{
+ if (!simple_dai)
+ return 0;
+
if (!simple_dai->clk)
return 0;
@@ -94,19 +100,17 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
unsigned int mclk, mclk_fs = 0;
int ret = 0;
- if (priv->mclk_fs)
- mclk_fs = priv->mclk_fs;
- else if (dai_props->mclk_fs)
+ if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;
if (mclk_fs) {
mclk = params_rate(params) * mclk_fs;
- ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
+ ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
if (ret < 0)
return ret;
- ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
+ ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
if (ret < 0)
return ret;
@@ -134,33 +138,169 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *codec = rtd->codec_dai;
- struct snd_soc_dai *cpu = rtd->cpu_dai;
- struct simple_dai_props *dai_props =
- simple_priv_to_props(priv, rtd->num);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
int ret;
- ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
+ ret = asoc_simple_card_init_dai(rtd->codec_dai,
+ dai_props->codec_dai);
if (ret < 0)
return ret;
- ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
+ ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+ dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
-static int asoc_simple_card_dai_link_of(struct device_node *node,
+static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+
+ asoc_simple_card_convert_fixup(&dai_props->adata, params);
+
+ return 0;
+}
+
+static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
+ struct device_node *node,
+ struct device_node *np,
+ struct device_node *codec,
+ struct simple_card_data *priv,
+ int *dai_idx, int link_idx,
+ int *conf_idx, int is_fe,
+ bool is_top_level_node)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
+ struct asoc_simple_dai *dai;
+ struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+
+ char prop[128];
+ char *prefix = "";
+ int ret;
+
+ /* For single DAI link & old style of DT node */
+ if (is_top_level_node)
+ prefix = PREFIX;
+
+ if (is_fe) {
+ int is_single_links = 0;
+
+ /* BE is dummy */
+ codecs->of_node = NULL;
+ codecs->dai_name = "snd-soc-dummy-dai";
+ codecs->name = "snd-soc-dummy";
+
+ /* FE settings */
+ dai_link->dynamic = 1;
+ dai_link->dpcm_merged_format = 1;
+
+ dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+
+ ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
+ &is_single_links);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "fe.%s",
+ dai_link->cpu_dai_name);
+ if (ret < 0)
+ return ret;
+
+ asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
+ } else {
+ struct snd_soc_codec_conf *cconf;
+
+ /* FE is dummy */
+ dai_link->cpu_of_node = NULL;
+ dai_link->cpu_dai_name = "snd-soc-dummy-dai";
+ dai_link->cpu_name = "snd-soc-dummy";
+
+ /* BE settings */
+ dai_link->no_pcm = 1;
+ dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
+
+ dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
+ cconf =
+ dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
+
+ ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "be.%s",
+ codecs->dai_name);
+ if (ret < 0)
+ return ret;
+
+ /* check "prefix" from top node */
+ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
+ PREFIX "prefix");
+ snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
+ "prefix");
+ snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
+ "prefix");
+ }
+
+ asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata);
+ asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata);
+
+ ret = asoc_simple_card_of_parse_tdm(np, dai);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_canonicalize_dailink(dai_link);
+ if (ret < 0)
+ return ret;
+
+ snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
+ of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(node, prop, &dai_props->mclk_fs);
+ of_property_read_u32(np, prop, &dai_props->mclk_fs);
+
+ ret = asoc_simple_card_parse_daifmt(dev, node, codec,
+ prefix, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
+
+ dai_link->dpcm_playback = 1;
+ dai_link->dpcm_capture = 1;
+ dai_link->ops = &asoc_simple_card_ops;
+ dai_link->init = asoc_simple_card_dai_init;
+
+ return 0;
+}
+
+static int asoc_simple_card_dai_link_of(struct device_node *top,
+ struct device_node *node,
struct simple_card_data *priv,
- int idx,
+ int *dai_idx, int link_idx,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
- struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
- struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
- struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct device_node *cpu = NULL;
struct device_node *plat = NULL;
struct device_node *codec = NULL;
@@ -193,12 +333,21 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
goto dai_link_of_err;
}
+ cpu_dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+ codec_dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
ret = asoc_simple_card_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
goto dai_link_of_err;
- of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
+ snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
+ of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
+ of_property_read_u32(node, prop, &dai_props->mclk_fs);
+ of_property_read_u32(cpu, prop, &dai_props->mclk_fs);
+ of_property_read_u32(codec, prop, &dai_props->mclk_fs);
ret = asoc_simple_card_parse_cpu(cpu, dai_link,
DAI, CELL, &single_cpu);
@@ -286,61 +435,148 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
+ struct device_node *top = dev->of_node;
struct snd_soc_card *card = simple_priv_to_card(priv);
- struct device_node *dai_link;
- struct device_node *node = dev->of_node;
- int ret;
-
- if (!node)
+ struct device_node *node;
+ struct device_node *np;
+ struct device_node *codec;
+ bool is_fe;
+ int ret, loop;
+ int dai_idx, link_idx, conf_idx;
+
+ if (!top)
return -EINVAL;
- dai_link = of_get_child_by_name(node, PREFIX "dai-link");
-
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0)
- goto card_parse_end;
+ return ret;
- ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
+ ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0)
- goto card_parse_end;
-
- /* Factor to mclk, used in hw_params() */
- of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
+ return ret;
/* Single/Muti DAI link(s) & New style of DT node */
- if (dai_link) {
- struct device_node *np = NULL;
- int i = 0;
-
- for_each_child_of_node(node, np) {
- dev_dbg(dev, "\tlink %d:\n", i);
- ret = asoc_simple_card_dai_link_of(np, priv,
- i, false);
- if (ret < 0) {
- of_node_put(np);
- goto card_parse_end;
+ loop = 1;
+ link_idx = 0;
+ dai_idx = 0;
+ conf_idx = 0;
+ node = of_get_child_by_name(top, PREFIX "dai-link");
+ if (!node) {
+ node = dev->of_node;
+ loop = 0;
+ }
+
+ do {
+ /* DPCM */
+ if (of_get_child_count(node) > 2) {
+ for_each_child_of_node(node, np) {
+ codec = of_get_child_by_name(node,
+ loop ? "codec" :
+ PREFIX "codec");
+ if (!codec)
+ return -ENODEV;
+
+ is_fe = (np != codec);
+
+ ret = asoc_simple_card_dai_link_of_dpcm(
+ top, node, np, codec, priv,
+ &dai_idx, link_idx++, &conf_idx,
+ is_fe, !loop);
}
- i++;
+ } else {
+ ret = asoc_simple_card_dai_link_of(
+ top, node, priv,
+ &dai_idx, link_idx++, !loop);
}
- } else {
- /* For single DAI link & old style of DT node */
- ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
if (ret < 0)
- goto card_parse_end;
- }
+ return ret;
+
+ node = of_get_next_child(top, node);
+ } while (loop && node);
ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
- goto card_parse_end;
-
- ret = asoc_simple_card_parse_aux_devs(node, priv);
+ return ret;
-card_parse_end:
- of_node_put(dai_link);
+ ret = asoc_simple_card_parse_aux_devs(top, priv);
return ret;
}
+static void asoc_simple_card_get_dais_count(struct device *dev,
+ int *link_num,
+ int *dais_num,
+ int *ccnf_num)
+{
+ struct device_node *top = dev->of_node;
+ struct device_node *node;
+ int loop;
+ int num;
+
+ /*
+ * link_num : number of links.
+ * CPU-Codec / CPU-dummy / dummy-Codec
+ * dais_num : number of DAIs
+ * ccnf_num : number of codec_conf
+ * same number for "dummy-Codec"
+ *
+ * ex1)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 7
+ * CPU2 -/ ccnf : 1
+ * CPU3 --- Codec2
+ *
+ * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+ * => 7 DAIs = 4xCPU + 3xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex2)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 6
+ * CPU2 -/ ccnf : 1
+ * CPU3 -/
+ *
+ * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex3)
+ * CPU0 --- Codec0 link : 6
+ * CPU1 -/ dais : 6
+ * CPU2 --- Codec1 ccnf : 2
+ * CPU3 -/
+ *
+ * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 2 ccnf = 2xdummy-Codec
+ */
+ if (!top) {
+ (*link_num) = 1;
+ (*dais_num) = 2;
+ (*ccnf_num) = 0;
+ return;
+ }
+
+ loop = 1;
+ node = of_get_child_by_name(top, PREFIX "dai-link");
+ if (!node) {
+ node = top;
+ loop = 0;
+ }
+
+ do {
+ num = of_get_child_count(node);
+ (*dais_num) += num;
+ if (num > 2) {
+ (*link_num) += num;
+ (*ccnf_num)++;
+ } else {
+ (*link_num)++;
+ }
+ node = of_get_next_child(top, node);
+ } while (loop && node);
+}
+
static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
@@ -362,25 +598,28 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
+ struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct snd_soc_card *card;
- int num, ret, i;
-
- /* Get the number of DAI links */
- if (np && of_get_child_by_name(np, PREFIX "dai-link"))
- num = of_get_child_count(np);
- else
- num = 1;
+ struct snd_soc_codec_conf *cconf;
+ int lnum = 0, dnum = 0, cnum = 0;
+ int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
- dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
- if (!dai_props || !dai_link)
+ asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
+ if (!lnum || !dnum)
+ return -EINVAL;
+
+ dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+ dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+ dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
+ cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
+ if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -389,7 +628,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
- for (i = 0; i < num; i++) {
+ for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -397,13 +636,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
/* Init snd_soc_card */
card = simple_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
- card->num_links = num;
+ card->num_links = lnum;
+ card->codec_conf = cconf;
+ card->num_configs = cnum;
card->probe = asoc_simple_soc_card_probe;
if (np && of_device_is_available(np)) {
@@ -419,6 +662,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct asoc_simple_card_info *cinfo;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *platform;
+ int dai_idx = 0;
cinfo = dev->platform_data;
if (!cinfo) {
@@ -435,6 +679,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
return -EINVAL;
}
+ dai_props->cpu_dai = &priv->dais[dai_idx++];
+ dai_props->codec_dai = &priv->dais[dai_idx++];
+
codecs = dai_link->codecs;
codecs->name = cinfo->codec;
codecs->dai_name = cinfo->codec_dai.name;
@@ -448,10 +695,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
dai_link->cpu_dai_name = cinfo->cpu_dai.name;
dai_link->dai_fmt = cinfo->daifmt;
dai_link->init = asoc_simple_card_dai_init;
- memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
- sizeof(priv->dai_props->cpu_dai));
- memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
- sizeof(priv->dai_props->codec_dai));
+ memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
+ sizeof(*priv->dai_props->cpu_dai));
+ memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
+ sizeof(*priv->dai_props->codec_dai));
}
snd_soc_card_set_drvdata(card, priv);
@@ -476,6 +723,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_simple_of_match[] = {
{ .compatible = "simple-audio-card", },
+ { .compatible = "simple-scu-audio-card", },
{},
};
MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index 85b46f0eae0f..9d7299d536a8 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -21,14 +21,18 @@
struct simple_card_data {
struct snd_soc_card snd_card;
- struct snd_soc_codec_conf codec_conf;
struct simple_dai_props {
- struct asoc_simple_dai dai;
+ struct asoc_simple_dai *cpu_dai;
+ struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs;
struct snd_soc_dai_link_component platform;
+ struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
} *dai_props;
struct snd_soc_dai_link *dai_link;
+ struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
+ struct snd_soc_codec_conf *codec_conf;
};
#define simple_priv_to_card(priv) (&(priv)->snd_card)
@@ -46,8 +50,17 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
+ int ret;
+
+ ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
+ if (ret)
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
- return asoc_simple_card_clk_enable(&dai_props->dai);
+ return ret;
}
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
@@ -57,7 +70,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(&dai_props->dai);
+ asoc_simple_card_clk_disable(dai_props->cpu_dai);
+
+ asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static const struct snd_soc_ops asoc_simple_card_ops = {
@@ -67,42 +82,57 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct snd_soc_dai *dai;
- struct snd_soc_dai_link *dai_link;
- struct simple_dai_props *dai_props;
- int num = rtd->num;
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+ int ret;
+
+ ret = asoc_simple_card_init_dai(rtd->codec_dai,
+ dai_props->codec_dai);
+ if (ret < 0)
+ return ret;
- dai_link = simple_priv_to_link(priv, num);
- dai_props = simple_priv_to_props(priv, num);
- dai = dai_link->dynamic ?
- rtd->cpu_dai :
- rtd->codec_dai;
+ ret = asoc_simple_card_init_dai(rtd->cpu_dai,
+ dai_props->cpu_dai);
+ if (ret < 0)
+ return ret;
- return asoc_simple_card_init_dai(dai, &dai_props->dai);
+ return 0;
}
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
+
+ asoc_simple_card_convert_fixup(&dai_props->adata, params);
+ /* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
-static int asoc_simple_card_dai_link_of(struct device_node *np,
+static int asoc_simple_card_dai_link_of(struct device_node *link,
+ struct device_node *np,
+ struct device_node *codec,
struct simple_card_data *priv,
- unsigned int daifmt,
- int idx, bool is_fe)
+ int *dai_idx, int link_idx,
+ int *conf_idx, int is_fe,
+ bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
- struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct asoc_simple_dai *dai;
+ char *prefix = "";
int ret;
+ /* For single DAI link & old style of DT node */
+ if (is_top_level_node)
+ prefix = PREFIX;
+
if (is_fe) {
int is_single_links = 0;
struct snd_soc_dai_link_component *codecs;
@@ -117,12 +147,15 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
+ dai =
+ dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
+
ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
&is_single_links);
if (ret)
return ret;
- ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai);
+ ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
if (ret < 0)
return ret;
@@ -134,6 +167,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
} else {
+ struct snd_soc_codec_conf *cconf;
+
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
@@ -143,11 +178,17 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
+ dai =
+ dai_props->codec_dai = &priv->dais[(*dai_idx)++];
+
+ cconf =
+ dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
+
ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
if (ret < 0)
return ret;
- ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai);
+ ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
if (ret < 0)
return ret;
@@ -157,13 +198,20 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
- snd_soc_of_parse_audio_prefix(card,
- &priv->codec_conf,
+ /* check "prefix" from top node */
+ snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
PREFIX "prefix");
+ /* check "prefix" from each node if top doesn't have */
+ if (!cconf->of_node)
+ snd_soc_of_parse_node_prefix(np, cconf,
+ dai_link->codecs->of_node,
+ "prefix");
}
- ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai);
+ asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata);
+
+ ret = asoc_simple_card_of_parse_tdm(np, dai);
if (ret)
return ret;
@@ -171,7 +219,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
- dai_link->dai_fmt = daifmt;
+ ret = asoc_simple_card_parse_daifmt(dev, link, codec,
+ prefix, &dai_link->dai_fmt);
+ if (ret < 0)
+ return ret;
+
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_simple_card_ops;
@@ -184,52 +236,136 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
+ struct device_node *top = dev->of_node;
+ struct device_node *node;
struct device_node *np;
+ struct device_node *codec;
struct snd_soc_card *card = simple_priv_to_card(priv);
- struct device_node *node = dev->of_node;
- unsigned int daifmt = 0;
bool is_fe;
- int ret, i;
+ int ret, loop;
+ int dai_idx, link_idx, conf_idx;
- if (!node)
+ if (!top)
return -EINVAL;
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0)
return ret;
- ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
+ ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0)
return ret;
- asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);
+ asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
- /* find 1st codec */
- np = of_get_child_by_name(node, PREFIX "codec");
- if (!np)
- return -ENODEV;
+ loop = 1;
+ link_idx = 0;
+ dai_idx = 0;
+ conf_idx = 0;
+ node = of_get_child_by_name(top, PREFIX "dai-link");
+ if (!node) {
+ node = dev->of_node;
+ loop = 0;
+ }
+
+ do {
+ codec = of_get_child_by_name(node,
+ loop ? "codec" : PREFIX "codec");
+ if (!codec)
+ return -ENODEV;
+
+ for_each_child_of_node(node, np) {
+ is_fe = (np != codec);
+
+ ret = asoc_simple_card_dai_link_of(node, np, codec, priv,
+ &dai_idx, link_idx++,
+ &conf_idx,
+ is_fe, !loop);
+ if (ret < 0)
+ return ret;
+ }
+ node = of_get_next_child(top, node);
+ } while (loop && node);
- ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);
+ ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
return ret;
- i = 0;
- for_each_child_of_node(node, np) {
- is_fe = false;
- if (strcmp(np->name, PREFIX "cpu") == 0)
- is_fe = true;
+ return 0;
+}
- ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);
- if (ret < 0)
- return ret;
- i++;
+static void asoc_simple_card_get_dais_count(struct device *dev,
+ int *link_num,
+ int *dais_num,
+ int *ccnf_num)
+{
+ struct device_node *top = dev->of_node;
+ struct device_node *node;
+ int loop;
+ int num;
+
+ /*
+ * link_num : number of links.
+ * CPU-Codec / CPU-dummy / dummy-Codec
+ * dais_num : number of DAIs
+ * ccnf_num : number of codec_conf
+ * same number for "dummy-Codec"
+ *
+ * ex1)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 7
+ * CPU2 -/ ccnf : 1
+ * CPU3 --- Codec2
+ *
+ * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
+ * => 7 DAIs = 4xCPU + 3xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex2)
+ * CPU0 --- Codec0 link : 5
+ * CPU1 --- Codec1 dais : 6
+ * CPU2 -/ ccnf : 1
+ * CPU3 -/
+ *
+ * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 1 ccnf = 1xdummy-Codec
+ *
+ * ex3)
+ * CPU0 --- Codec0 link : 6
+ * CPU1 -/ dais : 6
+ * CPU2 --- Codec1 ccnf : 2
+ * CPU3 -/
+ *
+ * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
+ * => 6 DAIs = 4xCPU + 2xCodec
+ * => 2 ccnf = 2xdummy-Codec
+ */
+ if (!top) {
+ (*link_num) = 1;
+ (*dais_num) = 2;
+ (*ccnf_num) = 0;
+ return;
}
- ret = asoc_simple_card_parse_card_name(card, PREFIX);
- if (ret < 0)
- return ret;
+ loop = 1;
+ node = of_get_child_by_name(top, PREFIX "dai-link");
+ if (!node) {
+ node = top;
+ loop = 0;
+ }
- return 0;
+ do {
+ num = of_get_child_count(node);
+ (*dais_num) += num;
+ if (num > 2) {
+ (*link_num) += num;
+ (*ccnf_num)++;
+ } else {
+ (*link_num)++;
+ }
+ node = of_get_next_child(top, node);
+ } while (loop && node);
}
static int asoc_simple_card_probe(struct platform_device *pdev)
@@ -237,21 +373,27 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
+ struct asoc_simple_dai *dais;
struct snd_soc_card *card;
+ struct snd_soc_codec_conf *cconf;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- int num, ret, i;
+ int ret, i;
+ int lnum = 0, dnum = 0, cnum = 0;
/* Allocate the private data */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- num = of_get_child_count(np);
+ asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
+ if (!lnum || !dnum)
+ return -EINVAL;
- dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
- dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
- if (!dai_props || !dai_link)
+ dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
+ dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
+ dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
+ cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
+ if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@@ -260,7 +402,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
- for (i = 0; i < num; i++) {
+ for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@@ -268,15 +410,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
+ priv->dais = dais;
+ priv->codec_conf = cconf;
/* Init snd_soc_card */
card = simple_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
- card->num_links = num;
- card->codec_conf = &priv->codec_conf;
- card->num_configs = 1;
+ card->num_links = lnum;
+ card->codec_conf = cconf;
+ card->num_configs = cnum;
ret = asoc_simple_card_parse_of(priv);
if (ret < 0) {
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 18e717703685..99a62ba409df 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -102,15 +102,74 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
recommended option
config SND_SOC_INTEL_SKYLAKE
- tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
+ tristate "All Skylake/SST Platforms"
depends on PCI && ACPI
- select SND_SOC_INTEL_SKYLAKE_COMMON
+ select SND_SOC_INTEL_SKL
+ select SND_SOC_INTEL_APL
+ select SND_SOC_INTEL_KBL
+ select SND_SOC_INTEL_GLK
+ select SND_SOC_INTEL_CNL
+ select SND_SOC_INTEL_CFL
help
- If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
- GeminiLake or CannonLake platform with the DSP enabled in the BIOS
- then enable this option by saying Y or m.
+ This is a backwards-compatible option to select all devices
+ supported by the Intel SST/Skylake driver. This option is no
+ longer recommended and will be deprecated when the SOF
+ driver is introduced. Distributions should explicitly
+ select which platform uses this driver.
+
+config SND_SOC_INTEL_SKL
+ tristate "Skylake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel Skylake platform with the DSP enabled
+ in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_APL
+ tristate "Broxton/ApolloLake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel Broxton/ApolloLake platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_KBL
+ tristate "Kabylake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel Kabylake platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_GLK
+ tristate "GeminiLake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel GeminiLake platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_CNL
+ tristate "CannonLake/WhiskyLake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel CNL/WHL platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_CFL
+ tristate "CoffeeLake Platforms"
+ depends on PCI && ACPI
+ select SND_SOC_INTEL_SKYLAKE_FAMILY
+ help
+ If you have a Intel CoffeeLake platform with the DSP
+ enabled in the BIOS then enable this option by saying Y or m.
+
+config SND_SOC_INTEL_SKYLAKE_FAMILY
+ tristate
+ select SND_SOC_INTEL_SKYLAKE_COMMON
-if SND_SOC_INTEL_SKYLAKE
+if SND_SOC_INTEL_SKYLAKE_FAMILY
config SND_SOC_INTEL_SKYLAKE_SSP_CLK
tristate
@@ -135,7 +194,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
then enable this option by saying Y or m.
-endif ## SND_SOC_INTEL_SKYLAKE
+endif ## SND_SOC_INTEL_SKYLAKE_FAMILY
config SND_SOC_ACPI_INTEL_MATCH
tristate
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index c90b04cc071d..ac542535b9d5 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -341,6 +341,10 @@ static int sst_acpi_probe(struct platform_device *pdev)
byt_rvp_platform_data.res_info = &bytcr_res_info;
}
+ /* update machine parameters */
+ mach->mach_params.acpi_ipc_irq_index =
+ pdata->res_info->acpi_ipc_irq_index;
+
plat_dev = platform_device_register_data(dev, pdata->platform, -1,
NULL, 0);
if (IS_ERR(plat_dev)) {
diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c
index 27413ebae956..b8c456753f01 100644
--- a/sound/soc/intel/atom/sst/sst_loader.c
+++ b/sound/soc/intel/atom/sst/sst_loader.c
@@ -354,14 +354,14 @@ static int sst_request_fw(struct intel_sst_drv *sst)
const struct firmware *fw;
retval = request_firmware(&fw, sst->firmware_name, sst->dev);
- if (fw == NULL) {
- dev_err(sst->dev, "fw is returning as null\n");
- return -EINVAL;
- }
if (retval) {
dev_err(sst->dev, "request fw failed %d\n", retval);
return retval;
}
+ if (fw == NULL) {
+ dev_err(sst->dev, "fw is returning as null\n");
+ return -EINVAL;
+ }
mutex_lock(&sst->sst_lock);
retval = sst_cache_and_parse_fw(sst, fw);
mutex_unlock(&sst->sst_lock);
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c
index af93244b4868..00a37a09dc9b 100644
--- a/sound/soc/intel/atom/sst/sst_pvt.c
+++ b/sound/soc/intel/atom/sst/sst_pvt.c
@@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large)
{
struct ipc_post *msg;
- msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
if (!msg)
return -ENOMEM;
if (large) {
- msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
+ msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
if (!msg->mailbox_data) {
kfree(msg);
return -ENOMEM;
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index b177db2a0dbb..0a7e40d06395 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
endif ## SND_SST_ATOM_HIFI2_PLATFORM
-if SND_SOC_INTEL_SKYLAKE
+if SND_SOC_INTEL_SKL
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "SKL with RT286 I2S mode"
@@ -212,6 +212,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+endif ## SND_SOC_INTEL_SKL
+
+if SND_SOC_INTEL_APL
+
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -239,6 +243,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+endif ## SND_SOC_INTEL_APL
+
+if SND_SOC_INTEL_KBL
+
config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
tristate "KBL with RT5663 and MAX98927 in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -293,6 +301,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
Say Y if you have such a device.
If unsure select "N".
+config SND_SOC_INTEL_KBL_RT5660_MACH
+ tristate "KBL with RT5660 in I2S Mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_RT5660
+ select SND_SOC_HDAC_HDMI
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for RT5660 I2S audio codec.
+ Say Y if you have such a device.
+
+endif ## SND_SOC_INTEL_KBL
+
+if SND_SOC_INTEL_GLK
+
config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
tristate "GLK with RT5682 and MAX98357A in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@@ -307,7 +329,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
Say Y if you have such a device.
If unsure select "N".
-endif ## SND_SOC_INTEL_SKYLAKE
+endif ## SND_SOC_INTEL_GLK
if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 5381e27df9cc..bf072ea299b7 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
+snd-soc-kbl_rt5660-objs := kbl_rt5660.o
snd-soc-skl_rt286-objs := skl_rt286.o
snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max9
obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o
+obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 8587bd3d1cc1..a22366ce33c4 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -29,7 +29,6 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
-#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -674,6 +673,33 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
+ { /* Point of View Mobii TAB-P1005W-232 (V2.0) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"),
+ },
+ .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_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
+ {
+ /* Prowise PT301 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Prowise"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PT301"),
+ },
+ .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_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
@@ -1152,10 +1178,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (is_valleyview()) {
- struct sst_platform_info *p_info = mach->pdata;
- const struct sst_res_info *res_info = p_info->res_info;
-
- if (res_info->acpi_ipc_irq_index == 0)
+ if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index c44298130720..e528995668b7 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
-#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -920,10 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (x86_match_cpu(baytrail_cpu_ids)) {
- struct sst_platform_info *p_info = mach->pdata;
- const struct sst_res_info *res_info = p_info->res_info;
-
- if (res_info->acpi_ipc_irq_index == 0)
+ if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index f5a5ea6a093c..250a356a0cbf 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -27,7 +27,6 @@
#include <linux/dmi.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
-#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -585,10 +584,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (is_valleyview()) {
- struct sst_platform_info *p_info = mach->pdata;
- const struct sst_res_info *res_info = p_info->res_info;
-
- if (res_info->acpi_ipc_irq_index == 0)
+ if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index 51f0d45d6f8f..9de64f447e7b 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -403,7 +403,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
const char *i2c_name;
int i;
- drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c
index c4b94e2617c5..c74c4f17316f 100644
--- a/sound/soc/intel/boards/glk_rt5682_max98357a.c
+++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c
@@ -603,7 +603,7 @@ static int geminilake_audio_probe(struct platform_device *pdev)
{
struct glk_card_private *ctx;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index 3fa1c3ca6d37..723a4935ed76 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -262,9 +262,9 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
jack = &ctx->kabylake_headset;
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);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
da7219_aad_jack_det(component, &ctx->kabylake_headset);
@@ -441,7 +441,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
}
-static struct snd_soc_ops skylaye_refcap_ops = {
+static struct snd_soc_ops skylake_refcap_ops = {
.startup = kabylake_refcap_startup,
};
@@ -525,7 +525,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -736,7 +736,7 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -935,7 +935,7 @@ static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_codec_private *ctx;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c
new file mode 100644
index 000000000000..3255e0029276
--- /dev/null
+++ b/sound/soc/intel/boards/kbl_rt5660.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018-19 Canonical Corporation.
+
+/*
+ * Intel Kabylake I2S Machine Driver with RT5660 Codec
+ *
+ * Modified from:
+ * Intel Kabylake I2S Machine driver supporting MAXIM98357a and
+ * DA7219 codecs
+ * Also referred to:
+ * Intel Broadwell I2S Machine driver supporting RT5677 codec
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../../codecs/hdac_hdmi.h"
+#include "../../codecs/rt5660.h"
+
+#define KBL_RT5660_CODEC_DAI "rt5660-aif1"
+#define DUAL_CHANNEL 2
+
+static struct snd_soc_card *kabylake_audio_card;
+static struct snd_soc_jack skylake_hdmi[3];
+static struct snd_soc_jack lineout_jack;
+static struct snd_soc_jack mic_jack;
+
+struct kbl_hdmi_pcm {
+ struct list_head head;
+ struct snd_soc_dai *codec_dai;
+ int device;
+};
+
+struct kbl_codec_private {
+ struct gpio_desc *gpio_lo_mute;
+ struct list_head hdmi_pcm_list;
+};
+
+enum {
+ KBL_DPCM_AUDIO_PB = 0,
+ KBL_DPCM_AUDIO_CP,
+ KBL_DPCM_AUDIO_HDMI1_PB,
+ KBL_DPCM_AUDIO_HDMI2_PB,
+ KBL_DPCM_AUDIO_HDMI3_PB,
+};
+
+#define GPIO_LINEOUT_MUTE_INDEX 0
+#define GPIO_LINEOUT_DET_INDEX 3
+#define GPIO_LINEIN_DET_INDEX 4
+
+static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true };
+static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false };
+static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false };
+
+
+static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = {
+ { "lineout-mute-gpios", &lineout_mute_gpio, 1 },
+ { "lineout-det-gpios", &lineout_det_gpio, 1 },
+ { "mic-det-gpios", &mic_det_gpio, 1 },
+ { NULL },
+};
+
+static struct snd_soc_jack_pin lineout_jack_pin = {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+};
+
+static struct snd_soc_jack_pin mic_jack_pin = {
+ .pin = "Line In",
+ .mask = SND_JACK_MICROPHONE,
+};
+
+static struct snd_soc_jack_gpio lineout_jack_gpio = {
+ .name = "lineout-det",
+ .report = SND_JACK_LINEOUT,
+ .debounce_time = 200,
+};
+
+static struct snd_soc_jack_gpio mic_jack_gpio = {
+ .name = "mic-det",
+ .report = SND_JACK_MICROPHONE,
+ .debounce_time = 200,
+};
+
+static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card);
+
+ gpiod_set_value_cansleep(priv->gpio_lo_mute,
+ !(SND_SOC_DAPM_EVENT_ON(event)));
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new kabylake_rt5660_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Line In"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
+};
+
+static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = {
+ SND_SOC_DAPM_MIC("Line In", NULL),
+ SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout),
+};
+
+static const struct snd_soc_dapm_route kabylake_rt5660_map[] = {
+ /* other jacks */
+ {"IN1P", NULL, "Line In"},
+ {"IN2P", NULL, "Line In"},
+ {"Line Out", NULL, "LOUTR"},
+ {"Line Out", NULL, "LOUTL"},
+
+ /* CODEC BE connections */
+ { "AIF1 Playback", NULL, "ssp0 Tx"},
+ { "ssp0 Tx", NULL, "codec0_out"},
+
+ { "codec0_in", NULL, "ssp0 Rx" },
+ { "ssp0 Rx", NULL, "AIF1 Capture" },
+
+ { "hifi1", NULL, "iDisp1 Tx"},
+ { "iDisp1 Tx", NULL, "iDisp1_out"},
+ { "hifi2", NULL, "iDisp2 Tx"},
+ { "iDisp2 Tx", NULL, "iDisp2_out"},
+ { "hifi3", NULL, "iDisp3 Tx"},
+ { "iDisp3 Tx", NULL, "iDisp3_out"},
+};
+
+static int kabylake_ssp0_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);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = DUAL_CHANNEL;
+
+ /* set SSP0 to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+
+ ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios);
+ if (ret)
+ dev_warn(component->dev, "Failed to add driver gpios\n");
+
+ /* Request rt5660 GPIO for lineout mute control, return if fails */
+ ctx->gpio_lo_mute = devm_gpiod_get(component->dev, "lineout-mute",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->gpio_lo_mute)) {
+ dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n");
+ return PTR_ERR(ctx->gpio_lo_mute);
+ }
+
+ /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */
+ ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack",
+ SND_JACK_LINEOUT, &lineout_jack,
+ &lineout_jack_pin, 1);
+ if (ret)
+ dev_warn(component->dev, "Can't create Lineout jack\n");
+ else {
+ lineout_jack_gpio.gpiod_dev = component->dev;
+ ret = snd_soc_jack_add_gpios(&lineout_jack, 1,
+ &lineout_jack_gpio);
+ if (ret)
+ dev_warn(component->dev, "Can't add Lineout jack gpio\n");
+ }
+
+ /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */
+ ret = snd_soc_card_jack_new(rtd->card, "Mic Jack",
+ SND_JACK_MICROPHONE, &mic_jack,
+ &mic_jack_pin, 1);
+ if (ret)
+ dev_warn(component->dev, "Can't create mic jack\n");
+ else {
+ mic_jack_gpio.gpiod_dev = component->dev;
+ ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio);
+ if (ret)
+ dev_warn(component->dev, "Can't add mic jack gpio\n");
+ }
+
+ /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+ snd_soc_dapm_force_enable_pin(dapm, "BST1");
+ snd_soc_dapm_force_enable_pin(dapm, "BST2");
+
+ return 0;
+}
+
+static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
+{
+ struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *dai = rtd->codec_dai;
+ struct kbl_hdmi_pcm *pcm;
+
+ pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+
+ pcm->device = device;
+ pcm->codec_dai = dai;
+
+ list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+ return 0;
+}
+
+static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
+}
+
+static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
+}
+
+static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
+}
+
+static int kabylake_rt5660_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 = rtd->codec_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ RT5660_SCLK_S_PLL1, params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ RT5660_PLL1_S_BCLK,
+ params_rate(params) * 50,
+ params_rate(params) * 512);
+ if (ret < 0)
+ dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
+
+ return ret;
+}
+
+static struct snd_soc_ops kabylake_rt5660_ops = {
+ .hw_params = kabylake_rt5660_hw_params,
+};
+
+static const unsigned int rates[] = {
+ 48000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static const unsigned int channels[] = {
+ DUAL_CHANNEL,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int kbl_fe_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ /*
+ * On this platform for PCM device we support,
+ * 48Khz
+ * stereo
+ * 16 bit audio
+ */
+
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+
+ return 0;
+}
+
+static const struct snd_soc_ops kabylake_rt5660_fe_ops = {
+ .startup = kbl_fe_startup,
+};
+
+/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */
+static struct snd_soc_dai_link kabylake_rt5660_dais[] = {
+ /* Front End DAI links */
+ [KBL_DPCM_AUDIO_PB] = {
+ .name = "Kbl Audio Port",
+ .stream_name = "Audio",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:1f.3",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .nonatomic = 1,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .ops = &kabylake_rt5660_fe_ops,
+ },
+ [KBL_DPCM_AUDIO_CP] = {
+ .name = "Kbl Audio Capture Port",
+ .stream_name = "Audio Record",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:1f.3",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .nonatomic = 1,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_capture = 1,
+ .ops = &kabylake_rt5660_fe_ops,
+ },
+ [KBL_DPCM_AUDIO_HDMI1_PB] = {
+ .name = "Kbl HDMI Port1",
+ .stream_name = "Hdmi1",
+ .cpu_dai_name = "HDMI1 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [KBL_DPCM_AUDIO_HDMI2_PB] = {
+ .name = "Kbl HDMI Port2",
+ .stream_name = "Hdmi2",
+ .cpu_dai_name = "HDMI2 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [KBL_DPCM_AUDIO_HDMI3_PB] = {
+ .name = "Kbl HDMI Port3",
+ .stream_name = "Hdmi3",
+ .cpu_dai_name = "HDMI3 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .init = NULL,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "SSP0-Codec",
+ .id = 0,
+ .cpu_dai_name = "SSP0 Pin",
+ .platform_name = "0000:00:1f.3",
+ .no_pcm = 1,
+ .codec_name = "i2c-10EC3277:00",
+ .codec_dai_name = KBL_RT5660_CODEC_DAI,
+ .init = kabylake_rt5660_codec_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = kabylake_ssp0_fixup,
+ .ops = &kabylake_rt5660_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "iDisp1",
+ .id = 1,
+ .cpu_dai_name = "iDisp1 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi1",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = kabylake_hdmi1_init,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp2",
+ .id = 2,
+ .cpu_dai_name = "iDisp2 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi2",
+ .platform_name = "0000:00:1f.3",
+ .init = kabylake_hdmi2_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp3",
+ .id = 3,
+ .cpu_dai_name = "iDisp3 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi3",
+ .platform_name = "0000:00:1f.3",
+ .init = kabylake_hdmi3_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+};
+
+
+#define NAME_SIZE 32
+static int kabylake_card_late_probe(struct snd_soc_card *card)
+{
+ struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
+ struct kbl_hdmi_pcm *pcm;
+ struct snd_soc_component *component = NULL;
+ int err, i = 0;
+ char jack_name[NAME_SIZE];
+
+ list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+ component = pcm->codec_dai->component;
+ snprintf(jack_name, sizeof(jack_name),
+ "HDMI/DP, pcm=%d Jack", pcm->device);
+ err = snd_soc_card_jack_new(card, jack_name,
+ SND_JACK_AVOUT, &skylake_hdmi[i],
+ NULL, 0);
+
+ if (err)
+ return err;
+
+ err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+ &skylake_hdmi[i]);
+ if (err < 0)
+ return err;
+
+ i++;
+
+ }
+
+ if (!component)
+ return -EINVAL;
+
+ return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
+
+/* kabylake audio machine driver for rt5660 */
+static struct snd_soc_card kabylake_audio_card_rt5660 = {
+ .name = "kblrt5660",
+ .owner = THIS_MODULE,
+ .dai_link = kabylake_rt5660_dais,
+ .num_links = ARRAY_SIZE(kabylake_rt5660_dais),
+ .controls = kabylake_rt5660_controls,
+ .num_controls = ARRAY_SIZE(kabylake_rt5660_controls),
+ .dapm_widgets = kabylake_rt5660_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets),
+ .dapm_routes = kabylake_rt5660_map,
+ .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map),
+ .fully_routed = true,
+ .late_probe = kabylake_card_late_probe,
+};
+
+static int kabylake_audio_probe(struct platform_device *pdev)
+{
+ struct kbl_codec_private *ctx;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+ kabylake_audio_card =
+ (struct snd_soc_card *)pdev->id_entry->driver_data;
+
+ kabylake_audio_card->dev = &pdev->dev;
+ snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
+ return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
+}
+
+static const struct platform_device_id kbl_board_ids[] = {
+ {
+ .name = "kbl_rt5660",
+ .driver_data =
+ (kernel_ulong_t)&kabylake_audio_card_rt5660,
+ },
+ { }
+};
+
+static struct platform_driver kabylake_audio = {
+ .probe = kabylake_audio_probe,
+ .driver = {
+ .name = "kbl_rt5660",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = kbl_board_ids,
+};
+
+module_platform_driver(kabylake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode");
+MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kbl_rt5660");
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 99e1320c485f..d71475200b08 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -25,9 +25,9 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/rt5663.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
@@ -586,7 +586,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
-static struct snd_soc_ops skylaye_refcap_ops = {
+static struct snd_soc_ops skylake_refcap_ops = {
.startup = kabylake_refcap_startup,
};
@@ -655,7 +655,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
@@ -969,7 +969,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = {
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_rt5663_private *ctx;
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
int ret;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
@@ -984,9 +984,9 @@ static int kabylake_audio_probe(struct platform_device *pdev)
kabylake_audio_card->dev = &pdev->dev;
snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
- pdata = dev_get_drvdata(&pdev->dev);
- if (pdata)
- dmic_constraints = pdata->dmic_num == 2 ?
+ mach = (&pdev->dev)->platform_data;
+ if (mach)
+ dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk");
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index a737c915d46a..7044d8c2b187 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -26,10 +26,10 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/rt5514.h"
#include "../../codecs/rt5663.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#define KBL_REALTEK_CODEC_DAI "rt5663-aif"
#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1"
@@ -648,7 +648,7 @@ static struct snd_soc_card kabylake_audio_card = {
static int kabylake_audio_probe(struct platform_device *pdev)
{
struct kbl_codec_private *ctx;
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -659,9 +659,9 @@ static int kabylake_audio_probe(struct platform_device *pdev)
kabylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&kabylake_audio_card, ctx);
- pdata = dev_get_drvdata(&pdev->dev);
- if (pdata)
- dmic_constraints = pdata->dmic_num == 2 ?
+ mach = (&pdev->dev)->platform_data;
+ if (mach)
+ dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card);
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index b415dd4c85f5..b9a21e64ead2 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -12,8 +12,8 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#include "skl_hda_dsp_common.h"
static const struct snd_soc_dapm_widget skl_hda_widgets[] = {
@@ -101,17 +101,17 @@ static struct snd_soc_card hda_soc_card = {
#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2)
#define IDISP_CODEC_MASK 0x4
-static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
+static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
{
struct snd_soc_card *card = &hda_soc_card;
struct snd_soc_dai_link *dai_link;
u32 codec_count, codec_mask;
int i, num_links, num_route;
- codec_mask = pdata->codec_mask;
+ codec_mask = mach_params->codec_mask;
codec_count = hweight_long(codec_mask);
- if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) {
+ if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) {
num_links = IDISP_DAI_COUNT;
num_route = IDISP_ROUTE_COUNT;
} else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) {
@@ -127,30 +127,30 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
card->num_dapm_routes = num_route;
for_each_card_prelinks(card, i, dai_link)
- dai_link->platform_name = pdata->platform;
+ dai_link->platform_name = mach_params->platform;
return 0;
}
static int skl_hda_audio_probe(struct platform_device *pdev)
{
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
struct skl_hda_private *ctx;
int ret;
dev_dbg(&pdev->dev, "%s: entry\n", __func__);
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
- pdata = dev_get_drvdata(&pdev->dev);
- if (!pdata)
+ mach = (&pdev->dev)->platform_data;
+ if (!mach)
return -EINVAL;
- ret = skl_hda_fill_card_info(pdata);
+ ret = skl_hda_fill_card_info(&mach->mach_params);
if (ret < 0) {
dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n");
return ret;
@@ -158,7 +158,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
ctx->pcm_count = hda_soc_card.num_links;
ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */
- ctx->platform_name = pdata->platform;
+ ctx->platform_name = mach->mach_params.platform;
hda_soc_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&hda_soc_card, ctx);
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index d31482b8c9bb..0922106bd323 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -21,9 +21,9 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_MAXIM_CODEC_DAI "HiFi"
@@ -400,7 +400,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
-static const struct snd_soc_ops skylaye_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
.startup = skylake_refcap_startup,
};
@@ -447,7 +447,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
@@ -641,7 +641,7 @@ static struct snd_soc_card skylake_audio_card = {
static int skylake_audio_probe(struct platform_device *pdev)
{
struct skl_nau8825_private *ctx;
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -652,9 +652,9 @@ static int skylake_audio_probe(struct platform_device *pdev)
skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
- pdata = dev_get_drvdata(&pdev->dev);
- if (pdata)
- dmic_constraints = pdata->dmic_num == 2 ?
+ mach = (&pdev->dev)->platform_data;
+ if (mach)
+ dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index e877bb60beb1..8433c521d39f 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -23,11 +23,11 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
-#include "../skylake/skl.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
@@ -449,7 +449,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
&constraints_16000);
}
-static const struct snd_soc_ops skylaye_refcap_ops = {
+static const struct snd_soc_ops skylake_refcap_ops = {
.startup = skylake_refcap_startup,
};
@@ -496,7 +496,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
- .ops = &skylaye_refcap_ops,
+ .ops = &skylake_refcap_ops,
},
[SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
@@ -694,7 +694,7 @@ static struct snd_soc_card skylake_audio_card = {
static int skylake_audio_probe(struct platform_device *pdev)
{
struct skl_nau88125_private *ctx;
- struct skl_machine_pdata *pdata;
+ struct snd_soc_acpi_mach *mach;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -705,9 +705,9 @@ static int skylake_audio_probe(struct platform_device *pdev)
skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
- pdata = dev_get_drvdata(&pdev->dev);
- if (pdata)
- dmic_constraints = pdata->dmic_num == 2 ?
+ mach = (&pdev->dev)->platform_data;
+ if (mach)
+ dmic_constraints = mach->mach_params.dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index c1f50a079d34..56c81e20b5bf 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -7,7 +7,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
soc-acpi-intel-hsw-bdw-match.o \
soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \
soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \
- soc-acpi-intel-cnl-match.o \
+ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-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-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
index f39386e540d3..61dedc103b19 100644
--- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
@@ -6,9 +6,41 @@
*
*/
+#include <linux/dmi.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+enum {
+ APL_RVP,
+};
+
+static const struct dmi_system_id apl_table[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
+ DMI_MATCH(DMI_BOARD_NAME, "Apollolake RVP1A"),
+ },
+ .driver_data = (void *)(APL_RVP),
+ },
+ {}
+};
+
+static struct snd_soc_acpi_mach *apl_quirk(void *arg)
+{
+ struct snd_soc_acpi_mach *mach = arg;
+ const struct dmi_system_id *dmi_id;
+ unsigned long apl_machine_id;
+
+ dmi_id = dmi_first_match(apl_table);
+ if (dmi_id) {
+ apl_machine_id = (unsigned long)dmi_id->driver_data;
+ if (apl_machine_id == APL_RVP)
+ return NULL;
+ }
+
+ return mach;
+}
+
static struct snd_soc_acpi_codecs bxt_codecs = {
.num_codecs = 1,
.codecs = {"MX98357A"}
@@ -19,6 +51,9 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
.id = "INT343A",
.drv_name = "bxt_alc298s_i2s",
.fw_filename = "intel/dsp_fw_bxtn.bin",
+ .sof_fw_filename = "intel/sof-apl.ri",
+ .sof_tplg_filename = "intel/sof-apl-rt298.tplg",
+ .asoc_plat_name = "0000:00:0e.0",
},
{
.id = "DLGS7219",
@@ -47,6 +82,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
{
.id = "INT34C3",
.drv_name = "bxt_tdf8532",
+ .machine_quirk = apl_quirk,
.sof_fw_filename = "intel/sof-apl.ri",
.sof_tplg_filename = "intel/sof-apl-tdf8532.tplg",
.asoc_plat_name = "0000:00:0e.0",
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
new file mode 100644
index 000000000000..33b441dca4d3
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata icl_pdata = {
+ .use_tplg_pcm = true,
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = {
+ {
+ .id = "INT34C2",
+ .drv_name = "icl_rt274",
+ .fw_filename = "intel/dsp_fw_icl.bin",
+ .pdata = &icl_pdata,
+ .sof_fw_filename = "intel/sof-icl.ri",
+ .sof_tplg_filename = "intel/sof-icl-rt274.tplg",
+ .asoc_plat_name = "0000:00:1f.3",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
index a317b7790fce..e6fa6f470526 100644
--- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
@@ -96,6 +96,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
.quirk_data = &kbl_7219_98927_codecs,
.pdata = &skl_dmic_data
},
+ {
+ .id = "10EC5660",
+ .drv_name = "kbl_rt5660",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ },
+ {
+ .id = "10EC3277",
+ .drv_name = "kbl_rt5660",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines);
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 8bfb8b0fa3d5..b0e6fb93eaf8 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -247,6 +247,14 @@ static const struct skl_dsp_ops dsp_ops[] = {
.init_fw = cnl_sst_init_fw,
.cleanup = cnl_sst_dsp_cleanup
},
+ {
+ .id = 0xa348,
+ .num_cores = 4,
+ .loader_ops = bxt_get_loader_ops,
+ .init = cnl_sst_dsp_init,
+ .init_fw = cnl_sst_init_fw,
+ .cleanup = cnl_sst_dsp_cleanup
+ },
};
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index 01a050cf8775..5d125a3df527 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -180,6 +180,9 @@ int skl_get_dmic_geo(struct skl *skl)
unsigned int dmic_geo = 0;
u8 j;
+ if (!nhlt)
+ return 0;
+
epnt = (struct nhlt_endpoint *)nhlt->desc;
for (j = 0; j < nhlt->endpoint_count; j++) {
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 5234fafb758a..9f3ce73593ae 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -249,6 +249,8 @@ enum skl_ipc_glb_reply {
IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121,
IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140,
IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141,
+ IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150,
+ IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151,
IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160,
IPC_GLB_REPLY_PPL_NOT_EXIST = 161,
@@ -392,18 +394,47 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
return 0;
}
-static int skl_ipc_set_reply_error_code(u32 reply)
+struct skl_ipc_err_map {
+ const char *msg;
+ enum skl_ipc_glb_reply reply;
+ int err;
+};
+
+static struct skl_ipc_err_map skl_err_map[] = {
+ {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM},
+ {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY},
+ {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING,
+ IPC_GLB_REPLY_SCLK_ALREADY_RUNNING},
+ {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING,
+ IPC_GLB_REPLY_MCLK_ALREADY_RUNNING},
+};
+
+static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply)
{
- switch (reply) {
- case IPC_GLB_REPLY_OUT_OF_MEMORY:
- return -ENOMEM;
+ int i;
- case IPC_GLB_REPLY_BUSY:
- return -EBUSY;
+ for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) {
+ if (skl_err_map[i].reply == reply)
+ break;
+ }
- default:
+ if (i == ARRAY_SIZE(skl_err_map)) {
+ dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n",
+ reply,
+ ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
return -EINVAL;
}
+
+ if (skl_err_map[i].err < 0)
+ dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
+ skl_err_map[i].msg,
+ ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+ else
+ dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n",
+ skl_err_map[i].msg,
+ ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+
+ return skl_err_map[i].err;
}
void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
@@ -441,10 +472,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
}
} else {
- msg->errno = skl_ipc_set_reply_error_code(reply);
- dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply);
- dev_err(ipc->dev, "FW Error Code: %u\n",
- ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp));
+ msg->errno = skl_ipc_set_reply_error_code(ipc, reply);
switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) {
case IPC_GLB_LOAD_MULTIPLE_MODS:
case IPC_GLB_LOAD_LIBRARY:
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 7487f388e65d..5abd35ca4e41 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -517,7 +517,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
if (pdata) {
skl->use_tplg_pcm = pdata->use_tplg_pcm;
- pdata->dmic_num = skl_get_dmic_geo(skl);
+ mach->mach_params.dmic_num = skl_get_dmic_geo(skl);
}
return 0;
@@ -527,7 +527,6 @@ static int skl_machine_device_register(struct skl *skl)
{
struct snd_soc_acpi_mach *mach = skl->mach;
struct hdac_bus *bus = skl_to_bus(skl);
- struct skl_machine_pdata *pdata;
struct platform_device *pdev;
int ret;
@@ -537,6 +536,16 @@ static int skl_machine_device_register(struct skl *skl)
return -EIO;
}
+ mach->mach_params.platform = dev_name(bus->dev);
+ mach->mach_params.codec_mask = bus->codec_mask;
+
+ ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach));
+ if (ret) {
+ dev_err(bus->dev, "failed to add machine device platform data\n");
+ platform_device_put(pdev);
+ return ret;
+ }
+
ret = platform_device_add(pdev);
if (ret) {
dev_err(bus->dev, "failed to add machine device\n");
@@ -544,12 +553,6 @@ static int skl_machine_device_register(struct skl *skl)
return -EIO;
}
- if (mach->pdata) {
- pdata = (struct skl_machine_pdata *)mach->pdata;
- pdata->platform = dev_name(bus->dev);
- pdata->codec_mask = bus->codec_mask;
- dev_set_drvdata(&pdev->dev, mach->pdata);
- }
skl->i2s_dev = pdev;
@@ -823,12 +826,10 @@ static void skl_probe_work(struct work_struct *work)
return;
}
- if (bus->ppcap) {
- err = skl_machine_device_register(skl);
- if (err < 0) {
- dev_err(bus->dev, "machine register failed: %d\n", err);
- goto out_err;
- }
+ err = skl_machine_device_register(skl);
+ if (err < 0) {
+ dev_err(bus->dev, "machine register failed: %d\n", err);
+ goto out_err;
}
/*
@@ -913,6 +914,21 @@ static int skl_first_init(struct hdac_bus *bus)
unsigned short gcap;
int cp_streams, pb_streams, start_idx;
+ /*
+ * detect DSP by checking class/subclass/prog-id information
+ * class=04 subclass 03 prog-if 00: no DSP, legacy driver needs to be used
+ * class=04 subclass 01 prog-if 00: DSP is present (and may be required e.g. for DMIC or SSP support)
+ * class=04 subclass 03 prog-if 80: either of DSP or legacy mode can be used
+ */
+ if (pci->class == 0x040300) {
+ dev_err(bus->dev, "The DSP is not enabled on this platform, aborting probe\n");
+ return -ENODEV;
+ } else if (pci->class != 0x040100 && pci->class != 0x040380) {
+ dev_err(bus->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class);
+ return -ENODEV;
+ }
+ dev_info(bus->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
+
err = pci_request_regions(pci, "Skylake HD audio");
if (err < 0)
return err;
@@ -928,6 +944,12 @@ static int skl_first_init(struct hdac_bus *bus)
snd_hdac_bus_parse_capabilities(bus);
+ /* check if PPCAP exists */
+ if (!bus->ppcap) {
+ dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n");
+ return -ENODEV;
+ }
+
if (skl_acquire_irq(bus, 0) < 0)
return -EBUSY;
@@ -937,23 +959,25 @@ static int skl_first_init(struct hdac_bus *bus)
gcap = snd_hdac_chip_readw(bus, GCAP);
dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap);
- /* allow 64bit DMA address if supported by H/W */
- if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
- dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
- } else {
- dma_set_mask(bus->dev, DMA_BIT_MASK(32));
- dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
- }
-
/* read number of streams from GCAP register */
cp_streams = (gcap >> 8) & 0x0f;
pb_streams = (gcap >> 12) & 0x0f;
- if (!pb_streams && !cp_streams)
+ if (!pb_streams && !cp_streams) {
+ dev_err(bus->dev, "no streams found in GCAP definitions?\n");
return -EIO;
+ }
bus->num_streams = cp_streams + pb_streams;
+ /* allow 64bit DMA address if supported by H/W */
+ if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) {
+ dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64));
+ } else {
+ dma_set_mask(bus->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32));
+ }
+
/* initialize streams */
snd_hdac_ext_stream_init_all
(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
@@ -986,8 +1010,10 @@ static int skl_probe(struct pci_dev *pci,
bus = skl_to_bus(skl);
err = skl_first_init(bus);
- if (err < 0)
+ if (err < 0) {
+ dev_err(bus->dev, "skl_first_init failed with err: %d\n", err);
goto out_free;
+ }
skl->pci_id = pci->device;
@@ -996,37 +1022,48 @@ static int skl_probe(struct pci_dev *pci,
skl->nhlt = skl_nhlt_init(bus->dev);
if (skl->nhlt == NULL) {
+#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
+ dev_err(bus->dev, "no nhlt info found\n");
err = -ENODEV;
goto out_free;
- }
-
- err = skl_nhlt_create_sysfs(skl);
- if (err < 0)
- goto out_nhlt_free;
+#else
+ dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n");
+#endif
+ } else {
- skl_nhlt_update_topology_bin(skl);
+ err = skl_nhlt_create_sysfs(skl);
+ if (err < 0) {
+ dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err);
+ goto out_nhlt_free;
+ }
- pci_set_drvdata(skl->pci, bus);
+ skl_nhlt_update_topology_bin(skl);
- /* check if dsp is there */
- if (bus->ppcap) {
/* create device for dsp clk */
err = skl_clock_device_register(skl);
- if (err < 0)
+ if (err < 0) {
+ dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err);
goto out_clk_free;
+ }
+ }
- err = skl_find_machine(skl, (void *)pci_id->driver_data);
- if (err < 0)
- goto out_nhlt_free;
+ pci_set_drvdata(skl->pci, bus);
- err = skl_init_dsp(skl);
- if (err < 0) {
- dev_dbg(bus->dev, "error failed to register dsp\n");
- goto out_nhlt_free;
- }
- skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
- skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+
+ err = skl_find_machine(skl, (void *)pci_id->driver_data);
+ if (err < 0) {
+ dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err);
+ goto out_nhlt_free;
+ }
+
+ err = skl_init_dsp(skl);
+ if (err < 0) {
+ dev_dbg(bus->dev, "error failed to register dsp\n");
+ goto out_nhlt_free;
}
+ skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
+ skl->skl_sst->clock_power_gating = skl_clock_power_gating;
+
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
@@ -1034,8 +1071,10 @@ static int skl_probe(struct pci_dev *pci,
/* create device for soc dmic */
err = skl_dmic_device_register(skl);
- if (err < 0)
+ if (err < 0) {
+ dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err);
goto out_dsp_free;
+ }
schedule_work(&skl->probe_work);
@@ -1103,21 +1142,36 @@ static void skl_remove(struct pci_dev *pci)
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70),
.driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
/* BXT-P */
{ PCI_DEVICE(0x8086, 0x5a98),
.driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
/* KBL */
{ PCI_DEVICE(0x8086, 0x9D71),
.driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
/* GLK */
{ PCI_DEVICE(0x8086, 0x3198),
.driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
/* CNL */
{ PCI_DEVICE(0x8086, 0x9dc8),
.driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
+ /* CFL */
+ { PCI_DEVICE(0x8086, 0xa348),
+ .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+#endif
{ 0, }
};
MODULE_DEVICE_TABLE(pci, skl_ids);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 8d48cd7c56c8..85f8bb6687dc 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -119,10 +119,7 @@ struct skl_dma_params {
};
struct skl_machine_pdata {
- u32 dmic_num;
bool use_tplg_pcm; /* use dais and dai links from topology */
- const char *platform;
- u32 codec_mask;
};
struct skl_dsp_ops {
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index 192f4d7b37b6..bff7d71d0742 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -828,7 +828,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
/* request irq */
irq_id = platform_get_irq(pdev, 0);
if (!irq_id) {
- dev_err(dev, "%s no irq found\n", dev->of_node->name);
+ dev_err(dev, "%pOFn no irq found\n", dev->of_node);
return -ENXIO;
}
ret = devm_request_irq(dev, irq_id, mt6797_afe_irq_handler,
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index c0b6697503fd..166aed28330d 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -1092,7 +1092,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
irq_id = platform_get_irq(pdev, 0);
if (irq_id <= 0) {
- dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name);
+ dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node);
return irq_id < 0 ? irq_id : -ENXIO;
}
ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
index 8b8426ed2363..8779fe23671d 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -54,6 +54,7 @@ config SND_MESON_AXG_SOUND_CARD
imply SND_MESON_AXG_TDMIN
imply SND_MESON_AXG_TDMOUT
imply SND_MESON_AXG_SPDIFOUT
+ imply SND_MESON_AXG_SPDIFIN
imply SND_MESON_AXG_PDM
help
Select Y or M to add support for the AXG SoC sound card
@@ -67,6 +68,13 @@ config SND_MESON_AXG_SPDIFOUT
Select Y or M to add support for SPDIF output serializer embedded
in the Amlogic AXG SoC family
+config SND_MESON_AXG_SPDIFIN
+ tristate "Amlogic AXG SPDIF Input Support"
+ imply SND_SOC_SPDIF
+ help
+ Select Y or M to add support for SPDIF input embedded
+ in the Amlogic AXG SoC family
+
config SND_MESON_AXG_PDM
tristate "Amlogic AXG PDM Input Support"
imply SND_SOC_DMIC
@@ -74,5 +82,4 @@ config SND_MESON_AXG_PDM
help
Select Y or M to add support for PDM input embedded
in the Amlogic AXG SoC family
-
endmenu
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
index 4cd25104029d..b45dfb9e2f88 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -8,6 +8,7 @@ snd-soc-meson-axg-tdm-interface-objs := axg-tdm-interface.o
snd-soc-meson-axg-tdmin-objs := axg-tdmin.o
snd-soc-meson-axg-tdmout-objs := axg-tdmout.o
snd-soc-meson-axg-sound-card-objs := axg-card.o
+snd-soc-meson-axg-spdifin-objs := axg-spdifin.o
snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
snd-soc-meson-axg-pdm-objs := axg-pdm.o
@@ -19,5 +20,6 @@ obj-$(CONFIG_SND_MESON_AXG_TDM_INTERFACE) += snd-soc-meson-axg-tdm-interface.o
obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o
obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o
obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
+obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o
obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h
index cb6c4013ca33..d9f516cfbeda 100644
--- a/sound/soc/meson/axg-fifo.h
+++ b/sound/soc/meson/axg-fifo.h
@@ -25,7 +25,8 @@ struct snd_soc_pcm_runtime;
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE)
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
#define AXG_FIFO_BURST 8
#define AXG_FIFO_MIN_CNT 64
diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c
new file mode 100644
index 000000000000..01b2035fa841
--- /dev/null
+++ b/sound/soc/meson/axg-spdifin.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm_params.h>
+
+#define SPDIFIN_CTRL0 0x00
+#define SPDIFIN_CTRL0_EN BIT(31)
+#define SPDIFIN_CTRL0_RST_OUT BIT(29)
+#define SPDIFIN_CTRL0_RST_IN BIT(28)
+#define SPDIFIN_CTRL0_WIDTH_SEL BIT(24)
+#define SPDIFIN_CTRL0_STATUS_CH_SHIFT 11
+#define SPDIFIN_CTRL0_STATUS_SEL GENMASK(10, 8)
+#define SPDIFIN_CTRL0_SRC_SEL GENMASK(5, 4)
+#define SPDIFIN_CTRL0_CHK_VALID BIT(3)
+#define SPDIFIN_CTRL1 0x04
+#define SPDIFIN_CTRL1_BASE_TIMER GENMASK(19, 0)
+#define SPDIFIN_CTRL1_IRQ_MASK GENMASK(27, 20)
+#define SPDIFIN_CTRL2 0x08
+#define SPDIFIN_THRES_PER_REG 3
+#define SPDIFIN_THRES_WIDTH 10
+#define SPDIFIN_CTRL3 0x0c
+#define SPDIFIN_CTRL4 0x10
+#define SPDIFIN_TIMER_PER_REG 4
+#define SPDIFIN_TIMER_WIDTH 8
+#define SPDIFIN_CTRL5 0x14
+#define SPDIFIN_CTRL6 0x18
+#define SPDIFIN_STAT0 0x1c
+#define SPDIFIN_STAT0_MODE GENMASK(30, 28)
+#define SPDIFIN_STAT0_MAXW GENMASK(17, 8)
+#define SPDIFIN_STAT0_IRQ GENMASK(7, 0)
+#define SPDIFIN_IRQ_MODE_CHANGED BIT(2)
+#define SPDIFIN_STAT1 0x20
+#define SPDIFIN_STAT2 0x24
+#define SPDIFIN_MUTE_VAL 0x28
+
+#define SPDIFIN_MODE_NUM 7
+
+struct axg_spdifin_cfg {
+ const unsigned int *mode_rates;
+ unsigned int ref_rate;
+};
+
+struct axg_spdifin {
+ const struct axg_spdifin_cfg *conf;
+ struct regmap *map;
+ struct clk *refclk;
+ struct clk *pclk;
+};
+
+/*
+ * TODO:
+ * It would have been nice to check the actual rate against the sample rate
+ * requested in hw_params(). Unfortunately, I was not able to make the mode
+ * detection and IRQ work reliably:
+ *
+ * 1. IRQs are generated on mode change only, so there is no notification
+ * on transition between no signal and mode 0 (32kHz).
+ * 2. Mode detection very often has glitches, and may detects the
+ * lowest or the highest mode before zeroing in on the actual mode.
+ *
+ * This makes calling snd_pcm_stop() difficult to get right. Even notifying
+ * the kcontrol would be very unreliable at this point.
+ * Let's keep things simple until the magic spell that makes this work is
+ * found.
+ */
+
+static unsigned int axg_spdifin_get_rate(struct axg_spdifin *priv)
+{
+ unsigned int stat, mode, rate = 0;
+
+ regmap_read(priv->map, SPDIFIN_STAT0, &stat);
+ mode = FIELD_GET(SPDIFIN_STAT0_MODE, stat);
+
+ /*
+ * If max width is zero, we are not capturing anything.
+ * Also Sometimes, when the capture is on but there is no data,
+ * mode is SPDIFIN_MODE_NUM, but not always ...
+ */
+ if (FIELD_GET(SPDIFIN_STAT0_MAXW, stat) &&
+ mode < SPDIFIN_MODE_NUM)
+ rate = priv->conf->mode_rates[mode];
+
+ return rate;
+}
+
+static int axg_spdifin_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+ /* Apply both reset */
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_RST_OUT |
+ SPDIFIN_CTRL0_RST_IN,
+ 0);
+
+ /* Clear out reset before in reset */
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_RST_OUT, SPDIFIN_CTRL0_RST_OUT);
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_RST_IN, SPDIFIN_CTRL0_RST_IN);
+
+ return 0;
+}
+
+static int axg_spdifin_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = clk_prepare_enable(priv->refclk);
+ if (ret) {
+ dev_err(dai->dev,
+ "failed to enable spdifin reference clock\n");
+ return ret;
+ }
+
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN,
+ SPDIFIN_CTRL0_EN);
+
+ return 0;
+}
+
+static void axg_spdifin_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0);
+ clk_disable_unprepare(priv->refclk);
+}
+
+static void axg_spdifin_write_mode_param(struct regmap *map, int mode,
+ unsigned int val,
+ unsigned int num_per_reg,
+ unsigned int base_reg,
+ unsigned int width)
+{
+ uint64_t offset = mode;
+ unsigned int reg, shift, rem;
+
+ rem = do_div(offset, num_per_reg);
+
+ reg = offset * regmap_get_reg_stride(map) + base_reg;
+ shift = width * (num_per_reg - 1 - rem);
+
+ regmap_update_bits(map, reg, GENMASK(width - 1, 0) << shift,
+ val << shift);
+}
+
+static void axg_spdifin_write_timer(struct regmap *map, int mode,
+ unsigned int val)
+{
+ axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_TIMER_PER_REG,
+ SPDIFIN_CTRL4, SPDIFIN_TIMER_WIDTH);
+}
+
+static void axg_spdifin_write_threshold(struct regmap *map, int mode,
+ unsigned int val)
+{
+ axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_THRES_PER_REG,
+ SPDIFIN_CTRL2, SPDIFIN_THRES_WIDTH);
+}
+
+static unsigned int axg_spdifin_mode_timer(struct axg_spdifin *priv,
+ int mode,
+ unsigned int rate)
+{
+ /*
+ * Number of period of the reference clock during a period of the
+ * input signal reference clock
+ */
+ return rate / (128 * priv->conf->mode_rates[mode]);
+}
+
+static int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai,
+ struct axg_spdifin *priv)
+{
+ unsigned int rate, t_next;
+ int ret, i = SPDIFIN_MODE_NUM - 1;
+
+ /* Set spdif input reference clock */
+ ret = clk_set_rate(priv->refclk, priv->conf->ref_rate);
+ if (ret) {
+ dev_err(dai->dev, "reference clock rate set failed\n");
+ return ret;
+ }
+
+ /*
+ * The rate actually set might be slightly different, get
+ * the actual rate for the following mode calculation
+ */
+ rate = clk_get_rate(priv->refclk);
+
+ /* HW will update mode every 1ms */
+ regmap_update_bits(priv->map, SPDIFIN_CTRL1,
+ SPDIFIN_CTRL1_BASE_TIMER,
+ FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000));
+
+ /* Threshold based on the minimum width between two edges */
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_WIDTH_SEL, SPDIFIN_CTRL0_WIDTH_SEL);
+
+ /* Calculate the last timer which has no threshold */
+ t_next = axg_spdifin_mode_timer(priv, i, rate);
+ axg_spdifin_write_timer(priv->map, i, t_next);
+
+ do {
+ unsigned int t;
+
+ i -= 1;
+
+ /* Calculate the timer */
+ t = axg_spdifin_mode_timer(priv, i, rate);
+
+ /* Set the timer value */
+ axg_spdifin_write_timer(priv->map, i, t);
+
+ /* Set the threshold value */
+ axg_spdifin_write_threshold(priv->map, i, t + t_next);
+
+ /* Save the current timer for the next threshold calculation */
+ t_next = t;
+
+ } while (i > 0);
+
+ return 0;
+}
+
+static int axg_spdifin_dai_probe(struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = clk_prepare_enable(priv->pclk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable pclk\n");
+ return ret;
+ }
+
+ ret = axg_spdifin_sample_mode_config(dai, priv);
+ if (ret) {
+ dev_err(dai->dev, "mode configuration failed\n");
+ clk_disable_unprepare(priv->pclk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)
+{
+ struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(priv->pclk);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops axg_spdifin_ops = {
+ .prepare = axg_spdifin_prepare,
+ .startup = axg_spdifin_startup,
+ .shutdown = axg_spdifin_shutdown,
+};
+
+static int axg_spdifin_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 axg_spdifin_get_status_mask(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+
+ for (i = 0; i < 24; i++)
+ ucontrol->value.iec958.status[i] = 0xff;
+
+ return 0;
+}
+
+static int axg_spdifin_get_status(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+ struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);
+ int i, j;
+
+ for (i = 0; i < 6; i++) {
+ unsigned int val;
+
+ regmap_update_bits(priv->map, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_STATUS_SEL,
+ FIELD_PREP(SPDIFIN_CTRL0_STATUS_SEL, i));
+
+ regmap_read(priv->map, SPDIFIN_STAT1, &val);
+
+ for (j = 0; j < 4; j++) {
+ unsigned int offset = i * 4 + j;
+
+ ucontrol->value.iec958.status[offset] =
+ (val >> (j * 8)) & 0xff;
+ }
+ }
+
+ return 0;
+}
+
+#define AXG_SPDIFIN_IEC958_MASK \
+ { \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ, \
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), \
+ .info = axg_spdifin_iec958_info, \
+ .get = axg_spdifin_get_status_mask, \
+ }
+
+#define AXG_SPDIFIN_IEC958_STATUS \
+ { \
+ .access = (SNDRV_CTL_ELEM_ACCESS_READ | \
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE), \
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE), \
+ .info = axg_spdifin_iec958_info, \
+ .get = axg_spdifin_get_status, \
+ }
+
+static const char * const spdifin_chsts_src_texts[] = {
+ "A", "B",
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_spdifin_chsts_src_enum, SPDIFIN_CTRL0,
+ SPDIFIN_CTRL0_STATUS_CH_SHIFT,
+ spdifin_chsts_src_texts);
+
+static int axg_spdifin_rate_lock_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 192000;
+
+ return 0;
+}
+
+static int axg_spdifin_rate_lock_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+ struct axg_spdifin *priv = snd_soc_component_get_drvdata(c);
+
+ ucontrol->value.integer.value[0] = axg_spdifin_get_rate(priv);
+
+ return 0;
+}
+
+#define AXG_SPDIFIN_LOCK_RATE(xname) \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .access = (SNDRV_CTL_ELEM_ACCESS_READ | \
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE), \
+ .get = axg_spdifin_rate_lock_get, \
+ .info = axg_spdifin_rate_lock_info, \
+ .name = xname, \
+ }
+
+static const struct snd_kcontrol_new axg_spdifin_controls[] = {
+ AXG_SPDIFIN_LOCK_RATE("Capture Rate Lock"),
+ SOC_DOUBLE("Capture Switch", SPDIFIN_CTRL0, 7, 6, 1, 1),
+ SOC_ENUM(SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Src",
+ axg_spdifin_chsts_src_enum),
+ AXG_SPDIFIN_IEC958_MASK,
+ AXG_SPDIFIN_IEC958_STATUS,
+};
+
+static const struct snd_soc_component_driver axg_spdifin_component_drv = {
+ .controls = axg_spdifin_controls,
+ .num_controls = ARRAY_SIZE(axg_spdifin_controls),
+};
+
+static const struct regmap_config axg_spdifin_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SPDIFIN_MUTE_VAL,
+};
+
+static const unsigned int axg_spdifin_mode_rates[SPDIFIN_MODE_NUM] = {
+ 32000, 44100, 48000, 88200, 96000, 176400, 192000,
+};
+
+static const struct axg_spdifin_cfg axg_cfg = {
+ .mode_rates = axg_spdifin_mode_rates,
+ .ref_rate = 333333333,
+};
+
+static const struct of_device_id axg_spdifin_of_match[] = {
+ {
+ .compatible = "amlogic,axg-spdifin",
+ .data = &axg_cfg,
+ }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_spdifin_of_match);
+
+static struct snd_soc_dai_driver *
+axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv)
+{
+ struct snd_soc_dai_driver *drv;
+ int i;
+
+ drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return ERR_PTR(-ENOMEM);
+
+ drv->name = "SPDIF Input";
+ drv->ops = &axg_spdifin_ops;
+ drv->probe = axg_spdifin_dai_probe;
+ drv->remove = axg_spdifin_dai_remove;
+ drv->capture.stream_name = "Capture";
+ drv->capture.channels_min = 1;
+ drv->capture.channels_max = 2;
+ drv->capture.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+
+ for (i = 0; i < SPDIFIN_MODE_NUM; i++) {
+ unsigned int rb =
+ snd_pcm_rate_to_rate_bit(priv->conf->mode_rates[i]);
+
+ if (rb == SNDRV_PCM_RATE_KNOT)
+ return ERR_PTR(-EINVAL);
+
+ drv->capture.rates |= rb;
+ }
+
+ return drv;
+}
+
+static int axg_spdifin_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct axg_spdifin *priv;
+ struct snd_soc_dai_driver *dai_drv;
+ struct resource *res;
+ void __iomem *regs;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
+
+ priv->conf = of_device_get_match_data(dev);
+ if (!priv->conf) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifin_regmap_cfg);
+ if (IS_ERR(priv->map)) {
+ dev_err(dev, "failed to init regmap: %ld\n",
+ PTR_ERR(priv->map));
+ return PTR_ERR(priv->map);
+ }
+
+ priv->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(priv->pclk)) {
+ ret = PTR_ERR(priv->pclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get pclk: %d\n", ret);
+ return ret;
+ }
+
+ priv->refclk = devm_clk_get(dev, "refclk");
+ if (IS_ERR(priv->refclk)) {
+ ret = PTR_ERR(priv->refclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get mclk: %d\n", ret);
+ return ret;
+ }
+
+ dai_drv = axg_spdifin_get_dai_drv(dev, priv);
+ if (IS_ERR(dai_drv)) {
+ dev_err(dev, "failed to get dai driver: %ld\n",
+ PTR_ERR(dai_drv));
+ return PTR_ERR(dai_drv);
+ }
+
+ return devm_snd_soc_register_component(dev, &axg_spdifin_component_drv,
+ dai_drv, 1);
+}
+
+static struct platform_driver axg_spdifin_pdrv = {
+ .probe = axg_spdifin_probe,
+ .driver = {
+ .name = "axg-spdifin",
+ .of_match_table = axg_spdifin_of_match,
+ },
+};
+module_platform_driver(axg_spdifin_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG SPDIF Input driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c
index c2c9bb312586..0e9ca3882ae5 100644
--- a/sound/soc/meson/axg-toddr.c
+++ b/sound/soc/meson/axg-toddr.c
@@ -25,6 +25,8 @@
#define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3)
#define CTRL0_TODDR_LSB_POS(x) ((x) << 3)
+#define TODDR_MSB_POS 31
+
static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *dai)
{
@@ -36,14 +38,7 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
- unsigned int type, width, msb = 31;
-
- /*
- * NOTE:
- * Almost all backend will place the MSB at bit 31, except SPDIF Input
- * which will put it at index 28. When adding support for the SPDIF
- * Input, we'll need to find which type of backend we are connected to.
- */
+ unsigned int type, width;
switch (params_physical_width(params)) {
case 8:
@@ -66,8 +61,8 @@ static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
CTRL0_TODDR_MSB_POS_MASK |
CTRL0_TODDR_LSB_POS_MASK,
CTRL0_TODDR_TYPE(type) |
- CTRL0_TODDR_MSB_POS(msb) |
- CTRL0_TODDR_LSB_POS(msb - (width - 1)));
+ CTRL0_TODDR_MSB_POS(TODDR_MSB_POS) |
+ CTRL0_TODDR_LSB_POS(TODDR_MSB_POS - (width - 1)));
return 0;
}
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
deleted file mode 100644
index 6dccea6fdaeb..000000000000
--- a/sound/soc/omap/Kconfig
+++ /dev/null
@@ -1,129 +0,0 @@
-config SND_OMAP_SOC
- tristate "SoC Audio for Texas Instruments OMAP chips (deprecated)"
- depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST)
- select SND_SDMA_SOC
-
-config SND_SDMA_SOC
- tristate "SoC Audio for Texas Instruments chips using sDMA"
- depends on DMA_OMAP || COMPILE_TEST
- select SND_SOC_GENERIC_DMAENGINE_PCM
-
-config SND_OMAP_SOC_DMIC
- tristate
-
-config SND_OMAP_SOC_MCBSP
- tristate
-
-config SND_OMAP_SOC_MCPDM
- tristate
-
-config SND_OMAP_SOC_HDMI_AUDIO
- tristate "HDMI audio support for OMAP4+ based SoCs"
- depends on SND_SDMA_SOC
- help
- For HDMI audio to work OMAPDSS HDMI support should be
- enabled.
- The hdmi audio driver implements cpu-dai component using the
- callbacks provided by OMAPDSS and registers the component
- under DSS HDMI device. Omap-pcm is registered for platform
- component also under DSS HDMI device. Dummy codec is used as
- as codec component. The hdmi audio driver implements also
- the card and registers it under its own platform device.
- The device for the driver is registered by OMAPDSS hdmi
- driver.
-
-config SND_OMAP_SOC_N810
- tristate "SoC Audio support for Nokia N810"
- depends on SND_SDMA_SOC && MACH_NOKIA_N810 && I2C
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC3X
- help
- Say Y if you want to add support for SoC audio on Nokia N810.
-
-config SND_OMAP_SOC_RX51
- tristate "SoC Audio support for Nokia N900 (RX-51)"
- depends on SND_SDMA_SOC && ARM && I2C
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC3X
- select SND_SOC_TPA6130A2
- depends on GPIOLIB
- help
- Say Y if you want to add support for SoC audio on Nokia N900
- cellphone.
-
-config SND_OMAP_SOC_AMS_DELTA
- tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
- depends on SND_SDMA_SOC && MACH_AMS_DELTA && TTY
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_CX20442
- help
- Say Y if you want to add support for SoC audio device connected to
- a handset and a speakerphone found on Amstrad E3 (Delta) videophone.
-
- Note that in order to get those devices fully supported, you have to
- build the kernel with standard serial port driver included and
- configured for at least 4 ports. Then, from userspace, you must load
- a line discipline #19 on the modem (ttyS3) serial line. The simplest
- way to achieve this is to install util-linux-ng and use the included
- ldattach utility. This can be started automatically from udev,
- a simple rule like this one should do the trick (it does for me):
- ACTION=="add", KERNEL=="controlC0", \
- RUN+="/usr/sbin/ldattach 19 /dev/ttyS3"
-
-config SND_OMAP_SOC_OSK5912
- tristate "SoC Audio support for omap osk5912"
- depends on SND_SDMA_SOC && MACH_OMAP_OSK && I2C
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC23_I2C
- help
- Say Y if you want to add support for SoC audio on osk5912.
-
-config SND_OMAP_SOC_AM3517EVM
- tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
- depends on SND_SDMA_SOC && MACH_OMAP3517EVM && I2C
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC23_I2C
- help
- Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
- EVM.
-
-config SND_OMAP_SOC_OMAP_TWL4030
- tristate "SoC Audio support for TI SoC based boards with twl4030 codec"
- depends on TWL4030_CORE && SND_SDMA_SOC
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for SoC audio on TI SoC based boards
- using twl4030 as c codec. This driver currently supports:
- - Beagleboard or Devkit8000
- - Gumstix Overo or CompuLab CM-T35/CM-T3730
- - IGEP v2
- - OMAP3EVM
- - SDP3430
- - Zoom2
-
-config SND_OMAP_SOC_OMAP_ABE_TWL6040
- tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
- depends on TWL6040_CORE && SND_SDMA_SOC && COMMON_CLK
- depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
- select SND_OMAP_SOC_DMIC
- select SND_OMAP_SOC_MCPDM
- select SND_SOC_TWL6040
- select SND_SOC_DMIC
- select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS)
- select CLK_TWL6040
- help
- Say Y if you want to add support for SoC audio on OMAP boards using
- ABE and twl6040 codec. This driver currently supports:
- - SDP4430/Blaze boards
- - PandaBoard (4430)
- - PandaBoardES (4460)
- - omap5-uevm (5432)
-
-config SND_OMAP_SOC_OMAP3_PANDORA
- tristate "SoC Audio support for OMAP3 Pandora"
- depends on TWL4030_CORE && SND_SDMA_SOC && MACH_OMAP3_PANDORA
- select SND_OMAP_SOC_MCBSP
- select SND_SOC_TWL4030
- help
- Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
deleted file mode 100644
index 53eba3413485..000000000000
--- a/sound/soc/omap/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# OMAP Platform Support
-snd-soc-sdma-objs := sdma-pcm.o
-snd-soc-omap-dmic-objs := omap-dmic.o
-snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
-snd-soc-omap-mcpdm-objs := omap-mcpdm.o
-snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
-
-obj-$(CONFIG_SND_SDMA_SOC) += snd-soc-sdma.o
-obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
-obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
-obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
-obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o
-
-# OMAP Machine Support
-snd-soc-n810-objs := n810.o
-snd-soc-rx51-objs := rx51.o
-snd-soc-ams-delta-objs := ams-delta.o
-snd-soc-osk5912-objs := osk5912.o
-snd-soc-am3517evm-objs := am3517evm.o
-snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
-snd-soc-omap-twl4030-objs := omap-twl4030.o
-snd-soc-omap3pandora-objs := omap3pandora.o
-
-obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
-obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
-obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
-obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
-obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
deleted file mode 100644
index d5651026ec10..000000000000
--- a/sound/soc/omap/am3517evm.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * am3517evm.c -- ALSA SoC support for OMAP3517 / AM3517 EVM
- *
- * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
- *
- * Based on sound/soc/omap/beagle.c by Steve Sakoman
- *
- * Copyright (C) 2009 Texas Instruments Incorporated
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
- * whether express or implied; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-
-#include "../codecs/tlv320aic23.h"
-
-#define CODEC_CLOCK 12000000
-
-static int am3517evm_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 = rtd->codec_dai;
- int ret;
-
- /* Set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0,
- CODEC_CLOCK, SND_SOC_CLOCK_IN);
- if (ret < 0)
- printk(KERN_ERR "can't set codec system clock\n");
-
- return ret;
-}
-
-static const struct snd_soc_ops am3517evm_ops = {
- .hw_params = am3517evm_hw_params,
-};
-
-/* am3517evm machine dapm widgets */
-static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
- SND_SOC_DAPM_HP("Line Out", NULL),
- SND_SOC_DAPM_LINE("Line In", NULL),
- SND_SOC_DAPM_MIC("Mic In", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- /* Line Out connected to LLOUT, RLOUT */
- {"Line Out", NULL, "LOUT"},
- {"Line Out", NULL, "ROUT"},
-
- {"LLINEIN", NULL, "Line In"},
- {"RLINEIN", NULL, "Line In"},
-
- {"MICIN", NULL, "Mic In"},
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link am3517evm_dai = {
- .name = "TLV320AIC23",
- .stream_name = "AIC23",
- .cpu_dai_name = "omap-mcbsp.1",
- .codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "omap-mcbsp.1",
- .codec_name = "tlv320aic23-codec.2-001a",
- .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .ops = &am3517evm_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_am3517evm = {
- .name = "am3517evm",
- .owner = THIS_MODULE,
- .dai_link = &am3517evm_dai,
- .num_links = 1,
-
- .dapm_widgets = tlv320aic23_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *am3517evm_snd_device;
-
-static int __init am3517evm_soc_init(void)
-{
- int ret;
-
- if (!machine_is_omap3517evm())
- return -ENODEV;
- pr_info("OMAP3517 / AM3517 EVM SoC init\n");
-
- am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
- if (!am3517evm_snd_device) {
- printk(KERN_ERR "Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm);
-
- ret = platform_device_add(am3517evm_snd_device);
- if (ret)
- goto err1;
-
- return 0;
-
-err1:
- printk(KERN_ERR "Unable to add platform device\n");
- platform_device_put(am3517evm_snd_device);
-
- return ret;
-}
-
-static void __exit am3517evm_soc_exit(void)
-{
- platform_device_unregister(am3517evm_snd_device);
-}
-
-module_init(am3517evm_soc_init);
-module_exit(am3517evm_soc_exit);
-
-MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
deleted file mode 100644
index 79d4dc785e5c..000000000000
--- a/sound/soc/omap/mcbsp.c
+++ /dev/null
@@ -1,1104 +0,0 @@
-/*
- * sound/soc/omap/mcbsp.c
- *
- * Copyright (C) 2004 Nokia Corporation
- * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- * Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Multichannel mode not supported.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "mcbsp.h"
-
-static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
- void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
- if (mcbsp->pdata->reg_size == 2) {
- ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
- writew_relaxed((u16)val, addr);
- } else {
- ((u32 *)mcbsp->reg_cache)[reg] = val;
- writel_relaxed(val, addr);
- }
-}
-
-static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
-{
- void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
-
- if (mcbsp->pdata->reg_size == 2) {
- return !from_cache ? readw_relaxed(addr) :
- ((u16 *)mcbsp->reg_cache)[reg];
- } else {
- return !from_cache ? readl_relaxed(addr) :
- ((u32 *)mcbsp->reg_cache)[reg];
- }
-}
-
-static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
-{
- writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
-}
-
-static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
-{
- return readl_relaxed(mcbsp->st_data->io_base_st + reg);
-}
-
-#define MCBSP_READ(mcbsp, reg) \
- omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
-#define MCBSP_WRITE(mcbsp, reg, val) \
- omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
-#define MCBSP_READ_CACHE(mcbsp, reg) \
- omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
-
-#define MCBSP_ST_READ(mcbsp, reg) \
- omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
-#define MCBSP_ST_WRITE(mcbsp, reg, val) \
- omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
-
-static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
-{
- dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
- dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n",
- MCBSP_READ(mcbsp, DRR2));
- dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n",
- MCBSP_READ(mcbsp, DRR1));
- dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n",
- MCBSP_READ(mcbsp, DXR2));
- dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n",
- MCBSP_READ(mcbsp, DXR1));
- dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, SPCR2));
- dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, SPCR1));
- dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, RCR2));
- dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, RCR1));
- dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n",
- MCBSP_READ(mcbsp, XCR2));
- dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n",
- MCBSP_READ(mcbsp, XCR1));
- dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
- MCBSP_READ(mcbsp, SRGR2));
- dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
- MCBSP_READ(mcbsp, SRGR1));
- dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n",
- MCBSP_READ(mcbsp, PCR0));
- dev_dbg(mcbsp->dev, "***********************\n");
-}
-
-static irqreturn_t omap_mcbsp_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcbsp *mcbsp = dev_id;
- u16 irqst;
-
- irqst = MCBSP_READ(mcbsp, IRQST);
- dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
-
- if (irqst & RSYNCERREN)
- dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
- if (irqst & RFSREN)
- dev_dbg(mcbsp->dev, "RX Frame Sync\n");
- if (irqst & REOFEN)
- dev_dbg(mcbsp->dev, "RX End Of Frame\n");
- if (irqst & RRDYEN)
- dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
- if (irqst & RUNDFLEN)
- dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
- if (irqst & ROVFLEN)
- dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
-
- if (irqst & XSYNCERREN)
- dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
- if (irqst & XFSXEN)
- dev_dbg(mcbsp->dev, "TX Frame Sync\n");
- if (irqst & XEOFEN)
- dev_dbg(mcbsp->dev, "TX End Of Frame\n");
- if (irqst & XRDYEN)
- dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
- if (irqst & XUNDFLEN)
- dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
- if (irqst & XOVFLEN)
- dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
- if (irqst & XEMPTYEOFEN)
- dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
-
- MCBSP_WRITE(mcbsp, IRQST, irqst);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcbsp *mcbsp_tx = dev_id;
- u16 irqst_spcr2;
-
- irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2);
- dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
-
- if (irqst_spcr2 & XSYNC_ERR) {
- dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
- irqst_spcr2);
- /* Writing zero to XSYNC_ERR clears the IRQ */
- MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2));
- }
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcbsp *mcbsp_rx = dev_id;
- u16 irqst_spcr1;
-
- irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1);
- dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
-
- if (irqst_spcr1 & RSYNC_ERR) {
- dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
- irqst_spcr1);
- /* Writing zero to RSYNC_ERR clears the IRQ */
- MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1));
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * omap_mcbsp_config simply write a config to the
- * appropriate McBSP.
- * You either call this function or set the McBSP registers
- * by yourself before calling omap_mcbsp_start().
- */
-void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
- const struct omap_mcbsp_reg_cfg *config)
-{
- dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
- mcbsp->id, mcbsp->phys_base);
-
- /* We write the given config */
- MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
- MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
- MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
- MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
- MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
- MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
- MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
- MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
- MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
- MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
- MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
- if (mcbsp->pdata->has_ccr) {
- MCBSP_WRITE(mcbsp, XCCR, config->xccr);
- MCBSP_WRITE(mcbsp, RCCR, config->rccr);
- }
- /* Enable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
-
- /* Enable TX/RX sync error interrupts by default */
- if (mcbsp->irq)
- MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
- RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
-}
-
-/**
- * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
- * @id - mcbsp id
- * @stream - indicates the direction of data flow (rx or tx)
- *
- * Returns the address of mcbsp data transmit register or data receive register
- * to be used by DMA for transferring/receiving data based on the value of
- * @stream for the requested mcbsp given by @id
- */
-static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
- unsigned int stream)
-{
- int data_reg;
-
- if (mcbsp->pdata->reg_size == 2) {
- if (stream)
- data_reg = OMAP_MCBSP_REG_DRR1;
- else
- data_reg = OMAP_MCBSP_REG_DXR1;
- } else {
- if (stream)
- data_reg = OMAP_MCBSP_REG_DRR;
- else
- data_reg = OMAP_MCBSP_REG_DXR;
- }
-
- return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
-}
-
-static void omap_st_on(struct omap_mcbsp *mcbsp)
-{
- unsigned int w;
-
- if (mcbsp->pdata->force_ick_on)
- mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
-
- /* Disable Sidetone clock auto-gating for normal operation */
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
-
- /* Enable McBSP Sidetone */
- w = MCBSP_READ(mcbsp, SSELCR);
- MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
-
- /* Enable Sidetone from Sidetone Core */
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
-}
-
-static void omap_st_off(struct omap_mcbsp *mcbsp)
-{
- unsigned int w;
-
- w = MCBSP_ST_READ(mcbsp, SSELCR);
- MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
-
- w = MCBSP_READ(mcbsp, SSELCR);
- MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
-
- /* Enable Sidetone clock auto-gating to reduce power consumption */
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
-
- if (mcbsp->pdata->force_ick_on)
- mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
-}
-
-static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
-{
- u16 val, i;
-
- val = MCBSP_ST_READ(mcbsp, SSELCR);
-
- if (val & ST_COEFFWREN)
- MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
- MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
-
- for (i = 0; i < 128; i++)
- MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
-
- i = 0;
-
- val = MCBSP_ST_READ(mcbsp, SSELCR);
- while (!(val & ST_COEFFWRDONE) && (++i < 1000))
- val = MCBSP_ST_READ(mcbsp, SSELCR);
-
- MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
-
- if (i == 1000)
- dev_err(mcbsp->dev, "McBSP FIR load error!\n");
-}
-
-static void omap_st_chgain(struct omap_mcbsp *mcbsp)
-{
- u16 w;
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- w = MCBSP_ST_READ(mcbsp, SSELCR);
-
- MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \
- ST_CH1GAIN(st_data->ch1gain));
-}
-
-int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENOENT;
-
- spin_lock_irq(&mcbsp->lock);
- if (channel == 0)
- st_data->ch0gain = chgain;
- else if (channel == 1)
- st_data->ch1gain = chgain;
- else
- ret = -EINVAL;
-
- if (st_data->enabled)
- omap_st_chgain(mcbsp);
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENOENT;
-
- spin_lock_irq(&mcbsp->lock);
- if (channel == 0)
- *chgain = st_data->ch0gain;
- else if (channel == 1)
- *chgain = st_data->ch1gain;
- else
- ret = -EINVAL;
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-static int omap_st_start(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (st_data->enabled && !st_data->running) {
- omap_st_fir_write(mcbsp, st_data->taps);
- omap_st_chgain(mcbsp);
-
- if (!mcbsp->free) {
- omap_st_on(mcbsp);
- st_data->running = 1;
- }
- }
-
- return 0;
-}
-
-int omap_st_enable(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (!st_data)
- return -ENODEV;
-
- spin_lock_irq(&mcbsp->lock);
- st_data->enabled = 1;
- omap_st_start(mcbsp);
- spin_unlock_irq(&mcbsp->lock);
-
- return 0;
-}
-
-static int omap_st_stop(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (st_data->running) {
- if (!mcbsp->free) {
- omap_st_off(mcbsp);
- st_data->running = 0;
- }
- }
-
- return 0;
-}
-
-int omap_st_disable(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int ret = 0;
-
- if (!st_data)
- return -ENODEV;
-
- spin_lock_irq(&mcbsp->lock);
- omap_st_stop(mcbsp);
- st_data->enabled = 0;
- spin_unlock_irq(&mcbsp->lock);
-
- return ret;
-}
-
-int omap_st_is_enabled(struct omap_mcbsp *mcbsp)
-{
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
-
- if (!st_data)
- return -ENODEV;
-
- return st_data->enabled;
-}
-
-/*
- * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH2 register.
- */
-void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
-{
- if (mcbsp->pdata->buffer_size == 0)
- return;
-
- if (threshold && threshold <= mcbsp->max_tx_thres)
- MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
-}
-
-/*
- * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
- * The threshold parameter is 1 based, and it is converted (threshold - 1)
- * for the THRSH1 register.
- */
-void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
-{
- if (mcbsp->pdata->buffer_size == 0)
- return;
-
- if (threshold && threshold <= mcbsp->max_rx_thres)
- MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
-}
-
-/*
- * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
- */
-u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
-{
- u16 buffstat;
-
- if (mcbsp->pdata->buffer_size == 0)
- return 0;
-
- /* Returns the number of free locations in the buffer */
- buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
-
- /* Number of slots are different in McBSP ports */
- return mcbsp->pdata->buffer_size - buffstat;
-}
-
-/*
- * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
- * to reach the threshold value (when the DMA will be triggered to read it)
- */
-u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
-{
- u16 buffstat, threshold;
-
- if (mcbsp->pdata->buffer_size == 0)
- return 0;
-
- /* Returns the number of used locations in the buffer */
- buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
- /* RX threshold */
- threshold = MCBSP_READ(mcbsp, THRSH1);
-
- /* Return the number of location till we reach the threshold limit */
- if (threshold <= buffstat)
- return 0;
- else
- return threshold - buffstat;
-}
-
-int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
-{
- void *reg_cache;
- int err;
-
- reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
- if (!reg_cache) {
- return -ENOMEM;
- }
-
- spin_lock(&mcbsp->lock);
- if (!mcbsp->free) {
- dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
- mcbsp->id);
- err = -EBUSY;
- goto err_kfree;
- }
-
- mcbsp->free = false;
- mcbsp->reg_cache = reg_cache;
- spin_unlock(&mcbsp->lock);
-
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
- mcbsp->pdata->ops->request(mcbsp->id - 1);
-
- /*
- * Make sure that transmitter, receiver and sample-rate generator are
- * not running before activating IRQs.
- */
- MCBSP_WRITE(mcbsp, SPCR1, 0);
- MCBSP_WRITE(mcbsp, SPCR2, 0);
-
- if (mcbsp->irq) {
- err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
- "McBSP", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request IRQ\n");
- goto err_clk_disable;
- }
- } else {
- err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
- "McBSP TX", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
- goto err_clk_disable;
- }
-
- err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
- "McBSP RX", (void *)mcbsp);
- if (err != 0) {
- dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
- goto err_free_irq;
- }
- }
-
- return 0;
-err_free_irq:
- free_irq(mcbsp->tx_irq, (void *)mcbsp);
-err_clk_disable:
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
- mcbsp->pdata->ops->free(mcbsp->id - 1);
-
- /* Disable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
- spin_lock(&mcbsp->lock);
- mcbsp->free = true;
- mcbsp->reg_cache = NULL;
-err_kfree:
- spin_unlock(&mcbsp->lock);
- kfree(reg_cache);
-
- return err;
-}
-
-void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
-{
- void *reg_cache;
-
- if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
- mcbsp->pdata->ops->free(mcbsp->id - 1);
-
- /* Disable wakeup behavior */
- if (mcbsp->pdata->has_wakeup)
- MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
-
- /* Disable interrupt requests */
- if (mcbsp->irq)
- MCBSP_WRITE(mcbsp, IRQEN, 0);
-
- if (mcbsp->irq) {
- free_irq(mcbsp->irq, (void *)mcbsp);
- } else {
- free_irq(mcbsp->rx_irq, (void *)mcbsp);
- free_irq(mcbsp->tx_irq, (void *)mcbsp);
- }
-
- reg_cache = mcbsp->reg_cache;
-
- /*
- * Select CLKS source from internal source unconditionally before
- * marking the McBSP port as free.
- * If the external clock source via MCBSP_CLKS pin has been selected the
- * system will refuse to enter idle if the CLKS pin source is not reset
- * back to internal source.
- */
- if (!mcbsp_omap1())
- omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
-
- spin_lock(&mcbsp->lock);
- if (mcbsp->free)
- dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
- else
- mcbsp->free = true;
- mcbsp->reg_cache = NULL;
- spin_unlock(&mcbsp->lock);
-
- kfree(reg_cache);
-}
-
-/*
- * Here we start the McBSP, by enabling transmitter, receiver or both.
- * If no transmitter or receiver is active prior calling, then sample-rate
- * generator and frame sync are started.
- */
-void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx)
-{
- int enable_srg = 0;
- u16 w;
-
- if (mcbsp->st_data)
- omap_st_start(mcbsp);
-
- /* Only enable SRG, if McBSP is master */
- w = MCBSP_READ_CACHE(mcbsp, PCR0);
- if (w & (FSXM | FSRM | CLKXM | CLKRM))
- enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
- MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
- if (enable_srg) {
- /* Start the sample generator */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
- }
-
- /* Enable transmitter and receiver */
- tx &= 1;
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | tx);
-
- rx &= 1;
- w = MCBSP_READ_CACHE(mcbsp, SPCR1);
- MCBSP_WRITE(mcbsp, SPCR1, w | rx);
-
- /*
- * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
- * REVISIT: 100us may give enough time for two CLKSRG, however
- * due to some unknown PM related, clock gating etc. reason it
- * is now at 500us.
- */
- udelay(500);
-
- if (enable_srg) {
- /* Start frame sync */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
- }
-
- if (mcbsp->pdata->has_ccr) {
- /* Release the transmitter and receiver */
- w = MCBSP_READ_CACHE(mcbsp, XCCR);
- w &= ~(tx ? XDISABLE : 0);
- MCBSP_WRITE(mcbsp, XCCR, w);
- w = MCBSP_READ_CACHE(mcbsp, RCCR);
- w &= ~(rx ? RDISABLE : 0);
- MCBSP_WRITE(mcbsp, RCCR, w);
- }
-
- /* Dump McBSP Regs */
- omap_mcbsp_dump_reg(mcbsp);
-}
-
-void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx)
-{
- int idle;
- u16 w;
-
- /* Reset transmitter */
- tx &= 1;
- if (mcbsp->pdata->has_ccr) {
- w = MCBSP_READ_CACHE(mcbsp, XCCR);
- w |= (tx ? XDISABLE : 0);
- MCBSP_WRITE(mcbsp, XCCR, w);
- }
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
-
- /* Reset receiver */
- rx &= 1;
- if (mcbsp->pdata->has_ccr) {
- w = MCBSP_READ_CACHE(mcbsp, RCCR);
- w |= (rx ? RDISABLE : 0);
- MCBSP_WRITE(mcbsp, RCCR, w);
- }
- w = MCBSP_READ_CACHE(mcbsp, SPCR1);
- MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
-
- idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
- MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
-
- if (idle) {
- /* Reset the sample rate generator */
- w = MCBSP_READ_CACHE(mcbsp, SPCR2);
- MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
- }
-
- if (mcbsp->st_data)
- omap_st_stop(mcbsp);
-}
-
-int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
-{
- struct clk *fck_src;
- const char *src;
- int r;
-
- if (fck_src_id == MCBSP_CLKS_PAD_SRC)
- src = "pad_fck";
- else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
- src = "prcm_fck";
- else
- return -EINVAL;
-
- fck_src = clk_get(mcbsp->dev, src);
- if (IS_ERR(fck_src)) {
- dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
- return -EINVAL;
- }
-
- pm_runtime_put_sync(mcbsp->dev);
-
- r = clk_set_parent(mcbsp->fclk, fck_src);
- if (r) {
- dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
- src);
- clk_put(fck_src);
- return r;
- }
-
- pm_runtime_get_sync(mcbsp->dev);
-
- clk_put(fck_src);
-
- return 0;
-
-}
-
-#define max_thres(m) (mcbsp->pdata->buffer_size)
-#define valid_threshold(m, val) ((val) <= max_thres(m))
-#define THRESHOLD_PROP_BUILDER(prop) \
-static ssize_t prop##_show(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
- \
- return sprintf(buf, "%u\n", mcbsp->prop); \
-} \
- \
-static ssize_t prop##_store(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t size) \
-{ \
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
- unsigned long val; \
- int status; \
- \
- status = kstrtoul(buf, 0, &val); \
- if (status) \
- return status; \
- \
- if (!valid_threshold(mcbsp, val)) \
- return -EDOM; \
- \
- mcbsp->prop = val; \
- return size; \
-} \
- \
-static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
-
-THRESHOLD_PROP_BUILDER(max_tx_thres);
-THRESHOLD_PROP_BUILDER(max_rx_thres);
-
-static const char *dma_op_modes[] = {
- "element", "threshold",
-};
-
-static ssize_t dma_op_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- int dma_op_mode, i = 0;
- ssize_t len = 0;
- const char * const *s;
-
- dma_op_mode = mcbsp->dma_op_mode;
-
- for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
- if (dma_op_mode == i)
- len += sprintf(buf + len, "[%s] ", *s);
- else
- len += sprintf(buf + len, "%s ", *s);
- }
- len += sprintf(buf + len, "\n");
-
- return len;
-}
-
-static ssize_t dma_op_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- int i;
-
- i = sysfs_match_string(dma_op_modes, buf);
- if (i < 0)
- return i;
-
- spin_lock_irq(&mcbsp->lock);
- if (!mcbsp->free) {
- size = -EBUSY;
- goto unlock;
- }
- mcbsp->dma_op_mode = i;
-
-unlock:
- spin_unlock_irq(&mcbsp->lock);
-
- return size;
-}
-
-static DEVICE_ATTR_RW(dma_op_mode);
-
-static const struct attribute *additional_attrs[] = {
- &dev_attr_max_tx_thres.attr,
- &dev_attr_max_rx_thres.attr,
- &dev_attr_dma_op_mode.attr,
- NULL,
-};
-
-static const struct attribute_group additional_attr_group = {
- .attrs = (struct attribute **)additional_attrs,
-};
-
-static ssize_t st_taps_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- ssize_t status = 0;
- int i;
-
- spin_lock_irq(&mcbsp->lock);
- for (i = 0; i < st_data->nr_taps; i++)
- status += sprintf(&buf[status], (i ? ", %d" : "%d"),
- st_data->taps[i]);
- if (i)
- status += sprintf(&buf[status], "\n");
- spin_unlock_irq(&mcbsp->lock);
-
- return status;
-}
-
-static ssize_t st_taps_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
- struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
- int val, tmp, status, i = 0;
-
- spin_lock_irq(&mcbsp->lock);
- memset(st_data->taps, 0, sizeof(st_data->taps));
- st_data->nr_taps = 0;
-
- do {
- status = sscanf(buf, "%d%n", &val, &tmp);
- if (status < 0 || status == 0) {
- size = -EINVAL;
- goto out;
- }
- if (val < -32768 || val > 32767) {
- size = -EINVAL;
- goto out;
- }
- st_data->taps[i++] = val;
- buf += tmp;
- if (*buf != ',')
- break;
- buf++;
- } while (1);
-
- st_data->nr_taps = i;
-
-out:
- spin_unlock_irq(&mcbsp->lock);
-
- return size;
-}
-
-static DEVICE_ATTR_RW(st_taps);
-
-static const struct attribute *sidetone_attrs[] = {
- &dev_attr_st_taps.attr,
- NULL,
-};
-
-static const struct attribute_group sidetone_attr_group = {
- .attrs = (struct attribute **)sidetone_attrs,
-};
-
-static int omap_st_add(struct omap_mcbsp *mcbsp, struct resource *res)
-{
- struct omap_mcbsp_st_data *st_data;
- int err;
-
- st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
- if (!st_data)
- return -ENOMEM;
-
- st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
- if (IS_ERR(st_data->mcbsp_iclk)) {
- dev_warn(mcbsp->dev,
- "Failed to get ick, sidetone might be broken\n");
- st_data->mcbsp_iclk = NULL;
- }
-
- st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
- resource_size(res));
- if (!st_data->io_base_st)
- return -ENOMEM;
-
- err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
- if (err)
- return err;
-
- mcbsp->st_data = st_data;
- return 0;
-}
-
-/*
- * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
- * 730 has only 2 McBSP, and both of them are MPU peripherals.
- */
-int omap_mcbsp_init(struct platform_device *pdev)
-{
- struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
- struct resource *res;
- int ret = 0;
-
- spin_lock_init(&mcbsp->lock);
- mcbsp->free = true;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
- if (!res)
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mcbsp->io_base))
- return PTR_ERR(mcbsp->io_base);
-
- mcbsp->phys_base = res->start;
- mcbsp->reg_cache_size = resource_size(res);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
- if (!res)
- mcbsp->phys_dma_base = mcbsp->phys_base;
- else
- mcbsp->phys_dma_base = res->start;
-
- /*
- * OMAP1, 2 uses two interrupt lines: TX, RX
- * OMAP2430, OMAP3 SoC have combined IRQ line as well.
- * OMAP4 and newer SoC only have the combined IRQ line.
- * Use the combined IRQ if available since it gives better debugging
- * possibilities.
- */
- mcbsp->irq = platform_get_irq_byname(pdev, "common");
- if (mcbsp->irq == -ENXIO) {
- mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
-
- if (mcbsp->tx_irq == -ENXIO) {
- mcbsp->irq = platform_get_irq(pdev, 0);
- mcbsp->tx_irq = 0;
- } else {
- mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
- mcbsp->irq = 0;
- }
- }
-
- if (!pdev->dev.of_node) {
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (!res) {
- dev_err(&pdev->dev, "invalid tx DMA channel\n");
- return -ENODEV;
- }
- mcbsp->dma_req[0] = res->start;
- mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (!res) {
- dev_err(&pdev->dev, "invalid rx DMA channel\n");
- return -ENODEV;
- }
- mcbsp->dma_req[1] = res->start;
- mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
- } else {
- mcbsp->dma_data[0].filter_data = "tx";
- mcbsp->dma_data[1].filter_data = "rx";
- }
-
- mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
- mcbsp->dma_data[0].maxburst = 4;
-
- mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
- mcbsp->dma_data[1].maxburst = 4;
-
- mcbsp->fclk = clk_get(&pdev->dev, "fck");
- if (IS_ERR(mcbsp->fclk)) {
- ret = PTR_ERR(mcbsp->fclk);
- dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
- return ret;
- }
-
- mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
- if (mcbsp->pdata->buffer_size) {
- /*
- * Initially configure the maximum thresholds to a safe value.
- * The McBSP FIFO usage with these values should not go under
- * 16 locations.
- * If the whole FIFO without safety buffer is used, than there
- * is a possibility that the DMA will be not able to push the
- * new data on time, causing channel shifts in runtime.
- */
- mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
- mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
-
- ret = sysfs_create_group(&mcbsp->dev->kobj,
- &additional_attr_group);
- if (ret) {
- dev_err(mcbsp->dev,
- "Unable to create additional controls\n");
- goto err_thres;
- }
- } else {
- mcbsp->max_tx_thres = -EINVAL;
- mcbsp->max_rx_thres = -EINVAL;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
- if (res) {
- ret = omap_st_add(mcbsp, res);
- if (ret) {
- dev_err(mcbsp->dev,
- "Unable to create sidetone controls\n");
- goto err_st;
- }
- }
-
- return 0;
-
-err_st:
- if (mcbsp->pdata->buffer_size)
- sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-err_thres:
- clk_put(mcbsp->fclk);
- return ret;
-}
-
-void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp)
-{
- if (mcbsp->pdata->buffer_size)
- sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-
- if (mcbsp->st_data) {
- sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
- clk_put(mcbsp->st_data->mcbsp_iclk);
- }
-}
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 943b44de1464..67159a6b90a8 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -79,7 +79,7 @@ config SND_PXA2XX_SOC_TOSA
tristate "SoC AC97 Audio support for Tosa"
depends on SND_PXA2XX_SOC && MACH_TOSA
depends on MFD_TC6393XB
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -89,7 +89,7 @@ config SND_PXA2XX_SOC_TOSA
config SND_PXA2XX_SOC_E740
tristate "SoC AC97 Audio support for e740"
depends on SND_PXA2XX_SOC && MACH_E740
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_SOC_WM9705
select SND_PXA2XX_SOC_AC97
help
@@ -99,7 +99,7 @@ config SND_PXA2XX_SOC_E740
config SND_PXA2XX_SOC_E750
tristate "SoC AC97 Audio support for e750"
depends on SND_PXA2XX_SOC && MACH_E750
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_SOC_WM9705
select SND_PXA2XX_SOC_AC97
help
@@ -109,7 +109,7 @@ config SND_PXA2XX_SOC_E750
config SND_PXA2XX_SOC_E800
tristate "SoC AC97 Audio support for e800"
depends on SND_PXA2XX_SOC && MACH_E800
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_SOC_WM9712
select SND_PXA2XX_SOC_AC97
help
@@ -120,7 +120,7 @@ config SND_PXA2XX_SOC_EM_X270
tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \
MACH_CM_X300)
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -131,7 +131,7 @@ config SND_PXA2XX_SOC_PALM27X
bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive"
depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \
MACH_PALMT5 || MACH_PALMTE2)
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
@@ -161,7 +161,7 @@ config SND_SOC_TTC_DKB
config SND_SOC_ZYLONITE
tristate "SoC Audio support for Marvell Zylonite"
depends on SND_PXA2XX_SOC && MACH_ZYLONITE
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_PXA_SOC_SSP
select SND_SOC_WM9713
@@ -169,16 +169,6 @@ config SND_SOC_ZYLONITE
Say Y if you want to add support for SoC audio on the
Marvell Zylonite reference platform.
-config SND_SOC_RAUMFELD
- tristate "SoC Audio support Raumfeld audio adapter"
- depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR)
- depends on I2C && SPI_MASTER
- select SND_PXA_SOC_SSP
- select SND_SOC_CS4270
- select SND_SOC_AK4104
- help
- Say Y if you want to add support for SoC audio on Raumfeld devices
-
config SND_PXA2XX_SOC_HX4700
tristate "SoC Audio support for HP iPAQ hx4700"
depends on SND_PXA2XX_SOC && MACH_H4700 && I2C
@@ -201,7 +191,7 @@ config SND_PXA2XX_SOC_MAGICIAN
config SND_PXA2XX_SOC_MIOA701
tristate "SoC Audio support for MIO A701"
depends on SND_PXA2XX_SOC && MACH_MIOA701
- depends on !AC97_BUS
+ depends on AC97_BUS=n
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9713
help
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 5b265662f04f..0ab2a9dcb720 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -49,6 +49,5 @@ obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
-obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
deleted file mode 100644
index 111a907c4eb9..000000000000
--- a/sound/soc/pxa/raumfeld.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * raumfeld_audio.c -- SoC audio for Raumfeld audio devices
- *
- * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
- *
- * based on code from:
- *
- * Wolfson Microelectronics PLC.
- * Openedhand Ltd.
- * Liam Girdwood <lrg@slimlogic.co.uk>
- * Richard Purdie <richard@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-
-#include "pxa-ssp.h"
-
-#define GPIO_SPDIF_RESET (38)
-#define GPIO_MCLK_RESET (111)
-#define GPIO_CODEC_RESET (120)
-
-static struct i2c_client *max9486_client;
-static struct i2c_board_info max9486_hwmon_info = {
- I2C_BOARD_INFO("max9485", 0x63),
-};
-
-#define MAX9485_MCLK_FREQ_112896 0x22
-#define MAX9485_MCLK_FREQ_122880 0x23
-#define MAX9485_MCLK_FREQ_225792 0x32
-#define MAX9485_MCLK_FREQ_245760 0x33
-
-static void set_max9485_clk(char clk)
-{
- i2c_master_send(max9486_client, &clk, 1);
-}
-
-static void raumfeld_enable_audio(bool en)
-{
- if (en) {
- gpio_set_value(GPIO_MCLK_RESET, 1);
-
- /* wait some time to let the clocks become stable */
- msleep(100);
-
- gpio_set_value(GPIO_SPDIF_RESET, 1);
- gpio_set_value(GPIO_CODEC_RESET, 1);
- } else {
- gpio_set_value(GPIO_MCLK_RESET, 0);
- gpio_set_value(GPIO_SPDIF_RESET, 0);
- gpio_set_value(GPIO_CODEC_RESET, 0);
- }
-}
-
-/* CS4270 */
-static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- /* set freq to 0 to enable all possible codec sample rates */
- return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
-}
-
-static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- /* set freq to 0 to enable all possible codec sample rates */
- snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
-}
-
-static int raumfeld_cs4270_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 = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int clk = 0;
- int ret = 0;
-
- switch (params_rate(params)) {
- case 44100:
- set_max9485_clk(MAX9485_MCLK_FREQ_112896);
- clk = 11289600;
- break;
- case 48000:
- set_max9485_clk(MAX9485_MCLK_FREQ_122880);
- clk = 12288000;
- break;
- case 88200:
- set_max9485_clk(MAX9485_MCLK_FREQ_225792);
- clk = 22579200;
- break;
- case 96000:
- set_max9485_clk(MAX9485_MCLK_FREQ_245760);
- clk = 24576000;
- break;
- default:
- return -EINVAL;
- }
-
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
- if (ret < 0)
- return ret;
-
- /* setup the CPU DAI */
- ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static const struct snd_soc_ops raumfeld_cs4270_ops = {
- .startup = raumfeld_cs4270_startup,
- .shutdown = raumfeld_cs4270_shutdown,
- .hw_params = raumfeld_cs4270_hw_params,
-};
-
-static int raumfeld_analog_suspend(struct snd_soc_card *card)
-{
- raumfeld_enable_audio(false);
- return 0;
-}
-
-static int raumfeld_analog_resume(struct snd_soc_card *card)
-{
- raumfeld_enable_audio(true);
- return 0;
-}
-
-/* AK4104 */
-
-static int raumfeld_ak4104_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 *cpu_dai = rtd->cpu_dai;
- int ret = 0, clk = 0;
-
- switch (params_rate(params)) {
- case 44100:
- set_max9485_clk(MAX9485_MCLK_FREQ_112896);
- clk = 11289600;
- break;
- case 48000:
- set_max9485_clk(MAX9485_MCLK_FREQ_122880);
- clk = 12288000;
- break;
- case 88200:
- set_max9485_clk(MAX9485_MCLK_FREQ_225792);
- clk = 22579200;
- break;
- case 96000:
- set_max9485_clk(MAX9485_MCLK_FREQ_245760);
- clk = 24576000;
- break;
- default:
- return -EINVAL;
- }
-
- /* setup the CPU DAI */
- ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops raumfeld_ak4104_ops = {
- .hw_params = raumfeld_ak4104_hw_params,
-};
-
-#define DAI_LINK_CS4270 \
-{ \
- .name = "CS4270", \
- .stream_name = "CS4270", \
- .cpu_dai_name = "pxa-ssp-dai.0", \
- .platform_name = "pxa-pcm-audio", \
- .codec_dai_name = "cs4270-hifi", \
- .codec_name = "cs4270.0-0048", \
- .dai_fmt = SND_SOC_DAIFMT_I2S | \
- SND_SOC_DAIFMT_NB_NF | \
- SND_SOC_DAIFMT_CBS_CFS, \
- .ops = &raumfeld_cs4270_ops, \
-}
-
-#define DAI_LINK_AK4104 \
-{ \
- .name = "ak4104", \
- .stream_name = "Playback", \
- .cpu_dai_name = "pxa-ssp-dai.1", \
- .codec_dai_name = "ak4104-hifi", \
- .platform_name = "pxa-pcm-audio", \
- .dai_fmt = SND_SOC_DAIFMT_I2S | \
- SND_SOC_DAIFMT_NB_NF | \
- SND_SOC_DAIFMT_CBS_CFS, \
- .ops = &raumfeld_ak4104_ops, \
- .codec_name = "spi0.0", \
-}
-
-static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] = {
- DAI_LINK_CS4270,
- DAI_LINK_AK4104,
-};
-
-static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] = {
- DAI_LINK_CS4270,
-};
-
-static struct snd_soc_card snd_soc_raumfeld_connector = {
- .name = "Raumfeld Connector",
- .owner = THIS_MODULE,
- .dai_link = snd_soc_raumfeld_connector_dai,
- .num_links = ARRAY_SIZE(snd_soc_raumfeld_connector_dai),
- .suspend_post = raumfeld_analog_suspend,
- .resume_pre = raumfeld_analog_resume,
-};
-
-static struct snd_soc_card snd_soc_raumfeld_speaker = {
- .name = "Raumfeld Speaker",
- .owner = THIS_MODULE,
- .dai_link = snd_soc_raumfeld_speaker_dai,
- .num_links = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai),
- .suspend_post = raumfeld_analog_suspend,
- .resume_pre = raumfeld_analog_resume,
-};
-
-static struct platform_device *raumfeld_audio_device;
-
-static int __init raumfeld_audio_init(void)
-{
- int ret;
-
- if (!machine_is_raumfeld_speaker() &&
- !machine_is_raumfeld_connector())
- return 0;
-
- max9486_client = i2c_new_device(i2c_get_adapter(0),
- &max9486_hwmon_info);
-
- if (!max9486_client)
- return -ENOMEM;
-
- set_max9485_clk(MAX9485_MCLK_FREQ_122880);
-
- /* Register analog device */
- raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
- if (!raumfeld_audio_device)
- return -ENOMEM;
-
- if (machine_is_raumfeld_speaker())
- platform_set_drvdata(raumfeld_audio_device,
- &snd_soc_raumfeld_speaker);
-
- if (machine_is_raumfeld_connector())
- platform_set_drvdata(raumfeld_audio_device,
- &snd_soc_raumfeld_connector);
-
- ret = platform_device_add(raumfeld_audio_device);
- if (ret < 0) {
- platform_device_put(raumfeld_audio_device);
- return ret;
- }
-
- raumfeld_enable_audio(true);
- return 0;
-}
-
-static void __exit raumfeld_audio_exit(void)
-{
- raumfeld_enable_audio(false);
-
- platform_device_unregister(raumfeld_audio_device);
-
- i2c_unregister_device(max9486_client);
-
- gpio_free(GPIO_MCLK_RESET);
- gpio_free(GPIO_CODEC_RESET);
- gpio_free(GPIO_SPDIF_RESET);
-}
-
-module_init(raumfeld_audio_init);
-module_exit(raumfeld_audio_exit);
-
-/* Module information */
-MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("Raumfeld audio SoC");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 2a4c912d1e48..804ae0d93058 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -66,6 +66,7 @@ config SND_SOC_QDSP6_ASM
tristate
config SND_SOC_QDSP6_ASM_DAI
+ select SND_SOC_COMPRESS
tristate
config SND_SOC_QDSP6
@@ -100,6 +101,7 @@ config SND_SOC_SDM845
depends on QCOM_APR
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
+ select SND_SOC_RT5663
help
To add support for audio on Qualcomm Technologies Inc.
SDM845 SoC-based systems.
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index d07271ea4c45..028bce671cbc 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
if (ret) {
dev_err(soc_runtime->dev,
"error writing to rdmactl reg: %d\n", ret);
- return ret;
+ return ret;
}
data->dma_ch = dma_ch;
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index 8f6c8fc073a9..dc645ba4d8d0 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -341,6 +341,7 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
switch (dai->id) {
case HDMI_RX:
+ case DISPLAY_PORT_RX:
q6afe_hdmi_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].hdmi);
break;
@@ -445,6 +446,7 @@ static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"HDMI Playback", NULL, "HDMI_RX"},
+ {"Display Port Playback", NULL, "DISPLAY_PORT_RX"},
{"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"},
{"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"},
{"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"},
@@ -561,13 +563,13 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
};
-static struct snd_soc_dai_ops q6hdmi_ops = {
+static const struct snd_soc_dai_ops q6hdmi_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6hdmi_hw_params,
.shutdown = q6afe_dai_shutdown,
};
-static struct snd_soc_dai_ops q6i2s_ops = {
+static const struct snd_soc_dai_ops q6i2s_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6i2s_hw_params,
.set_fmt = q6i2s_set_fmt,
@@ -575,14 +577,14 @@ static struct snd_soc_dai_ops q6i2s_ops = {
.set_sysclk = q6afe_mi2s_set_sysclk,
};
-static struct snd_soc_dai_ops q6slim_ops = {
+static const struct snd_soc_dai_ops q6slim_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6slim_hw_params,
.shutdown = q6afe_dai_shutdown,
.set_channel_map = q6slim_set_channel_map,
};
-static struct snd_soc_dai_ops q6tdm_ops = {
+static const struct snd_soc_dai_ops q6tdm_ops = {
.prepare = q6afe_dai_prepare,
.shutdown = q6afe_dai_shutdown,
.set_sysclk = q6afe_mi2s_set_sysclk,
@@ -1090,6 +1092,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5),
Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6),
Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7),
+ {
+ .playback = {
+ .stream_name = "Display Port Playback",
+ .rates = SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_max = 192000,
+ .rate_min = 48000,
+ },
+ .ops = &q6hdmi_ops,
+ .id = DISPLAY_PORT_RX,
+ .name = "DISPLAY_PORT",
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
};
static int q6afe_of_xlate_dai_name(struct snd_soc_component *component,
@@ -1311,6 +1332,7 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL,
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, 0, 0, 0),
};
static const struct snd_soc_component_driver q6afe_dai_component = {
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 829b5e987b2a..e0945f7a58c8 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -71,6 +71,7 @@
/* Port IDs */
#define AFE_API_VERSION_HDMI_CONFIG 0x1
#define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E
+#define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020
#define AFE_API_VERSION_SLIMBUS_CONFIG 0x1
/* Clock set API version */
@@ -704,6 +705,8 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
QUINARY_TDM_RX_7, 1, 1},
[QUINARY_TDM_TX_7] = { AFE_PORT_ID_QUINARY_TDM_TX_7,
QUINARY_TDM_TX_7, 0, 1},
+ [DISPLAY_PORT_RX] = { AFE_PORT_ID_HDMI_OVER_DP_RX,
+ DISPLAY_PORT_RX, 1, 1},
};
static void q6afe_port_free(struct kref *ref)
@@ -1384,6 +1387,7 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
switch (port_id) {
case AFE_PORT_ID_MULTICHAN_HDMI_RX:
+ case AFE_PORT_ID_HDMI_OVER_DP_RX:
cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
break;
case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX:
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 86115de5c1b2..5b986b74dd36 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -10,6 +10,8 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <linux/spinlock.h>
+#include <sound/compress_driver.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
@@ -30,6 +32,15 @@
#define CAPTURE_MIN_PERIOD_SIZE 320
#define SID_MASK_DEFAULT 0xF
+/* Default values used if user space does not set */
+#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
+#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
+#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
+#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
+#define Q6ASM_DAI_TX_RX 0
+#define Q6ASM_DAI_TX 1
+#define Q6ASM_DAI_RX 2
+
enum stream_state {
Q6ASM_STREAM_IDLE = 0,
Q6ASM_STREAM_STOPPED,
@@ -38,11 +49,18 @@ enum stream_state {
struct q6asm_dai_rtd {
struct snd_pcm_substream *substream;
+ struct snd_compr_stream *cstream;
+ struct snd_compr_params codec_param;
+ struct snd_dma_buffer dma_buffer;
+ spinlock_t lock;
phys_addr_t phys;
unsigned int pcm_size;
unsigned int pcm_count;
unsigned int pcm_irq_pos; /* IRQ position */
unsigned int periods;
+ unsigned int bytes_sent;
+ unsigned int bytes_received;
+ unsigned int copied_total;
uint16_t bits_per_sample;
uint16_t source; /* Encoding source bit mask */
struct audio_client *audio_client;
@@ -137,6 +155,21 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
.mask = 0,
};
+static const struct snd_compr_codec_caps q6asm_compr_caps = {
+ .num_descriptors = 1,
+ .descriptor[0].max_ch = 2,
+ .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
+ 24000, 32000, 44100, 48000, 88200,
+ 96000, 176400, 192000 },
+ .descriptor[0].num_sample_rates = 13,
+ .descriptor[0].bit_rate[0] = 320,
+ .descriptor[0].bit_rate[1] = 128,
+ .descriptor[0].num_bitrates = 2,
+ .descriptor[0].profiles = 0,
+ .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
+ .descriptor[0].formats = 0,
+};
+
static void event_handler(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
@@ -460,6 +493,306 @@ static struct snd_pcm_ops q6asm_dai_ops = {
.mmap = q6asm_dai_mmap,
};
+static void compress_event_handler(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6asm_dai_rtd *prtd = priv;
+ struct snd_compr_stream *substream = prtd->cstream;
+ unsigned long flags;
+ uint64_t avail;
+
+ switch (opcode) {
+ case ASM_CLIENT_EVENT_CMD_RUN_DONE:
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (!prtd->bytes_sent) {
+ q6asm_write_async(prtd->audio_client, prtd->pcm_count,
+ 0, 0, NO_TIMESTAMP);
+ prtd->bytes_sent += prtd->pcm_count;
+ }
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
+ case ASM_CLIENT_EVENT_CMD_EOS_DONE:
+ prtd->state = Q6ASM_STREAM_STOPPED;
+ break;
+
+ case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ prtd->copied_total += prtd->pcm_count;
+ snd_compr_fragment_elapsed(substream);
+
+ if (prtd->state != Q6ASM_STREAM_RUNNING) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
+ avail = prtd->bytes_received - prtd->bytes_sent;
+
+ if (avail >= prtd->pcm_count) {
+ q6asm_write_async(prtd->audio_client,
+ prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ prtd->bytes_sent += prtd->pcm_count;
+ }
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct q6asm_dai_data *pdata;
+ struct device *dev = c->dev;
+ struct q6asm_dai_rtd *prtd;
+ int stream_id, size, ret;
+
+ stream_id = cpu_dai->driver->id;
+ pdata = snd_soc_component_get_drvdata(c);
+ if (!pdata) {
+ dev_err(dev, "Drv data not found ..\n");
+ return -EINVAL;
+ }
+
+ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+ if (!prtd)
+ return -ENOMEM;
+
+ prtd->cstream = stream;
+ prtd->audio_client = q6asm_audio_client_alloc(dev,
+ (q6asm_cb)compress_event_handler,
+ prtd, stream_id, LEGACY_PCM_MODE);
+ if (!prtd->audio_client) {
+ dev_err(dev, "Could not allocate memory\n");
+ kfree(prtd);
+ return -ENOMEM;
+ }
+
+ size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
+ COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
+ &prtd->dma_buffer);
+ if (ret) {
+ dev_err(dev, "Cannot allocate buffer(s)\n");
+ return ret;
+ }
+
+ if (pdata->sid < 0)
+ prtd->phys = prtd->dma_buffer.addr;
+ else
+ prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
+
+ snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
+ spin_lock_init(&prtd->lock);
+ runtime->private_data = prtd;
+
+ return 0;
+}
+
+static int q6asm_dai_compr_free(struct snd_compr_stream *stream)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+
+ if (prtd->audio_client) {
+ if (prtd->state)
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+
+ snd_dma_free_pages(&prtd->dma_buffer);
+ q6asm_unmap_memory_regions(stream->direction,
+ prtd->audio_client);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ }
+ q6routing_stream_close(rtd->dai_link->id, stream->direction);
+ kfree(prtd);
+
+ return 0;
+}
+
+static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ int dir = stream->direction;
+ struct q6asm_dai_data *pdata;
+ struct device *dev = c->dev;
+ int ret;
+
+ memcpy(&prtd->codec_param, params, sizeof(*params));
+
+ pdata = snd_soc_component_get_drvdata(c);
+ if (!pdata)
+ return -EINVAL;
+
+ if (!prtd || !prtd->audio_client) {
+ dev_err(dev, "private data null or audio client freed\n");
+ return -EINVAL;
+ }
+
+ prtd->periods = runtime->fragments;
+ prtd->pcm_count = runtime->fragment_size;
+ prtd->pcm_size = runtime->fragments * runtime->fragment_size;
+ prtd->bits_per_sample = 16;
+ if (dir == SND_COMPRESS_PLAYBACK) {
+ ret = q6asm_open_write(prtd->audio_client, params->codec.id,
+ prtd->bits_per_sample);
+
+ if (ret < 0) {
+ dev_err(dev, "q6asm_open_write failed\n");
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return ret;
+ }
+ }
+
+ prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+ ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
+ prtd->session_id, dir);
+ if (ret) {
+ dev_err(dev, "Stream reg failed ret:%d\n", ret);
+ return ret;
+ }
+
+ ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
+ (prtd->pcm_size / prtd->periods),
+ prtd->periods);
+
+ if (ret < 0) {
+ dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
+ return -ENOMEM;
+ }
+
+ prtd->state = Q6ASM_STREAM_RUNNING;
+
+ return 0;
+}
+
+static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ prtd->state = Q6ASM_STREAM_STOPPED;
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int q6asm_dai_compr_pointer(struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ tstamp->copied_total = prtd->copied_total;
+ tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ return 0;
+}
+
+static int q6asm_dai_compr_ack(struct snd_compr_stream *stream,
+ size_t count)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->bytes_received += count;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ return count;
+}
+
+static int q6asm_dai_compr_mmap(struct snd_compr_stream *stream,
+ struct vm_area_struct *vma)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ struct device *dev = c->dev;
+
+ return dma_mmap_coherent(dev, vma,
+ prtd->dma_buffer.area, prtd->dma_buffer.addr,
+ prtd->dma_buffer.bytes);
+}
+
+static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream,
+ struct snd_compr_caps *caps)
+{
+ caps->direction = SND_COMPRESS_PLAYBACK;
+ caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
+ caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
+ caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
+ caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+ caps->num_codecs = 1;
+ caps->codecs[0] = SND_AUDIOCODEC_MP3;
+
+ return 0;
+}
+
+static int q6asm_dai_compr_get_codec_caps(struct snd_compr_stream *stream,
+ struct snd_compr_codec_caps *codec)
+{
+ switch (codec->codec) {
+ case SND_AUDIOCODEC_MP3:
+ *codec = q6asm_compr_caps;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_compr_ops q6asm_dai_compr_ops = {
+ .open = q6asm_dai_compr_open,
+ .free = q6asm_dai_compr_free,
+ .set_params = q6asm_dai_compr_set_params,
+ .pointer = q6asm_dai_compr_pointer,
+ .trigger = q6asm_dai_compr_trigger,
+ .get_caps = q6asm_dai_compr_get_caps,
+ .get_codec_caps = q6asm_dai_compr_get_codec_caps,
+ .mmap = q6asm_dai_compr_mmap,
+ .ack = q6asm_dai_compr_ack,
+};
+
static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm_substream *psubstream, *csubstream;
@@ -515,7 +848,7 @@ static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.ops = &q6asm_dai_ops,
.pcm_new = q6asm_dai_pcm_new,
.pcm_free = q6asm_dai_pcm_free,
-
+ .compr_ops = &q6asm_dai_compr_ops,
};
static struct snd_soc_dai_driver q6asm_fe_dais[] = {
@@ -529,6 +862,41 @@ static struct snd_soc_dai_driver q6asm_fe_dais[] = {
Q6ASM_FEDAI_DRIVER(8),
};
+static int of_q6asm_parse_dai_data(struct device *dev,
+ struct q6asm_dai_data *pdata)
+{
+ static struct snd_soc_dai_driver *dai_drv;
+ struct snd_soc_pcm_stream empty_stream;
+ struct device_node *node;
+ int ret, id, dir;
+
+ memset(&empty_stream, 0, sizeof(empty_stream));
+
+ for_each_child_of_node(dev->of_node, node) {
+ ret = of_property_read_u32(node, "reg", &id);
+ if (ret || id > MAX_SESSIONS || id < 0) {
+ dev_err(dev, "valid dai id not found:%d\n", ret);
+ continue;
+ }
+
+ dai_drv = &q6asm_fe_dais[id];
+
+ ret = of_property_read_u32(node, "direction", &dir);
+ if (ret)
+ continue;
+
+ if (dir == Q6ASM_DAI_RX)
+ dai_drv->capture = empty_stream;
+ else if (dir == Q6ASM_DAI_TX)
+ dai_drv->playback = empty_stream;
+
+ if (of_property_read_bool(node, "is-compress-dai"))
+ dai_drv->compress_new = snd_soc_new_compress;
+ }
+
+ return 0;
+}
+
static int q6asm_dai_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -549,6 +917,8 @@ static int q6asm_dai_probe(struct platform_device *pdev)
dev_set_drvdata(dev, pdata);
+ of_q6asm_parse_dai_data(dev, pdata);
+
return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
q6asm_fe_dais,
ARRAY_SIZE(q6asm_fe_dais));
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index e1cfa846a1dc..4f85cb19a309 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -12,6 +12,7 @@
#include <linux/kref.h>
#include <linux/of.h>
#include <uapi/sound/asound.h>
+#include <uapi/sound/compress_params.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mm.h>
@@ -36,6 +37,7 @@
#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3
#define ASM_SESSION_CMD_RUN_V2 0x00010DAA
#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5
+#define ASM_MEDIA_FMT_MP3 0x00010BE9
#define ASM_DATA_CMD_WRITE_V2 0x00010DAB
#define ASM_DATA_CMD_READ_V2 0x00010DAC
#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
@@ -868,6 +870,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format,
open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
switch (format) {
+ case SND_AUDIOCODEC_MP3:
+ open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
+ break;
case FORMAT_LINEAR_PCM:
open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
break;
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index d61b8404f7da..ddcd9978cf57 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -453,6 +453,9 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(HDMI_RX) };
+static const struct snd_kcontrol_new display_port_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(DISPLAY_PORT_RX) };
+
static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) };
@@ -655,6 +658,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
hdmi_mixer_controls,
ARRAY_SIZE(hdmi_mixer_controls)),
+ SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ display_port_mixer_controls,
+ ARRAY_SIZE(display_port_mixer_controls)),
+
SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
slimbus_rx_mixer_controls,
ARRAY_SIZE(slimbus_rx_mixer_controls)),
@@ -833,6 +840,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
static const struct snd_soc_dapm_route intercon[] = {
Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("DISPLAY_PORT_RX Audio Mixer",
+ "DISPLAY_PORT_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"),
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 9effbecc571f..1db8ef668223 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -6,18 +6,31 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
+#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <uapi/linux/input-event-codes.h>
#include "common.h"
#include "qdsp6/q6afe.h"
+#include "../codecs/rt5663.h"
#define DEFAULT_SAMPLE_RATE_48K 48000
#define DEFAULT_MCLK_RATE 24576000
-#define DEFAULT_BCLK_RATE 12288000
+#define TDM_BCLK_RATE 6144000
+#define MI2S_BCLK_RATE 1536000
+#define LEFT_SPK_TDM_TX_MASK 0x30
+#define RIGHT_SPK_TDM_TX_MASK 0xC0
+#define SPK_TDM_RX_MASK 0x03
+#define NUM_TDM_SLOTS 8
struct sdm845_snd_data {
+ struct snd_soc_jack jack;
+ bool jack_setup;
struct snd_soc_card *card;
uint32_t pri_mi2s_clk_count;
+ uint32_t sec_mi2s_clk_count;
uint32_t quat_tdm_clk_count;
};
@@ -28,12 +41,12 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, j;
int channels, slot_width;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- slot_width = 32;
+ slot_width = 16;
break;
default:
dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
@@ -75,6 +88,35 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
goto end;
}
}
+
+ for (j = 0; j < rtd->num_codecs; j++) {
+ struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+
+ if (!strcmp(codec_dai->component->name_prefix, "Left")) {
+ ret = snd_soc_dai_set_tdm_slot(
+ codec_dai, LEFT_SPK_TDM_TX_MASK,
+ SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
+ slot_width);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "DEV0 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!strcmp(codec_dai->component->name_prefix, "Right")) {
+ ret = snd_soc_dai_set_tdm_slot(
+ codec_dai, RIGHT_SPK_TDM_TX_MASK,
+ SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
+ slot_width);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "DEV1 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ }
+
end:
return ret;
}
@@ -84,9 +126,27 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ case PRIMARY_MI2S_TX:
+ /*
+ * Use ASRC for internal clocks, as PLL rate isn't multiple
+ * of BCLK.
+ */
+ rt5663_sel_asrc_clk_src(
+ codec_dai->component,
+ RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+ RT5663_CLK_SEL_I2S1_ASRC);
+ ret = snd_soc_dai_set_sysclk(
+ codec_dai, RT5663_SCLK_S_MCLK, DEFAULT_MCLK_RATE,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev,
+ "snd_soc_dai_set_sysclk err = %d\n", ret);
+ break;
case QUATERNARY_TDM_RX_0:
case QUATERNARY_TDM_TX_0:
ret = sdm845_tdm_snd_hw_params(substream, params);
@@ -98,24 +158,87 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_soc_card *card = rtd->card;
+ struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
+ int i, rval;
+
+ if (!pdata->jack_setup) {
+ struct snd_jack *jack;
+
+ 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->jack, NULL, 0);
+
+ if (rval < 0) {
+ dev_err(card->dev, "Unable to add Headphone Jack\n");
+ return rval;
+ }
+
+ jack = pdata->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);
+ pdata->jack_setup = true;
+ }
+
+ for (i = 0 ; i < dai_link->num_codecs; i++) {
+ struct snd_soc_dai *dai = rtd->codec_dais[i];
+
+ component = dai->component;
+ rval = snd_soc_component_set_jack(
+ component, &pdata->jack, NULL);
+ if (rval != 0 && rval != -ENOTSUPP) {
+ dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+ return rval;
+ }
+ }
+
+ return 0;
+}
+
+
static int sdm845_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_card *card = rtd->card;
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int j;
+ int ret;
switch (cpu_dai->id) {
case PRIMARY_MI2S_RX:
case PRIMARY_MI2S_TX:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF;
if (++(data->pri_mi2s_clk_count) == 1) {
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_MCLK_1,
DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
- DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ 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;
+
+ case SECONDARY_MI2S_TX:
+ if (++(data->sec_mi2s_clk_count) == 1) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
}
snd_soc_dai_set_fmt(cpu_dai, fmt);
break;
@@ -125,7 +248,35 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
if (++(data->quat_tdm_clk_count) == 1) {
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
- DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+
+ codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
+
+ for (j = 0; j < rtd->num_codecs; j++) {
+ codec_dai = rtd->codec_dais[j];
+
+ if (!strcmp(codec_dai->component->name_prefix,
+ "Left")) {
+ ret = snd_soc_dai_set_fmt(
+ codec_dai, codec_dai_fmt);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "Left TDM fmt err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!strcmp(codec_dai->component->name_prefix,
+ "Right")) {
+ ret = snd_soc_dai_set_fmt(
+ codec_dai, codec_dai_fmt);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "Right TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
}
break;
@@ -156,6 +307,14 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
};
break;
+ case SECONDARY_MI2S_TX:
+ if (--(data->sec_mi2s_clk_count) == 0) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ 0, SNDRV_PCM_STREAM_CAPTURE);
+ }
+ break;
+
case QUATERNARY_TDM_RX_0:
case QUATERNARY_TDM_TX_0:
if (--(data->quat_tdm_clk_count) == 0) {
@@ -171,7 +330,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
}
}
-static struct snd_soc_ops sdm845_be_ops = {
+static const struct snd_soc_ops sdm845_be_ops = {
.hw_params = sdm845_snd_hw_params,
.startup = sdm845_snd_startup,
.shutdown = sdm845_snd_shutdown,
@@ -193,7 +352,15 @@ static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static void sdm845_add_be_ops(struct snd_soc_card *card)
+static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static void sdm845_add_ops(struct snd_soc_card *card)
{
struct snd_soc_dai_link *link;
int i;
@@ -203,6 +370,7 @@ static void sdm845_add_be_ops(struct snd_soc_card *card)
link->ops = &sdm845_be_ops;
link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
}
+ link->init = sdm845_dai_init;
}
}
@@ -224,6 +392,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
goto data_alloc_fail;
}
+ card->dapm_widgets = sdm845_snd_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
card->dev = dev;
dev_set_drvdata(dev, card);
ret = qcom_snd_parse_of(card);
@@ -235,7 +405,7 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
data->card = card;
snd_soc_card_set_drvdata(card, data);
- sdm845_add_be_ops(card);
+ sdm845_add_ops(card);
ret = snd_soc_register_card(card);
if (ret) {
dev_err(dev, "Sound card registration failed\n");
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 28327dd2c6cb..e821ccc70f47 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -249,28 +249,8 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
out = out << shift;
mask = 0x0f1f << shift;
- switch (id / 2) {
- case 0:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out);
- break;
- case 1:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out);
- break;
- case 2:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out);
- break;
- case 3:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out);
- break;
- case 4:
- rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4, mask, in);
- rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out);
- break;
- }
+ rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2), mask, in);
+ rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out);
if (en)
rsnd_mod_bset(adg_mod, DIV_EN, en, en);
@@ -299,17 +279,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
if (id == 8)
return;
- switch (id / 4) {
- case 0:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val);
- break;
- case 1:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val);
- break;
- case 2:
- rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
- break;
- }
+ rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val);
dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
}
@@ -613,7 +583,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
return -ENOMEM;
ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
- NULL, NULL, 0, 0);
+ NULL, 0, 0);
if (ret)
return ret;
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index cc191cd5fb82..e6bb6a9a0684 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -116,10 +116,11 @@ static int rsnd_cmd_stop(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_cmd_ops = {
- .name = CMD_NAME,
- .init = rsnd_cmd_init,
- .start = rsnd_cmd_start,
- .stop = rsnd_cmd_stop,
+ .name = CMD_NAME,
+ .init = rsnd_cmd_init,
+ .start = rsnd_cmd_start,
+ .stop = rsnd_cmd_stop,
+ .get_status = rsnd_mod_get_status,
};
static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
@@ -162,7 +163,7 @@ int rsnd_cmd_probe(struct rsnd_priv *priv)
for_each_rsnd_cmd(cmd, priv, i) {
ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
&rsnd_cmd_ops, NULL,
- rsnd_mod_get_status, RSND_MOD_CMD, i);
+ RSND_MOD_CMD, i);
if (ret)
return ret;
}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 114f8f233764..59e250cc2e9d 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -123,8 +123,8 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- dev_warn(dev, "%s[%d] is not your expected module\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_warn(dev, "%s is not your expected module\n",
+ rsnd_mod_name(mod));
}
}
@@ -137,20 +137,69 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
return mod->ops->dma_req(io, mod);
}
-u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
+#define MOD_NAME_NUM 5
+#define MOD_NAME_SIZE 16
+char *rsnd_mod_name(struct rsnd_mod *mod)
+{
+ static char names[MOD_NAME_NUM][MOD_NAME_SIZE];
+ static int num;
+ char *name = names[num];
+
+ num++;
+ if (num >= MOD_NAME_NUM)
+ num = 0;
+
+ /*
+ * Let's use same char to avoid pointlessness memory
+ * Thus, rsnd_mod_name() should be used immediately
+ * Don't keep pointer
+ */
+ if ((mod)->ops->id_sub) {
+ snprintf(name, MOD_NAME_SIZE, "%s[%d%d]",
+ mod->ops->name,
+ rsnd_mod_id(mod),
+ rsnd_mod_id_sub(mod));
+ } else {
+ snprintf(name, MOD_NAME_SIZE, "%s[%d]",
+ mod->ops->name,
+ rsnd_mod_id(mod));
+ }
+
+ return name;
+}
+
+u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
enum rsnd_mod_type type)
{
return &mod->status;
}
+int rsnd_mod_id_raw(struct rsnd_mod *mod)
+{
+ return mod->id;
+}
+
+int rsnd_mod_id(struct rsnd_mod *mod)
+{
+ if ((mod)->ops->id)
+ return (mod)->ops->id(mod);
+
+ return rsnd_mod_id_raw(mod);
+}
+
+int rsnd_mod_id_sub(struct rsnd_mod *mod)
+{
+ if ((mod)->ops->id_sub)
+ return (mod)->ops->id_sub(mod);
+
+ return 0;
+}
+
int rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_mod_ops *ops,
struct clk *clk,
- u32* (*get_status)(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type),
enum rsnd_mod_type type,
int id)
{
@@ -164,7 +213,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
mod->type = type;
mod->clk = clk;
mod->priv = priv;
- mod->get_status = get_status;
return ret;
}
@@ -228,7 +276,20 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
if (ctu_mod) {
- u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod);
+ u32 converted_chan = rsnd_io_converted_chan(io);
+
+ /*
+ * !! Note !!
+ *
+ * converted_chan will be used for CTU,
+ * or TDM Split mode.
+ * User shouldn't use CTU with TDM Split mode.
+ */
+ if (rsnd_runtime_is_tdm_split(io)) {
+ struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
+
+ dev_err(dev, "CTU and TDM Split should be used\n");
+ }
if (converted_chan)
return converted_chan;
@@ -246,7 +307,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
rsnd_runtime_channel_original_with_params(io, params);
/* Use Multi SSI */
- if (rsnd_runtime_is_ssi_multi(io))
+ if (rsnd_runtime_is_multi_ssi(io))
chan /= rsnd_rdai_ssi_lane_get(rdai);
/* TDM Extend Mode needs 8ch */
@@ -256,7 +317,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
return chan;
}
-int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
+int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
int lane = rsnd_rdai_ssi_lane_get(rdai);
@@ -267,11 +328,16 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
return (chan > 2) && (lane > 1);
}
-int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io)
+int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io)
{
return rsnd_runtime_channel_for_ssi(io) >= 6;
}
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io)
+{
+ return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT);
+}
+
/*
* ADINR function
*/
@@ -472,20 +538,19 @@ static int rsnd_status_update(u32 *status,
enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \
for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \
int tmp = 0; \
- u32 *status = mod->get_status(io, mod, types[i]); \
+ u32 *status = mod->ops->get_status(mod, io, types[i]); \
int func_call = rsnd_status_update(status, \
__rsnd_mod_shift_##fn, \
__rsnd_mod_add_##fn, \
__rsnd_mod_call_##fn); \
- rsnd_dbg_dai_call(dev, "%s[%d]\t0x%08x %s\n", \
- rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \
+ rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n", \
+ rsnd_mod_name(mod), *status, \
(func_call && (mod)->ops->fn) ? #fn : ""); \
if (func_call && (mod)->ops->fn) \
tmp = (mod)->ops->fn(mod, io, param); \
if (tmp && (tmp != -EPROBE_DEFER)) \
- dev_err(dev, "%s[%d] : %s error %d\n", \
- rsnd_mod_name(mod), rsnd_mod_id(mod), \
- #fn, tmp); \
+ dev_err(dev, "%s : %s error %d\n", \
+ rsnd_mod_name(mod), #fn, tmp); \
ret |= tmp; \
} \
ret; \
@@ -512,8 +577,8 @@ int rsnd_dai_connect(struct rsnd_mod *mod,
io->mod[type] = mod;
- dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "%s is connected to io (%s)\n",
+ rsnd_mod_name(mod),
rsnd_io_is_play(io) ? "Playback" : "Capture");
return 0;
@@ -750,6 +815,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
switch (slots) {
case 2:
+ /* TDM Split Mode */
case 6:
case 8:
/* TDM Extend Mode */
@@ -965,6 +1031,82 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
.prepare = rsnd_soc_dai_prepare,
};
+static void rsnd_parse_connect_simple(struct rsnd_priv *priv,
+ struct device_node *dai_np,
+ int dai_i, int is_play)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
+ struct rsnd_dai_stream *io = is_play ?
+ &rdai->playback :
+ &rdai->capture;
+ struct device_node *ssiu_np = rsnd_ssiu_of_node(priv);
+ struct device_node *np;
+ int i, j;
+
+ if (!ssiu_np)
+ return;
+
+ if (!rsnd_io_to_mod_ssi(io))
+ return;
+
+ /*
+ * This driver assumes that it is TDM Split mode
+ * if it includes ssiu node
+ */
+ for (i = 0;; i++) {
+ struct device_node *node = is_play ?
+ of_parse_phandle(dai_np, "playback", i) :
+ of_parse_phandle(dai_np, "capture", i);
+
+ if (!node)
+ break;
+
+ j = 0;
+ for_each_child_of_node(ssiu_np, np) {
+ if (np == node) {
+ rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
+ dev_dbg(dev, "%s is part of TDM Split\n", io->name);
+ }
+ j++;
+ }
+
+ }
+}
+
+static void rsnd_parse_connect_graph(struct rsnd_priv *priv,
+ struct rsnd_dai_stream *io,
+ struct device_node *endpoint)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *remote_port = of_graph_get_remote_port(endpoint);
+ struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint);
+
+ if (!rsnd_io_to_mod_ssi(io))
+ return;
+
+ /* HDMI0 */
+ if (strstr(remote_node->full_name, "hdmi@fead0000")) {
+ rsnd_flags_set(io, RSND_STREAM_HDMI0);
+ dev_dbg(dev, "%s connected to HDMI0\n", io->name);
+ }
+
+ /* HDMI1 */
+ if (strstr(remote_node->full_name, "hdmi@feae0000")) {
+ rsnd_flags_set(io, RSND_STREAM_HDMI1);
+ dev_dbg(dev, "%s connected to HDMI1\n", io->name);
+ }
+
+ /*
+ * This driver assumes that it is TDM Split mode
+ * if remote node has multi endpoint
+ */
+ if (of_get_child_count(remote_port) > 1) {
+ rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
+ dev_dbg(dev, "%s is part of TDM Split\n", io->name);
+ }
+}
+
void rsnd_parse_connect_common(struct rsnd_dai *rdai,
struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
struct device_node *node,
@@ -1051,24 +1193,24 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
drv->name = rdai->name;
drv->ops = &rsnd_soc_dai_ops;
- snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
+ snprintf(io_playback->name, RSND_DAI_NAME_SIZE,
"DAI%d Playback", dai_i);
drv->playback.rates = RSND_RATES;
drv->playback.formats = RSND_FMTS;
drv->playback.channels_min = 2;
drv->playback.channels_max = 8;
- drv->playback.stream_name = rdai->playback.name;
+ drv->playback.stream_name = io_playback->name;
- snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
+ snprintf(io_capture->name, RSND_DAI_NAME_SIZE,
"DAI%d Capture", dai_i);
drv->capture.rates = RSND_RATES;
drv->capture.formats = RSND_FMTS;
drv->capture.channels_min = 2;
drv->capture.channels_max = 8;
- drv->capture.stream_name = rdai->capture.name;
+ drv->capture.stream_name = io_capture->name;
- rdai->playback.rdai = rdai;
- rdai->capture.rdai = rdai;
+ io_playback->rdai = rdai;
+ io_capture->rdai = rdai;
rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
rsnd_rdai_width_set(rdai, 32); /* default 32bit width */
@@ -1081,6 +1223,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
break;
rsnd_parse_connect_ssi(rdai, playback, capture);
+ rsnd_parse_connect_ssiu(rdai, playback, capture);
rsnd_parse_connect_src(rdai, playback, capture);
rsnd_parse_connect_ctu(rdai, playback, capture);
rsnd_parse_connect_mix(rdai, playback, capture);
@@ -1137,12 +1280,23 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
if (is_graph) {
for_each_endpoint_of_node(dai_node, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_i);
- rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
+ if (rsnd_is_gen3(priv)) {
+ struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
+
+ rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
+ rsnd_parse_connect_graph(priv, &rdai->capture, dai_np);
+ }
dai_i++;
}
} else {
- for_each_child_of_node(dai_node, dai_np)
- __rsnd_dai_probe(priv, dai_np, dai_i++);
+ for_each_child_of_node(dai_node, dai_np) {
+ __rsnd_dai_probe(priv, dai_np, dai_i);
+ if (rsnd_is_gen3(priv)) {
+ rsnd_parse_connect_simple(priv, dai_np, dai_i, 1);
+ rsnd_parse_connect_simple(priv, dai_np, dai_i, 0);
+ }
+ dai_i++;
+ }
}
return 0;
@@ -1157,8 +1311,40 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
int ret;
+ /*
+ * rsnd assumes that it might be used under DPCM if user want to use
+ * channel / rate convert. Then, rsnd should be FE.
+ * And then, this function will be called *after* BE settings.
+ * this means, each BE already has fixuped hw_params.
+ * see
+ * dpcm_fe_dai_hw_params()
+ * dpcm_be_dai_hw_params()
+ */
+ io->converted_rate = 0;
+ io->converted_chan = 0;
+ if (fe->dai_link->dynamic) {
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct snd_soc_dpcm *dpcm;
+ struct snd_pcm_hw_params *be_params;
+ int stream = substream->stream;
+
+ for_each_dpcm_be(fe, stream, dpcm) {
+ be_params = &dpcm->hw_params;
+ if (params_channels(hw_params) != params_channels(be_params))
+ io->converted_chan = params_channels(be_params);
+ if (params_rate(hw_params) != params_rate(be_params))
+ io->converted_rate = params_rate(be_params);
+ }
+ if (io->converted_chan)
+ dev_dbg(dev, "convert channels = %d\n", io->converted_chan);
+ if (io->converted_rate)
+ dev_dbg(dev, "convert rate = %d\n", io->converted_rate);
+ }
+
ret = rsnd_dai_call(hw_params, io, substream, hw_params);
if (ret)
return ret;
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index ad702377a6c3..8cb06dab234e 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -72,10 +72,7 @@
struct rsnd_ctu {
struct rsnd_mod mod;
struct rsnd_kctrl_cfg_m pass;
- struct rsnd_kctrl_cfg_m sv0;
- struct rsnd_kctrl_cfg_m sv1;
- struct rsnd_kctrl_cfg_m sv2;
- struct rsnd_kctrl_cfg_m sv3;
+ struct rsnd_kctrl_cfg_m sv[4];
struct rsnd_kctrl_cfg_s reset;
int channels;
u32 flags;
@@ -107,13 +104,6 @@ static void rsnd_ctu_halt(struct rsnd_mod *mod)
rsnd_mod_write(mod, CTU_SWRSR, 0);
}
-int rsnd_ctu_converted_channel(struct rsnd_mod *mod)
-{
- struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
-
- return ctu->channels;
-}
-
static int rsnd_ctu_probe_(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -127,7 +117,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
u32 cpmdr = 0;
u32 scmdr = 0;
- int i;
+ int i, j;
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
u32 val = rsnd_kctrl_valm(ctu->pass, i);
@@ -146,45 +136,13 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
rsnd_mod_write(mod, CTU_SCMDR, scmdr);
- if (scmdr > 0) {
- rsnd_mod_write(mod, CTU_SV00R, rsnd_kctrl_valm(ctu->sv0, 0));
- rsnd_mod_write(mod, CTU_SV01R, rsnd_kctrl_valm(ctu->sv0, 1));
- rsnd_mod_write(mod, CTU_SV02R, rsnd_kctrl_valm(ctu->sv0, 2));
- rsnd_mod_write(mod, CTU_SV03R, rsnd_kctrl_valm(ctu->sv0, 3));
- rsnd_mod_write(mod, CTU_SV04R, rsnd_kctrl_valm(ctu->sv0, 4));
- rsnd_mod_write(mod, CTU_SV05R, rsnd_kctrl_valm(ctu->sv0, 5));
- rsnd_mod_write(mod, CTU_SV06R, rsnd_kctrl_valm(ctu->sv0, 6));
- rsnd_mod_write(mod, CTU_SV07R, rsnd_kctrl_valm(ctu->sv0, 7));
- }
- if (scmdr > 1) {
- rsnd_mod_write(mod, CTU_SV10R, rsnd_kctrl_valm(ctu->sv1, 0));
- rsnd_mod_write(mod, CTU_SV11R, rsnd_kctrl_valm(ctu->sv1, 1));
- rsnd_mod_write(mod, CTU_SV12R, rsnd_kctrl_valm(ctu->sv1, 2));
- rsnd_mod_write(mod, CTU_SV13R, rsnd_kctrl_valm(ctu->sv1, 3));
- rsnd_mod_write(mod, CTU_SV14R, rsnd_kctrl_valm(ctu->sv1, 4));
- rsnd_mod_write(mod, CTU_SV15R, rsnd_kctrl_valm(ctu->sv1, 5));
- rsnd_mod_write(mod, CTU_SV16R, rsnd_kctrl_valm(ctu->sv1, 6));
- rsnd_mod_write(mod, CTU_SV17R, rsnd_kctrl_valm(ctu->sv1, 7));
- }
- if (scmdr > 2) {
- rsnd_mod_write(mod, CTU_SV20R, rsnd_kctrl_valm(ctu->sv2, 0));
- rsnd_mod_write(mod, CTU_SV21R, rsnd_kctrl_valm(ctu->sv2, 1));
- rsnd_mod_write(mod, CTU_SV22R, rsnd_kctrl_valm(ctu->sv2, 2));
- rsnd_mod_write(mod, CTU_SV23R, rsnd_kctrl_valm(ctu->sv2, 3));
- rsnd_mod_write(mod, CTU_SV24R, rsnd_kctrl_valm(ctu->sv2, 4));
- rsnd_mod_write(mod, CTU_SV25R, rsnd_kctrl_valm(ctu->sv2, 5));
- rsnd_mod_write(mod, CTU_SV26R, rsnd_kctrl_valm(ctu->sv2, 6));
- rsnd_mod_write(mod, CTU_SV27R, rsnd_kctrl_valm(ctu->sv2, 7));
- }
- if (scmdr > 3) {
- rsnd_mod_write(mod, CTU_SV30R, rsnd_kctrl_valm(ctu->sv3, 0));
- rsnd_mod_write(mod, CTU_SV31R, rsnd_kctrl_valm(ctu->sv3, 1));
- rsnd_mod_write(mod, CTU_SV32R, rsnd_kctrl_valm(ctu->sv3, 2));
- rsnd_mod_write(mod, CTU_SV33R, rsnd_kctrl_valm(ctu->sv3, 3));
- rsnd_mod_write(mod, CTU_SV34R, rsnd_kctrl_valm(ctu->sv3, 4));
- rsnd_mod_write(mod, CTU_SV35R, rsnd_kctrl_valm(ctu->sv3, 5));
- rsnd_mod_write(mod, CTU_SV36R, rsnd_kctrl_valm(ctu->sv3, 6));
- rsnd_mod_write(mod, CTU_SV37R, rsnd_kctrl_valm(ctu->sv3, 7));
+ for (i = 0; i < 4; i++) {
+
+ if (i >= scmdr)
+ break;
+
+ for (j = 0; j < RSND_MAX_CHANNELS; j++)
+ rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j));
}
rsnd_mod_write(mod, CTU_CTUIR, 0);
@@ -201,10 +159,10 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
rsnd_kctrl_valm(ctu->pass, i) = 0;
- rsnd_kctrl_valm(ctu->sv0, i) = 0;
- rsnd_kctrl_valm(ctu->sv1, i) = 0;
- rsnd_kctrl_valm(ctu->sv2, i) = 0;
- rsnd_kctrl_valm(ctu->sv3, i) = 0;
+ rsnd_kctrl_valm(ctu->sv[0], i) = 0;
+ rsnd_kctrl_valm(ctu->sv[1], i) = 0;
+ rsnd_kctrl_valm(ctu->sv[2], i) = 0;
+ rsnd_kctrl_valm(ctu->sv[3], i) = 0;
}
rsnd_kctrl_vals(ctu->reset) = 0;
}
@@ -233,43 +191,6 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_ctu_hw_params(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *fe_params)
-{
- struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
- struct snd_soc_pcm_runtime *fe = substream->private_data;
-
- /*
- * CTU assumes that it is used under DPCM if user want to use
- * channel transfer. Then, CTU should be FE.
- * And then, this function will be called *after* BE settings.
- * this means, each BE already has fixuped hw_params.
- * see
- * dpcm_fe_dai_hw_params()
- * dpcm_be_dai_hw_params()
- */
- ctu->channels = 0;
- if (fe->dai_link->dynamic) {
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
- struct snd_soc_dpcm *dpcm;
- struct snd_pcm_hw_params *be_params;
- int stream = substream->stream;
-
- for_each_dpcm_be(fe, stream, dpcm) {
- be_params = &dpcm->hw_params;
- if (params_channels(fe_params) != params_channels(be_params))
- ctu->channels = params_channels(be_params);
- }
-
- dev_dbg(dev, "CTU convert channels %d\n", ctu->channels);
- }
-
- return 0;
-}
-
static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd)
@@ -291,7 +212,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
rsnd_kctrl_accept_anytime,
NULL,
- &ctu->sv0, RSND_MAX_CHANNELS,
+ &ctu->sv[0], RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
@@ -300,7 +221,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
rsnd_kctrl_accept_anytime,
NULL,
- &ctu->sv1, RSND_MAX_CHANNELS,
+ &ctu->sv[1], RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
@@ -309,7 +230,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
rsnd_kctrl_accept_anytime,
NULL,
- &ctu->sv2, RSND_MAX_CHANNELS,
+ &ctu->sv[2], RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
@@ -318,7 +239,7 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
rsnd_kctrl_accept_anytime,
NULL,
- &ctu->sv3, RSND_MAX_CHANNELS,
+ &ctu->sv[3], RSND_MAX_CHANNELS,
0x00FFFFFF);
if (ret < 0)
return ret;
@@ -334,13 +255,34 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
return ret;
}
+static int rsnd_ctu_id(struct rsnd_mod *mod)
+{
+ /*
+ * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0
+ * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1
+ */
+ return mod->id / 4;
+}
+
+static int rsnd_ctu_id_sub(struct rsnd_mod *mod)
+{
+ /*
+ * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3
+ * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3
+ */
+ return mod->id % 4;
+}
+
static struct rsnd_mod_ops rsnd_ctu_ops = {
.name = CTU_NAME,
.probe = rsnd_ctu_probe_,
.init = rsnd_ctu_init,
.quit = rsnd_ctu_quit,
- .hw_params = rsnd_ctu_hw_params,
.pcm_new = rsnd_ctu_pcm_new,
+ .get_status = rsnd_mod_get_status,
+ .id = rsnd_ctu_id,
+ .id_sub = rsnd_ctu_id_sub,
+ .id_cmd = rsnd_mod_id_raw,
};
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
@@ -404,7 +346,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
}
ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
- clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
+ clk, RSND_MOD_CTU, i);
if (ret) {
of_node_put(np);
goto rsnd_ctu_probe_done;
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 6d1947515dc8..0324a5c39619 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -174,8 +174,8 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dev_dbg(dev, "%s[%d] %pad -> %pad\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "%s %pad -> %pad\n",
+ rsnd_mod_name(mod),
&cfg.src_addr, &cfg.dst_addr);
ret = dmaengine_slave_config(dmaen->chan, &cfg);
@@ -218,7 +218,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
int i = 0;
for_each_child_of_node(of_node, np) {
- if (i == rsnd_mod_id(mod) && (!chan))
+ if (i == rsnd_mod_id_raw(mod) && (!chan))
chan = of_dma_request_slave_channel(np, name);
i++;
}
@@ -289,12 +289,13 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_dmaen_ops = {
- .name = "audmac",
- .prepare = rsnd_dmaen_prepare,
- .cleanup = rsnd_dmaen_cleanup,
- .start = rsnd_dmaen_start,
- .stop = rsnd_dmaen_stop,
- .pointer= rsnd_dmaen_pointer,
+ .name = "audmac",
+ .prepare = rsnd_dmaen_prepare,
+ .cleanup = rsnd_dmaen_cleanup,
+ .start = rsnd_dmaen_start,
+ .stop = rsnd_dmaen_stop,
+ .pointer = rsnd_dmaen_pointer,
+ .get_status = rsnd_mod_get_status,
};
/*
@@ -343,14 +344,16 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+ struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
const u8 *entry = NULL;
int id = 255;
int size = 0;
- if (mod == ssi) {
- int busif = rsnd_ssi_get_busif(io);
+ if ((mod == ssi) ||
+ (mod == ssiu)) {
+ int busif = rsnd_mod_id_sub(ssiu);
entry = gen2_id_table_ssiu;
size = ARRAY_SIZE(gen2_id_table_ssiu);
@@ -368,8 +371,7 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
if ((!entry) || (size <= id)) {
struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
- dev_err(dev, "unknown connection (%s[%d])\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod));
/* use non-prohibited SRS number as error */
return 0x00; /* SSI00 */
@@ -477,10 +479,11 @@ static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
}
static struct rsnd_mod_ops rsnd_dmapp_ops = {
- .name = "audmac-pp",
- .start = rsnd_dmapp_start,
- .stop = rsnd_dmapp_stop,
- .quit = rsnd_dmapp_stop,
+ .name = "audmac-pp",
+ .start = rsnd_dmapp_start,
+ .stop = rsnd_dmapp_stop,
+ .quit = rsnd_dmapp_stop,
+ .get_status = rsnd_mod_get_status,
};
/*
@@ -529,13 +532,14 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
struct device *dev = rsnd_priv_to_dev(priv);
phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI);
phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
- int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
+ int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
+ !!(rsnd_io_to_mod_ssiu(io) == mod);
int use_src = !!rsnd_io_to_mod_src(io);
int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
!!rsnd_io_to_mod_mix(io) ||
!!rsnd_io_to_mod_ctu(io);
int id = rsnd_mod_id(mod);
- int busif = rsnd_ssi_get_busif(io);
+ int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io));
struct dma_addr {
dma_addr_t out_addr;
dma_addr_t in_addr;
@@ -619,7 +623,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
struct rsnd_mod **mod_from,
struct rsnd_mod **mod_to)
{
- struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+ struct rsnd_mod *ssi;
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
@@ -630,6 +634,28 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
struct device *dev = rsnd_priv_to_dev(priv);
int nr, i, idx;
+ /*
+ * It should use "rcar_sound,ssiu" on DT.
+ * But, we need to keep compatibility for old version.
+ *
+ * If it has "rcar_sound.ssiu", it will be used.
+ * If not, "rcar_sound.ssi" will be used.
+ * see
+ * rsnd_ssiu_dma_req()
+ * rsnd_ssi_dma_req()
+ */
+ if (rsnd_ssiu_of_node(priv)) {
+ struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
+
+ /* use SSIU */
+ ssi = ssiu;
+ if (this == rsnd_io_to_mod_ssi(io))
+ this = ssiu;
+ } else {
+ /* keep compatible, use SSI */
+ ssi = rsnd_io_to_mod_ssi(io);
+ }
+
if (!ssi)
return;
@@ -690,12 +716,10 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
*mod_to = mod[1];
}
- dev_dbg(dev, "module connection (this is %s[%d])\n",
- rsnd_mod_name(this), rsnd_mod_id(this));
+ dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this));
for (i = 0; i <= idx; i++) {
- dev_dbg(dev, " %s[%d]%s\n",
+ dev_dbg(dev, " %s%s\n",
rsnd_mod_name(mod[i] ? mod[i] : &mem),
- rsnd_mod_id (mod[i] ? mod[i] : &mem),
(mod[i] == *mod_from) ? " from" :
(mod[i] == *mod_to) ? " to" : "");
}
@@ -756,16 +780,14 @@ static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
*dma_mod = rsnd_mod_get(dma);
ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
- rsnd_mod_get_status, type, dma_id);
+ type, dma_id);
if (ret < 0)
return ret;
- dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
- rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
+ dev_dbg(dev, "%s %s -> %s\n",
+ rsnd_mod_name(*dma_mod),
rsnd_mod_name(mod_from ? mod_from : &mem),
- rsnd_mod_id (mod_from ? mod_from : &mem),
- rsnd_mod_name(mod_to ? mod_to : &mem),
- rsnd_mod_id (mod_to ? mod_to : &mem));
+ rsnd_mod_name(mod_to ? mod_to : &mem));
ret = attach(io, dma, mod_from, mod_to);
if (ret < 0)
@@ -823,5 +845,5 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
priv->dma = dmac;
/* dummy mem mod for debug */
- return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0);
+ return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0);
}
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 024ece46bf68..8d91c0eb0880 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -86,14 +86,8 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
val[i] = rsnd_kctrl_valm(dvc->volume, i);
/* Enable Digital Volume */
- rsnd_mod_write(mod, DVC_VOL0R, val[0]);
- rsnd_mod_write(mod, DVC_VOL1R, val[1]);
- rsnd_mod_write(mod, DVC_VOL2R, val[2]);
- rsnd_mod_write(mod, DVC_VOL3R, val[3]);
- rsnd_mod_write(mod, DVC_VOL4R, val[4]);
- rsnd_mod_write(mod, DVC_VOL5R, val[5]);
- rsnd_mod_write(mod, DVC_VOL6R, val[6]);
- rsnd_mod_write(mod, DVC_VOL7R, val[7]);
+ for (i = 0; i < RSND_MAX_CHANNELS; i++)
+ rsnd_mod_write(mod, DVC_VOLxR(i), val[i]);
}
static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
@@ -298,6 +292,7 @@ static struct rsnd_mod_ops rsnd_dvc_ops = {
.init = rsnd_dvc_init,
.quit = rsnd_dvc_quit,
.pcm_new = rsnd_dvc_pcm_new,
+ .get_status = rsnd_mod_get_status,
};
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
@@ -357,7 +352,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
}
ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
- clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
+ clk, RSND_MOD_DVC, i);
if (ret) {
of_node_put(np);
goto rsnd_dvc_probe_done;
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 1f7881cc16b2..7cda60188f41 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -26,8 +26,8 @@ struct rsnd_gen {
struct regmap *regmap[RSND_BASE_MAX];
/* RSND_REG_MAX base */
- struct regmap_field *regs[RSND_REG_MAX];
- const char *reg_name[RSND_REG_MAX];
+ struct regmap_field *regs[REG_MAX];
+ const char *reg_name[REG_MAX];
};
#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
@@ -49,11 +49,11 @@ struct rsnd_regmap_field_conf {
}
/* single address mapping */
#define RSND_GEN_S_REG(id, offset) \
- RSND_REG_SET(RSND_REG_##id, offset, 0, #id)
+ RSND_REG_SET(id, offset, 0, #id)
/* multi address mapping */
#define RSND_GEN_M_REG(id, offset, _id_offset) \
- RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id)
+ RSND_REG_SET(id, offset, _id_offset, #id)
/*
* basic function
@@ -71,9 +71,17 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
return 1;
}
-u32 rsnd_read(struct rsnd_priv *priv,
- struct rsnd_mod *mod, enum rsnd_reg reg)
+static int rsnd_mod_id_cmd(struct rsnd_mod *mod)
{
+ if (mod->ops->id_cmd)
+ return mod->ops->id_cmd(mod);
+
+ return rsnd_mod_id(mod);
+}
+
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
u32 val;
@@ -81,35 +89,36 @@ u32 rsnd_read(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg))
return 0;
- regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
+ regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val);
- dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod),
rsnd_reg_name(gen, reg), reg, val);
return val;
}
-void rsnd_write(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 data)
+void rsnd_mod_write(struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 data)
{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
if (!rsnd_is_accessible_reg(priv, gen, reg))
return;
- regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
+ regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data);
- dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n",
+ rsnd_mod_name(mod),
rsnd_reg_name(gen, reg), reg, data);
}
-void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 mask, u32 data)
+void rsnd_mod_bset(struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 mask, u32 data)
{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
@@ -117,10 +126,10 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
return;
regmap_fields_force_update_bits(gen->regs[reg],
- rsnd_mod_id(mod), mask, data);
+ rsnd_mod_id_cmd(mod), mask, data);
- dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
+ dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n",
+ rsnd_mod_name(mod),
rsnd_reg_name(gen, reg), reg, data, mask);
}
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 8e3b57eaa708..a3e0370f5704 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -256,6 +256,7 @@ static struct rsnd_mod_ops rsnd_mix_ops = {
.init = rsnd_mix_init,
.quit = rsnd_mix_quit,
.pcm_new = rsnd_mix_pcm_new,
+ .get_status = rsnd_mod_get_status,
};
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
@@ -315,7 +316,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
}
ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
- clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
+ clk, RSND_MOD_MIX, i);
if (ret) {
of_node_put(np);
goto rsnd_mix_probe_done;
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 4464d1d0a042..605e4b934982 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -42,165 +42,175 @@
*/
enum rsnd_reg {
/* SCU (MIX/CTU/DVC) */
- RSND_REG_SRC_I_BUSIF_MODE,
- RSND_REG_SRC_O_BUSIF_MODE,
- RSND_REG_SRC_ROUTE_MODE0,
- RSND_REG_SRC_SWRSR,
- RSND_REG_SRC_SRCIR,
- RSND_REG_SRC_ADINR,
- RSND_REG_SRC_IFSCR,
- RSND_REG_SRC_IFSVR,
- RSND_REG_SRC_SRCCR,
- RSND_REG_SRC_CTRL,
- RSND_REG_SRC_BSDSR,
- RSND_REG_SRC_BSISR,
- RSND_REG_SRC_INT_ENABLE0,
- RSND_REG_SRC_BUSIF_DALIGN,
- RSND_REG_SRCIN_TIMSEL0,
- RSND_REG_SRCIN_TIMSEL1,
- RSND_REG_SRCIN_TIMSEL2,
- RSND_REG_SRCIN_TIMSEL3,
- RSND_REG_SRCIN_TIMSEL4,
- RSND_REG_SRCOUT_TIMSEL0,
- RSND_REG_SRCOUT_TIMSEL1,
- RSND_REG_SRCOUT_TIMSEL2,
- RSND_REG_SRCOUT_TIMSEL3,
- RSND_REG_SRCOUT_TIMSEL4,
- RSND_REG_SCU_SYS_STATUS0,
- RSND_REG_SCU_SYS_STATUS1,
- RSND_REG_SCU_SYS_INT_EN0,
- RSND_REG_SCU_SYS_INT_EN1,
- RSND_REG_CMD_CTRL,
- RSND_REG_CMD_BUSIF_MODE,
- RSND_REG_CMD_BUSIF_DALIGN,
- RSND_REG_CMD_ROUTE_SLCT,
- RSND_REG_CMDOUT_TIMSEL,
- RSND_REG_CTU_SWRSR,
- RSND_REG_CTU_CTUIR,
- RSND_REG_CTU_ADINR,
- RSND_REG_CTU_CPMDR,
- RSND_REG_CTU_SCMDR,
- RSND_REG_CTU_SV00R,
- RSND_REG_CTU_SV01R,
- RSND_REG_CTU_SV02R,
- RSND_REG_CTU_SV03R,
- RSND_REG_CTU_SV04R,
- RSND_REG_CTU_SV05R,
- RSND_REG_CTU_SV06R,
- RSND_REG_CTU_SV07R,
- RSND_REG_CTU_SV10R,
- RSND_REG_CTU_SV11R,
- RSND_REG_CTU_SV12R,
- RSND_REG_CTU_SV13R,
- RSND_REG_CTU_SV14R,
- RSND_REG_CTU_SV15R,
- RSND_REG_CTU_SV16R,
- RSND_REG_CTU_SV17R,
- RSND_REG_CTU_SV20R,
- RSND_REG_CTU_SV21R,
- RSND_REG_CTU_SV22R,
- RSND_REG_CTU_SV23R,
- RSND_REG_CTU_SV24R,
- RSND_REG_CTU_SV25R,
- RSND_REG_CTU_SV26R,
- RSND_REG_CTU_SV27R,
- RSND_REG_CTU_SV30R,
- RSND_REG_CTU_SV31R,
- RSND_REG_CTU_SV32R,
- RSND_REG_CTU_SV33R,
- RSND_REG_CTU_SV34R,
- RSND_REG_CTU_SV35R,
- RSND_REG_CTU_SV36R,
- RSND_REG_CTU_SV37R,
- RSND_REG_MIX_SWRSR,
- RSND_REG_MIX_MIXIR,
- RSND_REG_MIX_ADINR,
- RSND_REG_MIX_MIXMR,
- RSND_REG_MIX_MVPDR,
- RSND_REG_MIX_MDBAR,
- RSND_REG_MIX_MDBBR,
- RSND_REG_MIX_MDBCR,
- RSND_REG_MIX_MDBDR,
- RSND_REG_MIX_MDBER,
- RSND_REG_DVC_SWRSR,
- RSND_REG_DVC_DVUIR,
- RSND_REG_DVC_ADINR,
- RSND_REG_DVC_DVUCR,
- RSND_REG_DVC_ZCMCR,
- RSND_REG_DVC_VOL0R,
- RSND_REG_DVC_VOL1R,
- RSND_REG_DVC_VOL2R,
- RSND_REG_DVC_VOL3R,
- RSND_REG_DVC_VOL4R,
- RSND_REG_DVC_VOL5R,
- RSND_REG_DVC_VOL6R,
- RSND_REG_DVC_VOL7R,
- RSND_REG_DVC_DVUER,
- RSND_REG_DVC_VRCTR,
- RSND_REG_DVC_VRPDR,
- RSND_REG_DVC_VRDBR,
+ SRC_I_BUSIF_MODE,
+ SRC_O_BUSIF_MODE,
+ SRC_ROUTE_MODE0,
+ SRC_SWRSR,
+ SRC_SRCIR,
+ SRC_ADINR,
+ SRC_IFSCR,
+ SRC_IFSVR,
+ SRC_SRCCR,
+ SRC_CTRL,
+ SRC_BSDSR,
+ SRC_BSISR,
+ SRC_INT_ENABLE0,
+ SRC_BUSIF_DALIGN,
+ SRCIN_TIMSEL0,
+ SRCIN_TIMSEL1,
+ SRCIN_TIMSEL2,
+ SRCIN_TIMSEL3,
+ SRCIN_TIMSEL4,
+ SRCOUT_TIMSEL0,
+ SRCOUT_TIMSEL1,
+ SRCOUT_TIMSEL2,
+ SRCOUT_TIMSEL3,
+ SRCOUT_TIMSEL4,
+ SCU_SYS_STATUS0,
+ SCU_SYS_STATUS1,
+ SCU_SYS_INT_EN0,
+ SCU_SYS_INT_EN1,
+ CMD_CTRL,
+ CMD_BUSIF_MODE,
+ CMD_BUSIF_DALIGN,
+ CMD_ROUTE_SLCT,
+ CMDOUT_TIMSEL,
+ CTU_SWRSR,
+ CTU_CTUIR,
+ CTU_ADINR,
+ CTU_CPMDR,
+ CTU_SCMDR,
+ CTU_SV00R,
+ CTU_SV01R,
+ CTU_SV02R,
+ CTU_SV03R,
+ CTU_SV04R,
+ CTU_SV05R,
+ CTU_SV06R,
+ CTU_SV07R,
+ CTU_SV10R,
+ CTU_SV11R,
+ CTU_SV12R,
+ CTU_SV13R,
+ CTU_SV14R,
+ CTU_SV15R,
+ CTU_SV16R,
+ CTU_SV17R,
+ CTU_SV20R,
+ CTU_SV21R,
+ CTU_SV22R,
+ CTU_SV23R,
+ CTU_SV24R,
+ CTU_SV25R,
+ CTU_SV26R,
+ CTU_SV27R,
+ CTU_SV30R,
+ CTU_SV31R,
+ CTU_SV32R,
+ CTU_SV33R,
+ CTU_SV34R,
+ CTU_SV35R,
+ CTU_SV36R,
+ CTU_SV37R,
+ MIX_SWRSR,
+ MIX_MIXIR,
+ MIX_ADINR,
+ MIX_MIXMR,
+ MIX_MVPDR,
+ MIX_MDBAR,
+ MIX_MDBBR,
+ MIX_MDBCR,
+ MIX_MDBDR,
+ MIX_MDBER,
+ DVC_SWRSR,
+ DVC_DVUIR,
+ DVC_ADINR,
+ DVC_DVUCR,
+ DVC_ZCMCR,
+ DVC_VOL0R,
+ DVC_VOL1R,
+ DVC_VOL2R,
+ DVC_VOL3R,
+ DVC_VOL4R,
+ DVC_VOL5R,
+ DVC_VOL6R,
+ DVC_VOL7R,
+ DVC_DVUER,
+ DVC_VRCTR,
+ DVC_VRPDR,
+ DVC_VRDBR,
/* ADG */
- RSND_REG_BRRA,
- RSND_REG_BRRB,
- RSND_REG_BRGCKR,
- RSND_REG_DIV_EN,
- RSND_REG_AUDIO_CLK_SEL0,
- RSND_REG_AUDIO_CLK_SEL1,
- RSND_REG_AUDIO_CLK_SEL2,
+ BRRA,
+ BRRB,
+ BRGCKR,
+ DIV_EN,
+ AUDIO_CLK_SEL0,
+ AUDIO_CLK_SEL1,
+ AUDIO_CLK_SEL2,
/* SSIU */
- RSND_REG_SSI_MODE,
- RSND_REG_SSI_MODE0,
- RSND_REG_SSI_MODE1,
- RSND_REG_SSI_MODE2,
- RSND_REG_SSI_CONTROL,
- RSND_REG_SSI_CTRL,
- RSND_REG_SSI_BUSIF0_MODE,
- RSND_REG_SSI_BUSIF0_ADINR,
- RSND_REG_SSI_BUSIF0_DALIGN,
- RSND_REG_SSI_BUSIF1_MODE,
- RSND_REG_SSI_BUSIF1_ADINR,
- RSND_REG_SSI_BUSIF1_DALIGN,
- RSND_REG_SSI_BUSIF2_MODE,
- RSND_REG_SSI_BUSIF2_ADINR,
- RSND_REG_SSI_BUSIF2_DALIGN,
- RSND_REG_SSI_BUSIF3_MODE,
- RSND_REG_SSI_BUSIF3_ADINR,
- RSND_REG_SSI_BUSIF3_DALIGN,
- RSND_REG_SSI_BUSIF4_MODE,
- RSND_REG_SSI_BUSIF4_ADINR,
- RSND_REG_SSI_BUSIF4_DALIGN,
- RSND_REG_SSI_BUSIF5_MODE,
- RSND_REG_SSI_BUSIF5_ADINR,
- RSND_REG_SSI_BUSIF5_DALIGN,
- RSND_REG_SSI_BUSIF6_MODE,
- RSND_REG_SSI_BUSIF6_ADINR,
- RSND_REG_SSI_BUSIF6_DALIGN,
- RSND_REG_SSI_BUSIF7_MODE,
- RSND_REG_SSI_BUSIF7_ADINR,
- RSND_REG_SSI_BUSIF7_DALIGN,
- RSND_REG_SSI_INT_ENABLE,
- RSND_REG_SSI_SYS_STATUS0,
- RSND_REG_SSI_SYS_STATUS1,
- RSND_REG_SSI_SYS_STATUS2,
- RSND_REG_SSI_SYS_STATUS3,
- RSND_REG_SSI_SYS_STATUS4,
- RSND_REG_SSI_SYS_STATUS5,
- RSND_REG_SSI_SYS_STATUS6,
- RSND_REG_SSI_SYS_STATUS7,
- RSND_REG_HDMI0_SEL,
- RSND_REG_HDMI1_SEL,
+ SSI_MODE,
+ SSI_MODE0,
+ SSI_MODE1,
+ SSI_MODE2,
+ SSI_CONTROL,
+ SSI_CTRL,
+ SSI_BUSIF0_MODE,
+ SSI_BUSIF1_MODE,
+ SSI_BUSIF2_MODE,
+ SSI_BUSIF3_MODE,
+ SSI_BUSIF4_MODE,
+ SSI_BUSIF5_MODE,
+ SSI_BUSIF6_MODE,
+ SSI_BUSIF7_MODE,
+ SSI_BUSIF0_ADINR,
+ SSI_BUSIF1_ADINR,
+ SSI_BUSIF2_ADINR,
+ SSI_BUSIF3_ADINR,
+ SSI_BUSIF4_ADINR,
+ SSI_BUSIF5_ADINR,
+ SSI_BUSIF6_ADINR,
+ SSI_BUSIF7_ADINR,
+ SSI_BUSIF0_DALIGN,
+ SSI_BUSIF1_DALIGN,
+ SSI_BUSIF2_DALIGN,
+ SSI_BUSIF3_DALIGN,
+ SSI_BUSIF4_DALIGN,
+ SSI_BUSIF5_DALIGN,
+ SSI_BUSIF6_DALIGN,
+ SSI_BUSIF7_DALIGN,
+ SSI_INT_ENABLE,
+ SSI_SYS_STATUS0,
+ SSI_SYS_STATUS1,
+ SSI_SYS_STATUS2,
+ SSI_SYS_STATUS3,
+ SSI_SYS_STATUS4,
+ SSI_SYS_STATUS5,
+ SSI_SYS_STATUS6,
+ SSI_SYS_STATUS7,
+ HDMI0_SEL,
+ HDMI1_SEL,
/* SSI */
- RSND_REG_SSICR,
- RSND_REG_SSISR,
- RSND_REG_SSITDR,
- RSND_REG_SSIRDR,
- RSND_REG_SSIWSR,
+ SSICR,
+ SSISR,
+ SSITDR,
+ SSIRDR,
+ SSIWSR,
- RSND_REG_MAX,
+ REG_MAX,
};
+#define SRCIN_TIMSEL(i) (SRCIN_TIMSEL0 + (i))
+#define SRCOUT_TIMSEL(i) (SRCOUT_TIMSEL0 + (i))
+#define CTU_SVxxR(i, j) (CTU_SV00R + (i * 8) + (j))
+#define DVC_VOLxR(i) (DVC_VOL0R + (i))
+#define AUDIO_CLK_SEL(i) (AUDIO_CLK_SEL0 + (i))
+#define SSI_BUSIF_MODE(i) (SSI_BUSIF0_MODE + (i))
+#define SSI_BUSIF_ADINR(i) (SSI_BUSIF0_ADINR + (i))
+#define SSI_BUSIF_DALIGN(i) (SSI_BUSIF0_DALIGN + (i))
+#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i))
+
struct rsnd_priv;
struct rsnd_mod;
@@ -210,20 +220,9 @@ struct rsnd_dai_stream;
/*
* R-Car basic functions
*/
-#define rsnd_mod_read(m, r) \
- rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
-#define rsnd_mod_write(m, r, d) \
- rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
-#define rsnd_mod_bset(m, r, s, d) \
- rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
-
-u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
-void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 data);
-void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 data);
-void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
- u32 mask, u32 data);
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg);
+void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data);
+void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data);
u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
@@ -301,6 +300,12 @@ struct rsnd_mod_ops {
int (*cleanup)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv);
+ u32 *(*get_status)(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type);
+ int (*id)(struct rsnd_mod *mod);
+ int (*id_sub)(struct rsnd_mod *mod);
+ int (*id_cmd)(struct rsnd_mod *mod);
};
struct rsnd_dai_stream;
@@ -310,9 +315,6 @@ struct rsnd_mod {
struct rsnd_mod_ops *ops;
struct rsnd_priv *priv;
struct clk *clk;
- u32 *(*get_status)(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type);
u32 status;
};
/*
@@ -375,8 +377,6 @@ struct rsnd_mod {
#define __rsnd_mod_call_pointer 0
#define rsnd_mod_to_priv(mod) ((mod)->priv)
-#define rsnd_mod_name(mod) ((mod)->ops->name)
-#define rsnd_mod_id(mod) ((mod)->id)
#define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
#define rsnd_mod_power_off(mod) clk_disable((mod)->clk)
#define rsnd_mod_get(ip) (&(ip)->mod)
@@ -385,9 +385,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_mod_ops *ops,
struct clk *clk,
- u32* (*get_status)(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type),
enum rsnd_mod_type type,
int id);
void rsnd_mod_quit(struct rsnd_mod *mod);
@@ -396,9 +393,13 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
void rsnd_mod_interrupt(struct rsnd_mod *mod,
void (*callback)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io));
-u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
+u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
enum rsnd_mod_type type);
+int rsnd_mod_id(struct rsnd_mod *mod);
+int rsnd_mod_id_raw(struct rsnd_mod *mod);
+int rsnd_mod_id_sub(struct rsnd_mod *mod);
+char *rsnd_mod_name(struct rsnd_mod *mod);
struct rsnd_mod *rsnd_mod_next(int *iterator,
struct rsnd_dai_stream *io,
enum rsnd_mod_type *array,
@@ -430,8 +431,9 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
rsnd_runtime_channel_for_ssi_with_params(io, NULL)
int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
struct snd_pcm_hw_params *params);
-int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
-int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io);
/*
* DT
@@ -440,6 +442,7 @@ int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
#define RSND_NODE_DAI "rcar_sound,dai"
#define RSND_NODE_SSI "rcar_sound,ssi"
+#define RSND_NODE_SSIU "rcar_sound,ssiu"
#define RSND_NODE_SRC "rcar_sound,src"
#define RSND_NODE_CTU "rcar_sound,ctu"
#define RSND_NODE_MIX "rcar_sound,mix"
@@ -456,8 +459,17 @@ struct rsnd_dai_stream {
struct rsnd_mod *dma;
struct rsnd_dai *rdai;
struct device *dmac_dev; /* for IPMMU */
+ u32 converted_rate; /* converted sampling rate */
+ int converted_chan; /* converted channels */
u32 parent_ssi_status;
+ u32 flags;
};
+
+/* flags */
+#define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */
+#define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */
+#define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */
+
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU)
@@ -472,6 +484,8 @@ struct rsnd_dai_stream {
#define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io)
#define rsnd_io_to_runtime(io) ((io)->substream ? \
(io)->substream->runtime : NULL)
+#define rsnd_io_converted_rate(io) ((io)->converted_rate)
+#define rsnd_io_converted_chan(io) ((io)->converted_chan)
int rsnd_io_is_working(struct rsnd_dai_stream *io);
struct rsnd_dai {
@@ -712,18 +726,9 @@ extern const char * const volume_ramp_rate[];
int rsnd_ssi_probe(struct rsnd_priv *priv);
void rsnd_ssi_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
-int rsnd_ssi_get_busif(struct rsnd_dai_stream *io);
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
-#define RSND_SSI_HDMI_PORT0 0xf0
-#define RSND_SSI_HDMI_PORT1 0xf1
-int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io);
-void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
- struct device_node *endpoint,
- int dai_i);
-
#define rsnd_ssi_is_pin_sharing(io) \
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
@@ -742,6 +747,10 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
struct rsnd_mod *mod);
int rsnd_ssiu_probe(struct rsnd_priv *priv);
void rsnd_ssiu_remove(struct rsnd_priv *priv);
+void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
+ struct device_node *playback,
+ struct device_node *capture);
+#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU)
/*
* R-Car SRC
@@ -767,7 +776,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
*/
int rsnd_ctu_probe(struct rsnd_priv *priv);
void rsnd_ctu_remove(struct rsnd_priv *priv);
-int rsnd_ctu_converted_channel(struct rsnd_mod *mod);
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
#define rsnd_parse_connect_ctu(rdai, playback, capture) \
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index cd38a43b976f..50348a2c9203 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -25,7 +25,6 @@ struct rsnd_src {
struct rsnd_mod *dma;
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
struct rsnd_kctrl_cfg_s sync; /* sync convert */
- u32 convert_rate; /* sampling rate convert */
int irq;
};
@@ -89,12 +88,12 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
return 0;
if (!rsnd_src_sync_is_enabled(mod))
- return src->convert_rate;
+ return rsnd_io_converted_rate(io);
convert_rate = src->sync.val;
if (!convert_rate)
- convert_rate = src->convert_rate;
+ convert_rate = rsnd_io_converted_rate(io);
if (!convert_rate)
convert_rate = runtime->rate;
@@ -135,40 +134,6 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
return rate;
}
-static int rsnd_src_hw_params(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *fe_params)
-{
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- struct snd_soc_pcm_runtime *fe = substream->private_data;
-
- /*
- * SRC assumes that it is used under DPCM if user want to use
- * sampling rate convert. Then, SRC should be FE.
- * And then, this function will be called *after* BE settings.
- * this means, each BE already has fixuped hw_params.
- * see
- * dpcm_fe_dai_hw_params()
- * dpcm_be_dai_hw_params()
- */
- src->convert_rate = 0;
- if (fe->dai_link->dynamic) {
- int stream = substream->stream;
- struct snd_soc_dpcm *dpcm;
- struct snd_pcm_hw_params *be_params;
-
- for_each_dpcm_be(fe, stream, dpcm) {
- be_params = &dpcm->hw_params;
-
- if (params_rate(fe_params) != params_rate(be_params))
- src->convert_rate = params_rate(be_params);
- }
- }
-
- return 0;
-}
-
static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
@@ -349,9 +314,8 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0);
status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1);
if ((status0 & val0) || (status1 & val1)) {
- rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x, 0x%08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod),
- status0, status1);
+ rsnd_dbg_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n",
+ rsnd_mod_name(mod), status0, status1);
ret = true;
}
@@ -527,16 +491,16 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_src_ops = {
- .name = SRC_NAME,
- .dma_req = rsnd_src_dma_req,
- .probe = rsnd_src_probe_,
- .init = rsnd_src_init,
- .quit = rsnd_src_quit,
- .start = rsnd_src_start,
- .stop = rsnd_src_stop,
- .irq = rsnd_src_irq,
- .hw_params = rsnd_src_hw_params,
- .pcm_new = rsnd_src_pcm_new,
+ .name = SRC_NAME,
+ .dma_req = rsnd_src_dma_req,
+ .probe = rsnd_src_probe_,
+ .init = rsnd_src_init,
+ .quit = rsnd_src_quit,
+ .start = rsnd_src_start,
+ .stop = rsnd_src_stop,
+ .irq = rsnd_src_irq,
+ .pcm_new = rsnd_src_pcm_new,
+ .get_status = rsnd_mod_get_status,
};
struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
@@ -605,8 +569,7 @@ int rsnd_src_probe(struct rsnd_priv *priv)
}
ret = rsnd_mod_init(priv, rsnd_mod_get(src),
- &rsnd_src_ops, clk, rsnd_mod_get_status,
- RSND_MOD_SRC, i);
+ &rsnd_src_ops, clk, RSND_MOD_SRC, i);
if (ret) {
of_node_put(np);
goto rsnd_src_probe_done;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 6ec78f3096dd..45ef295743ec 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -99,9 +99,7 @@ struct rsnd_ssi {
/* flags */
#define RSND_SSI_CLK_PIN_SHARE (1 << 0)
#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */
-#define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */
-#define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */
-#define RSND_SSI_PROBED (1 << 4)
+#define RSND_SSI_PROBED (1 << 2)
#define for_each_rsnd_ssi(pos, priv, i) \
for (i = 0; \
@@ -119,19 +117,7 @@ struct rsnd_ssi {
(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
-int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
-{
- struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
- if (rsnd_flags_has(ssi, RSND_SSI_HDMI0))
- return RSND_SSI_HDMI_PORT0;
-
- if (rsnd_flags_has(ssi, RSND_SSI_HDMI1))
- return RSND_SSI_HDMI_PORT1;
-
- return 0;
-}
+static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
{
@@ -150,11 +136,6 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
return use_busif;
}
-int rsnd_ssi_get_busif(struct rsnd_dai_stream *io)
-{
- return 0; /* BUSIF0 only for now */
-}
-
static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, SSISR, 0);
@@ -181,8 +162,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
udelay(5);
}
- dev_warn(dev, "%s[%d] status check failed\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod));
}
static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io)
@@ -224,7 +204,7 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
{
- if (rsnd_runtime_is_ssi_multi(io))
+ if (rsnd_runtime_is_multi_ssi(io))
return rsnd_ssi_multi_slaves(io);
return 0;
@@ -320,6 +300,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return 0;
}
+ if (rsnd_runtime_is_tdm_split(io))
+ chan = rsnd_io_converted_chan(io);
+
main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
if (!main_rate) {
dev_err(dev, "unsupported clock rate\n");
@@ -346,9 +329,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
ssi->rate = rate;
ssi->chan = chan;
- dev_dbg(dev, "%s[%d] outputs %u Hz\n",
- rsnd_mod_name(mod),
- rsnd_mod_id(mod), rate);
+ dev_dbg(dev, "%s outputs %d chan %u Hz\n",
+ rsnd_mod_name(mod), chan, rate);
return 0;
}
@@ -379,14 +361,23 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device *dev = rsnd_priv_to_dev(priv);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
u32 cr_own = ssi->cr_own;
u32 cr_mode = ssi->cr_mode;
u32 wsr = ssi->wsr;
- int is_tdm;
+ int width;
+ int is_tdm, is_tdm_split;
+
+ is_tdm = rsnd_runtime_is_tdm(io);
+ is_tdm_split = rsnd_runtime_is_tdm_split(io);
- is_tdm = rsnd_runtime_is_ssi_tdm(io);
+ if (is_tdm)
+ dev_dbg(dev, "TDM mode\n");
+ if (is_tdm_split)
+ dev_dbg(dev, "TDM Split mode\n");
cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
@@ -405,7 +396,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
* rsnd_ssiu_init_gen2()
*/
wsr = ssi->wsr;
- if (is_tdm) {
+ if (is_tdm || is_tdm_split) {
wsr |= WS_MODE;
cr_own |= CHNL_8;
}
@@ -421,7 +412,18 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_own |= TRMD;
cr_own &= ~DWL_MASK;
- switch (snd_pcm_format_width(runtime->format)) {
+ width = snd_pcm_format_width(runtime->format);
+ if (is_tdm_split) {
+ /*
+ * The SWL and DWL bits in SSICR should be fixed at 32-bit
+ * setting when TDM split mode.
+ * see datasheet
+ * Operation :: TDM Format Split Function (TDM Split Mode)
+ */
+ width = 32;
+ }
+
+ switch (width) {
case 8:
cr_own |= DWL_8;
break;
@@ -431,6 +433,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
case 24:
cr_own |= DWL_24;
break;
+ case 32:
+ cr_own |= DWL_32;
+ break;
}
if (rsnd_ssi_is_dma_mode(mod)) {
@@ -494,8 +499,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
return 0;
if (!ssi->usrcnt) {
- dev_err(dev, "%s[%d] usrcnt error\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod));
return -EIO;
}
@@ -654,8 +658,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
/* DMA only */
if (is_dma && (status & (UIRQ | OIRQ))) {
- rsnd_dbg_irq_status(dev, "%s[%d] err status : 0x%08x\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), status);
+ rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n",
+ rsnd_mod_name(mod), status);
stop = true;
}
@@ -681,6 +685,41 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
+static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type)
+{
+ /*
+ * SSIP (= SSI parent) needs to be special, otherwise,
+ * 2nd SSI might doesn't start. see also rsnd_mod_call()
+ *
+ * We can't include parent SSI status on SSI, because we don't know
+ * how many SSI requests parent SSI. Thus, it is localed on "io" now.
+ * ex) trouble case
+ * Playback: SSI0
+ * Capture : SSI1 (needs SSI0)
+ *
+ * 1) start Capture -> SSI0/SSI1 are started.
+ * 2) start Playback -> SSI0 doesn't work, because it is already
+ * marked as "started" on 1)
+ *
+ * OTOH, using each mod's status is good for MUX case.
+ * It doesn't need to start in 2nd start
+ * ex)
+ * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
+ * |
+ * IO-1: SRC1 -> CTU2 -+
+ *
+ * 1) start IO-0 -> start SSI0
+ * 2) start IO-1 -> SSI0 doesn't need to start, because it is
+ * already started on 1)
+ */
+ if (type == RSND_MOD_SSIP)
+ return &io->parent_ssi_status;
+
+ return rsnd_mod_get_status(mod, io, type);
+}
+
/*
* SSI PIO
*/
@@ -730,7 +769,7 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- int ret;
+ int ret = 0;
/*
* SSIP/SSIU/IRQ are not needed on
@@ -744,10 +783,6 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
* see rsnd_ssi_pcm_new()
*/
- ret = rsnd_ssiu_attach(io, mod);
- if (ret < 0)
- return ret;
-
/*
* SSI might be called again as PIO fallback
* It is easy to manual handling for IRQ request/free
@@ -876,18 +911,19 @@ static int rsnd_ssi_prepare(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
- .name = SSI_NAME,
- .probe = rsnd_ssi_common_probe,
- .remove = rsnd_ssi_common_remove,
- .init = rsnd_ssi_pio_init,
- .quit = rsnd_ssi_quit,
- .start = rsnd_ssi_start,
- .stop = rsnd_ssi_stop,
- .irq = rsnd_ssi_irq,
- .pointer = rsnd_ssi_pio_pointer,
- .pcm_new = rsnd_ssi_pcm_new,
- .hw_params = rsnd_ssi_hw_params,
- .prepare = rsnd_ssi_prepare,
+ .name = SSI_NAME,
+ .probe = rsnd_ssi_common_probe,
+ .remove = rsnd_ssi_common_remove,
+ .init = rsnd_ssi_pio_init,
+ .quit = rsnd_ssi_quit,
+ .start = rsnd_ssi_start,
+ .stop = rsnd_ssi_stop,
+ .irq = rsnd_ssi_irq,
+ .pointer = rsnd_ssi_pio_pointer,
+ .pcm_new = rsnd_ssi_pcm_new,
+ .hw_params = rsnd_ssi_hw_params,
+ .prepare = rsnd_ssi_prepare,
+ .get_status = rsnd_ssi_get_status,
};
static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
@@ -928,8 +964,7 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod,
*/
mod->ops = &rsnd_ssi_pio_ops;
- dev_info(dev, "%s[%d] fallback to PIO mode\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
+ dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod));
return 0;
}
@@ -941,6 +976,17 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
int is_play = rsnd_io_is_play(io);
char *name;
+ /*
+ * It should use "rcar_sound,ssiu" on DT.
+ * But, we need to keep compatibility for old version.
+ *
+ * If it has "rcar_sound.ssiu", it will be used.
+ * If not, "rcar_sound.ssi" will be used.
+ * see
+ * rsnd_ssiu_dma_req()
+ * rsnd_dma_of_path()
+ */
+
if (rsnd_ssi_use_busif(io))
name = is_play ? "rxu" : "txu";
else
@@ -951,27 +997,27 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
}
static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
- .name = SSI_NAME,
- .dma_req = rsnd_ssi_dma_req,
- .probe = rsnd_ssi_dma_probe,
- .remove = rsnd_ssi_common_remove,
- .init = rsnd_ssi_init,
- .quit = rsnd_ssi_quit,
- .start = rsnd_ssi_start,
- .stop = rsnd_ssi_stop,
- .irq = rsnd_ssi_irq,
- .pcm_new = rsnd_ssi_pcm_new,
- .fallback = rsnd_ssi_fallback,
- .hw_params = rsnd_ssi_hw_params,
- .prepare = rsnd_ssi_prepare,
+ .name = SSI_NAME,
+ .dma_req = rsnd_ssi_dma_req,
+ .probe = rsnd_ssi_dma_probe,
+ .remove = rsnd_ssi_common_remove,
+ .init = rsnd_ssi_init,
+ .quit = rsnd_ssi_quit,
+ .start = rsnd_ssi_start,
+ .stop = rsnd_ssi_stop,
+ .irq = rsnd_ssi_irq,
+ .pcm_new = rsnd_ssi_pcm_new,
+ .fallback = rsnd_ssi_fallback,
+ .hw_params = rsnd_ssi_hw_params,
+ .prepare = rsnd_ssi_prepare,
+ .get_status = rsnd_ssi_get_status,
};
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
+static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
{
return mod->ops == &rsnd_ssi_dma_ops;
}
-
/*
* ssi mod function
*/
@@ -1027,54 +1073,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
of_node_put(node);
}
-static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
- struct rsnd_dai_stream *io,
- struct device_node *remote_ep)
-{
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
- struct rsnd_ssi *ssi;
- struct device_node *remote_node = of_graph_get_port_parent(remote_ep);
-
- /* support Gen3 only */
- if (!rsnd_is_gen3(priv))
- return;
-
- if (!mod)
- return;
-
- ssi = rsnd_mod_to_ssi(mod);
-
- /* HDMI0 */
- if (strstr(remote_node->full_name, "hdmi@fead0000")) {
- rsnd_flags_set(ssi, RSND_SSI_HDMI0);
- dev_dbg(dev, "%s[%d] connected to HDMI0\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
- }
-
- /* HDMI1 */
- if (strstr(remote_node->full_name, "hdmi@feae0000")) {
- rsnd_flags_set(ssi, RSND_SSI_HDMI1);
- dev_dbg(dev, "%s[%d] connected to HDMI1\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
- }
-}
-
-void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
- struct device_node *endpoint,
- int dai_i)
-{
- struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
- struct device_node *remote_ep;
-
- remote_ep = of_graph_get_remote_endpoint(endpoint);
- if (!remote_ep)
- return;
-
- __rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep);
- __rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture, remote_ep);
-}
-
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
{
if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
@@ -1091,41 +1089,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE));
}
-static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type)
-{
- /*
- * SSIP (= SSI parent) needs to be special, otherwise,
- * 2nd SSI might doesn't start. see also rsnd_mod_call()
- *
- * We can't include parent SSI status on SSI, because we don't know
- * how many SSI requests parent SSI. Thus, it is localed on "io" now.
- * ex) trouble case
- * Playback: SSI0
- * Capture : SSI1 (needs SSI0)
- *
- * 1) start Capture -> SSI0/SSI1 are started.
- * 2) start Playback -> SSI0 doesn't work, because it is already
- * marked as "started" on 1)
- *
- * OTOH, using each mod's status is good for MUX case.
- * It doesn't need to start in 2nd start
- * ex)
- * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
- * |
- * IO-1: SRC1 -> CTU2 -+
- *
- * 1) start IO-0 -> start SSI0
- * 2) start IO-1 -> SSI0 doesn't need to start, because it is
- * already started on 1)
- */
- if (type == RSND_MOD_SSIP)
- return &io->parent_ssi_status;
-
- return rsnd_mod_get_status(io, mod, type);
-}
-
int rsnd_ssi_probe(struct rsnd_priv *priv)
{
struct device_node *node;
@@ -1192,7 +1155,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
ops = &rsnd_ssi_dma_ops;
ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
- rsnd_ssi_get_status, RSND_MOD_SSI, i);
+ RSND_MOD_SSI, i);
if (ret) {
of_node_put(np);
goto rsnd_ssi_probe_done;
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 39b67643b5dc..c5934adcfd01 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -12,8 +12,14 @@ struct rsnd_ssiu {
struct rsnd_mod mod;
u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
unsigned int usrcnt;
+ int id;
+ int id_sub;
};
+/* SSI_MODE */
+#define TDM_EXT (1 << 0)
+#define TDM_SPLIT (1 << 8)
+
#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
#define for_each_rsnd_ssiu(pos, priv, i) \
@@ -22,6 +28,33 @@ struct rsnd_ssiu {
((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
i++)
+/*
+ * SSI Gen2 Gen3
+ * 0 BUSIF0-3 BUSIF0-7
+ * 1 BUSIF0-3 BUSIF0-7
+ * 2 BUSIF0-3 BUSIF0-7
+ * 3 BUSIF0 BUSIF0-7
+ * 4 BUSIF0 BUSIF0-7
+ * 5 BUSIF0 BUSIF0
+ * 6 BUSIF0 BUSIF0
+ * 7 BUSIF0 BUSIF0
+ * 8 BUSIF0 BUSIF0
+ * 9 BUSIF0-3 BUSIF0-7
+ * total 22 52
+ */
+static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 };
+static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
+
+static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type)
+{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+ int busif = rsnd_mod_id_sub(mod);
+
+ return &ssiu->busif_status[busif];
+}
+
static int rsnd_ssiu_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -32,6 +65,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
int id = rsnd_mod_id(mod);
u32 mask1, val1;
u32 mask2, val2;
+ int i;
/* clear status */
switch (id) {
@@ -40,16 +74,12 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
case 2:
case 3:
case 4:
- rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4));
- rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4));
- rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4));
- rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4));
+ for (i = 0; i < 4; i++)
+ rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
break;
case 9:
- rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4);
- rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4);
- rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4);
- rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4);
+ for (i = 0; i < 4; i++)
+ rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << (id * 4));
break;
}
@@ -115,8 +145,9 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
}
static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
- .name = SSIU_NAME,
- .init = rsnd_ssiu_init,
+ .name = SSIU_NAME,
+ .init = rsnd_ssiu_init,
+ .get_status = rsnd_ssiu_get_status,
};
static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
@@ -124,7 +155,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
- int hdmi = rsnd_ssi_hdmi_port(io);
+ u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
+ u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
int ret;
u32 mode = 0;
@@ -134,20 +166,21 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
ssiu->usrcnt++;
- if (rsnd_runtime_is_ssi_tdm(io)) {
- /*
- * TDM Extend Mode
- * see
- * rsnd_ssi_config_init()
- */
- mode = 0x1;
- }
+ /*
+ * TDM Extend/Split Mode
+ * see
+ * rsnd_ssi_config_init()
+ */
+ if (rsnd_runtime_is_tdm(io))
+ mode = TDM_EXT;
+ else if (rsnd_runtime_is_tdm_split(io))
+ mode = TDM_SPLIT;
rsnd_mod_write(mod, SSI_MODE, mode);
if (rsnd_ssi_use_busif(io)) {
int id = rsnd_mod_id(mod);
- int busif = rsnd_ssi_get_busif(io);
+ int busif = rsnd_mod_id_sub(mod);
/*
* FIXME
@@ -162,46 +195,18 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
id, busif);
}
-#define RSND_WRITE_BUSIF(i) \
- rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR, \
- rsnd_get_adinr_bit(mod, io) | \
- (rsnd_io_is_play(io) ? \
- rsnd_runtime_channel_after_ctu(io) : \
- rsnd_runtime_channel_original(io))); \
- rsnd_mod_write(mod, SSI_BUSIF##i##_MODE, \
- rsnd_get_busif_shift(io, mod) | 1); \
- rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN, \
- rsnd_get_dalign(mod, io))
-
- switch (busif) {
- case 0:
- RSND_WRITE_BUSIF(0);
- break;
- case 1:
- RSND_WRITE_BUSIF(1);
- break;
- case 2:
- RSND_WRITE_BUSIF(2);
- break;
- case 3:
- RSND_WRITE_BUSIF(3);
- break;
- case 4:
- RSND_WRITE_BUSIF(4);
- break;
- case 5:
- RSND_WRITE_BUSIF(5);
- break;
- case 6:
- RSND_WRITE_BUSIF(6);
- break;
- case 7:
- RSND_WRITE_BUSIF(7);
- break;
- }
+ rsnd_mod_write(mod, SSI_BUSIF_ADINR(busif),
+ rsnd_get_adinr_bit(mod, io) |
+ (rsnd_io_is_play(io) ?
+ rsnd_runtime_channel_after_ctu(io) :
+ rsnd_runtime_channel_original(io)));
+ rsnd_mod_write(mod, SSI_BUSIF_MODE(busif),
+ rsnd_get_busif_shift(io, mod) | 1);
+ rsnd_mod_write(mod, SSI_BUSIF_DALIGN(busif),
+ rsnd_get_dalign(mod, io));
}
- if (hdmi) {
+ if (has_hdmi0 || has_hdmi1) {
enum rsnd_mod_type rsnd_ssi_array[] = {
RSND_MOD_SSIM1,
RSND_MOD_SSIM2,
@@ -227,14 +232,10 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
rsnd_mod_id(pos) << shift;
}
- switch (hdmi) {
- case RSND_SSI_HDMI_PORT0:
+ if (has_hdmi0)
rsnd_mod_write(mod, HDMI0_SEL, val);
- break;
- case RSND_SSI_HDMI_PORT1:
+ if (has_hdmi1)
rsnd_mod_write(mod, HDMI1_SEL, val);
- break;
- }
}
return 0;
@@ -244,7 +245,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- int busif = rsnd_ssi_get_busif(io);
+ int busif = rsnd_mod_id_sub(mod);
if (!rsnd_ssi_use_busif(io))
return 0;
@@ -262,7 +263,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
- int busif = rsnd_ssi_get_busif(io);
+ int busif = rsnd_mod_id_sub(mod);
if (!rsnd_ssi_use_busif(io))
return 0;
@@ -278,11 +279,53 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
return 0;
}
+static int rsnd_ssiu_id(struct rsnd_mod *mod)
+{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+
+ /* see rsnd_ssiu_probe() */
+ return ssiu->id;
+}
+
+static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
+{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+
+ /* see rsnd_ssiu_probe() */
+ return ssiu->id_sub;
+}
+
+static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ int is_play = rsnd_io_is_play(io);
+ char *name;
+
+ /*
+ * It should use "rcar_sound,ssiu" on DT.
+ * But, we need to keep compatibility for old version.
+ *
+ * If it has "rcar_sound.ssiu", it will be used.
+ * If not, "rcar_sound.ssi" will be used.
+ * see
+ * rsnd_ssi_dma_req()
+ * rsnd_dma_of_path()
+ */
+
+ name = is_play ? "rx" : "tx";
+
+ return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
+ mod, name);
+}
+
static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
- .name = SSIU_NAME,
- .init = rsnd_ssiu_init_gen2,
- .start = rsnd_ssiu_start_gen2,
- .stop = rsnd_ssiu_stop_gen2,
+ .name = SSIU_NAME,
+ .dma_req = rsnd_ssiu_dma_req,
+ .init = rsnd_ssiu_init_gen2,
+ .start = rsnd_ssiu_start_gen2,
+ .stop = rsnd_ssiu_stop_gen2,
+ .get_status = rsnd_ssiu_get_status,
};
static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
@@ -293,36 +336,85 @@ static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
}
-int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
- struct rsnd_mod *ssi_mod)
+static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
+ struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_io_to_priv(io);
- struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
+ struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+ struct rsnd_mod *mod;
+ struct rsnd_ssiu *ssiu;
+ int i;
- rsnd_mod_confirm_ssi(ssi_mod);
+ if (!ssi_mod)
+ return;
- return rsnd_dai_connect(mod, io, mod->type);
+ /* select BUSIF0 */
+ for_each_rsnd_ssiu(ssiu, priv, i) {
+ mod = rsnd_mod_get(ssiu);
+
+ if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
+ (rsnd_mod_id_sub(mod) == 0)) {
+ rsnd_dai_connect(mod, io, mod->type);
+ return;
+ }
+ }
}
-static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io,
- struct rsnd_mod *mod,
- enum rsnd_mod_type type)
+void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
+ struct device_node *playback,
+ struct device_node *capture)
{
- struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
- int busif = rsnd_ssi_get_busif(io);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device_node *node = rsnd_ssiu_of_node(priv);
+ struct device_node *np;
+ struct rsnd_mod *mod;
+ struct rsnd_dai_stream *io_p = &rdai->playback;
+ struct rsnd_dai_stream *io_c = &rdai->capture;
+ int i;
- return &ssiu->busif_status[busif];
+ /* use rcar_sound,ssiu if exist */
+ if (node) {
+ i = 0;
+ for_each_child_of_node(node, np) {
+ mod = rsnd_ssiu_mod_get(priv, i);
+ if (np == playback)
+ rsnd_dai_connect(mod, io_p, mod->type);
+ if (np == capture)
+ rsnd_dai_connect(mod, io_c, mod->type);
+ i++;
+ }
+
+ of_node_put(node);
+ }
+
+ /* Keep DT compatibility */
+ if (!rsnd_io_to_mod_ssiu(io_p))
+ rsnd_parse_connect_ssiu_compatible(priv, io_p);
+ if (!rsnd_io_to_mod_ssiu(io_c))
+ rsnd_parse_connect_ssiu_compatible(priv, io_c);
}
int rsnd_ssiu_probe(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *node;
struct rsnd_ssiu *ssiu;
struct rsnd_mod_ops *ops;
+ const int *list = NULL;
int i, nr, ret;
- /* same number to SSI */
- nr = priv->ssi_nr;
+ /*
+ * Keep DT compatibility.
+ * if it has "rcar_sound,ssiu", use it.
+ * if not, use "rcar_sound,ssi"
+ * see
+ * rsnd_ssiu_bufsif_to_id()
+ */
+ node = rsnd_ssiu_of_node(priv);
+ if (node)
+ nr = of_get_child_count(node);
+ else
+ nr = priv->ssi_nr;
+
ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
if (!ssiu)
return -ENOMEM;
@@ -335,10 +427,46 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
else
ops = &rsnd_ssiu_ops_gen2;
+ /* Keep compatibility */
+ nr = 0;
+ if ((node) &&
+ (ops == &rsnd_ssiu_ops_gen2)) {
+ ops->id = rsnd_ssiu_id;
+ ops->id_sub = rsnd_ssiu_id_sub;
+
+ if (rsnd_is_gen2(priv)) {
+ list = gen2_id;
+ nr = ARRAY_SIZE(gen2_id);
+ } else if (rsnd_is_gen3(priv)) {
+ list = gen3_id;
+ nr = ARRAY_SIZE(gen3_id);
+ } else {
+ dev_err(dev, "unknown SSIU\n");
+ return -ENODEV;
+ }
+ }
+
for_each_rsnd_ssiu(ssiu, priv, i) {
+ if (node) {
+ int j;
+
+ /*
+ * see
+ * rsnd_ssiu_get_id()
+ * rsnd_ssiu_get_id_sub()
+ */
+ for (j = 0; j < nr; j++) {
+ if (list[j] > i)
+ break;
+ ssiu->id = j;
+ ssiu->id_sub = i - list[ssiu->id];
+ }
+ } else {
+ ssiu->id = i;
+ }
+
ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
- ops, NULL, rsnd_ssiu_get_status,
- RSND_MOD_SSIU, i);
+ ops, NULL, RSND_MOD_SSIU, i);
if (ret)
return ret;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index b29d0f65611e..0462b3ec977a 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1467,7 +1467,7 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
for (i = 0; i < num_dais; ++i) {
struct snd_soc_dai_driver *drv = dais[i]->driver;
- if (!rtd->dai_link->no_pcm && drv->pcm_new)
+ if (drv->pcm_new)
ret = drv->pcm_new(rtd, dais[i]);
if (ret < 0) {
dev_err(dais[i]->dev,
@@ -3485,12 +3485,11 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
-void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
- struct snd_soc_codec_conf *codec_conf,
- struct device_node *of_node,
- const char *propname)
+void snd_soc_of_parse_node_prefix(struct device_node *np,
+ struct snd_soc_codec_conf *codec_conf,
+ struct device_node *of_node,
+ const char *propname)
{
- struct device_node *np = card->dev->of_node;
const char *str;
int ret;
@@ -3503,7 +3502,7 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
codec_conf->of_node = of_node;
codec_conf->name_prefix = str;
}
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix);
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname)
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index d597eba61992..bcb35cae2a2c 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -74,14 +74,14 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
return ret;
}
- dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
- sai->pdev->dev.of_node->name,
+ dev_dbg(&sai->pdev->dev, "Set %pOFn%s as synchro provider\n",
+ sai->pdev->dev.of_node,
synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
- dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
- sai->pdev->dev.of_node->name,
+ dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n",
+ sai->pdev->dev.of_node,
prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
clk_disable_unprepare(sai->pclk);
return -EINVAL;
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 211589b0b2ef..d4825700b63f 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -336,8 +336,7 @@ static int stm32_sai_mclk_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct stm32_sai_mclk_data *mclk = to_mclk_data(hw);
struct stm32_sai_sub_data *sai = mclk->sai_data;
- unsigned int div;
- int ret;
+ int div, ret;
div = stm32_sai_get_clk_div(sai, parent_rate, rate);
if (div < 0)
diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c
index 8f5f999df631..df1fed0aa001 100644
--- a/sound/soc/sunxi/sun50i-codec-analog.c
+++ b/sound/soc/sunxi/sun50i-codec-analog.c
@@ -274,6 +274,7 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
* stream widgets at the card level.
*/
+ SND_SOC_DAPM_REGULATOR_SUPPLY("hpvcc", 0, 0),
SND_SOC_DAPM_MUX("Headphone Source Playback Route",
SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL,
@@ -361,6 +362,7 @@ static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
{ "Headphone Source Playback Route", "Mixer", "Left Mixer" },
{ "Headphone Source Playback Route", "Mixer", "Right Mixer" },
{ "Headphone Amp", NULL, "Headphone Source Playback Route" },
+ { "Headphone Amp", NULL, "hpvcc" },
{ "HP", NULL, "Headphone Amp" },
/* Microphone Routes */
diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig
new file mode 100644
index 000000000000..4bf3c15d4e51
--- /dev/null
+++ b/sound/soc/ti/Kconfig
@@ -0,0 +1,209 @@
+menu "Audio support for Texas Instruments SoCs"
+depends on DMA_OMAP || TI_EDMA || COMPILE_TEST
+
+config SND_SOC_TI_EDMA_PCM
+ tristate
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+
+config SND_SOC_TI_SDMA_PCM
+ tristate
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+
+comment "Texas Instruments DAI support for:"
+config SND_SOC_DAVINCI_ASP
+ tristate "daVinci Audio Serial Port (ASP) or McBSP suport"
+ depends on ARCH_DAVINCI || COMPILE_TEST
+ select SND_SOC_TI_EDMA_PCM
+ help
+ Say Y or M here if you want audio support via daVinci ASP or McBSP.
+ The driver only implements the ASP support which is a subset of
+ daVinci McBSP (w/o the multichannel support).
+
+config SND_SOC_DAVINCI_MCASP
+ tristate "Multichannel Audio Serial Port (McASP) support"
+ select SND_SOC_TI_EDMA_PCM if TI_EDMA
+ select SND_SOC_TI_SDMA_PCM if DMA_OMAP
+ help
+ Say Y or M here if you want to have support for McASP IP found in
+ various Texas Instruments SoCs like:
+ - daVinci devices
+ - Sitara line of SoCs (AM335x, AM438x, etc)
+ - DRA7x devices
+ - Keystone devices
+
+config SND_SOC_DAVINCI_VCIF
+ tristate "daVinci Voice Interface (VCIF) suport"
+ depends on ARCH_DAVINCI || COMPILE_TEST
+ select SND_SOC_TI_EDMA_PCM
+ help
+ Say Y or M here if you want audio support via daVinci VCIF.
+
+config SND_SOC_OMAP_DMIC
+ tristate "Digital Microphone Module (DMIC) support"
+ depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST
+ select SND_SOC_TI_SDMA_PCM
+ help
+ Say Y or M here if you want to have support for DMIC IP found in
+ OMAP4 and OMAP5.
+
+config SND_SOC_OMAP_MCBSP
+ tristate "Multichannel Buffered Serial Port (McBSP) support"
+ depends on ARCH_OMAP || ARCH_OMAP1 || COMPILE_TEST
+ select SND_SOC_TI_SDMA_PCM
+ help
+ Say Y or M here if you want to have support for McBSP IP found in
+ Texas Instruments OMAP1/2/3/4/5 SoCs.
+
+config SND_SOC_OMAP_MCPDM
+ tristate "Multichannel PDM Controller (McPDM) support"
+ depends on ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST
+ select SND_SOC_TI_SDMA_PCM
+ help
+ Say Y or M here if you want to have support for McPDM IP found in
+ OMAP4 and OMAP5.
+
+comment "Audio support for boards with Texas Instruments SoCs"
+config SND_SOC_NOKIA_N810
+ tristate "SoC Audio support for Nokia N810"
+ depends on MACH_NOKIA_N810 && I2C
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TLV320AIC3X
+ help
+ Say Y or M if you want to add support for SoC audio on Nokia N810.
+
+config SND_SOC_NOKIA_RX51
+ tristate "SoC Audio support for Nokia RX-51"
+ depends on ARCH_OMAP3 && I2C && GPIOLIB
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TLV320AIC3X
+ select SND_SOC_TPA6130A2
+ help
+ Say Y or M if you want to add support for SoC audio on Nokia RX-51
+ hardware. This is also known as Nokia N900 product.
+
+config SND_SOC_OMAP3_PANDORA
+ tristate "SoC Audio support for OMAP3 Pandora"
+ depends on ARCH_OMAP3
+ depends on TWL4030_CORE
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TWL4030
+ help
+ Say Y or M if you want to add support for SoC audio on the 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 TWL4030_CORE
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TWL4030
+ help
+ Say Y or M if you want to add support for SoC audio on OMAP3 based
+ boards using twl4030 as codec. This driver currently supports:
+ - Beagleboard or Devkit8000
+ - Gumstix Overo or CompuLab CM-T35/CM-T3730
+ - IGEP v2
+ - OMAP3EVM
+ - SDP3430
+ - Zoom2
+
+config SND_SOC_OMAP_ABE_TWL6040
+ tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
+ depends on TWL6040_CORE && COMMON_CLK
+ depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
+ select SND_SOC_OMAP_DMIC
+ select SND_SOC_OMAP_MCPDM
+ select SND_SOC_TWL6040
+ help
+ Say Y or M if you want to add support for SoC audio on OMAP boards
+ using ABE and twl6040 codec. This driver currently supports:
+ - SDP4430/Blaze boards
+ - PandaBoard (4430)
+ - PandaBoardES (4460)
+ - OMAP5 uEVM
+
+config SND_SOC_OMAP_AMS_DELTA
+ tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
+ depends on MACH_AMS_DELTA && TTY
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_CX20442
+ help
+ Say Y or M if you want to add support for SoC audio device
+ connected to a handset and a speakerphone found on Amstrad E3 (Delta)
+ videophone.
+
+ Note that in order to get those devices fully supported, you have to
+ build the kernel with standard serial port driver included and
+ configured for at least 4 ports. Then, from userspace, you must load
+ a line discipline #19 on the modem (ttyS3) serial line. The simplest
+ way to achieve this is to install util-linux-ng and use the included
+ ldattach utility. This can be started automatically from udev,
+ a simple rule like this one should do the trick (it does for me):
+ ACTION=="add", KERNEL=="controlC0", \
+ RUN+="/usr/sbin/ldattach 19 /dev/ttyS3"
+
+config SND_SOC_OMAP_HDMI
+ tristate "OMAP4/5 HDMI audio support"
+ depends on OMAP4_DSS_HDMI || OMAP5_DSS_HDMI || COMPILE_TEST
+ select SND_SOC_TI_SDMA_PCM
+ help
+ For HDMI audio to work OMAPDSS HDMI support should be
+ enabled.
+ The hdmi audio driver implements cpu-dai component using the
+ callbacks provided by OMAPDSS and registers the component
+ under DSS HDMI device. Omap-pcm is registered for platform
+ component also under DSS HDMI device. Dummy codec is used as
+ as codec component. The hdmi audio driver implements also
+ the card and registers it under its own platform device.
+ The device for the driver is registered by OMAPDSS hdmi
+ driver.
+
+config SND_SOC_OMAP_OSK5912
+ tristate "SoC Audio support for omap osk5912"
+ depends on MACH_OMAP_OSK && I2C
+ select SND_SOC_OMAP_MCBSP
+ select SND_SOC_TLV320AIC23_I2C
+ help
+ Say Y or M if you want to add support for SoC audio on osk5912.
+
+config SND_SOC_DAVINCI_EVM
+ tristate "SoC Audio support for DaVinci EVMs"
+ depends on ARCH_DAVINCI && I2C
+ select SND_SOC_DAVINCI_ASP if MACH_DAVINCI_DM355_EVM
+ select SND_SOC_DAVINCI_ASP if SND_SOC_DM365_AIC3X_CODEC
+ select SND_SOC_DAVINCI_VCIF if SND_SOC_DM365_VOICE_CODEC
+ select SND_SOC_DAVINCI_ASP if MACH_DAVINCI_EVM # DM6446
+ select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DM6467_EVM
+ select SND_SOC_SPDIF if MACH_DAVINCI_DM6467_EVM
+ select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DA830_EVM
+ select SND_SOC_DAVINCI_MCASP if MACH_DAVINCI_DA850_EVM
+ select SND_SOC_TLV320AIC3X
+ help
+ Say Y if you want to add support for SoC audio on the following TI
+ DaVinci EVM platforms:
+ - DM355
+ - DM365
+ - DM6446
+ - DM6447
+ - DM830
+ - DM850
+
+choice
+ prompt "DM365 codec select"
+ depends on SND_SOC_DAVINCI_EVM
+ depends on MACH_DAVINCI_DM365_EVM
+
+config SND_SOC_DM365_AIC3X_CODEC
+ bool "Audio Codec - AIC3101"
+ help
+ Say Y if you want to add support for AIC3101 audio codec
+
+config SND_SOC_DM365_VOICE_CODEC
+ bool "Voice Codec - CQ93VC"
+ select MFD_DAVINCI_VOICECODEC
+ select SND_SOC_CQ0093VC
+ help
+ Say Y if you want to add support for SoC On-chip voice codec
+endchoice
+
+endmenu
+
diff --git a/sound/soc/ti/Makefile b/sound/soc/ti/Makefile
new file mode 100644
index 000000000000..08c44d56ef3e
--- /dev/null
+++ b/sound/soc/ti/Makefile
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Platform drivers
+snd-soc-ti-edma-objs := edma-pcm.o
+snd-soc-ti-sdma-objs := sdma-pcm.o
+
+obj-$(CONFIG_SND_SOC_TI_EDMA_PCM) += snd-soc-ti-edma.o
+obj-$(CONFIG_SND_SOC_TI_SDMA_PCM) += snd-soc-ti-sdma.o
+
+# CPU DAI drivers
+snd-soc-davinci-asp-objs := davinci-i2s.o
+snd-soc-davinci-mcasp-objs := davinci-mcasp.o
+snd-soc-davinci-vcif-objs := davinci-vcif.o
+snd-soc-omap-dmic-objs := omap-dmic.o
+snd-soc-omap-mcbsp-objs := omap-mcbsp.o omap-mcbsp-st.o
+snd-soc-omap-mcpdm-objs := omap-mcpdm.o
+
+obj-$(CONFIG_SND_SOC_DAVINCI_ASP) += snd-soc-davinci-asp.o
+obj-$(CONFIG_SND_SOC_DAVINCI_MCASP) += snd-soc-davinci-mcasp.o
+obj-$(CONFIG_SND_SOC_DAVINCI_VCIF) += snd-soc-davinci-vcif.o
+obj-$(CONFIG_SND_SOC_OMAP_DMIC) += snd-soc-omap-dmic.o
+obj-$(CONFIG_SND_SOC_OMAP_MCBSP) += snd-soc-omap-mcbsp.o
+obj-$(CONFIG_SND_SOC_OMAP_MCPDM) += snd-soc-omap-mcpdm.o
+
+# Machine drivers
+snd-soc-davinci-evm-objs := davinci-evm.o
+snd-soc-n810-objs := n810.o
+snd-soc-rx51-objs := rx51.o
+snd-soc-omap3pandora-objs := omap3pandora.o
+snd-soc-omap-twl4030-objs := omap-twl4030.o
+snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
+snd-soc-ams-delta-objs := ams-delta.o
+snd-soc-omap-hdmi-objs := omap-hdmi.o
+snd-soc-osk5912-objs := osk5912.o
+
+obj-$(CONFIG_SND_SOC_DAVINCI_EVM) += snd-soc-davinci-evm.o
+obj-$(CONFIG_SND_SOC_NOKIA_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_SOC_NOKIA_RX51) += snd-soc-rx51.o
+obj-$(CONFIG_SND_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
+obj-$(CONFIG_SND_SOC_OMAP3_TWL4030) += snd-soc-omap-twl4030.o
+obj-$(CONFIG_SND_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
+obj-$(CONFIG_SND_SOC_OMAP_AMS_DELTA) += snd-soc-ams-delta.o
+obj-$(CONFIG_SND_SOC_OMAP_HDMI) += snd-soc-omap-hdmi.o
+obj-$(CONFIG_SND_SOC_OMAP_OSK5912) += snd-soc-osk5912.o
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/ti/ams-delta.c
index 4dce494dfbd3..4dce494dfbd3 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/ti/ams-delta.c
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/ti/davinci-evm.c
index 7a369e0f2093..4869d6311510 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/ti/davinci-evm.c
@@ -170,7 +170,7 @@ static struct snd_soc_dai_link dm355_evm_dai = {
};
static struct snd_soc_dai_link dm365_evm_dai = {
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
+#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.cpu_dai_name = "davinci-mcbsp",
@@ -181,7 +181,7 @@ static struct snd_soc_dai_link dm365_evm_dai = {
.ops = &evm_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
SND_SOC_DAIFMT_IB_NF,
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
+#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
.name = "Voice Codec - CQ93VC",
.stream_name = "CQ93",
.cpu_dai_name = "davinci-vcif",
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c
index a3206e65e5e5..a3206e65e5e5 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/ti/davinci-i2s.c
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/ti/davinci-i2s.h
index 48dac3e2521a..48dac3e2521a 100644
--- a/sound/soc/davinci/davinci-i2s.h
+++ b/sound/soc/ti/davinci-i2s.h
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 267aee776b2d..eeda6d5565bc 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -28,6 +28,7 @@
#include <linux/of_device.h>
#include <linux/platform_data/davinci_asp.h>
#include <linux/math64.h>
+#include <linux/bitmap.h>
#include <sound/asoundef.h>
#include <sound/core.h>
@@ -38,7 +39,7 @@
#include <sound/dmaengine_pcm.h>
#include "edma-pcm.h"
-#include "../omap/sdma-pcm.h"
+#include "sdma-pcm.h"
#include "davinci-mcasp.h"
#define MCASP_MAX_AFIFO_DEPTH 64
@@ -84,6 +85,7 @@ struct davinci_mcasp {
u32 tdm_mask[2];
int slot_width;
u8 op_mode;
+ u8 dismod;
u8 num_serializer;
u8 *serial_dir;
u8 version;
@@ -95,6 +97,8 @@ struct davinci_mcasp {
int sysclk_freq;
bool bclk_master;
+ unsigned long pdir; /* Pin direction bitfield */
+
/* McASP FIFO related */
u8 txnumevt;
u8 rxnumevt;
@@ -169,6 +173,30 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
}
+static inline void mcasp_set_clk_pdir(struct davinci_mcasp *mcasp, bool enable)
+{
+ u32 bit = PIN_BIT_AMUTE;
+
+ for_each_set_bit_from(bit, &mcasp->pdir, PIN_BIT_AFSR + 1) {
+ if (enable)
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+ else
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+ }
+}
+
+static inline void mcasp_set_axr_pdir(struct davinci_mcasp *mcasp, bool enable)
+{
+ u32 bit;
+
+ for_each_set_bit(bit, &mcasp->pdir, PIN_BIT_AFSR) {
+ if (enable)
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+ else
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(bit));
+ }
+}
+
static void mcasp_start_rx(struct davinci_mcasp *mcasp)
{
if (mcasp->rxnumevt) { /* enable FIFO */
@@ -192,6 +220,7 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
}
/* Activate serializer(s) */
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
/* Release RX state machine */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
@@ -219,7 +248,10 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
/* Start clocks */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+ mcasp_set_clk_pdir(mcasp, true);
+
/* Activate serializer(s) */
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
/* wait for XDATA to be cleared */
@@ -228,6 +260,8 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
(cnt < 100000))
cnt++;
+ mcasp_set_axr_pdir(mcasp, true);
+
/* Release TX state machine */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
/* Release Frame Sync generator */
@@ -258,8 +292,10 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
* In synchronous mode stop the TX clocks if no other stream is
* running
*/
- if (mcasp_is_synchronous(mcasp) && !mcasp->streams)
+ if (mcasp_is_synchronous(mcasp) && !mcasp->streams) {
+ mcasp_set_clk_pdir(mcasp, false);
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
+ }
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
@@ -285,6 +321,9 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
*/
if (mcasp_is_synchronous(mcasp) && mcasp->streams)
val = TXHCLKRST | TXCLKRST | TXFSRST;
+ else
+ mcasp_set_clk_pdir(mcasp, false);
+
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
@@ -294,6 +333,8 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
}
+
+ mcasp_set_axr_pdir(mcasp, false);
}
static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
@@ -444,8 +485,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ /* BCLK */
+ set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+ set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+ /* Frame Sync */
+ set_bit(PIN_BIT_AFSX, &mcasp->pdir);
+ set_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
mcasp->bclk_master = 1;
break;
case SND_SOC_DAIFMT_CBS_CFM:
@@ -456,8 +502,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ /* BCLK */
+ set_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+ set_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+ /* Frame Sync */
+ clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
+ clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
mcasp->bclk_master = 1;
break;
case SND_SOC_DAIFMT_CBM_CFS:
@@ -468,8 +519,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ /* BCLK */
+ clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+ clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+ /* Frame Sync */
+ set_bit(PIN_BIT_AFSX, &mcasp->pdir);
+ set_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
mcasp->bclk_master = 0;
break;
case SND_SOC_DAIFMT_CBM_CFM:
@@ -480,8 +536,13 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
- ACLKX | AFSX | ACLKR | AHCLKR | AFSR);
+ /* BCLK */
+ clear_bit(PIN_BIT_ACLKX, &mcasp->pdir);
+ clear_bit(PIN_BIT_ACLKR, &mcasp->pdir);
+ /* Frame Sync */
+ clear_bit(PIN_BIT_AFSX, &mcasp->pdir);
+ clear_bit(PIN_BIT_AFSR, &mcasp->pdir);
+
mcasp->bclk_master = 0;
break;
default:
@@ -596,11 +657,11 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
if (dir == SND_SOC_CLOCK_OUT) {
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
+ set_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
} else {
mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
+ clear_bit(PIN_BIT_AHCLKX, &mcasp->pdir);
}
mcasp->sysclk_freq = freq;
@@ -773,17 +834,23 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
mcasp->serial_dir[i]);
if (mcasp->serial_dir[i] == TX_MODE &&
tx_ser < max_active_serializers) {
- mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
- DISMOD_LOW, DISMOD_MASK);
+ mcasp->dismod, DISMOD_MASK);
+ set_bit(PIN_BIT_AXR(i), &mcasp->pdir);
tx_ser++;
} else if (mcasp->serial_dir[i] == RX_MODE &&
rx_ser < max_active_serializers) {
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
rx_ser++;
} else if (mcasp->serial_dir[i] == INACTIVE_MODE) {
mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
SRMOD_INACTIVE, SRMOD_MASK);
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
+ } else if (mcasp->serial_dir[i] == TX_MODE) {
+ /* Unused TX pins, clear PDIR */
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+ mcasp->dismod, DISMOD_MASK);
+ clear_bit(PIN_BIT_AXR(i), &mcasp->pdir);
}
}
@@ -1645,6 +1712,7 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
if (pdev->dev.platform_data) {
pdata = pdev->dev.platform_data;
+ pdata->dismod = DISMOD_LOW;
return pdata;
} else if (match) {
pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata),
@@ -1734,6 +1802,18 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
if (ret >= 0)
pdata->sram_size_capture = val;
+ ret = of_property_read_u32(np, "dismod", &val);
+ if (ret >= 0) {
+ if (val == 0 || val == 2 || val == 3) {
+ pdata->dismod = DISMOD_VAL(val);
+ } else {
+ dev_warn(&pdev->dev, "Invalid dismod value: %u\n", val);
+ pdata->dismod = DISMOD_LOW;
+ }
+ } else {
+ pdata->dismod = DISMOD_LOW;
+ }
+
return pdata;
nodata:
@@ -1909,6 +1989,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->version = pdata->version;
mcasp->txnumevt = pdata->txnumevt;
mcasp->rxnumevt = pdata->rxnumevt;
+ mcasp->dismod = pdata->dismod;
mcasp->dev = &pdev->dev;
@@ -2068,9 +2149,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
ret = davinci_mcasp_get_dma_type(mcasp);
switch (ret) {
case PCM_EDMA:
-#if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
- (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
- IS_MODULE(CONFIG_SND_EDMA_SOC))
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_EDMA_PCM) || \
+ (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
+ IS_MODULE(CONFIG_SND_SOC_TI_EDMA_PCM))
ret = edma_pcm_platform_register(&pdev->dev);
#else
dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n");
@@ -2079,9 +2160,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
#endif
break;
case PCM_SDMA:
-#if IS_BUILTIN(CONFIG_SND_SDMA_SOC) || \
- (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
- IS_MODULE(CONFIG_SND_SDMA_SOC))
+#if IS_BUILTIN(CONFIG_SND_SOC_TI_SDMA_PCM) || \
+ (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \
+ IS_MODULE(CONFIG_SND_SOC_TI_SDMA_PCM))
ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL);
#else
dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n");
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/ti/davinci-mcasp.h
index afddc8010c54..5e4060d8fe56 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/ti/davinci-mcasp.h
@@ -108,27 +108,18 @@
/*
* DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
- */
-#define AXR(n) (1<<n)
-#define PFUNC_AMUTE BIT(25)
-#define ACLKX BIT(26)
-#define AHCLKX BIT(27)
-#define AFSX BIT(28)
-#define ACLKR BIT(29)
-#define AHCLKR BIT(30)
-#define AFSR BIT(31)
-
-/*
* DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
+ * DAVINCI_MCASP_PDOUT_REG - Pin output in GPIO mode
+ * DAVINCI_MCASP_PDSET_REG - Pin input in GPIO mode
*/
-#define AXR(n) (1<<n)
-#define PDIR_AMUTE BIT(25)
-#define ACLKX BIT(26)
-#define AHCLKX BIT(27)
-#define AFSX BIT(28)
-#define ACLKR BIT(29)
-#define AHCLKR BIT(30)
-#define AFSR BIT(31)
+#define PIN_BIT_AXR(n) (n)
+#define PIN_BIT_AMUTE 25
+#define PIN_BIT_ACLKX 26
+#define PIN_BIT_AHCLKX 27
+#define PIN_BIT_AFSX 28
+#define PIN_BIT_ACLKR 29
+#define PIN_BIT_AHCLKR 30
+#define PIN_BIT_AFSR 31
/*
* DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
@@ -218,6 +209,7 @@
#define DISMOD_3STATE (0x0)
#define DISMOD_LOW (0x2 << 2)
#define DISMOD_HIGH (0x3 << 2)
+#define DISMOD_VAL(x) ((x) << 2)
#define DISMOD_MASK DISMOD_HIGH
#define TXSTATE BIT(4)
#define RXSTATE BIT(5)
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/ti/davinci-vcif.c
index 5415b72393fa..5415b72393fa 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/ti/davinci-vcif.c
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/ti/edma-pcm.c
index 59e588abe54b..59e588abe54b 100644
--- a/sound/soc/davinci/edma-pcm.c
+++ b/sound/soc/ti/edma-pcm.c
diff --git a/sound/soc/davinci/edma-pcm.h b/sound/soc/ti/edma-pcm.h
index b0957744851c..8058bdb0f032 100644
--- a/sound/soc/davinci/edma-pcm.h
+++ b/sound/soc/ti/edma-pcm.h
@@ -20,13 +20,13 @@
#ifndef __EDMA_PCM_H__
#define __EDMA_PCM_H__
-#if IS_ENABLED(CONFIG_SND_EDMA_SOC)
+#if IS_ENABLED(CONFIG_SND_SOC_TI_EDMA_PCM)
int edma_pcm_platform_register(struct device *dev);
#else
static inline int edma_pcm_platform_register(struct device *dev)
{
return 0;
}
-#endif /* CONFIG_SND_EDMA_SOC */
+#endif /* CONFIG_SND_SOC_TI_EDMA_PCM */
#endif /* __EDMA_PCM_H__ */
diff --git a/sound/soc/omap/n810.c b/sound/soc/ti/n810.c
index 9cfefe44a75f..9cfefe44a75f 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/ti/n810.c
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c
index fed45b41f9d3..fed45b41f9d3 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/ti/omap-abe-twl6040.c
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/ti/omap-dmic.c
index cba9645b6487..cba9645b6487 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/ti/omap-dmic.c
diff --git a/sound/soc/omap/omap-dmic.h b/sound/soc/ti/omap-dmic.h
index 231e728bff0e..231e728bff0e 100644
--- a/sound/soc/omap/omap-dmic.h
+++ b/sound/soc/ti/omap-dmic.h
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/ti/omap-hdmi.c
index 673a9eb153b2..673a9eb153b2 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/ti/omap-hdmi.c
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/ti/omap-mcbsp-priv.h
index 46ae1269a698..7865cda4bf0a 100644
--- a/sound/soc/omap/mcbsp.h
+++ b/sound/soc/ti/omap-mcbsp-priv.h
@@ -1,28 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * sound/soc/omap/mcbsp.h
- *
* OMAP Multi-Channel Buffered Serial Port
*
* Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
-#ifndef __ASOC_MCBSP_H
-#define __ASOC_MCBSP_H
+
+#ifndef __OMAP_MCBSP_PRIV_H__
+#define __OMAP_MCBSP_PRIV_H__
+
+#include <linux/platform_data/asoc-ti-mcbsp.h>
#ifdef CONFIG_ARCH_OMAP1
#define mcbsp_omap1() 1
@@ -30,8 +17,6 @@
#define mcbsp_omap1() 0
#endif
-#include <sound/dmaengine_pcm.h>
-
/* McBSP register numbers. Register address offset = num * reg_step */
enum {
/* Common registers */
@@ -85,15 +70,6 @@ enum {
OMAP_MCBSP_REG_SSELCR,
};
-/* OMAP3 sidetone control registers */
-#define OMAP_ST_REG_REV 0x00
-#define OMAP_ST_REG_SYSCONFIG 0x10
-#define OMAP_ST_REG_IRQSTATUS 0x18
-#define OMAP_ST_REG_IRQENABLE 0x1C
-#define OMAP_ST_REG_SGAINCR 0x24
-#define OMAP_ST_REG_SFIRCR 0x28
-#define OMAP_ST_REG_SSELCR 0x2C
-
/************************** McBSP SPCR1 bit definitions ***********************/
#define RRST BIT(0)
#define RRDY BIT(1)
@@ -202,24 +178,6 @@ enum {
#define SIDLEMODE(value) (((value) & 0x3) << 3)
#define CLOCKACTIVITY(value) (((value) & 0x3) << 8)
-/********************** McBSP SSELCR bit definitions ***********************/
-#define SIDETONEEN BIT(10)
-
-/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
-#define ST_AUTOIDLE BIT(0)
-
-/********************** McBSP Sidetone SGAINCR bit definitions *************/
-#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
-#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
-
-/********************** McBSP Sidetone SFIRCR bit definitions **************/
-#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
-
-/********************** McBSP Sidetone SSELCR bit definitions **************/
-#define ST_SIDETONEEN BIT(0)
-#define ST_COEFFWREN BIT(1)
-#define ST_COEFFWRDONE BIT(2)
-
/********************** McBSP DMA operating modes **************************/
#define MCBSP_DMA_MODE_ELEMENT 0
#define MCBSP_DMA_MODE_THRESHOLD 1
@@ -278,16 +236,7 @@ struct omap_mcbsp_reg_cfg {
u16 rccr;
};
-struct omap_mcbsp_st_data {
- void __iomem *io_base_st;
- struct clk *mcbsp_iclk;
- bool running;
- bool enabled;
- s16 taps[128]; /* Sidetone filter coefficients */
- int nr_taps; /* Number of filter coefficients in use */
- s16 ch0gain;
- s16 ch1gain;
-};
+struct omap_mcbsp_st_data;
struct omap_mcbsp {
struct device *dev;
@@ -330,29 +279,46 @@ struct omap_mcbsp {
struct pm_qos_request pm_qos_req;
};
-void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
- const struct omap_mcbsp_reg_cfg *config);
-void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
-void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold);
-u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp);
-u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp);
-int omap_mcbsp_get_dma_op_mode(struct omap_mcbsp *mcbsp);
-int omap_mcbsp_request(struct omap_mcbsp *mcbsp);
-void omap_mcbsp_free(struct omap_mcbsp *mcbsp);
-void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int tx, int rx);
-void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx);
-
-/* McBSP functional clock source changing function */
-int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id);
+static inline void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+ void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+ if (mcbsp->pdata->reg_size == 2) {
+ ((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
+ writew_relaxed((u16)val, addr);
+ } else {
+ ((u32 *)mcbsp->reg_cache)[reg] = val;
+ writel_relaxed(val, addr);
+ }
+}
+
+static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg,
+ bool from_cache)
+{
+ void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
+
+ if (mcbsp->pdata->reg_size == 2) {
+ return !from_cache ? readw_relaxed(addr) :
+ ((u16 *)mcbsp->reg_cache)[reg];
+ } else {
+ return !from_cache ? readl_relaxed(addr) :
+ ((u32 *)mcbsp->reg_cache)[reg];
+ }
+}
+
+#define MCBSP_READ(mcbsp, reg) \
+ omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
+#define MCBSP_WRITE(mcbsp, reg, val) \
+ omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val)
+#define MCBSP_READ_CACHE(mcbsp, reg) \
+ omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
+
/* Sidetone specific API */
-int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);
-int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain);
-int omap_st_enable(struct omap_mcbsp *mcbsp);
-int omap_st_disable(struct omap_mcbsp *mcbsp);
-int omap_st_is_enabled(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_init(struct platform_device *pdev);
+void omap_mcbsp_st_cleanup(struct platform_device *pdev);
-int omap_mcbsp_init(struct platform_device *pdev);
-void omap_mcbsp_cleanup(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp);
+int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp);
-#endif /* __ASOC_MCBSP_H */
+#endif /* __OMAP_MCBSP_PRIV_H__ */
diff --git a/sound/soc/ti/omap-mcbsp-st.c b/sound/soc/ti/omap-mcbsp-st.c
new file mode 100644
index 000000000000..1a3fe854e856
--- /dev/null
+++ b/sound/soc/ti/omap-mcbsp-st.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * McBSP Sidetone support
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ * Peter Ujfalusi <peter.ujfalusi@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#include "omap-mcbsp.h"
+#include "omap-mcbsp-priv.h"
+
+/* OMAP3 sidetone control registers */
+#define OMAP_ST_REG_REV 0x00
+#define OMAP_ST_REG_SYSCONFIG 0x10
+#define OMAP_ST_REG_IRQSTATUS 0x18
+#define OMAP_ST_REG_IRQENABLE 0x1C
+#define OMAP_ST_REG_SGAINCR 0x24
+#define OMAP_ST_REG_SFIRCR 0x28
+#define OMAP_ST_REG_SSELCR 0x2C
+
+/********************** McBSP SSELCR bit definitions ***********************/
+#define SIDETONEEN BIT(10)
+
+/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
+#define ST_AUTOIDLE BIT(0)
+
+/********************** McBSP Sidetone SGAINCR bit definitions *************/
+#define ST_CH0GAIN(value) ((value) & 0xffff) /* Bits 0:15 */
+#define ST_CH1GAIN(value) (((value) & 0xffff) << 16) /* Bits 16:31 */
+
+/********************** McBSP Sidetone SFIRCR bit definitions **************/
+#define ST_FIRCOEFF(value) ((value) & 0xffff) /* Bits 0:15 */
+
+/********************** McBSP Sidetone SSELCR bit definitions **************/
+#define ST_SIDETONEEN BIT(0)
+#define ST_COEFFWREN BIT(1)
+#define ST_COEFFWRDONE BIT(2)
+
+struct omap_mcbsp_st_data {
+ void __iomem *io_base_st;
+ struct clk *mcbsp_iclk;
+ bool running;
+ bool enabled;
+ s16 taps[128]; /* Sidetone filter coefficients */
+ int nr_taps; /* Number of filter coefficients in use */
+ s16 ch0gain;
+ s16 ch1gain;
+};
+
+static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+{
+ writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
+}
+
+static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
+{
+ return readl_relaxed(mcbsp->st_data->io_base_st + reg);
+}
+
+#define MCBSP_ST_READ(mcbsp, reg) omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
+#define MCBSP_ST_WRITE(mcbsp, reg, val) \
+ omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val)
+
+static void omap_mcbsp_st_on(struct omap_mcbsp *mcbsp)
+{
+ unsigned int w;
+
+ if (mcbsp->pdata->force_ick_on)
+ mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, true);
+
+ /* Disable Sidetone clock auto-gating for normal operation */
+ w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
+ MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
+
+ /* Enable McBSP Sidetone */
+ w = MCBSP_READ(mcbsp, SSELCR);
+ MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
+
+ /* Enable Sidetone from Sidetone Core */
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+ MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
+}
+
+static void omap_mcbsp_st_off(struct omap_mcbsp *mcbsp)
+{
+ unsigned int w;
+
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+ MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
+
+ w = MCBSP_READ(mcbsp, SSELCR);
+ MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
+
+ /* Enable Sidetone clock auto-gating to reduce power consumption */
+ w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
+ MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
+
+ if (mcbsp->pdata->force_ick_on)
+ mcbsp->pdata->force_ick_on(mcbsp->st_data->mcbsp_iclk, false);
+}
+
+static void omap_mcbsp_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
+{
+ u16 val, i;
+
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ if (val & ST_COEFFWREN)
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN);
+
+ for (i = 0; i < 128; i++)
+ MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]);
+
+ i = 0;
+
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+ while (!(val & ST_COEFFWRDONE) && (++i < 1000))
+ val = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN));
+
+ if (i == 1000)
+ dev_err(mcbsp->dev, "McBSP FIR load error!\n");
+}
+
+static void omap_mcbsp_st_chgain(struct omap_mcbsp *mcbsp)
+{
+ u16 w;
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ w = MCBSP_ST_READ(mcbsp, SSELCR);
+
+ MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) |
+ ST_CH1GAIN(st_data->ch1gain));
+}
+
+static int omap_mcbsp_st_set_chgain(struct omap_mcbsp *mcbsp, int channel,
+ s16 chgain)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENOENT;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (channel == 0)
+ st_data->ch0gain = chgain;
+ else if (channel == 1)
+ st_data->ch1gain = chgain;
+ else
+ ret = -EINVAL;
+
+ if (st_data->enabled)
+ omap_mcbsp_st_chgain(mcbsp);
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_get_chgain(struct omap_mcbsp *mcbsp, int channel,
+ s16 *chgain)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENOENT;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (channel == 0)
+ *chgain = st_data->ch0gain;
+ else if (channel == 1)
+ *chgain = st_data->ch1gain;
+ else
+ ret = -EINVAL;
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_enable(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (!st_data)
+ return -ENODEV;
+
+ spin_lock_irq(&mcbsp->lock);
+ st_data->enabled = 1;
+ omap_mcbsp_st_start(mcbsp);
+ spin_unlock_irq(&mcbsp->lock);
+
+ return 0;
+}
+
+static int omap_mcbsp_st_disable(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int ret = 0;
+
+ if (!st_data)
+ return -ENODEV;
+
+ spin_lock_irq(&mcbsp->lock);
+ omap_mcbsp_st_stop(mcbsp);
+ st_data->enabled = 0;
+ spin_unlock_irq(&mcbsp->lock);
+
+ return ret;
+}
+
+static int omap_mcbsp_st_is_enabled(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (!st_data)
+ return -ENODEV;
+
+ return st_data->enabled;
+}
+
+static ssize_t st_taps_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ ssize_t status = 0;
+ int i;
+
+ spin_lock_irq(&mcbsp->lock);
+ for (i = 0; i < st_data->nr_taps; i++)
+ status += sprintf(&buf[status], (i ? ", %d" : "%d"),
+ st_data->taps[i]);
+ if (i)
+ status += sprintf(&buf[status], "\n");
+ spin_unlock_irq(&mcbsp->lock);
+
+ return status;
+}
+
+static ssize_t st_taps_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ int val, tmp, status, i = 0;
+
+ spin_lock_irq(&mcbsp->lock);
+ memset(st_data->taps, 0, sizeof(st_data->taps));
+ st_data->nr_taps = 0;
+
+ do {
+ status = sscanf(buf, "%d%n", &val, &tmp);
+ if (status < 0 || status == 0) {
+ size = -EINVAL;
+ goto out;
+ }
+ if (val < -32768 || val > 32767) {
+ size = -EINVAL;
+ goto out;
+ }
+ st_data->taps[i++] = val;
+ buf += tmp;
+ if (*buf != ',')
+ break;
+ buf++;
+ } while (1);
+
+ st_data->nr_taps = i;
+
+out:
+ spin_unlock_irq(&mcbsp->lock);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(st_taps);
+
+static const struct attribute *sidetone_attrs[] = {
+ &dev_attr_st_taps.attr,
+ NULL,
+};
+
+static const struct attribute_group sidetone_attr_group = {
+ .attrs = (struct attribute **)sidetone_attrs,
+};
+
+int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (st_data->enabled && !st_data->running) {
+ omap_mcbsp_st_fir_write(mcbsp, st_data->taps);
+ omap_mcbsp_st_chgain(mcbsp);
+
+ if (!mcbsp->free) {
+ omap_mcbsp_st_on(mcbsp);
+ st_data->running = 1;
+ }
+ }
+
+ return 0;
+}
+
+int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp)
+{
+ struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+
+ if (st_data->running) {
+ if (!mcbsp->free) {
+ omap_mcbsp_st_off(mcbsp);
+ st_data->running = 0;
+ }
+ }
+
+ return 0;
+}
+
+int omap_mcbsp_st_init(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+ struct omap_mcbsp_st_data *st_data;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
+ if (!res)
+ return 0;
+
+ st_data = devm_kzalloc(mcbsp->dev, sizeof(*mcbsp->st_data), GFP_KERNEL);
+ if (!st_data)
+ return -ENOMEM;
+
+ st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
+ if (IS_ERR(st_data->mcbsp_iclk)) {
+ dev_warn(mcbsp->dev,
+ "Failed to get ick, sidetone might be broken\n");
+ st_data->mcbsp_iclk = NULL;
+ }
+
+ st_data->io_base_st = devm_ioremap(mcbsp->dev, res->start,
+ resource_size(res));
+ if (!st_data->io_base_st)
+ return -ENOMEM;
+
+ ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+ if (ret)
+ return ret;
+
+ mcbsp->st_data = st_data;
+
+ return 0;
+}
+
+void omap_mcbsp_st_cleanup(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+
+ if (mcbsp->st_data) {
+ sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+ clk_put(mcbsp->st_data->mcbsp_iclk);
+ }
+}
+
+static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int max = mc->max;
+ int min = mc->min;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = min;
+ uinfo->value.integer.max = max;
+ return 0;
+}
+
+#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
+static int \
+omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
+ struct snd_ctl_elem_value *uc) \
+{ \
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
+ struct soc_mixer_control *mc = \
+ (struct soc_mixer_control *)kc->private_value; \
+ int max = mc->max; \
+ int min = mc->min; \
+ int val = uc->value.integer.value[0]; \
+ \
+ if (val < min || val > max) \
+ return -EINVAL; \
+ \
+ /* OMAP McBSP implementation uses index values 0..4 */ \
+ return omap_mcbsp_st_set_chgain(mcbsp, channel, val); \
+} \
+ \
+static int \
+omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
+ struct snd_ctl_elem_value *uc) \
+{ \
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
+ s16 chgain; \
+ \
+ if (omap_mcbsp_st_get_chgain(mcbsp, channel, &chgain)) \
+ return -EAGAIN; \
+ \
+ uc->value.integer.value[0] = chgain; \
+ return 0; \
+}
+
+OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
+
+static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+ u8 value = ucontrol->value.integer.value[0];
+
+ if (value == omap_mcbsp_st_is_enabled(mcbsp))
+ return 0;
+
+ if (value)
+ omap_mcbsp_st_enable(mcbsp);
+ else
+ omap_mcbsp_st_disable(mcbsp);
+
+ return 1;
+}
+
+static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ ucontrol->value.integer.value[0] = omap_mcbsp_st_is_enabled(mcbsp);
+ return 0;
+}
+
+#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
+ xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = omap_mcbsp_st_info_volsw, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.min = xmin, .max = xmax} }
+
+#define OMAP_MCBSP_ST_CONTROLS(port) \
+static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
+SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
+ omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
+ -32768, 32767, \
+ omap_mcbsp_get_st_ch0_volume, \
+ omap_mcbsp_set_st_ch0_volume), \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
+ -32768, 32767, \
+ omap_mcbsp_get_st_ch1_volume, \
+ omap_mcbsp_set_st_ch1_volume), \
+}
+
+OMAP_MCBSP_ST_CONTROLS(2);
+OMAP_MCBSP_ST_CONTROLS(3);
+
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (!mcbsp->st_data) {
+ dev_warn(mcbsp->dev, "No sidetone data for port\n");
+ return 0;
+ }
+
+ switch (port_id) {
+ case 2: /* McBSP 2 */
+ return snd_soc_add_dai_controls(cpu_dai,
+ omap_mcbsp2_st_controls,
+ ARRAY_SIZE(omap_mcbsp2_st_controls));
+ case 3: /* McBSP 3 */
+ return snd_soc_add_dai_controls(cpu_dai,
+ omap_mcbsp3_st_controls,
+ ARRAY_SIZE(omap_mcbsp3_st_controls));
+ default:
+ dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
+ break;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
index 2d6decbfc99e..a395598f1f20 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/ti/omap-mcbsp.c
@@ -35,21 +35,12 @@
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include "mcbsp.h"
+#include "omap-mcbsp-priv.h"
#include "omap-mcbsp.h"
#include "sdma-pcm.h"
#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
-#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
- xhandler_get, xhandler_put) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = omap_mcbsp_st_info_volsw, \
- .get = xhandler_get, .put = xhandler_put, \
- .private_value = (unsigned long) &(struct soc_mixer_control) \
- {.min = xmin, .max = xmax} }
-
enum {
OMAP_MCBSP_WORD_8 = 0,
OMAP_MCBSP_WORD_12,
@@ -59,6 +50,699 @@ enum {
OMAP_MCBSP_WORD_32,
};
+static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp)
+{
+ dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
+ dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", MCBSP_READ(mcbsp, DRR2));
+ dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", MCBSP_READ(mcbsp, DRR1));
+ dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", MCBSP_READ(mcbsp, DXR2));
+ dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", MCBSP_READ(mcbsp, DXR1));
+ dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", MCBSP_READ(mcbsp, SPCR2));
+ dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", MCBSP_READ(mcbsp, SPCR1));
+ dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", MCBSP_READ(mcbsp, RCR2));
+ dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", MCBSP_READ(mcbsp, RCR1));
+ dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", MCBSP_READ(mcbsp, XCR2));
+ dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", MCBSP_READ(mcbsp, XCR1));
+ dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", MCBSP_READ(mcbsp, SRGR2));
+ dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", MCBSP_READ(mcbsp, SRGR1));
+ dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", MCBSP_READ(mcbsp, PCR0));
+ dev_dbg(mcbsp->dev, "***********************\n");
+}
+
+static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
+{
+ struct clk *fck_src;
+ const char *src;
+ int r;
+
+ if (fck_src_id == MCBSP_CLKS_PAD_SRC)
+ src = "pad_fck";
+ else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
+ src = "prcm_fck";
+ else
+ return -EINVAL;
+
+ fck_src = clk_get(mcbsp->dev, src);
+ if (IS_ERR(fck_src)) {
+ dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
+ return -EINVAL;
+ }
+
+ pm_runtime_put_sync(mcbsp->dev);
+
+ r = clk_set_parent(mcbsp->fclk, fck_src);
+ if (r) {
+ dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
+ src);
+ clk_put(fck_src);
+ return r;
+ }
+
+ pm_runtime_get_sync(mcbsp->dev);
+
+ clk_put(fck_src);
+
+ return 0;
+}
+
+static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst;
+
+ irqst = MCBSP_READ(mcbsp, IRQST);
+ dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n", irqst);
+
+ if (irqst & RSYNCERREN)
+ dev_err(mcbsp->dev, "RX Frame Sync Error!\n");
+ if (irqst & RFSREN)
+ dev_dbg(mcbsp->dev, "RX Frame Sync\n");
+ if (irqst & REOFEN)
+ dev_dbg(mcbsp->dev, "RX End Of Frame\n");
+ if (irqst & RRDYEN)
+ dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n");
+ if (irqst & RUNDFLEN)
+ dev_err(mcbsp->dev, "RX Buffer Underflow!\n");
+ if (irqst & ROVFLEN)
+ dev_err(mcbsp->dev, "RX Buffer Overflow!\n");
+
+ if (irqst & XSYNCERREN)
+ dev_err(mcbsp->dev, "TX Frame Sync Error!\n");
+ if (irqst & XFSXEN)
+ dev_dbg(mcbsp->dev, "TX Frame Sync\n");
+ if (irqst & XEOFEN)
+ dev_dbg(mcbsp->dev, "TX End Of Frame\n");
+ if (irqst & XRDYEN)
+ dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n");
+ if (irqst & XUNDFLEN)
+ dev_err(mcbsp->dev, "TX Buffer Underflow!\n");
+ if (irqst & XOVFLEN)
+ dev_err(mcbsp->dev, "TX Buffer Overflow!\n");
+ if (irqst & XEMPTYEOFEN)
+ dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n");
+
+ MCBSP_WRITE(mcbsp, IRQST, irqst);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst_spcr2;
+
+ irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2);
+ dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
+
+ if (irqst_spcr2 & XSYNC_ERR) {
+ dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n",
+ irqst_spcr2);
+ /* Writing zero to XSYNC_ERR clears the IRQ */
+ MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2));
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data)
+{
+ struct omap_mcbsp *mcbsp = data;
+ u16 irqst_spcr1;
+
+ irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1);
+ dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
+
+ if (irqst_spcr1 & RSYNC_ERR) {
+ dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n",
+ irqst_spcr1);
+ /* Writing zero to RSYNC_ERR clears the IRQ */
+ MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1));
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * omap_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling omap_mcbsp_start().
+ */
+static void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
+ const struct omap_mcbsp_reg_cfg *config)
+{
+ dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n",
+ mcbsp->id, mcbsp->phys_base);
+
+ /* We write the given config */
+ MCBSP_WRITE(mcbsp, SPCR2, config->spcr2);
+ MCBSP_WRITE(mcbsp, SPCR1, config->spcr1);
+ MCBSP_WRITE(mcbsp, RCR2, config->rcr2);
+ MCBSP_WRITE(mcbsp, RCR1, config->rcr1);
+ MCBSP_WRITE(mcbsp, XCR2, config->xcr2);
+ MCBSP_WRITE(mcbsp, XCR1, config->xcr1);
+ MCBSP_WRITE(mcbsp, SRGR2, config->srgr2);
+ MCBSP_WRITE(mcbsp, SRGR1, config->srgr1);
+ MCBSP_WRITE(mcbsp, MCR2, config->mcr2);
+ MCBSP_WRITE(mcbsp, MCR1, config->mcr1);
+ MCBSP_WRITE(mcbsp, PCR0, config->pcr0);
+ if (mcbsp->pdata->has_ccr) {
+ MCBSP_WRITE(mcbsp, XCCR, config->xccr);
+ MCBSP_WRITE(mcbsp, RCCR, config->rccr);
+ }
+ /* Enable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
+
+ /* Enable TX/RX sync error interrupts by default */
+ if (mcbsp->irq)
+ MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN |
+ RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN);
+}
+
+/**
+ * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
+ * @mcbsp: omap_mcbsp struct for the McBSP instance
+ * @stream: Stream direction (playback/capture)
+ *
+ * Returns the address of mcbsp data transmit register or data receive register
+ * to be used by DMA for transferring/receiving data
+ */
+static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp,
+ unsigned int stream)
+{
+ int data_reg;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (mcbsp->pdata->reg_size == 2)
+ data_reg = OMAP_MCBSP_REG_DXR1;
+ else
+ data_reg = OMAP_MCBSP_REG_DXR;
+ } else {
+ if (mcbsp->pdata->reg_size == 2)
+ data_reg = OMAP_MCBSP_REG_DRR1;
+ else
+ data_reg = OMAP_MCBSP_REG_DRR;
+ }
+
+ return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step;
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH2 register.
+ */
+static void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+ if (threshold && threshold <= mcbsp->max_tx_thres)
+ MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH1 register.
+ */
+static void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold)
+{
+ if (threshold && threshold <= mcbsp->max_rx_thres)
+ MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
+}
+
+/*
+ * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
+ */
+static u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp)
+{
+ u16 buffstat;
+
+ /* Returns the number of free locations in the buffer */
+ buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
+
+ /* Number of slots are different in McBSP ports */
+ return mcbsp->pdata->buffer_size - buffstat;
+}
+
+/*
+ * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
+ * to reach the threshold value (when the DMA will be triggered to read it)
+ */
+static u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp)
+{
+ u16 buffstat, threshold;
+
+ /* Returns the number of used locations in the buffer */
+ buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
+ /* RX threshold */
+ threshold = MCBSP_READ(mcbsp, THRSH1);
+
+ /* Return the number of location till we reach the threshold limit */
+ if (threshold <= buffstat)
+ return 0;
+ else
+ return threshold - buffstat;
+}
+
+static int omap_mcbsp_request(struct omap_mcbsp *mcbsp)
+{
+ void *reg_cache;
+ int err;
+
+ reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL);
+ if (!reg_cache)
+ return -ENOMEM;
+
+ spin_lock(&mcbsp->lock);
+ if (!mcbsp->free) {
+ dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id);
+ err = -EBUSY;
+ goto err_kfree;
+ }
+
+ mcbsp->free = false;
+ mcbsp->reg_cache = reg_cache;
+ spin_unlock(&mcbsp->lock);
+
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->request)
+ mcbsp->pdata->ops->request(mcbsp->id - 1);
+
+ /*
+ * Make sure that transmitter, receiver and sample-rate generator are
+ * not running before activating IRQs.
+ */
+ MCBSP_WRITE(mcbsp, SPCR1, 0);
+ MCBSP_WRITE(mcbsp, SPCR2, 0);
+
+ if (mcbsp->irq) {
+ err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
+ "McBSP", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request IRQ\n");
+ goto err_clk_disable;
+ }
+ } else {
+ err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
+ "McBSP TX", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
+ goto err_clk_disable;
+ }
+
+ err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
+ "McBSP RX", (void *)mcbsp);
+ if (err != 0) {
+ dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
+ goto err_free_irq;
+ }
+ }
+
+ return 0;
+err_free_irq:
+ free_irq(mcbsp->tx_irq, (void *)mcbsp);
+err_clk_disable:
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+ /* Disable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+ spin_lock(&mcbsp->lock);
+ mcbsp->free = true;
+ mcbsp->reg_cache = NULL;
+err_kfree:
+ spin_unlock(&mcbsp->lock);
+ kfree(reg_cache);
+
+ return err;
+}
+
+static void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
+{
+ void *reg_cache;
+
+ if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ mcbsp->pdata->ops->free(mcbsp->id - 1);
+
+ /* Disable wakeup behavior */
+ if (mcbsp->pdata->has_wakeup)
+ MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
+
+ /* Disable interrupt requests */
+ if (mcbsp->irq)
+ MCBSP_WRITE(mcbsp, IRQEN, 0);
+
+ if (mcbsp->irq) {
+ free_irq(mcbsp->irq, (void *)mcbsp);
+ } else {
+ free_irq(mcbsp->rx_irq, (void *)mcbsp);
+ free_irq(mcbsp->tx_irq, (void *)mcbsp);
+ }
+
+ reg_cache = mcbsp->reg_cache;
+
+ /*
+ * Select CLKS source from internal source unconditionally before
+ * marking the McBSP port as free.
+ * If the external clock source via MCBSP_CLKS pin has been selected the
+ * system will refuse to enter idle if the CLKS pin source is not reset
+ * back to internal source.
+ */
+ if (!mcbsp_omap1())
+ omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC);
+
+ spin_lock(&mcbsp->lock);
+ if (mcbsp->free)
+ dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id);
+ else
+ mcbsp->free = true;
+ mcbsp->reg_cache = NULL;
+ spin_unlock(&mcbsp->lock);
+
+ kfree(reg_cache);
+}
+
+/*
+ * Here we start the McBSP, by enabling transmitter, receiver or both.
+ * If no transmitter or receiver is active prior calling, then sample-rate
+ * generator and frame sync are started.
+ */
+static void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream)
+{
+ int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int rx = !tx;
+ int enable_srg = 0;
+ u16 w;
+
+ if (mcbsp->st_data)
+ omap_mcbsp_st_start(mcbsp);
+
+ /* Only enable SRG, if McBSP is master */
+ w = MCBSP_READ_CACHE(mcbsp, PCR0);
+ if (w & (FSXM | FSRM | CLKXM | CLKRM))
+ enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+ MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+ if (enable_srg) {
+ /* Start the sample generator */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
+ }
+
+ /* Enable transmitter and receiver */
+ tx &= 1;
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | tx);
+
+ rx &= 1;
+ w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+ MCBSP_WRITE(mcbsp, SPCR1, w | rx);
+
+ /*
+ * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec
+ * REVISIT: 100us may give enough time for two CLKSRG, however
+ * due to some unknown PM related, clock gating etc. reason it
+ * is now at 500us.
+ */
+ udelay(500);
+
+ if (enable_srg) {
+ /* Start frame sync */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
+ }
+
+ if (mcbsp->pdata->has_ccr) {
+ /* Release the transmitter and receiver */
+ w = MCBSP_READ_CACHE(mcbsp, XCCR);
+ w &= ~(tx ? XDISABLE : 0);
+ MCBSP_WRITE(mcbsp, XCCR, w);
+ w = MCBSP_READ_CACHE(mcbsp, RCCR);
+ w &= ~(rx ? RDISABLE : 0);
+ MCBSP_WRITE(mcbsp, RCCR, w);
+ }
+
+ /* Dump McBSP Regs */
+ omap_mcbsp_dump_reg(mcbsp);
+}
+
+static void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream)
+{
+ int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int rx = !tx;
+ int idle;
+ u16 w;
+
+ /* Reset transmitter */
+ tx &= 1;
+ if (mcbsp->pdata->has_ccr) {
+ w = MCBSP_READ_CACHE(mcbsp, XCCR);
+ w |= (tx ? XDISABLE : 0);
+ MCBSP_WRITE(mcbsp, XCCR, w);
+ }
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w & ~tx);
+
+ /* Reset receiver */
+ rx &= 1;
+ if (mcbsp->pdata->has_ccr) {
+ w = MCBSP_READ_CACHE(mcbsp, RCCR);
+ w |= (rx ? RDISABLE : 0);
+ MCBSP_WRITE(mcbsp, RCCR, w);
+ }
+ w = MCBSP_READ_CACHE(mcbsp, SPCR1);
+ MCBSP_WRITE(mcbsp, SPCR1, w & ~rx);
+
+ idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+ MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+
+ if (idle) {
+ /* Reset the sample rate generator */
+ w = MCBSP_READ_CACHE(mcbsp, SPCR2);
+ MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6));
+ }
+
+ if (mcbsp->st_data)
+ omap_mcbsp_st_stop(mcbsp);
+}
+
+#define max_thres(m) (mcbsp->pdata->buffer_size)
+#define valid_threshold(m, val) ((val) <= max_thres(m))
+#define THRESHOLD_PROP_BUILDER(prop) \
+static ssize_t prop##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%u\n", mcbsp->prop); \
+} \
+ \
+static ssize_t prop##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t size) \
+{ \
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \
+ unsigned long val; \
+ int status; \
+ \
+ status = kstrtoul(buf, 0, &val); \
+ if (status) \
+ return status; \
+ \
+ if (!valid_threshold(mcbsp, val)) \
+ return -EDOM; \
+ \
+ mcbsp->prop = val; \
+ return size; \
+} \
+ \
+static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store)
+
+THRESHOLD_PROP_BUILDER(max_tx_thres);
+THRESHOLD_PROP_BUILDER(max_rx_thres);
+
+static const char * const dma_op_modes[] = {
+ "element", "threshold",
+};
+
+static ssize_t dma_op_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ int dma_op_mode, i = 0;
+ ssize_t len = 0;
+ const char * const *s;
+
+ dma_op_mode = mcbsp->dma_op_mode;
+
+ for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) {
+ if (dma_op_mode == i)
+ len += sprintf(buf + len, "[%s] ", *s);
+ else
+ len += sprintf(buf + len, "%s ", *s);
+ }
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static ssize_t dma_op_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct omap_mcbsp *mcbsp = dev_get_drvdata(dev);
+ int i;
+
+ i = sysfs_match_string(dma_op_modes, buf);
+ if (i < 0)
+ return i;
+
+ spin_lock_irq(&mcbsp->lock);
+ if (!mcbsp->free) {
+ size = -EBUSY;
+ goto unlock;
+ }
+ mcbsp->dma_op_mode = i;
+
+unlock:
+ spin_unlock_irq(&mcbsp->lock);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(dma_op_mode);
+
+static const struct attribute *additional_attrs[] = {
+ &dev_attr_max_tx_thres.attr,
+ &dev_attr_max_rx_thres.attr,
+ &dev_attr_dma_op_mode.attr,
+ NULL,
+};
+
+static const struct attribute_group additional_attr_group = {
+ .attrs = (struct attribute **)additional_attrs,
+};
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+static int omap_mcbsp_init(struct platform_device *pdev)
+{
+ struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+ struct resource *res;
+ int ret = 0;
+
+ spin_lock_init(&mcbsp->lock);
+ mcbsp->free = true;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+ if (!res)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mcbsp->io_base))
+ return PTR_ERR(mcbsp->io_base);
+
+ mcbsp->phys_base = res->start;
+ mcbsp->reg_cache_size = resource_size(res);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+ if (!res)
+ mcbsp->phys_dma_base = mcbsp->phys_base;
+ else
+ mcbsp->phys_dma_base = res->start;
+
+ /*
+ * OMAP1, 2 uses two interrupt lines: TX, RX
+ * OMAP2430, OMAP3 SoC have combined IRQ line as well.
+ * OMAP4 and newer SoC only have the combined IRQ line.
+ * Use the combined IRQ if available since it gives better debugging
+ * possibilities.
+ */
+ mcbsp->irq = platform_get_irq_byname(pdev, "common");
+ if (mcbsp->irq == -ENXIO) {
+ mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
+
+ if (mcbsp->tx_irq == -ENXIO) {
+ mcbsp->irq = platform_get_irq(pdev, 0);
+ mcbsp->tx_irq = 0;
+ } else {
+ mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
+ mcbsp->irq = 0;
+ }
+ }
+
+ if (!pdev->dev.of_node) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+ if (!res) {
+ dev_err(&pdev->dev, "invalid tx DMA channel\n");
+ return -ENODEV;
+ }
+ mcbsp->dma_req[0] = res->start;
+ mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+ if (!res) {
+ dev_err(&pdev->dev, "invalid rx DMA channel\n");
+ return -ENODEV;
+ }
+ mcbsp->dma_req[1] = res->start;
+ mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
+ } else {
+ mcbsp->dma_data[0].filter_data = "tx";
+ mcbsp->dma_data[1].filter_data = "rx";
+ }
+
+ mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp,
+ SNDRV_PCM_STREAM_CAPTURE);
+
+ mcbsp->fclk = clk_get(&pdev->dev, "fck");
+ if (IS_ERR(mcbsp->fclk)) {
+ ret = PTR_ERR(mcbsp->fclk);
+ dev_err(mcbsp->dev, "unable to get fck: %d\n", ret);
+ return ret;
+ }
+
+ mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
+ if (mcbsp->pdata->buffer_size) {
+ /*
+ * Initially configure the maximum thresholds to a safe value.
+ * The McBSP FIFO usage with these values should not go under
+ * 16 locations.
+ * If the whole FIFO without safety buffer is used, than there
+ * is a possibility that the DMA will be not able to push the
+ * new data on time, causing channel shifts in runtime.
+ */
+ mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
+ mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
+
+ ret = sysfs_create_group(&mcbsp->dev->kobj,
+ &additional_attr_group);
+ if (ret) {
+ dev_err(mcbsp->dev,
+ "Unable to create additional controls\n");
+ goto err_thres;
+ }
+ }
+
+ ret = omap_mcbsp_st_init(pdev);
+ if (ret)
+ goto err_st;
+
+ return 0;
+
+err_st:
+ if (mcbsp->pdata->buffer_size)
+ sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+err_thres:
+ clk_put(mcbsp->fclk);
+ return ret;
+}
+
/*
* Stream DMA parameters. DMA request line and port address are set runtime
* since they are different between OMAP1 and later OMAPs
@@ -71,6 +755,10 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
int words;
+ /* No need to proceed further if McBSP does not have FIFO */
+ if (mcbsp->pdata->buffer_size == 0)
+ return;
+
/*
* Configure McBSP threshold based on either:
* packet_size, when the sDMA is in packet mode, or based on the
@@ -201,27 +889,26 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
- int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
mcbsp->active++;
- omap_mcbsp_start(mcbsp, play, !play);
+ omap_mcbsp_start(mcbsp, substream->stream);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- omap_mcbsp_stop(mcbsp, play, !play);
+ omap_mcbsp_stop(mcbsp, substream->stream);
mcbsp->active--;
break;
default:
- err = -EINVAL;
+ return -EINVAL;
}
- return err;
+ return 0;
}
static snd_pcm_sframes_t omap_mcbsp_dai_delay(
@@ -234,6 +921,10 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
u16 fifo_use;
snd_pcm_sframes_t delay;
+ /* No need to proceed further if McBSP does not have FIFO */
+ if (mcbsp->pdata->buffer_size == 0)
+ return 0;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
else
@@ -649,132 +1340,6 @@ static const struct snd_soc_component_driver omap_mcbsp_component = {
.name = "omap-mcbsp",
};
-static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int max = mc->max;
- int min = mc->min;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = min;
- uinfo->value.integer.max = max;
- return 0;
-}
-
-#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel) \
-static int \
-omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \
- struct snd_ctl_elem_value *uc) \
-{ \
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
- struct soc_mixer_control *mc = \
- (struct soc_mixer_control *)kc->private_value; \
- int max = mc->max; \
- int min = mc->min; \
- int val = uc->value.integer.value[0]; \
- \
- if (val < min || val > max) \
- return -EINVAL; \
- \
- /* OMAP McBSP implementation uses index values 0..4 */ \
- return omap_st_set_chgain(mcbsp, channel, val); \
-} \
- \
-static int \
-omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \
- struct snd_ctl_elem_value *uc) \
-{ \
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc); \
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); \
- s16 chgain; \
- \
- if (omap_st_get_chgain(mcbsp, channel, &chgain)) \
- return -EAGAIN; \
- \
- uc->value.integer.value[0] = chgain; \
- return 0; \
-}
-
-OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
-OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
-
-static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
- u8 value = ucontrol->value.integer.value[0];
-
- if (value == omap_st_is_enabled(mcbsp))
- return 0;
-
- if (value)
- omap_st_enable(mcbsp);
- else
- omap_st_disable(mcbsp);
-
- return 1;
-}
-
-static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-
- ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
- return 0;
-}
-
-#define OMAP_MCBSP_ST_CONTROLS(port) \
-static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
-SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0, \
- omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), \
-OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
- -32768, 32767, \
- omap_mcbsp_get_st_ch0_volume, \
- omap_mcbsp_set_st_ch0_volume), \
-OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
- -32768, 32767, \
- omap_mcbsp_get_st_ch1_volume, \
- omap_mcbsp_set_st_ch1_volume), \
-}
-
-OMAP_MCBSP_ST_CONTROLS(2);
-OMAP_MCBSP_ST_CONTROLS(3);
-
-int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id)
-{
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-
- if (!mcbsp->st_data) {
- dev_warn(mcbsp->dev, "No sidetone data for port\n");
- return 0;
- }
-
- switch (port_id) {
- case 2: /* McBSP 2 */
- return snd_soc_add_dai_controls(cpu_dai,
- omap_mcbsp2_st_controls,
- ARRAY_SIZE(omap_mcbsp2_st_controls));
- case 3: /* McBSP 3 */
- return snd_soc_add_dai_controls(cpu_dai,
- omap_mcbsp3_st_controls,
- ARRAY_SIZE(omap_mcbsp3_st_controls));
- default:
- dev_err(mcbsp->dev, "Port %d not supported\n", port_id);
- break;
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
-
static struct omap_mcbsp_platform_data omap2420_pdata = {
.reg_step = 4,
.reg_size = 2,
@@ -862,6 +1427,11 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
if (ret)
return ret;
+ if (mcbsp->pdata->reg_size == 2) {
+ omap_mcbsp_dai.playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ omap_mcbsp_dai.capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ }
+
ret = devm_snd_soc_register_component(&pdev->dev,
&omap_mcbsp_component,
&omap_mcbsp_dai, 1);
@@ -881,7 +1451,10 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
if (pm_qos_request_active(&mcbsp->pm_qos_req))
pm_qos_remove_request(&mcbsp->pm_qos_req);
- omap_mcbsp_cleanup(mcbsp);
+ if (mcbsp->pdata->buffer_size)
+ sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
+
+ omap_mcbsp_st_cleanup(pdev);
clk_put(mcbsp->fclk);
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/ti/omap-mcbsp.h
index 2e3369c27be3..7911d24898c9 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/ti/omap-mcbsp.h
@@ -22,8 +22,10 @@
*
*/
-#ifndef __OMAP_I2S_H__
-#define __OMAP_I2S_H__
+#ifndef __OMAP_MCBSP_H__
+#define __OMAP_MCBSP_H__
+
+#include <sound/dmaengine_pcm.h>
/* Source clocks for McBSP sample rate generator */
enum omap_mcbsp_clksrg_clk {
@@ -41,4 +43,4 @@ enum omap_mcbsp_div {
int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd, int port_id);
-#endif
+#endif /* __OMAP_MCBSP_H__ */
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c
index 7d5bdc5a2890..7d5bdc5a2890 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/ti/omap-mcpdm.c
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/ti/omap-mcpdm.h
index de8cf26595b1..de8cf26595b1 100644
--- a/sound/soc/omap/omap-mcpdm.h
+++ b/sound/soc/ti/omap-mcpdm.h
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c
index cccc316743fa..cccc316743fa 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/ti/omap-twl4030.c
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/ti/omap3pandora.c
index 4e3de712159c..4e3de712159c 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/ti/omap3pandora.c
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/ti/osk5912.c
index e4096779ca05..e4096779ca05 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/ti/osk5912.c
diff --git a/sound/soc/omap/rx51.c b/sound/soc/ti/rx51.c
index 57448bd5ad77..57448bd5ad77 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/ti/rx51.c
diff --git a/sound/soc/omap/sdma-pcm.c b/sound/soc/ti/sdma-pcm.c
index 21a9c2499d48..21a9c2499d48 100644
--- a/sound/soc/omap/sdma-pcm.c
+++ b/sound/soc/ti/sdma-pcm.c
diff --git a/sound/soc/omap/sdma-pcm.h b/sound/soc/ti/sdma-pcm.h
index 34a7f90b2587..cb0627c8dd34 100644
--- a/sound/soc/omap/sdma-pcm.h
+++ b/sound/soc/ti/sdma-pcm.h
@@ -7,7 +7,7 @@
#ifndef __SDMA_PCM_H__
#define __SDMA_PCM_H__
-#if IS_ENABLED(CONFIG_SND_SDMA_SOC)
+#if IS_ENABLED(CONFIG_SND_SOC_TI_SDMA_PCM)
int sdma_pcm_platform_register(struct device *dev,
char *txdmachan, char *rxdmachan);
#else
@@ -16,6 +16,6 @@ static inline int sdma_pcm_platform_register(struct device *dev,
{
return -ENODEV;
}
-#endif /* CONFIG_SND_SDMA_SOC */
+#endif /* CONFIG_SND_SOC_TI_SDMA_PCM */
#endif /* __SDMA_PCM_H__ */
diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig
new file mode 100644
index 000000000000..25e287feb58c
--- /dev/null
+++ b/sound/soc/xilinx/Kconfig
@@ -0,0 +1,8 @@
+config SND_SOC_XILINX_I2S
+ tristate "Audio support for the the Xilinx I2S"
+ help
+ Select this option to enable Xilinx I2S Audio. This enables
+ I2S playback and capture using xilinx soft IP. In transmitter
+ mode, IP receives audio in AES format, extracts PCM and sends
+ PCM data. In receiver mode, IP receives PCM audio and
+ encapsulates PCM in AES format and sends AES data.
diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile
new file mode 100644
index 000000000000..6c1209b9ee75
--- /dev/null
+++ b/sound/soc/xilinx/Makefile
@@ -0,0 +1,2 @@
+snd-soc-xlnx-i2s-objs := xlnx_i2s.o
+obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o
diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c
new file mode 100644
index 000000000000..d4ae9eff41ce
--- /dev/null
+++ b/sound/soc/xilinx/xlnx_i2s.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx ASoC I2S audio support
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Author: Praveen Vuppala <praveenv@xilinx.com>
+ * Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "xlnx_i2s"
+
+#define I2S_CORE_CTRL_OFFSET 0x08
+#define I2S_I2STIM_OFFSET 0x20
+#define I2S_CH0_OFFSET 0x30
+#define I2S_I2STIM_VALID_MASK GENMASK(7, 0)
+
+static int xlnx_i2s_set_sclkout_div(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ void __iomem *base = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (!div || (div & ~I2S_I2STIM_VALID_MASK))
+ return -EINVAL;
+
+ writel(div, base + I2S_I2STIM_OFFSET);
+
+ return 0;
+}
+
+static int xlnx_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *i2s_dai)
+{
+ u32 reg_off, chan_id;
+ void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai);
+
+ chan_id = params_channels(params) / 2;
+
+ while (chan_id > 0) {
+ reg_off = I2S_CH0_OFFSET + ((chan_id - 1) * 4);
+ writel(chan_id, base + reg_off);
+ chan_id--;
+ }
+
+ return 0;
+}
+
+static int xlnx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *i2s_dai)
+{
+ void __iomem *base = snd_soc_dai_get_drvdata(i2s_dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ writel(1, base + I2S_CORE_CTRL_OFFSET);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ writel(0, base + I2S_CORE_CTRL_OFFSET);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops xlnx_i2s_dai_ops = {
+ .trigger = xlnx_i2s_trigger,
+ .set_clkdiv = xlnx_i2s_set_sclkout_div,
+ .hw_params = xlnx_i2s_hw_params
+};
+
+static const struct snd_soc_component_driver xlnx_i2s_component = {
+ .name = DRV_NAME,
+};
+
+static const struct of_device_id xlnx_i2s_of_match[] = {
+ { .compatible = "xlnx,i2s-transmitter-1.0", },
+ { .compatible = "xlnx,i2s-receiver-1.0", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xlnx_i2s_of_match);
+
+static int xlnx_i2s_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *base;
+ struct snd_soc_dai_driver *dai_drv;
+ int ret;
+ u32 ch, format, data_width;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+
+ dai_drv = devm_kzalloc(&pdev->dev, sizeof(*dai_drv), GFP_KERNEL);
+ if (!dai_drv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ ret = of_property_read_u32(node, "xlnx,num-channels", &ch);
+ if (ret < 0) {
+ dev_err(dev, "cannot get supported channels\n");
+ return ret;
+ }
+ ch = ch * 2;
+
+ ret = of_property_read_u32(node, "xlnx,dwidth", &data_width);
+ if (ret < 0) {
+ dev_err(dev, "cannot get data width\n");
+ return ret;
+ }
+ switch (data_width) {
+ case 16:
+ format = SNDRV_PCM_FMTBIT_S16_LE;
+ break;
+ case 24:
+ format = SNDRV_PCM_FMTBIT_S24_LE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (of_device_is_compatible(node, "xlnx,i2s-transmitter-1.0")) {
+ dai_drv->name = "xlnx_i2s_playback";
+ dai_drv->playback.stream_name = "Playback";
+ dai_drv->playback.formats = format;
+ dai_drv->playback.channels_min = ch;
+ dai_drv->playback.channels_max = ch;
+ dai_drv->playback.rates = SNDRV_PCM_RATE_8000_192000;
+ dai_drv->ops = &xlnx_i2s_dai_ops;
+ } else if (of_device_is_compatible(node, "xlnx,i2s-receiver-1.0")) {
+ dai_drv->name = "xlnx_i2s_capture";
+ dai_drv->capture.stream_name = "Capture";
+ dai_drv->capture.formats = format;
+ dai_drv->capture.channels_min = ch;
+ dai_drv->capture.channels_max = ch;
+ dai_drv->capture.rates = SNDRV_PCM_RATE_8000_192000;
+ dai_drv->ops = &xlnx_i2s_dai_ops;
+ } else {
+ return -ENODEV;
+ }
+
+ dev_set_drvdata(&pdev->dev, base);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &xlnx_i2s_component,
+ dai_drv, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "i2s component registration failed\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "%s DAI registered\n", dai_drv->name);
+
+ return ret;
+}
+
+static struct platform_driver xlnx_i2s_aud_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = xlnx_i2s_of_match,
+ },
+ .probe = xlnx_i2s_probe,
+};
+
+module_platform_driver(xlnx_i2s_aud_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Praveen Vuppala <praveenv@xilinx.com>");
+MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");