diff options
Diffstat (limited to 'sound/soc')
59 files changed, 729 insertions, 183 deletions
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 92c5ff0deea2..607a3eaeb6da 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -101,7 +101,7 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas struct acp_stream *stream; int slot_len, no_of_slots; - chip = dev_get_platdata(dev); + chip = dev_get_drvdata(dev->parent); switch (slot_width) { case SLOT_WIDTH_8: slot_len = 8; diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index 3be401c72270..99a244f495bd 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -267,7 +267,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card, /* generate DAI links by each sdw link */ while (sof_dais->initialised) { - int current_be_id; + int current_be_id = 0; ret = create_sdw_dailink(card, sof_dais, dai_links, ¤t_be_id, codec_conf); diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index e632f16c9102..1689b6b22598 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -315,6 +315,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83HN"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "83L3"), } }, @@ -342,6 +349,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { { .driver_data = &acp6x_card, .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "RB"), + DMI_MATCH(DMI_PRODUCT_NAME, "Nitro ANV15-41"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "83J2"), } @@ -349,6 +363,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { { .driver_data = &acp6x_card, .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83J3"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"), } @@ -360,7 +381,7 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "M5402RA"), } }, - { + { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), @@ -440,6 +461,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { { .driver_data = &acp6x_card, .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), + DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 17 D7VF"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Alienware"), DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"), } @@ -504,6 +532,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "Victus by HP Gaming Laptop 15-fb2xxx"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), DMI_MATCH(DMI_BOARD_NAME, "8A42"), } }, diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index c9e7d40c47cc..4a4ec1c09e13 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -464,6 +464,28 @@ err: return -EINVAL; } +static int mca_fe_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + unsigned int mask, nchannels; + + if (cl->tdm_slots) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + mask = cl->tdm_tx_mask; + else + mask = cl->tdm_rx_mask; + + nchannels = hweight32(mask); + } else { + nchannels = 2; + } + + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + 1, nchannels); +} + static int mca_fe_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { @@ -680,6 +702,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, } static const struct snd_soc_dai_ops mca_fe_ops = { + .startup = mca_fe_startup, .set_fmt = mca_fe_set_fmt, .set_bclk_ratio = mca_set_bclk_ratio, .set_tdm_slot = mca_fe_set_tdm_slot, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0d9d1d250f2b..6a72561c4189 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -746,10 +746,9 @@ config SND_SOC_CS_AMP_LIB tristate config SND_SOC_CS_AMP_LIB_TEST - tristate "KUnit test for Cirrus Logic cs-amp-lib" - depends on KUNIT + tristate "KUnit test for Cirrus Logic cs-amp-lib" if !KUNIT_ALL_TESTS + depends on SND_SOC_CS_AMP_LIB && KUNIT default KUNIT_ALL_TESTS - select SND_SOC_CS_AMP_LIB help This builds KUnit tests for the Cirrus Logic common amplifier library. diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 195841a567c3..9007484b31c7 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -811,7 +811,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) break; default: dev_err(cs35l56_base->dev, "Unknown device %x\n", devid); - return ret; + return -ENODEV; } cs35l56_base->type = devid & 0xFF; diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c index 73d764fc8539..984a7f470a31 100644 --- a/sound/soc/codecs/cs42l43-jack.c +++ b/sound/soc/codecs/cs42l43-jack.c @@ -654,6 +654,10 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv) reinit_completion(&priv->type_detect); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, + CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, + CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK); + cs42l43_start_hs_bias(priv, true); regmap_update_bits(cs42l43->regmap, CS42L43_HS2, CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT); @@ -665,6 +669,9 @@ static int cs42l43_run_type_detect(struct cs42l43_codec *priv) CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT); cs42l43_stop_hs_bias(priv); + regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL, + CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_VAL_MASK, 0); + if (!time_left) return -ETIMEDOUT; diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index ddc00927313c..dc7794c9ac44 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -152,7 +152,7 @@ int hda_codec_probe_complete(struct hda_codec *codec) ret = snd_hda_codec_build_controls(codec); if (ret < 0) { dev_err(&hdev->dev, "unable to create controls %d\n", ret); - goto out; + return ret; } /* Bus suspended codecs as it does not manage their pm */ @@ -160,7 +160,7 @@ int hda_codec_probe_complete(struct hda_codec *codec) /* rpm was forbidden in snd_hda_codec_device_new() */ snd_hda_codec_set_power_save(codec, 2000); snd_hda_codec_register(codec); -out: + /* Complement pm_runtime_get_sync(bus) in probe */ pm_runtime_mark_last_busy(bus->dev); pm_runtime_put_autosuspend(bus->dev); diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h index c234f2f4276a..78ada3a5bfae 100644 --- a/sound/soc/codecs/mt6359-accdet.h +++ b/sound/soc/codecs/mt6359-accdet.h @@ -123,6 +123,15 @@ struct mt6359_accdet { struct workqueue_struct *jd_workqueue; }; +#if IS_ENABLED(CONFIG_SND_SOC_MT6359_ACCDET) int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); +#else +static inline int +mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + return -EOPNOTSUPP; +} +#endif #endif diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index fac0617ab95b..6cbb8d0535b0 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -493,9 +493,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, } break; case 24: - if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) || - (format == SND_SOC_DAIFMT_DSP_B)) { - dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n"); + if (!provider_mode && ((format == SND_SOC_DAIFMT_DSP_A) || + (format == SND_SOC_DAIFMT_DSP_B))) { + dev_err(component->dev, "24-bit slots not supported in consumer mode using DSP\n"); return -EINVAL; } break; diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 5d99877f8839..e59bb77edf09 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -14,7 +14,7 @@ #include <linux/unaligned.h> #include <linux/firmware.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/of_irq.h> @@ -2035,10 +2035,8 @@ static const struct regmap_config pcmdevice_i2c_regmap = { static void pcmdevice_remove(struct pcmdevice_priv *pcm_dev) { - if (gpio_is_valid(pcm_dev->irq_info.gpio)) { - gpio_free(pcm_dev->irq_info.gpio); - free_irq(pcm_dev->irq_info.nmb, pcm_dev); - } + if (pcm_dev->irq) + free_irq(pcm_dev->irq, pcm_dev); mutex_destroy(&pcm_dev->codec_lock); } @@ -2110,7 +2108,7 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c) ndev = 1; dev_addrs[0] = i2c->addr; } - pcm_dev->irq_info.gpio = of_irq_get(np, 0); + pcm_dev->irq = of_irq_get(np, 0); for (i = 0; i < ndev; i++) pcm_dev->addr[i] = dev_addrs[i]; @@ -2133,22 +2131,10 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c) if (pcm_dev->chip_id == PCM1690) goto skip_interrupt; - if (gpio_is_valid(pcm_dev->irq_info.gpio)) { - dev_dbg(pcm_dev->dev, "irq-gpio = %d", pcm_dev->irq_info.gpio); - - ret = gpio_request(pcm_dev->irq_info.gpio, "PCMDEV-IRQ"); - if (!ret) { - int gpio = pcm_dev->irq_info.gpio; - - gpio_direction_input(gpio); - pcm_dev->irq_info.nmb = gpio_to_irq(gpio); - - } else - dev_err(pcm_dev->dev, "%s: GPIO %d request error\n", - __func__, pcm_dev->irq_info.gpio); + if (pcm_dev->irq) { + dev_dbg(pcm_dev->dev, "irq = %d", pcm_dev->irq); } else - dev_err(pcm_dev->dev, "Looking up irq-gpio failed %d\n", - pcm_dev->irq_info.gpio); + dev_err(pcm_dev->dev, "No irq provided\n"); skip_interrupt: ret = devm_snd_soc_register_component(&i2c->dev, diff --git a/sound/soc/codecs/pcm6240.h b/sound/soc/codecs/pcm6240.h index 1e125bb97286..2d8f9e798139 100644 --- a/sound/soc/codecs/pcm6240.h +++ b/sound/soc/codecs/pcm6240.h @@ -208,11 +208,6 @@ struct pcmdevice_regbin { struct pcmdevice_config_info **cfg_info; }; -struct pcmdevice_irqinfo { - int gpio; - int nmb; -}; - struct pcmdevice_priv { struct snd_soc_component *component; struct i2c_client *client; @@ -221,7 +216,7 @@ struct pcmdevice_priv { struct gpio_desc *hw_rst; struct regmap *regmap; struct pcmdevice_regbin regbin; - struct pcmdevice_irqinfo irq_info; + int irq; unsigned int addr[PCMDEVICE_MAX_I2C_DEVICES]; unsigned int chip_id; int cur_conf; diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index f2d194e76a94..8755a63478d7 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -2085,7 +2085,7 @@ static const struct reg_sequence rt1320_vc_patch_code_write[] = { { 0x3fc2bfc0, 0x03 }, { 0x0000d486, 0x43 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00 }, - { 0x1000db00, 0x04 }, + { 0x1000db00, 0x07 }, { 0x1000db01, 0x00 }, { 0x1000db02, 0x11 }, { 0x1000db03, 0x00 }, @@ -2106,6 +2106,21 @@ static const struct reg_sequence rt1320_vc_patch_code_write[] = { { 0x1000db12, 0x00 }, { 0x1000db13, 0x00 }, { 0x1000db14, 0x45 }, + { 0x1000db15, 0x0d }, + { 0x1000db16, 0x01 }, + { 0x1000db17, 0x00 }, + { 0x1000db18, 0x00 }, + { 0x1000db19, 0xbf }, + { 0x1000db1a, 0x13 }, + { 0x1000db1b, 0x09 }, + { 0x1000db1c, 0x00 }, + { 0x1000db1d, 0x00 }, + { 0x1000db1e, 0x00 }, + { 0x1000db1f, 0x12 }, + { 0x1000db20, 0x09 }, + { 0x1000db21, 0x00 }, + { 0x1000db22, 0x00 }, + { 0x1000db23, 0x00 }, { 0x0000d540, 0x01 }, { 0x0000c081, 0xfc }, { 0x0000f01e, 0x80 }, diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index 5449d6b5cf3d..bf83f4bc94fc 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -28,9 +28,50 @@ static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg) 0): case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, 0): - case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, - 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, - RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03, RT722_SDCA_CTL_SELECTED_MODE, + 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_MUTE, CH_L) ... + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_MUTE, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D, + RT722_SDCA_CTL_SELECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, + RT722_SDCA_CTL_FU_MUTE, CH_L) ... + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, + RT722_SDCA_CTL_FU_MUTE, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, + RT722_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, + RT722_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, + RT722_SDCA_CTL_FU_MUTE, CH_01) ... + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, + RT722_SDCA_CTL_FU_MUTE, CH_04): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, + RT722_SDCA_CTL_VENDOR_DEF, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, + RT722_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... + SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_MUTE, CH_L) ... + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_MUTE, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, + RT722_SDCA_CTL_VENDOR_DEF, CH_08): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, + RT722_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: return true; default: @@ -74,6 +115,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x5600000 ... 0x5600007: case 0x5700000 ... 0x5700004: case 0x5800000 ... 0x5800004: + case 0x5810000: case 0x5b00003: case 0x5c00011: case 0x5d00006: @@ -81,6 +123,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x5f00030: case 0x6100000 ... 0x6100051: case 0x6100055 ... 0x6100057: + case 0x6100060: case 0x6100062: case 0x6100064 ... 0x6100065: case 0x6100067: diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 58315eab492a..e8fbe8a399f6 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -14,6 +14,7 @@ #include <linux/regulator/consumer.h> #include <linux/regmap.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <sound/soc.h> #include <sound/pcm.h> @@ -23,6 +24,11 @@ #include "tas2764.h" +enum tas2764_devid { + DEVID_TAS2764 = 0, + DEVID_SN012776 = 1 +}; + struct tas2764_priv { struct snd_soc_component *component; struct gpio_desc *reset_gpio; @@ -30,7 +36,8 @@ struct tas2764_priv { struct regmap *regmap; struct device *dev; int irq; - + enum tas2764_devid devid; + int v_sense_slot; int i_sense_slot; @@ -180,33 +187,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new tas2764_asi1_mux = SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum); -static int tas2764_dac_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); - int ret; - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - tas2764->dac_powered = true; - ret = tas2764_update_pwr_ctrl(tas2764); - break; - case SND_SOC_DAPM_PRE_PMD: - tas2764->dac_powered = false; - ret = tas2764_update_pwr_ctrl(tas2764); - break; - default: - dev_err(tas2764->dev, "Unsupported event\n"); - return -EINVAL; - } - - if (ret < 0) - return ret; - - return 0; -} - static const struct snd_kcontrol_new isense_switch = SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1); static const struct snd_kcontrol_new vsense_switch = @@ -219,8 +199,7 @@ static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = { 1, &isense_switch), SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN, 1, &vsense_switch), - SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_OUTPUT("OUT"), SND_SOC_DAPM_SIGGEN("VMON"), SND_SOC_DAPM_SIGGEN("IMON") @@ -241,9 +220,28 @@ static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction) { struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(dai->component); + int ret; + + if (!mute) { + tas2764->dac_powered = true; + ret = tas2764_update_pwr_ctrl(tas2764); + if (ret) + return ret; + } tas2764->unmuted = !mute; - return tas2764_update_pwr_ctrl(tas2764); + ret = tas2764_update_pwr_ctrl(tas2764); + if (ret) + return ret; + + if (mute) { + tas2764->dac_powered = false; + ret = tas2764_update_pwr_ctrl(tas2764); + if (ret) + return ret; + } + + return 0; } static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth) @@ -534,10 +532,18 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = { }, }; +static uint8_t sn012776_bop_presets[] = { + 0x01, 0x32, 0x02, 0x22, 0x83, 0x2d, 0x80, 0x02, 0x06, + 0x32, 0x46, 0x30, 0x02, 0x06, 0x38, 0x40, 0x30, 0x02, + 0x06, 0x3e, 0x37, 0x30, 0xff, 0xe6 +}; + +static const struct regmap_config tas2764_i2c_regmap; + static int tas2764_codec_probe(struct snd_soc_component *component) { struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); - int ret; + int ret, i; tas2764->component = component; @@ -547,9 +553,10 @@ static int tas2764_codec_probe(struct snd_soc_component *component) } tas2764_reset(tas2764); + regmap_reinit_cache(tas2764->regmap, &tas2764_i2c_regmap); if (tas2764->irq) { - ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff); + ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0x00); if (ret < 0) return ret; @@ -586,6 +593,27 @@ static int tas2764_codec_probe(struct snd_soc_component *component) if (ret < 0) return ret; + switch (tas2764->devid) { + case DEVID_SN012776: + ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, + TAS2764_PWR_CTRL_BOP_SRC, + TAS2764_PWR_CTRL_BOP_SRC); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(sn012776_bop_presets); i++) { + ret = snd_soc_component_write(component, + TAS2764_BOP_CFG0 + i, + sn012776_bop_presets[i]); + + if (ret < 0) + return ret; + } + break; + default: + break; + } + return 0; } @@ -634,6 +662,7 @@ static const struct reg_default tas2764_reg_defaults[] = { { TAS2764_TDM_CFG2, 0x0a }, { TAS2764_TDM_CFG3, 0x10 }, { TAS2764_TDM_CFG5, 0x42 }, + { TAS2764_INT_CLK_CFG, 0x19 }, }; static const struct regmap_range_cfg tas2764_regmap_ranges[] = { @@ -651,6 +680,7 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = { static bool tas2764_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case TAS2764_SW_RST: case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: case TAS2764_INT_CLK_CFG: return true; @@ -715,6 +745,8 @@ static int tas2764_i2c_probe(struct i2c_client *client) if (!tas2764) return -ENOMEM; + tas2764->devid = (enum tas2764_devid)of_device_get_match_data(&client->dev); + tas2764->dev = &client->dev; tas2764->irq = client->irq; i2c_set_clientdata(client, tas2764); @@ -751,7 +783,8 @@ MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id tas2764_of_match[] = { - { .compatible = "ti,tas2764" }, + { .compatible = "ti,tas2764", .data = (void *)DEVID_TAS2764 }, + { .compatible = "ti,sn012776", .data = (void *)DEVID_SN012776 }, {}, }; MODULE_DEVICE_TABLE(of, tas2764_of_match); diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h index 9490f2686e38..69c0f91cb423 100644 --- a/sound/soc/codecs/tas2764.h +++ b/sound/soc/codecs/tas2764.h @@ -29,6 +29,7 @@ #define TAS2764_PWR_CTRL_ACTIVE 0x0 #define TAS2764_PWR_CTRL_MUTE BIT(0) #define TAS2764_PWR_CTRL_SHUTDOWN BIT(1) +#define TAS2764_PWR_CTRL_BOP_SRC BIT(7) #define TAS2764_VSENSE_POWER_EN 3 #define TAS2764_ISENSE_POWER_EN 4 @@ -116,4 +117,6 @@ #define TAS2764_INT_CLK_CFG TAS2764_REG(0x0, 0x5c) #define TAS2764_INT_CLK_CFG_IRQZ_CLR BIT(2) +#define TAS2764_BOP_CFG0 TAS2764_REG(0X0, 0x1d) + #endif /* __TAS2764__ */ diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 863c3f672ba9..0931b6109755 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -156,11 +156,37 @@ static const struct snd_kcontrol_new isense_switch = static const struct snd_kcontrol_new vsense_switch = SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1); +static int sense_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); + + /* + * Powering up ISENSE/VSENSE requires a trip through the shutdown state. + * Do that here to ensure that our changes are applied properly, otherwise + * we might end up with non-functional IVSENSE if playback started earlier, + * which would break software speaker protection. + */ + switch (event) { + case SND_SOC_DAPM_PRE_REG: + return snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, + TAS2770_PWR_CTRL_MASK, + TAS2770_PWR_CTRL_SHUTDOWN); + case SND_SOC_DAPM_POST_REG: + return tas2770_update_pwr_ctrl(tas2770); + default: + return 0; + } +} + static const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2770_asi1_mux), - SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch), - SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch), + SND_SOC_DAPM_SWITCH_E("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch, + sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG), + SND_SOC_DAPM_SWITCH_E("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch, + sense_event, SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG), SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_OUTPUT("OUT"), diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 373a31ddccb2..1375ac571fbf 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -17,7 +17,7 @@ #include <sound/soc.h> #include <sound/pcm_params.h> #include <sound/soc-dapm.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/of_irq.h> #include <sound/tlv.h> @@ -329,8 +329,7 @@ struct wcd9335_codec { int comp_enabled[COMPANDER_MAX]; int intr1; - int reset_gpio; - struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; + struct gpio_desc *reset_gpio; unsigned int rx_port_value[WCD9335_RX_MAX]; unsigned int tx_port_value[WCD9335_TX_MAX]; @@ -353,6 +352,10 @@ struct wcd9335_irq { char *name; }; +static const char * const wcd9335_supplies[] = { + "vdd-buck", "vdd-buck-sido", "vdd-tx", "vdd-rx", "vdd-io", +}; + static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = { WCD9335_SLIM_TX_CH(0), WCD9335_SLIM_TX_CH(1), @@ -4973,12 +4976,11 @@ static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = { static int wcd9335_parse_dt(struct wcd9335_codec *wcd) { struct device *dev = wcd->dev; - struct device_node *np = dev->of_node; int ret; - wcd->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); - if (wcd->reset_gpio < 0) - return dev_err_probe(dev, wcd->reset_gpio, "Reset GPIO missing from DT\n"); + wcd->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(wcd->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(wcd->reset_gpio), "Reset GPIO missing from DT\n"); wcd->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(wcd->mclk)) @@ -4988,30 +4990,16 @@ static int wcd9335_parse_dt(struct wcd9335_codec *wcd) if (IS_ERR(wcd->native_clk)) return dev_err_probe(dev, PTR_ERR(wcd->native_clk), "slimbus clock not found\n"); - wcd->supplies[0].supply = "vdd-buck"; - wcd->supplies[1].supply = "vdd-buck-sido"; - wcd->supplies[2].supply = "vdd-tx"; - wcd->supplies[3].supply = "vdd-rx"; - wcd->supplies[4].supply = "vdd-io"; - - ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies); + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd9335_supplies), + wcd9335_supplies); if (ret) - return dev_err_probe(dev, ret, "Failed to get supplies\n"); + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); return 0; } static int wcd9335_power_on_reset(struct wcd9335_codec *wcd) { - struct device *dev = wcd->dev; - int ret; - - ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, wcd->supplies); - if (ret) { - dev_err(dev, "Failed to get supplies: err = %d\n", ret); - return ret; - } - /* * For WCD9335, it takes about 600us for the Vout_A and * Vout_D to be ready after BUCK_SIDO is powered up. @@ -5021,9 +5009,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd) */ usleep_range(600, 650); - gpio_direction_output(wcd->reset_gpio, 0); + gpiod_set_value(wcd->reset_gpio, 1); msleep(20); - gpio_set_value(wcd->reset_gpio, 1); + gpiod_set_value(wcd->reset_gpio, 0); msleep(20); return 0; diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 910852eb9698..c7f1b28f3b23 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -2273,7 +2273,7 @@ static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data) { struct wcd934x_codec *wcd = data; unsigned long status = 0; - int i, j, port_id; + unsigned int i, j, port_id; unsigned int val, int_val = 0; irqreturn_t ret = IRQ_NONE; bool tx; diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 9c1997a42334..1df827a084ca 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -92,7 +92,6 @@ struct wcd937x_priv { struct regmap_irq_chip *wcd_regmap_irq_chip; struct regmap_irq_chip_data *irq_chip; struct regulator_bulk_data supplies[WCD937X_MAX_BULK_SUPPLY]; - struct regulator *buck_supply; struct snd_soc_jack *jack; unsigned long status_mask; s32 micb_ref[WCD937X_MAX_MICBIAS]; @@ -2897,10 +2896,8 @@ static int wcd937x_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "Failed to get supplies\n"); ret = regulator_bulk_enable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - if (ret) { - regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); + if (ret) return dev_err_probe(dev, ret, "Failed to enable supplies\n"); - } wcd937x_dt_parse_micbias_info(dev, wcd937x); @@ -2936,7 +2933,6 @@ static int wcd937x_probe(struct platform_device *pdev) err_disable_regulators: regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); return ret; } @@ -2953,7 +2949,6 @@ static void wcd937x_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(dev); regulator_bulk_disable(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); - regulator_bulk_free(WCD937X_MAX_BULK_SUPPLY, wcd937x->supplies); } #if defined(CONFIG_OF) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 47da5674d7c9..e31b7fb104e6 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -529,7 +529,7 @@ static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = { }, [WSA883X_PORT_VISENSE] = { .num = WSA883X_PORT_VISENSE + 1, - .ch_mask = 0x3, + .ch_mask = 0x1, }, }; diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 560a2c04b695..18b0ee8f15a5 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -891,7 +891,7 @@ static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = { }, [WSA884X_PORT_VISENSE] = { .num = WSA884X_PORT_VISENSE + 1, - .ch_mask = 0x3, + .ch_mask = 0x1, }, [WSA884X_PORT_CPS] = { .num = WSA884X_PORT_CPS + 1, diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index bd5c46d763c0..ffd4a6ca5f3c 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -517,7 +517,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); regmap_update_bits(asrc->regmap, REG_ASRCTR, - ASRCTR_USRi_MASK(index), 0); + ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), + ASRCTR_USR(index)); /* Set the input and output clock sources */ regmap_update_bits(asrc->regmap, REG_ASRCSR, diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index f501f47242fb..1bba48318e2d 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -156,11 +156,24 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, for_each_dpcm_be(rtd, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *substream_be; - struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(be, 0); + struct snd_soc_dai *dai_cpu = snd_soc_rtd_to_cpu(be, 0); + struct snd_soc_dai *dai_codec = snd_soc_rtd_to_codec(be, 0); + struct snd_soc_dai *dai; if (dpcm->fe != rtd) continue; + /* + * With audio graph card, original cpu dai is changed to codec + * device in backend, so if cpu dai is dummy device in backend, + * get the codec dai device, which is the real hardware device + * connected. + */ + if (!snd_soc_dai_is_dummy(dai_cpu)) + dai = dai_cpu; + else + dai = dai_codec; + substream_be = snd_soc_dpcm_get_substream(be, stream); dma_params_be = snd_soc_dai_get_dma_data(dai, substream_be); dev_be = dai->dev; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index c5efbceb06d1..25d4b27f5b76 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -771,13 +771,15 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) * anymore. Add software reset to fix this issue. * This is a hardware bug, and will be fix in the * next sai version. + * + * In consumer mode, this can happen even after a + * single open/close, especially if both tx and rx + * are running concurrently. */ - if (!sai->is_consumer_mode[tx]) { - /* Software Reset */ - regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); - /* Clear SR bit to finish the reset */ - regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0); - } + /* Software Reset */ + regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); + /* Clear SR bit to finish the reset */ + regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0); } static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 93dbe40008c0..e5ae435171d6 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -516,7 +516,7 @@ static int imx_card_parse_of(struct imx_card_data *data) if (!card->dai_link) return -ENOMEM; - data->link_data = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); + data->link_data = devm_kcalloc(dev, num_links, sizeof(*link_data), GFP_KERNEL); if (!data->link_data) return -ENOMEM; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 975ffd2cad29..809dbb9ded36 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1150,9 +1150,9 @@ void graph_util_parse_link_direction(struct device_node *np, bool is_playback_only = of_property_read_bool(np, "playback-only"); bool is_capture_only = of_property_read_bool(np, "capture-only"); - if (is_playback_only) + if (playback_only) *playback_only = is_playback_only; - if (is_capture_only) + if (capture_only) *capture_only = is_capture_only; } EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c index 1767ded4d983..c9978fb9c74e 100644 --- a/sound/soc/intel/avs/debugfs.c +++ b/sound/soc/intel/avs/debugfs.c @@ -372,7 +372,10 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s return ret; num_elems = *array; - resource_mask = array[1]; + if (!num_elems) { + ret = -EINVAL; + goto free_array; + } /* * Disable if just resource mask is provided - no log priority flags. @@ -380,6 +383,7 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s * Enable input format: mask, prio1, .., prioN * Where 'N' equals number of bits set in the 'mask'. */ + resource_mask = array[1]; if (num_elems == 1) { ret = disable_logs(adev, resource_mask); } else { diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index 4fba46e77c47..eff1d46040da 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -169,7 +169,9 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg dev_crit(adev->dev, "communication severed, rebooting dsp..\n"); - cancel_delayed_work_sync(&ipc->d0ix_work); + /* 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); ipc->in_d0ix = false; /* Re-enabled on recovery completion. */ pm_runtime_disable(adev->dev); diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cc10ae58b0c7..8dee46abf346 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -42,6 +42,7 @@ config SND_SOC_INTEL_SOF_NUVOTON_COMMON tristate config SND_SOC_INTEL_SOF_BOARD_HELPERS + select SND_SOC_ACPI_INTEL_MATCH tristate if SND_SOC_INTEL_CATPT diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 1148e9498d8e..b6434b473126 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -576,6 +576,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { /* Acer Aspire SW3-013 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-013"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 91e146e2487d..a9a740e24969 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -14,7 +14,7 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc soc-acpi-intel-lnl-match.o \ soc-acpi-intel-ptl-match.o \ soc-acpi-intel-hda-match.o \ - soc-acpi-intel-sdw-mockup-match.o + soc-acpi-intel-sdw-mockup-match.o sof-function-topology-lib.o snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c index 24d850df77ca..1ad704ca2c5f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -8,6 +8,7 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> #include <sound/soc-acpi-intel-ssp-common.h> +#include "sof-function-topology-lib.h" static const struct snd_soc_acpi_endpoint single_endpoint = { .num = 0, @@ -138,7 +139,7 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_r1_adr[] = { }, }; -static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = { +static const struct snd_soc_acpi_adr_device cs35l56_3_l3_adr[] = { { .adr = 0x00033301fa355601ull, .num_endpoints = 1, @@ -147,6 +148,24 @@ static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = { }, }; +static const struct snd_soc_acpi_adr_device cs35l56_2_r3_adr[] = { + { + .adr = 0x00023301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = { + { + .adr = 0x00033101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, +}; + static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { { /* Jack Playback Endpoint */ .num = 0, @@ -306,6 +325,25 @@ static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_2_l23[] = { }, { .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_l3_adr), + .adr_d = cs35l56_3_l3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_3_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_r3_adr), + .adr_d = cs35l56_2_r3_adr, + }, + { + .mask = BIT(3), .num_adr = ARRAY_SIZE(cs35l56_3_l1_adr), .adr_d = cs35l56_3_l1_adr, }, @@ -399,36 +437,49 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .links = arl_cs42l43_l0_cs35l56_l23, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2) | BIT(3), .links = arl_cs42l43_l0_cs35l56_2_l23, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = arl_cs42l43_l0_cs35l56_3_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2), .links = arl_cs42l43_l0_cs35l56_l2, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), .links = arl_cs42l43_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l0.tplg", - }, - { - .link_mask = BIT(2), - .links = arl_cs42l43_l2, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(2) | BIT(3), .links = arl_cs42l43_l2_cs35l56_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(2), + .links = arl_cs42l43_l2, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = 0x1, /* link0 required */ @@ -447,6 +498,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .links = arl_rt722_l0_rt1320_l2, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, {}, }; diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c new file mode 100644 index 000000000000..3cc81dcf047e --- /dev/null +++ b/sound/soc/intel/common/sof-function-topology-lib.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2025 Intel Corporation. +// + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/firmware.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "sof-function-topology-lib.h" + +enum tplg_device_id { + TPLG_DEVICE_SDCA_JACK, + TPLG_DEVICE_SDCA_AMP, + TPLG_DEVICE_SDCA_MIC, + TPLG_DEVICE_INTEL_PCH_DMIC, + TPLG_DEVICE_HDMI, + TPLG_DEVICE_MAX +}; + +#define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \ + BIT(TPLG_DEVICE_SDCA_MIC)) + +#define SOF_INTEL_PLATFORM_NAME_MAX 4 + +int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, + const char *prefix, const char ***tplg_files) +{ + struct snd_soc_acpi_mach_params mach_params = mach->mach_params; + struct snd_soc_dai_link *dai_link; + const struct firmware *fw; + char platform[SOF_INTEL_PLATFORM_NAME_MAX]; + unsigned long tplg_mask = 0; + int tplg_num = 0; + int tplg_dev; + int ret; + int i; + + ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform); + if (ret != 1) { + dev_err(card->dev, "Invalid platform name %s of tplg %s\n", + platform, mach->sof_tplg_filename); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + char *tplg_dev_name; + + dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id); + if (strstr(dai_link->name, "SimpleJack")) { + tplg_dev = TPLG_DEVICE_SDCA_JACK; + tplg_dev_name = "sdca-jack"; + } else if (strstr(dai_link->name, "SmartAmp")) { + tplg_dev = TPLG_DEVICE_SDCA_AMP; + tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, + "sdca-%damp", dai_link->num_cpus); + if (!tplg_dev_name) + return -ENOMEM; + } else if (strstr(dai_link->name, "SmartMic")) { + tplg_dev = TPLG_DEVICE_SDCA_MIC; + tplg_dev_name = "sdca-mic"; + } else if (strstr(dai_link->name, "dmic")) { + switch (mach_params.dmic_num) { + case 2: + tplg_dev_name = "dmic-2ch"; + break; + case 4: + tplg_dev_name = "dmic-4ch"; + break; + default: + dev_warn(card->dev, + "unsupported number of dmics: %d\n", + mach_params.dmic_num); + continue; + } + tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC; + } else if (strstr(dai_link->name, "iDisp")) { + tplg_dev = TPLG_DEVICE_HDMI; + tplg_dev_name = "hdmi-pcm5"; + + } else { + /* The dai link is not supported by separated tplg yet */ + dev_dbg(card->dev, + "dai_link %s is not supported by separated tplg yet\n", + dai_link->name); + return 0; + } + if (tplg_mask & BIT(tplg_dev)) + continue; + + tplg_mask |= BIT(tplg_dev); + + /* + * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg + * where <platform> is only required for the DMIC function as the nhlt blob + * is platform dependent. + */ + switch (tplg_dev) { + case TPLG_DEVICE_INTEL_PCH_DMIC: + (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, + "%s/sof-%s-%s-id%d.tplg", + prefix, platform, + tplg_dev_name, dai_link->id); + break; + default: + (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, + "%s/sof-%s-id%d.tplg", + prefix, tplg_dev_name, + dai_link->id); + break; + } + if (!(*tplg_files)[tplg_num]) + return -ENOMEM; + tplg_num++; + } + + dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); + + /* Check presence of sub-topologies */ + for (i = 0; i < tplg_num; i++) { + ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev); + if (!ret) { + release_firmware(fw); + } else { + dev_dbg(card->dev, "Failed to open topology file: %s\n", (*tplg_files)[i]); + return 0; + } + } + + return tplg_num; +} + diff --git a/sound/soc/intel/common/sof-function-topology-lib.h b/sound/soc/intel/common/sof-function-topology-lib.h new file mode 100644 index 000000000000..e7d0c39d0788 --- /dev/null +++ b/sound/soc/intel/common/sof-function-topology-lib.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * soc-acpi-intel-get-tplg.h - get-tplg-files ops + * + * Copyright (c) 2025, Intel Corporation. + * + */ + +#ifndef _SND_SOC_ACPI_INTEL_GET_TPLG_H +#define _SND_SOC_ACPI_INTEL_GET_TPLG_H + +int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, + const char *prefix, const char ***tplg_files); + +#endif diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c index e69c1bb2cb23..7f411b857782 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c @@ -58,7 +58,15 @@ static const char *aud_clks[MT8188_CLK_NUM] = { [MT8188_CLK_AUD_ADC] = "aud_adc", [MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires", [MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp", + [MT8188_CLK_AUD_AFE_DMIC1] = "aud_afe_dmic1", + [MT8188_CLK_AUD_AFE_DMIC2] = "aud_afe_dmic2", + [MT8188_CLK_AUD_AFE_DMIC3] = "aud_afe_dmic3", + [MT8188_CLK_AUD_AFE_DMIC4] = "aud_afe_dmic4", [MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires", + [MT8188_CLK_AUD_DMIC_HIRES1] = "aud_dmic_hires1", + [MT8188_CLK_AUD_DMIC_HIRES2] = "aud_dmic_hires2", + [MT8188_CLK_AUD_DMIC_HIRES3] = "aud_dmic_hires3", + [MT8188_CLK_AUD_DMIC_HIRES4] = "aud_dmic_hires4", [MT8188_CLK_AUD_I2SIN] = "aud_i2sin", [MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in", [MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out", diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h index ec53c171c170..c6c78d684f3e 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h +++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h @@ -54,7 +54,15 @@ enum { MT8188_CLK_AUD_ADC, MT8188_CLK_AUD_DAC_HIRES, MT8188_CLK_AUD_A1SYS_HP, + MT8188_CLK_AUD_AFE_DMIC1, + MT8188_CLK_AUD_AFE_DMIC2, + MT8188_CLK_AUD_AFE_DMIC3, + MT8188_CLK_AUD_AFE_DMIC4, MT8188_CLK_AUD_ADC_HIRES, + MT8188_CLK_AUD_DMIC_HIRES1, + MT8188_CLK_AUD_DMIC_HIRES2, + MT8188_CLK_AUD_DMIC_HIRES3, + MT8188_CLK_AUD_DMIC_HIRES4, MT8188_CLK_AUD_I2SIN, MT8188_CLK_AUD_TDM_IN, MT8188_CLK_AUD_I2S_OUT, diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c index 73e5c63aeec8..d36520c6272d 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c @@ -2855,10 +2855,6 @@ static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg) case AFE_DMIC3_SRC_DEBUG_MON0: case AFE_DMIC3_UL_SRC_MON0: case AFE_DMIC3_UL_SRC_MON1: - case DMIC_GAIN1_CUR: - case DMIC_GAIN2_CUR: - case DMIC_GAIN3_CUR: - case DMIC_GAIN4_CUR: case ETDM_IN1_MONITOR: case ETDM_IN2_MONITOR: case ETDM_OUT1_MONITOR: diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 8ebf6c7502aa..400cec09c3a3 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -822,12 +822,12 @@ SND_SOC_DAILINK_DEFS(ETDM1_IN_BE, SND_SOC_DAILINK_DEFS(ETDM2_IN_BE, DAILINK_COMP_ARRAY(COMP_CPU("ETDM2_IN")), - DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(ETDM1_OUT_BE, DAILINK_COMP_ARRAY(COMP_CPU("ETDM1_OUT")), - DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(ETDM2_OUT_BE, diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c index 11b9a5bc7163..89575bb8afed 100644 --- a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c +++ b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c @@ -812,11 +812,10 @@ static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { static int mt8365_dai_i2s_set_priv(struct mtk_base_afe *afe) { int i, ret; - struct mt8365_afe_private *afe_priv = afe->platform_priv; for (i = 0; i < DAI_I2S_NUM; i++) { ret = mt8365_dai_set_priv(afe, mt8365_i2s_priv[i].id, - sizeof(*afe_priv), + sizeof(mt8365_i2s_priv[i]), &mt8365_i2s_priv[i]); if (ret) return ret; diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 1a4ef124e4e2..ad38c74166a4 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -231,7 +231,7 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card, const char *p)) { /* If property is not provided, don't fail ... */ - if (!of_property_read_bool(card->dev->of_node, propname)) + if (!of_property_present(card->dev->of_node, propname)) return 0; /* ... but do fail if it is provided and the parsing fails */ diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index a479d7e5b7fb..314ff68506d9 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -91,6 +91,10 @@ static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, else ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, tx_ch, 0, NULL); + if (ret != 0 && ret != -ENOTSUPP) { + dev_err(rtd->dev, "failed to set cpu chan map, err:%d\n", ret); + return ret; + } } return 0; diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 19adadedc88a..1001fd321380 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -7,6 +7,7 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/pcm.h> +#include <sound/pcm_params.h> #include <linux/soundwire/sdw.h> #include <sound/jack.h> #include <linux/input-event-codes.h> @@ -39,9 +40,11 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); rate->min = rate->max = 48000; channels->min = channels->max = 2; + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; } diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c index adb1c008e871..2dc7787234c3 100644 --- a/sound/soc/sdw_utils/soc_sdw_cs42l43.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c @@ -20,6 +20,8 @@ #include <sound/soc-dapm.h> #include <sound/soc_sdw_utils.h> +#define CS42L43_SPK_VOLUME_0DB 128 /* 0dB Max */ + static const struct snd_soc_dapm_route cs42l43_hs_map[] = { { "Headphone", NULL, "cs42l43 AMP3_OUT" }, { "Headphone", NULL, "cs42l43 AMP4_OUT" }, @@ -117,6 +119,14 @@ int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_so return -ENOMEM; } + ret = snd_soc_limit_volume(card, "cs42l43 Speaker Digital Volume", + CS42L43_SPK_VOLUME_0DB); + if (ret) + dev_err(card->dev, "cs42l43 speaker volume limit failed: %d\n", ret); + else + dev_info(card->dev, "Setting CS42L43 Speaker volume limit to %d\n", + CS42L43_SPK_VOLUME_0DB); + ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_spk_map, ARRAY_SIZE(cs42l43_spk_map)); if (ret) diff --git a/sound/soc/sdw_utils/soc_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c index 6951dfb56526..b3d6ca249973 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c @@ -190,7 +190,7 @@ int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc const struct snd_soc_dapm_route *rt_amp_map; char codec_name[CODEC_NAME_SIZE]; struct snd_soc_dai *codec_dai; - int ret; + int ret = -EINVAL; int i; rt_amp_map = get_codec_name_and_route(dai, codec_name); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c index 7f24806d809d..74bca3d04e4f 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c @@ -29,6 +29,8 @@ int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_da mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "rt715-sdca"); else mic_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s", component->name_prefix); + if (!mic_name) + return -ENOMEM; card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s mic:%s", card->components, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 20248a29d167..e3c8d4f20b9c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3057,7 +3057,7 @@ int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop) unsigned int i, nb_controls; int ret; - if (!of_property_read_bool(dev->of_node, prop)) + if (!of_property_present(dev->of_node, prop)) return 0; strings = devm_kcalloc(dev, nb_controls_max, @@ -3131,23 +3131,17 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, if (rx_mask) snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask); - if (of_property_read_bool(np, "dai-tdm-slot-num")) { - ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); - if (ret) - return ret; - - if (slots) - *slots = val; - } - - if (of_property_read_bool(np, "dai-tdm-slot-width")) { - ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); - if (ret) - return ret; + ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); + if (ret && ret != -EINVAL) + return ret; + if (!ret && slots) + *slots = val; - if (slot_width) - *slot_width = val; - } + ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); + if (ret && ret != -EINVAL) + return ret; + if (!ret && slot_width) + *slot_width = val; return 0; } @@ -3411,12 +3405,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, * check "[prefix]frame-master" */ snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); - bit = of_property_read_bool(np, prop); + bit = of_property_present(np, prop); if (bit && bitclkmaster) *bitclkmaster = of_parse_phandle(np, prop, 0); snprintf(prop, sizeof(prop), "%sframe-master", prefix); - frame = of_property_read_bool(np, prop); + frame = of_property_present(np, prop); if (frame && framemaster) *framemaster = of_parse_phandle(np, prop, 0); diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 4e08892d24c6..de09d21add45 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -275,10 +275,11 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, if (dai->driver->ops && dai->driver->ops->xlate_tdm_slot_mask) - dai->driver->ops->xlate_tdm_slot_mask(slots, - &tx_mask, &rx_mask); + ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); else - snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + if (ret) + goto err; for_each_pcm_streams(stream) snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]); @@ -287,6 +288,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, dai->driver->ops->set_tdm_slot) ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, slots, slot_width); +err: return soc_dai_ret(dai, ret); } EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index b0e4e4168f38..fb11003d56cf 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -639,6 +639,33 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); +static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + struct snd_ctl_elem_value uctl; + int ret; + + if (!mc->platform_max) + return 0; + + ret = kctl->get(kctl, &uctl); + if (ret < 0) + return ret; + + if (uctl.value.integer.value[0] > mc->platform_max) + uctl.value.integer.value[0] = mc->platform_max; + + if (snd_soc_volsw_is_stereo(mc) && + uctl.value.integer.value[1] > mc->platform_max) + uctl.value.integer.value[1] = mc->platform_max; + + ret = kctl->put(kctl, &uctl); + if (ret < 0) + return ret; + + return 0; +} + /** * snd_soc_limit_volume - Set new limit to an existing volume control. * @@ -663,7 +690,7 @@ int snd_soc_limit_volume(struct snd_soc_card *card, struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; if (max <= mc->max - mc->min) { mc->platform_max = max; - ret = 0; + ret = snd_soc_clip_to_platform_max(kctl); } } return ret; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 1102599403c5..0e21ff9f7b74 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1633,10 +1633,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, /* * Filter for systems with 'component_chaining' enabled. * This helps to avoid unnecessary re-configuration of an - * already active BE on such systems. + * already active BE on such systems and ensures the BE DAI + * widget is powered ON after hw_params() BE DAI callback. */ if (fe->card->component_chaining && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) continue; diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c index a5d8b6a95a22..fe2ad0395f5d 100644 --- a/sound/soc/sof/amd/pci-acp70.c +++ b/sound/soc/sof/amd/pci-acp70.c @@ -34,6 +34,7 @@ static const struct sof_amd_acp_desc acp70_chip_info = { .ext_intr_cntl = ACP70_EXTERNAL_INTR_CNTL, .ext_intr_stat = ACP70_EXT_INTR_STAT, .ext_intr_stat1 = ACP70_EXT_INTR_STAT1, + .acp_error_stat = ACP70_ERROR_STATUS, .dsp_intr_base = ACP70_DSP_SW_INTR_BASE, .acp_sw0_i2s_err_reason = ACP7X_SW0_I2S_ERROR_REASON, .sram_pte_offset = ACP70_SRAM_PTE_OFFSET, diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 1989147aa6a4..5fe237688b91 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -76,7 +76,7 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev) snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops); - if (chip && chip->hw_ip_version == SOF_INTEL_ACE_2_0) + if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0) bus->use_pio_for_commands = true; #else snd_hdac_ext_bus_init(bus, dev, NULL, NULL); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c924a998d6f9..624598c9e2df 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1007,7 +1007,21 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, if (!*mach && codec_num <= 2) { bool tplg_fixup = false; - hda_mach = snd_soc_acpi_intel_hda_machines; + /* + * make a local copy of the match array since we might + * be modifying it + */ + hda_mach = devm_kmemdup_array(sdev->dev, + snd_soc_acpi_intel_hda_machines, + 2, /* we have one entry + sentinel in the array */ + sizeof(snd_soc_acpi_intel_hda_machines[0]), + GFP_KERNEL); + if (!hda_mach) { + dev_err(bus->dev, + "%s: failed to duplicate the HDA match table\n", + __func__); + return; + } dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); @@ -1195,11 +1209,11 @@ static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach) return 0; } -static char *remove_file_ext(const char *tplg_filename) +static char *remove_file_ext(struct device *dev, const char *tplg_filename) { char *filename, *tmp; - filename = kstrdup(tplg_filename, GFP_KERNEL); + filename = devm_kstrdup(dev, tplg_filename, GFP_KERNEL); if (!filename) return NULL; @@ -1283,7 +1297,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) */ if (!sof_pdata->tplg_filename) { /* remove file extension if it exists */ - tplg_filename = remove_file_ext(mach->sof_tplg_filename); + tplg_filename = remove_file_ext(sdev->dev, mach->sof_tplg_filename); if (!tplg_filename) return NULL; diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 576f407cd456..976a4794d610 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -531,6 +531,14 @@ static int sof_ipc4_bytes_ext_put(struct snd_sof_control *scontrol, return -EINVAL; } + /* Check header id */ + if (header.numid != SOF_CTRL_CMD_BINARY) { + dev_err_ratelimited(scomp->dev, + "Incorrect numid for bytes put %d\n", + header.numid); + return -EINVAL; + } + /* Verify the ABI header first */ if (copy_from_user(&abi_hdr, tlvd->tlv, sizeof(abi_hdr))) return -EFAULT; @@ -613,7 +621,8 @@ static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol, if (data_size > size) return -ENOSPC; - header.numid = scontrol->comp_id; + /* Set header id and length */ + header.numid = SOF_CTRL_CMD_BINARY; header.length = data_size; if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 4df2be3d39eb..9db2cdb32128 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -780,7 +780,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm /* allocate memory for max number of pipeline IDs */ pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines, - sizeof(struct snd_sof_widget *), GFP_KERNEL); + sizeof(*pipeline_list->pipelines), + GFP_KERNEL); if (!pipeline_list->pipelines) { sof_ipc4_pcm_free(sdev, spcm); return -ENOMEM; @@ -794,7 +795,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm spcm->stream[stream].private = stream_priv; - if (!support_info) + /* Delay reporting is only supported on playback */ + if (!support_info || stream == SNDRV_PCM_STREAM_CAPTURE) continue; time_info = kzalloc(sizeof(*time_info), GFP_KERNEL); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 37ca15cc5728..f9708b8fd73b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1059,7 +1059,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, struct snd_sof_dai *dai) { struct snd_soc_card *card = scomp->card; - struct snd_soc_pcm_runtime *rtd; + struct snd_soc_pcm_runtime *rtd, *full, *partial; struct snd_soc_dai *cpu_dai; int stream; int i; @@ -1076,12 +1076,22 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, else goto end; + full = NULL; + partial = NULL; list_for_each_entry(rtd, &card->rtd_list, list) { /* does stream match DAI link ? */ - if (!rtd->dai_link->stream_name || - !strstr(rtd->dai_link->stream_name, w->sname)) - continue; + if (rtd->dai_link->stream_name) { + if (!strcmp(rtd->dai_link->stream_name, w->sname)) { + full = rtd; + break; + } else if (strstr(rtd->dai_link->stream_name, w->sname)) { + partial = rtd; + } + } + } + rtd = full ? full : partial; + if (rtd) { for_each_rtd_cpu_dais(rtd, i, cpu_dai) { /* * Please create DAI widget in the right order diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 330bc0c09f56..93dd88fb805d 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -21,6 +21,7 @@ #include <linux/gpio/consumer.h> #include <sound/core.h> +#include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -235,6 +236,7 @@ struct sun4i_codec { struct clk *clk_module; struct reset_control *rst; struct gpio_desc *gpio_pa; + struct gpio_desc *gpio_hp; /* ADC_FIFOC register is at different offset on different SoCs */ struct regmap_field *reg_adc_fifoc; @@ -1263,6 +1265,49 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { .ops = &dummy_dai_ops, }; +static struct snd_soc_jack sun4i_headphone_jack; + +static struct snd_soc_jack_pin sun4i_headphone_jack_pins[] = { + { .pin = "Headphone", .mask = SND_JACK_HEADPHONE }, +}; + +static struct snd_soc_jack_gpio sun4i_headphone_jack_gpio = { + .name = "hp-det", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, +}; + +static int sun4i_codec_machine_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card); + int ret; + + if (scodec->gpio_hp) { + ret = snd_soc_card_jack_new_pins(card, "Headphone Jack", + SND_JACK_HEADPHONE, + &sun4i_headphone_jack, + sun4i_headphone_jack_pins, + ARRAY_SIZE(sun4i_headphone_jack_pins)); + if (ret) { + dev_err(rtd->dev, + "Headphone jack creation failed: %d\n", ret); + return ret; + } + + sun4i_headphone_jack_gpio.desc = scodec->gpio_hp; + ret = snd_soc_jack_add_gpios(&sun4i_headphone_jack, 1, + &sun4i_headphone_jack_gpio); + + if (ret) { + dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret); + return ret; + } + } + + return 0; +} + static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, int *num_links) { @@ -1288,6 +1333,7 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, link->codecs->name = dev_name(dev); link->platforms->name = dev_name(dev); link->dai_fmt = SND_SOC_DAIFMT_I2S; + link->init = sun4i_codec_machine_init; *num_links = 1; @@ -1728,6 +1774,13 @@ static int sun4i_codec_probe(struct platform_device *pdev) return ret; } + scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); + if (IS_ERR(scodec->gpio_hp)) { + ret = PTR_ERR(scodec->gpio_hp); + dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n"); + return ret; + } + /* reg_field setup */ scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, scodec->regmap, diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index 1920b996e9aa..51043e556b3e 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -1359,6 +1359,8 @@ static int tegra_ahub_probe(struct platform_device *pdev) return -ENOMEM; ahub->soc_data = of_device_get_match_data(&pdev->dev); + if (!ahub->soc_data) + return -ENODEV; platform_set_drvdata(pdev, ahub); diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c index cf43ac19c4a6..55e7cb96858f 100644 --- a/sound/soc/ti/omap-hdmi.c +++ b/sound/soc/ti/omap-hdmi.c @@ -361,17 +361,20 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) if (!card->dai_link) return -ENOMEM; - compnent = devm_kzalloc(dev, sizeof(*compnent), GFP_KERNEL); + compnent = devm_kzalloc(dev, 2 * sizeof(*compnent), GFP_KERNEL); if (!compnent) return -ENOMEM; - card->dai_link->cpus = compnent; + card->dai_link->cpus = &compnent[0]; card->dai_link->num_cpus = 1; card->dai_link->codecs = &snd_soc_dummy_dlc; card->dai_link->num_codecs = 1; + card->dai_link->platforms = &compnent[1]; + card->dai_link->num_platforms = 1; card->dai_link->name = card->name; card->dai_link->stream_name = card->name; card->dai_link->cpus->dai_name = dev_name(ad->dssdev); + card->dai_link->platforms->name = dev_name(ad->dssdev); card->num_links = 1; card->dev = dev; |