Commit 689968db authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-6.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "This became a slightly big update, but it's more or less expected, as
  the first batch after holidays.

  All changes (but for the last two last-minute fixes) have been stewed
  in linux-next long enough, so it's fairly safe to take:

   - PCM UAF fix in 32bit compat layer

   - ASoC board-specific fixes for Intel, AMD, Medathek, Qualcomm

   - SOF power management fixes

   - ASoC Intel link failure fixes

   - A series of fixes for USB-audio regressions

   - CS35L41 HD-audio codec regression fixes

   - HD-audio device-specific fixes / quirks

  Note that one SPI patch has been taken in ASoC subtree mistakenly, and
  the same fix is found in spi tree, but it should be OK to apply"

* tag 'sound-6.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (39 commits)
  ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
  ALSA: usb-audio: Fix possible NULL pointer dereference in snd_usb_pcm_has_fixed_rate()
  ALSA: hda/realtek: Enable mute/micmute LEDs on HP Spectre x360 13-aw0xxx
  ASoC: fsl-asoc-card: Fix naming of AC'97 CODEC widgets
  ASoC: fsl_ssi: Rename AC'97 streams to avoid collisions with AC'97 CODEC
  ALSA: hda/hdmi: Add a HP device 0x8715 to force connect list
  ALSA: control-led: use strscpy in set_led_id()
  ALSA: usb-audio: Always initialize fixed_rate in snd_usb_find_implicit_fb_sync_format()
  ASoC: dt-bindings: qcom,lpass-tx-macro: correct clocks on SC7280
  ASoC: dt-bindings: qcom,lpass-wsa-macro: correct clocks on SM8250
  ASoC: qcom: Fix building APQ8016 machine driver without SOUNDWIRE
  ALSA: hda: cs35l41: Check runtime suspend capability at runtime_idle
  ALSA: hda: cs35l41: Don't return -EINVAL from system suspend/resume
  ASoC: fsl_micfil: Correct the number of steps on SX controls
  ALSA: hda/realtek: fix mute/micmute LEDs don't work for a HP platform
  Revert "ALSA: usb-audio: Drop superfluous interface setup at parsing"
  ALSA: usb-audio: More refactoring of hw constraint rules
  ALSA: usb-audio: Relax hw constraints for implicit fb sync
  ALSA: usb-audio: Make sure to stop endpoints before closing EPs
  ALSA: hda - Enable headset mic on another Dell laptop with ALC3254
  ...
