summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-09-07 12:56:00 +0100
committerMark Brown <broonie@kernel.org>2026-09-07 12:56:00 +0100
commit26f010a489d49ab4b46bb03b5ed04e985b735c91 (patch)
treef2862928c6ff88fbe4ee899417dbeb76afa1dbe3
parent0933d0760dda85aeed9979bed666e802615370b3 (diff)
parentc1e01ea35093777d59c12128d549ff5016c38cec (diff)
downloadlinux-next-26f010a489d49ab4b46bb03b5ed04e985b735c91.tar.gz
linux-next-26f010a489d49ab4b46bb03b5ed04e985b735c91.zip
Merge branch 'for-linus' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
-rw-r--r--sound/hda/core/ext/controller.c4
-rw-r--r--sound/hda/core/ext/stream.c5
-rw-r--r--sound/soc/amd/renoir/acp3x-pdm-dma.c2
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c7
-rw-r--r--sound/soc/amd/yc/acp6x-pdm-dma.c2
-rw-r--r--sound/soc/codecs/ab8500-codec.c682
-rw-r--r--sound/soc/codecs/cs35l56-sdw.c7
-rw-r--r--sound/soc/codecs/cs35l56.c71
-rw-r--r--sound/soc/codecs/cs35l56.h2
-rw-r--r--sound/soc/codecs/es8326.c19
-rw-r--r--sound/soc/codecs/es8389.c34
-rw-r--r--sound/soc/codecs/rt1318-sdw.c24
-rw-r--r--sound/soc/codecs/rt1320-sdw.c2
-rw-r--r--sound/soc/codecs/rt712-sdca.c17
-rw-r--r--sound/soc/codecs/rt721-sdca.c17
-rw-r--r--sound/soc/codecs/rt722-sdca.c16
-rw-r--r--sound/soc/codecs/rt766-sdca.c5
-rw-r--r--sound/soc/codecs/tas2783-sdw.c25
-rw-r--r--sound/soc/fsl/fsl_micfil.c21
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c17
-rw-r--r--sound/soc/intel/avs/core.c59
-rw-r--r--sound/soc/intel/avs/debugfs.c12
-rw-r--r--sound/soc/intel/avs/ipc.c6
-rw-r--r--sound/soc/intel/avs/path.c11
-rw-r--r--sound/soc/intel/avs/pcm.c34
-rw-r--r--sound/soc/intel/avs/topology.c49
-rw-r--r--sound/soc/intel/avs/topology.h5
-rw-r--r--sound/soc/intel/boards/Kconfig4
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c8
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-nvl-match.c8
-rw-r--r--sound/soc/sprd/sprd-pcm-compress.c15
-rw-r--r--sound/soc/sti/uniperif_reader.c4
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c189
-rw-r--r--sound/soc/ux500/ux500_msp_dai.h14
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.c264
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.h12
36 files changed, 877 insertions, 796 deletions
diff --git a/sound/hda/core/ext/controller.c b/sound/hda/core/ext/controller.c
index b1f1eff1d181..6d0af7e6f63c 100644
--- a/sound/hda/core/ext/controller.c
+++ b/sound/hda/core/ext/controller.c
@@ -90,8 +90,10 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
for (idx = 0; idx < link_count; idx++) {
hlink = kzalloc_obj(*hlink);
- if (!hlink)
+ if (!hlink) {
+ snd_hdac_ext_link_free_all(bus);
return -ENOMEM;
+ }
hlink->index = idx;
hlink->bus = bus;
hlink->ml_addr = bus->mlcap + AZX_ML_BASE +
diff --git a/sound/hda/core/ext/stream.c b/sound/hda/core/ext/stream.c
index 517bd151fcc3..1f96e0484660 100644
--- a/sound/hda/core/ext/stream.c
+++ b/sound/hda/core/ext/stream.c
@@ -102,8 +102,10 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
for (i = 0; i < num_stream; i++) {
struct hdac_ext_stream *hext_stream = kzalloc_obj(*hext_stream);
- if (!hext_stream)
+ if (!hext_stream) {
+ snd_hdac_ext_stream_free_all(bus);
return -ENOMEM;
+ }
tag = ++stream_tag;
snd_hdac_ext_stream_init(bus, hext_stream, idx, dir, tag);
idx++;
@@ -111,7 +113,6 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
}
return 0;
-
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all);
diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c
index e60e3821703c..3f59b753243d 100644
--- a/sound/soc/amd/renoir/acp3x-pdm-dma.c
+++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c
@@ -104,7 +104,7 @@ static void disable_pdm_interrupts(void __iomem *acp_base)
u32 ext_int_ctrl;
ext_int_ctrl = rn_readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
- ext_int_ctrl |= ~PDM_DMA_INTR_MASK;
+ ext_int_ctrl &= ~PDM_DMA_INTR_MASK;
rn_writel(ext_int_ctrl, acp_base + ACP_EXTERNAL_INTR_CNTL);
}
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index 21d7ec0e7dbf..c64c727e1034 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -892,6 +892,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "TM2423"),
}
},
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP 255R 15.6 inch G10 Notebook PC"),
+ }
+ },
{}
};
diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c
index 710db721ffa4..40c4d833f4ed 100644
--- a/sound/soc/amd/yc/acp6x-pdm-dma.c
+++ b/sound/soc/amd/yc/acp6x-pdm-dma.c
@@ -275,9 +275,11 @@ static int acp6x_pdm_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct pdm_dev_data *adata = dev_get_drvdata(component->dev);
+ struct snd_pcm_runtime *runtime = substream->runtime;
acp6x_disable_pdm_interrupts(adata->acp6x_base);
adata->capture_stream = NULL;
+ kfree(runtime->private_data);
return 0;
}
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 2cf96cbdd294..e1a0e35836e6 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -14,17 +14,14 @@
* for ST-Ericsson.
*/
-#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
-#include <linux/mutex.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
@@ -54,32 +51,9 @@
/* Macrocell register definitions */
#define AB8500_GPIO_DIR4_REG 0x13 /* Bank AB8500_MISC */
-/* Nr of FIR/IIR-coeff banks in ANC-block */
-#define AB8500_NR_OF_ANC_COEFF_BANKS 2
-
-/* Minimum duration to keep ANC IIR Init bit high or
-low before proceeding with the configuration sequence */
-#define AB8500_ANC_SM_DELAY 2000
-
-/* Sidetone states */
-static const char * const enum_sid_state[] = {
- "Unconfigured",
- "Apply FIR",
- "FIR is configured",
-};
-enum sid_state {
- SID_UNCONFIGURED = 0,
- SID_APPLY_FIR = 1,
- SID_FIR_CONFIGURED = 2,
-};
-
/* Private data for AB8500 device-driver */
struct ab8500_codec_drvdata {
struct regmap *regmap;
- struct mutex ctrl_lock;
-
- /* Sidetone */
- enum sid_state sid_status;
};
static inline const char *amic_micbias_str(enum amic_micbias micbias)
@@ -259,7 +233,7 @@ static const struct snd_kcontrol_new dapm_anc_in_select[] = {
/* ANC - Enable/Disable */
static const struct snd_kcontrol_new dapm_anc_enable[] = {
SOC_DAPM_SINGLE("Switch", AB8500_ANCCONF1,
- AB8500_ANCCONF1_ENANC, 0, 0),
+ AB8500_ANCCONF1_ENANC, 1, 0),
};
/* ANC to Earpiece - Mute */
@@ -341,12 +315,6 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
/* DA/AD */
- SND_SOC_DAPM_INPUT("ADC Input"),
- SND_SOC_DAPM_ADC("ADC", "ab8500_0c", SND_SOC_NOPM, 0, 0),
-
- SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_OUTPUT("DAC Output"),
-
SND_SOC_DAPM_AIF_IN("DA_IN1", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DA_IN2", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DA_IN3", NULL, 0, SND_SOC_NOPM, 0, 0),
@@ -538,9 +506,8 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("AD3 Channel Volume",
SND_SOC_NOPM, 0, 0,
NULL, 0),
- SND_SOC_DAPM_MIXER("AD3 Enable",
- AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34, 0,
- NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AD34 Enable", AB8500_ADPATHENA,
+ AB8500_ADPATHENA_ENAD34, 0, NULL, 0),
/* Mic 2 */
@@ -599,9 +566,8 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
SND_SOC_NOPM, 0, 0,
NULL, 0),
- SND_SOC_DAPM_MIXER("AD12 Enable",
- AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD12, 0,
- NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AD12 Enable", AB8500_ADPATHENA,
+ AB8500_ADPATHENA_ENAD12, 0, NULL, 0),
/* HD Capture path */
@@ -615,12 +581,8 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("AD6 Channel Volume",
SND_SOC_NOPM, 0, 0,
NULL, 0),
- SND_SOC_DAPM_MIXER("AD57 Enable",
- AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0,
- NULL, 0),
- SND_SOC_DAPM_MIXER("AD68 Enable",
- AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0,
- NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AD5768 Enable", AB8500_ADPATHENA,
+ AB8500_ADPATHENA_ENAD5768, 0, NULL, 0),
/* Digital Microphone path */
@@ -652,15 +614,8 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("AD4 Channel Volume",
SND_SOC_NOPM, 0, 0,
NULL, 0),
- SND_SOC_DAPM_MIXER("AD4 Enable",
- AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34,
- 0, NULL, 0),
-
/* Acoustical Noise Cancellation path */
- SND_SOC_DAPM_INPUT("ANC Configure Input"),
- SND_SOC_DAPM_OUTPUT("ANC Configure Output"),
-
SND_SOC_DAPM_MUX("ANC Source",
SND_SOC_NOPM, 0, 0,
dapm_anc_in_select),
@@ -703,24 +658,13 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
{"Main Supply", NULL, "Audio Power"},
{"Main Supply", NULL, "Audio Analog Power"},
- {"DAC", NULL, "ab8500_0p"},
- {"DAC", NULL, "Main Supply"},
- {"ADC", NULL, "ab8500_0c"},
- {"ADC", NULL, "Main Supply"},
-
- /* ANC Configure */
- {"ANC Configure Input", NULL, "Main Supply"},
- {"ANC Configure Output", NULL, "ANC Configure Input"},
-
- /* AD/DA */
- {"ADC", NULL, "ADC Input"},
- {"DAC Output", NULL, "DAC"},
-
/* Powerup charge pump if DA1/2 is in use */
{"DA_IN1", NULL, "ab8500_0p"},
+ {"DA_IN1", NULL, "Main Supply"},
{"DA_IN1", NULL, "Charge Pump"},
{"DA_IN2", NULL, "ab8500_0p"},
+ {"DA_IN2", NULL, "Main Supply"},
{"DA_IN2", NULL, "Charge Pump"},
/* Headset path */
@@ -755,8 +699,10 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
/* HF or LineOut path */
{"DA_IN3", NULL, "ab8500_0p"},
+ {"DA_IN3", NULL, "Main Supply"},
{"DA3 Channel Volume", NULL, "DA_IN3"},
{"DA_IN4", NULL, "ab8500_0p"},
+ {"DA_IN4", NULL, "Main Supply"},
{"DA4 Channel Volume", NULL, "DA_IN4"},
{"Speaker Left Source", "Audio Path", "DA3 Channel Volume"},
@@ -814,8 +760,10 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
/* Vibrator path */
{"DA_IN5", NULL, "ab8500_0p"},
+ {"DA_IN5", NULL, "Main Supply"},
{"DA5 Channel Volume", NULL, "DA_IN5"},
{"DA_IN6", NULL, "ab8500_0p"},
+ {"DA_IN6", NULL, "Main Supply"},
{"DA6 Channel Volume", NULL, "DA_IN6"},
{"VIB1 DAC", NULL, "DA5 Channel Volume"},
@@ -857,13 +805,15 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
{"AD1 Channel Volume", NULL, "AD1 Source Select"},
{"AD2 Channel Volume", NULL, "AD2 Source Select"},
- {"AD12 Enable", NULL, "AD1 Channel Volume"},
- {"AD12 Enable", NULL, "AD2 Channel Volume"},
+ {"AD1 Channel Volume", NULL, "AD12 Enable"},
+ {"AD2 Channel Volume", NULL, "AD12 Enable"},
- {"AD_OUT1", NULL, "ab8500_0c"},
- {"AD_OUT1", NULL, "AD12 Enable"},
- {"AD_OUT2", NULL, "ab8500_0c"},
- {"AD_OUT2", NULL, "AD12 Enable"},
+ {"ab8500_0c", NULL, "AD_OUT1"},
+ {"AD_OUT1", NULL, "Main Supply"},
+ {"AD_OUT1", NULL, "AD1 Channel Volume"},
+ {"ab8500_0c", NULL, "AD_OUT2"},
+ {"AD_OUT2", NULL, "Main Supply"},
+ {"AD_OUT2", NULL, "AD2 Channel Volume"},
/* Mic 1 */
@@ -880,11 +830,11 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
{"AD3 Source Select", "Mic 1", "MIC1 ADC"},
{"AD3 Channel Volume", NULL, "AD3 Source Select"},
+ {"AD3 Channel Volume", NULL, "AD34 Enable"},
- {"AD3 Enable", NULL, "AD3 Channel Volume"},
-
- {"AD_OUT3", NULL, "ab8500_0c"},
- {"AD_OUT3", NULL, "AD3 Enable"},
+ {"ab8500_0c", NULL, "AD_OUT3"},
+ {"AD_OUT3", NULL, "Main Supply"},
+ {"AD_OUT3", NULL, "AD3 Channel Volume"},
/* HD Capture path */
@@ -893,14 +843,15 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
{"AD5 Channel Volume", NULL, "AD5 Source Select"},
{"AD6 Channel Volume", NULL, "AD6 Source Select"},
+ {"AD5 Channel Volume", NULL, "AD5768 Enable"},
+ {"AD6 Channel Volume", NULL, "AD5768 Enable"},
- {"AD57 Enable", NULL, "AD5 Channel Volume"},
- {"AD68 Enable", NULL, "AD6 Channel Volume"},
-
- {"AD_OUT57", NULL, "ab8500_0c"},
- {"AD_OUT57", NULL, "AD57 Enable"},
- {"AD_OUT68", NULL, "ab8500_0c"},
- {"AD_OUT68", NULL, "AD68 Enable"},
+ {"ab8500_0c", NULL, "AD_OUT57"},
+ {"AD_OUT57", NULL, "Main Supply"},
+ {"AD_OUT57", NULL, "AD5 Channel Volume"},
+ {"ab8500_0c", NULL, "AD_OUT68"},
+ {"AD_OUT68", NULL, "Main Supply"},
+ {"AD_OUT68", NULL, "AD6 Channel Volume"},
/* Digital Microphone path */
@@ -911,17 +862,25 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
{"DMic 5", NULL, "V-DMIC"},
{"DMic 6", NULL, "V-DMIC"},
- {"AD1 Source Select", NULL, "DMic 1"},
- {"AD2 Source Select", NULL, "DMic 2"},
- {"AD3 Source Select", NULL, "DMic 3"},
- {"AD5 Source Select", NULL, "DMic 5"},
- {"AD6 Source Select", NULL, "DMic 6"},
+ {"DMIC1", NULL, "DMic 1"},
+ {"DMIC2", NULL, "DMic 2"},
+ {"DMIC3", NULL, "DMic 3"},
+ {"DMIC4", NULL, "DMic 4"},
+ {"DMIC5", NULL, "DMic 5"},
+ {"DMIC6", NULL, "DMic 6"},
- {"AD4 Channel Volume", NULL, "DMic 4"},
- {"AD4 Enable", NULL, "AD4 Channel Volume"},
+ {"AD1 Source Select", "DMic 1", "DMIC1"},
+ {"AD2 Source Select", "DMic 2", "DMIC2"},
+ {"AD3 Source Select", "DMic 3", "DMIC3"},
+ {"AD5 Source Select", "DMic 5", "DMIC5"},
+ {"AD6 Source Select", "DMic 6", "DMIC6"},
- {"AD_OUT4", NULL, "ab8500_0c"},
- {"AD_OUT4", NULL, "AD4 Enable"},
+ {"AD4 Channel Volume", NULL, "DMIC4"},
+ {"AD4 Channel Volume", NULL, "AD34 Enable"},
+
+ {"ab8500_0c", NULL, "AD_OUT4"},
+ {"AD_OUT4", NULL, "Main Supply"},
+ {"AD_OUT4", NULL, "AD4 Channel Volume"},
/* LineIn Bypass path */
@@ -946,13 +905,13 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = {
/* Sidetone Filter path */
- {"Sidetone Left Source", "LineIn Left", "AD12 Enable"},
- {"Sidetone Left Source", "LineIn Right", "AD12 Enable"},
- {"Sidetone Left Source", "Mic 1", "AD3 Enable"},
+ {"Sidetone Left Source", "LineIn Left", "AD1 Channel Volume"},
+ {"Sidetone Left Source", "LineIn Right", "AD2 Channel Volume"},
+ {"Sidetone Left Source", "Mic 1", "AD3 Channel Volume"},
{"Sidetone Left Source", "Headset Left", "DA_IN1"},
- {"Sidetone Right Source", "LineIn Right", "AD12 Enable"},
- {"Sidetone Right Source", "Mic 1", "AD3 Enable"},
- {"Sidetone Right Source", "DMic 4", "AD4 Enable"},
+ {"Sidetone Right Source", "LineIn Right", "AD2 Channel Volume"},
+ {"Sidetone Right Source", "Mic 1", "AD3 Channel Volume"},
+ {"Sidetone Right Source", "DMic 4", "AD4 Channel Volume"},
{"Sidetone Right Source", "Headset Right", "DA_IN2"},
{"STFIR1 Control", NULL, "Sidetone Left Source"},
@@ -981,75 +940,6 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = {
};
/*
- * Control-events
- */
-
-static int sid_status_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
-
- guard(mutex)(&drvdata->ctrl_lock);
- ucontrol->value.enumerated.item[0] = drvdata->sid_status;
-
- return 0;
-}
-
-/* Write sidetone FIR-coefficients configuration sequence */
-static int sid_status_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
- unsigned int param, sidconf;
- int status = 1;
-
- dev_dbg(component->dev, "%s: Enter\n", __func__);
-
- if (ucontrol->value.enumerated.item[0] != SID_APPLY_FIR) {
- dev_err(component->dev,
- "%s: ERROR: This control supports '%s' only!\n",
- __func__, enum_sid_state[SID_APPLY_FIR]);
- return -EIO;
- }
-
- guard(mutex)(&drvdata->ctrl_lock);
-
- sidconf = snd_soc_component_read(component, AB8500_SIDFIRCONF);
- if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
- if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) {
- dev_err(component->dev, "%s: Sidetone busy while off!\n",
- __func__);
- status = -EPERM;
- } else {
- status = -EBUSY;
- }
- dev_dbg(component->dev, "%s: Exit\n", __func__);
- return status;
- }
-
- snd_soc_component_write(component, AB8500_SIDFIRADR, 0);
-
- for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) {
- snd_soc_component_write(component, AB8500_SIDFIRCOEF1, 0);
- snd_soc_component_write(component, AB8500_SIDFIRCOEF2, 0);
- }
-
- snd_soc_component_update_bits(component, AB8500_SIDFIRADR,
- BIT(AB8500_SIDFIRADR_FIRSIDSET),
- BIT(AB8500_SIDFIRADR_FIRSIDSET));
- snd_soc_component_update_bits(component, AB8500_SIDFIRADR,
- BIT(AB8500_SIDFIRADR_FIRSIDSET), 0);
-
- drvdata->sid_status = SID_FIR_CONFIGURED;
-
- dev_dbg(component->dev, "%s: Exit\n", __func__);
-
- return status;
-}
-
-/*
* Controls - Non-DAPM ASoC
*/
@@ -1332,9 +1222,6 @@ static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast,
AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOMAST_SHIFT,
enum_slavemaster);
-/* Sidetone */
-static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state);
-
/* ANC */
static struct snd_kcontrol_new ab8500_ctrls[] = {
@@ -1625,8 +1512,6 @@ static struct snd_kcontrol_new ab8500_ctrls[] = {
AB8500_ANC_WARP_DELAY_MIN, AB8500_ANC_WARP_DELAY_MAX, 0),
/* Sidetone */
- SOC_ENUM_EXT("Sidetone Status", soc_enum_sidstate,
- sid_status_control_get, sid_status_control_put),
SOC_SINGLE_STROBE("Sidetone Reset",
AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0),
};
@@ -1638,23 +1523,25 @@ static struct snd_kcontrol_new ab8500_ctrls[] = {
static int ab8500_audio_init_audioblock(struct snd_soc_component *component)
{
int status;
+ u8 mask = AB8500_STW4500CTRL3_CLK32KOUT2DIS |
+ AB8500_STW4500CTRL3_RESETAUDN;
dev_dbg(component->dev, "%s: Enter.\n", __func__);
- /* Reset audio-registers and disable 32kHz-clock output 2 */
- status = ab8500_sysctrl_write(AB8500_STW4500CTRL3,
- AB8500_STW4500CTRL3_CLK32KOUT2DIS |
- AB8500_STW4500CTRL3_RESETAUDN,
- AB8500_STW4500CTRL3_RESETAUDN);
+ /* Reset the audio registers and disable the unused 32 kHz output. */
+ status = ab8500_sysctrl_write(AB8500_STW4500CTRL3, mask,
+ AB8500_STW4500CTRL3_CLK32KOUT2DIS);
if (status < 0)
return status;
- return 0;
+ return ab8500_sysctrl_write(AB8500_STW4500CTRL3, mask, mask);
}
static int ab8500_audio_setup_mics(struct snd_soc_component *component,
struct amic_settings *amics)
{
+ struct device *dev = component->dev;
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
u8 value8;
unsigned int value;
@@ -1663,20 +1550,21 @@ static int ab8500_audio_setup_mics(struct snd_soc_component *component,
dev_dbg(component->dev, "%s: Enter.\n", __func__);
- /* Set DMic-clocks to outputs */
- status = abx500_get_register_interruptible(component->dev, AB8500_MISC,
- AB8500_GPIO_DIR4_REG,
- &value8);
- if (status < 0)
- return status;
- value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
- GPIO31_DIR_OUTPUT;
- status = abx500_set_register_interruptible(component->dev,
- AB8500_MISC,
- AB8500_GPIO_DIR4_REG,
- value);
- if (status < 0)
- return status;
+ /* Set DMic-clocks to outputs; these GPIOs do not exist on AB8505. */
+ if (!is_ab8505(ab8500)) {
+ status = abx500_get_register_interruptible(dev, AB8500_MISC,
+ AB8500_GPIO_DIR4_REG,
+ &value8);
+ if (status < 0)
+ return status;
+ value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
+ GPIO31_DIR_OUTPUT;
+ status = abx500_set_register_interruptible(dev, AB8500_MISC,
+ AB8500_GPIO_DIR4_REG,
+ value);
+ if (status < 0)
+ return status;
+ }
/* Attach regulators to AMic DAPM-paths */
dev_dbg(component->dev, "%s: Mic 1a regulator: %s\n", __func__,
@@ -1745,149 +1633,91 @@ static int ab8500_audio_set_ear_cmv(struct snd_soc_component *component,
return 0;
}
-static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai,
- unsigned int delay)
-{
- unsigned int mask, val;
- struct snd_soc_component *component = dai->component;
-
- mask = BIT(AB8500_DIGIFCONF2_IF0DEL);
- val = 0;
-
- switch (delay) {
- case 0:
- break;
- case 1:
- val |= BIT(AB8500_DIGIFCONF2_IF0DEL);
- break;
- default:
- dev_err(dai->component->dev,
- "%s: ERROR: Unsupported bit-delay (0x%x)!\n",
- __func__, delay);
- return -EINVAL;
- }
-
- dev_dbg(dai->component->dev, "%s: IF0 Bit-delay: %d bits.\n",
- __func__, delay);
- snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
-
- return 0;
-}
-
-/* Gates clocking according format mask */
-static int ab8500_codec_set_dai_clock_gate(struct snd_soc_component *component,
- unsigned int fmt)
-{
- unsigned int mask;
- unsigned int val;
-
- mask = BIT(AB8500_DIGIFCONF1_ENMASTGEN) |
- BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
-
- val = BIT(AB8500_DIGIFCONF1_ENMASTGEN);
-
- switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
- case SND_SOC_DAIFMT_CONT: /* continuous clock */
- dev_dbg(component->dev, "%s: IF0 Clock is continuous.\n",
- __func__);
- val |= BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
- break;
- case SND_SOC_DAIFMT_GATED: /* clock is gated */
- dev_dbg(component->dev, "%s: IF0 Clock is gated.\n",
- __func__);
- break;
- default:
- dev_err(component->dev,
- "%s: ERROR: Unsupported clock mask (0x%x)!\n",
- __func__, fmt & SND_SOC_DAIFMT_CLOCK_MASK);
- return -EINVAL;
- }
-
- snd_soc_component_update_bits(component, AB8500_DIGIFCONF1, mask, val);
-
- return 0;
-}
-
static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- unsigned int mask;
- unsigned int val;
struct snd_soc_component *component = dai->component;
- int status;
+ unsigned int conf1_mask, conf1_val = 0;
+ unsigned int conf2_mask, conf2_val = 0;
+ unsigned int conf3_mask, conf3_val = 0;
+ bool provider = false;
+ int ret;
dev_dbg(component->dev, "%s: Enter (fmt = 0x%x)\n", __func__, fmt);
- mask = BIT(AB8500_DIGIFCONF3_IF1DATOIF0AD) |
+ conf3_mask = BIT(AB8500_DIGIFCONF3_IF1DATOIF0AD) |
BIT(AB8500_DIGIFCONF3_IF1CLKTOIF0CLK) |
BIT(AB8500_DIGIFCONF3_IF0BFIFOEN) |
BIT(AB8500_DIGIFCONF3_IF0MASTER);
- val = 0;
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBP_CFP:
- dev_dbg(dai->component->dev,
+ dev_dbg(component->dev,
"%s: IF0 Master-mode: AB8500 provider.\n", __func__);
- val |= BIT(AB8500_DIGIFCONF3_IF0MASTER);
+ conf3_val |= BIT(AB8500_DIGIFCONF3_IF0MASTER);
+ provider = true;
break;
case SND_SOC_DAIFMT_CBC_CFC:
- dev_dbg(dai->component->dev,
+ dev_dbg(component->dev,
"%s: IF0 Master-mode: AB8500 consumer.\n", __func__);
break;
case SND_SOC_DAIFMT_CBC_CFP:
case SND_SOC_DAIFMT_CBP_CFC:
- dev_err(dai->component->dev,
+ dev_err(component->dev,
"%s: ERROR: The device is either a provider or a consumer.\n",
__func__);
fallthrough;
default:
- dev_err(dai->component->dev,
- "%s: ERROR: Unsupporter clocking mask 0x%x\n",
+ dev_err(component->dev,
+ "%s: ERROR: Unsupported clocking mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
return -EINVAL;
}
- snd_soc_component_update_bits(component, AB8500_DIGIFCONF3, mask, val);
-
- /* Set clock gating */
- status = ab8500_codec_set_dai_clock_gate(component, fmt);
- if (status) {
- dev_err(dai->component->dev,
- "%s: ERROR: Failed to set clock gate (%d).\n",
- __func__, status);
- return status;
+ conf1_mask = BIT(AB8500_DIGIFCONF1_ENMASTGEN) |
+ BIT(AB8500_DIGIFCONF1_ENFSBITCLK0);
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+ case SND_SOC_DAIFMT_CONT:
+ if (provider)
+ conf1_val = conf1_mask;
+ break;
+ case SND_SOC_DAIFMT_GATED:
+ if (provider)
+ conf1_val = BIT(AB8500_DIGIFCONF1_ENMASTGEN);
+ break;
+ default:
+ dev_err(component->dev, "%s: Unsupported clock mask 0x%x\n",
+ __func__, fmt & SND_SOC_DAIFMT_CLOCK_MASK);
+ return -EINVAL;
}
- /* Setting data transfer format */
-
- mask = BIT(AB8500_DIGIFCONF2_IF0FORMAT0) |
- BIT(AB8500_DIGIFCONF2_IF0FORMAT1) |
- BIT(AB8500_DIGIFCONF2_FSYNC0P) |
- BIT(AB8500_DIGIFCONF2_BITCLK0P);
- val = 0;
+ conf2_mask = BIT(AB8500_DIGIFCONF2_IF0FORMAT0) |
+ BIT(AB8500_DIGIFCONF2_IF0FORMAT1) |
+ BIT(AB8500_DIGIFCONF2_IF0DEL) |
+ BIT(AB8500_DIGIFCONF2_FSYNC0P) |
+ BIT(AB8500_DIGIFCONF2_BITCLK0P);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S: /* I2S mode */
- dev_dbg(dai->component->dev, "%s: IF0 Protocol: I2S\n", __func__);
- val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT1);
- ab8500_audio_set_bit_delay(dai, 0);
+ dev_dbg(component->dev, "%s: IF0 Protocol: I2S\n", __func__);
+ conf2_val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT1) |
+ BIT(AB8500_DIGIFCONF2_IF0DEL);
break;
case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */
- dev_dbg(dai->component->dev,
+ dev_dbg(component->dev,
"%s: IF0 Protocol: DSP A (TDM)\n", __func__);
- val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
- ab8500_audio_set_bit_delay(dai, 1);
+ conf2_val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0) |
+ BIT(AB8500_DIGIFCONF2_IF0DEL);
break;
case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */
- dev_dbg(dai->component->dev,
+ dev_dbg(component->dev,
"%s: IF0 Protocol: DSP B (TDM)\n", __func__);
- val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
- ab8500_audio_set_bit_delay(dai, 0);
+ conf2_val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0);
break;
default:
- dev_err(dai->component->dev,
+ dev_err(component->dev,
"%s: ERROR: Unsupported format (0x%x)!\n",
__func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
@@ -1895,39 +1725,50 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
- dev_dbg(dai->component->dev,
+ dev_dbg(component->dev,
"%s: IF0: Normal bit clock, normal frame\n",
__func__);
break;
case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */
- dev_dbg(dai->component->dev,
+ dev_dbg(component->dev,
"%s: IF0: Normal bit clock, inverted frame\n",
__func__);
- val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
+ conf2_val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
break;
case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */
- dev_dbg(dai->component->dev,
+ dev_dbg(component->dev,
"%s: IF0: Inverted bit clock, normal frame\n",
__func__);
- val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
+ conf2_val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
break;
case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */
- dev_dbg(dai->component->dev,
+ dev_dbg(component->dev,
"%s: IF0: Inverted bit clock, inverted frame\n",
__func__);
- val |= BIT(AB8500_DIGIFCONF2_FSYNC0P);
- val |= BIT(AB8500_DIGIFCONF2_BITCLK0P);
+ conf2_val |= BIT(AB8500_DIGIFCONF2_FSYNC0P) |
+ BIT(AB8500_DIGIFCONF2_BITCLK0P);
break;
default:
- dev_err(dai->component->dev,
+ dev_err(component->dev,
"%s: ERROR: Unsupported INV mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_INV_MASK);
return -EINVAL;
}
- snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
+ ret = snd_soc_component_update_bits(component, AB8500_DIGIFCONF3,
+ conf3_mask, conf3_val);
+ if (ret < 0)
+ return ret;
- return 0;
+ ret = snd_soc_component_update_bits(component, AB8500_DIGIFCONF1,
+ conf1_mask, conf1_val);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component, AB8500_DIGIFCONF2,
+ conf2_mask, conf2_val);
+
+ return ret < 0 ? ret : 0;
}
static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
@@ -1935,23 +1776,27 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
- unsigned int val, mask, slot, slots_active;
+ unsigned int active_mask, clock_ratio, slot, value, ad_out, reg;
+ unsigned int tx_active, rx_active;
+ unsigned int conf1_val, conf2_val;
+ unsigned int mask;
+ int channel, ret;
mask = BIT(AB8500_DIGIFCONF2_IF0WL0) |
BIT(AB8500_DIGIFCONF2_IF0WL1);
- val = 0;
+ conf2_val = 0;
switch (slot_width) {
case 16:
break;
case 20:
- val |= BIT(AB8500_DIGIFCONF2_IF0WL0);
+ conf2_val |= BIT(AB8500_DIGIFCONF2_IF0WL0);
break;
case 24:
- val |= BIT(AB8500_DIGIFCONF2_IF0WL1);
+ conf2_val |= BIT(AB8500_DIGIFCONF2_IF0WL1);
break;
case 32:
- val |= BIT(AB8500_DIGIFCONF2_IF0WL1) |
+ conf2_val |= BIT(AB8500_DIGIFCONF2_IF0WL1) |
BIT(AB8500_DIGIFCONF2_IF0WL0);
break;
default:
@@ -1960,27 +1805,11 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
}
- dev_dbg(dai->component->dev, "%s: IF0 slot-width: %d bits.\n",
- __func__, slot_width);
- snd_soc_component_update_bits(component, AB8500_DIGIFCONF2, mask, val);
-
- /* Setup TDM clocking according to slot count */
- dev_dbg(dai->component->dev, "%s: Slots, total: %d\n", __func__, slots);
- mask = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
- BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
switch (slots) {
case 2:
- val = AB8500_MASK_NONE;
- break;
case 4:
- val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0);
- break;
case 8:
- val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
- break;
case 16:
- val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
- BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
break;
default:
dev_err(dai->component->dev,
@@ -1988,92 +1817,134 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
__func__, slots);
return -EINVAL;
}
- snd_soc_component_update_bits(component, AB8500_DIGIFCONF1, mask, val);
-
- /* Setup TDM DA according to active tx slots */
- if (tx_mask & ~0xff)
- return -EINVAL;
-
- mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
- tx_mask = tx_mask << AB8500_DA_DATA0_OFFSET;
- slots_active = hweight32(tx_mask);
-
- dev_dbg(dai->component->dev, "%s: Slots, active, TX: %d\n", __func__,
- slots_active);
-
- switch (slots_active) {
- case 0:
+ clock_ratio = slots * slot_width;
+ switch (clock_ratio) {
+ case 32:
+ conf1_val = 0;
break;
- case 1:
- slot = ffs(tx_mask);
- snd_soc_component_update_bits(component, AB8500_DASLOTCONF1, mask, slot);
- snd_soc_component_update_bits(component, AB8500_DASLOTCONF3, mask, slot);
- snd_soc_component_update_bits(component, AB8500_DASLOTCONF2, mask, slot);
- snd_soc_component_update_bits(component, AB8500_DASLOTCONF4, mask, slot);
+ case 64:
+ conf1_val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0);
break;
- case 2:
- slot = ffs(tx_mask);
- snd_soc_component_update_bits(component, AB8500_DASLOTCONF1, mask, slot);
- snd_soc_component_update_bits(component, AB8500_DASLOTCONF3, mask, slot);
- slot = fls(tx_mask);
- snd_soc_component_update_bits(component, AB8500_DASLOTCONF2, mask, slot);
- snd_soc_component_update_bits(component, AB8500_DASLOTCONF4, mask, slot);
+ case 128:
+ conf1_val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
break;
- case 8:
- dev_dbg(dai->component->dev,
- "%s: In 8-channel mode DA-from-slot mapping is set manually.",
- __func__);
+ case 256:
+ conf1_val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
+ BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
break;
default:
- dev_err(dai->component->dev,
- "%s: Unsupported number of active TX-slots (%d)!\n",
- __func__, slots_active);
+ dev_err(component->dev, "%s: Unsupported BCLK ratio (%u)!\n",
+ __func__, clock_ratio);
return -EINVAL;
}
- /* Setup TDM AD according to active RX-slots */
+ active_mask = GENMASK(min(slots, 8) - 1, 0);
+ if ((tx_mask | rx_mask) & ~active_mask) {
+ dev_err(component->dev, "%s: Slot mask exceeds slot count\n",
+ __func__);
+ return -EINVAL;
+ }
- if (rx_mask & ~0xff)
+ tx_active = hweight32(tx_mask);
+ rx_active = hweight32(rx_mask);
+ if (tx_active != 0 && tx_active != 1 && tx_active != 2 &&
+ tx_active != 8) {
+ dev_err(component->dev, "%s: Unsupported active TX slots (%u)!\n",
+ __func__, tx_active);
return -EINVAL;
+ }
+ if (rx_active != 0 && rx_active != 1 && rx_active != 2 &&
+ rx_active != 8) {
+ dev_err(component->dev, "%s: Unsupported active RX slots (%u)!\n",
+ __func__, rx_active);
+ return -EINVAL;
+ }
- rx_mask = rx_mask << AB8500_AD_DATA0_OFFSET;
- slots_active = hweight32(rx_mask);
+ dev_dbg(component->dev,
+ "%s: %d slots of %d bits, TX active: %u, RX active: %u\n",
+ __func__, slots, slot_width, tx_active, rx_active);
- dev_dbg(dai->component->dev, "%s: Slots, active, RX: %d\n", __func__,
- slots_active);
+ ret = snd_soc_component_update_bits(component, AB8500_DIGIFCONF2,
+ mask, conf2_val);
+ if (ret < 0)
+ return ret;
- switch (slots_active) {
- case 0:
- break;
- case 1:
- slot = ffs(rx_mask);
- snd_soc_component_update_bits(component, AB8500_ADSLOTSEL(slot),
- AB8500_MASK_SLOT(slot),
- AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
- break;
- case 2:
- slot = ffs(rx_mask);
- snd_soc_component_update_bits(component,
- AB8500_ADSLOTSEL(slot),
- AB8500_MASK_SLOT(slot),
- AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
- slot = fls(rx_mask);
- snd_soc_component_update_bits(component,
- AB8500_ADSLOTSEL(slot),
- AB8500_MASK_SLOT(slot),
- AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT2, slot));
- break;
- case 8:
- dev_dbg(dai->component->dev,
- "%s: In 8-channel mode AD-to-slot mapping is set manually.",
- __func__);
- break;
- default:
- dev_err(dai->component->dev,
- "%s: Unsupported number of active RX-slots (%d)!\n",
- __func__, slots_active);
- return -EINVAL;
+ mask = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) |
+ BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1);
+ ret = snd_soc_component_update_bits(component, AB8500_DIGIFCONF1,
+ mask, conf1_val);
+ if (ret < 0)
+ return ret;
+
+ mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
+ if (tx_active == 1 || tx_active == 2) {
+ slot = __ffs(tx_mask) + AB8500_DA_DATA0_OFFSET;
+ reg = AB8500_DASLOTCONF1;
+ ret = snd_soc_component_update_bits(component, reg, mask, slot);
+ if (ret < 0)
+ return ret;
+ reg = AB8500_DASLOTCONF3;
+ ret = snd_soc_component_update_bits(component, reg, mask, slot);
+ if (ret < 0)
+ return ret;
+
+ if (tx_active == 2)
+ slot = __fls(tx_mask) + AB8500_DA_DATA0_OFFSET;
+ reg = AB8500_DASLOTCONF2;
+ ret = snd_soc_component_update_bits(component, reg, mask, slot);
+ if (ret < 0)
+ return ret;
+ reg = AB8500_DASLOTCONF4;
+ ret = snd_soc_component_update_bits(component, reg, mask, slot);
+ if (ret < 0)
+ return ret;
+ } else if (tx_active == 8) {
+ channel = 0;
+ for (slot = 0; slot < 8; slot++) {
+ if (!(tx_mask & BIT(slot)))
+ continue;
+ reg = AB8500_DASLOTCONF1 + channel++;
+ value = slot + AB8500_DA_DATA0_OFFSET;
+ ret = snd_soc_component_update_bits(component, reg, mask, value);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ if (rx_active == 1 || rx_active == 2) {
+ slot = __ffs(rx_mask) + AB8500_AD_DATA0_OFFSET;
+ value = AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3,
+ slot);
+ reg = AB8500_ADSLOTSEL(slot);
+ mask = AB8500_MASK_SLOT(slot);
+ ret = snd_soc_component_update_bits(component, reg, mask, value);
+ if (ret < 0)
+ return ret;
+
+ if (rx_active == 2) {
+ slot = __fls(rx_mask) + AB8500_AD_DATA0_OFFSET;
+ value = AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT2,
+ slot);
+ reg = AB8500_ADSLOTSEL(slot);
+ mask = AB8500_MASK_SLOT(slot);
+ ret = snd_soc_component_update_bits(component, reg, mask, value);
+ if (ret < 0)
+ return ret;
+ }
+ } else if (rx_active == 8) {
+ channel = 0;
+ for (slot = 0; slot < 8; slot++) {
+ if (!(rx_mask & BIT(slot)))
+ continue;
+ ad_out = AB8500_AD_OUT1 + channel++;
+ value = AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(ad_out, slot);
+ reg = AB8500_ADSLOTSEL(slot);
+ mask = AB8500_MASK_SLOT(slot);
+ ret = snd_soc_component_update_bits(component, reg, mask, value);
+ if (ret < 0)
+ return ret;
+ }
}
return 0;
@@ -2170,10 +2041,8 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
static int ab8500_codec_probe(struct snd_soc_component *component)
{
- struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
struct device *dev = component->dev;
struct device_node *np = dev->of_node;
- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
struct ab8500_codec_platform_data codec_pdata;
int status;
@@ -2181,6 +2050,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component)
ab8500_codec_of_probe(dev, np, &codec_pdata);
+ status = ab8500_audio_init_audioblock(component);
+ if (status < 0) {
+ dev_err(dev, "%s: failed to init audio-block (%d)!\n",
+ __func__, status);
+ return status;
+ }
+
status = ab8500_audio_setup_mics(component, &codec_pdata.amics);
if (status < 0) {
pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
@@ -2193,23 +2069,12 @@ static int ab8500_codec_probe(struct snd_soc_component *component)
return status;
}
- status = ab8500_audio_init_audioblock(component);
- if (status < 0) {
- dev_err(dev, "%s: failed to init audio-block (%d)!\n",
- __func__, status);
- return status;
- }
-
/* Override HW-defaults */
snd_soc_component_write(component, AB8500_ANACONF5,
BIT(AB8500_ANACONF5_HSAUTOEN));
snd_soc_component_write(component, AB8500_SHORTCIRCONF,
BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
- snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
-
- mutex_init(&drvdata->ctrl_lock);
-
return status;
}
@@ -2238,7 +2103,6 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->sid_status = SID_UNCONFIGURED;
dev_set_drvdata(&pdev->dev, drvdata);
drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev,
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 4fba59e80c37..98bb4542b914 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -386,11 +386,8 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
- if (!cs35l56->base.init_done)
- return 0;
-
- /* runtime_resume unmasks the interrupt */
- cs35l56_mask_soundwire_interrupts(cs35l56);
+ if (cs35l56->sdw_attached)
+ cs35l56_mask_soundwire_interrupts(cs35l56);
return cs35l56_system_suspend(dev);
}
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index b9118ad8fab5..890429ab0dfb 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -1365,12 +1365,6 @@ static int _cs35l56_component_probe(struct snd_soc_component *component)
BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) != ARRAY_SIZE(cs35l56_tx_input_values));
- if (!wait_for_completion_timeout(&cs35l56->init_completion,
- msecs_to_jiffies(5000))) {
- dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__);
- return -ENODEV;
- }
-
cs35l56->dsp.part = kasprintf(GFP_KERNEL, "cs35l%02x", cs35l56->base.type);
if (!cs35l56->dsp.part)
return -ENOMEM;
@@ -1939,6 +1933,40 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
return ret;
}
+static int cs35l56_component_register(struct cs35l56_private *cs35l56)
+{
+ int ret;
+
+ ret = snd_soc_register_component(cs35l56->base.dev,
+ &soc_component_dev_cs35l56,
+ cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
+ if (ret < 0) {
+ dev_err(cs35l56->base.dev, "Register codec failed: %d\n", ret);
+ return ret;
+ }
+
+ cs35l56->component_registered = true;
+
+ return 0;
+}
+
+static void cs35l56_component_register_work(struct work_struct *work)
+{
+ struct cs35l56_private *cs35l56 = container_of(work,
+ struct cs35l56_private,
+ component_register_work);
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(cs35l56->base.dev, pm_err);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm_err);
+ if (ret) {
+ dev_err(cs35l56->base.dev, "register_work failed to get pm_runtime: %d\n", ret);
+ return;
+ }
+
+ cs35l56_component_register(cs35l56);
+}
+
int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq)
{
int ret;
@@ -1947,6 +1975,7 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq)
mutex_init(&cs35l56->base.irq_lock);
cs35l56->base.cal_index = -1;
cs35l56->speaker_id = -ENOENT;
+ INIT_WORK(&cs35l56->component_register_work, cs35l56_component_register_work);
dev_set_drvdata(cs35l56->base.dev, cs35l56);
@@ -2020,12 +2049,17 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq)
if (ret)
goto err_remove_wm_adsp;
- ret = snd_soc_register_component(cs35l56->base.dev,
- &soc_component_dev_cs35l56,
- cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
- if (ret < 0) {
- dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
- goto err_free_irq;
+ /*
+ * Defer calling snd_soc_register_component() on SoundWire to prevent
+ * a deadlock where it calls our component_probe(), which requires the
+ * SoundWire enumeration to complete, but because we are still in probe()
+ * the SoundWire core will not call the update_status() callback. At time
+ * of writing snd_soc_register_component() never returns EPROBE_DEFER.
+ */
+ if (!cs35l56->sdw_peripheral) {
+ ret = cs35l56_component_register(cs35l56);
+ if (ret < 0)
+ goto err_free_irq;
}
return 0;
@@ -2055,6 +2089,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, "SND_SOC_CS35L56_CORE");
int cs35l56_init(struct cs35l56_private *cs35l56)
{
+ bool first_time_init = !cs35l56->base.init_done;
int ret;
/*
@@ -2131,13 +2166,23 @@ post_soft_reset:
cs35l56->base.init_done = true;
complete_all(&cs35l56->init_completion);
+ if (cs35l56->sdw_peripheral && first_time_init) {
+ /*
+ * Hardware now accessible, queue work to call
+ * snd_soc_register_component().
+ */
+ queue_work(system_freezable_wq, &cs35l56->component_register_work);
+ }
+
return 0;
}
EXPORT_SYMBOL_NS_GPL(cs35l56_init, "SND_SOC_CS35L56_CORE");
void cs35l56_remove(struct cs35l56_private *cs35l56)
{
- snd_soc_unregister_component(cs35l56->base.dev);
+ cancel_work_sync(&cs35l56->component_register_work);
+ if (cs35l56->component_registered)
+ snd_soc_unregister_component(cs35l56->base.dev);
cs35l56->base.init_done = false;
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index 35c02ae17de3..f7cf8aa653e2 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -32,6 +32,7 @@ struct sdw_slave;
struct cs35l56_private {
struct wm_adsp dsp; /* must be first member */
struct cs35l56_base base;
+ struct work_struct component_register_work;
struct work_struct dsp_work;
struct workqueue_struct *dsp_wq;
struct snd_soc_component *component;
@@ -41,6 +42,7 @@ struct cs35l56_private {
const char *fallback_fw_suffix;
bool soft_resetting;
bool sdw_attached;
+ bool component_registered;
struct completion init_completion;
int speaker_id;
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index c5460589a88b..b6eadc2e9659 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -26,6 +26,7 @@ struct es8326_priv {
struct snd_soc_component *component;
struct delayed_work jack_detect_work;
struct delayed_work button_press_work;
+ struct delayed_work capture_pop_work;
struct snd_soc_jack *jack;
int irq;
/* The lock protects the situation that an irq is generated
@@ -628,6 +629,7 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF,
0x30, 0x00);
} else {
+ cancel_delayed_work_sync(&es8326->capture_pop_work);
regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
0x0F, 0x0F);
if (es8326->version > ES8326_VERSION_B) {
@@ -666,8 +668,9 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x70);
regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x00);
}
- regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
- 0x0F, 0x00);
+
+ queue_delayed_work(system_dfl_wq, &es8326->capture_pop_work,
+ msecs_to_jiffies(40));
}
}
return 0;
@@ -773,6 +776,15 @@ static void es8326_disable_micbias(struct snd_soc_component *component)
snd_soc_dapm_mutex_unlock(dapm);
}
+static void es8326_capture_pop_handler(struct work_struct *work)
+{
+ struct es8326_priv *es8326 =
+ container_of(work, struct es8326_priv, capture_pop_work.work);
+
+ regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE,
+ 0x0F, 0x00);
+}
+
/*
* For button detection, set the following in soundcard
* snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
@@ -1140,6 +1152,7 @@ static int es8326_suspend(struct snd_soc_component *component)
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
cancel_delayed_work_sync(&es8326->jack_detect_work);
+ cancel_delayed_work_sync(&es8326->capture_pop_work);
es8326_disable_micbias(component);
es8326->calibrated = false;
regmap_write(es8326->regmap, ES8326_CLK_MUX, 0x2d);
@@ -1291,6 +1304,8 @@ static int es8326_i2c_probe(struct i2c_client *i2c)
es8326_jack_detect_handler);
INIT_DELAYED_WORK(&es8326->button_press_work,
es8326_jack_button_handler);
+ INIT_DELAYED_WORK(&es8326->capture_pop_work,
+ es8326_capture_pop_handler);
/* ES8316 is level-based while ES8326 is edge-based */
ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
index 80efce3e0a22..2ea0c4052ce1 100644
--- a/sound/soc/codecs/es8389.c
+++ b/sound/soc/codecs/es8389.c
@@ -812,6 +812,23 @@ static int es8389_pcm_hw_free(struct snd_pcm_substream *substream,
return 0;
}
+static void es8389_standby(struct snd_soc_component *component)
+{
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x04);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x04);
+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xD4);
+ usleep_range(70000, 72000);
+ regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x59);
+ regmap_write(es8389->regmap, ES8389_ADC_EN, 0x00);
+ regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0x00);
+ regmap_write(es8389->regmap, ES8389_RESET, 0x3E);
+ regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x80);
+ usleep_range(8000, 8500);
+ regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x00);
+}
+
static int es8389_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
@@ -834,18 +851,7 @@ static int es8389_set_bias_level(struct snd_soc_component *component,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x04);
- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x04);
- regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xD4);
- usleep_range(70000, 72000);
- regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x59);
- regmap_write(es8389->regmap, ES8389_ADC_EN, 0x00);
- regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0x00);
- regmap_write(es8389->regmap, ES8389_RESET, 0x3E);
- regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x80);
- usleep_range(8000, 8500);
- regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x00);
-
+ es8389_standby(component);
clk_disable_unprepare(es8389->mclk);
break;
case SND_SOC_BIAS_OFF:
@@ -1015,7 +1021,7 @@ static int es8389_suspend(struct snd_soc_component *component)
{
struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
- es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
+ es8389_standby(component);
regcache_cache_only(es8389->regmap, true);
regcache_mark_dirty(es8389->regmap);
@@ -1084,7 +1090,7 @@ static int es8389_probe(struct snd_soc_component *component)
es8389->hpf_freq = ES8389_HPF_DEFAULT;
es8389_init(component);
- es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
+ es8389_standby(component);
return 0;
}
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
index efadb6b1b82d..f9ba16269817 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -16,6 +16,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
+#include <sound/sdw.h>
#include <sound/initval.h>
#include "rt1318-sdw.h"
@@ -564,11 +565,10 @@ static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct rt1318_sdw_priv *rt1318 =
snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
+ struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
- enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
- int retval, port, num_channels, ch_mask;
+ int retval, port;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -582,23 +582,13 @@ static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream,
/* SoundWire specific configuration */
/* port 1 for playback */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
port = 1;
- } else {
- direction = SDW_DATA_DIR_TX;
+ else
port = 2;
- }
-
- num_channels = params_channels(params);
- ch_mask = (1 << num_channels) - 1;
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = num_channels;
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- port_config.ch_mask = ch_mask;
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
port_config.num = port;
retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config,
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 90333779971d..72af413306fa 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -3246,7 +3246,7 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct rt1320_sdw_priv *rt1320 =
snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
+ struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
struct sdw_port_config dmic_port_config[2];
struct sdw_stream_runtime *sdw_stream;
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index 13574513b181..eda87eb9ab66 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -23,6 +23,7 @@
#include <linux/soundwire/sdw_registers.h>
#include <linux/slab.h>
#include <sound/soc-dapm.h>
+#include <sound/sdw.h>
#include <sound/tlv.h>
#include "rt712-sdca.h"
@@ -1449,11 +1450,10 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
+ struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
- enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
- int retval, port, num_channels;
+ int retval, port;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id);
@@ -1471,7 +1471,6 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
/* SoundWire specific configuration */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
if (dai->id == RT712_AIF1)
port = 1;
else if (dai->id == RT712_AIF2)
@@ -1479,7 +1478,6 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
} else {
- direction = SDW_DATA_DIR_TX;
if (dai->id == RT712_AIF1)
port = 4;
else if (dai->id == RT712_AIF3)
@@ -1488,13 +1486,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
-
- num_channels = params_channels(params);
- port_config.ch_mask = GENMASK(num_channels - 1, 0);
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
port_config.num = port;
retval = sdw_stream_add_slave(rt712->slave, &stream_config,
diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c
index 159c35d19dba..a9479d0e4941 100644
--- a/sound/soc/codecs/rt721-sdca.c
+++ b/sound/soc/codecs/rt721-sdca.c
@@ -21,6 +21,7 @@
#include <linux/soundwire/sdw_registers.h>
#include <linux/slab.h>
#include <sound/soc-dapm.h>
+#include <sound/sdw.h>
#include <sound/tlv.h>
#include "rt721-sdca.h"
@@ -206,6 +207,7 @@ static void rt721_sdca_amp_preset(struct rt721_sdca_priv *rt721)
regmap_write(rt721->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00);
+ regmap_write(rt721->regmap, 0x2f5d, 0x1);
}
static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721)
@@ -1268,11 +1270,10 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
+ struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
- enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
- int retval, port, num_channels;
+ int retval, port;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -1291,7 +1292,6 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
* RT721_AIF3 with port = 6 for digital-mic capture
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
if (dai->id == RT721_AIF1)
port = 1;
else if (dai->id == RT721_AIF2)
@@ -1299,7 +1299,6 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
} else {
- direction = SDW_DATA_DIR_TX;
if (dai->id == RT721_AIF1)
port = 2;
else if (dai->id == RT721_AIF3)
@@ -1307,13 +1306,9 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
- num_channels = params_channels(params);
- port_config.ch_mask = GENMASK(num_channels - 1, 0);
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
port_config.num = port;
retval = sdw_stream_add_slave(rt721->slave, &stream_config,
diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c
index 4cbe9e909585..149cb6617126 100644
--- a/sound/soc/codecs/rt722-sdca.c
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -24,6 +24,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
+#include <sound/sdw.h>
#include <sound/tlv.h>
#include "rt722-sdca.h"
@@ -1442,11 +1443,10 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
+ struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
- enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
- int retval, port, num_channels;
+ int retval, port;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -1465,7 +1465,6 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
* RT722_AIF3 with port = 6 for digital-mic capture
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
if (dai->id == RT722_AIF1)
port = 1;
else if (dai->id == RT722_AIF2)
@@ -1473,7 +1472,6 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
} else {
- direction = SDW_DATA_DIR_TX;
if (dai->id == RT722_AIF1)
port = 2;
else if (dai->id == RT722_AIF3)
@@ -1481,13 +1479,9 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
}
- stream_config.frame_rate = params_rate(params);
- stream_config.ch_count = params_channels(params);
- stream_config.bps = snd_pcm_format_width(params_format(params));
- stream_config.direction = direction;
- num_channels = params_channels(params);
- port_config.ch_mask = GENMASK(num_channels - 1, 0);
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
port_config.num = port;
retval = sdw_stream_add_slave(rt722->slave, &stream_config,
diff --git a/sound/soc/codecs/rt766-sdca.c b/sound/soc/codecs/rt766-sdca.c
index 64d763b96a06..5a1c1e10e6d7 100644
--- a/sound/soc/codecs/rt766-sdca.c
+++ b/sound/soc/codecs/rt766-sdca.c
@@ -936,9 +936,8 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_component *component = dai->component;
struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
- struct sdw_stream_config stream_config;
+ struct sdw_stream_config stream_config = {0};
struct sdw_port_config port_config;
- enum sdw_data_direction direction;
struct sdw_stream_runtime *sdw_stream;
unsigned int sampling_rate;
int retval, port;
@@ -957,7 +956,6 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
/* SoundWire specific configuration */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- direction = SDW_DATA_DIR_RX;
if (dai->id == RT766_AIF1)
port = 3;
else if (dai->id == RT766_AIF2)
@@ -965,7 +963,6 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
else
return -EINVAL;
} else {
- direction = SDW_DATA_DIR_TX;
if (dai->id == RT766_AIF1)
port = 12;
else if (dai->id == RT766_AIF3)
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index eaebb0ebbe0d..7fcf8214bf34 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -1001,6 +1001,31 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
/* SoundWire specific configuration */
snd_sdw_params_to_config(substream, params,
&stream_config, &port_config);
+
+ /*
+ * The two mono amps each render one channel of the stereo stream:
+ * snd_sdw_params_to_config() hands every codec the full mask for
+ * playback, which leaves the pair in mirror mode and one channel
+ * unreproduced. Claim a single channel instead, keyed off the
+ * machine-assigned component prefix rather than the SoundWire
+ * address, which is board-specific: soc_sdw_ti_amp.c names the amps
+ * tas2783-1..4.
+ *
+ * Which side an amp then renders does not follow from the bit that
+ * is set - sdw_compute_slave_ports() advances the payload offset by
+ * the popcount of ch_mask and never looks at which bit it is - but
+ * from the amp's position in the codec order of the DAI link, which
+ * on these boards matches the prefix numbering.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ params_channels(params) == 2 && component->name_prefix) {
+ const char *idx_str = strrchr(component->name_prefix, '-');
+ unsigned long idx;
+
+ if (idx_str && !kstrtoul(idx_str + 1, 10, &idx) && idx)
+ port_config.ch_mask = (idx & 1) ? BIT(0) : BIT(1);
+ }
+
/* port 1 for playback */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
port_config.num = 1;
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index 60ac8eabab9d..5d8f0f76ab46 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -953,12 +953,17 @@ static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int s
/* Get root clock */
clk = micfil->mclk;
- /* Disable clock first, for it was enabled by pm_runtime */
+ /* Reparent root clock to the PLL matching this sample rate */
fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk,
micfil->pll11k_clk, ratio);
- ret = clk_prepare_enable(clk);
- if (ret)
- return ret;
+
+ /* Enable only once; hw_params can be called multiple times */
+ if (!micfil->mclk_flag) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+ micfil->mclk_flag = true;
+ }
return 0;
}
@@ -991,8 +996,6 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
if (ret)
return ret;
- micfil->mclk_flag = true;
-
/* floor(K * CLKDIV) */
switch (micfil->quality) {
case QUALITY_HIGH:
@@ -1068,8 +1071,10 @@ static int fsl_micfil_hw_free(struct snd_pcm_substream *substream,
{
struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai);
- clk_disable_unprepare(micfil->mclk);
- micfil->mclk_flag = false;
+ if (micfil->mclk_flag) {
+ clk_disable_unprepare(micfil->mclk);
+ micfil->mclk_flag = false;
+ }
return 0;
}
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index 03cfd91202d3..2e15a293298d 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -15,6 +15,22 @@
#include "../../../codecs/hda.h"
#include "../utils.h"
+static int avs_link_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ const struct snd_soc_pcm_stream *stream_info;
+ struct snd_soc_dai *codec_dai;
+
+ codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ stream_info = snd_soc_dai_get_pcm_stream(codec_dai, substream->stream);
+
+ return snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, stream_info->sig_bits);
+}
+
+static const struct snd_soc_ops avs_link_ops = {
+ .startup = avs_link_startup,
+};
+
static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count,
struct snd_soc_dai_link **links)
{
@@ -43,6 +59,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int
dl[i].platforms = platform;
dl[i].num_platforms = 1;
dl[i].ignore_pmdown_time = 1;
+ dl[i].ops = &avs_link_ops;
dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 2afe59646896..611ae9f034d4 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -92,16 +92,28 @@ static int avs_hdac_bus_init_streams(struct hdac_bus *bus)
{
unsigned int cp_streams, pb_streams;
unsigned int gcap;
+ int ret;
gcap = snd_hdac_chip_readw(bus, GCAP);
cp_streams = (gcap >> 8) & 0x0F;
pb_streams = (gcap >> 12) & 0x0F;
bus->num_streams = cp_streams + pb_streams;
- snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
- snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
+ ret = snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ return ret;
+ ret = snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto err;
+
+ ret = snd_hdac_bus_alloc_stream_pages(bus);
+ if (ret)
+ goto err;
- return snd_hdac_bus_alloc_stream_pages(bus);
+ return 0;
+err:
+ snd_hdac_ext_stream_free_all(bus);
+ return ret;
}
static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
@@ -383,6 +395,18 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct
struct device *dev = &pci->dev;
int ret;
+ ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
+ if (!ipc)
+ return -ENOMEM;
+
+ adev->modcfg_buf = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL);
+ if (!adev->modcfg_buf)
+ return -ENOMEM;
+
+ ret = avs_ipc_init(ipc, dev);
+ if (ret < 0)
+ return ret;
+
ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, &soc_hda_ext_bus_ops);
if (ret < 0)
return ret;
@@ -394,17 +418,6 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct
bus->mixer_assigned = -1;
mutex_init(&bus->prepare_mutex);
- ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
- if (!ipc)
- return -ENOMEM;
- ret = avs_ipc_init(ipc, dev);
- if (ret < 0)
- return ret;
-
- adev->modcfg_buf = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL);
- if (!adev->modcfg_buf)
- return -ENOMEM;
-
adev->dev = dev;
adev->spec = (const struct avs_spec *)id->driver_data;
adev->ipc = ipc;
@@ -456,13 +469,14 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
ret = pcim_request_all_regions(pci, "AVS HDAudio");
if (ret < 0)
- return ret;
+ goto err_request_regions;
bus->addr = pci_resource_start(pci, 0);
bus->remap_addr = pci_ioremap_bar(pci, 0);
if (!bus->remap_addr) {
dev_err(bus->dev, "ioremap error\n");
- return -ENXIO;
+ ret = -ENXIO;
+ goto err_request_regions;
}
adev->dsp_ba = pci_ioremap_bar(pci, 4);
@@ -473,8 +487,13 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
}
snd_hdac_bus_parse_capabilities(bus);
- if (bus->mlcap)
- snd_hdac_ext_bus_get_ml_capabilities(bus);
+ if (bus->mlcap) {
+ ret = snd_hdac_ext_bus_get_ml_capabilities(bus);
+ if (ret < 0) {
+ dev_err(dev, "failed to get ml capabilities: %d\n", ret);
+ goto err_ml_cap;
+ }
+ }
if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
@@ -516,9 +535,13 @@ err_acquire_irq:
snd_hdac_bus_free_stream_pages(bus);
snd_hdac_ext_stream_free_all(bus);
err_init_streams:
+ snd_hdac_ext_link_free_all(bus);
+err_ml_cap:
iounmap(adev->dsp_ba);
err_remap_bar4:
iounmap(bus->remap_addr);
+err_request_regions:
+ snd_hdac_ext_bus_exit(bus);
return ret;
}
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
index 9ab503da3b75..bc02737720ab 100644
--- a/sound/soc/intel/avs/debugfs.c
+++ b/sound/soc/intel/avs/debugfs.c
@@ -9,6 +9,7 @@
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/kfifo.h>
+#include <linux/module.h>
#include <linux/wait.h>
#include <linux/sched/signal.h>
#include <linux/string_helpers.h>
@@ -236,15 +237,20 @@ static int strace_open(struct inode *inode, struct file *file)
if (!try_module_get(adev->dev->driver->owner))
return -ENODEV;
- if (kfifo_initialized(&adev->trace_fifo))
- return -EBUSY;
+ if (kfifo_initialized(&adev->trace_fifo)) {
+ ret = -EBUSY;
+ goto err;
+ }
ret = kfifo_alloc(&adev->trace_fifo, PAGE_SIZE, GFP_KERNEL);
if (ret < 0)
- return ret;
+ goto err;
file->private_data = adev;
return 0;
+err:
+ module_put(adev->dev->driver->owner);
+ return ret;
}
static int strace_release(struct inode *inode, struct file *file)
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 39b0de9831da..5010b0f5be47 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -172,7 +172,7 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg
/* Avoid deadlock as the exception may be the response to SET_D0IX. */
if (current_work() != &ipc->d0ix_work.work)
- cancel_delayed_work_sync(&ipc->d0ix_work);
+ cancel_delayed_work(&ipc->d0ix_work);
ipc->in_d0ix = false;
/* Re-enabled on recovery completion. */
pm_runtime_disable(adev->dev);
@@ -395,11 +395,11 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
struct avs_ipc *ipc = adev->ipc;
int ret;
+ guard(mutex)(&ipc->msg_mutex);
+
if (!ipc->ready)
return -EPERM;
- guard(mutex)(&ipc->msg_mutex);
-
spin_lock(&ipc->rx_lock);
avs_ipc_msg_init(ipc, reply);
avs_dsp_send_tx(adev, request, true);
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index 213d6ecdd7cc..a8a2b3484338 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -836,15 +836,10 @@ static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_mod
static int avs_path_module_send_init_configs(struct avs_dev *adev, struct avs_path_module *mod)
{
- struct avs_soc_component *acomp;
-
- acomp = to_avs_soc_component(mod->template->owner->owner->owner->owner->comp);
-
- u32 num_ids = mod->template->num_config_ids;
- u32 *ids = mod->template->config_ids;
+ struct avs_tplg_module *template = mod->template;
- for (int i = 0; i < num_ids; i++) {
- struct avs_tplg_init_config *config = &acomp->tplg->init_configs[ids[i]];
+ for (int i = 0; i < template->num_init_configs; i++) {
+ struct avs_tplg_init_config *config = template->init_configs[i];
size_t len = config->length;
void *data = config->data;
u32 param = config->param;
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 2b886fae8209..ad25bd355769 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <sound/hda_register.h>
@@ -987,13 +988,25 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)
return ret;
}
+static int avs_request_topology(struct snd_soc_component *component, const char *name,
+ const struct firmware **fw)
+{
+ char *fullname __free(kfree) = NULL;
+
+ fullname = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix, name);
+ if (!fullname)
+ return -ENOMEM;
+
+ return request_firmware(fw, fullname, component->dev);
+}
+
static int avs_component_probe(struct snd_soc_component *component)
{
struct snd_soc_card *card = component->card;
struct snd_soc_acpi_mach *mach;
struct avs_soc_component *acomp;
+ const struct firmware *fw;
struct avs_dev *adev;
- char *filename;
int ret;
dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name);
@@ -1009,13 +1022,7 @@ static int avs_component_probe(struct snd_soc_component *component)
goto finalize;
/* Load specified topology and create debugfs for it. */
- filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
- mach->tplg_filename);
- if (!filename)
- return -ENOMEM;
-
- ret = avs_load_topology(component, filename);
- kfree(filename);
+ ret = avs_request_topology(component, mach->tplg_filename, &fw);
if (ret == -ENOENT && !strncmp(mach->tplg_filename, "hda-", 4)) {
unsigned int vendor_id;
@@ -1030,18 +1037,17 @@ static int avs_component_probe(struct snd_soc_component *component)
"hda-generic-tplg.bin");
if (!mach->tplg_filename)
return -ENOMEM;
- filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
- mach->tplg_filename);
- if (!filename)
- return -ENOMEM;
dev_info(card->dev, "trying to load fallback topology %s\n", mach->tplg_filename);
- ret = avs_load_topology(component, filename);
- kfree(filename);
+ ret = avs_request_topology(component, mach->tplg_filename, &fw);
}
if (ret < 0)
return ret;
+ ret = snd_soc_tplg_component_load(component, &avs_tplg_ops, fw);
+ if (ret)
+ return ret;
+
ret = avs_component_load_libraries(acomp);
if (ret < 0) {
dev_err(card->dev, "libraries loading failed: %d\n", ret);
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 673ac31f2fea..5d70be63a4a7 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -350,6 +350,7 @@ AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base);
AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext);
AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs);
AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings);
+AVS_DEFINE_PTR_PARSER(init_config, struct avs_tplg_init_config, init_configs);
AVS_DEFINE_PTR_PARSER(nhlt_config, struct avs_tplg_nhlt_config, nhlt_configs);
static int
@@ -1198,7 +1199,7 @@ static const struct avs_tplg_token_parser module_parsers[] = {
{
.token = AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
- .offset = offsetof(struct avs_tplg_module, num_config_ids),
+ .offset = offsetof(struct avs_tplg_module, num_init_configs),
.parse = avs_parse_byte_token,
},
{
@@ -1214,10 +1215,32 @@ static const struct avs_tplg_token_parser init_config_parsers[] = {
.token = AVS_TKN_MOD_INIT_CONFIG_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = 0,
- .parse = avs_parse_word_token,
+ .parse = avs_parse_init_config_ptr,
},
};
+static int avs_tplg_module_init_configs(struct snd_soc_component *comp,
+ struct avs_tplg_module *module,
+ struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
+{
+ struct avs_tplg_init_config **cfgs;
+ int ret;
+
+ if (!module->num_init_configs)
+ return -EINVAL;
+
+ cfgs = devm_kcalloc(comp->card->dev, module->num_init_configs, sizeof(*cfgs), GFP_KERNEL);
+ if (!cfgs)
+ return -ENOMEM;
+
+ ret = parse_dictionary_entries(comp, tuples, block_size, cfgs, module->num_init_configs,
+ sizeof(*cfgs), AVS_TKN_MOD_INIT_CONFIG_ID_U32,
+ init_config_parsers, ARRAY_SIZE(init_config_parsers));
+ if (!ret)
+ module->init_configs = cfgs;
+ return ret;
+}
+
static struct avs_tplg_module *
avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline *owner,
struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
@@ -1244,27 +1267,11 @@ avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline
block_size -= esize;
/* Parse trailing config ids if any. */
if (block_size) {
- u32 num_config_ids = module->num_config_ids;
- u32 *config_ids;
-
- if (!num_config_ids)
- return ERR_PTR(-EINVAL);
-
- config_ids = devm_kcalloc(comp->card->dev, num_config_ids, sizeof(*config_ids),
- GFP_KERNEL);
- if (!config_ids)
- return ERR_PTR(-ENOMEM);
-
tuples = avs_tplg_vendor_array_at(tuples, esize);
- ret = parse_dictionary_entries(comp, tuples, block_size,
- config_ids, num_config_ids, sizeof(*config_ids),
- AVS_TKN_MOD_INIT_CONFIG_ID_U32,
- init_config_parsers,
- ARRAY_SIZE(init_config_parsers));
+
+ ret = avs_tplg_module_init_configs(comp, module, tuples, block_size);
if (ret)
return ERR_PTR(ret);
-
- module->config_ids = config_ids;
}
module->owner = owner;
@@ -2194,7 +2201,7 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_
return 0;
}
-static const struct snd_soc_tplg_ops avs_tplg_ops = {
+const struct snd_soc_tplg_ops avs_tplg_ops = {
.io_ops = avs_control_ops,
.io_ops_count = ARRAY_SIZE(avs_control_ops),
.control_load = avs_control_load,
diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h
index 1cf7455b6c01..189984ce7b51 100644
--- a/sound/soc/intel/avs/topology.h
+++ b/sound/soc/intel/avs/topology.h
@@ -221,8 +221,8 @@ struct avs_tplg_module {
u8 domain;
struct avs_tplg_modcfg_ext *cfg_ext;
u32 ctl_id;
- u32 num_config_ids;
- u32 *config_ids;
+ u32 num_init_configs;
+ struct avs_tplg_init_config **init_configs;
struct avs_tplg_nhlt_config *nhlt_config;
struct avs_tplg_pipeline *owner;
@@ -230,6 +230,7 @@ struct avs_tplg_module {
struct list_head node;
};
+extern const struct snd_soc_tplg_ops avs_tplg_ops;
struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp);
int avs_load_topology(struct snd_soc_component *comp, const char *filename);
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index cddbd2aa424e..b795bcade8e9 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -533,12 +533,14 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
select SND_SOC_CS35L56_SPI
select SND_SOC_CS35L56_SDW
select SND_SOC_ES9356
+ imply SND_SOC_TAC5XX2_SDW
select SND_SOC_DMIC
select SND_SOC_INTEL_HDA_DSP_COMMON
imply SND_SOC_SDW_MOCKUP
help
Add support for Intel SoundWire-based platforms connected to
- MAX98373, RT700, RT711, RT1308 and RT715
+ MAX98373, RT700, RT711, RT1308, RT715, TAC5XX2_SDW family (including
+ TAC5572, TAC5682).
If unsure select "N".
endif
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index 7899f7ffd99b..88cf5c0ab2e3 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -909,6 +909,14 @@ static const struct platform_device_id board_ids[] = {
SOF_BT_OFFLOAD_PRESENT),
},
{
+ .name = "nvl_rt5682_def",
+ .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+ SOF_SSP_PORT_CODEC(0) |
+ SOF_SSP_PORT_AMP(1) |
+ SOF_SSP_PORT_BT_OFFLOAD(2) |
+ SOF_BT_OFFLOAD_PRESENT),
+ },
+ {
.name = "ptl_rt5682_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
SOF_SSP_PORT_CODEC(1) |
diff --git a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
index 8f6e987c791e..4a67f6b72fa5 100644
--- a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c
@@ -51,10 +51,10 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = {
},
{
.comp_ids = &nvl_rt5682_rt5682s_hp,
- .drv_name = "sof_rt5682",
- .sof_tplg_filename = "sof-nvl-rt5682", /* the tplg suffix is added at run time */
- .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
- SND_SOC_ACPI_TPLG_INTEL_SSP_MSB,
+ .drv_name = "nvl_rt5682_def",
+ .sof_tplg_filename = "sof-nvl", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME |
+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME,
},
/* place amp/hdmi-in only boards in the end of table */
{
diff --git a/sound/soc/sprd/sprd-pcm-compress.c b/sound/soc/sprd/sprd-pcm-compress.c
index a7d437b49fbf..e5249924b54d 100644
--- a/sound/soc/sprd/sprd-pcm-compress.c
+++ b/sound/soc/sprd/sprd-pcm-compress.c
@@ -17,7 +17,7 @@
/* Default values if userspace does not set */
#define SPRD_COMPR_MIN_FRAGMENT_SIZE SZ_8K
-#define SPRD_COMPR_MAX_FRAGMENT_SIZE SZ_128K
+#define SPRD_COMPR_MAX_FRAGMENT_SIZE SZ_32K
#define SPRD_COMPR_MIN_NUM_FRAGMENTS 4
#define SPRD_COMPR_MAX_NUM_FRAGMENTS 64
@@ -272,6 +272,19 @@ static int sprd_platform_compr_set_params(struct snd_soc_component *component,
int ret;
/*
+ * The stage 0 IRAM buffer and the stage 1 DDR buffer are allocated
+ * with fixed sizes at open time, so the requested fragment size and
+ * fragments must fit into them, otherwise sprd_platform_compr_copy()
+ * would overflow the buffers. Note the compress core only checks the
+ * fragment size and fragments against an u32 overflow, not against
+ * the buffer sizes advertised by get_caps.
+ */
+ if (params->buffer.fragment_size > SPRD_COMPR_IRAM_BUF_SIZE ||
+ (u64)params->buffer.fragment_size * params->buffer.fragments >
+ SPRD_COMPR_AREA_BUF_SIZE)
+ return -EINVAL;
+
+ /*
* Configure the DMA engine 2-stage transfer mode. Channel 1 set as the
* destination channel, and channel 0 set as the source channel, that
* means once the source channel's transaction is done, it will trigger
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c
index 45d7613f595c..5347f9620f25 100644
--- a/sound/soc/sti/uniperif_reader.c
+++ b/sound/soc/sti/uniperif_reader.c
@@ -416,6 +416,8 @@ int uni_reader_init(struct platform_device *pdev,
else
reader->hw = &uni_reader_pcm_hw;
+ spin_lock_init(&reader->irq_lock);
+
ret = devm_request_irq(&pdev->dev, reader->irq,
uni_reader_irq_handler, IRQF_SHARED,
dev_name(&pdev->dev), reader);
@@ -424,8 +426,6 @@ int uni_reader_init(struct platform_device *pdev,
return -EBUSY;
}
- spin_lock_init(&reader->irq_lock);
-
return 0;
}
EXPORT_SYMBOL_GPL(uni_reader_init);
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 499e826d7120..37c48cc70394 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -14,7 +14,7 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
-#include <linux/mfd/db8500-prcmu.h>
+#include <linux/reset.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
@@ -34,8 +34,10 @@ static int setup_pcm_multichan(struct snd_soc_dai *dai,
if (drvdata->slots > 1) {
msp_config->multichannel_configured = 1;
- multi->tx_multichannel_enable = true;
- multi->rx_multichannel_enable = true;
+ multi->tx_multichannel_enable =
+ msp_config->direction & MSP_DIR_TX;
+ multi->rx_multichannel_enable =
+ msp_config->direction & MSP_DIR_RX;
multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED;
multi->tx_channel_0_enable = drvdata->tx_mask;
@@ -57,72 +59,21 @@ static int setup_pcm_multichan(struct snd_soc_dai *dai,
return 0;
}
-static int setup_frameper(struct snd_soc_dai *dai, unsigned int rate,
- struct msp_protdesc *prot_desc)
+static void setup_frameper(struct snd_soc_dai *dai,
+ struct msp_protdesc *prot_desc)
{
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
- switch (drvdata->slots) {
- case 1:
- switch (rate) {
- case 8000:
- prot_desc->frame_period =
- FRAME_PER_SINGLE_SLOT_8_KHZ;
- break;
-
- case 16000:
- prot_desc->frame_period =
- FRAME_PER_SINGLE_SLOT_16_KHZ;
- break;
-
- case 44100:
- prot_desc->frame_period =
- FRAME_PER_SINGLE_SLOT_44_1_KHZ;
- break;
-
- case 48000:
- prot_desc->frame_period =
- FRAME_PER_SINGLE_SLOT_48_KHZ;
- break;
-
- default:
- dev_err(dai->dev,
- "%s: Error: Unsupported sample-rate (freq = %d)!\n",
- __func__, rate);
- return -EINVAL;
- }
- break;
-
- case 2:
- prot_desc->frame_period = FRAME_PER_2_SLOTS;
- break;
-
- case 8:
- prot_desc->frame_period = FRAME_PER_8_SLOTS;
- break;
-
- case 16:
- prot_desc->frame_period = FRAME_PER_16_SLOTS;
- break;
- default:
- dev_err(dai->dev,
- "%s: Error: Unsupported slot-count (slots = %d)!\n",
- __func__, drvdata->slots);
- return -EINVAL;
- }
-
- prot_desc->clocks_per_frame =
- prot_desc->frame_period+1;
+ prot_desc->clocks_per_frame = drvdata->slots * drvdata->slot_width;
+ prot_desc->frame_period = prot_desc->clocks_per_frame - 1;
dev_dbg(dai->dev, "%s: Clocks per frame: %u\n",
__func__,
prot_desc->clocks_per_frame);
-
- return 0;
}
-static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,
- struct msp_protdesc *prot_desc)
+static int setup_pcm_framing(struct snd_soc_dai *dai,
+ struct msp_protdesc *prot_desc)
{
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
@@ -163,7 +114,9 @@ static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,
prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
- return setup_frameper(dai, rate, prot_desc);
+ setup_frameper(dai, prot_desc);
+
+ return 0;
}
static int setup_clocking(struct snd_soc_dai *dai,
@@ -177,7 +130,16 @@ static int setup_clocking(struct snd_soc_dai *dai,
case SND_SOC_DAIFMT_NB_IF:
msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;
msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;
+ break;
+
+ case SND_SOC_DAIFMT_IB_NF:
+ msp_config->bclk_inverted = true;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ msp_config->bclk_inverted = true;
+ msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;
+ msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;
break;
default:
@@ -192,6 +154,7 @@ static int setup_clocking(struct snd_soc_dai *dai,
case SND_SOC_DAIFMT_BC_FC:
dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);
+ msp_config->clock_provider = false;
msp_config->iodelay = 0x20;
msp_config->rx_fsync_sel = 0;
msp_config->tx_fsync_sel = 1 << TFSSEL_SHIFT;
@@ -204,6 +167,7 @@ static int setup_clocking(struct snd_soc_dai *dai,
case SND_SOC_DAIFMT_BP_FP:
dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);
+ msp_config->clock_provider = true;
msp_config->tx_clk_sel = TX_CLK_SEL_SRG;
msp_config->tx_fsync_sel = TX_SYNC_SRG_PROG;
msp_config->rx_clk_sel = RX_CLK_SEL_SRG;
@@ -362,7 +326,7 @@ static int setup_msp_config(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- ret = setup_pcm_framing(dai, runtime->rate, prot_desc);
+ ret = setup_pcm_framing(dai, prot_desc);
if (ret < 0)
return ret;
@@ -424,21 +388,21 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
int ret;
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ unsigned int configured = is_playback ? PLAYBACK_CONFIGURED :
+ CAPTURE_CONFIGURED;
+ unsigned int dir = is_playback ? MSP_DIR_TX : MSP_DIR_RX;
dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
snd_pcm_stream_str(substream));
- if (drvdata->vape_opp_constraint == 1) {
- prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
- "ux500_msp_i2s", 50);
- drvdata->vape_opp_constraint = 0;
- }
-
- if (ux500_msp_i2s_close(drvdata->msp,
- is_playback ? MSP_DIR_TX : MSP_DIR_RX)) {
- dev_err(dai->dev,
- "%s: Error: MSP %d (%s): Unable to close i2s.\n",
- __func__, dai->id, snd_pcm_stream_str(substream));
+ if (drvdata->configured & configured) {
+ if (ux500_msp_i2s_close(drvdata->msp, dir)) {
+ dev_err(dai->dev,
+ "%s: Error: MSP %d (%s): Unable to close i2s.\n",
+ __func__, dai->id,
+ snd_pcm_stream_str(substream));
+ }
+ drvdata->configured &= ~configured;
}
/* Disable and unprepare clocks */
@@ -456,15 +420,23 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- int ret = 0;
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
struct snd_pcm_runtime *runtime = substream->runtime;
struct ux500_msp_config msp_config;
+ bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ unsigned int configured = is_playback ? PLAYBACK_CONFIGURED :
+ CAPTURE_CONFIGURED;
+ int ret;
dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__,
dai->id, snd_pcm_stream_str(substream), runtime->rate);
- setup_msp_config(substream, dai, &msp_config);
+ if (drvdata->configured & configured)
+ return 0;
+
+ ret = setup_msp_config(substream, dai, &msp_config);
+ if (ret)
+ return ret;
ret = ux500_msp_i2s_open(drvdata->msp, &msp_config);
if (ret < 0) {
@@ -473,22 +445,9 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
return ret;
}
- /* Set OPP-level */
- if ((drvdata->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) &&
- (drvdata->msp->f_bitclk > 19200000)) {
- /* If the bit-clock is higher than 19.2MHz, Vape should be
- * run in 100% OPP. Only when bit-clock is used (MSP master)
- */
- prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
- "ux500-msp-i2s", 100);
- drvdata->vape_opp_constraint = 1;
- } else {
- prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
- "ux500-msp-i2s", 50);
- drvdata->vape_opp_constraint = 0;
- }
+ drvdata->configured |= configured;
- return ret;
+ return 0;
}
static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
@@ -496,7 +455,6 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
unsigned int mask, slots_active;
- struct snd_pcm_runtime *runtime = substream->runtime;
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n",
@@ -504,9 +462,8 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- snd_pcm_hw_constraint_minmax(runtime,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- 1, 2);
+ if (params_channels(params) < 1 || params_channels(params) > 2)
+ return -EINVAL;
break;
case SND_SOC_DAIFMT_DSP_B:
@@ -518,9 +475,8 @@ static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
slots_active = hweight32(mask);
dev_dbg(dai->dev, "TDM-slots active: %d", slots_active);
- snd_pcm_hw_constraint_single(runtime,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- slots_active);
+ if (!slots_active || params_channels(params) != slots_active)
+ return -EINVAL;
break;
default:
@@ -553,20 +509,21 @@ static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,
default:
dev_err(dai->dev,
"%s: Error: Unsupported protocol/master (fmt = 0x%x)!\n",
- __func__, drvdata->fmt);
+ __func__, fmt);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
case SND_SOC_DAIFMT_NB_IF:
+ case SND_SOC_DAIFMT_IB_NF:
case SND_SOC_DAIFMT_IB_IF:
break;
default:
dev_err(dai->dev,
"%s: Error: Unsupported inversion (fmt = 0x%x)!\n",
- __func__, drvdata->fmt);
+ __func__, fmt);
return -EINVAL;
}
@@ -600,17 +557,23 @@ static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai,
__func__, slots);
return -EINVAL;
}
- drvdata->slots = slots;
- if (!(slot_width == 16)) {
+ if (slot_width != 16) {
dev_err(dai->dev, "%s: Error: Unsupported slot-width (%d)!\n",
__func__, slot_width);
return -EINVAL;
}
- drvdata->slot_width = slot_width;
- drvdata->tx_mask = tx_mask & cap;
- drvdata->rx_mask = rx_mask & cap;
+ if ((tx_mask | rx_mask) & ~cap) {
+ dev_err(dai->dev, "%s: Slot mask exceeds %d slots\n",
+ __func__, slots);
+ return -EINVAL;
+ }
+
+ drvdata->slots = slots;
+ drvdata->slot_width = slot_width;
+ drvdata->tx_mask = tx_mask;
+ drvdata->rx_mask = rx_mask;
return 0;
}
@@ -716,6 +679,7 @@ static const struct snd_soc_component_driver ux500_msp_component = {
static int ux500_msp_drv_probe(struct platform_device *pdev)
{
struct ux500_msp_i2s_drvdata *drvdata;
+ struct reset_control *reset;
int ret = 0;
drvdata = devm_kzalloc(&pdev->dev,
@@ -729,7 +693,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
drvdata->tx_mask = 0x01;
drvdata->rx_mask = 0x01;
drvdata->slot_width = 16;
- drvdata->master_clk = MSP_INPUT_FREQ_APB;
drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape");
if (IS_ERR(drvdata->reg_vape)) {
@@ -739,8 +702,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
__func__, ret);
return ret;
}
- prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
-
drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
if (IS_ERR(drvdata->pclk)) {
ret = PTR_ERR(drvdata->pclk);
@@ -758,9 +719,19 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
__func__, ret);
return ret;
}
+ drvdata->master_clk = clk_get_rate(drvdata->clk);
+ if (!drvdata->master_clk) {
+ dev_err(&pdev->dev, "MSP clock has no rate\n");
+ return -EINVAL;
+ }
+
+ reset = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL);
+ if (IS_ERR(reset))
+ return dev_err_probe(&pdev->dev, PTR_ERR(reset),
+ "Failed to deassert MSP reset\n");
ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp);
- if (!drvdata->msp) {
+ if (ret) {
dev_err(&pdev->dev,
"%s: ERROR: Failed to init MSP-struct (%d)!",
__func__, ret);
@@ -799,8 +770,6 @@ static void ux500_msp_drv_remove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev);
- prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
-
ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);
}
diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h
index 30bf70838196..aae582030d95 100644
--- a/sound/soc/ux500/ux500_msp_dai.h
+++ b/sound/soc/ux500/ux500_msp_dai.h
@@ -22,17 +22,6 @@
#define UX500_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
-#define FRAME_PER_SINGLE_SLOT_8_KHZ 31
-#define FRAME_PER_SINGLE_SLOT_16_KHZ 124
-#define FRAME_PER_SINGLE_SLOT_44_1_KHZ 63
-#define FRAME_PER_SINGLE_SLOT_48_KHZ 49
-#define FRAME_PER_2_SLOTS 31
-#define FRAME_PER_8_SLOTS 138
-#define FRAME_PER_16_SLOTS 277
-
-#define UX500_MSP_INTERNAL_CLOCK_FREQ 40000000
-#define UX500_MSP1_INTERNAL_CLOCK_FREQ UX500_MSP_INTERNAL_CLOCK_FREQ
-
#define UX500_MSP_MIN_CHANNELS 1
#define UX500_MSP_MAX_CHANNELS 8
@@ -47,6 +36,7 @@ struct ux500_msp_i2s_drvdata {
struct ux500_msp *msp;
struct regulator *reg_vape;
unsigned int fmt;
+ unsigned int configured;
unsigned int tx_mask;
unsigned int rx_mask;
int slots;
@@ -57,8 +47,6 @@ struct ux500_msp_i2s_drvdata {
struct clk *clk;
struct clk *pclk;
- /* Regulators */
- int vape_opp_constraint;
};
int ux500_msp_dai_set_data_delay(struct snd_soc_dai *dai, int delay);
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
index fbfeefa418ca..683b485fb570 100644
--- a/sound/soc/ux500/ux500_msp_i2s.c
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -201,10 +201,12 @@ static int configure_protocol(struct ux500_msp *msp,
/* The code below should not be separated. */
temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
- temp_reg |= MSP_TX_CLKPOL_BIT(~protdesc->tx_clk_pol);
+ temp_reg |= MSP_TX_CLKPOL_BIT(!protdesc->tx_clk_pol ^
+ config->bclk_inverted);
writel(temp_reg, msp->registers + MSP_GCR);
temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
- temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol);
+ temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol ^
+ config->bclk_inverted);
writel(temp_reg, msp->registers + MSP_GCR);
return 0;
@@ -212,35 +214,20 @@ static int configure_protocol(struct ux500_msp *msp,
static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)
{
+ struct msp_protdesc *protdesc;
+ u64 desired_bitclk;
+ unsigned int bitclk;
u32 reg_val_GCR;
- u32 frame_per = 0;
- u32 sck_div = 0;
- u32 frame_width = 0;
- u32 temp_reg = 0;
- struct msp_protdesc *protdesc = NULL;
+ u32 sck_div;
+ u32 temp_reg;
reg_val_GCR = readl(msp->registers + MSP_GCR);
writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR);
- if (config->default_protdesc)
- protdesc =
- (struct msp_protdesc *)&prot_descs[config->protocol];
- else
- protdesc = (struct msp_protdesc *)&config->protdesc;
-
switch (config->protocol) {
case MSP_PCM_PROTOCOL:
case MSP_PCM_COMPAND_PROTOCOL:
- frame_width = protdesc->frame_width;
- sck_div = config->f_inputclk / (config->frame_freq *
- (protdesc->clocks_per_frame));
- frame_per = protdesc->frame_period;
- break;
case MSP_I2S_PROTOCOL:
- frame_width = protdesc->frame_width;
- sck_div = config->f_inputclk / (config->frame_freq *
- (protdesc->clocks_per_frame));
- frame_per = protdesc->frame_period;
break;
default:
dev_err(msp->dev, "%s: ERROR: Unknown protocol (%d)!\n",
@@ -249,12 +236,35 @@ static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)
return -EINVAL;
}
+ if (config->default_protdesc)
+ protdesc = (struct msp_protdesc *)&prot_descs[config->protocol];
+ else
+ protdesc = &config->protdesc;
+
+ if (!config->frame_freq || !protdesc->clocks_per_frame)
+ return -EINVAL;
+
+ desired_bitclk = (u64)config->frame_freq * protdesc->clocks_per_frame;
+ if (desired_bitclk > config->f_inputclk)
+ return -EINVAL;
+ bitclk = desired_bitclk;
+ if (config->f_inputclk % bitclk) {
+ dev_err(msp->dev,
+ "Input clock %u cannot generate bit clock %u\n",
+ config->f_inputclk, bitclk);
+ return -EINVAL;
+ }
+
+ sck_div = config->f_inputclk / bitclk;
+ if (!sck_div || sck_div > SCK_DIV_MASK + 1)
+ return -EINVAL;
+
temp_reg = (sck_div - 1) & SCK_DIV_MASK;
- temp_reg |= FRAME_WIDTH_BITS(frame_width);
- temp_reg |= FRAME_PERIOD_BITS(frame_per);
+ temp_reg |= FRAME_WIDTH_BITS(protdesc->frame_width);
+ temp_reg |= FRAME_PERIOD_BITS(protdesc->frame_period);
writel(temp_reg, msp->registers + MSP_SRG);
- msp->f_bitclk = (config->f_inputclk)/(sck_div + 1);
+ msp->f_bitclk = config->f_inputclk / sck_div;
/* Enable bit-clock */
udelay(100);
@@ -344,20 +354,27 @@ static int configure_multichannel(struct ux500_msp *msp,
return 0;
}
-static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
+static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config,
+ bool first)
{
- int status = 0;
- u32 reg_val_DMACR, reg_val_GCR;
+ int status;
+ u32 reg_val_DMACR;
/* Configure msp with protocol dependent settings */
- configure_protocol(msp, config);
- setup_bitclk(msp, config);
+ status = configure_protocol(msp, config);
+ if (status)
+ return status;
+
+ if (first && config->clock_provider) {
+ status = setup_bitclk(msp, config);
+ if (status)
+ return status;
+ }
+
if (config->multichannel_configured == 1) {
status = configure_multichannel(msp, config);
if (status)
- dev_warn(msp->dev,
- "%s: WARN: configure_multichannel failed (%d)!\n",
- __func__, status);
+ return status;
}
reg_val_DMACR = readl(msp->registers + MSP_DMACR);
@@ -369,11 +386,7 @@ static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
writel(config->iodelay, msp->registers + MSP_IODLY);
- /* Enable frame generation logic */
- reg_val_GCR = readl(msp->registers + MSP_GCR);
- writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR);
-
- return status;
+ return 0;
}
static void flush_fifo_rx(struct ux500_msp *msp)
@@ -411,12 +424,37 @@ static void flush_fifo_tx(struct ux500_msp *msp)
writel(reg_val_GCR, msp->registers + MSP_GCR);
}
+static bool ux500_msp_config_compatible(struct ux500_msp *msp,
+ struct ux500_msp_config *config)
+{
+ struct ux500_msp_config *active = &msp->config;
+
+ return active->f_inputclk == config->f_inputclk &&
+ active->tx_clk_sel == config->tx_clk_sel &&
+ active->rx_clk_sel == config->rx_clk_sel &&
+ active->srg_clk_sel == config->srg_clk_sel &&
+ active->rx_fsync_pol == config->rx_fsync_pol &&
+ active->tx_fsync_pol == config->tx_fsync_pol &&
+ active->rx_fsync_sel == config->rx_fsync_sel &&
+ active->tx_fsync_sel == config->tx_fsync_sel &&
+ active->default_protdesc == config->default_protdesc &&
+ active->protocol == config->protocol &&
+ active->frame_freq == config->frame_freq &&
+ active->data_size == config->data_size &&
+ active->def_elem_len == config->def_elem_len &&
+ active->clock_provider == config->clock_provider &&
+ active->bclk_inverted == config->bclk_inverted &&
+ !memcmp(&active->protdesc, &config->protdesc,
+ sizeof(active->protdesc));
+}
+
int ux500_msp_i2s_open(struct ux500_msp *msp,
struct ux500_msp_config *config)
{
u32 old_reg, new_reg, mask;
int res;
unsigned int tx_sel, rx_sel, tx_busy, rx_busy;
+ bool first;
if (in_interrupt()) {
dev_err(msp->dev,
@@ -444,40 +482,68 @@ int ux500_msp_i2s_open(struct ux500_msp *msp,
return -EBUSY;
}
- msp->dir_busy |= (tx_sel ? MSP_DIR_TX : 0) | (rx_sel ? MSP_DIR_RX : 0);
-
- /* First do the global config register */
- mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |
- TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
- RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
- LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
-
- new_reg = (config->tx_clk_sel | config->rx_clk_sel |
- config->rx_fsync_pol | config->tx_fsync_pol |
- config->rx_fsync_sel | config->tx_fsync_sel |
- config->rx_fifo_config | config->tx_fifo_config |
- config->srg_clk_sel | config->loopback_enable |
- config->tx_data_enable);
+ first = !msp->dir_busy;
+ if (!first && !ux500_msp_config_compatible(msp, config)) {
+ dev_err(msp->dev, "%s: Incompatible duplex configuration\n",
+ __func__);
+ return -EBUSY;
+ }
- old_reg = readl(msp->registers + MSP_GCR);
- old_reg &= ~mask;
- new_reg |= old_reg;
- writel(new_reg, msp->registers + MSP_GCR);
+ if (first) {
+ /* First do the global config register */
+ mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |
+ TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
+ RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK |
+ SRG_CLK_SEL_MASK | LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
+
+ new_reg = config->tx_clk_sel | config->rx_clk_sel |
+ config->rx_fsync_pol | config->tx_fsync_pol |
+ config->rx_fsync_sel | config->tx_fsync_sel |
+ config->rx_fifo_config | config->tx_fifo_config |
+ config->srg_clk_sel | config->loopback_enable |
+ config->tx_data_enable;
+
+ old_reg = readl(msp->registers + MSP_GCR);
+ old_reg &= ~mask;
+ new_reg |= old_reg;
+ writel(new_reg, msp->registers + MSP_GCR);
+ writel(MSP_WMRK_TX_4_ELEMENTS | MSP_WMRK_RX_4_ELEMENTS,
+ msp->registers + MSP_WMRK);
+ }
- res = enable_msp(msp, config);
+ res = enable_msp(msp, config, first);
if (res < 0) {
dev_err(msp->dev, "%s: ERROR: enable_msp failed (%d)!\n",
__func__, res);
- return -EBUSY;
+ if (tx_sel)
+ writel(0, msp->registers + MSP_TCF);
+ if (rx_sel)
+ writel(0, msp->registers + MSP_RCF);
+ if (first) {
+ writel(0, msp->registers + MSP_GCR);
+ writel(0, msp->registers + MSP_DMACR);
+ writel(0, msp->registers + MSP_SRG);
+ writel(0, msp->registers + MSP_MCR);
+ }
+ return res;
+ }
+
+ msp->dir_busy |= config->direction;
+ if (first) {
+ msp->config = *config;
+ msp->clock_provider = config->clock_provider;
}
if (config->loopback_enable & 0x80)
msp->loopback_enable = 1;
/* Flush FIFOs */
- flush_fifo_tx(msp);
- flush_fifo_rx(msp);
+ if (tx_sel)
+ flush_fifo_tx(msp);
+ if (rx_sel)
+ flush_fifo_rx(msp);
- msp->msp_state = MSP_STATE_CONFIGURED;
+ if (!msp->dir_running)
+ msp->msp_state = MSP_STATE_CONFIGURED;
return 0;
}
@@ -494,7 +560,6 @@ static void disable_msp_rx(struct ux500_msp *msp)
~(RX_SERVICE_INT | RX_OVERRUN_ERROR_INT),
msp->registers + MSP_IMSC);
- msp->dir_busy &= ~MSP_DIR_RX;
}
static void disable_msp_tx(struct ux500_msp *msp)
@@ -510,7 +575,6 @@ static void disable_msp_tx(struct ux500_msp *msp)
~(TX_SERVICE_INT | TX_UNDERRUN_ERR_INT),
msp->registers + MSP_IMSC);
- msp->dir_busy &= ~MSP_DIR_TX;
}
static int disable_msp(struct ux500_msp *msp, unsigned int dir)
@@ -520,7 +584,7 @@ static int disable_msp(struct ux500_msp *msp, unsigned int dir)
reg_val_GCR = readl(msp->registers + MSP_GCR);
disable_tx = dir & MSP_DIR_TX;
- disable_rx = dir & MSP_DIR_TX;
+ disable_rx = dir & MSP_DIR_RX;
if (disable_tx && disable_rx) {
reg_val_GCR = readl(msp->registers + MSP_GCR);
writel(reg_val_GCR | LOOPBACK_MASK,
@@ -553,7 +617,15 @@ static int disable_msp(struct ux500_msp *msp, unsigned int dir)
int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
{
- u32 reg_val_GCR, enable_bit;
+ u32 reg_val_DMACR, reg_val_GCR, dma_enable_bit, enable_bit;
+ unsigned int dir;
+
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = MSP_DIR_TX;
+ else if (direction == SNDRV_PCM_STREAM_CAPTURE)
+ dir = MSP_DIR_RX;
+ else
+ return -EINVAL;
if (msp->msp_state == MSP_STATE_IDLE) {
dev_err(msp->dev, "%s: ERROR: MSP is not configured!\n",
@@ -565,21 +637,44 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
enable_bit = TX_ENABLE;
- else
+ dma_enable_bit = TX_DMA_ENABLE;
+ } else {
enable_bit = RX_ENABLE;
+ dma_enable_bit = RX_DMA_ENABLE;
+ }
+ if (!(msp->dir_busy & dir))
+ return -EINVAL;
+ reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+ writel(reg_val_DMACR | dma_enable_bit,
+ msp->registers + MSP_DMACR);
reg_val_GCR = readl(msp->registers + MSP_GCR);
+ if (msp->clock_provider)
+ enable_bit |= FRAME_GEN_ENABLE;
writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR);
+ msp->dir_running |= dir;
+ msp->msp_state = MSP_STATE_RUNNING;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ if (!(msp->dir_busy & dir))
+ return -EINVAL;
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
disable_msp_tx(msp);
- else
+ msp->dir_running &= ~MSP_DIR_TX;
+ } else {
disable_msp_rx(msp);
+ msp->dir_running &= ~MSP_DIR_RX;
+ }
+ if (!msp->dir_running) {
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR & ~FRAME_GEN_ENABLE,
+ msp->registers + MSP_GCR);
+ msp->msp_state = MSP_STATE_CONFIGURED;
+ }
break;
default:
return -EINVAL;
@@ -594,7 +689,18 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
+ if (!dir || dir & ~(MSP_DIR_TX | MSP_DIR_RX) ||
+ (msp->dir_busy & dir) != dir)
+ return -EINVAL;
+
status = disable_msp(msp, dir);
+ msp->dir_busy &= ~dir;
+ msp->dir_running &= ~dir;
+ if (msp->dir_busy && !msp->dir_running) {
+ writel(readl(msp->registers + MSP_GCR) & ~FRAME_GEN_ENABLE,
+ msp->registers + MSP_GCR);
+ msp->msp_state = MSP_STATE_CONFIGURED;
+ }
if (msp->dir_busy == 0) {
/* disable sample rate and frame generators */
msp->msp_state = MSP_STATE_IDLE;
@@ -618,6 +724,8 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
writel(0, msp->registers + MSP_RCE1);
writel(0, msp->registers + MSP_RCE2);
writel(0, msp->registers + MSP_RCE3);
+ memset(&msp->config, 0, sizeof(msp->config));
+ msp->clock_provider = false;
}
return status;
@@ -627,7 +735,7 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
int ux500_msp_i2s_init_msp(struct platform_device *pdev,
struct ux500_msp **msp_p)
{
- struct resource *res = NULL;
+ struct resource *res;
struct ux500_msp *msp;
*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
@@ -637,20 +745,10 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
msp->dev = &pdev->dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "%s: ERROR: Unable to get resource!\n",
- __func__);
- return -ENOMEM;
- }
-
+ msp->registers = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(msp->registers))
+ return PTR_ERR(msp->registers);
msp->tx_rx_addr = res->start + MSP_DR;
- msp->registers = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (msp->registers == NULL) {
- dev_err(&pdev->dev, "%s: ERROR: ioremap failed!\n", __func__);
- return -ENOMEM;
- }
msp->msp_state = MSP_STATE_IDLE;
msp->loopback_enable = 0;
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
index 69d4ebc409fc..2bf2699bdc49 100644
--- a/sound/soc/ux500/ux500_msp_i2s.h
+++ b/sound/soc/ux500/ux500_msp_i2s.h
@@ -12,8 +12,6 @@
#include <linux/platform_device.h>
-#define MSP_INPUT_FREQ_APB 48000000
-
/*** Stereo mode. Used for APB data accesses as 16 bits accesses (mono),
* 32 bits accesses (stereo).
***/
@@ -64,6 +62,7 @@ enum msp_direction {
#define MSP_SRG 0x10
#define MSP_FLR 0x14
#define MSP_DMACR 0x18
+#define MSP_WMRK 0x1c
#define MSP_IMSC 0x20
#define MSP_RIS 0x24
@@ -230,6 +229,10 @@ enum msp_direction {
#define RDMAE_SHIFT 0
#define TDMAE_SHIFT 1
+/* FIFO watermark register */
+#define MSP_WMRK_RX_4_ELEMENTS BIT(0)
+#define MSP_WMRK_TX_4_ELEMENTS BIT(3)
+
/* Interrupt Register */
#define RX_SERVICE_INT BIT(0)
#define RX_OVERRUN_ERROR_INT BIT(1)
@@ -460,6 +463,8 @@ struct ux500_msp_config {
enum msp_data_size data_size;
unsigned int def_elem_len;
unsigned int iodelay;
+ bool clock_provider;
+ bool bclk_inverted;
};
struct ux500_msp {
@@ -470,8 +475,11 @@ struct ux500_msp {
enum msp_state msp_state;
int def_elem_len;
unsigned int dir_busy;
+ unsigned int dir_running;
int loopback_enable;
unsigned int f_bitclk;
+ bool clock_provider;
+ struct ux500_msp_config config;
};
int ux500_msp_i2s_init_msp(struct platform_device *pdev,