summaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/Kconfig3
-rw-r--r--sound/soc/Makefile6
-rw-r--r--sound/soc/amd/Kconfig7
-rw-r--r--sound/soc/amd/Makefile6
-rw-r--r--sound/soc/amd/acp-pcm-dma.c356
-rw-r--r--sound/soc/amd/acp-rt5645.c199
-rw-r--r--sound/soc/amd/acp.h19
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c391
-rw-r--r--sound/soc/bcm/cygnus-ssp.c34
-rw-r--r--sound/soc/codecs/Kconfig13
-rw-r--r--sound/soc/codecs/Makefile1
-rw-r--r--sound/soc/codecs/arizona.c166
-rw-r--r--sound/soc/codecs/arizona.h6
-rw-r--r--sound/soc/codecs/cs43130.c16
-rw-r--r--sound/soc/codecs/cs47l24.c14
-rw-r--r--sound/soc/codecs/da7213.c58
-rw-r--r--sound/soc/codecs/da7213.h1
-rw-r--r--sound/soc/codecs/hdac_hdmi.c51
-rw-r--r--sound/soc/codecs/hdmi-codec.c5
-rw-r--r--sound/soc/codecs/max98090.c2
-rw-r--r--sound/soc/codecs/max98925.c23
-rw-r--r--sound/soc/codecs/max98927.c155
-rw-r--r--sound/soc/codecs/max98927.h7
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c120
-rw-r--r--sound/soc/codecs/msm8916-wcd-digital.c4
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c4
-rw-r--r--sound/soc/codecs/pcm512x-spi.c2
-rw-r--r--sound/soc/codecs/pcm512x.c4
-rw-r--r--sound/soc/codecs/pcm512x.h2
-rw-r--r--sound/soc/codecs/rl6231.c5
-rw-r--r--sound/soc/codecs/rt5514-spi.c46
-rw-r--r--sound/soc/codecs/rt5514.c6
-rw-r--r--sound/soc/codecs/rt5645.c39
-rw-r--r--sound/soc/codecs/rt5651.c219
-rw-r--r--sound/soc/codecs/rt5651.h4
-rw-r--r--sound/soc/codecs/rt5659.c26
-rw-r--r--sound/soc/codecs/rt5663.c272
-rw-r--r--sound/soc/codecs/rt5670.c143
-rw-r--r--sound/soc/codecs/rt5670.h4
-rw-r--r--sound/soc/codecs/tas571x.c3
-rw-r--r--sound/soc/codecs/tfa9879.c6
-rw-r--r--sound/soc/codecs/tlv320aic23.c1
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c2
-rw-r--r--sound/soc/codecs/tpa6130a2.c1
-rw-r--r--sound/soc/codecs/ts3a227e.c10
-rw-r--r--sound/soc/codecs/wm5102.c14
-rw-r--r--sound/soc/codecs/wm5110.c14
-rw-r--r--sound/soc/codecs/wm8741.c39
-rw-r--r--sound/soc/codecs/wm8753.c4
-rw-r--r--sound/soc/codecs/wm8993.c2
-rw-r--r--sound/soc/codecs/wm8994.c2
-rw-r--r--sound/soc/codecs/wm8997.c15
-rw-r--r--sound/soc/codecs/wm8998.c95
-rw-r--r--sound/soc/codecs/wm9705.c68
-rw-r--r--sound/soc/codecs/wm9712.c48
-rw-r--r--sound/soc/codecs/wm9713.c39
-rw-r--r--sound/soc/davinci/davinci-mcasp.c21
-rw-r--r--sound/soc/dwc/Kconfig4
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c14
-rw-r--r--sound/soc/fsl/fsl_spdif.c4
-rw-r--r--sound/soc/fsl/fsl_ssi.c46
-rw-r--r--sound/soc/generic/audio-graph-card.c47
-rw-r--r--sound/soc/img/img-i2s-in.c130
-rw-r--r--sound/soc/img/img-i2s-out.c120
-rw-r--r--sound/soc/img/img-parallel-out.c6
-rw-r--r--sound/soc/img/img-spdif-in.c110
-rw-r--r--sound/soc/img/img-spdif-out.c87
-rw-r--r--sound/soc/intel/Kconfig302
-rw-r--r--sound/soc/intel/Makefile2
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-compress.c2
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform.h2
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c312
-rw-r--r--sound/soc/intel/atom/sst/sst_loader.c1
-rw-r--r--sound/soc/intel/atom/sst/sst_stream.c1
-rw-r--r--sound/soc/intel/boards/Kconfig265
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c16
-rw-r--r--sound/soc/intel/boards/bytcht_da7213.c23
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c27
-rw-r--r--sound/soc/intel/boards/bytcht_nocodec.c10
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c118
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c297
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c185
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c128
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c68
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c76
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c3
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c16
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c16
-rw-r--r--sound/soc/intel/common/Makefile4
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-byt-match.c196
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cht-match.c194
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c64
-rw-r--r--sound/soc/intel/common/sst-acpi.c36
-rw-r--r--sound/soc/intel/common/sst-acpi.h82
-rw-r--r--sound/soc/intel/common/sst-firmware.c3
-rw-r--r--sound/soc/intel/skylake/skl-messages.c32
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c9
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c49
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c15
-rw-r--r--sound/soc/intel/skylake/skl-topology.c70
-rw-r--r--sound/soc/intel/skylake/skl-topology.h10
-rw-r--r--sound/soc/intel/skylake/skl.c50
-rw-r--r--sound/soc/intel/skylake/skl.h4
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c2
-rw-r--r--sound/soc/kirkwood/kirkwood.h2
-rw-r--r--sound/soc/omap/ams-delta.c4
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c3
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c32
-rw-r--r--sound/soc/qcom/lpass-platform.c2
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c159
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c1
-rw-r--r--sound/soc/samsung/i2s.c10
-rw-r--r--sound/soc/samsung/i2s.h3
-rw-r--r--sound/soc/samsung/tm2_wm5110.c7
-rw-r--r--sound/soc/sh/fsi.c11
-rw-r--r--sound/soc/sh/rcar/adg.c72
-rw-r--r--sound/soc/sh/rcar/core.c51
-rw-r--r--sound/soc/sh/rcar/ctu.c88
-rw-r--r--sound/soc/sh/rcar/dma.c84
-rw-r--r--sound/soc/sh/rcar/dvc.c60
-rw-r--r--sound/soc/sh/rcar/mix.c158
-rw-r--r--sound/soc/sh/rcar/rsnd.h22
-rw-r--r--sound/soc/sh/rcar/ssi.c58
-rw-r--r--sound/soc/soc-acpi.c (renamed from sound/soc/intel/common/sst-match-acpi.c)56
-rw-r--r--sound/soc/soc-compress.c461
-rw-r--r--sound/soc/soc-core.c222
-rw-r--r--sound/soc/soc-dapm.c158
-rw-r--r--sound/soc/soc-io.c14
-rw-r--r--sound/soc/soc-pcm.c462
-rw-r--r--sound/soc/stm/stm32_sai.c162
-rw-r--r--sound/soc/stm/stm32_sai.h22
-rw-r--r--sound/soc/stm/stm32_sai_sub.c162
-rw-r--r--sound/soc/stm/stm32_spdifrx.c23
-rw-r--r--sound/soc/sunxi/sun4i-codec.c29
-rw-r--r--sound/soc/sunxi/sun8i-codec.c72
-rw-r--r--sound/soc/zte/zx-spdif.c4
136 files changed, 6422 insertions, 2333 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index c0abad2067e1..d22758165496 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -36,6 +36,9 @@ config SND_SOC_COMPRESS
config SND_SOC_TOPOLOGY
bool
+config SND_SOC_ACPI
+ tristate
+
# All the supported SoCs
source "sound/soc/adi/Kconfig"
source "sound/soc/amd/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index bf8c1e2ce0bf..5327f4d6c668 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -15,6 +15,12 @@ ifneq ($(CONFIG_SND_SOC_AC97_BUS),)
snd-soc-core-objs += soc-ac97.o
endif
+ifneq ($(CONFIG_SND_SOC_ACPI),)
+snd-soc-acpi-objs := soc-acpi.o
+endif
+
+obj-$(CONFIG_SND_SOC_ACPI) += snd-soc-acpi.o
+
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 78187eb24f56..d5838402f667 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -2,3 +2,10 @@ config SND_SOC_AMD_ACP
tristate "AMD Audio Coprocessor support"
help
This option enables ACP DMA support on AMD platform.
+
+config SND_SOC_AMD_CZ_RT5645_MACH
+ tristate "AMD CZ support for RT5645"
+ select SND_SOC_RT5645
+ depends on SND_SOC_AMD_ACP && I2C
+ help
+ This option enables machine driver for rt5645.
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index 1a66ec0366b2..f07fd2e2870a 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -1,3 +1,5 @@
-snd-soc-acp-pcm-objs := acp-pcm-dma.o
+acp_audio_dma-objs := acp-pcm-dma.o
+snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
-obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o
+obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
+obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 08b1399d1da2..9f521a55d610 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -20,7 +20,7 @@
#include <linux/pm_runtime.h>
#include <sound/soc.h>
-
+#include <drm/amd_asic_type.h>
#include "acp.h"
#define PLAYBACK_MIN_NUM_PERIODS 2
@@ -35,6 +35,13 @@
#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
#define MIN_BUFFER MAX_BUFFER
+#define ST_PLAYBACK_MAX_PERIOD_SIZE 8192
+#define ST_CAPTURE_MAX_PERIOD_SIZE ST_PLAYBACK_MAX_PERIOD_SIZE
+#define ST_MAX_BUFFER (ST_PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
+#define ST_MIN_BUFFER ST_MAX_BUFFER
+
+#define DRV_NAME "acp_audio_dma"
+
static const struct snd_pcm_hardware acp_pcm_hardware_playback = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
@@ -73,10 +80,42 @@ static const struct snd_pcm_hardware acp_pcm_hardware_capture = {
.periods_max = CAPTURE_MAX_NUM_PERIODS,
};
-struct audio_drv_data {
- struct snd_pcm_substream *play_stream;
- struct snd_pcm_substream *capture_stream;
- void __iomem *acp_mmio;
+static const struct snd_pcm_hardware acp_st_pcm_hardware_playback = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .buffer_bytes_max = ST_MAX_BUFFER,
+ .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+ .period_bytes_max = ST_PLAYBACK_MAX_PERIOD_SIZE,
+ .periods_min = PLAYBACK_MIN_NUM_PERIODS,
+ .periods_max = PLAYBACK_MAX_NUM_PERIODS,
+};
+
+static const struct snd_pcm_hardware acp_st_pcm_hardware_capture = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .buffer_bytes_max = ST_MAX_BUFFER,
+ .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = ST_CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = CAPTURE_MIN_NUM_PERIODS,
+ .periods_max = CAPTURE_MAX_NUM_PERIODS,
};
static u32 acp_reg_read(void __iomem *acp_mmio, u32 reg)
@@ -143,8 +182,8 @@ static void config_dma_descriptor_in_sram(void __iomem *acp_mmio,
* system memory <-> ACP SRAM
*/
static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
- u32 size, int direction,
- u32 pte_offset)
+ u32 size, int direction,
+ u32 pte_offset, u32 asic_type)
{
u16 i;
u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
@@ -154,24 +193,46 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
dmadscr[i].xfer_val = 0;
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i;
- dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS +
- (size / 2) - (i * (size/2));
+ dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS
+ + (i * (size/2));
dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
+ (pte_offset * SZ_4K) + (i * (size/2));
- dmadscr[i].xfer_val |=
- (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) |
- (size / 2);
+ switch (asic_type) {
+ case CHIP_STONEY:
+ dmadscr[i].xfer_val |=
+ (ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM << 16) |
+ (size / 2);
+ break;
+ default:
+ dmadscr[i].xfer_val |=
+ (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) |
+ (size / 2);
+ }
} else {
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i;
- dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
- (i * (size/2));
- dmadscr[i].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
- + (pte_offset * SZ_4K) +
- (i * (size/2));
- dmadscr[i].xfer_val |=
- BIT(22) |
- (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
- (size / 2);
+ switch (asic_type) {
+ case CHIP_STONEY:
+ dmadscr[i].src = ACP_SHARED_RAM_BANK_3_ADDRESS +
+ (i * (size/2));
+ dmadscr[i].dest =
+ ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
+ (pte_offset * SZ_4K) + (i * (size/2));
+ dmadscr[i].xfer_val |=
+ BIT(22) |
+ (ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC << 16) |
+ (size / 2);
+ break;
+ default:
+ dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
+ (i * (size/2));
+ dmadscr[i].dest =
+ ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
+ (pte_offset * SZ_4K) + (i * (size/2));
+ dmadscr[i].xfer_val |=
+ BIT(22) |
+ (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
+ (size / 2);
+ }
}
config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
&dmadscr[i]);
@@ -192,7 +253,8 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
* ACP SRAM <-> I2S
*/
static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
- u32 size, int direction)
+ u32 size, int direction,
+ u32 asic_type)
{
u16 i;
@@ -213,8 +275,17 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i;
/* dmadscr[i].src is unused by hardware. */
dmadscr[i].src = 0;
- dmadscr[i].dest = ACP_SHARED_RAM_BANK_5_ADDRESS +
+ switch (asic_type) {
+ case CHIP_STONEY:
+ dmadscr[i].dest =
+ ACP_SHARED_RAM_BANK_3_ADDRESS +
(i * (size / 2));
+ break;
+ default:
+ dmadscr[i].dest =
+ ACP_SHARED_RAM_BANK_5_ADDRESS +
+ (i * (size / 2));
+ }
dmadscr[i].xfer_val |= BIT(22) |
(FROM_ACP_I2S_1 << 16) | (size / 2);
}
@@ -270,7 +341,8 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
}
static void config_acp_dma(void __iomem *acp_mmio,
- struct audio_substream_data *audio_config)
+ struct audio_substream_data *audio_config,
+ u32 asic_type)
{
u32 pte_offset;
@@ -284,11 +356,11 @@ static void config_acp_dma(void __iomem *acp_mmio,
/* Configure System memory <-> ACP SRAM DMA descriptors */
set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
- audio_config->direction, pte_offset);
+ audio_config->direction, pte_offset, asic_type);
/* Configure ACP SRAM <-> I2S DMA descriptors */
set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
- audio_config->direction);
+ audio_config->direction, asic_type);
}
/* Start a given DMA channel transfer */
@@ -425,7 +497,7 @@ static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank,
}
/* Initialize and bring ACP hardware to default state. */
-static int acp_init(void __iomem *acp_mmio)
+static int acp_init(void __iomem *acp_mmio, u32 asic_type)
{
u16 bank;
u32 val, count, sram_pte_offset;
@@ -499,10 +571,21 @@ static int acp_init(void __iomem *acp_mmio)
/* When ACP_TILE_P1 is turned on, all SRAM banks get turned on.
* Now, turn off all of them. This can't be done in 'poweron' of
* ACP pm domain, as this requires ACP to be initialized.
+ * For Stoney, Memory gating is disabled,i.e SRAM Banks
+ * won't be turned off. The default state for SRAM banks is ON.
+ * Setting SRAM bank state code skipped for STONEY platform.
*/
- for (bank = 1; bank < 48; bank++)
- acp_set_sram_bank_state(acp_mmio, bank, false);
+ if (asic_type != CHIP_STONEY) {
+ for (bank = 1; bank < 48; bank++)
+ acp_set_sram_bank_state(acp_mmio, bank, false);
+ }
+ /* Stoney supports 16bit resolution */
+ if (asic_type == CHIP_STONEY) {
+ val = acp_reg_read(acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
+ val |= 0x03;
+ acp_reg_write(val, acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
+ }
return 0;
}
@@ -572,9 +655,9 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
valid_irq = true;
if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) ==
PLAYBACK_START_DMA_DESCR_CH13)
- dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
- else
dscr_idx = PLAYBACK_END_DMA_DESCR_CH12;
+ else
+ dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx,
1, 0);
acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
@@ -626,10 +709,23 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
if (adata == NULL)
return -ENOMEM;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- runtime->hw = acp_pcm_hardware_playback;
- else
- runtime->hw = acp_pcm_hardware_capture;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (intr_data->asic_type) {
+ case CHIP_STONEY:
+ runtime->hw = acp_st_pcm_hardware_playback;
+ break;
+ default:
+ runtime->hw = acp_pcm_hardware_playback;
+ }
+ } else {
+ switch (intr_data->asic_type) {
+ case CHIP_STONEY:
+ runtime->hw = acp_st_pcm_hardware_capture;
+ break;
+ default:
+ runtime->hw = acp_pcm_hardware_capture;
+ }
+ }
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
@@ -652,14 +748,22 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
intr_data->play_stream = substream;
- for (bank = 1; bank <= 4; bank++)
- acp_set_sram_bank_state(intr_data->acp_mmio, bank,
- true);
+ /* For Stoney, Memory gating is disabled,i.e SRAM Banks
+ * won't be turned off. The default state for SRAM banks is ON.
+ * Setting SRAM bank state code skipped for STONEY platform.
+ */
+ if (intr_data->asic_type != CHIP_STONEY) {
+ for (bank = 1; bank <= 4; bank++)
+ acp_set_sram_bank_state(intr_data->acp_mmio,
+ bank, true);
+ }
} else {
intr_data->capture_stream = substream;
- for (bank = 5; bank <= 8; bank++)
- acp_set_sram_bank_state(intr_data->acp_mmio, bank,
- true);
+ if (intr_data->asic_type != CHIP_STONEY) {
+ for (bank = 5; bank <= 8; bank++)
+ acp_set_sram_bank_state(intr_data->acp_mmio,
+ bank, true);
+ }
}
return 0;
@@ -673,6 +777,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
struct page *pg;
struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd;
+ struct snd_soc_pcm_runtime *prtd = substream->private_data;
+ struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
runtime = substream->runtime;
rtd = runtime->private_data;
@@ -700,7 +806,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
rtd->direction = substream->stream;
- config_acp_dma(rtd->acp_mmio, rtd);
+ config_acp_dma(rtd->acp_mmio, rtd, adata->asic_type);
status = 0;
} else {
status = -ENOMEM;
@@ -713,40 +819,48 @@ static int acp_dma_hw_free(struct snd_pcm_substream *substream)
return snd_pcm_lib_free_pages(substream);
}
+static u64 acp_get_byte_count(void __iomem *acp_mmio, int stream)
+{
+ union acp_dma_count playback_dma_count;
+ union acp_dma_count capture_dma_count;
+ u64 bytescount = 0;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ playback_dma_count.bcount.high = acp_reg_read(acp_mmio,
+ mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH);
+ playback_dma_count.bcount.low = acp_reg_read(acp_mmio,
+ mmACP_I2S_TRANSMIT_BYTE_CNT_LOW);
+ bytescount = playback_dma_count.bytescount;
+ } else {
+ capture_dma_count.bcount.high = acp_reg_read(acp_mmio,
+ mmACP_I2S_RECEIVED_BYTE_CNT_HIGH);
+ capture_dma_count.bcount.low = acp_reg_read(acp_mmio,
+ mmACP_I2S_RECEIVED_BYTE_CNT_LOW);
+ bytescount = capture_dma_count.bytescount;
+ }
+ return bytescount;
+}
+
static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
{
- u16 dscr;
- u32 mul, dma_config, period_bytes;
+ u32 buffersize;
u32 pos = 0;
+ u64 bytescount = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_substream_data *rtd = runtime->private_data;
- period_bytes = frames_to_bytes(runtime, runtime->period_size);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- dscr = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CUR_DSCR_13);
+ buffersize = frames_to_bytes(runtime, runtime->buffer_size);
+ bytescount = acp_get_byte_count(rtd->acp_mmio, substream->stream);
- if (dscr == PLAYBACK_START_DMA_DESCR_CH13)
- mul = 0;
- else
- mul = 1;
- pos = (mul * period_bytes);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (bytescount > rtd->renderbytescount)
+ bytescount = bytescount - rtd->renderbytescount;
} else {
- dma_config = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CNTL_14);
- if (dma_config != 0) {
- dscr = acp_reg_read(rtd->acp_mmio,
- mmACP_DMA_CUR_DSCR_14);
- if (dscr == CAPTURE_START_DMA_DESCR_CH14)
- mul = 1;
- else
- mul = 2;
- pos = (mul * period_bytes);
- }
-
- if (pos >= (2 * period_bytes))
- pos = 0;
-
+ if (bytescount > rtd->capturebytescount)
+ bytescount = bytescount - rtd->capturebytescount;
}
+ pos = do_div(bytescount, buffersize);
return bytes_to_frames(runtime, pos);
}
@@ -768,23 +882,6 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
PLAYBACK_START_DMA_DESCR_CH13,
NUM_DSCRS_PER_CHANNEL, 0);
- /* Fill ACP SRAM (2 periods) with zeros from System RAM
- * which is zero-ed in hw_params
- */
- acp_dma_start(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
-
- /* ACP SRAM (2 periods of buffer size) is intially filled with
- * zeros. Before rendering starts, 2nd half of SRAM will be
- * filled with valid audio data DMA'ed from first half of system
- * RAM and 1st half of SRAM will be filled with Zeros. This is
- * the initial scenario when redering starts from SRAM. Later
- * on, 2nd half of system memory will be DMA'ed to 1st half of
- * SRAM, 1st half of system memory will be DMA'ed to 2nd half of
- * SRAM in ping-pong way till rendering stops.
- */
- config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
- PLAYBACK_START_DMA_DESCR_CH12,
- 1, 0);
} else {
config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM,
CAPTURE_START_DMA_DESCR_CH14,
@@ -799,7 +896,8 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
int ret;
- u32 loops = 1000;
+ u32 loops = 4000;
+ u64 bytescount = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -811,7 +909,11 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
+ bytescount = acp_get_byte_count(rtd->acp_mmio,
+ substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (rtd->renderbytescount == 0)
+ rtd->renderbytescount = bytescount;
acp_dma_start(rtd->acp_mmio,
SYSRAM_TO_ACP_CH_NUM, false);
while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) &
@@ -828,6 +930,8 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
ACP_TO_I2S_DMA_CH_NUM, true);
} else {
+ if (rtd->capturebytescount == 0)
+ rtd->capturebytescount = bytescount;
acp_dma_start(rtd->acp_mmio,
I2S_TO_ACP_DMA_CH_NUM, true);
}
@@ -841,12 +945,15 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
* channels will stopped automatically after its transfer
* completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM
*/
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = acp_dma_stop(rtd->acp_mmio,
ACP_TO_I2S_DMA_CH_NUM);
- else
+ rtd->renderbytescount = 0;
+ } else {
ret = acp_dma_stop(rtd->acp_mmio,
I2S_TO_ACP_DMA_CH_NUM);
+ rtd->capturebytescount = 0;
+ }
break;
default:
ret = -EINVAL;
@@ -857,10 +964,27 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
{
- return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+ int ret;
+ struct audio_drv_data *adata = dev_get_drvdata(rtd->platform->dev);
+
+ 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,
+ ST_MAX_BUFFER);
+ break;
+ default:
+ ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
NULL, MIN_BUFFER,
MAX_BUFFER);
+ break;
+ }
+ if (ret < 0)
+ dev_err(rtd->platform->dev,
+ "buffer preallocation failer error:%d\n", ret);
+ return ret;
}
static int acp_dma_close(struct snd_pcm_substream *substream)
@@ -875,14 +999,23 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
adata->play_stream = NULL;
- for (bank = 1; bank <= 4; bank++)
- acp_set_sram_bank_state(adata->acp_mmio, bank,
- false);
- } else {
+ /* For Stoney, Memory gating is disabled,i.e SRAM Banks
+ * won't be turned off. The default state for SRAM banks is ON.
+ * Setting SRAM bank state code skipped for STONEY platform.
+ * added condition checks for Carrizo platform only
+ */
+ if (adata->asic_type != CHIP_STONEY) {
+ for (bank = 1; bank <= 4; bank++)
+ acp_set_sram_bank_state(adata->acp_mmio, bank,
+ false);
+ }
+ } else {
adata->capture_stream = NULL;
- for (bank = 5; bank <= 8; bank++)
- acp_set_sram_bank_state(adata->acp_mmio, bank,
- false);
+ if (adata->asic_type != CHIP_STONEY) {
+ for (bank = 5; bank <= 8; bank++)
+ acp_set_sram_bank_state(adata->acp_mmio, bank,
+ false);
+ }
}
/* Disable ACP irq, when the current stream is being closed and
@@ -916,6 +1049,7 @@ static int acp_audio_probe(struct platform_device *pdev)
int status;
struct audio_drv_data *audio_drv_data;
struct resource *res;
+ const u32 *pdata = pdev->dev.platform_data;
audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data),
GFP_KERNEL);
@@ -932,6 +1066,7 @@ static int acp_audio_probe(struct platform_device *pdev)
audio_drv_data->play_stream = NULL;
audio_drv_data->capture_stream = NULL;
+ audio_drv_data->asic_type = *pdata;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
@@ -949,7 +1084,7 @@ static int acp_audio_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, audio_drv_data);
/* Initialize the ACP */
- acp_init(audio_drv_data->acp_mmio);
+ acp_init(audio_drv_data->acp_mmio, audio_drv_data->asic_type);
status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform);
if (status != 0) {
@@ -980,21 +1115,31 @@ static int acp_pcm_resume(struct device *dev)
u16 bank;
struct audio_drv_data *adata = dev_get_drvdata(dev);
- acp_init(adata->acp_mmio);
+ acp_init(adata->acp_mmio, adata->asic_type);
if (adata->play_stream && adata->play_stream->runtime) {
- for (bank = 1; bank <= 4; bank++)
- acp_set_sram_bank_state(adata->acp_mmio, bank,
+ /* For Stoney, Memory gating is disabled,i.e SRAM Banks
+ * won't be turned off. The default state for SRAM banks is ON.
+ * Setting SRAM bank state code skipped for STONEY platform.
+ */
+ if (adata->asic_type != CHIP_STONEY) {
+ for (bank = 1; bank <= 4; bank++)
+ acp_set_sram_bank_state(adata->acp_mmio, bank,
true);
+ }
config_acp_dma(adata->acp_mmio,
- adata->play_stream->runtime->private_data);
+ adata->play_stream->runtime->private_data,
+ adata->asic_type);
}
if (adata->capture_stream && adata->capture_stream->runtime) {
- for (bank = 5; bank <= 8; bank++)
- acp_set_sram_bank_state(adata->acp_mmio, bank,
+ if (adata->asic_type != CHIP_STONEY) {
+ for (bank = 5; bank <= 8; bank++)
+ acp_set_sram_bank_state(adata->acp_mmio, bank,
true);
+ }
config_acp_dma(adata->acp_mmio,
- adata->capture_stream->runtime->private_data);
+ adata->capture_stream->runtime->private_data,
+ adata->asic_type);
}
acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
return 0;
@@ -1013,7 +1158,7 @@ static int acp_pcm_runtime_resume(struct device *dev)
{
struct audio_drv_data *adata = dev_get_drvdata(dev);
- acp_init(adata->acp_mmio);
+ acp_init(adata->acp_mmio, adata->asic_type);
acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
return 0;
}
@@ -1028,14 +1173,15 @@ static struct platform_driver acp_dma_driver = {
.probe = acp_audio_probe,
.remove = acp_audio_remove,
.driver = {
- .name = "acp_audio_dma",
+ .name = DRV_NAME,
.pm = &acp_pm_ops,
},
};
module_platform_driver(acp_dma_driver);
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
MODULE_DESCRIPTION("AMD ACP PCM Driver");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:acp-dma-audio");
+MODULE_ALIAS("platform:"DRV_NAME);
diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c
new file mode 100644
index 000000000000..941aed6bb364
--- /dev/null
+++ b/sound/soc/amd/acp-rt5645.c
@@ -0,0 +1,199 @@
+/*
+ * Machine driver for AMD ACP Audio engine using Realtek RT5645 codec
+ *
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * This file is modified from rt288 machine driver
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ */
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+
+#include "../codecs/rt5645.h"
+
+#define CZ_PLAT_CLK 24000000
+
+static struct snd_soc_jack cz_jack;
+
+static int cz_aif1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
+ CZ_PLAT_CLK, params_rate(params) * 512);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1,
+ params_rate(params) * 512, SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cz_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct snd_soc_card *card;
+ struct snd_soc_codec *codec;
+
+ codec = rtd->codec;
+ card = rtd->card;
+
+ ret = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &cz_jack, NULL, 0);
+ if (ret) {
+ dev_err(card->dev, "HP jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ rt5645_set_jack_detect(codec, &cz_jack, &cz_jack, &cz_jack);
+
+ return 0;
+}
+
+static struct snd_soc_ops cz_aif1_ops = {
+ .hw_params = cz_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link cz_dai_rt5650[] = {
+ {
+ .name = "amd-rt5645-play",
+ .stream_name = "RT5645_AIF1",
+ .platform_name = "acp_audio_dma.0.auto",
+ .cpu_dai_name = "designware-i2s.1.auto",
+ .codec_dai_name = "rt5645-aif1",
+ .codec_name = "i2c-10EC5650:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .init = cz_init,
+ .ops = &cz_aif1_ops,
+ },
+ {
+ .name = "amd-rt5645-cap",
+ .stream_name = "RT5645_AIF1",
+ .platform_name = "acp_audio_dma.0.auto",
+ .cpu_dai_name = "designware-i2s.2.auto",
+ .codec_dai_name = "rt5645-aif1",
+ .codec_name = "i2c-10EC5650:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .ops = &cz_aif1_ops,
+ },
+};
+
+static const struct snd_soc_dapm_widget cz_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route cz_audio_route[] = {
+ {"Headphones", NULL, "HPOL"},
+ {"Headphones", NULL, "HPOR"},
+ {"RECMIXL", NULL, "Headset Mic"},
+ {"RECMIXR", NULL, "Headset Mic"},
+ {"Speakers", NULL, "SPOL"},
+ {"Speakers", NULL, "SPOR"},
+ {"DMIC L2", NULL, "Int Mic"},
+ {"DMIC R2", NULL, "Int Mic"},
+};
+
+static const struct snd_kcontrol_new cz_mc_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphones"),
+ SOC_DAPM_PIN_SWITCH("Speakers"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static struct snd_soc_card cz_card = {
+ .name = "acprt5650",
+ .owner = THIS_MODULE,
+ .dai_link = cz_dai_rt5650,
+ .num_links = ARRAY_SIZE(cz_dai_rt5650),
+ .dapm_widgets = cz_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cz_widgets),
+ .dapm_routes = cz_audio_route,
+ .num_dapm_routes = ARRAY_SIZE(cz_audio_route),
+ .controls = cz_mc_controls,
+ .num_controls = ARRAY_SIZE(cz_mc_controls),
+};
+
+static int cz_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct snd_soc_card *card;
+
+ card = &cz_card;
+ cz_card.dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "devm_snd_soc_register_card(%s) failed: %d\n",
+ cz_card.name, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct acpi_device_id cz_audio_acpi_match[] = {
+ { "AMDI1002", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
+
+static struct platform_driver cz_pcm_driver = {
+ .driver = {
+ .name = "cz-rt5645",
+ .acpi_match_table = ACPI_PTR(cz_audio_acpi_match),
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = cz_probe,
+};
+
+module_platform_driver(cz_pcm_driver);
+
+MODULE_AUTHOR("akshu.agrawal@amd.com");
+MODULE_DESCRIPTION("cz-rt5645 audio support");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index 9d338216c5ae..ecb458935d1e 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -20,6 +20,7 @@
/* Capture SRAM address (as a source in dma descriptor) */
#define ACP_SHARED_RAM_BANK_5_ADDRESS 0x400A000
+#define ACP_SHARED_RAM_BANK_3_ADDRESS 0x4006000
#define ACP_DMA_RESET_TIME 10000
#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF
@@ -68,6 +69,7 @@
#define CAPTURE_START_DMA_DESCR_CH15 6
#define CAPTURE_END_DMA_DESCR_CH15 7
+#define mmACP_I2S_16BIT_RESOLUTION_EN 0x5209
enum acp_dma_priority_level {
/* 0x0 Specifies the DMA channel is given normal priority */
ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
@@ -82,9 +84,26 @@ struct audio_substream_data {
u16 num_of_pages;
u16 direction;
uint64_t size;
+ u64 renderbytescount;
+ u64 capturebytescount;
void __iomem *acp_mmio;
};
+struct audio_drv_data {
+ struct snd_pcm_substream *play_stream;
+ struct snd_pcm_substream *capture_stream;
+ void __iomem *acp_mmio;
+ u32 asic_type;
+};
+
+union acp_dma_count {
+ struct {
+ u32 low;
+ u32 high;
+ } bcount;
+ u64 bytescount;
+};
+
enum {
ACP_TILE_P1 = 0,
ACP_TILE_P2,
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 6ba20498202e..2e449d7173fc 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -31,6 +31,7 @@
* General Public License for more details.
*/
+#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -99,6 +100,8 @@
#define BCM2835_I2S_CHWID(v) (v)
#define BCM2835_I2S_CH1(v) ((v) << 16)
#define BCM2835_I2S_CH2(v) (v)
+#define BCM2835_I2S_CH1_POS(v) BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(v))
+#define BCM2835_I2S_CH2_POS(v) BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(v))
#define BCM2835_I2S_TX_PANIC(v) ((v) << 24)
#define BCM2835_I2S_RX_PANIC(v) ((v) << 16)
@@ -110,12 +113,19 @@
#define BCM2835_I2S_INT_RXR BIT(1)
#define BCM2835_I2S_INT_TXW BIT(0)
+/* Frame length register is 10 bit, maximum length 1024 */
+#define BCM2835_I2S_MAX_FRAME_LENGTH 1024
+
/* General device struct */
struct bcm2835_i2s_dev {
struct device *dev;
struct snd_dmaengine_dai_dma_data dma_data[2];
unsigned int fmt;
- unsigned int bclk_ratio;
+ unsigned int tdm_slots;
+ unsigned int rx_mask;
+ unsigned int tx_mask;
+ unsigned int slot_width;
+ unsigned int frame_length;
struct regmap *i2s_regmap;
struct clk *clk;
@@ -225,19 +235,120 @@ static int bcm2835_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
unsigned int ratio)
{
struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
- dev->bclk_ratio = ratio;
+
+ if (!ratio) {
+ dev->tdm_slots = 0;
+ return 0;
+ }
+
+ if (ratio > BCM2835_I2S_MAX_FRAME_LENGTH)
+ return -EINVAL;
+
+ dev->tdm_slots = 2;
+ dev->rx_mask = 0x03;
+ dev->tx_mask = 0x03;
+ dev->slot_width = ratio / 2;
+ dev->frame_length = ratio;
+
return 0;
}
+static int bcm2835_i2s_set_dai_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int width)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ if (slots) {
+ if (slots < 0 || width < 0)
+ return -EINVAL;
+
+ /* Limit masks to available slots */
+ rx_mask &= GENMASK(slots - 1, 0);
+ tx_mask &= GENMASK(slots - 1, 0);
+
+ /*
+ * The driver is limited to 2-channel setups.
+ * Check that exactly 2 bits are set in the masks.
+ */
+ if (hweight_long((unsigned long) rx_mask) != 2
+ || hweight_long((unsigned long) tx_mask) != 2)
+ return -EINVAL;
+
+ if (slots * width > BCM2835_I2S_MAX_FRAME_LENGTH)
+ return -EINVAL;
+ }
+
+ dev->tdm_slots = slots;
+
+ dev->rx_mask = rx_mask;
+ dev->tx_mask = tx_mask;
+ dev->slot_width = width;
+ dev->frame_length = slots * width;
+
+ return 0;
+}
+
+/*
+ * Convert logical slot number into physical slot number.
+ *
+ * If odd_offset is 0 sequential number is identical to logical number.
+ * This is used for DSP modes with slot numbering 0 1 2 3 ...
+ *
+ * Otherwise odd_offset defines the physical offset for odd numbered
+ * slots. This is used for I2S and left/right justified modes to
+ * translate from logical slot numbers 0 1 2 3 ... into physical slot
+ * numbers 0 2 ... 3 4 ...
+ */
+static int bcm2835_i2s_convert_slot(unsigned int slot, unsigned int odd_offset)
+{
+ if (!odd_offset)
+ return slot;
+
+ if (slot & 1)
+ return (slot >> 1) + odd_offset;
+
+ return slot >> 1;
+}
+
+/*
+ * Calculate channel position from mask and slot width.
+ *
+ * Mask must contain exactly 2 set bits.
+ * Lowest set bit is channel 1 position, highest set bit channel 2.
+ * The constant offset is added to both channel positions.
+ *
+ * If odd_offset is > 0 slot positions are translated to
+ * I2S-style TDM slot numbering ( 0 2 ... 3 4 ...) with odd
+ * logical slot numbers starting at physical slot odd_offset.
+ */
+static void bcm2835_i2s_calc_channel_pos(
+ unsigned int *ch1_pos, unsigned int *ch2_pos,
+ unsigned int mask, unsigned int width,
+ unsigned int bit_offset, unsigned int odd_offset)
+{
+ *ch1_pos = bcm2835_i2s_convert_slot((ffs(mask) - 1), odd_offset)
+ * width + bit_offset;
+ *ch2_pos = bcm2835_i2s_convert_slot((fls(mask) - 1), odd_offset)
+ * width + bit_offset;
+}
+
static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
- unsigned int sampling_rate = params_rate(params);
- unsigned int data_length, data_delay, bclk_ratio;
- unsigned int ch1pos, ch2pos, mode, format;
+ unsigned int data_length, data_delay, framesync_length;
+ unsigned int slots, slot_width, odd_slot_offset;
+ int frame_length, bclk_rate;
+ unsigned int rx_mask, tx_mask;
+ unsigned int rx_ch1_pos, rx_ch2_pos, tx_ch1_pos, tx_ch2_pos;
+ unsigned int mode, format;
+ bool bit_clock_master = false;
+ bool frame_sync_master = false;
+ bool frame_start_falling_edge = false;
uint32_t csreg;
+ int ret = 0;
/*
* If a stream is already enabled,
@@ -248,42 +359,70 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON))
return 0;
- /*
- * Adjust the data length according to the format.
- * We prefill the half frame length with an integer
- * divider of 2400 as explained at the clock settings.
- * Maybe it is overwritten there, if the Integer mode
- * does not apply.
- */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- data_length = 16;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- data_length = 24;
+ data_length = params_width(params);
+ data_delay = 0;
+ odd_slot_offset = 0;
+ mode = 0;
+
+ if (dev->tdm_slots) {
+ slots = dev->tdm_slots;
+ slot_width = dev->slot_width;
+ frame_length = dev->frame_length;
+ rx_mask = dev->rx_mask;
+ tx_mask = dev->tx_mask;
+ bclk_rate = dev->frame_length * params_rate(params);
+ } else {
+ slots = 2;
+ slot_width = params_width(params);
+ rx_mask = 0x03;
+ tx_mask = 0x03;
+
+ frame_length = snd_soc_params_to_frame_size(params);
+ if (frame_length < 0)
+ return frame_length;
+
+ bclk_rate = snd_soc_params_to_bclk(params);
+ if (bclk_rate < 0)
+ return bclk_rate;
+ }
+
+ /* Check if data fits into slots */
+ if (data_length > slot_width)
+ return -EINVAL;
+
+ /* Check if CPU is bit clock master */
+ switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBS_CFM:
+ bit_clock_master = true;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
- data_length = 32;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBM_CFM:
+ bit_clock_master = false;
break;
default:
return -EINVAL;
}
- /* If bclk_ratio already set, use that one. */
- if (dev->bclk_ratio)
- bclk_ratio = dev->bclk_ratio;
- else
- /* otherwise calculate a fitting block ratio */
- bclk_ratio = 2 * data_length;
-
- /* Clock should only be set up here if CPU is clock master */
+ /* Check if CPU is frame sync master */
switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ frame_sync_master = true;
+ break;
case SND_SOC_DAIFMT_CBS_CFM:
- clk_set_rate(dev->clk, sampling_rate * bclk_ratio);
+ case SND_SOC_DAIFMT_CBM_CFM:
+ frame_sync_master = false;
break;
default:
- break;
+ return -EINVAL;
+ }
+
+ /* Clock should only be set up here if CPU is clock master */
+ if (bit_clock_master) {
+ ret = clk_set_rate(dev->clk, bclk_rate);
+ if (ret)
+ return ret;
}
/* Setup the frame format */
@@ -294,43 +433,94 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
format |= BCM2835_I2S_CHWID((data_length-8)&0xf);
+ /* CH2 format is the same as for CH1 */
+ format = BCM2835_I2S_CH1(format) | BCM2835_I2S_CH2(format);
+
switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- data_delay = 1;
- break;
- default:
+ /* I2S mode needs an even number of slots */
+ if (slots & 1)
+ return -EINVAL;
+
/*
- * TODO
- * Others are possible but are not implemented at the moment.
+ * Use I2S-style logical slot numbering: even slots
+ * are in first half of frame, odd slots in second half.
*/
- dev_err(dev->dev, "%s:bad format\n", __func__);
- return -EINVAL;
- }
+ odd_slot_offset = slots >> 1;
- ch1pos = data_delay;
- ch2pos = bclk_ratio / 2 + data_delay;
+ /* MSB starts one cycle after frame start */
+ data_delay = 1;
- switch (params_channels(params)) {
- case 2:
- format = BCM2835_I2S_CH1(format) | BCM2835_I2S_CH2(format);
- format |= BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(ch1pos));
- format |= BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(ch2pos));
+ /* Setup frame sync signal for 50% duty cycle */
+ framesync_length = frame_length / 2;
+ frame_start_falling_edge = true;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ if (slots & 1)
+ return -EINVAL;
+
+ odd_slot_offset = slots >> 1;
+ data_delay = 0;
+ framesync_length = frame_length / 2;
+ frame_start_falling_edge = false;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ if (slots & 1)
+ return -EINVAL;
+
+ /* Odd frame lengths aren't supported */
+ if (frame_length & 1)
+ return -EINVAL;
+
+ odd_slot_offset = slots >> 1;
+ data_delay = slot_width - data_length;
+ framesync_length = frame_length / 2;
+ frame_start_falling_edge = false;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ data_delay = 1;
+ framesync_length = 1;
+ frame_start_falling_edge = false;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ data_delay = 0;
+ framesync_length = 1;
+ frame_start_falling_edge = false;
break;
default:
return -EINVAL;
}
+ bcm2835_i2s_calc_channel_pos(&rx_ch1_pos, &rx_ch2_pos,
+ rx_mask, slot_width, data_delay, odd_slot_offset);
+ bcm2835_i2s_calc_channel_pos(&tx_ch1_pos, &tx_ch2_pos,
+ tx_mask, slot_width, data_delay, odd_slot_offset);
+
+ /*
+ * Transmitting data immediately after frame start, eg
+ * in left-justified or DSP mode A, only works stable
+ * if bcm2835 is the frame clock master.
+ */
+ if ((!rx_ch1_pos || !tx_ch1_pos) && !frame_sync_master)
+ dev_warn(dev->dev,
+ "Unstable slave config detected, L/R may be swapped");
+
/*
* Set format for both streams.
* We cannot set another frame length
* (and therefore word length) anyway,
* so the format will be the same.
*/
- regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format);
- regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format);
+ regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG,
+ format
+ | BCM2835_I2S_CH1_POS(rx_ch1_pos)
+ | BCM2835_I2S_CH2_POS(rx_ch2_pos));
+ regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG,
+ format
+ | BCM2835_I2S_CH1_POS(tx_ch1_pos)
+ | BCM2835_I2S_CH2_POS(tx_ch2_pos));
/* Setup the I2S mode */
- mode = 0;
if (data_length <= 16) {
/*
@@ -342,65 +532,41 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP;
}
- mode |= BCM2835_I2S_FLEN(bclk_ratio - 1);
- mode |= BCM2835_I2S_FSLEN(bclk_ratio / 2);
+ mode |= BCM2835_I2S_FLEN(frame_length - 1);
+ mode |= BCM2835_I2S_FSLEN(framesync_length);
- /* Master or slave? */
- switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- /* CPU is master */
- break;
- case SND_SOC_DAIFMT_CBM_CFS:
- /*
- * CODEC is bit clock master
- * CPU is frame master
- */
+ /* CLKM selects bcm2835 clock slave mode */
+ if (!bit_clock_master)
mode |= BCM2835_I2S_CLKM;
- break;
- case SND_SOC_DAIFMT_CBS_CFM:
- /*
- * CODEC is frame master
- * CPU is bit clock master
- */
+
+ /* FSM selects bcm2835 frame sync slave mode */
+ if (!frame_sync_master)
mode |= BCM2835_I2S_FSM;
+
+ /* CLKI selects normal clocking mode, sampling on rising edge */
+ switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ case SND_SOC_DAIFMT_NB_IF:
+ mode |= BCM2835_I2S_CLKI;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
- /* CODEC is master */
- mode |= BCM2835_I2S_CLKM;
- mode |= BCM2835_I2S_FSM;
+ case SND_SOC_DAIFMT_IB_NF:
+ case SND_SOC_DAIFMT_IB_IF:
break;
default:
- dev_err(dev->dev, "%s:bad master\n", __func__);
return -EINVAL;
}
- /*
- * Invert clocks?
- *
- * The BCM approach seems to be inverted to the classical I2S approach.
- */
+ /* FSI selects frame start on falling edge */
switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
- /* None. Therefore, both for BCM */
- mode |= BCM2835_I2S_CLKI;
- mode |= BCM2835_I2S_FSI;
- break;
- case SND_SOC_DAIFMT_IB_IF:
- /* Both. Therefore, none for BCM */
+ case SND_SOC_DAIFMT_IB_NF:
+ if (frame_start_falling_edge)
+ mode |= BCM2835_I2S_FSI;
break;
case SND_SOC_DAIFMT_NB_IF:
- /*
- * Invert only frame sync. Therefore,
- * invert only bit clock for BCM
- */
- mode |= BCM2835_I2S_CLKI;
- break;
- case SND_SOC_DAIFMT_IB_NF:
- /*
- * Invert only bit clock. Therefore,
- * invert only frame sync for BCM
- */
- mode |= BCM2835_I2S_FSI;
+ case SND_SOC_DAIFMT_IB_IF:
+ if (!frame_start_falling_edge)
+ mode |= BCM2835_I2S_FSI;
break;
default:
return -EINVAL;
@@ -423,7 +589,27 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
/* Clear FIFOs */
bcm2835_i2s_clear_fifos(dev, true, true);
- return 0;
+ dev_dbg(dev->dev,
+ "slots: %d width: %d rx mask: 0x%02x tx_mask: 0x%02x\n",
+ slots, slot_width, rx_mask, tx_mask);
+
+ dev_dbg(dev->dev, "frame len: %d sync len: %d data len: %d\n",
+ frame_length, framesync_length, data_length);
+
+ dev_dbg(dev->dev, "rx pos: %d,%d tx pos: %d,%d\n",
+ rx_ch1_pos, rx_ch2_pos, tx_ch1_pos, tx_ch2_pos);
+
+ dev_dbg(dev->dev, "sampling rate: %d bclk rate: %d\n",
+ params_rate(params), bclk_rate);
+
+ dev_dbg(dev->dev, "CLKM: %d CLKI: %d FSM: %d FSI: %d frame start: %s edge\n",
+ !!(mode & BCM2835_I2S_CLKM),
+ !!(mode & BCM2835_I2S_CLKI),
+ !!(mode & BCM2835_I2S_FSM),
+ !!(mode & BCM2835_I2S_FSI),
+ (mode & BCM2835_I2S_FSI) ? "falling" : "rising");
+
+ return ret;
}
static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream,
@@ -559,6 +745,7 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
.hw_params = bcm2835_i2s_hw_params,
.set_fmt = bcm2835_i2s_set_dai_fmt,
.set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio,
+ .set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot,
};
static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
@@ -578,7 +765,9 @@ static struct snd_soc_dai_driver bcm2835_i2s_dai = {
.playback = {
.channels_min = 2,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_192000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 8000,
+ .rate_max = 384000,
.formats = SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S32_LE
@@ -586,13 +775,16 @@ static struct snd_soc_dai_driver bcm2835_i2s_dai = {
.capture = {
.channels_min = 2,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_192000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 8000,
+ .rate_max = 384000,
.formats = SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S32_LE
},
.ops = &bcm2835_i2s_dai_ops,
- .symmetric_rates = 1
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
};
static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg)
@@ -699,9 +891,6 @@ static int bcm2835_i2s_probe(struct platform_device *pdev)
dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].flags =
SND_DMAENGINE_PCM_DAI_FLAG_PACK;
- /* BCLK ratio - use default */
- dev->bclk_ratio = 0;
-
/* Store the pdev */
dev->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, dev);
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 15c438f0f22d..abafadc0b534 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -655,23 +655,10 @@ static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
- /* Configure channels as mono or stereo/TDM */
- if (params_channels(params) == 1)
- value |= BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
- else
- value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
+ value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- if (aio->port_type == PORT_SPDIF) {
- dev_err(aio->cygaud->dev,
- "SPDIF does not support 8bit format\n");
- return -EINVAL;
- }
- bitres = 8;
- break;
-
case SNDRV_PCM_FORMAT_S16_LE:
bitres = 16;
break;
@@ -842,6 +829,7 @@ int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
return -EINVAL;
}
}
+EXPORT_SYMBOL_GPL(cygnus_ssp_set_custom_fsync_width);
static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
@@ -998,7 +986,7 @@ static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
active_slots = hweight32(tx_mask);
- if ((active_slots < 0) || (active_slots > 16))
+ if (active_slots > 16)
return -EINVAL;
/* Slot value must be even */
@@ -1136,15 +1124,21 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
.set_tdm_slot = cygnus_set_dai_tdm_slot,
};
+static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = {
+ .startup = cygnus_ssp_startup,
+ .shutdown = cygnus_ssp_shutdown,
+ .trigger = cygnus_ssp_trigger,
+ .hw_params = cygnus_ssp_hw_params,
+ .set_sysclk = cygnus_ssp_set_sysclk,
+};
#define INIT_CPU_DAI(num) { \
.name = "cygnus-ssp" #num, \
.playback = { \
- .channels_min = 1, \
+ .channels_min = 2, \
.channels_max = 16, \
.rates = SNDRV_PCM_RATE_KNOT, \
- .formats = SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE | \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S32_LE, \
}, \
.capture = { \
@@ -1152,7 +1146,7 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
.channels_max = 16, \
.rates = SNDRV_PCM_RATE_KNOT, \
.formats = SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
+ SNDRV_PCM_FMTBIT_S32_LE, \
}, \
.ops = &cygnus_ssp_dai_ops, \
.suspend = cygnus_ssp_suspend, \
@@ -1174,7 +1168,7 @@ static const struct snd_soc_dai_driver cygnus_spdif_dai_info = {
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
- .ops = &cygnus_ssp_dai_ops,
+ .ops = &cygnus_spdif_dai_ops,
.suspend = cygnus_ssp_suspend,
.resume = cygnus_ssp_resume,
};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index c367d11079bc..a42ddbc93f3d 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -214,9 +214,9 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8998 if MFD_WM8998
select SND_SOC_WM9081 if I2C
select SND_SOC_WM9090 if I2C
- select SND_SOC_WM9705 if SND_SOC_AC97_BUS
- select SND_SOC_WM9712 if SND_SOC_AC97_BUS
- select SND_SOC_WM9713 if SND_SOC_AC97_BUS
+ select SND_SOC_WM9705 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
+ select SND_SOC_WM9712 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
+ select SND_SOC_WM9713 if (SND_SOC_AC97_BUS || SND_SOC_AC97_BUS_NEW)
help
Normally ASoC codec drivers are only built if a machine driver which
uses them is also built since they are only usable with a machine
@@ -749,6 +749,10 @@ config SND_SOC_RT5514
config SND_SOC_RT5514_SPI
tristate
+config SND_SOC_RT5514_SPI_BUILTIN
+ bool # force RT5514_SPI to be built-in to avoid link errors
+ default SND_SOC_RT5514=y && SND_SOC_RT5514_SPI=m
+
config SND_SOC_RT5616
tristate "Realtek RT5616 CODEC"
depends on I2C
@@ -1128,14 +1132,17 @@ config SND_SOC_WM9090
config SND_SOC_WM9705
tristate
select REGMAP_AC97
+ select AC97_BUS_COMPAT if AC97_BUS_NEW
config SND_SOC_WM9712
tristate
select REGMAP_AC97
+ select AC97_BUS_COMPAT if AC97_BUS_NEW
config SND_SOC_WM9713
tristate
select REGMAP_AC97
+ select AC97_BUS_COMPAT if AC97_BUS_NEW
config SND_SOC_ZX_AUD96P22
tristate "ZTE ZX AUD96P22 CODEC"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 05018b7ca72b..0001069ce2a7 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -360,6 +360,7 @@ obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o
obj-$(CONFIG_SND_SOC_RT5514_SPI) += snd-soc-rt5514-spi.o
+obj-$(CONFIG_SND_SOC_RT5514_SPI_BUILTIN) += snd-soc-rt5514-spi.o
obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index a1149f6a8450..b3375e19598a 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -293,16 +294,99 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
}
EXPORT_SYMBOL_GPL(arizona_init_gpio);
-int arizona_init_notifiers(struct snd_soc_codec *codec)
+int arizona_init_common(struct arizona *arizona)
{
- struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
- struct arizona *arizona = priv->arizona;
+ struct arizona_pdata *pdata = &arizona->pdata;
+ unsigned int val, mask;
+ int i;
BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
+ for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
+ /* Default is 0 so noop with defaults */
+ if (pdata->out_mono[i])
+ val = ARIZONA_OUT1_MONO;
+ else
+ val = 0;
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
+ ARIZONA_OUT1_MONO, val);
+ }
+
+ for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
+ if (pdata->spk_mute[i])
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
+ ARIZONA_SPK1_MUTE_ENDIAN_MASK |
+ ARIZONA_SPK1_MUTE_SEQ1_MASK,
+ pdata->spk_mute[i]);
+
+ if (pdata->spk_fmt[i])
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
+ ARIZONA_SPK1_FMT_MASK,
+ pdata->spk_fmt[i]);
+ }
+
+ for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
+ /* Default for both is 0 so noop with defaults */
+ val = pdata->dmic_ref[i] << ARIZONA_IN1_DMIC_SUP_SHIFT;
+ if (pdata->inmode[i] & ARIZONA_INMODE_DMIC)
+ val |= 1 << ARIZONA_IN1_MODE_SHIFT;
+
+ switch (arizona->type) {
+ case WM8998:
+ case WM1814:
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8),
+ ARIZONA_IN1L_SRC_SE_MASK,
+ (pdata->inmode[i] & ARIZONA_INMODE_SE)
+ << ARIZONA_IN1L_SRC_SE_SHIFT);
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8),
+ ARIZONA_IN1R_SRC_SE_MASK,
+ (pdata->inmode[i] & ARIZONA_INMODE_SE)
+ << ARIZONA_IN1R_SRC_SE_SHIFT);
+
+ mask = ARIZONA_IN1_DMIC_SUP_MASK |
+ ARIZONA_IN1_MODE_MASK;
+ break;
+ default:
+ if (pdata->inmode[i] & ARIZONA_INMODE_SE)
+ val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
+
+ mask = ARIZONA_IN1_DMIC_SUP_MASK |
+ ARIZONA_IN1_MODE_MASK |
+ ARIZONA_IN1_SINGLE_ENDED_MASK;
+ break;
+ }
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_IN1L_CONTROL + (i * 8),
+ mask, val);
+ }
+
return 0;
}
-EXPORT_SYMBOL_GPL(arizona_init_notifiers);
+EXPORT_SYMBOL_GPL(arizona_init_common);
+
+int arizona_init_vol_limit(struct arizona *arizona)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(arizona->pdata.out_vol_limit); ++i) {
+ if (arizona->pdata.out_vol_limit[i])
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_DAC_VOLUME_LIMIT_1L + i * 4,
+ ARIZONA_OUT1L_VOL_LIM_MASK,
+ arizona->pdata.out_vol_limit[i]);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_vol_limit);
const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"None",
@@ -2695,6 +2779,80 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
+int arizona_of_get_audio_pdata(struct arizona *arizona)
+{
+ struct arizona_pdata *pdata = &arizona->pdata;
+ struct device_node *np = arizona->dev->of_node;
+ struct property *prop;
+ const __be32 *cur;
+ u32 val;
+ u32 pdm_val[ARIZONA_MAX_PDM_SPK];
+ int ret;
+ int count = 0;
+
+ count = 0;
+ of_property_for_each_u32(np, "wlf,inmode", prop, cur, val) {
+ if (count == ARRAY_SIZE(pdata->inmode))
+ break;
+
+ pdata->inmode[count] = val;
+ count++;
+ }
+
+ count = 0;
+ of_property_for_each_u32(np, "wlf,dmic-ref", prop, cur, val) {
+ if (count == ARRAY_SIZE(pdata->dmic_ref))
+ break;
+
+ pdata->dmic_ref[count] = val;
+ count++;
+ }
+
+ count = 0;
+ of_property_for_each_u32(np, "wlf,out-mono", prop, cur, val) {
+ if (count == ARRAY_SIZE(pdata->out_mono))
+ break;
+
+ pdata->out_mono[count] = !!val;
+ count++;
+ }
+
+ count = 0;
+ of_property_for_each_u32(np, "wlf,max-channels-clocked", prop, cur, val) {
+ if (count == ARRAY_SIZE(pdata->max_channels_clocked))
+ break;
+
+ pdata->max_channels_clocked[count] = val;
+ count++;
+ }
+
+ count = 0;
+ of_property_for_each_u32(np, "wlf,out-volume-limit", prop, cur, val) {
+ if (count == ARRAY_SIZE(pdata->out_vol_limit))
+ break;
+
+ pdata->out_vol_limit[count] = val;
+ count++;
+ }
+
+ ret = of_property_read_u32_array(np, "wlf,spk-fmt",
+ pdm_val, ARRAY_SIZE(pdm_val));
+
+ if (ret >= 0)
+ for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
+ pdata->spk_fmt[count] = pdm_val[count];
+
+ ret = of_property_read_u32_array(np, "wlf,spk-mute",
+ pdm_val, ARRAY_SIZE(pdm_val));
+
+ if (ret >= 0)
+ for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
+ pdata->spk_mute[count] = pdm_val[count];
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_of_get_audio_pdata);
+
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 1822e3b3de80..dfdf6d8c9687 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -313,7 +313,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
int arizona_init_spk(struct snd_soc_codec *codec);
int arizona_init_gpio(struct snd_soc_codec *codec);
int arizona_init_mono(struct snd_soc_codec *codec);
-int arizona_init_notifiers(struct snd_soc_codec *codec);
+
+int arizona_init_common(struct arizona *arizona);
+int arizona_init_vol_limit(struct arizona *arizona);
int arizona_init_spk_irqs(struct arizona *arizona);
int arizona_free_spk_irqs(struct arizona *arizona);
@@ -350,4 +352,6 @@ static inline int arizona_unregister_notifier(struct snd_soc_codec *codec,
return blocking_notifier_chain_unregister(&arizona->notifier, nb);
}
+int arizona_of_get_audio_pdata(struct arizona *arizona);
+
#endif
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index 643e37fc218e..5ba0edc19df4 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -909,6 +909,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2,
CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_XSP <<
CS43130_DSD_SRC_SHIFT);
+ break;
}
if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
@@ -1039,6 +1040,7 @@ static int cs43130_pcm_ch_put(struct snd_kcontrol *kcontrol,
else
regmap_multi_reg_write(cs43130->regmap, pcm_ch_dis_seq,
ARRAY_SIZE(pcm_ch_dis_seq));
+ break;
}
return snd_soc_put_enum_double(kcontrol, ucontrol);
@@ -1152,6 +1154,7 @@ static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
case CS4399_CHIP_ID:
regmap_multi_reg_write(cs43130->regmap, dsd_seq,
ARRAY_SIZE(dsd_seq));
+ break;
}
break;
case SND_SOC_DAPM_POST_PMU:
@@ -1162,6 +1165,7 @@ static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
case CS4399_CHIP_ID:
regmap_multi_reg_write(cs43130->regmap, unmute_seq,
ARRAY_SIZE(unmute_seq));
+ break;
}
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -1184,6 +1188,7 @@ static int cs43130_dsd_event(struct snd_soc_dapm_widget *w,
regmap_update_bits(cs43130->regmap,
CS43130_DSD_PATH_CTL_1,
CS43130_MUTE_MASK, CS43130_MUTE_EN);
+ break;
}
break;
default:
@@ -1206,6 +1211,7 @@ static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
case CS4399_CHIP_ID:
regmap_multi_reg_write(cs43130->regmap, pcm_seq,
ARRAY_SIZE(pcm_seq));
+ break;
}
break;
case SND_SOC_DAPM_POST_PMU:
@@ -1216,6 +1222,7 @@ static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
case CS4399_CHIP_ID:
regmap_multi_reg_write(cs43130->regmap, unmute_seq,
ARRAY_SIZE(unmute_seq));
+ break;
}
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -1238,6 +1245,7 @@ static int cs43130_pcm_event(struct snd_soc_dapm_widget *w,
regmap_update_bits(cs43130->regmap,
CS43130_PCM_PATH_CTL_1,
CS43130_MUTE_MASK, CS43130_MUTE_EN);
+ break;
}
break;
default:
@@ -1277,6 +1285,7 @@ static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
case CS43198_CHIP_ID:
regmap_multi_reg_write(cs43130->regmap, pop_free_seq2,
ARRAY_SIZE(pop_free_seq2));
+ break;
}
break;
case SND_SOC_DAPM_POST_PMU:
@@ -1301,6 +1310,7 @@ static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
case CS43198_CHIP_ID:
usleep_range(12000, 12010);
regmap_write(cs43130->regmap, CS43130_DXD13, 0);
+ break;
}
regmap_write(cs43130->regmap, CS43130_DXD1, 0);
@@ -1311,6 +1321,7 @@ static int cs43130_dac_event(struct snd_soc_dapm_widget *w,
case CS4399_CHIP_ID:
regmap_multi_reg_write(cs43130->regmap, dac_postpmd_seq,
ARRAY_SIZE(dac_postpmd_seq));
+ break;
}
break;
default:
@@ -2133,6 +2144,7 @@ exit:
cs43130_hpload_proc(cs43130, hp_dis_cal_seq2,
ARRAY_SIZE(hp_dis_cal_seq2),
CS43130_HPLOAD_OFF_INT, ac_idx);
+ break;
}
regmap_multi_reg_write(cs43130->regmap, hp_cln_seq,
@@ -2543,6 +2555,7 @@ static int cs43130_i2c_probe(struct i2c_client *client,
digital_hp_routes;
soc_codec_dev_cs43130.component_driver.num_dapm_routes =
ARRAY_SIZE(digital_hp_routes);
+ break;
}
ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_cs43130,
@@ -2586,8 +2599,7 @@ static int cs43130_i2c_remove(struct i2c_client *client)
device_remove_file(&client->dev, &dev_attr_hpload_ac_r);
}
- if (cs43130->reset_gpio)
- gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
+ gpiod_set_value_cansleep(cs43130->reset_gpio, 0);
pm_runtime_disable(&client->dev);
regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index e09fc8f037f1..94c0209977d0 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -1130,7 +1130,6 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
arizona_init_gpio(codec);
arizona_init_mono(codec);
- arizona_init_notifiers(codec);
ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
if (ret)
@@ -1230,6 +1229,14 @@ static int cs47l24_probe(struct platform_device *pdev)
if (!cs47l24)
return -ENOMEM;
+ if (IS_ENABLED(CONFIG_OF)) {
+ if (!dev_get_platdata(arizona->dev)) {
+ ret = arizona_of_get_audio_pdata(arizona);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
platform_set_drvdata(pdev, cs47l24);
cs47l24->core.arizona = arizona;
@@ -1288,6 +1295,11 @@ static int cs47l24_probe(struct platform_device *pdev)
return ret;
}
+ arizona_init_common(arizona);
+
+ ret = arizona_init_vol_limit(arizona);
+ if (ret < 0)
+ goto err_dsp_irq;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
goto err_dsp_irq;
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index cc0b2d2eaf15..41d9b1da27c2 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1220,6 +1220,7 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct snd_soc_codec *codec = codec_dai->codec;
struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
u8 dai_clk_mode = 0, dai_ctrl = 0;
+ u8 dai_offset = 0;
/* Set master/slave mode */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1234,17 +1235,46 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
}
/* Set clock normal/inverted */
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- break;
- case SND_SOC_DAIFMT_NB_IF:
- dai_clk_mode |= DA7213_DAI_WCLK_POL_INV;
- break;
- case SND_SOC_DAIFMT_IB_NF:
- dai_clk_mode |= DA7213_DAI_CLK_POL_INV;
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ dai_clk_mode |= DA7213_DAI_WCLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ dai_clk_mode |= DA7213_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ dai_clk_mode |= DA7213_DAI_WCLK_POL_INV |
+ DA7213_DAI_CLK_POL_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
- case SND_SOC_DAIFMT_IB_IF:
- dai_clk_mode |= DA7213_DAI_WCLK_POL_INV | DA7213_DAI_CLK_POL_INV;
+ case SND_SOC_DAI_FORMAT_DSP_A:
+ case SND_SOC_DAI_FORMAT_DSP_B:
+ /* The bclk is inverted wrt ASoC conventions */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ dai_clk_mode |= DA7213_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ dai_clk_mode |= DA7213_DAI_WCLK_POL_INV |
+ DA7213_DAI_CLK_POL_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ dai_clk_mode |= DA7213_DAI_WCLK_POL_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
default:
return -EINVAL;
@@ -1261,6 +1291,13 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
case SND_SOC_DAIFMT_RIGHT_J:
dai_ctrl |= DA7213_DAI_FORMAT_RIGHT_J;
break;
+ case SND_SOC_DAI_FORMAT_DSP_A: /* L data MSB after FRM LRC */
+ dai_ctrl |= DA7213_DAI_FORMAT_DSP;
+ dai_offset = 1;
+ break;
+ case SND_SOC_DAI_FORMAT_DSP_B: /* L data MSB during FRM LRC */
+ dai_ctrl |= DA7213_DAI_FORMAT_DSP;
+ break;
default:
return -EINVAL;
}
@@ -1271,6 +1308,7 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
snd_soc_write(codec, DA7213_DAI_CLK_MODE, dai_clk_mode);
snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK,
dai_ctrl);
+ snd_soc_write(codec, DA7213_DAI_OFFSET, dai_offset);
return 0;
}
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h
index 16ef56f77cd4..5a78dba1dcb5 100644
--- a/sound/soc/codecs/da7213.h
+++ b/sound/soc/codecs/da7213.h
@@ -188,6 +188,7 @@
#define DA7213_DAI_FORMAT_I2S_MODE (0x0 << 0)
#define DA7213_DAI_FORMAT_LEFT_J (0x1 << 0)
#define DA7213_DAI_FORMAT_RIGHT_J (0x2 << 0)
+#define DA7213_DAI_FORMAT_DSP (0x3 << 0)
#define DA7213_DAI_FORMAT_MASK (0x3 << 0)
#define DA7213_DAI_WORD_LENGTH_S16_LE (0x0 << 2)
#define DA7213_DAI_WORD_LENGTH_S20_LE (0x1 << 2)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index e824d47cc22b..f3b4f4dfae6a 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -942,7 +942,8 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
if (!se)
return -ENOMEM;
- sprintf(kc_name, "Pin %d port %d Input", pin->nid, port->id);
+ snprintf(kc_name, NAME_SIZE, "Pin %d port %d Input",
+ pin->nid, port->id);
kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL);
if (!kc->name)
return -ENOMEM;
@@ -1452,6 +1453,8 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
int i, num_nodes;
struct hdac_device *hdac = &edev->hdac;
struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_cvt *temp_cvt, *cvt_next;
+ struct hdac_hdmi_pin *temp_pin, *pin_next;
int ret;
hdac_hdmi_skl_enable_all_pins(hdac);
@@ -1481,32 +1484,54 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
case AC_WID_AUD_OUT:
ret = hdac_hdmi_add_cvt(edev, nid);
if (ret < 0)
- return ret;
+ goto free_widgets;
break;
case AC_WID_PIN:
ret = hdac_hdmi_add_pin(edev, nid);
if (ret < 0)
- return ret;
+ goto free_widgets;
break;
}
}
hdac->end_nid = nid;
- if (!hdmi->num_pin || !hdmi->num_cvt)
- return -EIO;
+ if (!hdmi->num_pin || !hdmi->num_cvt) {
+ ret = -EIO;
+ goto free_widgets;
+ }
ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt);
if (ret) {
dev_err(&hdac->dev, "Failed to create dais with err: %d\n",
ret);
- return ret;
+ goto free_widgets;
}
*num_dais = hdmi->num_cvt;
+ ret = hdac_hdmi_init_dai_map(edev);
+ if (ret < 0)
+ goto free_widgets;
+
+ return ret;
+
+free_widgets:
+ list_for_each_entry_safe(temp_cvt, cvt_next, &hdmi->cvt_list, head) {
+ list_del(&temp_cvt->head);
+ kfree(temp_cvt->name);
+ kfree(temp_cvt);
+ }
+
+ list_for_each_entry_safe(temp_pin, pin_next, &hdmi->pin_list, head) {
+ for (i = 0; i < temp_pin->num_ports; i++)
+ temp_pin->ports[i].pin = NULL;
+ kfree(temp_pin->ports);
+ list_del(&temp_pin->head);
+ kfree(temp_pin);
+ }
- return hdac_hdmi_init_dai_map(edev);
+ return ret;
}
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
@@ -1894,6 +1919,9 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_port *port;
+ if (!pcm)
+ return;
+
if (list_empty(&pcm->port_list))
return;
@@ -1912,6 +1940,9 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+ if (!pcm)
+ return false;
+
if (list_empty(&pcm->port_list))
return false;
@@ -1925,6 +1956,9 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_port *port;
+ if (!pcm)
+ return 0;
+
if (list_empty(&pcm->port_list))
return 0;
@@ -1978,6 +2012,9 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
+ if (!hdac_id)
+ return -ENODEV;
+
if (hdac_id->driver_data)
hdmi_priv->drv_data =
(struct hdac_hdmi_drv_data *)hdac_id->driver_data;
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 3abf82563408..5672e516bec3 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -303,11 +303,8 @@ enum {
static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
-
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
- uinfo->count = sizeof(hcp->eld);
+ uinfo->count = FIELD_SIZEOF(struct hdmi_codec_priv, eld);
return 0;
}
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 13bcfb1ef9b4..f5075d1f79e6 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2115,7 +2115,7 @@ static void max98090_pll_work(struct work_struct *work)
if (!snd_soc_codec_is_active(codec))
return;
- dev_info(codec->dev, "PLL unlocked\n");
+ dev_info_ratelimited(codec->dev, "PLL unlocked\n");
/* Toggle shutdown OFF then ON */
snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c
index 327eaa25c9bd..921f95fc396d 100644
--- a/sound/soc/codecs/max98925.c
+++ b/sound/soc/codecs/max98925.c
@@ -579,7 +579,7 @@ static int max98925_i2c_probe(struct i2c_client *i2c,
ret = PTR_ERR(max98925->regmap);
dev_err(&i2c->dev,
"Failed to allocate regmap: %d\n", ret);
- goto err_out;
+ return ret;
}
if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
@@ -596,16 +596,20 @@ static int max98925_i2c_probe(struct i2c_client *i2c,
}
max98925->i_slot = value;
}
- ret = regmap_read(max98925->regmap,
- MAX98925_REV_VERSION, &reg);
- if ((ret < 0) ||
- ((reg != MAX98925_VERSION) &&
- (reg != MAX98925_VERSION1))) {
- dev_err(&i2c->dev,
- "device initialization error (%d 0x%02X)\n",
+
+ ret = regmap_read(max98925->regmap, MAX98925_REV_VERSION, &reg);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Read revision failed\n");
+ return ret;
+ }
+
+ if ((reg != MAX98925_VERSION) && (reg != MAX98925_VERSION1)) {
+ ret = -ENODEV;
+ dev_err(&i2c->dev, "Invalid revision (%d 0x%02X)\n",
ret, reg);
- goto err_out;
+ return ret;
}
+
dev_info(&i2c->dev, "device version 0x%02X\n", reg);
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98925,
@@ -613,7 +617,6 @@ static int max98925_i2c_probe(struct i2c_client *i2c,
if (ret < 0)
dev_err(&i2c->dev,
"Failed to register codec: %d\n", ret);
-err_out:
return ret;
}
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index d9dbbe72f8ad..a1d39353719d 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -1,7 +1,7 @@
/*
* max98927.c -- MAX98927 ALSA Soc Audio driver
*
- * Copyright (C) 2016 Maxim Integrated Products
+ * Copyright (C) 2016-2017 Maxim Integrated Products
* Author: Ryan Lee <ryans.lee@maximintegrated.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -146,6 +146,7 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
unsigned int mode = 0;
unsigned int format = 0;
+ bool use_pdm = false;
unsigned int invert = 0;
dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
@@ -187,22 +188,27 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- max98927->iface |= SND_SOC_DAIFMT_I2S;
format = MAX98927_PCM_FORMAT_I2S;
break;
case SND_SOC_DAIFMT_LEFT_J:
- max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
format = MAX98927_PCM_FORMAT_LJ;
break;
+ case SND_SOC_DAIFMT_DSP_A:
+ format = MAX98927_PCM_FORMAT_TDM_MODE1;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ format = MAX98927_PCM_FORMAT_TDM_MODE0;
+ break;
case SND_SOC_DAIFMT_PDM:
- max98927->iface |= SND_SOC_DAIFMT_PDM;
+ use_pdm = true;
break;
default:
return -EINVAL;
}
+ max98927->iface = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
- /* pcm channel configuration */
- if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
+ if (!use_pdm) {
+ /* pcm channel configuration */
regmap_update_bits(max98927->regmap,
MAX98927_R0018_PCM_RX_EN_A,
MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
@@ -217,13 +223,11 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
MAX98927_R003B_SPK_SRC_SEL,
MAX98927_SPK_SRC_MASK, 0);
- } else
regmap_update_bits(max98927->regmap,
- MAX98927_R0018_PCM_RX_EN_A,
- MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
-
- /* pdm channel configuration */
- if (max98927->iface & SND_SOC_DAIFMT_PDM) {
+ MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 0);
+ } else {
+ /* pdm channel configuration */
regmap_update_bits(max98927->regmap,
MAX98927_R0035_PDM_RX_CTRL,
MAX98927_PDM_RX_EN_MASK, 1);
@@ -231,10 +235,11 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
regmap_update_bits(max98927->regmap,
MAX98927_R003B_SPK_SRC_SEL,
MAX98927_SPK_SRC_MASK, 3);
- } else
+
regmap_update_bits(max98927->regmap,
- MAX98927_R0035_PDM_RX_CTRL,
- MAX98927_PDM_RX_EN_MASK, 0);
+ MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
+ }
return 0;
}
@@ -245,6 +250,21 @@ static const int rate_table[] = {
13000000, 19200000,
};
+/* BCLKs per LRCLK */
+static const int bclk_sel_table[] = {
+ 32, 48, 64, 96, 128, 192, 256, 384, 512,
+};
+
+static int max98927_get_bclk_sel(int bclk)
+{
+ int i;
+ /* match BCLKs per LRCLK */
+ for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
+ if (bclk_sel_table[i] == bclk)
+ return i + 2;
+ }
+ return 0;
+}
static int max98927_set_clock(struct max98927_priv *max98927,
struct snd_pcm_hw_params *params)
{
@@ -270,23 +290,20 @@ static int max98927_set_clock(struct max98927_priv *max98927,
i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
}
- switch (blr_clk_ratio) {
- case 32:
- value = 2;
- break;
- case 48:
- value = 3;
- break;
- case 64:
- value = 4;
- break;
- default:
- return -EINVAL;
+ if (!max98927->tdm_mode) {
+ /* BCLK configuration */
+ value = max98927_get_bclk_sel(blr_clk_ratio);
+ if (!value) {
+ dev_err(codec->dev, "format unsupported %d\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0022_PCM_CLK_SETUP,
+ MAX98927_PCM_CLK_SETUP_BSEL_MASK,
+ value);
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0022_PCM_CLK_SETUP,
- MAX98927_PCM_CLK_SETUP_BSEL_MASK,
- value);
return 0;
}
@@ -386,6 +403,78 @@ err:
return -EINVAL;
}
+static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+ int bsel = 0;
+ unsigned int chan_sz = 0;
+
+ max98927->tdm_mode = true;
+
+ /* BCLK configuration */
+ bsel = max98927_get_bclk_sel(slots * slot_width);
+ if (bsel == 0) {
+ dev_err(codec->dev, "BCLK %d not supported\n",
+ slots * slot_width);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0022_PCM_CLK_SETUP,
+ MAX98927_PCM_CLK_SETUP_BSEL_MASK,
+ bsel);
+
+ /* Channel size configuration */
+ switch (slot_width) {
+ case 16:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
+ break;
+ case 24:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
+ break;
+ case 32:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
+ break;
+ default:
+ dev_err(codec->dev, "format unsupported %d\n",
+ slot_width);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+ /* Rx slot configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R0018_PCM_RX_EN_A,
+ rx_mask & 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R0019_PCM_RX_EN_B,
+ (rx_mask & 0xFF00) >> 8);
+
+ /* Tx slot configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R001A_PCM_TX_EN_A,
+ tx_mask & 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R001B_PCM_TX_EN_B,
+ (tx_mask & 0xFF00) >> 8);
+
+ /* Tx slot Hi-Z configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ ~tx_mask & 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ (~tx_mask & 0xFF00) >> 8);
+
+ return 0;
+}
+
#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000
#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -405,6 +494,7 @@ static const struct snd_soc_dai_ops max98927_dai_ops = {
.set_sysclk = max98927_dai_set_sysclk,
.set_fmt = max98927_dai_set_fmt,
.hw_params = max98927_dai_hw_params,
+ .set_tdm_slot = max98927_dai_tdm_slot,
};
static int max98927_dac_event(struct snd_soc_dapm_widget *w,
@@ -414,6 +504,9 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ max98927->tdm_mode = 0;
+ break;
case SND_SOC_DAPM_POST_PMU:
regmap_update_bits(max98927->regmap,
MAX98927_R003A_AMP_EN,
diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
index ece6a608cbe1..9ea839735433 100644
--- a/sound/soc/codecs/max98927.h
+++ b/sound/soc/codecs/max98927.h
@@ -1,7 +1,7 @@
/*
* max98927.h -- MAX98927 ALSA Soc Audio driver
*
- * Copyright 2013-15 Maxim Integrated Products
+ * Copyright (C) 2016-2017 Maxim Integrated Products
* Author: Ryan Lee <ryans.lee@maximintegrated.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -161,7 +161,9 @@
#define MAX98927_PCM_MODE_CFG_FORMAT_SHIFT (3)
#define MAX98927_PCM_FORMAT_I2S (0x0 << 0)
#define MAX98927_PCM_FORMAT_LJ (0x1 << 0)
-
+#define MAX98927_PCM_FORMAT_TDM_MODE0 (0x3 << 0)
+#define MAX98927_PCM_FORMAT_TDM_MODE1 (0x4 << 0)
+#define MAX98927_PCM_FORMAT_TDM_MODE2 (0x5 << 0)
#define MAX98927_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
@@ -268,5 +270,6 @@ struct max98927_priv {
unsigned int iface;
unsigned int master;
unsigned int digital_gain;
+ bool tdm_mode;
};
#endif
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index 549c269acc7d..5f3c42c4f74a 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -104,7 +104,7 @@
#define CDC_A_MICB_1_VAL (0xf141)
#define MICB_MIN_VAL 1600
#define MICB_STEP_SIZE 50
-#define MICB_VOLTAGE_REGVAL(v) ((v - MICB_MIN_VAL)/MICB_STEP_SIZE)
+#define MICB_VOLTAGE_REGVAL(v) (((v - MICB_MIN_VAL)/MICB_STEP_SIZE) << 3)
#define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3)
#define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3)
#define MICB_1_VAL_MICB_OUT_VAL_V1P80V ((0x4) << 3)
@@ -285,7 +285,7 @@ struct pm8916_wcd_analog_priv {
u16 codec_version;
bool mbhc_btn_enabled;
/* special event to detect accessory type */
- bool mbhc_btn0_pressed;
+ int mbhc_btn0_released;
bool detect_accessory_type;
struct clk *mclk;
struct snd_soc_codec *codec;
@@ -349,8 +349,9 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
| MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
if (wcd->micbias_mv) {
- snd_soc_write(codec, CDC_A_MICB_1_VAL,
- MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
+ snd_soc_update_bits(codec, CDC_A_MICB_1_VAL,
+ MICB_1_VAL_MICB_OUT_VAL_MASK,
+ MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
/*
* Special headset needs MICBIAS as 2.7V so wait for
* 50 msec for the MICBIAS to reach 2.7 volts.
@@ -443,50 +444,6 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
wcd->micbias1_cap_mode);
}
-static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
-{
- struct snd_soc_codec *codec = wcd->codec;
- u32 plug_type = 0;
- u32 int_en_mask;
-
- snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
- CDC_A_MBHC_DET_CTL_L_DET_EN |
- CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
- CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
- CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);
-
- if (wcd->hphl_jack_type_normally_open)
- plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;
-
- if (wcd->gnd_jack_type_normally_open)
- plug_type |= CDC_A_GND_PLUG_TYPE_NO;
-
- snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
- CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
- CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
- plug_type |
- CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
-
-
- snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
- CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
- CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
-
- /* enable MBHC clock */
- snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
- DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
- DIG_CLK_CTL_D_MBHC_CLK_EN);
-
- int_en_mask = MBHC_SWITCH_INT;
- if (wcd->mbhc_btn_enabled)
- int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
-
- snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
- snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
- wcd->mbhc_btn0_pressed = false;
- wcd->detect_accessory_type = true;
-}
-
static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
bool micbias2_enabled)
{
@@ -534,6 +491,56 @@ static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
return 0;
}
+static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
+{
+ struct snd_soc_codec *codec = wcd->codec;
+ bool micbias_enabled = false;
+ u32 plug_type = 0;
+ u32 int_en_mask;
+
+ snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
+ CDC_A_MBHC_DET_CTL_L_DET_EN |
+ CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
+ CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
+ CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);
+
+ if (wcd->hphl_jack_type_normally_open)
+ plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;
+
+ if (wcd->gnd_jack_type_normally_open)
+ plug_type |= CDC_A_GND_PLUG_TYPE_NO;
+
+ snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
+ CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
+ CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
+ plug_type |
+ CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
+
+
+ snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
+ CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
+ CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
+
+ /* enable MBHC clock */
+ snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+ DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
+ DIG_CLK_CTL_D_MBHC_CLK_EN);
+
+ if (snd_soc_read(codec, CDC_A_MICB_2_EN) & CDC_A_MICB_2_EN_ENABLE)
+ micbias_enabled = true;
+
+ pm8916_mbhc_configure_bias(wcd, micbias_enabled);
+
+ int_en_mask = MBHC_SWITCH_INT;
+ if (wcd->mbhc_btn_enabled)
+ int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
+
+ snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
+ snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
+ wcd->mbhc_btn0_released = false;
+ wcd->detect_accessory_type = true;
+}
+
static int pm8916_wcd_analog_enable_micbias_int2(struct
snd_soc_dapm_widget
*w, struct snd_kcontrol
@@ -614,6 +621,7 @@ static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w,
case CDC_A_TX_2_EN:
snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
MICB_1_CTL_CFILT_REF_SEL_MASK, 0);
+ /* fall through */
case CDC_A_TX_3_EN:
snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL,
CONN_TX2_SERIAL_TX2_MUX,
@@ -950,7 +958,7 @@ static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
/* check if its BTN0 thats released */
if ((val != -1) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
- priv->mbhc_btn0_pressed = false;
+ priv->mbhc_btn0_released = true;
} else {
snd_soc_jack_report(priv->jack, 0, btn_mask);
@@ -983,9 +991,7 @@ static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
break;
case 0x0:
/* handle BTN_0 specially for type detection */
- if (priv->detect_accessory_type)
- priv->mbhc_btn0_pressed = true;
- else
+ if (!priv->detect_accessory_type)
snd_soc_jack_report(priv->jack,
SND_JACK_BTN_0, btn_mask);
break;
@@ -1029,19 +1035,19 @@ static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
* both press and release event received then its
* a headset.
*/
- if (priv->mbhc_btn0_pressed)
+ if (priv->mbhc_btn0_released)
snd_soc_jack_report(priv->jack,
- SND_JACK_HEADPHONE, hs_jack_mask);
+ SND_JACK_HEADSET, hs_jack_mask);
else
snd_soc_jack_report(priv->jack,
- SND_JACK_HEADSET, hs_jack_mask);
+ SND_JACK_HEADPHONE, hs_jack_mask);
priv->detect_accessory_type = false;
} else { /* removal */
snd_soc_jack_report(priv->jack, 0, hs_jack_mask);
priv->detect_accessory_type = true;
- priv->mbhc_btn0_pressed = false;
+ priv->mbhc_btn0_released = false;
}
return IRQ_HANDLED;
@@ -1241,6 +1247,8 @@ static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = {
{ }
};
+MODULE_DEVICE_TABLE(of, pm8916_wcd_analog_spmi_match_table);
+
static struct platform_driver pm8916_wcd_analog_spmi_driver = {
.driver = {
.name = "qcom,pm8916-wcd-spmi-codec",
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
index 66df8f810f0d..a10a724eb448 100644
--- a/sound/soc/codecs/msm8916-wcd-digital.c
+++ b/sound/soc/codecs/msm8916-wcd-digital.c
@@ -238,7 +238,7 @@ static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE(
static const struct soc_enum rx2_mix1_inp_enum[] = {
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text),
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text),
- SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text),
+ SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B2_CTL, 0, 6, rx_mix1_text),
};
/* RX2 MIX2 */
@@ -249,7 +249,7 @@ static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE(
static const struct soc_enum rx3_mix1_inp_enum[] = {
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text),
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text),
- SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text),
+ SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B2_CTL, 0, 6, rx_mix1_text),
};
/* DEC */
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index dbff416e38be..5f9c069569d5 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -1,7 +1,7 @@
/*
* Driver for the PCM512x CODECs
*
- * Author: Mark Brown <broonie@linaro.org>
+ * Author: Mark Brown <broonie@kernel.org>
* Copyright 2014 Linaro Ltd
*
* This program is free software; you can redistribute it and/or
@@ -75,5 +75,5 @@ static struct i2c_driver pcm512x_i2c_driver = {
module_i2c_driver(pcm512x_i2c_driver);
MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C");
-MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
index 712ed6598c48..25c63510ae15 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -1,7 +1,7 @@
/*
* Driver for the PCM512x CODECs
*
- * Author: Mark Brown <broonie@linaro.org>
+ * Author: Mark Brown <broonie@kernel.org>
* Copyright 2014 Linaro Ltd
*
* This program is free software; you can redistribute it and/or
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 68feae262476..e0f3556d3872 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1,7 +1,7 @@
/*
* Driver for the PCM512x CODECs
*
- * Author: Mark Brown <broonie@linaro.org>
+ * Author: Mark Brown <broonie@kernel.org>
* Copyright 2014 Linaro Ltd
*
* This program is free software; you can redistribute it and/or
@@ -1602,5 +1602,5 @@ const struct dev_pm_ops pcm512x_pm_ops = {
EXPORT_SYMBOL_GPL(pcm512x_pm_ops);
MODULE_DESCRIPTION("ASoC PCM512x codec driver");
-MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
index b7c310207223..d70d9c0c2088 100644
--- a/sound/soc/codecs/pcm512x.h
+++ b/sound/soc/codecs/pcm512x.h
@@ -1,7 +1,7 @@
/*
* Driver for the PCM512x CODECs
*
- * Author: Mark Brown <broonie@linaro.org>
+ * Author: Mark Brown <broonie@kernel.org>
* Copyright 2014 Linaro Ltd
*
* This program is free software; you can redistribute it and/or
diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c
index 7b447d0b173a..974a9040651d 100644
--- a/sound/soc/codecs/rl6231.c
+++ b/sound/soc/codecs/rl6231.c
@@ -71,7 +71,7 @@ EXPORT_SYMBOL_GPL(rl6231_get_pre_div);
*/
int rl6231_calc_dmic_clk(int rate)
{
- int div[] = {2, 3, 4, 6, 8, 12};
+ static const int div[] = {2, 3, 4, 6, 8, 12};
int i;
if (rate < 1000000 * div[0]) {
@@ -189,7 +189,8 @@ EXPORT_SYMBOL_GPL(rl6231_pll_calc);
int rl6231_get_clk_info(int sclk, int rate)
{
- int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+ int i;
+ static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
if (sclk <= 0 || rate <= 0)
return -EINVAL;
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 12f2ecf3a4fe..2df91db765ac 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -147,8 +147,13 @@ done:
static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp)
{
+ size_t period_bytes;
u8 buf[8];
+ if (!rt5514_dsp->substream)
+ return;
+
+ period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream);
rt5514_dsp->get_size = 0;
/**
@@ -176,6 +181,10 @@ static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp)
rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base;
+ if (rt5514_dsp->buf_size % period_bytes)
+ rt5514_dsp->buf_size = (rt5514_dsp->buf_size / period_bytes) *
+ period_bytes;
+
if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit &&
rt5514_dsp->buf_rp && rt5514_dsp->buf_size)
schedule_delayed_work(&rt5514_dsp->copy_work, 0);
@@ -447,9 +456,45 @@ static int rt5514_spi_probe(struct spi_device *spi)
return ret;
}
+ device_init_wakeup(&spi->dev, true);
+
+ return 0;
+}
+
+static int __maybe_unused rt5514_suspend(struct device *dev)
+{
+ int irq = to_spi_device(dev)->irq;
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(irq);
+
+ return 0;
+}
+
+static int __maybe_unused rt5514_resume(struct device *dev)
+{
+ struct snd_soc_platform *platform = snd_soc_lookup_platform(dev);
+ struct rt5514_dsp *rt5514_dsp =
+ snd_soc_platform_get_drvdata(platform);
+ int irq = to_spi_device(dev)->irq;
+ u8 buf[8];
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(irq);
+
+ if (rt5514_dsp->substream) {
+ rt5514_spi_burst_read(RT5514_IRQ_CTRL, (u8 *)&buf, sizeof(buf));
+ if (buf[0] & RT5514_IRQ_STATUS_BIT)
+ rt5514_schedule_copy(rt5514_dsp);
+ }
+
return 0;
}
+static const struct dev_pm_ops rt5514_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt5514_suspend, rt5514_resume)
+};
+
static const struct of_device_id rt5514_of_match[] = {
{ .compatible = "realtek,rt5514", },
{},
@@ -459,6 +504,7 @@ MODULE_DEVICE_TABLE(of, rt5514_of_match);
static struct spi_driver rt5514_spi_driver = {
.driver = {
.name = "rt5514",
+ .pm = &rt5514_pm_ops,
.of_match_table = of_match_ptr(rt5514_of_match),
},
.probe = rt5514_spi_probe,
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index d7956ababd11..2a5b5d74e697 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1143,7 +1143,7 @@ static const struct acpi_device_id rt5514_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5514_acpi_match);
#endif
-static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev)
+static int rt5514_parse_dp(struct rt5514_priv *rt5514, struct device *dev)
{
device_property_read_u32(dev, "realtek,dmic-init-delay-ms",
&rt5514->pdata.dmic_init_delay);
@@ -1183,8 +1183,8 @@ static int rt5514_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt5514->pdata = *pdata;
- else if (i2c->dev.of_node)
- rt5514_parse_dt(rt5514, &i2c->dev);
+ else
+ rt5514_parse_dp(rt5514, &i2c->dev);
rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap);
if (IS_ERR(rt5514->i2c_regmap)) {
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index a98647ac497c..f020d2d1eef4 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -55,6 +55,8 @@ MODULE_PARM_DESC(quirk, "RT5645 pdata quirk override");
#define RT5645_HWEQ_NUM 57
+#define TIME_TO_POWER_MS 400
+
static const struct regmap_range_cfg rt5645_ranges[] = {
{
.name = "PR",
@@ -432,6 +434,7 @@ struct rt5645_priv {
int jack_type;
bool en_button_func;
bool hp_on;
+ int v_id;
};
static int rt5645_reset(struct snd_soc_codec *codec)
@@ -2516,9 +2519,7 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "SPKVOL L", "Switch", "SPK MIXL" },
{ "SPKVOL R", "Switch", "SPK MIXR" },
- { "SPOL MIX", "DAC R1 Switch", "DAC R1" },
{ "SPOL MIX", "DAC L1 Switch", "DAC L1" },
- { "SPOL MIX", "SPKVOL R Switch", "SPKVOL R" },
{ "SPOL MIX", "SPKVOL L Switch", "SPKVOL L" },
{ "SPOR MIX", "DAC R1 Switch", "DAC R1" },
{ "SPOR MIX", "SPKVOL R Switch", "SPKVOL R" },
@@ -2707,6 +2708,11 @@ static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
{ "DAC R2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 R Mux" },
};
+static const struct snd_soc_dapm_route rt5645_old_dapm_routes[] = {
+ { "SPOL MIX", "DAC R1 Switch", "DAC R1" },
+ { "SPOL MIX", "SPKVOL R Switch", "SPKVOL R" },
+};
+
static int rt5645_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
@@ -3340,9 +3346,9 @@ static irqreturn_t rt5645_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void rt5645_btn_check_callback(unsigned long data)
+static void rt5645_btn_check_callback(struct timer_list *t)
{
- struct rt5645_priv *rt5645 = (struct rt5645_priv *)data;
+ struct rt5645_priv *rt5645 = from_timer(rt5645, t, btn_check_timer);
queue_delayed_work(system_power_efficient_wq,
&rt5645->jack_detect_work, msecs_to_jiffies(5));
@@ -3363,6 +3369,11 @@ static int rt5645_probe(struct snd_soc_codec *codec)
snd_soc_dapm_add_routes(dapm,
rt5645_specific_dapm_routes,
ARRAY_SIZE(rt5645_specific_dapm_routes));
+ if (rt5645->v_id < 3) {
+ snd_soc_dapm_add_routes(dapm,
+ rt5645_old_dapm_routes,
+ ARRAY_SIZE(rt5645_old_dapm_routes));
+ }
break;
case CODEC_TYPE_RT5650:
snd_soc_dapm_new_controls(dapm,
@@ -3637,14 +3648,14 @@ static const struct dmi_system_id dmi_platform_gpd_win[] = {
{}
};
-static struct rt5645_platform_data general_platform_data2 = {
+static const struct rt5645_platform_data general_platform_data2 = {
.dmic1_data_pin = RT5645_DMIC_DATA_IN2N,
.dmic2_data_pin = RT5645_DMIC2_DISABLE,
.jd_mode = 3,
.inv_jd1_1 = true,
};
-static struct dmi_system_id dmi_platform_asus_t100ha[] = {
+static const struct dmi_system_id dmi_platform_asus_t100ha[] = {
{
.ident = "ASUS T100HAN",
.matches = {
@@ -3655,11 +3666,11 @@ static struct dmi_system_id dmi_platform_asus_t100ha[] = {
{ }
};
-static struct rt5645_platform_data minix_z83_4_platform_data = {
+static const struct rt5645_platform_data minix_z83_4_platform_data = {
.jd_mode = 3,
};
-static struct dmi_system_id dmi_platform_minix_z83_4[] = {
+static const struct dmi_system_id dmi_platform_minix_z83_4[] = {
{
.ident = "MINIX Z83-4",
.matches = {
@@ -3775,6 +3786,12 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
ret);
return ret;
}
+
+ /*
+ * Read after 400msec, as it is the interval required between
+ * read and power On.
+ */
+ msleep(TIME_TO_POWER_MS);
regmap_read(regmap, RT5645_VENDOR_ID2, &val);
switch (val) {
@@ -3803,6 +3820,9 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
regmap_write(rt5645->regmap, RT5645_RESET, 0);
+ regmap_read(regmap, RT5645_VENDOR_ID, &val);
+ rt5645->v_id = val & 0xff;
+
ret = regmap_register_patch(rt5645->regmap, init_list,
ARRAY_SIZE(init_list));
if (ret != 0)
@@ -3934,8 +3954,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
}
- setup_timer(&rt5645->btn_check_timer,
- rt5645_btn_check_callback, (unsigned long)rt5645);
+ timer_setup(&rt5645->btn_check_timer, rt5645_btn_check_callback, 0);
INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index da60b28ba3df..831b297978a4 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
+#include <linux/dmi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -26,10 +27,15 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
+#include <sound/jack.h>
#include "rl6231.h"
#include "rt5651.h"
+#define RT5651_JD_MAP(quirk) ((quirk) & GENMASK(7, 0))
+#define RT5651_IN2_DIFF BIT(16)
+#define RT5651_DMIC_EN BIT(17)
+
#define RT5651_DEVICE_ID_VALUE 0x6281
#define RT5651_PR_RANGE_BASE (0xff + 1)
@@ -37,6 +43,8 @@
#define RT5651_PR_BASE (RT5651_PR_RANGE_BASE + (0 * RT5651_PR_SPACING))
+static unsigned long rt5651_quirk;
+
static const struct regmap_range_cfg rt5651_ranges[] = {
{ .name = "PR", .range_min = RT5651_PR_BASE,
.range_max = RT5651_PR_BASE + 0xb4,
@@ -880,11 +888,14 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5651_PWR_ANLG2,
RT5651_PWR_PLL_BIT, 0, NULL, 0),
/* Input Side */
+ SND_SOC_DAPM_SUPPLY("JD Power", RT5651_PWR_ANLG2,
+ RT5651_PWM_JD_M_BIT, 0, NULL, 0),
+
/* micbias */
SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1,
RT5651_PWR_LDO_BIT, 0, NULL, 0),
- SND_SOC_DAPM_MICBIAS("micbias1", RT5651_PWR_ANLG2,
- RT5651_PWR_MB1_BIT, 0),
+ SND_SOC_DAPM_SUPPLY("micbias1", RT5651_PWR_ANLG2,
+ RT5651_PWR_MB1_BIT, 0, NULL, 0),
/* Input Lines */
SND_SOC_DAPM_INPUT("MIC1"),
SND_SOC_DAPM_INPUT("MIC2"),
@@ -1528,6 +1539,8 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
static int rt5651_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
@@ -1556,8 +1569,13 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, RT5651_PWR_DIG2, 0x0000);
snd_soc_write(codec, RT5651_PWR_VOL, 0x0000);
snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000);
- snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000);
- snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000);
+ if (rt5651->pdata.jd_src) {
+ snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0204);
+ snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0002);
+ } else {
+ snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000);
+ snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000);
+ }
break;
default:
@@ -1570,6 +1588,7 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
static int rt5651_probe(struct snd_soc_codec *codec)
{
struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
rt5651->codec = codec;
@@ -1585,6 +1604,15 @@ static int rt5651_probe(struct snd_soc_codec *codec)
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+ if (rt5651->pdata.jd_src) {
+ snd_soc_dapm_force_enable_pin(dapm, "JD Power");
+ snd_soc_dapm_force_enable_pin(dapm, "LDO");
+ snd_soc_dapm_sync(dapm);
+
+ regmap_update_bits(rt5651->regmap, RT5651_MICBIAS,
+ 0x38, 0x38);
+ }
+
return 0;
}
@@ -1718,15 +1746,130 @@ static const struct i2c_device_id rt5651_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id);
+static int rt5651_quirk_cb(const struct dmi_system_id *id)
+{
+ rt5651_quirk = (unsigned long) id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id rt5651_quirk_table[] = {
+ {
+ .callback = rt5651_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
+ },
+ .driver_data = (unsigned long *) RT5651_JD1_1,
+ },
+ {}
+};
+
static int rt5651_parse_dt(struct rt5651_priv *rt5651, struct device_node *np)
{
- rt5651->pdata.in2_diff = of_property_read_bool(np,
- "realtek,in2-differential");
- rt5651->pdata.dmic_en = of_property_read_bool(np,
- "realtek,dmic-en");
+ if (of_property_read_bool(np, "realtek,in2-differential"))
+ rt5651_quirk |= RT5651_IN2_DIFF;
+ if (of_property_read_bool(np, "realtek,dmic-en"))
+ rt5651_quirk |= RT5651_DMIC_EN;
+
+ return 0;
+}
+
+static void rt5651_set_pdata(struct rt5651_priv *rt5651)
+{
+ if (rt5651_quirk & RT5651_IN2_DIFF)
+ rt5651->pdata.in2_diff = true;
+ if (rt5651_quirk & RT5651_DMIC_EN)
+ rt5651->pdata.dmic_en = true;
+ if (RT5651_JD_MAP(rt5651_quirk))
+ rt5651->pdata.jd_src = RT5651_JD_MAP(rt5651_quirk);
+}
+
+static irqreturn_t rt5651_irq(int irq, void *data)
+{
+ struct rt5651_priv *rt5651 = data;
+
+ queue_delayed_work(system_power_efficient_wq,
+ &rt5651->jack_detect_work, msecs_to_jiffies(250));
+
+ return IRQ_HANDLED;
+}
+
+static int rt5651_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ int jack_type;
+
+ if (jack_insert) {
+ snd_soc_dapm_force_enable_pin(dapm, "LDO");
+ snd_soc_dapm_sync(dapm);
+
+ snd_soc_update_bits(codec, RT5651_MICBIAS,
+ RT5651_MIC1_OVCD_MASK |
+ RT5651_MIC1_OVTH_MASK |
+ RT5651_PWR_CLK12M_MASK |
+ RT5651_PWR_MB_MASK,
+ RT5651_MIC1_OVCD_EN |
+ RT5651_MIC1_OVTH_600UA |
+ RT5651_PWR_MB_PU |
+ RT5651_PWR_CLK12M_PU);
+ msleep(100);
+ if (snd_soc_read(codec, RT5651_IRQ_CTRL2) & RT5651_MB1_OC_CLR)
+ jack_type = SND_JACK_HEADPHONE;
+ else
+ jack_type = SND_JACK_HEADSET;
+ snd_soc_update_bits(codec, RT5651_IRQ_CTRL2,
+ RT5651_MB1_OC_CLR, 0);
+ } else { /* jack out */
+ jack_type = 0;
+
+ snd_soc_update_bits(codec, RT5651_MICBIAS,
+ RT5651_MIC1_OVCD_MASK,
+ RT5651_MIC1_OVCD_DIS);
+ }
+
+ return jack_type;
+}
+
+static void rt5651_jack_detect_work(struct work_struct *work)
+{
+ struct rt5651_priv *rt5651 =
+ container_of(work, struct rt5651_priv, jack_detect_work.work);
+
+ int report, val = 0;
+
+ if (!rt5651->codec)
+ return;
+
+ switch (rt5651->pdata.jd_src) {
+ case RT5651_JD1_1:
+ val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x1000;
+ break;
+ case RT5651_JD1_2:
+ val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x2000;
+ break;
+ case RT5651_JD2:
+ val = snd_soc_read(rt5651->codec, RT5651_INT_IRQ_ST) & 0x4000;
+ break;
+ default:
+ break;
+ }
+
+ report = rt5651_jack_detect(rt5651->codec, !val);
+
+ snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
+}
+
+int rt5651_set_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *hp_jack)
+{
+ struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
+
+ rt5651->hp_jack = hp_jack;
+ rt5651_irq(0, rt5651);
return 0;
}
+EXPORT_SYMBOL_GPL(rt5651_set_jack_detect);
static int rt5651_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
@@ -1746,6 +1889,10 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
rt5651->pdata = *pdata;
else if (i2c->dev.of_node)
rt5651_parse_dt(rt5651, i2c->dev.of_node);
+ else
+ dmi_check_system(rt5651_quirk_table);
+
+ rt5651_set_pdata(rt5651);
rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap);
if (IS_ERR(rt5651->regmap)) {
@@ -1779,6 +1926,59 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
rt5651->hp_mute = 1;
+ if (rt5651->pdata.jd_src) {
+
+ /* IRQ output on GPIO1 */
+ regmap_update_bits(rt5651->regmap, RT5651_GPIO_CTRL1,
+ RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ);
+
+ switch (rt5651->pdata.jd_src) {
+ case RT5651_JD1_1:
+ regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2,
+ RT5651_JD_TRG_SEL_MASK,
+ RT5651_JD_TRG_SEL_JD1_1);
+ regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1,
+ RT5651_JD1_1_IRQ_EN,
+ RT5651_JD1_1_IRQ_EN);
+ break;
+ case RT5651_JD1_2:
+ regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2,
+ RT5651_JD_TRG_SEL_MASK,
+ RT5651_JD_TRG_SEL_JD1_2);
+ regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1,
+ RT5651_JD1_2_IRQ_EN,
+ RT5651_JD1_2_IRQ_EN);
+ break;
+ case RT5651_JD2:
+ regmap_update_bits(rt5651->regmap, RT5651_JD_CTRL2,
+ RT5651_JD_TRG_SEL_MASK,
+ RT5651_JD_TRG_SEL_JD2);
+ regmap_update_bits(rt5651->regmap, RT5651_IRQ_CTRL1,
+ RT5651_JD2_IRQ_EN,
+ RT5651_JD2_IRQ_EN);
+ break;
+ case RT5651_JD_NULL:
+ break;
+ default:
+ dev_warn(&i2c->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
+ break;
+ }
+ }
+
+ INIT_DELAYED_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work);
+
+ if (i2c->irq) {
+ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+ rt5651_irq,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT, "rt5651", rt5651);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ return ret;
+ }
+ }
+
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,
rt5651_dai, ARRAY_SIZE(rt5651_dai));
@@ -1787,6 +1987,9 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
static int rt5651_i2c_remove(struct i2c_client *i2c)
{
+ struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c);
+
+ cancel_delayed_work_sync(&rt5651->jack_detect_work);
snd_soc_unregister_codec(&i2c->dev);
return 0;
diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h
index 1bd33cfa6411..4f8b202121d7 100644
--- a/sound/soc/codecs/rt5651.h
+++ b/sound/soc/codecs/rt5651.h
@@ -2062,6 +2062,8 @@ struct rt5651_priv {
struct snd_soc_codec *codec;
struct rt5651_platform_data pdata;
struct regmap *regmap;
+ struct snd_soc_jack *hp_jack;
+ struct delayed_work jack_detect_work;
int sysclk;
int sysclk_src;
@@ -2077,4 +2079,6 @@ struct rt5651_priv {
bool hp_mute;
};
+int rt5651_set_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *hp_jack);
#endif /* __RT5651_H__ */
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index fa66b11df8d4..07e7757417bc 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -3385,10 +3385,9 @@ static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai,
- int clk_id, unsigned int freq, int dir)
+static int rt5659_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
+ int source, unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = dai->codec;
struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
unsigned int reg_val = 0;
@@ -3414,20 +3413,21 @@ static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai,
rt5659->sysclk = freq;
rt5659->sysclk_src = clk_id;
- dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+ dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n",
+ freq, clk_id);
return 0;
}
-static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
- unsigned int freq_in, unsigned int freq_out)
+static int rt5659_set_codec_pll(struct snd_soc_codec *codec, int pll_id,
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
{
- struct snd_soc_codec *codec = dai->codec;
struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec);
struct rl6231_pll_code pll_code;
int ret;
- if (Source == rt5659->pll_src && freq_in == rt5659->pll_in &&
+ if (source == rt5659->pll_src && freq_in == rt5659->pll_in &&
freq_out == rt5659->pll_out)
return 0;
@@ -3441,7 +3441,7 @@ static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
return 0;
}
- switch (Source) {
+ switch (source) {
case RT5659_PLL1_S_MCLK:
snd_soc_update_bits(codec, RT5659_GLB_CLK,
RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK);
@@ -3459,7 +3459,7 @@ static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3);
break;
default:
- dev_err(codec->dev, "Unknown PLL Source %d\n", Source);
+ dev_err(codec->dev, "Unknown PLL source %d\n", source);
return -EINVAL;
}
@@ -3481,7 +3481,7 @@ static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
rt5659->pll_in = freq_in;
rt5659->pll_out = freq_out;
- rt5659->pll_src = Source;
+ rt5659->pll_src = source;
return 0;
}
@@ -3666,9 +3666,7 @@ static int rt5659_resume(struct snd_soc_codec *codec)
static const struct snd_soc_dai_ops rt5659_aif_dai_ops = {
.hw_params = rt5659_hw_params,
.set_fmt = rt5659_set_dai_fmt,
- .set_sysclk = rt5659_set_dai_sysclk,
.set_tdm_slot = rt5659_set_tdm_slot,
- .set_pll = rt5659_set_dai_pll,
.set_bclk_ratio = rt5659_set_bclk_ratio,
};
@@ -3747,6 +3745,8 @@ static const struct snd_soc_codec_driver soc_codec_dev_rt5659 = {
.dapm_routes = rt5659_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes),
},
+ .set_sysclk = rt5659_set_codec_sysclk,
+ .set_pll = rt5659_set_codec_pll,
};
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index e45b895d8279..b036c9dc0c8c 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -38,13 +38,24 @@ enum {
CODEC_VER_0,
};
+struct impedance_mapping_table {
+ unsigned int imp_min;
+ unsigned int imp_max;
+ unsigned int vol;
+ unsigned int dc_offset_l_manual;
+ unsigned int dc_offset_r_manual;
+ unsigned int dc_offset_l_manual_mic;
+ unsigned int dc_offset_r_manual_mic;
+};
+
struct rt5663_priv {
struct snd_soc_codec *codec;
struct rt5663_platform_data pdata;
struct regmap *regmap;
- struct delayed_work jack_detect_work;
+ struct delayed_work jack_detect_work, jd_unplug_work;
struct snd_soc_jack *hs_jack;
struct timer_list btn_check_timer;
+ struct impedance_mapping_table *imp_table;
int codec_ver;
int sysclk;
@@ -1575,6 +1586,9 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
rt5663->jack_type = SND_JACK_HEADSET;
rt5663_enable_push_button_irq(codec, true);
+ if (rt5663->pdata.impedance_sensing_num)
+ break;
+
if (rt5663->pdata.dc_offset_l_manual_mic) {
regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
rt5663->pdata.dc_offset_l_manual_mic >>
@@ -1596,6 +1610,9 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
default:
rt5663->jack_type = SND_JACK_HEADPHONE;
+ if (rt5663->pdata.impedance_sensing_num)
+ break;
+
if (rt5663->pdata.dc_offset_l_manual) {
regmap_write(rt5663->regmap, RT5663_MIC_DECRO_2,
rt5663->pdata.dc_offset_l_manual >> 16);
@@ -1623,6 +1640,177 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
return rt5663->jack_type;
}
+static int rt5663_impedance_sensing(struct snd_soc_codec *codec)
+{
+ struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec);
+ unsigned int value, i, reg84, reg26, reg2fa, reg91, reg10, reg80;
+
+ for (i = 0; i < rt5663->pdata.impedance_sensing_num; i++) {
+ if (rt5663->imp_table[i].vol == 7)
+ break;
+ }
+
+ if (rt5663->jack_type == SND_JACK_HEADSET) {
+ snd_soc_write(codec, RT5663_MIC_DECRO_2,
+ rt5663->imp_table[i].dc_offset_l_manual_mic >> 16);
+ snd_soc_write(codec, RT5663_MIC_DECRO_3,
+ rt5663->imp_table[i].dc_offset_l_manual_mic & 0xffff);
+ snd_soc_write(codec, RT5663_MIC_DECRO_5,
+ rt5663->imp_table[i].dc_offset_r_manual_mic >> 16);
+ snd_soc_write(codec, RT5663_MIC_DECRO_6,
+ rt5663->imp_table[i].dc_offset_r_manual_mic & 0xffff);
+ } else {
+ snd_soc_write(codec, RT5663_MIC_DECRO_2,
+ rt5663->imp_table[i].dc_offset_l_manual >> 16);
+ snd_soc_write(codec, RT5663_MIC_DECRO_3,
+ rt5663->imp_table[i].dc_offset_l_manual & 0xffff);
+ snd_soc_write(codec, RT5663_MIC_DECRO_5,
+ rt5663->imp_table[i].dc_offset_r_manual >> 16);
+ snd_soc_write(codec, RT5663_MIC_DECRO_6,
+ rt5663->imp_table[i].dc_offset_r_manual & 0xffff);
+ }
+
+ reg84 = snd_soc_read(codec, RT5663_ASRC_2);
+ reg26 = snd_soc_read(codec, RT5663_STO1_ADC_MIXER);
+ reg2fa = snd_soc_read(codec, RT5663_DUMMY_1);
+ reg91 = snd_soc_read(codec, RT5663_HP_CHARGE_PUMP_1);
+ reg10 = snd_soc_read(codec, RT5663_RECMIX);
+ reg80 = snd_soc_read(codec, RT5663_GLB_CLK);
+
+ snd_soc_update_bits(codec, RT5663_STO_DRE_1, 0x8000, 0);
+ snd_soc_write(codec, RT5663_ASRC_2, 0);
+ snd_soc_write(codec, RT5663_STO1_ADC_MIXER, 0x4040);
+ snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+ RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK |
+ RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+ RT5663_PWR_VREF1 | RT5663_PWR_VREF2);
+ usleep_range(10000, 10005);
+ snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+ RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK,
+ RT5663_PWR_FV1 | RT5663_PWR_FV2);
+ snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK,
+ RT5663_SCLK_SRC_RCCLK);
+ snd_soc_update_bits(codec, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
+ RT5663_DIG_25M_CLK_EN);
+ snd_soc_update_bits(codec, RT5663_ADDA_CLK_1, RT5663_I2S_PD1_MASK, 0);
+ snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0xff00);
+ snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0xfffc);
+ snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_1, 0x1232);
+ snd_soc_write(codec, RT5663_HP_LOGIC_2, 0x0005);
+ snd_soc_write(codec, RT5663_DEPOP_2, 0x3003);
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0030);
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0x0003);
+ snd_soc_update_bits(codec, RT5663_PWR_DIG_2,
+ RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F,
+ RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F);
+ snd_soc_update_bits(codec, RT5663_PWR_DIG_1,
+ RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
+ RT5663_PWR_LDO_DACREF_MASK | RT5663_PWR_ADC_L1 |
+ RT5663_PWR_ADC_R1,
+ RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
+ RT5663_PWR_LDO_DACREF_ON | RT5663_PWR_ADC_L1 |
+ RT5663_PWR_ADC_R1);
+ msleep(40);
+ snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+ RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2,
+ RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2);
+ msleep(30);
+ snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371);
+ snd_soc_write(codec, RT5663_STO_DAC_MIXER, 0);
+ snd_soc_write(codec, RT5663_BYPASS_STO_DAC, 0x000c);
+ snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa);
+ snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224);
+ snd_soc_write(codec, RT5663_HP_OUT_EN, 0x8088);
+ snd_soc_write(codec, RT5663_CHOP_ADC, 0x3000);
+ snd_soc_write(codec, RT5663_ADDA_RST, 0xc000);
+ snd_soc_write(codec, RT5663_STO1_HPF_ADJ1, 0x3320);
+ snd_soc_write(codec, RT5663_HP_CALIB_2, 0x00c9);
+ snd_soc_write(codec, RT5663_DUMMY_1, 0x004c);
+ snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7733);
+ snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777);
+ snd_soc_write(codec, RT5663_STO_DRE_9, 0x0007);
+ snd_soc_write(codec, RT5663_STO_DRE_10, 0x0007);
+ snd_soc_write(codec, RT5663_DUMMY_2, 0x02a4);
+ snd_soc_write(codec, RT5663_RECMIX, 0x0005);
+ snd_soc_write(codec, RT5663_HP_IMP_SEN_1, 0x4334);
+ snd_soc_update_bits(codec, RT5663_IRQ_3, 0x0004, 0x0004);
+ snd_soc_write(codec, RT5663_HP_LOGIC_1, 0x2200);
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x3000);
+ snd_soc_write(codec, RT5663_HP_LOGIC_1, 0x6200);
+
+ for (i = 0; i < 100; i++) {
+ msleep(20);
+ if (snd_soc_read(codec, RT5663_INT_ST_1) & 0x2)
+ break;
+ }
+
+ value = snd_soc_read(codec, RT5663_HP_IMP_SEN_4);
+
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0);
+ snd_soc_write(codec, RT5663_INT_ST_1, 0);
+ snd_soc_write(codec, RT5663_HP_LOGIC_1, 0);
+ snd_soc_update_bits(codec, RT5663_RC_CLK, RT5663_DIG_25M_CLK_MASK,
+ RT5663_DIG_25M_CLK_DIS);
+ snd_soc_write(codec, RT5663_GLB_CLK, reg80);
+ snd_soc_write(codec, RT5663_RECMIX, reg10);
+ snd_soc_write(codec, RT5663_DUMMY_2, 0x00a4);
+ snd_soc_write(codec, RT5663_DUMMY_1, reg2fa);
+ snd_soc_write(codec, RT5663_HP_CALIB_2, 0x00c8);
+ snd_soc_write(codec, RT5663_STO1_HPF_ADJ1, 0xb320);
+ snd_soc_write(codec, RT5663_ADDA_RST, 0xe400);
+ snd_soc_write(codec, RT5663_CHOP_ADC, 0x2000);
+ snd_soc_write(codec, RT5663_HP_OUT_EN, 0x0008);
+ snd_soc_update_bits(codec, RT5663_PWR_ANLG_2,
+ RT5663_PWR_RECMIX1 | RT5663_PWR_RECMIX2, 0);
+ snd_soc_update_bits(codec, RT5663_PWR_DIG_1,
+ RT5663_PWR_DAC_L1 | RT5663_PWR_DAC_R1 |
+ RT5663_PWR_LDO_DACREF_MASK | RT5663_PWR_ADC_L1 |
+ RT5663_PWR_ADC_R1, 0);
+ snd_soc_update_bits(codec, RT5663_PWR_DIG_2,
+ RT5663_PWR_ADC_S1F | RT5663_PWR_DAC_S1F, 0);
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0003, 0);
+ snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0);
+ snd_soc_write(codec, RT5663_HP_LOGIC_2, 0);
+ snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_1, reg91);
+ snd_soc_update_bits(codec, RT5663_PWR_ANLG_1,
+ RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK, 0);
+ snd_soc_write(codec, RT5663_STO1_ADC_MIXER, reg26);
+ snd_soc_write(codec, RT5663_ASRC_2, reg84);
+
+ for (i = 0; i < rt5663->pdata.impedance_sensing_num; i++) {
+ if (value >= rt5663->imp_table[i].imp_min &&
+ value <= rt5663->imp_table[i].imp_max)
+ break;
+ }
+
+ snd_soc_update_bits(codec, RT5663_STO_DRE_9, RT5663_DRE_GAIN_HP_MASK,
+ rt5663->imp_table[i].vol);
+ snd_soc_update_bits(codec, RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_MASK,
+ rt5663->imp_table[i].vol);
+
+ if (rt5663->jack_type == SND_JACK_HEADSET) {
+ snd_soc_write(codec, RT5663_MIC_DECRO_2,
+ rt5663->imp_table[i].dc_offset_l_manual_mic >> 16);
+ snd_soc_write(codec, RT5663_MIC_DECRO_3,
+ rt5663->imp_table[i].dc_offset_l_manual_mic & 0xffff);
+ snd_soc_write(codec, RT5663_MIC_DECRO_5,
+ rt5663->imp_table[i].dc_offset_r_manual_mic >> 16);
+ snd_soc_write(codec, RT5663_MIC_DECRO_6,
+ rt5663->imp_table[i].dc_offset_r_manual_mic & 0xffff);
+ } else {
+ snd_soc_write(codec, RT5663_MIC_DECRO_2,
+ rt5663->imp_table[i].dc_offset_l_manual >> 16);
+ snd_soc_write(codec, RT5663_MIC_DECRO_3,
+ rt5663->imp_table[i].dc_offset_l_manual & 0xffff);
+ snd_soc_write(codec, RT5663_MIC_DECRO_5,
+ rt5663->imp_table[i].dc_offset_r_manual >> 16);
+ snd_soc_write(codec, RT5663_MIC_DECRO_6,
+ rt5663->imp_table[i].dc_offset_r_manual & 0xffff);
+ }
+
+ return 0;
+}
+
static int rt5663_button_detect(struct snd_soc_codec *codec)
{
int btn_type, val;
@@ -1702,6 +1890,8 @@ static void rt5663_jack_detect_work(struct work_struct *work)
break;
case CODEC_VER_0:
report = rt5663_jack_detect(rt5663->codec, 1);
+ if (rt5663->pdata.impedance_sensing_num)
+ rt5663_impedance_sensing(rt5663->codec);
break;
default:
dev_err(codec->dev, "Unknown CODEC Version\n");
@@ -1751,8 +1941,15 @@ static void rt5663_jack_detect_work(struct work_struct *work)
break;
}
/* button release or spurious interrput*/
- if (btn_type == 0)
+ if (btn_type == 0) {
report = rt5663->jack_type;
+ cancel_delayed_work_sync(
+ &rt5663->jd_unplug_work);
+ } else {
+ queue_delayed_work(system_wq,
+ &rt5663->jd_unplug_work,
+ msecs_to_jiffies(500));
+ }
}
} else {
/* jack out */
@@ -1773,6 +1970,37 @@ static void rt5663_jack_detect_work(struct work_struct *work)
SND_JACK_BTN_2 | SND_JACK_BTN_3);
}
+static void rt5663_jd_unplug_work(struct work_struct *work)
+{
+ struct rt5663_priv *rt5663 =
+ container_of(work, struct rt5663_priv, jd_unplug_work.work);
+ struct snd_soc_codec *codec = rt5663->codec;
+
+ if (!codec)
+ return;
+
+ if (!rt5663_check_jd_status(codec)) {
+ /* jack out */
+ switch (rt5663->codec_ver) {
+ case CODEC_VER_1:
+ rt5663_v2_jack_detect(rt5663->codec, 0);
+ break;
+ case CODEC_VER_0:
+ rt5663_jack_detect(rt5663->codec, 0);
+ break;
+ default:
+ dev_err(codec->dev, "Unknown CODEC Version\n");
+ }
+
+ snd_soc_jack_report(rt5663->hs_jack, 0, SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+ } else {
+ queue_delayed_work(system_wq, &rt5663->jd_unplug_work,
+ msecs_to_jiffies(500));
+ }
+}
+
static const struct snd_kcontrol_new rt5663_snd_controls[] = {
/* DAC Digital Volume */
SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL,
@@ -1797,10 +2025,6 @@ static const struct snd_kcontrol_new rt5663_v2_specific_controls[] = {
};
static const struct snd_kcontrol_new rt5663_specific_controls[] = {
- /* Headphone Output Volume */
- SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9,
- RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1,
- rt5663_hp_vol_tlv),
/* Mic Boost Volume*/
SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_CBJ_2,
RT5663_GAIN_BST1_SHIFT, 8, 0, in_bst_tlv),
@@ -1808,6 +2032,13 @@ static const struct snd_kcontrol_new rt5663_specific_controls[] = {
SOC_ENUM("IF1 ADC Data Swap", rt5663_if1_adc_enum),
};
+static const struct snd_kcontrol_new rt5663_hpvol_controls[] = {
+ /* Headphone Output Volume */
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9,
+ RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1,
+ rt5663_hp_vol_tlv),
+};
+
static int rt5663_is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_widget *sink)
{
@@ -2890,6 +3121,10 @@ static int rt5663_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(rt5663_specific_dapm_routes));
snd_soc_add_codec_controls(codec, rt5663_specific_controls,
ARRAY_SIZE(rt5663_specific_controls));
+
+ if (!rt5663->imp_table)
+ snd_soc_add_codec_controls(codec, rt5663_hpvol_controls,
+ ARRAY_SIZE(rt5663_hpvol_controls));
break;
}
@@ -3178,6 +3413,8 @@ static void rt5663_calibrate(struct rt5663_priv *rt5663)
static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev)
{
+ int table_size;
+
device_property_read_u32(dev, "realtek,dc_offset_l_manual",
&rt5663->pdata.dc_offset_l_manual);
device_property_read_u32(dev, "realtek,dc_offset_r_manual",
@@ -3186,6 +3423,17 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev)
&rt5663->pdata.dc_offset_l_manual_mic);
device_property_read_u32(dev, "realtek,dc_offset_r_manual_mic",
&rt5663->pdata.dc_offset_r_manual_mic);
+ device_property_read_u32(dev, "realtek,impedance_sensing_num",
+ &rt5663->pdata.impedance_sensing_num);
+
+ if (rt5663->pdata.impedance_sensing_num) {
+ table_size = sizeof(struct impedance_mapping_table) *
+ rt5663->pdata.impedance_sensing_num;
+ rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL);
+ device_property_read_u32_array(dev,
+ "realtek,impedance_sensing_table",
+ (u32 *)rt5663->imp_table, table_size);
+ }
return 0;
}
@@ -3219,7 +3467,16 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
ret);
return ret;
}
- regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
+
+ ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
+ if (ret || (val != RT5663_DEVICE_ID_2 && val != RT5663_DEVICE_ID_1)) {
+ dev_err(&i2c->dev,
+ "Device with ID register %#x is not rt5663, retry one time.\n",
+ val);
+ msleep(100);
+ regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
+ }
+
switch (val) {
case RT5663_DEVICE_ID_2:
rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_v2_regmap);
@@ -3338,6 +3595,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
}
INIT_DELAYED_WORK(&rt5663->jack_detect_work, rt5663_jack_detect_work);
+ INIT_DELAYED_WORK(&rt5663->jd_unplug_work, rt5663_jd_unplug_work);
if (i2c->irq) {
ret = request_irq(i2c->irq, rt5663_irq,
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 9545764ef3eb..c5094b4399e2 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -34,6 +34,24 @@
#include "rt5670.h"
#include "rt5670-dsp.h"
+#define RT5670_DEV_GPIO BIT(0)
+#define RT5670_IN2_DIFF BIT(1)
+#define RT5670_DMIC_EN BIT(2)
+#define RT5670_DMIC1_IN2P BIT(3)
+#define RT5670_DMIC1_GPIO6 BIT(4)
+#define RT5670_DMIC1_GPIO7 BIT(5)
+#define RT5670_DMIC2_INR BIT(6)
+#define RT5670_DMIC2_GPIO8 BIT(7)
+#define RT5670_DMIC3_GPIO5 BIT(8)
+#define RT5670_JD_MODE1 BIT(9)
+#define RT5670_JD_MODE2 BIT(10)
+#define RT5670_JD_MODE3 BIT(11)
+
+static unsigned long rt5670_quirk;
+static unsigned int quirk_override;
+module_param_named(quirk, quirk_override, uint, 0444);
+MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+
#define RT5670_DEVICE_ID 0x6271
#define RT5670_PR_RANGE_BASE (0xff + 1)
@@ -2582,6 +2600,24 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
return 0;
}
+static int rt5670_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+ if (dai->id != RT5670_AIF1)
+ return 0;
+
+ if ((ratio % 50) == 0)
+ snd_soc_update_bits(codec, RT5670_GEN_CTRL3,
+ RT5670_TDM_DATA_MODE_SEL, RT5670_TDM_DATA_MODE_50FS);
+ else
+ snd_soc_update_bits(codec, RT5670_GEN_CTRL3,
+ RT5670_TDM_DATA_MODE_SEL, RT5670_TDM_DATA_MODE_NOR);
+
+ return 0;
+}
+
static int rt5670_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -2712,6 +2748,7 @@ static const struct snd_soc_dai_ops rt5670_aif_dai_ops = {
.set_fmt = rt5670_set_dai_fmt,
.set_tdm_slot = rt5670_set_tdm_slot,
.set_pll = rt5670_set_dai_pll,
+ .set_bclk_ratio = rt5670_set_bclk_ratio,
};
static struct snd_soc_dai_driver rt5670_dai[] = {
@@ -2808,56 +2845,84 @@ static const struct acpi_device_id rt5670_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
#endif
-static const struct dmi_system_id dmi_platform_intel_braswell[] = {
+static int rt5670_quirk_cb(const struct dmi_system_id *id)
+{
+ rt5670_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id dmi_platform_intel_quirks[] = {
{
+ .callback = rt5670_quirk_cb,
.ident = "Intel Braswell",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
},
+ .driver_data = (unsigned long *)(RT5670_DMIC_EN |
+ RT5670_DMIC1_IN2P |
+ RT5670_DEV_GPIO |
+ RT5670_JD_MODE1),
},
{
+ .callback = rt5670_quirk_cb,
.ident = "Dell Wyse 3040",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"),
},
+ .driver_data = (unsigned long *)(RT5670_DMIC_EN |
+ RT5670_DMIC1_IN2P |
+ RT5670_DEV_GPIO |
+ RT5670_JD_MODE1),
},
{
+ .callback = rt5670_quirk_cb,
.ident = "Lenovo Thinkpad Tablet 10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
},
+ .driver_data = (unsigned long *)(RT5670_DMIC_EN |
+ RT5670_DMIC1_IN2P |
+ RT5670_DEV_GPIO |
+ RT5670_JD_MODE1),
},
{
+ .callback = rt5670_quirk_cb,
.ident = "Lenovo Thinkpad Tablet 10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
},
+ .driver_data = (unsigned long *)(RT5670_DMIC_EN |
+ RT5670_DMIC1_IN2P |
+ RT5670_DEV_GPIO |
+ RT5670_JD_MODE1),
},
- {}
-};
-
-static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode2[] = {
{
+ .callback = rt5670_quirk_cb,
.ident = "Lenovo Thinkpad Tablet 10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"),
},
+ .driver_data = (unsigned long *)(RT5670_DMIC_EN |
+ RT5670_DMIC1_IN2P |
+ RT5670_DEV_GPIO |
+ RT5670_JD_MODE2),
},
- {}
-};
-
-static const struct dmi_system_id dmi_platform_intel_bytcht_jdmode3[] = {
{
+ .callback = rt5670_quirk_cb,
.ident = "Dell Venue 8 Pro 5855",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5855"),
},
+ .driver_data = (unsigned long *)(RT5670_DMIC_EN |
+ RT5670_DMIC2_INR |
+ RT5670_DEV_GPIO |
+ RT5670_JD_MODE3),
},
{}
};
@@ -2881,21 +2946,61 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt5670->pdata = *pdata;
- if (dmi_check_system(dmi_platform_intel_braswell)) {
- rt5670->pdata.dmic_en = true;
- rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+ dmi_check_system(dmi_platform_intel_quirks);
+ if (quirk_override) {
+ dev_info(&i2c->dev, "Overriding quirk 0x%x => 0x%x\n",
+ (unsigned int)rt5670_quirk, quirk_override);
+ rt5670_quirk = quirk_override;
+ }
+
+ if (rt5670_quirk & RT5670_DEV_GPIO) {
rt5670->pdata.dev_gpio = true;
- rt5670->pdata.jd_mode = 1;
- } else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode2)) {
+ dev_info(&i2c->dev, "quirk dev_gpio\n");
+ }
+ if (rt5670_quirk & RT5670_IN2_DIFF) {
+ rt5670->pdata.in2_diff = true;
+ dev_info(&i2c->dev, "quirk IN2_DIFF\n");
+ }
+ if (rt5670_quirk & RT5670_DMIC_EN) {
rt5670->pdata.dmic_en = true;
+ dev_info(&i2c->dev, "quirk DMIC enabled\n");
+ }
+ if (rt5670_quirk & RT5670_DMIC1_IN2P) {
rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
- rt5670->pdata.dev_gpio = true;
+ dev_info(&i2c->dev, "quirk DMIC1 on IN2P pin\n");
+ }
+ if (rt5670_quirk & RT5670_DMIC1_GPIO6) {
+ rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_GPIO6;
+ dev_info(&i2c->dev, "quirk DMIC1 on GPIO6 pin\n");
+ }
+ if (rt5670_quirk & RT5670_DMIC1_GPIO7) {
+ rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_GPIO7;
+ dev_info(&i2c->dev, "quirk DMIC1 on GPIO7 pin\n");
+ }
+ if (rt5670_quirk & RT5670_DMIC2_INR) {
+ rt5670->pdata.dmic2_data_pin = RT5670_DMIC_DATA_IN3N;
+ dev_info(&i2c->dev, "quirk DMIC2 on INR pin\n");
+ }
+ if (rt5670_quirk & RT5670_DMIC2_GPIO8) {
+ rt5670->pdata.dmic2_data_pin = RT5670_DMIC_DATA_GPIO8;
+ dev_info(&i2c->dev, "quirk DMIC2 on GPIO8 pin\n");
+ }
+ if (rt5670_quirk & RT5670_DMIC3_GPIO5) {
+ rt5670->pdata.dmic3_data_pin = RT5670_DMIC_DATA_GPIO5;
+ dev_info(&i2c->dev, "quirk DMIC3 on GPIO5 pin\n");
+ }
+
+ if (rt5670_quirk & RT5670_JD_MODE1) {
+ rt5670->pdata.jd_mode = 1;
+ dev_info(&i2c->dev, "quirk JD mode 1\n");
+ }
+ if (rt5670_quirk & RT5670_JD_MODE2) {
rt5670->pdata.jd_mode = 2;
- } else if (dmi_check_system(dmi_platform_intel_bytcht_jdmode3)) {
- rt5670->pdata.dmic_en = true;
- rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
- rt5670->pdata.dev_gpio = true;
+ dev_info(&i2c->dev, "quirk JD mode 2\n");
+ }
+ if (rt5670_quirk & RT5670_JD_MODE3) {
rt5670->pdata.jd_mode = 3;
+ dev_info(&i2c->dev, "quirk JD mode 3\n");
}
rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h
index 5ba485cae4e6..265df80d504e 100644
--- a/sound/soc/codecs/rt5670.h
+++ b/sound/soc/codecs/rt5670.h
@@ -1816,6 +1816,10 @@
#define RT5670_ZCD_HP_DIS (0x0 << 15)
#define RT5670_ZCD_HP_EN (0x1 << 15)
+/* General Control 3 (0xfc) */
+#define RT5670_TDM_DATA_MODE_SEL (0x1 << 11)
+#define RT5670_TDM_DATA_MODE_NOR (0x0 << 11)
+#define RT5670_TDM_DATA_MODE_50FS (0x1 << 11)
/* Codec Private Register definition */
/* 3D Speaker Control (0x63) */
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index 810369f687d7..a09499977be4 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -697,7 +697,8 @@ static int tas571x_i2c_probe(struct i2c_client *client,
return PTR_ERR(priv->mclk);
}
- BUG_ON(priv->chip->num_supply_names > TAS571X_MAX_SUPPLIES);
+ if (WARN_ON(priv->chip->num_supply_names > TAS571X_MAX_SUPPLIES))
+ return -EINVAL;
for (i = 0; i < priv->chip->num_supply_names; i++)
priv->supplies[i].supply = priv->chip->supply_names[i];
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
index 95e0a7abeb7a..f8dd67ca0744 100644
--- a/sound/soc/codecs/tfa9879.c
+++ b/sound/soc/codecs/tfa9879.c
@@ -312,9 +312,15 @@ static const struct i2c_device_id tfa9879_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id);
+static const struct of_device_id tfa9879_of_match[] = {
+ { .compatible = "nxp,tfa9879", },
+ { }
+};
+
static struct i2c_driver tfa9879_i2c_driver = {
.driver = {
.name = "tfa9879",
+ .of_match_table = tfa9879_of_match,
},
.probe = tfa9879_i2c_probe,
.remove = tfa9879_i2c_remove,
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 3d42138a7974..74909211c608 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -454,6 +454,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
break;
case SND_SOC_DAIFMT_DSP_A:
iface_reg |= TLV320AIC23_LRP_ON;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_B:
iface_reg |= TLV320AIC23_FOR_DSP;
break;
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 54a87a905eb6..e2862372c26e 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -929,7 +929,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_I2S:
break;
case SND_SOC_DAIFMT_DSP_A:
- dsp_a_val = 0x1;
+ dsp_a_val = 0x1; /* fall through */
case SND_SOC_DAIFMT_DSP_B:
/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 2e014c80d113..616cd4bebd01 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -274,6 +274,7 @@ static int tpa6130a2_probe(struct i2c_client *client,
default:
dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
data->id);
+ /* fall through */
case TPA6130A2:
regulator = "Vdd";
break;
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index 43568435c208..738e04b09116 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
+#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -374,11 +375,20 @@ static const struct of_device_id ts3a227e_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ts3a227e_of_match);
+#ifdef CONFIG_ACPI
+static struct acpi_device_id ts3a227e_acpi_match[] = {
+ { "104C227E", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, ts3a227e_acpi_match);
+#endif
+
static struct i2c_driver ts3a227e_driver = {
.driver = {
.name = "ts3a227e",
.pm = &ts3a227e_pm,
.of_match_table = of_match_ptr(ts3a227e_of_match),
+ .acpi_match_table = ACPI_PTR(ts3a227e_acpi_match),
},
.probe = ts3a227e_i2c_probe,
.id_table = ts3a227e_i2c_ids,
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 72486bf072f2..4f0481d3c7a7 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -1951,7 +1951,6 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
return ret;
arizona_init_gpio(codec);
- arizona_init_notifiers(codec);
snd_soc_component_disable_pin(component, "HAPTICS");
@@ -2043,6 +2042,14 @@ static int wm5102_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm5102);
+ if (IS_ENABLED(CONFIG_OF)) {
+ if (!dev_get_platdata(arizona->dev)) {
+ ret = arizona_of_get_audio_pdata(arizona);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
mutex_init(&arizona->dac_comp_lock);
wm5102->core.arizona = arizona;
@@ -2098,6 +2105,11 @@ static int wm5102_probe(struct platform_device *pdev)
return ret;
}
+ arizona_init_common(arizona);
+
+ ret = arizona_init_vol_limit(arizona);
+ if (ret < 0)
+ goto err_dsp_irq;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
goto err_dsp_irq;
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 858a24fc28e8..6ed1e1f9ce51 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2290,7 +2290,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
arizona_init_gpio(codec);
arizona_init_mono(codec);
- arizona_init_notifiers(codec);
for (i = 0; i < WM5110_NUM_ADSP; ++i) {
ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
@@ -2398,6 +2397,14 @@ static int wm5110_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm5110);
+ if (IS_ENABLED(CONFIG_OF)) {
+ if (!dev_get_platdata(arizona->dev)) {
+ ret = arizona_of_get_audio_pdata(arizona);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
wm5110->core.arizona = arizona;
wm5110->core.num_inputs = 8;
@@ -2454,6 +2461,11 @@ static int wm5110_probe(struct platform_device *pdev)
return ret;
}
+ arizona_init_common(arizona);
+
+ ret = arizona_init_vol_limit(arizona);
+ if (ret < 0)
+ goto err_dsp_irq;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
goto err_dsp_irq;
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index b8c1940f2243..a394dbee77aa 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -196,7 +196,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_codec *codec = dai->codec;
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
- u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
+ unsigned int iface;
int i;
/* The set of sample rates that can be supported depends on the
@@ -223,15 +223,16 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
/* bit size */
switch (params_width(params)) {
case 16:
+ iface = 0x0;
break;
case 20:
- iface |= 0x0001;
+ iface = 0x1;
break;
case 24:
- iface |= 0x0002;
+ iface = 0x2;
break;
case 32:
- iface |= 0x0003;
+ iface = 0x3;
break;
default:
dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d",
@@ -242,7 +243,9 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d, rate param = %d",
params_width(params), params_rate(params));
- snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface);
+ snd_soc_update_bits(codec, WM8741_FORMAT_CONTROL, WM8741_IWL_MASK,
+ iface);
+
return 0;
}
@@ -295,7 +298,7 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1C3;
+ unsigned int iface;
/* check master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -308,18 +311,19 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- iface |= 0x0008;
+ iface = 0x08;
break;
case SND_SOC_DAIFMT_RIGHT_J:
+ iface = 0x00;
break;
case SND_SOC_DAIFMT_LEFT_J:
- iface |= 0x0004;
+ iface = 0x04;
break;
case SND_SOC_DAIFMT_DSP_A:
- iface |= 0x000C;
+ iface = 0x0C;
break;
case SND_SOC_DAIFMT_DSP_B:
- iface |= 0x001C;
+ iface = 0x1C;
break;
default:
return -EINVAL;
@@ -329,14 +333,14 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
- case SND_SOC_DAIFMT_IB_IF:
- iface |= 0x0010;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface |= 0x10;
break;
case SND_SOC_DAIFMT_IB_NF:
- iface |= 0x0020;
+ iface |= 0x20;
break;
- case SND_SOC_DAIFMT_NB_IF:
- iface |= 0x0030;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= 0x30;
break;
default:
return -EINVAL;
@@ -347,7 +351,10 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
fmt & SND_SOC_DAIFMT_FORMAT_MASK,
((fmt & SND_SOC_DAIFMT_INV_MASK)));
- snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface);
+ snd_soc_update_bits(codec, WM8741_FORMAT_CONTROL,
+ WM8741_BCP_MASK | WM8741_LRP_MASK | WM8741_FMT_MASK,
+ iface);
+
return 0;
}
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index d05d76e79c70..0271a5253bd3 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -971,7 +971,7 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec *codec,
case SND_SOC_DAIFMT_CBS_CFS:
break;
case SND_SOC_DAIFMT_CBM_CFM:
- ioctl |= 0x2;
+ ioctl |= 0x2; /* fall through */
case SND_SOC_DAIFMT_CBM_CFS:
voice |= 0x0040;
break;
@@ -1096,7 +1096,7 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec *codec,
case SND_SOC_DAIFMT_CBS_CFS:
break;
case SND_SOC_DAIFMT_CBM_CFM:
- ioctl |= 0x1;
+ ioctl |= 0x1; /* fall through */
case SND_SOC_DAIFMT_CBM_CFS:
hifi |= 0x0040;
break;
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 195f7bf6eb22..830ffd80de4a 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1076,6 +1076,7 @@ static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai,
switch (clk_id) {
case WM8993_SYSCLK_MCLK:
wm8993->mclk_rate = freq;
+ /* fall through */
case WM8993_SYSCLK_FLL:
wm8993->sysclk_source = clk_id;
break;
@@ -1123,6 +1124,7 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
aif1 |= WM8993_AIF_LRCLK_INV;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
aif1 |= 0x18;
break;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 3896523b71e9..f91b49e1ece3 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -860,6 +860,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
switch (wm8994->vmid_mode) {
default:
WARN_ON(NULL == "Invalid VMID mode");
+ /* fall through */
case WM8994_VMID_NORMAL:
/* Startup bias, VMID ramp & buffer */
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
@@ -2654,6 +2655,7 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_DSP_B:
aif1 |= WM8994_AIF1_LRCLK_INV;
lrclk |= WM8958_AIF1_LRCLK_INV;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
aif1 |= 0x18;
break;
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 49401a8aae64..77f512767273 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -1068,8 +1068,6 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec)
if (ret < 0)
return ret;
- arizona_init_notifiers(codec);
-
snd_soc_component_disable_pin(component, "HAPTICS");
priv->core.arizona->dapm = dapm;
@@ -1136,6 +1134,14 @@ static int wm8997_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm8997);
+ if (IS_ENABLED(CONFIG_OF)) {
+ if (!dev_get_platdata(arizona->dev)) {
+ ret = arizona_of_get_audio_pdata(arizona);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
wm8997->core.arizona = arizona;
wm8997->core.num_inputs = 4;
@@ -1168,6 +1174,11 @@ static int wm8997_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
+ arizona_init_common(arizona);
+
+ ret = arizona_init_vol_limit(arizona);
+ if (ret < 0)
+ return ret;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
return ret;
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 44f447136e22..2d211dbe7422 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -101,7 +101,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
return 0;
}
-static int wm8998_in1mux_put(struct snd_kcontrol *kcontrol,
+static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
@@ -109,84 +109,38 @@ static int wm8998_in1mux_put(struct snd_kcontrol *kcontrol,
struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = wm8998->core.arizona;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int mux, inmode;
- unsigned int mode_val, src_val;
+ unsigned int mode_reg, mode_index;
+ unsigned int mux, inmode, src_val, mode_val;
mux = ucontrol->value.enumerated.item[0];
if (mux > 1)
return -EINVAL;
- /* L and R registers have same shift and mask */
- inmode = arizona->pdata.inmode[2 * mux];
- src_val = mux << ARIZONA_IN1L_SRC_SHIFT;
- if (inmode & ARIZONA_INMODE_SE)
- src_val |= 1 << ARIZONA_IN1L_SRC_SE_SHIFT;
-
- switch (arizona->pdata.inmode[0]) {
- case ARIZONA_INMODE_DMIC:
- if (mux)
- mode_val = 0; /* B always analogue */
- else
- mode_val = 1 << ARIZONA_IN1_MODE_SHIFT;
-
- snd_soc_update_bits(codec, ARIZONA_IN1L_CONTROL,
- ARIZONA_IN1_MODE_MASK, mode_val);
-
- /* IN1A is digital so L and R must change together */
- /* src_val setting same for both registers */
- snd_soc_update_bits(codec,
- ARIZONA_ADC_DIGITAL_VOLUME_1L,
- ARIZONA_IN1L_SRC_MASK |
- ARIZONA_IN1L_SRC_SE_MASK, src_val);
- snd_soc_update_bits(codec,
- ARIZONA_ADC_DIGITAL_VOLUME_1R,
- ARIZONA_IN1R_SRC_MASK |
- ARIZONA_IN1R_SRC_SE_MASK, src_val);
+ switch (e->reg) {
+ case ARIZONA_ADC_DIGITAL_VOLUME_2L:
+ mode_reg = ARIZONA_IN2L_CONTROL;
+ mode_index = 1 + (2 * mux);
break;
default:
- /* both analogue */
- snd_soc_update_bits(codec,
- e->reg,
- ARIZONA_IN1L_SRC_MASK |
- ARIZONA_IN1L_SRC_SE_MASK,
- src_val);
+ mode_reg = ARIZONA_IN1L_CONTROL;
+ mode_index = (2 * mux);
break;
}
- return snd_soc_dapm_mux_update_power(dapm, kcontrol,
- ucontrol->value.enumerated.item[0],
- e, NULL);
-}
-
-static int wm8998_in2mux_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
- struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
- struct arizona *arizona = wm8998->core.arizona;
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int mux, inmode, src_val, mode_val;
-
- mux = ucontrol->value.enumerated.item[0];
- if (mux > 1)
- return -EINVAL;
-
- inmode = arizona->pdata.inmode[1 + (2 * mux)];
+ inmode = arizona->pdata.inmode[mode_index];
if (inmode & ARIZONA_INMODE_DMIC)
- mode_val = 1 << ARIZONA_IN2_MODE_SHIFT;
+ mode_val = 1 << ARIZONA_IN1_MODE_SHIFT;
else
mode_val = 0;
- src_val = mux << ARIZONA_IN2L_SRC_SHIFT;
+ src_val = mux << ARIZONA_IN1L_SRC_SHIFT;
if (inmode & ARIZONA_INMODE_SE)
- src_val |= 1 << ARIZONA_IN2L_SRC_SE_SHIFT;
+ src_val |= 1 << ARIZONA_IN1L_SRC_SE_SHIFT;
- snd_soc_update_bits(codec, ARIZONA_IN2L_CONTROL,
- ARIZONA_IN2_MODE_MASK, mode_val);
+ snd_soc_update_bits(codec, mode_reg, ARIZONA_IN1_MODE_MASK, mode_val);
- snd_soc_update_bits(codec, ARIZONA_ADC_DIGITAL_VOLUME_2L,
- ARIZONA_IN2L_SRC_MASK | ARIZONA_IN2L_SRC_SE_MASK,
+ snd_soc_update_bits(codec, e->reg,
+ ARIZONA_IN1L_SRC_MASK | ARIZONA_IN1L_SRC_SE_MASK,
src_val);
return snd_soc_dapm_mux_update_power(dapm, kcontrol,
@@ -216,14 +170,14 @@ static SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
static const struct snd_kcontrol_new wm8998_in1mux[2] = {
SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum,
- snd_soc_dapm_get_enum_double, wm8998_in1mux_put),
+ snd_soc_dapm_get_enum_double, wm8998_inmux_put),
SOC_DAPM_ENUM_EXT("IN1R Mux", wm8998_in1muxr_enum,
- snd_soc_dapm_get_enum_double, wm8998_in1mux_put),
+ snd_soc_dapm_get_enum_double, wm8998_inmux_put),
};
static const struct snd_kcontrol_new wm8998_in2mux =
SOC_DAPM_ENUM_EXT("IN2 Mux", wm8998_in2mux_enum,
- snd_soc_dapm_get_enum_double, wm8998_in2mux_put);
+ snd_soc_dapm_get_enum_double, wm8998_inmux_put);
static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
@@ -1330,7 +1284,6 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec)
return ret;
arizona_init_gpio(codec);
- arizona_init_notifiers(codec);
snd_soc_component_disable_pin(component, "HAPTICS");
@@ -1399,6 +1352,14 @@ static int wm8998_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm8998);
+ if (IS_ENABLED(CONFIG_OF)) {
+ if (!dev_get_platdata(arizona->dev)) {
+ ret = arizona_of_get_audio_pdata(arizona);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
wm8998->core.arizona = arizona;
wm8998->core.num_inputs = 3; /* IN1L, IN1R, IN2 */
@@ -1423,6 +1384,8 @@ static int wm8998_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
+ arizona_init_common(arizona);
+
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
return ret;
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index f6d5c0f2aea5..2c09f71fe433 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/mfd/wm97xx.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
@@ -18,12 +19,19 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/compat.h>
#include <sound/initval.h>
#include <sound/soc.h>
#define WM9705_VENDOR_ID 0x574d4c05
#define WM9705_VENDOR_ID_MASK 0xffffffff
+struct wm9705_priv {
+ struct snd_ac97 *ac97;
+ struct wm97xx_platform_data *mfd_pdata;
+};
+
static const struct reg_default wm9705_reg_defaults[] = {
{ 0x02, 0x8000 },
{ 0x04, 0x8000 },
@@ -292,10 +300,10 @@ static int wm9705_soc_suspend(struct snd_soc_codec *codec)
static int wm9705_soc_resume(struct snd_soc_codec *codec)
{
- struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+ struct wm9705_priv *wm9705 = snd_soc_codec_get_drvdata(codec);
int ret;
- ret = snd_ac97_reset(ac97, true, WM9705_VENDOR_ID,
+ ret = snd_ac97_reset(wm9705->ac97, true, WM9705_VENDOR_ID,
WM9705_VENDOR_ID_MASK);
if (ret < 0)
return ret;
@@ -311,38 +319,45 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
static int wm9705_soc_probe(struct snd_soc_codec *codec)
{
- struct snd_ac97 *ac97;
+ struct wm9705_priv *wm9705 = snd_soc_codec_get_drvdata(codec);
struct regmap *regmap;
- int ret;
-
- ac97 = snd_soc_new_ac97_codec(codec, WM9705_VENDOR_ID,
- WM9705_VENDOR_ID_MASK);
- if (IS_ERR(ac97)) {
- dev_err(codec->dev, "Failed to register AC97 codec\n");
- return PTR_ERR(ac97);
- }
- regmap = regmap_init_ac97(ac97, &wm9705_regmap_config);
- if (IS_ERR(regmap)) {
- ret = PTR_ERR(regmap);
- goto err_free_ac97_codec;
+ if (wm9705->mfd_pdata) {
+ wm9705->ac97 = wm9705->mfd_pdata->ac97;
+ regmap = wm9705->mfd_pdata->regmap;
+ } else {
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ wm9705->ac97 = snd_soc_new_ac97_codec(codec, WM9705_VENDOR_ID,
+ WM9705_VENDOR_ID_MASK);
+ if (IS_ERR(wm9705->ac97)) {
+ dev_err(codec->dev, "Failed to register AC97 codec\n");
+ return PTR_ERR(wm9705->ac97);
+ }
+
+ regmap = regmap_init_ac97(wm9705->ac97, &wm9705_regmap_config);
+ if (IS_ERR(regmap)) {
+ snd_soc_free_ac97_codec(wm9705->ac97);
+ return PTR_ERR(regmap);
+ }
+#endif
}
- snd_soc_codec_set_drvdata(codec, ac97);
+ snd_soc_codec_set_drvdata(codec, wm9705->ac97);
snd_soc_codec_init_regmap(codec, regmap);
return 0;
-err_free_ac97_codec:
- snd_soc_free_ac97_codec(ac97);
- return ret;
}
static int wm9705_soc_remove(struct snd_soc_codec *codec)
{
- struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ struct wm9705_priv *wm9705 = snd_soc_codec_get_drvdata(codec);
- snd_soc_codec_exit_regmap(codec);
- snd_soc_free_ac97_codec(ac97);
+ if (!wm9705->mfd_pdata) {
+ snd_soc_codec_exit_regmap(codec);
+ snd_soc_free_ac97_codec(wm9705->ac97);
+ }
+#endif
return 0;
}
@@ -364,6 +379,15 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
static int wm9705_probe(struct platform_device *pdev)
{
+ struct wm9705_priv *wm9705;
+
+ wm9705 = devm_kzalloc(&pdev->dev, sizeof(*wm9705), GFP_KERNEL);
+ if (wm9705 == NULL)
+ return -ENOMEM;
+
+ wm9705->mfd_pdata = dev_get_platdata(&pdev->dev);
+ platform_set_drvdata(pdev, wm9705);
+
return snd_soc_register_codec(&pdev->dev,
&soc_codec_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
}
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 1a3e1797994a..4f6d1a442bc4 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/mfd/wm97xx.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
@@ -19,6 +20,8 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/compat.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/tlv.h>
@@ -30,6 +33,7 @@ struct wm9712_priv {
struct snd_ac97 *ac97;
unsigned int hp_mixer[2];
struct mutex lock;
+ struct wm97xx_platform_data *mfd_pdata;
};
static const struct reg_default wm9712_reg_defaults[] = {
@@ -636,18 +640,26 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
struct regmap *regmap;
int ret;
- wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID,
- WM9712_VENDOR_ID_MASK);
- if (IS_ERR(wm9712->ac97)) {
- ret = PTR_ERR(wm9712->ac97);
- dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
- return ret;
- }
-
- regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config);
- if (IS_ERR(regmap)) {
- ret = PTR_ERR(regmap);
- goto err_free_ac97_codec;
+ if (wm9712->mfd_pdata) {
+ wm9712->ac97 = wm9712->mfd_pdata->ac97;
+ regmap = wm9712->mfd_pdata->regmap;
+ } else {
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID,
+ WM9712_VENDOR_ID_MASK);
+ if (IS_ERR(wm9712->ac97)) {
+ ret = PTR_ERR(wm9712->ac97);
+ dev_err(codec->dev,
+ "Failed to register AC97 codec: %d\n", ret);
+ return ret;
+ }
+
+ regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config);
+ if (IS_ERR(regmap)) {
+ snd_soc_free_ac97_codec(wm9712->ac97);
+ return PTR_ERR(regmap);
+ }
+#endif
}
snd_soc_codec_init_regmap(codec, regmap);
@@ -656,17 +668,18 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, AC97_VIDEO, 0x3000, 0x3000);
return 0;
-err_free_ac97_codec:
- snd_soc_free_ac97_codec(wm9712->ac97);
- return ret;
}
static int wm9712_soc_remove(struct snd_soc_codec *codec)
{
+#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
- snd_soc_codec_exit_regmap(codec);
- snd_soc_free_ac97_codec(wm9712->ac97);
+ if (!wm9712->mfd_pdata) {
+ snd_soc_codec_exit_regmap(codec);
+ snd_soc_free_ac97_codec(wm9712->ac97);
+ }
+#endif
return 0;
}
@@ -697,6 +710,7 @@ static int wm9712_probe(struct platform_device *pdev)
mutex_init(&wm9712->lock);
+ wm9712->mfd_pdata = dev_get_platdata(&pdev->dev);
platform_set_drvdata(pdev, wm9712);
return snd_soc_register_codec(&pdev->dev,
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 7e4822185feb..df7220656d98 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -17,12 +17,15 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/mfd/wm97xx.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/compat.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
@@ -38,6 +41,7 @@ struct wm9713_priv {
u32 pll_in; /* PLL input frequency */
unsigned int hp_mixer[2];
struct mutex lock;
+ struct wm97xx_platform_data *mfd_pdata;
};
#define HPL_MIXER 0
@@ -1205,17 +1209,23 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
static int wm9713_soc_probe(struct snd_soc_codec *codec)
{
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
- struct regmap *regmap;
+ struct regmap *regmap = NULL;
- wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID,
- WM9713_VENDOR_ID_MASK);
- if (IS_ERR(wm9713->ac97))
- return PTR_ERR(wm9713->ac97);
-
- regmap = regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
- if (IS_ERR(regmap)) {
- snd_soc_free_ac97_codec(wm9713->ac97);
- return PTR_ERR(regmap);
+ if (wm9713->mfd_pdata) {
+ wm9713->ac97 = wm9713->mfd_pdata->ac97;
+ regmap = wm9713->mfd_pdata->regmap;
+ } else {
+#ifdef CONFIG_SND_SOC_AC97_BUS
+ wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID,
+ WM9713_VENDOR_ID_MASK);
+ if (IS_ERR(wm9713->ac97))
+ return PTR_ERR(wm9713->ac97);
+ regmap = regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
+ if (IS_ERR(regmap)) {
+ snd_soc_free_ac97_codec(wm9713->ac97);
+ return PTR_ERR(regmap);
+ }
+#endif
}
snd_soc_codec_init_regmap(codec, regmap);
@@ -1228,10 +1238,14 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
static int wm9713_soc_remove(struct snd_soc_codec *codec)
{
+#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
- snd_soc_codec_exit_regmap(codec);
- snd_soc_free_ac97_codec(wm9713->ac97);
+ if (!wm9713->mfd_pdata) {
+ snd_soc_codec_exit_regmap(codec);
+ snd_soc_free_ac97_codec(wm9713->ac97);
+ }
+#endif
return 0;
}
@@ -1262,6 +1276,7 @@ static int wm9713_probe(struct platform_device *pdev)
mutex_init(&wm9713->lock);
+ wm9713->mfd_pdata = dev_get_platdata(&pdev->dev);
platform_set_drvdata(pdev, wm9713);
return snd_soc_register_codec(&pdev->dev,
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index f395bbc7c354..804c6f2bcf21 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1721,7 +1721,8 @@ static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp)
PTR_ERR(chan));
return PTR_ERR(chan);
}
- BUG_ON(!chan->device || !chan->device->dev);
+ if (WARN_ON(!chan->device || !chan->device->dev))
+ return -EINVAL;
if (chan->device->dev->of_node)
ret = of_property_read_string(chan->device->dev->of_node,
@@ -1867,6 +1868,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (irq >= 0) {
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common",
dev_name(&pdev->dev));
+ if (!irq_name) {
+ ret = -ENOMEM;
+ goto err;
+ }
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
davinci_mcasp_common_irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
@@ -1884,6 +1889,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (irq >= 0) {
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx",
dev_name(&pdev->dev));
+ if (!irq_name) {
+ ret = -ENOMEM;
+ goto err;
+ }
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
davinci_mcasp_rx_irq_handler,
IRQF_ONESHOT, irq_name, mcasp);
@@ -1899,6 +1908,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (irq >= 0) {
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx",
dev_name(&pdev->dev));
+ if (!irq_name) {
+ ret = -ENOMEM;
+ goto err;
+ }
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
davinci_mcasp_tx_irq_handler,
IRQF_ONESHOT, irq_name, mcasp);
@@ -1982,8 +1995,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
- !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list)
- return -ENOMEM;
+ !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) {
+ ret = -ENOMEM;
+ goto err;
+ }
ret = davinci_mcasp_set_ch_constraints(mcasp);
if (ret)
diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig
index c6fd95fa5ca6..aa0c6ec4d93c 100644
--- a/sound/soc/dwc/Kconfig
+++ b/sound/soc/dwc/Kconfig
@@ -4,8 +4,8 @@ config SND_DESIGNWARE_I2S
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for I2S driver for
- Synopsys desigwnware I2S device. The device supports upto
- maximum of 8 channels each for play and record.
+ Synopsys designware I2S device. The device supports up to
+ a maximum of 8 channels each for play and record.
config SND_DESIGNWARE_PCM
bool "PCM PIO extension for I2S driver"
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 2db4d0c80d33..1225e0399de8 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -166,7 +166,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx],
cpu_priv->sysclk_freq[tx],
cpu_priv->sysclk_dir[tx]);
- if (ret) {
+ if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set sysclk for cpu dai\n");
return ret;
}
@@ -174,7 +174,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
if (cpu_priv->slot_width) {
ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2,
cpu_priv->slot_width);
- if (ret) {
+ if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set TDM slot for cpu dai\n");
return ret;
}
@@ -270,7 +270,7 @@ static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id,
pll_out, SND_SOC_CLOCK_IN);
- if (ret) {
+ if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set SYSCLK: %d\n", ret);
return ret;
}
@@ -283,7 +283,7 @@ static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
codec_priv->mclk_freq,
SND_SOC_CLOCK_IN);
- if (ret) {
+ if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to switch away from FLL: %d\n", ret);
return ret;
}
@@ -459,7 +459,7 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
- if (ret) {
+ if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set sysclk in %s\n", __func__);
return ret;
}
@@ -639,6 +639,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
devm_kasprintf(&pdev->dev, GFP_KERNEL,
"ac97-codec.%u",
(unsigned int)idx);
+ if (!priv->dai_link[0].codec_name) {
+ ret = -ENOMEM;
+ goto asrc_fail;
+ }
}
priv->dai_link[0].platform_of_node = cpu_np;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 7e6cc4da0088..4f7469c1864c 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -1110,7 +1110,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
struct clk *clk, u64 savesub,
enum spdif_txrate index, bool round)
{
- const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
+ static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
u64 rate_ideal, rate_actual, sub;
u32 sysclk_dfmin, sysclk_dfmax;
@@ -1169,7 +1169,7 @@ out:
static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
enum spdif_txrate index)
{
- const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
+ static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
struct platform_device *pdev = spdif_priv->pdev;
struct device *dev = &pdev->dev;
u64 savesub = 100000, ret;
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 64598d1183f8..f2f51e06e22c 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -197,12 +197,13 @@ struct fsl_ssi_soc_data {
* @use_dma: DMA is used or FIQ with stream filter
* @use_dual_fifo: DMA with support for both FIFOs used
* @fifo_deph: Depth of the SSI FIFOs
+ * @slot_width: width of each DAI slot
+ * @slots: number of slots
* @rxtx_reg_val: Specific register settings for receive/transmit configuration
*
* @clk: SSI clock
* @baudclk: SSI baud clock for master mode
* @baudclk_streams: Active streams that are using baudclk
- * @bitclk_freq: bitclock frequency set by .set_dai_sysclk
*
* @dma_params_tx: DMA transmit parameters
* @dma_params_rx: DMA receive parameters
@@ -233,12 +234,13 @@ struct fsl_ssi_private {
bool use_dual_fifo;
bool has_ipg_clk_name;
unsigned int fifo_depth;
+ unsigned int slot_width;
+ unsigned int slots;
struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
struct clk *clk;
struct clk *baudclk;
unsigned int baudclk_streams;
- unsigned int bitclk_freq;
/* regcache for volatile regs */
u32 regcache_sfcsr;
@@ -700,8 +702,8 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
* Note: This function can be only called when using SSI as DAI master
*
* Quick instruction for parameters:
- * freq: Output BCLK frequency = samplerate * 32 (fixed) * channels
- * dir: SND_SOC_CLOCK_OUT -> TxBCLK, SND_SOC_CLOCK_IN -> RxBCLK.
+ * freq: Output BCLK frequency = samplerate * slots * slot_width
+ * (In 2-channel I2S Master mode, slot_width is fixed 32)
*/
static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai,
@@ -712,15 +714,21 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
unsigned long clkrate, baudrate, tmprate;
+ unsigned int slots = params_channels(hw_params);
+ unsigned int slot_width = 32;
u64 sub, savesub = 100000;
unsigned int freq;
bool baudclk_is_used;
- /* Prefer the explicitly set bitclock frequency */
- if (ssi_private->bitclk_freq)
- freq = ssi_private->bitclk_freq;
- else
- freq = params_channels(hw_params) * 32 * params_rate(hw_params);
+ /* Override slots and slot_width if being specifically set... */
+ if (ssi_private->slots)
+ slots = ssi_private->slots;
+ /* ...but keep 32 bits if slots is 2 -- I2S Master mode */
+ if (ssi_private->slot_width && slots != 2)
+ slot_width = ssi_private->slot_width;
+
+ /* Generate bit clock based on the slot number and slot width */
+ freq = slots * slot_width * params_rate(hw_params);
/* Don't apply it to any non-baudclk circumstance */
if (IS_ERR(ssi_private->baudclk))
@@ -805,16 +813,6 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
return 0;
}
-static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
-
- ssi_private->bitclk_freq = freq;
-
- return 0;
-}
-
/**
* fsl_ssi_hw_params - program the sample size
*
@@ -1095,6 +1093,12 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
struct regmap *regs = ssi_private->regs;
u32 val;
+ /* The word length should be 8, 10, 12, 16, 18, 20, 22 or 24 */
+ if (slot_width & 1 || slot_width < 8 || slot_width > 24) {
+ dev_err(cpu_dai->dev, "invalid slot width: %d\n", slot_width);
+ return -EINVAL;
+ }
+
/* The slot number should be >= 2 if using Network mode or I2S mode */
regmap_read(regs, CCSR_SSI_SCR, &val);
val &= CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_NET;
@@ -1121,6 +1125,9 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, val);
+ ssi_private->slot_width = slot_width;
+ ssi_private->slots = slots;
+
return 0;
}
@@ -1191,7 +1198,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
.hw_params = fsl_ssi_hw_params,
.hw_free = fsl_ssi_hw_free,
.set_fmt = fsl_ssi_set_dai_fmt,
- .set_sysclk = fsl_ssi_set_dai_sysclk,
.set_tdm_slot = fsl_ssi_set_dai_tdm_slot,
.trigger = fsl_ssi_trigger,
};
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 488c52f9405f..1b6164249341 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -29,7 +29,9 @@ struct graph_card_data {
struct graph_dai_props {
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
+ unsigned int mclk_fs;
} *dai_props;
+ unsigned int mclk_fs;
struct snd_soc_dai_link *dai_link;
struct gpio_desc *pa_gpio;
};
@@ -95,9 +97,43 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
asoc_simple_card_clk_disable(&dai_props->codec_dai);
}
+static int asoc_graph_card_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;
+ 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);
+ unsigned int mclk, mclk_fs = 0;
+ int ret = 0;
+
+ if (priv->mclk_fs)
+ mclk_fs = priv->mclk_fs;
+ else if (dai_props->mclk_fs)
+ mclk_fs = dai_props->mclk_fs;
+
+ if (mclk_fs) {
+ mclk = params_rate(params) * mclk_fs;
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+ SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ goto err;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+ SND_SOC_CLOCK_OUT);
+ if (ret && ret != -ENOTSUPP)
+ goto err;
+ }
+ return 0;
+err:
+ return ret;
+}
+
static const struct snd_soc_ops asoc_graph_card_ops = {
.startup = asoc_graph_card_startup,
.shutdown = asoc_graph_card_shutdown,
+ .hw_params = asoc_graph_card_hw_params,
};
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
@@ -146,10 +182,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
if (ret < 0)
goto dai_link_of_err;
- /*
- * we need to consider "mclk-fs" around here
- * see simple-card
- */
+ of_property_read_u32(rcpu_ep, "mclk-fs", &dai_props->mclk_fs);
ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
if (ret < 0)
@@ -217,10 +250,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
if (ret < 0)
return ret;
- /*
- * we need to consider "mclk-fs" around here
- * see simple-card
- */
+ /* 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++);
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
index 567f9767fb73..d7fbb0a0a28b 100644
--- a/sound/soc/img/img-i2s-in.c
+++ b/sound/soc/img/img-i2s-in.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <sound/core.h>
@@ -60,8 +61,33 @@ struct img_i2s_in {
void __iomem *channel_base;
unsigned int active_channels;
struct snd_soc_dai_driver dai_driver;
+ u32 suspend_ctl;
+ u32 *suspend_ch_ctl;
};
+static int img_i2s_in_runtime_suspend(struct device *dev)
+{
+ struct img_i2s_in *i2s = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(i2s->clk_sys);
+
+ return 0;
+}
+
+static int img_i2s_in_runtime_resume(struct device *dev)
+{
+ struct img_i2s_in *i2s = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(i2s->clk_sys);
+ if (ret) {
+ dev_err(dev, "Unable to enable sys clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg)
{
writel(val, i2s->base + reg);
@@ -279,7 +305,7 @@ static int img_i2s_in_hw_params(struct snd_pcm_substream *substream,
static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
- int i;
+ int i, ret;
u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0;
u32 reg;
@@ -319,6 +345,10 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK;
+ ret = pm_runtime_get_sync(i2s->dev);
+ if (ret < 0)
+ return ret;
+
for (i = 0; i < i2s->active_channels; i++)
img_i2s_in_ch_disable(i2s, i);
@@ -338,6 +368,8 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
for (i = 0; i < i2s->active_channels; i++)
img_i2s_in_ch_enable(i2s, i);
+ pm_runtime_put(i2s->dev);
+
return 0;
}
@@ -427,9 +459,15 @@ static int img_i2s_in_probe(struct platform_device *pdev)
return PTR_ERR(i2s->clk_sys);
}
- ret = clk_prepare_enable(i2s->clk_sys);
- if (ret)
- return ret;
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_i2s_in_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto err_suspend;
i2s->active_channels = 1;
i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
@@ -447,7 +485,7 @@ static int img_i2s_in_probe(struct platform_device *pdev)
if (IS_ERR(rst)) {
if (PTR_ERR(rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
- goto err_clk_disable;
+ goto err_suspend;
}
dev_dbg(dev, "No top level reset found\n");
@@ -469,42 +507,110 @@ static int img_i2s_in_probe(struct platform_device *pdev)
IMG_I2S_IN_CH_CTL_JUST_MASK |
IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL);
+ pm_runtime_put(&pdev->dev);
+
+ i2s->suspend_ch_ctl = devm_kzalloc(dev,
+ sizeof(*i2s->suspend_ch_ctl) * i2s->max_i2s_chan, GFP_KERNEL);
+ if (!i2s->suspend_ch_ctl) {
+ ret = -ENOMEM;
+ goto err_suspend;
+ }
+
ret = devm_snd_soc_register_component(dev, &img_i2s_in_component,
&i2s->dai_driver, 1);
if (ret)
- goto err_clk_disable;
+ goto err_suspend;
ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0);
if (ret)
- goto err_clk_disable;
+ goto err_suspend;
return 0;
-err_clk_disable:
- clk_disable_unprepare(i2s->clk_sys);
+err_suspend:
+ if (!pm_runtime_enabled(&pdev->dev))
+ img_i2s_in_runtime_suspend(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
return ret;
}
static int img_i2s_in_dev_remove(struct platform_device *pdev)
{
- struct img_i2s_in *i2s = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ img_i2s_in_runtime_suspend(&pdev->dev);
- clk_disable_unprepare(i2s->clk_sys);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int img_i2s_in_suspend(struct device *dev)
+{
+ struct img_i2s_in *i2s = dev_get_drvdata(dev);
+ int i, ret;
+ u32 reg;
+
+ if (pm_runtime_status_suspended(dev)) {
+ ret = img_i2s_in_runtime_resume(dev);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL);
+ i2s->suspend_ch_ctl[i] = reg;
+ }
+
+ i2s->suspend_ctl = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL);
+
+ img_i2s_in_runtime_suspend(dev);
return 0;
}
+static int img_i2s_in_resume(struct device *dev)
+{
+ struct img_i2s_in *i2s = dev_get_drvdata(dev);
+ int i, ret;
+ u32 reg;
+
+ ret = img_i2s_in_runtime_resume(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = i2s->suspend_ch_ctl[i];
+ img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL);
+ }
+
+ img_i2s_in_writel(i2s, i2s->suspend_ctl, IMG_I2S_IN_CTL);
+
+ if (pm_runtime_status_suspended(dev))
+ img_i2s_in_runtime_suspend(dev);
+
+ return 0;
+}
+#endif
+
static const struct of_device_id img_i2s_in_of_match[] = {
{ .compatible = "img,i2s-in" },
{}
};
MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
+static const struct dev_pm_ops img_i2s_in_pm_ops = {
+ SET_RUNTIME_PM_OPS(img_i2s_in_runtime_suspend,
+ img_i2s_in_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend, img_i2s_in_resume)
+};
+
static struct platform_driver img_i2s_in_driver = {
.driver = {
.name = "img-i2s-in",
- .of_match_table = img_i2s_in_of_match
+ .of_match_table = img_i2s_in_of_match,
+ .pm = &img_i2s_in_pm_ops
},
.probe = img_i2s_in_probe,
.remove = img_i2s_in_dev_remove
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index 78b7f6cd675b..30a95bcef2db 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -63,29 +63,36 @@ struct img_i2s_out {
unsigned int active_channels;
struct reset_control *rst;
struct snd_soc_dai_driver dai_driver;
+ u32 suspend_ctl;
+ u32 *suspend_ch_ctl;
};
-static int img_i2s_out_suspend(struct device *dev)
+static int img_i2s_out_runtime_suspend(struct device *dev)
{
struct img_i2s_out *i2s = dev_get_drvdata(dev);
- if (!i2s->force_clk_active)
- clk_disable_unprepare(i2s->clk_ref);
+ clk_disable_unprepare(i2s->clk_ref);
+ clk_disable_unprepare(i2s->clk_sys);
return 0;
}
-static int img_i2s_out_resume(struct device *dev)
+static int img_i2s_out_runtime_resume(struct device *dev)
{
struct img_i2s_out *i2s = dev_get_drvdata(dev);
int ret;
- if (!i2s->force_clk_active) {
- ret = clk_prepare_enable(i2s->clk_ref);
- if (ret) {
- dev_err(dev, "clk_enable failed: %d\n", ret);
- return ret;
- }
+ ret = clk_prepare_enable(i2s->clk_sys);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(i2s->clk_ref);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ clk_disable_unprepare(i2s->clk_sys);
+ return ret;
}
return 0;
@@ -287,7 +294,7 @@ static int img_i2s_out_hw_params(struct snd_pcm_substream *substream,
static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
- int i;
+ int i, ret;
bool force_clk_active;
u32 chan_control_mask, control_mask, chan_control_set = 0;
u32 reg, control_set = 0;
@@ -342,6 +349,10 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
+ ret = pm_runtime_get_sync(i2s->dev);
+ if (ret < 0)
+ return ret;
+
img_i2s_out_disable(i2s);
reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
@@ -361,6 +372,7 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
img_i2s_out_ch_enable(i2s, i);
img_i2s_out_enable(i2s);
+ pm_runtime_put(i2s->dev);
i2s->force_clk_active = force_clk_active;
@@ -467,9 +479,20 @@ static int img_i2s_out_probe(struct platform_device *pdev)
return PTR_ERR(i2s->clk_ref);
}
- ret = clk_prepare_enable(i2s->clk_sys);
- if (ret)
- return ret;
+ i2s->suspend_ch_ctl = devm_kzalloc(dev,
+ sizeof(*i2s->suspend_ch_ctl) * i2s->max_i2s_chan, GFP_KERNEL);
+ if (!i2s->suspend_ch_ctl)
+ return -ENOMEM;
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_i2s_out_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto err_suspend;
reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK;
img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
@@ -483,13 +506,7 @@ static int img_i2s_out_probe(struct platform_device *pdev)
img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
img_i2s_out_reset(i2s);
-
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev)) {
- ret = img_i2s_out_resume(&pdev->dev);
- if (ret)
- goto err_pm_disable;
- }
+ pm_runtime_put(&pdev->dev);
i2s->active_channels = 1;
i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO;
@@ -517,26 +534,70 @@ static int img_i2s_out_probe(struct platform_device *pdev)
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
- img_i2s_out_suspend(&pdev->dev);
+ img_i2s_out_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(i2s->clk_sys);
return ret;
}
static int img_i2s_out_dev_remove(struct platform_device *pdev)
{
- struct img_i2s_out *i2s = platform_get_drvdata(pdev);
-
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
- img_i2s_out_suspend(&pdev->dev);
+ img_i2s_out_runtime_suspend(&pdev->dev);
- clk_disable_unprepare(i2s->clk_sys);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int img_i2s_out_suspend(struct device *dev)
+{
+ struct img_i2s_out *i2s = dev_get_drvdata(dev);
+ int i, ret;
+ u32 reg;
+
+ if (pm_runtime_status_suspended(dev)) {
+ ret = img_i2s_out_runtime_resume(dev);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL);
+ i2s->suspend_ch_ctl[i] = reg;
+ }
+
+ i2s->suspend_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
+
+ img_i2s_out_runtime_suspend(dev);
+
+ return 0;
+}
+
+static int img_i2s_out_resume(struct device *dev)
+{
+ struct img_i2s_out *i2s = dev_get_drvdata(dev);
+ int i, ret;
+ u32 reg;
+
+ ret = img_i2s_out_runtime_resume(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < i2s->max_i2s_chan; i++) {
+ reg = i2s->suspend_ch_ctl[i];
+ img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
+ }
+
+ img_i2s_out_writel(i2s, i2s->suspend_ctl, IMG_I2S_OUT_CTL);
+
+ if (pm_runtime_status_suspended(dev))
+ img_i2s_out_runtime_suspend(dev);
return 0;
}
+#endif
static const struct of_device_id img_i2s_out_of_match[] = {
{ .compatible = "img,i2s-out" },
@@ -545,8 +606,9 @@ static const struct of_device_id img_i2s_out_of_match[] = {
MODULE_DEVICE_TABLE(of, img_i2s_out_of_match);
static const struct dev_pm_ops img_i2s_out_pm_ops = {
- SET_RUNTIME_PM_OPS(img_i2s_out_suspend,
- img_i2s_out_resume, NULL)
+ SET_RUNTIME_PM_OPS(img_i2s_out_runtime_suspend,
+ img_i2s_out_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend, img_i2s_out_resume)
};
static struct platform_driver img_i2s_out_driver = {
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
index 23b0f0f6ec9c..acc005217be0 100644
--- a/sound/soc/img/img-parallel-out.c
+++ b/sound/soc/img/img-parallel-out.c
@@ -153,6 +153,7 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
u32 reg, control_set = 0;
+ int ret;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
@@ -164,9 +165,14 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
+ ret = pm_runtime_get_sync(prl->dev);
+ if (ret < 0)
+ return ret;
+
reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL);
reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set;
img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL);
+ pm_runtime_put(prl->dev);
return 0;
}
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
index 8adfd65d4390..cedd40c8d1f3 100644
--- a/sound/soc/img/img-spdif-in.c
+++ b/sound/soc/img/img-spdif-in.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <sound/core.h>
@@ -82,11 +83,36 @@ struct img_spdif_in {
unsigned int single_freq;
unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN];
bool active;
+ u32 suspend_clkgen;
+ u32 suspend_ctl;
/* Write-only registers */
unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN];
};
+static int img_spdif_in_runtime_suspend(struct device *dev)
+{
+ struct img_spdif_in *spdif = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(spdif->clk_sys);
+
+ return 0;
+}
+
+static int img_spdif_in_runtime_resume(struct device *dev)
+{
+ struct img_spdif_in *spdif = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(spdif->clk_sys);
+ if (ret) {
+ dev_err(dev, "Unable to enable sys clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static inline void img_spdif_in_writel(struct img_spdif_in *spdif,
u32 val, u32 reg)
{
@@ -723,15 +749,21 @@ static int img_spdif_in_probe(struct platform_device *pdev)
return PTR_ERR(spdif->clk_sys);
}
- ret = clk_prepare_enable(spdif->clk_sys);
- if (ret)
- return ret;
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_spdif_in_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto err_suspend;
rst = devm_reset_control_get_exclusive(&pdev->dev, "rst");
if (IS_ERR(rst)) {
if (PTR_ERR(rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
- goto err_clk_disable;
+ goto err_pm_put;
}
dev_dbg(dev, "No top level reset found\n");
img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK,
@@ -759,42 +791,98 @@ static int img_spdif_in_probe(struct platform_device *pdev)
IMG_SPDIF_IN_CTL_TRK_MASK;
img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL);
+ pm_runtime_put(&pdev->dev);
+
ret = devm_snd_soc_register_component(&pdev->dev,
&img_spdif_in_component, &img_spdif_in_dai, 1);
if (ret)
- goto err_clk_disable;
+ goto err_suspend;
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret)
- goto err_clk_disable;
+ goto err_suspend;
return 0;
-err_clk_disable:
- clk_disable_unprepare(spdif->clk_sys);
+err_pm_put:
+ pm_runtime_put(&pdev->dev);
+err_suspend:
+ if (!pm_runtime_enabled(&pdev->dev))
+ img_spdif_in_runtime_suspend(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
return ret;
}
static int img_spdif_in_dev_remove(struct platform_device *pdev)
{
- struct img_spdif_in *spdif = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ img_spdif_in_runtime_suspend(&pdev->dev);
- clk_disable_unprepare(spdif->clk_sys);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int img_spdif_in_suspend(struct device *dev)
+{
+ struct img_spdif_in *spdif = dev_get_drvdata(dev);
+ int ret;
+
+ if (pm_runtime_status_suspended(dev)) {
+ ret = img_spdif_in_runtime_resume(dev);
+ if (ret)
+ return ret;
+ }
+
+ spdif->suspend_clkgen = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CLKGEN);
+ spdif->suspend_ctl = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL);
+
+ img_spdif_in_runtime_suspend(dev);
return 0;
}
+static int img_spdif_in_resume(struct device *dev)
+{
+ struct img_spdif_in *spdif = dev_get_drvdata(dev);
+ int i, ret;
+
+ ret = img_spdif_in_runtime_resume(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++)
+ img_spdif_in_aclkgen_writel(spdif, i);
+
+ img_spdif_in_writel(spdif, spdif->suspend_clkgen, IMG_SPDIF_IN_CLKGEN);
+ img_spdif_in_writel(spdif, spdif->suspend_ctl, IMG_SPDIF_IN_CTL);
+
+ if (pm_runtime_status_suspended(dev))
+ img_spdif_in_runtime_suspend(dev);
+
+ return 0;
+}
+#endif
+
static const struct of_device_id img_spdif_in_of_match[] = {
{ .compatible = "img,spdif-in" },
{}
};
MODULE_DEVICE_TABLE(of, img_spdif_in_of_match);
+static const struct dev_pm_ops img_spdif_in_pm_ops = {
+ SET_RUNTIME_PM_OPS(img_spdif_in_runtime_suspend,
+ img_spdif_in_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(img_spdif_in_suspend, img_spdif_in_resume)
+};
+
static struct platform_driver img_spdif_in_driver = {
.driver = {
.name = "img-spdif-in",
- .of_match_table = img_spdif_in_of_match
+ .of_match_table = img_spdif_in_of_match,
+ .pm = &img_spdif_in_pm_ops
},
.probe = img_spdif_in_probe,
.remove = img_spdif_in_dev_remove
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
index 383655da2e60..934ed3df2ebf 100644
--- a/sound/soc/img/img-spdif-out.c
+++ b/sound/soc/img/img-spdif-out.c
@@ -47,25 +47,36 @@ struct img_spdif_out {
struct snd_dmaengine_dai_dma_data dma_data;
struct device *dev;
struct reset_control *rst;
+ u32 suspend_ctl;
+ u32 suspend_csl;
+ u32 suspend_csh;
};
-static int img_spdif_out_suspend(struct device *dev)
+static int img_spdif_out_runtime_suspend(struct device *dev)
{
struct img_spdif_out *spdif = dev_get_drvdata(dev);
clk_disable_unprepare(spdif->clk_ref);
+ clk_disable_unprepare(spdif->clk_sys);
return 0;
}
-static int img_spdif_out_resume(struct device *dev)
+static int img_spdif_out_runtime_resume(struct device *dev)
{
struct img_spdif_out *spdif = dev_get_drvdata(dev);
int ret;
+ ret = clk_prepare_enable(spdif->clk_sys);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+
ret = clk_prepare_enable(spdif->clk_ref);
if (ret) {
dev_err(dev, "clk_enable failed: %d\n", ret);
+ clk_disable_unprepare(spdif->clk_sys);
return ret;
}
@@ -355,21 +366,21 @@ static int img_spdif_out_probe(struct platform_device *pdev)
return PTR_ERR(spdif->clk_ref);
}
- ret = clk_prepare_enable(spdif->clk_sys);
- if (ret)
- return ret;
-
- img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK,
- IMG_SPDIF_OUT_CTL);
-
- img_spdif_out_reset(spdif);
-
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
- ret = img_spdif_out_resume(&pdev->dev);
+ ret = img_spdif_out_runtime_resume(&pdev->dev);
if (ret)
goto err_pm_disable;
}
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto err_suspend;
+
+ img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK,
+ IMG_SPDIF_OUT_CTL);
+
+ img_spdif_out_reset(spdif);
+ pm_runtime_put(&pdev->dev);
spin_lock_init(&spdif->lock);
@@ -393,27 +404,62 @@ static int img_spdif_out_probe(struct platform_device *pdev)
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
- img_spdif_out_suspend(&pdev->dev);
+ img_spdif_out_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(spdif->clk_sys);
return ret;
}
static int img_spdif_out_dev_remove(struct platform_device *pdev)
{
- struct img_spdif_out *spdif = platform_get_drvdata(pdev);
-
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
- img_spdif_out_suspend(&pdev->dev);
+ img_spdif_out_runtime_suspend(&pdev->dev);
- clk_disable_unprepare(spdif->clk_sys);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int img_spdif_out_suspend(struct device *dev)
+{
+ struct img_spdif_out *spdif = dev_get_drvdata(dev);
+ int ret;
+
+ if (pm_runtime_status_suspended(dev)) {
+ ret = img_spdif_out_runtime_resume(dev);
+ if (ret)
+ return ret;
+ }
+
+ spdif->suspend_ctl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL);
+ spdif->suspend_csl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL);
+ spdif->suspend_csh = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV);
+
+ img_spdif_out_runtime_suspend(dev);
return 0;
}
+static int img_spdif_out_resume(struct device *dev)
+{
+ struct img_spdif_out *spdif = dev_get_drvdata(dev);
+ int ret;
+
+ ret = img_spdif_out_runtime_resume(dev);
+ if (ret)
+ return ret;
+
+ img_spdif_out_writel(spdif, spdif->suspend_ctl, IMG_SPDIF_OUT_CTL);
+ img_spdif_out_writel(spdif, spdif->suspend_csl, IMG_SPDIF_OUT_CSL);
+ img_spdif_out_writel(spdif, spdif->suspend_csh, IMG_SPDIF_OUT_CSH_UV);
+
+ if (pm_runtime_status_suspended(dev))
+ img_spdif_out_runtime_suspend(dev);
+
+ return 0;
+}
+#endif
static const struct of_device_id img_spdif_out_of_match[] = {
{ .compatible = "img,spdif-out" },
{}
@@ -421,8 +467,9 @@ static const struct of_device_id img_spdif_out_of_match[] = {
MODULE_DEVICE_TABLE(of, img_spdif_out_of_match);
static const struct dev_pm_ops img_spdif_out_pm_ops = {
- SET_RUNTIME_PM_OPS(img_spdif_out_suspend,
- img_spdif_out_resume, NULL)
+ SET_RUNTIME_PM_OPS(img_spdif_out_runtime_suspend,
+ img_spdif_out_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(img_spdif_out_suspend, img_spdif_out_resume)
};
static struct platform_driver img_spdif_out_driver = {
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index b3c7f554ec30..bb8be10b8437 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -1,19 +1,3 @@
-config SND_MFLD_MACHINE
- tristate "SOC Machine Audio driver for Intel Medfield MID platform"
- depends on INTEL_SCU_IPC
- select SND_SOC_SN95031
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_PCI
- help
- This adds support for ASoC machine driver for Intel(R) MID Medfield platform
- used as alsa device in audio substem in Intel(R) MID devices
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SST_ATOM_HIFI2_PLATFORM
- tristate
- select SND_SOC_COMPRESS
-
config SND_SST_IPC
tristate
@@ -27,10 +11,12 @@ config SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST
select IOSF_MBI
+config SND_SOC_INTEL_COMMON
+ tristate
+
config SND_SOC_INTEL_SST
tristate
select SND_SOC_INTEL_SST_ACPI if ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
config SND_SOC_INTEL_SST_FIRMWARE
tristate
@@ -39,280 +25,42 @@ config SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_SST_ACPI
tristate
-config SND_SOC_INTEL_SST_MATCH
+config SND_SOC_ACPI_INTEL_MATCH
tristate
+ select SND_SOC_ACPI if ACPI
+
+config SND_SOC_INTEL_SST_TOPLEVEL
+ tristate "Intel ASoC SST drivers"
+ depends on X86 || COMPILE_TEST
+ select SND_SOC_INTEL_MACH
+ select SND_SOC_INTEL_COMMON
config SND_SOC_INTEL_HASWELL
- tristate
+ tristate "Intel ASoC SST driver for Haswell/Broadwell"
+ depends on SND_SOC_INTEL_SST_TOPLEVEL && SND_DMA_SGBUF
+ depends on DMADEVICES
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_BAYTRAIL
- tristate
- select SND_SOC_INTEL_SST
- select SND_SOC_INTEL_SST_FIRMWARE
-
-config SND_SOC_INTEL_HASWELL_MACH
- tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
- depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
- depends on DMADEVICES
- select SND_SOC_INTEL_HASWELL
- select SND_SOC_RT5640
- help
- This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
- Ultrabook platforms.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
- tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
- depends on X86 && ACPI && I2C
- select SND_SOC_INTEL_SKYLAKE
- select SND_SOC_DA7219
- select SND_SOC_MAX98357A
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- select SND_HDA_DSP_LOADER
- help
- This adds support for ASoC machine driver for Broxton-P platforms
- with DA7219 + MAX98357A I2S audio codec.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_BXT_RT298_MACH
- tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
- depends on X86 && ACPI && I2C
- select SND_SOC_INTEL_SKYLAKE
- select SND_SOC_RT298
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- select SND_HDA_DSP_LOADER
- help
- This adds support for ASoC machine driver for Broxton platforms
- with RT286 I2S audio codec.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_BYT_RT5640_MACH
- tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
- depends on X86_INTEL_LPSS && I2C
+ tristate "Intel ASoC SST driver for Baytrail (legacy)"
+ depends on SND_SOC_INTEL_SST_TOPLEVEL
depends on DMADEVICES
- depends on SND_SST_IPC_ACPI = n
- select SND_SOC_INTEL_BAYTRAIL
- select SND_SOC_RT5640
- help
- This adds audio driver for Intel Baytrail platform based boards
- with the RT5640 audio codec. This driver is deprecated, use
- SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality.
-
-config SND_SOC_INTEL_BYT_MAX98090_MACH
- tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
- depends on X86_INTEL_LPSS && I2C
- depends on DMADEVICES
- depends on SND_SST_IPC_ACPI = n
- select SND_SOC_INTEL_BAYTRAIL
- select SND_SOC_MAX98090
- help
- This adds audio driver for Intel Baytrail platform based boards
- with the MAX98090 audio codec.
-
-config SND_SOC_INTEL_BDW_RT5677_MACH
- tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
- depends on X86_INTEL_LPSS && GPIOLIB && I2C
- depends on DMADEVICES
- select SND_SOC_INTEL_HASWELL
- select SND_SOC_RT5677
- help
- This adds support for Intel Broadwell platform based boards with
- the RT5677 audio codec.
-
-config SND_SOC_INTEL_BROADWELL_MACH
- tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
- depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
- depends on DMADEVICES
- select SND_SOC_INTEL_HASWELL
- select SND_SOC_RT286
- help
- This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
- Ultrabook platforms.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_BYTCR_RT5640_MACH
- tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
- depends on X86 && I2C && ACPI
- select SND_SOC_RT5640
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
- help
- This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
- platforms with RT5640 audio codec.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_BYTCR_RT5651_MACH
- tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
- depends on X86 && I2C && ACPI
- select SND_SOC_RT5651
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
- help
- This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
- platforms with RT5651 audio codec.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
- tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
- depends on X86_INTEL_LPSS && I2C && ACPI
- select SND_SOC_RT5670
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
- help
- This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
- platforms with RT5672 audio codec.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
- tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
- depends on X86_INTEL_LPSS && I2C && ACPI
- select SND_SOC_RT5645
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
- help
- This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
- platforms with RT5645/5650 audio codec.
- If unsure select "N".
-
-config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
- tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec"
- depends on X86_INTEL_LPSS && I2C && ACPI
- select SND_SOC_MAX98090
- select SND_SOC_TS3A227E
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
- help
- This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
- platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
- If unsure select "N".
-
-config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
- tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec"
- depends on X86_INTEL_LPSS && I2C && ACPI
- select SND_SOC_DA7213
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
- help
- This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail
- platforms with DA7212/7213 audio codec.
- If unsure select "N".
-
-config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
- tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec"
- depends on X86_INTEL_LPSS && I2C && ACPI
- select SND_SOC_ES8316
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
- help
- This adds support for ASoC machine driver for Intel(R) Baytrail &
- Cherrytrail platforms with ES8316 audio codec.
- If unsure select "N".
-
-config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
- tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
- depends on X86_INTEL_LPSS && I2C && ACPI
- select SND_SST_ATOM_HIFI2_PLATFORM
- select SND_SST_IPC_ACPI
- select SND_SOC_INTEL_SST_MATCH if ACPI
- help
- This adds support for ASoC machine driver for the MinnowBoard Max or
- Up boards and provides access to I2S signals on the Low-Speed
- connector
- If unsure select "N".
-
-config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
- tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode"
- depends on X86_INTEL_LPSS && I2C
select SND_SOC_INTEL_SST
- select SND_SOC_INTEL_SKYLAKE
- select SND_SOC_RT5663
- select SND_SOC_MAX98927
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for RT5663 + MAX98927.
- Say Y if you have such a device.
- If unsure select "N".
+ select SND_SOC_INTEL_SST_FIRMWARE
-config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
- tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
- depends on X86_INTEL_LPSS && I2C && SPI
- select SND_SOC_INTEL_SST
- select SND_SOC_INTEL_SKYLAKE
- select SND_SOC_RT5663
- select SND_SOC_RT5514
- select SND_SOC_RT5514_SPI
- select SND_SOC_MAX98927
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for RT5663 + RT5514 + MAX98927.
- Say Y if you have such a device.
- If unsure select "N".
+config SND_SST_ATOM_HIFI2_PLATFORM
+ tristate "Intel ASoC SST driver for HiFi2 platforms (*field, *trail)"
+ depends on SND_SOC_INTEL_SST_TOPLEVEL && X86
+ select SND_SOC_COMPRESS
config SND_SOC_INTEL_SKYLAKE
- tristate
+ tristate "Intel ASoC SST driver for SKL/BXT/KBL/GLK/CNL"
+ depends on SND_SOC_INTEL_SST_TOPLEVEL && PCI && ACPI
select SND_HDA_EXT_CORE
select SND_HDA_DSP_LOADER
select SND_SOC_TOPOLOGY
select SND_SOC_INTEL_SST
-config SND_SOC_INTEL_SKL_RT286_MACH
- tristate "ASoC Audio driver for SKL with RT286 I2S mode"
- depends on X86 && ACPI && I2C
- select SND_SOC_INTEL_SKYLAKE
- select SND_SOC_RT286
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC machine driver for Skylake platforms
- with RT286 I2S audio codec.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
- tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
- depends on X86_INTEL_LPSS && I2C
- select SND_SOC_INTEL_SKYLAKE
- select SND_SOC_NAU8825
- select SND_SOC_SSM4567
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for NAU88L25 + SSM4567.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
- tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
- depends on X86_INTEL_LPSS && I2C
- select SND_SOC_INTEL_SKYLAKE
- select SND_SOC_NAU8825
- select SND_SOC_MAX98357A
- select SND_SOC_DMIC
- select SND_SOC_HDAC_HDMI
- help
- This adds support for ASoC Onboard Codec I2S machine driver. This will
- create an alsa sound card for NAU88L25 + MAX98357A.
- Say Y if you have such a device.
- If unsure select "N".
+# ASoC codec drivers
+source "sound/soc/intel/boards/Kconfig"
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 62f37ffffdf0..b973d457e834 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# Core support
-obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
+obj-$(CONFIG_SND_SOC_INTEL_COMMON) += common/
# Platform Support
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c
index 1bead81bb510..1dbcab5a6ff0 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-compress.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c
@@ -259,7 +259,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
}
-struct snd_compr_ops sst_platform_compr_ops = {
+const struct snd_compr_ops sst_platform_compr_ops = {
.open = sst_platform_compr_open,
.free = sst_platform_compr_free,
diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h
index cb32cc7e5ec1..31a58c25472c 100644
--- a/sound/soc/intel/atom/sst-mfld-platform.h
+++ b/sound/soc/intel/atom/sst-mfld-platform.h
@@ -25,7 +25,7 @@
#include "sst-atom-controls.h"
extern struct sst_device *sst;
-extern struct snd_compr_ops sst_platform_compr_ops;
+extern const struct snd_compr_ops sst_platform_compr_ops;
#define SST_MONO 1
#define SST_STEREO 2
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 0e928d54305d..32d6e02e2104 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -23,7 +23,6 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <linux/pm_runtime.h>
@@ -41,9 +40,10 @@
#include <acpi/acpi_bus.h>
#include <asm/cpu_device_id.h>
#include <asm/iosf_mbi.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
#include "../sst-mfld-platform.h"
#include "../../common/sst-dsp.h"
-#include "../../common/sst-acpi.h"
#include "sst.h"
/* LPE viewpoint addresses */
@@ -239,19 +239,26 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
return 0;
}
+static int is_byt(void)
+{
+ bool status = false;
+ static const struct x86_cpu_id cpu_ids[] = {
+ { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
+ {}
+ };
+ if (x86_match_cpu(cpu_ids))
+ status = true;
+ return status;
+}
static int is_byt_cr(struct device *dev, bool *bytcr)
{
int status = 0;
if (IS_ENABLED(CONFIG_IOSF_MBI)) {
- static const struct x86_cpu_id cpu_ids[] = {
- { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
- {}
- };
u32 bios_status;
- if (!x86_match_cpu(cpu_ids) || !iosf_mbi_available()) {
+ if (!is_byt() || !iosf_mbi_available()) {
/* bail silently */
return status;
}
@@ -285,7 +292,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
int ret = 0;
struct intel_sst_drv *ctx;
const struct acpi_device_id *id;
- struct sst_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach;
struct platform_device *mdev;
struct platform_device *plat_dev;
struct sst_platform_info *pdata;
@@ -297,13 +304,17 @@ static int sst_acpi_probe(struct platform_device *pdev)
return -ENODEV;
dev_dbg(dev, "for %s\n", id->id);
- mach = (struct sst_acpi_mach *)id->driver_data;
- mach = sst_acpi_find_machine(mach);
+ mach = (struct snd_soc_acpi_mach *)id->driver_data;
+ mach = snd_soc_acpi_find_machine(mach);
if (mach == NULL) {
dev_err(dev, "No matching machine driver found\n");
return -ENODEV;
}
+ if (is_byt())
+ mach->pdata = &byt_rvp_platform_data;
+ else
+ mach->pdata = &chv_platform_data;
pdata = mach->pdata;
ret = kstrtouint(id->id, 16, &dev_id);
@@ -381,286 +392,9 @@ static int sst_acpi_remove(struct platform_device *pdev)
return 0;
}
-static unsigned long cht_machine_id;
-
-#define CHT_SURFACE_MACH 1
-#define BYT_THINKPAD_10 2
-
-static int cht_surface_quirk_cb(const struct dmi_system_id *id)
-{
- cht_machine_id = CHT_SURFACE_MACH;
- return 1;
-}
-
-static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id)
-{
- cht_machine_id = BYT_THINKPAD_10;
- return 1;
-}
-
-
-static const struct dmi_system_id byt_table[] = {
- {
- .callback = byt_thinkpad10_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
- },
- },
- {
- .callback = byt_thinkpad10_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
- },
- },
- {
- .callback = byt_thinkpad10_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"),
- },
- },
- { }
-};
-
-static const struct dmi_system_id cht_table[] = {
- {
- .callback = cht_surface_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
- },
- },
- { }
-};
-
-
-static struct sst_acpi_mach cht_surface_mach = {
- .id = "10EC5640",
- .drv_name = "cht-bsw-rt5645",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "cht-bsw",
- .pdata = &chv_platform_data,
-};
-
-static struct sst_acpi_mach byt_thinkpad_10 = {
- .id = "10EC5640",
- .drv_name = "cht-bsw-rt5672",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "cht-bsw",
- .pdata = &byt_rvp_platform_data,
-};
-
-static struct sst_acpi_mach *cht_quirk(void *arg)
-{
- struct sst_acpi_mach *mach = arg;
-
- dmi_check_system(cht_table);
-
- if (cht_machine_id == CHT_SURFACE_MACH)
- return &cht_surface_mach;
- else
- return mach;
-}
-
-static struct sst_acpi_mach *byt_quirk(void *arg)
-{
- struct sst_acpi_mach *mach = arg;
-
- dmi_check_system(byt_table);
-
- if (cht_machine_id == BYT_THINKPAD_10)
- return &byt_thinkpad_10;
- else
- return mach;
-}
-
-
-static struct sst_acpi_mach sst_acpi_bytcr[] = {
- {
- .id = "10EC5640",
- .drv_name = "bytcr_rt5640",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "bytcr_rt5640",
- .machine_quirk = byt_quirk,
- .pdata = &byt_rvp_platform_data,
- },
- {
- .id = "10EC5642",
- .drv_name = "bytcr_rt5640",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "bytcr_rt5640",
- .pdata = &byt_rvp_platform_data
- },
- {
- .id = "INTCCFFD",
- .drv_name = "bytcr_rt5640",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "bytcr_rt5640",
- .pdata = &byt_rvp_platform_data
- },
- {
- .id = "10EC5651",
- .drv_name = "bytcr_rt5651",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "bytcr_rt5651",
- .pdata = &byt_rvp_platform_data
- },
- {
- .id = "DLGS7212",
- .drv_name = "bytcht_da7213",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "bytcht_da7213",
- .pdata = &byt_rvp_platform_data
- },
- {
- .id = "DLGS7213",
- .drv_name = "bytcht_da7213",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "bytcht_da7213",
- .pdata = &byt_rvp_platform_data
- },
- /* some Baytrail platforms rely on RT5645, use CHT machine driver */
- {
- .id = "10EC5645",
- .drv_name = "cht-bsw-rt5645",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "cht-bsw",
- .pdata = &byt_rvp_platform_data
- },
- {
- .id = "10EC5648",
- .drv_name = "cht-bsw-rt5645",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "cht-bsw",
- .pdata = &byt_rvp_platform_data
- },
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
- /*
- * This is always last in the table so that it is selected only when
- * enabled explicitly and there is no codec-related information in SSDT
- */
- {
- .id = "80860F28",
- .drv_name = "bytcht_nocodec",
- .fw_filename = "intel/fw_sst_0f28.bin",
- .board = "bytcht_nocodec",
- .pdata = &byt_rvp_platform_data
- },
-#endif
- {},
-};
-
-/* Cherryview-based platforms: CherryTrail and Braswell */
-static struct sst_acpi_mach sst_acpi_chv[] = {
- {
- .id = "10EC5670",
- .drv_name = "cht-bsw-rt5672",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "cht-bsw",
- .pdata = &chv_platform_data
- },
- {
- .id = "10EC5672",
- .drv_name = "cht-bsw-rt5672",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "cht-bsw",
- .pdata = &chv_platform_data
- },
- {
- .id = "10EC5645",
- .drv_name = "cht-bsw-rt5645",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "cht-bsw",
- .pdata = &chv_platform_data
- },
- {
- .id = "10EC5650",
- .drv_name = "cht-bsw-rt5645",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "cht-bsw",
- .pdata = &chv_platform_data
- },
- {
- .id = "10EC3270",
- .drv_name = "cht-bsw-rt5645",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "cht-bsw",
- .pdata = &chv_platform_data
- },
-
- {
- .id = "193C9890",
- .drv_name = "cht-bsw-max98090",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "cht-bsw",
- .pdata = &chv_platform_data
- },
- {
- .id = "DLGS7212",
- .drv_name = "bytcht_da7213",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "bytcht_da7213",
- .pdata = &chv_platform_data
- },
- {
- .id = "DLGS7213",
- .drv_name = "bytcht_da7213",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "bytcht_da7213",
- .pdata = &chv_platform_data
- },
- {
- .id = "ESSX8316",
- .drv_name = "bytcht_es8316",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "bytcht_es8316",
- .pdata = &chv_platform_data
- },
- /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
- {
- .id = "10EC5640",
- .drv_name = "bytcr_rt5640",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "bytcr_rt5640",
- .machine_quirk = cht_quirk,
- .pdata = &chv_platform_data
- },
- {
- .id = "10EC3276",
- .drv_name = "bytcr_rt5640",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "bytcr_rt5640",
- .pdata = &chv_platform_data
- },
- /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
- {
- .id = "10EC5651",
- .drv_name = "bytcr_rt5651",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "bytcr_rt5651",
- .pdata = &chv_platform_data
- },
-#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
- /*
- * This is always last in the table so that it is selected only when
- * enabled explicitly and there is no codec-related information in SSDT
- */
- {
- .id = "808622A8",
- .drv_name = "bytcht_nocodec",
- .fw_filename = "intel/fw_sst_22a8.bin",
- .board = "bytcht_nocodec",
- .pdata = &chv_platform_data
- },
-#endif
- {},
-};
-
static const struct acpi_device_id sst_acpi_ids[] = {
- { "80860F28", (unsigned long)&sst_acpi_bytcr},
- { "808622A8", (unsigned long) &sst_acpi_chv},
+ { "80860F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines},
+ { "808622A8", (unsigned long)&snd_soc_acpi_intel_cherrytrail_machines},
{ },
};
diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c
index 33917146d9c4..a686eef2cf7f 100644
--- a/sound/soc/intel/atom/sst/sst_loader.c
+++ b/sound/soc/intel/atom/sst/sst_loader.c
@@ -415,7 +415,6 @@ int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
return ret_val;
}
- BUG_ON(!sst_drv_ctx->fw_in_mem);
block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID);
if (block == NULL)
return -ENOMEM;
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
index 83d8dda15233..65e257b17a7e 100644
--- a/sound/soc/intel/atom/sst/sst_stream.c
+++ b/sound/soc/intel/atom/sst/sst_stream.c
@@ -45,7 +45,6 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
void *data = NULL;
dev_dbg(sst_drv_ctx->dev, "Enter\n");
- BUG_ON(!params);
str_params = (struct snd_sst_params *)params;
memset(&alloc_param, 0, sizeof(alloc_param));
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
new file mode 100644
index 000000000000..6f754708a48c
--- /dev/null
+++ b/sound/soc/intel/boards/Kconfig
@@ -0,0 +1,265 @@
+config SND_SOC_INTEL_MACH
+ tristate "Intel Audio machine drivers"
+ depends on SND_SOC_INTEL_SST_TOPLEVEL
+ select SND_SOC_ACPI_INTEL_MATCH if ACPI
+
+if SND_SOC_INTEL_MACH
+
+config SND_MFLD_MACHINE
+ tristate "SOC Machine Audio driver for Intel Medfield MID platform"
+ depends on INTEL_SCU_IPC
+ select SND_SOC_SN95031
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_PCI
+ help
+ This adds support for ASoC machine driver for Intel(R) MID Medfield platform
+ used as alsa device in audio substem in Intel(R) MID devices
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_HASWELL_MACH
+ tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
+ depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
+ depends on SND_SOC_INTEL_HASWELL
+ select SND_SOC_RT5640
+ help
+ This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
+ Ultrabook platforms.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_BDW_RT5677_MACH
+ tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
+ depends on X86_INTEL_LPSS && GPIOLIB && I2C
+ depends on SND_SOC_INTEL_HASWELL
+ select SND_SOC_RT5677
+ help
+ This adds support for Intel Broadwell platform based boards with
+ the RT5677 audio codec.
+
+config SND_SOC_INTEL_BROADWELL_MACH
+ tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
+ depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
+ depends on SND_SOC_INTEL_HASWELL
+ select SND_SOC_RT286
+ help
+ This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
+ Ultrabook platforms.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_BYT_MAX98090_MACH
+ tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
+ depends on X86_INTEL_LPSS && I2C
+ depends on SND_SST_IPC_ACPI = n
+ depends on SND_SOC_INTEL_BAYTRAIL
+ select SND_SOC_MAX98090
+ help
+ This adds audio driver for Intel Baytrail platform based boards
+ with the MAX98090 audio codec.
+
+config SND_SOC_INTEL_BYT_RT5640_MACH
+ tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
+ depends on X86_INTEL_LPSS && I2C
+ depends on SND_SST_IPC_ACPI = n
+ depends on SND_SOC_INTEL_BAYTRAIL
+ select SND_SOC_RT5640
+ help
+ This adds audio driver for Intel Baytrail platform based boards
+ with the RT5640 audio codec. This driver is deprecated, use
+ SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality.
+
+config SND_SOC_INTEL_BYTCR_RT5640_MACH
+ tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
+ depends on X86 && I2C && ACPI
+ select SND_SOC_RT5640
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+ platforms with RT5640 audio codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_BYTCR_RT5651_MACH
+ tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
+ depends on X86 && I2C && ACPI
+ select SND_SOC_RT5651
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
+ platforms with RT5651 audio codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
+ tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
+ depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_RT5670
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+ platforms with RT5672 audio codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
+ tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
+ depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_RT5645
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+ platforms with RT5645/5650 audio codec.
+ If unsure select "N".
+
+config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
+ tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec"
+ depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_MAX98090
+ select SND_SOC_TS3A227E
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+ platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
+ tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec"
+ depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_DA7213
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail
+ platforms with DA7212/7213 audio codec.
+ If unsure select "N".
+
+config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
+ tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec"
+ depends on X86_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_ES8316
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Baytrail &
+ Cherrytrail platforms with ES8316 audio codec.
+ If unsure select "N".
+
+config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
+ tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
+ depends on X86_INTEL_LPSS && I2C && ACPI
+ depends on SND_SST_ATOM_HIFI2_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for the MinnowBoard Max or
+ Up boards and provides access to I2S signals on the Low-Speed
+ connector
+ If unsure select "N".
+
+config SND_SOC_INTEL_SKL_RT286_MACH
+ tristate "ASoC Audio driver for SKL with RT286 I2S mode"
+ depends on X86 && ACPI && I2C
+ depends on SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_RT286
+ select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
+ help
+ This adds support for ASoC machine driver for Skylake platforms
+ with RT286 I2S audio codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
+ tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode"
+ depends on X86_INTEL_LPSS && I2C
+ depends on SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_NAU8825
+ select SND_SOC_SSM4567
+ select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for NAU88L25 + SSM4567.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
+ tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode"
+ depends on X86_INTEL_LPSS && I2C
+ depends on SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_NAU8825
+ select SND_SOC_MAX98357A
+ select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for NAU88L25 + MAX98357A.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
+ tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
+ depends on X86 && ACPI && I2C
+ depends on SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_DA7219
+ select SND_SOC_MAX98357A
+ select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
+ select SND_HDA_DSP_LOADER
+ help
+ This adds support for ASoC machine driver for Broxton-P platforms
+ with DA7219 + MAX98357A I2S audio codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_BXT_RT298_MACH
+ tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
+ depends on X86 && ACPI && I2C
+ depends on SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_RT298
+ select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
+ select SND_HDA_DSP_LOADER
+ help
+ This adds support for ASoC machine driver for Broxton platforms
+ with RT286 I2S audio codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
+ tristate "ASoC Audio driver for KBL with RT5663 and MAX98927 in I2S Mode"
+ depends on X86_INTEL_LPSS && I2C
+ select SND_SOC_INTEL_SST
+ depends on SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_RT5663
+ select SND_SOC_MAX98927
+ select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for RT5663 + MAX98927.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
+ tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
+ depends on X86_INTEL_LPSS && I2C && SPI
+ select SND_SOC_INTEL_SST
+ depends on SND_SOC_INTEL_SKYLAKE
+ select SND_SOC_RT5663
+ select SND_SOC_RT5514
+ select SND_SOC_RT5514_SPI
+ select SND_SOC_MAX98927
+ select SND_SOC_HDAC_HDMI
+ help
+ This adds support for ASoC Onboard Codec I2S machine driver. This will
+ create an alsa sound card for RT5663 + RT5514 + MAX98927.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+endif
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index ce35ec7884d1..f8a91a6f2a17 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -55,20 +55,6 @@ enum {
BXT_DPCM_AUDIO_HDMI3_PB,
};
-static inline struct snd_soc_dai *bxt_get_codec_dai(struct snd_soc_card *card)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- list_for_each_entry(rtd, &card->rtd_list, list) {
-
- if (!strncmp(rtd->codec_dai->name, BXT_DIALOG_CODEC_DAI,
- strlen(BXT_DIALOG_CODEC_DAI)))
- return rtd->codec_dai;
- }
-
- return NULL;
-}
-
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
@@ -77,7 +63,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_soc_card *card = dapm->card;
struct snd_soc_dai *codec_dai;
- codec_dai = bxt_get_codec_dai(card);
+ codec_dai = snd_soc_card_get_codec_dai(card, BXT_DIALOG_CODEC_DAI);
if (!codec_dai) {
dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
return -EIO;
diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c
index 18873e23f404..c4d82ad41bd7 100644
--- a/sound/soc/intel/boards/bytcht_da7213.c
+++ b/sound/soc/intel/boards/bytcht_da7213.c
@@ -27,9 +27,9 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/da7213.h"
#include "../atom/sst-atom-controls.h"
-#include "../common/sst-acpi.h"
static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
@@ -185,19 +185,11 @@ static struct snd_soc_dai_link dailink[] = {
.dpcm_playback = 1,
.ops = &aif1_ops,
},
- [MERR_DPCM_COMPR] = {
- .name = "Compressed Port",
- .stream_name = "Compress",
- .cpu_dai_name = "compress-cpu-dai",
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .platform_name = "sst-mfld-platform",
- },
/* CODEC<->CODEC link */
/* back ends */
{
.name = "SSP2-Codec",
- .id = 1,
+ .id = 0,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
@@ -231,19 +223,18 @@ static char codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
static int bytcht_da7213_probe(struct platform_device *pdev)
{
- int ret_val = 0;
- int i;
struct snd_soc_card *card;
- struct sst_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach;
const char *i2c_name = NULL;
int dai_index = 0;
+ int ret_val = 0;
+ int i;
mach = (&pdev->dev)->platform_data;
card = &bytcht_da7213_card;
card->dev = &pdev->dev;
/* fix index of codec dai */
- dai_index = MERR_DPCM_COMPR + 1;
for (i = 0; i < ARRAY_SIZE(dailink); i++) {
if (!strcmp(dailink[i].codec_name, "i2c-DLGS7213:00")) {
dai_index = i;
@@ -252,8 +243,8 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
}
/* fixup codec name based on HID */
- i2c_name = sst_acpi_find_name_from_hid(mach->id);
- if (i2c_name != NULL) {
+ i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ if (i2c_name) {
snprintf(codec_name, sizeof(codec_name),
"%s%s", "i2c-", i2c_name);
dailink[dai_index].codec_name = codec_name;
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 52635462dac6..8088396717e3 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -29,28 +29,14 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-acpi.h>
#include "../atom/sst-atom-controls.h"
-#include "../common/sst-acpi.h"
#include "../common/sst-dsp.h"
struct byt_cht_es8316_private {
struct clk *mclk;
};
-#define CODEC_DAI1 "ES8316 HiFi"
-
-static inline struct snd_soc_dai *get_codec_dai(struct snd_soc_card *card)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- list_for_each_entry(rtd, &card->rtd_list, list) {
- if (!strncmp(rtd->codec_dai->name, CODEC_DAI1,
- strlen(CODEC_DAI1)))
- return rtd->codec_dai;
- }
- return NULL;
-}
-
static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
@@ -208,22 +194,13 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = {
.ops = &byt_cht_es8316_aif1_ops,
},
- [MERR_DPCM_COMPR] = {
- .name = "Compressed Port",
- .stream_name = "Compress",
- .cpu_dai_name = "compress-cpu-dai",
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .platform_name = "sst-mfld-platform",
- },
-
/* back ends */
{
/* Only SSP2 has been tested here, so BYT-CR platforms that
* require SSP0 will not work.
*/
.name = "SSP2-Codec",
- .id = 1,
+ .id = 0,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c
index 1dd9441806fa..b80ec027a0e8 100644
--- a/sound/soc/intel/boards/bytcht_nocodec.c
+++ b/sound/soc/intel/boards/bytcht_nocodec.c
@@ -133,19 +133,11 @@ static struct snd_soc_dai_link dais[] = {
.dpcm_playback = 1,
.ops = &aif1_ops,
},
- [MERR_DPCM_COMPR] = {
- .name = "Compressed Port",
- .stream_name = "Compress",
- .cpu_dai_name = "compress-cpu-dai",
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .platform_name = "sst-mfld-platform",
- },
/* CODEC<->CODEC link */
/* back ends */
{
.name = "SSP2-LowSpeed Connector",
- .id = 1,
+ .id = 0,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 4a76b099a508..f2c0fc415e52 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -22,19 +22,19 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
-#include <linux/clk.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/rt5640.h"
#include "../atom/sst-atom-controls.h"
-#include "../common/sst-acpi.h"
#include "../common/sst-dsp.h"
enum {
@@ -44,13 +44,13 @@ enum {
BYT_RT5640_IN3_MAP,
};
-#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
+#define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(7, 0))
#define BYT_RT5640_DMIC_EN BIT(16)
#define BYT_RT5640_MONO_SPEAKER BIT(17)
#define BYT_RT5640_DIFF_MIC BIT(18) /* defaut is single-ended */
-#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */
-#define BYT_RT5640_SSP0_AIF1 BIT(20)
-#define BYT_RT5640_SSP0_AIF2 BIT(21)
+#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */
+#define BYT_RT5640_SSP0_AIF1 BIT(20)
+#define BYT_RT5640_SSP0_AIF2 BIT(21)
#define BYT_RT5640_MCLK_EN BIT(22)
#define BYT_RT5640_MCLK_25MHZ BIT(23)
@@ -145,22 +145,6 @@ static void log_quirks(struct device *dev)
#define BYT_CODEC_DAI1 "rt5640-aif1"
#define BYT_CODEC_DAI2 "rt5640-aif2"
-static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- list_for_each_entry(rtd, &card->rtd_list, list) {
- if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1,
- strlen(BYT_CODEC_DAI1)))
- return rtd->codec_dai;
- if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI2,
- strlen(BYT_CODEC_DAI2)))
- return rtd->codec_dai;
-
- }
- return NULL;
-}
-
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
@@ -170,7 +154,10 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
int ret;
- codec_dai = byt_get_codec_dai(card);
+ codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1);
+ if (!codec_dai)
+ codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI2);
+
if (!codec_dai) {
dev_err(card->dev,
"Codec dai not found; Unable to set platform clock\n");
@@ -178,7 +165,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
}
if (SND_SOC_DAPM_EVENT_ON(event)) {
- if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) {
+ if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) {
ret = clk_prepare_enable(priv->mclk);
if (ret < 0) {
dev_err(card->dev,
@@ -199,7 +186,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
48000 * 512,
SND_SOC_CLOCK_IN);
if (!ret) {
- if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk)
+ if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN)
clk_disable_unprepare(priv->mclk);
}
}
@@ -376,8 +363,8 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
},
- .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
- BYT_RT5640_MCLK_EN),
+ .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+ BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
@@ -385,12 +372,11 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
},
- .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
- BYT_RT5640_MONO_SPEAKER |
- BYT_RT5640_DIFF_MIC |
- BYT_RT5640_SSP0_AIF2 |
- BYT_RT5640_MCLK_EN
- ),
+ .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+ BYT_RT5640_MONO_SPEAKER |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF2 |
+ BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
@@ -398,9 +384,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
},
- .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
- BYT_RT5640_DMIC_EN |
- BYT_RT5640_MCLK_EN),
+ .driver_data = (void *)(BYT_RT5640_DMIC2_MAP |
+ BYT_RT5640_DMIC_EN |
+ BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
@@ -408,8 +394,8 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
},
- .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
- BYT_RT5640_MCLK_EN),
+ .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+ BYT_RT5640_MCLK_EN),
},
{
.callback = byt_rt5640_quirk_cb,
@@ -417,8 +403,8 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
},
- .driver_data = (unsigned long *)(BYT_RT5640_DMIC1_MAP |
- BYT_RT5640_DMIC_EN),
+ .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+ BYT_RT5640_DMIC_EN),
},
{
.callback = byt_rt5640_quirk_cb,
@@ -426,9 +412,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
},
- .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP |
- BYT_RT5640_MCLK_EN |
- BYT_RT5640_SSP0_AIF1),
+ .driver_data = (void *)(BYT_RT5640_IN3_MAP |
+ BYT_RT5640_MCLK_EN |
+ BYT_RT5640_SSP0_AIF1),
},
{
.callback = byt_rt5640_quirk_cb,
@@ -436,7 +422,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
},
- .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
+ .driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_MCLK_EN |
BYT_RT5640_SSP0_AIF1),
@@ -446,9 +432,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
},
- .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP |
- BYT_RT5640_MCLK_EN |
- BYT_RT5640_SSP0_AIF1),
+ .driver_data = (void *)(BYT_RT5640_IN3_MAP |
+ BYT_RT5640_MCLK_EN |
+ BYT_RT5640_SSP0_AIF1),
},
{}
@@ -456,12 +442,12 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
{
- int ret;
- struct snd_soc_codec *codec = runtime->codec;
struct snd_soc_card *card = runtime->card;
- const struct snd_soc_dapm_route *custom_map;
struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
+ struct snd_soc_codec *codec = runtime->codec;
+ const struct snd_soc_dapm_route *custom_map;
int num_routes;
+ int ret;
card->dapm.idle_bias_off = true;
@@ -549,7 +535,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
- if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) {
+ if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) {
/*
* The firmware might enable the clock at
* boot (this information may or may not
@@ -693,18 +679,10 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
.dpcm_playback = 1,
.ops = &byt_rt5640_aif1_ops,
},
- [MERR_DPCM_COMPR] = {
- .name = "Baytrail Compressed Port",
- .stream_name = "Baytrail Compress",
- .cpu_dai_name = "compress-cpu-dai",
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .platform_name = "sst-mfld-platform",
- },
/* back ends */
{
.name = "SSP2-Codec",
- .id = 1,
+ .id = 0,
.cpu_dai_name = "ssp2-port", /* overwritten for ssp0 routing */
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
@@ -758,12 +736,12 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
{
- int ret_val = 0;
- struct sst_acpi_mach *mach;
+ struct byt_rt5640_private *priv;
+ struct snd_soc_acpi_mach *mach;
const char *i2c_name = NULL;
+ int ret_val = 0;
+ int dai_index = 0;
int i;
- int dai_index;
- struct byt_rt5640_private *priv;
is_bytcr = false;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
@@ -776,7 +754,6 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&byt_rt5640_card, priv);
/* fix index of codec dai */
- dai_index = MERR_DPCM_COMPR + 1;
for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) {
if (!strcmp(byt_rt5640_dais[i].codec_name, "i2c-10EC5640:00")) {
dai_index = i;
@@ -785,8 +762,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
}
/* fixup codec name based on HID */
- i2c_name = sst_acpi_find_name_from_hid(mach->id);
- if (i2c_name != NULL) {
+ i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ if (i2c_name) {
snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
"%s%s", "i2c-", i2c_name);
@@ -819,7 +796,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
struct acpi_buffer state = {0, NULL};
- struct sst_acpi_package_context pkg_ctx;
+ struct snd_soc_acpi_package_context pkg_ctx;
bool pkg_found = false;
state.length = sizeof(chan_package);
@@ -831,7 +808,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
pkg_ctx.state = &state;
pkg_ctx.data_valid = false;
- pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx);
+ pkg_found = snd_soc_acpi_find_package_from_hid(mach->id,
+ &pkg_ctx);
if (pkg_found) {
if (chan_package.aif_value == 1) {
dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n");
@@ -891,7 +869,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
byt_rt5640_cpu_dai_name;
}
- if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && (is_valleyview())) {
+ if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) {
priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
if (IS_ERR(priv->mclk)) {
ret_val = PTR_ERR(priv->mclk);
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 4a3516b38c2c..d955836c6870 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -21,24 +21,124 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/slab.h>
+#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/rt5651.h"
#include "../atom/sst-atom-controls.h"
+enum {
+ BYT_RT5651_DMIC_MAP,
+ BYT_RT5651_IN1_MAP,
+ BYT_RT5651_IN2_MAP,
+};
+
+#define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(7, 0))
+#define BYT_RT5651_DMIC_EN BIT(16)
+#define BYT_RT5651_MCLK_EN BIT(17)
+#define BYT_RT5651_MCLK_25MHZ BIT(18)
+
+struct byt_rt5651_private {
+ struct clk *mclk;
+ struct snd_soc_jack jack;
+};
+
+static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC_MAP |
+ BYT_RT5651_DMIC_EN |
+ BYT_RT5651_MCLK_EN;
+
+static void log_quirks(struct device *dev)
+{
+ if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC_MAP)
+ dev_info(dev, "quirk DMIC_MAP enabled");
+ if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_MAP)
+ dev_info(dev, "quirk IN1_MAP enabled");
+ if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP)
+ dev_info(dev, "quirk IN2_MAP enabled");
+ if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN)
+ dev_info(dev, "quirk DMIC enabled");
+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN)
+ dev_info(dev, "quirk MCLK_EN enabled");
+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ)
+ dev_info(dev, "quirk MCLK_25MHZ enabled");
+}
+
+#define BYT_CODEC_DAI1 "rt5651-aif1"
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1);
+ if (!codec_dai) {
+ dev_err(card->dev,
+ "Codec dai not found; Unable to set platform clock\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) {
+ ret = clk_prepare_enable(priv->mclk);
+ if (ret < 0) {
+ dev_err(card->dev,
+ "could not configure MCLK state");
+ return ret;
+ }
+ }
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_PLL1,
+ 48000 * 512,
+ SND_SOC_CLOCK_IN);
+ } else {
+ /*
+ * Set codec clock source to internal clock before
+ * turning off the platform clock. Codec needs clock
+ * for Jack detection and button press
+ */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_RCCLK,
+ 48000 * 512,
+ SND_SOC_CLOCK_IN);
+ if (!ret)
+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN)
+ clk_disable_unprepare(priv->mclk);
+ }
+
+ if (ret < 0) {
+ dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Internal Mic", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
};
static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
+ {"Headphone", NULL, "Platform Clock"},
+ {"Headset Mic", NULL, "Platform Clock"},
+ {"Internal Mic", NULL, "Platform Clock"},
+ {"Speaker", NULL, "Platform Clock"},
+
{"AIF1 Playback", NULL, "ssp2 Tx"},
{"ssp2 Tx", NULL, "codec_out0"},
{"ssp2 Tx", NULL, "codec_out1"},
@@ -47,38 +147,30 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
{"ssp2 Rx", NULL, "AIF1 Capture"},
{"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */
- {"IN2P", NULL, "Headset Mic"},
{"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"},
{"Speaker", NULL, "LOUTL"},
{"Speaker", NULL, "LOUTR"},
};
-static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic1_map[] = {
- {"DMIC1", NULL, "Internal Mic"},
-};
-
-static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic2_map[] = {
- {"DMIC2", NULL, "Internal Mic"},
+static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = {
+ {"IN2P", NULL, "Headset Mic"},
+ {"DMIC L1", NULL, "Internal Mic"},
+ {"DMIC R1", NULL, "Internal Mic"},
};
static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = {
{"Internal Mic", NULL, "micbias1"},
+ {"IN2P", NULL, "Headset Mic"},
{"IN1P", NULL, "Internal Mic"},
};
-enum {
- BYT_RT5651_DMIC1_MAP,
- BYT_RT5651_DMIC2_MAP,
- BYT_RT5651_IN1_MAP,
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = {
+ {"Internal Mic", NULL, "micbias1"},
+ {"IN1P", NULL, "Headset Mic"},
+ {"IN2P", NULL, "Internal Mic"},
};
-#define BYT_RT5651_MAP(quirk) ((quirk) & 0xff)
-#define BYT_RT5651_DMIC_EN BIT(16)
-
-static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP |
- BYT_RT5651_DMIC_EN;
-
static const struct snd_kcontrol_new byt_rt5651_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -86,6 +178,17 @@ static const struct snd_kcontrol_new byt_rt5651_controls[] = {
SOC_DAPM_PIN_SWITCH("Speaker"),
};
+static struct snd_soc_jack_pin bytcr_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -103,9 +206,26 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_BCLK1,
- params_rate(params) * 50,
- params_rate(params) * 512);
+ if (!(byt_rt5651_quirk & BYT_RT5651_MCLK_EN)) {
+ /* 2x25 bit slots on SSP2 */
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ RT5651_PLL1_S_BCLK1,
+ params_rate(params) * 50,
+ params_rate(params) * 512);
+ } else {
+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ RT5651_PLL1_S_MCLK,
+ 25000000,
+ params_rate(params) * 512);
+ } else {
+ ret = snd_soc_dai_set_pll(codec_dai, 0,
+ RT5651_PLL1_S_MCLK,
+ 19200000,
+ params_rate(params) * 512);
+ }
+ }
+
if (ret < 0) {
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
return ret;
@@ -114,33 +234,60 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int byt_rt5651_quirk_cb(const struct dmi_system_id *id)
+{
+ byt_rt5651_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
static const struct dmi_system_id byt_rt5651_quirk_table[] = {
+ {
+ .callback = byt_rt5651_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
+ },
+ .driver_data = (void *)(BYT_RT5651_DMIC_MAP |
+ BYT_RT5651_DMIC_EN),
+ },
+ {
+ .callback = byt_rt5651_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
+ },
+ .driver_data = (void *)(BYT_RT5651_IN2_MAP),
+ },
{}
};
static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
{
- int ret;
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_codec *codec = runtime->codec;
+ struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
const struct snd_soc_dapm_route *custom_map;
int num_routes;
+ int ret;
card->dapm.idle_bias_off = true;
- dmi_check_system(byt_rt5651_quirk_table);
switch (BYT_RT5651_MAP(byt_rt5651_quirk)) {
case BYT_RT5651_IN1_MAP:
custom_map = byt_rt5651_intmic_in1_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_map);
break;
- case BYT_RT5651_DMIC2_MAP:
- custom_map = byt_rt5651_intmic_dmic2_map;
- num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic2_map);
+ case BYT_RT5651_IN2_MAP:
+ custom_map = byt_rt5651_intmic_in2_map;
+ num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map);
break;
default:
- custom_map = byt_rt5651_intmic_dmic1_map;
- num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic1_map);
+ custom_map = byt_rt5651_intmic_dmic_map;
+ num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
}
+ ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
+ if (ret)
+ return ret;
ret = snd_soc_add_card_controls(card, byt_rt5651_controls,
ARRAY_SIZE(byt_rt5651_controls));
@@ -151,6 +298,40 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) {
+ /*
+ * The firmware might enable the clock at
+ * boot (this information may or may not
+ * be reflected in the enable clock register).
+ * To change the rate we must disable the clock
+ * first to cover these cases. Due to common
+ * clock framework restrictions that do not allow
+ * to disable a clock that has not been enabled,
+ * we need to enable the clock first.
+ */
+ ret = clk_prepare_enable(priv->mclk);
+ if (!ret)
+ clk_disable_unprepare(priv->mclk);
+
+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ)
+ ret = clk_set_rate(priv->mclk, 25000000);
+ else
+ ret = clk_set_rate(priv->mclk, 19200000);
+
+ if (ret)
+ dev_err(card->dev, "unable to set MCLK rate\n");
+ }
+
+ ret = snd_soc_card_jack_new(runtime->card, "Headset",
+ SND_JACK_HEADSET, &priv->jack,
+ bytcr_jack_pins, ARRAY_SIZE(bytcr_jack_pins));
+ if (ret) {
+ dev_err(runtime->dev, "Headset jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ rt5651_set_jack_detect(codec, &priv->jack);
+
return ret;
}
@@ -253,19 +434,11 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
.dpcm_playback = 1,
.ops = &byt_rt5651_aif1_ops,
},
- [MERR_DPCM_COMPR] = {
- .name = "Compressed Port",
- .stream_name = "Compress",
- .cpu_dai_name = "compress-cpu-dai",
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .platform_name = "sst-mfld-platform",
- },
/* CODEC<->CODEC link */
/* back ends */
{
.name = "SSP2-Codec",
- .id = 1,
+ .id = 0,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
@@ -296,13 +469,65 @@ static struct snd_soc_card byt_rt5651_card = {
.fully_routed = true,
};
+static char byt_rt5651_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
+
static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
{
+ struct byt_rt5651_private *priv;
+ struct snd_soc_acpi_mach *mach;
+ const char *i2c_name = NULL;
int ret_val = 0;
+ int dai_index = 0;
+ int i;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
+ if (!priv)
+ return -ENOMEM;
/* register the soc card */
byt_rt5651_card.dev = &pdev->dev;
+ mach = byt_rt5651_card.dev->platform_data;
+ snd_soc_card_set_drvdata(&byt_rt5651_card, priv);
+
+ /* fix index of codec dai */
+ for (i = 0; i < ARRAY_SIZE(byt_rt5651_dais); i++) {
+ if (!strcmp(byt_rt5651_dais[i].codec_name, "i2c-10EC5651:00")) {
+ dai_index = i;
+ break;
+ }
+ }
+
+ /* fixup codec name based on HID */
+ i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ if (i2c_name) {
+ snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name),
+ "%s%s", "i2c-", i2c_name);
+
+ byt_rt5651_dais[dai_index].codec_name = byt_rt5651_codec_name;
+ }
+
+ /* check quirks before creating card */
+ dmi_check_system(byt_rt5651_quirk_table);
+ log_quirks(&pdev->dev);
+
+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) {
+ priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+ if (IS_ERR(priv->mclk)) {
+ dev_err(&pdev->dev,
+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
+ PTR_ERR(priv->mclk));
+ /*
+ * Fall back to bit clock usage for -ENOENT (clock not
+ * available likely due to missing dependencies), bail
+ * for all other errors, including -EPROBE_DEFER
+ */
+ if (ret_val != -ENOENT)
+ return ret_val;
+ byt_rt5651_quirk &= ~BYT_RT5651_MCLK_EN;
+ }
+ }
+
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
if (ret_val) {
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 20755ecc7f9e..d3e1c7e12004 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -35,15 +36,48 @@
#define CHT_CODEC_DAI "HiFi"
struct cht_mc_private {
+ struct clk *mclk;
struct snd_soc_jack jack;
bool ts3a227e_present;
};
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = clk_prepare_enable(ctx->mclk);
+ if (ret < 0) {
+ dev_err(card->dev,
+ "could not configure MCLK state");
+ return ret;
+ }
+ } else {
+ clk_disable_unprepare(ctx->mclk);
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
};
static const struct snd_soc_dapm_route cht_audio_map[] = {
@@ -60,6 +94,10 @@ static const struct snd_soc_dapm_route cht_audio_map[] = {
{"codec_in0", NULL, "ssp2 Rx" },
{"codec_in1", NULL, "ssp2 Rx" },
{"ssp2 Rx", NULL, "HiFi Capture"},
+ {"Headphone", NULL, "Platform Clock"},
+ {"Headset Mic", NULL, "Platform Clock"},
+ {"Int Mic", NULL, "Platform Clock"},
+ {"Ext Spk", NULL, "Platform Clock"},
};
static const struct snd_kcontrol_new cht_mc_controls[] = {
@@ -109,6 +147,40 @@ static struct notifier_block cht_jack_nb = {
.notifier_call = cht_ti_jack_event,
};
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+ {
+ .name = "hp",
+ .report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
+ .debounce_time = 200,
+ },
+ {
+ .name = "mic",
+ .invert = 1,
+ .report = SND_JACK_MICROPHONE,
+ .debounce_time = 200,
+ },
+};
+
+static const struct acpi_gpio_params hp_gpios = { 0, 0, false };
+static const struct acpi_gpio_params mic_gpios = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_max98090_gpios[] = {
+ { "hp-gpios", &hp_gpios, 1 },
+ { "mic-gpios", &mic_gpios, 1 },
+ {},
+};
+
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
@@ -116,30 +188,55 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
struct snd_soc_jack *jack = &ctx->jack;
- /**
- * TI supports 4 butons headset detection
- * KEY_MEDIA
- * KEY_VOICECOMMAND
- * KEY_VOLUMEUP
- * KEY_VOLUMEDOWN
- */
- if (ctx->ts3a227e_present)
- jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3;
- else
- jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;
+ if (ctx->ts3a227e_present) {
+ /*
+ * The jack has already been created in the
+ * cht_max98090_headset_init() function.
+ */
+ snd_soc_jack_notifier_register(jack, &cht_jack_nb);
+ return 0;
+ }
- ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
- jack_type, jack, NULL, 0);
+ jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;
+ ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
+ jack_type, jack,
+ hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
if (ret) {
dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret);
return ret;
}
- if (ctx->ts3a227e_present)
- snd_soc_jack_notifier_register(jack, &cht_jack_nb);
+ ret = snd_soc_jack_add_gpiods(runtime->card->dev->parent, jack,
+ ARRAY_SIZE(hs_jack_gpios),
+ hs_jack_gpios);
+ if (ret) {
+ /*
+ * flag error but don't bail if jack detect is broken
+ * due to platform issues or bad BIOS/configuration
+ */
+ dev_err(runtime->dev,
+ "jack detection gpios not added, error %d\n", ret);
+ }
+
+ /*
+ * The firmware might enable the clock at
+ * boot (this information may or may not
+ * be reflected in the enable clock register).
+ * To change the rate we must disable the clock
+ * first to cover these cases. Due to common
+ * clock framework restrictions that do not allow
+ * to disable a clock that has not been enabled,
+ * we need to enable the clock first.
+ */
+ ret = clk_prepare_enable(ctx->mclk);
+ if (!ret)
+ clk_disable_unprepare(ctx->mclk);
+
+ ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
+
+ if (ret)
+ dev_err(runtime->dev, "unable to set MCLK rate\n");
return ret;
}
@@ -160,7 +257,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret;
}
- fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS;
ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
@@ -173,8 +270,8 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
- /* set SSP2 to 24-bit */
- params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
+ /* set SSP2 to 16-bit */
+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
@@ -188,8 +285,29 @@ static int cht_max98090_headset_init(struct snd_soc_component *component)
{
struct snd_soc_card *card = component->card;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_jack *jack = &ctx->jack;
+ int jack_type;
+ int ret;
- return ts3a227e_enable_jack_detect(component, &ctx->jack);
+ /*
+ * TI supports 4 butons headset detection
+ * KEY_MEDIA
+ * KEY_VOICECOMMAND
+ * KEY_VOLUMEUP
+ * KEY_VOLUMEDOWN
+ */
+ jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3;
+
+ ret = snd_soc_card_jack_new(card, "Headset Jack", jack_type,
+ jack, NULL, 0);
+ if (ret) {
+ dev_err(card->dev, "Headset Jack creation failed %d\n", ret);
+ return ret;
+ }
+
+ return ts3a227e_enable_jack_detect(component, jack);
}
static const struct snd_soc_ops cht_aif1_ops = {
@@ -232,18 +350,10 @@ static struct snd_soc_dai_link cht_dailink[] = {
.dpcm_playback = 1,
.ops = &cht_aif1_ops,
},
- [MERR_DPCM_COMPR] = {
- .name = "Compressed Port",
- .stream_name = "Compress",
- .cpu_dai_name = "compress-cpu-dai",
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .platform_name = "sst-mfld-platform",
- },
/* back ends */
{
.name = "SSP2-Codec",
- .id = 1,
+ .id = 0,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
@@ -277,6 +387,7 @@ static struct snd_soc_card snd_soc_card_cht = {
static int snd_cht_mc_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
int ret_val = 0;
struct cht_mc_private *drv;
@@ -289,11 +400,25 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
/* no need probe TI jack detection chip */
snd_soc_card_cht.aux_dev = NULL;
snd_soc_card_cht.num_aux_devs = 0;
+
+ ret_val = devm_acpi_dev_add_driver_gpios(dev->parent,
+ acpi_max98090_gpios);
+ if (ret_val)
+ dev_dbg(dev, "Unable to add GPIO mapping table\n");
}
/* register the soc card */
snd_soc_card_cht.dev = &pdev->dev;
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
+
+ drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+ if (IS_ERR(drv->mclk)) {
+ dev_err(&pdev->dev,
+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
+ PTR_ERR(drv->mclk));
+ return PTR_ERR(drv->mclk);
+ }
+
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
if (ret_val) {
dev_err(&pdev->dev,
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 5bcde01d15e6..18d129caa974 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -21,20 +21,20 @@
*/
#include <linux/module.h>
-#include <linux/acpi.h>
#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
-#include <linux/clk.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/rt5645.h"
#include "../atom/sst-atom-controls.h"
-#include "../common/sst-acpi.h"
#define CHT_PLAT_CLK_3_HZ 19200000
#define CHT_CODEC_DAI1 "rt5645-aif1"
@@ -53,7 +53,7 @@ struct cht_mc_private {
struct clk *mclk;
};
-#define CHT_RT5645_MAP(quirk) ((quirk) & 0xff)
+#define CHT_RT5645_MAP(quirk) ((quirk) & GENMASK(7, 0))
#define CHT_RT5645_SSP2_AIF2 BIT(16) /* default is using AIF1 */
#define CHT_RT5645_SSP0_AIF1 BIT(17)
#define CHT_RT5645_SSP0_AIF2 BIT(18)
@@ -70,21 +70,6 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk SSP0_AIF2 enabled");
}
-static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- list_for_each_entry(rtd, &card->rtd_list, list) {
- if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI1,
- strlen(CHT_CODEC_DAI1)))
- return rtd->codec_dai;
- if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI2,
- strlen(CHT_CODEC_DAI2)))
- return rtd->codec_dai;
- }
- return NULL;
-}
-
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
@@ -94,20 +79,21 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret;
- codec_dai = cht_get_codec_dai(card);
+ codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI1);
+ if (!codec_dai)
+ codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI2);
+
if (!codec_dai) {
dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
return -EIO;
}
if (SND_SOC_DAPM_EVENT_ON(event)) {
- if (ctx->mclk) {
- ret = clk_prepare_enable(ctx->mclk);
- if (ret < 0) {
- dev_err(card->dev,
- "could not configure MCLK state");
- return ret;
- }
+ ret = clk_prepare_enable(ctx->mclk);
+ if (ret < 0) {
+ dev_err(card->dev,
+ "could not configure MCLK state");
+ return ret;
}
} else {
/* Set codec sysclk source to its internal clock because codec PLL will
@@ -122,8 +108,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
return ret;
}
- if (ctx->mclk)
- clk_disable_unprepare(ctx->mclk);
+ clk_disable_unprepare(ctx->mclk);
}
return 0;
@@ -258,11 +243,11 @@ static const struct dmi_system_id cht_rt5645_quirk_table[] = {
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
{
- int ret;
- int jack_type;
- struct snd_soc_codec *codec = runtime->codec;
struct snd_soc_card *card = runtime->card;
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
+ struct snd_soc_codec *codec = runtime->codec;
+ int jack_type;
+ int ret;
if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) ||
(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {
@@ -320,26 +305,26 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack);
- if (ctx->mclk) {
- /*
- * The firmware might enable the clock at
- * boot (this information may or may not
- * be reflected in the enable clock register).
- * To change the rate we must disable the clock
- * first to cover these cases. Due to common
- * clock framework restrictions that do not allow
- * to disable a clock that has not been enabled,
- * we need to enable the clock first.
- */
- ret = clk_prepare_enable(ctx->mclk);
- if (!ret)
- clk_disable_unprepare(ctx->mclk);
- ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
+ /*
+ * The firmware might enable the clock at
+ * boot (this information may or may not
+ * be reflected in the enable clock register).
+ * To change the rate we must disable the clock
+ * first to cover these cases. Due to common
+ * clock framework restrictions that do not allow
+ * to disable a clock that has not been enabled,
+ * we need to enable the clock first.
+ */
+ ret = clk_prepare_enable(ctx->mclk);
+ if (!ret)
+ clk_disable_unprepare(ctx->mclk);
+
+ ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
+
+ if (ret)
+ dev_err(runtime->dev, "unable to set MCLK rate\n");
- if (ret)
- dev_err(runtime->dev, "unable to set MCLK rate\n");
- }
return ret;
}
@@ -460,19 +445,11 @@ static struct snd_soc_dai_link cht_dailink[] = {
.dpcm_playback = 1,
.ops = &cht_aif1_ops,
},
- [MERR_DPCM_COMPR] = {
- .name = "Compressed Port",
- .stream_name = "Compress",
- .cpu_dai_name = "compress-cpu-dai",
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .platform_name = "sst-mfld-platform",
- },
/* CODEC<->CODEC link */
/* back ends */
{
.name = "SSP2-Codec",
- .id = 1,
+ .id = 0,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
@@ -545,15 +522,15 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_cht_mc_probe(struct platform_device *pdev)
{
- int ret_val = 0;
- int i;
- struct cht_mc_private *drv;
struct snd_soc_card *card = snd_soc_cards[0].soc_card;
- struct sst_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach;
+ struct cht_mc_private *drv;
const char *i2c_name = NULL;
- int dai_index = 0;
bool found = false;
bool is_bytcr = false;
+ int dai_index = 0;
+ int ret_val = 0;
+ int i;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
if (!drv)
@@ -589,8 +566,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
/* fixup codec name based on HID */
- i2c_name = sst_acpi_find_name_from_hid(mach->id);
- if (i2c_name != NULL) {
+ i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
+ if (i2c_name) {
snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
"%s%s", "i2c-", i2c_name);
cht_dailink[dai_index].codec_name = cht_rt5645_codec_name;
@@ -622,7 +599,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
/* format specified: 2 64-bit integers */
struct acpi_buffer format = {sizeof("NN"), "NN"};
struct acpi_buffer state = {0, NULL};
- struct sst_acpi_package_context pkg_ctx;
+ struct snd_soc_acpi_package_context pkg_ctx;
bool pkg_found = false;
state.length = sizeof(chan_package);
@@ -634,7 +611,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
pkg_ctx.state = &state;
pkg_ctx.data_valid = false;
- pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx);
+ pkg_found = snd_soc_acpi_find_package_from_hid(mach->id,
+ &pkg_ctx);
if (pkg_found) {
if (chan_package.aif_value == 1) {
dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n");
@@ -682,14 +660,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
cht_rt5645_cpu_dai_name;
}
- if (is_valleyview()) {
- drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
- if (IS_ERR(drv->mclk)) {
- dev_err(&pdev->dev,
- "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
- PTR_ERR(drv->mclk));
- return PTR_ERR(drv->mclk);
- }
+ drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+ if (IS_ERR(drv->mclk)) {
+ dev_err(&pdev->dev,
+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
+ PTR_ERR(drv->mclk));
+ return PTR_ERR(drv->mclk);
}
snd_soc_card_set_drvdata(card, drv);
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index f597d5582223..f8f21eee9b2d 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -20,14 +20,14 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
-#include <asm/cpu_device_id.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
+#include <sound/soc-acpi.h>
#include "../../codecs/rt5670.h"
#include "../atom/sst-atom-controls.h"
-#include "../common/sst-acpi.h"
+
/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */
#define CHT_PLAT_CLK_3_HZ 19200000
@@ -51,18 +51,6 @@ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
},
};
-static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- list_for_each_entry(rtd, &card->rtd_list, list) {
- if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
- strlen(CHT_CODEC_DAI)))
- return rtd->codec_dai;
- }
- return NULL;
-}
-
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
@@ -72,7 +60,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret;
- codec_dai = cht_get_codec_dai(card);
+ codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI);
if (!codec_dai) {
dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
return -EIO;
@@ -315,20 +303,12 @@ static struct snd_soc_dai_link cht_dailink[] = {
.dpcm_playback = 1,
.ops = &cht_aif1_ops,
},
- [MERR_DPCM_COMPR] = {
- .name = "Compressed Port",
- .stream_name = "Compress",
- .cpu_dai_name = "compress-cpu-dai",
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .platform_name = "sst-mfld-platform",
- },
/* Back End DAI links */
{
/* SSP2 - Codec */
.name = "SSP2-Codec",
- .id = 1,
+ .id = 0,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
@@ -348,9 +328,11 @@ static struct snd_soc_dai_link cht_dailink[] = {
static int cht_suspend_pre(struct snd_soc_card *card)
{
struct snd_soc_component *component;
+ struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
list_for_each_entry(component, &card->component_dev_list, card_list) {
- if (!strcmp(component->name, "i2c-10EC5670:00")) {
+ if (!strncmp(component->name,
+ ctx->codec_name, sizeof(ctx->codec_name))) {
struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
@@ -364,9 +346,11 @@ static int cht_suspend_pre(struct snd_soc_card *card)
static int cht_resume_post(struct snd_soc_card *card)
{
struct snd_soc_component *component;
+ struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
list_for_each_entry(component, &card->component_dev_list, card_list) {
- if (!strcmp(component->name, "i2c-10EC5670:00")) {
+ if (!strncmp(component->name,
+ ctx->codec_name, sizeof(ctx->codec_name))) {
struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
dev_dbg(codec->dev, "enabling jack detect for resume.\n");
@@ -380,7 +364,7 @@ static int cht_resume_post(struct snd_soc_card *card)
/* SoC card */
static struct snd_soc_card snd_soc_card_cht = {
- .name = "cherrytrailcraudio",
+ .name = "cht-bsw-rt5672",
.owner = THIS_MODULE,
.dai_link = cht_dailink,
.num_links = ARRAY_SIZE(cht_dailink),
@@ -394,25 +378,13 @@ static struct snd_soc_card snd_soc_card_cht = {
.resume_post = cht_resume_post,
};
-static bool is_valleyview(void)
-{
- static const struct x86_cpu_id cpu_ids[] = {
- { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
- {}
- };
-
- if (!x86_match_cpu(cpu_ids))
- return false;
- return true;
-}
-
#define RT5672_I2C_DEFAULT "i2c-10EC5670:00"
static int snd_cht_mc_probe(struct platform_device *pdev)
{
int ret_val = 0;
struct cht_mc_private *drv;
- struct sst_acpi_mach *mach = pdev->dev.platform_data;
+ struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
const char *i2c_name;
int i;
@@ -424,7 +396,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
/* fixup codec name based on HID */
if (mach) {
- i2c_name = sst_acpi_find_name_from_hid(mach->id);
+ i2c_name = snd_soc_acpi_find_name_from_hid(mach->id);
if (i2c_name) {
snprintf(drv->codec_name, sizeof(drv->codec_name),
"i2c-%s", i2c_name);
@@ -439,14 +411,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
}
- if (is_valleyview()) {
- drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
- if (IS_ERR(drv->mclk)) {
- dev_err(&pdev->dev,
- "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
- PTR_ERR(drv->mclk));
- return PTR_ERR(drv->mclk);
- }
+ drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
+ if (IS_ERR(drv->mclk)) {
+ dev_err(&pdev->dev,
+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
+ PTR_ERR(drv->mclk));
+ return PTR_ERR(drv->mclk);
}
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 7f7607420706..6f9a8bcf20f3 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -17,6 +17,7 @@
* GNU General Public License for more details.
*/
+#include <linux/input.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
@@ -208,6 +209,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
int ret;
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_jack *jack;
/*
* Headset buttons map to the google Reference headset.
@@ -221,6 +223,13 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
}
+
+ jack = &ctx->kabylake_headset;
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+ 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);
+
rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
return ret;
}
@@ -341,13 +350,28 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
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);
+ struct snd_soc_dpcm *dpcm = container_of(
+ params, struct snd_soc_dpcm, hw_params);
+ struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link;
+ struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link;
- /* The ADSP will convert the FE rate to 48k, stereo */
- rate->min = rate->max = 48000;
- channels->min = channels->max = 2;
- /* set SSP1 to 24 bit */
- snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ /*
+ * The ADSP will convert the FE rate to 48k, stereo, 24 bit
+ */
+ if (!strcmp(fe_dai_link->name, "Kbl Audio Port") ||
+ !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") ||
+ !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) {
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+ snd_mask_none(fmt);
+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ }
+ /*
+ * The speaker on the SSP0 supports S16_LE and not S24_LE.
+ * thus changing the mask here
+ */
+ if (!strcmp(be_dai_link->name, "SSP0-Codec"))
+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
@@ -390,6 +414,43 @@ static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
+static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int ret = 0, j;
+
+ for (j = 0; j < rtd->num_codecs; j++) {
+ struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+
+ if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
+ /*
+ * Use channel 4 and 5 for the first amp
+ */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+ if (ret < 0) {
+ dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
+ /*
+ * Use channel 6 and 7 for the second amp
+ */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+ if (ret < 0) {
+ dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ }
+ return ret;
+}
+
+static struct snd_soc_ops kabylake_ssp0_ops = {
+ .hw_params = kabylake_ssp0_hw_params,
+};
+
static unsigned int channels_dmic[] = {
2, 4,
};
@@ -593,12 +654,13 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.no_pcm = 1,
.codecs = max98927_codec_components,
.num_codecs = ARRAY_SIZE(max98927_codec_components),
- .dai_fmt = SND_SOC_DAIFMT_I2S |
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
.be_hw_params_fixup = kabylake_ssp_fixup,
.dpcm_playback = 1,
+ .ops = &kabylake_ssp0_ops,
},
{
/* SSP1 - Codec */
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 88ff54220007..6072164f2d43 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -302,6 +302,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
* The ADSP will convert the FE rate to 48k, stereo, 24 bit
*/
if (!strcmp(fe_dai_link->name, "Kbl Audio Port") ||
+ !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") ||
!strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) {
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
@@ -604,6 +605,8 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
codec = pcm->codec_dai->codec;
+ 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, &ctx->kabylake_hdmi[i],
NULL, 0);
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index 5ed0aa27b467..1b5a689dc99b 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -54,20 +54,6 @@ enum {
SKL_DPCM_AUDIO_HDMI3_PB,
};
-static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- list_for_each_entry(rtd, &card->rtd_list, list) {
-
- if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
- strlen(SKL_NUVOTON_CODEC_DAI)))
- return rtd->codec_dai;
- }
-
- return NULL;
-}
-
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
@@ -76,7 +62,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_soc_dai *codec_dai;
int ret;
- codec_dai = skl_get_codec_dai(card);
+ codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
if (!codec_dai) {
dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
return -EIO;
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index 01b8b140bb08..7bea4bc77481 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -57,20 +57,6 @@ enum {
SKL_DPCM_AUDIO_HDMI3_PB,
};
-static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
-{
- struct snd_soc_pcm_runtime *rtd;
-
- list_for_each_entry(rtd, &card->rtd_list, list) {
-
- if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
- strlen(SKL_NUVOTON_CODEC_DAI)))
- return rtd->codec_dai;
- }
-
- return NULL;
-}
-
static const struct snd_kcontrol_new skylake_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -86,7 +72,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_soc_dai *codec_dai;
int ret;
- codec_dai = skl_get_codec_dai(card);
+ codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
if (!codec_dai) {
dev_err(card->dev, "Codec dai not found\n");
return -EIO;
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index 0e029f354f6b..7379d8830c39 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -1,11 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
snd-soc-sst-dsp-objs := sst-dsp.o
snd-soc-sst-acpi-objs := sst-acpi.o
-snd-soc-sst-match-objs := sst-match-acpi.o
snd-soc-sst-ipc-objs := sst-ipc.o
snd-soc-sst-firmware-objs := sst-firmware.o
+snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o soc-acpi-intel-hsw-bdw-match.o
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
-obj-$(CONFIG_SND_SOC_INTEL_SST_MATCH) += snd-soc-sst-match.o
obj-$(CONFIG_SND_SOC_INTEL_SST_FIRMWARE) += snd-soc-sst-firmware.o
+obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
new file mode 100644
index 000000000000..bfe1ca68a542
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
@@ -0,0 +1,196 @@
+/*
+ * soc-apci-intel-byt-match.c - tables and support for BYT ACPI enumeration.
+ *
+ * Copyright (c) 2017, Intel Corporation.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+#include <linux/dmi.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+static unsigned long byt_machine_id;
+
+#define BYT_THINKPAD_10 1
+
+static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id)
+{
+ byt_machine_id = BYT_THINKPAD_10;
+ return 1;
+}
+
+
+static const struct dmi_system_id byt_table[] = {
+ {
+ .callback = byt_thinkpad10_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
+ },
+ },
+ {
+ .callback = byt_thinkpad10_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"),
+ },
+ },
+ {
+ .callback = byt_thinkpad10_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"),
+ },
+ },
+ { }
+};
+
+static struct snd_soc_acpi_mach byt_thinkpad_10 = {
+ .id = "10EC5640",
+ .drv_name = "cht-bsw-rt5672",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-rt5670.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+};
+
+static struct snd_soc_acpi_mach *byt_quirk(void *arg)
+{
+ struct snd_soc_acpi_mach *mach = arg;
+
+ dmi_check_system(byt_table);
+
+ if (byt_machine_id == BYT_THINKPAD_10)
+ return &byt_thinkpad_10;
+ else
+ return mach;
+}
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_legacy_machines[] = {
+ {
+ .id = "10EC5640",
+ .drv_name = "byt-rt5640",
+ .fw_filename = "intel/fw_sst_0f28.bin-48kHz_i2s_master",
+ },
+ {
+ .id = "193C9890",
+ .drv_name = "byt-max98090",
+ .fw_filename = "intel/fw_sst_0f28.bin-48kHz_i2s_master",
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_baytrail_legacy_machines);
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
+ {
+ .id = "10EC5640",
+ .drv_name = "bytcr_rt5640",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "bytcr_rt5640",
+ .machine_quirk = byt_quirk,
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "10EC5642",
+ .drv_name = "bytcr_rt5640",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "bytcr_rt5640",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "INTCCFFD",
+ .drv_name = "bytcr_rt5640",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "bytcr_rt5640",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "10EC5651",
+ .drv_name = "bytcr_rt5651",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "bytcr_rt5651",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-rt5651.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "DLGS7212",
+ .drv_name = "bytcht_da7213",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "bytcht_da7213",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-da7213.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "DLGS7213",
+ .drv_name = "bytcht_da7213",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "bytcht_da7213",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-da7213.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ /* some Baytrail platforms rely on RT5645, use CHT machine driver */
+ {
+ .id = "10EC5645",
+ .drv_name = "cht-bsw-rt5645",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-rt5645.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "10EC5648",
+ .drv_name = "cht-bsw-rt5645",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-rt5645.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ /* use CHT driver to Baytrail Chromebooks */
+ {
+ .id = "193C9890",
+ .drv_name = "cht-bsw-max98090",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-byt.ri",
+ .sof_tplg_filename = "intel/reef-byt-max98090.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
+ /*
+ * This is always last in the table so that it is selected only when
+ * enabled explicitly and there is no codec-related information in SSDT
+ */
+ {
+ .id = "80860F28",
+ .drv_name = "bytcht_nocodec",
+ .fw_filename = "intel/fw_sst_0f28.bin",
+ .board = "bytcht_nocodec",
+ },
+#endif
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_baytrail_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
new file mode 100644
index 000000000000..b50a0d53846b
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
@@ -0,0 +1,194 @@
+/*
+ * soc-apci-intel-cht-match.c - tables and support for CHT ACPI enumeration.
+ *
+ * Copyright (c) 2017, Intel Corporation.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+#include <linux/dmi.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+static unsigned long cht_machine_id;
+
+#define CHT_SURFACE_MACH 1
+
+static int cht_surface_quirk_cb(const struct dmi_system_id *id)
+{
+ cht_machine_id = CHT_SURFACE_MACH;
+ return 1;
+}
+
+static const struct dmi_system_id cht_table[] = {
+ {
+ .callback = cht_surface_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+ },
+ },
+ { }
+};
+
+static struct snd_soc_acpi_mach cht_surface_mach = {
+ .id = "10EC5640",
+ .drv_name = "cht-bsw-rt5645",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+};
+
+static struct snd_soc_acpi_mach *cht_quirk(void *arg)
+{
+ struct snd_soc_acpi_mach *mach = arg;
+
+ dmi_check_system(cht_table);
+
+ if (cht_machine_id == CHT_SURFACE_MACH)
+ return &cht_surface_mach;
+ else
+ return mach;
+}
+
+/* Cherryview-based platforms: CherryTrail and Braswell */
+struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
+ {
+ .id = "10EC5670",
+ .drv_name = "cht-bsw-rt5672",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5670.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "10EC5672",
+ .drv_name = "cht-bsw-rt5672",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5670.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "10EC5645",
+ .drv_name = "cht-bsw-rt5645",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "10EC5650",
+ .drv_name = "cht-bsw-rt5645",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "10EC3270",
+ .drv_name = "cht-bsw-rt5645",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "193C9890",
+ .drv_name = "cht-bsw-max98090",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "cht-bsw",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-max98090.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "DLGS7212",
+ .drv_name = "bytcht_da7213",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "bytcht_da7213",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-da7213.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "DLGS7213",
+ .drv_name = "bytcht_da7213",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "bytcht_da7213",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-da7213.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "ESSX8316",
+ .drv_name = "bytcht_es8316",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "bytcht_es8316",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-es8316.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
+ {
+ .id = "10EC5640",
+ .drv_name = "bytcr_rt5640",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "bytcr_rt5640",
+ .machine_quirk = cht_quirk,
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5640.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ {
+ .id = "10EC3276",
+ .drv_name = "bytcr_rt5640",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "bytcr_rt5640",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5640.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+ /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
+ {
+ .id = "10EC5651",
+ .drv_name = "bytcr_rt5651",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "bytcr_rt5651",
+ .sof_fw_filename = "intel/reef-cht.ri",
+ .sof_tplg_filename = "intel/reef-cht-rt5651.tplg",
+ .asoc_plat_name = "sst-mfld-platform",
+ },
+#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
+ /*
+ * This is always last in the table so that it is selected only when
+ * enabled explicitly and there is no codec-related information in SSDT
+ */
+ {
+ .id = "808622A8",
+ .drv_name = "bytcht_nocodec",
+ .fw_filename = "intel/fw_sst_22a8.bin",
+ .board = "bytcht_nocodec",
+ },
+#endif
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cherrytrail_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
new file mode 100644
index 000000000000..e0e8c8c27528
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
@@ -0,0 +1,64 @@
+/*
+ * soc-apci-intel-hsw-bdw-match.c - tables and support for ACPI enumeration.
+ *
+ * Copyright (c) 2017, Intel Corporation.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+#include <linux/dmi.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = {
+ {
+ .id = "INT33CA",
+ .drv_name = "haswell-audio",
+ .fw_filename = "intel/IntcSST1.bin",
+ .sof_fw_filename = "intel/reef-hsw.ri",
+ .sof_tplg_filename = "intel/reef-hsw.tplg",
+ .asoc_plat_name = "haswell-pcm-audio",
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_haswell_machines);
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
+ {
+ .id = "INT343A",
+ .drv_name = "broadwell-audio",
+ .fw_filename = "intel/IntcSST2.bin",
+ .sof_fw_filename = "intel/reef-bdw.ri",
+ .sof_tplg_filename = "intel/reef-bdw-rt286.tplg",
+ .asoc_plat_name = "haswell-pcm-audio",
+ },
+ {
+ .id = "RT5677CE",
+ .drv_name = "bdw-rt5677",
+ .fw_filename = "intel/IntcSST2.bin",
+ .sof_fw_filename = "intel/reef-bdw.ri",
+ .sof_tplg_filename = "intel/reef-bdw-rt286.tplg",
+ .asoc_plat_name = "haswell-pcm-audio",
+ },
+ {
+ .id = "INT33CA",
+ .drv_name = "haswell-audio",
+ .fw_filename = "intel/IntcSST2.bin",
+ .sof_fw_filename = "intel/reef-bdw.ri",
+ .sof_tplg_filename = "intel/reef-bdw-rt5640.tplg",
+ .asoc_plat_name = "haswell-pcm-audio",
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_broadwell_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c
index 1285cc597b6b..cf6fbbd4e378 100644
--- a/sound/soc/intel/common/sst-acpi.c
+++ b/sound/soc/intel/common/sst-acpi.c
@@ -21,7 +21,8 @@
#include <linux/platform_device.h>
#include "sst-dsp.h"
-#include "sst-acpi.h"
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
#define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000
#define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000
@@ -30,7 +31,7 @@
/* Descriptor for setting up SST platform data */
struct sst_acpi_desc {
const char *drv_name;
- struct sst_acpi_mach *machines;
+ struct snd_soc_acpi_mach *machines;
/* Platform resource indexes. Must set to -1 if not used */
int resindex_lpe_base;
int resindex_pcicfg_base;
@@ -49,7 +50,7 @@ struct sst_acpi_priv {
struct platform_device *pdev_pcm;
struct sst_pdata sst_pdata;
struct sst_acpi_desc *desc;
- struct sst_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach;
};
static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
@@ -59,7 +60,7 @@ static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
struct sst_acpi_desc *desc = sst_acpi->desc;
- struct sst_acpi_mach *mach = sst_acpi->mach;
+ struct snd_soc_acpi_mach *mach = sst_acpi->mach;
sst_pdata->fw = fw;
if (!fw) {
@@ -85,7 +86,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct sst_acpi_priv *sst_acpi;
struct sst_pdata *sst_pdata;
- struct sst_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach;
struct sst_acpi_desc *desc;
struct resource *mmio;
int ret = 0;
@@ -99,7 +100,7 @@ static int sst_acpi_probe(struct platform_device *pdev)
return -ENODEV;
desc = (struct sst_acpi_desc *)id->driver_data;
- mach = sst_acpi_find_machine(desc->machines);
+ mach = snd_soc_acpi_find_machine(desc->machines);
if (mach == NULL) {
dev_err(dev, "No matching ASoC machine driver found\n");
return -ENODEV;
@@ -179,14 +180,9 @@ static int sst_acpi_remove(struct platform_device *pdev)
return 0;
}
-static struct sst_acpi_mach haswell_machines[] = {
- { "INT33CA", "haswell-audio", "intel/IntcSST1.bin", NULL, NULL, NULL },
- {}
-};
-
static struct sst_acpi_desc sst_acpi_haswell_desc = {
.drv_name = "haswell-pcm-audio",
- .machines = haswell_machines,
+ .machines = snd_soc_acpi_intel_haswell_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_fw_base = -1,
@@ -197,15 +193,9 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = {
.dma_size = SST_LPT_DSP_DMA_SIZE,
};
-static struct sst_acpi_mach broadwell_machines[] = {
- { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL },
- { "RT5677CE", "bdw-rt5677", "intel/IntcSST2.bin", NULL, NULL, NULL },
- {}
-};
-
static struct sst_acpi_desc sst_acpi_broadwell_desc = {
.drv_name = "haswell-pcm-audio",
- .machines = broadwell_machines,
+ .machines = snd_soc_acpi_intel_broadwell_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_fw_base = -1,
@@ -217,15 +207,9 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
};
#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
-static struct sst_acpi_mach baytrail_machines[] = {
- { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
- { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
- {}
-};
-
static struct sst_acpi_desc sst_acpi_baytrail_desc = {
.drv_name = "baytrail-pcm-audio",
- .machines = baytrail_machines,
+ .machines = snd_soc_acpi_intel_baytrail_legacy_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_fw_base = 2,
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
deleted file mode 100644
index afe9b87b8bd5..000000000000
--- a/sound/soc/intel/common/sst-acpi.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2013-15, Intel Corporation. All rights reserved.
- *
- * 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.
- *
- * 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.
- *
- */
-
-#include <linux/stddef.h>
-#include <linux/acpi.h>
-
-struct sst_acpi_package_context {
- char *name; /* package name */
- int length; /* number of elements */
- struct acpi_buffer *format;
- struct acpi_buffer *state;
- bool data_valid;
-};
-
-#if IS_ENABLED(CONFIG_ACPI)
-/* translation fron HID to I2C name, needed for DAI codec_name */
-const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]);
-bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
- struct sst_acpi_package_context *ctx);
-#else
-static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
-{
- return NULL;
-}
-static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
- struct sst_acpi_package_context *ctx)
-{
- return false;
-}
-#endif
-
-/* acpi match */
-struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
-
-/* acpi check hid */
-bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN]);
-
-/* Descriptor for SST ASoC machine driver */
-struct sst_acpi_mach {
- /* ACPI ID for the matching machine driver. Audio codec for instance */
- const u8 id[ACPI_ID_LEN];
- /* machine driver name */
- const char *drv_name;
- /* firmware file name */
- const char *fw_filename;
-
- /* board name */
- const char *board;
- struct sst_acpi_mach * (*machine_quirk)(void *arg);
- const void *quirk_data;
- void *pdata;
-};
-
-#define SST_ACPI_MAX_CODECS 3
-
-/**
- * struct sst_codecs: Structure to hold secondary codec information apart from
- * the matched one, this data will be passed to the quirk function to match
- * with the ACPI detected devices
- *
- * @num_codecs: number of secondary codecs used in the platform
- * @codecs: holds the codec IDs
- *
- */
-struct sst_codecs {
- int num_codecs;
- u8 codecs[SST_ACPI_MAX_CODECS][ACPI_ID_LEN];
-};
-
-/* check all codecs */
-struct sst_acpi_mach *sst_acpi_codec_list(void *arg);
diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c
index a086c35f91bb..657afc02f1c4 100644
--- a/sound/soc/intel/common/sst-firmware.c
+++ b/sound/soc/intel/common/sst-firmware.c
@@ -19,6 +19,7 @@
#include <linux/sched.h>
#include <linux/firmware.h>
#include <linux/export.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
@@ -274,7 +275,6 @@ int sst_dma_new(struct sst_dsp *sst)
struct sst_pdata *sst_pdata = sst->pdata;
struct sst_dma *dma;
struct resource mem;
- const char *dma_dev_name;
int ret = 0;
if (sst->pdata->resindex_dma_base == -1)
@@ -285,7 +285,6 @@ int sst_dma_new(struct sst_dsp *sst)
* is attached to the ADSP IP. */
switch (sst->pdata->dma_engine) {
case SST_DMA_TYPE_DW:
- dma_dev_name = "dw_dmac";
break;
default:
dev_err(sst->dev, "error: invalid DMA engine %d\n",
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 89f70133c8e4..61b5bfa79d13 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -613,8 +613,10 @@ skip_buf_size_calc:
}
#define DMA_CONTROL_ID 5
+#define DMA_I2S_BLOB_SIZE 21
-int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
+int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
+ u32 caps_size, u32 node_id)
{
struct skl_dma_control *dma_ctrl;
struct skl_ipc_large_config_msg msg = {0};
@@ -624,24 +626,27 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
/*
* if blob size zero, then return
*/
- if (mconfig->formats_config.caps_size == 0)
+ if (caps_size == 0)
return 0;
msg.large_param_id = DMA_CONTROL_ID;
- msg.param_data_size = sizeof(struct skl_dma_control) +
- mconfig->formats_config.caps_size;
+ msg.param_data_size = sizeof(struct skl_dma_control) + caps_size;
dma_ctrl = kzalloc(msg.param_data_size, GFP_KERNEL);
if (dma_ctrl == NULL)
return -ENOMEM;
- dma_ctrl->node_id = skl_get_node_id(ctx, mconfig);
+ dma_ctrl->node_id = node_id;
- /* size in dwords */
- dma_ctrl->config_length = mconfig->formats_config.caps_size / 4;
+ /*
+ * NHLT blob may contain additional configs along with i2s blob.
+ * firmware expects only the i2s blob size as the config_length.
+ * So fix to i2s blob size.
+ * size in dwords.
+ */
+ dma_ctrl->config_length = DMA_I2S_BLOB_SIZE;
- memcpy(dma_ctrl->config_data, mconfig->formats_config.caps,
- mconfig->formats_config.caps_size);
+ memcpy(dma_ctrl->config_data, caps, caps_size);
err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl);
@@ -702,18 +707,11 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
struct skl_module *module = mconfig->module;
struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
- int i = 0;
skl_set_base_module_format(ctx, mconfig,
(struct skl_base_cfg *)mixer_mconfig);
mixer_mconfig->out_ch_cfg = fmt->ch_cfg;
-
- /* Select F/W default coefficient */
- mixer_mconfig->coeff_sel = 0x0;
-
- /* User coeff, don't care since we are selecting F/W defaults */
- for (i = 0; i < UP_DOWN_MIXER_MAX_COEFF; i++)
- mixer_mconfig->coeff[i] = 0xDEADBEEF;
+ mixer_mconfig->ch_map = fmt->ch_map;
}
/*
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index e7d766d56c8e..d14c50a60289 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -20,6 +20,8 @@
#include <linux/pci.h>
#include "skl.h"
+#define NHLT_ACPI_HEADER_SIG "NHLT"
+
/* Unique identification for getting NHLT blobs */
static guid_t osc_guid =
GUID_INIT(0xA69F886E, 0x6CEB, 0x4594,
@@ -45,6 +47,13 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
MEMREMAP_WB);
ACPI_FREE(obj);
+ if (nhlt_table && (strncmp(nhlt_table->header.signature,
+ NHLT_ACPI_HEADER_SIG,
+ strlen(NHLT_ACPI_HEADER_SIG)) != 0)) {
+ memunmap(nhlt_table);
+ dev_err(dev, "NHLT ACPI header signature incorrect\n");
+ return NULL;
+ }
return nhlt_table;
}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 2b1e513b1680..1dd97479e0c0 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -355,7 +355,8 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
}
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
- skl_tplg_d0i3_put(skl, mconfig->d0i3_caps);
+ if (mconfig)
+ skl_tplg_d0i3_put(skl, mconfig->d0i3_caps);
kfree(dma_params);
}
@@ -652,7 +653,7 @@ static const struct snd_soc_dai_ops skl_link_dai_ops = {
.trigger = skl_link_pcm_trigger,
};
-static struct snd_soc_dai_driver skl_platform_dai[] = {
+static struct snd_soc_dai_driver skl_fe_dai[] = {
{
.name = "System Pin",
.ops = &skl_pcm_dai_ops,
@@ -796,8 +797,10 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.sig_bits = 32,
},
},
+};
/* BE CPU Dais */
+static struct snd_soc_dai_driver skl_platform_dai[] = {
{
.name = "SSP0 Pin",
.ops = &skl_be_ssp_dai_ops,
@@ -975,6 +978,14 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
};
+int skl_dai_load(struct snd_soc_component *cmp,
+ struct snd_soc_dai_driver *pcm_dai)
+{
+ pcm_dai->ops = &skl_pcm_dai_ops;
+
+ return 0;
+}
+
static int skl_platform_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -1362,6 +1373,8 @@ int skl_platform_register(struct device *dev)
int ret;
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
struct skl *skl = ebus_to_skl(ebus);
+ struct snd_soc_dai_driver *dais;
+ int num_dais = ARRAY_SIZE(skl_platform_dai);
INIT_LIST_HEAD(&skl->ppl_list);
INIT_LIST_HEAD(&skl->bind_list);
@@ -1371,14 +1384,38 @@ int skl_platform_register(struct device *dev)
dev_err(dev, "soc platform registration failed %d\n", ret);
return ret;
}
+
+ skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai),
+ GFP_KERNEL);
+ if (!skl->dais) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (!skl->use_tplg_pcm) {
+ dais = krealloc(skl->dais, sizeof(skl_fe_dai) +
+ sizeof(skl_platform_dai), GFP_KERNEL);
+ if (!dais) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ skl->dais = dais;
+ memcpy(&skl->dais[ARRAY_SIZE(skl_platform_dai)], skl_fe_dai,
+ sizeof(skl_fe_dai));
+ num_dais += ARRAY_SIZE(skl_fe_dai);
+ }
+
ret = snd_soc_register_component(dev, &skl_component,
- skl_platform_dai,
- ARRAY_SIZE(skl_platform_dai));
+ skl->dais, num_dais);
if (ret) {
dev_err(dev, "soc component registration failed %d\n", ret);
- snd_soc_unregister_platform(dev);
+ goto err;
}
+ return 0;
+err:
+ snd_soc_unregister_platform(dev);
return ret;
}
@@ -1398,5 +1435,7 @@ int skl_platform_unregister(struct device *dev)
snd_soc_unregister_component(dev);
snd_soc_unregister_platform(dev);
+ kfree(skl->dais);
+
return 0;
}
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index 369ef7ce981c..8ff89280d9fd 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -251,6 +251,7 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
struct uuid_module *module;
struct firmware stripped_fw;
unsigned int safe_file;
+ int ret = 0;
/* Get the FW pointer to derive ADSP header */
stripped_fw.data = fw->data;
@@ -299,8 +300,10 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
for (i = 0; i < num_entry; i++, mod_entry++) {
module = kzalloc(sizeof(*module), GFP_KERNEL);
- if (!module)
- return -ENOMEM;
+ if (!module) {
+ ret = -ENOMEM;
+ goto free_uuid_list;
+ }
uuid_bin = (uuid_le *)mod_entry->uuid.id;
memcpy(&module->uuid, uuid_bin, sizeof(module->uuid));
@@ -311,8 +314,8 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
size = sizeof(int) * mod_entry->instance_max_count;
module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
if (!module->instance_id) {
- kfree(module);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_uuid_list;
}
list_add_tail(&module->list, &skl->uuid_list);
@@ -323,6 +326,10 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw,
}
return 0;
+
+free_uuid_list:
+ skl_freeup_uuid_list(skl);
+ return ret;
}
void skl_freeup_uuid_list(struct skl_sst *ctx)
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 22f768ca3c73..a072bcf209d2 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -2036,21 +2036,45 @@ static int skl_tplg_add_pipe(struct device *dev,
return 0;
}
-static int skl_tplg_fill_pin(struct device *dev, u32 tkn,
+static int skl_tplg_get_uuid(struct device *dev, u8 *guid,
+ struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
+{
+ if (uuid_tkn->token == SKL_TKN_UUID) {
+ memcpy(guid, &uuid_tkn->uuid, 16);
+ return 0;
+ }
+
+ dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
+
+ return -EINVAL;
+}
+
+static int skl_tplg_fill_pin(struct device *dev,
+ struct snd_soc_tplg_vendor_value_elem *tkn_elem,
struct skl_module_pin *m_pin,
- int pin_index, u32 value)
+ int pin_index)
{
- switch (tkn) {
+ int ret;
+
+ switch (tkn_elem->token) {
case SKL_TKN_U32_PIN_MOD_ID:
- m_pin[pin_index].id.module_id = value;
+ m_pin[pin_index].id.module_id = tkn_elem->value;
break;
case SKL_TKN_U32_PIN_INST_ID:
- m_pin[pin_index].id.instance_id = value;
+ m_pin[pin_index].id.instance_id = tkn_elem->value;
+ break;
+
+ case SKL_TKN_UUID:
+ ret = skl_tplg_get_uuid(dev, m_pin[pin_index].id.mod_uuid.b,
+ (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
+ if (ret < 0)
+ return ret;
+
break;
default:
- dev_err(dev, "%d Not a pin token\n", value);
+ dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
return -EINVAL;
}
@@ -2083,9 +2107,7 @@ static int skl_tplg_fill_pins_info(struct device *dev,
return -EINVAL;
}
- ret = skl_tplg_fill_pin(dev, tkn_elem->token,
- m_pin, pin_count, tkn_elem->value);
-
+ ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
if (ret < 0)
return ret;
@@ -2170,19 +2192,6 @@ static int skl_tplg_widget_fill_fmt(struct device *dev,
return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
}
-static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
- struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
-{
- if (uuid_tkn->token == SKL_TKN_UUID)
- memcpy(&mconfig->guid, &uuid_tkn->uuid, 16);
- else {
- dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
- return -EINVAL;
- }
-
- return 0;
-}
-
static void skl_tplg_fill_pin_dynamic_val(
struct skl_module_pin *mpin, u32 pin_count, u32 value)
{
@@ -2382,7 +2391,7 @@ static int skl_tplg_get_token(struct device *dev,
case SKL_TKN_U32_MAX_MCPS:
case SKL_TKN_U32_OBS:
case SKL_TKN_U32_IBS:
- ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, dir, pin_index);
+ ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
if (ret < 0)
return ret;
@@ -2488,6 +2497,7 @@ static int skl_tplg_get_token(struct device *dev,
case SKL_TKN_U32_PIN_MOD_ID:
case SKL_TKN_U32_PIN_INST_ID:
+ case SKL_TKN_UUID:
ret = skl_tplg_fill_pins_info(dev,
mconfig, tkn_elem, dir,
pin_index);
@@ -2550,6 +2560,7 @@ static int skl_tplg_get_tokens(struct device *dev,
struct snd_soc_tplg_vendor_value_elem *tkn_elem;
int tkn_count = 0, ret;
int off = 0, tuple_size = 0;
+ bool is_module_guid = true;
if (block_size <= 0)
return -EINVAL;
@@ -2565,7 +2576,15 @@ static int skl_tplg_get_tokens(struct device *dev,
continue;
case SND_SOC_TPLG_TUPLE_TYPE_UUID:
- ret = skl_tplg_get_uuid(dev, mconfig, array->uuid);
+ if (is_module_guid) {
+ ret = skl_tplg_get_uuid(dev, mconfig->guid,
+ array->uuid);
+ is_module_guid = false;
+ } else {
+ ret = skl_tplg_get_token(dev, array->value, skl,
+ mconfig);
+ }
+
if (ret < 0)
return ret;
@@ -3331,6 +3350,7 @@ static struct snd_soc_tplg_ops skl_tplg_ops = {
.io_ops = skl_tplg_kcontrol_ops,
.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
.manifest = skl_manifest_load,
+ .dai_load = skl_dai_load,
};
/*
@@ -3404,7 +3424,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
ret = request_firmware(&fw, skl->tplg_name, bus->dev);
if (ret < 0) {
- dev_err(bus->dev, "tplg fw %s load failed with %d\n",
+ dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin",
skl->tplg_name, ret);
ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
if (ret < 0) {
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 2717db92036b..b6496513fe55 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -34,7 +34,7 @@
#define MAX_FIXED_DMIC_PARAMS_SIZE 727
/* Maximum number of coefficients up down mixer module */
-#define UP_DOWN_MIXER_MAX_COEFF 6
+#define UP_DOWN_MIXER_MAX_COEFF 8
#define MODULE_MAX_IN_PINS 8
#define MODULE_MAX_OUT_PINS 8
@@ -161,6 +161,7 @@ struct skl_up_down_mixer_cfg {
u32 coeff_sel;
/* Pass the user coeff in this array */
s32 coeff[UP_DOWN_MIXER_MAX_COEFF];
+ u32 ch_map;
} __packed;
struct skl_algo_cfg {
@@ -455,8 +456,8 @@ static inline struct skl *get_skl_ctx(struct device *dev)
int skl_tplg_be_update_params(struct snd_soc_dai *dai,
struct skl_pipe_params *params);
-int skl_dsp_set_dma_control(struct skl_sst *ctx,
- struct skl_module_cfg *mconfig);
+int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
+ u32 caps_size, u32 node_id);
void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
struct skl_pipe_params *params, int stream);
int skl_tplg_init(struct snd_soc_platform *platform,
@@ -501,4 +502,7 @@ int skl_pcm_host_dma_prepare(struct device *dev,
struct skl_pipe_params *params);
int skl_pcm_link_dma_prepare(struct device *dev,
struct skl_pipe_params *params);
+
+int skl_dai_load(struct snd_soc_component *cmp,
+ struct snd_soc_dai_driver *pcm_dai);
#endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index f94b484abb99..31d8634e8aa1 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -28,7 +28,7 @@
#include <linux/firmware.h>
#include <linux/delay.h>
#include <sound/pcm.h>
-#include "../common/sst-acpi.h"
+#include <sound/soc-acpi.h>
#include <sound/hda_register.h>
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
@@ -439,10 +439,10 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
{
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
struct platform_device *pdev;
- struct sst_acpi_mach *mach = driver_data;
+ struct snd_soc_acpi_mach *mach = driver_data;
int ret;
- mach = sst_acpi_find_machine(mach);
+ mach = snd_soc_acpi_find_machine(mach);
if (mach == NULL) {
dev_err(bus->dev, "No matching machine driver found\n");
return -ENODEV;
@@ -462,8 +462,11 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
return -EIO;
}
- if (mach->pdata)
+ if (mach->pdata) {
+ skl->use_tplg_pcm =
+ ((struct skl_machine_pdata *)mach->pdata)->use_tplg_pcm;
dev_set_drvdata(&pdev->dev, mach->pdata);
+ }
skl->i2s_dev = pdev;
@@ -875,33 +878,36 @@ static void skl_remove(struct pci_dev *pci)
dev_set_drvdata(&pci->dev, NULL);
}
-static struct sst_codecs skl_codecs = {
+static struct snd_soc_acpi_codecs skl_codecs = {
.num_codecs = 1,
.codecs = {"10508825"}
};
-static struct sst_codecs kbl_codecs = {
+static struct snd_soc_acpi_codecs kbl_codecs = {
.num_codecs = 1,
.codecs = {"10508825"}
};
-static struct sst_codecs bxt_codecs = {
+static struct snd_soc_acpi_codecs bxt_codecs = {
.num_codecs = 1,
.codecs = {"MX98357A"}
};
-static struct sst_codecs kbl_poppy_codecs = {
+static struct snd_soc_acpi_codecs kbl_poppy_codecs = {
.num_codecs = 1,
.codecs = {"10EC5663"}
};
-static struct sst_codecs kbl_5663_5514_codecs = {
+static struct snd_soc_acpi_codecs kbl_5663_5514_codecs = {
.num_codecs = 2,
.codecs = {"10EC5663", "10EC5514"}
};
+static struct skl_machine_pdata cnl_pdata = {
+ .use_tplg_pcm = true,
+};
-static struct sst_acpi_mach sst_skl_devdata[] = {
+static struct snd_soc_acpi_mach sst_skl_devdata[] = {
{
.id = "INT343A",
.drv_name = "skl_alc286s_i2s",
@@ -911,7 +917,7 @@ static struct sst_acpi_mach sst_skl_devdata[] = {
.id = "INT343B",
.drv_name = "skl_n88l25_s4567",
.fw_filename = "intel/dsp_fw_release.bin",
- .machine_quirk = sst_acpi_codec_list,
+ .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &skl_codecs,
.pdata = &skl_dmic_data
},
@@ -919,14 +925,14 @@ static struct sst_acpi_mach sst_skl_devdata[] = {
.id = "MX98357A",
.drv_name = "skl_n88l25_m98357a",
.fw_filename = "intel/dsp_fw_release.bin",
- .machine_quirk = sst_acpi_codec_list,
+ .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &skl_codecs,
.pdata = &skl_dmic_data
},
{}
};
-static struct sst_acpi_mach sst_bxtp_devdata[] = {
+static struct snd_soc_acpi_mach sst_bxtp_devdata[] = {
{
.id = "INT343A",
.drv_name = "bxt_alc298s_i2s",
@@ -936,13 +942,13 @@ static struct sst_acpi_mach sst_bxtp_devdata[] = {
.id = "DLGS7219",
.drv_name = "bxt_da7219_max98357a_i2s",
.fw_filename = "intel/dsp_fw_bxtn.bin",
- .machine_quirk = sst_acpi_codec_list,
+ .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &bxt_codecs,
},
{}
};
-static struct sst_acpi_mach sst_kbl_devdata[] = {
+static struct snd_soc_acpi_mach sst_kbl_devdata[] = {
{
.id = "INT343A",
.drv_name = "kbl_alc286s_i2s",
@@ -952,7 +958,7 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
.id = "INT343B",
.drv_name = "kbl_n88l25_s4567",
.fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = sst_acpi_codec_list,
+ .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_codecs,
.pdata = &skl_dmic_data
},
@@ -960,7 +966,7 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
.id = "MX98357A",
.drv_name = "kbl_n88l25_m98357a",
.fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = sst_acpi_codec_list,
+ .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_codecs,
.pdata = &skl_dmic_data
},
@@ -968,7 +974,7 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
.id = "MX98927",
.drv_name = "kbl_r5514_5663_max",
.fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = sst_acpi_codec_list,
+ .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_5663_5514_codecs,
.pdata = &skl_dmic_data
},
@@ -976,7 +982,7 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
.id = "MX98927",
.drv_name = "kbl_rt5663_m98927",
.fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = sst_acpi_codec_list,
+ .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &kbl_poppy_codecs,
.pdata = &skl_dmic_data
},
@@ -989,7 +995,7 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
{}
};
-static struct sst_acpi_mach sst_glk_devdata[] = {
+static struct snd_soc_acpi_mach sst_glk_devdata[] = {
{
.id = "INT343A",
.drv_name = "glk_alc298s_i2s",
@@ -998,12 +1004,14 @@ static struct sst_acpi_mach sst_glk_devdata[] = {
{}
};
-static const struct sst_acpi_mach sst_cnl_devdata[] = {
+static const struct snd_soc_acpi_mach sst_cnl_devdata[] = {
{
.id = "INT34C2",
.drv_name = "cnl_rt274",
.fw_filename = "intel/dsp_fw_cnl.bin",
+ .pdata = &cnl_pdata,
},
+ {}
};
/* PCI IDs */
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 8d9d6899f761..e00cde8200dd 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -53,6 +53,7 @@ struct skl {
struct platform_device *dmic_dev;
struct platform_device *i2s_dev;
struct snd_soc_platform *platform;
+ struct snd_soc_dai_driver *dais;
struct nhlt_acpi_table *nhlt; /* nhlt ptr */
struct skl_sst *skl_sst; /* sst skl ctx */
@@ -73,6 +74,7 @@ struct skl {
struct skl_debug *debugfs;
u8 nr_modules;
struct skl_module **modules;
+ bool use_tplg_pcm;
};
#define skl_to_ebus(s) (&(s)->ebus)
@@ -85,9 +87,9 @@ struct skl_dma_params {
u8 stream_tag;
};
-/* to pass dmic data */
struct skl_machine_pdata {
u32 dmic_num;
+ bool use_tplg_pcm; /* use dais and dai links from topology */
};
struct skl_dsp_ops {
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index cf23af159acf..505b0ff03c3b 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -318,7 +318,7 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
}
}
-struct snd_soc_platform_driver kirkwood_soc_platform = {
+const struct snd_soc_platform_driver kirkwood_soc_platform = {
.ops = &kirkwood_dma_ops,
.pcm_new = kirkwood_dma_new,
.pcm_free = kirkwood_dma_free_dma_buffers,
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
index 90e32a781424..783cb1a4f30e 100644
--- a/sound/soc/kirkwood/kirkwood.h
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -143,6 +143,6 @@ struct kirkwood_dma_data {
int burst;
};
-extern struct snd_soc_platform_driver kirkwood_soc_platform;
+extern const struct snd_soc_platform_driver kirkwood_soc_platform;
#endif
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 6c49f3d6fd96..d40219678700 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -260,7 +260,7 @@ static bool cx81801_cmd_pending;
static bool ams_delta_muted;
static DEFINE_SPINLOCK(ams_delta_lock);
-static void cx81801_timeout(unsigned long data)
+static void cx81801_timeout(struct timer_list *unused)
{
int muted;
@@ -349,7 +349,7 @@ static void cx81801_receive(struct tty_struct *tty,
/* First modem response, complete setup procedure */
/* Initialize timer used for config pulse generation */
- setup_timer(&cx81801_timer, cx81801_timeout, 0);
+ timer_setup(&cx81801_timer, cx81801_timeout, 0);
v253_ops.receive_buf(tty, cp, fp, count);
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
index 3e9cc4842a1d..8eeac7cab1c1 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -362,6 +362,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
card->name = devm_kasprintf(dev, GFP_KERNEL,
"HDMI %s", dev_name(ad->dssdev));
+ if (!card->name)
+ return -ENOMEM;
+
card->owner = THIS_MODULE;
card->dai_link =
devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index f49bf02e5ec2..803818aabee9 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -29,21 +29,41 @@
static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
{
- pxa2xx_ac97_try_warm_reset(ac97);
+ pxa2xx_ac97_try_warm_reset();
- pxa2xx_ac97_finish_reset(ac97);
+ pxa2xx_ac97_finish_reset();
}
static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
{
- pxa2xx_ac97_try_cold_reset(ac97);
+ pxa2xx_ac97_try_cold_reset();
- pxa2xx_ac97_finish_reset(ac97);
+ pxa2xx_ac97_finish_reset();
+}
+
+static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ int ret;
+
+ ret = pxa2xx_ac97_read(ac97->num, reg);
+ if (ret < 0)
+ return 0;
+ else
+ return (unsigned short)(ret & 0xffff);
+}
+
+static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
+ unsigned short reg, unsigned short val)
+{
+ int ret;
+
+ ret = pxa2xx_ac97_write(ac97->num, reg, val);
}
static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
- .read = pxa2xx_ac97_read,
- .write = pxa2xx_ac97_write,
+ .read = pxa2xx_ac97_legacy_read,
+ .write = pxa2xx_ac97_legacy_write,
.warm_reset = pxa2xx_ac97_warm_reset,
.reset = pxa2xx_ac97_cold_reset,
};
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index e1945e1772cd..caf71aab8196 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -74,7 +74,6 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
data->i2s_port = cpu_dai->driver->id;
runtime->private_data = data;
- dma_ch = 0;
if (v->alloc_dma_channel)
dma_ch = v->alloc_dma_channel(drvdata, dir);
else
@@ -122,7 +121,6 @@ static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
struct lpass_pcm_data *data;
data = runtime->private_data;
- v = drvdata->variant;
drvdata->substream[data->dma_ch] = NULL;
if (v->free_dma_channel)
v->free_dma_channel(drvdata, data->dma_ch);
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 0513fe480353..d64fbbd50544 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -23,6 +23,7 @@
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
+#include <linux/i2c.h>
#include <linux/input.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -47,18 +48,7 @@ static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Speakers", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
- /* Input Lines */
- {"MIC", NULL, "Headset Mic"},
- {"DMIC1L", NULL, "Int Mic"},
- {"DMIC1R", NULL, "Int Mic"},
-
- /* Output Lines */
- {"Headphones", NULL, "HPL"},
- {"Headphones", NULL, "HPR"},
- {"Speakers", NULL, "Speaker"},
+ SND_SOC_DAPM_LINE("HDMI", NULL),
};
static const struct snd_kcontrol_new rockchip_controls[] = {
@@ -66,6 +56,7 @@ static const struct snd_kcontrol_new rockchip_controls[] = {
SOC_DAPM_PIN_SWITCH("Speakers"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("HDMI"),
};
static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
@@ -314,8 +305,6 @@ static struct snd_soc_card rockchip_sound_card = {
.owner = THIS_MODULE,
.dapm_widgets = rockchip_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
- .dapm_routes = rockchip_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
.controls = rockchip_controls,
.num_controls = ARRAY_SIZE(rockchip_controls),
};
@@ -329,15 +318,6 @@ enum {
DAILINK_RT5514_DSP,
};
-static const char * const dailink_compat[] = {
- [DAILINK_CDNDP] = "rockchip,rk3399-cdn-dp",
- [DAILINK_DA7219] = "dlg,da7219",
- [DAILINK_DMIC] = "dmic-codec",
- [DAILINK_MAX98357A] = "maxim,max98357a",
- [DAILINK_RT5514] = "realtek,rt5514-i2c",
- [DAILINK_RT5514_DSP] = "realtek,rt5514-spi",
-};
-
static const struct snd_soc_dai_link rockchip_dais[] = {
[DAILINK_CDNDP] = {
.name = "DP",
@@ -391,13 +371,117 @@ static const struct snd_soc_dai_link rockchip_dais[] = {
},
};
+static const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = {
+ /* Output */
+ {"HDMI", NULL, "TX"},
+};
+
+static const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = {
+ /* Output */
+ {"Headphones", NULL, "HPL"},
+ {"Headphones", NULL, "HPR"},
+
+ /* Input */
+ {"MIC", NULL, "Headset Mic"},
+};
+
+static const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = {
+ /* Input */
+ {"DMic", NULL, "Int Mic"},
+};
+
+static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = {
+ /* Output */
+ {"Speakers", NULL, "Speaker"},
+};
+
+static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = {
+ /* Input */
+ {"DMIC1L", NULL, "Int Mic"},
+ {"DMIC1R", NULL, "Int Mic"},
+};
+
+struct rockchip_sound_route {
+ const struct snd_soc_dapm_route *routes;
+ int num_routes;
+};
+
+static const struct rockchip_sound_route rockchip_routes[] = {
+ [DAILINK_CDNDP] = {
+ .routes = rockchip_sound_cdndp_routes,
+ .num_routes = ARRAY_SIZE(rockchip_sound_cdndp_routes),
+ },
+ [DAILINK_DA7219] = {
+ .routes = rockchip_sound_da7219_routes,
+ .num_routes = ARRAY_SIZE(rockchip_sound_da7219_routes),
+ },
+ [DAILINK_DMIC] = {
+ .routes = rockchip_sound_dmic_routes,
+ .num_routes = ARRAY_SIZE(rockchip_sound_dmic_routes),
+ },
+ [DAILINK_MAX98357A] = {
+ .routes = rockchip_sound_max98357a_routes,
+ .num_routes = ARRAY_SIZE(rockchip_sound_max98357a_routes),
+ },
+ [DAILINK_RT5514] = {
+ .routes = rockchip_sound_rt5514_routes,
+ .num_routes = ARRAY_SIZE(rockchip_sound_rt5514_routes),
+ },
+ [DAILINK_RT5514_DSP] = {},
+};
+
+struct dailink_match_data {
+ const char *compatible;
+ struct bus_type *bus_type;
+};
+
+static const struct dailink_match_data dailink_match[] = {
+ [DAILINK_CDNDP] = {
+ .compatible = "rockchip,rk3399-cdn-dp",
+ },
+ [DAILINK_DA7219] = {
+ .compatible = "dlg,da7219",
+ },
+ [DAILINK_DMIC] = {
+ .compatible = "dmic-codec",
+ },
+ [DAILINK_MAX98357A] = {
+ .compatible = "maxim,max98357a",
+ },
+ [DAILINK_RT5514] = {
+ .compatible = "realtek,rt5514",
+ .bus_type = &i2c_bus_type,
+ },
+ [DAILINK_RT5514_DSP] = {
+ .compatible = "realtek,rt5514",
+ .bus_type = &spi_bus_type,
+ },
+};
+
+static int of_dev_node_match(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
static int rockchip_sound_codec_node_match(struct device_node *np_codec)
{
+ struct device *dev;
int i;
- for (i = 0; i < ARRAY_SIZE(dailink_compat); i++) {
- if (of_device_is_compatible(np_codec, dailink_compat[i]))
- return i;
+ for (i = 0; i < ARRAY_SIZE(dailink_match); i++) {
+ if (!of_device_is_compatible(np_codec,
+ dailink_match[i].compatible))
+ continue;
+
+ if (dailink_match[i].bus_type) {
+ dev = bus_find_device(dailink_match[i].bus_type, NULL,
+ np_codec, of_dev_node_match);
+ if (!dev)
+ continue;
+ put_device(dev);
+ }
+
+ return i;
}
return -1;
}
@@ -408,16 +492,28 @@ static int rockchip_sound_of_parse_dais(struct device *dev,
struct device_node *np_cpu, *np_cpu0, *np_cpu1;
struct device_node *np_codec;
struct snd_soc_dai_link *dai;
+ struct snd_soc_dapm_route *routes;
int i, index;
+ int num_routes;
card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
GFP_KERNEL);
if (!card->dai_link)
return -ENOMEM;
+ num_routes = 0;
+ for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++)
+ num_routes += rockchip_routes[i].num_routes;
+ routes = devm_kzalloc(dev, num_routes * sizeof(*routes),
+ GFP_KERNEL);
+ if (!routes)
+ return -ENOMEM;
+ card->dapm_routes = routes;
+
np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);
+ card->num_dapm_routes = 0;
card->num_links = 0;
for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
np_codec = of_parse_phandle(dev->of_node,
@@ -445,6 +541,17 @@ static int rockchip_sound_of_parse_dais(struct device *dev,
dai->codec_of_node = np_codec;
dai->platform_of_node = np_cpu;
dai->cpu_of_node = np_cpu;
+
+ if (card->num_dapm_routes + rockchip_routes[index].num_routes >
+ num_routes) {
+ dev_err(dev, "Too many routes\n");
+ return -EINVAL;
+ }
+
+ memcpy(routes + card->num_dapm_routes,
+ rockchip_routes[index].routes,
+ rockchip_routes[index].num_routes * sizeof(*routes));
+ card->num_dapm_routes += rockchip_routes[index].num_routes;
}
return 0;
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index b6590467fd14..908211e1d6fc 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -692,7 +692,6 @@ static int rockchip_i2s_remove(struct platform_device *pdev)
if (!pm_runtime_status_suspended(&pdev->dev))
i2s_runtime_suspend(&pdev->dev);
- clk_disable_unprepare(i2s->mclk);
clk_disable_unprepare(i2s->hclk);
return 0;
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 10a4da06c0a1..233f1c9a4b6c 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -552,8 +552,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
}
ret = clk_prepare_enable(i2s->op_clk);
- if (ret)
+ if (ret) {
+ clk_put(i2s->op_clk);
+ i2s->op_clk = NULL;
goto err;
+ }
i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
/* Over-ride the other's */
@@ -1096,6 +1099,7 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev,
i2s->pdev = pdev;
i2s->pri_dai = NULL;
i2s->sec_dai = NULL;
+ i2s->i2s_dai_drv.id = 1;
i2s->i2s_dai_drv.symmetric_rates = 1;
i2s->i2s_dai_drv.probe = samsung_i2s_dai_probe;
i2s->i2s_dai_drv.remove = samsung_i2s_dai_remove;
@@ -1108,10 +1112,13 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev,
i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS;
if (!sec) {
+ i2s->i2s_dai_drv.name = SAMSUNG_I2S_DAI;
i2s->i2s_dai_drv.capture.channels_min = 1;
i2s->i2s_dai_drv.capture.channels_max = 2;
i2s->i2s_dai_drv.capture.rates = i2s_dai_data->pcm_rates;
i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
+ } else {
+ i2s->i2s_dai_drv.name = SAMSUNG_I2S_DAI_SEC;
}
return i2s;
}
@@ -1285,6 +1292,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
}
}
}
+ quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pri_dai->addr = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h
index 21ff24e930db..79781de2f247 100644
--- a/sound/soc/samsung/i2s.h
+++ b/sound/soc/samsung/i2s.h
@@ -13,6 +13,9 @@
#ifndef __SND_SOC_SAMSUNG_I2S_H
#define __SND_SOC_SAMSUNG_I2S_H
+#define SAMSUNG_I2S_DAI "samsung-i2s"
+#define SAMSUNG_I2S_DAI_SEC "samsung-i2s-sec"
+
#define SAMSUNG_I2S_DIV_BCLK 1
#define SAMSUNG_I2S_RCLKSRC_0 0
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index 68698f3d72f9..a55d18703fe7 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -383,6 +383,7 @@ static struct snd_soc_dai_link tm2_dai_links[] = {
{
.name = "WM5110 AIF1",
.stream_name = "HiFi Primary",
+ .cpu_dai_name = SAMSUNG_I2S_DAI,
.codec_dai_name = "wm5110-aif1",
.ops = &tm2_aif1_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
@@ -390,6 +391,7 @@ static struct snd_soc_dai_link tm2_dai_links[] = {
}, {
.name = "WM5110 Voice",
.stream_name = "Voice call",
+ .cpu_dai_name = SAMSUNG_I2S_DAI,
.codec_dai_name = "wm5110-aif2",
.ops = &tm2_aif2_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
@@ -398,6 +400,7 @@ static struct snd_soc_dai_link tm2_dai_links[] = {
}, {
.name = "WM5110 BT",
.stream_name = "Bluetooth",
+ .cpu_dai_name = SAMSUNG_I2S_DAI,
.codec_dai_name = "wm5110-aif3",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
@@ -436,8 +439,7 @@ static int tm2_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(card, priv);
card->dev = dev;
- priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias",
- GPIOF_OUT_INIT_LOW);
+ priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias", GPIOD_OUT_HIGH);
if (IS_ERR(priv->gpio_mic_bias)) {
dev_err(dev, "Failed to get mic bias gpio\n");
return PTR_ERR(priv->gpio_mic_bias);
@@ -477,7 +479,6 @@ static int tm2_probe(struct platform_device *pdev)
}
for (i = 0; i < card->num_links; i++) {
- card->dai_link[i].cpu_dai_name = NULL;
card->dai_link[i].cpu_name = NULL;
card->dai_link[i].platform_name = NULL;
card->dai_link[i].codec_of_node = codec_dai_node;
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 6d3c7706d93f..c3aaf4788557 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1932,14 +1932,9 @@ static int fsi_probe(struct platform_device *pdev)
core = NULL;
if (np) {
- const struct of_device_id *of_id;
-
- of_id = of_match_device(fsi_of_match, &pdev->dev);
- if (of_id) {
- core = of_id->data;
- fsi_of_parse("fsia", np, &info.port_a, &pdev->dev);
- fsi_of_parse("fsib", np, &info.port_b, &pdev->dev);
- }
+ core = of_device_get_match_data(&pdev->dev);
+ fsi_of_parse("fsia", np, &info.port_a, &pdev->dev);
+ fsi_of_parse("fsib", np, &info.port_b, &pdev->dev);
} else {
const struct platform_device_id *id_entry = pdev->id_entry;
if (id_entry)
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 938baff86ef2..8ddb08714faa 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -44,7 +44,6 @@ struct rsnd_adg {
#define LRCLK_ASYNC (1 << 0)
#define AUDIO_OUT_48 (1 << 1)
-#define adg_mode_flags(adg) (adg->flags)
#define for_each_rsnd_clk(pos, adg, i) \
for (i = 0; \
@@ -58,6 +57,13 @@ struct rsnd_adg {
i++)
#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
+static const char * const clk_name[] = {
+ [CLKA] = "clk_a",
+ [CLKB] = "clk_b",
+ [CLKC] = "clk_c",
+ [CLKI] = "clk_i",
+};
+
static u32 rsnd_adg_calculate_rbgx(unsigned long div)
{
int i, ratio;
@@ -280,6 +286,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+ struct device *dev = rsnd_priv_to_dev(priv);
int id = rsnd_mod_id(ssi_mod);
int shift = (id % 4) * 8;
u32 mask = 0xFF << shift;
@@ -306,12 +313,13 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
break;
}
+
+ dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
}
int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
- struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
int i;
int sel_table[] = {
@@ -321,8 +329,6 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
[CLKI] = 0x0,
};
- dev_dbg(dev, "request clock = %d\n", rate);
-
/*
* find suitable clock from
* AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
@@ -366,8 +372,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
rsnd_adg_set_ssi_clk(ssi_mod, data);
- if (adg_mode_flags(adg) & LRCLK_ASYNC) {
- if (adg_mode_flags(adg) & AUDIO_OUT_48)
+ if (rsnd_flags_has(adg, LRCLK_ASYNC)) {
+ if (rsnd_flags_has(adg, AUDIO_OUT_48))
ckr = 0x80000000;
} else {
if (0 == (rate % 8000))
@@ -378,9 +384,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
rsnd_mod_write(adg_mod, BRRA, adg->rbga);
rsnd_mod_write(adg_mod, BRRB, adg->rbgb);
- dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
- rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
- data, rate);
+ dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
+ (ckr) ? 'B' : 'A',
+ (ckr) ? adg->rbgb_rate_for_48khz :
+ adg->rbga_rate_for_441khz);
return 0;
}
@@ -409,21 +416,12 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
{
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
- static const char * const clk_name[] = {
- [CLKA] = "clk_a",
- [CLKB] = "clk_b",
- [CLKC] = "clk_c",
- [CLKI] = "clk_i",
- };
int i;
for (i = 0; i < CLKMAX; i++) {
clk = devm_clk_get(dev, clk_name[i]);
adg->clk[i] = IS_ERR(clk) ? NULL : clk;
}
-
- for_each_rsnd_clk(clk, adg, i)
- dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
}
static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
@@ -479,10 +477,10 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
}
if (req_rate[0] % 48000 == 0)
- adg->flags = AUDIO_OUT_48;
+ rsnd_flags_set(adg, AUDIO_OUT_48);
if (of_get_property(np, "clkout-lr-asynchronous", NULL))
- adg->flags = LRCLK_ASYNC;
+ rsnd_flags_set(adg, LRCLK_ASYNC);
/*
* This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
@@ -512,7 +510,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
adg->rbga_rate_for_441khz = rate / div;
ckr |= brg_table[i] << 20;
if (req_441kHz_rate &&
- !(adg_mode_flags(adg) & AUDIO_OUT_48))
+ !rsnd_flags_has(adg, AUDIO_OUT_48))
parent_clk_name = __clk_get_name(clk);
}
}
@@ -528,7 +526,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
adg->rbgb_rate_for_48khz = rate / div;
ckr |= brg_table[i] << 16;
if (req_48kHz_rate &&
- (adg_mode_flags(adg) & AUDIO_OUT_48))
+ rsnd_flags_has(adg, AUDIO_OUT_48))
parent_clk_name = __clk_get_name(clk);
}
}
@@ -572,12 +570,35 @@ rsnd_adg_get_clkout_end:
adg->ckr = ckr;
adg->rbga = rbga;
adg->rbgb = rbgb;
+}
+
+#ifdef DEBUG
+static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct clk *clk;
+ int i;
+
+ for_each_rsnd_clk(clk, adg, i)
+ dev_dbg(dev, "%s : %p : %ld\n",
+ clk_name[i], clk, clk_get_rate(clk));
- for_each_rsnd_clkout(clk, adg, i)
- dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk));
dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
- ckr, rbga, rbgb);
+ adg->ckr, adg->rbga, adg->rbgb);
+ dev_dbg(dev, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz);
+ dev_dbg(dev, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz);
+
+ /*
+ * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
+ * by BRGCKR::BRGCKR_31
+ */
+ for_each_rsnd_clkout(clk, adg, i)
+ dev_dbg(dev, "clkout %d : %p : %ld\n", i,
+ clk, clk_get_rate(clk));
}
+#else
+#define rsnd_adg_clk_dbg_info(priv, adg)
+#endif
int rsnd_adg_probe(struct rsnd_priv *priv)
{
@@ -596,6 +617,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
rsnd_adg_get_clkin(priv, adg);
rsnd_adg_get_clkout(priv, adg);
+ rsnd_adg_clk_dbg_info(priv, adg);
priv->adg = adg;
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 107133297e8d..c70eb2097816 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -121,14 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
}
}
-char *rsnd_mod_name(struct rsnd_mod *mod)
-{
- if (!mod || !mod->ops)
- return "unknown";
-
- return mod->ops->name;
-}
-
struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
@@ -172,8 +164,7 @@ int rsnd_mod_init(struct rsnd_priv *priv,
void rsnd_mod_quit(struct rsnd_mod *mod)
{
- if (mod->clk)
- clk_unprepare(mod->clk);
+ clk_unprepare(mod->clk);
mod->clk = NULL;
}
@@ -200,7 +191,10 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
int rsnd_io_is_working(struct rsnd_dai_stream *io)
{
/* see rsnd_dai_stream_init/quit() */
- return !!io->substream;
+ if (io->substream)
+ return snd_pcm_running(io->substream);
+
+ return 0;
}
int rsnd_runtime_channel_original(struct rsnd_dai_stream *io)
@@ -407,11 +401,9 @@ struct rsnd_mod *rsnd_mod_next(int *iterator,
for (; *iterator < max; (*iterator)++) {
type = (array) ? array[*iterator] : *iterator;
- mod = io->mod[type];
- if (!mod)
- continue;
-
- return mod;
+ mod = rsnd_io_to_mod(io, type);
+ if (mod)
+ return mod;
}
return NULL;
@@ -1242,6 +1234,33 @@ struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg)
return &cfg->cfg;
}
+const char * const volume_ramp_rate[] = {
+ "128 dB/1 step", /* 00000 */
+ "64 dB/1 step", /* 00001 */
+ "32 dB/1 step", /* 00010 */
+ "16 dB/1 step", /* 00011 */
+ "8 dB/1 step", /* 00100 */
+ "4 dB/1 step", /* 00101 */
+ "2 dB/1 step", /* 00110 */
+ "1 dB/1 step", /* 00111 */
+ "0.5 dB/1 step", /* 01000 */
+ "0.25 dB/1 step", /* 01001 */
+ "0.125 dB/1 step", /* 01010 = VOLUME_RAMP_MAX_MIX */
+ "0.125 dB/2 steps", /* 01011 */
+ "0.125 dB/4 steps", /* 01100 */
+ "0.125 dB/8 steps", /* 01101 */
+ "0.125 dB/16 steps", /* 01110 */
+ "0.125 dB/32 steps", /* 01111 */
+ "0.125 dB/64 steps", /* 10000 */
+ "0.125 dB/128 steps", /* 10001 */
+ "0.125 dB/256 steps", /* 10010 */
+ "0.125 dB/512 steps", /* 10011 */
+ "0.125 dB/1024 steps", /* 10100 */
+ "0.125 dB/2048 steps", /* 10101 */
+ "0.125 dB/4096 steps", /* 10110 */
+ "0.125 dB/8192 steps", /* 10111 = VOLUME_RAMP_MAX_DVC */
+};
+
int rsnd_kctrl_new(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd,
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index e7f53f44165d..d201d551866d 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -81,8 +81,11 @@ struct rsnd_ctu {
struct rsnd_kctrl_cfg_m sv3;
struct rsnd_kctrl_cfg_s reset;
int channels;
+ u32 flags;
};
+#define KCTRL_INITIALIZED (1 << 0)
+
#define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
#define for_each_rsnd_ctu(pos, priv, i) \
for ((i) = 0; \
@@ -130,7 +133,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
int i;
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
- u32 val = ctu->pass.val[i];
+ u32 val = rsnd_kctrl_valm(ctu->pass, i);
cpmdr |= val << (28 - (i * 4));
@@ -147,44 +150,44 @@ 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, ctu->sv0.val[0]);
- rsnd_mod_write(mod, CTU_SV01R, ctu->sv0.val[1]);
- rsnd_mod_write(mod, CTU_SV02R, ctu->sv0.val[2]);
- rsnd_mod_write(mod, CTU_SV03R, ctu->sv0.val[3]);
- rsnd_mod_write(mod, CTU_SV04R, ctu->sv0.val[4]);
- rsnd_mod_write(mod, CTU_SV05R, ctu->sv0.val[5]);
- rsnd_mod_write(mod, CTU_SV06R, ctu->sv0.val[6]);
- rsnd_mod_write(mod, CTU_SV07R, ctu->sv0.val[7]);
+ 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, ctu->sv1.val[0]);
- rsnd_mod_write(mod, CTU_SV11R, ctu->sv1.val[1]);
- rsnd_mod_write(mod, CTU_SV12R, ctu->sv1.val[2]);
- rsnd_mod_write(mod, CTU_SV13R, ctu->sv1.val[3]);
- rsnd_mod_write(mod, CTU_SV14R, ctu->sv1.val[4]);
- rsnd_mod_write(mod, CTU_SV15R, ctu->sv1.val[5]);
- rsnd_mod_write(mod, CTU_SV16R, ctu->sv1.val[6]);
- rsnd_mod_write(mod, CTU_SV17R, ctu->sv1.val[7]);
+ 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, ctu->sv2.val[0]);
- rsnd_mod_write(mod, CTU_SV21R, ctu->sv2.val[1]);
- rsnd_mod_write(mod, CTU_SV22R, ctu->sv2.val[2]);
- rsnd_mod_write(mod, CTU_SV23R, ctu->sv2.val[3]);
- rsnd_mod_write(mod, CTU_SV24R, ctu->sv2.val[4]);
- rsnd_mod_write(mod, CTU_SV25R, ctu->sv2.val[5]);
- rsnd_mod_write(mod, CTU_SV26R, ctu->sv2.val[6]);
- rsnd_mod_write(mod, CTU_SV27R, ctu->sv2.val[7]);
+ 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, ctu->sv3.val[0]);
- rsnd_mod_write(mod, CTU_SV31R, ctu->sv3.val[1]);
- rsnd_mod_write(mod, CTU_SV32R, ctu->sv3.val[2]);
- rsnd_mod_write(mod, CTU_SV33R, ctu->sv3.val[3]);
- rsnd_mod_write(mod, CTU_SV34R, ctu->sv3.val[4]);
- rsnd_mod_write(mod, CTU_SV35R, ctu->sv3.val[5]);
- rsnd_mod_write(mod, CTU_SV36R, ctu->sv3.val[6]);
- rsnd_mod_write(mod, CTU_SV37R, ctu->sv3.val[7]);
+ 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));
}
rsnd_mod_write(mod, CTU_CTUIR, 0);
@@ -196,17 +199,17 @@ static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
int i;
- if (!ctu->reset.val)
+ if (!rsnd_kctrl_vals(ctu->reset))
return;
for (i = 0; i < RSND_MAX_CHANNELS; i++) {
- ctu->pass.val[i] = 0;
- ctu->sv0.val[i] = 0;
- ctu->sv1.val[i] = 0;
- ctu->sv2.val[i] = 0;
- ctu->sv3.val[i] = 0;
+ 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;
}
- ctu->reset.val = 0;
+ rsnd_kctrl_vals(ctu->reset) = 0;
}
static int rsnd_ctu_init(struct rsnd_mod *mod,
@@ -277,6 +280,9 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
int ret;
+ if (rsnd_flags_has(ctu, KCTRL_INITIALIZED))
+ return 0;
+
/* CTU Pass */
ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
rsnd_kctrl_accept_anytime,
@@ -326,6 +332,8 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
rsnd_ctu_value_reset,
&ctu->reset, 1);
+ rsnd_flags_set(ctu, KCTRL_INITIALIZED);
+
return ret;
}
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 041ec1080d52..fd557abfe390 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -60,6 +60,14 @@ struct rsnd_dma_ctrl {
#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
+/* for DEBUG */
+static struct rsnd_mod_ops mem_ops = {
+ .name = "mem",
+};
+
+static struct rsnd_mod mem = {
+};
+
/*
* Audio DMAC
*/
@@ -211,11 +219,9 @@ static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod,
dma->mod_from,
dma->mod_to);
if (IS_ERR_OR_NULL(dmaen->chan)) {
- int ret = PTR_ERR(dmaen->chan);
-
dmaen->chan = NULL;
dev_err(dev, "can't get dma channel\n");
- return ret;
+ return -EIO;
}
return 0;
@@ -747,20 +753,22 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
rsnd_mod_name(this), rsnd_mod_id(this));
for (i = 0; i <= idx; i++) {
dev_dbg(dev, " %s[%d]%s\n",
- rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
- (mod[i] == *mod_from) ? " from" :
- (mod[i] == *mod_to) ? " to" : "");
+ 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" : "");
}
}
-int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
- struct rsnd_mod **dma_mod)
+static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+ struct rsnd_mod **dma_mod)
{
struct rsnd_mod *mod_from = NULL;
struct rsnd_mod *mod_to = NULL;
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_dma *dma;
struct rsnd_mod_ops *ops;
enum rsnd_mod_type type;
int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma,
@@ -800,40 +808,47 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
type = RSND_MOD_AUDMA;
}
- if (!(*dma_mod)) {
- struct rsnd_dma *dma;
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
- dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
- if (!dma)
- return -ENOMEM;
+ *dma_mod = rsnd_mod_get(dma);
- *dma_mod = rsnd_mod_get(dma);
+ ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
+ rsnd_mod_get_status, type, dma_id);
+ if (ret < 0)
+ return ret;
- ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
- rsnd_mod_get_status, 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),
+ 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));
- dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n",
- rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod),
- rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
- rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
+ ret = attach(io, dma, mod_from, mod_to);
+ if (ret < 0)
+ return ret;
+
+ dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
+ dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0);
+ dma->mod_from = mod_from;
+ dma->mod_to = mod_to;
+
+ return 0;
+}
+
+int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+ struct rsnd_mod **dma_mod)
+{
+ if (!(*dma_mod)) {
+ int ret = rsnd_dma_alloc(io, mod, dma_mod);
- ret = attach(io, dma, mod_from, mod_to);
if (ret < 0)
return ret;
-
- dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
- dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0);
- dma->mod_from = mod_from;
- dma->mod_to = mod_to;
}
- ret = rsnd_dai_connect(*dma_mod, io, type);
- if (ret < 0)
- return ret;
-
- return 0;
+ return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type);
}
int rsnd_dma_probe(struct rsnd_priv *priv)
@@ -866,5 +881,6 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
priv->dma = dmac;
- return 0;
+ /* dummy mem mod for debug */
+ return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, NULL, 0, 0);
}
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 1743ade3cc55..dbe54f024d68 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -44,8 +44,11 @@ struct rsnd_dvc {
struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
+ u32 flags;
};
+#define KCTRL_INITIALIZED (1 << 0)
+
#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
@@ -58,33 +61,6 @@ struct rsnd_dvc {
((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \
i++)
-static const char * const dvc_ramp_rate[] = {
- "128 dB/1 step", /* 00000 */
- "64 dB/1 step", /* 00001 */
- "32 dB/1 step", /* 00010 */
- "16 dB/1 step", /* 00011 */
- "8 dB/1 step", /* 00100 */
- "4 dB/1 step", /* 00101 */
- "2 dB/1 step", /* 00110 */
- "1 dB/1 step", /* 00111 */
- "0.5 dB/1 step", /* 01000 */
- "0.25 dB/1 step", /* 01001 */
- "0.125 dB/1 step", /* 01010 */
- "0.125 dB/2 steps", /* 01011 */
- "0.125 dB/4 steps", /* 01100 */
- "0.125 dB/8 steps", /* 01101 */
- "0.125 dB/16 steps", /* 01110 */
- "0.125 dB/32 steps", /* 01111 */
- "0.125 dB/64 steps", /* 10000 */
- "0.125 dB/128 steps", /* 10001 */
- "0.125 dB/256 steps", /* 10010 */
- "0.125 dB/512 steps", /* 10011 */
- "0.125 dB/1024 steps", /* 10100 */
- "0.125 dB/2048 steps", /* 10101 */
- "0.125 dB/4096 steps", /* 10110 */
- "0.125 dB/8192 steps", /* 10111 */
-};
-
static void rsnd_dvc_activation(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, DVC_SWRSR, 0);
@@ -97,8 +73,9 @@ static void rsnd_dvc_halt(struct rsnd_mod *mod)
rsnd_mod_write(mod, DVC_SWRSR, 0);
}
-#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val)
-#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13))
+#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \
+ rsnd_kctrl_vals(dvc->rdown))
+#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13))
static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
@@ -108,12 +85,12 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
int i;
/* Enable Ramp */
- if (dvc->ren.val)
+ if (rsnd_kctrl_vals(dvc->ren))
for (i = 0; i < RSND_MAX_CHANNELS; i++)
- val[i] = dvc->volume.cfg.max;
+ val[i] = rsnd_kctrl_max(dvc->volume);
else
for (i = 0; i < RSND_MAX_CHANNELS; i++)
- val[i] = dvc->volume.val[i];
+ val[i] = rsnd_kctrl_valm(dvc->volume, i);
/* Enable Digital Volume */
rsnd_mod_write(mod, DVC_VOL0R, val[0]);
@@ -143,7 +120,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
dvucr |= 0x101;
/* Enable Ramp */
- if (dvc->ren.val) {
+ if (rsnd_kctrl_vals(dvc->ren)) {
dvucr |= 0x10;
/*
@@ -185,10 +162,10 @@ static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
u32 vrdbr = 0;
int i;
- for (i = 0; i < dvc->mute.cfg.size; i++)
- zcmcr |= (!!dvc->mute.cfg.val[i]) << i;
+ for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++)
+ zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i;
- if (dvc->ren.val) {
+ if (rsnd_kctrl_vals(dvc->ren)) {
vrpdr = rsnd_dvc_get_vrpdr(dvc);
vrdbr = rsnd_dvc_get_vrdbr(dvc);
}
@@ -254,6 +231,9 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
int channels = rsnd_rdai_channels_get(rdai);
int ret;
+ if (rsnd_flags_has(dvc, KCTRL_INITIALIZED))
+ return 0;
+
/* Volume */
ret = rsnd_kctrl_new_m(mod, io, rtd,
is_play ?
@@ -292,7 +272,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
rsnd_kctrl_accept_anytime,
rsnd_dvc_volume_update,
&dvc->rup,
- dvc_ramp_rate);
+ volume_ramp_rate,
+ VOLUME_RAMP_MAX_DVC);
if (ret < 0)
return ret;
@@ -302,11 +283,14 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
rsnd_kctrl_accept_anytime,
rsnd_dvc_volume_update,
&dvc->rdown,
- dvc_ramp_rate);
+ volume_ramp_rate,
+ VOLUME_RAMP_MAX_DVC);
if (ret < 0)
return ret;
+ rsnd_flags_set(dvc, KCTRL_INITIALIZED);
+
return 0;
}
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 6c4826c189a4..7998380766f6 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -7,6 +7,33 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
+/*
+ * CTUn MIXn
+ * +------+ +------+
+ * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| ->
+ * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| ->
+ * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| ->
+ * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| ->
+ * +------+ +------+
+ *
+ * ex)
+ * DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
+ * DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
+ *
+ * MIX Volume
+ * amixer set "MIX",0 100% // DAI0 Volume
+ * amixer set "MIX",1 100% // DAI1 Volume
+ *
+ * Volume Ramp
+ * amixer set "MIX Ramp Up Rate" "0.125 dB/1 step"
+ * amixer set "MIX Ramp Down Rate" "4 dB/1 step"
+ * amixer set "MIX Ramp" on
+ * aplay xxx.wav &
+ * amixer set "MIX",0 80% // DAI0 Volume Down
+ * amixer set "MIX",1 100% // DAI1 Volume Up
+ */
+
#include "rsnd.h"
#define MIX_NAME_SIZE 16
@@ -14,8 +41,27 @@
struct rsnd_mix {
struct rsnd_mod mod;
+ struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
+ struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
+ struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
+ struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
+ struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
+ struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
+ struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */
+ u32 flags;
};
+#define ONCE_KCTRL_INITIALIZED (1 << 0)
+#define HAS_VOLA (1 << 1)
+#define HAS_VOLB (1 << 2)
+#define HAS_VOLC (1 << 3)
+#define HAS_VOLD (1 << 4)
+
+#define VOL_MAX 0x3ff
+
+#define rsnd_mod_to_mix(_mod) \
+ container_of((_mod), struct rsnd_mix, mod)
+
#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
#define rsnd_mix_nr(priv) ((priv)->mix_nr)
#define for_each_rsnd_mix(pos, priv, i) \
@@ -36,26 +82,43 @@ static void rsnd_mix_halt(struct rsnd_mod *mod)
rsnd_mod_write(mod, MIX_SWRSR, 0);
}
+#define rsnd_mix_get_vol(mix, X) \
+ rsnd_flags_has(mix, HAS_VOL##X) ? \
+ (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
- rsnd_mod_write(mod, MIX_MDBAR, 0);
- rsnd_mod_write(mod, MIX_MDBBR, 0);
- rsnd_mod_write(mod, MIX_MDBCR, 0);
- rsnd_mod_write(mod, MIX_MDBDR, 0);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+ u32 volA = rsnd_mix_get_vol(mix, A);
+ u32 volB = rsnd_mix_get_vol(mix, B);
+ u32 volC = rsnd_mix_get_vol(mix, C);
+ u32 volD = rsnd_mix_get_vol(mix, D);
+
+ dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
+ volA, volB, volC, volD);
+
+ rsnd_mod_write(mod, MIX_MDBAR, volA);
+ rsnd_mod_write(mod, MIX_MDBBR, volB);
+ rsnd_mod_write(mod, MIX_MDBCR, volC);
+ rsnd_mod_write(mod, MIX_MDBDR, volD);
}
static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
+ struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+
rsnd_mod_write(mod, MIX_MIXIR, 1);
/* General Information */
rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
/* volume step */
- rsnd_mod_write(mod, MIX_MIXMR, 0);
- rsnd_mod_write(mod, MIX_MVPDR, 0);
+ rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
+ rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
+ rsnd_kctrl_vals(mix->rdw));
/* common volume parameter */
rsnd_mix_volume_parameter(io, mod);
@@ -109,11 +172,94 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
return 0;
}
+static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+ struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+ struct rsnd_kctrl_cfg_s *volume;
+ int ret;
+
+ switch (rsnd_mod_id(src_mod)) {
+ case 3:
+ case 6: /* MDBAR */
+ volume = &mix->volumeA;
+ rsnd_flags_set(mix, HAS_VOLA);
+ break;
+ case 4:
+ case 9: /* MDBBR */
+ volume = &mix->volumeB;
+ rsnd_flags_set(mix, HAS_VOLB);
+ break;
+ case 0:
+ case 1: /* MDBCR */
+ volume = &mix->volumeC;
+ rsnd_flags_set(mix, HAS_VOLC);
+ break;
+ case 2:
+ case 5: /* MDBDR */
+ volume = &mix->volumeD;
+ rsnd_flags_set(mix, HAS_VOLD);
+ break;
+ default:
+ dev_err(dev, "unknown SRC is connected\n");
+ return -EINVAL;
+ }
+
+ /* Volume */
+ ret = rsnd_kctrl_new_s(mod, io, rtd,
+ "MIX Playback Volume",
+ rsnd_kctrl_accept_anytime,
+ rsnd_mix_volume_update,
+ volume, VOL_MAX);
+ if (ret < 0)
+ return ret;
+ rsnd_kctrl_vals(*volume) = VOL_MAX;
+
+ if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
+ return ret;
+
+ /* Ramp */
+ ret = rsnd_kctrl_new_s(mod, io, rtd,
+ "MIX Ramp Switch",
+ rsnd_kctrl_accept_anytime,
+ rsnd_mix_volume_update,
+ &mix->ren, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_kctrl_new_e(mod, io, rtd,
+ "MIX Ramp Up Rate",
+ rsnd_kctrl_accept_anytime,
+ rsnd_mix_volume_update,
+ &mix->rup,
+ volume_ramp_rate,
+ VOLUME_RAMP_MAX_MIX);
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_kctrl_new_e(mod, io, rtd,
+ "MIX Ramp Down Rate",
+ rsnd_kctrl_accept_anytime,
+ rsnd_mix_volume_update,
+ &mix->rdw,
+ volume_ramp_rate,
+ VOLUME_RAMP_MAX_MIX);
+
+ rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);
+
+ return ret;
+}
+
static struct rsnd_mod_ops rsnd_mix_ops = {
.name = MIX_NAME,
.probe = rsnd_mix_probe_,
.init = rsnd_mix_init,
.quit = rsnd_mix_quit,
+ .pcm_new = rsnd_mix_pcm_new,
};
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index c5de71f2dc8c..57cd2bc773c2 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -355,8 +355,9 @@ struct rsnd_mod {
#define __rsnd_mod_call_nolock_start 0
#define __rsnd_mod_call_nolock_stop 1
-#define rsnd_mod_to_priv(mod) ((mod)->priv)
-#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
+#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)
@@ -371,7 +372,6 @@ int rsnd_mod_init(struct rsnd_priv *priv,
enum rsnd_mod_type type,
int id);
void rsnd_mod_quit(struct rsnd_mod *mod);
-char *rsnd_mod_name(struct rsnd_mod *mod);
struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
struct rsnd_mod *mod);
void rsnd_mod_interrupt(struct rsnd_mod *mod,
@@ -601,6 +601,10 @@ struct rsnd_priv {
#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
+#define rsnd_flags_has(p, f) ((p)->flags & (f))
+#define rsnd_flags_set(p, f) ((p)->flags |= (f))
+#define rsnd_flags_del(p, f) ((p)->flags &= ~(f))
+
/*
* rsnd_kctrl
*/
@@ -627,6 +631,10 @@ struct rsnd_kctrl_cfg_s {
struct rsnd_kctrl_cfg cfg;
u32 val;
};
+#define rsnd_kctrl_size(x) ((x).cfg.size)
+#define rsnd_kctrl_max(x) ((x).cfg.max)
+#define rsnd_kctrl_valm(x, i) ((x).val[i]) /* = (x).cfg.val[i] */
+#define rsnd_kctrl_vals(x) ((x).val) /* = (x).cfg.val[0] */
int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io);
int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io);
@@ -652,9 +660,13 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
NULL, 1, max)
-#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts) \
+#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts, size) \
rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
- texts, 1, ARRAY_SIZE(texts))
+ texts, 1, size)
+
+extern const char * const volume_ramp_rate[];
+#define VOLUME_RAMP_MAX_DVC (0x17 + 1)
+#define VOLUME_RAMP_MAX_MIX (0x0a + 1)
/*
* R-Car SSI
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index fffc07e72627..fece1e5f582f 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -101,9 +101,6 @@ struct rsnd_ssi {
#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_ssi_flags_has(p, f) ((p)->flags & f)
-#define rsnd_ssi_flags_set(p, f) ((p)->flags |= f)
-#define rsnd_ssi_flags_del(p, f) ((p)->flags = ((p)->flags & ~f))
#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
#define rsnd_ssi_is_multi_slave(mod, io) \
(rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod)))
@@ -116,10 +113,10 @@ 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_ssi_flags_has(ssi, RSND_SSI_HDMI0))
+ if (rsnd_flags_has(ssi, RSND_SSI_HDMI0))
return RSND_SSI_HDMI_PORT0;
- if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI1))
+ if (rsnd_flags_has(ssi, RSND_SSI_HDMI1))
return RSND_SSI_HDMI_PORT1;
return 0;
@@ -134,7 +131,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
if (!rsnd_ssi_is_dma_mode(mod))
return 0;
- if (!(rsnd_ssi_flags_has(ssi, RSND_SSI_NO_BUSIF)))
+ if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF)))
use_busif = 1;
if (rsnd_io_to_mod_src(io))
use_busif = 1;
@@ -198,10 +195,15 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
{
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+ u32 mods;
- return rsnd_ssi_multi_slaves_runtime(io) |
- 1 << rsnd_mod_id(ssi_mod) |
- 1 << rsnd_mod_id(ssi_parent_mod);
+ mods = rsnd_ssi_multi_slaves_runtime(io) |
+ 1 << rsnd_mod_id(ssi_mod);
+
+ if (ssi_parent_mod)
+ mods |= 1 << rsnd_mod_id(ssi_parent_mod);
+
+ return mods;
}
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
@@ -601,15 +603,18 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
if (rsnd_ssi_is_parent(mod, io))
return 0;
- /*
- * disable all IRQ,
- * and, wait all data was sent
- */
cr = ssi->cr_own |
ssi->cr_clk;
- rsnd_mod_write(mod, SSICR, cr | EN);
- rsnd_ssi_status_check(mod, DIRQ);
+ /*
+ * disable all IRQ,
+ * Playback: Wait all data was sent
+ * Capture: It might not receave data. Do nothing
+ */
+ if (rsnd_io_is_play(io)) {
+ rsnd_mod_write(mod, SSICR, cr | EN);
+ rsnd_ssi_status_check(mod, DIRQ);
+ }
/*
* disable SSI,
@@ -793,13 +798,13 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
* But it don't need to call request_irq() many times.
* Let's control it by RSND_SSI_PROBED flag.
*/
- if (!rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+ if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
ret = request_irq(ssi->irq,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), mod);
- rsnd_ssi_flags_set(ssi, RSND_SSI_PROBED);
+ rsnd_flags_set(ssi, RSND_SSI_PROBED);
}
return ret;
@@ -817,10 +822,10 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
return 0;
/* PIO will request IRQ again */
- if (rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+ if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
free_irq(ssi->irq, mod);
- rsnd_ssi_flags_del(ssi, RSND_SSI_PROBED);
+ rsnd_flags_del(ssi, RSND_SSI_PROBED);
}
return 0;
@@ -1003,13 +1008,13 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
ssi = rsnd_mod_to_ssi(mod);
if (strstr(remote_ep->full_name, "hdmi0")) {
- rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI0);
+ rsnd_flags_set(ssi, RSND_SSI_HDMI0);
dev_dbg(dev, "%s[%d] connected to HDMI0\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
}
if (strstr(remote_ep->full_name, "hdmi1")) {
- rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI1);
+ rsnd_flags_set(ssi, RSND_SSI_HDMI1);
dev_dbg(dev, "%s[%d] connected to HDMI1\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
}
@@ -1042,7 +1047,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- return !!(rsnd_ssi_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE));
+ return !!(rsnd_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE));
}
static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
@@ -1112,6 +1117,9 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
i = 0;
for_each_child_of_node(node, np) {
+ if (!of_device_is_available(np))
+ goto skip;
+
ssi = rsnd_ssi_get(priv, i);
snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
@@ -1125,10 +1133,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
}
if (of_get_property(np, "shared-pin", NULL))
- rsnd_ssi_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
+ rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
if (of_get_property(np, "no-busif", NULL))
- rsnd_ssi_flags_set(ssi, RSND_SSI_NO_BUSIF);
+ rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF);
ssi->irq = irq_of_parse_and_map(np, 0);
if (!ssi->irq) {
@@ -1148,7 +1156,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
of_node_put(np);
goto rsnd_ssi_probe_done;
}
-
+skip:
i++;
}
diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/soc-acpi.c
index 56d26f36a3cb..f21df28bc28e 100644
--- a/sound/soc/intel/common/sst-match-acpi.c
+++ b/sound/soc/soc-acpi.c
@@ -1,5 +1,5 @@
/*
- * sst_match_apci.c - SST (LPE) match for ACPI enumeration.
+ * soc-apci.c - support for ACPI enumeration.
*
* Copyright (c) 2013-15, Intel Corporation.
*
@@ -14,9 +14,9 @@
* more details.
*/
-#include "sst-acpi.h"
+#include <sound/soc-acpi.h>
-static acpi_status sst_acpi_find_name(acpi_handle handle, u32 level,
+static acpi_status snd_soc_acpi_find_name(acpi_handle handle, u32 level,
void *context, void **ret)
{
struct acpi_device *adev;
@@ -34,12 +34,12 @@ static acpi_status sst_acpi_find_name(acpi_handle handle, u32 level,
return AE_OK;
}
-const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
+const char *snd_soc_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
{
const char *name = NULL;
acpi_status status;
- status = acpi_get_devices(hid, sst_acpi_find_name, NULL,
+ status = acpi_get_devices(hid, snd_soc_acpi_find_name, NULL,
(void **)&name);
if (ACPI_FAILURE(status) || name[0] == '\0')
@@ -47,9 +47,9 @@ const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
return name;
}
-EXPORT_SYMBOL_GPL(sst_acpi_find_name_from_hid);
+EXPORT_SYMBOL_GPL(snd_soc_acpi_find_name_from_hid);
-static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+static acpi_status snd_soc_acpi_mach_match(acpi_handle handle, u32 level,
void *context, void **ret)
{
unsigned long long sta;
@@ -63,26 +63,27 @@ static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
return AE_OK;
}
-bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN])
+bool snd_soc_acpi_check_hid(const u8 hid[ACPI_ID_LEN])
{
acpi_status status;
bool found = false;
- status = acpi_get_devices(hid, sst_acpi_mach_match, &found, NULL);
+ status = acpi_get_devices(hid, snd_soc_acpi_mach_match, &found, NULL);
if (ACPI_FAILURE(status))
return false;
return found;
}
-EXPORT_SYMBOL_GPL(sst_acpi_check_hid);
+EXPORT_SYMBOL_GPL(snd_soc_acpi_check_hid);
-struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
+struct snd_soc_acpi_mach *
+snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines)
{
- struct sst_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach;
for (mach = machines; mach->id[0]; mach++) {
- if (sst_acpi_check_hid(mach->id) == true) {
+ if (snd_soc_acpi_check_hid(mach->id) == true) {
if (mach->machine_quirk == NULL)
return mach;
@@ -92,14 +93,14 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
}
return NULL;
}
-EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
+EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine);
-static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level,
- void *context, void **ret)
+static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level,
+ void *context, void **ret)
{
struct acpi_device *adev;
acpi_status status = AE_OK;
- struct sst_acpi_package_context *pkg_ctx = context;
+ struct snd_soc_acpi_package_context *pkg_ctx = context;
pkg_ctx->data_valid = false;
@@ -137,37 +138,38 @@ static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level,
return AE_OK;
}
-bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
- struct sst_acpi_package_context *ctx)
+bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
+ struct snd_soc_acpi_package_context *ctx)
{
acpi_status status;
- status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL);
+ status = acpi_get_devices(hid, snd_soc_acpi_find_package, ctx, NULL);
if (ACPI_FAILURE(status) || !ctx->data_valid)
return false;
return true;
}
-EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid);
+EXPORT_SYMBOL_GPL(snd_soc_acpi_find_package_from_hid);
-struct sst_acpi_mach *sst_acpi_codec_list(void *arg)
+struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
{
- struct sst_acpi_mach *mach = arg;
- struct sst_codecs *codec_list = (struct sst_codecs *) mach->quirk_data;
+ struct snd_soc_acpi_mach *mach = arg;
+ struct snd_soc_acpi_codecs *codec_list =
+ (struct snd_soc_acpi_codecs *) mach->quirk_data;
int i;
if (mach->quirk_data == NULL)
return mach;
for (i = 0; i < codec_list->num_codecs; i++) {
- if (sst_acpi_check_hid(codec_list->codecs[i]) != true)
+ if (snd_soc_acpi_check_hid(codec_list->codecs[i]) != true)
return NULL;
}
return mach;
}
-EXPORT_SYMBOL_GPL(sst_acpi_codec_list);
+EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list);
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel Common ACPI Match module");
+MODULE_DESCRIPTION("ALSA SoC ACPI module");
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 2cb8d3b55fbc..d9b1e6417fb9 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -30,8 +30,10 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -44,7 +46,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
}
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->open) {
ret = platform->driver->compr_ops->open(cstream);
if (ret < 0) {
pr_err("compress asoc: can't open platform %s\n",
@@ -53,6 +55,27 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
}
}
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->open)
+ continue;
+
+ __ret = component->driver->compr_ops->open(cstream);
+ if (__ret < 0) {
+ pr_err("compress asoc: can't open platform %s\n",
+ component->name);
+ ret = __ret;
+ }
+ }
+ if (ret < 0)
+ goto machine_err;
+
if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
ret = rtd->dai_link->compr_ops->startup(cstream);
if (ret < 0) {
@@ -68,7 +91,21 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
return 0;
machine_err:
- if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->free)
+ continue;
+
+ component->driver->compr_ops->free(cstream);
+ }
+
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
platform->driver->compr_ops->free(cstream);
plat_err:
if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
@@ -84,11 +121,13 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
struct snd_pcm_substream *fe_substream =
fe->pcm->streams[cstream->direction].substream;
struct snd_soc_platform *platform = fe->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = fe->cpu_dai;
struct snd_soc_dpcm *dpcm;
struct snd_soc_dapm_widget_list *list;
int stream;
- int ret = 0;
+ int ret = 0, __ret;
if (cstream->direction == SND_COMPRESS_PLAYBACK)
stream = SNDRV_PCM_STREAM_PLAYBACK;
@@ -107,7 +146,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->open) {
ret = platform->driver->compr_ops->open(cstream);
if (ret < 0) {
pr_err("compress asoc: can't open platform %s\n",
@@ -116,6 +155,27 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
}
}
+ for_each_rtdcom(fe, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->open)
+ continue;
+
+ __ret = component->driver->compr_ops->open(cstream);
+ if (__ret < 0) {
+ pr_err("compress asoc: can't open platform %s\n",
+ component->name);
+ ret = __ret;
+ }
+ }
+ if (ret < 0)
+ goto machine_err;
+
if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
ret = fe->dai_link->compr_ops->startup(cstream);
if (ret < 0) {
@@ -167,7 +227,21 @@ fe_err:
if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
fe->dai_link->compr_ops->shutdown(cstream);
machine_err:
- if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+ for_each_rtdcom(fe, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->free)
+ continue;
+
+ component->driver->compr_ops->free(cstream);
+ }
+
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
platform->driver->compr_ops->free(cstream);
plat_err:
if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
@@ -210,6 +284,8 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int stream;
@@ -235,7 +311,21 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
rtd->dai_link->compr_ops->shutdown(cstream);
- if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->free)
+ continue;
+
+ component->driver->compr_ops->free(cstream);
+ }
+
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
platform->driver->compr_ops->free(cstream);
if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
@@ -267,6 +357,8 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_soc_platform *platform = fe->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = fe->cpu_dai;
struct snd_soc_dpcm *dpcm;
int stream, ret;
@@ -304,9 +396,23 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
fe->dai_link->compr_ops->shutdown(cstream);
- if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->free)
platform->driver->compr_ops->free(cstream);
+ for_each_rtdcom(fe, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->free)
+ continue;
+
+ component->driver->compr_ops->free(cstream);
+ }
+
if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
@@ -319,18 +425,38 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
ret = platform->driver->compr_ops->trigger(cstream, cmd);
if (ret < 0)
goto out;
}
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->trigger)
+ continue;
+
+ __ret = component->driver->compr_ops->trigger(cstream, cmd);
+ if (__ret < 0)
+ ret = __ret;
+ }
+ if (ret < 0)
+ goto out;
+
if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger)
cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
@@ -353,16 +479,36 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_soc_platform *platform = fe->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- int ret = 0, stream;
+ int ret = 0, __ret, stream;
if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
cmd == SND_COMPR_TRIGGER_DRAIN) {
- if (platform->driver->compr_ops &&
+ if (platform &&
+ platform->driver->compr_ops &&
platform->driver->compr_ops->trigger)
return platform->driver->compr_ops->trigger(cstream,
cmd);
+
+ for_each_rtdcom(fe, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->trigger)
+ continue;
+
+ __ret = component->driver->compr_ops->trigger(cstream, cmd);
+ if (__ret < 0)
+ ret = __ret;
+ }
+ return ret;
}
if (cstream->direction == SND_COMPRESS_PLAYBACK)
@@ -379,12 +525,30 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
goto out;
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
ret = platform->driver->compr_ops->trigger(cstream, cmd);
if (ret < 0)
goto out;
}
+ for_each_rtdcom(fe, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->trigger)
+ continue;
+
+ __ret = component->driver->compr_ops->trigger(cstream, cmd);
+ if (__ret < 0)
+ ret = __ret;
+ }
+ if (ret < 0)
+ goto out;
+
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
ret = dpcm_be_dai_trigger(fe, stream, cmd);
@@ -415,8 +579,10 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -432,12 +598,30 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
goto err;
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
ret = platform->driver->compr_ops->set_params(cstream, params);
if (ret < 0)
goto err;
}
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->set_params)
+ continue;
+
+ __ret = component->driver->compr_ops->set_params(cstream, params);
+ if (__ret < 0)
+ ret = __ret;
+ }
+ if (ret < 0)
+ goto err;
+
if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
ret = rtd->dai_link->compr_ops->set_params(cstream);
if (ret < 0)
@@ -471,8 +655,10 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
struct snd_pcm_substream *fe_substream =
fe->pcm->streams[cstream->direction].substream;
struct snd_soc_platform *platform = fe->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- int ret = 0, stream;
+ int ret = 0, __ret, stream;
if (cstream->direction == SND_COMPRESS_PLAYBACK)
stream = SNDRV_PCM_STREAM_PLAYBACK;
@@ -487,12 +673,30 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
goto out;
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
ret = platform->driver->compr_ops->set_params(cstream, params);
if (ret < 0)
goto out;
}
+ for_each_rtdcom(fe, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->set_params)
+ continue;
+
+ __ret = component->driver->compr_ops->set_params(cstream, params);
+ if (__ret < 0)
+ ret = __ret;
+ }
+ if (ret < 0)
+ goto out;
+
if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
ret = fe->dai_link->compr_ops->set_params(cstream);
if (ret < 0)
@@ -531,8 +735,10 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -542,8 +748,27 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
goto err;
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_params) {
ret = platform->driver->compr_ops->get_params(cstream, params);
+ if (ret < 0)
+ goto err;
+ }
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->get_params)
+ continue;
+
+ __ret = component->driver->compr_ops->get_params(cstream, params);
+ if (__ret < 0)
+ ret = __ret;
+ }
err:
mutex_unlock(&rtd->pcm_mutex);
@@ -555,13 +780,35 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
- int ret = 0;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
+ int ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_caps) {
ret = platform->driver->compr_ops->get_caps(cstream, caps);
+ if (ret < 0)
+ goto err;
+ }
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->get_caps)
+ continue;
+
+ __ret = component->driver->compr_ops->get_caps(cstream, caps);
+ if (__ret < 0)
+ ret = __ret;
+ }
+
+err:
mutex_unlock(&rtd->pcm_mutex);
return ret;
}
@@ -571,13 +818,35 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
- int ret = 0;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
+ int ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) {
ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
+ if (ret < 0)
+ goto err;
+ }
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->get_codec_caps)
+ continue;
+
+ __ret = component->driver->compr_ops->get_codec_caps(cstream, codec);
+ if (__ret < 0)
+ ret = __ret;
+ }
+
+err:
mutex_unlock(&rtd->pcm_mutex);
return ret;
}
@@ -586,8 +855,10 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -597,8 +868,27 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
goto err;
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->ack) {
ret = platform->driver->compr_ops->ack(cstream, bytes);
+ if (ret < 0)
+ goto err;
+ }
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->ack)
+ continue;
+
+ __ret = component->driver->compr_ops->ack(cstream, bytes);
+ if (__ret < 0)
+ ret = __ret;
+ }
err:
mutex_unlock(&rtd->pcm_mutex);
@@ -610,7 +900,9 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
- int ret = 0;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
+ int ret = 0, __ret;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -618,9 +910,29 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
- if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->pointer) {
ret = platform->driver->compr_ops->pointer(cstream, tstamp);
+ if (ret < 0)
+ goto err;
+ }
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->pointer)
+ continue;
+ __ret = component->driver->compr_ops->pointer(cstream, tstamp);
+ if (__ret < 0)
+ ret = __ret;
+ }
+
+err:
mutex_unlock(&rtd->pcm_mutex);
return ret;
}
@@ -630,13 +942,34 @@ static int soc_compr_copy(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
- int ret = 0;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
+ int ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->copy) {
ret = platform->driver->compr_ops->copy(cstream, buf, count);
+ if (ret < 0)
+ goto err;
+ }
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->copy)
+ continue;
+ __ret = component->driver->compr_ops->copy(cstream, buf, count);
+ if (__ret < 0)
+ ret = __ret;
+ }
+err:
mutex_unlock(&rtd->pcm_mutex);
return ret;
}
@@ -646,8 +979,10 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, __ret;
if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) {
ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai);
@@ -655,8 +990,27 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
return ret;
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->set_metadata) {
ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
+ if (ret < 0)
+ return ret;
+ }
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->set_metadata)
+ continue;
+
+ __ret = component->driver->compr_ops->set_metadata(cstream, metadata);
+ if (__ret < 0)
+ ret = __ret;
+ }
return ret;
}
@@ -666,8 +1020,10 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, __ret;
if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) {
ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai);
@@ -675,8 +1031,27 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
return ret;
}
- if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->get_metadata) {
ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
+ if (ret < 0)
+ return ret;
+ }
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->get_metadata)
+ continue;
+
+ __ret = component->driver->compr_ops->get_metadata(cstream, metadata);
+ if (__ret < 0)
+ ret = __ret;
+ }
return ret;
}
@@ -723,6 +1098,8 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_compr *compr;
@@ -798,9 +1175,25 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
}
+
/* Add copy callback for not memory mapped DSPs */
- if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
+ if (platform && platform->driver->compr_ops && platform->driver->compr_ops->copy)
+ compr->ops->copy = soc_compr_copy;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->compr_ops ||
+ !component->driver->compr_ops->copy)
+ continue;
+
compr->ops->copy = soc_compr_copy;
+ }
+
mutex_init(&compr->lock);
ret = snd_compress_new(rtd->card->snd_card, num, direction,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index fee4b0ef5566..c0edac80df34 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -614,6 +614,8 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
+static const struct snd_soc_ops null_snd_soc_ops;
+
static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
{
@@ -626,6 +628,9 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
INIT_LIST_HEAD(&rtd->component_list);
rtd->card = card;
rtd->dai_link = dai_link;
+ if (!rtd->dai_link->ops)
+ rtd->dai_link->ops = &null_snd_soc_ops;
+
rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) *
dai_link->num_codecs,
GFP_KERNEL);
@@ -639,8 +644,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd)
{
- if (rtd && rtd->codec_dais)
- kfree(rtd->codec_dais);
+ kfree(rtd->codec_dais);
snd_soc_rtdcom_del_all(rtd);
kfree(rtd);
}
@@ -2632,7 +2636,7 @@ EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- if (dai->driver && dai->driver->ops->set_sysclk)
+ if (dai->driver->ops->set_sysclk)
return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
@@ -2700,7 +2704,7 @@ EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk);
int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div)
{
- if (dai->driver && dai->driver->ops->set_clkdiv)
+ if (dai->driver->ops->set_clkdiv)
return dai->driver->ops->set_clkdiv(dai, div_id, div);
else
return -EINVAL;
@@ -2720,7 +2724,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out)
{
- if (dai->driver && dai->driver->ops->set_pll)
+ if (dai->driver->ops->set_pll)
return dai->driver->ops->set_pll(dai, pll_id, source,
freq_in, freq_out);
@@ -2786,7 +2790,7 @@ EXPORT_SYMBOL_GPL(snd_soc_component_set_pll);
*/
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
{
- if (dai->driver && dai->driver->ops->set_bclk_ratio)
+ if (dai->driver->ops->set_bclk_ratio)
return dai->driver->ops->set_bclk_ratio(dai, ratio);
else
return -EINVAL;
@@ -2796,7 +2800,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
/**
* snd_soc_dai_set_fmt - configure DAI hardware audio format.
* @dai: DAI
- * @fmt: SND_SOC_DAIFMT_ format value.
+ * @fmt: SND_SOC_DAIFMT_* format value.
*
* Configures the DAI hardware format and clocking.
*/
@@ -2860,7 +2864,7 @@ static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
- if (dai->driver && dai->driver->ops->xlate_tdm_slot_mask)
+ if (dai->driver->ops->xlate_tdm_slot_mask)
dai->driver->ops->xlate_tdm_slot_mask(slots,
&tx_mask, &rx_mask);
else
@@ -2869,7 +2873,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
dai->tx_mask = tx_mask;
dai->rx_mask = rx_mask;
- if (dai->driver && dai->driver->ops->set_tdm_slot)
+ if (dai->driver->ops->set_tdm_slot)
return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
else
@@ -2893,7 +2897,7 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot)
{
- if (dai->driver && dai->driver->ops->set_channel_map)
+ if (dai->driver->ops->set_channel_map)
return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
rx_num, rx_slot);
else
@@ -2910,7 +2914,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
*/
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
{
- if (dai->driver && dai->driver->ops->set_tristate)
+ if (dai->driver->ops->set_tristate)
return dai->driver->ops->set_tristate(dai, tristate);
else
return -EINVAL;
@@ -3250,6 +3254,30 @@ static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm,
return component->driver->stream_event(component, event);
}
+static int snd_soc_component_drv_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ if (component->driver->pcm_new)
+ return component->driver->pcm_new(rtd);
+
+ return 0;
+}
+
+static void snd_soc_component_drv_pcm_free(struct snd_soc_component *component,
+ struct snd_pcm *pcm)
+{
+ if (component->driver->pcm_free)
+ component->driver->pcm_free(pcm);
+}
+
+static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm,
+ enum snd_soc_bias_level level)
+{
+ struct snd_soc_component *component = dapm->component;
+
+ return component->driver->set_bias_level(component, level);
+}
+
static int snd_soc_component_initialize(struct snd_soc_component *component,
const struct snd_soc_component_driver *driver, struct device *dev)
{
@@ -3270,16 +3298,21 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
component->set_sysclk = component->driver->set_sysclk;
component->set_pll = component->driver->set_pll;
component->set_jack = component->driver->set_jack;
+ component->pcm_new = snd_soc_component_drv_pcm_new;
+ component->pcm_free = snd_soc_component_drv_pcm_free;
dapm = snd_soc_component_get_dapm(component);
dapm->dev = dev;
dapm->component = component;
dapm->bias_level = SND_SOC_BIAS_OFF;
- dapm->idle_bias_off = true;
+ dapm->idle_bias_off = !driver->idle_bias_on;
+ dapm->suspend_bias_off = driver->suspend_bias_off;
if (driver->seq_notifier)
dapm->seq_notifier = snd_soc_component_seq_notifier;
if (driver->stream_event)
dapm->stream_event = snd_soc_component_stream_event;
+ if (driver->set_bias_level)
+ dapm->set_bias_level = snd_soc_component_set_bias_level;
INIT_LIST_HEAD(&component->dai_list);
mutex_init(&component->io_mutex);
@@ -3371,19 +3404,49 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
list_del(&component->list);
}
-int snd_soc_register_component(struct device *dev,
- const struct snd_soc_component_driver *component_driver,
- struct snd_soc_dai_driver *dai_drv,
- int num_dai)
+#define ENDIANNESS_MAP(name) \
+ (SNDRV_PCM_FMTBIT_##name##LE | SNDRV_PCM_FMTBIT_##name##BE)
+static u64 endianness_format_map[] = {
+ ENDIANNESS_MAP(S16_),
+ ENDIANNESS_MAP(U16_),
+ ENDIANNESS_MAP(S24_),
+ ENDIANNESS_MAP(U24_),
+ ENDIANNESS_MAP(S32_),
+ ENDIANNESS_MAP(U32_),
+ ENDIANNESS_MAP(S24_3),
+ ENDIANNESS_MAP(U24_3),
+ ENDIANNESS_MAP(S20_3),
+ ENDIANNESS_MAP(U20_3),
+ ENDIANNESS_MAP(S18_3),
+ ENDIANNESS_MAP(U18_3),
+ ENDIANNESS_MAP(FLOAT_),
+ ENDIANNESS_MAP(FLOAT64_),
+ ENDIANNESS_MAP(IEC958_SUBFRAME_),
+};
+
+/*
+ * Fix up the DAI formats for endianness: codecs don't actually see
+ * the endianness of the data but we're using the CPU format
+ * definitions which do need to include endianness so we ensure that
+ * codec DAIs always have both big and little endian variants set.
+ */
+static void convert_endianness_formats(struct snd_soc_pcm_stream *stream)
{
- struct snd_soc_component *component;
- int ret;
+ int i;
- component = kzalloc(sizeof(*component), GFP_KERNEL);
- if (!component) {
- dev_err(dev, "ASoC: Failed to allocate memory\n");
- return -ENOMEM;
- }
+ for (i = 0; i < ARRAY_SIZE(endianness_format_map); i++)
+ if (stream->formats & endianness_format_map[i])
+ stream->formats |= endianness_format_map[i];
+}
+
+int snd_soc_add_component(struct device *dev,
+ struct snd_soc_component *component,
+ const struct snd_soc_component_driver *component_driver,
+ struct snd_soc_dai_driver *dai_drv,
+ int num_dai)
+{
+ int ret;
+ int i;
ret = snd_soc_component_initialize(component, component_driver, dev);
if (ret)
@@ -3392,7 +3455,15 @@ int snd_soc_register_component(struct device *dev,
component->ignore_pmdown_time = true;
component->registered_as_component = true;
- ret = snd_soc_register_dais(component, dai_drv, num_dai, true);
+ if (component_driver->endianness) {
+ for (i = 0; i < num_dai; i++) {
+ convert_endianness_formats(&dai_drv[i].playback);
+ convert_endianness_formats(&dai_drv[i].capture);
+ }
+ }
+
+ ret = snd_soc_register_dais(component, dai_drv, num_dai,
+ !component_driver->non_legacy_dai_naming);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
goto err_cleanup;
@@ -3408,6 +3479,22 @@ err_free:
kfree(component);
return ret;
}
+EXPORT_SYMBOL_GPL(snd_soc_add_component);
+
+int snd_soc_register_component(struct device *dev,
+ const struct snd_soc_component_driver *component_driver,
+ struct snd_soc_dai_driver *dai_drv,
+ int num_dai)
+{
+ struct snd_soc_component *component;
+
+ component = kzalloc(sizeof(*component), GFP_KERNEL);
+ if (!component)
+ return -ENOMEM;
+
+ return snd_soc_add_component(dev, component, component_driver,
+ dai_drv, num_dai);
+}
EXPORT_SYMBOL_GPL(snd_soc_register_component);
/**
@@ -3448,6 +3535,32 @@ void snd_soc_unregister_component(struct device *dev)
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
+struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
+ const char *driver_name)
+{
+ struct snd_soc_component *component;
+ struct snd_soc_component *ret;
+
+ ret = NULL;
+ mutex_lock(&client_mutex);
+ list_for_each_entry(component, &component_list, list) {
+ if (dev != component->dev)
+ continue;
+
+ if (driver_name &&
+ (driver_name != component->driver->name) &&
+ (strcmp(component->driver->name, driver_name) != 0))
+ continue;
+
+ ret = component;
+ break;
+ }
+ mutex_unlock(&client_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_lookup_component);
+
static int snd_soc_platform_drv_probe(struct snd_soc_component *component)
{
struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
@@ -3462,6 +3575,26 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
platform->driver->remove(platform);
}
+static int snd_soc_platform_drv_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
+
+ if (platform->driver->pcm_new)
+ return platform->driver->pcm_new(rtd);
+
+ return 0;
+}
+
+static void snd_soc_platform_drv_pcm_free(struct snd_soc_component *component,
+ struct snd_pcm *pcm)
+{
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
+
+ if (platform->driver->pcm_free)
+ platform->driver->pcm_free(pcm);
+}
+
/**
* snd_soc_add_platform - Add a platform to the ASoC core
* @dev: The parent device for the platform
@@ -3485,6 +3618,10 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
platform->component.probe = snd_soc_platform_drv_probe;
if (platform_drv->remove)
platform->component.remove = snd_soc_platform_drv_remove;
+ if (platform_drv->pcm_new)
+ platform->component.pcm_new = snd_soc_platform_drv_pcm_new;
+ if (platform_drv->pcm_free)
+ platform->component.pcm_free = snd_soc_platform_drv_pcm_free;
#ifdef CONFIG_DEBUG_FS
platform->component.debugfs_prefix = "platform";
@@ -3582,39 +3719,6 @@ void snd_soc_unregister_platform(struct device *dev)
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
-static u64 codec_format_map[] = {
- SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE,
- SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE,
- SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE,
- SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE,
- SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
- SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE,
- SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
- SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE,
- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE,
- SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE,
- SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE,
- SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE,
- SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE,
- SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE,
- SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE
- | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
-};
-
-/* Fix up the DAI formats for endianness: codecs don't actually see
- * the endianness of the data but we're using the CPU format
- * definitions which do need to include endianness so we ensure that
- * codec DAIs always have both big and little endian variants set.
- */
-static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(codec_format_map); i++)
- if (stream->formats & codec_format_map[i])
- stream->formats |= codec_format_map[i];
-}
-
static int snd_soc_codec_drv_probe(struct snd_soc_component *component)
{
struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
@@ -3765,8 +3869,8 @@ int snd_soc_register_codec(struct device *dev,
codec->component.regmap = codec_drv->get_regmap(dev);
for (i = 0; i < num_dai; i++) {
- fixup_codec_formats(&dai_drv[i].playback);
- fixup_codec_formats(&dai_drv[i].capture);
+ convert_endianness_formats(&dai_drv[i].playback);
+ convert_endianness_formats(&dai_drv[i].capture);
}
ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index dcef67a9bd48..a10b21cfc31e 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2884,7 +2884,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
{
int i, r, ret = 0;
- mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
for (i = 0; i < num; i++) {
r = snd_soc_dapm_add_route(dapm, route);
if (r < 0) {
@@ -2915,7 +2915,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
{
int i;
- mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
for (i = 0; i < num; i++) {
snd_soc_dapm_del_route(dapm, route);
route++;
@@ -3681,7 +3681,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- if (source->driver->ops && source->driver->ops->startup) {
+ if (source->driver->ops->startup) {
ret = source->driver->ops->startup(&substream, source);
if (ret < 0) {
dev_err(source->dev,
@@ -3695,7 +3695,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
goto out;
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- if (sink->driver->ops && sink->driver->ops->startup) {
+ if (sink->driver->ops->startup) {
ret = sink->driver->ops->startup(&substream, sink);
if (ret < 0) {
dev_err(sink->dev,
@@ -3725,13 +3725,13 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
ret = 0;
source->active--;
- if (source->driver->ops && source->driver->ops->shutdown) {
+ if (source->driver->ops->shutdown) {
substream.stream = SNDRV_PCM_STREAM_CAPTURE;
source->driver->ops->shutdown(&substream, source);
}
sink->active--;
- if (sink->driver->ops && sink->driver->ops->shutdown) {
+ if (sink->driver->ops->shutdown) {
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
sink->driver->ops->shutdown(&substream, sink);
}
@@ -3778,18 +3778,27 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
return 0;
}
-int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
- const struct snd_soc_pcm_stream *params,
- unsigned int num_params,
- struct snd_soc_dapm_widget *source,
- struct snd_soc_dapm_widget *sink)
+static void
+snd_soc_dapm_free_kcontrol(struct snd_soc_card *card,
+ unsigned long *private_value,
+ int num_params,
+ const char **w_param_text)
+{
+ int count;
+
+ devm_kfree(card->dev, (void *)*private_value);
+ for (count = 0 ; count < num_params; count++)
+ devm_kfree(card->dev, (void *)w_param_text[count]);
+ devm_kfree(card->dev, w_param_text);
+}
+
+static struct snd_kcontrol_new *
+snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
+ char *link_name,
+ const struct snd_soc_pcm_stream *params,
+ int num_params, const char **w_param_text,
+ unsigned long *private_value)
{
- struct snd_soc_dapm_widget template;
- struct snd_soc_dapm_widget *w;
- char *link_name;
- int ret, count;
- unsigned long private_value;
- const char **w_param_text;
struct soc_enum w_param_enum[] = {
SOC_ENUM_SINGLE(0, 0, 0, NULL),
};
@@ -3798,19 +3807,9 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
snd_soc_dapm_dai_link_get,
snd_soc_dapm_dai_link_put),
};
+ struct snd_kcontrol_new *kcontrol_news;
const struct snd_soc_pcm_stream *config = params;
-
- w_param_text = devm_kcalloc(card->dev, num_params,
- sizeof(char *), GFP_KERNEL);
- if (!w_param_text)
- return -ENOMEM;
-
- link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
- source->name, sink->name);
- if (!link_name) {
- ret = -ENOMEM;
- goto outfree_w_param;
- }
+ int count;
for (count = 0 ; count < num_params; count++) {
if (!config->stream_name) {
@@ -3821,57 +3820,94 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
devm_kasprintf(card->dev, GFP_KERNEL,
"Anonymous Configuration %d",
count);
- if (!w_param_text[count]) {
- ret = -ENOMEM;
- goto outfree_link_name;
- }
} else {
w_param_text[count] = devm_kmemdup(card->dev,
config->stream_name,
strlen(config->stream_name) + 1,
GFP_KERNEL);
- if (!w_param_text[count]) {
- ret = -ENOMEM;
- goto outfree_link_name;
- }
}
+ if (!w_param_text[count])
+ goto outfree_w_param;
config++;
}
+
w_param_enum[0].items = num_params;
w_param_enum[0].texts = w_param_text;
- memset(&template, 0, sizeof(template));
- template.reg = SND_SOC_NOPM;
- template.id = snd_soc_dapm_dai_link;
- template.name = link_name;
- template.event = snd_soc_dai_link_event;
- template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD;
- template.num_kcontrols = 1;
- /* duplicate w_param_enum on heap so that memory persists */
- private_value =
+ *private_value =
(unsigned long) devm_kmemdup(card->dev,
(void *)(kcontrol_dai_link[0].private_value),
sizeof(struct soc_enum), GFP_KERNEL);
- if (!private_value) {
+ if (!*private_value) {
dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
link_name);
- ret = -ENOMEM;
- goto outfree_link_name;
+ goto outfree_w_param;
}
- kcontrol_dai_link[0].private_value = private_value;
+ kcontrol_dai_link[0].private_value = *private_value;
/* duplicate kcontrol_dai_link on heap so that memory persists */
- template.kcontrol_news =
- devm_kmemdup(card->dev, &kcontrol_dai_link[0],
+ kcontrol_news = devm_kmemdup(card->dev, &kcontrol_dai_link[0],
sizeof(struct snd_kcontrol_new),
GFP_KERNEL);
- if (!template.kcontrol_news) {
+ if (!kcontrol_news) {
dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
link_name);
- ret = -ENOMEM;
- goto outfree_private_value;
+ goto outfree_w_param;
}
+ return kcontrol_news;
+
+outfree_w_param:
+ snd_soc_dapm_free_kcontrol(card, private_value, num_params, w_param_text);
+ return NULL;
+}
+
+int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
+ const struct snd_soc_pcm_stream *params,
+ unsigned int num_params,
+ struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_widget template;
+ struct snd_soc_dapm_widget *w;
+ const char **w_param_text;
+ unsigned long private_value;
+ char *link_name;
+ int ret;
+
+ link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
+ source->name, sink->name);
+ if (!link_name)
+ return -ENOMEM;
+
+ memset(&template, 0, sizeof(template));
+ template.reg = SND_SOC_NOPM;
+ template.id = snd_soc_dapm_dai_link;
+ template.name = link_name;
+ template.event = snd_soc_dai_link_event;
+ template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD;
+ template.kcontrol_news = NULL;
+
+ /* allocate memory for control, only in case of multiple configs */
+ if (num_params > 1) {
+ w_param_text = devm_kcalloc(card->dev, num_params,
+ sizeof(char *), GFP_KERNEL);
+ if (!w_param_text) {
+ ret = -ENOMEM;
+ goto param_fail;
+ }
+ template.num_kcontrols = 1;
+ template.kcontrol_news =
+ snd_soc_dapm_alloc_kcontrol(card,
+ link_name, params, num_params,
+ w_param_text, &private_value);
+ if (!template.kcontrol_news) {
+ ret = -ENOMEM;
+ goto param_fail;
+ }
+ } else {
+ w_param_text = NULL;
+ }
dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
@@ -3903,15 +3939,9 @@ outfree_w:
devm_kfree(card->dev, w);
outfree_kcontrol_news:
devm_kfree(card->dev, (void *)template.kcontrol_news);
-outfree_private_value:
- devm_kfree(card->dev, (void *)private_value);
-outfree_link_name:
+ snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text);
+param_fail:
devm_kfree(card->dev, link_name);
-outfree_w_param:
- for (count = 0 ; count < num_params; count++)
- devm_kfree(card->dev, (void *)w_param_text[count]);
- devm_kfree(card->dev, w_param_text);
-
return ret;
}
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 9b3939049cef..20340ade20a7 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -41,6 +41,20 @@ int snd_soc_component_read(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(snd_soc_component_read);
+unsigned int snd_soc_component_read32(struct snd_soc_component *component,
+ unsigned int reg)
+{
+ unsigned int val;
+ int ret;
+
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret < 0)
+ return -1;
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_read32);
+
/**
* snd_soc_component_write() - Write register value
* @component: Component to write to
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 94b88b897c3b..8075856668c2 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -133,16 +133,25 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
*/
bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
int i;
bool ignore = true;
if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
return true;
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ ignore &= !component->driver->pmdown_time;
+ }
+
+ /* this will be removed */
for (i = 0; i < rtd->num_codecs; i++)
ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time;
- return rtd->cpu_dai->component->ignore_pmdown_time && ignore;
+ return ignore;
}
/**
@@ -459,7 +468,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
const char *codec_dai_name = "multicodec";
- int i, ret = 0;
+ int i, ret = 0, __ret;
pinctrl_pm_select_default_state(cpu_dai->dev);
for (i = 0; i < rtd->num_codecs; i++)
@@ -474,7 +483,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
/* startup the audio subsystem */
- if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) {
+ if (cpu_dai->driver->ops->startup) {
ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev, "ASoC: can't open interface"
@@ -483,7 +492,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
- if (platform->driver->ops && platform->driver->ops->open) {
+ if (platform && platform->driver->ops && platform->driver->ops->open) {
ret = platform->driver->ops->open(substream);
if (ret < 0) {
dev_err(platform->dev, "ASoC: can't open platform"
@@ -492,9 +501,32 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
+ ret = 0;
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->open)
+ continue;
+
+ __ret = component->driver->ops->open(substream);
+ if (__ret < 0) {
+ dev_err(component->dev,
+ "ASoC: can't open component %s: %d\n",
+ component->name, ret);
+ ret = __ret;
+ }
+ }
+ if (ret < 0)
+ goto component_err;
+
for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i];
- if (codec_dai->driver->ops && codec_dai->driver->ops->startup) {
+ if (codec_dai->driver->ops->startup) {
ret = codec_dai->driver->ops->startup(substream,
codec_dai);
if (ret < 0) {
@@ -511,7 +543,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
codec_dai->rx_mask = 0;
}
- if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
+ if (rtd->dai_link->ops->startup) {
ret = rtd->dai_link->ops->startup(substream);
if (ret < 0) {
pr_err("ASoC: %s startup failed: %d\n",
@@ -585,7 +617,7 @@ dynamic:
return 0;
config_err:
- if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+ if (rtd->dai_link->ops->shutdown)
rtd->dai_link->ops->shutdown(substream);
machine_err:
@@ -598,7 +630,22 @@ codec_dai_err:
codec_dai->driver->ops->shutdown(substream, codec_dai);
}
- if (platform->driver->ops && platform->driver->ops->close)
+component_err:
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->close)
+ continue;
+
+ component->driver->ops->close(substream);
+ }
+
+ if (platform && platform->driver->ops && platform->driver->ops->close)
platform->driver->ops->close(substream);
platform_err:
@@ -692,12 +739,26 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
codec_dai->driver->ops->shutdown(substream, codec_dai);
}
- if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+ if (rtd->dai_link->ops->shutdown)
rtd->dai_link->ops->shutdown(substream);
- if (platform->driver->ops && platform->driver->ops->close)
+ if (platform && platform->driver->ops && platform->driver->ops->close)
platform->driver->ops->close(substream);
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->close)
+ continue;
+
+ component->driver->ops->close(substream);
+ }
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
/* powered down playback stream now */
@@ -745,13 +806,15 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
int i, ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
+ if (rtd->dai_link->ops->prepare) {
ret = rtd->dai_link->ops->prepare(substream);
if (ret < 0) {
dev_err(rtd->card->dev, "ASoC: machine prepare error:"
@@ -760,7 +823,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
}
}
- if (platform->driver->ops && platform->driver->ops->prepare) {
+ if (platform && platform->driver->ops && platform->driver->ops->prepare) {
ret = platform->driver->ops->prepare(substream);
if (ret < 0) {
dev_err(platform->dev, "ASoC: platform prepare error:"
@@ -769,9 +832,28 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
}
}
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->prepare)
+ continue;
+
+ ret = component->driver->ops->prepare(substream);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "ASoC: platform prepare error: %d\n", ret);
+ goto out;
+ }
+ }
+
for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i];
- if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) {
+ if (codec_dai->driver->ops->prepare) {
ret = codec_dai->driver->ops->prepare(substream,
codec_dai);
if (ret < 0) {
@@ -783,7 +865,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
}
}
- if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) {
+ if (cpu_dai->driver->ops->prepare) {
ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev,
@@ -829,7 +911,7 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
{
int ret;
- if (dai->driver->ops && dai->driver->ops->hw_params) {
+ if (dai->driver->ops->hw_params) {
ret = dai->driver->ops->hw_params(substream, params, dai);
if (ret < 0) {
dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
@@ -851,16 +933,13 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int i, ret = 0;
+ int i, ret = 0, __ret;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
-
- ret = soc_pcm_params_symmetry(substream, params);
- if (ret)
- goto out;
-
- if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
+ if (rtd->dai_link->ops->hw_params) {
ret = rtd->dai_link->ops->hw_params(substream, params);
if (ret < 0) {
dev_err(rtd->card->dev, "ASoC: machine hw_params"
@@ -915,7 +994,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
goto interface_err;
- if (platform->driver->ops && platform->driver->ops->hw_params) {
+ if (platform && platform->driver->ops && platform->driver->ops->hw_params) {
ret = platform->driver->ops->hw_params(substream, params);
if (ret < 0) {
dev_err(platform->dev, "ASoC: %s hw params failed: %d\n",
@@ -924,18 +1003,62 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
+ ret = 0;
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->hw_params)
+ continue;
+
+ __ret = component->driver->ops->hw_params(substream, params);
+ if (__ret < 0) {
+ dev_err(component->dev,
+ "ASoC: %s hw params failed: %d\n",
+ component->name, ret);
+ ret = __ret;
+ }
+ }
+ if (ret < 0)
+ goto component_err;
+
/* store the parameters for each DAIs */
cpu_dai->rate = params_rate(params);
cpu_dai->channels = params_channels(params);
cpu_dai->sample_bits =
snd_pcm_format_physical_width(params_format(params));
+ ret = soc_pcm_params_symmetry(substream, params);
+ if (ret)
+ goto component_err;
out:
mutex_unlock(&rtd->pcm_mutex);
return ret;
+component_err:
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->hw_free)
+ continue;
+
+ component->driver->ops->hw_free(substream);
+ }
+
+ if (platform && platform->driver->ops && platform->driver->ops->hw_free)
+ platform->driver->ops->hw_free(substream);
+
platform_err:
- if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
+ if (cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
interface_err:
@@ -944,12 +1067,12 @@ interface_err:
codec_err:
while (--i >= 0) {
struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
- if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
+ if (codec_dai->driver->ops->hw_free)
codec_dai->driver->ops->hw_free(substream, codec_dai);
codec_dai->rate = 0;
}
- if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+ if (rtd->dai_link->ops->hw_free)
rtd->dai_link->ops->hw_free(substream);
mutex_unlock(&rtd->pcm_mutex);
@@ -963,6 +1086,8 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
@@ -995,21 +1120,36 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
}
/* free any machine hw params */
- if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+ if (rtd->dai_link->ops->hw_free)
rtd->dai_link->ops->hw_free(substream);
/* free any DMA resources */
- if (platform->driver->ops && platform->driver->ops->hw_free)
+ if (platform && platform->driver->ops && platform->driver->ops->hw_free)
platform->driver->ops->hw_free(substream);
+ /* free any component resources */
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->hw_free)
+ continue;
+
+ component->driver->ops->hw_free(substream);
+ }
+
/* now free hw params for the DAIs */
for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i];
- if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
+ if (codec_dai->driver->ops->hw_free)
codec_dai->driver->ops->hw_free(substream, codec_dai);
}
- if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
+ if (cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
mutex_unlock(&rtd->pcm_mutex);
@@ -1020,13 +1160,15 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
int i, ret;
for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i];
- if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) {
+ if (codec_dai->driver->ops->trigger) {
ret = codec_dai->driver->ops->trigger(substream,
cmd, codec_dai);
if (ret < 0)
@@ -1034,19 +1176,35 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
}
- if (platform->driver->ops && platform->driver->ops->trigger) {
+ if (platform && platform->driver->ops && platform->driver->ops->trigger) {
ret = platform->driver->ops->trigger(substream, cmd);
if (ret < 0)
return ret;
}
- if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) {
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->trigger)
+ continue;
+
+ ret = component->driver->ops->trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (cpu_dai->driver->ops->trigger) {
ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
if (ret < 0)
return ret;
}
- if (rtd->dai_link->ops && rtd->dai_link->ops->trigger) {
+ if (rtd->dai_link->ops->trigger) {
ret = rtd->dai_link->ops->trigger(substream, cmd);
if (ret < 0)
return ret;
@@ -1065,8 +1223,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i];
- if (codec_dai->driver->ops &&
- codec_dai->driver->ops->bespoke_trigger) {
+ if (codec_dai->driver->ops->bespoke_trigger) {
ret = codec_dai->driver->ops->bespoke_trigger(substream,
cmd, codec_dai);
if (ret < 0)
@@ -1074,7 +1231,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
}
}
- if (cpu_dai->driver->ops && cpu_dai->driver->ops->bespoke_trigger) {
+ if (cpu_dai->driver->ops->bespoke_trigger) {
ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
if (ret < 0)
return ret;
@@ -1090,6 +1247,8 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1098,15 +1257,31 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
snd_pcm_sframes_t codec_delay = 0;
int i;
- if (platform->driver->ops && platform->driver->ops->pointer)
+ if (platform && platform->driver->ops && platform->driver->ops->pointer)
offset = platform->driver->ops->pointer(substream);
- if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay)
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->pointer)
+ continue;
+
+ /* FIXME: use 1st pointer */
+ offset = component->driver->ops->pointer(substream);
+ break;
+ }
+
+ if (cpu_dai->driver->ops->delay)
delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i];
- if (codec_dai->driver->ops && codec_dai->driver->ops->delay)
+ if (codec_dai->driver->ops->delay)
codec_delay = max(codec_delay,
codec_dai->driver->ops->delay(substream,
codec_dai));
@@ -2285,9 +2460,27 @@ static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
- if (platform->driver->ops && platform->driver->ops->ioctl)
+ if (platform && platform->driver->ops && platform->driver->ops->ioctl)
return platform->driver->ops->ioctl(substream, cmd, arg);
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ /* ignore duplication for now */
+ if (platform && (component == &platform->component))
+ continue;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->ioctl)
+ continue;
+
+ /* FIXME: use 1st ioctl */
+ return component->driver->ops->ioctl(substream, cmd, arg);
+ }
+
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
@@ -2632,12 +2825,163 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
return ret;
}
+static void soc_pcm_private_free(struct snd_pcm *pcm)
+{
+ struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ /* need to sync the delayed work before releasing resources */
+
+ flush_delayed_work(&rtd->delayed_work);
+ component = rtdcom->component;
+
+ if (component->pcm_free)
+ component->pcm_free(component, pcm);
+ }
+}
+
+static int soc_rtdcom_ack(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->ack)
+ continue;
+
+ /* FIXME. it returns 1st ask now */
+ return component->driver->ops->ack(substream);
+ }
+
+ return -EINVAL;
+}
+
+static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel,
+ unsigned long pos, void __user *buf,
+ unsigned long bytes)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->copy_user)
+ continue;
+
+ /* FIXME. it returns 1st copy now */
+ return component->driver->ops->copy_user(substream, channel,
+ pos, buf, bytes);
+ }
+
+ return -EINVAL;
+}
+
+static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel,
+ unsigned long pos, void *buf, unsigned long bytes)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->copy_kernel)
+ continue;
+
+ /* FIXME. it returns 1st copy now */
+ return component->driver->ops->copy_kernel(substream, channel,
+ pos, buf, bytes);
+ }
+
+ return -EINVAL;
+}
+
+static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel,
+ unsigned long pos, unsigned long bytes)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->fill_silence)
+ continue;
+
+ /* FIXME. it returns 1st silence now */
+ return component->driver->ops->fill_silence(substream, channel,
+ pos, bytes);
+ }
+
+ return -EINVAL;
+}
+
+static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+ struct page *page;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->page)
+ continue;
+
+ /* FIXME. it returns 1st page now */
+ page = component->driver->ops->page(substream, offset);
+ if (page)
+ return page;
+ }
+
+ return NULL;
+}
+
+static int soc_rtdcom_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->mmap)
+ continue;
+
+ /* FIXME. it returns 1st mmap now */
+ return component->driver->ops->mmap(substream, vma);
+ }
+
+ return -EINVAL;
+}
+
/* create a new pcm */
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
{
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_component *component;
+ struct snd_soc_rtdcom_list *rtdcom;
struct snd_pcm *pcm;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
@@ -2732,7 +3076,28 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
rtd->ops.ioctl = soc_pcm_ioctl;
}
- if (platform->driver->ops) {
+ for_each_rtdcom(rtd, rtdcom) {
+ const struct snd_pcm_ops *ops = rtdcom->component->driver->ops;
+
+ if (!ops)
+ continue;
+
+ if (ops->ack)
+ rtd->ops.ack = soc_rtdcom_ack;
+ if (ops->copy_user)
+ rtd->ops.copy_user = soc_rtdcom_copy_user;
+ if (ops->copy_kernel)
+ rtd->ops.copy_kernel = soc_rtdcom_copy_kernel;
+ if (ops->fill_silence)
+ rtd->ops.fill_silence = soc_rtdcom_fill_silence;
+ if (ops->page)
+ rtd->ops.page = soc_rtdcom_page;
+ if (ops->mmap)
+ rtd->ops.mmap = soc_rtdcom_mmap;
+ }
+
+ /* overwrite */
+ if (platform && platform->driver->ops) {
rtd->ops.ack = platform->driver->ops->ack;
rtd->ops.copy_user = platform->driver->ops->copy_user;
rtd->ops.copy_kernel = platform->driver->ops->copy_kernel;
@@ -2747,17 +3112,22 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
if (capture)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
- if (platform->driver->pcm_new) {
- ret = platform->driver->pcm_new(rtd);
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (!component->pcm_new)
+ continue;
+
+ ret = component->pcm_new(component, rtd);
if (ret < 0) {
- dev_err(platform->dev,
+ dev_err(component->dev,
"ASoC: pcm constructor failed: %d\n",
ret);
return ret;
}
}
- pcm->private_free = platform->driver->pcm_free;
+ pcm->private_free = soc_pcm_private_free;
out:
dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
(rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 1258bef4dcb3..d6f71a3406e9 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -16,6 +16,7 @@
* details.
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/module.h>
@@ -27,6 +28,16 @@
#include "stm32_sai.h"
+static LIST_HEAD(sync_providers);
+static DEFINE_MUTEX(sync_mutex);
+
+struct sync_provider {
+ struct list_head link;
+ struct device_node *node;
+ int (*sync_conf)(void *data, int synco);
+ void *data;
+};
+
static const struct stm32_sai_conf stm32_sai_conf_f4 = {
.version = SAI_STM32F4,
};
@@ -41,23 +52,143 @@ static const struct of_device_id stm32_sai_ids[] = {
{}
};
+static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
+{
+ int ret;
+
+ /* Enable peripheral clock to allow GCR register access */
+ ret = clk_prepare_enable(sai->pclk);
+ if (ret) {
+ dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
+
+ clk_disable_unprepare(sai->pclk);
+
+ return 0;
+}
+
+static int stm32_sai_sync_conf_provider(void *data, int synco)
+{
+ struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
+ u32 prev_synco;
+ int ret;
+
+ /* Enable peripheral clock to allow GCR register access */
+ ret = clk_prepare_enable(sai->pclk);
+ if (ret) {
+ dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
+ sai->pdev->dev.of_node->name,
+ 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,
+ prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+ clk_disable_unprepare(sai->pclk);
+ return -EINVAL;
+ }
+
+ writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
+
+ clk_disable_unprepare(sai->pclk);
+
+ return 0;
+}
+
+static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
+{
+ struct sync_provider *provider;
+ int ret;
+
+ mutex_lock(&sync_mutex);
+ list_for_each_entry(provider, &sync_providers, link) {
+ if (provider->node == np) {
+ ret = provider->sync_conf(provider->data, synco);
+ mutex_unlock(&sync_mutex);
+ return ret;
+ }
+ }
+ mutex_unlock(&sync_mutex);
+
+ /* SAI sync provider not found */
+ return -ENODEV;
+}
+
+static int stm32_sai_set_sync(struct stm32_sai_data *sai,
+ struct device_node *np_provider,
+ int synco, int synci)
+{
+ int ret;
+
+ /* Configure sync client */
+ stm32_sai_sync_conf_client(sai, synci);
+
+ /* Configure sync provider */
+ ret = stm32_sai_set_sync_provider(np_provider, synco);
+
+ return ret;
+}
+
+static int stm32_sai_sync_add_provider(struct platform_device *pdev,
+ void *data)
+{
+ struct sync_provider *sp;
+
+ sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
+ if (!sp)
+ return -ENOMEM;
+
+ sp->node = of_node_get(pdev->dev.of_node);
+ sp->data = data;
+ sp->sync_conf = &stm32_sai_sync_conf_provider;
+
+ mutex_lock(&sync_mutex);
+ list_add(&sp->link, &sync_providers);
+ mutex_unlock(&sync_mutex);
+
+ return 0;
+}
+
+static void stm32_sai_sync_del_provider(struct device_node *np)
+{
+ struct sync_provider *sp;
+
+ mutex_lock(&sync_mutex);
+ list_for_each_entry(sp, &sync_providers, link) {
+ if (sp->node == np) {
+ list_del(&sp->link);
+ of_node_put(sp->node);
+ break;
+ }
+ }
+ mutex_unlock(&sync_mutex);
+}
+
static int stm32_sai_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct stm32_sai_data *sai;
struct reset_control *rst;
struct resource *res;
- void __iomem *base;
const struct of_device_id *of_id;
+ int ret;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
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);
+ sai->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sai->base))
+ return PTR_ERR(sai->base);
of_id = of_match_device(stm32_sai_ids, &pdev->dev);
if (of_id)
@@ -65,6 +196,14 @@ static int stm32_sai_probe(struct platform_device *pdev)
else
return -EINVAL;
+ if (!STM_SAI_IS_F4(sai)) {
+ sai->pclk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(sai->pclk)) {
+ dev_err(&pdev->dev, "missing bus clock pclk\n");
+ return PTR_ERR(sai->pclk);
+ }
+ }
+
sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
if (IS_ERR(sai->clk_x8k)) {
dev_err(&pdev->dev, "missing x8k parent clock\n");
@@ -85,23 +224,34 @@ static int stm32_sai_probe(struct platform_device *pdev)
}
/* reset */
- rst = reset_control_get_exclusive(&pdev->dev, NULL);
+ rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (!IS_ERR(rst)) {
reset_control_assert(rst);
udelay(2);
reset_control_deassert(rst);
}
+ ret = stm32_sai_sync_add_provider(pdev, sai);
+ if (ret < 0)
+ return ret;
+ sai->set_sync = &stm32_sai_set_sync;
+
sai->pdev = pdev;
platform_set_drvdata(pdev, sai);
- return of_platform_populate(np, NULL, NULL, &pdev->dev);
+ ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+ if (ret < 0)
+ stm32_sai_sync_del_provider(np);
+
+ return ret;
}
static int stm32_sai_remove(struct platform_device *pdev)
{
of_platform_depopulate(&pdev->dev);
+ stm32_sai_sync_del_provider(pdev->dev.of_node);
+
return 0;
}
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 889974dc62d9..bb062e70de63 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -16,9 +16,11 @@
* details.
*/
+#include <linux/bitfield.h>
+
/******************** SAI Register Map **************************************/
-/* common register */
+/* Global configuration register */
#define STM_SAI_GCR 0x00
/* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
@@ -37,12 +39,13 @@
/******************** Bit definition for SAI_GCR register *******************/
#define SAI_GCR_SYNCIN_SHIFT 0
+#define SAI_GCR_SYNCIN_WDTH 2
#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
-#define SAI_GCR_SYNCIN_SET(x) ((x) << SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_MAX FIELD_GET(SAI_GCR_SYNCIN_MASK,\
+ SAI_GCR_SYNCIN_MASK)
#define SAI_GCR_SYNCOUT_SHIFT 4
#define SAI_GCR_SYNCOUT_MASK GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
-#define SAI_GCR_SYNCOUT_SET(x) ((x) << SAI_GCR_SYNCOUT_SHIFT)
/******************* Bit definition for SAI_XCR1 register *******************/
#define SAI_XCR1_RX_TX_SHIFT 0
@@ -231,6 +234,12 @@
#define STM_SAI_IS_F4(ip) ((ip)->conf->version == SAI_STM32F4)
#define STM_SAI_IS_H7(ip) ((ip)->conf->version == SAI_STM32H7)
+enum stm32_sai_syncout {
+ STM_SAI_SYNC_OUT_NONE,
+ STM_SAI_SYNC_OUT_A,
+ STM_SAI_SYNC_OUT_B,
+};
+
enum stm32_sai_version {
SAI_STM32F4,
SAI_STM32H7
@@ -247,15 +256,22 @@ struct stm32_sai_conf {
/**
* struct stm32_sai_data - private data of SAI instance driver
* @pdev: device data pointer
+ * @base: common register bank virtual base address
+ * @pclk: SAI bus clock
* @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
* @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
* @version: SOC version
* @irq: SAI interrupt line
+ * @set_sync: pointer to synchro mode configuration callback
*/
struct stm32_sai_data {
struct platform_device *pdev;
+ void __iomem *base;
+ struct clk *pclk;
struct clk *clk_x8k;
struct clk *clk_x11k;
struct stm32_sai_conf *conf;
int irq;
+ int (*set_sync)(struct stm32_sai_data *sai,
+ struct device_node *np_provider, int synco, int synci);
};
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 90d439613899..08583b958430 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -55,6 +55,12 @@
#define STM_SAI_IS_SUB_B(x) ((x)->id == STM_SAI_B_ID)
#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B")
+#define SAI_SYNC_NONE 0x0
+#define SAI_SYNC_INTERNAL 0x1
+#define SAI_SYNC_EXTERNAL 0x2
+
+#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
+
/**
* struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
* @pdev: device data pointer
@@ -65,6 +71,7 @@
* @cpu_dai: DAI runtime data pointer
* @substream: PCM substream data pointer
* @pdata: SAI block parent data pointer
+ * @np_sync_provider: synchronization provider node
* @sai_ck: kernel clock feeding the SAI clock generator
* @phys_addr: SAI registers physical base address
* @mclk_rate: SAI block master clock frequency (Hz). set at init
@@ -73,6 +80,8 @@
* @master: SAI block mode flag. (true=master, false=slave) set at init
* @fmt: SAI block format. relevant only for custom protocols. set at init
* @sync: SAI block synchronization mode. (none, internal or external)
+ * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
+ * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
* @fs_length: frame synchronization length. depends on protocol settings
* @slots: rx or tx slot number
* @slot_width: rx or tx slot width in bits
@@ -88,6 +97,7 @@ struct stm32_sai_sub_data {
struct snd_soc_dai *cpu_dai;
struct snd_pcm_substream *substream;
struct stm32_sai_data *pdata;
+ struct device_node *np_sync_provider;
struct clk *sai_ck;
dma_addr_t phys_addr;
unsigned int mclk_rate;
@@ -96,6 +106,8 @@ struct stm32_sai_sub_data {
bool master;
int fmt;
int sync;
+ int synco;
+ int synci;
int fs_length;
int slots;
int slot_width;
@@ -184,7 +196,6 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
static irqreturn_t stm32_sai_isr(int irq, void *devid)
{
struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
- struct snd_pcm_substream *substream = sai->substream;
struct platform_device *pdev = sai->pdev;
unsigned int sr, imr, flags;
snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
@@ -199,6 +210,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
SAI_XCLRFR_MASK);
+ if (!sai->substream) {
+ dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
+ return IRQ_NONE;
+ }
+
if (flags & SAI_XIMR_OVRUDRIE) {
dev_err(&pdev->dev, "IRQ %s\n",
STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
@@ -227,9 +243,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
}
if (status != SNDRV_PCM_STATE_RUNNING) {
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(substream);
+ snd_pcm_stream_lock(sai->substream);
+ snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(sai->substream);
}
return IRQ_HANDLED;
@@ -304,12 +320,15 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
- int cr1 = 0, frcr = 0;
- int cr1_mask = 0, frcr_mask = 0;
+ int cr1, frcr = 0;
+ int cr1_mask, frcr_mask = 0;
int ret;
dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
+ cr1_mask = SAI_XCR1_PRTCFG_MASK;
+ cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
/* SCK active high for all protocols */
case SND_SOC_DAIFMT_I2S:
@@ -336,7 +355,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
return -EINVAL;
}
- cr1_mask |= SAI_XCR1_PRTCFG_MASK | SAI_XCR1_CKSTR;
+ cr1_mask |= SAI_XCR1_CKSTR;
frcr_mask |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF |
SAI_XFRCR_FSDEF;
@@ -380,6 +399,14 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
+
+ /* Set slave mode if sub-block is synchronized with another SAI */
+ if (sai->sync) {
+ dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
+ cr1 |= SAI_XCR1_SLAVE;
+ sai->master = false;
+ }
+
cr1_mask |= SAI_XCR1_SLAVE;
/* do not generate master by default */
@@ -412,8 +439,6 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
}
/* Enable ITs */
- regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
- SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
@@ -442,34 +467,33 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
{
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int cr1, cr1_mask, ret;
- int fth = STM_SAI_FIFO_TH_HALF;
- /* FIFO config */
+ /*
+ * DMA bursts increment is set to 4 words.
+ * SAI fifo threshold is set to half fifo, to keep enough space
+ * for DMA incoming bursts.
+ */
regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX,
SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
- SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
+ SAI_XCR2_FFLUSH |
+ SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
/* Mode, data format and channel config */
- cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+ cr1_mask = SAI_XCR1_DS_MASK;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
- cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_8);
+ cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_8);
break;
case SNDRV_PCM_FORMAT_S16_LE:
- cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_16);
+ cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_16);
break;
case SNDRV_PCM_FORMAT_S32_LE:
- cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_32);
+ cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_32);
break;
default:
dev_err(cpu_dai->dev, "Data format not supported");
return -EINVAL;
}
- cr1_mask = SAI_XCR1_DS_MASK | SAI_XCR1_PRTCFG_MASK;
-
- cr1_mask |= SAI_XCR1_RX_TX;
- if (STM_SAI_IS_CAPTURE(sai))
- cr1 |= SAI_XCR1_RX_TX;
cr1_mask |= SAI_XCR1_MONO;
if ((sai->slots == 2) && (params_channels(params) == 1))
@@ -481,10 +505,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
return ret;
}
- /* DMA config */
- sai->dma_params.maxburst = STM_SAI_FIFO_SIZE * fth / sizeof(u32);
- snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&sai->dma_params);
-
return 0;
}
@@ -691,6 +711,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_STOP:
dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
+ regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+ SAI_XIMR_MASK, 0);
+
regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
SAI_XCR1_SAIEN,
(unsigned int)~SAI_XCR1_SAIEN);
@@ -725,9 +748,15 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+ int cr1 = 0, cr1_mask;
sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
- sai->dma_params.maxburst = 1;
+ /*
+ * DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice,
+ * as it allows bytes, half-word and words transfers. (See DMA fifos
+ * constraints).
+ */
+ sai->dma_params.maxburst = 4;
/* Buswidth will be set by framework at runtime */
sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
@@ -736,7 +765,21 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
else
snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
- return 0;
+ cr1_mask = SAI_XCR1_RX_TX;
+ if (STM_SAI_IS_CAPTURE(sai))
+ cr1 |= SAI_XCR1_RX_TX;
+
+ /* Configure synchronization */
+ if (sai->sync == SAI_SYNC_EXTERNAL) {
+ /* Configure synchro client and provider */
+ sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
+ sai->synco, sai->synci);
+ }
+
+ cr1_mask |= SAI_XCR1_SYNCEN_MASK;
+ cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
+
+ return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
}
static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
@@ -822,6 +865,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node;
struct resource *res;
void __iomem *base;
+ struct of_phandle_args args;
+ int ret;
if (!np)
return -ENODEV;
@@ -855,6 +900,69 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
return -EINVAL;
}
+ /* Get synchronization property */
+ args.np = NULL;
+ ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
+ if (ret < 0 && ret != -ENOENT) {
+ dev_err(&pdev->dev, "Failed to get st,sync property\n");
+ return ret;
+ }
+
+ sai->sync = SAI_SYNC_NONE;
+ if (args.np) {
+ if (args.np == np) {
+ dev_err(&pdev->dev, "%s sync own reference\n",
+ np->name);
+ of_node_put(args.np);
+ return -EINVAL;
+ }
+
+ sai->np_sync_provider = of_get_parent(args.np);
+ if (!sai->np_sync_provider) {
+ dev_err(&pdev->dev, "%s parent node not found\n",
+ np->name);
+ of_node_put(args.np);
+ return -ENODEV;
+ }
+
+ sai->sync = SAI_SYNC_INTERNAL;
+ if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
+ if (!STM_SAI_HAS_EXT_SYNC(sai)) {
+ dev_err(&pdev->dev,
+ "External synchro not supported\n");
+ of_node_put(args.np);
+ return -EINVAL;
+ }
+ sai->sync = SAI_SYNC_EXTERNAL;
+
+ sai->synci = args.args[0];
+ if (sai->synci < 1 ||
+ (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
+ dev_err(&pdev->dev, "Wrong SAI index\n");
+ of_node_put(args.np);
+ return -EINVAL;
+ }
+
+ if (of_property_match_string(args.np, "compatible",
+ "st,stm32-sai-sub-a") >= 0)
+ sai->synco = STM_SAI_SYNC_OUT_A;
+
+ if (of_property_match_string(args.np, "compatible",
+ "st,stm32-sai-sub-b") >= 0)
+ sai->synco = STM_SAI_SYNC_OUT_B;
+
+ if (!sai->synco) {
+ dev_err(&pdev->dev, "Unknown SAI sub-block\n");
+ of_node_put(args.np);
+ return -EINVAL;
+ }
+ }
+
+ dev_dbg(&pdev->dev, "%s synchronized with %s\n",
+ pdev->name, args.np->full_name);
+ }
+
+ of_node_put(args.np);
sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
if (IS_ERR(sai->sai_ck)) {
dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 84cc5678beba..b9bdefcd3e10 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -392,6 +392,12 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev,
{
int ret;
+ spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl");
+ if (IS_ERR(spdifrx->ctrl_chan)) {
+ dev_err(dev, "dma_request_slave_channel failed\n");
+ return PTR_ERR(spdifrx->ctrl_chan);
+ }
+
spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer),
GFP_KERNEL);
if (!spdifrx->dmab)
@@ -406,12 +412,6 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev,
return ret;
}
- spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl");
- if (!spdifrx->ctrl_chan) {
- dev_err(dev, "dma_request_slave_channel failed\n");
- return -EINVAL;
- }
-
spdifrx->slave_config.direction = DMA_DEV_TO_MEM;
spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr +
STM32_SPDIFRX_CSR);
@@ -423,7 +423,6 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev,
&spdifrx->slave_config);
if (ret < 0) {
dev_err(dev, "dmaengine_slave_config returned error %d\n", ret);
- dma_release_channel(spdifrx->ctrl_chan);
spdifrx->ctrl_chan = NULL;
}
@@ -750,17 +749,21 @@ static int stm32_spdifrx_hw_params(struct snd_pcm_substream *substream,
switch (data_size) {
case 16:
fmt = SPDIFRX_DRFMT_PACKED;
- spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
case 32:
fmt = SPDIFRX_DRFMT_LEFT;
- spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
break;
default:
dev_err(&spdifrx->pdev->dev, "Unexpected data format\n");
return -EINVAL;
}
+ /*
+ * Set buswidth to 4 bytes for all data formats.
+ * Packed format: transfer 2 x 2 bytes samples
+ * Left format: transfer 1 x 3 bytes samples + 1 dummy byte
+ */
+ spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params);
return regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR,
@@ -958,7 +961,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
return 0;
error:
- if (spdifrx->ctrl_chan)
+ if (!IS_ERR(spdifrx->ctrl_chan))
dma_release_channel(spdifrx->ctrl_chan);
if (spdifrx->dmab)
snd_dma_free_pages(spdifrx->dmab);
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index baa9007464ed..5da4efe7a550 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -346,11 +346,6 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
0x3 << 8,
0x1 << 8);
- /* Fill most significant bits with valid data MSB */
- regmap_field_update_bits(scodec->reg_adc_fifoc,
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
-
return 0;
}
@@ -490,6 +485,30 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
0);
+ /* Set the number of sample bits to either 16 or 24 bits */
+ if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
+
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
+ 0);
+
+ scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ } else {
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
+ 0);
+
+ /* Fill most significant bits with valid data MSB */
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
+
+ scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ }
+
return 0;
}
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index abfb710df7cb..3dd183be08a4 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -73,6 +73,7 @@
#define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8)
#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4)
#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6)
+#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
struct sun8i_codec {
struct device *dev;
@@ -170,11 +171,11 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* clock masters */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS: /* DAI Slave */
- value = 0x0; /* Codec Master */
+ case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
+ value = 0x1;
break;
- case SND_SOC_DAIFMT_CBM_CFM: /* DAI Master */
- value = 0x1; /* Codec Slave */
+ case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
+ value = 0x0;
break;
default:
return -EINVAL;
@@ -197,9 +198,20 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
+
+ /*
+ * It appears that the DAI and the codec don't share the same
+ * polarity for the LRCK signal when they mean 'normal' and
+ * 'inverted' in the datasheet.
+ *
+ * Since the DAI here is our regular i2s driver that have been
+ * tested with way more codecs than just this one, it means
+ * that the codec probably gets it backward, and we have to
+ * invert the value here.
+ */
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
- value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
+ !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
/* DAI format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -226,12 +238,57 @@ static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+struct sun8i_codec_clk_div {
+ u8 div;
+ u8 val;
+};
+
+static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
+ { .div = 1, .val = 0 },
+ { .div = 2, .val = 1 },
+ { .div = 4, .val = 2 },
+ { .div = 6, .val = 3 },
+ { .div = 8, .val = 4 },
+ { .div = 12, .val = 5 },
+ { .div = 16, .val = 6 },
+ { .div = 24, .val = 7 },
+ { .div = 32, .val = 8 },
+ { .div = 48, .val = 9 },
+ { .div = 64, .val = 10 },
+ { .div = 96, .val = 11 },
+ { .div = 128, .val = 12 },
+ { .div = 192, .val = 13 },
+};
+
+static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
+ unsigned int rate,
+ unsigned int word_size)
+{
+ unsigned long clk_rate = clk_get_rate(scodec->clk_module);
+ unsigned int div = clk_rate / rate / word_size / 2;
+ unsigned int best_val = 0, best_diff = ~0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
+ const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
+ unsigned int diff = abs(bdiv->div - div);
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_val = bdiv->val;
+ }
+ }
+
+ return best_val;
+}
+
static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
int sample_rate;
+ u8 bclk_div;
/*
* The CPU DAI handles only a sample of 16 bits. Configure the
@@ -241,6 +298,11 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
+ bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
+ regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+ SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
+ bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
+
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
diff --git a/sound/soc/zte/zx-spdif.c b/sound/soc/zte/zx-spdif.c
index b143f9f682d2..17b6ce35037a 100644
--- a/sound/soc/zte/zx-spdif.c
+++ b/sound/soc/zte/zx-spdif.c
@@ -139,11 +139,11 @@ static int zx_spdif_hw_params(struct snd_pcm_substream *substream,
{
struct zx_spdif_info *zx_spdif = dev_get_drvdata(socdai->dev);
struct zx_spdif_info *spdif = snd_soc_dai_get_drvdata(socdai);
- struct snd_dmaengine_dai_dma_data *dma_data = &zx_spdif->dma_data;
+ struct snd_dmaengine_dai_dma_data *dma_data =
+ snd_soc_dai_get_dma_data(socdai, substream);
u32 val, ch_num, rate;
int ret;
- dma_data = snd_soc_dai_get_dma_data(socdai, substream);
dma_data->addr_width = params_width(params) >> 3;
val = readl_relaxed(zx_spdif->reg_base + ZX_CTRL);