summaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/amd/Kconfig9
-rw-r--r--sound/soc/amd/Makefile2
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c276
-rw-r--r--sound/soc/amd/acp-pcm-dma.c177
-rw-r--r--sound/soc/amd/acp.h8
-rw-r--r--sound/soc/codecs/Kconfig6
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ak5386.c62
-rw-r--r--sound/soc/codecs/ak5558.c415
-rw-r--r--sound/soc/codecs/ak5558.h52
-rw-r--r--sound/soc/codecs/alc5623.c147
-rw-r--r--sound/soc/codecs/alc5632.c138
12 files changed, 1022 insertions, 272 deletions
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index d5838402f667..6cbf9cf4d1a4 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -3,6 +3,15 @@ config SND_SOC_AMD_ACP
help
This option enables ACP DMA support on AMD platform.
+config SND_SOC_AMD_CZ_DA7219MX98357_MACH
+ tristate "AMD CZ support for DA7219 and MAX9835"
+ select SND_SOC_DA7219
+ select SND_SOC_MAX98357A
+ select SND_SOC_ADAU7002
+ depends on SND_SOC_AMD_ACP && I2C
+ help
+ This option enables machine driver for DA7219 and MAX9835.
+
config SND_SOC_AMD_CZ_RT5645_MACH
tristate "AMD CZ support for RT5645"
select SND_SOC_RT5645
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index f07fd2e2870a..79b0622fa5d3 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -1,5 +1,7 @@
acp_audio_dma-objs := acp-pcm-dma.o
+snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o
snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
+obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
new file mode 100644
index 000000000000..b205c782e494
--- /dev/null
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -0,0 +1,276 @@
+/*
+ * Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec
+ *
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * 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/clk.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+
+#include "../codecs/da7219.h"
+#include "../codecs/da7219-aad.h"
+
+#define CZ_PLAT_CLK 24000000
+#define MCLK_RATE 24576000
+#define DUAL_CHANNEL 2
+
+static struct snd_soc_jack cz_jack;
+struct clk *da7219_dai_clk;
+
+static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_component *component = codec_dai->component;
+
+ dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK,
+ CZ_PLAT_CLK, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL,
+ CZ_PLAT_CLK, MCLK_RATE);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+
+ da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
+
+ 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;
+ }
+
+ da7219_aad_jack_det(component, &cz_jack);
+
+ return 0;
+}
+
+static int cz_da7219_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;
+
+ ret = clk_prepare_enable(da7219_dai_clk);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't enable master clock %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cz_da7219_hw_free(struct snd_pcm_substream *substream)
+{
+ clk_disable_unprepare(da7219_dai_clk);
+
+ return 0;
+}
+
+static const unsigned int channels[] = {
+ DUAL_CHANNEL,
+};
+
+static const unsigned int rates[] = {
+ 48000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static int cz_fe_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ /*
+ * On this platform for PCM device we support stereo
+ */
+
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+
+ return 0;
+}
+
+static struct snd_soc_ops cz_da7219_cap_ops = {
+ .hw_params = cz_da7219_hw_params,
+ .hw_free = cz_da7219_hw_free,
+ .startup = cz_fe_startup,
+};
+
+static struct snd_soc_ops cz_max_play_ops = {
+ .hw_params = cz_da7219_hw_params,
+ .hw_free = cz_da7219_hw_free,
+};
+
+static struct snd_soc_ops cz_dmic_cap_ops = {
+ .hw_params = cz_da7219_hw_params,
+ .hw_free = cz_da7219_hw_free,
+};
+
+static struct snd_soc_dai_link cz_dai_7219_98357[] = {
+ {
+ .name = "amd-da7219-play-cap",
+ .stream_name = "Playback and Capture",
+ .platform_name = "acp_audio_dma.0.auto",
+ .cpu_dai_name = "designware-i2s.3.auto",
+ .codec_dai_name = "da7219-hifi",
+ .codec_name = "i2c-DLGS7219:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .init = cz_da7219_init,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &cz_da7219_cap_ops,
+ },
+ {
+ .name = "amd-max98357-play",
+ .stream_name = "HiFi Playback",
+ .platform_name = "acp_audio_dma.0.auto",
+ .cpu_dai_name = "designware-i2s.1.auto",
+ .codec_dai_name = "HiFi",
+ .codec_name = "MX98357A:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .dpcm_playback = 1,
+ .ops = &cz_max_play_ops,
+ },
+ {
+ .name = "dmic",
+ .stream_name = "DMIC Capture",
+ .platform_name = "acp_audio_dma.0.auto",
+ .cpu_dai_name = "designware-i2s.2.auto",
+ .codec_dai_name = "adau7002-hifi",
+ .codec_name = "ADAU7002:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .dpcm_capture = 1,
+ .ops = &cz_dmic_cap_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, "HPL"},
+ {"Headphones", NULL, "HPR"},
+ {"MIC", NULL, "Headset Mic"},
+ {"Speakers", NULL, "Speaker"},
+ {"PDM_DAT", 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 = "acpd7219m98357",
+ .owner = THIS_MODULE,
+ .dai_link = cz_dai_7219_98357,
+ .num_links = ARRAY_SIZE(cz_dai_7219_98357),
+ .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[] = {
+ { "AMD7219", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
+
+static struct platform_driver cz_pcm_driver = {
+ .driver = {
+ .name = "cz-da7219-max98357a",
+ .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("DA7219 & MAX98357A audio support");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index a586999ede6f..540088d317f2 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -184,19 +184,18 @@ 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 asic_type)
+ u32 size, int direction, u32 pte_offset,
+ u16 ch, u32 sram_bank,
+ u16 dma_dscr_idx, u32 asic_type)
{
u16 i;
- u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
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
- + (i * (size/2));
+ dma_dscr_idx = dma_dscr_idx + i;
+ dmadscr[i].dest = sram_bank + (i * (size/2));
dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
+ (pte_offset * SZ_4K) + (i * (size/2));
switch (asic_type) {
@@ -211,25 +210,19 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
(size / 2);
}
} else {
- dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i;
+ dma_dscr_idx = dma_dscr_idx + i;
+ dmadscr[i].src = sram_bank + (i * (size/2));
+ dmadscr[i].dest =
+ ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
+ (pte_offset * SZ_4K) + (i * (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) |
@@ -239,72 +232,49 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
&dmadscr[i]);
}
- if (direction == SNDRV_PCM_STREAM_PLAYBACK)
- config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM,
- PLAYBACK_START_DMA_DESCR_CH12,
- NUM_DSCRS_PER_CHANNEL,
- ACP_DMA_PRIORITY_LEVEL_NORMAL);
- else
- config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM,
- CAPTURE_START_DMA_DESCR_CH14,
- NUM_DSCRS_PER_CHANNEL,
- ACP_DMA_PRIORITY_LEVEL_NORMAL);
+ config_acp_dma_channel(acp_mmio, ch,
+ dma_dscr_idx - 1,
+ NUM_DSCRS_PER_CHANNEL,
+ ACP_DMA_PRIORITY_LEVEL_NORMAL);
}
/* Initialize the DMA descriptor information for transfer between
* ACP SRAM <-> I2S
*/
-static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
- u32 size, int direction,
- u32 asic_type)
+static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
+ int direction, u32 sram_bank,
+ u16 destination, u16 ch,
+ u16 dma_dscr_idx, u32 asic_type)
{
u16 i;
- u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL];
for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) {
dmadscr[i].xfer_val = 0;
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
- dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i;
- dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS +
- (i * (size/2));
+ dma_dscr_idx = dma_dscr_idx + i;
+ dmadscr[i].src = sram_bank + (i * (size/2));
/* dmadscr[i].dest is unused by hardware. */
dmadscr[i].dest = 0;
- dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) |
+ dmadscr[i].xfer_val |= BIT(22) | (destination << 16) |
(size / 2);
} else {
- dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i;
+ dma_dscr_idx = dma_dscr_idx + i;
/* dmadscr[i].src is unused by hardware. */
dmadscr[i].src = 0;
- 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].dest =
+ sram_bank + (i * (size / 2));
dmadscr[i].xfer_val |= BIT(22) |
- (FROM_ACP_I2S_1 << 16) | (size / 2);
+ (destination << 16) | (size / 2);
}
config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
&dmadscr[i]);
}
/* Configure the DMA channel with the above descriptore */
- if (direction == SNDRV_PCM_STREAM_PLAYBACK)
- config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
- PLAYBACK_START_DMA_DESCR_CH13,
- NUM_DSCRS_PER_CHANNEL,
- ACP_DMA_PRIORITY_LEVEL_NORMAL);
- else
- config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM,
- CAPTURE_START_DMA_DESCR_CH15,
- NUM_DSCRS_PER_CHANNEL,
- ACP_DMA_PRIORITY_LEVEL_NORMAL);
+ config_acp_dma_channel(acp_mmio, ch, dma_dscr_idx - 1,
+ NUM_DSCRS_PER_CHANNEL,
+ ACP_DMA_PRIORITY_LEVEL_NORMAL);
}
/* Create page table entries in ACP SRAM for the allocated memory */
@@ -346,23 +316,51 @@ static void config_acp_dma(void __iomem *acp_mmio,
struct audio_substream_data *audio_config,
u32 asic_type)
{
- u32 pte_offset;
+ u32 pte_offset, sram_bank;
+ u16 ch1, ch2, destination, dma_dscr_idx;
- if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK) {
pte_offset = ACP_PLAYBACK_PTE_OFFSET;
- else
+ ch1 = SYSRAM_TO_ACP_CH_NUM;
+ ch2 = ACP_TO_I2S_DMA_CH_NUM;
+ sram_bank = ACP_SHARED_RAM_BANK_1_ADDRESS;
+ destination = TO_ACP_I2S_1;
+
+ } else {
pte_offset = ACP_CAPTURE_PTE_OFFSET;
+ ch1 = SYSRAM_TO_ACP_CH_NUM;
+ ch2 = ACP_TO_I2S_DMA_CH_NUM;
+ switch (asic_type) {
+ case CHIP_STONEY:
+ sram_bank = ACP_SHARED_RAM_BANK_3_ADDRESS;
+ break;
+ default:
+ sram_bank = ACP_SHARED_RAM_BANK_5_ADDRESS;
+ }
+ destination = FROM_ACP_I2S_1;
+ }
acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages,
pte_offset);
+ if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
+ else
+ dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
/* Configure System memory <-> ACP SRAM DMA descriptors */
set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
- audio_config->direction, pte_offset, asic_type);
+ audio_config->direction, pte_offset,
+ ch1, sram_bank, dma_dscr_idx, asic_type);
+ if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
+ else
+ dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15;
/* Configure ACP SRAM <-> I2S DMA descriptors */
set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
- audio_config->direction, asic_type);
+ audio_config->direction, sram_bank,
+ destination, ch2, dma_dscr_idx,
+ asic_type);
}
/* Start a given DMA channel transfer */
@@ -657,7 +655,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
1, 0);
acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
- snd_pcm_period_elapsed(irq_data->play_stream);
+ snd_pcm_period_elapsed(irq_data->play_i2ssp_stream);
acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16,
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
@@ -680,7 +678,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
valid_irq = true;
- snd_pcm_period_elapsed(irq_data->capture_stream);
+ snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
}
@@ -738,11 +736,11 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
* This enablement is not required for another stream, if current
* stream is not closed
*/
- if (!intr_data->play_stream && !intr_data->capture_stream)
+ if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream)
acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- intr_data->play_stream = substream;
+ intr_data->play_i2ssp_stream = substream;
/* 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.
@@ -753,7 +751,7 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
bank, true);
}
} else {
- intr_data->capture_stream = substream;
+ intr_data->capture_i2ssp_stream = substream;
if (intr_data->asic_type != CHIP_STONEY) {
for (bank = 5; bank <= 8; bank++)
acp_set_sram_bank_state(intr_data->acp_mmio,
@@ -862,11 +860,11 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
bytescount = acp_get_byte_count(rtd->acp_mmio, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (bytescount > rtd->renderbytescount)
- bytescount = bytescount - rtd->renderbytescount;
+ if (bytescount > rtd->i2ssp_renderbytescount)
+ bytescount = bytescount - rtd->i2ssp_renderbytescount;
} else {
- if (bytescount > rtd->capturebytescount)
- bytescount = bytescount - rtd->capturebytescount;
+ if (bytescount > rtd->i2ssp_capturebytescount)
+ bytescount = bytescount - rtd->i2ssp_capturebytescount;
}
pos = do_div(bytescount, buffersize);
return bytes_to_frames(runtime, pos);
@@ -923,8 +921,8 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
bytescount = acp_get_byte_count(rtd->acp_mmio,
substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (rtd->renderbytescount == 0)
- rtd->renderbytescount = bytescount;
+ if (rtd->i2ssp_renderbytescount == 0)
+ rtd->i2ssp_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) &
@@ -941,8 +939,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;
+ if (rtd->i2ssp_capturebytescount == 0)
+ rtd->i2ssp_capturebytescount = bytescount;
acp_dma_start(rtd->acp_mmio,
I2S_TO_ACP_DMA_CH_NUM, true);
}
@@ -958,12 +956,16 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = acp_dma_stop(rtd->acp_mmio,
+ SYSRAM_TO_ACP_CH_NUM);
+ ret = acp_dma_stop(rtd->acp_mmio,
ACP_TO_I2S_DMA_CH_NUM);
- rtd->renderbytescount = 0;
+ rtd->i2ssp_renderbytescount = 0;
} else {
ret = acp_dma_stop(rtd->acp_mmio,
I2S_TO_ACP_DMA_CH_NUM);
- rtd->capturebytescount = 0;
+ ret = acp_dma_stop(rtd->acp_mmio,
+ ACP_TO_SYSRAM_CH_NUM);
+ rtd->i2ssp_capturebytescount = 0;
}
break;
default:
@@ -1011,7 +1013,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
kfree(rtd);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- adata->play_stream = NULL;
+ adata->play_i2ssp_stream = NULL;
/* 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.
@@ -1023,7 +1025,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
false);
}
} else {
- adata->capture_stream = NULL;
+ adata->capture_i2ssp_stream = NULL;
if (adata->asic_type != CHIP_STONEY) {
for (bank = 5; bank <= 8; bank++)
acp_set_sram_bank_state(adata->acp_mmio, bank,
@@ -1034,7 +1036,7 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
/* Disable ACP irq, when the current stream is being closed and
* another stream is also not active.
*/
- if (!adata->play_stream && !adata->capture_stream)
+ if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream)
acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
return 0;
@@ -1085,8 +1087,9 @@ static int acp_audio_probe(struct platform_device *pdev)
* and device doesn't generate any interrupts.
*/
- audio_drv_data->play_stream = NULL;
- audio_drv_data->capture_stream = NULL;
+ audio_drv_data->play_i2ssp_stream = NULL;
+ audio_drv_data->capture_i2ssp_stream = NULL;
+
audio_drv_data->asic_type = *pdata;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -1150,7 +1153,7 @@ static int acp_pcm_resume(struct device *dev)
return status;
}
- if (adata->play_stream && adata->play_stream->runtime) {
+ if (adata->play_i2ssp_stream && adata->play_i2ssp_stream->runtime) {
/* 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.
@@ -1161,17 +1164,17 @@ static int acp_pcm_resume(struct device *dev)
true);
}
config_acp_dma(adata->acp_mmio,
- adata->play_stream->runtime->private_data,
+ adata->play_i2ssp_stream->runtime->private_data,
adata->asic_type);
}
- if (adata->capture_stream && adata->capture_stream->runtime) {
+ if (adata->capture_i2ssp_stream && adata->capture_i2ssp_stream->runtime) {
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_i2ssp_stream->runtime->private_data,
adata->asic_type);
}
acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index 9293f179f272..ba01510eb818 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -86,14 +86,14 @@ struct audio_substream_data {
u16 num_of_pages;
u16 direction;
uint64_t size;
- u64 renderbytescount;
- u64 capturebytescount;
+ u64 i2ssp_renderbytescount;
+ u64 i2ssp_capturebytescount;
void __iomem *acp_mmio;
};
struct audio_drv_data {
- struct snd_pcm_substream *play_stream;
- struct snd_pcm_substream *capture_stream;
+ struct snd_pcm_substream *play_i2ssp_stream;
+ struct snd_pcm_substream *capture_i2ssp_stream;
void __iomem *acp_mmio;
u32 asic_type;
};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0158aa1db84c..7f637521dd42 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK4642 if I2C
select SND_SOC_AK4671 if I2C
select SND_SOC_AK5386
+ select SND_SOC_AK5558 if I2C
select SND_SOC_ALC5623 if I2C
select SND_SOC_ALC5632 if I2C
select SND_SOC_BT_SCO
@@ -405,6 +406,11 @@ config SND_SOC_AK4671
config SND_SOC_AK5386
tristate "AKM AK5638 CODEC"
+config SND_SOC_AK5558
+ tristate "AKM AK5558 CODEC"
+ depends on I2C
+ select REGMAP_I2C
+
config SND_SOC_ALC5623
tristate "Realtek ALC5623 CODEC"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 082f26977912..bc5eff111337 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -35,6 +35,7 @@ snd-soc-ak4641-objs := ak4641.o
snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-ak5386-objs := ak5386.o
+snd-soc-ak5558-objs := ak5558.o
snd-soc-arizona-objs := arizona.o
snd-soc-bt-sco-objs := bt-sco.o
snd-soc-cq93vc-objs := cq93vc.o
@@ -281,6 +282,7 @@ obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.o
+obj-$(CONFIG_SND_SOC_AK5558) += snd-soc-ak5558.o
obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index d0e16c03815c..d212960b4dda 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -38,30 +38,29 @@ static const struct snd_soc_dapm_route ak5386_dapm_routes[] = {
{ "Capture", NULL, "AINR" },
};
-static int ak5386_soc_probe(struct snd_soc_codec *codec)
+static int ak5386_soc_probe(struct snd_soc_component *component)
{
- struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
}
-static int ak5386_soc_remove(struct snd_soc_codec *codec)
+static void ak5386_soc_remove(struct snd_soc_component *component)
{
- struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
- return 0;
}
#ifdef CONFIG_PM
-static int ak5386_soc_suspend(struct snd_soc_codec *codec)
+static int ak5386_soc_suspend(struct snd_soc_component *component)
{
- struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies);
return 0;
}
-static int ak5386_soc_resume(struct snd_soc_codec *codec)
+static int ak5386_soc_resume(struct snd_soc_component *component)
{
- struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
}
#else
@@ -69,28 +68,30 @@ static int ak5386_soc_resume(struct snd_soc_codec *codec)
#define ak5386_soc_resume NULL
#endif /* CONFIG_PM */
-static const struct snd_soc_codec_driver soc_codec_ak5386 = {
- .probe = ak5386_soc_probe,
- .remove = ak5386_soc_remove,
- .suspend = ak5386_soc_suspend,
- .resume = ak5386_soc_resume,
- .component_driver = {
- .dapm_widgets = ak5386_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets),
- .dapm_routes = ak5386_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes),
- },
+static const struct snd_soc_component_driver soc_component_ak5386 = {
+ .probe = ak5386_soc_probe,
+ .remove = ak5386_soc_remove,
+ .suspend = ak5386_soc_suspend,
+ .resume = ak5386_soc_resume,
+ .dapm_widgets = ak5386_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets),
+ .dapm_routes = ak5386_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
};
static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int format)
{
- struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_component *component = codec_dai->component;
format &= SND_SOC_DAIFMT_FORMAT_MASK;
if (format != SND_SOC_DAIFMT_LEFT_J &&
format != SND_SOC_DAIFMT_I2S) {
- dev_err(codec->dev, "Invalid DAI format\n");
+ dev_err(component->dev, "Invalid DAI format\n");
return -EINVAL;
}
@@ -101,8 +102,8 @@ static int ak5386_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_codec *codec = dai->codec;
- struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
/*
* From the datasheet:
@@ -123,8 +124,8 @@ static int ak5386_hw_params(struct snd_pcm_substream *substream,
static int ak5386_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_codec *codec = dai->codec;
- struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *component = dai->component;
+ struct ak5386_priv *priv = snd_soc_component_get_drvdata(component);
if (gpio_is_valid(priv->reset_gpio))
gpio_set_value(priv->reset_gpio, 0);
@@ -192,19 +193,12 @@ static int ak5386_probe(struct platform_device *pdev)
"AK5386 Reset"))
priv->reset_gpio = -EINVAL;
- return snd_soc_register_codec(dev, &soc_codec_ak5386,
+ return devm_snd_soc_register_component(dev, &soc_component_ak5386,
&ak5386_dai, 1);
}
-static int ak5386_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_codec(&pdev->dev);
- return 0;
-}
-
static struct platform_driver ak5386_driver = {
.probe = ak5386_probe,
- .remove = ak5386_remove,
.driver = {
.name = "ak5386",
.of_match_table = of_match_ptr(ak5386_dt_ids),
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
new file mode 100644
index 000000000000..f4ed5cc40661
--- /dev/null
+++ b/sound/soc/codecs/ak5558.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Audio driver for AK5558 ADC
+//
+// Copyright (C) 2015 Asahi Kasei Microdevices Corporation
+// Copyright 2018 NXP
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "ak5558.h"
+
+/* AK5558 Codec Private Data */
+struct ak5558_priv {
+ struct snd_soc_component component;
+ struct regmap *regmap;
+ struct i2c_client *i2c;
+ struct gpio_desc *reset_gpiod; /* Reset & Power down GPIO */
+ int slots;
+ int slot_width;
+};
+
+/* ak5558 register cache & default register settings */
+static const struct reg_default ak5558_reg[] = {
+ { 0x0, 0xFF }, /* 0x00 AK5558_00_POWER_MANAGEMENT1 */
+ { 0x1, 0x01 }, /* 0x01 AK5558_01_POWER_MANAGEMENT2 */
+ { 0x2, 0x01 }, /* 0x02 AK5558_02_CONTROL1 */
+ { 0x3, 0x00 }, /* 0x03 AK5558_03_CONTROL2 */
+ { 0x4, 0x00 }, /* 0x04 AK5558_04_CONTROL3 */
+ { 0x5, 0x00 } /* 0x05 AK5558_05_DSD */
+};
+
+static const char * const mono_texts[] = {
+ "8 Slot", "2 Slot", "4 Slot", "1 Slot",
+};
+
+static const struct soc_enum ak5558_mono_enum[] = {
+ SOC_ENUM_SINGLE(AK5558_01_POWER_MANAGEMENT2, 1,
+ ARRAY_SIZE(mono_texts), mono_texts),
+};
+
+static const char * const digfil_texts[] = {
+ "Sharp Roll-Off", "Show Roll-Off",
+ "Short Delay Sharp Roll-Off", "Short Delay Show Roll-Off",
+};
+
+static const struct soc_enum ak5558_adcset_enum[] = {
+ SOC_ENUM_SINGLE(AK5558_04_CONTROL3, 0,
+ ARRAY_SIZE(digfil_texts), digfil_texts),
+};
+
+static const struct snd_kcontrol_new ak5558_snd_controls[] = {
+ SOC_ENUM("AK5558 Monaural Mode", ak5558_mono_enum[0]),
+ SOC_ENUM("AK5558 Digital Filter", ak5558_adcset_enum[0]),
+};
+
+static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = {
+ /* Analog Input */
+ SND_SOC_DAPM_INPUT("AIN1"),
+ SND_SOC_DAPM_INPUT("AIN2"),
+ SND_SOC_DAPM_INPUT("AIN3"),
+ SND_SOC_DAPM_INPUT("AIN4"),
+ SND_SOC_DAPM_INPUT("AIN5"),
+ SND_SOC_DAPM_INPUT("AIN6"),
+ SND_SOC_DAPM_INPUT("AIN7"),
+ SND_SOC_DAPM_INPUT("AIN8"),
+
+ SND_SOC_DAPM_ADC("ADC Ch1", NULL, AK5558_00_POWER_MANAGEMENT1, 0, 0),
+ SND_SOC_DAPM_ADC("ADC Ch2", NULL, AK5558_00_POWER_MANAGEMENT1, 1, 0),
+ SND_SOC_DAPM_ADC("ADC Ch3", NULL, AK5558_00_POWER_MANAGEMENT1, 2, 0),
+ SND_SOC_DAPM_ADC("ADC Ch4", NULL, AK5558_00_P