Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
October 2019
- 143 participants
- 345 discussions
[alsa-devel] [PATCH v2 00/10] Basic sound support for Arndale board / wm8994 updates
by Sylwester Nawrocki 02 Oct '19
by Sylwester Nawrocki 02 Oct '19
02 Oct '19
This patch series adds basic audio support for Exynos5250 SoC based Arndale
board, the Bluetooth receiver source and HDMI output are not covered yet.
There is also one fix for wm8994 driver related to WM1811 CODEC and wm8994
updates to handle MCLK clocks, similar to patches:
ae1ea48c5c59 ("ASoC: arizona: Add gating for source clocks of the FLLs")
7a4413d0dc96 ("ASoC: arizona: Add gating for clock when used for direct MCLK")
The main changes since v1:
- Fixed bug in "ASoC: wm8994: Add support for MCLKn clock gating" patch
(thanks to Charles),
- dropped the MFD part patch and moved getting of clocks to the CODEC driver,
- Added missing Kconfig entries to patch "ASoC: samsung: arndale: Add
support for WM1811 CODEC",
- Added a patch renaming the driver and a patch for exynos_defconfig.
Sylwester Nawrocki (10):
ASoC: wm8994: Do not register inapplicable controls for WM1811
ASoC: samsung: arndale: Add missing OF node dereferencing
ASoC: wm8994: Add support for setting MCLK clock rate
ASoC: wm8994: Add support for MCLKn clock gating
ASoC: samsung: arndale: Simplify DAI link initialization
ASoC: dt-bindings: Document "samsung,arndale-wm1811" compatible
ASoC: samsung: arndale: Add support for WM1811 CODEC
ASoC: samsung: Rename Arndale card driver
ARM: dts: arndale: Add audio support (WM1811 CODEC boards)
ARM: exynos_defconfig: Enable Arndale audio driver
.../devicetree/bindings/sound/arndale.txt | 5 +-
arch/arm/boot/dts/exynos5250-arndale.dts | 27 ++-
arch/arm/configs/exynos_defconfig | 1 +
sound/soc/codecs/wm8994.c | 199 +++++++++++++---
sound/soc/codecs/wm8994.h | 10 +-
sound/soc/samsung/Kconfig | 12 +-
sound/soc/samsung/Makefile | 4 +-
sound/soc/samsung/arndale.c | 217 ++++++++++++++++++
sound/soc/samsung/arndale_rt5631.c | 138 -----------
9 files changed, 438 insertions(+), 175 deletions(-)
create mode 100644 sound/soc/samsung/arndale.c
delete mode 100644 sound/soc/samsung/arndale_rt5631.c
--
2.17.1
4
29
[alsa-devel] [PATCH] ALSA: hda: add Intel DSP configuration / probe code
by Jaroslav Kysela 02 Oct '19
by Jaroslav Kysela 02 Oct '19
02 Oct '19
For distributions, we need one place where we can decide
which driver will be activated for the auto-configation of the
Intel's HDA hardware with DSP. Actually, we cover three drivers:
* Legacy HDA
* Intel SST
* Intel Sound Open Firmware (SOF)
All those drivers registers similar PCI IDs, so the first
driver probed from the PCI stack can win. But... it is not
guaranteed that the correct driver wins.
This commit changes Intel's NHLT ACPI module to a common
DSP probe module for the Intel's hardware. All above sound
drivers calls this code. The user can force another behaviour
using the module parameter 'dsp_driver' located in
the 'snd-intel-dspcfg' module.
This change allows to add specific dmi checks for the specific
systems like proposed in the pull request:
https://github.com/thesofproject/linux/pull/927
Tested on Lenovo Carbon X1 7th gen.
Signed-off-by: Jaroslav Kysela <perex(a)perex.cz>
Cc: Pierre-Louis Bossart <pierre-louis.bossart(a)linux.intel.com>
Cc: Cezary Rojewski <cezary.rojewski(a)intel.com>
---
include/sound/intel-dsp-config.h | 35 ++++++++++++
sound/hda/Kconfig | 10 +++-
sound/hda/Makefile | 7 ++-
sound/hda/intel-dsp-config.c | 97 ++++++++++++++++++++++++++++++++
sound/hda/intel-nhlt.c | 3 -
sound/pci/hda/Kconfig | 11 +---
sound/pci/hda/hda_intel.c | 49 +++++-----------
sound/soc/intel/Kconfig | 2 +-
sound/soc/intel/skylake/skl.c | 19 ++-----
sound/soc/sof/intel/Kconfig | 2 +-
sound/soc/sof/sof-pci-dev.c | 6 ++
11 files changed, 173 insertions(+), 68 deletions(-)
create mode 100644 include/sound/intel-dsp-config.h
create mode 100644 sound/hda/intel-dsp-config.c
diff --git a/include/sound/intel-dsp-config.h b/include/sound/intel-dsp-config.h
new file mode 100644
index 000000000000..700f86282a83
--- /dev/null
+++ b/include/sound/intel-dsp-config.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * intel-dsp-config.h - Intel DSP config
+ *
+ * Copyright (c) 2019 Jaroslav Kysela <perex(a)perex.cz>
+ */
+
+#ifndef __INTEL_DSP_CONFIG_H__
+#define __INTEL_DSP_CONFIG_H__
+
+struct pci_dev;
+
+enum {
+ SND_INTEL_DSP_DRIVER_ANY = 0,
+ SND_INTEL_DSP_DRIVER_NODSP,
+ SND_INTEL_DSP_DRIVER_LEGACY,
+ SND_INTEL_DSP_DRIVER_SST,
+ SND_INTEL_DSP_DRIVER_SOF,
+ SND_INTEL_DSP_DRIVER_LAST = SND_INTEL_DSP_DRIVER_SOF
+};
+
+#if IS_ENABLED(CONFIG_SND_INTEL_DSP_CONFIG)
+
+int snd_intel_dsp_driver_probe(struct pci_dev *pci);
+
+#else
+
+static inline int snd_intel_dsp_driver_probe(struct pci_dev *pci)
+{
+ return SND_INTEL_DSP_DRIVER_ANY;
+}
+
+#endif
+
+#endif
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index 3d33fc1757ba..b0c88fe040ee 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -34,6 +34,12 @@ config SND_HDA_PREALLOC_SIZE
via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
config SND_INTEL_NHLT
- tristate
+ bool
# this config should be selected only for Intel ACPI platforms.
- # A fallback is provided so that the code compiles in all cases.
\ No newline at end of file
+ # A fallback is provided so that the code compiles in all cases.
+
+config SND_INTEL_DSP_CONFIG
+ tristate
+ select SND_INTEL_NHLT if ACPI
+ # this config should be selected only for Intel DSP platforms.
+ # A fallback is provided so that the code compiles in all cases.
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index 8560f6ef1b19..c593253c9829 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -14,5 +14,8 @@ obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
#extended hda
obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/
-snd-intel-nhlt-objs := intel-nhlt.o
-obj-$(CONFIG_SND_INTEL_NHLT) += snd-intel-nhlt.o
+snd-intel-dspcfg-objs := intel-dsp-config.o
+ifneq ($(CONFIG_ACPI),)
+ snd-intel-dspcfg-objs += intel-nhlt.o
+endif
+obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
new file mode 100644
index 000000000000..1abbf74ba643
--- /dev/null
+++ b/sound/hda/intel-dsp-config.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Jaroslav Kysela <perex(a)perex.cz>
+
+#include <sound/core.h>
+#include <linux/pci.h>
+#include <sound/intel-nhlt.h>
+#include <sound/intel-dsp-config.h>
+
+static int dsp_driver;
+
+module_param(dsp_driver, int, 0444);
+MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=noDSP, 2=legacy, 3=SST, 4=SOF)");
+
+static const u16 sof_skl_table[] = {
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP)
+ 0x02c8, /* Cometlake-LP */
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H)
+ 0x06c8, /* Cometlake-H */
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
+ 0x3198, /* Geminilake */
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
+ 0x5a98, /* Broxton-P (Appololake) */
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
+ 0x9dc8, /* Cannonlake */
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
+ 0xa348, /* Coffelake */
+#endif
+};
+
+static int snd_intel_dsp_check_device(u16 device, const u16 *table, u32 len)
+{
+ for (; len > 0; len--, table++) {
+ if (*table == device)
+ return 1;
+ }
+ return 0;
+}
+
+static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
+{
+ struct nhlt_acpi_table *nhlt;
+ int ret = 0;
+
+ if (snd_intel_dsp_check_device(pci->device, sof_skl_table, ARRAY_SIZE(sof_skl_table))) {
+ nhlt = intel_nhlt_init(&pci->dev);
+ if (nhlt) {
+ if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt))
+ ret = 1;
+ intel_nhlt_free(nhlt);
+ }
+ }
+ return ret;
+}
+
+int snd_intel_dsp_driver_probe(struct pci_dev *pci)
+{
+ if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
+ return dsp_driver;
+
+ /* Intel vendor only */
+ if (snd_BUG_ON(pci->vendor != 0x8086))
+ return SND_INTEL_DSP_DRIVER_ANY;
+
+ /*
+ * detect DSP by checking class/subclass/prog-id information
+ * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
+ * class=04 subclass 01 prog-if 00: DSP is present
+ * (and may be required e.g. for DMIC or SSP support)
+ * class=04 subclass 03 prog-if 80: use DSP or legacy mode
+ */
+ if (pci->class == 0x040300)
+ return SND_INTEL_DSP_DRIVER_NODSP;
+ if (pci->class != 0x040100 && pci->class != 0x040380) {
+ dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDA legacy driver\n", pci->class);
+ return SND_INTEL_DSP_DRIVER_LEGACY;
+ }
+
+ dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
+
+ /* DMIC check for Skylake+ */
+ if (snd_intel_dsp_check_dmic(pci)) {
+ dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
+ return SND_INTEL_DSP_DRIVER_SOF;
+ }
+
+ return SND_INTEL_DSP_DRIVER_ANY;
+}
+
+EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel DSP config driver");
diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c
index daede96f28ee..097ff6c10099 100644
--- a/sound/hda/intel-nhlt.c
+++ b/sound/hda/intel-nhlt.c
@@ -102,6 +102,3 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
return dmic_geo;
}
EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel NHLT driver");
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index dae47a45b2b8..bd48335d09d7 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -12,7 +12,7 @@ config SND_HDA_INTEL
tristate "HD Audio PCI"
depends on SND_PCI
select SND_HDA
- select SND_INTEL_NHLT if ACPI
+ select SND_INTEL_DSP_CONFIG
help
Say Y here to include support for Intel "High Definition
Audio" (Azalia) and its compatible devices.
@@ -23,15 +23,6 @@ config SND_HDA_INTEL
To compile this driver as a module, choose M here: the module
will be called snd-hda-intel.
-config SND_HDA_INTEL_DETECT_DMIC
- bool "DMIC detection and probe abort"
- depends on SND_HDA_INTEL
- help
- Say Y to detect digital microphones on SKL+ devices. DMICs
- cannot be handled by the HDaudio legacy driver and are
- currently only supported by the SOF driver.
- If unsure say N.
-
config SND_HDA_TEGRA
tristate "NVIDIA Tegra HD Audio"
depends on ARCH_TEGRA
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 240f4ca76391..c76c2deea47c 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -46,7 +46,7 @@
#include <sound/initval.h>
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
-#include <sound/intel-nhlt.h>
+#include <sound/intel-dsp-config.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include <linux/firmware.h>
@@ -124,7 +124,7 @@ static char *patch[SNDRV_CARDS];
static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
CONFIG_SND_HDA_INPUT_BEEP_MODE};
#endif
-static bool dmic_detect = IS_ENABLED(CONFIG_SND_HDA_INTEL_DETECT_DMIC);
+static bool no_dsp_driver;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -159,8 +159,8 @@ module_param_array(beep_mode, bool, NULL, 0444);
MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
"(0=off, 1=on) (default=1).");
#endif
-module_param(dmic_detect, bool, 0444);
-MODULE_PARM_DESC(dmic_detect, "DMIC detect on SKL+ platforms");
+module_param(no_dsp_driver, bool, 0444);
+MODULE_PARM_DESC(no_dsp_driver, "Do not return from probe when another DSP driver claims device");
#ifdef CONFIG_PM
static int param_set_xint(const char *val, const struct kernel_param *kp);
@@ -2020,25 +2020,6 @@ static const struct hda_controller_ops pci_hda_ops = {
.position_check = azx_position_check,
};
-static int azx_check_dmic(struct pci_dev *pci, struct azx *chip)
-{
- struct nhlt_acpi_table *nhlt;
- int ret = 0;
-
- if (chip->driver_type == AZX_DRIVER_SKL &&
- pci->class != 0x040300) {
- nhlt = intel_nhlt_init(&pci->dev);
- if (nhlt) {
- if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) {
- ret = -ENODEV;
- dev_info(&pci->dev, "Digital mics found on Skylake+ platform, aborting probe\n");
- }
- intel_nhlt_free(nhlt);
- }
- }
- return ret;
-}
-
static int azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@@ -2056,6 +2037,17 @@ static int azx_probe(struct pci_dev *pci,
return -ENOENT;
}
+ /*
+ * stop probe if another Intel's DSP driver should be activated
+ */
+ if (!no_dsp_driver) {
+ err = snd_intel_dsp_driver_probe(pci);
+ if (err != SND_INTEL_DSP_DRIVER_ANY &&
+ err != SND_INTEL_DSP_DRIVER_NODSP &&
+ err != SND_INTEL_DSP_DRIVER_LEGACY)
+ return -ENODEV;
+ }
+
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0) {
@@ -2069,17 +2061,6 @@ static int azx_probe(struct pci_dev *pci,
card->private_data = chip;
hda = container_of(chip, struct hda_intel, chip);
- /*
- * stop probe if digital microphones detected on Skylake+ platform
- * with the DSP enabled. This is an opt-in behavior defined at build
- * time or at run-time with a module parameter
- */
- if (dmic_detect) {
- err = azx_check_dmic(pci, chip);
- if (err < 0)
- goto out_free;
- }
-
pci_set_drvdata(pci, card);
err = register_vga_switcheroo(chip);
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 01c99750212a..9ad89d56092b 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -215,7 +215,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
select SND_SOC_INTEL_SST
select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
select SND_SOC_ACPI_INTEL_MATCH
- select SND_INTEL_NHLT if ACPI
+ select SND_INTEL_DSP_CONFIG
help
If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 141dbbf975ac..58ba3e9469ba 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -27,6 +27,7 @@
#include <sound/hda_i915.h>
#include <sound/hda_codec.h>
#include <sound/intel-nhlt.h>
+#include <sound/intel-dsp-config.h>
#include "skl.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
@@ -987,22 +988,10 @@ static int skl_probe(struct pci_dev *pci,
switch (skl_pci_binding) {
case SND_SKL_PCI_BIND_AUTO:
- /*
- * detect DSP by checking class/subclass/prog-id information
- * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
- * class=04 subclass 01 prog-if 00: DSP is present
- * (and may be required e.g. for DMIC or SSP support)
- * class=04 subclass 03 prog-if 80: use DSP or legacy mode
- */
- if (pci->class == 0x040300) {
- dev_info(&pci->dev, "The DSP is not enabled on this platform, aborting probe\n");
+ err = snd_intel_dsp_driver_probe(pci);
+ if (err != SND_INTEL_DSP_DRIVER_ANY &&
+ err != SND_INTEL_DSP_DRIVER_SST)
return -ENODEV;
- }
- if (pci->class != 0x040100 && pci->class != 0x040380) {
- dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class);
- return -ENODEV;
- }
- dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
break;
case SND_SKL_PCI_BIND_LEGACY:
dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n");
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index 479ba249e219..8a5d5c0f95f2 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -286,7 +286,7 @@ config SND_SOC_SOF_HDA
tristate
select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK
select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC
- select SND_INTEL_NHLT if ACPI
+ select SND_INTEL_DSP_CONFIG
help
This option is not user-selectable but automagically handled by
'select' statements at a higher level
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index d66412a77873..3a9e0e2a150d 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
+#include <sound/intel-dsp-config.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
#include <sound/sof.h>
@@ -277,6 +278,11 @@ static int sof_pci_probe(struct pci_dev *pci,
const struct snd_sof_dsp_ops *ops;
int ret;
+ ret = snd_intel_dsp_driver_probe(pci);
+ if (ret != SND_INTEL_DSP_DRIVER_ANY &&
+ ret != SND_INTEL_DSP_DRIVER_SOF)
+ return -ENODEV;
+
dev_dbg(&pci->dev, "PCI DSP detected");
/* get ops for platform */
--
2.20.1
3
4
[alsa-devel] [PATCH 1/2] dt-bindings: sound: Convert Samsung I2S controller to dt-schema
by Maciej Falkowski 02 Oct '19
by Maciej Falkowski 02 Oct '19
02 Oct '19
Convert Samsung I2S controller to newer dt-schema format
Signed-off-by: Maciej Falkowski <m.falkowski(a)samsung.com>
---
.../devicetree/bindings/sound/samsung-i2s.txt | 84 -------------
.../bindings/sound/samsung-i2s.yaml | 119 ++++++++++++++++++
2 files changed, 119 insertions(+), 84 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/sound/samsung-i2s.txt
create mode 100644 Documentation/devicetree/bindings/sound/samsung-i2s.yaml
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
deleted file mode 100644
index a88cb00fa096..000000000000
--- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-* Samsung I2S controller
-
-Required SoC Specific Properties:
-
-- compatible : should be one of the following.
- - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
- - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
- secondary fifo, s/w reset control and internal mux for root clk src.
- - samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
- playback, stereo channel capture, secondary fifo using internal
- or external dma, s/w reset control, internal mux for root clk src
- and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
- is to allow transfer of multiple channel audio data on single data line.
- - samsung,exynos7-i2s: with all the available features of exynos5 i2s,
- exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo
- with only external dma and more no.of root clk sampling frequencies.
- - samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports
- stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with
- slightly modified bit offsets.
-
-- reg: physical base address of the controller and length of memory mapped
- region.
-- dmas: list of DMA controller phandle and DMA request line ordered pairs.
-- dma-names: identifier string for each DMA request line in the dmas property.
- These strings correspond 1:1 with the ordered pairs in dmas.
-- clocks: Handle to iis clock and RCLK source clk.
-- clock-names:
- i2s0 uses some base clocks from CMU and some are from audio subsystem internal
- clock controller. The clock names for i2s0 should be "iis", "i2s_opclk0" and
- "i2s_opclk1" as shown in the example below.
- i2s1 and i2s2 uses clocks from CMU. The clock names for i2s1 and i2s2 should
- be "iis" and "i2s_opclk0".
- "iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root
- clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2
- doesn't have any such mux.
-- #clock-cells: should be 1, this property must be present if the I2S device
- is a clock provider in terms of the common clock bindings, described in
- ../clock/clock-bindings.txt.
-- clock-output-names (deprecated): from the common clock bindings, names of
- the CDCLK I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
- "i2s_cdclk3" for the I2S0, I2S1, I2S2 devices respectively.
-
-There are following clocks available at the I2S device nodes:
- CLK_I2S_CDCLK - the CDCLK (CODECLKO) gate clock,
- CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the
- IISPSR register),
- CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in
- IISMOD register).
-
-Refer to the SoC datasheet for availability of the above clocks.
-The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
-in the IIS Multi Audio Interface.
-
-Note: Old DTs may not have the #clock-cells property and then not use the I2S
-node as a clock supplier.
-
-Optional SoC Specific Properties:
-
-- samsung,idma-addr: Internal DMA register base address of the audio
- sub system(used in secondary sound source).
-- pinctrl-0: Should specify pin control groups used for this controller.
-- pinctrl-names: Should contain only one value - "default".
-- #sound-dai-cells: should be 1.
-
-
-Example:
-
-i2s0: i2s@3830000 {
- compatible = "samsung,s5pv210-i2s";
- reg = <0x03830000 0x100>;
- dmas = <&pdma0 10
- &pdma0 9
- &pdma0 8>;
- dma-names = "tx", "rx", "tx-sec";
- clocks = <&clock_audss EXYNOS_I2S_BUS>,
- <&clock_audss EXYNOS_I2S_BUS>,
- <&clock_audss EXYNOS_SCLK_I2S>;
- clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
- #clock-cells = <1>;
- samsung,idma-addr = <0x03000000>;
- pinctrl-names = "default";
- pinctrl-0 = <&i2s0_bus>;
- #sound-dai-cells = <1>;
-};
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml
new file mode 100644
index 000000000000..59dc76035cb4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml
@@ -0,0 +1,119 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/samsung-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung SoC I2S controller
+
+maintainers:
+ - Krzysztof Kozlowski <krzk(a)kernel.org>
+ - Sangbeom Kim <sbkim73(a)samsung.com>
+ - Sylwester Nawrocki <s.nawrocki(a)samsung.com>
+
+properties:
+ compatible:
+ description: |
+ samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
+
+ samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
+ secondary fifo, s/w reset control and internal mux for root clk src.
+
+ samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
+ playback, stereo channel capture, secondary fifo using internal
+ or external dma, s/w reset control, internal mux for root clk src
+ and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
+ is to allow transfer of multiple channel audio data on single data line.
+
+ samsung,exynos7-i2s: with all the available features of exynos5 i2s.
+
+ exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo
+ with only external dma and more no.of root clk sampling frequencies.
+
+ samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports
+ stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with
+ slightly modified bit offsets.
+ enum:
+ - "samsung,s3c6410-i2s"
+ - "samsung,s5pv210-i2s"
+ - "samsung,exynos5420-i2s"
+ - "samsung,exynos7-i2s"
+ - "samsung,exynos7-i2s1"
+
+ reg:
+ maxItems: 1
+
+ dmas:
+ description: list of DMA controller phandle and DMA request line ordered pairs.
+
+ dma-names:
+ description: |
+ identifier string for each DMA request line in the dmas property.
+ These strings correspond 1:1 with the ordered pairs in dmas.
+
+ clocks:
+ minItems: 1
+ maxItems: 3
+
+ clock-names:
+ oneOf:
+ - items:
+ - const: iis
+ - items:
+ - const: iis
+ - const: i2s_opclk0
+ - items:
+ - const: iis
+ - const: i2s_opclk0
+ - const: i2s_opclk1
+ description: |
+ "iis" is the i2s bus clock.
+ For i2s1 and i2s2 - "iis", "i2s_opclk0"
+ For i2s0 - "iis", "i2s_opclk0", "i2s_opclk1"
+
+ "#clock-cells":
+ const: 1
+
+ samsung,idma-addr:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ Internal DMA register base address of the audio
+ sub system(used in secondary sound source).
+
+ pinctrl-0:
+ description: Should specify pin control groups used for this controller.
+
+ pinctrl-names:
+ const: default
+
+ "#sound-dai-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - dmas
+ - dma-names
+ - clocks
+ - clock-names
+
+examples:
+ - |
+ i2s0: i2s@3830000 {
+ compatible = "samsung,s5pv210-i2s";
+ reg = <0x03830000 0x100>;
+ dmas = <&pdma0 10
+ &pdma0 9
+ &pdma0 8>;
+ dma-names = "tx", "rx", "tx-sec";
+ clocks = <&clock_audss 0>, // EXYNOS_I2S_BUS
+ <&clock_audss 0>, // EXYNOS_I2S_BUS
+ <&clock_audss 0>; // EXYNOS_SCLK_I2S
+ clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+ #clock-cells = <1>;
+ samsung,idma-addr = <0x03000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s0_bus>;
+ #sound-dai-cells = <1>;
+ };
+
--
2.17.1
5
19
[alsa-devel] Period size setting is ignored when dmix is used
by Andrea Narciso - ART S.p.A. 02 Oct '19
by Andrea Narciso - ART S.p.A. 02 Oct '19
02 Oct '19
I would like to set different period size (or time) values for different ALSA applications, in order to optimize latency and processor load based on specific application needs.
For example, a telephony application will use a shorter period size/time than a media player application, so that low latency does not affect the quality of the call.
I found out that if dmix plugin is used in the ALSA path, period size/time settings are completely ignored and forced to default values (supposedly read from the ALSA driver of the HW card).
For example, not using dmix, period size value is correctly accepted (but of course I cannot play audio from multiple applications at the same time):
aplay -vv --period-size=4096 -D plug:hw <WAV file name>
Plug PCM: Hardware PCM card 0 'HDA Intel' device 0 subdevice 0
...
period_size : 4096
...
Adding dmix instead, I can play audio from multiple applications at the same time, but period size is ignored and I cannot therefore set different latencies for different applications:
aplay -vv --period-size=4096 -D plug:dmix <WAV file name>
Plug PCM: Hardware PCM card 0 'HDA Intel' device 0 subdevice 0
...
period_size : 1024
...
Am I missing something? Is there a way to implement mixing + different latency settings in ALSA applications, without using an audio server?
Thanks
Andrea
2
1
02 Oct '19
The ssc audio driver can call into both pdc and dma backends. With the
latest rework, the logic to do this in a safe way avoiding link errors
was removed, bringing back link errors that were fixed long ago in commit
061981ff8cc8 ("ASoC: atmel: properly select dma driver state") such as
sound/soc/atmel/atmel_ssc_dai.o: In function `atmel_ssc_set_audio':
atmel_ssc_dai.c:(.text+0xac): undefined reference to `atmel_pcm_pdc_platform_register'
Fix it this time using Makefile hacks and a comment to prevent this
from accidentally getting removed again rather than Kconfig hacks.
Fixes: 18291410557f ("ASoC: atmel: enable SOC_SSC_PDC and SOC_SSC_DMA in Kconfig")
Signed-off-by: Arnd Bergmann <arnd(a)arndb.de>
---
sound/soc/atmel/Kconfig | 4 ++--
sound/soc/atmel/Makefile | 10 ++++++++--
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index f118c229ed82..25c31bf64936 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -10,11 +10,11 @@ config SND_ATMEL_SOC
if SND_ATMEL_SOC
config SND_ATMEL_SOC_PDC
- tristate
+ bool
depends on HAS_DMA
config SND_ATMEL_SOC_DMA
- tristate
+ bool
select SND_SOC_GENERIC_DMAENGINE_PCM
config SND_ATMEL_SOC_SSC
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index 1f6890ed3738..c7d2989791be 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -6,8 +6,14 @@ snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
snd-soc-atmel-i2s-objs := atmel-i2s.o
snd-soc-mchp-i2s-mcc-objs := mchp-i2s-mcc.o
-obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
-obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
+# pdc and dma need to both be built-in if any user of
+# ssc is built-in.
+ifdef CONFIG_SND_ATMEL_SOC_PDC
+obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel-pcm-pdc.o
+endif
+ifdef CONFIG_SND_ATMEL_SOC_DMA
+obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel-pcm-dma.o
+endif
obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o
obj-$(CONFIG_SND_MCHP_SOC_I2S_MCC) += snd-soc-mchp-i2s-mcc.o
--
2.20.0
4
6
[alsa-devel] [PATCH v3 RESEND 1/3] ASoC: samsung: arndale: Simplify DAI link initialization
by Sylwester Nawrocki 02 Oct '19
by Sylwester Nawrocki 02 Oct '19
02 Oct '19
There is only one DAI link so we can drop an unnecessary loop statement.
Use card->dai_link in place of direct static arndale_rt5631_dai[] array
dereference as a prerequisite for adding support for other CODECs.
Unnecessary assignment of dai_link->codecs->name to NULL is removed.
Reviewed-by: Charles Keepax <ckeepax(a)opensource.cirrus.com>
Acked-by: Krzysztof Kozlowski <krzk(a)kernel.org>
Signed-off-by: Sylwester Nawrocki <s.nawrocki(a)samsung.com>
---
Changes since v1:
- rebased due to reordering patches in the series
---
sound/soc/samsung/arndale_rt5631.c | 42 +++++++++++++-----------------
1 file changed, 18 insertions(+), 24 deletions(-)
diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c
index fd8c6642fb0d..004c84fafad9 100644
--- a/sound/soc/samsung/arndale_rt5631.c
+++ b/sound/soc/samsung/arndale_rt5631.c
@@ -88,36 +88,30 @@ static void arndale_put_of_nodes(struct snd_soc_card *card)
static int arndale_audio_probe(struct platform_device *pdev)
{
- int n, ret;
struct device_node *np = pdev->dev.of_node;
struct snd_soc_card *card = &arndale_rt5631;
+ struct snd_soc_dai_link *dai_link;
+ int ret;
card->dev = &pdev->dev;
+ dai_link = card->dai_link;
+
+ dai_link->cpus->of_node = of_parse_phandle(np, "samsung,audio-cpu", 0);
+ if (!dai_link->cpus->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'samsung,audio-cpu' missing or invalid\n");
+ return -EINVAL;
+ }
- for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) {
- if (!arndale_rt5631_dai[n].cpus->dai_name) {
- arndale_rt5631_dai[n].cpus->of_node = of_parse_phandle(np,
- "samsung,audio-cpu", n);
-
- if (!arndale_rt5631_dai[n].cpus->of_node) {
- dev_err(&pdev->dev,
- "Property 'samsung,audio-cpu' missing or invalid\n");
- return -EINVAL;
- }
- }
- if (!arndale_rt5631_dai[n].platforms->name)
- arndale_rt5631_dai[n].platforms->of_node =
- arndale_rt5631_dai[n].cpus->of_node;
-
- arndale_rt5631_dai[n].codecs->name = NULL;
- arndale_rt5631_dai[n].codecs->of_node = of_parse_phandle(np,
- "samsung,audio-codec", n);
- if (!arndale_rt5631_dai[0].codecs->of_node) {
- dev_err(&pdev->dev,
+ if (!dai_link->platforms->name)
+ dai_link->platforms->of_node = dai_link->cpus->of_node;
+
+ dai_link->codecs->of_node = of_parse_phandle(np, "samsung,audio-codec", 0);
+ if (!dai_link->codecs->of_node) {
+ dev_err(&pdev->dev,
"Property 'samsung,audio-codec' missing or invalid\n");
- ret = -EINVAL;
- goto err_put_of_nodes;
- }
+ ret = -EINVAL;
+ goto err_put_of_nodes;
}
ret = devm_snd_soc_register_card(card->dev, card);
--
2.17.1
4
8
[alsa-devel] [PATCH v2 1/2] ASOC: Add ADAU7118 8 Channel PDM-to-I2S/TDM Converter driver
by Nuno Sá 02 Oct '19
by Nuno Sá 02 Oct '19
02 Oct '19
This patch adds support for the 8 channel PDM-to-I2S/TDM converter. The
ADAU7118 converts four stereo pulse density modulation (PDM) bitstreams
into one pulse code modulation (PCM) output stream. The source for the PDM
data can be eight microphones or other PDM sources. The PCM audio data is
output on a serial audio interface port in either inter-IC serial (I2S) or
time domain multiplexed (TDM) format.
Signed-off-by: Nuno Sá <nuno.sa(a)analog.com>
---
Changes in v2:
* Use C++ coment style on the entire comment in the .c files;
* Do not use ternery operator;
* Do not use `devm_regulator_get_optional` as the device always requires power;
* Let DAPM suspend/resume the device.
MAINTAINERS | 1 +
sound/soc/codecs/Kconfig | 28 ++
sound/soc/codecs/Makefile | 6 +
sound/soc/codecs/adau7118-hw.c | 43 +++
sound/soc/codecs/adau7118-i2c.c | 82 +++++
sound/soc/codecs/adau7118.c | 586 ++++++++++++++++++++++++++++++++
sound/soc/codecs/adau7118.h | 24 ++
7 files changed, 770 insertions(+)
create mode 100644 sound/soc/codecs/adau7118-hw.c
create mode 100644 sound/soc/codecs/adau7118-i2c.c
create mode 100644 sound/soc/codecs/adau7118.c
create mode 100644 sound/soc/codecs/adau7118.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 296de2b51c83..8ba47cac8e83 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1002,6 +1002,7 @@ F: drivers/media/i2c/adv7842*
ANALOG DEVICES INC ASOC CODEC DRIVERS
M: Lars-Peter Clausen <lars(a)metafoo.de>
+M: Nuno Sá <nuno.sa(a)analog.com>
L: alsa-devel(a)alsa-project.org (moderated for non-subscribers)
W: http://wiki.analog.com/
W: http://ez.analog.com/community/linux-device-drivers
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index bcac95785493..ae213c6392ec 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -34,6 +34,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ADAU1977_I2C if I2C
select SND_SOC_ADAU1701 if I2C
select SND_SOC_ADAU7002
+ select SND_SOC_ADAU7118_I2C if I2C
+ select SND_SOC_ADAU7118_HW
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4118 if I2C
@@ -396,6 +398,32 @@ config SND_SOC_ADAU1977_I2C
config SND_SOC_ADAU7002
tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter"
+config SND_SOC_ADAU7118
+ tristate
+
+config SND_SOC_ADAU7118_HW
+ tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - HW Mode"
+ select SND_SOC_ADAU7118
+ help
+ Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
+ Converter. In this mode, the device works in standalone mode which
+ means that there is no bus to comunicate with it. Stereo mode is not
+ supported in this mode.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-soc-adau7118-hw.
+
+config SND_SOC_ADAU7118_I2C
+ tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - I2C"
+ select SND_SOC_ADAU7118
+ select REGMAP_I2C
+ help
+ Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
+ Converter over I2C. This gives full support over the device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-soc-adau7118-i2c.
+
config SND_SOC_ADAV80X
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 73b2d5982dcb..2118407a1dd5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -22,6 +22,9 @@ snd-soc-adau1977-objs := adau1977.o
snd-soc-adau1977-spi-objs := adau1977-spi.o
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
snd-soc-adau7002-objs := adau7002.o
+snd-soc-adau7118-objs := adau7118.o
+snd-soc-adau7118-i2c-objs := adau7118-i2c.o
+snd-soc-adau7118-hw-objs := adau7118-hw.o
snd-soc-adav80x-objs := adav80x.o
snd-soc-adav801-objs := adav801.o
snd-soc-adav803-objs := adav803.o
@@ -305,6 +308,9 @@ obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
obj-$(CONFIG_SND_SOC_ADAU7002) += snd-soc-adau7002.o
+obj-$(CONFIG_SND_SOC_ADAU7118) += snd-soc-adau7118.o
+obj-$(CONFIG_SND_SOC_ADAU7118_I2C) += snd-soc-adau7118-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU7118_HW) += snd-soc-adau7118-hw.o
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c
new file mode 100644
index 000000000000..45a5d2dcc0f2
--- /dev/null
+++ b/sound/soc/codecs/adau7118-hw.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter Standalone Hw
+// driver
+//
+// Copyright 2019 Analog Devices Inc.
+
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "adau7118.h"
+
+static int adau7118_probe_hw(struct platform_device *pdev)
+{
+ return adau7118_probe(&pdev->dev, NULL, true);
+}
+
+static const struct of_device_id adau7118_of_match[] = {
+ { .compatible = "adi,adau7118" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, adau7118_of_match);
+
+static const struct platform_device_id adau7118_id[] = {
+ { .name = "adau7118" },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, adau7118_id);
+
+static struct platform_driver adau7118_driver_hw = {
+ .driver = {
+ .name = "adau7118",
+ .of_match_table = adau7118_of_match,
+ },
+ .probe = adau7118_probe_hw,
+ .id_table = adau7118_id,
+};
+module_platform_driver(adau7118_driver_hw);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa(a)analog.com>");
+MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver for standalone hw mode");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c
new file mode 100644
index 000000000000..a8211362fe82
--- /dev/null
+++ b/sound/soc/codecs/adau7118-i2c.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver over I2C
+//
+// Copyright 2019 Analog Devices Inc.
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "adau7118.h"
+
+static const struct reg_default adau7118_reg_defaults[] = {
+ { ADAU7118_REG_VENDOR_ID, 0x41 },
+ { ADAU7118_REG_DEVICE_ID1, 0x71 },
+ { ADAU7118_REG_DEVICE_ID2, 0x18 },
+ { ADAU7118_REG_REVISION_ID, 0x00 },
+ { ADAU7118_REG_ENABLES, 0x3F },
+ { ADAU7118_REG_DEC_RATIO_CLK_MAP, 0xC0 },
+ { ADAU7118_REG_HPF_CONTROL, 0xD0 },
+ { ADAU7118_REG_SPT_CTRL1, 0x41 },
+ { ADAU7118_REG_SPT_CTRL2, 0x00 },
+ { ADAU7118_REG_SPT_CX(0), 0x01 },
+ { ADAU7118_REG_SPT_CX(1), 0x11 },
+ { ADAU7118_REG_SPT_CX(2), 0x21 },
+ { ADAU7118_REG_SPT_CX(3), 0x31 },
+ { ADAU7118_REG_SPT_CX(4), 0x41 },
+ { ADAU7118_REG_SPT_CX(5), 0x51 },
+ { ADAU7118_REG_SPT_CX(6), 0x61 },
+ { ADAU7118_REG_SPT_CX(7), 0x71 },
+ { ADAU7118_REG_DRIVE_STRENGTH, 0x2a },
+ { ADAU7118_REG_RESET, 0x00 },
+};
+
+static const struct regmap_config adau7118_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_defaults = adau7118_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(adau7118_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .max_register = ADAU7118_REG_RESET,
+};
+
+static int adau7118_probe_i2c(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regmap *map;
+
+ map = devm_regmap_init_i2c(i2c, &adau7118_regmap_config);
+ if (IS_ERR(map)) {
+ dev_err(&i2c->dev, "Failed to init regmap %ld\n", PTR_ERR(map));
+ return PTR_ERR(map);
+ }
+
+ return adau7118_probe(&i2c->dev, map, false);
+}
+
+static const struct of_device_id adau7118_of_match[] = {
+ { .compatible = "adi,adau7118" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, adau7118_of_match);
+
+static const struct i2c_device_id adau7118_id[] = {
+ {"adau7118", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, adau7118_id);
+
+static struct i2c_driver adau7118_driver = {
+ .driver = {
+ .name = "adau7118",
+ .of_match_table = adau7118_of_match,
+ },
+ .probe = adau7118_probe_i2c,
+ .id_table = adau7118_id,
+};
+module_i2c_driver(adau7118_driver);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa(a)analog.com>");
+MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver over I2C");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c
new file mode 100644
index 000000000000..bf5a5d75f81a
--- /dev/null
+++ b/sound/soc/codecs/adau7118.c
@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver
+//
+// Copyright 2019 Analog Devices Inc.
+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "adau7118.h"
+
+#define ADAU7118_DEC_RATIO_MASK GENMASK(1, 0)
+#define ADAU7118_DEC_RATIO(x) FIELD_PREP(ADAU7118_DEC_RATIO_MASK, x)
+#define ADAU7118_CLK_MAP_MASK GENMASK(7, 4)
+#define ADAU7118_SLOT_WIDTH_MASK GENMASK(5, 4)
+#define ADAU7118_SLOT_WIDTH(x) FIELD_PREP(ADAU7118_SLOT_WIDTH_MASK, x)
+#define ADAU7118_TRISTATE_MASK BIT(6)
+#define ADAU7118_TRISTATE(x) FIELD_PREP(ADAU7118_TRISTATE_MASK, x)
+#define ADAU7118_DATA_FMT_MASK GENMASK(3, 1)
+#define ADAU7118_DATA_FMT(x) FIELD_PREP(ADAU7118_DATA_FMT_MASK, x)
+#define ADAU7118_SAI_MODE_MASK BIT(0)
+#define ADAU7118_SAI_MODE(x) FIELD_PREP(ADAU7118_SAI_MODE_MASK, x)
+#define ADAU7118_LRCLK_BCLK_POL_MASK GENMASK(1, 0)
+#define ADAU7118_LRCLK_BCLK_POL(x) \
+ FIELD_PREP(ADAU7118_LRCLK_BCLK_POL_MASK, x)
+#define ADAU7118_SPT_SLOT_MASK GENMASK(7, 4)
+#define ADAU7118_SPT_SLOT(x) FIELD_PREP(ADAU7118_SPT_SLOT_MASK, x)
+#define ADAU7118_FULL_SOFT_R_MASK BIT(1)
+#define ADAU7118_FULL_SOFT_R(x) FIELD_PREP(ADAU7118_FULL_SOFT_R_MASK, x)
+
+struct adau7118_data {
+ struct regmap *map;
+ struct device *dev;
+ struct regulator *iovdd;
+ struct regulator *dvdd;
+ u32 slot_width;
+ u32 slots;
+ bool hw_mode;
+ bool right_j;
+};
+
+/* Input Enable */
+static const struct snd_kcontrol_new adau7118_dapm_pdm_control[4] = {
+ SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 0, 1, 0),
+ SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 1, 1, 0),
+ SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 2, 1, 0),
+ SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 3, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget adau7118_widgets_sw[] = {
+ /* Input Enable Switches */
+ SND_SOC_DAPM_SWITCH("PDM0", SND_SOC_NOPM, 0, 0,
+ &adau7118_dapm_pdm_control[0]),
+ SND_SOC_DAPM_SWITCH("PDM1", SND_SOC_NOPM, 0, 0,
+ &adau7118_dapm_pdm_control[1]),
+ SND_SOC_DAPM_SWITCH("PDM2", SND_SOC_NOPM, 0, 0,
+ &adau7118_dapm_pdm_control[2]),
+ SND_SOC_DAPM_SWITCH("PDM3", SND_SOC_NOPM, 0, 0,
+ &adau7118_dapm_pdm_control[3]),
+
+ /* PDM Clocks */
+ SND_SOC_DAPM_SUPPLY("PDM_CLK0", ADAU7118_REG_ENABLES, 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PDM_CLK1", ADAU7118_REG_ENABLES, 5, 0, NULL, 0),
+
+ /* Output channels */
+ SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7),
+ 0, 0),
+};
+
+static const struct snd_soc_dapm_route adau7118_routes_sw[] = {
+ { "PDM0", "Capture Switch", "PDM_DAT0" },
+ { "PDM1", "Capture Switch", "PDM_DAT1" },
+ { "PDM2", "Capture Switch", "PDM_DAT2" },
+ { "PDM3", "Capture Switch", "PDM_DAT3" },
+ { "AIF1TX1", NULL, "PDM0" },
+ { "AIF1TX2", NULL, "PDM0" },
+ { "AIF1TX3", NULL, "PDM1" },
+ { "AIF1TX4", NULL, "PDM1" },
+ { "AIF1TX5", NULL, "PDM2" },
+ { "AIF1TX6", NULL, "PDM2" },
+ { "AIF1TX7", NULL, "PDM3" },
+ { "AIF1TX8", NULL, "PDM3" },
+ { "Capture", NULL, "PDM_CLK0" },
+ { "Capture", NULL, "PDM_CLK1" },
+};
+
+static const struct snd_soc_dapm_widget adau7118_widgets_hw[] = {
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route adau7118_routes_hw[] = {
+ { "AIF1TX", NULL, "PDM_DAT0" },
+ { "AIF1TX", NULL, "PDM_DAT1" },
+ { "AIF1TX", NULL, "PDM_DAT2" },
+ { "AIF1TX", NULL, "PDM_DAT3" },
+};
+
+static const struct snd_soc_dapm_widget adau7118_widgets[] = {
+ SND_SOC_DAPM_INPUT("PDM_DAT0"),
+ SND_SOC_DAPM_INPUT("PDM_DAT1"),
+ SND_SOC_DAPM_INPUT("PDM_DAT2"),
+ SND_SOC_DAPM_INPUT("PDM_DAT3"),
+};
+
+static int adau7118_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ int chan, ret;
+
+ dev_dbg(st->dev, "Set channel map, %d", tx_num);
+
+ for (chan = 0; chan < tx_num; chan++) {
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CX(chan),
+ ADAU7118_SPT_SLOT_MASK,
+ ADAU7118_SPT_SLOT(tx_slot[chan]));
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ int ret = 0;
+ u32 regval;
+
+ dev_dbg(st->dev, "Set format, fmt:%d\n", fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_DATA_FMT_MASK,
+ ADAU7118_DATA_FMT(0));
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_DATA_FMT_MASK,
+ ADAU7118_DATA_FMT(1));
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ st->right_j = true;
+ break;
+ default:
+ dev_err(st->dev, "Invalid format %d",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ regval = ADAU7118_LRCLK_BCLK_POL(0);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ regval = ADAU7118_LRCLK_BCLK_POL(2);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ regval = ADAU7118_LRCLK_BCLK_POL(1);
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ regval = ADAU7118_LRCLK_BCLK_POL(3);
+ break;
+ default:
+ dev_err(st->dev, "Invalid Inv mask %d",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL2,
+ ADAU7118_LRCLK_BCLK_POL_MASK,
+ regval);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ int ret;
+
+ dev_dbg(st->dev, "Set tristate, %d\n", tristate);
+
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_TRISTATE_MASK,
+ ADAU7118_TRISTATE(tristate));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots,
+ int slot_width)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ int ret = 0;
+ u32 regval;
+
+ dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width);
+
+ switch (slot_width) {
+ case 32:
+ regval = ADAU7118_SLOT_WIDTH(0);
+ break;
+ case 24:
+ regval = ADAU7118_SLOT_WIDTH(2);
+ break;
+ case 16:
+ regval = ADAU7118_SLOT_WIDTH(1);
+ break;
+ default:
+ dev_err(st->dev, "Invalid slot width:%d\n", slot_width);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_SLOT_WIDTH_MASK, regval);
+ if (ret < 0)
+ return ret;
+
+ st->slot_width = slot_width;
+ st->slots = slots;
+
+ return 0;
+}
+
+static int adau7118_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ u32 data_width = params_width(params), slots_width;
+ int ret;
+ u32 regval;
+
+ if (!st->slots) {
+ /* set stereo mode */
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_SAI_MODE_MASK,
+ ADAU7118_SAI_MODE(0));
+ if (ret < 0)
+ return ret;
+
+ slots_width = 32;
+ } else {
+ slots_width = st->slot_width;
+ }
+
+ if (data_width > slots_width) {
+ dev_err(st->dev, "Invalid data_width:%d, slots_width:%d",
+ data_width, slots_width);
+ return -EINVAL;
+ }
+
+ if (st->right_j) {
+ switch (slots_width - data_width) {
+ case 8:
+ /* delay bclck by 8 */
+ regval = ADAU7118_DATA_FMT(2);
+ break;
+ case 12:
+ /* delay bclck by 12 */
+ regval = ADAU7118_DATA_FMT(3);
+ break;
+ case 16:
+ /* delay bclck by 16 */
+ regval = ADAU7118_DATA_FMT(4);
+ break;
+ default:
+ dev_err(st->dev,
+ "Cannot set right_j setting, slot_w:%d, data_w:%d\n",
+ slots_width, data_width);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_DATA_FMT_MASK,
+ regval);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adau7118_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct adau7118_data *st = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(st->dev, "Set bias level %d\n", level);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_component_get_bias_level(component) ==
+ SND_SOC_BIAS_OFF) {
+ /* power on */
+ ret = regulator_enable(st->iovdd);
+ if (ret)
+ return ret;
+
+ /* there's no timing constraints before enabling dvdd */
+ ret = regulator_enable(st->dvdd);
+ if (ret) {
+ regulator_disable(st->iovdd);
+ return ret;
+ }
+
+ if (st->hw_mode)
+ return 0;
+
+ regcache_cache_only(st->map, false);
+ /* sync cache */
+ ret = snd_soc_component_cache_sync(component);
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* power off */
+ ret = regulator_disable(st->dvdd);
+ if (ret)
+ return ret;
+
+ ret = regulator_disable(st->iovdd);
+ if (ret)
+ return ret;
+
+ if (st->hw_mode)
+ return 0;
+
+ /* cache only */
+ regcache_mark_dirty(st->map);
+ regcache_cache_only(st->map, true);
+
+ break;
+ }
+
+ return ret;
+}
+
+static int adau7118_component_probe(struct snd_soc_component *component)
+{
+ struct adau7118_data *st = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ int ret = 0;
+
+ if (st->hw_mode) {
+ ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw,
+ ARRAY_SIZE(adau7118_widgets_hw));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw,
+ ARRAY_SIZE(adau7118_routes_hw));
+ } else {
+ snd_soc_component_init_regmap(component, st->map);
+ ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw,
+ ARRAY_SIZE(adau7118_widgets_sw));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw,
+ ARRAY_SIZE(adau7118_routes_sw));
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_dai_ops adau7118_ops = {
+ .hw_params = adau7118_hw_params,
+ .set_channel_map = adau7118_set_channel_map,
+ .set_fmt = adau7118_set_fmt,
+ .set_tdm_slot = adau7118_set_tdm_slot,
+ .set_tristate = adau7118_set_tristate,
+};
+
+static struct snd_soc_dai_driver adau7118_dai = {
+ .name = "adau7118-hifi-capture",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 4000,
+ .rate_max = 192000,
+ .sig_bits = 24,
+ },
+};
+
+static const struct snd_soc_component_driver adau7118_component_driver = {
+ .probe = adau7118_component_probe,
+ .set_bias_level = adau7118_set_bias_level,
+ .dapm_widgets = adau7118_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(adau7118_widgets),
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static void adau7118_regulator_disable(void *data)
+{
+ struct adau7118_data *st = data;
+ int ret;
+ /*
+ * If we fail to disable DVDD, don't bother in trying IOVDD. We
+ * actually don't want to be left in the situation where DVDD
+ * is enabled and IOVDD is disabled.
+ */
+ ret = regulator_disable(st->dvdd);
+ if (ret)
+ return;
+
+ regulator_disable(st->iovdd);
+}
+
+static int adau7118_regulator_setup(struct adau7118_data *st)
+{
+ st->iovdd = devm_regulator_get(st->dev, "IOVDD");
+ if (IS_ERR(st->iovdd)) {
+ dev_err(st->dev, "Could not get iovdd: %ld\n",
+ PTR_ERR(st->iovdd));
+ return PTR_ERR(st->iovdd);
+ }
+
+ st->dvdd = devm_regulator_get(st->dev, "DVDD");
+ if (IS_ERR(st->dvdd)) {
+ dev_err(st->dev, "Could not get dvdd: %ld\n",
+ PTR_ERR(st->dvdd));
+ return PTR_ERR(st->dvdd);
+ }
+ /* just assume the device is in reset */
+ if (!st->hw_mode) {
+ regcache_mark_dirty(st->map);
+ regcache_cache_only(st->map, true);
+ }
+
+ return devm_add_action_or_reset(st->dev, adau7118_regulator_disable,
+ st);
+}
+
+static int adau7118_parset_dt(const struct adau7118_data *st)
+{
+ int ret;
+ u32 dec_ratio = 0;
+ /* 4 inputs */
+ u32 clk_map[4], regval;
+
+ if (st->hw_mode)
+ return 0;
+
+ ret = device_property_read_u32(st->dev, "adi,decimation-ratio",
+ &dec_ratio);
+ if (!ret) {
+ switch (dec_ratio) {
+ case 64:
+ regval = ADAU7118_DEC_RATIO(0);
+ break;
+ case 32:
+ regval = ADAU7118_DEC_RATIO(1);
+ break;
+ case 16:
+ regval = ADAU7118_DEC_RATIO(2);
+ break;
+ default:
+ dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(st->map,
+ ADAU7118_REG_DEC_RATIO_CLK_MAP,
+ ADAU7118_DEC_RATIO_MASK, regval);
+ if (ret)
+ return ret;
+ }
+
+ ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map",
+ clk_map, ARRAY_SIZE(clk_map));
+ if (!ret) {
+ int pdm;
+ u32 _clk_map = 0;
+
+ for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++)
+ _clk_map |= (clk_map[pdm] << (pdm + 4));
+
+ ret = regmap_update_bits(st->map,
+ ADAU7118_REG_DEC_RATIO_CLK_MAP,
+ ADAU7118_CLK_MAP_MASK, _clk_map);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode)
+{
+ struct adau7118_data *st;
+ int ret;
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->dev = dev;
+ st->hw_mode = hw_mode;
+ dev_set_drvdata(dev, st);
+
+ if (!hw_mode) {
+ st->map = map;
+ adau7118_dai.ops = &adau7118_ops;
+ /*
+ * Perform a full soft reset. This will set all register's
+ * with their reset values.
+ */
+ ret = regmap_update_bits(map, ADAU7118_REG_RESET,
+ ADAU7118_FULL_SOFT_R_MASK,
+ ADAU7118_FULL_SOFT_R(1));
+ if (ret)
+ return ret;
+ }
+
+ ret = adau7118_parset_dt(st);
+ if (ret)
+ return ret;
+
+ ret = adau7118_regulator_setup(st);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_component(dev,
+ &adau7118_component_driver,
+ &adau7118_dai, 1);
+}
+EXPORT_SYMBOL_GPL(adau7118_probe);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa(a)analog.com>");
+MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau7118.h b/sound/soc/codecs/adau7118.h
new file mode 100644
index 000000000000..c65679a4dff1
--- /dev/null
+++ b/sound/soc/codecs/adau7118.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_ADAU7118_H
+#define _LINUX_ADAU7118_H
+
+struct regmap;
+struct device;
+
+/* register map */
+#define ADAU7118_REG_VENDOR_ID 0x00
+#define ADAU7118_REG_DEVICE_ID1 0x01
+#define ADAU7118_REG_DEVICE_ID2 0x02
+#define ADAU7118_REG_REVISION_ID 0x03
+#define ADAU7118_REG_ENABLES 0x04
+#define ADAU7118_REG_DEC_RATIO_CLK_MAP 0x05
+#define ADAU7118_REG_HPF_CONTROL 0x06
+#define ADAU7118_REG_SPT_CTRL1 0x07
+#define ADAU7118_REG_SPT_CTRL2 0x08
+#define ADAU7118_REG_SPT_CX(num) (0x09 + (num))
+#define ADAU7118_REG_DRIVE_STRENGTH 0x11
+#define ADAU7118_REG_RESET 0x12
+
+int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode);
+
+#endif
--
2.23.0
1
1
[alsa-devel] [PATCH 1/2] ASOC: Add ADAU7118 8 Channel PDM-to-I2S/TDM Converter driver
by Nuno Sá 02 Oct '19
by Nuno Sá 02 Oct '19
02 Oct '19
This patch adds support for the 8 channel PDM-to-I2S/TDM converter. The
ADAU7118 converts four stereo pulse density modulation (PDM) bitstreams
into one pulse code modulation (PCM) output stream. The source for the PDM
data can be eight microphones or other PDM sources. The PCM audio data is
output on a serial audio interface port in either inter-IC serial (I2S) or
time domain multiplexed (TDM) format.
Signed-off-by: Nuno Sá <nuno.sa(a)analog.com>
---
MAINTAINERS | 1 +
sound/soc/codecs/Kconfig | 28 ++
sound/soc/codecs/Makefile | 6 +
sound/soc/codecs/adau7118-hw.c | 43 +++
sound/soc/codecs/adau7118-i2c.c | 82 +++++
sound/soc/codecs/adau7118.c | 621 ++++++++++++++++++++++++++++++++
sound/soc/codecs/adau7118.h | 24 ++
7 files changed, 805 insertions(+)
create mode 100644 sound/soc/codecs/adau7118-hw.c
create mode 100644 sound/soc/codecs/adau7118-i2c.c
create mode 100644 sound/soc/codecs/adau7118.c
create mode 100644 sound/soc/codecs/adau7118.h
diff --git a/MAINTAINERS b/MAINTAINERS
index a50e97a63bc8..77c920559d82 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -985,6 +985,7 @@ F: drivers/media/i2c/adv7842*
ANALOG DEVICES INC ASOC CODEC DRIVERS
M: Lars-Peter Clausen <lars(a)metafoo.de>
+M: Nuno Sá <nuno.sa(a)analog.com>
L: alsa-devel(a)alsa-project.org (moderated for non-subscribers)
W: http://wiki.analog.com/
W: http://ez.analog.com/community/linux-device-drivers
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9f89a5346299..006b0686776c 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -34,6 +34,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ADAU1977_I2C if I2C
select SND_SOC_ADAU1701 if I2C
select SND_SOC_ADAU7002
+ select SND_SOC_ADAU7118_I2C if I2C
+ select SND_SOC_ADAU7118_HW
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4118 if I2C
@@ -392,6 +394,32 @@ config SND_SOC_ADAU1977_I2C
config SND_SOC_ADAU7002
tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter"
+config SND_SOC_ADAU7118
+ tristate
+
+config SND_SOC_ADAU7118_HW
+ tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - HW Mode"
+ select SND_SOC_ADAU7118
+ help
+ Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
+ Converter. In this mode, the device works in standalone mode which
+ means that there is no bus to comunicate with it. Stereo mode is not
+ supported in this mode.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-soc-adau7118-hw.
+
+config SND_SOC_ADAU7118_I2C
+ tristate "Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM Converter - I2C"
+ select SND_SOC_ADAU7118
+ select REGMAP_I2C
+ help
+ Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
+ Converter over I2C. This gives full support over the device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-soc-adau7118-i2c.
+
config SND_SOC_ADAV80X
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 5b4bb8cf4325..974dc1eda797 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -22,6 +22,9 @@ snd-soc-adau1977-objs := adau1977.o
snd-soc-adau1977-spi-objs := adau1977-spi.o
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
snd-soc-adau7002-objs := adau7002.o
+snd-soc-adau7118-objs := adau7118.o
+snd-soc-adau7118-i2c-objs := adau7118-i2c.o
+snd-soc-adau7118-hw-objs := adau7118-hw.o
snd-soc-adav80x-objs := adav80x.o
snd-soc-adav801-objs := adav801.o
snd-soc-adav803-objs := adav803.o
@@ -301,6 +304,9 @@ obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
obj-$(CONFIG_SND_SOC_ADAU7002) += snd-soc-adau7002.o
+obj-$(CONFIG_SND_SOC_ADAU7118) += snd-soc-adau7118.o
+obj-$(CONFIG_SND_SOC_ADAU7118_I2C) += snd-soc-adau7118-i2c.o
+obj-$(CONFIG_SND_SOC_ADAU7118_HW) += snd-soc-adau7118-hw.o
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c
new file mode 100644
index 000000000000..499dd48ea01b
--- /dev/null
+++ b/sound/soc/codecs/adau7118-hw.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter Standalone Hw
+ * driver
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "adau7118.h"
+
+static int adau7118_probe_hw(struct platform_device *pdev)
+{
+ return adau7118_probe(&pdev->dev, NULL, true);
+}
+
+static const struct of_device_id adau7118_of_match[] = {
+ { .compatible = "adi,adau7118" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, adau7118_of_match);
+
+static const struct platform_device_id adau7118_id[] = {
+ { .name = "adau7118" },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, adau7118_id);
+
+static struct platform_driver adau7118_driver_hw = {
+ .driver = {
+ .name = "adau7118",
+ .of_match_table = adau7118_of_match,
+ },
+ .probe = adau7118_probe_hw,
+ .id_table = adau7118_id,
+};
+module_platform_driver(adau7118_driver_hw);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa(a)analog.com>");
+MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver for standalone hw mode");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c
new file mode 100644
index 000000000000..1fd0b0287699
--- /dev/null
+++ b/sound/soc/codecs/adau7118-i2c.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver over I2C
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "adau7118.h"
+
+static const struct reg_default adau7118_reg_defaults[] = {
+ { ADAU7118_REG_VENDOR_ID, 0x41 },
+ { ADAU7118_REG_DEVICE_ID1, 0x71 },
+ { ADAU7118_REG_DEVICE_ID2, 0x18 },
+ { ADAU7118_REG_REVISION_ID, 0x00 },
+ { ADAU7118_REG_ENABLES, 0x3F },
+ { ADAU7118_REG_DEC_RATIO_CLK_MAP, 0xC0 },
+ { ADAU7118_REG_HPF_CONTROL, 0xD0 },
+ { ADAU7118_REG_SPT_CTRL1, 0x41 },
+ { ADAU7118_REG_SPT_CTRL2, 0x00 },
+ { ADAU7118_REG_SPT_CX(0), 0x01 },
+ { ADAU7118_REG_SPT_CX(1), 0x11 },
+ { ADAU7118_REG_SPT_CX(2), 0x21 },
+ { ADAU7118_REG_SPT_CX(3), 0x31 },
+ { ADAU7118_REG_SPT_CX(4), 0x41 },
+ { ADAU7118_REG_SPT_CX(5), 0x51 },
+ { ADAU7118_REG_SPT_CX(6), 0x61 },
+ { ADAU7118_REG_SPT_CX(7), 0x71 },
+ { ADAU7118_REG_DRIVE_STRENGTH, 0x2a },
+ { ADAU7118_REG_RESET, 0x00 },
+};
+
+static const struct regmap_config adau7118_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_defaults = adau7118_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(adau7118_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .max_register = ADAU7118_REG_RESET,
+};
+
+static int adau7118_probe_i2c(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regmap *map;
+
+ map = devm_regmap_init_i2c(i2c, &adau7118_regmap_config);
+ if (IS_ERR(map)) {
+ dev_err(&i2c->dev, "Failed to init regmap %ld\n", PTR_ERR(map));
+ return PTR_ERR(map);
+ }
+
+ return adau7118_probe(&i2c->dev, map, false);
+}
+
+static const struct of_device_id adau7118_of_match[] = {
+ { .compatible = "adi,adau7118" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, adau7118_of_match);
+
+static const struct i2c_device_id adau7118_id[] = {
+ {"adau7118", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, adau7118_id);
+
+static struct i2c_driver adau7118_driver = {
+ .driver = {
+ .name = "adau7118",
+ .of_match_table = adau7118_of_match,
+ },
+ .probe = adau7118_probe_i2c,
+ .id_table = adau7118_id,
+};
+module_i2c_driver(adau7118_driver);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa(a)analog.com>");
+MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver over I2C");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c
new file mode 100644
index 000000000000..d6b90e31042f
--- /dev/null
+++ b/sound/soc/codecs/adau7118.c
@@ -0,0 +1,621 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "adau7118.h"
+
+#define ADAU7118_DEC_RATIO_MASK GENMASK(1, 0)
+#define ADAU7118_DEC_RATIO(x) FIELD_PREP(ADAU7118_DEC_RATIO_MASK, x)
+#define ADAU7118_CLK_MAP_MASK GENMASK(7, 4)
+#define ADAU7118_SLOT_WIDTH_MASK GENMASK(5, 4)
+#define ADAU7118_SLOT_WIDTH(x) FIELD_PREP(ADAU7118_SLOT_WIDTH_MASK, x)
+#define ADAU7118_TRISTATE_MASK BIT(6)
+#define ADAU7118_TRISTATE(x) FIELD_PREP(ADAU7118_TRISTATE_MASK, x)
+#define ADAU7118_DATA_FMT_MASK GENMASK(3, 1)
+#define ADAU7118_DATA_FMT(x) FIELD_PREP(ADAU7118_DATA_FMT_MASK, x)
+#define ADAU7118_SAI_MODE_MASK BIT(0)
+#define ADAU7118_SAI_MODE(x) FIELD_PREP(ADAU7118_SAI_MODE_MASK, x)
+#define ADAU7118_LRCLK_BCLK_POL_MASK GENMASK(1, 0)
+#define ADAU7118_LRCLK_BCLK_POL(x) \
+ FIELD_PREP(ADAU7118_LRCLK_BCLK_POL_MASK, x)
+#define ADAU7118_SPT_SLOT_MASK GENMASK(7, 4)
+#define ADAU7118_SPT_SLOT(x) FIELD_PREP(ADAU7118_SPT_SLOT_MASK, x)
+#define ADAU7118_FULL_SOFT_R_MASK BIT(1)
+#define ADAU7118_FULL_SOFT_R(x) FIELD_PREP(ADAU7118_FULL_SOFT_R_MASK, x)
+
+struct adau7118_data {
+ struct regmap *map;
+ struct device *dev;
+ struct regulator *iovdd;
+ struct regulator *dvdd;
+ u32 slot_width;
+ u32 slots;
+ bool hw_mode;
+ bool right_j;
+};
+
+/* Input Enable */
+static const struct snd_kcontrol_new adau7118_dapm_pdm_control[4] = {
+ SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 0, 1, 0),
+ SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 1, 1, 0),
+ SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 2, 1, 0),
+ SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 3, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget adau7118_widgets_sw[] = {
+ /* Input Enable Switches */
+ SND_SOC_DAPM_SWITCH("PDM0", SND_SOC_NOPM, 0, 0,
+ &adau7118_dapm_pdm_control[0]),
+ SND_SOC_DAPM_SWITCH("PDM1", SND_SOC_NOPM, 0, 0,
+ &adau7118_dapm_pdm_control[1]),
+ SND_SOC_DAPM_SWITCH("PDM2", SND_SOC_NOPM, 0, 0,
+ &adau7118_dapm_pdm_control[2]),
+ SND_SOC_DAPM_SWITCH("PDM3", SND_SOC_NOPM, 0, 0,
+ &adau7118_dapm_pdm_control[3]),
+
+ /* PDM Clocks */
+ SND_SOC_DAPM_SUPPLY("PDM_CLK0", ADAU7118_REG_ENABLES, 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PDM_CLK1", ADAU7118_REG_ENABLES, 5, 0, NULL, 0),
+
+ /* Output channels */
+ SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6),
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7),
+ 0, 0),
+};
+
+static const struct snd_soc_dapm_route adau7118_routes_sw[] = {
+ { "PDM0", "Capture Switch", "PDM_DAT0" },
+ { "PDM1", "Capture Switch", "PDM_DAT1" },
+ { "PDM2", "Capture Switch", "PDM_DAT2" },
+ { "PDM3", "Capture Switch", "PDM_DAT3" },
+ { "AIF1TX1", NULL, "PDM0" },
+ { "AIF1TX2", NULL, "PDM0" },
+ { "AIF1TX3", NULL, "PDM1" },
+ { "AIF1TX4", NULL, "PDM1" },
+ { "AIF1TX5", NULL, "PDM2" },
+ { "AIF1TX6", NULL, "PDM2" },
+ { "AIF1TX7", NULL, "PDM3" },
+ { "AIF1TX8", NULL, "PDM3" },
+ { "Capture", NULL, "PDM_CLK0" },
+ { "Capture", NULL, "PDM_CLK1" },
+};
+
+static const struct snd_soc_dapm_widget adau7118_widgets_hw[] = {
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route adau7118_routes_hw[] = {
+ { "AIF1TX", NULL, "PDM_DAT0" },
+ { "AIF1TX", NULL, "PDM_DAT1" },
+ { "AIF1TX", NULL, "PDM_DAT2" },
+ { "AIF1TX", NULL, "PDM_DAT3" },
+};
+
+static const struct snd_soc_dapm_widget adau7118_widgets[] = {
+ SND_SOC_DAPM_INPUT("PDM_DAT0"),
+ SND_SOC_DAPM_INPUT("PDM_DAT1"),
+ SND_SOC_DAPM_INPUT("PDM_DAT2"),
+ SND_SOC_DAPM_INPUT("PDM_DAT3"),
+};
+
+static int adau7118_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ int chan, ret;
+
+ dev_dbg(st->dev, "Set channel map, %d", tx_num);
+
+ for (chan = 0; chan < tx_num; chan++) {
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CX(chan),
+ ADAU7118_SPT_SLOT_MASK,
+ ADAU7118_SPT_SLOT(tx_slot[chan]));
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ int ret = 0;
+ u32 regval;
+
+ dev_dbg(st->dev, "Set format, fmt:%d\n", fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_DATA_FMT_MASK,
+ ADAU7118_DATA_FMT(0));
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_DATA_FMT_MASK,
+ ADAU7118_DATA_FMT(1));
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ st->right_j = true;
+ break;
+ default:
+ dev_err(st->dev, "Invalid format %d",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ regval = ADAU7118_LRCLK_BCLK_POL(0);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ regval = ADAU7118_LRCLK_BCLK_POL(2);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ regval = ADAU7118_LRCLK_BCLK_POL(1);
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ regval = ADAU7118_LRCLK_BCLK_POL(3);
+ break;
+ default:
+ dev_err(st->dev, "Invalid Inv mask %d",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL2,
+ ADAU7118_LRCLK_BCLK_POL_MASK,
+ regval);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ int ret;
+
+ dev_dbg(st->dev, "Set tristate, %d\n", tristate);
+
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_TRISTATE_MASK,
+ ADAU7118_TRISTATE(tristate));
+
+ return ret < 0 ? ret : 0;
+}
+
+static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots,
+ int slot_width)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ int ret = 0;
+ u32 regval;
+
+ dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width);
+
+ switch (slot_width) {
+ case 32:
+ regval = ADAU7118_SLOT_WIDTH(0);
+ break;
+ case 24:
+ regval = ADAU7118_SLOT_WIDTH(2);
+ break;
+ case 16:
+ regval = ADAU7118_SLOT_WIDTH(1);
+ break;
+ default:
+ dev_err(st->dev, "Invalid slot width:%d\n", slot_width);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_SLOT_WIDTH_MASK, regval);
+ if (ret < 0)
+ return ret;
+
+ st->slot_width = slot_width;
+ st->slots = slots;
+
+ return 0;
+}
+
+static int adau7118_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct adau7118_data *st =
+ snd_soc_component_get_drvdata(dai->component);
+ u32 data_width = params_width(params), slots_width;
+ int ret;
+ u32 regval;
+
+ if (!st->slots) {
+ /* set stereo mode */
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_SAI_MODE_MASK,
+ ADAU7118_SAI_MODE(0));
+ if (ret < 0)
+ return ret;
+
+ slots_width = 32;
+ } else {
+ slots_width = st->slot_width;
+ }
+
+ if (data_width > slots_width) {
+ dev_err(st->dev, "Invalid data_width:%d, slots_width:%d",
+ data_width, slots_width);
+ return -EINVAL;
+ }
+
+ if (st->right_j) {
+ switch (slots_width - data_width) {
+ case 8:
+ /* delay bclck by 8 */
+ regval = ADAU7118_DATA_FMT(2);
+ break;
+ case 12:
+ /* delay bclck by 12 */
+ regval = ADAU7118_DATA_FMT(3);
+ break;
+ case 16:
+ /* delay bclck by 16 */
+ regval = ADAU7118_DATA_FMT(4);
+ break;
+ default:
+ dev_err(st->dev,
+ "Cannot set right_j setting, slot_w:%d, data_w:%d\n",
+ slots_width, data_width);
+ return -EINVAL;
+ }
+
+ ret = snd_soc_component_update_bits(dai->component,
+ ADAU7118_REG_SPT_CTRL1,
+ ADAU7118_DATA_FMT_MASK,
+ regval);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adau7118_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct adau7118_data *st = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ dev_dbg(st->dev, "Set bias level %d\n", level);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (snd_soc_component_get_bias_level(component) ==
+ SND_SOC_BIAS_OFF) {
+ if (!st->iovdd)
+ return 0;
+
+ /* power on */
+ ret = regulator_enable(st->iovdd);
+ if (ret)
+ return ret;
+
+ /* there's no timing constraints before enabling dvdd */
+ ret = regulator_enable(st->dvdd);
+ if (ret) {
+ regulator_disable(st->iovdd);
+ return ret;
+ }
+
+ if (st->hw_mode)
+ return 0;
+
+ regcache_cache_only(st->map, false);
+ /* sync cache */
+ ret = snd_soc_component_cache_sync(component);
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* power off */
+ if (!st->iovdd)
+ return 0;
+
+ ret = regulator_disable(st->dvdd);
+ if (ret)
+ return ret;
+
+ ret = regulator_disable(st->iovdd);
+ if (ret)
+ return ret;
+
+ if (st->hw_mode)
+ return 0;
+
+ /* cache only */
+ regcache_mark_dirty(st->map);
+ regcache_cache_only(st->map, true);
+
+ break;
+ }
+
+ return ret;
+}
+
+static int adau7118_component_probe(struct snd_soc_component *component)
+{
+ struct adau7118_data *st = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ int ret = 0;
+
+ if (st->hw_mode) {
+ ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw,
+ ARRAY_SIZE(adau7118_widgets_hw));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw,
+ ARRAY_SIZE(adau7118_routes_hw));
+ } else {
+ snd_soc_component_init_regmap(component, st->map);
+ ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw,
+ ARRAY_SIZE(adau7118_widgets_sw));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw,
+ ARRAY_SIZE(adau7118_routes_sw));
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int adau7118_suspend(struct snd_soc_component *component)
+{
+ return snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
+}
+
+static int adau7118_resume(struct snd_soc_component *component)
+{
+ return snd_soc_component_force_bias_level(component,
+ SND_SOC_BIAS_STANDBY);
+}
+#else
+#define adau7118_suspend NULL
+#define adau7118_resume NULL
+#endif
+
+static const struct snd_soc_dai_ops adau7118_ops = {
+ .hw_params = adau7118_hw_params,
+ .set_channel_map = adau7118_set_channel_map,
+ .set_fmt = adau7118_set_fmt,
+ .set_tdm_slot = adau7118_set_tdm_slot,
+ .set_tristate = adau7118_set_tristate,
+};
+
+static struct snd_soc_dai_driver adau7118_dai = {
+ .name = "adau7118-hifi-capture",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 4000,
+ .rate_max = 192000,
+ .sig_bits = 24,
+ },
+};
+
+static const struct snd_soc_component_driver adau7118_component_driver = {
+ .probe = adau7118_component_probe,
+ .set_bias_level = adau7118_set_bias_level,
+ .suspend = adau7118_suspend,
+ .resume = adau7118_resume,
+ .dapm_widgets = adau7118_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(adau7118_widgets),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static void adau7118_regulator_disable(void *data)
+{
+ struct adau7118_data *st = data;
+ int ret;
+ /*
+ * If we fail to disable DVDD, don't bother in trying IOVDD. We
+ * actually don't want to be left in the situation where DVDD
+ * is enabled and IOVDD is disabled.
+ */
+ ret = regulator_disable(st->dvdd);
+ if (ret)
+ return;
+
+ regulator_disable(st->iovdd);
+}
+
+static int adau7118_regulator_setup(struct adau7118_data *st)
+{
+ int ret = 0;
+
+ st->iovdd = devm_regulator_get_optional(st->dev, "IOVDD");
+ if (!IS_ERR(st->iovdd)) {
+ /*
+ * Only get dvdd if iovdd is present. Furthermore,
+ * if iovdd is present, dvdd must also be given. The two
+ * supplies should be controlled together since dvdd should
+ * not be applied before iovdd.
+ */
+ st->dvdd = devm_regulator_get(st->dev, "DVDD");
+ if (IS_ERR(st->dvdd)) {
+ dev_err(st->dev, "Could not get dvdd: %ld\n",
+ PTR_ERR(st->dvdd));
+ return PTR_ERR(st->dvdd);
+ }
+ /* just assume the device is in reset */
+ if (!st->hw_mode) {
+ regcache_mark_dirty(st->map);
+ regcache_cache_only(st->map, true);
+ }
+
+ ret = devm_add_action_or_reset(st->dev,
+ adau7118_regulator_disable, st);
+ } else {
+ if (PTR_ERR(st->iovdd) == -ENODEV) {
+ st->iovdd = NULL;
+ } else {
+ dev_err(st->dev, "Failed to get IOVDD %ld\n",
+ PTR_ERR(st->iovdd));
+ return PTR_ERR(st->iovdd);
+ }
+ }
+
+ return ret;
+}
+
+static int adau7118_parset_dt(const struct adau7118_data *st)
+{
+ int ret;
+ u32 dec_ratio = 0;
+ /* 4 inputs */
+ u32 clk_map[4], regval;
+
+ if (st->hw_mode)
+ return 0;
+
+ ret = device_property_read_u32(st->dev, "adi,decimation-ratio",
+ &dec_ratio);
+ if (!ret) {
+ switch (dec_ratio) {
+ case 64:
+ regval = ADAU7118_DEC_RATIO(0);
+ break;
+ case 32:
+ regval = ADAU7118_DEC_RATIO(1);
+ break;
+ case 16:
+ regval = ADAU7118_DEC_RATIO(2);
+ break;
+ default:
+ dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(st->map,
+ ADAU7118_REG_DEC_RATIO_CLK_MAP,
+ ADAU7118_DEC_RATIO_MASK, regval);
+ if (ret)
+ return ret;
+ }
+
+ ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map",
+ clk_map, ARRAY_SIZE(clk_map));
+ if (!ret) {
+ int pdm;
+ u32 _clk_map = 0;
+
+ for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++)
+ _clk_map |= (clk_map[pdm] << (pdm + 4));
+
+ ret = regmap_update_bits(st->map,
+ ADAU7118_REG_DEC_RATIO_CLK_MAP,
+ ADAU7118_CLK_MAP_MASK, _clk_map);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode)
+{
+ struct adau7118_data *st;
+ int ret;
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->dev = dev;
+ st->hw_mode = hw_mode;
+ dev_set_drvdata(dev, st);
+
+ if (!hw_mode) {
+ st->map = map;
+ adau7118_dai.ops = &adau7118_ops;
+ /*
+ * Perform a full soft reset. This will set all register's
+ * with their reset values.
+ */
+ ret = regmap_update_bits(map, ADAU7118_REG_RESET,
+ ADAU7118_FULL_SOFT_R_MASK,
+ ADAU7118_FULL_SOFT_R(1));
+ if (ret)
+ return ret;
+ }
+
+ ret = adau7118_parset_dt(st);
+ if (ret)
+ return ret;
+
+ ret = adau7118_regulator_setup(st);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_component(dev,
+ &adau7118_component_driver,
+ &adau7118_dai, 1);
+}
+EXPORT_SYMBOL_GPL(adau7118_probe);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa(a)analog.com>");
+MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau7118.h b/sound/soc/codecs/adau7118.h
new file mode 100644
index 000000000000..c65679a4dff1
--- /dev/null
+++ b/sound/soc/codecs/adau7118.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_ADAU7118_H
+#define _LINUX_ADAU7118_H
+
+struct regmap;
+struct device;
+
+/* register map */
+#define ADAU7118_REG_VENDOR_ID 0x00
+#define ADAU7118_REG_DEVICE_ID1 0x01
+#define ADAU7118_REG_DEVICE_ID2 0x02
+#define ADAU7118_REG_REVISION_ID 0x03
+#define ADAU7118_REG_ENABLES 0x04
+#define ADAU7118_REG_DEC_RATIO_CLK_MAP 0x05
+#define ADAU7118_REG_HPF_CONTROL 0x06
+#define ADAU7118_REG_SPT_CTRL1 0x07
+#define ADAU7118_REG_SPT_CTRL2 0x08
+#define ADAU7118_REG_SPT_CX(num) (0x09 + (num))
+#define ADAU7118_REG_DRIVE_STRENGTH 0x11
+#define ADAU7118_REG_RESET 0x12
+
+int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode);
+
+#endif
--
2.23.0
3
8
See images in links.
1)
"http://grossmann-venter.com/visitors/ug/alsa/alsa-pulse-181vsl_unplug.png"
2) "http://grossmann-venter.com/visitors/ug/alsa/alsa-dont
recognize1818VSLpng"
1) As soon as pulseaudio is started Alsa says 1818VSL is unplugged....?
2) Clearly Presonus 1818VSL is found as lsusb output says, but alsa has
no clue about it.
How do
I get alsa to recognise 181VSL as it is found by lsusb so it is presnet
on the system.
It used to work fine but alsa just stopped working with 1818VSL recently
for no reason.
I know this is a developers group, but please at least answer where I
can get help. Alsa help is absolutely non-existing.
I also posted a bug with no response in another thread.
Thanks.
2
3
Hi Mark
Current snd_soc_component_driver is using snd_pcm_ops.
But, it is mainly for ALSA, thus, it not good much to ALSA SoC.
For example .open case (1)(2),
each callback can't know it is called for which component.
Thus, it need to use using snd_soc_rtdcom_lookup() (3).
--- ALSA SoC ---
...
if (component->driver->ops &&
component->driver->ops->open)
(1) return component->driver->ops->open(substream);
...
--- driver ---
(2) static int xxx_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
(3) struct snd_soc_component *component = snd_soc_rtdcom_lookup(..);
...
}
It works today, but, will not work in the future if we support multi
CPU/Codec/Platform, because 1 rtd might have multiple components which
have same driver name.
In other words snd_soc_rtdcom_lookup() doesn't work correctly in the future.
To solve this issue, each callback needs to be called with component.
This patch copies each snd_pcm_ops member under component driver,
and having "component" as parameter.
--- ALSA SoC ---
...
if (component->driver->open)
=> return component->driver->open(component, substream);
...
--- driver ---
=> static int xxx_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
...
}
Kuninori Morimoto (44):
ASoC: soc-core: merge snd_pcm_ops member to component driver
ASoC: soc-core: add new pcm_construct/pcm_destruct
ASoC: soc-core: add snd_soc_pcm_lib_ioctl()
ASoC: intel: sst-haswell-pcm: remove snd_pcm_ops
ASoC: intel: skl-pcm: remove snd_pcm_ops
ASoC: intel: sst-mfld-platform-pcm: remove snd_pcm_ops
ASoC: intel: sst-baytrail-pcm: remove snd_pcm_ops
ASoC: amd: acp3x-pcm-dma: remove snd_pcm_ops
ASoC: amd: acp-pcm-dma: remove snd_pcm_ops
ASoC: atmel: atmel-pcm-pdc: remove snd_pcm_ops
ASoC: au1x: dbdma2: remove snd_pcm_ops
ASoC: au1x: dma: remove snd_pcm_ops
ASoC: xtensa: xtfpga-i2s: remove snd_pcm_ops
ASoC: xilinx: xlnx_formatter_pcm: remove snd_pcm_ops
ASoC: uniphier: aio-dma: remove snd_pcm_ops
ASoC: txx9: txx9aclc: remove snd_pcm_ops
ASoC: stm: stm32_adfsdm: remove snd_pcm_ops
ASoC: sprd: sprd-pcm-dma: remove snd_pcm_ops
ASoC: sof: pcm: remove snd_pcm_ops
ASoC: sh: rsnd: remove snd_pcm_ops
ASoC: sh: fsi: remove snd_pcm_ops
ASoC: sh: dma-sh7760: remove snd_pcm_ops
ASoC: sh: siu_pcm: remove snd_pcm_ops
ASoC: samsung: idma: remove snd_pcm_ops
ASoC: qcom: lpass-platform: remove snd_pcm_ops
ASoC: qcom: q6routing: remove snd_pcm_ops
ASoC: qcom: q6asm-dai: remove snd_pcm_ops
ASoC: pxa: mmp-pcm: remove snd_pcm_ops
ASoC: pxa: remove snd_pcm_ops
ASoC: meson: remove snd_pcm_ops
ASoC: mediatek: mtk-btcvsd: remove snd_pcm_ops
ASoC: mediatek: remove snd_pcm_ops
ASoC: kirkwood: kirkwood-dma: remove snd_pcm_ops
ASoC: dwc: dwc-pcm: remove snd_pcm_ops
ASoC: rt5514-spi: remove snd_pcm_ops
ASoC: bcm: cygnus-pcm: remove snd_pcm_ops
ASoC: fsl: imx-pcm-fiq: remove snd_pcm_ops
ASoC: fsl: fsl_dma: remove snd_pcm_ops
ASoC: fsl: mpc5200_dma: remove snd_pcm_ops
ASoC: fsl: fsl_asrc_dma: remove snd_pcm_ops
ASoC: fsl: fsl_dma: don't use snd_soc_rtdcom_lookup()
ASoC: soc-generic-dmaengine-pcm: remove snd_pcm_ops
ASoC: soc-utils: remove snd_pcm_ops
ASoC: soc-component: remove snd_pcm_ops from component driver
include/sound/pxa2xx-lib.h | 26 +++++-
include/sound/soc-component.h | 41 ++++++++-
include/sound/soc.h | 5 +
sound/arm/pxa2xx-pcm-lib.c | 80 +++++++++++++---
sound/soc/amd/acp-pcm-dma.c | 63 ++++++-------
sound/soc/amd/raven/acp3x-pcm-dma.c | 54 +++++------
sound/soc/atmel/atmel-pcm-pdc.c | 48 +++++-----
sound/soc/au1x/dbdma2.c | 64 +++++++------
sound/soc/au1x/dma.c | 63 +++++++------
sound/soc/bcm/cygnus-pcm.c | 56 +++++------
sound/soc/codecs/rt5514-spi.c | 41 +++++----
sound/soc/dwc/dwc-pcm.c | 48 +++++-----
sound/soc/fsl/fsl_asrc_dma.c | 56 +++++------
sound/soc/fsl/fsl_dma.c | 53 +++++------
sound/soc/fsl/imx-pcm-fiq.c | 56 ++++++-----
sound/soc/fsl/mpc5200_dma.c | 51 ++++++-----
sound/soc/intel/atom/sst-mfld-platform-pcm.c | 30 +++---
sound/soc/intel/baytrail/sst-baytrail-pcm.c | 52 +++++------
sound/soc/intel/haswell/sst-haswell-pcm.c | 62 +++++++------
sound/soc/intel/skylake/skl-pcm.c | 67 +++++++++-----
sound/soc/kirkwood/kirkwood-dma.c | 50 +++++-----
.../soc/mediatek/common/mtk-afe-platform-driver.c | 28 +++---
.../soc/mediatek/common/mtk-afe-platform-driver.h | 10 +-
sound/soc/mediatek/common/mtk-btcvsd.c | 76 ++++++---------
sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | 11 ++-
sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 11 ++-
sound/soc/meson/axg-fifo.c | 56 +++++------
sound/soc/meson/axg-fifo.h | 20 +++-
sound/soc/meson/axg-frddr.c | 24 ++++-
sound/soc/meson/axg-toddr.c | 24 ++++-
sound/soc/pxa/mmp-pcm.c | 62 ++++++++-----
sound/soc/pxa/pxa-ssp.c | 14 ++-
sound/soc/pxa/pxa2xx-ac97.c | 14 ++-
sound/soc/pxa/pxa2xx-i2s.c | 14 ++-
sound/soc/pxa/pxa2xx-pcm.c | 14 ++-
sound/soc/qcom/lpass-platform.c | 70 +++++++-------
sound/soc/qcom/qdsp6/q6asm-dai.c | 71 +++++++-------
sound/soc/qcom/qdsp6/q6routing.c | 14 +--
sound/soc/samsung/idma.c | 58 ++++++------
sound/soc/sh/dma-sh7760.c | 46 +++++-----
sound/soc/sh/fsi.c | 31 ++++---
sound/soc/sh/rcar/core.c | 23 +++--
sound/soc/sh/siu_pcm.c | 44 +++++----
sound/soc/soc-component.c | 76 +++++++--------
sound/soc/soc-core.c | 12 +++
sound/soc/soc-generic-dmaengine-pcm.c | 102 ++++++++++-----------
sound/soc/soc-pcm.c | 11 +--
sound/soc/soc-utils.c | 11 +--
sound/soc/sof/pcm.c | 88 +++++++++---------
sound/soc/sprd/sprd-pcm-dma.c | 74 +++++++--------
sound/soc/stm/stm32_adfsdm.c | 42 +++++----
sound/soc/txx9/txx9aclc.c | 48 +++++-----
sound/soc/uniphier/aio-dma.c | 51 ++++++-----
sound/soc/xilinx/xlnx_formatter_pcm.c | 54 +++++------
sound/soc/xtensa/xtfpga-i2s.c | 30 +++---
55 files changed, 1311 insertions(+), 1089 deletions(-)
--
2.7.4
1
0