mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
sound fixes for 7.3-rc4
A collection of small fixes. Most of them are device-specific fixes
while there are a few core fixes. The continued flux, but not too
scaring yet. Some highlights below.
ALSA Core:
- Fix potential UAF after asynchronous card release
- Fix a race condition in PCM timer initialization order
USB-Audio:
- Hardening fixes for issues reported by fuzzer for 6fire, bcd2000,
and implicit FB packets
- Fix double list addition in implicit FB handling
- Quirks for AVerMedia GC553Pro and Behringer FCA1616
HD-Audio:
- Quirks / fixes for HP OmniBook 7, OMEN 15, and Victus 15 laptops
ASoC:
- Support for DAI link codec channel mask to avoid mismatches
- Fix HDMI-codec channel status change report
- Fixes for various codecs and platforms: Realtek rt712/rt721
(calibration, reset fixes), Cirrus Logic (empty EFI variable
validation, capture channel fixup), AMD ACP SoundWire (bounds
checks, refactorings), ADAU1977 (OF match table support, SPI
cleanups), ES8336 (Huawei Matebook B3-420 quirk), UX500 (macro fix)
-----BEGIN PGP SIGNATURE-----
iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmqrwIYOHHRpd2FpQHN1
c2UuZGUACgkQLtJE4w1nLE8WeQ//eN0ufLXXqy5U6X7kri8eM4vjRDZa5v1z8oD/
oHBdkgPmSAOJOddCVHuyPyx5BP4reBgKbukxUTBjuJvVRD4iOYfvXSW1LzVCVcly
f60rJl1/Ck3RcXfVabNV9eeGCFtAwR00U/3oH7z0eDhjwisX2F4ucAMmgxyJUKTh
pLdMPFsI/XW5CWeVbPVObGlOB8Bf/c79wy5NAnpixAkR1WaXUSLKoF5djO9qIQex
eTIknPmMYLLSfzFfO0TWY1PPRPz5qJHDr6Acer0VMTHyZF0yg2bR+gRInbM1at2H
c/lg8m899ZbobSCiHFEJdPH/W5x3iHqFi3hKVtKtQ5niot+gWTirQpjUCZ2HxNOp
5fYEyieSJ0W/t2NfNW0SP+DUOvKaIxY9VUuGCW7z/YgjW5DvSxipd2FOC4Av0s6F
l67vYazzPzf9d34NIM333FHeSZ4WMXVKKTfB34CQD93lVB1GladNA6lFFer5zuqG
Sc8q+YGUF65OZEnbslANIDvqPG0eMNlqBn/iyqXQO+P/C6oXWIlqFm4DUtM5a8wB
3Vf/e9L4mzXwKZfoW2xsJLgfpAO0faYiTAO6fr7wjBPrRl7VoenOlsCshN5GLTmM
b4bQ29LZrpk9e3e8BdGdZzT/kfQEZ31O5sawaj6f+a2JG09xCi9qxklxV5wFvZ5E
FTO+HgE=
=PnHM
-----END PGP SIGNATURE-----
Merge tag 'sound-7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai:
"A collection of small fixes. Most of them are device-specific fixes
while there are a few core fixes. The continued flux, but not too
scaring yet. Some highlights below.
ALSA Core:
- Fix potential UAF after asynchronous card release
- Fix a race condition in PCM timer initialization order
USB-Audio:
- Hardening fixes for issues reported by fuzzer for 6fire, bcd2000,
and implicit FB packets
- Fix double list addition in implicit FB handling
- Quirks for AVerMedia GC553Pro and Behringer FCA1616
HD-Audio:
- Quirks / fixes for HP OmniBook 7, OMEN 15, and Victus 15 laptops
ASoC:
- Support for DAI link codec channel mask to avoid mismatches
- Fix HDMI-codec channel status change report
- Fixes for various codecs and platforms: Realtek rt712/rt721
(calibration, reset fixes), Cirrus Logic (empty EFI variable
validation, capture channel fixup), AMD ACP SoundWire (bounds
checks, refactorings), ADAU1977 (OF match table support, SPI
cleanups), ES8336 (Huawei Matebook B3-420 quirk), UX500 (macro
fix)"
* tag 'sound-7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (33 commits)
ASoC: adau1977-i2c: add OF match table for I2C
ASoC: adau1977-spi: drop __maybe_unused and of_match_ptr()
ASoC: adau1977: make the Kconfig symbols user selectable
ASoC: amd: acp: fix card name length warning in SOF SoundWire machine driver
ASoC: amd: acp: fix ffs() operator precedence for SoundWire link ID
ASoC: amd: acp: refactor codec config count in SOF SoundWire machine driver
ASoC: amd: acp: bounds-check SoundWire link ID in machine drivers
ASoC: cs-amp-lib: Prevent NULL pointer if efi variable is zero length
ASoC: codecs: rt712-sdca-dmic: fix uninitialized stream_config->type
ASoC: hdmi-codec: Report a change when the channel status moves
ASoC: ux500: Parenthesize MSP_{RX,TX}_CLKPOL_BIT() arguments
ASoC: rt721: Reset codec to fix abnormal sound
ALSA: usb-audio: fix list_add double-add in push_back_to_ready_list
ALSA: hda: trace PCM open only after assigning a stream
ALSA: usb-audio: skip the broken mute control on AVerMedia GC553Pro
ALSA: hda/realtek: Enable mute LEDs on HP OmniBook 7 17-dc0xxx
ALSA: 6fire: fix OOB write from device-reported iso length
ALSA: usb-audio: Add capture quirk for Behringer FCA1616
ALSA: hda/realtek: Add mute LED quirk for HP OMEN 15-ax
ASoC: Intel: sof_es8336: Add a quirk for Huawei Matebook B3-420
...
This commit is contained in:
commit
4982d3552a
|
|
@ -699,7 +699,8 @@ struct snd_soc_dai_link_component {
|
|||
struct snd_soc_dai_link_ch_map {
|
||||
unsigned int cpu;
|
||||
unsigned int codec;
|
||||
unsigned int ch_mask;
|
||||
unsigned int cpu_ch_mask;
|
||||
unsigned int codec_ch_mask;
|
||||
};
|
||||
|
||||
struct snd_soc_dai_link {
|
||||
|
|
|
|||
|
|
@ -250,8 +250,6 @@ int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
|
|||
struct snd_soc_dai_link *dai_links,
|
||||
struct asoc_sdw_codec_info *info,
|
||||
bool playback);
|
||||
int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_soc_dai *dai);
|
||||
int asoc_sdw_cs35l56_volume_limit(struct snd_soc_card *card, const char *name_prefix);
|
||||
|
||||
/* MAXIM codec support */
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
|
|||
kfree(card); /* manually free here, as no destructor called */
|
||||
return err;
|
||||
}
|
||||
card->dev = parent;
|
||||
card->dev = get_device(parent);
|
||||
card->number = idx;
|
||||
WARN_ON(IS_MODULE(CONFIG_SND) && !module);
|
||||
card->module = module;
|
||||
|
|
@ -603,6 +603,7 @@ static int snd_card_do_free(struct snd_card *card)
|
|||
dev_warn(card->dev, "unable to free card info\n");
|
||||
/* Not fatal error */
|
||||
}
|
||||
put_device(card->dev);
|
||||
if (card->release_completion)
|
||||
complete(card->release_completion);
|
||||
if (!managed)
|
||||
|
|
|
|||
|
|
@ -111,12 +111,15 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream)
|
|||
snd_pcm_direction_name(substream->stream),
|
||||
tid.card, tid.device, tid.subdevice);
|
||||
timer->hw = snd_pcm_timer;
|
||||
/* Set before registering: a concurrent reader can invoke our hw
|
||||
* callbacks as soon as the timer is on the global list.
|
||||
*/
|
||||
timer->private_data = substream;
|
||||
timer->private_free = snd_pcm_timer_free;
|
||||
if (snd_device_register(timer->card, timer) < 0) {
|
||||
snd_device_free(timer->card, timer);
|
||||
return;
|
||||
}
|
||||
timer->private_data = substream;
|
||||
timer->private_free = snd_pcm_timer_free;
|
||||
substream->timer = timer;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4303,6 +4303,7 @@ enum {
|
|||
ALC287_FIXUP_LEGION_16ACHG6,
|
||||
ALC287_FIXUP_CS35L41_I2C_2,
|
||||
ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED,
|
||||
ALC287_FIXUP_CS35L41_I2C_2_HP_MUTE_LEDS,
|
||||
ALC287_FIXUP_CS35L41_I2C_4,
|
||||
ALC245_FIXUP_CS35L41_SPI_1,
|
||||
ALC245_FIXUP_CS35L41_SPI_2,
|
||||
|
|
@ -6614,6 +6615,12 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.chained = true,
|
||||
.chain_id = ALC285_FIXUP_HP_MUTE_LED,
|
||||
},
|
||||
[ALC287_FIXUP_CS35L41_I2C_2_HP_MUTE_LEDS] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = cs35l41_fixup_i2c_two,
|
||||
.chained = true,
|
||||
.chain_id = ALC245_FIXUP_HP_X360_MUTE_LEDS,
|
||||
},
|
||||
[ALC287_FIXUP_CS35L41_I2C_4] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = cs35l41_fixup_i2c_four,
|
||||
|
|
@ -7358,6 +7365,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8158, "HP", ALC256_FIXUP_HP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x103c, 0x820d, "HP Pavilion 15", ALC295_FIXUP_HP_X360),
|
||||
SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC),
|
||||
SND_PCI_QUIRK(0x103c, 0x8259, "HP OMEN 15-ax202nf", ALC269_FIXUP_HP_MUTE_LED_MIC3),
|
||||
SND_PCI_QUIRK(0x103c, 0x827e, "HP x360", ALC295_FIXUP_HP_X360),
|
||||
SND_PCI_QUIRK(0x103c, 0x827f, "HP x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
|
||||
SND_PCI_QUIRK(0x103c, 0x82bf, "HP G3 mini", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
|
||||
|
|
@ -7568,6 +7576,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
|
||||
SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
|
||||
SND_PCI_QUIRK(0x103c, 0x8ba9, "HP Omen 16-wd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8bb1, "HP Victus 15-fa1xxx (MB 8BB1)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8bb6, "HP Laptop 15-fd0039nt", ALC236_FIXUP_HP_15_FD0XXX),
|
||||
|
|
@ -7660,7 +7669,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8dcd, "HP Victus 15-fa2xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2_HP_MUTE_LEDS),
|
||||
SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8d9e, "HP 17 Turbine OmniBook X DIS", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8d9f, "HP 14 Cadet (x360)", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
|
|
|
|||
|
|
@ -586,11 +586,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
|||
snd_hda_codec_pcm_get(apcm->info);
|
||||
mutex_lock(&chip->open_mutex);
|
||||
azx_dev = azx_assign_device(chip, substream);
|
||||
trace_azx_pcm_open(chip, azx_dev);
|
||||
if (azx_dev == NULL) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
trace_azx_pcm_open(chip, azx_dev);
|
||||
runtime->private_data = azx_dev;
|
||||
|
||||
runtime->hw = azx_pcm_hw;
|
||||
|
|
|
|||
|
|
@ -205,9 +205,19 @@ static int create_sdw_dailink(struct snd_soc_card *card,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!soc_end->link_mask) {
|
||||
dev_err(dev, "invalid zero link_mask\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((ffs(soc_end->link_mask) - 1) >= amd_ctx->max_sdw_links) {
|
||||
dev_err(dev, "link_id %d exceeds max_sdw_links %d\n",
|
||||
ffs(soc_end->link_mask) - 1, amd_ctx->max_sdw_links);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (amd_ctx->acp_rev) {
|
||||
case ACP63_PCI_REV:
|
||||
ret = get_acp63_cpu_pin_id(ffs(soc_end->link_mask - 1),
|
||||
ret = get_acp63_cpu_pin_id(ffs(soc_end->link_mask) - 1,
|
||||
*be_id, &cpu_pin_id, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -215,7 +225,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
|
|||
case ACP70_PCI_REV:
|
||||
case ACP71_PCI_REV:
|
||||
case ACP72_PCI_REV:
|
||||
ret = get_acp70_cpu_pin_id(ffs(soc_end->link_mask - 1),
|
||||
ret = get_acp70_cpu_pin_id(ffs(soc_end->link_mask) - 1,
|
||||
*be_id, &cpu_pin_id, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -121,9 +121,18 @@ static int create_sdw_dailink(struct snd_soc_card *card,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!sof_end->link_mask) {
|
||||
dev_err(dev, "invalid zero link_mask\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((ffs(sof_end->link_mask) - 1) >= amd_ctx->max_sdw_links) {
|
||||
dev_err(dev, "link_id %d exceeds max_sdw_links %d\n",
|
||||
ffs(sof_end->link_mask) - 1, amd_ctx->max_sdw_links);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (amd_ctx->acp_rev) {
|
||||
case ACP63_PCI_REV:
|
||||
ret = get_acp63_cpu_pin_id(ffs(sof_end->link_mask - 1),
|
||||
ret = get_acp63_cpu_pin_id(ffs(sof_end->link_mask) - 1,
|
||||
*be_id, &cpu_pin_id, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -131,7 +140,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
|
|||
case ACP70_PCI_REV:
|
||||
case ACP71_PCI_REV:
|
||||
case ACP72_PCI_REV:
|
||||
ret = get_acp70_cpu_pin_id(ffs(sof_end->link_mask - 1),
|
||||
ret = get_acp70_cpu_pin_id(ffs(sof_end->link_mask) - 1,
|
||||
*be_id, &cpu_pin_id, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -277,6 +286,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
|
|||
int num_devs = 0;
|
||||
int num_ends = 0;
|
||||
int num_aux = 0;
|
||||
int num_confs;
|
||||
int num_links;
|
||||
int be_id = 0;
|
||||
int ret;
|
||||
|
|
@ -287,6 +297,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
|
|||
return ret;
|
||||
}
|
||||
|
||||
num_confs = num_ends;
|
||||
/* One per DAI link, worst case is a DAI link for every endpoint */
|
||||
struct asoc_sdw_dailink *sof_dais __free(kfree) =
|
||||
kzalloc_objs(*sof_dais, num_ends);
|
||||
|
|
@ -303,7 +314,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
|
|||
if (!sof_aux)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_devs);
|
||||
ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -315,7 +326,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
|
|||
|
||||
dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num);
|
||||
|
||||
codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
|
||||
codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL);
|
||||
if (!codec_conf)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -326,7 +337,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
|
|||
return -ENOMEM;
|
||||
|
||||
card->codec_conf = codec_conf;
|
||||
card->num_configs = num_devs;
|
||||
card->num_configs = num_confs;
|
||||
card->dai_link = dai_links;
|
||||
card->num_links = num_links;
|
||||
card->aux_dev = sof_aux;
|
||||
|
|
@ -379,7 +390,7 @@ static int mc_probe(struct platform_device *pdev)
|
|||
ctx->private = amd_ctx;
|
||||
card = &ctx->card;
|
||||
card->dev = &pdev->dev;
|
||||
card->name = "amd-soundwire";
|
||||
card->name = "amd-sdw";
|
||||
card->owner = THIS_MODULE;
|
||||
card->late_probe = asoc_sdw_card_late_probe;
|
||||
|
||||
|
|
|
|||
|
|
@ -524,13 +524,13 @@ config SND_SOC_ADAU1977
|
|||
tristate
|
||||
|
||||
config SND_SOC_ADAU1977_SPI
|
||||
tristate
|
||||
tristate "Analog Devices ADAU1977/ADAU1978/ADAU1979 CODEC - SPI"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_ADAU1977
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_ADAU1977_I2C
|
||||
tristate
|
||||
tristate "Analog Devices ADAU1977/ADAU1978/ADAU1979 CODEC - I2C"
|
||||
depends on I2C
|
||||
select SND_SOC_ADAU1977
|
||||
select REGMAP_I2C
|
||||
|
|
|
|||
|
|
@ -34,9 +34,18 @@ static const struct i2c_device_id adau1977_i2c_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids);
|
||||
|
||||
static const struct of_device_id adau1977_i2c_of_match[] = {
|
||||
{ .compatible = "adi,adau1977" },
|
||||
{ .compatible = "adi,adau1978" },
|
||||
{ .compatible = "adi,adau1979" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adau1977_i2c_of_match);
|
||||
|
||||
static struct i2c_driver adau1977_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adau1977",
|
||||
.of_match_table = adau1977_i2c_of_match,
|
||||
},
|
||||
.probe = adau1977_i2c_probe,
|
||||
.id_table = adau1977_i2c_ids,
|
||||
|
|
|
|||
|
|
@ -53,18 +53,18 @@ static const struct spi_device_id adau1977_spi_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(spi, adau1977_spi_ids);
|
||||
|
||||
static const struct of_device_id adau1977_spi_of_match[] __maybe_unused = {
|
||||
{ .compatible = "adi,adau1977" },
|
||||
{ .compatible = "adi,adau1978" },
|
||||
{ .compatible = "adi,adau1979" },
|
||||
{ },
|
||||
static const struct of_device_id adau1977_spi_of_match[] = {
|
||||
{ .compatible = "adi,adau1977" },
|
||||
{ .compatible = "adi,adau1978" },
|
||||
{ .compatible = "adi,adau1979" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adau1977_spi_of_match);
|
||||
|
||||
static struct spi_driver adau1977_spi_driver = {
|
||||
.driver = {
|
||||
.name = "adau1977",
|
||||
.of_match_table = of_match_ptr(adau1977_spi_of_match),
|
||||
.of_match_table = adau1977_spi_of_match,
|
||||
},
|
||||
.probe = adau1977_spi_probe,
|
||||
.id_table = adau1977_spi_ids,
|
||||
|
|
|
|||
|
|
@ -317,6 +317,8 @@ static void *cs_amp_alloc_get_efi_variable(efi_char16_t *name,
|
|||
unsigned long size = 0;
|
||||
|
||||
status = cs_amp_get_efi_variable(name, guid, NULL, &size, NULL);
|
||||
if (status == EFI_SUCCESS)
|
||||
return ERR_PTR(-ENOENT);
|
||||
if (status != EFI_BUFFER_TOO_SMALL)
|
||||
return ERR_PTR(cs_amp_convert_efi_status(status));
|
||||
|
||||
|
|
|
|||
|
|
@ -426,10 +426,14 @@ static int hdmi_codec_iec958_default_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (!memcmp(hcp->iec_status, ucontrol->value.iec958.status,
|
||||
sizeof(hcp->iec_status)))
|
||||
return 0;
|
||||
|
||||
memcpy(hcp->iec_status, ucontrol->value.iec958.status,
|
||||
sizeof(hcp->iec_status));
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int hdmi_codec_iec958_mask_get(struct snd_kcontrol *kcontrol,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/sdw.h>
|
||||
#include <sound/tlv.h>
|
||||
#include "rt712-sdca.h"
|
||||
#include "rt712-sdca-dmic.h"
|
||||
|
|
@ -632,10 +633,10 @@ static int rt712_sdca_dmic_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct rt712_sdca_dmic_priv *rt712 = snd_soc_component_get_drvdata(component);
|
||||
struct sdw_stream_config stream_config;
|
||||
struct sdw_stream_config stream_config = {0};
|
||||
struct sdw_port_config port_config;
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
int retval, num_channels;
|
||||
int retval;
|
||||
unsigned int sampling_rate;
|
||||
|
||||
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
|
||||
|
|
@ -647,13 +648,8 @@ static int rt712_sdca_dmic_hw_params(struct snd_pcm_substream *substream,
|
|||
if (!rt712->slave)
|
||||
return -EINVAL;
|
||||
|
||||
stream_config.frame_rate = params_rate(params);
|
||||
stream_config.ch_count = params_channels(params);
|
||||
stream_config.bps = snd_pcm_format_width(params_format(params));
|
||||
stream_config.direction = SDW_DATA_DIR_TX;
|
||||
|
||||
num_channels = params_channels(params);
|
||||
port_config.ch_mask = GENMASK(num_channels - 1, 0);
|
||||
/* SoundWire specific configuration */
|
||||
snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
|
||||
port_config.num = 2;
|
||||
|
||||
retval = sdw_stream_add_slave(rt712->slave, &stream_config,
|
||||
|
|
|
|||
|
|
@ -18,12 +18,16 @@
|
|||
static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case 0x004d:
|
||||
case 0x201a ... 0x201f:
|
||||
case 0x2029 ... 0x202a:
|
||||
case 0x202d ... 0x2034:
|
||||
case 0x2230 ... 0x2232:
|
||||
case 0x2f01 ... 0x2f0a:
|
||||
case 0x2f35 ... 0x2f36:
|
||||
case 0x2f3a:
|
||||
case 0x2f3d:
|
||||
case 0x2f41:
|
||||
case 0x2f50:
|
||||
case 0x2f54:
|
||||
case 0x2f58 ... 0x2f5d:
|
||||
|
|
@ -48,6 +52,7 @@ static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg)
|
|||
static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case 0x004d:
|
||||
case 0x201b:
|
||||
case 0x201c:
|
||||
case 0x201d:
|
||||
|
|
@ -56,6 +61,9 @@ static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg)
|
|||
case 0x2230:
|
||||
case 0x2f01:
|
||||
case 0x2f35:
|
||||
case 0x2f3a:
|
||||
case 0x2f3d:
|
||||
case 0x2f41:
|
||||
case 0x320c:
|
||||
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
|
||||
case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
|
||||
|
|
|
|||
|
|
@ -73,14 +73,57 @@ static int rt712_sdca_index_update_bits(struct rt712_sdca_priv *rt712,
|
|||
return rt712_sdca_index_write(rt712, nid, reg, tmp);
|
||||
}
|
||||
|
||||
static void rt712_sdca_clk_patch(struct rt712_sdca_priv *rt712)
|
||||
{
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0000);
|
||||
regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x03);
|
||||
usleep_range(1000, 1100);
|
||||
regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x02);
|
||||
usleep_range(1000, 1100);
|
||||
regmap_update_bits(rt712->regmap, RT712_PLL2_CONF2, 0x0080, 0x0000);
|
||||
regmap_update_bits(rt712->regmap, RT712_PLL2_CONF2, 0x001f, 0x0017);
|
||||
regmap_update_bits(rt712->regmap, RT712_PLL2_CONF3, 0x0010, 0x0000);
|
||||
regmap_update_bits(rt712->regmap, RT712_PLL2_CONF1, 0x0081, 0x0001);
|
||||
regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x03);
|
||||
usleep_range(1000, 1100);
|
||||
regmap_update_bits(rt712->regmap, RT712_PLL2_CONF1, 0x0081, 0x0081);
|
||||
regmap_update_bits(rt712->regmap, RT712_PLL2_CONF2, 0x0080, 0x0080);
|
||||
regmap_update_bits(rt712->regmap, RT712_PLL2_CONF2, 0x001f, 0x0000);
|
||||
regmap_update_bits(rt712->regmap, RT712_PLL2_CONF3, 0x0010, 0x0010);
|
||||
usleep_range(1000, 1100);
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0081);
|
||||
}
|
||||
|
||||
static void rt712_sdca_clk_patch2(struct rt712_sdca_priv *rt712)
|
||||
{
|
||||
rt712_sdca_index_update_bits(rt712, RT712_VENDOR_REG, 0x49, 0x0800,
|
||||
0x0000);
|
||||
rt712_sdca_index_update_bits(rt712, RT712_VENDOR_REG, 0x49, 0xf000,
|
||||
0x0000);
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0000);
|
||||
rt712_sdca_index_update_bits(rt712, RT712_VENDOR_ANALOG_CTL, 0x0c, 0xc000,
|
||||
0xc000);
|
||||
rt712_sdca_index_update_bits(rt712, RT712_VENDOR_ANALOG_CTL, 0x00, 0xc000,
|
||||
0xc000);
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0081);
|
||||
regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x02);
|
||||
usleep_range(1000, 1100);
|
||||
regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x03);
|
||||
usleep_range(1000, 1100);
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0000);
|
||||
}
|
||||
|
||||
static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712)
|
||||
{
|
||||
unsigned int val, loop_rc = 0, loop_dc = 0;
|
||||
struct device *dev;
|
||||
struct regmap *regmap = rt712->regmap;
|
||||
unsigned int clk_base;
|
||||
int chk_cnt = 100;
|
||||
int ret = 0;
|
||||
|
||||
regmap_read(rt712->regmap, RT712_SDW_ROOT_CLK, &clk_base);
|
||||
|
||||
mutex_lock(&rt712->calibrate_mutex);
|
||||
dev = regmap_get_device(regmap);
|
||||
|
||||
|
|
@ -109,8 +152,35 @@ static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712)
|
|||
if (ret < 0)
|
||||
goto _cali_fail_;
|
||||
}
|
||||
if (loop_dc == chk_cnt)
|
||||
dev_err(dev, "%s, calibration time-out!\n", __func__);
|
||||
|
||||
if (loop_dc == chk_cnt) {
|
||||
if (clk_base == RT712_CLK_FREQ_24_576MHZ) {
|
||||
rt712_sdca_clk_patch(rt712);
|
||||
rt712_sdca_clk_patch2(rt712);
|
||||
}
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_FSM_CTL, 0x4100);
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_CALI,
|
||||
RT712_DAC_DC_CALI_CTL1, 0x7883);
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_CALI,
|
||||
RT712_DAC_DC_CALI_CTL1, 0xf893);
|
||||
rt712_sdca_index_read(rt712, RT712_VENDOR_CALI,
|
||||
RT712_DAC_DC_CALI_CTL1, &val);
|
||||
|
||||
for (loop_dc = 0; loop_dc < chk_cnt &&
|
||||
(val & RT712_DAC_DC_CALI_TRIGGER); loop_dc++) {
|
||||
usleep_range(10000, 11000);
|
||||
ret = rt712_sdca_index_read(rt712, RT712_VENDOR_CALI,
|
||||
RT712_DAC_DC_CALI_CTL1, &val);
|
||||
|
||||
if (ret < 0)
|
||||
goto _cali_fail_;
|
||||
}
|
||||
|
||||
if (loop_dc == chk_cnt)
|
||||
dev_err(dev, "%s, calibration time-out!\n", __func__);
|
||||
else
|
||||
dev_dbg(dev, "%s, calibration success!\n", __func__);
|
||||
}
|
||||
|
||||
if (loop_dc == chk_cnt || loop_rc == chk_cnt)
|
||||
ret = -ETIMEDOUT;
|
||||
|
|
@ -1759,9 +1829,13 @@ static void rt712_sdca_va_io_init(struct rt712_sdca_priv *rt712)
|
|||
|
||||
static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int jack_func_status, mic_func_status, amp_func_status;
|
||||
struct device *dev = &rt712->slave->dev;
|
||||
unsigned int clk_base;
|
||||
int ret = 0;
|
||||
|
||||
regmap_read(rt712->regmap, RT712_SDW_ROOT_CLK, &clk_base);
|
||||
dev_dbg(dev, "%s clk_base=%x", __func__, clk_base);
|
||||
|
||||
regmap_read(rt712->regmap,
|
||||
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status);
|
||||
|
|
@ -1773,6 +1847,12 @@ static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
|
|||
__func__, jack_func_status, mic_func_status, amp_func_status);
|
||||
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL3, 0x7778);
|
||||
|
||||
if (clk_base == RT712_CLK_FREQ_24_576MHZ) {
|
||||
rt712_sdca_clk_patch(rt712);
|
||||
rt712_sdca_clk_patch2(rt712);
|
||||
}
|
||||
|
||||
/* DMIC */
|
||||
if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
|
||||
rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526);
|
||||
|
|
|
|||
|
|
@ -162,6 +162,16 @@ struct rt712_dmic_kctrl_priv {
|
|||
#define RT712_EAPD_HIGH 0x2
|
||||
#define RT712_EAPD_LOW 0x0
|
||||
|
||||
/* SDW clock root frequency */
|
||||
#define RT712_SDW_ROOT_CLK 0x004d
|
||||
#define RT712_SDW_SCALE_CLK0 0x0062
|
||||
#define RT712_SDW_SCALE_CLK1 0x0072
|
||||
|
||||
/* PLL2 config */
|
||||
#define RT712_PLL2_CONF1 0x2f3a
|
||||
#define RT712_PLL2_CONF2 0x2f3d
|
||||
#define RT712_PLL2_CONF3 0x2f41
|
||||
|
||||
/* RC Calibration register */
|
||||
#define RT712_RC_CAL 0x3201
|
||||
|
||||
|
|
@ -254,6 +264,14 @@ enum rt712_sdca_version {
|
|||
RT712_VB,
|
||||
};
|
||||
|
||||
enum {
|
||||
RT712_CLK_FREQ_19_2_MHZ = 1,
|
||||
RT712_CLK_FREQ_24MHZ = 2,
|
||||
RT712_CLK_FREQ_24_576MHZ = 3,
|
||||
RT712_CLK_FREQ_22_5792MHZ = 4,
|
||||
};
|
||||
|
||||
|
||||
int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave);
|
||||
int rt712_sdca_init(struct device *dev, struct regmap *regmap,
|
||||
struct regmap *mbq_regmap, struct sdw_slave *slave);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int re
|
|||
case 0x0310100:
|
||||
case 0x2000000 ... 0x2000003:
|
||||
case 0x2000013:
|
||||
case 0x2000026:
|
||||
case 0x200002c:
|
||||
case 0x200003c:
|
||||
case 0x2000046:
|
||||
|
|
@ -142,6 +143,7 @@ static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int re
|
|||
case 0x200000d:
|
||||
case 0x2000019:
|
||||
case 0x2000020:
|
||||
case 0x2000026:
|
||||
case 0x200002c:
|
||||
case 0x2000030:
|
||||
case 0x2000046:
|
||||
|
|
@ -155,6 +157,7 @@ static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int re
|
|||
case 0x5810039:
|
||||
case 0x5b10018:
|
||||
case 0x5b10019:
|
||||
case 0x6100006:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1497,6 +1497,15 @@ int rt721_sdca_init(struct device *dev, struct regmap *regmap,
|
|||
&soc_sdca_dev_rt721, rt721_sdca_dai, ARRAY_SIZE(rt721_sdca_dai));
|
||||
}
|
||||
|
||||
static void rt721_sdca_reset(struct rt721_sdca_priv *rt721)
|
||||
{
|
||||
rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_VENDOR_REG,
|
||||
RT721_VD_HIDDEN_CTRL, RT721_HIDDEN_REG_SW_RESET,
|
||||
RT721_HIDDEN_REG_SW_RESET);
|
||||
rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
|
||||
RT721_HDA_LEGACY_RESET_CTL, 0x1, 0x1);
|
||||
}
|
||||
|
||||
int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev);
|
||||
|
|
@ -1530,9 +1539,17 @@ int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
|||
}
|
||||
|
||||
pm_runtime_get_noresume(&slave->dev);
|
||||
|
||||
if (!rt721->first_hw_init)
|
||||
rt721_sdca_reset(rt721);
|
||||
|
||||
rt721_sdca_dmic_preset(rt721);
|
||||
rt721_sdca_amp_preset(rt721);
|
||||
rt721_sdca_jack_preset(rt721);
|
||||
|
||||
if (rt721->hs_jack && (!rt721->first_hw_init))
|
||||
rt721_sdca_jack_init(rt721);
|
||||
|
||||
if (rt721->first_hw_init) {
|
||||
regcache_cache_bypass(rt721->regmap, false);
|
||||
regcache_mark_dirty(rt721->regmap);
|
||||
|
|
|
|||
|
|
@ -775,9 +775,12 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
|
|||
s++;
|
||||
}
|
||||
|
||||
adsp_dbg(dsp, "Try '%s'\n", fw->filename);
|
||||
ret = wm_adsp_firmware_request(&fw->firmware, fw->filename, cs_dsp->dev);
|
||||
if (ret < 0) {
|
||||
adsp_dbg(dsp, "Failed to request '%s': %d\n", fw->filename, ret);
|
||||
if (ret != -ENOENT)
|
||||
adsp_dbg(dsp, "Failed to request '%s': %d\n", fw->filename, ret);
|
||||
|
||||
kfree(fw->filename);
|
||||
fw->filename = NULL;
|
||||
if (ret != -ENOENT)
|
||||
|
|
|
|||
|
|
@ -360,6 +360,15 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = {
|
|||
.driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO |
|
||||
SOC_ES8336_HEADSET_MIC1)
|
||||
},
|
||||
{
|
||||
.callback = sof_es8336_quirk_cb,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "NDZ-WXX9"),
|
||||
},
|
||||
.driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO |
|
||||
SOC_ES8336_HEADSET_MIC1)
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <sound/soc-dai.h>
|
||||
#include <sound/soc_sdw_utils.h>
|
||||
|
||||
#define CS_AMP_CHANNELS_PER_AMP 4
|
||||
#define CS35L56_SPK_VOLUME_0DB 400 /* 0dB Max */
|
||||
|
||||
int asoc_sdw_cs35l56_volume_limit(struct snd_soc_card *card, const char *name_prefix)
|
||||
|
|
@ -64,51 +63,6 @@ int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai
|
|||
}
|
||||
EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, "SND_SOC_SDW_UTILS");
|
||||
|
||||
int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
|
||||
{
|
||||
const struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
||||
const struct snd_soc_dai_link_ch_map *ch_map;
|
||||
const struct snd_soc_dai_link_component *codec_dlc;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
u8 ch_slot[8] = {};
|
||||
unsigned int amps_per_bus, ch_per_amp, mask;
|
||||
int i, ret;
|
||||
|
||||
WARN_ON(dai_link->num_cpus > ARRAY_SIZE(ch_slot));
|
||||
|
||||
/*
|
||||
* CS35L56 has 4 TX channels. When the capture is aggregated the
|
||||
* same bus slots will be allocated to all the amps on a bus. Only
|
||||
* one amp on that bus can be transmitting in each slot so divide
|
||||
* the available 4 slots between all the amps on a bus.
|
||||
*/
|
||||
amps_per_bus = dai_link->num_codecs / dai_link->num_cpus;
|
||||
if ((amps_per_bus == 0) || (amps_per_bus > CS_AMP_CHANNELS_PER_AMP)) {
|
||||
dev_err(rtd->card->dev, "Illegal num_codecs:%u / num_cpus:%u\n",
|
||||
dai_link->num_codecs, dai_link->num_cpus);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch_per_amp = CS_AMP_CHANNELS_PER_AMP / amps_per_bus;
|
||||
|
||||
for_each_rtd_ch_maps(rtd, i, ch_map) {
|
||||
codec_dlc = snd_soc_link_to_codec(rtd->dai_link, i);
|
||||
codec_dai = snd_soc_find_dai(codec_dlc);
|
||||
mask = GENMASK(ch_per_amp - 1, 0) << ch_slot[ch_map->cpu];
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, mask, 4, 32);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->card->dev, "Failed to set TDM slot:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ch_slot[ch_map->cpu] += ch_per_amp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_feedback_rtd_init, "SND_SOC_SDW_UTILS");
|
||||
|
||||
int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
|
||||
struct snd_soc_dai_link *dai_links,
|
||||
struct asoc_sdw_codec_info *info,
|
||||
|
|
|
|||
|
|
@ -811,7 +811,6 @@ struct asoc_sdw_codec_info codec_info_list[] = {
|
|||
.dai_name = "cs35l56-sdw1c",
|
||||
.dai_type = SOC_SDW_DAI_TYPE_AMP,
|
||||
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
|
||||
.rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
|
||||
},
|
||||
},
|
||||
.dai_num = 2,
|
||||
|
|
@ -840,7 +839,6 @@ struct asoc_sdw_codec_info codec_info_list[] = {
|
|||
.dai_name = "cs35l56-sdw1c",
|
||||
.dai_type = SOC_SDW_DAI_TYPE_AMP,
|
||||
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
|
||||
.rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
|
||||
},
|
||||
},
|
||||
.dai_num = 2,
|
||||
|
|
@ -869,7 +867,6 @@ struct asoc_sdw_codec_info codec_info_list[] = {
|
|||
.dai_name = "cs35l56-sdw1c",
|
||||
.dai_type = SOC_SDW_DAI_TYPE_AMP,
|
||||
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
|
||||
.rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
|
||||
},
|
||||
},
|
||||
.dai_num = 2,
|
||||
|
|
@ -898,7 +895,6 @@ struct asoc_sdw_codec_info codec_info_list[] = {
|
|||
.dai_name = "cs35l56-sdw1c",
|
||||
.dai_type = SOC_SDW_DAI_TYPE_AMP,
|
||||
.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
|
||||
.rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
|
||||
},
|
||||
},
|
||||
.dai_num = 2,
|
||||
|
|
@ -1565,7 +1561,7 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
int ch = params_channels(params);
|
||||
unsigned int ch_mask;
|
||||
unsigned int cpu_ch_mask, codec_ch_mask;
|
||||
int num_codecs;
|
||||
int step;
|
||||
int i;
|
||||
|
|
@ -1575,8 +1571,9 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
/* Identical data will be sent to all codecs in playback */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ch_mask = GENMASK(ch - 1, 0);
|
||||
cpu_ch_mask = GENMASK(ch - 1, 0);
|
||||
step = 0;
|
||||
codec_ch_mask = 0;
|
||||
} else {
|
||||
num_codecs = rtd->dai_link->num_codecs;
|
||||
|
||||
|
|
@ -1586,17 +1583,24 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch_mask = GENMASK(ch / num_codecs - 1, 0);
|
||||
step = hweight_long(ch_mask);
|
||||
cpu_ch_mask = GENMASK(ch / num_codecs - 1, 0);
|
||||
step = hweight_long(cpu_ch_mask);
|
||||
codec_ch_mask = cpu_ch_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* The captured data will be combined from each cpu DAI if the dai
|
||||
* link has more than one codec DAIs. Set codec channel mask and
|
||||
* ASoC will set the corresponding channel numbers for each cpu dai.
|
||||
*
|
||||
* sdw_stream_add_slave() assigns different payload offsets to each
|
||||
* codec in a capture stream, so that the same channels on each
|
||||
* codec map to different channels on the CPU.
|
||||
*/
|
||||
for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
|
||||
ch_maps->ch_mask = ch_mask << (i * step);
|
||||
for_each_link_ch_maps(rtd->dai_link, i, ch_maps) {
|
||||
ch_maps->cpu_ch_mask = cpu_ch_mask << (i * step);
|
||||
ch_maps->codec_ch_mask = codec_ch_mask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1206,7 +1206,9 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
goto out;
|
||||
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
unsigned int tdm_mask = snd_soc_dai_tdm_mask_get(codec_dai, substream->stream);
|
||||
unsigned int ch_mask = snd_soc_dai_tdm_mask_get(codec_dai, substream->stream);
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
int j;
|
||||
|
||||
/*
|
||||
* Skip CODECs which don't support the current stream type,
|
||||
|
|
@ -1228,9 +1230,15 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
/* copy params for each codec */
|
||||
tmp_params = *params;
|
||||
|
||||
/* fixup params based on TDM slot masks */
|
||||
if (tdm_mask)
|
||||
soc_pcm_codec_params_fixup(&tmp_params, tdm_mask);
|
||||
/* fixup params based on TDM or ch_map masks */
|
||||
if (!ch_mask) {
|
||||
for_each_rtd_ch_maps(rtd, j, ch_maps)
|
||||
if (ch_maps->codec == i)
|
||||
ch_mask |= ch_maps->codec_ch_mask;
|
||||
}
|
||||
|
||||
if (ch_mask)
|
||||
soc_pcm_codec_params_fixup(&tmp_params, ch_mask);
|
||||
|
||||
ret = snd_soc_dai_hw_params(codec_dai, substream,
|
||||
&tmp_params);
|
||||
|
|
@ -1264,7 +1272,7 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
*/
|
||||
for_each_rtd_ch_maps(rtd, j, ch_maps)
|
||||
if (ch_maps->cpu == i)
|
||||
ch_mask |= ch_maps->ch_mask;
|
||||
ch_mask |= ch_maps->cpu_ch_mask;
|
||||
|
||||
/* fixup cpu channel number */
|
||||
if (ch_mask)
|
||||
|
|
|
|||
|
|
@ -147,8 +147,8 @@ enum msp_direction {
|
|||
#define RCKPOL_MASK BIT(0)
|
||||
#define TCKPOL_MASK BIT(0)
|
||||
#define SPICKM_MASK (BIT(1) | BIT(0))
|
||||
#define MSP_RX_CLKPOL_BIT(n) ((n & RCKPOL_MASK) << RCKPOL_SHIFT)
|
||||
#define MSP_TX_CLKPOL_BIT(n) ((n & TCKPOL_MASK) << TCKPOL_SHIFT)
|
||||
#define MSP_RX_CLKPOL_BIT(n) (((n) & RCKPOL_MASK) << RCKPOL_SHIFT)
|
||||
#define MSP_TX_CLKPOL_BIT(n) (((n) & TCKPOL_MASK) << TCKPOL_SHIFT)
|
||||
|
||||
#define P1ELEN_SHIFT 0
|
||||
#define P1FLEN_SHIFT 3
|
||||
|
|
|
|||
|
|
@ -335,11 +335,19 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
|
|||
|
||||
/* setup out urb structure */
|
||||
for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
|
||||
unsigned int frames = 0;
|
||||
|
||||
isoc_out = &out_urb->instance->iso_frame_desc[i];
|
||||
isoc_in = &in_urb->instance->iso_frame_desc[i];
|
||||
if (isoc_in->actual_length > 4)
|
||||
frames = (isoc_in->actual_length - 4)
|
||||
/ (rt->in_n_analog << 2);
|
||||
frames = min_t(unsigned int, frames,
|
||||
(rt->out_packet_size - 4)
|
||||
/ (rt->out_n_analog << 2));
|
||||
|
||||
isoc_out->offset = total_length;
|
||||
isoc_out->length = (isoc_in->actual_length - 4) / (rt->in_n_analog << 2)
|
||||
* (rt->out_n_analog << 2) + 4;
|
||||
isoc_out->length = frames * (rt->out_n_analog << 2) + 4;
|
||||
isoc_out->status = 0;
|
||||
total_length += isoc_out->length;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ struct bcd2000 {
|
|||
struct usb_interface *intf;
|
||||
int card_index;
|
||||
|
||||
spinlock_t midi_lock;
|
||||
int midi_out_active;
|
||||
struct snd_rawmidi *rmidi;
|
||||
struct snd_rawmidi_substream *midi_receive_substream;
|
||||
|
|
@ -90,6 +91,8 @@ static void bcd2000_midi_input_trigger(struct snd_rawmidi_substream *substream,
|
|||
int up)
|
||||
{
|
||||
struct bcd2000 *bcd2k = substream->rmidi->private_data;
|
||||
|
||||
guard(spinlock_irqsave)(&bcd2k->midi_lock);
|
||||
bcd2k->midi_receive_substream = up ? substream : NULL;
|
||||
}
|
||||
|
||||
|
|
@ -195,6 +198,8 @@ static void bcd2000_midi_output_trigger(struct snd_rawmidi_substream *substream,
|
|||
{
|
||||
struct bcd2000 *bcd2k = substream->rmidi->private_data;
|
||||
|
||||
guard(spinlock_irqsave)(&bcd2k->midi_lock);
|
||||
|
||||
if (up) {
|
||||
bcd2k->midi_out_substream = substream;
|
||||
/* check if there is data userspace wants to send */
|
||||
|
|
@ -219,6 +224,7 @@ static void bcd2000_output_complete(struct urb *urb)
|
|||
return;
|
||||
|
||||
/* check if there is more data userspace wants to send */
|
||||
guard(spinlock_irqsave)(&bcd2k->midi_lock);
|
||||
bcd2000_midi_send(bcd2k);
|
||||
}
|
||||
|
||||
|
|
@ -234,6 +240,8 @@ static void bcd2000_input_complete(struct urb *urb)
|
|||
if (!bcd2k || urb->status == -ESHUTDOWN)
|
||||
return;
|
||||
|
||||
guard(spinlock_irqsave)(&bcd2k->midi_lock);
|
||||
|
||||
if (urb->actual_length > 0)
|
||||
bcd2000_midi_handle_input(bcd2k, urb->transfer_buffer,
|
||||
urb->actual_length);
|
||||
|
|
@ -348,16 +356,26 @@ static int bcd2000_init_midi(struct bcd2000 *bcd2k)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bcd2000_midi_free(struct bcd2000 *bcd2k,
|
||||
struct urb **urb_p)
|
||||
{
|
||||
struct urb *urb = *urb_p;
|
||||
|
||||
if (!urb)
|
||||
return;
|
||||
|
||||
usb_poison_urb(urb);
|
||||
scoped_guard(spinlock_irq, &bcd2k->midi_lock)
|
||||
*urb_p = NULL;
|
||||
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
|
||||
static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k,
|
||||
struct usb_interface *interface)
|
||||
{
|
||||
usb_poison_urb(bcd2k->midi_out_urb);
|
||||
usb_poison_urb(bcd2k->midi_in_urb);
|
||||
|
||||
usb_free_urb(bcd2k->midi_out_urb);
|
||||
usb_free_urb(bcd2k->midi_in_urb);
|
||||
bcd2k->midi_out_urb = NULL;
|
||||
bcd2k->midi_in_urb = NULL;
|
||||
bcd2000_midi_free(bcd2k, &bcd2k->midi_out_urb);
|
||||
bcd2000_midi_free(bcd2k, &bcd2k->midi_in_urb);
|
||||
|
||||
if (bcd2k->intf) {
|
||||
usb_set_intfdata(bcd2k->intf, NULL);
|
||||
|
|
@ -393,6 +411,7 @@ static int bcd2000_probe(struct usb_interface *interface,
|
|||
bcd2k->card = card;
|
||||
bcd2k->card_index = card_index;
|
||||
bcd2k->intf = interface;
|
||||
spin_lock_init(&bcd2k->midi_lock);
|
||||
|
||||
snd_card_set_dev(card, &interface->dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ struct snd_usb_endpoint {
|
|||
unsigned int phase; /* phase accumulator */
|
||||
unsigned int maxpacksize; /* max packet size in bytes */
|
||||
unsigned int maxframesize; /* max packet size in frames */
|
||||
unsigned int max_urb_packs; /* packets allocated per data URB */
|
||||
unsigned int max_urb_frames; /* max URB size in frames */
|
||||
unsigned int curpacksize; /* current packet size in bytes (for capture) */
|
||||
unsigned int curframesize; /* current packet size in frames (for capture) */
|
||||
|
|
|
|||
|
|
@ -449,7 +449,9 @@ static void push_back_to_ready_list(struct snd_usb_endpoint *ep,
|
|||
struct snd_urb_ctx *ctx)
|
||||
{
|
||||
guard(spinlock_irqsave)(&ep->lock);
|
||||
list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
|
||||
/* ctx may still be linked: a stale completion racing a stop/restart. */
|
||||
if (list_empty(&ctx->ready_list))
|
||||
list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -492,9 +494,10 @@ int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
|
|||
|
||||
/* copy over the length information */
|
||||
if (implicit_fb) {
|
||||
ctx->packets = packet->packets;
|
||||
ctx->packets = min_t(int, packet->packets,
|
||||
ep->max_urb_packs);
|
||||
memcpy(ctx->packet_size, packet->packet_size,
|
||||
packet->packets * sizeof(packet->packet_size[0]));
|
||||
ctx->packets * sizeof(packet->packet_size[0]));
|
||||
}
|
||||
|
||||
/* call the data handler to fill in playback data */
|
||||
|
|
@ -1036,6 +1039,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
|
|||
*/
|
||||
static int stop_urbs(struct snd_usb_endpoint *ep, bool force, bool keep_pending)
|
||||
{
|
||||
struct snd_urb_ctx *ctx, *n;
|
||||
unsigned int i;
|
||||
|
||||
if (!force && atomic_read(&ep->running))
|
||||
|
|
@ -1045,7 +1049,9 @@ static int stop_urbs(struct snd_usb_endpoint *ep, bool force, bool keep_pending)
|
|||
return 0;
|
||||
|
||||
scoped_guard(spinlock_irqsave, &ep->lock) {
|
||||
INIT_LIST_HEAD(&ep->ready_playback_urbs);
|
||||
/* Unlink each ctx; INIT_LIST_HEAD() alone would leave them looking linked. */
|
||||
list_for_each_entry_safe(ctx, n, &ep->ready_playback_urbs, ready_list)
|
||||
list_del_init(&ctx->ready_list);
|
||||
ep->next_packet_head = 0;
|
||||
ep->next_packet_queued = 0;
|
||||
}
|
||||
|
|
@ -1242,15 +1248,16 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
|
|||
ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods);
|
||||
}
|
||||
|
||||
if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
|
||||
urb_packs++; /* for transfer delimiter */
|
||||
ep->max_urb_packs = urb_packs;
|
||||
|
||||
/* allocate and initialize data urbs */
|
||||
for (i = 0; i < ep->nurbs; i++) {
|
||||
struct snd_urb_ctx *u = &ep->urb[i];
|
||||
u->index = i;
|
||||
u->ep = ep;
|
||||
u->packets = urb_packs;
|
||||
|
||||
if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
|
||||
u->packets++; /* for transfer delimiter */
|
||||
u->buffer_size = maxsize * u->packets;
|
||||
u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
|
||||
if (!u->urb)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ 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(0x1397, 0x0004, 0x01, 1), /* Behringer FCA1616 */
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -531,6 +531,15 @@ static const struct usbmix_name_map audient_id24_map[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* The GC553Pro returns no data for GET_CUR on its advertised mute control.
|
||||
* SET_CUR succeeds but does not mute capture, so skip the control entirely.
|
||||
*/
|
||||
static const struct usbmix_name_map avermedia_gc553pro_map[] = {
|
||||
{ 3, NULL, UAC_FU_MUTE },
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Control map entries
|
||||
*/
|
||||
|
|
@ -577,6 +586,10 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
|
|||
.id = USB_ID(0x0763, 0x2031),
|
||||
.selector_map = c400_selectors,
|
||||
},
|
||||
{
|
||||
.id = USB_ID(0x07ca, 0x1553),
|
||||
.map = avermedia_gc553pro_map,
|
||||
},
|
||||
{
|
||||
.id = USB_ID(0x08bb, 0x2702),
|
||||
.map = linex_map,
|
||||
|
|
|
|||
|
|
@ -354,8 +354,8 @@ static void virtsnd_remove(struct virtio_device *vdev)
|
|||
if (snd->card)
|
||||
snd_card_free(snd->card);
|
||||
|
||||
vdev->config->del_vqs(vdev);
|
||||
virtio_reset_device(vdev);
|
||||
vdev->config->del_vqs(vdev);
|
||||
|
||||
for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) {
|
||||
struct virtio_pcm_substream *vss = &snd->substreams[i];
|
||||
|
|
@ -383,8 +383,8 @@ static int virtsnd_freeze(struct virtio_device *vdev)
|
|||
virtsnd_disable_event_vq(snd);
|
||||
virtsnd_ctl_msg_cancel_all(snd);
|
||||
|
||||
vdev->config->del_vqs(vdev);
|
||||
virtio_reset_device(vdev);
|
||||
vdev->config->del_vqs(vdev);
|
||||
|
||||
for (i = 0; i < snd->nsubstreams; ++i)
|
||||
cancel_work_sync(&snd->substreams[i].elapsed_period);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user