aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/pcm_native.c4
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c3
-rw-r--r--sound/firewire/fireface/ff-transaction.c2
-rw-r--r--sound/firewire/tascam/tascam-transaction.c2
-rw-r--r--sound/hda/intel-dsp-config.c4
-rw-r--r--sound/pci/hda/hda_codec.c24
-rw-r--r--sound/pci/hda/hda_intel.c21
-rw-r--r--sound/pci/hda/hda_tegra.c2
-rw-r--r--sound/pci/hda/patch_conexant.c1
-rw-r--r--sound/pci/hda/patch_hdmi.c3
-rw-r--r--sound/pci/hda/patch_realtek.c25
-rw-r--r--sound/pci/hda/patch_via.c14
-rw-r--r--sound/soc/amd/raven/pci-acp3x.c16
-rw-r--r--sound/soc/amd/renoir/rn-pci-acp3x.c32
-rw-r--r--sound/soc/atmel/Kconfig4
-rw-r--r--sound/soc/codecs/Kconfig2
-rw-r--r--sound/soc/codecs/ak4458.c22
-rw-r--r--sound/soc/codecs/hdmi-codec.c2
-rw-r--r--sound/soc/codecs/max98373-i2c.c20
-rw-r--r--sound/soc/codecs/max98373-sdw.c20
-rw-r--r--sound/soc/codecs/max98373.c34
-rw-r--r--sound/soc/codecs/max98373.h8
-rw-r--r--sound/soc/codecs/rt711.c6
-rw-r--r--sound/soc/codecs/wm_adsp.c3
-rw-r--r--sound/soc/fsl/imx-hdmi.c3
-rw-r--r--sound/soc/intel/boards/haswell.c1
-rw-r--r--sound/soc/intel/boards/sof_sdw.c10
-rw-r--r--sound/soc/intel/skylake/cnl-sst.c1
-rw-r--r--sound/soc/intel/skylake/skl-topology.c15
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c5
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c5
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c49
-rw-r--r--sound/soc/meson/axg-tdm-interface.c14
-rw-r--r--sound/soc/meson/axg-tdmin.c13
-rw-r--r--sound/soc/qcom/lpass-cpu.c42
-rw-r--r--sound/soc/qcom/lpass-ipq806x.c2
-rw-r--r--sound/soc/qcom/lpass-lpaif-reg.h2
-rw-r--r--sound/soc/qcom/lpass-platform.c62
-rw-r--r--sound/soc/qcom/lpass-sc7180.c11
-rw-r--r--sound/soc/qcom/lpass.h2
-rw-r--r--sound/soc/sh/rcar/adg.c18
-rw-r--r--sound/soc/soc-dapm.c1
-rw-r--r--sound/soc/soc-topology.c11
-rw-r--r--sound/soc/sof/Kconfig2
-rw-r--r--sound/soc/sof/intel/Kconfig3
-rw-r--r--sound/soc/sof/intel/hda-codec.c37
-rw-r--r--sound/soc/sof/intel/hda-dsp.c9
-rw-r--r--sound/soc/sof/intel/hda.h2
-rw-r--r--sound/soc/sof/sof-acpi-dev.c11
-rw-r--r--sound/soc/sof/sof-pci-dev.c10
-rw-r--r--sound/usb/card.c5
-rw-r--r--sound/usb/card.h3
-rw-r--r--sound/usb/clock.c21
-rw-r--r--sound/usb/endpoint.c93
-rw-r--r--sound/usb/endpoint.h2
-rw-r--r--sound/usb/format.c11
-rw-r--r--sound/usb/implicit.c62
-rw-r--r--sound/usb/midi.c4
-rw-r--r--sound/usb/pcm.c174
-rw-r--r--sound/usb/quirks-table.h6
-rw-r--r--sound/usb/quirks.c86
-rw-r--r--sound/usb/usbaudio.h1
62 files changed, 752 insertions, 331 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 9f3f8e953ff0..c4aac703dc22 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -382,8 +382,8 @@ retry:
continue;
/*
- * The 'deps' array includes maximum three dependencies
- * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth
+ * The 'deps' array includes maximum four dependencies
+ * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fifth
* member of this array is a sentinel and should be
* negative value.
*
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index 11554d0412f0..1b8409ec2c97 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -611,7 +611,8 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
if (info->is_midi) {
struct midi_info minf;
- snd_seq_oss_midi_make_info(dp, info->midi_mapped, &minf);
+ if (snd_seq_oss_midi_make_info(dp, info->midi_mapped, &minf))
+ return -ENXIO;
inf->synth_type = SYNTH_TYPE_MIDI;
inf->synth_subtype = 0;
inf->nr_voices = 16;
diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index 7f82762ccc8c..ee7122c461d4 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -88,7 +88,7 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
/* Set interval to next transaction. */
ff->next_ktime[port] = ktime_add_ns(ktime_get(),
- ff->rx_bytes[port] * 8 * NSEC_PER_SEC / 31250);
+ ff->rx_bytes[port] * 8 * (NSEC_PER_SEC / 31250));
if (quad_count == 1)
tcode = TCODE_WRITE_QUADLET_REQUEST;
diff --git a/sound/firewire/tascam/tascam-transaction.c b/sound/firewire/tascam/tascam-transaction.c
index 90288b4b4637..a073cece4a7d 100644
--- a/sound/firewire/tascam/tascam-transaction.c
+++ b/sound/firewire/tascam/tascam-transaction.c
@@ -209,7 +209,7 @@ static void midi_port_work(struct work_struct *work)
/* Set interval to next transaction. */
port->next_ktime = ktime_add_ns(ktime_get(),
- port->consume_bytes * 8 * NSEC_PER_SEC / 31250);
+ port->consume_bytes * 8 * (NSEC_PER_SEC / 31250));
/* Start this transaction. */
port->idling = false;
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index 6a0d070c60c9..c45686172517 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -307,6 +307,10 @@ static const struct config_entry config_table[] = {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
.device = 0xa0c8,
},
+ {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = 0x43c8,
+ },
#endif
/* Elkhart Lake */
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 687216e74526..eec1775dfffe 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2934,7 +2934,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
snd_hdac_leave_pm(&codec->core);
}
-static int hda_codec_suspend(struct device *dev)
+static int hda_codec_runtime_suspend(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
unsigned int state;
@@ -2953,7 +2953,7 @@ static int hda_codec_suspend(struct device *dev)
return 0;
}
-static int hda_codec_resume(struct device *dev)
+static int hda_codec_runtime_resume(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
@@ -2968,16 +2968,6 @@ static int hda_codec_resume(struct device *dev)
return 0;
}
-static int hda_codec_runtime_suspend(struct device *dev)
-{
- return hda_codec_suspend(dev);
-}
-
-static int hda_codec_runtime_resume(struct device *dev)
-{
- return hda_codec_resume(dev);
-}
-
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
@@ -2998,31 +2988,31 @@ static void hda_codec_pm_complete(struct device *dev)
static int hda_codec_pm_suspend(struct device *dev)
{
dev->power.power_state = PMSG_SUSPEND;
- return hda_codec_suspend(dev);
+ return pm_runtime_force_suspend(dev);
}
static int hda_codec_pm_resume(struct device *dev)
{
dev->power.power_state = PMSG_RESUME;
- return hda_codec_resume(dev);
+ return pm_runtime_force_resume(dev);
}
static int hda_codec_pm_freeze(struct device *dev)
{
dev->power.power_state = PMSG_FREEZE;
- return hda_codec_suspend(dev);
+ return pm_runtime_force_suspend(dev);
}
static int hda_codec_pm_thaw(struct device *dev)
{
dev->power.power_state = PMSG_THAW;
- return hda_codec_resume(dev);
+ return pm_runtime_force_resume(dev);
}
static int hda_codec_pm_restore(struct device *dev)
{
dev->power.power_state = PMSG_RESTORE;
- return hda_codec_resume(dev);
+ return pm_runtime_force_resume(dev);
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 6852668f1bcb..068847e263e8 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1444,7 +1444,7 @@ static bool atpx_present(void)
dhandle = ACPI_HANDLE(&pdev->dev);
if (dhandle) {
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
- if (!ACPI_FAILURE(status)) {
+ if (ACPI_SUCCESS(status)) {
pci_dev_put(pdev);
return true;
}
@@ -1454,7 +1454,7 @@ static bool atpx_present(void)
dhandle = ACPI_HANDLE(&pdev->dev);
if (dhandle) {
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
- if (!ACPI_FAILURE(status)) {
+ if (ACPI_SUCCESS(status)) {
pci_dev_put(pdev);
return true;
}
@@ -2220,8 +2220,6 @@ static const struct snd_pci_quirk power_save_denylist[] = {
SND_PCI_QUIRK(0x1849, 0x7662, "Asrock H81M-HDS", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0),
- /* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */
- SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
SND_PCI_QUIRK(0x1558, 0x6504, "Clevo W65_67SB", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
@@ -2486,6 +2484,9 @@ static const struct pci_device_id azx_ids[] = {
/* CometLake-S */
{ PCI_DEVICE(0x8086, 0xa3f0),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ /* CometLake-R */
+ { PCI_DEVICE(0x8086, 0xf0c8),
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
/* Icelake */
{ PCI_DEVICE(0x8086, 0x34c8),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
@@ -2509,6 +2510,9 @@ static const struct pci_device_id azx_ids[] = {
/* Alderlake-S */
{ PCI_DEVICE(0x8086, 0x7ad0),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+ /* Alderlake-P */
+ { PCI_DEVICE(0x8086, 0x51c8),
+ .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
/* Elkhart Lake */
{ PCI_DEVICE(0x8086, 0x4b55),
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
@@ -2600,7 +2604,8 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
/* ATI HDMI */
{ PCI_DEVICE(0x1002, 0x0002),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
+ AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0x1308),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0x157a),
@@ -2662,9 +2667,11 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x1002, 0xaab0),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaac0),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
+ AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xaac8),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
+ AZX_DCAPS_PM_RUNTIME },
{ PCI_DEVICE(0x1002, 0xaad8),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
AZX_DCAPS_PM_RUNTIME },
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 70164d1428d4..361cf2041911 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -388,7 +388,7 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
* in powers of 2, next available ratio is 16 which can be
* used as a limiting factor here.
*/
- if (of_device_is_compatible(np, "nvidia,tegra194-hda"))
+ if (of_device_is_compatible(np, "nvidia,tegra30-hda"))
chip->bus.core.sdo_limit = 16;
/* codec detection */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index be5000dd1585..d49cc4409d59 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -1070,6 +1070,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
static const struct hda_device_id snd_hda_id_conexant[] = {
HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
+ HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 1e4a4b83fbf6..97adff0cbcab 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1733,7 +1733,7 @@ static void silent_stream_disable(struct hda_codec *codec,
per_pin->silent_stream = false;
unlock_out:
- mutex_unlock(&spec->pcm_lock);
+ mutex_unlock(&per_pin->lock);
}
/* update ELD and jack state via audio component */
@@ -4346,6 +4346,7 @@ HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi),
HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi),
HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi),
HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI", patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi),
HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index dde5ba209541..290645516313 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6289,6 +6289,7 @@ enum {
ALC221_FIXUP_HP_FRONT_MIC,
ALC292_FIXUP_TPT460,
ALC298_FIXUP_SPK_VOLUME,
+ ALC298_FIXUP_LENOVO_SPK_VOLUME,
ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
ALC269_FIXUP_ATIV_BOOK_8,
ALC221_FIXUP_HP_MIC_NO_PRESENCE,
@@ -6370,6 +6371,7 @@ enum {
ALC256_FIXUP_HP_HEADSET_MIC,
ALC236_FIXUP_DELL_AIO_HEADSET_MIC,
ALC282_FIXUP_ACER_DISABLE_LINEOUT,
+ ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -7119,6 +7121,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
},
+ [ALC298_FIXUP_LENOVO_SPK_VOLUME] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc298_fixup_speaker_volume,
+ },
[ALC295_FIXUP_DISABLE_DAC3] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc295_fixup_disable_dac3,
@@ -7803,6 +7809,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE
},
+ [ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -7821,6 +7833,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x1025, 0x1094, "Acer Aspire E5-575T", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1025, 0x1099, "Acer Aspire E5-523G", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x110e, "Acer Aspire ES1-432", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1166, "Acer Veriton N4640G", ALC269_FIXUP_LIFEBOOK),
@@ -7885,7 +7898,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x09bf, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0a2e, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0a30, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC),
- SND_PCI_QUIRK(0x1028, 0x0a58, "Dell Precision 3650 Tower", ALC255_FIXUP_DELL_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1028, 0x0a58, "Dell", ALC255_FIXUP_DELL_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -7959,11 +7972,17 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8780, "HP ZBook Fury 17 G7 Mobile Workstation",
+ ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation",
+ ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
@@ -7987,6 +8006,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
+ SND_PCI_QUIRK(0x1043, 0x1982, "ASUS B1400CEPE", ALC256_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x19ce, "ASUS B9450FA", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x19e1, "ASUS UX581LV", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
@@ -8021,6 +8041,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE),
SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
@@ -8126,6 +8148,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3151, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x17aa, 0x3176, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940", ALC298_FIXUP_LENOVO_SPK_VOLUME),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 7ef8f3105cdb..a5c1a2c4eae4 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -113,6 +113,7 @@ static struct via_spec *via_new_spec(struct hda_codec *codec)
spec->codec_type = VT1708S;
spec->gen.indep_hp = 1;
spec->gen.keep_eapd_on = 1;
+ spec->gen.dac_min_mute = 1;
spec->gen.pcm_playback_hook = via_playback_pcm_hook;
spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
codec->power_save_node = 1;
@@ -1002,6 +1003,7 @@ static const struct hda_verb vt1802_init_verbs[] = {
enum {
VIA_FIXUP_INTMIC_BOOST,
VIA_FIXUP_ASUS_G75,
+ VIA_FIXUP_POWER_SAVE,
};
static void via_fixup_intmic_boost(struct hda_codec *codec,
@@ -1011,6 +1013,13 @@ static void via_fixup_intmic_boost(struct hda_codec *codec,
override_mic_boost(codec, 0x30, 0, 2, 40);
}
+static void via_fixup_power_save(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ codec->power_save_node = 0;
+}
+
static const struct hda_fixup via_fixups[] = {
[VIA_FIXUP_INTMIC_BOOST] = {
.type = HDA_FIXUP_FUNC,
@@ -1025,11 +1034,16 @@ static const struct hda_fixup via_fixups[] = {
{ }
}
},
+ [VIA_FIXUP_POWER_SAVE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = via_fixup_power_save,
+ },
};
static const struct snd_pci_quirk vt2002p_fixups[] = {
SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75),
SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),
+ SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", VIA_FIXUP_POWER_SAVE),
{}
};
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
index 8c138e490f0c..d3536fd6a124 100644
--- a/sound/soc/amd/raven/pci-acp3x.c
+++ b/sound/soc/amd/raven/pci-acp3x.c
@@ -140,21 +140,14 @@ static int snd_acp3x_probe(struct pci_dev *pci,
goto release_regions;
}
- /* check for msi interrupt support */
- ret = pci_enable_msi(pci);
- if (ret)
- /* msi is not enabled */
- irqflags = IRQF_SHARED;
- else
- /* msi is enabled */
- irqflags = 0;
+ irqflags = IRQF_SHARED;
addr = pci_resource_start(pci, 0);
adata->acp3x_base = devm_ioremap(&pci->dev, addr,
pci_resource_len(pci, 0));
if (!adata->acp3x_base) {
ret = -ENOMEM;
- goto disable_msi;
+ goto release_regions;
}
pci_set_master(pci);
pci_set_drvdata(pci, adata);
@@ -162,7 +155,7 @@ static int snd_acp3x_probe(struct pci_dev *pci,
adata->pme_en = rv_readl(adata->acp3x_base + mmACP_PME_EN);
ret = acp3x_init(adata);
if (ret)
- goto disable_msi;
+ goto release_regions;
val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
switch (val) {
@@ -251,8 +244,6 @@ unregister_devs:
de_init:
if (acp3x_deinit(adata->acp3x_base))
dev_err(&pci->dev, "ACP de-init failed\n");
-disable_msi:
- pci_disable_msi(pci);
release_regions:
pci_release_regions(pci);
disable_pci:
@@ -311,7 +302,6 @@ static void snd_acp3x_remove(struct pci_dev *pci)
dev_err(&pci->dev, "ACP de-init failed\n");
pm_runtime_forbid(&pci->dev);
pm_runtime_get_noresume(&pci->dev);
- pci_disable_msi(pci);
pci_release_regions(pci);
pci_disable_device(pci);
}
diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c
index fa169bf09886..050a61fe9693 100644
--- a/sound/soc/amd/renoir/rn-pci-acp3x.c
+++ b/sound/soc/amd/renoir/rn-pci-acp3x.c
@@ -165,10 +165,38 @@ static int rn_acp_deinit(void __iomem *acp_base)
static const struct dmi_system_id rn_acp_quirk_table[] = {
{
- /* Lenovo IdeaPad Flex 5 14ARE05, IdeaPad 5 15ARE05 */
+ /* Lenovo IdeaPad S340-14API */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
- DMI_EXACT_MATCH(DMI_BOARD_NAME, "LNVNB161216"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "81NB"),
+ }
+ },
+ {
+ /* Lenovo IdeaPad Flex 5 14ARE05 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "81X2"),
+ }
+ },
+ {
+ /* Lenovo IdeaPad 5 15ARE05 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "81YQ"),
+ }
+ },
+ {
+ /* Lenovo ThinkPad E14 Gen 2 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "20T6CTO1WW"),
+ }
+ },
+ {
+ /* Lenovo ThinkPad X395 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "20NLCTO1WW"),
}
},
{}
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 142373ec411a..9fe9471f4514 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -143,7 +143,7 @@ config SND_MCHP_SOC_SPDIFTX
- sama7g5
This S/PDIF TX driver is compliant with IEC-60958 standard and
- includes programable User Data and Channel Status fields.
+ includes programmable User Data and Channel Status fields.
config SND_MCHP_SOC_SPDIFRX
tristate "Microchip ASoC driver for boards using S/PDIF RX"
@@ -157,5 +157,5 @@ config SND_MCHP_SOC_SPDIFRX
- sama7g5
This S/PDIF RX driver is compliant with IEC-60958 standard and
- includes programable User Data and Channel Status fields.
+ includes programmable User Data and Channel Status fields.
endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index ba4eb54aafcb..9bf6bfdaf11e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -457,7 +457,7 @@ config SND_SOC_ADAU7118_HW
help
Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
Converter. In this mode, the device works in standalone mode which
- means that there is no bus to comunicate with it. Stereo mode is not
+ means that there is no bus to communicate with it. Stereo mode is not
supported in this mode.
To compile this driver as a module, choose M here: the module
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 1010c9ee2e83..472caad17012 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -595,18 +595,10 @@ static struct snd_soc_dai_driver ak4497_dai = {
.ops = &ak4458_dai_ops,
};
-static void ak4458_power_off(struct ak4458_priv *ak4458)
+static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
{
if (ak4458->reset_gpiod) {
- gpiod_set_value_cansleep(ak4458->reset_gpiod, 0);
- usleep_range(1000, 2000);
- }
-}
-
-static void ak4458_power_on(struct ak4458_priv *ak4458)
-{
- if (ak4458->reset_gpiod) {
- gpiod_set_value_cansleep(ak4458->reset_gpiod, 1);
+ gpiod_set_value_cansleep(ak4458->reset_gpiod, active);
usleep_range(1000, 2000);
}
}
@@ -620,7 +612,7 @@ static int ak4458_init(struct snd_soc_component *component)
if (ak4458->mute_gpiod)
gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
- ak4458_power_on(ak4458);
+ ak4458_reset(ak4458, false);
ret = snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
0x80, 0x80); /* ACKS bit = 1; 10000000 */
@@ -650,7 +642,7 @@ static void ak4458_remove(struct snd_soc_component *component)
{
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
- ak4458_power_off(ak4458);
+ ak4458_reset(ak4458, true);
}
#ifdef CONFIG_PM
@@ -660,7 +652,7 @@ static int __maybe_unused ak4458_runtime_suspend(struct device *dev)
regcache_cache_only(ak4458->regmap, true);
- ak4458_power_off(ak4458);
+ ak4458_reset(ak4458, true);
if (ak4458->mute_gpiod)
gpiod_set_value_cansleep(ak4458->mute_gpiod, 0);
@@ -685,8 +677,8 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
if (ak4458->mute_gpiod)
gpiod_set_value_cansleep(ak4458->mute_gpiod, 1);
- ak4458_power_off(ak4458);
- ak4458_power_on(ak4458);
+ ak4458_reset(ak4458, true);
+ ak4458_reset(ak4458, false);
regcache_cache_only(ak4458->regmap, false);
regcache_mark_dirty(ak4458->regmap);
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index d5fcc4db8284..0f3ac22f2cf8 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -717,7 +717,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component,
void *data)
{
struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
- int ret = -EOPNOTSUPP;
+ int ret = -ENOTSUPP;
if (hcp->hcd.ops->hook_plugged_cb) {
hcp->jack = jack;
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index 92921e34f948..85f6865019d4 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -19,6 +19,12 @@
#include <sound/tlv.h>
#include "max98373.h"
+static const u32 max98373_i2c_cache_reg[] = {
+ MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK,
+ MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK,
+ MAX98373_R20B6_BDE_CUR_STATE_READBACK,
+};
+
static struct reg_default max98373_reg[] = {
{MAX98373_R2000_SW_RESET, 0x00},
{MAX98373_R2001_INT_RAW1, 0x00},
@@ -472,6 +478,11 @@ static struct snd_soc_dai_driver max98373_dai[] = {
static int max98373_suspend(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
+ int i;
+
+ /* cache feedback register values before suspend */
+ for (i = 0; i < max98373->cache_num; i++)
+ regmap_read(max98373->regmap, max98373->cache[i].reg, &max98373->cache[i].val);
regcache_cache_only(max98373->regmap, true);
regcache_mark_dirty(max98373->regmap);
@@ -509,6 +520,7 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
{
int ret = 0;
int reg = 0;
+ int i;
struct max98373_priv *max98373 = NULL;
max98373 = devm_kzalloc(&i2c->dev, sizeof(*max98373), GFP_KERNEL);
@@ -534,6 +546,14 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
return ret;
}
+ max98373->cache_num = ARRAY_SIZE(max98373_i2c_cache_reg);
+ max98373->cache = devm_kcalloc(&i2c->dev, max98373->cache_num,
+ sizeof(*max98373->cache),
+ GFP_KERNEL);
+
+ for (i = 0; i < max98373->cache_num; i++)
+ max98373->cache[i].reg = max98373_i2c_cache_reg[i];
+
/* voltage/current slot & gpio configuration */
max98373_slot_config(&i2c->dev, max98373);
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index ec2e79c57357..b8d471d79e93 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -23,6 +23,12 @@ struct sdw_stream_data {
struct sdw_stream_runtime *sdw_stream;
};
+static const u32 max98373_sdw_cache_reg[] = {
+ MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK,
+ MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK,
+ MAX98373_R20B6_BDE_CUR_STATE_READBACK,
+};
+
static struct reg_default max98373_reg[] = {
{MAX98373_R0040_SCP_INIT_STAT_1, 0x00},
{MAX98373_R0041_SCP_INIT_MASK_1, 0x00},
@@ -245,6 +251,11 @@ static const struct regmap_config max98373_sdw_regmap = {
static __maybe_unused int max98373_suspend(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
+ int i;
+
+ /* cache feedback register values before suspend */
+ for (i = 0; i < max98373->cache_num; i++)
+ regmap_read(max98373->regmap, max98373->cache[i].reg, &max98373->cache[i].val);
regcache_cache_only(max98373->regmap, true);
@@ -757,6 +768,7 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
{
struct max98373_priv *max98373;
int ret;
+ int i;
struct device *dev = &slave->dev;
/* Allocate and assign private driver data structure */
@@ -768,6 +780,14 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
max98373->regmap = regmap;
max98373->slave = slave;
+ max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg);
+ max98373->cache = devm_kcalloc(dev, max98373->cache_num,
+ sizeof(*max98373->cache),
+ GFP_KERNEL);
+
+ for (i = 0; i < max98373->cache_num; i++)
+ max98373->cache[i].reg = max98373_sdw_cache_reg[i];
+
/* Read voltage and slot configuration */
max98373_slot_config(dev, max98373);
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
index 929bb1798c43..31d571d4fac1 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -168,6 +168,31 @@ static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum,
MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0,
max98373_ADC_samplerate_text);
+static int max98373_feedback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
+ int i;
+
+ if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
+ /*
+ * Register values will be cached before suspend. The cached value
+ * will be a valid value and userspace will happy with that.
+ */
+ for (i = 0; i < max98373->cache_num; i++) {
+ if (mc->reg == max98373->cache[i].reg) {
+ ucontrol->value.integer.value[0] = max98373->cache[i].val;
+ return 0;
+ }
+ }
+ }
+
+ return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
static const struct snd_kcontrol_new max98373_snd_controls[] = {
SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG,
MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
@@ -209,8 +234,10 @@ SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
MAX98373_FLT_EN_SHIFT, 1, 0),
SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
MAX98373_FLT_EN_SHIFT, 1, 0),
-SOC_SINGLE("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0),
-SOC_SINGLE("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0),
+SOC_SINGLE_EXT("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0,
+ max98373_feedback_get, NULL),
+SOC_SINGLE_EXT("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0,
+ max98373_feedback_get, NULL),
SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
0, 0x3, 0),
SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
@@ -226,7 +253,8 @@ SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0),
SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0),
SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0),
SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0),
-SOC_SINGLE("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0),
+SOC_SINGLE_EXT("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0,
+ max98373_feedback_get, NULL),
SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0),
SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0),
SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h
index 4ab29b9d51c7..71f5a5228f34 100644
--- a/sound/soc/codecs/max98373.h
+++ b/sound/soc/codecs/max98373.h
@@ -203,6 +203,11 @@
/* MAX98373_R2000_SW_RESET */
#define MAX98373_SOFT_RESET (0x1 << 0)
+struct max98373_cache {
+ u32 reg;
+ u32 val;
+};
+
struct max98373_priv {
struct regmap *regmap;
int reset_gpio;
@@ -212,6 +217,9 @@ struct max98373_priv {
bool interleave_mode;
unsigned int ch_size;
bool tdm_mode;
+ /* cache for reading a valid fake feedback value */
+ struct max98373_cache *cache;
+ int cache_num;
/* variables to support soundwire */
struct sdw_slave *slave;
bool hw_init;
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
index 5771c02c3459..85f744184a60 100644
--- a/sound/soc/codecs/rt711.c
+++ b/sound/soc/codecs/rt711.c
@@ -462,6 +462,8 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
unsigned int read_ll, read_rl;
int i;
+ mutex_lock(&rt711->calibrate_mutex);
+
/* Can't use update bit function, so read the original value first */
addr_h = mc->reg;
addr_l = mc->rreg;
@@ -547,6 +549,8 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
+
+ mutex_unlock(&rt711->calibrate_mutex);
return 0;
}
@@ -859,9 +863,11 @@ static int rt711_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
+ mutex_lock(&rt711->calibrate_mutex);
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE,
AC_PWRST_D3);
+ mutex_unlock(&rt711->calibrate_mutex);
break;
default:
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index dec8716aa8ef..985b2dcecf13 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -2031,11 +2031,14 @@ static struct wm_coeff_ctl *wm_adsp_get_ctl(struct wm_adsp *dsp,
unsigned int alg)
{
struct wm_coeff_ctl *pos, *rslt = NULL;
+ const char *fw_txt = wm_adsp_fw_text[dsp->fw];
list_for_each_entry(pos, &dsp->ctl_list, list) {
if (!pos->subname)
continue;
if (strncmp(pos->subname, name, pos->subname_len) == 0 &&
+ strncmp(pos->fw_name, fw_txt,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0 &&
pos->alg_region.alg == alg &&
pos->alg_region.type == type) {
rslt = pos;
diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c
index 2c2a76a71940..dbbb7618351c 100644
--- a/sound/soc/fsl/imx-hdmi.c
+++ b/sound/soc/fsl/imx-hdmi.c
@@ -90,7 +90,7 @@ static int imx_hdmi_init(struct snd_soc_pcm_runtime *rtd)
}
ret = snd_soc_component_set_jack(component, &data->hdmi_jack, NULL);
- if (ret && ret != -EOPNOTSUPP) {
+ if (ret && ret != -ENOTSUPP) {
dev_err(card->dev, "Can't set HDMI Jack %d\n", ret);
return ret;
}
@@ -164,6 +164,7 @@ static int imx_hdmi_probe(struct platform_device *pdev)
if ((hdmi_out && hdmi_in) || (!hdmi_out && !hdmi_in)) {
dev_err(&pdev->dev, "Invalid HDMI DAI link\n");
+ ret = -EINVAL;
goto fail;
}
diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
index c55d1239e705..c763bfeb1f38 100644
--- a/sound/soc/intel/boards/haswell.c
+++ b/sound/soc/intel/boards/haswell.c
@@ -189,6 +189,7 @@ static struct platform_driver haswell_audio = {
.probe = haswell_audio_probe,
.driver = {
.name = "haswell-audio",
+ .pm = &snd_soc_pm_ops,
},
};
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index ca968901ac96..6d0d6ef711e0 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -71,6 +71,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
+ },
+ .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
+ SOF_RT715_DAI_ID_FIX |
+ SOF_SDW_FOUR_SPK),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
},
.driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c
index fcd8dff27ae8..1275c149acc0 100644
--- a/sound/soc/intel/skylake/cnl-sst.c
+++ b/sound/soc/intel/skylake/cnl-sst.c
@@ -224,6 +224,7 @@ static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
"dsp boot timeout, status=%#x error=%#x\n",
sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS),
sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE));
+ ret = -ETIMEDOUT;
goto err;
}
} else {
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index ae466cd59292..b824086203b9 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -3619,19 +3619,20 @@ static void skl_tplg_complete(struct snd_soc_component *component)
list_for_each_entry(dobj, &component->dobj_list, list) {
struct snd_kcontrol *kcontrol = dobj->control.kcontrol;
- struct soc_enum *se =
- (struct soc_enum *)kcontrol->private_value;
- char **texts = dobj->control.dtexts;
+ struct soc_enum *se;
+ char **texts;
char chan_text[4];
- if (dobj->type != SND_SOC_DOBJ_ENUM ||
- dobj->control.kcontrol->put !=
- skl_tplg_multi_config_set_dmic)
+ if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol ||
+ kcontrol->put != skl_tplg_multi_config_set_dmic)
continue;
+
+ se = (struct soc_enum *)kcontrol->private_value;
+ texts = dobj->control.dtexts;
sprintf(chan_text, "c%d", mach->mach_params.dmic_num);
for (i = 0; i < se->items; i++) {
- struct snd_ctl_elem_value val;
+ struct snd_ctl_elem_value val = {};
if (strstr(texts[i], chan_text)) {
val.value.enumerated.item[0] = i;
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 078e58f1ad0b..cfbd0c65c7a3 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -532,6 +532,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.dpcm_playback = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
+ .ignore = 1,
.init = mt8183_da7219_max98357_hdmi_init,
SND_SOC_DAILINK_REG(tdm),
},
@@ -754,8 +755,10 @@ static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev)
}
}
- if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0)
+ if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
dai_link->codecs->of_node = hdmi_codec;
+ dai_link->ignore = 0;
+ }
if (!dai_link->platforms->name)
dai_link->platforms->of_node = platform_node;
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index 8c8340854859..1ce3eddbee13 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -515,6 +515,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
.ops = &mt8183_mt6358_tdm_ops,
+ .ignore = 1,
.init = mt8183_mt6358_ts3a227_max98357_hdmi_init,
SND_SOC_DAILINK_REG(tdm),
},
@@ -661,8 +662,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
SND_SOC_DAIFMT_CBM_CFM;
}
- if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0)
+ if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
dai_link->codecs->of_node = hdmi_codec;
+ dai_link->ignore = 0;
+ }
if (!dai_link->platforms->name)
dai_link->platforms->of_node = platform_node;
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
index 716fbb4126b5..ae2c748eb19c 100644
--- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -401,6 +401,53 @@ static const struct snd_soc_ops mt8192_mt6359_rt1015_rt5682_capture1_ops = {
.startup = mt8192_mt6359_rt1015_rt5682_cap1_startup,
};
+static int
+mt8192_mt6359_rt5682_startup(struct snd_pcm_substream *substream)
+{
+ static const unsigned int channels[] = {
+ 1, 2
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+ };
+ static const unsigned int rates[] = {
+ 48000
+ };
+ static const struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+ };
+
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+ if (ret < 0) {
+ dev_err(rtd->dev, "hw_constraint_list channels failed\n");
+ return ret;
+ }
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+ if (ret < 0) {
+ dev_err(rtd->dev, "hw_constraint_list rate failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops mt8192_mt6359_rt5682_ops = {
+ .startup = mt8192_mt6359_rt5682_startup,
+};
+
/* FE */
SND_SOC_DAILINK_DEFS(playback1,
DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
@@ -648,6 +695,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
+ .ops = &mt8192_mt6359_rt5682_ops,
SND_SOC_DAILINK_REG(playback3),
},
{
@@ -721,6 +769,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
+ .ops = &mt8192_mt6359_rt5682_ops,
SND_SOC_DAILINK_REG(capture2),
},
{
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c
index c8664ab80d45..87cac440b369 100644
--- a/sound/soc/meson/axg-tdm-interface.c
+++ b/sound/soc/meson/axg-tdm-interface.c
@@ -467,8 +467,20 @@ static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component,
return ret;
}
+static const struct snd_soc_dapm_widget axg_tdm_iface_dapm_widgets[] = {
+ SND_SOC_DAPM_SIGGEN("Playback Signal"),
+};
+
+static const struct snd_soc_dapm_route axg_tdm_iface_dapm_routes[] = {
+ { "Loopback", NULL, "Playback Signal" },
+};
+
static const struct snd_soc_component_driver axg_tdm_iface_component_drv = {
- .set_bias_level = axg_tdm_iface_set_bias_level,
+ .dapm_widgets = axg_tdm_iface_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(axg_tdm_iface_dapm_widgets),
+ .dapm_routes = axg_tdm_iface_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(axg_tdm_iface_dapm_routes),
+ .set_bias_level = axg_tdm_iface_set_bias_level,
};
static const struct of_device_id axg_tdm_iface_of_match[] = {
diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c
index 88ed95ae886b..b4faf9d5c1aa 100644
--- a/sound/soc/meson/axg-tdmin.c
+++ b/sound/soc/meson/axg-tdmin.c
@@ -228,15 +228,6 @@ static const struct axg_tdm_formatter_driver axg_tdmin_drv = {
.regmap_cfg = &axg_tdmin_regmap_cfg,
.ops = &axg_tdmin_ops,
.quirks = &(const struct axg_tdm_formatter_hw) {
- .skew_offset = 2,
- },
-};
-
-static const struct axg_tdm_formatter_driver g12a_tdmin_drv = {
- .component_drv = &axg_tdmin_component_drv,
- .regmap_cfg = &axg_tdmin_regmap_cfg,
- .ops = &axg_tdmin_ops,
- .quirks = &(const struct axg_tdm_formatter_hw) {
.skew_offset = 3,
},
};
@@ -247,10 +238,10 @@ static const struct of_device_id axg_tdmin_of_match[] = {
.data = &axg_tdmin_drv,
}, {
.compatible = "amlogic,g12a-tdmin",
- .data = &g12a_tdmin_drv,
+ .data = &axg_tdmin_drv,
}, {
.compatible = "amlogic,sm1-tdmin",
- .data = &g12a_tdmin_drv,
+ .data = &axg_tdmin_drv,
}, {}
};
MODULE_DEVICE_TABLE(of, axg_tdmin_of_match);
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index af684fd19ab9..66b834312f33 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -270,18 +270,6 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
unsigned int id = dai->driver->id;
int ret = -EINVAL;
- unsigned int val = 0;
-
- ret = regmap_read(drvdata->lpaif_map,
- LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), &val);
- if (ret) {
- dev_err(dai->dev, "error reading from i2sctl reg: %d\n", ret);
- return ret;
- }
- if (val == LPAIF_I2SCTL_RESET_STATE) {
- dev_err(dai->dev, "error in i2sctl register state\n");
- return -ENOTRECOVERABLE;
- }
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -356,8 +344,30 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
}
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
+static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component,
+ struct of_phandle_args *args,
+ const char **dai_name)
+{
+ struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+ struct lpass_variant *variant = drvdata->variant;
+ int id = args->args[0];
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < variant->num_dai; i++) {
+ if (variant->dai_driver[i].id == id) {
+ *dai_name = variant->dai_driver[i].name;
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
.name = "lpass-cpu",
+ .of_xlate_dai_name = asoc_qcom_of_xlate_dai_name,
};
static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
@@ -454,20 +464,16 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
struct lpass_variant *v = drvdata->variant;
int i;
- for (i = 0; i < v->i2s_ports; ++i)
- if (reg == LPAIF_I2SCTL_REG(v, i))
- return true;
for (i = 0; i < v->irq_ports; ++i)
if (reg == LPAIF_IRQSTAT_REG(v, i))
return true;
for (i = 0; i < v->rdma_channels; ++i)
- if (reg == LPAIF_RDMACURR_REG(v, i) || reg == LPAIF_RDMACTL_REG(v, i))
+ if (reg == LPAIF_RDMACURR_REG(v, i))
return true;
for (i = 0; i < v->wrdma_channels; ++i)
- if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start) ||
- reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
+ if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
return true;
return false;
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 92f98b4df47f..ef8a7984f232 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -131,7 +131,7 @@ static struct lpass_variant ipq806x_data = {
.micmode = REG_FIELD_ID(0x0010, 4, 7, 5, 0x4),
.micmono = REG_FIELD_ID(0x0010, 3, 3, 5, 0x4),
.wssrc = REG_FIELD_ID(0x0010, 2, 2, 5, 0x4),
- .bitwidth = REG_FIELD_ID(0x0010, 0, 0, 5, 0x4),
+ .bitwidth = REG_FIELD_ID(0x0010, 0, 1, 5, 0x4),
.rdma_dyncclk = REG_FIELD_ID(0x6000, 12, 12, 4, 0x1000),
.rdma_bursten = REG_FIELD_ID(0x6000, 11, 11, 4, 0x1000),
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
index 405542832e99..baf72f124ea9 100644
--- a/sound/soc/qcom/lpass-lpaif-reg.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -133,7 +133,7 @@
#define LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan))
#define LPAIF_INTFDMA_REG(v, chan, reg, dai_id) \
- ((v->dai_driver[dai_id].id == LPASS_DP_RX) ? \
+ ((dai_id == LPASS_DP_RX) ? \
LPAIF_HDMI_RDMA##reg##_REG(v, chan) : \
LPAIF_RDMA##reg##_REG(v, chan))
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 80b09dede5f9..0074b7f2dbc1 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -257,6 +257,9 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
break;
case MI2S_PRIMARY:
case MI2S_SECONDARY:
+ case MI2S_TERTIARY:
+ case MI2S_QUATERNARY:
+ case MI2S_QUINARY:
ret = regmap_fields_write(dmactl->intf, id,
LPAIF_DMACTL_AUDINTF(dma_port));
if (ret) {
@@ -452,7 +455,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
unsigned int reg_irqclr = 0, val_irqclr = 0;
unsigned int reg_irqen = 0, val_irqen = 0, val_mask = 0;
unsigned int dai_id = cpu_dai->driver->id;
- unsigned int dma_ctrl_reg = 0;
ch = pcm_data->dma_ch;
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -469,17 +471,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
id = pcm_data->dma_ch - v->wrdma_channel_start;
map = drvdata->lpaif_map;
}
- ret = regmap_read(map, LPAIF_DMACTL_REG(v, ch, dir, dai_id), &dma_ctrl_reg);
- if (ret) {
- dev_err(soc_runtime->dev, "error reading from rdmactl reg: %d\n", ret);
- return ret;
- }
- if (dma_ctrl_reg == LPAIF_DMACTL_RESET_STATE ||
- dma_ctrl_reg == LPAIF_DMACTL_RESET_STATE + 1) {
- dev_err(soc_runtime->dev, "error in rdmactl register state\n");
- return -ENOTRECOVERABLE;
- }
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -500,7 +492,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
"error writing to rdmactl reg: %d\n", ret);
return ret;
}
- map = drvdata->hdmiif_map;
reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
val_irqclr = (LPAIF_IRQ_ALL(ch) |
LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
@@ -519,7 +510,9 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
break;
case MI2S_PRIMARY:
case MI2S_SECONDARY:
- map = drvdata->lpaif_map;
+ case MI2S_TERTIARY:
+ case MI2S_QUATERNARY:
+ case MI2S_QUINARY:
reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
val_irqclr = LPAIF_IRQ_ALL(ch);
@@ -563,7 +556,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
"error writing to rdmactl reg: %d\n", ret);
return ret;
}
- map = drvdata->hdmiif_map;
reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
val_mask = (LPAIF_IRQ_ALL(ch) |
LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
@@ -573,7 +565,9 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
break;
case MI2S_PRIMARY:
case MI2S_SECONDARY:
- map = drvdata->lpaif_map;
+ case MI2S_TERTIARY:
+ case MI2S_QUATERNARY:
+ case MI2S_QUINARY:
reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
val_mask = LPAIF_IRQ_ALL(ch);
val_irqen = 0;
@@ -670,6 +664,9 @@ static irqreturn_t lpass_dma_interrupt_handler(
break;
case MI2S_PRIMARY:
case MI2S_SECONDARY:
+ case MI2S_TERTIARY:
+ case MI2S_QUATERNARY:
+ case MI2S_QUINARY:
map = drvdata->lpaif_map;
reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
val = 0;
@@ -838,6 +835,39 @@ static void lpass_platform_pcm_free(struct snd_soc_component *component,
}
}
+static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
+{
+ struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+ struct regmap *map;
+ unsigned int dai_id = component->id;
+
+ if (dai_id == LPASS_DP_RX)
+ map = drvdata->hdmiif_map;
+ else
+ map = drvdata->lpaif_map;
+
+ regcache_cache_only(map, true);
+ regcache_mark_dirty(map);
+
+ return 0;
+}
+
+static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
+{
+ struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+ struct regmap *map;
+ unsigned int dai_id = component->id;
+
+ if (dai_id == LPASS_DP_RX)
+ map = drvdata->hdmiif_map;
+ else
+ map = drvdata->lpaif_map;
+
+ regcache_cache_only(map, false);
+ return regcache_sync(map);
+}
+
+
static const struct snd_soc_component_driver lpass_component_driver = {
.name = DRV_NAME,
.open = lpass_platform_pcmops_open,
@@ -850,6 +880,8 @@ static const struct snd_soc_component_driver lpass_component_driver = {
.mmap = lpass_platform_pcmops_mmap,
.pcm_construct = lpass_platform_pcm_new,
.pcm_destruct = lpass_platform_pcm_free,
+ .suspend = lpass_platform_pcmops_suspend,
+ .resume = lpass_platform_pcmops_resume,
};
diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c
index 85db650c2169..735c9dac28f2 100644
--- a/sound/soc/qcom/lpass-sc7180.c
+++ b/sound/soc/qcom/lpass-sc7180.c
@@ -20,7 +20,7 @@
#include "lpass.h"
static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
- [MI2S_PRIMARY] = {
+ {
.id = MI2S_PRIMARY,
.name = "Primary MI2S",
.playback = {
@@ -44,9 +44,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
},
.probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
- },
-
- [MI2S_SECONDARY] = {
+ }, {
.id = MI2S_SECONDARY,
.name = "Secondary MI2S",
.playback = {
@@ -60,8 +58,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
},
.probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
- },
- [LPASS_DP_RX] = {
+ }, {
.id = LPASS_DP_RX,
.name = "Hdmi",
.playback = {
@@ -174,7 +171,7 @@ static struct lpass_variant sc7180_data = {
.rdma_channels = 5,
.hdmi_rdma_reg_base = 0x64000,
.hdmi_rdma_reg_stride = 0x1000,
- .hdmi_rdma_channels = 4,
+ .hdmi_rdma_channels = 3,
.dmactl_audif_start = 1,
.wrdma_reg_base = 0x18000,
.wrdma_reg_stride = 0x1000,
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 0195372905ed..2d68af0da34d 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -12,7 +12,7 @@
#include <linux/compiler.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <dt-bindings/sound/sc7180-lpass.h>
+#include <dt-bindings/sound/qcom,lpass.h>
#include "lpass-hdmi.h"
#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index b9aacf3d3b29..abdfd9cf91e2 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -366,25 +366,27 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
- int i, ret;
+ int i;
for_each_rsnd_clk(clk, adg, i) {
- ret = 0;
if (enable) {
- ret = clk_prepare_enable(clk);
+ int ret = clk_prepare_enable(clk);
/*
* We shouldn't use clk_get_rate() under
* atomic context. Let's keep it when
* rsnd_adg_clk_enable() was called
*/
- adg->clk_rate[i] = clk_get_rate(adg->clk[i]);
+ adg->clk_rate[i] = 0;
+ if (ret < 0)
+ dev_warn(dev, "can't use clk %d\n", i);
+ else
+ adg->clk_rate[i] = clk_get_rate(clk);
} else {
- clk_disable_unprepare(clk);
+ if (adg->clk_rate[i])
+ clk_disable_unprepare(clk);
+ adg->clk_rate[i] = 0;
}
-
- if (ret < 0)
- dev_warn(dev, "can't use clk %d\n", i);
}
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 9f0c86cbdcca..2b75d0139e47 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2486,6 +2486,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
enum snd_soc_dapm_direction dir;
list_del(&w->list);
+ list_del(&w->dirty);
/*
* remove source and sink paths associated to this widget.
* While removing the path, remove reference to it from both
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 950c45008e24..22e7b4c9115b 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -447,7 +447,7 @@ static void remove_dai(struct snd_soc_component *comp,
{
struct snd_soc_dai_driver *dai_drv =
container_of(dobj, struct snd_soc_dai_driver, dobj);
- struct snd_soc_dai *dai;
+ struct snd_soc_dai *dai, *_dai;
if (pass != SOC_TPLG_PASS_PCM_DAI)
return;
@@ -455,9 +455,9 @@ static void remove_dai(struct snd_soc_component *comp,
if (dobj->ops && dobj->ops->dai_unload)
dobj->ops->dai_unload(comp, dobj);
- for_each_component_dais(comp, dai)
+ for_each_component_dais_safe(comp, dai, _dai)
if (dai->driver == dai_drv)
- dai->driver = NULL;
+ snd_soc_unregister_dai(dai);
list_del(&dobj->list);
}
@@ -902,7 +902,7 @@ static int soc_tplg_denum_create_values(struct soc_tplg *tplg, struct soc_enum *
return -EINVAL;
se->dobj.control.dvalues = devm_kcalloc(tplg->dev, le32_to_cpu(ec->items),
- sizeof(u32),
+ sizeof(*se->dobj.control.dvalues),
GFP_KERNEL);
if (!se->dobj.control.dvalues)
return -ENOMEM;
@@ -1742,7 +1742,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list);
/* register the DAI to the component */
- dai = devm_snd_soc_register_dai(tplg->dev, tplg->comp, dai_drv, false);
+ dai = snd_soc_register_dai(tplg->comp, dai_drv, false);
if (!dai)
return -ENOMEM;
@@ -1750,6 +1750,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
if (ret != 0) {
dev_err(dai->dev, "Failed to create DAI widgets %d\n", ret);
+ snd_soc_unregister_dai(dai);
return ret;
}
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index 031dad5fc4c7..3e8b6c035ce3 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -122,7 +122,7 @@ config SND_SOC_SOF_DEBUG_XRUN_STOP
bool "SOF stop on XRUN"
help
This option forces PCMs to stop on any XRUN event. This is useful to
- preserve any trace data ond pipeline status prior to the XRUN.
+ preserve any trace data and pipeline status prior to the XRUN.
Say Y if you are debugging SOF FW pipeline XRUNs.
If unsure select "N".
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index d306c370e5d1..4797a1cf8c80 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -355,7 +355,7 @@ config SND_SOC_SOF_HDA
config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK
bool "SOF support for SoundWire"
- depends on SOUNDWIRE && ACPI
+ depends on ACPI
help
This adds support for SoundWire with Sound Open Firmware
for Intel(R) platforms.
@@ -371,6 +371,7 @@ config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
config SND_SOC_SOF_INTEL_SOUNDWIRE
tristate
+ select SOUNDWIRE
select SOUNDWIRE_INTEL
help
This option is not user-selectable but automagically handled by
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index 6875fa570c2c..6744318de612 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -63,16 +63,18 @@ static int hda_codec_load_module(struct hda_codec *codec)
}
/* enable controller wake up event for all codecs with jack connectors */
-void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev)
+void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable)
{
struct hda_bus *hbus = sof_to_hbus(sdev);
struct hdac_bus *bus = sof_to_bus(sdev);
struct hda_codec *codec;
unsigned int mask = 0;
- list_for_each_codec(codec, hbus)
- if (codec->jacktbl.used)
- mask |= BIT(codec->core.addr);
+ if (enable) {
+ list_for_each_codec(codec, hbus)
+ if (codec->jacktbl.used)
+ mask |= BIT(codec->core.addr);
+ }
snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask);
}
@@ -81,23 +83,18 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev)
void hda_codec_jack_check(struct snd_sof_dev *sdev)
{
struct hda_bus *hbus = sof_to_hbus(sdev);
- struct hdac_bus *bus = sof_to_bus(sdev);
struct hda_codec *codec;
- /* disable controller Wake Up event*/
- snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0);
-
list_for_each_codec(codec, hbus)
/*
* Wake up all jack-detecting codecs regardless whether an event
* has been recorded in STATESTS
*/
if (codec->jacktbl.used)
- schedule_delayed_work(&codec->jackpoll_work,
- codec->jackpoll_interval);
+ pm_request_resume(&codec->core.dev);
}
#else
-void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) {}
+void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) {}
void hda_codec_jack_check(struct snd_sof_dev *sdev) {}
#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
EXPORT_SYMBOL_NS(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC);
@@ -156,7 +153,8 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
if (!hdev->bus->audio_component) {
dev_dbg(sdev->dev,
"iDisp hw present but no driver\n");
- goto error;
+ ret = -ENOENT;
+ goto out;
}
hda_priv->need_display_power = true;
}
@@ -173,24 +171,23 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
* other return codes without modification
*/
if (ret == 0)
- goto error;
+ ret = -ENOENT;
}
- return ret;
-
-error:
- snd_hdac_ext_bus_device_exit(hdev);
- return -ENOENT;
-
+out:
+ if (ret < 0) {
+ snd_hdac_device_unregister(hdev);
+ put_device(&hdev->dev);
+ }
#else
hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL);
if (!hdev)
return -ENOMEM;
ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev, HDA_DEV_ASOC);
+#endif
return ret;
-#endif
}
/* Codec initialization */
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 2b001151fe37..1c5e05b88a90 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -617,7 +617,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
if (runtime_suspend)
- hda_codec_jack_wake_enable(sdev);
+ hda_codec_jack_wake_enable(sdev, true);
/* power down all hda link */
snd_hdac_ext_bus_link_power_down_all(bus);
@@ -683,8 +683,11 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* check jack status */
- if (runtime_resume)
- hda_codec_jack_check(sdev);
+ if (runtime_resume) {
+ hda_codec_jack_wake_enable(sdev, false);
+ if (sdev->system_suspend_target == SOF_SUSPEND_NONE)
+ hda_codec_jack_check(sdev);
+ }
/* turn off the links that were off before suspend */
list_for_each_entry(hlink, &bus->hlink_list, list) {
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 9ec8ae0fd649..a3b6f3e9121c 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -650,7 +650,7 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev);
*/
void hda_codec_probe_bus(struct snd_sof_dev *sdev,
bool hda_codec_use_common_hdmi);
-void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev);
+void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable);
void hda_codec_jack_check(struct snd_sof_dev *sdev);
#endif /* CONFIG_SND_SOC_SOF_HDA */
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
index 2a369c2c6551..cc2e257087e4 100644
--- a/sound/soc/sof/sof-acpi-dev.c
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -131,12 +131,13 @@ static int sof_acpi_probe(struct platform_device *pdev)
if (!id)
return -ENODEV;
- ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
- if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
- dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n");
- return -ENODEV;
+ if (IS_REACHABLE(CONFIG_SND_INTEL_DSP_CONFIG)) {
+ ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
+ if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
+ dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n");
+ return -ENODEV;
+ }
}
-
dev_dbg(dev, "ACPI DSP detected");
sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 63b989e3ec40..215711ac7450 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -344,10 +344,12 @@ static int sof_pci_probe(struct pci_dev *pci,
const struct snd_sof_dsp_ops *ops;
int ret;
- ret = snd_intel_dsp_driver_probe(pci);
- if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
- dev_dbg(&pci->dev, "SOF PCI driver not selected, aborting probe\n");
- return -ENODEV;
+ if (IS_REACHABLE(CONFIG_SND_INTEL_DSP_CONFIG)) {
+ ret = snd_intel_dsp_driver_probe(pci);
+ if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
+ dev_dbg(&pci->dev, "SOF PCI driver not selected, aborting probe\n");
+ return -ENODEV;
+ }
}
dev_dbg(&pci->dev, "PCI DSP detected");
diff --git a/sound/usb/card.c b/sound/usb/card.c
index d731ca62d599..e08fbf8e3ee0 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -450,10 +450,8 @@ lookup_device_name(u32 id)
static void snd_usb_audio_free(struct snd_card *card)
{
struct snd_usb_audio *chip = card->private_data;
- struct snd_usb_endpoint *ep, *n;
- list_for_each_entry_safe(ep, n, &chip->ep_list, list)
- snd_usb_endpoint_free(ep);
+ snd_usb_endpoint_free_all(chip);
mutex_destroy(&chip->mutex);
if (!atomic_read(&chip->shutdown))
@@ -611,6 +609,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
chip->usb_id = usb_id;
INIT_LIST_HEAD(&chip->pcm_list);
INIT_LIST_HEAD(&chip->ep_list);
+ INIT_LIST_HEAD(&chip->iface_ref_list);
INIT_LIST_HEAD(&chip->midi_list);
INIT_LIST_HEAD(&chip->mixer_list);
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 6a027c349194..37091b117614 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -18,6 +18,7 @@ struct audioformat {
unsigned int frame_size; /* samples per frame for non-audio */
unsigned char iface; /* interface number */
unsigned char altsetting; /* corresponding alternate setting */
+ unsigned char ep_idx; /* endpoint array index */
unsigned char altset_idx; /* array index of altenate setting */
unsigned char attributes; /* corresponding attributes of cs endpoint */
unsigned char endpoint; /* endpoint */
@@ -42,6 +43,7 @@ struct audioformat {
};
struct snd_usb_substream;
+struct snd_usb_iface_ref;
struct snd_usb_endpoint;
struct snd_usb_power_domain;
@@ -58,6 +60,7 @@ struct snd_urb_ctx {
struct snd_usb_endpoint {
struct snd_usb_audio *chip;
+ struct snd_usb_iface_ref *iface_ref;
int opened; /* open refcount; protect with chip->mutex */
atomic_t running; /* running status */
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 31051f2be46d..dc68ed65e478 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -485,18 +485,9 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip,
const struct audioformat *fmt, int rate)
{
struct usb_device *dev = chip->dev;
- struct usb_host_interface *alts;
- unsigned int ep;
unsigned char data[3];
int err, crate;
- alts = snd_usb_get_host_interface(chip, fmt->iface, fmt->altsetting);
- if (!alts)
- return -EINVAL;
- if (get_iface_desc(alts)->bNumEndpoints < 1)
- return -EINVAL;
- ep = get_endpoint(alts, 0)->bEndpointAddress;
-
/* if endpoint doesn't have sampling rate control, bail out */
if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE))
return 0;
@@ -506,11 +497,11 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip,
data[2] = rate >> 16;
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
- UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
- data, sizeof(data));
+ UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
+ fmt->endpoint, data, sizeof(data));
if (err < 0) {
dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n",
- fmt->iface, fmt->altsetting, rate, ep);
+ fmt->iface, fmt->altsetting, rate, fmt->endpoint);
return err;
}
@@ -524,11 +515,11 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip,
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
- UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
- data, sizeof(data));
+ UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
+ fmt->endpoint, data, sizeof(data));
if (err < 0) {
dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n",
- fmt->iface, fmt->altsetting, ep);
+ fmt->iface, fmt->altsetting, fmt->endpoint);
chip->sample_rate_read_error++;
return 0; /* some devices don't support reading */
}
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 162da7a50046..8e568823c992 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -24,6 +24,14 @@
#define EP_FLAG_RUNNING 1
#define EP_FLAG_STOPPING 2
+/* interface refcounting */
+struct snd_usb_iface_ref {
+ unsigned char iface;
+ bool need_setup;
+ int opened;
+ struct list_head list;
+};
+
/*
* snd_usb_endpoint is a model that abstracts everything related to an
* USB endpoint and its streaming.
@@ -489,6 +497,28 @@ exit_clear:
}
/*
+ * Find or create a refcount object for the given interface
+ *
+ * The objects are released altogether in snd_usb_endpoint_free_all()
+ */
+static struct snd_usb_iface_ref *
+iface_ref_find(struct snd_usb_audio *chip, int iface)
+{
+ struct snd_usb_iface_ref *ip;
+
+ list_for_each_entry(ip, &chip->iface_ref_list, list)
+ if (ip->iface == iface)
+ return ip;
+
+ ip = kzalloc(sizeof(*ip), GFP_KERNEL);
+ if (!ip)
+ return NULL;
+ ip->iface = iface;
+ list_add_tail(&ip->list, &chip->iface_ref_list);
+ return ip;
+}
+
+/*
* Get the existing endpoint object corresponding EP
* Returns NULL if not present.
*/
@@ -520,8 +550,8 @@ snd_usb_get_endpoint(struct snd_usb_audio *chip, int ep_num)
*
* Returns zero on success or a negative error code.
*
- * New endpoints will be added to chip->ep_list and must be freed by
- * calling snd_usb_endpoint_free().
+ * New endpoints will be added to chip->ep_list and freed by
+ * calling snd_usb_endpoint_free_all().
*
* For SND_USB_ENDPOINT_TYPE_SYNC, the caller needs to guarantee that
* bNumEndpoints > 1 beforehand.
@@ -653,11 +683,17 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
} else {
ep->iface = fp->iface;
ep->altsetting = fp->altsetting;
- ep->ep_idx = 0;
+ ep->ep_idx = fp->ep_idx;
}
usb_audio_dbg(chip, "Open EP 0x%x, iface=%d:%d, idx=%d\n",
ep_num, ep->iface, ep->altsetting, ep->ep_idx);
+ ep->iface_ref = iface_ref_find(chip, ep->iface);
+ if (!ep->iface_ref) {
+ ep = NULL;
+ goto unlock;
+ }
+
ep->cur_audiofmt = fp;
ep->cur_channels = fp->channels;
ep->cur_rate = params_rate(params);
@@ -681,6 +717,11 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
ep->implicit_fb_sync);
} else {
+ if (WARN_ON(!ep->iface_ref)) {
+ ep = NULL;
+ goto unlock;
+ }
+
if (!endpoint_compatible(ep, fp, params)) {
usb_audio_err(chip, "Incompatible EP setup for 0x%x\n",
ep_num);
@@ -692,6 +733,9 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
ep_num, ep->opened);
}
+ if (!ep->iface_ref->opened++)
+ ep->iface_ref->need_setup = true;
+
ep->opened++;
unlock:
@@ -760,12 +804,16 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
mutex_lock(&chip->mutex);
usb_audio_dbg(chip, "Closing EP 0x%x (count %d)\n",
ep->ep_num, ep->opened);
- if (!--ep->opened) {
+
+ if (!--ep->iface_ref->opened)
endpoint_set_interface(chip, ep, false);
+
+ if (!--ep->opened) {
ep->iface = 0;
ep->altsetting = 0;
ep->cur_audiofmt = NULL;
ep->cur_rate = 0;
+ ep->iface_ref = NULL;
usb_audio_dbg(chip, "EP 0x%x closed\n", ep->ep_num);
}
mutex_unlock(&chip->mutex);
@@ -775,6 +823,8 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep)
{
ep->need_setup = true;
+ if (ep->iface_ref)
+ ep->iface_ref->need_setup = true;
}
/*
@@ -1195,11 +1245,22 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
int err = 0;
mutex_lock(&chip->mutex);
+ if (WARN_ON(!ep->iface_ref))
+ goto unlock;
if (!ep->need_setup)
goto unlock;
- /* No need to (re-)configure the sync EP belonging to the same altset */
- if (ep->ep_idx) {
+ /* If the interface has been already set up, just set EP parameters */
+ if (!ep->iface_ref->need_setup) {
+ /* sample rate setup of UAC1 is per endpoint, and we need
+ * to update at each EP configuration
+ */
+ if (ep->cur_audiofmt->protocol == UAC_VERSION_1) {
+ err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt,
+ ep->cur_rate);
+ if (err < 0)
+ goto unlock;
+ }
err = snd_usb_endpoint_set_params(chip, ep);
if (err < 0)
goto unlock;
@@ -1242,6 +1303,8 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
goto unlock;
}
+ ep->iface_ref->need_setup = false;
+
done:
ep->need_setup = false;
err = 1;
@@ -1387,15 +1450,21 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
}
/**
- * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
+ * snd_usb_endpoint_free_all: Free the resources of an snd_usb_endpoint
+ * @card: The chip
*
- * @ep: the endpoint to free
- *
- * This free all resources of the given ep.
+ * This free all endpoints and those resources
*/
-void snd_usb_endpoint_free(struct snd_usb_endpoint *ep)
+void snd_usb_endpoint_free_all(struct snd_usb_audio *chip)
{
- kfree(ep);
+ struct snd_usb_endpoint *ep, *en;
+ struct snd_usb_iface_ref *ip, *in;
+
+ list_for_each_entry_safe(ep, en, &chip->ep_list, list)
+ kfree(ep);
+
+ list_for_each_entry_safe(ip, in, &chip->iface_ref_list, list)
+ kfree(ip);
}
/*
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 11e3bb839fd7..eea4ca49876d 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -42,7 +42,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_release(struct snd_usb_endpoint *ep);
-void snd_usb_endpoint_free(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_free_all(struct snd_usb_audio *chip);
int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 9ebc5d202c87..e6ff317a6785 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -466,6 +466,17 @@ static int validate_sample_rate_table_v2v3(struct snd_usb_audio *chip,
unsigned int nr_rates;
int i, err;
+ /* performing the rate verification may lead to unexpected USB bus
+ * behavior afterwards by some unknown reason. Do this only for the
+ * known devices.
+ */
+ switch (USB_ID_VENDOR(chip->usb_id)) {
+ case 0x07fd: /* MOTU */
+ break;
+ default:
+ return 0; /* don't perform the validation as default */
+ }
+
table = kcalloc(fp->nr_rates, sizeof(*table), GFP_KERNEL);
if (!table)
return -ENOMEM;
diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c
index eb3a4c433c3e..521cc846d9d9 100644
--- a/sound/usb/implicit.c
+++ b/sound/usb/implicit.c
@@ -58,8 +58,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */
IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */
IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */
- IMPLICIT_FB_FIXED_DEV(0x2b73, 0x000a, 0x82, 0), /* Pioneer DJ DJM-900NXS2 */
- IMPLICIT_FB_FIXED_DEV(0x2b73, 0x0017, 0x82, 0), /* Pioneer DJ DJM-250MK2 */
IMPLICIT_FB_FIXED_DEV(0x1686, 0xf029, 0x82, 2), /* Zoom UAC-2 */
IMPLICIT_FB_FIXED_DEV(0x2466, 0x8003, 0x86, 2), /* Fractal Audio Axe-Fx II */
IMPLICIT_FB_FIXED_DEV(0x0499, 0x172a, 0x86, 2), /* Yamaha MODX */
@@ -74,10 +72,12 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
/* No quirk for playback but with capture quirk (see below) */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x0130), /* BOSS BR-80 */
+ IMPLICIT_FB_SKIP_DEV(0x0582, 0x0171), /* BOSS RC-505 */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x0189), /* BOSS GT-100v2 */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d6), /* BOSS GT-1 */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8), /* BOSS Katana */
IMPLICIT_FB_SKIP_DEV(0x0582, 0x01e5), /* BOSS GT-001 */
+ IMPLICIT_FB_SKIP_DEV(0x0582, 0x0203), /* BOSS AD-10 */
{} /* terminator */
};
@@ -85,10 +85,12 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
/* Implicit feedback quirk table for capture: only FIXED type */
static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = {
IMPLICIT_FB_FIXED_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */
+ IMPLICIT_FB_FIXED_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */
IMPLICIT_FB_FIXED_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */
IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */
IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */
IMPLICIT_FB_FIXED_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */
+ IMPLICIT_FB_FIXED_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */
{} /* terminator */
};
@@ -96,7 +98,7 @@ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = {
/* set up sync EP information on the audioformat */
static int add_implicit_fb_sync_ep(struct snd_usb_audio *chip,
struct audioformat *fmt,
- int ep, int ifnum,
+ int ep, int ep_idx, int ifnum,
const struct usb_host_interface *alts)
{
struct usb_interface *iface;
@@ -111,7 +113,7 @@ static int add_implicit_fb_sync_ep(struct snd_usb_audio *chip,
fmt->sync_ep = ep;
fmt->sync_iface = ifnum;
fmt->sync_altsetting = alts->desc.bAlternateSetting;
- fmt->sync_ep_idx = 0;
+ fmt->sync_ep_idx = ep_idx;
fmt->implicit_fb = 1;
usb_audio_dbg(chip,
"%d:%d: added %s implicit_fb sync_ep %x, iface %d:%d\n",
@@ -143,7 +145,7 @@ static int add_generic_uac2_implicit_fb(struct snd_usb_audio *chip,
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
USB_ENDPOINT_USAGE_IMPLICIT_FB)
return 0;
- return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
+ return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
ifnum, alts);
}
@@ -169,10 +171,33 @@ static int add_roland_implicit_fb(struct snd_usb_audio *chip,
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
USB_ENDPOINT_USAGE_IMPLICIT_FB)
return 0;
- return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
+ return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
ifnum, alts);
}
+/* Playback and capture EPs on Pioneer devices share the same iface/altset,
+ * but they don't seem working with the implicit fb mode well, hence we
+ * just return as if the sync were already set up.
+ */
+static int skip_pioneer_sync_ep(struct snd_usb_audio *chip,
+ struct audioformat *fmt,
+ struct usb_host_interface *alts)
+{
+ struct usb_endpoint_descriptor *epd;
+
+ if (alts->desc.bNumEndpoints != 2)
+ return 0;
+
+ epd = get_endpoint(alts, 1);
+ if (!usb_endpoint_is_isoc_in(epd) ||
+ (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC ||
+ ((epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
+ USB_ENDPOINT_USAGE_DATA &&
+ (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
+ USB_ENDPOINT_USAGE_IMPLICIT_FB))
+ return 0;
+ return 1; /* don't handle with the implicit fb, just skip sync EP */
+}
static int __add_generic_implicit_fb(struct snd_usb_audio *chip,
struct audioformat *fmt,
@@ -193,7 +218,7 @@ static int __add_generic_implicit_fb(struct snd_usb_audio *chip,
if (!usb_endpoint_is_isoc_in(epd) ||
(epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC)
return 0;
- return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
+ return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
iface, alts);
}
@@ -246,7 +271,7 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
case IMPLICIT_FB_NONE:
return 0; /* No quirk */
case IMPLICIT_FB_FIXED:
- return add_implicit_fb_sync_ep(chip, fmt, p->ep_num,
+ return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0,
p->iface, NULL);
}
}
@@ -274,6 +299,14 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
return 1;
}
+ /* Pioneer devices with vendor spec class */
+ if (attr == USB_ENDPOINT_SYNC_ASYNC &&
+ alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+ USB_ID_VENDOR(chip->usb_id) == 0x2b73 /* Pioneer */) {
+ if (skip_pioneer_sync_ep(chip, fmt, alts))
+ return 1;
+ }
+
/* Try the generic implicit fb if available */
if (chip->generic_implicit_fb)
return add_generic_implicit_fb(chip, fmt, alts);
@@ -291,8 +324,8 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip,
p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts);
if (p && p->type == IMPLICIT_FB_FIXED)
- return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, p->iface,
- NULL);
+ return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0,
+ p->iface, NULL);
return 0;
}
@@ -374,20 +407,19 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
int stream)
{
struct snd_usb_substream *subs;
- const struct audioformat *fp, *sync_fmt;
+ const struct audioformat *fp, *sync_fmt = NULL;
int score, high_score;
- /* When sharing the same altset, use the original audioformat */
+ /* Use the original audioformat as fallback for the shared altset */
if (target->iface == target->sync_iface &&
target->altsetting == target->sync_altsetting)
- return target;
+ sync_fmt = target;
subs = find_matching_substream(chip, stream, target->sync_ep,
target->fmt_type);
if (!subs)
- return NULL;
+ return sync_fmt;
- sync_fmt = NULL;
high_score = 0;
list_for_each_entry(fp, &subs->fmt_list, list) {
score = match_endpoint_audioformats(subs, fp,
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index c8213652470c..0c23fa6d8525 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1889,6 +1889,8 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi,
ms_ep = find_usb_ms_endpoint_descriptor(hostep);
if (!ms_ep)
continue;
+ if (ms_ep->bNumEmbMIDIJack > 0x10)
+ continue;
if (usb_endpoint_dir_out(ep)) {
if (endpoints[epidx].out_ep) {
if (++epidx >= MIDI_MAX_ENDPOINTS) {
@@ -2141,6 +2143,8 @@ static int snd_usbmidi_detect_roland(struct snd_usb_midi *umidi,
cs_desc[1] == USB_DT_CS_INTERFACE &&
cs_desc[2] == 0xf1 &&
cs_desc[3] == 0x02) {
+ if (cs_desc[4] > 0x10 || cs_desc[5] > 0x10)
+ continue;
endpoint->in_cables = (1 << cs_desc[4]) - 1;
endpoint->out_cables = (1 << cs_desc[5]) - 1;
return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 56079901769f..078bb4c94033 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -663,7 +663,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,
check_fmts.bits[1] = (u32)(fp->formats >> 32);
snd_mask_intersect(&check_fmts, fmts);
if (snd_mask_empty(&check_fmts)) {
- hwc_debug(" > check: no supported format %d\n", fp->format);
+ hwc_debug(" > check: no supported format 0x%llx\n", fp->formats);
return 0;
}
/* check the channels */
@@ -775,24 +775,11 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
return apply_hw_params_minmax(it, rmin, rmax);
}
-static int hw_rule_format(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
+static int apply_hw_params_format_bits(struct snd_mask *fmt, u64 fbits)
{
- struct snd_usb_substream *subs = rule->private;
- const struct audioformat *fp;
- struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- u64 fbits;
u32 oldbits[2];
int changed;
- hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]);
- fbits = 0;
- list_for_each_entry(fp, &subs->fmt_list, list) {
- if (!hw_check_valid_format(subs, params, fp))
- continue;
- fbits |= fp->formats;
- }
-
oldbits[0] = fmt->bits[0];
oldbits[1] = fmt->bits[1];
fmt->bits[0] &= (u32)fbits;
@@ -806,6 +793,24 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
return changed;
}
+static int hw_rule_format(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_usb_substream *subs = rule->private;
+ const struct audioformat *fp;
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+ u64 fbits;
+
+ hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]);
+ fbits = 0;
+ list_for_each_entry(fp, &subs->fmt_list, list) {
+ if (!hw_check_valid_format(subs, params, fp))
+ continue;
+ fbits |= fp->formats;
+ }
+ return apply_hw_params_format_bits(fmt, fbits);
+}
+
static int hw_rule_period_time(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -833,64 +838,92 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params,
return apply_hw_params_minmax(it, pmin, UINT_MAX);
}
-/* apply PCM hw constraints from the concurrent sync EP */
-static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime,
- struct snd_usb_substream *subs)
+/* get the EP or the sync EP for implicit fb when it's already set up */
+static const struct snd_usb_endpoint *
+get_sync_ep_from_substream(struct snd_usb_substream *subs)
{
struct snd_usb_audio *chip = subs->stream->chip;
- struct snd_usb_endpoint *ep;
const struct audioformat *fp;
- int err;
+ const struct snd_usb_endpoint *ep;
list_for_each_entry(fp, &subs->fmt_list, list) {
ep = snd_usb_get_endpoint(chip, fp->endpoint);
if (ep && ep->cur_rate)
- goto found;
+ return ep;
if (!fp->implicit_fb)
continue;
/* for the implicit fb, check the sync ep as well */
ep = snd_usb_get_endpoint(chip, fp->sync_ep);
if (ep && ep->cur_rate)
- goto found;
+ return ep;
}
- return 0;
+ return NULL;
+}
- found:
- if (!find_format(&subs->fmt_list, ep->cur_format, ep->cur_rate,
- ep->cur_channels, false, NULL)) {
- usb_audio_dbg(chip, "EP 0x%x being used, but not applicable\n",
- ep->ep_num);
+/* additional hw constraints for implicit feedback mode */
+static int hw_rule_format_implicit_fb(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_usb_substream *subs = rule->private;
+ const struct snd_usb_endpoint *ep;
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ ep = get_sync_ep_from_substream(subs);
+ if (!ep)
return 0;
- }
- usb_audio_dbg(chip, "EP 0x%x being used, using fixed params:\n",
- ep->ep_num);
- usb_audio_dbg(chip, "rate=%d, period_size=%d, periods=%d\n",
- ep->cur_rate, ep->cur_period_frames,
- ep->cur_buffer_periods);
+ hwc_debug("applying %s\n", __func__);
+ return apply_hw_params_format_bits(fmt, pcm_format_to_bits(ep->cur_format));
+}
- runtime->hw.formats = subs->formats;
- runtime->hw.rate_min = runtime->hw.rate_max = ep->cur_rate;
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
- runtime->hw.periods_min = runtime->hw.periods_max =
- ep->cur_buffer_periods;
+static int hw_rule_rate_implicit_fb(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_usb_substream *subs = rule->private;
+ const struct snd_usb_endpoint *ep;
+ struct snd_interval *it;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_channels, subs,
- SNDRV_PCM_HW_PARAM_FORMAT,
- SNDRV_PCM_HW_PARAM_RATE,
- -1);
- if (err < 0)
- return err;
+ ep = get_sync_ep_from_substream(subs);
+ if (!ep)
+ return 0;
- err = snd_pcm_hw_constraint_minmax(runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- ep->cur_period_frames,
- ep->cur_period_frames);
- if (err < 0)
- return err;
+ hwc_debug("applying %s\n", __func__);
+ it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ return apply_hw_params_minmax(it, ep->cur_rate, ep->cur_rate);
+}
- return 1; /* notify the finding */
+static int hw_rule_period_size_implicit_fb(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_usb_substream *subs = rule->private;
+ const struct snd_usb_endpoint *ep;
+ struct snd_interval *it;
+
+ ep = get_sync_ep_from_substream(subs);
+ if (!ep)
+ return 0;
+
+ hwc_debug("applying %s\n", __func__);
+ it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ return apply_hw_params_minmax(it, ep->cur_period_frames,
+ ep->cur_period_frames);
+}
+
+static int hw_rule_periods_implicit_fb(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_usb_substream *subs = rule->private;
+ const struct snd_usb_endpoint *ep;
+ struct snd_interval *it;
+
+ ep = get_sync_ep_from_substream(subs);
+ if (!ep)
+ return 0;
+
+ hwc_debug("applying %s\n", __func__);
+ it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIODS);
+ return apply_hw_params_minmax(it, ep->cur_buffer_periods,
+ ep->cur_buffer_periods);
}
/*
@@ -899,20 +932,11 @@ static int apply_hw_constraint_from_sync(struct snd_pcm_runtime *runtime,
static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs)
{
- struct snd_usb_audio *chip = subs->stream->chip;
const struct audioformat *fp;
unsigned int pt, ptmin;
int param_period_time_if_needed = -1;
int err;
- mutex_lock(&chip->mutex);
- err = apply_hw_constraint_from_sync(runtime, subs);
- mutex_unlock(&chip->mutex);
- if (err < 0)
- return err;
- if (err > 0) /* found the matching? */
- goto add_extra_rules;
-
runtime->hw.formats = subs->formats;
runtime->hw.rate_min = 0x7fffffff;
@@ -957,6 +981,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
hw_rule_rate, subs,
+ SNDRV_PCM_HW_PARAM_RATE,
SNDRV_PCM_HW_PARAM_FORMAT,
SNDRV_PCM_HW_PARAM_CHANNELS,
param_period_time_if_needed,
@@ -964,9 +989,9 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
if (err < 0)
return err;
-add_extra_rules:
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
hw_rule_channels, subs,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
SNDRV_PCM_HW_PARAM_FORMAT,
SNDRV_PCM_HW_PARAM_RATE,
param_period_time_if_needed,
@@ -975,6 +1000,7 @@ add_extra_rules:
return err;
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
hw_rule_format, subs,
+ SNDRV_PCM_HW_PARAM_FORMAT,
SNDRV_PCM_HW_PARAM_RATE,
SNDRV_PCM_HW_PARAM_CHANNELS,
param_period_time_if_needed,
@@ -993,6 +1019,28 @@ add_extra_rules:
return err;
}
+ /* additional hw constraints for implicit fb */
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
+ hw_rule_format_implicit_fb, subs,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ hw_rule_rate_implicit_fb, subs,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ hw_rule_period_size_implicit_fb, subs,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS,
+ hw_rule_periods_implicit_fb, subs,
+ SNDRV_PCM_HW_PARAM_PERIODS, -1);
+ if (err < 0)
+ return err;
+
return 0;
}
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 0e11cb96fa8c..c8a4bdf18207 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3362,6 +3362,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x86,
+ .ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC|
USB_ENDPOINT_SYNC_ASYNC|
USB_ENDPOINT_USAGE_IMPLICIT_FB,
@@ -3450,6 +3451,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x82,
+ .ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC|
USB_ENDPOINT_SYNC_ASYNC|
USB_ENDPOINT_USAGE_IMPLICIT_FB,
@@ -3506,6 +3508,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x82,
+ .ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC|
USB_ENDPOINT_SYNC_ASYNC|
USB_ENDPOINT_USAGE_IMPLICIT_FB,
@@ -3562,6 +3565,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x82,
+ .ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC|
USB_ENDPOINT_SYNC_ASYNC|
USB_ENDPOINT_USAGE_IMPLICIT_FB,
@@ -3619,6 +3623,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x82,
+ .ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC|
USB_ENDPOINT_SYNC_ASYNC|
USB_ENDPOINT_USAGE_IMPLICIT_FB,
@@ -3679,6 +3684,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x82,
+ .ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC|
USB_ENDPOINT_SYNC_ASYNC|
USB_ENDPOINT_USAGE_IMPLICIT_FB,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index e4a690bb4c99..e196e364cef1 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -120,6 +120,40 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
return 0;
}
+/* create the audio stream and the corresponding endpoints from the fixed
+ * audioformat object; this is used for quirks with the fixed EPs
+ */
+static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,
+ struct audioformat *fp)
+{
+ int stream, err;
+
+ stream = (fp->endpoint & USB_DIR_IN) ?
+ SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+
+ snd_usb_audioformat_set_sync_ep(chip, fp);
+
+ err = snd_usb_add_audio_stream(chip, stream, fp);
+ if (err < 0)
+ return err;
+
+ err = snd_usb_add_endpoint(chip, fp->endpoint,
+ SND_USB_ENDPOINT_TYPE_DATA);
+ if (err < 0)
+ return err;
+
+ if (fp->sync_ep) {
+ err = snd_usb_add_endpoint(chip, fp->sync_ep,
+ fp->implicit_fb ?
+ SND_USB_ENDPOINT_TYPE_DATA :
+ SND_USB_ENDPOINT_TYPE_SYNC);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
/*
* create a stream for an endpoint/altsetting without proper descriptors
*/
@@ -131,8 +165,8 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
struct audioformat *fp;
struct usb_host_interface *alts;
struct usb_interface_descriptor *altsd;
- int stream, err;
unsigned *rate_table = NULL;
+ int err;
fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
if (!fp)
@@ -153,11 +187,6 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
fp->rate_table = rate_table;
}
- stream = (fp->endpoint & USB_DIR_IN)
- ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
- err = snd_usb_add_audio_stream(chip, stream, fp);
- if (err < 0)
- goto error;
if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
fp->altset_idx >= iface->num_altsetting) {
err = -EINVAL;
@@ -165,7 +194,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
}
alts = &iface->altsetting[fp->altset_idx];
altsd = get_iface_desc(alts);
- if (altsd->bNumEndpoints < 1) {
+ if (altsd->bNumEndpoints <= fp->ep_idx) {
err = -EINVAL;
goto error;
}
@@ -175,7 +204,14 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
if (fp->datainterval == 0)
fp->datainterval = snd_usb_parse_datainterval(chip, alts);
if (fp->maxpacksize == 0)
- fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+ fp->maxpacksize = le16_to_cpu(get_endpoint(alts, fp->ep_idx)->wMaxPacketSize);
+ if (!fp->fmt_type)
+ fp->fmt_type = UAC_FORMAT_TYPE_I;
+
+ err = add_audio_stream_from_fixed_fmt(chip, fp);
+ if (err < 0)
+ goto error;
+
usb_set_interface(chip->dev, fp->iface, 0);
snd_usb_init_pitch(chip, fp);
snd_usb_init_sample_rate(chip, fp, fp->rate_max);
@@ -417,7 +453,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
struct usb_host_interface *alts;
struct usb_interface_descriptor *altsd;
struct audioformat *fp;
- int stream, err;
+ int err;
/* both PCM and MIDI interfaces have 2 or more altsettings */
if (iface->num_altsetting < 2)
@@ -482,9 +518,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
return -ENXIO;
}
- stream = (fp->endpoint & USB_DIR_IN)
- ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
- err = snd_usb_add_audio_stream(chip, stream, fp);
+ err = add_audio_stream_from_fixed_fmt(chip, fp);
if (err < 0) {
list_del(&fp->list); /* unlink for avoiding double-free */
kfree(fp);
@@ -1436,30 +1470,6 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs,
subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;
}
-
-/*
- * Pioneer DJ DJM-900NXS2
- * Device needs to know the sample rate each time substream is started
- */
-static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs)
-{
- unsigned int cur_rate = subs->data_endpoint->cur_rate;
- /* Convert sample rate value to little endian */
- u8 sr[3];
-
- sr[0] = cur_rate & 0xff;
- sr[1] = (cur_rate >> 8) & 0xff;
- sr[2] = (cur_rate >> 16) & 0xff;
-
- /* Configure device */
- usb_set_interface(subs->dev, 0, 1);
- snd_usb_ctl_msg(subs->stream->chip->dev,
- usb_rcvctrlpipe(subs->stream->chip->dev, 0),
- 0x01, 0x22, 0x0100, 0x0082, &sr, 0x0003);
-
- return 0;
-}
-
void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
const struct audioformat *fmt)
{
@@ -1470,10 +1480,6 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
set_format_emu_quirk(subs, fmt);
break;
- case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */
- case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
- pioneer_djm_set_format_quirk(subs);
- break;
case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
subs->stream_offset_adj = 2;
break;
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 980287aadd36..215c1771dd57 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -44,6 +44,7 @@ struct snd_usb_audio {
struct list_head pcm_list; /* list of pcm streams */
struct list_head ep_list; /* list of audio-related endpoints */
+ struct list_head iface_ref_list; /* list of interface refcounts */
int pcm_devs;
struct list_head midi_list; /* list of midi interfaces */