diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-06-14 05:37:06 -1000 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-06-14 05:37:06 -1000 |
commit | bcb46a0e0e5c79291ffbc1e4b5d1d3d119e0f984 (patch) | |
tree | aa8377f39f70c46ede21f8b3696815eb273d2934 /sound | |
parent | c11fb13a117e5a6736481c779cb971249ed96016 (diff) | |
parent | 17d304604a88cf20c8dfd2c95d3decb9c4f8bca4 (diff) | |
download | linux-bcb46a0e0e5c79291ffbc1e4b5d1d3d119e0f984.tar.bz2 |
Merge tag 'sound-5.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai:
"It might feel like deja vu to receive a bulk of changes at rc5, and it
happens again; we've got a collection of fixes for ASoC. Most of fixes
are targeted for the newly merged SOF (Sound Open Firmware) stuff and
the relevant fixes for Intel platforms.
Other than that, there are a few regression fixes for the recent ASoC
core changes and HD-audio quirk, as well as a couple of FireWire fixes
and for other ASoC codecs"
* tag 'sound-5.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (54 commits)
Revert "ALSA: hda/realtek - Improve the headset mic for Acer Aspire laptops"
ALSA: ice1712: Check correct return value to snd_i2c_sendbytes (EWS/DMX 6Fire)
ALSA: oxfw: allow PCM capture for Stanton SCS.1m
ALSA: firewire-motu: fix destruction of data for isochronous resources
ASoC: Intel: sst: fix kmalloc call with wrong flags
ASoC: core: Fix deadlock in snd_soc_instantiate_card()
SoC: rt274: Fix internal jack assignment in set_jack callback
ALSA: hdac: fix memory release for SST and SOF drivers
ASoC: SOF: Intel: hda: use the defined ppcap functions
ASoC: core: move DAI pre-links initiation to snd_soc_instantiate_card
ASoC: Intel: cht_bsw_rt5672: fix kernel oops with platform_name override
ASoC: Intel: cht_bsw_nau8824: fix kernel oops with platform_name override
ASoC: Intel: bytcht_es8316: fix kernel oops with platform_name override
ASoC: Intel: cht_bsw_max98090: fix kernel oops with platform_name override
ASoC: sun4i-i2s: Add offset to RX channel select
ASoC: sun4i-i2s: Fix sun8i tx channel offset mask
ASoC: max98090: remove 24-bit format support if RJ is 0
ASoC: da7219: Fix build error without CONFIG_I2C
ASoC: SOF: Intel: hda: Fix COMPILE_TEST build error
ASoC: SOF: fix DSP oops definitions in FW ABI
...
Diffstat (limited to 'sound')
41 files changed, 423 insertions, 246 deletions
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 37e47fa7b0e3..81f7edc560d0 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -344,7 +344,7 @@ static void destroy_stream(struct snd_motu *motu, } amdtp_stream_destroy(stream); - fw_iso_resources_free(resources); + fw_iso_resources_destroy(resources); } int snd_motu_stream_init_duplex(struct snd_motu *motu) diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 5e31c460a90f..9fd145cc4b07 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -148,9 +148,6 @@ static int detect_quirks(struct snd_oxfw *oxfw) oxfw->midi_input_ports = 0; oxfw->midi_output_ports = 0; - /* Output stream exists but no data channels are useful. */ - oxfw->has_output = false; - return snd_oxfw_scs1x_add(oxfw); } diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index ad1b55a1f045..a3a113ef5d56 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -162,7 +162,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init); void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev) { snd_hdac_device_exit(hdev); - kfree(hdev); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c5e46df9c548..6c51b8363f8b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -826,7 +826,14 @@ static int snd_hda_codec_dev_free(struct snd_device *device) if (codec->core.type == HDA_DEV_LEGACY) snd_hdac_device_unregister(&codec->core); codec_display_power(codec, false); - put_device(hda_codec_dev(codec)); + + /* + * In the case of ASoC HD-audio bus, the device refcount is released in + * snd_hdac_ext_bus_device_remove() explicitly. + */ + if (codec->core.type == HDA_DEV_LEGACY) + put_device(hda_codec_dev(codec)); + return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 974244978509..5b3c26991f26 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4120,18 +4120,19 @@ static struct coef_fw alc225_pre_hsmode[] = { static void alc_headset_mode_unplugged(struct hda_codec *codec) { static struct coef_fw coef0255[] = { + WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */ WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */ WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */ {} }; - static struct coef_fw coef0255_1[] = { - WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */ - {} - }; static struct coef_fw coef0256[] = { WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */ + WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */ + WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */ + WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */ + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ {} }; static struct coef_fw coef0233[] = { @@ -4194,13 +4195,11 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) switch (codec->core.vendor_id) { case 0x10ec0255: - alc_process_coef_fw(codec, coef0255_1); alc_process_coef_fw(codec, coef0255); break; case 0x10ec0236: case 0x10ec0256: alc_process_coef_fw(codec, coef0256); - alc_process_coef_fw(codec, coef0255); break; case 0x10ec0234: case 0x10ec0274: @@ -4253,6 +4252,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */ {} }; + static struct coef_fw coef0256[] = { + UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/ + WRITE_COEFEX(0x57, 0x03, 0x09a3), + WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */ + {} + }; static struct coef_fw coef0233[] = { UPDATE_COEF(0x35, 0, 1<<14), WRITE_COEF(0x06, 0x2100), @@ -4300,14 +4305,19 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, }; switch (codec->core.vendor_id) { - case 0x10ec0236: case 0x10ec0255: - case 0x10ec0256: alc_write_coef_idx(codec, 0x45, 0xc489); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); alc_process_coef_fw(codec, coef0255); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; + case 0x10ec0236: + case 0x10ec0256: + alc_write_coef_idx(codec, 0x45, 0xc489); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0256); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; case 0x10ec0234: case 0x10ec0274: case 0x10ec0294: @@ -4389,6 +4399,14 @@ static void alc_headset_mode_default(struct hda_codec *codec) WRITE_COEF(0x49, 0x0049), {} }; + static struct coef_fw coef0256[] = { + WRITE_COEF(0x45, 0xc489), + WRITE_COEFEX(0x57, 0x03, 0x0da3), + WRITE_COEF(0x49, 0x0049), + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ + WRITE_COEF(0x06, 0x6100), + {} + }; static struct coef_fw coef0233[] = { WRITE_COEF(0x06, 0x2100), WRITE_COEF(0x32, 0x4ea3), @@ -4439,11 +4457,16 @@ static void alc_headset_mode_default(struct hda_codec *codec) alc_process_coef_fw(codec, alc225_pre_hsmode); alc_process_coef_fw(codec, coef0225); break; - case 0x10ec0236: case 0x10ec0255: - case 0x10ec0256: alc_process_coef_fw(codec, coef0255); break; + case 0x10ec0236: + case 0x10ec0256: + alc_write_coef_idx(codec, 0x1b, 0x0e4b); + alc_write_coef_idx(codec, 0x45, 0xc089); + msleep(50); + alc_process_coef_fw(codec, coef0256); + break; case 0x10ec0234: case 0x10ec0274: case 0x10ec0294: @@ -4487,8 +4510,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) }; static struct coef_fw coef0256[] = { WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */ - WRITE_COEF(0x1b, 0x0c6b), - WRITE_COEFEX(0x57, 0x03, 0x8ea6), + WRITE_COEF(0x1b, 0x0e6b), {} }; static struct coef_fw coef0233[] = { @@ -4606,8 +4628,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) }; static struct coef_fw coef0256[] = { WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */ - WRITE_COEF(0x1b, 0x0c6b), - WRITE_COEFEX(0x57, 0x03, 0x8ea6), + WRITE_COEF(0x1b, 0x0e6b), {} }; static struct coef_fw coef0233[] = { @@ -4739,13 +4760,37 @@ static void alc_determine_headset_type(struct hda_codec *codec) }; switch (codec->core.vendor_id) { - case 0x10ec0236: case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; + case 0x10ec0236: case 0x10ec0256: + alc_write_coef_idx(codec, 0x1b, 0x0e4b); + alc_write_coef_idx(codec, 0x06, 0x6104); + alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3); + + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + msleep(80); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + alc_process_coef_fw(codec, coef0255); msleep(300); val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; + + alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3); + alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); + + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + msleep(80); + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); break; case 0x10ec0234: case 0x10ec0274: @@ -6210,15 +6255,13 @@ static const struct hda_fixup alc269_fixups[] = { .chain_id = ALC269_FIXUP_THINKPAD_ACPI, }, [ALC255_FIXUP_ACER_MIC_NO_PRESENCE] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - /* Enable the Mic */ - { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 }, - {} + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } }, .chained = true, - .chain_id = ALC269_FIXUP_LIFEBOOK_EXTMIC + .chain_id = ALC255_FIXUP_HEADSET_MODE }, [ALC255_FIXUP_ASUS_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, @@ -7263,10 +7306,6 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x19, 0x0181303F}, {0x21, 0x0221102f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE, - {0x12, 0x90a60140}, - {0x14, 0x90170120}, - {0x21, 0x02211030}), - SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE, {0x12, 0x90a601c0}, {0x14, 0x90171120}, {0x21, 0x02211030}), diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 3729b132ad85..fe08dd9f1564 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -812,7 +812,7 @@ static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg snd_i2c_lock(ice->i2c); byte = reg; - if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1)) { + if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) { snd_i2c_unlock(ice->i2c); dev_err(ice->card->dev, "cannot send pca\n"); return -EIO; diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index eab7c76cfcd9..71562154c0b1 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -304,7 +304,10 @@ static int ak4458_rstn_control(struct snd_soc_component *component, int bit) AK4458_00_CONTROL1, AK4458_RSTN_MASK, 0x0); - return ret; + if (ret < 0) + return ret; + + return 0; } static int ak4458_hw_params(struct snd_pcm_substream *substream, @@ -536,9 +539,10 @@ static void ak4458_power_on(struct ak4458_priv *ak4458) } } -static void ak4458_init(struct snd_soc_component *component) +static int ak4458_init(struct snd_soc_component *component) { struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); + int ret; /* External Mute ON */ if (ak4458->mute_gpiod) @@ -546,21 +550,21 @@ static void ak4458_init(struct snd_soc_component *component) ak4458_power_on(ak4458); - snd_soc_component_update_bits(component, AK4458_00_CONTROL1, + ret = snd_soc_component_update_bits(component, AK4458_00_CONTROL1, 0x80, 0x80); /* ACKS bit = 1; 10000000 */ + if (ret < 0) + return ret; - ak4458_rstn_control(component, 1); + return ak4458_rstn_control(component, 1); } static int ak4458_probe(struct snd_soc_component *component) { struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); - ak4458_init(component); - ak4458->fs = 48000; - return 0; + return ak4458_init(component); } static void ak4458_remove(struct snd_soc_component *component) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index ab27d2b94d02..c0190ec59e74 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -60,7 +60,7 @@ static const struct reg_default cs4265_reg_defaults[] = { static bool cs4265_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS4265_CHIP_ID ... CS4265_SPDIF_CTL2: + case CS4265_CHIP_ID ... CS4265_MAX_REGISTER: return true; default: return false; diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index ebb9e0cf8364..28a4ac36c4f8 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -558,6 +558,7 @@ static int cs42xx8_runtime_resume(struct device *dev) msleep(5); regcache_cache_only(cs42xx8->regmap, false); + regcache_mark_dirty(cs42xx8->regmap); ret = regcache_sync(cs42xx8->regmap); if (ret) { diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 7619ea31ab50..ada8c25e643d 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1909,6 +1909,21 @@ static int max98090_configure_dmic(struct max98090_priv *max98090, return 0; } +static int max98090_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component); + unsigned int fmt = max98090->dai_fmt; + + /* Remove 24-bit format support if it is not in right justified mode. */ + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_RIGHT_J) { + substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(substream->runtime, 0, 16, 16); + } + return 0; +} + static int max98090_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -2316,6 +2331,7 @@ EXPORT_SYMBOL_GPL(max98090_mic_detect); #define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) static const struct snd_soc_dai_ops max98090_dai_ops = { + .startup = max98090_dai_startup, .set_sysclk = max98090_dai_set_sysclk, .set_fmt = max98090_dai_set_fmt, .set_tdm_slot = max98090_set_tdm_slot, diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index adf59039a3b6..cdd312db3e78 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -405,6 +405,8 @@ static int rt274_mic_detect(struct snd_soc_component *component, { struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component); + rt274->jack = jack; + if (jack == NULL) { /* Disable jack detection */ regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL, @@ -412,7 +414,6 @@ static int rt274_mic_detect(struct snd_soc_component *component, return 0; } - rt274->jack = jack; regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL, RT274_IRQ_EN, RT274_IRQ_EN); diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 9a037108b1ae..a746e11ccfe3 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2882,6 +2882,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = { RT5670_DEV_GPIO | RT5670_JD_MODE3), }, + { + .callback = rt5670_quirk_cb, + .ident = "Aegex 10 tablet (RU2)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AEGEX"), + DMI_MATCH(DMI_PRODUCT_VERSION, "RU2"), + }, + .driver_data = (unsigned long *)(RT5670_DMIC_EN | + RT5670_DMIC2_INR | + RT5670_DEV_GPIO | + RT5670_JD_MODE3), + }, {} }; diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 84b6bd8b50e1..a4dfa0345c6e 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -101,7 +101,7 @@ static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen) u32 word_size = min_t(u32, dstlen, 8); for (w = 0; w < dstlen; w += word_size) { - for (i = 0; i < word_size; i++) { + for (i = 0; i < word_size && i + w < dstlen; i++) { si = w + word_size - i - 1; dst[w + i] = si < srclen ? src[si] : 0; } @@ -152,8 +152,9 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) status |= spi_sync(g_spi, &m); mutex_unlock(&spi_mutex); + /* Copy data back to caller buffer */ - rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len); + rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len); } return status; } diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 0b937924d2e4..ea035c12a325 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -282,8 +282,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) return -EINVAL; } - if ((outrate > 8000 && outrate < 30000) && - (outrate/inrate > 24 || inrate/outrate > 8)) { + if ((outrate >= 8000 && outrate <= 30000) && + (outrate > 24 * inrate || inrate > 8 * outrate)) { pair_err("exceed supported ratio range [1/24, 8] for \ inrate/outrate: %d/%d\n", inrate, outrate); return -EINVAL; diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index 1ec298dd0e4f..13db2854db3e 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -158,11 +158,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large) { struct ipc_post *msg; - msg = kzalloc(sizeof(*msg), GFP_KERNEL); + msg = kzalloc(sizeof(*msg), GFP_ATOMIC); if (!msg) return -ENOMEM; if (large) { - msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); + msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); if (!msg->mailbox_data) { kfree(msg); return -ENOMEM; diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 1f00d473793f..2fe1ce879123 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -487,6 +487,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) } /* override plaform name, if required */ + byt_cht_es8316_card.dev = dev; platform_name = mach->mach_params.platform; ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, @@ -567,7 +568,6 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", mic_name[BYT_CHT_ES8316_MAP(quirk)]); byt_cht_es8316_card.long_name = long_name; - byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index d72623f508b7..613b37172441 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -446,6 +446,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } /* override plaform name, if required */ + snd_soc_card_cht.dev = &pdev->dev; mach = (&pdev->dev)->platform_data; platform_name = mach->mach_params.platform; @@ -455,7 +456,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return ret_val; /* register the soc card */ - snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); if (drv->quirks & QUIRK_PMC_PLT_CLK_0) diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 1c17f82fc922..b0d658e3d3f7 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -249,6 +249,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); /* override plaform name, if required */ + snd_soc_card_cht.dev = &pdev->dev; mach = (&pdev->dev)->platform_data; platform_name = mach->mach_params.platform; @@ -258,7 +259,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return ret_val; /* register the soc card */ - snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { dev_err(&pdev->dev, diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 1731cc0fac25..028e571f6a77 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -418,6 +418,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } /* override plaform name, if required */ + snd_soc_card_cht.dev = &pdev->dev; platform_name = mach->mach_params.platform; ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, @@ -435,7 +436,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); /* register the soc card */ - snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { dev_err(&pdev->dev, diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index f28fb98cc306..3343dbcd506f 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -29,9 +29,10 @@ #define SOF_RT5682_MCLK_EN BIT(3) #define SOF_RT5682_MCLK_24MHZ BIT(4) #define SOF_SPEAKER_AMP_PRESENT BIT(5) -#define SOF_RT5682_SSP_AMP(quirk) ((quirk) & GENMASK(8, 6)) -#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) #define SOF_RT5682_SSP_AMP_SHIFT 6 +#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) +#define SOF_RT5682_SSP_AMP(quirk) \ + (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -144,9 +145,9 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) jack = &ctx->sof_headset; snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); ret = snd_soc_component_set_jack(component, jack, NULL); if (ret) { diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index abd34fa27749..55e80c3d2af0 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -13,6 +13,7 @@ static unsigned long byt_machine_id; #define BYT_THINKPAD_10 1 #define BYT_POV_P1006W 2 +#define BYT_AEGEX_10 3 static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) { @@ -26,6 +27,12 @@ static int byt_pov_p1006w_quirk_cb(const struct dmi_system_id *id) return 1; } +static int byt_aegex10_quirk_cb(const struct dmi_system_id *id) +{ + byt_machine_id = BYT_AEGEX_10; + return 1; +} + static const struct dmi_system_id byt_table[] = { { .callback = byt_thinkpad10_quirk_cb, @@ -66,9 +73,18 @@ static const struct dmi_system_id byt_table[] = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), }, }, + { + /* Aegex 10 tablet (RU2) */ + .callback = byt_aegex10_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AEGEX"), + DMI_MATCH(DMI_PRODUCT_VERSION, "RU2"), + }, + }, { } }; +/* The Thinkapd 10 and Aegex 10 tablets have the same ID problem */ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .id = "10EC5640", .drv_name = "cht-bsw-rt5672", @@ -95,6 +111,7 @@ static struct snd_soc_acpi_mach *byt_quirk(void *arg) switch (byt_machine_id) { case BYT_THINKPAD_10: + case BYT_AEGEX_10: return &byt_thinkpad_10; case BYT_POV_P1006W: return &byt_pov_p1006w; diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index df7c52cad5c3..c36c0aa4f683 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -29,17 +29,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_tplg_filename = "sof-cnl-rt274.tplg", }, { - .id = "10EC5682", + .id = "MX98357A", .drv_name = "sof_rt5682", + .quirk_data = &cml_codecs, .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682.tplg", + .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", }, { - .id = "MX98357A", + .id = "10EC5682", .drv_name = "sof_rt5682", - .quirk_data = &cml_codecs, .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", + .sof_tplg_filename = "sof-cml-rt5682.tplg", }, {}, diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 933ab51af05b..111e44b64b38 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -133,7 +133,7 @@ config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A config SND_SOC_MT8183_DA7219_MAX98357A tristate "ASoC Audio driver for MT8183 with DA7219 MAX98357A codec" - depends on SND_SOC_MT8183 + depends on SND_SOC_MT8183 && I2C select SND_SOC_MT6358 select SND_SOC_MAX98357A select SND_SOC_DA7219 diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2403bec2fccf..41c0cfaf2db5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -228,7 +228,10 @@ static void soc_init_card_debugfs(struct snd_soc_card *card) static void soc_cleanup_card_debugfs(struct snd_soc_card *card) { + if (!card->debugfs_card_root) + return; debugfs_remove_recursive(card->debugfs_card_root); + card->debugfs_card_root = NULL; } static void snd_soc_debugfs_init(void) @@ -2037,8 +2040,10 @@ match: static int soc_cleanup_card_resources(struct snd_soc_card *card) { /* free the ALSA card at first; this syncs with pending operations */ - if (card->snd_card) + if (card->snd_card) { snd_card_free(card->snd_card); + card->snd_card = NULL; + } /* remove and free each DAI */ soc_remove_dai_links(card); @@ -2065,6 +2070,16 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) int ret, i, order; mutex_lock(&client_mutex); + for_each_card_prelinks(card, i, dai_link) { + ret = soc_init_dai_link(card, dai_link); + if (ret) { + soc_cleanup_platform(card); + dev_err(card->dev, "ASoC: failed to init link %s: %d\n", + dai_link->name, ret); + mutex_unlock(&client_mutex); + return ret; + } + } mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); card->dapm.bias_level = SND_SOC_BIAS_OFF; @@ -2789,26 +2804,9 @@ static int snd_soc_bind_card(struct snd_soc_card *card) */ int snd_soc_register_card(struct snd_soc_card *card) { - int i, ret; - struct snd_soc_dai_link *link; - if (!card->name || !card->dev) return -EINVAL; - mutex_lock(&client_mutex); - for_each_card_prelinks(card, i, link) { - - ret = soc_init_dai_link(card, link); - if (ret) { - soc_cleanup_platform(card); - dev_err(card->dev, "ASoC: failed to init link %s\n", - link->name); - mutex_unlock(&client_mutex); - return ret; - } - } - mutex_unlock(&client_mutex); - dev_set_drvdata(card->dev, card); snd_soc_initialize_card_lists(card); @@ -2839,12 +2837,14 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) snd_soc_dapm_shutdown(card); snd_soc_flush_all_delayed_work(card); + mutex_lock(&client_mutex); /* remove all components used by DAI links on this card */ for_each_comp_order(order) { for_each_card_rtds(card, rtd) { soc_remove_link_components(card, rtd, order); } } + mutex_unlock(&client_mutex); soc_cleanup_card_resources(card); if (!unregister) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 81a7a12196ff..55f8278077f4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2193,7 +2193,10 @@ static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) { + if (!dapm->debugfs_dapm) + return; debugfs_remove_recursive(dapm->debugfs_dapm); + dapm->debugfs_dapm = NULL; } #else @@ -3831,8 +3834,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret); goto out; } - source->active++; } + source->active++; ret = soc_dai_hw_params(&substream, params, source); if (ret < 0) goto out; @@ -3853,8 +3856,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret); goto out; } - sink->active++; } + sink->active++; ret = soc_dai_hw_params(&substream, params, sink); if (ret < 0) goto out; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0a4f60c7a188..c46ad0f66292 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2479,7 +2479,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) continue; dev_dbg(be->dev, "ASoC: prepare BE %s\n", diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 048c7b034d70..71d87a86f060 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -45,7 +45,10 @@ config SND_SOC_SOF_OPTIONS if SND_SOC_SOF_OPTIONS config SND_SOC_SOF_NOCODEC - tristate "SOF nocodec mode Support" + tristate + +config SND_SOC_SOF_NOCODEC_SUPPORT + bool "SOF nocodec mode support" help This adds support for a dummy/nocodec machine driver fallback option if no known codec is detected. This is typically only @@ -81,7 +84,7 @@ if SND_SOC_SOF_DEBUG config SND_SOC_SOF_FORCE_NOCODEC_MODE bool "SOF force nocodec Mode" - depends on SND_SOC_SOF_NOCODEC + depends on SND_SOC_SOF_NOCODEC_SUPPORT help This forces SOF to use dummy/nocodec as machine driver, even though there is a codec detected on the real platform. This is @@ -136,6 +139,7 @@ endif ## SND_SOC_SOF_OPTIONS config SND_SOC_SOF tristate select SND_SOC_TOPOLOGY + select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 11762c4580f1..84e2cbfbbcbb 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -349,6 +349,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; + size_t size = data->size + sizeof(*data); int ret, err; if (be->max > sizeof(ucontrol->value.bytes.data)) { @@ -358,10 +359,10 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - if (data->size > be->max) { + if (size > be->max) { dev_err_ratelimited(sdev->dev, - "error: size too big %d bytes max is %d\n", - data->size, be->max); + "error: size too big %zu bytes max is %d\n", + size, be->max); return -EINVAL; } @@ -375,7 +376,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, } /* copy from kcontrol */ - memcpy(data, ucontrol->value.bytes.data, data->size); + memcpy(data, ucontrol->value.bytes.data, size); /* notify DSP of byte control updates */ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 32105e0fabe8..5beda47cdf9f 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -382,7 +382,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) if (IS_ERR(plat_data->pdev_mach)) { ret = PTR_ERR(plat_data->pdev_mach); - goto comp_err; + goto fw_run_err; } dev_dbg(sdev->dev, "created machine %s\n", @@ -393,8 +393,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return 0; -comp_err: - snd_soc_unregister_component(sdev->dev); +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) fw_run_err: snd_sof_fw_unload(sdev); fw_load_err: @@ -403,6 +402,21 @@ ipc_err: snd_sof_free_debug(sdev); dbg_err: snd_sof_remove(sdev); +#else + + /* + * when the probe_continue is handled in a work queue, the + * probe does not fail so we don't release resources here. + * They will be released with an explicit call to + * snd_sof_device_remove() when the PCI/ACPI device is removed + */ + +fw_run_err: +fw_load_err: +ipc_err: +dbg_err: + +#endif return ret; } @@ -484,7 +498,6 @@ int snd_sof_device_remove(struct device *dev) snd_sof_ipc_free(sdev); snd_sof_free_debug(sdev); snd_sof_free_trace(sdev); - snd_sof_remove(sdev); /* * Unregister machine driver. This will unbind the snd_card which @@ -494,6 +507,14 @@ int snd_sof_device_remove(struct device *dev) if (!IS_ERR_OR_NULL(pdata->pdev_mach)) platform_device_unregister(pdata->pdev_mach); + /* + * Unregistering the machine driver results in unloading the topology. + * Some widgets, ex: scheduler, attempt to power down the core they are + * scheduled on, when they are unloaded. Therefore, the DSP must be + * removed only after the topology has been unloaded. + */ + snd_sof_remove(sdev); + /* release firmware */ release_firmware(pdata->fw); pdata->fw = NULL; diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 065cb868bdfa..70d524ef9bc0 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -220,17 +220,20 @@ static void bdw_get_registers(struct snd_sof_dev *sdev, struct sof_ipc_panic_info *panic_info, u32 *stack, size_t stack_words) { - /* first read regsisters */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + u32 offset = sdev->dsp_oops_offset; + + /* first read registers */ + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* note: variable AR register array is not read */ /* then get panic info */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), - panic_info, sizeof(*panic_info)); + offset += xoops->arch_hdr.totalsize; + sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + - sizeof(*panic_info), stack, - stack_words * sizeof(u32)); + offset += sizeof(*panic_info); + sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32)); } static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) @@ -283,6 +286,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) SHIM_IMRX, SHIM_IMRX_DONE, SHIM_IMRX_DONE); + spin_lock_irq(&sdev->ipc_lock); + /* * handle immediate reply from DSP core. If the msg is * found, set done bit in cmd_done which is called at the @@ -294,6 +299,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) snd_sof_ipc_reply(sdev, ipcx); bdw_dsp_done(sdev); + + spin_unlock_irq(&sdev->ipc_lock); } ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); @@ -485,7 +492,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; - unsigned long flags; int ret = 0; /* @@ -501,8 +507,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - spin_lock_irqsave(&sdev->ipc_lock, flags); - if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; @@ -521,8 +525,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) } msg->reply_error = ret; - - spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static void bdw_host_done(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 7bf9143d3106..39d1ae01c45d 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -265,17 +265,20 @@ static void byt_get_registers(struct snd_sof_dev *sdev, struct sof_ipc_panic_info *panic_info, u32 *stack, size_t stack_words) { + u32 offset = sdev->dsp_oops_offset; + /* first read regsisters */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* note: variable AR register array is not read */ /* then get panic info */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), - panic_info, sizeof(*panic_info)); + offset += xoops->arch_hdr.totalsize; + sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + - sizeof(*panic_info), stack, - stack_words * sizeof(u32)); + offset += sizeof(*panic_info); + sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32)); } static void byt_dump(struct snd_sof_dev *sdev, u32 flags) @@ -329,6 +332,9 @@ static irqreturn_t byt_irq_thread(int irq, void *context) SHIM_IMRX, SHIM_IMRX_DONE, SHIM_IMRX_DONE); + + spin_lock_irq(&sdev->ipc_lock); + /* * handle immediate reply from DSP core. If the msg is * found, set done bit in cmd_done which is called at the @@ -340,6 +346,8 @@ static irqreturn_t byt_irq_thread(int irq, void *context) snd_sof_ipc_reply(sdev, ipcx); byt_dsp_done(sdev); + + spin_unlock_irq(&sdev->ipc_lock); } /* new message from DSP */ @@ -383,7 +391,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; - unsigned long flags; int ret = 0; /* @@ -399,8 +406,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - spin_lock_irqsave(&sdev->ipc_lock, flags); - if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; @@ -419,8 +424,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) } msg->reply_error = ret; - - spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static void byt_host_done(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 08a1a3d3c08d..b2eba7adcad8 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -64,6 +64,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) CNL_DSP_REG_HIPCCTL, CNL_DSP_REG_HIPCCTL_DONE, 0); + spin_lock_irq(&sdev->ipc_lock); + /* handle immediate reply from DSP core */ hda_dsp_ipc_get_reply(sdev); snd_sof_ipc_reply(sdev, msg); @@ -75,6 +77,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) cnl_ipc_dsp_done(sdev); + spin_unlock_irq(&sdev->ipc_lock); + ret = IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 2c3645736e1f..07bc123112c9 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -161,21 +161,105 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) -/* - * While performing reset, controller may not come back properly and causing - * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset - * (init chip) and then again set CGCTL.MISCBDCGE to 1 - */ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) { struct hdac_bus *bus = sof_to_bus(sdev); - int ret; + struct hdac_stream *stream; + int sd_offset, ret = 0; + + if (bus->chip_init) + return 0; hda_dsp_ctrl_misc_clock_gating(sdev, false); - ret = snd_hdac_bus_init_chip(bus, full_reset); + + if (full_reset) { + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + + /* reset HDA controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to reset HDA controller\n"); + return ret; + } + + usleep_range(500, 1000); + + /* exit HDA controller reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); + return ret; + } + + usleep_range(1000, 1200); + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* check to see if controller is ready */ + if (!snd_hdac_chip_readb(bus, GCTL)) { + dev_dbg(bus->dev, "controller not ready!\n"); + return -EBUSY; + } + + /* Accept unsolicited responses */ + snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); + + /* detect codecs */ + if (!bus->codec_mask) { + bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS); + dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask); + } +#endif + + /* clear stream status */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + } + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* clear rirb status */ + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); +#endif + + /* clear interrupt status register */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* initialize the codec command I/O */ + snd_hdac_bus_init_cmd_io(bus); +#endif + + /* enable CIE and GIE interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* program the position buffer */ + if (bus->use_posbuf && bus->posbuf.addr) { + snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr); + snd_hdac_chip_writel(bus, DPUBASE, + upper_32_bits(bus->posbuf.addr)); + } +#endif + + bus->chip_init = true; + hda_dsp_ctrl_misc_clock_gating(sdev, true); return ret; } -#endif diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 73ead7070cde..51b285103394 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -72,7 +72,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; struct sof_ipc_cmd_hdr *hdr; - unsigned long flags; int ret = 0; /* @@ -84,7 +83,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); return; } - spin_lock_irqsave(&sdev->ipc_lock, flags); hdr = msg->msg_data; if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { @@ -123,7 +121,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) out: msg->reply_error = ret; - spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static bool hda_dsp_ipc_is_sof(uint32_t msg) @@ -172,6 +169,18 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) HDA_DSP_REG_HIPCCTL, HDA_DSP_REG_HIPCCTL_DONE, 0); + /* + * Make sure the interrupt thread cannot be preempted between + * waking up the sender and re-enabling the interrupt. Also + * protect against a theoretical race with sof_ipc_tx_message(): + * if the DSP is fast enough to receive an IPC message, reply to + * it, and the host interrupt processing calls this function on + * a different core from the one, where the sending is taking + * place, the message might not yet be marked as expecting a + * reply. + */ + spin_lock_irq(&sdev->ipc_lock); + /* handle immediate reply from DSP core - ignore ROM messages */ if (hda_dsp_ipc_is_sof(msg)) { hda_dsp_ipc_get_reply(sdev); @@ -187,6 +196,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* set the done bit */ hda_dsp_ipc_dsp_done(sdev); + spin_unlock_irq(&sdev->ipc_lock); + ret = IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7e3980a2f7ba..faf1a8ada091 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -108,17 +108,21 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, struct sof_ipc_panic_info *panic_info, u32 *stack, size_t stack_words) { + u32 offset = sdev->dsp_oops_offset; + /* first read registers */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops, - sizeof(*xoops)); + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* note: variable AR register array is not read */ /* then get panic info */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + - sizeof(*xoops), panic_info, sizeof(*panic_info)); + offset += xoops->arch_hdr.totalsize; + sof_block_read(sdev, sdev->mmio_bar, offset, + panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + - sizeof(*xoops) + sizeof(*panic_info), stack, + offset += sizeof(*panic_info); + sof_block_read(sdev, sdev->mmio_bar, offset, stack, stack_words * sizeof(u32)); } @@ -223,7 +227,9 @@ static int hda_init(struct snd_sof_dev *sdev) /* initialise hdac bus */ bus->addr = pci_resource_start(pci, 0); +#if IS_ENABLED(CONFIG_PCI) bus->remap_addr = pci_ioremap_bar(pci, 0); +#endif if (!bus->remap_addr) { dev_err(bus->dev, "error: ioremap error\n"); return -ENXIO; @@ -264,9 +270,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, return tplg_filename; } +#endif + static int hda_init_caps(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_ext_link *hlink; struct snd_soc_acpi_mach_params *mach_params; struct snd_soc_acpi_mach *hda_mach; @@ -274,8 +283,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct snd_soc_acpi_mach *mach; const char *tplg_filename; int codec_num = 0; - int ret = 0; int i; +#endif + int ret = 0; device_disable_async_suspend(bus->dev); @@ -283,6 +293,14 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (bus->ppcap) dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); + ret = hda_dsp_ctrl_init_chip(sdev, true); + if (ret < 0) { + dev_err(bus->dev, "error: init chip failed with ret: %d\n", + ret); + return ret; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); @@ -293,12 +311,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) return ret; } - ret = hda_dsp_ctrl_init_chip(sdev, true); - if (ret < 0) { - dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); - goto out; - } - /* codec detection */ if (!bus->codec_mask) { dev_info(bus->dev, "no hda codecs found!\n"); @@ -339,8 +351,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* use local variable for readability */ tplg_filename = pdata->tplg_filename; tplg_filename = fixup_tplg_name(sdev, tplg_filename); - if (!tplg_filename) - goto out; + if (!tplg_filename) { + hda_codec_i915_exit(sdev); + return ret; + } pdata->tplg_filename = tplg_filename; } } @@ -364,35 +378,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev) */ list_for_each_entry(hlink, &bus->hlink_list, list) snd_hdac_ext_bus_link_put(bus, hlink); - - return 0; - -out: - hda_codec_i915_exit(sdev); - return ret; -} - -#else - -static int hda_init_caps(struct snd_sof_dev *sdev) -{ - /* - * set CGCTL.MISCBDCGE to 0 during reset and set back to 1 - * when reset finished. - * TODO: maybe no need for init_caps? - */ - hda_dsp_ctrl_misc_clock_gating(sdev, 0); - - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - +#endif return 0; } -#endif - static const struct sof_intel_dsp_desc *get_chip_info(struct snd_sof_pdata *pdata) { @@ -409,9 +398,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) struct pci_dev *pci = to_pci_dev(sdev->dev); struct sof_intel_hda_dev *hdev; struct hdac_bus *bus; - struct hdac_stream *stream; const struct sof_intel_dsp_desc *chip; - int sd_offset, ret = 0; + int ret = 0; /* * detect DSP by checking class/subclass/prog-id information @@ -468,7 +456,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) goto hdac_bus_unmap; /* DSP base */ +#if IS_ENABLED(CONFIG_PCI) sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); +#endif if (!sdev->bar[HDA_DSP_BAR]) { dev_err(sdev->dev, "error: ioremap error\n"); ret = -ENXIO; @@ -558,56 +548,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) if (ret < 0) goto free_ipc_irq; - /* reset HDA controller */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to reset HDA controller\n"); - goto free_ipc_irq; - } - - /* exit HDA controller reset */ - ret = hda_dsp_ctrl_link_reset(sdev, false); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); - goto free_ipc_irq; - } - - /* clear stream status */ - list_for_each_entry(stream, &bus->stream_list, list) { - sd_offset = SOF_STREAM_SD_OFFSET(stream); - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); - } - - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - - /* clear interrupt status register */ - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); - - /* enable CIE and GIE interrupts */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); - - /* re-enable CGCTL.MISCBDCGE after reset */ - hda_dsp_ctrl_misc_clock_gating(sdev, true); - - device_disable_async_suspend(&pci->dev); - - /* enable DSP features */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN); - - /* enable DSP IRQ */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_PIE, SOF_HDA_PPCTL_PIE); + /* enable ppcap interrupt */ + hda_dsp_ctrl_ppcap_enable(sdev, true); + hda_dsp_ctrl_ppcap_int_enable(sdev, true); /* initialize waitq for code loading */ init_waitqueue_head(&sdev->waitq); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index f0b9d3c53f6f..2414640a32d1 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -115,7 +115,7 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) } break; case SOF_IPC_GLB_COMP_MSG: - str = "GLB_COMP_MSG: SET_VALUE"; + str = "GLB_COMP_MSG"; switch (type) { case SOF_IPC_COMP_SET_VALUE: str2 = "SET_VALUE"; break; @@ -308,19 +308,8 @@ EXPORT_SYMBOL(sof_ipc_tx_message); int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) { struct snd_sof_ipc_msg *msg = &sdev->ipc->msg; - unsigned long flags; - - /* - * Protect against a theoretical race with sof_ipc_tx_message(): if the - * DSP is fast enough to receive an IPC message, reply to it, and the - * host interrupt processing calls this function on a different core - * from the one, where the sending is taking place, the message might - * not yet be marked as expecting a reply. - */ - spin_lock_irqsave(&sdev->ipc_lock, flags); if (msg->ipc_complete) { - spin_unlock_irqrestore(&sdev->ipc_lock, flags); dev_err(sdev->dev, "error: no reply expected, received 0x%x", msg_id); return -EINVAL; @@ -330,8 +319,6 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) msg->ipc_complete = true; wake_up(&msg->waitq); - spin_unlock_irqrestore(&sdev->ipc_lock, flags); - return 0; } EXPORT_SYMBOL(snd_sof_ipc_reply); @@ -776,16 +763,19 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev) } } - if (ready->debug.bits.build) { + if (ready->flags & SOF_IPC_INFO_BUILD) { dev_info(sdev->dev, "Firmware debug build %d on %s-%s - options:\n" " GDB: %s\n" " lock debug: %s\n" " lock vdebug: %s\n", v->build, v->date, v->time, - ready->debug.bits.gdb ? "enabled" : "disabled", - ready->debug.bits.locks ? "enabled" : "disabled", - ready->debug.bits.locks_verbose ? "enabled" : "disabled"); + ready->flags & SOF_IPC_INFO_GDB ? + "enabled" : "disabled", + ready->flags & SOF_IPC_INFO_LOCKS ? + "enabled" : "disabled", + ready->flags & SOF_IPC_INFO_LOCKSV ? + "enabled" : "disabled"); } /* copy the fw_version into debugfs at first boot */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 81c7452aae17..628fae552442 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -372,6 +372,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) msecs_to_jiffies(sdev->boot_timeout)); if (ret == 0) { dev_err(sdev->dev, "error: firmware boot failure\n"); + /* after this point FW_READY msg should be ignored */ + sdev->boot_complete = true; snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | SOF_DBG_TEXT | SOF_DBG_PCI); return -EIO; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 649968841dad..dace6c4cd91e 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -211,8 +211,8 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); - INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, - sof_pcm_period_elapsed_work); + /* clear hw_params_upon_resume flag */ + spcm->hw_params_upon_resume[substream->stream] = 0; return ret; } @@ -429,8 +429,8 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - /* clear hw_params_upon_resume flag */ - spcm->hw_params_upon_resume[substream->stream] = 0; + INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, + sof_pcm_period_elapsed_work); caps = &spcm->pcm.caps[substream->stream]; diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index c3ad23a85b99..46a4905a9dce 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -110,7 +110,7 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, u32 stack_words) { struct sof_ipc_dsp_oops_xtensa *xoops = oops; - u32 stack_ptr = xoops->stack; + u32 stack_ptr = xoops->plat_hdr.stackptr; /* 4 * 8chars + 3 ws + 1 terminating NUL */ unsigned char buf[4 * 8 + 3 + 1]; int i; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index f2deffe026c5..9e1f00e8c32b 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1320,6 +1320,15 @@ static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w, gpiod_set_value_cansleep(scodec->gpio_pa, !!SND_SOC_DAPM_EVENT_ON(event)); + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* + * Need a delay to wait for DAC to push the data. 700ms seems + * to be the best compromise not to feel this delay while + * playing a sound. + */ + msleep(700); + } + return 0; } diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index c53bfed8d4c2..fd7c37596f21 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -106,7 +106,7 @@ #define SUN8I_I2S_TX_CHAN_MAP_REG 0x44 #define SUN8I_I2S_TX_CHAN_SEL_REG 0x34 -#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 11) +#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12) #define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12) #define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4) #define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4) @@ -456,6 +456,10 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, SUN8I_I2S_TX_CHAN_OFFSET_MASK, SUN8I_I2S_TX_CHAN_OFFSET(offset)); + + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); } regmap_field_write(i2s->field_fmt_mode, val); |