summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c75
-rw-r--r--sound/soc/amd/acp-pcm-dma.c8
-rw-r--r--sound/soc/amd/acp.h3
-rw-r--r--sound/soc/atmel/Kconfig11
-rw-r--r--sound/soc/atmel/Makefile2
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c13
-rw-r--r--sound/soc/atmel/mikroe-proto.c165
-rw-r--r--sound/soc/atmel/tse850-pcm5142.c78
-rw-r--r--sound/soc/bcm/cygnus-ssp.c13
-rw-r--r--sound/soc/codecs/Kconfig28
-rw-r--r--sound/soc/codecs/Makefile8
-rw-r--r--sound/soc/codecs/adau17x1.c86
-rw-r--r--sound/soc/codecs/adau17x1.h4
-rw-r--r--sound/soc/codecs/cs4265.c7
-rw-r--r--sound/soc/codecs/dmic.c1
-rw-r--r--sound/soc/codecs/hdac_hda.c483
-rw-r--r--sound/soc/codecs/hdac_hda.h24
-rw-r--r--sound/soc/codecs/hdac_hdmi.c9
-rw-r--r--sound/soc/codecs/max98373.c1
-rw-r--r--sound/soc/codecs/pcm3060-i2c.c60
-rw-r--r--sound/soc/codecs/pcm3060-spi.c59
-rw-r--r--sound/soc/codecs/pcm3060.c295
-rw-r--r--sound/soc/codecs/pcm3060.h88
-rw-r--r--sound/soc/codecs/rt5514-spi.c1
-rw-r--r--sound/soc/codecs/rt5668.c4
-rw-r--r--sound/soc/codecs/rt5670.c12
-rw-r--r--sound/soc/codecs/rt5682.c22
-rw-r--r--sound/soc/codecs/sgtl5000.c2
-rw-r--r--sound/soc/codecs/tas5720.c103
-rw-r--r--sound/soc/codecs/tas6424.c58
-rw-r--r--sound/soc/codecs/tas6424.h10
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c85
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h23
-rw-r--r--sound/soc/codecs/tscs454.c2
-rw-r--r--sound/soc/davinci/davinci-mcasp.c37
-rw-r--r--sound/soc/fsl/fsl_esai.c2
-rw-r--r--sound/soc/fsl/fsl_utils.c4
-rw-r--r--sound/soc/generic/audio-graph-card.c18
-rw-r--r--sound/soc/generic/audio-graph-scu-card.c55
-rw-r--r--sound/soc/generic/simple-card-utils.c47
-rw-r--r--sound/soc/generic/simple-card.c30
-rw-r--r--sound/soc/generic/simple-scu-card.c54
-rw-r--r--sound/soc/intel/boards/Kconfig9
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5672.c5
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c5
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c5
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.c127
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.h38
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c182
-rw-r--r--sound/soc/intel/common/Makefile3
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-byt-match.c7
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hda-match.c40
-rw-r--r--sound/soc/intel/common/sst-dsp-priv.h4
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c70
-rw-r--r--sound/soc/intel/skylake/skl-topology.c3
-rw-r--r--sound/soc/intel/skylake/skl.c96
-rw-r--r--sound/soc/intel/skylake/skl.h12
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c5
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c5
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c5
-rw-r--r--sound/soc/meson/Kconfig13
-rw-r--r--sound/soc/meson/Makefile2
-rw-r--r--sound/soc/meson/axg-card.c13
-rw-r--r--sound/soc/meson/axg-fifo.c2
-rw-r--r--sound/soc/meson/axg-pdm.c654
-rw-r--r--sound/soc/meson/axg-tdm-interface.c50
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c4
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c4
-rw-r--r--sound/soc/pxa/Kconfig5
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c48
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6core.c8
-rw-r--r--sound/soc/sh/hac.c3
-rw-r--r--sound/soc/sh/rcar/adg.c4
-rw-r--r--sound/soc/sh/rcar/core.c124
-rw-r--r--sound/soc/sh/rcar/dma.c102
-rw-r--r--sound/soc/sh/rcar/gen.c33
-rw-r--r--sound/soc/sh/rcar/rsnd.h63
-rw-r--r--sound/soc/sh/rcar/ssi.c89
-rw-r--r--sound/soc/sh/rcar/ssiu.c92
-rw-r--r--sound/soc/soc-core.c152
-rw-r--r--sound/soc/soc-dapm.c429
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c2
-rw-r--r--sound/soc/soc-pcm.c156
-rw-r--r--sound/soc/soc-topology.c11
-rw-r--r--sound/soc/stm/stm32_sai.c2
-rw-r--r--sound/soc/stm/stm32_sai_sub.c7
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c3
89 files changed, 3914 insertions, 876 deletions
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index 8e3275a96a82..717a017f0db6 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -42,7 +42,7 @@
#include "../codecs/da7219.h"
#include "../codecs/da7219-aad.h"
-#define CZ_PLAT_CLK 25000000
+#define CZ_PLAT_CLK 48000000
#define DUAL_CHANNEL 2
static struct snd_soc_jack cz_jack;
@@ -133,7 +133,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
.mask = 0,
};
-static int cz_da7219_startup(struct snd_pcm_substream *substream)
+static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -150,7 +150,28 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
- machine->i2s_instance = I2S_SP_INSTANCE;
+ machine->play_i2s_instance = I2S_SP_INSTANCE;
+ return da7219_clk_enable(substream);
+}
+
+static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
+
+ /*
+ * 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);
+
+ machine->cap_i2s_instance = I2S_SP_INSTANCE;
machine->capture_channel = CAP_CHANNEL1;
return da7219_clk_enable(substream);
}
@@ -162,11 +183,22 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
static int cz_max_startup(struct snd_pcm_substream *substream)
{
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
- machine->i2s_instance = I2S_BT_INSTANCE;
+ /*
+ * 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);
+
+ machine->play_i2s_instance = I2S_BT_INSTANCE;
return da7219_clk_enable(substream);
}
@@ -177,21 +209,43 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream)
static int cz_dmic0_startup(struct snd_pcm_substream *substream)
{
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
- machine->i2s_instance = I2S_BT_INSTANCE;
+ /*
+ * 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);
+
+ machine->cap_i2s_instance = I2S_BT_INSTANCE;
return da7219_clk_enable(substream);
}
static int cz_dmic1_startup(struct snd_pcm_substream *substream)
{
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
- machine->i2s_instance = I2S_SP_INSTANCE;
+ /*
+ * 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);
+
+ machine->cap_i2s_instance = I2S_SP_INSTANCE;
machine->capture_channel = CAP_CHANNEL0;
return da7219_clk_enable(substream);
}
@@ -201,8 +255,13 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
da7219_clk_disable();
}
+static const struct snd_soc_ops cz_da7219_play_ops = {
+ .startup = cz_da7219_play_startup,
+ .shutdown = cz_da7219_shutdown,
+};
+
static const struct snd_soc_ops cz_da7219_cap_ops = {
- .startup = cz_da7219_startup,
+ .startup = cz_da7219_cap_startup,
.shutdown = cz_da7219_shutdown,
};
@@ -233,7 +292,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
| SND_SOC_DAIFMT_CBM_CFM,
.init = cz_da7219_init,
.dpcm_playback = 1,
- .ops = &cz_da7219_cap_ops,
+ .ops = &cz_da7219_play_ops,
},
{
.name = "amd-da7219-cap",
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 77b265bd0505..c7e972b17c90 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -867,8 +867,12 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
if (pinfo) {
- rtd->i2s_instance = pinfo->i2s_instance;
- rtd->capture_channel = pinfo->capture_channel;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ rtd->i2s_instance = pinfo->play_i2s_instance;
+ } else {
+ rtd->i2s_instance = pinfo->cap_i2s_instance;
+ rtd->capture_channel = pinfo->capture_channel;
+ }
}
if (adata->asic_type == CHIP_STONEY) {
val = acp_reg_read(adata->acp_mmio,
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index be3963e8f4fa..dbbb1a85638d 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -158,7 +158,8 @@ struct audio_drv_data {
* and dma driver
*/
struct acp_platform_info {
- u16 i2s_instance;
+ u16 play_i2s_instance;
+ u16 cap_i2s_instance;
u16 capture_channel;
};
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 64b784e96f84..81a0712d4f14 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -97,4 +97,15 @@ config SND_ATMEL_SOC_I2S
help
Say Y or M if you want to add support for Atmel ASoc driver for boards
using I2S.
+
+config SND_SOC_MIKROE_PROTO
+ tristate "Support for Mikroe-PROTO board"
+ depends on OF
+ select SND_SOC_WM8731
+ help
+ Say Y or M if you want to add support for MikroElektronika PROTO Audio
+ Board. This board contains the WM8731 codec, which can be configured
+ using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins.
+ Both playback and capture are supported.
+
endif
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index cd87cb4bcff5..9f41bfa0fea3 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -17,6 +17,7 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
snd-atmel-soc-classd-objs := atmel-classd.o
snd-atmel-soc-pdmic-objs := atmel-pdmic.o
snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
+snd-soc-mikroe-proto-objs := mikroe-proto.o
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
@@ -24,3 +25,4 @@ obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o
+obj-$(CONFIG_SND_SOC_MIKROE_PROTO) += snd-soc-mikroe-proto.o
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index d3b69682d9c2..6291ec7f9dd6 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -1005,11 +1005,11 @@ static int asoc_ssc_init(struct device *dev)
struct ssc_device *ssc = dev_get_drvdata(dev);
int ret;
- ret = snd_soc_register_component(dev, &atmel_ssc_component,
+ ret = devm_snd_soc_register_component(dev, &atmel_ssc_component,
&atmel_ssc_dai, 1);
if (ret) {
dev_err(dev, "Could not register DAI: %d\n", ret);
- goto err;
+ return ret;
}
if (ssc->pdata->use_dma)
@@ -1019,15 +1019,10 @@ static int asoc_ssc_init(struct device *dev)
if (ret) {
dev_err(dev, "Could not register PCM: %d\n", ret);
- goto err_unregister_dai;
+ return ret;
}
return 0;
-
-err_unregister_dai:
- snd_soc_unregister_component(dev);
-err:
- return ret;
}
static void asoc_ssc_exit(struct device *dev)
@@ -1038,8 +1033,6 @@ static void asoc_ssc_exit(struct device *dev)
atmel_pcm_dma_platform_unregister(dev);
else
atmel_pcm_pdc_platform_unregister(dev);
-
- snd_soc_unregister_component(dev);
}
/**
diff --git a/sound/soc/atmel/mikroe-proto.c b/sound/soc/atmel/mikroe-proto.c
new file mode 100644
index 000000000000..d47aaa5bf75a
--- /dev/null
+++ b/sound/soc/atmel/mikroe-proto.c
@@ -0,0 +1,165 @@
+/*
+ * ASoC driver for PROTO AudioCODEC (with a WM8731)
+ *
+ * Author: Florian Meier, <koalo@koalo.de>
+ * Copyright 2013
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "../codecs/wm8731.h"
+
+#define XTAL_RATE 12288000 /* This is fixed on this board */
+
+static int snd_proto_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Set proto sysclk */
+ int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
+ XTAL_RATE, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget snd_proto_widget[] = {
+ SND_SOC_DAPM_MIC("Microphone Jack", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route snd_proto_route[] = {
+ /* speaker connected to LHPOUT/RHPOUT */
+ {"Headphone Jack", NULL, "LHPOUT"},
+ {"Headphone Jack", NULL, "RHPOUT"},
+
+ /* mic is connected to Mic Jack, with WM8731 Mic Bias */
+ {"MICIN", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Microphone Jack"},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_proto = {
+ .name = "snd_mikroe_proto",
+ .owner = THIS_MODULE,
+ .dapm_widgets = snd_proto_widget,
+ .num_dapm_widgets = ARRAY_SIZE(snd_proto_widget),
+ .dapm_routes = snd_proto_route,
+ .num_dapm_routes = ARRAY_SIZE(snd_proto_route),
+};
+
+static int snd_proto_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *dai;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *codec_np, *cpu_np;
+ struct device_node *bitclkmaster = NULL;
+ struct device_node *framemaster = NULL;
+ unsigned int dai_fmt;
+ int ret = 0;
+
+ if (!np) {
+ dev_err(&pdev->dev, "No device node supplied\n");
+ return -EINVAL;
+ }
+
+ snd_proto.dev = &pdev->dev;
+ ret = snd_soc_of_parse_card_name(&snd_proto, "model");
+ if (ret)
+ return ret;
+
+ dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ snd_proto.dai_link = dai;
+ snd_proto.num_links = 1;
+
+ dai->name = "WM8731";
+ dai->stream_name = "WM8731 HiFi";
+ dai->codec_dai_name = "wm8731-hifi";
+ dai->init = &snd_proto_init;
+
+ codec_np = of_parse_phandle(np, "audio-codec", 0);
+ if (!codec_np) {
+ dev_err(&pdev->dev, "audio-codec node missing\n");
+ return -EINVAL;
+ }
+ dai->codec_of_node = codec_np;
+
+ cpu_np = of_parse_phandle(np, "i2s-controller", 0);
+ if (!cpu_np) {
+ dev_err(&pdev->dev, "i2s-controller missing\n");
+ return -EINVAL;
+ }
+ dai->cpu_of_node = cpu_np;
+ dai->platform_of_node = cpu_np;
+
+ dai_fmt = snd_soc_of_parse_daifmt(np, NULL,
+ &bitclkmaster, &framemaster);
+ if (bitclkmaster != framemaster) {
+ dev_err(&pdev->dev, "Must be the same bitclock and frame master\n");
+ return -EINVAL;
+ }
+ if (bitclkmaster) {
+ dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+ if (codec_np == bitclkmaster)
+ dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+ else
+ dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+ }
+ of_node_put(bitclkmaster);
+ of_node_put(framemaster);
+ dai->dai_fmt = dai_fmt;
+
+ of_node_put(codec_np);
+ of_node_put(cpu_np);
+
+ ret = snd_soc_register_card(&snd_proto);
+ if (ret && ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "snd_soc_register_card() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int snd_proto_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_proto);
+}
+
+static const struct of_device_id snd_proto_of_match[] = {
+ { .compatible = "mikroe,mikroe-proto", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_proto_of_match);
+
+static struct platform_driver snd_proto_driver = {
+ .driver = {
+ .name = "snd-mikroe-proto",
+ .of_match_table = snd_proto_of_match,
+ },
+ .probe = snd_proto_probe,
+ .remove = snd_proto_remove,
+};
+
+module_platform_driver(snd_proto_driver);
+
+MODULE_AUTHOR("Florian Meier");
+MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c
index 3a1393283156..214adcad5419 100644
--- a/sound/soc/atmel/tse850-pcm5142.c
+++ b/sound/soc/atmel/tse850-pcm5142.c
@@ -1,44 +1,38 @@
-/*
- * TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec
- *
- * Copyright (C) 2016 Axentia Technologies AB
- *
- * Author: Peter Rosin <peda@axentia.se>
- *
- * 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.
- */
-
-/*
- * loop1 relays
- * IN1 +---o +------------+ o---+ OUT1
- * \ /
- * + +
- * | / |
- * +--o +--. |
- * | add | |
- * | V |
- * | .---. |
- * DAC +----------->|Sum|---+
- * | '---' |
- * | |
- * + +
- *
- * IN2 +---o--+------------+--o---+ OUT2
- * loop2 relays
- *
- * The 'loop1' gpio pin controlls two relays, which are either in loop
- * position, meaning that input and output are directly connected, or
- * they are in mixer position, meaning that the signal is passed through
- * the 'Sum' mixer. Similarly for 'loop2'.
- *
- * In the above, the 'loop1' relays are inactive, thus feeding IN1 to the
- * mixer (if 'add' is active) and feeding the mixer output to OUT1. The
- * 'loop2' relays are active, short-cutting the TSE-850 from channel 2.
- * IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name
- * of the (filtered) output from the PCM5142 codec.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec
+//
+// Copyright (C) 2016 Axentia Technologies AB
+//
+// Author: Peter Rosin <peda@axentia.se>
+//
+// loop1 relays
+// IN1 +---o +------------+ o---+ OUT1
+// \ /
+// + +
+// | / |
+// +--o +--. |
+// | add | |
+// | V |
+// | .---. |
+// DAC +----------->|Sum|---+
+// | '---' |
+// | |
+// + +
+//
+// IN2 +---o--+------------+--o---+ OUT2
+// loop2 relays
+//
+// The 'loop1' gpio pin controlls two relays, which are either in loop
+// position, meaning that input and output are directly connected, or
+// they are in mixer position, meaning that the signal is passed through
+// the 'Sum' mixer. Similarly for 'loop2'.
+//
+// In the above, the 'loop1' relays are inactive, thus feeding IN1 to the
+// mixer (if 'add' is active) and feeding the mixer output to OUT1. The
+// 'loop2' relays are active, short-cutting the TSE-850 from channel 2.
+// IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name
+// of the (filtered) output from the PCM5142 codec.
#include <linux/clk.h>
#include <linux/gpio.h>
@@ -452,4 +446,4 @@ module_platform_driver(tse850_driver);
/* Module information */
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index b733f1446353..b7c358b48d8d 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -1334,7 +1334,7 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
cygaud->active_ports = 0;
dev_dbg(dev, "Registering %d DAIs\n", active_port_count);
- err = snd_soc_register_component(dev, &cygnus_ssp_component,
+ err = devm_snd_soc_register_component(dev, &cygnus_ssp_component,
cygnus_ssp_dai, active_port_count);
if (err) {
dev_err(dev, "snd_soc_register_dai failed\n");
@@ -1345,32 +1345,27 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
if (cygaud->irq_num <= 0) {
dev_err(dev, "platform_get_irq failed\n");
err = cygaud->irq_num;
- goto err_irq;
+ return err;
}
err = audio_clk_init(pdev, cygaud);
if (err) {
dev_err(dev, "audio clock initialization failed\n");
- goto err_irq;
+ return err;
}
err = cygnus_soc_platform_register(dev, cygaud);
if (err) {
dev_err(dev, "platform reg error %d\n", err);
- goto err_irq;
+ return err;
}
return 0;
-
-err_irq:
- snd_soc_unregister_component(dev);
- return err;
}
static int cygnus_ssp_remove(struct platform_device *pdev)
{
cygnus_soc_platform_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
return 0;
}
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index efb095dbcd71..9989d35e0fc6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ES7241
select SND_SOC_GTM601
select SND_SOC_HDAC_HDMI
+ select SND_SOC_HDAC_HDA
select SND_SOC_ICS43432
select SND_SOC_INNO_RK3036
select SND_SOC_ISABELLE if I2C
@@ -119,6 +120,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM186X_I2C if I2C
select SND_SOC_PCM186X_SPI if SPI_MASTER
select SND_SOC_PCM3008
+ select SND_SOC_PCM3060_I2C if I2C
+ select SND_SOC_PCM3060_SPI if SPI_MASTER
select SND_SOC_PCM3168A_I2C if I2C
select SND_SOC_PCM3168A_SPI if SPI_MASTER
select SND_SOC_PCM5102A
@@ -575,7 +578,11 @@ config SND_SOC_DA9055
tristate
config SND_SOC_DMIC
- tristate
+ tristate "Generic Digital Microphone CODEC"
+ depends on GPIOLIB
+ help
+ Enable support for the Generic Digital Microphone CODEC.
+ Select this if your sound card has DMICs.
config SND_SOC_HDMI_CODEC
tristate
@@ -615,6 +622,10 @@ config SND_SOC_HDAC_HDMI
select SND_PCM_ELD
select HDMI
+config SND_SOC_HDAC_HDA
+ tristate
+ select SND_HDA
+
config SND_SOC_ICS43432
tristate
@@ -732,6 +743,21 @@ config SND_SOC_PCM186X_SPI
config SND_SOC_PCM3008
tristate
+config SND_SOC_PCM3060
+ tristate
+
+config SND_SOC_PCM3060_I2C
+ tristate "Texas Instruments PCM3060 CODEC - I2C"
+ depends on I2C
+ select SND_SOC_PCM3060
+ select REGMAP_I2C
+
+config SND_SOC_PCM3060_SPI
+ tristate "Texas Instruments PCM3060 CODEC - SPI"
+ depends on SPI_MASTER
+ select SND_SOC_PCM3060
+ select REGMAP_SPI
+
config SND_SOC_PCM3168A
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 7ae7c85e8219..3d694c26192c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -78,6 +78,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o
snd-soc-gtm601-objs := gtm601.o
snd-soc-hdac-hdmi-objs := hdac_hdmi.o
+snd-soc-hdac-hda-objs := hdac_hda.o
snd-soc-ics43432-objs := ics43432.o
snd-soc-inno-rk3036-objs := inno_rk3036.o
snd-soc-isabelle-objs := isabelle.o
@@ -119,6 +120,9 @@ snd-soc-pcm186x-objs := pcm186x.o
snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o
snd-soc-pcm186x-spi-objs := pcm186x-spi.o
snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-pcm3060-objs := pcm3060.o
+snd-soc-pcm3060-i2c-objs := pcm3060-i2c.o
+snd-soc-pcm3060-spi-objs := pcm3060-spi.o
snd-soc-pcm3168a-objs := pcm3168a.o
snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o
@@ -338,6 +342,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
+obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o
obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
@@ -379,6 +384,9 @@ obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o
obj-$(CONFIG_SND_SOC_PCM186X_I2C) += snd-soc-pcm186x-i2c.o
obj-$(CONFIG_SND_SOC_PCM186X_SPI) += snd-soc-pcm186x-spi.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_PCM3060) += snd-soc-pcm3060.o
+obj-$(CONFIG_SND_SOC_PCM3060_I2C) += snd-soc-pcm3060-i2c.o
+obj-$(CONFIG_SND_SOC_PCM3060_SPI) += snd-soc-pcm3060-spi.o
obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 57169b8ff14e..3959e6ad113d 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -21,11 +21,18 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
+#include <asm/unaligned.h>
#include "sigmadsp.h"
#include "adau17x1.h"
#include "adau-utils.h"
+#define ADAU17X1_SAFELOAD_TARGET_ADDRESS 0x0006
+#define ADAU17X1_SAFELOAD_TRIGGER 0x0007
+#define ADAU17X1_SAFELOAD_DATA 0x0001
+#define ADAU17X1_SAFELOAD_DATA_SIZE 20
+#define ADAU17X1_WORD_SIZE 4
+
static const char * const adau17x1_capture_mixer_boost_text[] = {
"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
};
@@ -60,6 +67,9 @@ static const struct snd_kcontrol_new adau17x1_controls[] = {
SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum),
};
+static int adau17x1_setup_firmware(struct snd_soc_component *component,
+ unsigned int rate);
+
static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -313,7 +323,7 @@ static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
{ "Capture", NULL, "Right Decimator" },
};
-bool adau17x1_has_dsp(struct adau *adau)
+static bool adau17x1_has_dsp(struct adau *adau)
{
switch (adau->type) {
case ADAU1761:
@@ -324,7 +334,17 @@ bool adau17x1_has_dsp(struct adau *adau)
return false;
}
}
-EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
+
+static bool adau17x1_has_safeload(struct adau *adau)
+{
+ switch (adau->type) {
+ case ADAU1761:
+ case ADAU1781:
+ return true;
+ default:
+ return false;
+ }
+}
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
@@ -836,7 +856,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
}
EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
-int adau17x1_setup_firmware(struct snd_soc_component *component,
+static int adau17x1_setup_firmware(struct snd_soc_component *component,
unsigned int rate)
{
int ret;
@@ -880,7 +900,6 @@ err:
return ret;
}
-EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
int adau17x1_add_widgets(struct snd_soc_component *component)
{
@@ -957,6 +976,56 @@ int adau17x1_resume(struct snd_soc_component *component)
}
EXPORT_SYMBOL_GPL(adau17x1_resume);
+static int adau17x1_safeload(struct sigmadsp *sigmadsp, unsigned int addr,
+ const uint8_t bytes[], size_t len)
+{
+ uint8_t buf[ADAU17X1_WORD_SIZE];
+ uint8_t data[ADAU17X1_SAFELOAD_DATA_SIZE];
+ unsigned int addr_offset;
+ unsigned int nbr_words;
+ int ret;
+
+ /* write data to safeload addresses. Check if len is not a multiple of
+ * 4 bytes, if so we need to zero pad.
+ */
+ nbr_words = len / ADAU17X1_WORD_SIZE;
+ if ((len - nbr_words * ADAU17X1_WORD_SIZE) == 0) {
+ ret = regmap_raw_write(sigmadsp->control_data,
+ ADAU17X1_SAFELOAD_DATA, bytes, len);
+ } else {
+ nbr_words++;
+ memset(data, 0, ADAU17X1_SAFELOAD_DATA_SIZE);
+ memcpy(data, bytes, len);
+ ret = regmap_raw_write(sigmadsp->control_data,
+ ADAU17X1_SAFELOAD_DATA, data,
+ nbr_words * ADAU17X1_WORD_SIZE);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Write target address, target address is offset by 1 */
+ addr_offset = addr - 1;
+ put_unaligned_be32(addr_offset, buf);
+ ret = regmap_raw_write(sigmadsp->control_data,
+ ADAU17X1_SAFELOAD_TARGET_ADDRESS, buf, ADAU17X1_WORD_SIZE);
+ if (ret < 0)
+ return ret;
+
+ /* write nbr of words to trigger address */
+ put_unaligned_be32(nbr_words, buf);
+ ret = regmap_raw_write(sigmadsp->control_data,
+ ADAU17X1_SAFELOAD_TRIGGER, buf, ADAU17X1_WORD_SIZE);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct sigmadsp_ops adau17x1_sigmadsp_ops = {
+ .safeload = adau17x1_safeload,
+};
+
int adau17x1_probe(struct device *dev, struct regmap *regmap,
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
const char *firmware_name)
@@ -1002,8 +1071,13 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
dev_set_drvdata(dev, adau);
if (firmware_name) {
- adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
- firmware_name);
+ if (adau17x1_has_safeload(adau)) {
+ adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap,
+ &adau17x1_sigmadsp_ops, firmware_name);
+ } else {
+ adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap,
+ NULL, firmware_name);
+ }
if (IS_ERR(adau->sigmadsp)) {
dev_warn(dev, "Could not find firmware file: %ld\n",
PTR_ERR(adau->sigmadsp));
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
index e6fe87beec07..98a3b6f5bc96 100644
--- a/sound/soc/codecs/adau17x1.h
+++ b/sound/soc/codecs/adau17x1.h
@@ -68,10 +68,6 @@ int adau17x1_resume(struct snd_soc_component *component);
extern const struct snd_soc_dai_ops adau17x1_dai_ops;
-int adau17x1_setup_firmware(struct snd_soc_component *component,
- unsigned int rate);
-bool adau17x1_has_dsp(struct adau *adau);
-
#define ADAU17X1_CLOCK_CONTROL 0x4000
#define ADAU17X1_PLL_CONTROL 0x4002
#define ADAU17X1_REC_POWER_MGMT 0x4009
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 407554175282..d9eebf6af7a8 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -154,11 +154,11 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = {
SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1,
6, 1, 0),
SOC_ENUM("C Data Access", cam_mode_enum),
+ SOC_SINGLE("SPDIF Switch", CS4265_SPDIF_CTL2, 5, 1, 1),
SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
3, 1, 0),
SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
- SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2,
- 0, 1, 0),
+ SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2, 0, 1, 0),
SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
};
@@ -496,7 +496,8 @@ static int cs4265_set_bias_level(struct snd_soc_component *component,
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
#define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
- SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
static const struct snd_soc_dai_ops cs4265_ops = {
.hw_params = cs4265_pcm_hw_params,
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index 8c4926df9286..71322e0410ee 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -148,6 +148,7 @@ static const struct of_device_id dmic_dev_match[] = {
{.compatible = "dmic-codec"},
{}
};
+MODULE_DEVICE_TABLE(of, dmic_dev_match);
static struct platform_driver dmic_driver = {
.driver = {
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
new file mode 100644
index 000000000000..2aaa83028e55
--- /dev/null
+++ b/sound/soc/codecs/hdac_hda.c
@@ -0,0 +1,483 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2015-18 Intel Corporation.
+
+/*
+ * hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers
+ * with ASoC platform drivers. These APIs are called by the legacy HDA
+ * codec drivers using hdac_ext_bus_ops ops.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_codec.h>
+#include <sound/hda_register.h>
+#include "hdac_hda.h"
+
+#define HDAC_ANALOG_DAI_ID 0
+#define HDAC_DIGITAL_DAI_ID 1
+#define HDAC_ALT_ANALOG_DAI_ID 2
+
+#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_U24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_U32_LE | \
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
+
+static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width);
+static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
+ struct snd_soc_dai *dai);
+
+static struct snd_soc_dai_ops hdac_hda_dai_ops = {
+ .startup = hdac_hda_dai_open,
+ .shutdown = hdac_hda_dai_close,
+ .prepare = hdac_hda_dai_prepare,
+ .hw_free = hdac_hda_dai_hw_free,
+ .set_tdm_slot = hdac_hda_dai_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver hdac_hda_dais[] = {
+{
+ .id = HDAC_ANALOG_DAI_ID,
+ .name = "Analog Codec DAI",
+ .ops = &hdac_hda_dai_ops,
+ .playback = {
+ .stream_name = "Analog Codec Playback",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = STUB_FORMATS,
+ .sig_bits = 24,
+ },
+ .capture = {
+ .stream_name = "Analog Codec Capture",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = STUB_FORMATS,
+ .sig_bits = 24,
+ },
+},
+{
+ .id = HDAC_DIGITAL_DAI_ID,
+ .name = "Digital Codec DAI",
+ .ops = &hdac_hda_dai_ops,
+ .playback = {
+ .stream_name = "Digital Codec Playback",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = STUB_FORMATS,
+ .sig_bits = 24,
+ },
+ .capture = {
+ .stream_name = "Digital Codec Capture",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = STUB_FORMATS,
+ .sig_bits = 24,
+ },
+},
+{
+ .id = HDAC_ALT_ANALOG_DAI_ID,
+ .name = "Alt Analog Codec DAI",
+ .ops = &hdac_hda_dai_ops,
+ .playback = {
+ .stream_name = "Alt Analog Codec Playback",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = STUB_FORMATS,
+ .sig_bits = 24,
+ },
+ .capture = {
+ .stream_name = "Alt Analog Codec Capture",
+ .channels_min = 1,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = STUB_FORMATS,
+ .sig_bits = 24,
+ },
+}
+
+};
+
+static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct hdac_hda_priv *hda_pvt;
+ struct hdac_hda_pcm *pcm;
+
+ hda_pvt = snd_soc_component_get_drvdata(component);
+ pcm = &hda_pvt->pcm[dai->id];
+ if (tx_mask)
+ pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
+ else
+ pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
+
+ return 0;
+}
+
+static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct hdac_hda_priv *hda_pvt;
+ struct hda_pcm_stream *hda_stream;
+ struct hda_pcm *pcm;
+
+ hda_pvt = snd_soc_component_get_drvdata(component);
+ pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
+ if (!pcm)
+ return -EINVAL;
+
+ hda_stream = &pcm->stream[substream->stream];
+ snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream);
+
+ return 0;
+}
+
+static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct hdac_hda_priv *hda_pvt;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hdac_device *hdev;
+ struct hda_pcm_stream *hda_stream;
+ unsigned int format_val;
+ struct hda_pcm *pcm;
+ unsigned int stream;
+ int ret = 0;
+
+ hda_pvt = snd_soc_component_get_drvdata(component);
+ hdev = &hda_pvt->codec.core;
+ pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
+ if (!pcm)
+ return -EINVAL;
+
+ hda_stream = &pcm->stream[substream->stream];
+
+ format_val = snd_hdac_calc_stream_format(runtime->rate,
+ runtime->channels,
+ runtime->format,
+ hda_stream->maxbps,
+ 0);
+ if (!format_val) {
+ dev_err(&hdev->dev,
+ "invalid format_val, rate=%d, ch=%d, format=%d\n",
+ runtime->rate, runtime->channels, runtime->format);
+ return -EINVAL;
+ }
+
+ stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream];
+
+ ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream,
+ stream, format_val, substream);
+ if (ret < 0)
+ dev_err(&hdev->dev, "codec prepare failed %d\n", ret);
+
+ return ret;
+}
+
+static int hdac_hda_dai_open(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct hdac_hda_priv *hda_pvt;
+ struct hda_pcm_stream *hda_stream;
+ struct hda_pcm *pcm;
+ int ret;
+
+ hda_pvt = snd_soc_component_get_drvdata(component);
+ pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
+ if (!pcm)
+ return -EINVAL;
+
+ snd_hda_codec_pcm_get(pcm);
+
+ hda_stream = &pcm->stream[substream->stream];
+
+ ret = hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream);
+ if (ret < 0)
+ snd_hda_codec_pcm_put(pcm);
+
+ return ret;
+}
+
+static void hdac_hda_dai_close(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct hdac_hda_priv *hda_pvt;
+ struct hda_pcm_stream *hda_stream;
+ struct hda_pcm *pcm;
+
+ hda_pvt = snd_soc_component_get_drvdata(component);
+ pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai);
+ if (!pcm)
+ return;
+
+ hda_stream = &pcm->stream[substream->stream];
+
+ hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream);
+
+ snd_hda_codec_pcm_put(pcm);
+}
+
+static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
+ struct snd_soc_dai *dai)
+{
+ struct hda_codec *hcodec = &hda_pvt->codec;
+ struct hda_pcm *cpcm;
+ const char *pcm_name;
+
+ switch (dai->id) {
+ case HDAC_ANALOG_DAI_ID:
+ pcm_name = "Analog";
+ break;
+ case HDAC_DIGITAL_DAI_ID:
+ pcm_name = "Digital";
+ break;
+ case HDAC_ALT_ANALOG_DAI_ID:
+ pcm_name = "Alt Analog";
+ break;
+ default:
+ dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id);
+ return NULL;
+ }
+
+ list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) {
+ if (strpbrk(cpcm->name, pcm_name))
+ return cpcm;
+ }
+
+ dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name);
+ return NULL;
+}
+
+static int hdac_hda_codec_probe(struct snd_soc_component *component)
+{
+ struct hdac_hda_priv *hda_pvt =
+ snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ struct hdac_device *hdev = &hda_pvt->codec.core;
+ struct hda_codec *hcodec = &hda_pvt->codec;
+ struct hdac_ext_link *hlink;
+ hda_codec_patch_t patch;
+ int ret;
+
+ hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ if (!hlink) {
+ dev_err(&hdev->dev, "hdac link not found\n");
+ return -EIO;
+ }
+
+ snd_hdac_ext_bus_link_get(hdev->bus, hlink);
+
+ ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
+ hdev->addr, hcodec);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
+ goto error_no_pm;
+ }
+
+ /*
+ * snd_hda_codec_device_new decrements the usage count so call get pm
+ * else the device will be powered off
+ */
+ pm_runtime_get_noresume(&hdev->dev);
+
+ hcodec->bus->card = dapm->card->snd_card;
+
+ ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name);
+ goto error;
+ }
+
+ ret = snd_hdac_regmap_init(&hcodec->core);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "regmap init failed\n");
+ goto error;
+ }
+
+ patch = (hda_codec_patch_t)hcodec->preset->driver_data;
+ if (patch) {
+ ret = patch(hcodec);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "patch failed %d\n", ret);
+ goto error;
+ }
+ } else {
+ dev_dbg(&hdev->dev, "no patch file found\n");
+ }
+
+ ret = snd_hda_codec_parse_pcms(hcodec);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
+ goto error;
+ }
+
+ ret = snd_hda_codec_build_controls(hcodec);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "unable to create controls %d\n", ret);
+ goto error;
+ }
+
+ hcodec->core.lazy_cache = true;
+
+ /*
+ * hdac_device core already sets the state to active and calls
+ * get_noresume. So enable runtime and set the device to suspend.
+ * pm_runtime_enable is also called during codec registeration
+ */
+ pm_runtime_put(&hdev->dev);
+ pm_runtime_suspend(&hdev->dev);
+
+ return 0;
+
+error:
+ pm_runtime_put(&hdev->dev);
+error_no_pm:
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
+ return ret;
+}
+
+static void hdac_hda_codec_remove(struct snd_soc_component *component)
+{
+ struct hdac_hda_priv *hda_pvt =
+ snd_soc_component_get_drvdata(component);
+ struct hdac_device *hdev = &hda_pvt->codec.core;
+ struct hdac_ext_link *hlink = NULL;
+
+ hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ if (!hlink) {
+ dev_err(&hdev->dev, "hdac link not found\n");
+ return;
+ }
+
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
+ pm_runtime_disable(&hdev->dev);
+}
+
+static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = {
+ {"AIF1TX", NULL, "Codec Input Pin1"},
+ {"AIF2TX", NULL, "Codec Input Pin2"},
+ {"AIF3TX", NULL, "Codec Input Pin3"},
+
+ {"Codec Output Pin1", NULL, "AIF1RX"},
+ {"Codec Output Pin2", NULL, "AIF2RX"},
+ {"Codec Output Pin3", NULL, "AIF3RX"},
+};
+
+static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+
+ /* Input Pins */
+ SND_SOC_DAPM_INPUT("Codec Input Pin1"),
+ SND_SOC_DAPM_INPUT("Codec Input Pin2"),
+ SND_SOC_DAPM_INPUT("Codec Input Pin3"),
+
+ /* Output Pins */
+ SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
+ SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
+ SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
+};
+
+static const struct snd_soc_component_driver hdac_hda_codec = {
+ .probe = hdac_hda_codec_probe,
+ .remove = hdac_hda_codec_remove,
+ .idle_bias_on = false,
+ .dapm_widgets = hdac_hda_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets),
+ .dapm_routes = hdac_hda_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes),
+};
+
+static int hdac_hda_dev_probe(struct hdac_device *hdev)
+{
+ struct hdac_ext_link *hlink;
+ struct hdac_hda_priv *hda_pvt;
+ int ret;
+
+ /* hold the ref while we probe */
+ hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
+ if (!hlink) {
+ dev_err(&hdev->dev, "hdac link not found\n");
+ return -EIO;
+ }
+ snd_hdac_ext_bus_link_get(hdev->bus, hlink);
+
+ hda_pvt = hdac_to_hda_priv(hdev);
+ if (!hda_pvt)
+ return -ENOMEM;
+
+ /* ASoC specific initialization */
+ ret = devm_snd_soc_register_component(&hdev->dev,
+ &hdac_hda_codec, hdac_hda_dais,
+ ARRAY_SIZE(hdac_hda_dais));
+ if (ret < 0) {
+ dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret);
+ return ret;
+ }
+
+ dev_set_drvdata(&hdev->dev, hda_pvt);
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
+
+ return ret;
+}
+
+static int hdac_hda_dev_remove(struct hdac_device *hdev)
+{
+ return 0;
+}
+
+static struct hdac_ext_bus_ops hdac_ops = {
+ .hdev_attach = hdac_hda_dev_probe,
+ .hdev_detach = hdac_hda_dev_remove,
+};
+
+struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void)
+{
+ return &hdac_ops;
+}
+EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers");
+MODULE_AUTHOR("Rakesh Ughreja<rakesh.a.ughreja@intel.com>");
diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h
new file mode 100644
index 000000000000..e444ef593360
--- /dev/null
+++ b/sound/soc/codecs/hdac_hda.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright(c) 2015-18 Intel Corporation.
+ */
+
+#ifndef __HDAC_HDA_H__
+#define __HDAC_HDA_H__
+
+struct hdac_hda_pcm {
+ int stream_tag[2];
+};
+
+struct hdac_hda_priv {
+ struct hda_codec codec;
+ struct hdac_hda_pcm pcm[2];
+};
+
+#define hdac_to_hda_priv(_hdac) \
+ container_of(_hdac, struct hdac_hda_priv, codec.core)
+#define hdac_to_hda_codec(_hdac) container_of(_hdac, struct hda_codec, core)
+
+struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void);
+
+#endif /* __HDAC_HDA_H__ */
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 7b8533abf637..41d90dc6ebf7 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1410,6 +1410,12 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev,
if (ret)
return ret;
+ /* Filter out 44.1, 88.2 and 176.4Khz */
+ rates &= ~(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_176400);
+ if (!rates)
+ return -EINVAL;
+
sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
hdmi_dais[i].name = devm_kstrdup(&hdev->dev,
dai_name, GFP_KERNEL);
@@ -1961,9 +1967,6 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head);
- if (!port)
- return 0;
-
if (!port || !port->eld.eld_valid)
return 0;
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
index 1093f766d0d2..d6868c9a9ce6 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -2,6 +2,7 @@
// Copyright (c) 2017, Maxim Integrated
#include <linux/acpi.h>
+#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c
new file mode 100644
index 000000000000..cdc8314882bc
--- /dev/null
+++ b/sound/soc/codecs/pcm3060-i2c.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// PCM3060 I2C driver
+//
+// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "pcm3060.h"
+
+static int pcm3060_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct pcm3060_priv *priv;
+
+ priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, priv);
+
+ priv->regmap = devm_regmap_init_i2c(i2c, &pcm3060_regmap);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ return pcm3060_probe(&i2c->dev);
+}
+
+static const struct i2c_device_id pcm3060_i2c_id[] = {
+ { .name = "pcm3060" },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, pcm3060_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcm3060_of_match[] = {
+ { .compatible = "ti,pcm3060" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, pcm3060_of_match);
+#endif /* CONFIG_OF */
+
+static struct i2c_driver pcm3060_i2c_driver = {
+ .driver = {
+ .name = "pcm3060",
+#ifdef CONFIG_OF
+ .of_match_table = pcm3060_of_match,
+#endif /* CONFIG_OF */
+ },
+ .id_table = pcm3060_i2c_id,
+ .probe = pcm3060_i2c_probe,
+};
+
+module_i2c_driver(pcm3060_i2c_driver);
+
+MODULE_DESCRIPTION("PCM3060 I2C driver");
+MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060-spi.c b/sound/soc/codecs/pcm3060-spi.c
new file mode 100644
index 000000000000..f6f19fa80932
--- /dev/null
+++ b/sound/soc/codecs/pcm3060-spi.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// PCM3060 SPI driver
+//
+// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "pcm3060.h"
+
+static int pcm3060_spi_probe(struct spi_device *spi)
+{
+ struct pcm3060_priv *priv;
+
+ priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, priv);
+
+ priv->regmap = devm_regmap_init_spi(spi, &pcm3060_regmap);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ return pcm3060_probe(&spi->dev);
+}
+
+static const struct spi_device_id pcm3060_spi_id[] = {
+ { .name = "pcm3060" },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, pcm3060_spi_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcm3060_of_match[] = {
+ { .compatible = "ti,pcm3060" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, pcm3060_of_match);
+#endif /* CONFIG_OF */
+
+static struct spi_driver pcm3060_spi_driver = {
+ .driver = {
+ .name = "pcm3060",
+#ifdef CONFIG_OF
+ .of_match_table = pcm3060_of_match,
+#endif /* CONFIG_OF */
+ },
+ .id_table = pcm3060_spi_id,
+ .probe = pcm3060_spi_probe,
+};
+
+module_spi_driver(pcm3060_spi_driver);
+
+MODULE_DESCRIPTION("PCM3060 SPI driver");
+MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c
new file mode 100644
index 000000000000..494d9d662be8
--- /dev/null
+++ b/sound/soc/codecs/pcm3060.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// PCM3060 codec driver
+//
+// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
+
+#include <linux/module.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm3060.h"
+
+/* dai */
+
+static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_component *comp = dai->component;
+ struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
+
+ if (dir != SND_SOC_CLOCK_IN) {
+ dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir);
+ return -EINVAL;
+ }
+
+ priv->dai[dai->id].sclk_freq = freq;
+
+ return 0;
+}
+
+static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *comp = dai->component;
+ struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
+ unsigned int reg;
+ unsigned int val;
+
+ if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
+ dev_err(comp->dev, "unsupported DAI polarity: 0x%x\n", fmt);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ priv->dai[dai->id].is_master = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ priv->dai[dai->id].is_master = false;
+ break;
+ default:
+ dev_err(comp->dev, "unsupported DAI master mode: 0x%x\n", fmt);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ val = PCM3060_REG_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ val = PCM3060_REG_FMT_RJ;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ val = PCM3060_REG_FMT_LJ;
+ break;
+ default:
+ dev_err(comp->dev, "unsupported DAI format: 0x%x\n", fmt);
+ return -EINVAL;
+ }
+
+ if (dai->id == PCM3060_DAI_ID_DAC)
+ reg = PCM3060_REG67;
+ else
+ reg = PCM3060_REG72;
+
+ regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val);
+
+ return 0;
+}
+
+static int pcm3060_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *comp = dai->component;
+ struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
+ unsigned int rate;
+ unsigned int ratio;
+ unsigned int reg;
+ unsigned int val;
+
+ if (!priv->dai[dai->id].is_master) {
+ val = PCM3060_REG_MS_S;
+ goto val_ready;
+ }
+
+ rate = params_rate(params);
+ if (!rate) {
+ dev_err(comp->dev, "rate is not configured\n");
+ return -EINVAL;
+ }
+
+ ratio = priv->dai[dai->id].sclk_freq / rate;
+
+ switch (ratio) {
+ case 768:
+ val = PCM3060_REG_MS_M768;
+ break;
+ case 512:
+ val = PCM3060_REG_MS_M512;
+ break;
+ case 384:
+ val = PCM3060_REG_MS_M384;
+ break;
+ case 256:
+ val = PCM3060_REG_MS_M256;
+ break;
+ case 192:
+ val = PCM3060_REG_MS_M192;
+ break;
+ case 128:
+ val = PCM3060_REG_MS_M128;
+ break;
+ default:
+ dev_err(comp->dev, "unsupported ratio: %d\n", ratio);
+ return -EINVAL;
+ }
+
+val_ready:
+ if (dai->id == PCM3060_DAI_ID_DAC)
+ reg = PCM3060_REG67;
+ else
+ reg = PCM3060_REG72;
+
+ regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops pcm3060_dai_ops = {
+ .set_sysclk = pcm3060_set_sysclk,
+ .set_fmt = pcm3060_set_fmt,
+ .hw_params = pcm3060_hw_params,
+};
+
+#define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define PCM3060_DAI_RATES_DAC (PCM3060_DAI_RATES_ADC | \
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+static struct snd_soc_dai_driver pcm3060_dai[] = {
+ {
+ .name = "pcm3060-dac",
+ .id = PCM3060_DAI_ID_DAC,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PCM3060_DAI_RATES_DAC,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &pcm3060_dai_ops,
+ },
+ {
+ .name = "pcm3060-adc",
+ .id = PCM3060_DAI_ID_ADC,
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PCM3060_DAI_RATES_ADC,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &pcm3060_dai_ops,
+ },
+};
+
+/* dapm */
+
+static DECLARE_TLV_DB_SCALE(pcm3060_dapm_tlv, -10050, 50, 1);
+
+static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
+ SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume",
+ PCM3060_REG65, PCM3060_REG66, 0,
+ PCM3060_REG_AT2_MIN, PCM3060_REG_AT2_MAX,
+ 0, pcm3060_dapm_tlv),
+ SOC_DOUBLE("Master Playback Switch", PCM3060_REG68,
+ PCM3060_REG_SHIFT_MUT21, PCM3060_REG_SHIFT_MUT22, 1, 1),
+
+ SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume",
+ PCM3060_REG70, PCM3060_REG71, 0,
+ PCM3060_REG_AT1_MIN, PCM3060_REG_AT1_MAX,
+ 0, pcm3060_dapm_tlv),
+ SOC_DOUBLE("Master Capture Switch", PCM3060_REG73,
+ PCM3060_REG_SHIFT_MUT11, PCM3060_REG_SHIFT_MUT12, 1, 1),
+};
+
+static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("OUTL+"),
+ SND_SOC_DAPM_OUTPUT("OUTR+"),
+ SND_SOC_DAPM_OUTPUT("OUTL-"),
+ SND_SOC_DAPM_OUTPUT("OUTR-"),
+
+ SND_SOC_DAPM_INPUT("INL"),
+ SND_SOC_DAPM_INPUT("INR"),
+};
+
+static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
+ { "OUTL+", NULL, "Playback" },
+ { "OUTR+", NULL, "Playback" },
+ { "OUTL-", NULL, "Playback" },
+ { "OUTR-", NULL, "Playback" },
+
+ { "Capture", NULL, "INL" },
+ { "Capture", NULL, "INR" },
+};
+
+/* soc component */
+
+static const struct snd_soc_component_driver pcm3060_soc_comp_driver = {
+ .controls = pcm3060_dapm_controls,
+ .num_controls = ARRAY_SIZE(pcm3060_dapm_controls),
+ .dapm_widgets = pcm3060_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets),
+ .dapm_routes = pcm3060_dapm_map,
+ .num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map),
+};
+
+/* regmap */
+
+static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg)
+{
+ return (reg >= PCM3060_REG64);
+}
+
+static bool pcm3060_reg_readable(struct device *dev, unsigned int reg)
+{
+ return (reg >= PCM3060_REG64);
+}
+
+static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg)
+{
+ /* PCM3060_REG64 is volatile */
+ return (reg == PCM3060_REG64);
+}
+
+static const struct reg_default pcm3060_reg_defaults[] = {
+ { PCM3060_REG64, 0xF0 },
+ { PCM3060_REG65, 0xFF },
+ { PCM3060_REG66, 0xFF },
+ { PCM3060_REG67, 0x00 },
+ { PCM3060_REG68, 0x00 },
+ { PCM3060_REG69, 0x00 },
+ { PCM3060_REG70, 0xD7 },
+ { PCM3060_REG71, 0xD7 },
+ { PCM3060_REG72, 0x00 },
+ { PCM3060_REG73, 0x00 },
+};
+
+const struct regmap_config pcm3060_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = pcm3060_reg_writeable,
+ .readable_reg = pcm3060_reg_readable,
+ .volatile_reg = pcm3060_reg_volatile,
+ .max_register = PCM3060_REG73,
+ .reg_defaults = pcm3060_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL(pcm3060_regmap);
+
+/* device */
+
+int pcm3060_probe(struct device *dev)
+{
+ int rc;
+
+ rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
+ pcm3060_dai,
+ ARRAY_SIZE(pcm3060_dai));
+ if (rc) {
+ dev_err(dev, "failed to register component, rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(pcm3060_probe);
+
+MODULE_DESCRIPTION("PCM3060 codec driver");
+MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h
new file mode 100644
index 000000000000..fd89a68aa8a7
--- /dev/null
+++ b/sound/soc/codecs/pcm3060.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PCM3060 codec driver
+ *
+ * Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech>
+ */
+
+#ifndef _SND_SOC_PCM3060_H
+#define _SND_SOC_PCM3060_H
+
+#include <linux/device.h>
+#include <linux/regmap.h>
+
+extern const struct regmap_config pcm3060_regmap;
+
+#define PCM3060_DAI_ID_DAC 0
+#define PCM3060_DAI_ID_ADC 1
+#define PCM3060_DAI_IDS_NUM 2
+
+struct pcm3060_priv_dai {
+ bool is_master;
+ unsigned int sclk_freq;
+};
+
+struct pcm3060_priv {
+ struct regmap *regmap;
+ struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM];
+};
+
+int pcm3060_probe(struct device *dev);
+int pcm3060_remove(struct device *dev);
+
+/* registers */
+
+#define PCM3060_REG64 0x40
+#define PCM3060_REG_MRST 0x80
+#define PCM3060_REG_SRST 0x40
+#define PCM3060_REG_ADPSV 0x20
+#define PCM3060_REG_DAPSV 0x10
+#define PCM3060_REG_SE 0x01
+
+#define PCM3060_REG65 0x41
+#define PCM3060_REG66 0x42
+#define PCM3060_REG_AT2_MIN 0x36
+#define PCM3060_REG_AT2_MAX 0xFF
+
+#define PCM3060_REG67 0x43
+#define PCM3060_REG72 0x48
+#define PCM3060_REG_CSEL 0x80
+#define PCM3060_REG_MASK_MS 0x70
+#define PCM3060_REG_MS_S 0x00
+#define PCM3060_REG_MS_M768 (0x01 << 4)
+#define PCM3060_REG_MS_M512 (0x02 << 4)
+#define PCM3060_REG_MS_M384 (0x03 << 4)
+#define PCM3060_REG_MS_M256 (0x04 << 4)
+#define PCM3060_REG_MS_M192 (0x05 << 4)
+#define PCM3060_REG_MS_M128 (0x06 << 4)
+#define PCM3060_REG_MASK_FMT 0x03
+#define PCM3060_REG_FMT_I2S 0x00
+#define PCM3060_REG_FMT_LJ 0x01
+#define PCM3060_REG_FMT_RJ 0x02
+
+#define PCM3060_REG68 0x44
+#define PCM3060_REG_OVER 0x40
+#define PCM3060_REG_DREV2 0x04
+#define PCM3060_REG_SHIFT_MUT21 0x00
+#define PCM3060_REG_SHIFT_MUT22 0x01
+
+#define PCM3060_REG69 0x45
+#define PCM3060_REG_FLT 0x80
+#define PCM3060_REG_MASK_DMF 0x60
+#define PCM3060_REG_DMC 0x10
+#define PCM3060_REG_ZREV 0x02
+#define PCM3060_REG_AZRO 0x01
+
+#define PCM3060_REG70 0x46
+#define PCM3060_REG71 0x47
+#define PCM3060_REG_AT1_MIN 0x0E
+#define PCM3060_REG_AT1_MAX 0xFF
+
+#define PCM3060_REG73 0x49
+#define PCM3060_REG_ZCDD 0x10
+#define PCM3060_REG_BYP 0x08
+#define PCM3060_REG_DREV1 0x04
+#define PCM3060_REG_SHIFT_MUT11 0x00
+#define PCM3060_REG_SHIFT_MUT12 0x01
+
+#endif /* _SND_SOC_PCM3060_H */
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 18686ffb0cd5..6478d10c4f4a 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -268,7 +268,6 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
.hw_params = rt5514_spi_hw_params,
.hw_free = rt5514_spi_hw_free,
.pointer = rt5514_spi_pcm_pointer,
- .mmap = snd_pcm_lib_mmap_vmalloc,
.page = snd_pcm_lib_get_vmalloc_page,
};
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index 3c19d03f2446..4412cd2910cd 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -2587,14 +2587,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c,
}
- return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
+ return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
rt5668_dai, ARRAY_SIZE(rt5668_dai));
}
static int rt5668_i2c_remove(struct i2c_client *i2c)
{
- snd_soc_unregister_component(&i2c->dev);
-
return 0;
}
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 732ef928b25d..455fe7cff700 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2877,6 +2877,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = {
},
{
.callback = rt5670_quirk_cb,
+ .ident = "Lenovo Thinkpad Tablet 8",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"),
+ },
+ .driver_data = (unsigned long *)(RT5670_DMIC_EN |
+ RT5670_DMIC2_INR |
+ RT5670_DEV_GPIO |
+ RT5670_JD_MODE1),
+ },
+ {
+ .callback = rt5670_quirk_cb,
.ident = "Lenovo Thinkpad Tablet 10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index afe7d5b19313..731c6a849f69 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -2454,27 +2454,15 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf);
usleep_range(15000, 20000);
regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf);
- regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
- regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001);
- regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
- regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080);
- regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040);
- regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069);
+ regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300);
+ regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000);
+ regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100);
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000);
- regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000);
- regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26);
- regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05);
- regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c);
- regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d);
- regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f);
- regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321);
regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1);
- regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311);
- regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000);
- regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320);
+ regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00);
@@ -2490,7 +2478,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
pr_err("HP Calibration Failure\n");
/* restore settings */
- regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
+ regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000);
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
mutex_unlock(&rt5682->calibrate_mutex);
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 60764f6201b1..add18d6d77da 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1218,7 +1218,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_component *component)
* Searching for a suitable index solving this formula:
* idx = 40 * log10(vag_val / lo_cagcntrl) + 15
*/
- vol_quot = (vag * 100) / lo_vag;
+ vol_quot = lo_vag ? (vag * 100) / lo_vag : 0;
lo_vol = 0;
for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) {
if (vol_quot >= vol_quot_table[i])
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index ae3d032ac35a..6bd0e5d5347f 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -152,6 +152,7 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
+ struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
unsigned int first_slot;
int ret;
@@ -185,6 +186,20 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
if (ret < 0)
goto error_snd_soc_component_update_bits;
+ /* Configure TDM slot width. This is only applicable to TAS5722. */
+ switch (tas5720->devtype) {
+ case TAS5722:
+ ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
+ TAS5722_TDM_SLOT_16B,
+ slot_width == 16 ?
+ TAS5722_TDM_SLOT_16B : 0);
+ if (ret < 0)
+ goto error_snd_soc_component_update_bits;
+ break;
+ default:
+ break;
+ }
+
return 0;
error_snd_soc_component_update_bits:
@@ -485,15 +500,56 @@ static const DECLARE_TLV_DB_RANGE(dac_analog_tlv,
);
/*
- * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
- * setting the gain below -100 dB (register value <0x7) is effectively a MUTE
- * as per device datasheet.
+ * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps
+ * depending on the device. Note that setting the gain below -100 dB
+ * (register value <0x7) is effectively a MUTE as per device datasheet.
+ *
+ * Note that for the TAS5722 the digital volume controls are actually split
+ * over two registers, so we need custom getters/setters for access.
*/
-static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0);
+
+static int tas5722_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ unsigned int val;
+
+ snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG, &val);
+ ucontrol->value.integer.value[0] = val << 1;
+
+ snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG, &val);
+ ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB;
+
+ return 0;
+}
+
+static int tas5722_volume_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ unsigned int sel = ucontrol->value.integer.value[0];
+
+ snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1);
+ snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
+ TAS5722_VOL_CONTROL_LSB, sel);
+
+ return 0;
+}
static const struct snd_kcontrol_new tas5720_snd_controls[] = {
SOC_SINGLE_TLV("Speaker Driver Playback Volume",
- TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv),
+ TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, tas5720_dac_tlv),
+ SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
+ TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
+};
+
+static const struct snd_kcontrol_new tas5722_snd_controls[] = {
+ SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume",
+ 0, 0, 511, 0,
+ tas5722_volume_get, tas5722_volume_set,
+ tas5722_dac_tlv),
SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
};
@@ -527,6 +583,23 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
.non_legacy_dai_naming = 1,
};
+static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
+ .probe = tas5720_codec_probe,
+ .remove = tas5720_codec_remove,
+ .suspend = tas5720_suspend,
+ .resume = tas5720_resume,
+ .controls = tas5722_snd_controls,
+ .num_controls = ARRAY_SIZE(tas5722_snd_controls),
+ .dapm_widgets = tas5720_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets),
+ .dapm_routes = tas5720_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
/* PCM rates supported by the TAS5720 driver */
#define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
@@ -613,9 +686,23 @@ static int tas5720_probe(struct i2c_client *client,
dev_set_drvdata(dev, data);
- ret = devm_snd_soc_register_component(&client->dev,
- &soc_component_dev_tas5720,
- tas5720_dai, ARRAY_SIZE(tas5720_dai));
+ switch (id->driver_data) {
+ case TAS5720:
+ ret = devm_snd_soc_register_component(&client->dev,
+ &soc_component_dev_tas5720,
+ tas5720_dai,
+ ARRAY_SIZE(tas5720_dai));
+ break;
+ case TAS5722:
+ ret = devm_snd_soc_register_component(&client->dev,
+ &soc_component_dev_tas5722,
+ tas5720_dai,
+ ARRAY_SIZE(tas5720_dai));
+ break;
+ default:
+ dev_err(dev, "unexpected private driver data\n");
+ return -EINVAL;
+ }
if (ret < 0) {
dev_err(dev, "failed to register component: %d\n", ret);
return ret;
diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c
index 0d6145549a98..36aebdb8f55c 100644
--- a/sound/soc/codecs/tas6424.c
+++ b/sound/soc/codecs/tas6424.c
@@ -41,6 +41,7 @@ struct tas6424_data {
struct regmap *regmap;
struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES];
struct delayed_work fault_check_work;
+ unsigned int last_cfault;
unsigned int last_fault1;
unsigned int last_fault2;
unsigned int last_warn;
@@ -406,9 +407,54 @@ static void tas6424_fault_check_work(struct work_struct *work)
unsigned int reg;
int ret;
+ ret = regmap_read(tas6424->regmap, TAS6424_CHANNEL_FAULT, &reg);
+ if (ret < 0) {
+ dev_err(dev, "failed to read CHANNEL_FAULT register: %d\n", ret);
+ goto out;
+ }
+
+ if (!reg) {
+ tas6424->last_cfault = reg;
+ goto check_global_fault1_reg;
+ }
+
+ /*
+ * Only flag errors once for a given occurrence. This is needed as
+ * the TAS6424 will take time clearing the fault condition internally
+ * during which we don't want to bombard the system with the same
+ * error message over and over.
+ */
+ if ((reg & TAS6424_FAULT_OC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH1))
+ dev_crit(dev, "experienced a channel 1 overcurrent fault\n");
+
+ if ((reg & TAS6424_FAULT_OC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH2))
+ dev_crit(dev, "experienced a channel 2 overcurrent fault\n");
+
+ if ((reg & TAS6424_FAULT_OC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH3))
+ dev_crit(dev, "experienced a channel 3 overcurrent fault\n");
+
+ if ((reg & TAS6424_FAULT_OC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_OC_CH4))
+ dev_crit(dev, "experienced a channel 4 overcurrent fault\n");
+
+ if ((reg & TAS6424_FAULT_DC_CH1) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH1))
+ dev_crit(dev, "experienced a channel 1 DC fault\n");
+
+ if ((reg & TAS6424_FAULT_DC_CH2) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH2))
+ dev_crit(dev, "experienced a channel 2 DC fault\n");
+
+ if ((reg & TAS6424_FAULT_DC_CH3) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH3))
+ dev_crit(dev, "experienced a channel 3 DC fault\n");
+
+ if ((reg & TAS6424_FAULT_DC_CH4) && !(tas6424->last_cfault & TAS6424_FAULT_DC_CH4))
+ dev_crit(dev, "experienced a channel 4 DC fault\n");
+
+ /* Store current fault1 value so we can detect any changes next time */
+ tas6424->last_cfault = reg;
+
+check_global_fault1_reg:
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, &reg);
if (ret < 0) {
- dev_err(dev, "failed to read FAULT1 register: %d\n", ret);
+ dev_err(dev, "failed to read GLOB_FAULT1 register: %d\n", ret);
goto out;
}
@@ -429,12 +475,6 @@ static void tas6424_fault_check_work(struct work_struct *work)
goto check_global_fault2_reg;
}
- /*
- * Only flag errors once for a given occurrence. This is needed as
- * the TAS6424 will take time clearing the fault condition internally
- * during which we don't want to bombard the system with the same
- * error message over and over.
- */
if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV))
dev_crit(dev, "experienced a PVDD overvoltage fault\n");
@@ -453,7 +493,7 @@ static void tas6424_fault_check_work(struct work_struct *work)
check_global_fault2_reg:
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, &reg);
if (ret < 0) {
- dev_err(dev, "failed to read FAULT2 register: %d\n", ret);
+ dev_err(dev, "failed to read GLOB_FAULT2 register: %d\n", ret);
goto out;
}
@@ -530,7 +570,7 @@ check_warn_reg:
/* Store current warn value so we can detect any changes next time */
tas6424->last_warn = reg;
- /* Clear any faults by toggling the CLEAR_FAULT control bit */
+ /* Clear any warnings by toggling the CLEAR_FAULT control bit */
ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT);
if (ret < 0)
diff --git a/sound/soc/codecs/tas6424.h b/sound/soc/codecs/tas6424.h
index b5958c45ed0e..c67a7835ca66 100644
--- a/sound/soc/codecs/tas6424.h
+++ b/sound/soc/codecs/tas6424.h
@@ -116,6 +116,16 @@
#define TAS6424_LDGBYPASS_MASK BIT(TAS6424_LDGBYPASS_SHIFT)
/* TAS6424_GLOB_FAULT1_REG */
+#define TAS6424_FAULT_OC_CH1 BIT(7)
+#define TAS6424_FAULT_OC_CH2 BIT(6)
+#define TAS6424_FAULT_OC_CH3 BIT(5)
+#define TAS6424_FAULT_OC_CH4 BIT(4)
+#define TAS6424_FAULT_DC_CH1 BIT(3)
+#define TAS6424_FAULT_DC_CH2 BIT(2)
+#define TAS6424_FAULT_DC_CH3 BIT(1)
+#define TAS6424_FAULT_DC_CH4 BIT(0)
+
+/* TAS6424_GLOB_FAULT1_REG */
#define TAS6424_FAULT_CLOCK BIT(4)
#define TAS6424_FAULT_PVDD_OV BIT(3)
#define TAS6424_FAULT_VBAT_OV BIT(2)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index bf92d36b8f8a..608ad49ad978 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -167,6 +167,7 @@ struct aic31xx_priv {
u8 p_div;
int rate_div_line;
bool master_dapm_route_applied;
+ int irq;
};
struct aic31xx_rate_divs {
@@ -1391,6 +1392,69 @@ static const struct acpi_device_id aic31xx_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
#endif
+static irqreturn_t aic31xx_irq(int irq, void *data)
+{
+ struct aic31xx_priv *aic31xx = data;
+ struct device *dev = aic31xx->dev;
+ unsigned int value;
+ bool handled = false;
+ int ret;
+
+ ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value);
+ if (ret) {
+ dev_err(dev, "Failed to read interrupt mask: %d\n", ret);
+ goto exit;
+ }
+
+ if (value)
+ handled = true;
+ else
+ goto read_overflow;
+
+ if (value & AIC31XX_HPLSCDETECT)
+ dev_err(dev, "Short circuit on Left output is detected\n");
+ if (value & AIC31XX_HPRSCDETECT)
+ dev_err(dev, "Short circuit on Right output is detected\n");
+ if (value & ~(AIC31XX_HPLSCDETECT |
+ AIC31XX_HPRSCDETECT))
+ dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value);
+
+read_overflow:
+ ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value);
+ if (ret) {
+ dev_err(dev, "Failed to read overflow flag: %d\n", ret);
+ goto exit;
+ }
+
+ if (value)
+ handled = true;
+ else
+ goto exit;
+
+ if (value & AIC31XX_DAC_OF_LEFT)
+ dev_warn(dev, "Left-channel DAC overflow has occurred\n");
+ if (value & AIC31XX_DAC_OF_RIGHT)
+ dev_warn(dev, "Right-channel DAC overflow has occurred\n");
+ if (value & AIC31XX_DAC_OF_SHIFTER)
+ dev_warn(dev, "DAC barrel shifter overflow has occurred\n");
+ if (value & AIC31XX_ADC_OF)
+ dev_warn(dev, "ADC overflow has occurred\n");
+ if (value & AIC31XX_ADC_OF_SHIFTER)
+ dev_warn(dev, "ADC barrel shifter overflow has occurred\n");
+ if (value & ~(AIC31XX_DAC_OF_LEFT |
+ AIC31XX_DAC_OF_RIGHT |
+ AIC31XX_DAC_OF_SHIFTER |
+ AIC31XX_ADC_OF |
+ AIC31XX_ADC_OF_SHIFTER))
+ dev_warn(dev, "Unknown overflow interrupt flags: 0x%08x\n", value);
+
+exit:
+ if (handled)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
static int aic31xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1413,6 +1477,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
aic31xx->dev = &i2c->dev;
+ aic31xx->irq = i2c->irq;
aic31xx->codec_type = id->driver_data;
@@ -1456,6 +1521,26 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
return ret;
}
+ if (aic31xx->irq > 0) {
+ regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1,
+ AIC31XX_GPIO1_FUNC_MASK,
+ AIC31XX_GPIO1_INT1 <<
+ AIC31XX_GPIO1_FUNC_SHIFT);
+
+ regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
+ AIC31XX_SC |
+ AIC31XX_ENGINE);
+
+ ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq,
+ NULL, aic31xx_irq,
+ IRQF_ONESHOT, "aic31xx-irq",
+ aic31xx);
+ if (ret) {
+ dev_err(aic31xx->dev, "Unable to request IRQ\n");
+ return ret;
+ }
+ }
+
if (aic31xx->codec_type & DAC31XX_BIT)
return devm_snd_soc_register_component(&i2c->dev,
&soc_codec_driver_aic31xx,
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 0b587585b38b..2636f2c6bc79 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -173,6 +173,13 @@ struct aic31xx_pdata {
#define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1)
#define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0)
+/* AIC31XX_OFFLAG */
+#define AIC31XX_DAC_OF_LEFT BIT(7)
+#define AIC31XX_DAC_OF_RIGHT BIT(6)
+#define AIC31XX_DAC_OF_SHIFTER BIT(5)
+#define AIC31XX_ADC_OF BIT(3)
+#define AIC31XX_ADC_OF_SHIFTER BIT(1)
+
/* AIC31XX_INTRDACFLAG */
#define AIC31XX_HPLSCDETECT BIT(7)
#define AIC31XX_HPRSCDETECT BIT(6)
@@ -191,6 +198,22 @@ struct aic31xx_pdata {
#define AIC31XX_SC BIT(3)
#define AIC31XX_ENGINE BIT(2)
+/* AIC31XX_GPIO1 */
+#define AIC31XX_GPIO1_FUNC_MASK GENMASK(5, 2)
+#define AIC31XX_GPIO1_FUNC_SHIFT 2
+#define AIC31XX_GPIO1_DISABLED 0x00
+#define AIC31XX_GPIO1_INPUT 0x01
+#define AIC31XX_GPIO1_GPI 0x02
+#define AIC31XX_GPIO1_GPO 0x03
+#define AIC31XX_GPIO1_CLKOUT 0x04
+#define AIC31XX_GPIO1_INT1 0x05
+#define AIC31XX_GPIO1_INT2 0x06
+#define AIC31XX_GPIO1_ADC_WCLK 0x07
+#define AIC31XX_GPIO1_SBCLK 0x08
+#define AIC31XX_GPIO1_SWCLK 0x09
+#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10
+#define AIC31XX_GPIO1_SDOUT 0x11
+
/* AIC31XX_DACSETUP */
#define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index ff85a0bf6170..93d84e5ae2d5 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -3459,7 +3459,7 @@ static int tscs454_i2c_probe(struct i2c_client *i2c,
/* Sync pg sel reg with cache */
regmap_write(tscs454->regmap, R_PAGESEL, 0x00);
- ret = snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454,
+ ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_tscs454,
tscs454_dais, ARRAY_SIZE(tscs454_dais));
if (ret) {
dev_err(&i2c->dev, "Failed to register component (%d)\n", ret);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index f70db8412c7c..267aee776b2d 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1041,6 +1041,42 @@ static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
return error_ppm;
}
+static inline u32 davinci_mcasp_tx_delay(struct davinci_mcasp *mcasp)
+{
+ if (!mcasp->txnumevt)
+ return 0;
+
+ return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_WFIFOSTS_OFFSET);
+}
+
+static inline u32 davinci_mcasp_rx_delay(struct davinci_mcasp *mcasp)
+{
+ if (!mcasp->rxnumevt)
+ return 0;
+
+ return mcasp_get_reg(mcasp, mcasp->fifo_base + MCASP_RFIFOSTS_OFFSET);
+}
+
+static snd_pcm_sframes_t davinci_mcasp_delay(
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 fifo_use;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ fifo_use = davinci_mcasp_tx_delay(mcasp);
+ else
+ fifo_use = davinci_mcasp_rx_delay(mcasp);
+
+ /*
+ * Divide the used locations with the channel count to get the
+ * FIFO usage in samples (don't care about partial samples in the
+ * buffer).
+ */
+ return fifo_use / substream->runtime->channels;
+}
+
static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
@@ -1365,6 +1401,7 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.startup = davinci_mcasp_startup,
.shutdown = davinci_mcasp_shutdown,
.trigger = davinci_mcasp_trigger,
+ .delay = davinci_mcasp_delay,
.hw_params = davinci_mcasp_hw_params,
.set_fmt = davinci_mcasp_set_dai_fmt,
.set_clkdiv = davinci_mcasp_set_clkdiv,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index c1d1d06783e5..57b484768a58 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -807,7 +807,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
return -ENOMEM;
esai_priv->pdev = pdev;
- strncpy(esai_priv->name, np->name, sizeof(esai_priv->name) - 1);
+ snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np);
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
index 7f0fa4b52223..9981668ab590 100644
--- a/sound/soc/fsl/fsl_utils.c
+++ b/sound/soc/fsl/fsl_utils.c
@@ -57,8 +57,8 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
of_node_put(dma_channel_np);
return ret;
}
- snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
- (unsigned long long) res.start, dma_channel_np->name);
+ snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%pOFn",
+ (unsigned long long) res.start, dma_channel_np);
iprop = of_get_property(dma_channel_np, "cell-index", NULL);
if (!iprop) {
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 2094d2c8919f..fb6635f8d5d7 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -25,6 +25,8 @@ struct graph_card_data {
struct graph_dai_props {
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
+ struct snd_soc_dai_link_component codecs; /* single codec */
+ struct snd_soc_dai_link_component platform;
unsigned int mclk_fs;
} *dai_props;
unsigned int mclk_fs;
@@ -213,7 +215,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"%s-%s",
dai_link->cpu_dai_name,
- dai_link->codec_dai_name);
+ dai_link->codecs->dai_name);
if (ret < 0)
goto dai_link_of_err;
@@ -299,7 +301,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_dai_props *dai_props;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
- int num, ret;
+ int num, ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -315,6 +317,18 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
if (!dai_props || !dai_link)
return -ENOMEM;
+ /*
+ * Use snd_soc_dai_link_component instead of legacy style
+ * It is codec only. but cpu/platform will be supported in the future.
+ * see
+ * soc-core.c :: snd_soc_init_multicodec()
+ */
+ for (i = 0; i < num; i++) {
+ dai_link[i].codecs = &dai_props[i].codecs;
+ dai_link[i].num_codecs = 1;
+ dai_link[i].platform = &dai_props[i].platform;
+ }
+
priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
if (IS_ERR(priv->pa_gpio)) {
ret = PTR_ERR(priv->pa_gpio);
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c
index 92882e392d6c..b83bb31021a9 100644
--- a/sound/soc/generic/audio-graph-scu-card.c
+++ b/sound/soc/generic/audio-graph-scu-card.c
@@ -25,7 +25,11 @@
struct graph_card_data {
struct snd_soc_card snd_card;
struct snd_soc_codec_conf codec_conf;
- struct asoc_simple_dai *dai_props;
+ struct graph_dai_props {
+ struct asoc_simple_dai dai;
+ struct snd_soc_dai_link_component codecs;
+ struct snd_soc_dai_link_component platform;
+ } *dai_props;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_card_data adata;
};
@@ -39,18 +43,18 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
- return asoc_simple_card_clk_enable(dai_props);
+ return asoc_simple_card_clk_enable(&dai_props->dai);
}
static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(dai_props);
+ asoc_simple_card_clk_disable(&dai_props->dai);
}
static const struct snd_soc_ops asoc_graph_card_ops = {
@@ -63,7 +67,7 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai;
struct snd_soc_dai_link *dai_link;
- struct asoc_simple_dai *dai_props;
+ struct graph_dai_props *dai_props;
int num = rtd->num;
dai_link = graph_priv_to_link(priv, num);
@@ -72,7 +76,7 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
rtd->cpu_dai :
rtd->codec_dai;
- return asoc_simple_card_init_dai(dai, dai_props);
+ return asoc_simple_card_init_dai(dai, &dai_props->dai);
}
static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -92,15 +96,18 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
{
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
- struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, idx);
+ struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
struct snd_soc_card *card = graph_priv_to_card(priv);
int ret;
if (is_fe) {
+ struct snd_soc_dai_link_component *codecs;
+
/* BE is dummy */
- dai_link->codec_of_node = NULL;
- dai_link->codec_dai_name = "snd-soc-dummy-dai";
- dai_link->codec_name = "snd-soc-dummy";
+ codecs = dai_link->codecs;
+ codecs->of_node = NULL;
+ codecs->dai_name = "snd-soc-dummy-dai";
+ codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
@@ -110,7 +117,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret)
return ret;
- ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai_props);
+ ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai);
if (ret < 0)
return ret;
@@ -137,23 +144,23 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
- ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai_props);
+ ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"be.%s",
- dai_link->codec_dai_name);
+ dai_link->codecs->dai_name);
if (ret < 0)
return ret;
snd_soc_of_parse_audio_prefix(card,
&priv->codec_conf,
- dai_link->codec_of_node,
+ dai_link->codecs->of_node,
"prefix");
}
- ret = asoc_simple_card_of_parse_tdm(ep, dai_props);
+ ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai);
if (ret)
return ret;
@@ -331,10 +338,10 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
{
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
- struct asoc_simple_dai *dai_props;
+ struct graph_dai_props *dai_props;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
- int num, ret;
+ int num, ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -350,6 +357,18 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
if (!dai_props || !dai_link)
return -ENOMEM;
+ /*
+ * Use snd_soc_dai_link_component instead of legacy style
+ * It is codec only. but cpu/platform will be supported in the future.
+ * see
+ * soc-core.c :: snd_soc_init_multicodec()
+ */
+ for (i = 0; i < num; i++) {
+ dai_link[i].codecs = &dai_props[i].codecs;
+ dai_link[i].num_codecs = 1;
+ dai_link[i].platform = &dai_props[i].platform;
+ }
+
priv->dai_props = dai_props;
priv->dai_link = dai_link;
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index d3f3f0fec74c..b400dbf1f834 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -173,12 +173,24 @@ int asoc_simple_card_parse_clk(struct device *dev,
struct device_node *node,
struct device_node *dai_of_node,
struct asoc_simple_dai *simple_dai,
- const char *name)
+ const char *dai_name,
+ struct snd_soc_dai_link_component *dlc)
{
struct clk *clk;
u32 val;
/*
+ * Use snd_soc_dai_link_component instead of legacy style.
+ * It is only for codec, but cpu will be supported in the future.
+ * see
+ * soc-core.c :: snd_soc_init_multicodec()
+ */
+ if (dlc) {
+ dai_of_node = dlc->of_node;
+ dai_name = dlc->dai_name;
+ }
+
+ /*
* Parse dai->sysclk come from "clocks = <&xxx>"
* (if system has common clock)
* or "system-clock-frequency = <xxx>"
@@ -200,7 +212,7 @@ int asoc_simple_card_parse_clk(struct device *dev,
if (of_property_read_bool(node, "system-clock-direction-out"))
simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
- dev_dbg(dev, "%s : sysclk = %d, direction %d\n", name,
+ dev_dbg(dev, "%s : sysclk = %d, direction %d\n", dai_name,
simple_dai->sysclk, simple_dai->clk_direction);
return 0;
@@ -208,6 +220,7 @@ int asoc_simple_card_parse_clk(struct device *dev,
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk);
int asoc_simple_card_parse_dai(struct device_node *node,
+ struct snd_soc_dai_link_component *dlc,
struct device_node **dai_of_node,
const char **dai_name,
const char *list_name,
@@ -221,6 +234,17 @@ int asoc_simple_card_parse_dai(struct device_node *node,
return 0;
/*
+ * Use snd_soc_dai_link_component instead of legacy style.
+ * It is only for codec, but cpu will be supported in the future.
+ * see
+ * soc-core.c :: snd_soc_init_multicodec()
+ */
+ if (dlc) {
+ dai_name = &dlc->dai_name;
+ dai_of_node = &dlc->of_node;
+ }
+
+ /*
* Get node via "sound-dai = <&phandle port>"
* it will be used as xxx_of_node on soc_bind_dai_link()
*/
@@ -278,6 +302,7 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep)
}
int asoc_simple_card_parse_graph_dai(struct device_node *ep,
+ struct snd_soc_dai_link_component *dlc,
struct device_node **dai_of_node,
const char **dai_name)
{
@@ -285,6 +310,17 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep,
struct of_phandle_args args;
int ret;
+ /*
+ * Use snd_soc_dai_link_component instead of legacy style.
+ * It is only for codec, but cpu will be supported in the future.
+ * see
+ * soc-core.c :: snd_soc_init_multicodec()
+ */
+ if (dlc) {
+ dai_name = &dlc->dai_name;
+ dai_of_node = &dlc->of_node;
+ }
+
if (!ep)
return 0;
if (!dai_name)
@@ -340,10 +376,11 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai);
int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)
{
/* Assumes platform == cpu */
- if (!dai_link->platform_of_node)
- dai_link->platform_of_node = dai_link->cpu_of_node;
+ if (!dai_link->platform->of_node)
+ dai_link->platform->of_node = dai_link->cpu_of_node;
return 0;
+
}
EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink);
@@ -373,7 +410,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
num_links < card->num_links;
num_links++, dai_link++) {
of_node_put(dai_link->cpu_of_node);
- of_node_put(dai_link->codec_of_node);
+ of_node_put(dai_link->codecs->of_node);
}
return 0;
}
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 64bf3560c1d1..5a3f59aa4ba5 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -20,6 +20,8 @@ struct simple_card_data {
struct simple_dai_props {
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
+ struct snd_soc_dai_link_component codecs; /* single codec */
+ struct snd_soc_dai_link_component platform;
unsigned int mclk_fs;
} *dai_props;
unsigned int mclk_fs;
@@ -234,7 +236,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"%s-%s",
dai_link->cpu_dai_name,
- dai_link->codec_dai_name);
+ dai_link->codecs->dai_name);
if (ret < 0)
goto dai_link_of_err;
@@ -363,7 +365,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct snd_soc_card *card;
- int num, ret;
+ int num, ret, i;
/* Get the number of DAI links */
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
@@ -381,6 +383,18 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!dai_props || !dai_link)
return -ENOMEM;
+ /*
+ * Use snd_soc_dai_link_component instead of legacy style
+ * It is codec only. but cpu/platform will be supported in the future.
+ * see
+ * soc-core.c :: snd_soc_init_multicodec()
+ */
+ for (i = 0; i < num; i++) {
+ dai_link[i].codecs = &dai_props[i].codecs;
+ dai_link[i].num_codecs = 1;
+ dai_link[i].platform = &dai_props[i].platform;
+ }
+
priv->dai_props = dai_props;
priv->dai_link = dai_link;
@@ -403,6 +417,8 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
} else {
struct asoc_simple_card_info *cinfo;
+ struct snd_soc_dai_link_component *codecs;
+ struct snd_soc_dai_link_component *platform;
cinfo = dev->platform_data;
if (!cinfo) {
@@ -419,13 +435,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
return -EINVAL;
}
+ codecs = dai_link->codecs;
+ codecs->name = cinfo->codec;
+ codecs->dai_name = cinfo->codec_dai.name;
+
+ platform = dai_link->platform;
+ platform->name = cinfo->platform;
+
card->name = (cinfo->card) ? cinfo->card : cinfo->name;
dai_link->name = cinfo->name;
dai_link->stream_name = cinfo->name;
- dai_link->platform_name = cinfo->platform;
- dai_link->codec_name = cinfo->codec;
dai_link->cpu_dai_name = cinfo->cpu_dai.name;
- dai_link->codec_dai_name = cinfo->codec_dai.name;
dai_link->dai_fmt = cinfo->daifmt;
dai_link->init = asoc_simple_card_dai_init;
memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index 16a83bc51e0e..85b46f0eae0f 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -22,7 +22,11 @@
struct simple_card_data {
struct snd_soc_card snd_card;
struct snd_soc_codec_conf codec_conf;
- struct asoc_simple_dai *dai_props;
+ struct simple_dai_props {
+ struct asoc_simple_dai dai;
+ struct snd_soc_dai_link_component codecs;
+ struct snd_soc_dai_link_component platform;
+ } *dai_props;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_card_data adata;
};
@@ -40,20 +44,20 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct asoc_simple_dai *dai_props =
+ struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
- return asoc_simple_card_clk_enable(dai_props);
+ return asoc_simple_card_clk_enable(&dai_props->dai);
}
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
- struct asoc_simple_dai *dai_props =
+ struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
- asoc_simple_card_clk_disable(dai_props);
+ asoc_simple_card_clk_disable(&dai_props->dai);
}
static const struct snd_soc_ops asoc_simple_card_ops = {
@@ -66,7 +70,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai;
struct snd_soc_dai_link *dai_link;
- struct asoc_simple_dai *dai_props;
+ struct simple_dai_props *dai_props;
int num = rtd->num;
dai_link = simple_priv_to_link(priv, num);
@@ -75,7 +79,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
rtd->cpu_dai :
rtd->codec_dai;
- return asoc_simple_card_init_dai(dai, dai_props);
+ return asoc_simple_card_init_dai(dai, &dai_props->dai);
}
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -95,17 +99,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
- struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, idx);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
struct snd_soc_card *card = simple_priv_to_card(priv);
int ret;
if (is_fe) {
int is_single_links = 0;
+ struct snd_soc_dai_link_component *codecs;
/* BE is dummy */
- dai_link->codec_of_node = NULL;
- dai_link->codec_dai_name = "snd-soc-dummy-dai";
- dai_link->codec_name = "snd-soc-dummy";
+ codecs = dai_link->codecs;
+ codecs->of_node = NULL;
+ codecs->dai_name = "snd-soc-dummy-dai";
+ codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
@@ -116,7 +122,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret)
return ret;
- ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai_props);
+ ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai);
if (ret < 0)
return ret;
@@ -141,23 +147,23 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
- ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai_props);
+ ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"be.%s",
- dai_link->codec_dai_name);
+ dai_link->codecs->dai_name);
if (ret < 0)
return ret;
snd_soc_of_parse_audio_prefix(card,
&priv->codec_conf,
- dai_link->codec_of_node,
+ dai_link->codecs->of_node,
PREFIX "prefix");
}
- ret = asoc_simple_card_of_parse_tdm(np, dai_props);
+ ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai);
if (ret)
return ret;
@@ -230,11 +236,11 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
{
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
- struct asoc_simple_dai *dai_props;
+ struct simple_dai_props *dai_props;
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- int num, ret;
+ int num, ret, i;
/* Allocate the private data */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -248,6 +254,18 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
if (!dai_props || !dai_link)
return -ENOMEM;
+ /*
+ * Use snd_soc_dai_link_component instead of legacy style
+ * It is codec only. but cpu/platform will be supported in the future.
+ * see
+ * soc-core.c :: snd_soc_init_multicodec()
+ */
+ for (i = 0; i < num; i++) {
+ dai_link[i].codecs = &dai_props[i].codecs;
+ dai_link[i].num_codecs = 1;
+ dai_link[i].platform = &dai_props[i].platform;
+ }
+
priv->dai_props = dai_props;
priv->dai_link = dai_link;
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index cccda87f4b34..88e4b4284738 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -279,6 +279,15 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for DA7219 + MAX98357A I2S audio codec.
Say Y if you have such a device.
+
+config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
+ tristate "SKL/KBL/BXT/APL with HDA Codecs"
+ select SND_SOC_HDAC_HDMI
+ select SND_SOC_HDAC_HDA
+ help
+ This adds support for ASoC machine driver for Intel platforms
+ SKL/KBL/BXT/APL with iDisp, HDA audio codecs.
+ Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 87ef8b4058e5..6e88373cbe35 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
snd-soc-skl_rt286-objs := skl_rt286.o
+snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
@@ -46,3 +47,4 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt566
obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
+obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
index e5aa13058dd7..e054318185ea 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
@@ -16,6 +16,7 @@
* General Public License for more details.
*/
+#include <linux/input.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -212,6 +213,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
if (ret)
return ret;
+ snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+
rt5670_set_jack_detect(component, &ctx->headset);
if (ctx->mclk) {
/*
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 21a6490746a6..99e1320c485f 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -488,11 +488,10 @@ 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;
+ struct snd_soc_dai *codec_dai;
int ret = 0, j;
- for (j = 0; j < rtd->num_codecs; j++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
-
+ for_each_rtd_codec_dai(rtd, j, codec_dai) {
if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
/*
* Use channel 4 and 5 for the first amp
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index a892b37eab7c..a737c915d46a 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -353,11 +353,10 @@ 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;
+ struct snd_soc_dai *codec_dai;
int ret = 0, j;
- for (j = 0; j < rtd->num_codecs; j++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
-
+ for_each_rtd_codec_dai(rtd, j, codec_dai) {
if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) {
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16);
if (ret < 0) {
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c
new file mode 100644
index 000000000000..3fdbf239da74
--- /dev/null
+++ b/sound/soc/intel/boards/skl_hda_dsp_common.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2015-18 Intel Corporation.
+
+/*
+ * Common functions used in different Intel machine drivers
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/hdac_hdmi.h"
+#include "../skylake/skl.h"
+#include "skl_hda_dsp_common.h"
+
+#define NAME_SIZE 32
+
+int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device)
+{
+ struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
+ struct skl_hda_hdmi_pcm *pcm;
+ char dai_name[NAME_SIZE];
+
+ pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+
+ snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d",
+ ctx->dai_index);
+ pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name);
+ if (!pcm->codec_dai)
+ return -EINVAL;
+
+ pcm->device = device;
+ list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+ return 0;
+}
+
+/* skl_hda_digital audio interface glue - connects codec <--> CPU */
+struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = {
+ /* Back End DAI links */
+ {
+ .name = "iDisp1",
+ .id = 1,
+ .cpu_dai_name = "iDisp1 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi1",
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp2",
+ .id = 2,
+ .cpu_dai_name = "iDisp2 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi2",
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp3",
+ .id = 3,
+ .cpu_dai_name = "iDisp3 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi3",
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "Analog Playback and Capture",
+ .id = 4,
+ .cpu_dai_name = "Analog CPU DAI",
+ .codec_name = "ehdaudio0D0",
+ .codec_dai_name = "Analog Codec DAI",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .init = NULL,
+ .no_pcm = 1,
+ },
+ {
+ .name = "Digital Playback and Capture",
+ .id = 5,
+ .cpu_dai_name = "Digital CPU DAI",
+ .codec_name = "ehdaudio0D0",
+ .codec_dai_name = "Digital Codec DAI",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .init = NULL,
+ .no_pcm = 1,
+ },
+};
+
+int skl_hda_hdmi_jack_init(struct snd_soc_card *card)
+{
+ struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_component *component = NULL;
+ struct skl_hda_hdmi_pcm *pcm;
+ char jack_name[NAME_SIZE];
+ int err;
+
+ list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+ component = pcm->codec_dai->component;
+ snprintf(jack_name, sizeof(jack_name),
+ "HDMI/DP, pcm=%d Jack", pcm->device);
+ err = snd_soc_card_jack_new(card, jack_name,
+ SND_JACK_AVOUT, &pcm->hdmi_jack,
+ NULL, 0);
+
+ if (err)
+ return err;
+
+ err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+ &pcm->hdmi_jack);
+ if (err < 0)
+ return err;
+ }
+
+ if (!component)
+ return -EINVAL;
+
+ return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h
new file mode 100644
index 000000000000..87c50aff56cd
--- /dev/null
+++ b/sound/soc/intel/boards/skl_hda_dsp_common.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright(c) 2015-18 Intel Corporation.
+ */
+
+/*
+ * This file defines data structures used in Machine Driver for Intel
+ * platforms with HDA Codecs.
+ */
+
+#ifndef __SOUND_SOC_HDA_DSP_COMMON_H
+#define __SOUND_SOC_HDA_DSP_COMMON_H
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+
+#define HDA_DSP_MAX_BE_DAI_LINKS 5
+
+struct skl_hda_hdmi_pcm {
+ struct list_head head;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_jack hdmi_jack;
+ int device;
+};
+
+struct skl_hda_private {
+ struct list_head hdmi_pcm_list;
+ int pcm_count;
+ int dai_index;
+ const char *platform_name;
+};
+
+extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS];
+int skl_hda_hdmi_jack_init(struct snd_soc_card *card);
+int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device);
+
+#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
new file mode 100644
index 000000000000..b213e9b47505
--- /dev/null
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2015-18 Intel Corporation.
+
+/*
+ * Machine Driver for SKL+ platforms with DSP and iDisp, HDA Codecs
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/hdac_hdmi.h"
+#include "../skylake/skl.h"
+#include "skl_hda_dsp_common.h"
+
+static const struct snd_soc_dapm_widget skl_hda_widgets[] = {
+ SND_SOC_DAPM_HP("Analog Out", NULL),
+ SND_SOC_DAPM_MIC("Analog In", NULL),
+ SND_SOC_DAPM_HP("Alt Analog Out", NULL),
+ SND_SOC_DAPM_MIC("Alt Analog In", NULL),
+ SND_SOC_DAPM_SPK("Digital Out", NULL),
+ SND_SOC_DAPM_MIC("Digital In", NULL),
+};
+
+static const struct snd_soc_dapm_route skl_hda_map[] = {
+ { "hifi3", NULL, "iDisp3 Tx"},
+ { "iDisp3 Tx", NULL, "iDisp3_out"},
+ { "hifi2", NULL, "iDisp2 Tx"},
+ { "iDisp2 Tx", NULL, "iDisp2_out"},
+ { "hifi1", NULL, "iDisp1 Tx"},
+ { "iDisp1 Tx", NULL, "iDisp1_out"},
+
+ { "Analog Out", NULL, "Codec Output Pin1" },
+ { "Digital Out", NULL, "Codec Output Pin2" },
+ { "Alt Analog Out", NULL, "Codec Output Pin3" },
+
+ { "Codec Input Pin1", NULL, "Analog In" },
+ { "Codec Input Pin2", NULL, "Digital In" },
+ { "Codec Input Pin3", NULL, "Alt Analog In" },
+
+ /* CODEC BE connections */
+ { "Analog Codec Playback", NULL, "Analog CPU Playback" },
+ { "Analog CPU Playback", NULL, "codec0_out" },
+ { "Digital Codec Playback", NULL, "Digital CPU Playback" },
+ { "Digital CPU Playback", NULL, "codec1_out" },
+ { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" },
+ { "Alt Analog CPU Playback", NULL, "codec2_out" },
+
+ { "codec0_in", NULL, "Analog CPU Capture" },
+ { "Analog CPU Capture", NULL, "Analog Codec Capture" },
+ { "codec1_in", NULL, "Digital CPU Capture" },
+ { "Digital CPU Capture", NULL, "Digital Codec Capture" },
+ { "codec2_in", NULL, "Alt Analog CPU Capture" },
+ { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" },
+};
+
+static int skl_hda_card_late_probe(struct snd_soc_card *card)
+{
+ return skl_hda_hdmi_jack_init(card);
+}
+
+static int
+skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
+{
+ struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
+ int ret = 0;
+
+ dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name);
+ link->platform_name = ctx->platform_name;
+ link->nonatomic = 1;
+
+ if (strstr(link->name, "HDMI")) {
+ ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count);
+
+ if (ret < 0)
+ return ret;
+
+ ctx->dai_index++;
+ }
+
+ ctx->pcm_count++;
+ return ret;
+}
+
+static struct snd_soc_card hda_soc_card = {
+ .name = "skl_hda_card",
+ .owner = THIS_MODULE,
+ .dai_link = skl_hda_be_dai_links,
+ .dapm_widgets = skl_hda_widgets,
+ .dapm_routes = skl_hda_map,
+ .add_dai_link = skl_hda_add_dai_link,
+ .fully_routed = true,
+ .late_probe = skl_hda_card_late_probe,
+};
+
+#define IDISP_DAI_COUNT 3
+/* there are two routes per iDisp output */
+#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2)
+#define IDISP_CODEC_MASK 0x4
+
+static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
+{
+ struct snd_soc_card *card = &hda_soc_card;
+ u32 codec_count, codec_mask;
+ int i, num_links, num_route;
+
+ codec_mask = pdata->codec_mask;
+ codec_count = hweight_long(codec_mask);
+
+ if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) {
+ num_links = IDISP_DAI_COUNT;
+ num_route = IDISP_ROUTE_COUNT;
+ } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) {
+ num_links = ARRAY_SIZE(skl_hda_be_dai_links);
+ num_route = ARRAY_SIZE(skl_hda_map),
+ card->dapm_widgets = skl_hda_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets);
+ } else {
+ return -EINVAL;
+ }
+
+ card->num_links = num_links;
+ card->num_dapm_routes = num_route;
+
+ for (i = 0; i < num_links; i++)
+ skl_hda_be_dai_links[i].platform_name = pdata->platform;
+
+ return 0;
+}
+
+static int skl_hda_audio_probe(struct platform_device *pdev)
+{
+ struct skl_machine_pdata *pdata;
+ struct skl_hda_private *ctx;
+ int ret;
+
+ dev_dbg(&pdev->dev, "%s: entry\n", __func__);
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ if (!ctx)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+ pdata = dev_get_drvdata(&pdev->dev);
+ if (!pdata)
+ return -EINVAL;
+
+ ret = skl_hda_fill_card_info(pdata);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n");
+ return ret;
+ }
+
+ ctx->pcm_count = hda_soc_card.num_links;
+ ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */
+ ctx->platform_name = pdata->platform;
+
+ hda_soc_card.dev = &pdev->dev;
+ snd_soc_card_set_drvdata(&hda_soc_card, ctx);
+
+ return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card);
+}
+
+static struct platform_driver skl_hda_audio = {
+ .probe = skl_hda_audio_probe,
+ .driver = {
+ .name = "skl_hda_dsp_generic",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(skl_hda_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver");
+MODULE_AUTHOR("Rakesh Ughreja <rakesh.a.ughreja@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_hda_dsp_generic");
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index 915a34cdc8ac..c1f50a079d34 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -7,7 +7,8 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
soc-acpi-intel-hsw-bdw-match.o \
soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \
soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \
- soc-acpi-intel-cnl-match.o
+ soc-acpi-intel-cnl-match.o \
+ soc-acpi-intel-hda-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
diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
index 4daa8a4f0c0c..097dc06377ba 100644
--- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
@@ -34,6 +34,13 @@ 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 8"),
+ },
+ },
+ {
+ .callback = byt_thinkpad10_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"),
},
},
diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c
new file mode 100644
index 000000000000..533c1064f84b
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, Intel Corporation.
+
+/*
+ * soc-apci-intel-hda-match.c - tables and support for HDA+ACPI enumeration.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata hda_pdata = {
+ .use_tplg_pcm = true,
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = {
+ {
+ /* .id is not used in this file */
+ .drv_name = "skl_hda_dsp_generic",
+
+ /* .fw_filename is dynamically set in skylake driver */
+
+ /* .sof_fw_filename is dynamically set in sof/intel driver */
+
+ .sof_tplg_filename = "intel/sof-hda-generic.tplg",
+
+ /*
+ * .machine_quirk and .quirk_data are not used here but
+ * can be used if we need a more complicated machine driver
+ * combining HDA+other device (e.g. DMIC).
+ */
+ .pdata = &hda_pdata,
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_hda_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
index 8734040d64d3..363145716a6d 100644
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ b/sound/soc/intel/common/sst-dsp-priv.h
@@ -153,7 +153,7 @@ struct sst_block_allocator {
};
/*
- * Runtime Module Instance - A module object can be instanciated multiple
+ * Runtime Module Instance - A module object can be instantiated multiple
* times within the DSP FW.
*/
struct sst_module_runtime {
@@ -193,7 +193,7 @@ enum sst_module_state {
*
* Each Firmware file can consist of 1..N modules. A module can span multiple
* ADSP memory blocks. The simplest FW will be a file with 1 module. A module
- * can be instanciated multiple times in the DSP.
+ * can be instantiated multiple times in the DSP.
*/
struct sst_module {
struct sst_dsp *dsp;
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 823e39103edd..00b7a91b18c9 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -32,6 +32,7 @@
#define HDA_MONO 1
#define HDA_STEREO 2
#define HDA_QUAD 4
+#define HDA_MAX 8
static const struct snd_pcm_hardware azx_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
@@ -569,7 +570,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
stream_tag = hdac_stream(link_dev)->stream_tag;
/* set the stream tag in the codec dai dma params */
- snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
+ else
+ snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0);
p_params.s_fmt = snd_pcm_format_width(params_format(params));
p_params.ch = params_channels(params);
@@ -995,21 +999,63 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
},
{
- .name = "HD-Codec Pin",
+ .name = "Analog CPU DAI",
.ops = &skl_link_dai_ops,
.playback = {
- .stream_name = "HD-Codec Tx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .stream_name = "Analog CPU Playback",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_MAX,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
- .stream_name = "HD-Codec Rx",
- .channels_min = HDA_STEREO,
- .channels_max = HDA_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .stream_name = "Analog CPU Capture",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_MAX,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+},
+{
+ .name = "Alt Analog CPU DAI",
+ .ops = &skl_link_dai_ops,
+ .playback = {
+ .stream_name = "Alt Analog CPU Playback",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_MAX,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "Alt Analog CPU Capture",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_MAX,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+},
+{
+ .name = "Digital CPU DAI",
+ .ops = &skl_link_dai_ops,
+ .playback = {
+ .stream_name = "Digital CPU Playback",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_MAX,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .capture = {
+ .stream_name = "Digital CPU Capture",
+ .channels_min = HDA_MONO,
+ .channels_max = HDA_MAX,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
},
},
};
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 2620d77729c5..52a9915da0f5 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -898,11 +898,10 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
bc = (struct skl_algo_data *)sb->dobj.private;
if (bc->set_params == SKL_PARAM_BIND) {
- params = kzalloc(bc->max, GFP_KERNEL);
+ params = kmemdup(bc->params, bc->max, GFP_KERNEL);
if (!params)
return -ENOMEM;
- memcpy(params, bc->params, bc->max);
skl_fill_sink_instance_id(ctx, params, bc->max,
mconfig);
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index cf09721ca13e..e7fd14daeb4f 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -33,9 +33,11 @@
#include <sound/hda_register.h>
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
+#include <sound/hda_codec.h>
#include "skl.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
+#include "../../../soc/codecs/hdac_hda.h"
/*
* initialize the PCI registers
@@ -472,6 +474,25 @@ static struct skl_ssp_clk skl_ssp_clks[] = {
{.name = "ssp5_sclkfs"},
};
+static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl *skl,
+ struct snd_soc_acpi_mach *machines)
+{
+ struct hdac_bus *bus = skl_to_bus(skl);
+ struct snd_soc_acpi_mach *mach;
+
+ /* check if we have any codecs detected on bus */
+ if (bus->codec_mask == 0)
+ return NULL;
+
+ /* point to common table */
+ mach = snd_soc_acpi_intel_hda_machines;
+
+ /* all entries in the machine table use the same firmware */
+ mach->fw_filename = machines->fw_filename;
+
+ return mach;
+}
+
static int skl_find_machine(struct skl *skl, void *driver_data)
{
struct hdac_bus *bus = skl_to_bus(skl);
@@ -479,9 +500,13 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
struct skl_machine_pdata *pdata;
mach = snd_soc_acpi_find_machine(mach);
- if (mach == NULL) {
- dev_err(bus->dev, "No matching machine driver found\n");
- return -ENODEV;
+ if (!mach) {
+ dev_dbg(bus->dev, "No matching I2S machine driver found\n");
+ mach = skl_find_hda_machine(skl, driver_data);
+ if (!mach) {
+ dev_err(bus->dev, "No matching machine driver found\n");
+ return -ENODEV;
+ }
}
skl->mach = mach;
@@ -498,8 +523,9 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
static int skl_machine_device_register(struct skl *skl)
{
- struct hdac_bus *bus = skl_to_bus(skl);
struct snd_soc_acpi_mach *mach = skl->mach;
+ struct hdac_bus *bus = skl_to_bus(skl);
+ struct skl_machine_pdata *pdata;
struct platform_device *pdev;
int ret;
@@ -516,8 +542,12 @@ static int skl_machine_device_register(struct skl *skl)
return -EIO;
}
- if (mach->pdata)
+ if (mach->pdata) {
+ pdata = (struct skl_machine_pdata *)mach->pdata;
+ pdata->platform = dev_name(bus->dev);
+ pdata->codec_mask = bus->codec_mask;
dev_set_drvdata(&pdev->dev, mach->pdata);
+ }
skl->i2s_dev = pdev;
@@ -628,6 +658,24 @@ static void skl_clock_device_unregister(struct skl *skl)
platform_device_unregister(skl->clk_dev);
}
+#define IDISP_INTEL_VENDOR_ID 0x80860000
+
+/*
+ * load the legacy codec driver
+ */
+static void load_codec_module(struct hda_codec *codec)
+{
+#ifdef MODULE
+ char modalias[MODULE_NAME_LEN];
+ const char *mod = NULL;
+
+ snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias));
+ mod = modalias;
+ dev_dbg(&codec->core.dev, "loading %s codec module\n", mod);
+ request_module(mod);
+#endif
+}
+
/*
* Probe the given codec address
*/
@@ -637,7 +685,9 @@ static int probe_codec(struct hdac_bus *bus, int addr)
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
unsigned int res = -1;
struct skl *skl = bus_to_skl(bus);
+ struct hdac_hda_priv *hda_codec;
struct hdac_device *hdev;
+ int err;
mutex_lock(&bus->cmd_mutex);
snd_hdac_bus_send_cmd(bus, cmd);
@@ -645,13 +695,26 @@ static int probe_codec(struct hdac_bus *bus, int addr)
mutex_unlock(&bus->cmd_mutex);
if (res == -1)
return -EIO;
- dev_dbg(bus->dev, "codec #%d probed OK\n", addr);
+ dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res);
- hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL);
- if (!hdev)
+ hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec),
+ GFP_KERNEL);
+ if (!hda_codec)
return -ENOMEM;
- return snd_hdac_ext_bus_device_init(bus, addr, hdev);
+ hda_codec->codec.bus = skl_to_hbus(skl);
+ hdev = &hda_codec->codec.core;
+
+ err = snd_hdac_ext_bus_device_init(bus, addr, hdev);
+ if (err < 0)
+ return err;
+
+ /* use legacy bus only for HDA codecs, idisp uses ext bus */
+ if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) {
+ hdev->type = HDA_DEV_LEGACY;
+ load_codec_module(&hda_codec->codec);
+ }
+ return 0;
}
/* Codec initialization */
@@ -786,9 +849,10 @@ static int skl_create(struct pci_dev *pci,
const struct hdac_io_ops *io_ops,
struct skl **rskl)
{
+ struct hdac_ext_bus_ops *ext_ops = NULL;
struct skl *skl;
struct hdac_bus *bus;
-
+ struct hda_bus *hbus;
int err;
*rskl = NULL;
@@ -803,13 +867,23 @@ static int skl_create(struct pci_dev *pci,
return -ENOMEM;
}
+ hbus = skl_to_hbus(skl);
bus = skl_to_bus(skl);
- snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL);
+
+#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA)
+ ext_ops = snd_soc_hdac_hda_get_ops();
+#endif
+ snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops);
bus->use_posbuf = 1;
skl->pci = pci;
INIT_WORK(&skl->probe_work, skl_probe_work);
bus->bdl_pos_adj = 0;
+ mutex_init(&hbus->prepare_mutex);
+ hbus->pci = pci;
+ hbus->mixer_assigned = -1;
+ hbus->modelname = "sklbus";
+
*rskl = skl;
return 0;
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 78aa8bdcb619..8d48cd7c56c8 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -23,6 +23,7 @@
#include <sound/hda_register.h>
#include <sound/hdaudio_ext.h>
+#include <sound/hda_codec.h>
#include <sound/soc.h>
#include "skl-nhlt.h"
#include "skl-ssp-clk.h"
@@ -71,7 +72,7 @@ struct skl_fw_config {
};
struct skl {
- struct hdac_bus hbus;
+ struct hda_bus hbus;
struct pci_dev *pci;
unsigned int init_done:1; /* delayed init status */
@@ -105,8 +106,11 @@ struct skl {
struct snd_soc_acpi_mach *mach;
};
-#define skl_to_bus(s) (&(s)->hbus)
-#define bus_to_skl(bus) container_of(bus, struct skl, hbus)
+#define skl_to_bus(s) (&(s)->hbus.core)
+#define bus_to_skl(bus) container_of(bus, struct skl, hbus.core)
+
+#define skl_to_hbus(s) (&(s)->hbus)
+#define hbus_to_skl(hbus) container_of((hbus), struct skl, (hbus))
/* to pass dai dma data */
struct skl_dma_params {
@@ -117,6 +121,8 @@ struct skl_dma_params {
struct skl_machine_pdata {
u32 dmic_num;
bool use_tplg_pcm; /* use dais and dai links from topology */
+ const char *platform;
+ u32 codec_mask;
};
struct skl_dsp_ops {
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index 582174d98c6c..5b4e90180827 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -44,11 +44,10 @@ static int mt8173_rt5650_rt5514_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;
int i, ret;
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
-
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
/* pll from mclk 12.288M */
ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
params_rate(params) * 512);
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index b3670c8a5b8d..82675ed057de 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -48,11 +48,10 @@ static int mt8173_rt5650_rt5676_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;
int i, ret;
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
-
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
/* pll from mclk 12.288M */
ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
params_rate(params) * 512);
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index 7a89b4aad182..ef05fbc40c32 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -59,6 +59,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned int mclk_clock;
+ struct snd_soc_dai *codec_dai;
int i, ret;
switch (mt8173_rt5650_priv.pll_from) {
@@ -76,9 +77,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream,
break;
}
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
-
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
/* pll from mclk */
ret = snd_soc_dai_set_pll(codec_dai, 0, 0, mclk_clock,
params_rate(params) * 512);
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
index 8af8bc358a90..8b8426ed2363 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -4,6 +4,8 @@ menu "ASoC support for Amlogic platforms"
config SND_MESON_AXG_FIFO
tristate
select REGMAP_MMIO
+ imply COMMON_CLK_AXG_AUDIO
+ imply RESET_MESON_AUDIO_ARB
config SND_MESON_AXG_FRDDR
tristate "Amlogic AXG Playback FIFO support"
@@ -22,6 +24,7 @@ config SND_MESON_AXG_TODDR
config SND_MESON_AXG_TDM_FORMATTER
tristate
select REGMAP_MMIO
+ imply COMMON_CLK_AXG_AUDIO
config SND_MESON_AXG_TDM_INTERFACE
tristate
@@ -51,6 +54,7 @@ config SND_MESON_AXG_SOUND_CARD
imply SND_MESON_AXG_TDMIN
imply SND_MESON_AXG_TDMOUT
imply SND_MESON_AXG_SPDIFOUT
+ imply SND_MESON_AXG_PDM
help
Select Y or M to add support for the AXG SoC sound card
@@ -58,8 +62,17 @@ config SND_MESON_AXG_SPDIFOUT
tristate "Amlogic AXG SPDIF Output Support"
select SND_PCM_IEC958
imply SND_SOC_SPDIF
+ imply COMMON_CLK_AXG_AUDIO
help
Select Y or M to add support for SPDIF output serializer embedded
in the Amlogic AXG SoC family
+config SND_MESON_AXG_PDM
+ tristate "Amlogic AXG PDM Input Support"
+ imply SND_SOC_DMIC
+ imply COMMON_CLK_AXG_AUDIO
+ help
+ Select Y or M to add support for PDM input embedded
+ in the Amlogic AXG SoC family
+
endmenu
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
index c5e003b093db..4cd25104029d 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -9,6 +9,7 @@ snd-soc-meson-axg-tdmin-objs := axg-tdmin.o
snd-soc-meson-axg-tdmout-objs := axg-tdmout.o
snd-soc-meson-axg-sound-card-objs := axg-card.o
snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
+snd-soc-meson-axg-pdm-objs := axg-pdm.o
obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o
obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o
@@ -19,3 +20,4 @@ obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o
obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o
obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
+obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
index 2914ba0d965b..197e10a96e28 100644
--- a/sound/soc/meson/axg-card.c
+++ b/sound/soc/meson/axg-card.c
@@ -97,14 +97,15 @@ static void axg_card_clean_references(struct axg_card *priv)
{
struct snd_soc_card *card = &priv->card;
struct snd_soc_dai_link *link;
+ struct snd_soc_dai_link_component *codec;
int i, j;
if (card->dai_link) {
for (i = 0; i < card->num_links; i++) {
link = &card->dai_link[i];
of_node_put(link->cpu_of_node);
- for (j = 0; j < link->num_codecs; j++)
- of_node_put(link->codecs[j].of_node);
+ for_each_link_codecs(link, j, codec)
+ of_node_put(codec->of_node);
}
}
@@ -167,8 +168,7 @@ static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream,
if (be->mclk_fs) {
mclk = params_rate(params) * be->mclk_fs;
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
SND_SOC_CLOCK_IN);
if (ret && ret != -ENOTSUPP)
@@ -196,8 +196,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dai *codec_dai;
int ret, i;
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
ret = snd_soc_dai_set_tdm_slot(codec_dai,
be->codec_masks[i].tx,
be->codec_masks[i].rx,
@@ -478,7 +477,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card,
ret = axg_card_set_link_name(card, link, "be");
if (ret)
- dev_err(card->dev, "error setting %s link name\n", np->name);
+ dev_err(card->dev, "error setting %pOFn link name\n", np);
return ret;
}
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c
index 30262550e37b..0e4f65e654c4 100644
--- a/sound/soc/meson/axg-fifo.c
+++ b/sound/soc/meson/axg-fifo.c
@@ -203,6 +203,8 @@ static int axg_fifo_pcm_open(struct snd_pcm_substream *ss)
ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0,
dev_name(dev), ss);
+ if (ret)
+ return ret;
/* Enable pclk to access registers and clock the fifo ip */
ret = clk_prepare_enable(fifo->pclk);
diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c
new file mode 100644
index 000000000000..9d5684493ffc
--- /dev/null
+++ b/sound/soc/meson/axg-pdm.c
@@ -0,0 +1,654 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm_params.h>
+
+#define PDM_CTRL 0x00
+#define PDM_CTRL_EN BIT(31)
+#define PDM_CTRL_OUT_MODE BIT(29)
+#define PDM_CTRL_BYPASS_MODE BIT(28)
+#define PDM_CTRL_RST_FIFO BIT(16)
+#define PDM_CTRL_CHAN_RSTN_MASK GENMASK(15, 8)
+#define PDM_CTRL_CHAN_RSTN(x) ((x) << 8)
+#define PDM_CTRL_CHAN_EN_MASK GENMASK(7, 0)
+#define PDM_CTRL_CHAN_EN(x) ((x) << 0)
+#define PDM_HCIC_CTRL1 0x04
+#define PDM_FILTER_EN BIT(31)
+#define PDM_HCIC_CTRL1_GAIN_SFT_MASK GENMASK(29, 24)
+#define PDM_HCIC_CTRL1_GAIN_SFT(x) ((x) << 24)
+#define PDM_HCIC_CTRL1_GAIN_MULT_MASK GENMASK(23, 16)
+#define PDM_HCIC_CTRL1_GAIN_MULT(x) ((x) << 16)
+#define PDM_HCIC_CTRL1_DSR_MASK GENMASK(8, 4)
+#define PDM_HCIC_CTRL1_DSR(x) ((x) << 4)
+#define PDM_HCIC_CTRL1_STAGE_NUM_MASK GENMASK(3, 0)
+#define PDM_HCIC_CTRL1_STAGE_NUM(x) ((x) << 0)
+#define PDM_HCIC_CTRL2 0x08
+#define PDM_F1_CTRL 0x0c
+#define PDM_LPF_ROUND_MODE_MASK GENMASK(17, 16)
+#define PDM_LPF_ROUND_MODE(x) ((x) << 16)
+#define PDM_LPF_DSR_MASK GENMASK(15, 12)
+#define PDM_LPF_DSR(x) ((x) << 12)
+#define PDM_LPF_STAGE_NUM_MASK GENMASK(8, 0)
+#define PDM_LPF_STAGE_NUM(x) ((x) << 0)
+#define PDM_LPF_MAX_STAGE 336
+#define PDM_LPF_NUM 3
+#define PDM_F2_CTRL 0x10
+#define PDM_F3_CTRL 0x14
+#define PDM_HPF_CTRL 0x18
+#define PDM_HPF_SFT_STEPS_MASK GENMASK(20, 16)
+#define PDM_HPF_SFT_STEPS(x) ((x) << 16)
+#define PDM_HPF_OUT_FACTOR_MASK GENMASK(15, 0)
+#define PDM_HPF_OUT_FACTOR(x) ((x) << 0)
+#define PDM_CHAN_CTRL 0x1c
+#define PDM_CHAN_CTRL_POINTER_WIDTH 8
+#define PDM_CHAN_CTRL_POINTER_MAX ((1 << PDM_CHAN_CTRL_POINTER_WIDTH) - 1)
+#define PDM_CHAN_CTRL_NUM 4
+#define PDM_CHAN_CTRL1 0x20
+#define PDM_COEFF_ADDR 0x24
+#define PDM_COEFF_DATA 0x28
+#define PDM_CLKG_CTRL 0x2c
+#define PDM_STS 0x30
+
+struct axg_pdm_lpf {
+ unsigned int ds;
+ unsigned int round_mode;
+ const unsigned int *tap;
+ unsigned int tap_num;
+};
+
+struct axg_pdm_hcic {
+ unsigned int shift;
+ unsigned int mult;
+ unsigned int steps;
+ unsigned int ds;
+};
+
+struct axg_pdm_hpf {
+ unsigned int out_factor;
+ unsigned int steps;
+};
+
+struct axg_pdm_filters {
+ struct axg_pdm_hcic hcic;
+ struct axg_pdm_hpf hpf;
+ struct axg_pdm_lpf lpf[PDM_LPF_NUM];
+};
+
+struct axg_pdm_cfg {
+ const struct axg_pdm_filters *filters;
+ unsigned int sys_rate;
+};
+
+struct axg_pdm {
+ const struct axg_pdm_cfg *cfg;
+ struct regmap *map;
+ struct clk *dclk;
+ struct clk *sysclk;
+ struct clk *pclk;
+};
+
+static void axg_pdm_enable(struct regmap *map)
+{
+ /* Reset AFIFO */
+ regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, PDM_CTRL_RST_FIFO);
+ regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, 0);
+
+ /* Enable PDM */
+ regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, PDM_CTRL_EN);
+}
+
+static void axg_pdm_disable(struct regmap *map)
+{
+ regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, 0);
+}
+
+static void axg_pdm_filters_enable(struct regmap *map, bool enable)
+{
+ unsigned int val = enable ? PDM_FILTER_EN : 0;
+
+ regmap_update_bits(map, PDM_HCIC_CTRL1, PDM_FILTER_EN, val);
+ regmap_update_bits(map, PDM_F1_CTRL, PDM_FILTER_EN, val);
+ regmap_update_bits(map, PDM_F2_CTRL, PDM_FILTER_EN, val);
+ regmap_update_bits(map, PDM_F3_CTRL, PDM_FILTER_EN, val);
+ regmap_update_bits(map, PDM_HPF_CTRL, PDM_FILTER_EN, val);
+}
+
+static int axg_pdm_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ axg_pdm_enable(priv->map);
+ return 0;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ axg_pdm_disable(priv->map);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static unsigned int axg_pdm_get_os(struct axg_pdm *priv)
+{
+ const struct axg_pdm_filters *filters = priv->cfg->filters;
+ unsigned int os = filters->hcic.ds;
+ int i;
+
+ /*
+ * The global oversampling factor is defined by the down sampling
+ * factor applied by each filter (HCIC and LPFs)
+ */
+
+ for (i = 0; i < PDM_LPF_NUM; i++)
+ os *= filters->lpf[i].ds;
+
+ return os;
+}
+
+static int axg_pdm_set_sysclk(struct axg_pdm *priv, unsigned int os,
+ unsigned int rate)
+{
+ unsigned int sys_rate = os * 2 * rate * PDM_CHAN_CTRL_POINTER_MAX;
+
+ /*
+ * Set the default system clock rate unless it is too fast for
+ * for the requested sample rate. In this case, the sample pointer
+ * counter could overflow so set a lower system clock rate
+ */
+ if (sys_rate < priv->cfg->sys_rate)
+ return clk_set_rate(priv->sysclk, sys_rate);
+
+ return clk_set_rate(priv->sysclk, priv->cfg->sys_rate);
+}
+
+static int axg_pdm_set_sample_pointer(struct axg_pdm *priv)
+{
+ unsigned int spmax, sp, val;
+ int i;
+
+ /* Max sample counter value per half period of dclk */
+ spmax = DIV_ROUND_UP_ULL((u64)clk_get_rate(priv->sysclk),
+ clk_get_rate(priv->dclk) * 2);
+
+ /* Check if sysclk is not too fast - should not happen */
+ if (WARN_ON(spmax > PDM_CHAN_CTRL_POINTER_MAX))
+ return -EINVAL;
+
+ /* Capture the data when we are at 75% of the half period */
+ sp = spmax * 3 / 4;
+
+ for (i = 0, val = 0; i < PDM_CHAN_CTRL_NUM; i++)
+ val |= sp << (PDM_CHAN_CTRL_POINTER_WIDTH * i);
+
+ regmap_write(priv->map, PDM_CHAN_CTRL, val);
+ regmap_write(priv->map, PDM_CHAN_CTRL1, val);
+
+ return 0;
+}
+
+static void axg_pdm_set_channel_mask(struct axg_pdm *priv,
+ unsigned int channels)
+{
+ unsigned int mask = GENMASK(channels - 1, 0);
+
+ /* Put all channel in reset */
+ regmap_update_bits(priv->map, PDM_CTRL,
+ PDM_CTRL_CHAN_RSTN_MASK, 0);
+
+ /* Take the necessary channels out of reset and enable them */
+ regmap_update_bits(priv->map, PDM_CTRL,
+ PDM_CTRL_CHAN_RSTN_MASK |
+ PDM_CTRL_CHAN_EN_MASK,
+ PDM_CTRL_CHAN_RSTN(mask) |
+ PDM_CTRL_CHAN_EN(mask));
+}
+
+static int axg_pdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
+ unsigned int os = axg_pdm_get_os(priv);
+ unsigned int rate = params_rate(params);
+ unsigned int val;
+ int ret;
+
+ switch (params_width(params)) {
+ case 24:
+ val = PDM_CTRL_OUT_MODE;
+ break;
+ case 32:
+ val = 0;
+ break;
+ default:
+ dev_err(dai->dev, "unsupported sample width\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_OUT_MODE, val);
+
+ ret = axg_pdm_set_sysclk(priv, os, rate);
+ if (ret) {
+ dev_err(dai->dev, "failed to set system clock\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(priv->dclk, rate * os);
+ if (ret) {
+ dev_err(dai->dev, "failed to set dclk\n");
+ return ret;
+ }
+
+ ret = axg_pdm_set_sample_pointer(priv);
+ if (ret) {
+ dev_err(dai->dev, "invalid clock setting\n");
+ return ret;
+ }
+
+ axg_pdm_set_channel_mask(priv, params_channels(params));
+
+ return 0;
+}
+
+static int axg_pdm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = clk_prepare_enable(priv->dclk);
+ if (ret) {
+ dev_err(dai->dev, "enabling dclk failed\n");
+ return ret;
+ }
+
+ /* Enable the filters */
+ axg_pdm_filters_enable(priv->map, true);
+
+ return ret;
+}
+
+static void axg_pdm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
+
+ axg_pdm_filters_enable(priv->map, false);
+ clk_disable_unprepare(priv->dclk);
+}
+
+static const struct snd_soc_dai_ops axg_pdm_dai_ops = {
+ .trigger = axg_pdm_trigger,
+ .hw_params = axg_pdm_hw_params,
+ .startup = axg_pdm_startup,
+ .shutdown = axg_pdm_shutdown,
+};
+
+static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv)
+{
+ const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic;
+ unsigned int val;
+
+ val = PDM_HCIC_CTRL1_STAGE_NUM(hcic->steps);
+ val |= PDM_HCIC_CTRL1_DSR(hcic->ds);
+ val |= PDM_HCIC_CTRL1_GAIN_MULT(hcic->mult);
+ val |= PDM_HCIC_CTRL1_GAIN_SFT(hcic->shift);
+
+ regmap_update_bits(priv->map, PDM_HCIC_CTRL1,
+ PDM_HCIC_CTRL1_STAGE_NUM_MASK |
+ PDM_HCIC_CTRL1_DSR_MASK |
+ PDM_HCIC_CTRL1_GAIN_MULT_MASK |
+ PDM_HCIC_CTRL1_GAIN_SFT_MASK,
+ val);
+}
+
+static void axg_pdm_set_lpf_ctrl(struct axg_pdm *priv, unsigned int index)
+{
+ const struct axg_pdm_lpf *lpf = &priv->cfg->filters->lpf[index];
+ unsigned int offset = index * regmap_get_reg_stride(priv->map)
+ + PDM_F1_CTRL;
+ unsigned int val;
+
+ val = PDM_LPF_STAGE_NUM(lpf->tap_num);
+ val |= PDM_LPF_DSR(lpf->ds);
+ val |= PDM_LPF_ROUND_MODE(lpf->round_mode);
+
+ regmap_update_bits(priv->map, offset,
+ PDM_LPF_STAGE_NUM_MASK |
+ PDM_LPF_DSR_MASK |
+ PDM_LPF_ROUND_MODE_MASK,
+ val);
+}
+
+static void axg_pdm_set_hpf_ctrl(struct axg_pdm *priv)
+{
+ const struct axg_pdm_hpf *hpf = &priv->cfg->filters->hpf;
+ unsigned int val;
+
+ val = PDM_HPF_OUT_FACTOR(hpf->out_factor);
+ val |= PDM_HPF_SFT_STEPS(hpf->steps);
+
+ regmap_update_bits(priv->map, PDM_HPF_CTRL,
+ PDM_HPF_OUT_FACTOR_MASK |
+ PDM_HPF_SFT_STEPS_MASK,
+ val);
+}
+
+static int axg_pdm_set_lpf_filters(struct axg_pdm *priv)
+{
+ const struct axg_pdm_lpf *lpf = priv->cfg->filters->lpf;
+ unsigned int count = 0;
+ int i, j;
+
+ for (i = 0; i < PDM_LPF_NUM; i++)
+ count += lpf[i].tap_num;
+
+ /* Make sure the coeffs fit in the memory */
+ if (count >= PDM_LPF_MAX_STAGE)
+ return -EINVAL;
+
+ /* Set the initial APB bus register address */
+ regmap_write(priv->map, PDM_COEFF_ADDR, 0);
+
+ /* Set the tap filter values of all 3 filters */
+ for (i = 0; i < PDM_LPF_NUM; i++) {
+ axg_pdm_set_lpf_ctrl(priv, i);
+
+ for (j = 0; j < lpf[i].tap_num; j++)
+ regmap_write(priv->map, PDM_COEFF_DATA, lpf[i].tap[j]);
+ }
+
+ return 0;
+}
+
+static int axg_pdm_dai_probe(struct snd_soc_dai *dai)
+{
+ struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = clk_prepare_enable(priv->pclk);
+ if (ret) {
+ dev_err(dai->dev, "enabling pclk failed\n");
+ return ret;
+ }
+
+ /*
+ * sysclk must be set and enabled as well to access the pdm registers
+ * Accessing the register w/o it will give a bus error.
+ */
+ ret = clk_set_rate(priv->sysclk, priv->cfg->sys_rate);
+ if (ret) {
+ dev_err(dai->dev, "setting sysclk failed\n");
+ goto err_pclk;
+ }
+
+ ret = clk_prepare_enable(priv->sysclk);
+ if (ret) {
+ dev_err(dai->dev, "enabling sysclk failed\n");
+ goto err_pclk;
+ }
+
+ /* Make sure the device is initially disabled */
+ axg_pdm_disable(priv->map);
+
+ /* Make sure filter bypass is disabled */
+ regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_BYPASS_MODE, 0);
+
+ /* Load filter settings */
+ axg_pdm_set_hcic_ctrl(priv);
+ axg_pdm_set_hpf_ctrl(priv);
+
+ ret = axg_pdm_set_lpf_filters(priv);
+ if (ret) {
+ dev_err(dai->dev, "invalid filter configuration\n");
+ goto err_sysclk;
+ }
+
+ return 0;
+
+err_sysclk:
+ clk_disable_unprepare(priv->sysclk);
+err_pclk:
+ clk_disable_unprepare(priv->pclk);
+ return ret;
+}
+
+static int axg_pdm_dai_remove(struct snd_soc_dai *dai)
+{
+ struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(priv->sysclk);
+ clk_disable_unprepare(priv->pclk);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver axg_pdm_dai_drv = {
+ .name = "PDM",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 48000,
+ .formats = (SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ },
+ .ops = &axg_pdm_dai_ops,
+ .probe = axg_pdm_dai_probe,
+ .remove = axg_pdm_dai_remove,
+};
+
+static const struct snd_soc_component_driver axg_pdm_component_drv = {};
+
+static const struct regmap_config axg_pdm_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = PDM_STS,
+};
+
+static const unsigned int lpf1_default_tap[] = {
+ 0x000014, 0xffffb2, 0xfffed9, 0xfffdce, 0xfffd45,
+ 0xfffe32, 0x000147, 0x000645, 0x000b86, 0x000e21,
+ 0x000ae3, 0x000000, 0xffeece, 0xffdca8, 0xffd212,
+ 0xffd7d1, 0xfff2a7, 0x001f4c, 0x0050c2, 0x0072aa,
+ 0x006ff1, 0x003c32, 0xffdc4e, 0xff6a18, 0xff0fef,
+ 0xfefbaf, 0xff4c40, 0x000000, 0x00ebc8, 0x01c077,
+ 0x02209e, 0x01c1a4, 0x008e60, 0xfebe52, 0xfcd690,
+ 0xfb8fa5, 0xfba498, 0xfd9812, 0x0181ce, 0x06f5f3,
+ 0x0d112f, 0x12a958, 0x169686, 0x18000e, 0x169686,
+ 0x12a958, 0x0d112f, 0x06f5f3, 0x0181ce, 0xfd9812,
+ 0xfba498, 0xfb8fa5, 0xfcd690, 0xfebe52, 0x008e60,
+ 0x01c1a4, 0x02209e, 0x01c077, 0x00ebc8, 0x000000,
+ 0xff4c40, 0xfefbaf, 0xff0fef, 0xff6a18, 0xffdc4e,
+ 0x003c32, 0x006ff1, 0x0072aa, 0x0050c2, 0x001f4c,
+ 0xfff2a7, 0xffd7d1, 0xffd212, 0xffdca8, 0xffeece,
+ 0x000000, 0x000ae3, 0x000e21, 0x000b86, 0x000645,
+ 0x000147, 0xfffe32, 0xfffd45, 0xfffdce, 0xfffed9,
+ 0xffffb2, 0x000014,
+};
+
+static const unsigned int lpf2_default_tap[] = {
+ 0x00050a, 0xfff004, 0x0002c1, 0x003c12, 0xffa818,
+ 0xffc87d, 0x010aef, 0xff5223, 0xfebd93, 0x028f41,
+ 0xff5c0e, 0xfc63f8, 0x055f81, 0x000000, 0xf478a0,
+ 0x11c5e3, 0x2ea74d, 0x11c5e3, 0xf478a0, 0x000000,
+ 0x055f81, 0xfc63f8, 0xff5c0e, 0x028f41, 0xfebd93,
+ 0xff5223, 0x010aef, 0xffc87d, 0xffa818, 0x003c12,
+ 0x0002c1, 0xfff004, 0x00050a,
+};
+
+static const unsigned int lpf3_default_tap[] = {
+ 0x000000, 0x000081, 0x000000, 0xfffedb, 0x000000,
+ 0x00022d, 0x000000, 0xfffc46, 0x000000, 0x0005f7,
+ 0x000000, 0xfff6eb, 0x000000, 0x000d4e, 0x000000,
+ 0xffed1e, 0x000000, 0x001a1c, 0x000000, 0xffdcb0,
+ 0x000000, 0x002ede, 0x000000, 0xffc2d1, 0x000000,
+ 0x004ebe, 0x000000, 0xff9beb, 0x000000, 0x007dd7,
+ 0x000000, 0xff633a, 0x000000, 0x00c1d2, 0x000000,
+ 0xff11d5, 0x000000, 0x012368, 0x000000, 0xfe9c45,
+ 0x000000, 0x01b252, 0x000000, 0xfdebf6, 0x000000,
+ 0x0290b8, 0x000000, 0xfcca0d, 0x000000, 0x041d7c,
+ 0x000000, 0xfa8152, 0x000000, 0x07e9c6, 0x000000,
+ 0xf28fb5, 0x000000, 0x28b216, 0x3fffde, 0x28b216,
+ 0x000000, 0xf28fb5, 0x000000, 0x07e9c6, 0x000000,
+ 0xfa8152, 0x000000, 0x041d7c, 0x000000, 0xfcca0d,
+ 0x000000, 0x0290b8, 0x000000, 0xfdebf6, 0x000000,
+ 0x01b252, 0x000000, 0xfe9c45, 0x000000, 0x012368,
+ 0x000000, 0xff11d5, 0x000000, 0x00c1d2, 0x000000,
+ 0xff633a, 0x000000, 0x007dd7, 0x000000, 0xff9beb,
+ 0x000000, 0x004ebe, 0x000000, 0xffc2d1, 0x000000,
+ 0x002ede, 0x000000, 0xffdcb0, 0x000000, 0x001a1c,
+ 0x000000, 0xffed1e, 0x000000, 0x000d4e, 0x000000,
+ 0xfff6eb, 0x000000, 0x0005f7, 0x000000, 0xfffc46,
+ 0x000000, 0x00022d, 0x000000, 0xfffedb, 0x000000,
+ 0x000081, 0x000000,
+};
+
+/*
+ * These values are sane defaults for the axg platform:
+ * - OS = 64
+ * - Latency = 38700 (?)
+ *
+ * TODO: There is a lot of different HCIC, LPFs and HPF configurations possible.
+ * the configuration may depend on the dmic used by the platform, the
+ * expected tradeoff between latency and quality, etc ... If/When other
+ * settings are required, we should add a fw interface to this driver to
+ * load new filter settings.
+ */
+static const struct axg_pdm_filters axg_default_filters = {
+ .hcic = {
+ .shift = 0x15,
+ .mult = 0x80,
+ .steps = 7,
+ .ds = 8,
+ },
+ .hpf = {
+ .out_factor = 0x8000,
+ .steps = 13,
+ },
+ .lpf = {
+ [0] = {
+ .ds = 2,
+ .round_mode = 1,
+ .tap = lpf1_default_tap,
+ .tap_num = ARRAY_SIZE(lpf1_default_tap),
+ },
+ [1] = {
+ .ds = 2,
+ .round_mode = 0,
+ .tap = lpf2_default_tap,
+ .tap_num = ARRAY_SIZE(lpf2_default_tap),
+ },
+ [2] = {
+ .ds = 2,
+ .round_mode = 1,
+ .tap = lpf3_default_tap,
+ .tap_num = ARRAY_SIZE(lpf3_default_tap)
+ },
+ },
+};
+
+static const struct axg_pdm_cfg axg_pdm_config = {
+ .filters = &axg_default_filters,
+ .sys_rate = 250000000,
+};
+
+static const struct of_device_id axg_pdm_of_match[] = {
+ {
+ .compatible = "amlogic,axg-pdm",
+ .data = &axg_pdm_config,
+ }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_pdm_of_match);
+
+static int axg_pdm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct axg_pdm *priv;
+ struct resource *res;
+ void __iomem *regs;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
+
+ priv->cfg = of_device_get_match_data(dev);
+ if (!priv->cfg) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ priv->map = devm_regmap_init_mmio(dev, regs, &axg_pdm_regmap_cfg);
+ if (IS_ERR(priv->map)) {
+ dev_err(dev, "failed to init regmap: %ld\n",
+ PTR_ERR(priv->map));
+ return PTR_ERR(priv->map);
+ }
+
+ priv->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(priv->pclk)) {
+ ret = PTR_ERR(priv->pclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get pclk: %d\n", ret);
+ return ret;
+ }
+
+ priv->dclk = devm_clk_get(dev, "dclk");
+ if (IS_ERR(priv->dclk)) {
+ ret = PTR_ERR(priv->dclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get dclk: %d\n", ret);
+ return ret;
+ }
+
+ priv->sysclk = devm_clk_get(dev, "sysclk");
+ if (IS_ERR(priv->sysclk)) {
+ ret = PTR_ERR(priv->sysclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get dclk: %d\n", ret);
+ return ret;
+ }
+
+ return devm_snd_soc_register_component(dev, &axg_pdm_component_drv,
+ &axg_pdm_dai_drv, 1);
+}
+
+static struct platform_driver axg_pdm_pdrv = {
+ .probe = axg_pdm_probe,
+ .driver = {
+ .name = "axg-pdm",
+ .of_match_table = axg_pdm_of_match,
+ },
+};
+module_platform_driver(axg_pdm_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG PDM Input driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c
index 7b8baf46d968..585ce030b79b 100644
--- a/sound/soc/meson/axg-tdm-interface.c
+++ b/sound/soc/meson/axg-tdm-interface.c
@@ -42,6 +42,7 @@ int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
struct axg_tdm_stream *rx = (struct axg_tdm_stream *)
dai->capture_dma_data;
unsigned int tx_slots, rx_slots;
+ unsigned int fmt = 0;
tx_slots = axg_tdm_slots_total(tx_mask);
rx_slots = axg_tdm_slots_total(rx_mask);
@@ -52,38 +53,45 @@ int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
return -EINVAL;
}
- /*
- * Amend the dai driver channel number and let dpcm channel merge do
- * its job
- */
- if (tx) {
- tx->mask = tx_mask;
- dai->driver->playback.channels_max = tx_slots;
- }
-
- if (rx) {
- rx->mask = rx_mask;
- dai->driver->capture.channels_max = rx_slots;
- }
-
iface->slots = slots;
switch (slot_width) {
case 0:
- /* defaults width to 32 if not provided */
- iface->slot_width = 32;
- break;
- case 8:
- case 16:
- case 24:
+ slot_width = 32;
+ /* Fall-through */
case 32:
- iface->slot_width = slot_width;
+ fmt |= SNDRV_PCM_FMTBIT_S32_LE;
+ /* Fall-through */
+ case 24:
+ fmt |= SNDRV_PCM_FMTBIT_S24_LE;
+ fmt |= SNDRV_PCM_FMTBIT_S20_LE;
+ /* Fall-through */
+ case 16:
+ fmt |= SNDRV_PCM_FMTBIT_S16_LE;
+ /* Fall-through */
+ case 8:
+ fmt |= SNDRV_PCM_FMTBIT_S8;
break;
default:
dev_err(dai->dev, "unsupported slot width: %d\n", slot_width);
return -EINVAL;
}
+ iface->slot_width = slot_width;
+
+ /* Amend the dai driver and let dpcm merge do its job */
+ if (tx) {
+ tx->mask = tx_mask;
+ dai->driver->playback.channels_max = tx_slots;
+ dai->driver->playback.formats = fmt;
+ }
+
+ if (rx) {
+ rx->mask = rx_mask;
+ dai->driver->capture.channels_max = rx_slots;
+ dai->driver->capture.formats = fmt;
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(axg_tdm_set_tdm_slots);
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index 81b09d740ed9..6384bb6dacfd 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -356,7 +356,7 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
if (ret)
goto out;
- ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
+ ret = devm_snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
&nuc900_ac97_dai, 1);
if (ret)
goto out;
@@ -373,8 +373,6 @@ out:
static int nuc900_ac97_drvremove(struct platform_device *pdev)
{
- snd_soc_unregister_component(&pdev->dev);
-
nuc900_ac97_data = NULL;
snd_soc_set_ac97_ops(NULL);
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
index 8a99a8837dc9..673a9eb153b2 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -348,7 +348,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
default:
return -EINVAL;
}
- ret = snd_soc_register_component(ad->dssdev, &omap_hdmi_component,
+ ret = devm_snd_soc_register_component(ad->dssdev, &omap_hdmi_component,
dai_drv, 1);
if (ret)
return ret;
@@ -383,7 +383,6 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
ret = snd_soc_register_card(card);
if (ret) {
dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
- snd_soc_unregister_component(ad->dssdev);
return ret;
}
@@ -400,7 +399,6 @@ static int omap_hdmi_audio_remove(struct platform_device *pdev)
struct hdmi_audio_data *ad = platform_get_drvdata(pdev);
snd_soc_unregister_card(ad->card);
- snd_soc_unregister_component(ad->dssdev);
return 0;
}
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 776e148b0aa2..29f577e6dfc0 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -19,14 +19,13 @@ config SND_MMP_SOC
config SND_PXA2XX_AC97
tristate
- select SND_AC97_CODEC
config SND_PXA2XX_SOC_AC97
tristate
- select AC97_BUS
+ select AC97_BUS_NEW
select SND_PXA2XX_LIB
select SND_PXA2XX_LIB_AC97
- select SND_SOC_AC97_BUS
+ select SND_SOC_AC97_BUS_NEW
config SND_PXA2XX_SOC_I2S
select SND_PXA2XX_LIB
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 9f779657bc86..f8a3aa6c6d4e 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -17,6 +17,7 @@
#include <linux/dmaengine.h>
#include <linux/dma/pxa-dma.h>
+#include <sound/ac97/controller.h>
#include <sound/core.h>
#include <sound/ac97_codec.h>
#include <sound/soc.h>
@@ -27,43 +28,35 @@
#include <mach/regs-ac97.h>
#include <mach/audio.h>
-static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
+static void pxa2xx_ac97_warm_reset(struct ac97_controller *adrv)
{
pxa2xx_ac97_try_warm_reset();
pxa2xx_ac97_finish_reset();
}
-static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
+static void pxa2xx_ac97_cold_reset(struct ac97_controller *adrv)
{
pxa2xx_ac97_try_cold_reset();
pxa2xx_ac97_finish_reset();
}
-static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97,
- unsigned short reg)
+static int pxa2xx_ac97_read_actrl(struct ac97_controller *adrv, int slot,
+ unsigned short reg)
{
- int ret;
-
- ret = pxa2xx_ac97_read(ac97->num, reg);
- if (ret < 0)
- return 0;
- else
- return (unsigned short)(ret & 0xffff);
+ return pxa2xx_ac97_read(slot, reg);
}
-static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
- unsigned short reg, unsigned short val)
+static int pxa2xx_ac97_write_actrl(struct ac97_controller *adrv, int slot,
+ unsigned short reg, unsigned short val)
{
- int ret;
-
- ret = pxa2xx_ac97_write(ac97->num, reg, val);
+ return pxa2xx_ac97_write(slot, reg, val);
}
-static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
- .read = pxa2xx_ac97_legacy_read,
- .write = pxa2xx_ac97_legacy_write,
+static struct ac97_controller_ops pxa2xx_ac97_ops = {
+ .read = pxa2xx_ac97_read_actrl,
+ .write = pxa2xx_ac97_write_actrl,
.warm_reset = pxa2xx_ac97_warm_reset,
.reset = pxa2xx_ac97_cold_reset,
};
@@ -233,6 +226,9 @@ MODULE_DEVICE_TABLE(of, pxa2xx_ac97_dt_ids);
static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
{
int ret;
+ struct ac97_controller *ctrl;
+ pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data;
+ void **codecs_pdata;
if (pdev->id != -1) {
dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");
@@ -245,10 +241,14 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
return ret;
}
- ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops);
- if (ret != 0)
- return ret;
+ codecs_pdata = pdata ? pdata->codec_pdata : NULL;
+ ctrl = snd_ac97_controller_register(&pxa2xx_ac97_ops, &pdev->dev,
+ AC97_SLOTS_AVAILABLE_ALL,
+ codecs_pdata);
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+ platform_set_drvdata(pdev, ctrl);
/* Punt most of the init to the SoC probe; we may need the machine
* driver to do interesting things with the clocking to get us up
* and running.
@@ -259,8 +259,10 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
{
+ struct ac97_controller *ctrl = platform_get_drvdata(pdev);
+
snd_soc_unregister_component(&pdev->dev);
- snd_soc_set_ac97_ops(NULL);
+ snd_ac97_controller_unregister(ctrl);
pxa2xx_ac97_hw_remove(pdev);
return 0;
}
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 9db9a2944ef2..c75fab38905d 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -493,7 +493,7 @@ static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
}
}
- return ret;
+ return 0;
}
static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c
index 06f03a5fe9bd..ca1be7305524 100644
--- a/sound/soc/qcom/qdsp6/q6core.c
+++ b/sound/soc/qcom/qdsp6/q6core.c
@@ -105,12 +105,10 @@ static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data)
bytes = sizeof(*fwk) + fwk->num_services *
sizeof(fwk->svc_api_info[0]);
- core->fwk_version = kzalloc(bytes, GFP_ATOMIC);
+ core->fwk_version = kmemdup(data->payload, bytes, GFP_ATOMIC);
if (!core->fwk_version)
return -ENOMEM;
- memcpy(core->fwk_version, data->payload, bytes);
-
core->fwk_version_supported = true;
core->resp_received = true;
@@ -124,12 +122,10 @@ static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data)
len = sizeof(*v) + v->num_services * sizeof(v->svc_api_info[0]);
- core->svc_version = kzalloc(len, GFP_ATOMIC);
+ core->svc_version = kmemdup(data->payload, len, GFP_ATOMIC);
if (!core->svc_version)
return -ENOMEM;
- memcpy(core->svc_version, data->payload, len);
-
core->get_version_supported = true;
core->resp_received = true;
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index c2b496398e6b..17622ceb98c0 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -319,13 +319,12 @@ static int hac_soc_platform_probe(struct platform_device *pdev)
if (ret != 0)
return ret;
- return snd_soc_register_component(&pdev->dev, &sh4_hac_component,
+ return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component,
sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
}
static int hac_soc_platform_remove(struct platform_device *pdev)
{
- snd_soc_unregister_component(&pdev->dev);
snd_soc_set_ac97_ops(NULL);
return 0;
}
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 051f96405346..28327dd2c6cb 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -582,7 +582,7 @@ static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
int i;
for_each_rsnd_clk(clk, adg, i)
- dev_dbg(dev, "%s : %p : %ld\n",
+ dev_dbg(dev, "%s : %pa : %ld\n",
clk_name[i], clk, clk_get_rate(clk));
dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
@@ -595,7 +595,7 @@ static void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct rsnd_adg *adg)
* by BRGCKR::BRGCKR_31
*/
for_each_rsnd_clkout(clk, adg, i)
- dev_dbg(dev, "clkout %d : %p : %ld\n", i,
+ dev_dbg(dev, "clkout %d : %pa : %ld\n", i,
clk, clk_get_rate(clk));
}
#else
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index d23c2bbff0cf..40d7dc4f7839 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -102,7 +102,9 @@
#include "rsnd.h"
#define RSND_RATES SNDRV_PCM_RATE_8000_192000
-#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\
+ SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
static const struct of_device_id rsnd_of_match[] = {
{ .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
@@ -280,6 +282,8 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
struct device *dev = rsnd_priv_to_dev(priv);
switch (snd_pcm_format_width(runtime->format)) {
+ case 8:
+ return 16 << 16;
case 16:
return 8 << 16;
case 24:
@@ -331,7 +335,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
target = cmd ? cmd : ssiu;
}
- /* Non target mod or 24bit data needs normal DALIGN */
+ /* Non target mod or non 16bit needs normal DALIGN */
if ((snd_pcm_format_width(runtime->format) != 16) ||
(mod != target))
return 0x76543210;
@@ -367,7 +371,7 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
* HW 24bit data is located as 0x******00
*
*/
- if (snd_pcm_format_width(runtime->format) == 16)
+ if (snd_pcm_format_width(runtime->format) != 24)
return 0;
for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
@@ -540,6 +544,14 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
return rdai->ssi_lane;
}
+int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width)
+{
+ if (width > 0)
+ rdai->chan_width = width;
+
+ return rdai->chan_width;
+}
+
struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
{
if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
@@ -681,6 +693,7 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
rdai->frm_clk_inv = 0;
break;
case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_DSP_B:
rdai->sys_delay = 1;
rdai->data_alignment = 0;
rdai->frm_clk_inv = 1;
@@ -690,6 +703,11 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
rdai->data_alignment = 1;
rdai->frm_clk_inv = 1;
break;
+ case SND_SOC_DAIFMT_DSP_A:
+ rdai->sys_delay = 0;
+ rdai->data_alignment = 0;
+ rdai->frm_clk_inv = 1;
+ break;
}
/* set clock inversion */
@@ -720,6 +738,16 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct device *dev = rsnd_priv_to_dev(priv);
+ switch (slot_width) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ dev_err(dev, "unsupported slot width value: %d\n", slot_width);
+ return -EINVAL;
+ }
+
switch (slots) {
case 2:
case 6:
@@ -727,6 +755,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
/* TDM Extend Mode */
rsnd_rdai_channels_set(rdai, slots);
rsnd_rdai_ssi_lane_set(rdai, 1);
+ rsnd_rdai_width_set(rdai, slot_width);
break;
default:
dev_err(dev, "unsupported TDM slots (%d)\n", slots);
@@ -755,7 +784,7 @@ static unsigned int rsnd_soc_hw_rate_list[] = {
192000,
};
-static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
+static int rsnd_soc_hw_rule(struct rsnd_dai *rdai,
unsigned int *list, int list_num,
struct snd_interval *baseline, struct snd_interval *iv)
{
@@ -772,14 +801,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
if (!snd_interval_test(iv, list[i]))
continue;
- rate = rsnd_ssi_clk_query(priv,
+ rate = rsnd_ssi_clk_query(rdai,
baseline->min, list[i], NULL);
if (rate > 0) {
p.min = min(p.min, list[i]);
p.max = max(p.max, list[i]);
}
- rate = rsnd_ssi_clk_query(priv,
+ rate = rsnd_ssi_clk_query(rdai,
baseline->max, list[i], NULL);
if (rate > 0) {
p.min = min(p.min, list[i]);
@@ -790,17 +819,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
return snd_interval_refine(iv, &p);
}
-static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule,
- int is_play)
+static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval ic;
- struct snd_soc_dai *dai = rule->private;
- struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
- struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
+ struct rsnd_dai_stream *io = rule->private;
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
/*
* possible sampling rate limitation is same as
@@ -811,34 +837,19 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
ic.min =
ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
- return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list,
+ return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list,
ARRAY_SIZE(rsnd_soc_hw_rate_list),
&ic, ir);
}
-static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- return __rsnd_soc_hw_rule_rate(params, rule, 1);
-}
-
-static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- return __rsnd_soc_hw_rule_rate(params, rule, 0);
-}
-
-static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule,
- int is_play)
+static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
{
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval ic;
- struct snd_soc_dai *dai = rule->private;
- struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
- struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
+ struct rsnd_dai_stream *io = rule->private;
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
/*
* possible sampling rate limitation is same as
@@ -849,23 +860,11 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
ic.min =
ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
- return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list,
+ return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list,
ARRAY_SIZE(rsnd_soc_hw_channels_list),
ir, &ic);
}
-static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- return __rsnd_soc_hw_rule_channels(params, rule, 1);
-}
-
-static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- return __rsnd_soc_hw_rule_channels(params, rule, 0);
-}
-
static const struct snd_pcm_hardware rsnd_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
@@ -882,12 +881,10 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
- struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int max_channels = rsnd_rdai_channels_get(rdai);
- int ret;
int i;
rsnd_dai_stream_init(io, substream);
@@ -922,25 +919,16 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- is_play ? rsnd_soc_hw_rule_rate_playback :
- rsnd_soc_hw_rule_rate_capture,
- dai,
+ rsnd_soc_hw_rule_rate,
+ is_play ? &rdai->playback : &rdai->capture,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- is_play ? rsnd_soc_hw_rule_channels_playback :
- rsnd_soc_hw_rule_channels_capture,
- dai,
+ rsnd_soc_hw_rule_channels,
+ is_play ? &rdai->playback : &rdai->capture,
SNDRV_PCM_HW_PARAM_RATE, -1);
}
- /*
- * call rsnd_dai_call without spinlock
- */
- ret = rsnd_dai_call(nolock_start, io, priv);
- if (ret < 0)
- rsnd_dai_call(nolock_stop, io, priv);
-
- return ret;
+ return 0;
}
static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
@@ -953,7 +941,7 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
/*
* call rsnd_dai_call without spinlock
*/
- rsnd_dai_call(nolock_stop, io, priv);
+ rsnd_dai_call(cleanup, io, priv);
rsnd_dai_stream_quit(io);
}
@@ -1083,6 +1071,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
rdai->capture.rdai = rdai;
rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
+ rsnd_rdai_width_set(rdai, 32); /* default 32bit width */
for (io_i = 0;; io_i++) {
playback = of_parse_phandle(dai_np, "playback", io_i);
@@ -1274,8 +1263,15 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ if (!runtime) {
+ dev_warn(dev, "Can't update kctrl when idle\n");
+ return 0;
+ }
- return !!runtime;
+ return 1;
}
struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index d65ea7bc4dac..0bbc4b0ea2c6 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -106,9 +106,9 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
+static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
@@ -116,7 +116,7 @@ static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod,
/*
* DMAEngine release uses mutex lock.
* Thus, it shouldn't be called under spinlock.
- * Let's call it under nolock_start
+ * Let's call it under prepare
*/
if (dmaen->chan)
dma_release_channel(dmaen->chan);
@@ -126,9 +126,9 @@ static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv)
+static int rsnd_dmaen_prepare(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
@@ -142,7 +142,7 @@ static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod,
/*
* DMAEngine request uses mutex lock.
* Thus, it shouldn't be called under spinlock.
- * Let's call it under nolock_start
+ * Let's call it under prepare
*/
dmaen->chan = rsnd_dmaen_request_channel(io,
dma->mod_from,
@@ -291,8 +291,8 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_dmaen_ops = {
.name = "audmac",
- .nolock_start = rsnd_dmaen_nolock_start,
- .nolock_stop = rsnd_dmaen_nolock_stop,
+ .prepare = rsnd_dmaen_prepare,
+ .cleanup = rsnd_dmaen_cleanup,
.start = rsnd_dmaen_start,
.stop = rsnd_dmaen_stop,
.pointer= rsnd_dmaen_pointer,
@@ -302,16 +302,26 @@ static struct rsnd_mod_ops rsnd_dmaen_ops = {
* Audio DMAC peri peri
*/
static const u8 gen2_id_table_ssiu[] = {
- 0x00, /* SSI00 */
- 0x04, /* SSI10 */
- 0x08, /* SSI20 */
- 0x0c, /* SSI3 */
- 0x0d, /* SSI4 */
- 0x0e, /* SSI5 */
- 0x0f, /* SSI6 */
- 0x10, /* SSI7 */
- 0x11, /* SSI8 */
- 0x12, /* SSI90 */
+ /* SSI00 ~ SSI07 */
+ 0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c,
+ /* SSI10 ~ SSI17 */
+ 0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40,
+ /* SSI20 ~ SSI27 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44,
+ /* SSI30 ~ SSI37 */
+ 0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
+ /* SSI40 ~ SSI47 */
+ 0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,
+ /* SSI5 */
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* SSI6 */
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* SSI7 */
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* SSI8 */
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* SSI90 ~ SSI97 */
+ 0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56,
};
static const u8 gen2_id_table_scu[] = {
0x2d, /* SCU_SRCI0 */
@@ -337,18 +347,23 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
const u8 *entry = NULL;
- int id = rsnd_mod_id(mod);
+ int id = 255;
int size = 0;
if (mod == ssi) {
+ int busif = rsnd_ssi_get_busif(io);
+
entry = gen2_id_table_ssiu;
size = ARRAY_SIZE(gen2_id_table_ssiu);
+ id = (rsnd_mod_id(mod) * 8) + busif;
} else if (mod == src) {
entry = gen2_id_table_scu;
size = ARRAY_SIZE(gen2_id_table_scu);
+ id = rsnd_mod_id(mod);
} else if (mod == dvc) {
entry = gen2_id_table_cmd;
size = ARRAY_SIZE(gen2_id_table_cmd);
+ id = rsnd_mod_id(mod);
}
if ((!entry) || (size <= id)) {
@@ -382,7 +397,7 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
struct device *dev = rsnd_priv_to_dev(priv);
- dev_dbg(dev, "w %p : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data);
+ dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data);
iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg));
}
@@ -491,11 +506,11 @@ static struct rsnd_mod_ops rsnd_dmapp_ops = {
#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
-#define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
-#define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
+#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400))
+#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j)
-#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
-#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
+#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400))
+#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j)
#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i))
#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i))
@@ -521,6 +536,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
!!rsnd_io_to_mod_mix(io) ||
!!rsnd_io_to_mod_ctu(io);
int id = rsnd_mod_id(mod);
+ int busif = rsnd_ssi_get_busif(io);
struct dma_addr {
dma_addr_t out_addr;
dma_addr_t in_addr;
@@ -537,25 +553,35 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
},
/* SSI */
/* Capture */
- {{{ RDMA_SSI_O_N(ssi, id), 0 },
- { RDMA_SSIU_O_P(ssi, id), 0 },
- { RDMA_SSIU_O_P(ssi, id), 0 } },
+ {{{ RDMA_SSI_O_N(ssi, id), 0 },
+ { RDMA_SSIU_O_P(ssi, id, busif), 0 },
+ { RDMA_SSIU_O_P(ssi, id, busif), 0 } },
/* Playback */
- {{ 0, RDMA_SSI_I_N(ssi, id) },
- { 0, RDMA_SSIU_I_P(ssi, id) },
- { 0, RDMA_SSIU_I_P(ssi, id) } }
+ {{ 0, RDMA_SSI_I_N(ssi, id) },
+ { 0, RDMA_SSIU_I_P(ssi, id, busif) },
+ { 0, RDMA_SSIU_I_P(ssi, id, busif) } }
},
/* SSIU */
/* Capture */
- {{{ RDMA_SSIU_O_N(ssi, id), 0 },
- { RDMA_SSIU_O_P(ssi, id), 0 },
- { RDMA_SSIU_O_P(ssi, id), 0 } },
+ {{{ RDMA_SSIU_O_N(ssi, id, busif), 0 },
+ { RDMA_SSIU_O_P(ssi, id, busif), 0 },
+ { RDMA_SSIU_O_P(ssi, id, busif), 0 } },
/* Playback */
- {{ 0, RDMA_SSIU_I_N(ssi, id) },
- { 0, RDMA_SSIU_I_P(ssi, id) },
- { 0, RDMA_SSIU_I_P(ssi, id) } } },
+ {{ 0, RDMA_SSIU_I_N(ssi, id, busif) },
+ { 0, RDMA_SSIU_I_P(ssi, id, busif) },
+ { 0, RDMA_SSIU_I_P(ssi, id, busif) } } },
};
+ /*
+ * FIXME
+ *
+ * We can't support SSI9-4/5/6/7, because its address is
+ * out of calculation rule
+ */
+ if ((id == 9) && (busif >= 4))
+ dev_err(dev, "This driver doesn't support SSI%d-%d, so far",
+ id, busif);
+
/* it shouldn't happen */
if (use_cmd && !use_src)
dev_err(dev, "DVC is selected without SRC\n");
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 0230301fe078..1f7881cc16b2 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -219,12 +219,33 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
RSND_GEN_S_REG(HDMI1_SEL, 0x9e4),
/* FIXME: it needs SSI_MODE2/3 in the future */
- RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80),
- RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80),
- RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
- RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
- RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80),
+ RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80),
+ RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80),
+ RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80),
+ RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80),
};
static const struct rsnd_regmap_field_conf conf_scu[] = {
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 8f7a0abfa751..e857311ee5c1 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -156,9 +156,30 @@ enum rsnd_reg {
RSND_REG_SSI_MODE2,
RSND_REG_SSI_CONTROL,
RSND_REG_SSI_CTRL,
- RSND_REG_SSI_BUSIF_MODE,
- RSND_REG_SSI_BUSIF_ADINR,
- RSND_REG_SSI_BUSIF_DALIGN,
+ RSND_REG_SSI_BUSIF0_MODE,
+ RSND_REG_SSI_BUSIF0_ADINR,
+ RSND_REG_SSI_BUSIF0_DALIGN,
+ RSND_REG_SSI_BUSIF1_MODE,
+ RSND_REG_SSI_BUSIF1_ADINR,
+ RSND_REG_SSI_BUSIF1_DALIGN,
+ RSND_REG_SSI_BUSIF2_MODE,
+ RSND_REG_SSI_BUSIF2_ADINR,
+ RSND_REG_SSI_BUSIF2_DALIGN,
+ RSND_REG_SSI_BUSIF3_MODE,
+ RSND_REG_SSI_BUSIF3_ADINR,
+ RSND_REG_SSI_BUSIF3_DALIGN,
+ RSND_REG_SSI_BUSIF4_MODE,
+ RSND_REG_SSI_BUSIF4_ADINR,
+ RSND_REG_SSI_BUSIF4_DALIGN,
+ RSND_REG_SSI_BUSIF5_MODE,
+ RSND_REG_SSI_BUSIF5_ADINR,
+ RSND_REG_SSI_BUSIF5_DALIGN,
+ RSND_REG_SSI_BUSIF6_MODE,
+ RSND_REG_SSI_BUSIF6_ADINR,
+ RSND_REG_SSI_BUSIF6_DALIGN,
+ RSND_REG_SSI_BUSIF7_MODE,
+ RSND_REG_SSI_BUSIF7_ADINR,
+ RSND_REG_SSI_BUSIF7_DALIGN,
RSND_REG_SSI_INT_ENABLE,
RSND_REG_SSI_SYS_STATUS0,
RSND_REG_SSI_SYS_STATUS1,
@@ -274,15 +295,12 @@ struct rsnd_mod_ops {
int (*fallback)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv);
- int (*nolock_start)(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv);
- int (*nolock_stop)(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io,
- struct rsnd_priv *priv);
int (*prepare)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv);
+ int (*cleanup)(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv);
};
struct rsnd_dai_stream;
@@ -302,7 +320,7 @@ struct rsnd_mod {
*
* 0xH0000CBA
*
- * A 0: nolock_start 1: nolock_stop
+ * A 0: prepare 1: cleanup
* B 0: init 1: quit
* C 0: start 1: stop
*
@@ -314,8 +332,8 @@ struct rsnd_mod {
* H 0: pointer
* H 0: prepare
*/
-#define __rsnd_mod_shift_nolock_start 0
-#define __rsnd_mod_shift_nolock_stop 0
+#define __rsnd_mod_shift_prepare 0
+#define __rsnd_mod_shift_cleanup 0
#define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4
#define __rsnd_mod_shift_start 8
@@ -327,12 +345,11 @@ struct rsnd_mod {
#define __rsnd_mod_shift_fallback 28 /* always called */
#define __rsnd_mod_shift_hw_params 28 /* always called */
#define __rsnd_mod_shift_pointer 28 /* always called */
-#define __rsnd_mod_shift_prepare 28 /* always called */
#define __rsnd_mod_add_probe 0
#define __rsnd_mod_add_remove 0
-#define __rsnd_mod_add_nolock_start 1
-#define __rsnd_mod_add_nolock_stop -1
+#define __rsnd_mod_add_prepare 1
+#define __rsnd_mod_add_cleanup -1
#define __rsnd_mod_add_init 1
#define __rsnd_mod_add_quit -1
#define __rsnd_mod_add_start 1
@@ -342,10 +359,11 @@ struct rsnd_mod {
#define __rsnd_mod_add_fallback 0
#define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_add_pointer 0
-#define __rsnd_mod_add_prepare 0
#define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove 0
+#define __rsnd_mod_call_prepare 0
+#define __rsnd_mod_call_cleanup 1
#define __rsnd_mod_call_init 0
#define __rsnd_mod_call_quit 1
#define __rsnd_mod_call_start 0
@@ -355,9 +373,6 @@ struct rsnd_mod {
#define __rsnd_mod_call_fallback 0
#define __rsnd_mod_call_hw_params 0
#define __rsnd_mod_call_pointer 0
-#define __rsnd_mod_call_nolock_start 0
-#define __rsnd_mod_call_nolock_stop 1
-#define __rsnd_mod_call_prepare 0
#define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_name(mod) ((mod)->ops->name)
@@ -438,6 +453,7 @@ struct rsnd_dai_stream {
char name[RSND_DAI_NAME_SIZE];
struct snd_pcm_substream *substream;
struct rsnd_mod *mod[RSND_MOD_MAX];
+ struct rsnd_mod *dma;
struct rsnd_dai *rdai;
struct device *dmac_dev; /* for IPMMU */
u32 parent_ssi_status;
@@ -467,6 +483,7 @@ struct rsnd_dai {
int max_channels; /* 2ch - 16ch */
int ssi_lane; /* 1lane - 4lane */
+ int chan_width; /* 16/24/32 bit width */
unsigned int clk_master:1;
unsigned int bit_clk_inv:1;
@@ -500,6 +517,11 @@ int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai,
int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
int ssi_lane);
+#define rsnd_rdai_width_set(rdai, width) \
+ rsnd_rdai_width_ctrl(rdai, width)
+#define rsnd_rdai_width_get(rdai) \
+ rsnd_rdai_width_ctrl(rdai, 0)
+int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width);
void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
@@ -692,6 +714,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
+int rsnd_ssi_get_busif(struct rsnd_dai_stream *io);
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
#define RSND_SSI_HDMI_PORT0 0xf0
@@ -709,7 +732,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
struct device_node *playback,
struct device_node *capture);
-unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
+unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
int param1, int param2, int *idx);
/*
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 3f880ec66459..3adcc4f778f7 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -42,7 +42,13 @@
#define DWL_24 (5 << 19) /* Data Word Length */
#define DWL_32 (6 << 19) /* Data Word Length */
+/*
+ * System word length
+ */
+#define SWL_16 (1 << 16) /* R/W System Word Length */
+#define SWL_24 (2 << 16) /* R/W System Word Length */
#define SWL_32 (3 << 16) /* R/W System Word Length */
+
#define SCKD (1 << 15) /* Serial Bit Clock Direction */
#define SWSD (1 << 14) /* Serial WS Direction */
#define SCKP (1 << 13) /* Serial Bit Clock Polarity */
@@ -72,7 +78,6 @@
struct rsnd_ssi {
struct rsnd_mod mod;
- struct rsnd_mod *dma;
u32 flags;
u32 cr_own;
@@ -145,6 +150,11 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
return use_busif;
}
+int rsnd_ssi_get_busif(struct rsnd_dai_stream *io)
+{
+ return 0; /* BUSIF0 only for now */
+}
+
static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
{
rsnd_mod_write(mod, SSISR, 0);
@@ -220,14 +230,32 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
return 0;
}
-unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
+static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai)
+{
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int width = rsnd_rdai_width_get(rdai);
+
+ switch (width) {
+ case 32: return SWL_32;
+ case 24: return SWL_24;
+ case 16: return SWL_16;
+ }
+
+ dev_err(dev, "unsupported slot width value: %d\n", width);
+ return 0;
+}
+
+unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
int param1, int param2, int *idx)
{
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
int ssi_clk_mul_table[] = {
1, 2, 4, 8, 16, 6, 12,
};
int j, ret;
unsigned int main_rate;
+ int width = rsnd_rdai_width_get(rdai);
for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
@@ -240,12 +268,7 @@ unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
if (j == 0)
continue;
- /*
- * this driver is assuming that
- * system word is 32bit x chan
- * see rsnd_ssi_init()
- */
- main_rate = 32 * param1 * param2 * ssi_clk_mul_table[j];
+ main_rate = width * param1 * param2 * ssi_clk_mul_table[j];
ret = rsnd_adg_clk_query(priv, main_rate);
if (ret < 0)
@@ -289,10 +312,15 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return -EINVAL;
}
+ if (ssi->chan != chan) {
+ dev_err(dev, "SSI parent/child should use same chan\n");
+ return -EINVAL;
+ }
+
return 0;
}
- main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx);
+ main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
if (!main_rate) {
dev_err(dev, "unsupported clock rate\n");
return -EIO;
@@ -312,9 +340,11 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
* SSICR : FORCE, SCKD, SWSD
* SSIWSR : CONT
*/
- ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx);
+ ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) |
+ SCKD | SWSD | CKDV(idx);
ssi->wsr = CONT;
ssi->rate = rate;
+ ssi->chan = chan;
dev_dbg(dev, "%s[%d] outputs %u Hz\n",
rsnd_mod_name(mod),
@@ -340,6 +370,7 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
ssi->cr_clk = 0;
ssi->rate = 0;
+ ssi->chan = 0;
rsnd_adg_ssi_clk_stop(mod);
}
@@ -357,11 +388,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
is_tdm = rsnd_runtime_is_ssi_tdm(io);
- /*
- * always use 32bit system word.
- * see also rsnd_ssi_master_clk_enable()
- */
- cr_own |= FORCE | SWL_32;
+ cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
if (rdai->bit_clk_inv)
cr_own |= SCKP;
@@ -384,6 +411,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_own &= ~DWL_MASK;
switch (snd_pcm_format_width(runtime->format)) {
+ case 8:
+ cr_own |= DWL_8;
+ break;
case 16:
cr_own |= DWL_16;
break;
@@ -488,26 +518,16 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- int chan = params_channels(params);
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ unsigned int fmt_width = snd_pcm_format_width(params_format(params));
- /*
- * snd_pcm_ops::hw_params will be called *before*
- * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0
- * in 1st call.
- */
- if (ssi->usrcnt) {
- /*
- * Already working.
- * It will happen if SSI has parent/child connection.
- * it is error if child <-> parent SSI uses
- * different channels.
- */
- if (ssi->chan != chan)
- return -EIO;
- }
+ if (fmt_width > rdai->chan_width) {
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
- ssi->chan = chan;
+ dev_err(dev, "invalid combination of slot-width and format-data-width\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -873,7 +893,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
int ret;
/*
@@ -888,7 +907,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
return ret;
/* SSI probe might be called many times in MUX multi path */
- ret = rsnd_dma_attach(io, mod, &ssi->dma);
+ ret = rsnd_dma_attach(io, mod, &io->dma);
return ret;
}
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 016fbf5ac242..39b67643b5dc 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -10,9 +10,12 @@
struct rsnd_ssiu {
struct rsnd_mod mod;
+ u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
+ unsigned int usrcnt;
};
#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
+#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
#define for_each_rsnd_ssiu(pos, priv, i) \
for (i = 0; \
(i < rsnd_ssiu_nr(priv)) && \
@@ -120,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
int hdmi = rsnd_ssi_hdmi_port(io);
int ret;
u32 mode = 0;
@@ -128,6 +132,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
if (ret < 0)
return ret;
+ ssiu->usrcnt++;
+
if (rsnd_runtime_is_ssi_tdm(io)) {
/*
* TDM Extend Mode
@@ -140,15 +146,59 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SSI_MODE, mode);
if (rsnd_ssi_use_busif(io)) {
- rsnd_mod_write(mod, SSI_BUSIF_ADINR,
- rsnd_get_adinr_bit(mod, io) |
- (rsnd_io_is_play(io) ?
- rsnd_runtime_channel_after_ctu(io) :
- rsnd_runtime_channel_original(io)));
- rsnd_mod_write(mod, SSI_BUSIF_MODE,
- rsnd_get_busif_shift(io, mod) | 1);
- rsnd_mod_write(mod, SSI_BUSIF_DALIGN,
- rsnd_get_dalign(mod, io));
+ int id = rsnd_mod_id(mod);
+ int busif = rsnd_ssi_get_busif(io);
+
+ /*
+ * FIXME
+ *
+ * We can't support SSI9-4/5/6/7, because its address is
+ * out of calculation rule
+ */
+ if ((id == 9) && (busif >= 4)) {
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ dev_err(dev, "This driver doesn't support SSI%d-%d, so far",
+ id, busif);
+ }
+
+#define RSND_WRITE_BUSIF(i) \
+ rsnd_mod_write(mod, SSI_BUSIF##i##_ADINR, \
+ rsnd_get_adinr_bit(mod, io) | \
+ (rsnd_io_is_play(io) ? \
+ rsnd_runtime_channel_after_ctu(io) : \
+ rsnd_runtime_channel_original(io))); \
+ rsnd_mod_write(mod, SSI_BUSIF##i##_MODE, \
+ rsnd_get_busif_shift(io, mod) | 1); \
+ rsnd_mod_write(mod, SSI_BUSIF##i##_DALIGN, \
+ rsnd_get_dalign(mod, io))
+
+ switch (busif) {
+ case 0:
+ RSND_WRITE_BUSIF(0);
+ break;
+ case 1:
+ RSND_WRITE_BUSIF(1);
+ break;
+ case 2:
+ RSND_WRITE_BUSIF(2);
+ break;
+ case 3:
+ RSND_WRITE_BUSIF(3);
+ break;
+ case 4:
+ RSND_WRITE_BUSIF(4);
+ break;
+ case 5:
+ RSND_WRITE_BUSIF(5);
+ break;
+ case 6:
+ RSND_WRITE_BUSIF(6);
+ break;
+ case 7:
+ RSND_WRITE_BUSIF(7);
+ break;
+ }
}
if (hdmi) {
@@ -194,10 +244,12 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ int busif = rsnd_ssi_get_busif(io);
+
if (!rsnd_ssi_use_busif(io))
return 0;
- rsnd_mod_write(mod, SSI_CTRL, 0x1);
+ rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
if (rsnd_ssi_multi_slaves_runtime(io))
rsnd_mod_write(mod, SSI_CONTROL, 0x1);
@@ -209,10 +261,16 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+ int busif = rsnd_ssi_get_busif(io);
+
if (!rsnd_ssi_use_busif(io))
return 0;
- rsnd_mod_write(mod, SSI_CTRL, 0);
+ rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
+
+ if (--ssiu->usrcnt)
+ return 0;
if (rsnd_ssi_multi_slaves_runtime(io))
rsnd_mod_write(mod, SSI_CONTROL, 0);
@@ -246,6 +304,16 @@ int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
return rsnd_dai_connect(mod, io, mod->type);
}
+static u32 *rsnd_ssiu_get_status(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod,
+ enum rsnd_mod_type type)
+{
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+ int busif = rsnd_ssi_get_busif(io);
+
+ return &ssiu->busif_status[busif];
+}
+
int rsnd_ssiu_probe(struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
@@ -269,7 +337,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
for_each_rsnd_ssiu(ssiu, priv, i) {
ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
- ops, NULL, rsnd_mod_get_status,
+ ops, NULL, rsnd_ssiu_get_status,
RSND_MOD_SSIU, i);
if (ret)
return ret;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 473eefe8658e..4e9367aacc0c 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -452,12 +452,12 @@ int snd_soc_suspend(struct device *dev)
/* mute any active DACs */
list_for_each_entry(rtd, &card->rtd_list, list) {
+ struct snd_soc_dai *dai;
if (rtd->dai_link->ignore_suspend)
continue;
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, dai) {
struct snd_soc_dai_driver *drv = dai->driver;
if (drv->ops->digital_mute && dai->playback_active)
@@ -625,12 +625,12 @@ static void soc_resume_deferred(struct work_struct *work)
/* unmute any active DACs */
list_for_each_entry(rtd, &card->rtd_list, list) {
+ struct snd_soc_dai *dai;
if (rtd->dai_link->ignore_suspend)
continue;
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, dai) {
struct snd_soc_dai_driver *drv = dai->driver;
if (drv->ops->digital_mute && dai->playback_active)
@@ -674,15 +674,14 @@ int snd_soc_resume(struct device *dev)
/* activate pins from sleep state */
list_for_each_entry(rtd, &card->rtd_list, list) {
- struct snd_soc_dai **codec_dais = rtd->codec_dais;
+ struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int j;
if (cpu_dai->active)
pinctrl_pm_select_default_state(cpu_dai->dev);
- for (j = 0; j < rtd->num_codecs; j++) {
- struct snd_soc_dai *codec_dai = codec_dais[j];
+ for_each_rtd_codec_dai(rtd, j, codec_dai) {
if (codec_dai->active)
pinctrl_pm_select_default_state(codec_dai->dev);
}
@@ -877,6 +876,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
rtd->num_codecs = dai_link->num_codecs;
/* Find CODEC from registered CODECs */
+ /* we can use for_each_rtd_codec_dai() after this */
codec_dais = rtd->codec_dais;
for (i = 0; i < rtd->num_codecs; i++) {
codec_dais[i] = snd_soc_find_dai(&codecs[i]);
@@ -892,8 +892,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
rtd->codec_dai = codec_dais[0];
/* if there's no platform we match on the empty platform */
- platform_name = dai_link->platform_name;
- if (!platform_name && !dai_link->platform_of_node)
+ platform_name = dai_link->platform->name;
+ if (!platform_name && !dai_link->platform->of_node)
platform_name = "snd-soc-dummy";
/* find one from the set of registered platforms */
@@ -902,8 +902,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
if (!platform_of_node && component->dev->parent->of_node)
platform_of_node = component->dev->parent->of_node;
- if (dai_link->platform_of_node) {
- if (platform_of_node != dai_link->platform_of_node)
+ if (dai_link->platform->of_node) {
+ if (platform_of_node != dai_link->platform->of_node)
continue;
} else {
if (strcmp(component->name, platform_name))
@@ -959,6 +959,7 @@ static void soc_remove_link_dais(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd, int order)
{
int i;
+ struct snd_soc_dai *codec_dai;
/* unregister the rtd device */
if (rtd->dev_registered) {
@@ -967,8 +968,8 @@ static void soc_remove_link_dais(struct snd_soc_card *card,
}
/* remove the CODEC DAI */
- for (i = 0; i < rtd->num_codecs; i++)
- soc_remove_dai(rtd->codec_dais[i], order);
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ soc_remove_dai(codec_dai, order);
soc_remove_dai(rtd->cpu_dai, order);
}
@@ -1015,6 +1016,31 @@ static void soc_remove_dai_links(struct snd_soc_card *card)
}
}
+static int snd_soc_init_platform(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_link)
+{
+ /*
+ * FIXME
+ *
+ * this function should be removed in the future
+ */
+ /* convert Legacy platform link */
+ if (dai_link->platform)
+ return 0;
+
+ dai_link->platform = devm_kzalloc(card->dev,
+ sizeof(struct snd_soc_dai_link_component),
+ GFP_KERNEL);
+ if (!dai_link->platform)
+ return -ENOMEM;
+
+ dai_link->platform->name = dai_link->platform_name;
+ dai_link->platform->of_node = dai_link->platform_of_node;
+ dai_link->platform->dai_name = NULL;
+
+ return 0;
+}
+
static int snd_soc_init_multicodec(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link)
{
@@ -1046,6 +1072,13 @@ static int soc_init_dai_link(struct snd_soc_card *card,
struct snd_soc_dai_link *link)
{
int i, ret;
+ struct snd_soc_dai_link_component *codec;
+
+ ret = snd_soc_init_platform(card, link);
+ if (ret) {
+ dev_err(card->dev, "ASoC: failed to init multiplatform\n");
+ return ret;
+ }
ret = snd_soc_init_multicodec(card, link);
if (ret) {
@@ -1053,19 +1086,19 @@ static int soc_init_dai_link(struct snd_soc_card *card,
return ret;
}
- for (i = 0; i < link->num_codecs; i++) {
+ for_each_link_codecs(link, i, codec) {
/*
* Codec must be specified by 1 of name or OF node,
* not both or neither.
*/
- if (!!link->codecs[i].name ==
- !!link->codecs[i].of_node) {
+ if (!!codec->name ==
+ !!codec->of_node) {
dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
link->name);
return -EINVAL;
}
/* Codec DAI name must be specified */
- if (!link->codecs[i].dai_name) {
+ if (!codec->dai_name) {
dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
link->name);
return -EINVAL;
@@ -1076,13 +1109,12 @@ static int soc_init_dai_link(struct snd_soc_card *card,
* Platform may be specified by either name or OF node, but
* can be left unspecified, and a dummy platform will be used.
*/
- if (link->platform_name && link->platform_of_node) {
+ if (link->platform->name && link->platform->of_node) {
dev_err(card->dev,
"ASoC: Both platform name/of_node are set for %s\n",
link->name);
return -EINVAL;
}
-
/*
* CPU device may be specified by either name or OF node, but
* can be left unspecified, and will be matched based on DAI
@@ -1431,48 +1463,6 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais,
return 0;
}
-static int soc_link_dai_widgets(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link,
- struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dapm_widget *sink, *source;
- int ret;
-
- if (rtd->num_codecs > 1)
- dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n");
-
- /* link the DAI widgets */
- sink = codec_dai->playback_widget;
- source = cpu_dai->capture_widget;
- if (sink && source) {
- ret = snd_soc_dapm_new_pcm(card, rtd, dai_link->params,
- dai_link->num_params,
- source, sink);
- if (ret != 0) {
- dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
- sink->name, source->name, ret);
- return ret;
- }
- }
-
- sink = cpu_dai->playback_widget;
- source = codec_dai->capture_widget;
- if (sink && source) {
- ret = snd_soc_dapm_new_pcm(card, rtd, dai_link->params,
- dai_link->num_params,
- source, sink);
- if (ret != 0) {
- dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
- sink->name, source->name, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
static int soc_probe_link_dais(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd, int order)
{
@@ -1480,6 +1470,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_component *component;
+ struct snd_soc_dai *codec_dai;
int i, ret, num;
dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
@@ -1493,8 +1484,8 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
return ret;
/* probe the CODEC DAI */
- for (i = 0; i < rtd->num_codecs; i++) {
- ret = soc_probe_dai(rtd->codec_dais[i], order);
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ ret = soc_probe_dai(codec_dai, order);
if (ret)
return ret;
}
@@ -1573,11 +1564,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
} else {
INIT_DELAYED_WORK(&rtd->delayed_work,
codec2codec_close_delayed_work);
-
- /* link the DAI widgets */
- ret = soc_link_dai_widgets(card, dai_link, rtd);
- if (ret)
- return ret;
}
}
@@ -1681,14 +1667,12 @@ static void soc_remove_aux_devices(struct snd_soc_card *card)
int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
unsigned int dai_fmt)
{
- struct snd_soc_dai **codec_dais = rtd->codec_dais;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai;
unsigned int i;
int ret;
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = codec_dais[i];
-
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
if (ret != 0 && ret != -ENOTSUPP) {
dev_warn(codec_dai->dev,
@@ -1917,7 +1901,11 @@ static void soc_check_tplg_fes(struct snd_soc_card *card)
card->dai_link[i].name);
/* override platform component */
- dai_link->platform_name = component->name;
+ if (snd_soc_init_platform(card, dai_link) < 0) {
+ dev_err(card->dev, "init platform error");
+ continue;
+ }
+ dai_link->platform->name = component->name;
/* convert non BE into BE */
dai_link->no_pcm = 1;
@@ -2231,11 +2219,11 @@ int snd_soc_poweroff(struct device *dev)
/* deactivate pins to sleep state */
list_for_each_entry(rtd, &card->rtd_list, list) {
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai;
int i;
pinctrl_pm_select_sleep_state(cpu_dai->dev);
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
pinctrl_pm_select_sleep_state(codec_dai->dev);
}
}
@@ -2741,10 +2729,10 @@ int snd_soc_register_card(struct snd_soc_card *card)
/* deactivate pins to sleep state */
list_for_each_entry(rtd, &card->rtd_list, list) {
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai;
int j;
- for (j = 0; j < rtd->num_codecs; j++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+ for_each_rtd_codec_dai(rtd, j, codec_dai) {
if (!codec_dai->active)
pinctrl_pm_select_sleep_state(codec_dai->dev);
}
@@ -2910,8 +2898,6 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
* @component: The component the DAIs are registered for
* @dai_drv: DAI driver to use for the DAIs
* @count: Number of DAIs
- * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the
- * parent's name.
*/
static int snd_soc_register_dais(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv, size_t count)
@@ -3764,10 +3750,10 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
*/
void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link)
{
- struct snd_soc_dai_link_component *component = dai_link->codecs;
+ struct snd_soc_dai_link_component *component;
int index;
- for (index = 0; index < dai_link->num_codecs; index++, component++) {
+ for_each_link_codecs(dai_link, index, component) {
if (!component->of_node)
break;
of_node_put(component->of_node);
@@ -3819,9 +3805,7 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
dai_link->num_codecs = num_codecs;
/* Parse the list */
- for (index = 0, component = dai_link->codecs;
- index < dai_link->num_codecs;
- index++, component++) {
+ for_each_link_codecs(dai_link, index, component) {
ret = of_parse_phandle_with_args(of_node, name,
"#sound-dai-cells",
index, &args);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 461d951917c0..43983c69f6aa 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -364,10 +364,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
ret = PTR_ERR(data->widget);
goto err_data;
}
- if (!data->widget) {
- ret = -ENOMEM;
- goto err_data;
- }
}
break;
case snd_soc_dapm_demux:
@@ -402,10 +398,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
ret = PTR_ERR(data->widget);
goto err_data;
}
- if (!data->widget) {
- ret = -ENOMEM;
- goto err_data;
- }
snd_soc_dapm_add_path(widget->dapm, data->widget,
widget, NULL, NULL);
@@ -1026,9 +1018,10 @@ static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
struct snd_kcontrol *kcontrol;
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_card *card = dapm->card->snd_card;
+ struct snd_soc_pcm_runtime *rtd = w->priv;
/* create control for links with > 1 config */
- if (w->num_params <= 1)
+ if (rtd->dai_link->num_params <= 1)
return 0;
/* add kcontrol */
@@ -1320,14 +1313,13 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w,
soc_dapm_async_complete(w->dapm);
-#ifdef CONFIG_HAVE_CLK
if (SND_SOC_DAPM_EVENT_ON(event)) {
return clk_prepare_enable(w->clk);
} else {
clk_disable_unprepare(w->clk);
return 0;
}
-#endif
+
return 0;
}
EXPORT_SYMBOL_GPL(dapm_clock_event);
@@ -1953,7 +1945,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
dapm_pre_sequence_async(&card->dapm, 0);
/* Run other bias changes in parallel */
list_for_each_entry(d, &card->dapm_list, list) {
- if (d != &card->dapm)
+ if (d != &card->dapm && d->bias_level != d->target_bias_level)
async_schedule_domain(dapm_pre_sequence_async, d,
&async_domain);
}
@@ -1977,7 +1969,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
/* Run all the bias changes in parallel */
list_for_each_entry(d, &card->dapm_list, list) {
- if (d != &card->dapm)
+ if (d != &card->dapm && d->bias_level != d->target_bias_level)
async_schedule_domain(dapm_post_sequence_async, d,
&async_domain);
}
@@ -2371,12 +2363,13 @@ static ssize_t dapm_widget_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
+ struct snd_soc_dai *codec_dai;
int i, count = 0;
mutex_lock(&rtd->card->dapm_mutex);
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component;
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ struct snd_soc_component *cmpnt = codec_dai->component;
count += dapm_widget_show_component(cmpnt, buf + count);
}
@@ -3426,35 +3419,6 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
struct snd_soc_dapm_widget *
-snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_widget *widget)
-{
- struct snd_soc_dapm_widget *w;
-
- mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- w = snd_soc_dapm_new_control_unlocked(dapm, widget);
- /* Do not nag about probe deferrals */
- if (IS_ERR(w)) {
- int ret = PTR_ERR(w);
-
- if (ret != -EPROBE_DEFER)
- dev_err(dapm->dev,
- "ASoC: Failed to create DAPM control %s (%d)\n",
- widget->name, ret);
- goto out_unlock;
- }
- if (!w)
- dev_err(dapm->dev,
- "ASoC: Failed to create DAPM control %s\n",
- widget->name);
-
-out_unlock:
- mutex_unlock(&dapm->card->dapm_mutex);
- return w;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
-
-struct snd_soc_dapm_widget *
snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget)
{
@@ -3464,53 +3428,37 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
int ret;
if ((w = dapm_cnew_widget(widget)) == NULL)
- return NULL;
+ return ERR_PTR(-ENOMEM);
switch (w->id) {
case snd_soc_dapm_regulator_supply:
w->regulator = devm_regulator_get(dapm->dev, w->name);
if (IS_ERR(w->regulator)) {
ret = PTR_ERR(w->regulator);
- if (ret == -EPROBE_DEFER)
- return ERR_PTR(ret);
- dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
- w->name, ret);
- return NULL;
+ goto request_failed;
}
if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
- dev_warn(w->dapm->dev,
+ dev_warn(dapm->dev,
"ASoC: Failed to bypass %s: %d\n",
w->name, ret);
}
break;
case snd_soc_dapm_pinctrl:
w->pinctrl = devm_pinctrl_get(dapm->dev);
- if (IS_ERR_OR_NULL(w->pinctrl)) {
+ if (IS_ERR(w->pinctrl)) {
ret = PTR_ERR(w->pinctrl);
- if (ret == -EPROBE_DEFER)
- return ERR_PTR(ret);
- dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
- w->name, ret);
- return NULL;
+ goto request_failed;
}
break;
case snd_soc_dapm_clock_supply:
-#ifdef CONFIG_CLKDEV_LOOKUP
w->clk = devm_clk_get(dapm->dev, w->name);
if (IS_ERR(w->clk)) {
ret = PTR_ERR(w->clk);
- if (ret == -EPROBE_DEFER)
- return ERR_PTR(ret);
- dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
- w->name, ret);
- return NULL;
+ goto request_failed;
}
-#else
- return NULL;
-#endif
break;
default:
break;
@@ -3523,7 +3471,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
w->name = kstrdup_const(widget->name, GFP_KERNEL);
if (w->name == NULL) {
kfree(w);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
switch (w->id) {
@@ -3600,9 +3548,39 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
/* machine layer sets up unconnected pins and insertions */
w->connected = 1;
return w;
+
+request_failed:
+ if (ret != -EPROBE_DEFER)
+ dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
+ w->name, ret);
+
+ return ERR_PTR(ret);
}
/**
+ * snd_soc_dapm_new_control - create new dapm control
+ * @dapm: DAPM context
+ * @widget: widget template
+ *
+ * Creates new DAPM control based upon a template.
+ *
+ * Returns a widget pointer on success or an error pointer on failure
+ */
+struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
+ const struct snd_soc_dapm_widget *widget)
+{
+ struct snd_soc_dapm_widget *w;
+
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ w = snd_soc_dapm_new_control_unlocked(dapm, widget);
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ return w;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
+
+/**
* snd_soc_dapm_new_controls - create new dapm controls
* @dapm: DAPM context
* @widget: widget array
@@ -3625,19 +3603,6 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
w = snd_soc_dapm_new_control_unlocked(dapm, widget);
if (IS_ERR(w)) {
ret = PTR_ERR(w);
- /* Do not nag about probe deferrals */
- if (ret == -EPROBE_DEFER)
- break;
- dev_err(dapm->dev,
- "ASoC: Failed to create DAPM control %s (%d)\n",
- widget->name, ret);
- break;
- }
- if (!w) {
- dev_err(dapm->dev,
- "ASoC: Failed to create DAPM control %s\n",
- widget->name);
- ret = -ENOMEM;
break;
}
widget++;
@@ -3650,32 +3615,23 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_dapm_path *source_p, *sink_p;
+ struct snd_soc_dapm_path *path;
struct snd_soc_dai *source, *sink;
struct snd_soc_pcm_runtime *rtd = w->priv;
- const struct snd_soc_pcm_stream *config = w->params + w->params_select;
+ const struct snd_soc_pcm_stream *config;
struct snd_pcm_substream substream;
struct snd_pcm_hw_params *params = NULL;
struct snd_pcm_runtime *runtime = NULL;
unsigned int fmt;
- int ret;
+ int ret = 0;
+
+ config = rtd->dai_link->params + rtd->params_select;
if (WARN_ON(!config) ||
WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
return -EINVAL;
- /* We only support a single source and sink, pick the first */
- source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT],
- struct snd_soc_dapm_path,
- list_node[SND_SOC_DAPM_DIR_OUT]);
- sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN],
- struct snd_soc_dapm_path,
- list_node[SND_SOC_DAPM_DIR_IN]);
-
- source = source_p->source->priv;
- sink = sink_p->sink->priv;
-
/* Be a little careful as we don't want to overflow the mask array */
if (config->formats) {
fmt = ffs(config->formats) - 1;
@@ -3717,59 +3673,90 @@ 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->startup) {
- ret = source->driver->ops->startup(&substream, source);
- if (ret < 0) {
- dev_err(source->dev,
- "ASoC: startup() failed: %d\n", ret);
- goto out;
+ snd_soc_dapm_widget_for_each_source_path(w, path) {
+ source = path->source->priv;
+
+ if (source->driver->ops->startup) {
+ ret = source->driver->ops->startup(&substream,
+ source);
+ if (ret < 0) {
+ dev_err(source->dev,
+ "ASoC: startup() failed: %d\n",
+ ret);
+ goto out;
+ }
+ source->active++;
}
- source->active++;
+ ret = soc_dai_hw_params(&substream, params, source);
+ if (ret < 0)
+ goto out;
}
- ret = soc_dai_hw_params(&substream, params, source);
- if (ret < 0)
- goto out;
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- if (sink->driver->ops->startup) {
- ret = sink->driver->ops->startup(&substream, sink);
- if (ret < 0) {
- dev_err(sink->dev,
- "ASoC: startup() failed: %d\n", ret);
- goto out;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ if (sink->driver->ops->startup) {
+ ret = sink->driver->ops->startup(&substream,
+ sink);
+ if (ret < 0) {
+ dev_err(sink->dev,
+ "ASoC: startup() failed: %d\n",
+ ret);
+ goto out;
+ }
+ sink->active++;
}
- sink->active++;
+ ret = soc_dai_hw_params(&substream, params, sink);
+ if (ret < 0)
+ goto out;
}
- ret = soc_dai_hw_params(&substream, params, sink);
- if (ret < 0)
- goto out;
break;
case SND_SOC_DAPM_POST_PMU:
- ret = snd_soc_dai_digital_mute(sink, 0,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret != 0 && ret != -ENOTSUPP)
- dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
- ret = 0;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ ret = snd_soc_dai_digital_mute(sink, 0,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret != 0 && ret != -ENOTSUPP)
+ dev_warn(sink->dev,
+ "ASoC: Failed to unmute: %d\n", ret);
+ ret = 0;
+ }
break;
case SND_SOC_DAPM_PRE_PMD:
- ret = snd_soc_dai_digital_mute(sink, 1,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret != 0 && ret != -ENOTSUPP)
- dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
- ret = 0;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ ret = snd_soc_dai_digital_mute(sink, 1,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret != 0 && ret != -ENOTSUPP)
+ dev_warn(sink->dev,
+ "ASoC: Failed to mute: %d\n", ret);
+ ret = 0;
+ }
+
+ snd_soc_dapm_widget_for_each_source_path(w, path) {
+ source = path->source->priv;
- source->active--;
- if (source->driver->ops->shutdown) {
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- source->driver->ops->shutdown(&substream, source);
+ source->active--;
+ if (source->driver->ops->shutdown) {
+ substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+ source->driver->ops->shutdown(&substream,
+ source);
+ }
}
- sink->active--;
- if (sink->driver->ops->shutdown) {
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- sink->driver->ops->shutdown(&substream, sink);
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ sink->active--;
+ if (sink->driver->ops->shutdown) {
+ substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+ sink->driver->ops->shutdown(&substream, sink);
+ }
}
break;
@@ -3788,8 +3775,9 @@ static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_pcm_runtime *rtd = w->priv;
- ucontrol->value.enumerated.item[0] = w->params_select;
+ ucontrol->value.enumerated.item[0] = rtd->params_select;
return 0;
}
@@ -3798,18 +3786,19 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_pcm_runtime *rtd = w->priv;
/* Can't change the config when widget is already powered */
if (w->power)
return -EBUSY;
- if (ucontrol->value.enumerated.item[0] == w->params_select)
+ if (ucontrol->value.enumerated.item[0] == rtd->params_select)
return 0;
- if (ucontrol->value.enumerated.item[0] >= w->num_params)
+ if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params)
return -EINVAL;
- w->params_select = ucontrol->value.enumerated.item[0];
+ rtd->params_select = ucontrol->value.enumerated.item[0];
return 0;
}
@@ -3896,12 +3885,10 @@ outfree_w_param:
return NULL;
}
-int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
- struct snd_soc_pcm_runtime *rtd,
- const struct snd_soc_pcm_stream *params,
- unsigned int num_params,
- struct snd_soc_dapm_widget *source,
- struct snd_soc_dapm_widget *sink)
+static struct snd_soc_dapm_widget *
+snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
{
struct snd_soc_dapm_widget template;
struct snd_soc_dapm_widget *w;
@@ -3913,7 +3900,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
source->name, sink->name);
if (!link_name)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
memset(&template, 0, sizeof(template));
template.reg = SND_SOC_NOPM;
@@ -3925,9 +3912,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
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 (rtd->dai_link->num_params > 1) {
+ w_param_text = devm_kcalloc(card->dev,
+ rtd->dai_link->num_params,
+ sizeof(char *), GFP_KERNEL);
if (!w_param_text) {
ret = -ENOMEM;
goto param_fail;
@@ -3936,7 +3924,9 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
template.num_kcontrols = 1;
template.kcontrol_news =
snd_soc_dapm_alloc_kcontrol(card,
- link_name, params, num_params,
+ link_name,
+ rtd->dai_link->params,
+ rtd->dai_link->num_params,
w_param_text, &private_value);
if (!template.kcontrol_news) {
ret = -ENOMEM;
@@ -3950,37 +3940,20 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
if (IS_ERR(w)) {
ret = PTR_ERR(w);
- /* Do not nag about probe deferrals */
- if (ret != -EPROBE_DEFER)
- dev_err(card->dev,
- "ASoC: Failed to create %s widget (%d)\n",
- link_name, ret);
- goto outfree_kcontrol_news;
- }
- if (!w) {
- dev_err(card->dev, "ASoC: Failed to create %s widget\n",
- link_name);
- ret = -ENOMEM;
goto outfree_kcontrol_news;
}
- w->params = params;
- w->num_params = num_params;
w->priv = rtd;
- ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
- if (ret)
- goto outfree_w;
- return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
+ return w;
-outfree_w:
- devm_kfree(card->dev, w);
outfree_kcontrol_news:
devm_kfree(card->dev, (void *)template.kcontrol_news);
- snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text);
+ snd_soc_dapm_free_kcontrol(card, &private_value,
+ rtd->dai_link->num_params, w_param_text);
param_fail:
devm_kfree(card->dev, link_name);
- return ret;
+ return ERR_PTR(ret);
}
int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
@@ -4003,21 +3976,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
template.name);
w = snd_soc_dapm_new_control_unlocked(dapm, &template);
- if (IS_ERR(w)) {
- int ret = PTR_ERR(w);
-
- /* Do not nag about probe deferrals */
- if (ret != -EPROBE_DEFER)
- dev_err(dapm->dev,
- "ASoC: Failed to create %s widget (%d)\n",
- dai->driver->playback.stream_name, ret);
- return ret;
- }
- if (!w) {
- dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
- dai->driver->playback.stream_name);
- return -ENOMEM;
- }
+ if (IS_ERR(w))
+ return PTR_ERR(w);
w->priv = dai;
dai->playback_widget = w;
@@ -4032,21 +3992,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
template.name);
w = snd_soc_dapm_new_control_unlocked(dapm, &template);
- if (IS_ERR(w)) {
- int ret = PTR_ERR(w);
-
- /* Do not nag about probe deferrals */
- if (ret != -EPROBE_DEFER)
- dev_err(dapm->dev,
- "ASoC: Failed to create %s widget (%d)\n",
- dai->driver->playback.stream_name, ret);
- return ret;
- }
- if (!w) {
- dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
- dai->driver->capture.stream_name);
- return -ENOMEM;
- }
+ if (IS_ERR(w))
+ return PTR_ERR(w);
w->priv = dai;
dai->capture_widget = w;
@@ -4115,34 +4062,79 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dapm_widget *sink, *source;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dapm_widget *playback = NULL, *capture = NULL;
+ struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu;
int i;
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+ if (rtd->dai_link->params) {
+ playback_cpu = cpu_dai->capture_widget;
+ capture_cpu = cpu_dai->playback_widget;
+ } else {
+ playback = cpu_dai->playback_widget;
+ capture = cpu_dai->capture_widget;
+ playback_cpu = playback;
+ capture_cpu = capture;
+ }
+
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
/* connect BE DAI playback if widgets are valid */
- if (codec_dai->playback_widget && cpu_dai->playback_widget) {
- source = cpu_dai->playback_widget;
- sink = codec_dai->playback_widget;
+ codec = codec_dai->playback_widget;
+
+ if (playback_cpu && codec) {
+ if (!playback) {
+ playback = snd_soc_dapm_new_dai(card, rtd,
+ playback_cpu,
+ codec);
+ if (IS_ERR(playback)) {
+ dev_err(rtd->dev,
+ "ASoC: Failed to create DAI %s: %ld\n",
+ codec_dai->name,
+ PTR_ERR(playback));
+ continue;
+ }
+
+ snd_soc_dapm_add_path(&card->dapm, playback_cpu,
+ playback, NULL, NULL);
+ }
+
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
- cpu_dai->component->name, source->name,
- codec_dai->component->name, sink->name);
+ cpu_dai->component->name, playback_cpu->name,
+ codec_dai->component->name, codec->name);
- snd_soc_dapm_add_path(&card->dapm, source, sink,
- NULL, NULL);
+ snd_soc_dapm_add_path(&card->dapm, playback, codec,
+ NULL, NULL);
}
+ }
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
/* connect BE DAI capture if widgets are valid */
- if (codec_dai->capture_widget && cpu_dai->capture_widget) {
- source = codec_dai->capture_widget;
- sink = cpu_dai->capture_widget;
+ codec = codec_dai->capture_widget;
+
+ if (codec && capture_cpu) {
+ if (!capture) {
+ capture = snd_soc_dapm_new_dai(card, rtd,
+ codec,
+ capture_cpu);
+ if (IS_ERR(capture)) {
+ dev_err(rtd->dev,
+ "ASoC: Failed to create DAI %s: %ld\n",
+ codec_dai->name,
+ PTR_ERR(capture));
+ continue;
+ }
+
+ snd_soc_dapm_add_path(&card->dapm, capture,
+ capture_cpu, NULL, NULL);
+ }
+
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
- codec_dai->component->name, source->name,
- cpu_dai->component->name, sink->name);
+ codec_dai->component->name, codec->name,
+ cpu_dai->component->name, capture_cpu->name);
- snd_soc_dapm_add_path(&card->dapm, source, sink,
- NULL, NULL);
+ snd_soc_dapm_add_path(&card->dapm, codec, capture,
+ NULL, NULL);
}
}
}
@@ -4197,7 +4189,7 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
* dynamic FE links have no fixed DAI mapping.
* CODEC<->CODEC links have no direct connection.
*/
- if (rtd->dai_link->dynamic || rtd->dai_link->params)
+ if (rtd->dai_link->dynamic)
continue;
dapm_connect_dai_link_widgets(card, rtd);
@@ -4207,11 +4199,12 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
int event)
{
+ struct snd_soc_dai *codec_dai;
int i;
soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
- for (i = 0; i < rtd->num_codecs; i++)
- soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ soc_dapm_dai_stream_event(codec_dai, stream, event);
dapm_power_widgets(rtd->card, event);
}
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 52fd7af952a5..30e791a53352 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -147,7 +147,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
ret = dma_get_slave_caps(chan, &dma_caps);
if (ret == 0) {
- if (dma_caps.cmd_pause)
+ if (dma_caps.cmd_pause && dma_caps.cmd_resume)
hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME;
if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT)
hw.info |= SNDRV_PCM_INFO_BATCH;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index e8b98bfd4cf1..79f5dd541d29 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -59,25 +59,26 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream)
void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai;
int i;
lockdep_assert_held(&rtd->pcm_mutex);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
cpu_dai->playback_active++;
- for (i = 0; i < rtd->num_codecs; i++)
- rtd->codec_dais[i]->playback_active++;
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ codec_dai->playback_active++;
} else {
cpu_dai->capture_active++;
- for (i = 0; i < rtd->num_codecs; i++)
- rtd->codec_dais[i]->capture_active++;
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ codec_dai->capture_active++;
}
cpu_dai->active++;
cpu_dai->component->active++;
- for (i = 0; i < rtd->num_codecs; i++) {
- rtd->codec_dais[i]->active++;
- rtd->codec_dais[i]->component->active++;
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ codec_dai->active++;
+ codec_dai->component->active++;
}
}
@@ -94,25 +95,26 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai;
int i;
lockdep_assert_held(&rtd->pcm_mutex);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
cpu_dai->playback_active--;
- for (i = 0; i < rtd->num_codecs; i++)
- rtd->codec_dais[i]->playback_active--;
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ codec_dai->playback_active--;
} else {
cpu_dai->capture_active--;
- for (i = 0; i < rtd->num_codecs; i++)
- rtd->codec_dais[i]->capture_active--;
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ codec_dai->capture_active--;
}
cpu_dai->active--;
cpu_dai->component->active--;
- for (i = 0; i < rtd->num_codecs; i++) {
- rtd->codec_dais[i]->component->active--;
- rtd->codec_dais[i]->active--;
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ codec_dai->component->active--;
+ codec_dai->active--;
}
}
@@ -253,6 +255,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai;
unsigned int rate, channels, sample_bits, symmetry, i;
rate = params_rate(params);
@@ -263,8 +266,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
symmetry = cpu_dai->driver->symmetric_rates ||
rtd->dai_link->symmetric_rates;
- for (i = 0; i < rtd->num_codecs; i++)
- symmetry |= rtd->codec_dais[i]->driver->symmetric_rates;
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ symmetry |= codec_dai->driver->symmetric_rates;
if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
@@ -275,8 +278,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
symmetry = cpu_dai->driver->symmetric_channels ||
rtd->dai_link->symmetric_channels;
- for (i = 0; i < rtd->num_codecs; i++)
- symmetry |= rtd->codec_dais[i]->driver->symmetric_channels;
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ symmetry |= codec_dai->driver->symmetric_channels;
if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
@@ -287,8 +290,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
symmetry = cpu_dai->driver->symmetric_samplebits ||
rtd->dai_link->symmetric_samplebits;
- for (i = 0; i < rtd->num_codecs; i++)
- symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits;
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ symmetry |= codec_dai->driver->symmetric_samplebits;
if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
@@ -304,17 +307,18 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
struct snd_soc_dai_link *link = rtd->dai_link;
+ struct snd_soc_dai *codec_dai;
unsigned int symmetry, i;
symmetry = cpu_driver->symmetric_rates || link->symmetric_rates ||
cpu_driver->symmetric_channels || link->symmetric_channels ||
cpu_driver->symmetric_samplebits || link->symmetric_samplebits;
- for (i = 0; i < rtd->num_codecs; i++)
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
symmetry = symmetry ||
- rtd->codec_dais[i]->driver->symmetric_rates ||
- rtd->codec_dais[i]->driver->symmetric_channels ||
- rtd->codec_dais[i]->driver->symmetric_samplebits;
+ codec_dai->driver->symmetric_rates ||
+ codec_dai->driver->symmetric_channels ||
+ codec_dai->driver->symmetric_samplebits;
return symmetry;
}
@@ -342,8 +346,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
unsigned int bits = 0, cpu_bits;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->playback.sig_bits == 0) {
bits = 0;
break;
@@ -352,8 +355,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
}
cpu_bits = cpu_dai->driver->playback.sig_bits;
} else {
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->capture.sig_bits == 0) {
bits = 0;
break;
@@ -372,6 +374,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hardware *hw = &runtime->hw;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai;
struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver;
struct snd_soc_dai_driver *codec_dai_drv;
struct snd_soc_pcm_stream *codec_stream;
@@ -388,7 +391,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
cpu_stream = &cpu_dai_drv->capture;
/* first calculate min/max only for CODECs in the DAI link */
- for (i = 0; i < rtd->num_codecs; i++) {
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
/*
* Skip CODECs which don't support the current stream type.
@@ -399,11 +402,11 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
* bailed out on a higher level, since there would be no
* CODEC to support the transfer direction in that case.
*/
- if (!snd_soc_dai_stream_valid(rtd->codec_dais[i],
+ if (!snd_soc_dai_stream_valid(codec_dai,
substream->stream))
continue;
- codec_dai_drv = rtd->codec_dais[i]->driver;
+ codec_dai_drv = codec_dai->driver;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
codec_stream = &codec_dai_drv->playback;
else
@@ -482,8 +485,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
int i, ret = 0;
pinctrl_pm_select_default_state(cpu_dai->dev);
- for (i = 0; i < rtd->num_codecs; i++)
- pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev);
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ pinctrl_pm_select_default_state(codec_dai->dev);
for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component;
@@ -520,8 +523,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
component = NULL;
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->ops->startup) {
ret = codec_dai->driver->ops->startup(substream,
codec_dai);
@@ -588,10 +590,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
goto config_err;
}
- for (i = 0; i < rtd->num_codecs; i++) {
- if (rtd->codec_dais[i]->active) {
- ret = soc_pcm_apply_symmetry(substream,
- rtd->codec_dais[i]);
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ if (codec_dai->active) {
+ ret = soc_pcm_apply_symmetry(substream, codec_dai);
if (ret != 0)
goto config_err;
}
@@ -620,8 +621,7 @@ machine_err:
i = rtd->num_codecs;
codec_dai_err:
- while (--i >= 0) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) {
if (codec_dai->driver->ops->shutdown)
codec_dai->driver->ops->shutdown(substream, codec_dai);
}
@@ -641,9 +641,9 @@ out:
pm_runtime_put_autosuspend(component->dev);
}
- for (i = 0; i < rtd->num_codecs; i++) {
- if (!rtd->codec_dais[i]->active)
- pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ if (!codec_dai->active)
+ pinctrl_pm_select_sleep_state(codec_dai->dev);
}
if (!cpu_dai->active)
pinctrl_pm_select_sleep_state(cpu_dai->dev);
@@ -701,8 +701,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
if (!cpu_dai->active)
cpu_dai->rate = 0;
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (!codec_dai->active)
codec_dai->rate = 0;
}
@@ -712,8 +711,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
if (cpu_dai->driver->ops->shutdown)
cpu_dai->driver->ops->shutdown(substream, cpu_dai);
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->ops->shutdown)
codec_dai->driver->ops->shutdown(substream, codec_dai);
}
@@ -751,9 +749,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
pm_runtime_put_autosuspend(component->dev);
}
- for (i = 0; i < rtd->num_codecs; i++) {
- if (!rtd->codec_dais[i]->active)
- pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ if (!codec_dai->active)
+ pinctrl_pm_select_sleep_state(codec_dai->dev);
}
if (!cpu_dai->active)
pinctrl_pm_select_sleep_state(cpu_dai->dev);
@@ -801,8 +799,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
}
}
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->ops->prepare) {
ret = codec_dai->driver->ops->prepare(substream,
codec_dai);
@@ -834,8 +831,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
snd_soc_dapm_stream_event(rtd, substream->stream,
SND_SOC_DAPM_STREAM_START);
- for (i = 0; i < rtd->num_codecs; i++)
- snd_soc_dai_digital_mute(rtd->codec_dais[i], 0,
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ snd_soc_dai_digital_mute(codec_dai, 0,
substream->stream);
snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
@@ -920,6 +917,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
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);
@@ -932,8 +930,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
struct snd_pcm_hw_params codec_params;
/*
@@ -1018,8 +1015,7 @@ interface_err:
i = rtd->num_codecs;
codec_err:
- while (--i >= 0) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) {
if (codec_dai->driver->ops->hw_free)
codec_dai->driver->ops->hw_free(substream, codec_dai);
codec_dai->rate = 0;
@@ -1052,8 +1048,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
cpu_dai->sample_bits = 0;
}
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->active == 1) {
codec_dai->rate = 0;
codec_dai->channels = 0;
@@ -1062,10 +1057,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
}
/* apply codec digital mute */
- for (i = 0; i < rtd->num_codecs; i++) {
- if ((playback && rtd->codec_dais[i]->playback_active == 1) ||
- (!playback && rtd->codec_dais[i]->capture_active == 1))
- snd_soc_dai_digital_mute(rtd->codec_dais[i], 1,
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ if ((playback && codec_dai->playback_active == 1) ||
+ (!playback && codec_dai->capture_active == 1))
+ snd_soc_dai_digital_mute(codec_dai, 1,
substream->stream);
}
@@ -1077,8 +1072,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
soc_pcm_components_hw_free(substream, NULL);
/* now free hw params for the DAIs */
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->ops->hw_free)
codec_dai->driver->ops->hw_free(substream, codec_dai);
}
@@ -1099,8 +1093,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_soc_dai *codec_dai;
int i, ret;
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->ops->trigger) {
ret = codec_dai->driver->ops->trigger(substream,
cmd, codec_dai);
@@ -1144,8 +1137,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai;
int i, ret;
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->ops->bespoke_trigger) {
ret = codec_dai->driver->ops->bespoke_trigger(substream,
cmd, codec_dai);
@@ -1199,8 +1191,7 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
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];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->ops->delay)
codec_delay = max(codec_delay,
codec_dai->driver->ops->delay(substream,
@@ -1388,6 +1379,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
{
struct snd_soc_card *card = widget->dapm->card;
struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai *dai;
int i;
if (dir == SND_SOC_DAPM_DIR_OUT) {
@@ -1398,8 +1390,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
if (rtd->cpu_dai->playback_widget == widget)
return true;
- for (i = 0; i < rtd->num_codecs; ++i) {
- struct snd_soc_dai *dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, dai) {
if (dai->playback_widget == widget)
return true;
}
@@ -1412,8 +1403,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
if (rtd->cpu_dai->capture_widget == widget)
return true;
- for (i = 0; i < rtd->num_codecs; ++i) {
- struct snd_soc_dai *dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, dai) {
if (dai->capture_widget == widget)
return true;
}
@@ -1680,7 +1670,7 @@ static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
struct snd_soc_pcm_stream *stream)
{
runtime->hw.rate_min = stream->rate_min;
- runtime->hw.rate_max = stream->rate_max;
+ runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
runtime->hw.channels_min = stream->channels_min;
runtime->hw.channels_max = stream->channels_max;
if (runtime->hw.formats)
@@ -1907,6 +1897,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
struct snd_pcm_substream *be_substream =
snd_soc_dpcm_get_substream(be, stream);
struct snd_soc_pcm_runtime *rtd = be_substream->private_data;
+ struct snd_soc_dai *codec_dai;
int i;
if (rtd->dai_link->be_hw_params_fixup)
@@ -1923,10 +1914,10 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
return err;
}
- for (i = 0; i < rtd->num_codecs; i++) {
- if (rtd->codec_dais[i]->active) {
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ if (codec_dai->active) {
err = soc_pcm_apply_symmetry(fe_substream,
- rtd->codec_dais[i]);
+ codec_dai);
if (err < 0)
return err;
}
@@ -3041,8 +3032,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
playback = rtd->dai_link->dpcm_playback;
capture = rtd->dai_link->dpcm_capture;
} else {
- for (i = 0; i < rtd->num_codecs; i++) {
- codec_dai = rtd->codec_dais[i];
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
if (codec_dai->driver->playback.channels_min)
playback = 1;
if (codec_dai->driver->capture.channels_min)
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 66e77e020745..17f81b9a5754 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -1565,17 +1565,6 @@ widget:
widget = snd_soc_dapm_new_control_unlocked(dapm, &template);
if (IS_ERR(widget)) {
ret = PTR_ERR(widget);
- /* Do not nag about probe deferrals */
- if (ret != -EPROBE_DEFER)
- dev_err(tplg->dev,
- "ASoC: failed to create widget %s controls (%d)\n",
- w->name, ret);
- goto hdr_err;
- }
- if (widget == NULL) {
- dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n",
- w->name);
- ret = -ENOMEM;
goto hdr_err;
}
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index f22654253c43..d597eba61992 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -104,7 +104,7 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client,
if (!pdev) {
dev_err(&sai_client->pdev->dev,
- "Device not found for node %s\n", np_provider->name);
+ "Device not found for node %pOFn\n", np_provider);
return -ENODEV;
}
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 06fba9650ac4..56a227e0bd71 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -1124,16 +1124,15 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
sai->sync = SAI_SYNC_NONE;
if (args.np) {
if (args.np == np) {
- dev_err(&pdev->dev, "%s sync own reference\n",
- np->name);
+ dev_err(&pdev->dev, "%pOFn sync own reference\n", np);
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);
+ dev_err(&pdev->dev, "%pOFn parent node not found\n",
+ np);
of_node_put(args.np);
return -ENODEV;
}
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index e2ad00e3cae1..1cfca698ae4b 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -208,13 +208,12 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
if (err < 0)
return err;
- return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
+ return devm_snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
&txx9aclc_ac97_dai, 1);
}
static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
{
- snd_soc_unregister_component(&pdev->dev);
snd_soc_set_ac97_ops(NULL);
return 0;
}