parents d863f053 56b88b50
...@@ -16,6 +16,7 @@ properties: ...@@ -16,6 +16,7 @@ properties:
compatible: compatible:
enum: enum:
- mediatek,mt8186-mt6366-rt1019-rt5682s-sound - mediatek,mt8186-mt6366-rt1019-rt5682s-sound
- mediatek,mt8186-mt6366-rt5682s-max98360-sound
mediatek,platform: mediatek,platform:
$ref: "/schemas/types.yaml#/definitions/phandle" $ref: "/schemas/types.yaml#/definitions/phandle"
......
...@@ -30,7 +30,9 @@ properties: ...@@ -30,7 +30,9 @@ properties:
const: 0 const: 0
clocks: clocks:
maxItems: 5 oneOf:
- maxItems: 3
- maxItems: 5
clock-names: clock-names:
oneOf: oneOf:
......
...@@ -9,9 +9,6 @@ title: LPASS(Low Power Audio Subsystem) VA Macro audio codec ...@@ -9,9 +9,6 @@ title: LPASS(Low Power Audio Subsystem) VA Macro audio codec
maintainers: maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org> - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
allOf:
- $ref: dai-common.yaml#
properties: properties:
compatible: compatible:
enum: enum:
...@@ -30,15 +27,12 @@ properties: ...@@ -30,15 +27,12 @@ properties:
const: 0 const: 0
clocks: clocks:
maxItems: 5 minItems: 5
maxItems: 6
clock-names: clock-names:
items: minItems: 5
- const: mclk maxItems: 6
- const: npl
- const: macro
- const: dcodec
- const: fsgen
clock-output-names: clock-output-names:
maxItems: 1 maxItems: 1
...@@ -55,10 +49,51 @@ required: ...@@ -55,10 +49,51 @@ required:
- reg - reg
- "#sound-dai-cells" - "#sound-dai-cells"
allOf:
- $ref: dai-common.yaml#
- if:
properties:
compatible:
enum:
- qcom,sc7280-lpass-wsa-macro
- qcom,sm8450-lpass-wsa-macro
- qcom,sc8280xp-lpass-wsa-macro
then:
properties:
clocks:
maxItems: 5
clock-names:
items:
- const: mclk
- const: npl
- const: macro
- const: dcodec
- const: fsgen
- if:
properties:
compatible:
enum:
- qcom,sm8250-lpass-wsa-macro
then:
properties:
clocks:
minItems: 6
clock-names:
items:
- const: mclk
- const: npl
- const: macro
- const: dcodec
- const: va
- const: fsgen
unevaluatedProperties: false unevaluatedProperties: false
examples: examples:
- | - |
#include <dt-bindings/clock/qcom,sm8250-lpass-aoncc.h>
#include <dt-bindings/sound/qcom,q6afe.h> #include <dt-bindings/sound/qcom,q6afe.h>
codec@3240000 { codec@3240000 {
compatible = "qcom,sm8250-lpass-wsa-macro"; compatible = "qcom,sm8250-lpass-wsa-macro";
...@@ -69,7 +104,8 @@ examples: ...@@ -69,7 +104,8 @@ examples:
<&audiocc 0>, <&audiocc 0>,
<&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
<&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
<&aoncc LPASS_CDC_VA_MCLK>,
<&vamacro>; <&vamacro>;
clock-names = "mclk", "npl", "macro", "dcodec", "fsgen"; clock-names = "mclk", "npl", "macro", "dcodec", "va", "fsgen";
clock-output-names = "mclk"; clock-output-names = "mclk";
}; };
...@@ -1203,14 +1203,19 @@ static int snd_ctl_elem_read(struct snd_card *card, ...@@ -1203,14 +1203,19 @@ static int snd_ctl_elem_read(struct snd_card *card,
const u32 pattern = 0xdeadbeef; const u32 pattern = 0xdeadbeef;
int ret; int ret;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id); kctl = snd_ctl_find_id(card, &control->id);
if (kctl == NULL) if (kctl == NULL) {
return -ENOENT; ret = -ENOENT;
goto unlock;
}
index_offset = snd_ctl_get_ioff(kctl, &control->id); index_offset = snd_ctl_get_ioff(kctl, &control->id);
vd = &kctl->vd[index_offset]; vd = &kctl->vd[index_offset];
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
return -EPERM; ret = -EPERM;
goto unlock;
}
snd_ctl_build_ioff(&control->id, kctl, index_offset); snd_ctl_build_ioff(&control->id, kctl, index_offset);
...@@ -1220,7 +1225,7 @@ static int snd_ctl_elem_read(struct snd_card *card, ...@@ -1220,7 +1225,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
info.id = control->id; info.id = control->id;
ret = __snd_ctl_elem_info(card, kctl, &info, NULL); ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
if (ret < 0) if (ret < 0)
return ret; goto unlock;
#endif #endif
if (!snd_ctl_skip_validation(&info)) if (!snd_ctl_skip_validation(&info))
...@@ -1230,7 +1235,7 @@ static int snd_ctl_elem_read(struct snd_card *card, ...@@ -1230,7 +1235,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
ret = kctl->get(kctl, control); ret = kctl->get(kctl, control);
snd_power_unref(card); snd_power_unref(card);
if (ret < 0) if (ret < 0)
return ret; goto unlock;
if (!snd_ctl_skip_validation(&info) && if (!snd_ctl_skip_validation(&info) &&
sanity_check_elem_value(card, control, &info, pattern) < 0) { sanity_check_elem_value(card, control, &info, pattern) < 0) {
dev_err(card->dev, dev_err(card->dev,
...@@ -1238,8 +1243,11 @@ static int snd_ctl_elem_read(struct snd_card *card, ...@@ -1238,8 +1243,11 @@ static int snd_ctl_elem_read(struct snd_card *card,
control->id.iface, control->id.device, control->id.iface, control->id.device,
control->id.subdevice, control->id.name, control->id.subdevice, control->id.name,
control->id.index); control->id.index);
return -EINVAL; ret = -EINVAL;
goto unlock;
} }
unlock:
up_read(&card->controls_rwsem);
return ret; return ret;
} }
...@@ -1253,9 +1261,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card, ...@@ -1253,9 +1261,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
if (IS_ERR(control)) if (IS_ERR(control))
return PTR_ERR(control); return PTR_ERR(control);
down_read(&card->controls_rwsem);
result = snd_ctl_elem_read(card, control); result = snd_ctl_elem_read(card, control);
up_read(&card->controls_rwsem);
if (result < 0) if (result < 0)
goto error; goto error;
......
...@@ -530,12 +530,11 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si ...@@ -530,12 +530,11 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si
bool attach) bool attach)
{ {
char buf2[256], *s, *os; char buf2[256], *s, *os;
size_t len = max(sizeof(s) - 1, count);
struct snd_ctl_elem_id id; struct snd_ctl_elem_id id;
int err; int err;
strncpy(buf2, buf, len); if (strscpy(buf2, buf, sizeof(buf2)) < 0)
buf2[len] = '\0'; return -E2BIG;
memset(&id, 0, sizeof(id)); memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
s = buf2; s = buf2;
......
...@@ -598,8 +598,8 @@ static int cs35l41_system_suspend(struct device *dev) ...@@ -598,8 +598,8 @@ static int cs35l41_system_suspend(struct device *dev)
dev_dbg(cs35l41->dev, "System Suspend\n"); dev_dbg(cs35l41->dev, "System Suspend\n");
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) { if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
dev_err(cs35l41->dev, "System Suspend not supported\n"); dev_err_once(cs35l41->dev, "System Suspend not supported\n");
return -EINVAL; return 0; /* don't block the whole system suspend */
} }
ret = pm_runtime_force_suspend(dev); ret = pm_runtime_force_suspend(dev);
...@@ -624,8 +624,8 @@ static int cs35l41_system_resume(struct device *dev) ...@@ -624,8 +624,8 @@ static int cs35l41_system_resume(struct device *dev)
dev_dbg(cs35l41->dev, "System Resume\n"); dev_dbg(cs35l41->dev, "System Resume\n");
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) { if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
dev_err(cs35l41->dev, "System Resume not supported\n"); dev_err_once(cs35l41->dev, "System Resume not supported\n");
return -EINVAL; return 0; /* don't block the whole system resume */
} }
if (cs35l41->reset_gpio) { if (cs35l41->reset_gpio) {
...@@ -647,6 +647,15 @@ static int cs35l41_system_resume(struct device *dev) ...@@ -647,6 +647,15 @@ static int cs35l41_system_resume(struct device *dev)
return ret; return ret;
} }
static int cs35l41_runtime_idle(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
return -EBUSY; /* suspend not supported yet on this model */
return 0;
}
static int cs35l41_runtime_suspend(struct device *dev) static int cs35l41_runtime_suspend(struct device *dev)
{ {
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
...@@ -1536,7 +1545,8 @@ void cs35l41_hda_remove(struct device *dev) ...@@ -1536,7 +1545,8 @@ void cs35l41_hda_remove(struct device *dev)
EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41); EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
const struct dev_pm_ops cs35l41_hda_pm_ops = { const struct dev_pm_ops cs35l41_hda_pm_ops = {
RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL) RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume,
cs35l41_runtime_idle)
SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume) SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
}; };
EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41); EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41);
......
...@@ -1981,6 +1981,7 @@ static const struct snd_pci_quirk force_connect_list[] = { ...@@ -1981,6 +1981,7 @@ static const struct snd_pci_quirk force_connect_list[] = {
SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1), SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1), SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1), SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1), SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
{} {}
......
...@@ -3564,6 +3564,15 @@ static void alc256_init(struct hda_codec *codec) ...@@ -3564,6 +3564,15 @@ static void alc256_init(struct hda_codec *codec)
hda_nid_t hp_pin = alc_get_hp_pin(spec); hda_nid_t hp_pin = alc_get_hp_pin(spec);
bool hp_pin_sense; bool hp_pin_sense;
if (spec->ultra_low_power) {
alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
alc_update_coef_idx(codec, 0x08, 7<<4, 0);
alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
msleep(30);
}
if (!hp_pin) if (!hp_pin)
hp_pin = 0x21; hp_pin = 0x21;
...@@ -3575,14 +3584,6 @@ static void alc256_init(struct hda_codec *codec) ...@@ -3575,14 +3584,6 @@ static void alc256_init(struct hda_codec *codec)
msleep(2); msleep(2);
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
if (spec->ultra_low_power) {
alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
alc_update_coef_idx(codec, 0x08, 7<<4, 0);
alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
msleep(30);
}
snd_hda_codec_write(codec, hp_pin, 0, snd_hda_codec_write(codec, hp_pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
...@@ -3713,6 +3714,13 @@ static void alc225_init(struct hda_codec *codec) ...@@ -3713,6 +3714,13 @@ static void alc225_init(struct hda_codec *codec)
hda_nid_t hp_pin = alc_get_hp_pin(spec); hda_nid_t hp_pin = alc_get_hp_pin(spec);
bool hp1_pin_sense, hp2_pin_sense; bool hp1_pin_sense, hp2_pin_sense;
if (spec->ultra_low_power) {
alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
alc_update_coef_idx(codec, 0x33, 1<<11, 0);
msleep(30);
}
if (spec->codec_variant != ALC269_TYPE_ALC287 && if (spec->codec_variant != ALC269_TYPE_ALC287 &&
spec->codec_variant != ALC269_TYPE_ALC245) spec->codec_variant != ALC269_TYPE_ALC245)
/* required only at boot or S3 and S4 resume time */ /* required only at boot or S3 and S4 resume time */
...@@ -3734,12 +3742,6 @@ static void alc225_init(struct hda_codec *codec) ...@@ -3734,12 +3742,6 @@ static void alc225_init(struct hda_codec *codec)
msleep(2); msleep(2);
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
if (spec->ultra_low_power) {
alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
alc_update_coef_idx(codec, 0x33, 1<<11, 0);
msleep(30);
}
if (hp1_pin_sense || spec->ultra_low_power) if (hp1_pin_sense || spec->ultra_low_power)
snd_hda_codec_write(codec, hp_pin, 0, snd_hda_codec_write(codec, hp_pin, 0,
...@@ -4644,6 +4646,16 @@ static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec, ...@@ -4644,6 +4646,16 @@ static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec,
} }
} }
static void alc285_fixup_hp_gpio_micmute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
if (action == HDA_FIXUP_ACT_PRE_PROBE)
spec->micmute_led_polarity = 1;
alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
}
static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec, static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action) const struct hda_fixup *fix, int action)
{ {
...@@ -4665,6 +4677,13 @@ static void alc285_fixup_hp_mute_led(struct hda_codec *codec, ...@@ -4665,6 +4677,13 @@ static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
alc285_fixup_hp_coef_micmute_led(codec, fix, action); alc285_fixup_hp_coef_micmute_led(codec, fix, action);
} }
static void alc285_fixup_hp_spectre_x360_mute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
alc285_fixup_hp_gpio_micmute_led(codec, fix, action);
}
static void alc236_fixup_hp_mute_led(struct hda_codec *codec, static void alc236_fixup_hp_mute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action) const struct hda_fixup *fix, int action)
{ {
...@@ -7106,6 +7125,7 @@ enum { ...@@ -7106,6 +7125,7 @@ enum {
ALC285_FIXUP_ASUS_G533Z_PINS, ALC285_FIXUP_ASUS_G533Z_PINS,
ALC285_FIXUP_HP_GPIO_LED, ALC285_FIXUP_HP_GPIO_LED,
ALC285_FIXUP_HP_MUTE_LED, ALC285_FIXUP_HP_MUTE_LED,
ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
ALC236_FIXUP_HP_GPIO_LED, ALC236_FIXUP_HP_GPIO_LED,
ALC236_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED,
ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
...@@ -8486,6 +8506,10 @@ static const struct hda_fixup alc269_fixups[] = { ...@@ -8486,6 +8506,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC, .type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_hp_mute_led, .v.func = alc285_fixup_hp_mute_led,
}, },
[ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_hp_spectre_x360_mute_led,
},
[ALC236_FIXUP_HP_GPIO_LED] = { [ALC236_FIXUP_HP_GPIO_LED] = {
.type = HDA_FIXUP_FUNC, .type = HDA_FIXUP_FUNC,
.v.func = alc236_fixup_hp_gpio_led, .v.func = alc236_fixup_hp_gpio_led,
...@@ -9239,6 +9263,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -9239,6 +9263,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS), SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS), SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS), SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
...@@ -9327,6 +9352,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -9327,6 +9352,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
...@@ -9406,6 +9432,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -9406,6 +9432,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
......
...@@ -206,6 +206,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { ...@@ -206,6 +206,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"), DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"),
} }
}, },
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "M5402RA"),
}
},
{ {
.driver_data = &acp6x_card, .driver_data = &acp6x_card,
.matches = { .matches = {
...@@ -220,6 +227,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { ...@@ -220,6 +227,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Redmi Book Pro 14 2022"), DMI_MATCH(DMI_PRODUCT_NAME, "Redmi Book Pro 14 2022"),
} }
}, },
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Razer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Blade 14 (2022) - RZ09-0427"),
}
},
{} {}
}; };
......
...@@ -177,8 +177,20 @@ static int rt9120_codec_probe(struct snd_soc_component *comp) ...@@ -177,8 +177,20 @@ static int rt9120_codec_probe(struct snd_soc_component *comp)
return 0; return 0;
} }
static int rt9120_codec_suspend(struct snd_soc_component *comp)
{
return pm_runtime_force_suspend(comp->dev);
}
static int rt9120_codec_resume(struct snd_soc_component *comp)
{
return pm_runtime_force_resume(comp->dev);
}
static const struct snd_soc_component_driver rt9120_component_driver = { static const struct snd_soc_component_driver rt9120_component_driver = {
.probe = rt9120_codec_probe, .probe = rt9120_codec_probe,
.suspend = rt9120_codec_suspend,
.resume = rt9120_codec_resume,
.controls = rt9120_snd_controls, .controls = rt9120_snd_controls,
.num_controls = ARRAY_SIZE(rt9120_snd_controls), .num_controls = ARRAY_SIZE(rt9120_snd_controls),
.dapm_widgets = rt9120_dapm_widgets, .dapm_widgets = rt9120_dapm_widgets,
......
...@@ -697,6 +697,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, ...@@ -697,6 +697,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
int dcs_mask; int dcs_mask;
int dcs_l, dcs_r; int dcs_l, dcs_r;
int dcs_l_reg, dcs_r_reg; int dcs_l_reg, dcs_r_reg;
int an_out_reg;
int timeout; int timeout;
int pwr_reg; int pwr_reg;
...@@ -712,6 +713,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, ...@@ -712,6 +713,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1; dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1;
dcs_r_reg = WM8904_DC_SERVO_8; dcs_r_reg = WM8904_DC_SERVO_8;
dcs_l_reg = WM8904_DC_SERVO_9; dcs_l_reg = WM8904_DC_SERVO_9;
an_out_reg = WM8904_ANALOGUE_OUT1_LEFT;
dcs_l = 0; dcs_l = 0;
dcs_r = 1; dcs_r = 1;
break; break;
...@@ -720,6 +722,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, ...@@ -720,6 +722,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3; dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3;
dcs_r_reg = WM8904_DC_SERVO_6; dcs_r_reg = WM8904_DC_SERVO_6;
dcs_l_reg = WM8904_DC_SERVO_7; dcs_l_reg = WM8904_DC_SERVO_7;
an_out_reg = WM8904_ANALOGUE_OUT2_LEFT;
dcs_l = 2; dcs_l = 2;
dcs_r = 3; dcs_r = 3;
break; break;
...@@ -792,6 +795,10 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, ...@@ -792,6 +795,10 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
snd_soc_component_update_bits(component, reg, snd_soc_component_update_bits(component, reg,
WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP, WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP); WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
/* Update volume, requires PGA to be powered */
val = snd_soc_component_read(component, an_out_reg);
snd_soc_component_write(component, an_out_reg, val);
break; break;
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
......
...@@ -121,11 +121,11 @@ static const struct snd_soc_dapm_route audio_map[] = { ...@@ -121,11 +121,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
static const struct snd_soc_dapm_route audio_map_ac97[] = { static const struct snd_soc_dapm_route audio_map_ac97[] = {
/* 1st half -- Normal DAPM routes */ /* 1st half -- Normal DAPM routes */
{"Playback", NULL, "AC97 Playback"}, {"AC97 Playback", NULL, "CPU AC97 Playback"},
{"AC97 Capture", NULL, "Capture"}, {"CPU AC97 Capture", NULL, "AC97 Capture"},
/* 2nd half -- ASRC DAPM routes */ /* 2nd half -- ASRC DAPM routes */
{"AC97 Playback", NULL, "ASRC-Playback"}, {"CPU AC97 Playback", NULL, "ASRC-Playback"},
{"ASRC-Capture", NULL, "AC97 Capture"}, {"ASRC-Capture", NULL, "CPU AC97 Capture"},
}; };
static const struct snd_soc_dapm_route audio_map_tx[] = { static const struct snd_soc_dapm_route audio_map_tx[] = {
......
...@@ -315,21 +315,21 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol, ...@@ -315,21 +315,21 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol,
static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv), MICFIL_OUTGAIN_CHX_SHIFT(0), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL, SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0x7, gain_tlv), MICFIL_OUTGAIN_CHX_SHIFT(1), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL, SOC_SINGLE_SX_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0x7, gain_tlv), MICFIL_OUTGAIN_CHX_SHIFT(2), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL, SOC_SINGLE_SX_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0x7, gain_tlv), MICFIL_OUTGAIN_CHX_SHIFT(3), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL, SOC_SINGLE_SX_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0x7, gain_tlv), MICFIL_OUTGAIN_CHX_SHIFT(4), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL, SOC_SINGLE_SX_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0x7, gain_tlv), MICFIL_OUTGAIN_CHX_SHIFT(5), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL, SOC_SINGLE_SX_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0x7, gain_tlv), MICFIL_OUTGAIN_CHX_SHIFT(6), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL, SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0x7, gain_tlv), MICFIL_OUTGAIN_CHX_SHIFT(7), 0x8, 0xF, gain_tlv),
SOC_ENUM_EXT("MICFIL Quality Select", SOC_ENUM_EXT("MICFIL Quality Select",
fsl_micfil_quality_enum, fsl_micfil_quality_enum,
micfil_quality_get, micfil_quality_set), micfil_quality_get, micfil_quality_set),
......
...@@ -1189,14 +1189,14 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { ...@@ -1189,14 +1189,14 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.symmetric_channels = 1, .symmetric_channels = 1,
.probe = fsl_ssi_dai_probe, .probe = fsl_ssi_dai_probe,
.playback = { .playback = {
.stream_name = "AC97 Playback", .stream_name = "CPU AC97 Playback",
.channels_min = 2, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S20, .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S20,
}, },
.capture = { .capture = {
.stream_name = "AC97 Capture", .stream_name = "CPU AC97 Capture",
.channels_min = 2, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
.rates = SNDRV_PCM_RATE_48000, .rates = SNDRV_PCM_RATE_48000,
......
...@@ -554,10 +554,12 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH ...@@ -554,10 +554,12 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH
select SND_SOC_RT1015P select SND_SOC_RT1015P
select SND_SOC_MAX98373_I2C select SND_SOC_MAX98373_I2C
select SND_SOC_MAX98357A select SND_SOC_MAX98357A
select SND_SOC_NAU8315
select SND_SOC_DMIC select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI select SND_SOC_HDAC_HDMI
select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_INTEL_HDA_DSP_COMMON
select SND_SOC_INTEL_SOF_MAXIM_COMMON select SND_SOC_INTEL_SOF_MAXIM_COMMON
select SND_SOC_INTEL_SOF_REALTEK_COMMON
help help
This adds support for ASoC machine driver for SOF platforms This adds support for ASoC machine driver for SOF platforms
with nau8825 codec. with nau8825 codec.
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15) #define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15)
#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16) #define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16)
#define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(17) #define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(17)
#define SOF_NAU8318_SPEAKER_AMP_PRESENT BIT(18)
static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0); static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
...@@ -338,6 +339,13 @@ static struct snd_soc_dai_link_component rt1019p_component[] = { ...@@ -338,6 +339,13 @@ static struct snd_soc_dai_link_component rt1019p_component[] = {
} }
}; };
static struct snd_soc_dai_link_component nau8318_components[] = {
{
.name = "NVTN2012:00",
.dai_name = "nau8315-hifi",
}
};
static struct snd_soc_dai_link_component dummy_component[] = { static struct snd_soc_dai_link_component dummy_component[] = {
{ {
.name = "snd-soc-dummy", .name = "snd-soc-dummy",
...@@ -486,6 +494,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, ...@@ -486,6 +494,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
max_98360a_dai_link(&links[id]); max_98360a_dai_link(&links[id]);
} else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) { } else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
sof_rt1015p_dai_link(&links[id]); sof_rt1015p_dai_link(&links[id]);
} else if (sof_nau8825_quirk &
SOF_NAU8318_SPEAKER_AMP_PRESENT) {
links[id].codecs = nau8318_components;
links[id].num_codecs = ARRAY_SIZE(nau8318_components);
links[id].init = speaker_codec_init;
} else { } else {
goto devm_err; goto devm_err;
} }
...@@ -618,7 +631,7 @@ static const struct platform_device_id board_ids[] = { ...@@ -618,7 +631,7 @@ static const struct platform_device_id board_ids[] = {
}, },
{ {
.name = "adl_rt1019p_nau8825", .name = "adl_rt1019p_8825",
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
SOF_SPEAKER_AMP_PRESENT | SOF_SPEAKER_AMP_PRESENT |
SOF_RT1019P_SPEAKER_AMP_PRESENT | SOF_RT1019P_SPEAKER_AMP_PRESENT |
...@@ -626,7 +639,7 @@ static const struct platform_device_id board_ids[] = { ...@@ -626,7 +639,7 @@ static const struct platform_device_id board_ids[] = {
SOF_NAU8825_NUM_HDMIDEV(4)), SOF_NAU8825_NUM_HDMIDEV(4)),
}, },
{ {
.name = "adl_max98373_nau8825", .name = "adl_max98373_8825",
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
SOF_SPEAKER_AMP_PRESENT | SOF_SPEAKER_AMP_PRESENT |
SOF_MAX98373_SPEAKER_AMP_PRESENT | SOF_MAX98373_SPEAKER_AMP_PRESENT |
...@@ -637,7 +650,7 @@ static const struct platform_device_id board_ids[] = { ...@@ -637,7 +650,7 @@ static const struct platform_device_id board_ids[] = {
}, },
{ {
/* The limitation of length of char array, shorten the name */ /* The limitation of length of char array, shorten the name */
.name = "adl_mx98360a_nau8825", .name = "adl_mx98360a_8825",
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
SOF_SPEAKER_AMP_PRESENT | SOF_SPEAKER_AMP_PRESENT |
SOF_MAX98360A_SPEAKER_AMP_PRESENT | SOF_MAX98360A_SPEAKER_AMP_PRESENT |
...@@ -648,7 +661,7 @@ static const struct platform_device_id board_ids[] = { ...@@ -648,7 +661,7 @@ static const struct platform_device_id board_ids[] = {
}, },
{ {
.name = "adl_rt1015p_nau8825", .name = "adl_rt1015p_8825",
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
SOF_SPEAKER_AMP_PRESENT | SOF_SPEAKER_AMP_PRESENT |
SOF_RT1015P_SPEAKER_AMP_PRESENT | SOF_RT1015P_SPEAKER_AMP_PRESENT |
...@@ -657,6 +670,16 @@ static const struct platform_device_id board_ids[] = { ...@@ -657,6 +670,16 @@ static const struct platform_device_id board_ids[] = {
SOF_BT_OFFLOAD_SSP(2) | SOF_BT_OFFLOAD_SSP(2) |
SOF_SSP_BT_OFFLOAD_PRESENT), SOF_SSP_BT_OFFLOAD_PRESENT),
}, },
{
.name = "adl_nau8318_8825",
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
SOF_SPEAKER_AMP_PRESENT |
SOF_NAU8318_SPEAKER_AMP_PRESENT |
SOF_NAU8825_SSP_AMP(1) |
SOF_NAU8825_NUM_HDMIDEV(4) |
SOF_BT_OFFLOAD_SSP(2) |
SOF_SSP_BT_OFFLOAD_PRESENT),
},
{ } { }
}; };
MODULE_DEVICE_TABLE(platform, board_ids); MODULE_DEVICE_TABLE(platform, board_ids);
......
...@@ -450,6 +450,11 @@ static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = { ...@@ -450,6 +450,11 @@ static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = {
.codecs = {"INTC10B0"} .codecs = {"INTC10B0"}
}; };
static const struct snd_soc_acpi_codecs adl_nau8318_amp = {
.num_codecs = 1,
.codecs = {"NVTN2012"}
};
struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
{ {
.comp_ids = &adl_rt5682_rt5682s_hp, .comp_ids = &adl_rt5682_rt5682s_hp,
...@@ -474,21 +479,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { ...@@ -474,21 +479,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
}, },
{ {
.id = "10508825", .id = "10508825",
.drv_name = "adl_rt1019p_nau8825", .drv_name = "adl_rt1019p_8825",
.machine_quirk = snd_soc_acpi_codec_list, .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_rt1019p_amp, .quirk_data = &adl_rt1019p_amp,
.sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg", .sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg",
}, },
{ {
.id = "10508825", .id = "10508825",
.drv_name = "adl_max98373_nau8825", .drv_name = "adl_max98373_8825",
.machine_quirk = snd_soc_acpi_codec_list, .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_max98373_amp, .quirk_data = &adl_max98373_amp,
.sof_tplg_filename = "sof-adl-max98373-nau8825.tplg", .sof_tplg_filename = "sof-adl-max98373-nau8825.tplg",
}, },
{ {
.id = "10508825", .id = "10508825",
.drv_name = "adl_mx98360a_nau8825", .drv_name = "adl_mx98360a_8825",
.machine_quirk = snd_soc_acpi_codec_list, .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_max98360a_amp, .quirk_data = &adl_max98360a_amp,
.sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg", .sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
...@@ -502,11 +507,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { ...@@ -502,11 +507,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
}, },
{ {
.id = "10508825", .id = "10508825",
.drv_name = "adl_rt1015p_nau8825", .drv_name = "adl_rt1015p_8825",
.machine_quirk = snd_soc_acpi_codec_list, .machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_rt1015p_amp, .quirk_data = &adl_rt1015p_amp,
.sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg", .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
}, },
{
.id = "10508825",
.drv_name = "adl_nau8318_8825",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_nau8318_amp,
.sof_tplg_filename = "sof-adl-nau8318-nau8825.tplg",
},
{ {
.id = "10508825", .id = "10508825",
.drv_name = "sof_nau8825", .drv_name = "sof_nau8825",
......
...@@ -203,6 +203,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01_rt71 ...@@ -203,6 +203,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01_rt71
{} {}
}; };
static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01[] = {
{
.mask = BIT(2),
.num_adr = ARRAY_SIZE(rt711_sdca_2_adr),
.adr_d = rt711_sdca_2_adr,
},
{
.mask = BIT(0),
.num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
.adr_d = rt1316_0_group2_adr,
},
{
.mask = BIT(1),
.num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
.adr_d = rt1316_1_group2_adr,
},
{}
};
static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt714_link3[] = { static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt714_link3[] = {
{ {
.mask = BIT(0), .mask = BIT(0),
...@@ -227,6 +246,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt71 ...@@ -227,6 +246,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt71
{} {}
}; };
static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12[] = {
{
.mask = BIT(0),
.num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
.adr_d = rt711_sdca_0_adr,
},
{
.mask = BIT(1),
.num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
.adr_d = rt1318_1_group1_adr,
},
{
.mask = BIT(2),
.num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
.adr_d = rt1318_2_group1_adr,
},
{}
};
static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = { static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {
{ {
.mask = BIT(1), .mask = BIT(1),
...@@ -271,12 +309,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = { ...@@ -271,12 +309,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
.drv_name = "sof_sdw", .drv_name = "sof_sdw",
.sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12-rt714-l3.tplg", .sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12-rt714-l3.tplg",
}, },
{
.link_mask = 0x7, /* rt711 on link0 & two rt1318s on link1 and link2 */
.links = rpl_sdw_rt711_link0_rt1318_link12,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12.tplg",
},
{ {
.link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */ .link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
.links = rpl_sdw_rt1316_link12_rt714_link0, .links = rpl_sdw_rt1316_link12_rt714_link0,
.drv_name = "sof_sdw", .drv_name = "sof_sdw",
.sof_tplg_filename = "sof-rpl-rt1316-l12-rt714-l0.tplg", .sof_tplg_filename = "sof-rpl-rt1316-l12-rt714-l0.tplg",
}, },
{
.link_mask = 0x7, /* rt711 on link2 & two rt1316s on link0 and link1 */
.links = rpl_sdw_rt711_link2_rt1316_link01,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-rpl-rt711-l2-rt1316-l01.tplg",
},
{ {
.link_mask = 0x1, /* link0 required */ .link_mask = 0x1, /* link0 required */
.links = rpl_rvp, .links = rpl_rvp,
......
...@@ -182,10 +182,12 @@ config SND_SOC_MT8186_MT6366_DA7219_MAX98357 ...@@ -182,10 +182,12 @@ config SND_SOC_MT8186_MT6366_DA7219_MAX98357
If unsure select "N". If unsure select "N".
config SND_SOC_MT8186_MT6366_RT1019_RT5682S config SND_SOC_MT8186_MT6366_RT1019_RT5682S
tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S codec" tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S MAX98357A/MAX98360 codec"
depends on I2C && GPIOLIB depends on I2C && GPIOLIB
depends on SND_SOC_MT8186 && MTK_PMIC_WRAP depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
select SND_SOC_MAX98357A
select SND_SOC_MT6358 select SND_SOC_MT6358
select SND_SOC_MAX98357A
select SND_SOC_RT1015P select SND_SOC_RT1015P
select SND_SOC_RT5682S select SND_SOC_RT5682S
select SND_SOC_BT_SCO select SND_SOC_BT_SCO
......
...@@ -1083,6 +1083,21 @@ static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = { ...@@ -1083,6 +1083,21 @@ static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = {
.num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf), .num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
}; };
static struct snd_soc_card mt8186_mt6366_rt5682s_max98360_soc_card = {
.name = "mt8186_rt5682s_max98360",
.owner = THIS_MODULE,
.dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links,
.num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links),
.controls = mt8186_mt6366_rt1019_rt5682s_controls,
.num_controls = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_controls),
.dapm_widgets = mt8186_mt6366_rt1019_rt5682s_widgets,
.num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_widgets),
.dapm_routes = mt8186_mt6366_rt1019_rt5682s_routes,
.num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_routes),
.codec_conf = mt8186_mt6366_rt1019_rt5682s_codec_conf,
.num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
};
static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev) static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
{ {
struct snd_soc_card *card; struct snd_soc_card *card;
...@@ -1232,9 +1247,14 @@ static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev) ...@@ -1232,9 +1247,14 @@ static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
#if IS_ENABLED(CONFIG_OF) #if IS_ENABLED(CONFIG_OF)
static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = { static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = {
{ .compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound", {
.compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound",
.data = &mt8186_mt6366_rt1019_rt5682s_soc_card, .data = &mt8186_mt6366_rt1019_rt5682s_soc_card,
}, },
{
.compatible = "mediatek,mt8186-mt6366-rt5682s-max98360-sound",
.data = &mt8186_mt6366_rt5682s_max98360_soc_card,
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, mt8186_mt6366_rt1019_rt5682s_dt_match); MODULE_DEVICE_TABLE(of, mt8186_mt6366_rt1019_rt5682s_dt_match);
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
menuconfig SND_SOC_QCOM menuconfig SND_SOC_QCOM
tristate "ASoC support for QCOM platforms" tristate "ASoC support for QCOM platforms"
depends on ARCH_QCOM || COMPILE_TEST depends on ARCH_QCOM || COMPILE_TEST
imply SND_SOC_QCOM_COMMON
help help
Say Y or M if you want to add support to use audio devices Say Y or M if you want to add support to use audio devices
in Qualcomm Technologies SOC-based platforms. in Qualcomm Technologies SOC-based platforms.
...@@ -60,14 +59,16 @@ config SND_SOC_STORM ...@@ -60,14 +59,16 @@ config SND_SOC_STORM
config SND_SOC_APQ8016_SBC config SND_SOC_APQ8016_SBC
tristate "SoC Audio support for APQ8016 SBC platforms" tristate "SoC Audio support for APQ8016 SBC platforms"
select SND_SOC_LPASS_APQ8016 select SND_SOC_LPASS_APQ8016
depends on SND_SOC_QCOM_COMMON select SND_SOC_QCOM_COMMON
help help
Support for Qualcomm Technologies LPASS audio block in Support for Qualcomm Technologies LPASS audio block in
APQ8016 SOC-based systems. APQ8016 SOC-based systems.
Say Y if you want to use audio devices on MI2S. Say Y if you want to use audio devices on MI2S.
config SND_SOC_QCOM_COMMON config SND_SOC_QCOM_COMMON
depends on SOUNDWIRE tristate
config SND_SOC_QCOM_SDW
tristate tristate
config SND_SOC_QDSP6_COMMON config SND_SOC_QDSP6_COMMON
...@@ -144,7 +145,7 @@ config SND_SOC_MSM8996 ...@@ -144,7 +145,7 @@ config SND_SOC_MSM8996
depends on QCOM_APR depends on QCOM_APR
depends on COMMON_CLK depends on COMMON_CLK
select SND_SOC_QDSP6 select SND_SOC_QDSP6
depends on SND_SOC_QCOM_COMMON select SND_SOC_QCOM_COMMON
help help
Support for Qualcomm Technologies LPASS audio block in Support for Qualcomm Technologies LPASS audio block in
APQ8096 SoC-based systems. APQ8096 SoC-based systems.
...@@ -155,7 +156,7 @@ config SND_SOC_SDM845 ...@@ -155,7 +156,7 @@ config SND_SOC_SDM845
depends on QCOM_APR && I2C && SOUNDWIRE depends on QCOM_APR && I2C && SOUNDWIRE
depends on COMMON_CLK depends on COMMON_CLK
select SND_SOC_QDSP6 select SND_SOC_QDSP6
depends on SND_SOC_QCOM_COMMON select SND_SOC_QCOM_COMMON
select SND_SOC_RT5663 select SND_SOC_RT5663
select SND_SOC_MAX98927 select SND_SOC_MAX98927
imply SND_SOC_CROS_EC_CODEC imply SND_SOC_CROS_EC_CODEC
...@@ -169,7 +170,8 @@ config SND_SOC_SM8250 ...@@ -169,7 +170,8 @@ config SND_SOC_SM8250
depends on QCOM_APR && SOUNDWIRE depends on QCOM_APR && SOUNDWIRE
depends on COMMON_CLK depends on COMMON_CLK
select SND_SOC_QDSP6 select SND_SOC_QDSP6
depends on SND_SOC_QCOM_COMMON select SND_SOC_QCOM_COMMON
select SND_SOC_QCOM_SDW
help help
To add support for audio on Qualcomm Technologies Inc. To add support for audio on Qualcomm Technologies Inc.
SM8250 SoC-based systems. SM8250 SoC-based systems.
...@@ -180,7 +182,8 @@ config SND_SOC_SC8280XP ...@@ -180,7 +182,8 @@ config SND_SOC_SC8280XP
depends on QCOM_APR && SOUNDWIRE depends on QCOM_APR && SOUNDWIRE
depends on COMMON_CLK depends on COMMON_CLK
select SND_SOC_QDSP6 select SND_SOC_QDSP6
depends on SND_SOC_QCOM_COMMON select SND_SOC_QCOM_COMMON
select SND_SOC_QCOM_SDW
help help
To add support for audio on Qualcomm Technologies Inc. To add support for audio on Qualcomm Technologies Inc.
SC8280XP SoC-based systems. SC8280XP SoC-based systems.
...@@ -190,7 +193,7 @@ config SND_SOC_SC7180 ...@@ -190,7 +193,7 @@ config SND_SOC_SC7180
tristate "SoC Machine driver for SC7180 boards" tristate "SoC Machine driver for SC7180 boards"
depends on I2C && GPIOLIB depends on I2C && GPIOLIB
depends on SOUNDWIRE || SOUNDWIRE=n depends on SOUNDWIRE || SOUNDWIRE=n
depends on SND_SOC_QCOM_COMMON select SND_SOC_QCOM_COMMON
select SND_SOC_LPASS_SC7180 select SND_SOC_LPASS_SC7180
select SND_SOC_MAX98357A select SND_SOC_MAX98357A
select SND_SOC_RT5682_I2C select SND_SOC_RT5682_I2C
...@@ -204,7 +207,7 @@ config SND_SOC_SC7180 ...@@ -204,7 +207,7 @@ config SND_SOC_SC7180
config SND_SOC_SC7280 config SND_SOC_SC7280
tristate "SoC Machine driver for SC7280 boards" tristate "SoC Machine driver for SC7280 boards"
depends on I2C && SOUNDWIRE depends on I2C && SOUNDWIRE
depends on SND_SOC_QCOM_COMMON select SND_SOC_QCOM_COMMON
select SND_SOC_LPASS_SC7280 select SND_SOC_LPASS_SC7280
select SND_SOC_MAX98357A select SND_SOC_MAX98357A
select SND_SOC_WCD938X_SDW select SND_SOC_WCD938X_SDW
......
...@@ -28,6 +28,7 @@ snd-soc-sdm845-objs := sdm845.o ...@@ -28,6 +28,7 @@ snd-soc-sdm845-objs := sdm845.o
snd-soc-sm8250-objs := sm8250.o snd-soc-sm8250-objs := sm8250.o
snd-soc-sc8280xp-objs := sc8280xp.o snd-soc-sc8280xp-objs := sc8280xp.o
snd-soc-qcom-common-objs := common.o snd-soc-qcom-common-objs := common.o
snd-soc-qcom-sdw-objs := sdw.o
obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
...@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o ...@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o
obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o
#DSP lib #DSP lib
obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/ obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/
...@@ -180,120 +180,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ...@@ -180,120 +180,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
} }
EXPORT_SYMBOL_GPL(qcom_snd_parse_of); EXPORT_SYMBOL_GPL(qcom_snd_parse_of);
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime,
bool *stream_prepared)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int ret;
if (!sruntime)
return 0;
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
break;
default:
return 0;
}
if (*stream_prepared) {
sdw_disable_stream(sruntime);
sdw_deprepare_stream(sruntime);
*stream_prepared = false;
}
ret = sdw_prepare_stream(sruntime);
if (ret)
return ret;
/**
* NOTE: there is a strict hw requirement about the ordering of port
* enables and actual WSA881x PA enable. PA enable should only happen
* after soundwire ports are enabled if not DC on the line is
* accumulated resulting in Click/Pop Noise
* PA enable/mute are handled as part of codec DAPM and digital mute.
*/
ret = sdw_enable_stream(sruntime);
if (ret) {
sdw_deprepare_stream(sruntime);
return ret;
}
*stream_prepared = true;
return ret;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct sdw_stream_runtime **psruntime)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct sdw_stream_runtime *sruntime;
int i;
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
for_each_rtd_codec_dais(rtd, i, codec_dai) {
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
if (sruntime != ERR_PTR(-ENOTSUPP))
*psruntime = sruntime;
}
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime, bool *stream_prepared)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
if (sruntime && *stream_prepared) {
sdw_disable_stream(sruntime);
sdw_deprepare_stream(sruntime);
*stream_prepared = false;
}
break;
default:
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *jack, bool *jack_setup) struct snd_soc_jack *jack, bool *jack_setup)
{ {
......
...@@ -5,19 +5,9 @@ ...@@ -5,19 +5,9 @@
#define __QCOM_SND_COMMON_H__ #define __QCOM_SND_COMMON_H__
#include <sound/soc.h> #include <sound/soc.h>
#include <linux/soundwire/sdw.h>
int qcom_snd_parse_of(struct snd_soc_card *card); int qcom_snd_parse_of(struct snd_soc_card *card);
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *jack, bool *jack_setup); struct snd_soc_jack *jack, bool *jack_setup);
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *runtime,
bool *stream_prepared);
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct sdw_stream_runtime **psruntime);
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime,
bool *stream_prepared);
#endif #endif
...@@ -1037,10 +1037,11 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev, ...@@ -1037,10 +1037,11 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
struct lpass_data *data) struct lpass_data *data)
{ {
struct device_node *node; struct device_node *node;
int ret, id; int ret, i, id;
/* Allow all channels by default for backwards compatibility */ /* Allow all channels by default for backwards compatibility */
for (id = 0; id < data->variant->num_dai; id++) { for (i = 0; i < data->variant->num_dai; i++) {
id = data->variant->dai_driver[i].id;
data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH; data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH; data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/input-event-codes.h> #include <linux/input-event-codes.h>
#include "qdsp6/q6afe.h" #include "qdsp6/q6afe.h"
#include "common.h" #include "common.h"
#include "sdw.h"
#define DRIVER_NAME "sc8280xp" #define DRIVER_NAME "sc8280xp"
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018, Linaro Limited.
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
#include <linux/module.h>
#include <sound/soc.h>
#include "qdsp6/q6afe.h"
#include "sdw.h"
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime,
bool *stream_prepared)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int ret;
if (!sruntime)
return 0;
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
break;
default:
return 0;
}
if (*stream_prepared) {
sdw_disable_stream(sruntime);
sdw_deprepare_stream(sruntime);
*stream_prepared = false;
}
ret = sdw_prepare_stream(sruntime);
if (ret)
return ret;
/**
* NOTE: there is a strict hw requirement about the ordering of port
* enables and actual WSA881x PA enable. PA enable should only happen
* after soundwire ports are enabled if not DC on the line is
* accumulated resulting in Click/Pop Noise
* PA enable/mute are handled as part of codec DAPM and digital mute.
*/
ret = sdw_enable_stream(sruntime);
if (ret) {
sdw_deprepare_stream(sruntime);
return ret;
}
*stream_prepared = true;
return ret;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct sdw_stream_runtime **psruntime)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct sdw_stream_runtime *sruntime;
int i;
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
for_each_rtd_codec_dais(rtd, i, codec_dai) {
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
if (sruntime != ERR_PTR(-ENOTSUPP))
*psruntime = sruntime;
}
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime, bool *stream_prepared)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
if (sruntime && *stream_prepared) {
sdw_disable_stream(sruntime);
sdw_deprepare_stream(sruntime);
*stream_prepared = false;
}
break;
default:
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
#ifndef __QCOM_SND_SDW_H__
#define __QCOM_SND_SDW_H__
#include <linux/soundwire/sdw.h>
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *runtime,
bool *stream_prepared);
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct sdw_stream_runtime **psruntime);
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime,
bool *stream_prepared);
#endif
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/input-event-codes.h> #include <linux/input-event-codes.h>
#include "qdsp6/q6afe.h" #include "qdsp6/q6afe.h"
#include "common.h" #include "common.h"
#include "sdw.h"
#define DRIVER_NAME "sm8250" #define DRIVER_NAME "sm8250"
#define MI2S_BCLK_RATE 1536000 #define MI2S_BCLK_RATE 1536000
......
...@@ -353,7 +353,9 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) ...@@ -353,7 +353,9 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
return err; return err;
} }
return 0; return snd_sof_debugfs_buf_item(sdev, &sdev->fw_state,
sizeof(sdev->fw_state),
"fw_state", 0444);
} }
EXPORT_SYMBOL_GPL(snd_sof_dbg_init); EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
......
...@@ -182,7 +182,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) ...@@ -182,7 +182,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
pm_message_t pm_state; pm_message_t pm_state;
u32 target_state = 0; u32 target_state = snd_sof_dsp_power_target(sdev);
int ret; int ret;
/* do nothing if dsp suspend callback is not set */ /* do nothing if dsp suspend callback is not set */
...@@ -192,6 +192,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) ...@@ -192,6 +192,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
if (runtime_suspend && !sof_ops(sdev)->runtime_suspend) if (runtime_suspend && !sof_ops(sdev)->runtime_suspend)
return 0; return 0;
if (tplg_ops && tplg_ops->tear_down_all_pipelines)
tplg_ops->tear_down_all_pipelines(sdev, false);
if (sdev->fw_state != SOF_FW_BOOT_COMPLETE) if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
goto suspend; goto suspend;
...@@ -206,7 +209,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) ...@@ -206,7 +209,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
} }
} }
target_state = snd_sof_dsp_power_target(sdev);
pm_state.event = target_state; pm_state.event = target_state;
/* Skip to platform-specific suspend if DSP is entering D0 */ /* Skip to platform-specific suspend if DSP is entering D0 */
...@@ -217,9 +219,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) ...@@ -217,9 +219,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
goto suspend; goto suspend;
} }
if (tplg_ops->tear_down_all_pipelines)
tplg_ops->tear_down_all_pipelines(sdev, false);
/* suspend DMA trace */ /* suspend DMA trace */
sof_fw_trace_suspend(sdev, pm_state); sof_fw_trace_suspend(sdev, pm_state);
......
...@@ -471,7 +471,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, ...@@ -471,7 +471,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
subs = find_matching_substream(chip, stream, target->sync_ep, subs = find_matching_substream(chip, stream, target->sync_ep,
target->fmt_type); target->fmt_type);
if (!subs) if (!subs)
return sync_fmt; goto end;
high_score = 0; high_score = 0;
list_for_each_entry(fp, &subs->fmt_list, list) { list_for_each_entry(fp, &subs->fmt_list, list) {
...@@ -485,6 +485,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip, ...@@ -485,6 +485,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
} }
} }
end:
if (fixed_rate) if (fixed_rate)
*fixed_rate = snd_usb_pcm_has_fixed_rate(subs); *fixed_rate = snd_usb_pcm_has_fixed_rate(subs);
return sync_fmt; return sync_fmt;
......
...@@ -160,9 +160,12 @@ find_substream_format(struct snd_usb_substream *subs, ...@@ -160,9 +160,12 @@ find_substream_format(struct snd_usb_substream *subs,
bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs) bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs)
{ {
const struct audioformat *fp; const struct audioformat *fp;
struct snd_usb_audio *chip = subs->stream->chip; struct snd_usb_audio *chip;
int rate = -1; int rate = -1;
if (!subs)
return false;
chip = subs->stream->chip;
if (!(chip->quirk_flags & QUIRK_FLAG_FIXED_RATE)) if (!(chip->quirk_flags & QUIRK_FLAG_FIXED_RATE))
return false; return false;
list_for_each_entry(fp, &subs->fmt_list, list) { list_for_each_entry(fp, &subs->fmt_list, list) {
...@@ -525,6 +528,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, ...@@ -525,6 +528,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
if (snd_usb_endpoint_compatible(chip, subs->data_endpoint, if (snd_usb_endpoint_compatible(chip, subs->data_endpoint,
fmt, hw_params)) fmt, hw_params))
goto unlock; goto unlock;
if (stop_endpoints(subs, false))
sync_pending_stops(subs);
close_endpoints(chip, subs); close_endpoints(chip, subs);
} }
...@@ -787,11 +792,27 @@ static int apply_hw_params_minmax(struct snd_interval *it, unsigned int rmin, ...@@ -787,11 +792,27 @@ static int apply_hw_params_minmax(struct snd_interval *it, unsigned int rmin,
return changed; return changed;
} }
/* get the specified endpoint object that is being used by other streams
* (i.e. the parameter is locked)
*/
static const struct snd_usb_endpoint *
get_endpoint_in_use(struct snd_usb_audio *chip, int endpoint,
const struct snd_usb_endpoint *ref_ep)
{
const struct snd_usb_endpoint *ep;
ep = snd_usb_get_endpoint(chip, endpoint);
if (ep && ep->cur_audiofmt && (ep != ref_ep || ep->opened > 1))
return ep;
return NULL;
}
static int hw_rule_rate(struct snd_pcm_hw_params *params, static int hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule) struct snd_pcm_hw_rule *rule)
{ {
struct snd_usb_substream *subs = rule->private; struct snd_usb_substream *subs = rule->private;
struct snd_usb_audio *chip = subs->stream->chip; struct snd_usb_audio *chip = subs->stream->chip;
const struct snd_usb_endpoint *ep;
const struct audioformat *fp; const struct audioformat *fp;
struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
unsigned int rmin, rmax, r; unsigned int rmin, rmax, r;
...@@ -803,6 +824,29 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params, ...@@ -803,6 +824,29 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
list_for_each_entry(fp, &subs->fmt_list, list) { list_for_each_entry(fp, &subs->fmt_list, list) {
if (!hw_check_valid_format(subs, params, fp)) if (!hw_check_valid_format(subs, params, fp))
continue; continue;
ep = get_endpoint_in_use(chip, fp->endpoint,
subs->data_endpoint);
if (ep) {
hwc_debug("rate limit %d for ep#%x\n",
ep->cur_rate, fp->endpoint);
rmin = min(rmin, ep->cur_rate);
rmax = max(rmax, ep->cur_rate);
continue;
}
if (fp->implicit_fb) {
ep = get_endpoint_in_use(chip, fp->sync_ep,
subs->sync_endpoint);
if (ep) {
hwc_debug("rate limit %d for sync_ep#%x\n",
ep->cur_rate, fp->sync_ep);
rmin = min(rmin, ep->cur_rate);
rmax = max(rmax, ep->cur_rate);
continue;
}
}
r = snd_usb_endpoint_get_clock_rate(chip, fp->clock); r = snd_usb_endpoint_get_clock_rate(chip, fp->clock);
if (r > 0) { if (r > 0) {
if (!snd_interval_test(it, r)) if (!snd_interval_test(it, r))
...@@ -872,6 +916,8 @@ static int hw_rule_format(struct snd_pcm_hw_params *params, ...@@ -872,6 +916,8 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule) struct snd_pcm_hw_rule *rule)
{ {
struct snd_usb_substream *subs = rule->private; struct snd_usb_substream *subs = rule->private;
struct snd_usb_audio *chip = subs->stream->chip;
const struct snd_usb_endpoint *ep;
const struct audioformat *fp; const struct audioformat *fp;
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
u64 fbits; u64 fbits;
...@@ -881,6 +927,27 @@ static int hw_rule_format(struct snd_pcm_hw_params *params, ...@@ -881,6 +927,27 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
list_for_each_entry(fp, &subs->fmt_list, list) { list_for_each_entry(fp, &subs->fmt_list, list) {
if (!hw_check_valid_format(subs, params, fp)) if (!hw_check_valid_format(subs, params, fp))
continue; continue;
ep = get_endpoint_in_use(chip, fp->endpoint,
subs->data_endpoint);
if (ep) {
hwc_debug("format limit %d for ep#%x\n",
ep->cur_format, fp->endpoint);
fbits |= pcm_format_to_bits(ep->cur_format);
continue;
}
if (fp->implicit_fb) {
ep = get_endpoint_in_use(chip, fp->sync_ep,
subs->sync_endpoint);
if (ep) {
hwc_debug("format limit %d for sync_ep#%x\n",
ep->cur_format, fp->sync_ep);
fbits |= pcm_format_to_bits(ep->cur_format);
continue;
}
}
fbits |= fp->formats; fbits |= fp->formats;
} }
return apply_hw_params_format_bits(fmt, fbits); return apply_hw_params_format_bits(fmt, fbits);
...@@ -913,98 +980,95 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params, ...@@ -913,98 +980,95 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params,
return apply_hw_params_minmax(it, pmin, UINT_MAX); return apply_hw_params_minmax(it, pmin, UINT_MAX);
} }
/* 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;
const struct audioformat *fp;
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_audiofmt) {
/* if EP is already opened solely for this substream,
* we still allow us to change the parameter; otherwise
* this substream has to follow the existing parameter
*/
if (ep->cur_audiofmt != subs->cur_audiofmt || ep->opened > 1)
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_audiofmt)
return ep;
}
return NULL;
}
/* additional hw constraints for implicit feedback mode */ /* 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;
hwc_debug("applying %s\n", __func__);
return apply_hw_params_format_bits(fmt, pcm_format_to_bits(ep->cur_format));
}
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;
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_RATE);
return apply_hw_params_minmax(it, ep->cur_rate, ep->cur_rate);
}
static int hw_rule_period_size_implicit_fb(struct snd_pcm_hw_params *params, static int hw_rule_period_size_implicit_fb(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule) struct snd_pcm_hw_rule *rule)
{ {
struct snd_usb_substream *subs = rule->private; struct snd_usb_substream *subs = rule->private;
struct snd_usb_audio *chip = subs->stream->chip;
const struct audioformat *fp;
const struct snd_usb_endpoint *ep; const struct snd_usb_endpoint *ep;
struct snd_interval *it; struct snd_interval *it;
unsigned int rmin, rmax;
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); it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
return apply_hw_params_minmax(it, ep->cur_period_frames, hwc_debug("hw_rule_period_size: (%u,%u)\n", it->min, it->max);
ep->cur_period_frames); rmin = UINT_MAX;
rmax = 0;
list_for_each_entry(fp, &subs->fmt_list, list) {
if (!hw_check_valid_format(subs, params, fp))
continue;
ep = get_endpoint_in_use(chip, fp->endpoint,
subs->data_endpoint);
if (ep) {
hwc_debug("period size limit %d for ep#%x\n",
ep->cur_period_frames, fp->endpoint);
rmin = min(rmin, ep->cur_period_frames);
rmax = max(rmax, ep->cur_period_frames);
continue;
}
if (fp->implicit_fb) {
ep = get_endpoint_in_use(chip, fp->sync_ep,
subs->sync_endpoint);
if (ep) {
hwc_debug("period size limit %d for sync_ep#%x\n",
ep->cur_period_frames, fp->sync_ep);
rmin = min(rmin, ep->cur_period_frames);
rmax = max(rmax, ep->cur_period_frames);
continue;
}
}
}
if (!rmax)
return 0; /* no limit by implicit fb */
return apply_hw_params_minmax(it, rmin, rmax);
} }
static int hw_rule_periods_implicit_fb(struct snd_pcm_hw_params *params, static int hw_rule_periods_implicit_fb(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule) struct snd_pcm_hw_rule *rule)
{ {
struct snd_usb_substream *subs = rule->private; struct snd_usb_substream *subs = rule->private;
struct snd_usb_audio *chip = subs->stream->chip;
const struct audioformat *fp;
const struct snd_usb_endpoint *ep; const struct snd_usb_endpoint *ep;
struct snd_interval *it; struct snd_interval *it;
unsigned int rmin, rmax;
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); it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIODS);
return apply_hw_params_minmax(it, ep->cur_buffer_periods, hwc_debug("hw_rule_periods: (%u,%u)\n", it->min, it->max);
ep->cur_buffer_periods); rmin = UINT_MAX;
rmax = 0;
list_for_each_entry(fp, &subs->fmt_list, list) {
if (!hw_check_valid_format(subs, params, fp))
continue;
ep = get_endpoint_in_use(chip, fp->endpoint,
subs->data_endpoint);
if (ep) {
hwc_debug("periods limit %d for ep#%x\n",
ep->cur_buffer_periods, fp->endpoint);
rmin = min(rmin, ep->cur_buffer_periods);
rmax = max(rmax, ep->cur_buffer_periods);
continue;
}
if (fp->implicit_fb) {
ep = get_endpoint_in_use(chip, fp->sync_ep,
subs->sync_endpoint);
if (ep) {
hwc_debug("periods limit %d for sync_ep#%x\n",
ep->cur_buffer_periods, fp->sync_ep);
rmin = min(rmin, ep->cur_buffer_periods);
rmax = max(rmax, ep->cur_buffer_periods);
continue;
}
}
}
if (!rmax)
return 0; /* no limit by implicit fb */
return apply_hw_params_minmax(it, rmin, rmax);
} }
/* /*
...@@ -1113,16 +1177,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre ...@@ -1113,16 +1177,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
return err; return err;
/* additional hw constraints for implicit fb */ /* 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, err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
hw_rule_period_size_implicit_fb, subs, hw_rule_period_size_implicit_fb, subs,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
......
...@@ -1222,6 +1222,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, ...@@ -1222,6 +1222,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
if (err < 0) if (err < 0)
return err; return err;
} }
/* try to set the interface... */
usb_set_interface(chip->dev, iface_no, 0);
snd_usb_init_pitch(chip, fp);
snd_usb_init_sample_rate(chip, fp, fp->rate_max);
usb_set_interface(chip->dev, iface_no, altno);
} }
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment