mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
sound fixes for 7.2-rc1
A collection of small bug fixes accumulated over the last week.
Most are device-specific fixes while there are a few core fixes as
well.
Here are the highlights:
ALSA Core:
- A fix for an uninitialised heap leak in ALSA sequencer core
- A fix for error handling/resource leak in compress-offload API
USB-audio:
- A teardown-ordering fix in USB MIDI 2.0 to prevent use-after-free
- Bounds and length checks for packet data in Native Instruments caiaq
/ Traktor Kontrol input parsers
- Avoidance of expensive kobject path lookups in DualSense controller
matches
- Robustness/memory leak fixes for Qualcomm USB offload driver
- Focusrite Control Protocol (FCP) NULL-pointer dereference fix and a
new device quirk (ISA C8X)
- Device-specific quirks for Yamaha CDS3000 and SC13A
HD-Audio:
- A bunch of quirks and mute/mic-mute LED fixups for various laptops
(Acer, Clevo, Lenovo, HP)
ASoC & SoundWire:
- Avoid failing card registration if the device_link creation fails
- A workaround for SoundWire randconfig build failures by making
helper functions static inline
- Corrected MCLK reference validation for CS530x codecs
- Clean up of untested, problematic guard() macro replacements in
Rockchip SAI driver
- Fix for eDMA maxburst misalignment with channel count in Freescale
ASRC
- Miscellaneous hardware-specific fixes (qcom, rt5650, tlv320aic3x,
tas2781/3)
Others:
- Bounds and length checks for packet data in Apple iSight
-----BEGIN PGP SIGNATURE-----
iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmo+mnEOHHRpd2FpQHN1
c2UuZGUACgkQLtJE4w1nLE92VQ/+ItB+EBTpiba9YQYBrzUzq2R3BiNR/EZjU33G
UMut1zQYQJ53eMmN8yMYc0GMbtk9dCFUAtRGPyQCNEHS6uFw51t3A4wlcXvIu1Sx
kQqtyaDQ2jp98J72ms4WtN42o29MjcFmhBBcTb3Kw12T+OVTYYneccsGPsHqCXsZ
RBjJFpDr0Xo1TfnOy9nt/UNUUIMJEtZ1gGlYBqzQgNoLeYH3+dRKBoX2qVAvhIcL
FJnSGiDgyLpt6uucPAAeIzGHawQXW4ej7XY4S8cLscsB7mY7VEtPFIMx4bN1QYIO
Ioj2P9KLG4/KYOV8oRQ6kzYTwtO7St9Kd/+xpU5Divjxf6TqRGlv/hlQCTBBZPLq
RVUsEiE36UlSuipyruK34KubtVkbqUgUjBiPygFr6cLKb6fc6sjWrK5P8KUtN860
8q1froUK43gwdVcdmLgrMbFCspE+KUp3xzSDh9tcVq6Ffw+otuuC0cJeVG4j+GOf
xntsUqlAX6XSudTvTfa1pqvQmynBqvBy4wW9yrRfvEJ6eJqRlT17Sbs6AzpeLE4k
dpeHlHwHtk5kfEGkYarJ3CEDw1GfHdLfQ6B6lBmCKq6DwnTZbq+lX5C3wB+OXVom
xn5enCuaygVnXs6RF6DP3KlSvLoCJ09BEehkERxVg1uyVnGkioXXwNU8vdjkj2Qd
srITNeo=
=hJ5w
-----END PGP SIGNATURE-----
Merge tag 'sound-fix-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai:
"A collection of small bug fixes accumulated over the last week.
Most are device-specific fixes while there are a few core fixes as
well.
Here are the highlights:
ALSA Core:
- A fix for an uninitialised heap leak in ALSA sequencer core
- A fix for error handling/resource leak in compress-offload API
USB-audio:
- A teardown-ordering fix in USB MIDI 2.0 to prevent use-after-free
- Bounds and length checks for packet data in Native Instruments
caiaq / Traktor Kontrol input parsers
- Avoidance of expensive kobject path lookups in DualSense controller
matches
- Robustness/memory leak fixes for Qualcomm USB offload driver
- Focusrite Control Protocol (FCP) NULL-pointer dereference fix and a
new device quirk (ISA C8X)
- Device-specific quirks for Yamaha CDS3000 and SC13A
HD-Audio:
- A bunch of quirks and mute/mic-mute LED fixups for various laptops
(Acer, Clevo, Lenovo, HP)
ASoC & SoundWire:
- Avoid failing card registration if the device_link creation fails
- A workaround for SoundWire randconfig build failures by making
helper functions static inline
- Corrected MCLK reference validation for CS530x codecs
- Clean up of untested, problematic guard() macro replacements in
Rockchip SAI driver
- Fix for eDMA maxburst misalignment with channel count in Freescale
ASRC
- Miscellaneous hardware-specific fixes (qcom, rt5650, tlv320aic3x,
tas2781/3)
Others:
- Bounds and length checks for packet data in Apple iSight"
* tag 'sound-fix-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (46 commits)
ALSA: FCP: Fix NULL pointer dereference in interface lookup
ALSA: hda/realtek: Update Acer Nitro ANV15-41 quirk to enable mute LED
ASoC: fsl_asrc_dma: fix eDMA maxburst misalignment with channel count
ASoC: codecs: pcm512x: only print info once on no sclk
ASoC: tas2781: Update default register address to TAS2563
ALSA: firewire: isight: bound the sample count to the packet payload
ALSA: usb-audio: qcom: Free QMI handle
ALSA: hda: Add Lenovo Legion 7i 16IAX7 17AA3874 quirk
ALSA: usb-audio: avoid kobject path lookup in DualSense match
ALSA: hda/realtek: Add quirk for Acer Nitro ANV15-41
ASoC: soc-core: Don't fail if device_link could not be created
ASoC: rockchip: rockchip_sai: #include <linux/platform_device.h> explicitly
ALSA: seq: Fix uninitialised heap leak in snd_seq_event_dup()
ASoC: rt5575: Use __le32 for SPI burst write address
ASoC: tas2783: Update loaded firmware names to linux-firmware 20260519
ASoC: SDCA: Validate written enum value in ge_put_enum_double()
ASoC: realtek: Add back local call to sdw_show_ping_status()
ASoC: ti: Add back local call to sdw_show_ping_status()
ASoC: max98373: Add back local call to sdw_show_ping_status()
ASoC: es9356: Add back local call to sdw_show_ping_status()
...
This commit is contained in:
commit
14923571e7
|
|
@ -1372,34 +1372,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *slave)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(sdw_slave_get_current_bank);
|
||||
|
||||
/**
|
||||
* sdw_slave_wait_for_init - Wait for device initialisation
|
||||
* @slave: Pointer to the SoundWire peripheral.
|
||||
* @timeout_ms: Timeout in milliseconds.
|
||||
*
|
||||
* Wait for a peripheral device to enumerate and be initialised by the
|
||||
* SoundWire core.
|
||||
*
|
||||
* Return: Zero on success, and a negative error code on failure.
|
||||
*/
|
||||
int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
|
||||
{
|
||||
unsigned long time;
|
||||
|
||||
time = wait_for_completion_timeout(&slave->initialization_complete,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
if (!time) {
|
||||
dev_err(&slave->dev, "Initialization not complete\n");
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
slave->unattach_request = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdw_slave_wait_for_init);
|
||||
|
||||
static int sdw_slave_set_frequency(struct sdw_slave *slave)
|
||||
{
|
||||
int scale_index;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/idr.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/lockdep_types.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mutex.h>
|
||||
|
|
@ -1093,8 +1094,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *sdev);
|
|||
|
||||
int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base);
|
||||
|
||||
int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms);
|
||||
|
||||
/* messaging and data APIs */
|
||||
int sdw_read(struct sdw_slave *slave, u32 addr);
|
||||
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
|
||||
|
|
@ -1138,12 +1137,6 @@ static inline int sdw_slave_get_current_bank(struct sdw_slave *sdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
|
||||
{
|
||||
WARN_ONCE(1, "SoundWire API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* messaging and data APIs */
|
||||
static inline int sdw_read(struct sdw_slave *slave, u32 addr)
|
||||
{
|
||||
|
|
@ -1207,4 +1200,33 @@ static inline int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u
|
|||
|
||||
#endif /* CONFIG_SOUNDWIRE */
|
||||
|
||||
/**
|
||||
* sdw_slave_wait_for_init - Wait for device initialisation
|
||||
* @slave: Pointer to the SoundWire peripheral.
|
||||
* @timeout_ms: Timeout in milliseconds.
|
||||
*
|
||||
* Wait for a peripheral device to enumerate and be initialised by the
|
||||
* SoundWire core.
|
||||
*
|
||||
* Return: Zero on success, and a negative error code on failure.
|
||||
*/
|
||||
static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
|
||||
{
|
||||
unsigned long time;
|
||||
|
||||
if (!slave)
|
||||
return 0;
|
||||
|
||||
time = wait_for_completion_timeout(&slave->initialization_complete,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
if (!time) {
|
||||
dev_err(&slave->dev, "Initialization not complete\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
slave->unattach_request = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __SOUNDWIRE_H */
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <sound/soc.h>
|
||||
|
||||
struct device_link;
|
||||
|
||||
/*
|
||||
* Component probe and remove ordering levels for components with runtime
|
||||
* dependencies.
|
||||
|
|
@ -216,6 +218,8 @@ struct snd_soc_component {
|
|||
struct list_head card_aux_list; /* for auxiliary bound components */
|
||||
struct list_head card_list;
|
||||
|
||||
struct device_link *card_device_link;
|
||||
|
||||
const struct snd_soc_component_driver *driver;
|
||||
|
||||
struct list_head dai_list;
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@
|
|||
#define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e)
|
||||
|
||||
/* XM_340 */
|
||||
#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x63, 0x3c)
|
||||
#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x02, 0x4c)
|
||||
/* XM_341 */
|
||||
#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x63, 0x38)
|
||||
#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x02, 0x64)
|
||||
|
||||
/* Volume control */
|
||||
#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0c)
|
||||
|
|
|
|||
|
|
@ -1083,15 +1083,18 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_
|
|||
file descriptors are allocated before fd_install() */
|
||||
if (!task->input || !task->input->file || !task->output || !task->output->file) {
|
||||
retval = -EINVAL;
|
||||
goto cleanup;
|
||||
goto free_driver_task;
|
||||
}
|
||||
fd_i = get_unused_fd_flags(O_WRONLY|O_CLOEXEC);
|
||||
if (fd_i < 0)
|
||||
goto cleanup;
|
||||
if (fd_i < 0) {
|
||||
retval = fd_i;
|
||||
goto free_driver_task;
|
||||
}
|
||||
fd_o = get_unused_fd_flags(O_RDONLY|O_CLOEXEC);
|
||||
if (fd_o < 0) {
|
||||
retval = fd_o;
|
||||
put_unused_fd(fd_i);
|
||||
goto cleanup;
|
||||
goto free_driver_task;
|
||||
}
|
||||
/* keep dmabuf reference until freed with task free ioctl */
|
||||
get_dma_buf(task->input);
|
||||
|
|
@ -1103,6 +1106,8 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_
|
|||
list_add_tail(&task->list, &stream->runtime->tasks);
|
||||
stream->runtime->total_tasks++;
|
||||
return 0;
|
||||
free_driver_task:
|
||||
stream->ops->task_free(stream, task);
|
||||
cleanup:
|
||||
snd_compr_task_free(task);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
const unsigned char *id, unsigned int len)
|
||||
{
|
||||
*(__u32 *)params->sync = cpu_to_le32(substream->pcm->card->number);
|
||||
*(__le32 *)params->sync = cpu_to_le32(substream->pcm->card->number);
|
||||
len = min(12, len);
|
||||
memcpy(params->sync + 4, id, len);
|
||||
memset(params->sync + 4 + len, 0, 12 - len);
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
|
|||
size = snd_seq_event_packet_size(event);
|
||||
memcpy(&cell->ump, event, size);
|
||||
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
|
||||
if (size < sizeof(cell->event))
|
||||
if (size < sizeof(cell->ump))
|
||||
cell->ump.raw.extra = 0;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -179,7 +179,8 @@ static void isight_packet(struct fw_iso_context *context, u32 cycle,
|
|||
if (likely(length >= 16 &&
|
||||
payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
|
||||
count = be32_to_cpu(payload->sample_count);
|
||||
if (likely(count <= (length - 16) / 4)) {
|
||||
if (likely(count <= (length - 16) / 4 &&
|
||||
count <= MAX_FRAMES_PER_PACKET)) {
|
||||
total = be32_to_cpu(payload->sample_total);
|
||||
if (unlikely(total != isight->total_samples)) {
|
||||
if (!isight->first_packet)
|
||||
|
|
|
|||
|
|
@ -291,6 +291,7 @@ enum {
|
|||
CXT_FIXUP_HEADSET_MIC,
|
||||
CXT_FIXUP_HP_MIC_NO_PRESENCE,
|
||||
CXT_PINCFG_SWS_JS201D,
|
||||
CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10,
|
||||
CXT_PINCFG_TOP_SPEAKER,
|
||||
CXT_FIXUP_HP_A_U,
|
||||
CXT_FIXUP_ACER_SWIFT_HP,
|
||||
|
|
@ -826,6 +827,12 @@ static const struct hda_pintbl cxt_pincfg_lemote[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
/* Lenovo IdeaPad Slim 5 16AKP10 with SN6140 */
|
||||
static const struct hda_pintbl cxt_pincfg_lenovo_ideapad_slim5_16akp10[] = {
|
||||
{ 0x1a, 0x95a60130 }, /* Internal mic, fixed/always-connected */
|
||||
{}
|
||||
};
|
||||
|
||||
/* SuoWoSi/South-holding JS201D with sn6140 */
|
||||
static const struct hda_pintbl cxt_pincfg_sws_js201d[] = {
|
||||
{ 0x16, 0x03211040 }, /* hp out */
|
||||
|
|
@ -1006,6 +1013,10 @@ static const struct hda_fixup cxt_fixups[] = {
|
|||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = cxt_pincfg_sws_js201d,
|
||||
},
|
||||
[CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = cxt_pincfg_lenovo_ideapad_slim5_16akp10,
|
||||
},
|
||||
[CXT_PINCFG_TOP_SPEAKER] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
|
|
@ -1114,6 +1125,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
|
|||
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x38b6, "Lenovo IdeaPad Slim 5 16AKP10", CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
|
||||
|
|
|
|||
|
|
@ -6807,11 +6807,13 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC287_FIXUP_ACER_MICMUTE_LED),
|
||||
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x161f, "Acer S40-54", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
|
||||
SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
|
||||
SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED),
|
||||
SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED),
|
||||
SND_PCI_QUIRK(0x1025, 0x1758, "Acer Nitro ANV15-41", ALC245_FIXUP_ACER_MICMUTE_LED),
|
||||
SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
|
||||
|
|
@ -6986,6 +6988,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
|
||||
SND_PCI_QUIRK(0x103c, 0x8548, "HP EliteBook x360 830 G6", ALC285_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x854a, "HP EliteBook 830 G6", ALC285_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x854d, "HP EliteBook 840 G6", ALC285_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x856a, "HP Pavilion 15-cs1xxx", ALC295_FIXUP_HP_PAVILION_MUTE_LED_1B),
|
||||
SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11),
|
||||
SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360),
|
||||
|
|
@ -7326,6 +7329,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f2d, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f2e, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f37, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f38, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f39, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f3a, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f3c, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f3d, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f40, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
|
||||
|
|
@ -7597,6 +7604,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1558, 0x51b3, "Clevo NS70AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1558, 0x5700, "Clevo X560WN[RST]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1558, 0x6480, "Clevo V6xxAW", ALC245_FIXUP_CLEVO_NOISY_MIC),
|
||||
SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
|
||||
|
|
@ -7753,11 +7761,13 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
|
||||
HDA_CODEC_QUIRK(0x17aa, 0x386a, "Lenovo Yoga 7 16IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
|
||||
HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1),
|
||||
HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */
|
||||
SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3874, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C),
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ static const struct cs35l41_config cs35l41_config_table[] = {
|
|||
{ "17AA3866", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
|
||||
{ "17AA386E", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
|
||||
{ "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
|
||||
{ "17AA3874", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
|
||||
{ "17AA3877", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
|
||||
{ "17AA3878", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
|
||||
{ "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
|
||||
|
|
@ -554,6 +555,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
|
|||
{ "CSC3551", "17AA3866", generic_dsd_config },
|
||||
{ "CSC3551", "17AA386E", generic_dsd_config },
|
||||
{ "CSC3551", "17AA386F", generic_dsd_config },
|
||||
{ "CSC3551", "17AA3874", generic_dsd_config },
|
||||
{ "CSC3551", "17AA3877", generic_dsd_config },
|
||||
{ "CSC3551", "17AA3878", generic_dsd_config },
|
||||
{ "CSC3551", "17AA38A9", generic_dsd_config },
|
||||
|
|
|
|||
|
|
@ -1181,19 +1181,17 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
|
|||
runtime->private_free = snd_emu10k1_pcm_free_substream;
|
||||
runtime->hw = snd_emu10k1_playback;
|
||||
err = snd_emu10k1_playback_set_constraints(runtime);
|
||||
if (err < 0) {
|
||||
kfree(epcm);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto free_epcm;
|
||||
|
||||
if (emu->card_capabilities->emu_model)
|
||||
sample_rate = emu->emu1010.word_clock;
|
||||
else
|
||||
sample_rate = 48000;
|
||||
err = snd_pcm_hw_rule_noresample(runtime, sample_rate);
|
||||
if (err < 0) {
|
||||
kfree(epcm);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto free_epcm;
|
||||
|
||||
mix = &emu->pcm_mixer[substream->number];
|
||||
for (i = 0; i < 8; i++)
|
||||
mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i;
|
||||
|
|
@ -1204,6 +1202,10 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
|
|||
mix->epcm = epcm;
|
||||
snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1);
|
||||
return 0;
|
||||
|
||||
free_epcm:
|
||||
kfree(epcm);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_emu10k1_playback_close(struct snd_pcm_substream *substream)
|
||||
|
|
|
|||
|
|
@ -564,10 +564,9 @@ static int snd_aica_probe(struct platform_device *devptr)
|
|||
return -ENOMEM;
|
||||
err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER,
|
||||
THIS_MODULE, 0, &dreamcastcard->card);
|
||||
if (unlikely(err < 0)) {
|
||||
kfree(dreamcastcard);
|
||||
return err;
|
||||
}
|
||||
if (unlikely(err < 0))
|
||||
goto free_card;
|
||||
|
||||
strscpy(dreamcastcard->card->driver, "snd_aica");
|
||||
strscpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
|
||||
strscpy(dreamcastcard->card->longname,
|
||||
|
|
@ -593,6 +592,7 @@ static int snd_aica_probe(struct platform_device *devptr)
|
|||
return 0;
|
||||
freedreamcast:
|
||||
snd_card_free(dreamcastcard->card);
|
||||
free_card:
|
||||
kfree(dreamcastcard);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1093,6 +1093,29 @@ static int cs530x_component_probe(struct snd_soc_component *component)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool cs530x_mclk_freq_is_valid(struct cs530x_priv *cs530x,
|
||||
unsigned int freq)
|
||||
{
|
||||
/*
|
||||
* All these chips support 48 kHz- and 44.1 kHz-related sample rates,
|
||||
* but they differ in what MCLK frequency is required for achieving
|
||||
* the sample rate.
|
||||
*/
|
||||
switch (cs530x->devtype) {
|
||||
case CS4282:
|
||||
case CS4302:
|
||||
case CS4304:
|
||||
case CS4308:
|
||||
return freq == 49152000 || freq == 45158400;
|
||||
case CS5302:
|
||||
case CS5304:
|
||||
case CS5308:
|
||||
return freq == 24576000 || freq == 22579200;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
|
||||
int source, unsigned int freq, int dir)
|
||||
{
|
||||
|
|
@ -1101,11 +1124,7 @@ static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
|
|||
|
||||
switch (source) {
|
||||
case CS530X_SYSCLK_SRC_MCLK:
|
||||
switch (freq) {
|
||||
case CS530X_SYSCLK_REF_45_1MHZ:
|
||||
case CS530X_SYSCLK_REF_49_1MHZ:
|
||||
break;
|
||||
default:
|
||||
if (!cs530x_mclk_freq_is_valid(cs530x, freq)) {
|
||||
dev_err(component->dev, "Invalid MCLK source rate %d\n", freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,12 +200,6 @@
|
|||
/* IN_VOL_CTL5 and OUT_VOL_CTL5 */
|
||||
#define CS530X_INOUT_VU BIT(0)
|
||||
|
||||
/* MCLK Reference Source Frequency */
|
||||
/* 41KHz related */
|
||||
#define CS530X_SYSCLK_REF_45_1MHZ 45158400
|
||||
/* 48KHz related */
|
||||
#define CS530X_SYSCLK_REF_49_1MHZ 49152000
|
||||
|
||||
/* System Clock Source */
|
||||
#define CS530X_SYSCLK_SRC_MCLK 0
|
||||
#define CS530X_SYSCLK_SRC_PLL 1
|
||||
|
|
|
|||
|
|
@ -1111,8 +1111,10 @@ static int es9356_sdca_dev_resume(struct device *dev)
|
|||
es9356->disable_irq = false;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, es9356_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(es9356->regmap, false);
|
||||
regcache_sync(es9356->regmap);
|
||||
|
|
|
|||
|
|
@ -272,8 +272,10 @@ static int max98373_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, MAX98373_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(max98373->regmap, false);
|
||||
regcache_sync(max98373->regmap);
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
|
|||
struct regmap *regmap = pcm512x->regmap;
|
||||
|
||||
if (IS_ERR(pcm512x->sclk)) {
|
||||
dev_info(dev, "No SCLK, using BCLK: %ld\n",
|
||||
dev_info_once(dev, "No SCLK, using BCLK: %ld\n",
|
||||
PTR_ERR(pcm512x->sclk));
|
||||
|
||||
/* Disable reporting of missing SCLK as an error */
|
||||
|
|
|
|||
|
|
@ -779,8 +779,10 @@ static int rt1017_sdca_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT1017_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt1017->regmap, false);
|
||||
regcache_sync(rt1017->regmap);
|
||||
|
|
|
|||
|
|
@ -774,8 +774,10 @@ static int rt1308_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT1308_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt1308->regmap, false);
|
||||
regcache_sync_region(rt1308->regmap, 0xc000, 0xcfff);
|
||||
|
|
|
|||
|
|
@ -751,8 +751,10 @@ static int rt1316_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT1316_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt1316->regmap, false);
|
||||
regcache_sync(rt1316->regmap);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
struct rt5575_spi_burst_write {
|
||||
u8 cmd;
|
||||
u32 addr;
|
||||
__le32 addr;
|
||||
u8 data[RT5575_SPI_BUF_LEN];
|
||||
u8 dummy;
|
||||
} __packed;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ static const struct reg_sequence rt5650_init_list[] = {
|
|||
{RT5645_PWR_ANLG1, 0x02},
|
||||
{RT5645_IL_CMD3, 0x6728},
|
||||
{RT5645_PR_BASE + 0x3a, 0x0000},
|
||||
{RT5645_CLSD_OUT_CTRL1, 0x4059},
|
||||
{RT5645_GEN_CTRL3, 0x0200},
|
||||
};
|
||||
|
||||
static const struct reg_default rt5645_reg[] = {
|
||||
|
|
@ -1855,13 +1857,9 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
|
|||
RT5645_PWR_CLS_D_L,
|
||||
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
|
||||
RT5645_PWR_CLS_D_L);
|
||||
snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
|
||||
RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
|
||||
RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
|
||||
snd_soc_component_write(component, RT5645_EQ_CTRL2, 0);
|
||||
snd_soc_component_update_bits(component, RT5645_PWR_DIG1,
|
||||
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@
|
|||
#define RT5645_A_JD_CTRL1 0x94
|
||||
#define RT5645_VAD_CTRL4 0x9d
|
||||
#define RT5645_CLSD_OUT_CTRL 0xa0
|
||||
#define RT5645_CLSD_OUT_CTRL1 0xa1
|
||||
/* Function - Digital */
|
||||
#define RT5645_ADC_EQ_CTRL1 0xae
|
||||
#define RT5645_ADC_EQ_CTRL2 0xaf
|
||||
|
|
|
|||
|
|
@ -769,8 +769,10 @@ static int rt5682_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt5682->sdw_regmap, false);
|
||||
regcache_cache_only(rt5682->regmap, false);
|
||||
|
|
|
|||
|
|
@ -528,8 +528,10 @@ static int rt700_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT700_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt700->regmap, false);
|
||||
regcache_sync_region(rt700->regmap, 0x3000, 0x8fff);
|
||||
|
|
|
|||
|
|
@ -454,8 +454,10 @@ static int rt711_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt711->regmap, false);
|
||||
regcache_sync(rt711->regmap);
|
||||
|
|
|
|||
|
|
@ -911,8 +911,10 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt712->regmap, false);
|
||||
regcache_sync(rt712->regmap);
|
||||
|
|
|
|||
|
|
@ -467,8 +467,10 @@ static int rt712_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt712->regmap, false);
|
||||
regcache_sync(rt712->regmap);
|
||||
|
|
|
|||
|
|
@ -230,8 +230,10 @@ static int rt715_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt715->regmap, false);
|
||||
regcache_sync_region(rt715->regmap,
|
||||
|
|
|
|||
|
|
@ -507,8 +507,10 @@ static int rt715_dev_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt715->regmap, false);
|
||||
regcache_sync_region(rt715->regmap, 0x3000, 0x8fff);
|
||||
|
|
|
|||
|
|
@ -505,8 +505,10 @@ static int rt721_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt721->regmap, false);
|
||||
regcache_sync(rt721->regmap);
|
||||
|
|
|
|||
|
|
@ -552,8 +552,10 @@ static int rt722_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(rt722->regmap, false);
|
||||
regcache_sync(rt722->regmap);
|
||||
|
|
|
|||
|
|
@ -1445,8 +1445,10 @@ static s32 tac5xx2_sdca_dev_resume(struct device *dev)
|
|||
}
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, TAC5XX2_PROBE_TIMEOUT_MS);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(tac_dev->regmap, false);
|
||||
regcache_mark_dirty(tac_dev->regmap);
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ struct tas2783_prv {
|
|||
wait_queue_head_t fw_wait;
|
||||
bool fw_dl_task_done;
|
||||
bool fw_dl_success;
|
||||
/* use fallback fw name */
|
||||
bool fw_use_fallback;
|
||||
};
|
||||
|
||||
static const struct reg_default tas2783_reg_default[] = {
|
||||
|
|
@ -740,11 +742,19 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* firmware binary not found*/
|
||||
if (!fmw || !fmw->data) {
|
||||
/* firmware binary not found*/
|
||||
dev_err(tas_dev->dev,
|
||||
"Failed to read fw binary %s\n",
|
||||
tas_dev->rca_binaryname);
|
||||
if (!tas_dev->fw_use_fallback) {
|
||||
tas_dev->fw_use_fallback = true;
|
||||
dev_info(tas_dev->dev,
|
||||
"Failed to read preferred fw binary: %s, attempting fallback binary load\n",
|
||||
tas_dev->rca_binaryname);
|
||||
} else {
|
||||
dev_err(tas_dev->dev,
|
||||
"Failed to read fallback fw binary %s\n",
|
||||
tas_dev->rca_binaryname);
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1083,8 +1093,10 @@ static s32 tas2783_sdca_dev_resume(struct device *dev)
|
|||
int ret;
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, TAS2783_PROBE_TIMEOUT);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sdw_show_ping_status(slave->bus, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(tas_dev->regmap, false);
|
||||
regcache_sync(tas_dev->regmap);
|
||||
|
|
@ -1103,13 +1115,16 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
|
|||
bool pci_found = false;
|
||||
#if IS_ENABLED(CONFIG_PCI)
|
||||
struct device *dev = &slave->dev;
|
||||
struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev);
|
||||
struct pci_dev *pci = NULL;
|
||||
const char *fw_uid_prefix = tas_dev->fw_use_fallback ? "" : "0x";
|
||||
|
||||
for (; dev; dev = dev->parent) {
|
||||
if (dev->bus == &pci_bus_type) {
|
||||
pci = to_pci_dev(dev);
|
||||
scnprintf(name, size, "%04X-%1X-%1X.bin",
|
||||
pci->subsystem_device, bus->link_id, unique_id);
|
||||
scnprintf(name, size, "%04X-%1X-%s%1X.bin",
|
||||
pci->subsystem_device, bus->link_id,
|
||||
fw_uid_prefix, unique_id);
|
||||
pci_found = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1121,28 +1136,15 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
|
|||
bus->link_id, unique_id);
|
||||
}
|
||||
|
||||
static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
|
||||
s32 ret;
|
||||
u8 unique_id = tas_dev->sdw_peripheral->id.unique_id;
|
||||
|
||||
if (tas_dev->hw_init)
|
||||
return 0;
|
||||
|
||||
tas_dev->fw_dl_task_done = false;
|
||||
tas_dev->fw_dl_success = false;
|
||||
|
||||
ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
|
||||
if (ret) {
|
||||
dev_err(dev, "sw reset failed, err=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
usleep_range(2000, 2200);
|
||||
|
||||
tas_generate_fw_name(slave, tas_dev->rca_binaryname,
|
||||
sizeof(tas_dev->rca_binaryname));
|
||||
|
||||
tas_dev->fw_dl_task_done = false;
|
||||
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
|
||||
tas_dev->rca_binaryname, tas_dev->dev,
|
||||
GFP_KERNEL, tas_dev, tas2783_fw_ready);
|
||||
|
|
@ -1157,8 +1159,35 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
|
|||
msecs_to_jiffies(TIMEOUT_FW_DL_MS));
|
||||
if (!ret) {
|
||||
dev_err(tas_dev->dev, "fw request, wait_event timeout\n");
|
||||
ret = -EAGAIN;
|
||||
} else {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
|
||||
s32 ret;
|
||||
|
||||
if (tas_dev->hw_init)
|
||||
return 0;
|
||||
|
||||
tas_dev->fw_dl_success = false;
|
||||
|
||||
ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
|
||||
if (ret) {
|
||||
dev_err(dev, "sw reset failed, err=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
usleep_range(2000, 2200);
|
||||
|
||||
tas_dev->fw_use_fallback = false;
|
||||
ret = tas_fw_load(tas_dev, slave);
|
||||
if (!ret && tas_dev->fw_use_fallback)
|
||||
ret = tas_fw_load(tas_dev, slave);
|
||||
|
||||
if (!ret) {
|
||||
if (tas_dev->sa_func_data)
|
||||
ret = sdca_regmap_write_init(dev, tas_dev->regmap,
|
||||
tas_dev->sa_func_data);
|
||||
|
|
|
|||
|
|
@ -1049,11 +1049,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
static const u8 dual_rate_q[] = {4, 8, 9, 12, 16};
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
|
||||
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
|
||||
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
|
||||
u16 d, pll_d = 1;
|
||||
bool dual_rate;
|
||||
int clk;
|
||||
int width = aic3x->slot_width;
|
||||
|
||||
|
|
@ -1079,14 +1081,25 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
/* Fsref can be 44100 or 48000 */
|
||||
fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
|
||||
dual_rate = params_rate(params) >= 64000;
|
||||
|
||||
/* Try to find a value for Q which allows us to bypass the PLL and
|
||||
* generate CODEC_CLK directly. */
|
||||
for (pll_q = 2; pll_q < 18; pll_q++)
|
||||
if (aic3x->sysclk / (128 * pll_q) == fsref) {
|
||||
bypass_pll = 1;
|
||||
break;
|
||||
if (dual_rate) {
|
||||
for (int i = 0; i < ARRAY_SIZE(dual_rate_q); i++) {
|
||||
pll_q = dual_rate_q[i];
|
||||
if (aic3x->sysclk / (128 * pll_q) == fsref) {
|
||||
bypass_pll = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (pll_q = 2; pll_q < 18; pll_q++)
|
||||
if (aic3x->sysclk / (128 * pll_q) == fsref) {
|
||||
bypass_pll = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bypass_pll) {
|
||||
pll_q &= 0xf;
|
||||
|
|
@ -1106,13 +1119,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
|
|||
* right DAC to right channel input */
|
||||
data = (LDAC2LCH | RDAC2RCH);
|
||||
data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
|
||||
if (params_rate(params) >= 64000)
|
||||
if (dual_rate)
|
||||
data |= DUAL_RATE_MODE;
|
||||
snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data);
|
||||
|
||||
/* codec sample rate select */
|
||||
data = (fsref * 20) / params_rate(params);
|
||||
if (params_rate(params) < 64000)
|
||||
if (!dual_rate)
|
||||
data /= 2;
|
||||
data /= 5;
|
||||
data -= 2;
|
||||
|
|
|
|||
|
|
@ -288,6 +288,26 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
|
|||
config_be.dst_addr_width = buswidth;
|
||||
config_be.dst_maxburst = dma_params_be->maxburst;
|
||||
|
||||
/*
|
||||
* For eDMA, the back-end may report a maxburst size that is not evenly
|
||||
* divisible by the channel count. This causes the DMA transfer length
|
||||
* to misalign with the FIFO boundary, resulting in wrong data and
|
||||
* audible noise. Align maxburst to the nearest valid boundary:
|
||||
* - If maxburst >= channel count, override to the channel count so
|
||||
* each transfer equals exactly one audio frame.
|
||||
* - If maxburst < channel count, override to 1 to avoid partial-frame
|
||||
* transfers.
|
||||
*/
|
||||
if (asrc->use_edma && (dma_params_be->maxburst % params_channels(params))) {
|
||||
if (dma_params_be->maxburst >= params_channels(params)) {
|
||||
config_be.src_maxburst = params_channels(params);
|
||||
config_be.dst_maxburst = params_channels(params);
|
||||
} else {
|
||||
config_be.src_maxburst = 1;
|
||||
config_be.dst_maxburst = 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&audio_config, 0, sizeof(audio_config));
|
||||
config_be.peripheral_config = &audio_config;
|
||||
config_be.peripheral_size = sizeof(audio_config);
|
||||
|
|
|
|||
|
|
@ -778,18 +778,6 @@ static void graph_link_init(struct simple_util_priv *priv,
|
|||
graph_parse_daifmt(ports_cpu, &daifmt);
|
||||
graph_parse_daifmt(ports_codec, &daifmt);
|
||||
graph_parse_daifmt(lnk, &daifmt);
|
||||
if (daifmt) {
|
||||
struct device *dev = simple_priv_to_dev(priv);
|
||||
|
||||
/*
|
||||
* Recommend to use Auto Select by using .auto_selectable_formats.
|
||||
* linux/sound/soc/renesas/rcar/core.c can be good sample for it.
|
||||
*
|
||||
* One note is that Audio Graph Card2 still keeps compatible to set
|
||||
* DAI format via DT.
|
||||
*/
|
||||
dev_warn_once(dev, "use .auto_selectable_formats on each corresponding CPU/Codec driver");
|
||||
}
|
||||
|
||||
graph_util_parse_link_direction(lnk, &playback_only, &capture_only);
|
||||
graph_util_parse_link_direction(ports_cpu, &playback_only, &capture_only);
|
||||
|
|
|
|||
|
|
@ -587,6 +587,10 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
|
|||
token = hdr->token & APM_WRITE_TOKEN_MASK;
|
||||
|
||||
done = data->payload;
|
||||
if (!graph->rx_data.buf) {
|
||||
mutex_unlock(&graph->lock);
|
||||
break;
|
||||
}
|
||||
phys = graph->rx_data.buf[token].phys;
|
||||
mutex_unlock(&graph->lock);
|
||||
/* token numbering starts at 0 */
|
||||
|
|
@ -609,6 +613,10 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
|
|||
client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
|
||||
mutex_lock(&graph->lock);
|
||||
rd_done = data->payload;
|
||||
if (!graph->tx_data.buf) {
|
||||
mutex_unlock(&graph->lock);
|
||||
break;
|
||||
}
|
||||
phys = graph->tx_data.buf[hdr->token].phys;
|
||||
mutex_unlock(&graph->lock);
|
||||
/* token numbering starts at 0 */
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "rockchip_sai.h"
|
||||
|
||||
#define DRV_NAME "rockchip-sai"
|
||||
|
|
@ -215,12 +217,14 @@ static void rockchip_sai_xfer_clk_stop_and_wait(struct rk_sai_dev *sai, unsigned
|
|||
static int rockchip_sai_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rk_sai_dev *sai = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
rockchip_sai_fsync_lost_detect(sai, 0);
|
||||
rockchip_sai_fsync_err_detect(sai, 0);
|
||||
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock)
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
|
||||
regcache_cache_only(sai->regmap, true);
|
||||
/*
|
||||
|
|
@ -480,6 +484,7 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned int mask = 0, val = 0;
|
||||
unsigned int clk_gates;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
pm_runtime_get_sync(dai->dev);
|
||||
|
|
@ -495,56 +500,56 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
sai->is_master_mode = false;
|
||||
break;
|
||||
default:
|
||||
pm_runtime_put(dai->dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
|
||||
if (sai->initialized) {
|
||||
if (sai->has_capture && sai->has_playback)
|
||||
rockchip_sai_xfer_stop(sai, -1);
|
||||
else if (sai->has_capture)
|
||||
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
|
||||
else
|
||||
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
} else {
|
||||
rockchip_sai_clear(sai, 0);
|
||||
sai->initialized = true;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
|
||||
|
||||
mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
|
||||
rockchip_sai_fmt_create(sai, fmt);
|
||||
}
|
||||
|
||||
if (clk_gates)
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
|
||||
clk_gates);
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
|
||||
if (sai->initialized) {
|
||||
if (sai->has_capture && sai->has_playback)
|
||||
rockchip_sai_xfer_stop(sai, -1);
|
||||
else if (sai->has_capture)
|
||||
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
|
||||
else
|
||||
rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
} else {
|
||||
rockchip_sai_clear(sai, 0);
|
||||
sai->initialized = true;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
|
||||
|
||||
mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
|
||||
|
||||
rockchip_sai_fmt_create(sai, fmt);
|
||||
|
||||
err_xfer_unlock:
|
||||
if (clk_gates)
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
|
||||
clk_gates);
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
err_pm_put:
|
||||
pm_runtime_put(dai->dev);
|
||||
|
||||
return ret;
|
||||
|
|
@ -560,6 +565,7 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
unsigned int ch_per_lane, slot_width;
|
||||
unsigned int val, fscr, reg;
|
||||
unsigned int lanes, req_lanes;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!rockchip_sai_stream_valid(substream, dai))
|
||||
|
|
@ -586,8 +592,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
dev_err(sai->dev, "not enough lanes (%d) for requested number of %s channels (%d)\n",
|
||||
lanes, reg == SAI_TXCR ? "playback" : "capture",
|
||||
params_channels(params));
|
||||
pm_runtime_put(sai->dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
} else {
|
||||
lanes = req_lanes;
|
||||
}
|
||||
|
|
@ -613,88 +619,84 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
val = SAI_XCR_VDW(32);
|
||||
break;
|
||||
default:
|
||||
pm_runtime_put(sai->dev);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
val |= SAI_XCR_CSR(lanes);
|
||||
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
|
||||
|
||||
if (!sai->is_tdm)
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(params_physical_width(params)));
|
||||
if (!sai->is_tdm)
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(params_physical_width(params)));
|
||||
|
||||
regmap_read(sai->regmap, reg, &val);
|
||||
regmap_read(sai->regmap, reg, &val);
|
||||
|
||||
slot_width = SAI_XCR_SBW_V(val);
|
||||
ch_per_lane = params_channels(params) / lanes;
|
||||
slot_width = SAI_XCR_SBW_V(val);
|
||||
ch_per_lane = params_channels(params) / lanes;
|
||||
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
|
||||
SAI_XCR_SNB(ch_per_lane));
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
|
||||
SAI_XCR_SNB(ch_per_lane));
|
||||
|
||||
fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
|
||||
fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
|
||||
|
||||
switch (sai->fpw) {
|
||||
case FPW_ONE_BCLK_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(1);
|
||||
break;
|
||||
case FPW_ONE_SLOT_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(slot_width);
|
||||
break;
|
||||
case FPW_HALF_FRAME_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
|
||||
break;
|
||||
default:
|
||||
dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
regmap_update_bits(sai->regmap, SAI_FSCR,
|
||||
SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
|
||||
|
||||
if (sai->is_master_mode) {
|
||||
bclk_rate = sai->fw_ratio * slot_width *
|
||||
ch_per_lane * params_rate(params);
|
||||
ret = clk_set_rate(sai->mclk, sai->mclk_rate);
|
||||
if (ret)
|
||||
dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
|
||||
sai->mclk_rate, ERR_PTR(ret));
|
||||
else {
|
||||
mclk_rate = clk_get_rate(sai->mclk);
|
||||
if (mclk_rate < bclk_rate) {
|
||||
dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
|
||||
mclk_rate, bclk_rate);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
|
||||
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
|
||||
mclk_req_rate = bclk_rate * div_bclk;
|
||||
|
||||
if (mclk_rate <
|
||||
mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
|
||||
mclk_rate >
|
||||
mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
|
||||
dev_err(sai->dev,
|
||||
"Mismatch mclk: %u, expected %u (+/- %dHz)\n",
|
||||
mclk_rate, mclk_req_rate,
|
||||
CLK_SHIFT_RATE_HZ_MAX);
|
||||
ret = -EINVAL;
|
||||
} else
|
||||
regmap_update_bits(sai->regmap,
|
||||
SAI_CKR,
|
||||
SAI_CKR_MDIV_MASK,
|
||||
SAI_CKR_MDIV(div_bclk));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (sai->fpw) {
|
||||
case FPW_ONE_BCLK_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(1);
|
||||
break;
|
||||
case FPW_ONE_SLOT_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(slot_width);
|
||||
break;
|
||||
case FPW_HALF_FRAME_WIDTH:
|
||||
fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
|
||||
break;
|
||||
default:
|
||||
dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
|
||||
ret = -EINVAL;
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_FSCR,
|
||||
SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
|
||||
|
||||
if (sai->is_master_mode) {
|
||||
bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params);
|
||||
ret = clk_set_rate(sai->mclk, sai->mclk_rate);
|
||||
if (ret) {
|
||||
dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
|
||||
sai->mclk_rate, ERR_PTR(ret));
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
mclk_rate = clk_get_rate(sai->mclk);
|
||||
if (mclk_rate < bclk_rate) {
|
||||
dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
|
||||
mclk_rate, bclk_rate);
|
||||
ret = -EINVAL;
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
|
||||
mclk_req_rate = bclk_rate * div_bclk;
|
||||
|
||||
if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
|
||||
mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
|
||||
dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
|
||||
mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX);
|
||||
ret = -EINVAL;
|
||||
goto err_xfer_unlock;
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
|
||||
SAI_CKR_MDIV(div_bclk));
|
||||
}
|
||||
|
||||
err_xfer_unlock:
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
err_pm_put:
|
||||
pm_runtime_put(sai->dev);
|
||||
|
||||
return ret;
|
||||
|
|
@ -704,6 +706,7 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long flags;
|
||||
|
||||
if (!rockchip_sai_stream_valid(substream, dai))
|
||||
return 0;
|
||||
|
|
@ -724,12 +727,13 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
|
|||
* udelay falls short.
|
||||
*/
|
||||
udelay(20);
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock)
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK |
|
||||
SAI_XFER_FSS_MASK,
|
||||
SAI_XFER_CLK_EN |
|
||||
SAI_XFER_FSS_EN);
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK |
|
||||
SAI_XFER_FSS_MASK,
|
||||
SAI_XFER_CLK_EN |
|
||||
SAI_XFER_FSS_EN);
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
}
|
||||
|
||||
rockchip_sai_fsync_lost_detect(sai, 1);
|
||||
|
|
@ -912,6 +916,7 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
int slots, int slot_width)
|
||||
{
|
||||
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long flags;
|
||||
unsigned int clk_gates;
|
||||
int sw = slot_width;
|
||||
|
||||
|
|
@ -927,16 +932,16 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
return -EINVAL;
|
||||
|
||||
pm_runtime_get_sync(dai->dev);
|
||||
scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
|
||||
regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(sw));
|
||||
regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(sw));
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
|
||||
clk_gates);
|
||||
}
|
||||
spin_lock_irqsave(&sai->xfer_lock, flags);
|
||||
rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
|
||||
regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(sw));
|
||||
regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
|
||||
SAI_XCR_SBW(sw));
|
||||
regmap_update_bits(sai->regmap, SAI_XFER,
|
||||
SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
|
||||
clk_gates);
|
||||
spin_unlock_irqrestore(&sai->xfer_lock, flags);
|
||||
pm_runtime_put(dai->dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -160,6 +160,9 @@ static int ge_put_enum_double(struct snd_kcontrol *kcontrol,
|
|||
unsigned int reg = e->reg;
|
||||
int ret;
|
||||
|
||||
if (item[0] >= e->items)
|
||||
return -EINVAL;
|
||||
|
||||
reg &= ~SDW_SDCA_CTL_CSEL(0x3F);
|
||||
reg |= SDW_SDCA_CTL_CSEL(SDCA_CTL_GE_DETECTED_MODE);
|
||||
|
||||
|
|
|
|||
|
|
@ -1980,19 +1980,15 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
|
|||
}
|
||||
}
|
||||
|
||||
static void snd_soc_remove_device_links(struct snd_soc_card *card,
|
||||
struct snd_soc_component *stop_at)
|
||||
static void snd_soc_remove_device_links(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_component *component;
|
||||
|
||||
for_each_card_components(card, component) {
|
||||
if (card->dev == component->dev)
|
||||
continue;
|
||||
|
||||
device_link_remove(card->dev, component->dev);
|
||||
|
||||
if (component == stop_at)
|
||||
return;
|
||||
if (component->card_device_link) {
|
||||
device_link_del(component->card_device_link);
|
||||
component->card_device_link = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2001,7 +1997,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card)
|
|||
if (snd_soc_card_is_instantiated(card)) {
|
||||
card->instantiated = false;
|
||||
|
||||
snd_soc_remove_device_links(card, NULL);
|
||||
snd_soc_remove_device_links(card);
|
||||
|
||||
soc_cleanup_card_resources(card);
|
||||
}
|
||||
|
|
@ -2012,7 +2008,6 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
|
|||
struct snd_soc_pcm_runtime *rtd;
|
||||
struct snd_soc_component *component;
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
|
||||
struct snd_soc_component *last_devlinked_component = NULL;
|
||||
int ret;
|
||||
|
||||
snd_soc_card_mutex_lock_root(card);
|
||||
|
|
@ -2141,19 +2136,21 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
|
|||
* Add device_link from card to component so that system_suspend
|
||||
* will be done in the correct order. The card must suspend first
|
||||
* to stop audio activity before the components suspend.
|
||||
*
|
||||
* If a driver pair already have a link in the opposite direction
|
||||
* they must manage their own suspend order.
|
||||
*/
|
||||
for_each_card_components(card, component) {
|
||||
if (card->dev == component->dev)
|
||||
continue;
|
||||
|
||||
if (!device_link_add(card->dev, component->dev, DL_FLAG_STATELESS)) {
|
||||
dev_warn(card->dev, "Failed to create device link to %s\n",
|
||||
component->card_device_link = device_link_add(card->dev,
|
||||
component->dev,
|
||||
DL_FLAG_STATELESS);
|
||||
if (!component->card_device_link) {
|
||||
dev_warn(card->dev, "Could not create device link to %s\n",
|
||||
dev_name(component->dev));
|
||||
ret = -EINVAL;
|
||||
goto probe_end;
|
||||
}
|
||||
|
||||
last_devlinked_component = component;
|
||||
}
|
||||
|
||||
ret = snd_soc_card_late_probe(card);
|
||||
|
|
@ -2185,9 +2182,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
|
|||
|
||||
probe_end:
|
||||
if (ret < 0) {
|
||||
if (last_devlinked_component)
|
||||
snd_soc_remove_device_links(card, last_devlinked_component);
|
||||
|
||||
snd_soc_remove_device_links(card);
|
||||
soc_cleanup_card_resources(card);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,12 +237,16 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
|
|||
|
||||
switch (cdev->chip.usb_id) {
|
||||
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
|
||||
if (len < 2)
|
||||
return;
|
||||
i = decode_erp(buf[0], buf[1]);
|
||||
input_report_abs(input_dev, ABS_X, i);
|
||||
input_sync(input_dev);
|
||||
break;
|
||||
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
|
||||
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
|
||||
if (len < 16)
|
||||
return;
|
||||
i = decode_erp(buf[7], buf[5]);
|
||||
input_report_abs(input_dev, ABS_HAT0X, i);
|
||||
i = decode_erp(buf[12], buf[14]);
|
||||
|
|
@ -263,6 +267,8 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
|
|||
break;
|
||||
|
||||
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
|
||||
if (len < 22)
|
||||
return;
|
||||
/* 4 under the left screen */
|
||||
input_report_abs(input_dev, ABS_HAT0X, decode_erp(buf[21], buf[20]));
|
||||
input_report_abs(input_dev, ABS_HAT0Y, decode_erp(buf[15], buf[14]));
|
||||
|
|
@ -308,9 +314,13 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *cdev,
|
|||
switch (cdev->chip.usb_id) {
|
||||
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
|
||||
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
|
||||
if (len < 5)
|
||||
return;
|
||||
input_report_abs(cdev->input_dev, ABS_MISC, 255 - buf[4]);
|
||||
break;
|
||||
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
|
||||
if (len < 7)
|
||||
return;
|
||||
/* rotary encoders */
|
||||
input_report_abs(cdev->input_dev, ABS_X, buf[5] & 0xf);
|
||||
input_report_abs(cdev->input_dev, ABS_Y, buf[5] >> 4);
|
||||
|
|
@ -330,7 +340,7 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *cdev,
|
|||
{
|
||||
struct device *dev = caiaqdev_to_dev(cdev);
|
||||
|
||||
while (len) {
|
||||
while (len >= TKS4_MSGBLOCK_SIZE) {
|
||||
unsigned int i, block_id = (buf[0] << 8) | buf[1];
|
||||
|
||||
switch (block_id) {
|
||||
|
|
|
|||
|
|
@ -1083,6 +1083,8 @@ static int fcp_find_fc_interface(struct usb_mixer_interface *mixer)
|
|||
|
||||
if (desc->bInterfaceClass != 255)
|
||||
continue;
|
||||
if (desc->bNumEndpoints < 1)
|
||||
continue;
|
||||
|
||||
epd = get_endpoint(intf->altsetting, 0);
|
||||
private->bInterfaceNumber = desc->bInterfaceNumber;
|
||||
|
|
|
|||
|
|
@ -470,6 +470,11 @@ static int create_midi2_endpoint(struct snd_usb_midi2_interface *umidi,
|
|||
static void free_midi2_endpoint(struct snd_usb_midi2_endpoint *ep)
|
||||
{
|
||||
list_del(&ep->list);
|
||||
if (!ep->disconnected) {
|
||||
ep->disconnected = 1;
|
||||
kill_midi_urbs(ep, false);
|
||||
drain_urb_queue(ep);
|
||||
}
|
||||
free_midi_urbs(ep);
|
||||
kfree(ep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -577,46 +577,30 @@ static bool snd_dualsense_ih_match(struct input_handler *handler,
|
|||
{
|
||||
struct dualsense_mixer_elem_info *mei;
|
||||
struct usb_device *snd_dev;
|
||||
char *input_dev_path, *usb_dev_path;
|
||||
size_t usb_dev_path_len;
|
||||
bool match = false;
|
||||
struct device *parent;
|
||||
|
||||
mei = container_of(handler, struct dualsense_mixer_elem_info, ih);
|
||||
snd_dev = mei->info.head.mixer->chip->dev;
|
||||
|
||||
input_dev_path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
|
||||
if (!input_dev_path) {
|
||||
dev_warn(&snd_dev->dev, "Failed to get input dev path\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
usb_dev_path = kobject_get_path(&snd_dev->dev.kobj, GFP_KERNEL);
|
||||
if (!usb_dev_path) {
|
||||
dev_warn(&snd_dev->dev, "Failed to get USB dev path\n");
|
||||
goto free_paths;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure the VID:PID matched input device supposedly owned by the
|
||||
* hid-playstation driver belongs to the actual hardware handled by
|
||||
* the current USB audio device, which implies input_dev_path being
|
||||
* a subpath of usb_dev_path.
|
||||
* the current USB audio device.
|
||||
*
|
||||
* This verification is necessary when there is more than one identical
|
||||
* controller attached to the host system.
|
||||
*
|
||||
* The input device is registered below the HID device, USB interface and
|
||||
* USB device, so compare the parent chain directly instead of building
|
||||
* kobject path strings. This avoids dereferencing kobject names while the
|
||||
* USB device hierarchy is being torn down during disconnect.
|
||||
*/
|
||||
usb_dev_path_len = strlen(usb_dev_path);
|
||||
if (usb_dev_path_len >= strlen(input_dev_path))
|
||||
goto free_paths;
|
||||
for (parent = dev->dev.parent; parent; parent = parent->parent) {
|
||||
if (parent == &snd_dev->dev)
|
||||
return true;
|
||||
}
|
||||
|
||||
usb_dev_path[usb_dev_path_len] = '/';
|
||||
match = !memcmp(input_dev_path, usb_dev_path, usb_dev_path_len + 1);
|
||||
|
||||
free_paths:
|
||||
kfree(input_dev_path);
|
||||
kfree(usb_dev_path);
|
||||
|
||||
return match;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int snd_dualsense_ih_connect(struct input_handler *handler,
|
||||
|
|
@ -4526,6 +4510,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
|
|||
case USB_ID(0x1235, 0x821b): /* Focusrite Scarlett 16i16 4th Gen */
|
||||
case USB_ID(0x1235, 0x821c): /* Focusrite Scarlett 18i16 4th Gen */
|
||||
case USB_ID(0x1235, 0x821d): /* Focusrite Scarlett 18i20 4th Gen */
|
||||
case USB_ID(0x1235, 0x821e): /* Focusrite ISA C8X */
|
||||
err = snd_fcp_init(mixer);
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -1160,6 +1160,7 @@ uaudio_endpoint_setup(struct snd_usb_substream *subs,
|
|||
tr_pa = page_to_phys(pg);
|
||||
mem_info->dma = sg_dma_address(sgt->sgl);
|
||||
sg_free_table(sgt);
|
||||
kfree(sgt);
|
||||
|
||||
/* data transfer ring */
|
||||
iova = uaudio_iommu_map_pa(MEM_XFER_RING, dma_coherent, tr_pa,
|
||||
|
|
@ -1229,6 +1230,7 @@ static int uaudio_event_ring_setup(struct snd_usb_substream *subs,
|
|||
er_pa = page_to_phys(pg);
|
||||
mem_info->dma = sg_dma_address(sgt->sgl);
|
||||
sg_free_table(sgt);
|
||||
kfree(sgt);
|
||||
|
||||
iova = uaudio_iommu_map_pa(MEM_EVENT_RING, dma_coherent, er_pa,
|
||||
PAGE_SIZE);
|
||||
|
|
@ -1618,8 +1620,13 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle,
|
|||
if (req_msg->service_interval_valid) {
|
||||
ret = get_data_interval_from_si(subs,
|
||||
req_msg->service_interval);
|
||||
if (ret == -EINVAL)
|
||||
if (ret == -EINVAL) {
|
||||
if (req_msg->enable) {
|
||||
guard(mutex)(&chip->mutex);
|
||||
subs->opened = 0;
|
||||
}
|
||||
goto response;
|
||||
}
|
||||
|
||||
datainterval = ret;
|
||||
}
|
||||
|
|
@ -1640,6 +1647,11 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle,
|
|||
subs->opened = 0;
|
||||
}
|
||||
} else {
|
||||
if (info_idx < 0) {
|
||||
ret = -EINVAL;
|
||||
goto response;
|
||||
}
|
||||
|
||||
info = &uadev[pcm_card_num].info[info_idx];
|
||||
if (info->data_ep_pipe) {
|
||||
ep = usb_pipe_endpoint(uadev[pcm_card_num].udev,
|
||||
|
|
@ -1976,6 +1988,7 @@ static int qc_usb_audio_probe(struct auxiliary_device *auxdev,
|
|||
release_qmi:
|
||||
qc_usb_audio_cleanup_qmi_dev();
|
||||
qmi_handle_release(svc->uaudio_svc_hdl);
|
||||
kfree(svc->uaudio_svc_hdl);
|
||||
free_svc:
|
||||
kfree(svc);
|
||||
|
||||
|
|
@ -2000,6 +2013,7 @@ static void qc_usb_audio_remove(struct auxiliary_device *auxdev)
|
|||
qc_usb_audio_cleanup_qmi_dev();
|
||||
|
||||
qmi_handle_release(svc->uaudio_svc_hdl);
|
||||
kfree(svc->uaudio_svc_hdl);
|
||||
kfree(svc);
|
||||
uaudio_svc = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,6 +390,20 @@ YAMAHA_DEVICE(0x105d, NULL),
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0499, 0x150d),
|
||||
QUIRK_DRIVER_INFO {
|
||||
/* .vendor_name = "Yamaha", */
|
||||
/* .product_name = "CDS3000", */
|
||||
QUIRK_DATA_COMPOSITE {
|
||||
{ QUIRK_DATA_STANDARD_AUDIO(1) },
|
||||
{ QUIRK_DATA_STANDARD_AUDIO(2) },
|
||||
{ QUIRK_DATA_MIDI_YAMAHA(3) },
|
||||
{ QUIRK_DATA_IGNORE(4) },
|
||||
QUIRK_COMPOSITE_END
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0499, 0x1718),
|
||||
QUIRK_DRIVER_INFO {
|
||||
|
|
|
|||
|
|
@ -2413,6 +2413,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|||
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
|
||||
DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
|
||||
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
|
||||
DEVICE_FLG(0x1ff7, 0x0f81, /* SC13A Webcam */
|
||||
QUIRK_FLAG_GET_SAMPLE_RATE),
|
||||
DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
|
||||
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
|
||||
DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user