Files
omarchy-pkgs/pkgbuilds/linux-omarchy-eevdf/0510-sound-updates.patch
T

12142 lines
418 KiB
Diff

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1757,6 +1757,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
* by the drivers/platform/x86/serial-multi-instantiate.c driver, which
* knows which client device id to use for each resource.
*/
+ {"AWDZ8399", },
{"BSG1160", },
{"BSG2150", },
{"CSC3551", },
diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c
--- a/drivers/platform/x86/serial-multi-instantiate.c
+++ b/drivers/platform/x86/serial-multi-instantiate.c
@@ -307,6 +307,15 @@ static void smi_remove(struct platform_device *pdev)
smi_devs_unregister(smi);
}
+static const struct smi_node aw88399_hda = {
+ .instances = {
+ { "aw88399-hda", IRQ_RESOURCE_AUTO, 0 },
+ { "aw88399-hda", IRQ_RESOURCE_AUTO, 0 },
+ {}
+ },
+ .bus_type = SMI_AUTO_DETECT,
+};
+
static const struct smi_node bsg1160_data = {
.instances = {
{ "bmc150_accel", IRQ_RESOURCE_GPIO, 0 },
@@ -405,6 +414,7 @@ static const struct smi_node tas2781_hda = {
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
*/
static const struct acpi_device_id smi_acpi_ids[] = {
+ { "AWDZ8399", (unsigned long)&aw88399_hda },
{ "BSG1160", (unsigned long)&bsg1160_data },
{ "BSG2150", (unsigned long)&bsg2150_data },
{ "CSC3551", (unsigned long)&cs35l41_hda },
diff --git a/include/sound/ac97/codec.h b/include/sound/ac97/codec.h
--- a/include/sound/ac97/codec.h
+++ b/include/sound/ac97/codec.h
@@ -33,7 +33,7 @@ struct ac97_id {
};
/**
- * ac97_codec_device - a ac97 codec
+ * struct ac97_codec_device - a ac97 codec
* @dev: the core device
* @vendor_id: the vendor_id of the codec, as sensed on the AC-link
* @num: the codec number, 0 is primary, 1 is first slave, etc ...
@@ -53,7 +53,7 @@ struct ac97_codec_device {
};
/**
- * ac97_codec_driver - a ac97 codec driver
+ * struct ac97_codec_driver - a ac97 codec driver
* @driver: the device driver structure
* @probe: the function called when a ac97_codec_device is matched
* @remove: the function called when the device is unbound/removed
diff --git a/include/sound/asequencer.h b/include/sound/asequencer.h
--- a/include/sound/asequencer.h
+++ b/include/sound/asequencer.h
@@ -11,9 +11,6 @@
#include <sound/asound.h>
#include <uapi/sound/asequencer.h>
-/* helper macro */
-#define snd_seq_event_bounce_ext_data(ev) ((void*)((char *)(ev)->data.ext.ptr + sizeof(struct snd_seq_event_bounce)))
-
/*
* type check macros
*/
diff --git a/include/sound/aw88399.h b/include/sound/aw88399.h
new file mode 100644
--- /dev/null
+++ b/include/sound/aw88399.h
@@ -0,0 +1,621 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * linux/sound/aw88399.h -- Platform data for AW88399
+ *
+ * Copyright (c) 2023 AWINIC Technology CO., LTD
+ *
+ * Author: Weidong Wang <wangweidong.a@awinic.com>
+ */
+
+#ifndef __SOUND_AW88399_H
+#define __SOUND_AW88399_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+/* registers list */
+#define AW88399_ID_REG (0x00)
+#define AW88399_SYSST_REG (0x01)
+#define AW88399_SYSINT_REG (0x02)
+#define AW88399_SYSINTM_REG (0x03)
+#define AW88399_SYSCTRL_REG (0x04)
+#define AW88399_SYSCTRL2_REG (0x05)
+#define AW88399_I2SCTRL1_REG (0x06)
+#define AW88399_I2SCTRL2_REG (0x07)
+#define AW88399_I2SCTRL3_REG (0x08)
+#define AW88399_DACCFG1_REG (0x09)
+#define AW88399_DACCFG2_REG (0x0A)
+#define AW88399_DACCFG3_REG (0x0B)
+#define AW88399_DACCFG4_REG (0x0C)
+#define AW88399_DACCFG5_REG (0x0D)
+#define AW88399_DACCFG6_REG (0x0E)
+#define AW88399_DACCFG7_REG (0x0F)
+#define AW88399_MPDCFG1_REG (0x10)
+#define AW88399_MPDCFG2_REG (0x11)
+#define AW88399_MPDCFG3_REG (0x12)
+#define AW88399_MPDCFG4_REG (0x13)
+#define AW88399_PWMCTRL1_REG (0x14)
+#define AW88399_PWMCTRL2_REG (0x15)
+#define AW88399_PWMCTRL3_REG (0x16)
+#define AW88399_I2SCFG1_REG (0x17)
+#define AW88399_DBGCTRL_REG (0x18)
+#define AW88399_HAGCST_REG (0x20)
+#define AW88399_VBAT_REG (0x21)
+#define AW88399_TEMP_REG (0x22)
+#define AW88399_PVDD_REG (0x23)
+#define AW88399_ISNDAT_REG (0x24)
+#define AW88399_VSNDAT_REG (0x25)
+#define AW88399_I2SINT_REG (0x26)
+#define AW88399_I2SCAPCNT_REG (0x27)
+#define AW88399_ANASTA1_REG (0x28)
+#define AW88399_ANASTA2_REG (0x29)
+#define AW88399_ANASTA3_REG (0x2A)
+#define AW88399_TESTDET_REG (0x2B)
+#define AW88399_DSMCFG1_REG (0x30)
+#define AW88399_DSMCFG2_REG (0x31)
+#define AW88399_DSMCFG3_REG (0x32)
+#define AW88399_DSMCFG4_REG (0x33)
+#define AW88399_DSMCFG5_REG (0x34)
+#define AW88399_DSMCFG6_REG (0x35)
+#define AW88399_DSMCFG7_REG (0x36)
+#define AW88399_DSMCFG8_REG (0x37)
+#define AW88399_TESTIN_REG (0x38)
+#define AW88399_TESTOUT_REG (0x39)
+#define AW88399_MEMTEST_REG (0x3A)
+#define AW88399_VSNCTRL1_REG (0x3B)
+#define AW88399_ISNCTRL1_REG (0x3C)
+#define AW88399_ISNCTRL2_REG (0x3D)
+#define AW88399_DSPMADD_REG (0x40)
+#define AW88399_DSPMDAT_REG (0x41)
+#define AW88399_WDT_REG (0x42)
+#define AW88399_ACR1_REG (0x43)
+#define AW88399_ACR2_REG (0x44)
+#define AW88399_ASR1_REG (0x45)
+#define AW88399_ASR2_REG (0x46)
+#define AW88399_DSPCFG_REG (0x47)
+#define AW88399_ASR3_REG (0x48)
+#define AW88399_ASR4_REG (0x49)
+#define AW88399_DSPVCALB_REG (0x4A)
+#define AW88399_CRCCTRL_REG (0x4B)
+#define AW88399_DSPDBG1_REG (0x4C)
+#define AW88399_DSPDBG2_REG (0x4D)
+#define AW88399_DSPDBG3_REG (0x4E)
+#define AW88399_PLLCTRL1_REG (0x50)
+#define AW88399_PLLCTRL2_REG (0x51)
+#define AW88399_PLLCTRL3_REG (0x52)
+#define AW88399_CDACTRL1_REG (0x53)
+#define AW88399_CDACTRL2_REG (0x54)
+#define AW88399_CDACTRL3_REG (0x55)
+#define AW88399_SADCCTRL1_REG (0x56)
+#define AW88399_SADCCTRL2_REG (0x57)
+#define AW88399_BOPCTRL1_REG (0x58)
+#define AW88399_BOPCTRL2_REG (0x5A)
+#define AW88399_BOPCTRL3_REG (0x5B)
+#define AW88399_BOPCTRL4_REG (0x5C)
+#define AW88399_BOPCTRL5_REG (0x5D)
+#define AW88399_BOPCTRL6_REG (0x5E)
+#define AW88399_BOPCTRL7_REG (0x5F)
+#define AW88399_BSTCTRL1_REG (0x60)
+#define AW88399_BSTCTRL2_REG (0x61)
+#define AW88399_BSTCTRL3_REG (0x62)
+#define AW88399_BSTCTRL4_REG (0x63)
+#define AW88399_BSTCTRL5_REG (0x64)
+#define AW88399_BSTCTRL6_REG (0x65)
+#define AW88399_BSTCTRL7_REG (0x66)
+#define AW88399_BSTCTRL8_REG (0x67)
+#define AW88399_BSTCTRL9_REG (0x68)
+#define AW88399_BSTCTRL10_REG (0x69)
+#define AW88399_CPCTRL_REG (0x6A)
+#define AW88399_EFWH_REG (0x6C)
+#define AW88399_EFWM2_REG (0x6D)
+#define AW88399_EFWM1_REG (0x6E)
+#define AW88399_EFWL_REG (0x6F)
+#define AW88399_TESTCTRL1_REG (0x70)
+#define AW88399_TESTCTRL2_REG (0x71)
+#define AW88399_EFCTRL1_REG (0x72)
+#define AW88399_EFCTRL2_REG (0x73)
+#define AW88399_EFRH4_REG (0x74)
+#define AW88399_EFRH3_REG (0x75)
+#define AW88399_EFRH2_REG (0x76)
+#define AW88399_EFRH1_REG (0x77)
+#define AW88399_EFRL4_REG (0x78)
+#define AW88399_EFRL3_REG (0x79)
+#define AW88399_EFRL2_REG (0x7A)
+#define AW88399_EFRL1_REG (0x7B)
+#define AW88399_TM_REG (0x7C)
+#define AW88399_TM2_REG (0x7D)
+
+#define AW88399_REG_MAX (0x7E)
+#define AW88399_MUTE_VOL (1023)
+
+#define AW88399_DSP_CFG_ADDR (0x9B00)
+#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68)
+#define AW88399_DSP_FW_ADDR (0x8980)
+#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40)
+#define AW88399_DSP_ROM_CHECK_DATA (0x4638)
+
+#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000))
+#define AW88399_CALI_RE_HBITS_SHIFT (16)
+
+#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF))
+#define AW88399_CALI_RE_LBITS_SHIFT (0)
+
+#define AW88399_I2STXEN_START_BIT (9)
+#define AW88399_I2STXEN_BITS_LEN (1)
+#define AW88399_I2STXEN_MASK \
+ (~(((1<<AW88399_I2STXEN_BITS_LEN)-1) << AW88399_I2STXEN_START_BIT))
+
+#define AW88399_I2STXEN_DISABLE (0)
+#define AW88399_I2STXEN_DISABLE_VALUE \
+ (AW88399_I2STXEN_DISABLE << AW88399_I2STXEN_START_BIT)
+
+#define AW88399_I2STXEN_ENABLE (1)
+#define AW88399_I2STXEN_ENABLE_VALUE \
+ (AW88399_I2STXEN_ENABLE << AW88399_I2STXEN_START_BIT)
+
+#define AW88399_VOL_START_BIT (0)
+#define AW88399_VOL_BITS_LEN (10)
+#define AW88399_VOL_MASK \
+ (~(((1<<AW88399_VOL_BITS_LEN)-1) << AW88399_VOL_START_BIT))
+
+#define AW88399_PWDN_START_BIT (0)
+#define AW88399_PWDN_BITS_LEN (1)
+#define AW88399_PWDN_MASK \
+ (~(((1<<AW88399_PWDN_BITS_LEN)-1) << AW88399_PWDN_START_BIT))
+
+#define AW88399_PWDN_POWER_DOWN (1)
+#define AW88399_PWDN_POWER_DOWN_VALUE \
+ (AW88399_PWDN_POWER_DOWN << AW88399_PWDN_START_BIT)
+
+#define AW88399_PWDN_WORKING (0)
+#define AW88399_PWDN_WORKING_VALUE \
+ (AW88399_PWDN_WORKING << AW88399_PWDN_START_BIT)
+
+#define AW88399_DSPBY_START_BIT (2)
+#define AW88399_DSPBY_BITS_LEN (1)
+#define AW88399_DSPBY_MASK \
+ (~(((1<<AW88399_DSPBY_BITS_LEN)-1) << AW88399_DSPBY_START_BIT))
+
+#define AW88399_DSPBY_WORKING (0)
+#define AW88399_DSPBY_WORKING_VALUE \
+ (AW88399_DSPBY_WORKING << AW88399_DSPBY_START_BIT)
+
+#define AW88399_DSPBY_BYPASS (1)
+#define AW88399_DSPBY_BYPASS_VALUE \
+ (AW88399_DSPBY_BYPASS << AW88399_DSPBY_START_BIT)
+
+#define AW88399_MEM_CLKSEL_START_BIT (3)
+#define AW88399_MEM_CLKSEL_BITS_LEN (1)
+#define AW88399_MEM_CLKSEL_MASK \
+ (~(((1<<AW88399_MEM_CLKSEL_BITS_LEN)-1) << AW88399_MEM_CLKSEL_START_BIT))
+
+#define AW88399_MEM_CLKSEL_OSCCLK (0)
+#define AW88399_MEM_CLKSEL_OSCCLK_VALUE \
+ (AW88399_MEM_CLKSEL_OSCCLK << AW88399_MEM_CLKSEL_START_BIT)
+
+#define AW88399_MEM_CLKSEL_DAPHCLK (1)
+#define AW88399_MEM_CLKSEL_DAPHCLK_VALUE \
+ (AW88399_MEM_CLKSEL_DAPHCLK << AW88399_MEM_CLKSEL_START_BIT)
+
+#define AW88399_DITHER_EN_START_BIT (15)
+#define AW88399_DITHER_EN_BITS_LEN (1)
+#define AW88399_DITHER_EN_MASK \
+ (~(((1<<AW88399_DITHER_EN_BITS_LEN)-1) << AW88399_DITHER_EN_START_BIT))
+
+#define AW88399_DITHER_EN_DISABLE (0)
+#define AW88399_DITHER_EN_DISABLE_VALUE \
+ (AW88399_DITHER_EN_DISABLE << AW88399_DITHER_EN_START_BIT)
+
+#define AW88399_DITHER_EN_ENABLE (1)
+#define AW88399_DITHER_EN_ENABLE_VALUE \
+ (AW88399_DITHER_EN_ENABLE << AW88399_DITHER_EN_START_BIT)
+
+#define AW88399_HMUTE_START_BIT (8)
+#define AW88399_HMUTE_BITS_LEN (1)
+#define AW88399_HMUTE_MASK \
+ (~(((1<<AW88399_HMUTE_BITS_LEN)-1) << AW88399_HMUTE_START_BIT))
+
+#define AW88399_HMUTE_DISABLE (0)
+#define AW88399_HMUTE_DISABLE_VALUE \
+ (AW88399_HMUTE_DISABLE << AW88399_HMUTE_START_BIT)
+
+#define AW88399_HMUTE_ENABLE (1)
+#define AW88399_HMUTE_ENABLE_VALUE \
+ (AW88399_HMUTE_ENABLE << AW88399_HMUTE_START_BIT)
+
+#define AW88399_EF_DBMD_START_BIT (2)
+#define AW88399_EF_DBMD_BITS_LEN (1)
+#define AW88399_EF_DBMD_MASK \
+ (~(((1<<AW88399_EF_DBMD_BITS_LEN)-1) << AW88399_EF_DBMD_START_BIT))
+
+#define AW88399_EF_DBMD_OR (1)
+#define AW88399_EF_DBMD_OR_VALUE \
+ (AW88399_EF_DBMD_OR << AW88399_EF_DBMD_START_BIT)
+
+#define AW88399_VDSEL_START_BIT (5)
+#define AW88399_VDSEL_BITS_LEN (1)
+#define AW88399_VDSEL_MASK \
+ (~(((1<<AW88399_VDSEL_BITS_LEN)-1) << AW88399_VDSEL_START_BIT))
+
+#define AW88399_EF_ISN_GESLP_H_START_BIT (0)
+#define AW88399_EF_ISN_GESLP_H_BITS_LEN (10)
+#define AW88399_EF_ISN_GESLP_H_MASK \
+ (~(((1<<AW88399_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_H_START_BIT))
+
+/* EF_VSN_GESLP_H bit 9:0 (EFRH3 0x75) */
+#define AW88399_EF_VSN_GESLP_H_START_BIT (0)
+#define AW88399_EF_VSN_GESLP_H_BITS_LEN (10)
+#define AW88399_EF_VSN_GESLP_H_MASK \
+ (~(((1<<AW88399_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_H_START_BIT))
+
+#define AW88399_EF_ISN_GESLP_L_START_BIT (0)
+#define AW88399_EF_ISN_GESLP_L_BITS_LEN (10)
+#define AW88399_EF_ISN_GESLP_L_MASK \
+ (~(((1<<AW88399_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_L_START_BIT))
+
+/* EF_VSN_GESLP_L bit 9:0 (EFRL3 0x79) */
+#define AW88399_EF_VSN_GESLP_L_START_BIT (0)
+#define AW88399_EF_VSN_GESLP_L_BITS_LEN (10)
+#define AW88399_EF_VSN_GESLP_L_MASK \
+ (~(((1<<AW88399_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_L_START_BIT))
+
+#define AW88399_INTERNAL_VSN_TRIM_H_START_BIT (9)
+#define AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN (6)
+#define AW88399_INTERNAL_VSN_TRIM_H_MASK \
+ (~(((1<<AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_H_START_BIT))
+
+#define AW88399_INTERNAL_VSN_TRIM_L_START_BIT (9)
+#define AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN (6)
+#define AW88399_INTERNAL_VSN_TRIM_L_MASK \
+ (~(((1<<AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_L_START_BIT))
+
+#define AW88399_RCV_MODE_START_BIT (7)
+#define AW88399_RCV_MODE_BITS_LEN (1)
+#define AW88399_RCV_MODE_MASK \
+ (~(((1<<AW88399_RCV_MODE_BITS_LEN)-1) << AW88399_RCV_MODE_START_BIT))
+
+#define AW88399_CLKI_START_BIT (4)
+#define AW88399_NOCLKI_START_BIT (5)
+#define AW88399_PLLI_START_BIT (0)
+#define AW88399_PLLI_INT_VALUE (1)
+#define AW88399_PLLI_INT_INTERRUPT \
+ (AW88399_PLLI_INT_VALUE << AW88399_PLLI_START_BIT)
+
+#define AW88399_CLKI_INT_VALUE (1)
+#define AW88399_CLKI_INT_INTERRUPT \
+ (AW88399_CLKI_INT_VALUE << AW88399_CLKI_START_BIT)
+
+#define AW88399_NOCLKI_INT_VALUE (1)
+#define AW88399_NOCLKI_INT_INTERRUPT \
+ (AW88399_NOCLKI_INT_VALUE << AW88399_NOCLKI_START_BIT)
+
+#define AW88399_BIT_SYSINT_CHECK \
+ (AW88399_PLLI_INT_INTERRUPT | \
+ AW88399_CLKI_INT_INTERRUPT | \
+ AW88399_NOCLKI_INT_INTERRUPT)
+
+#define AW88399_CRC_CHECK_START_BIT (12)
+#define AW88399_CRC_CHECK_BITS_LEN (3)
+#define AW88399_CRC_CHECK_BITS_MASK \
+ (~(((1<<AW88399_CRC_CHECK_BITS_LEN)-1) << AW88399_CRC_CHECK_START_BIT))
+
+#define AW88399_RCV_MODE_RECEIVER (1)
+#define AW88399_RCV_MODE_RECEIVER_VALUE \
+ (AW88399_RCV_MODE_RECEIVER << AW88399_RCV_MODE_START_BIT)
+
+#define AW88399_AMPPD_START_BIT (1)
+#define AW88399_AMPPD_BITS_LEN (1)
+#define AW88399_AMPPD_MASK \
+ (~(((1<<AW88399_AMPPD_BITS_LEN)-1) << AW88399_AMPPD_START_BIT))
+
+#define AW88399_AMPPD_WORKING (0)
+#define AW88399_AMPPD_WORKING_VALUE \
+ (AW88399_AMPPD_WORKING << AW88399_AMPPD_START_BIT)
+
+#define AW88399_AMPPD_POWER_DOWN (1)
+#define AW88399_AMPPD_POWER_DOWN_VALUE \
+ (AW88399_AMPPD_POWER_DOWN << AW88399_AMPPD_START_BIT)
+
+#define AW88399_RAM_CG_BYP_START_BIT (0)
+#define AW88399_RAM_CG_BYP_BITS_LEN (1)
+#define AW88399_RAM_CG_BYP_MASK \
+ (~(((1<<AW88399_RAM_CG_BYP_BITS_LEN)-1) << AW88399_RAM_CG_BYP_START_BIT))
+
+#define AW88399_RAM_CG_BYP_WORK (0)
+#define AW88399_RAM_CG_BYP_WORK_VALUE \
+ (AW88399_RAM_CG_BYP_WORK << AW88399_RAM_CG_BYP_START_BIT)
+
+#define AW88399_RAM_CG_BYP_BYPASS (1)
+#define AW88399_RAM_CG_BYP_BYPASS_VALUE \
+ (AW88399_RAM_CG_BYP_BYPASS << AW88399_RAM_CG_BYP_START_BIT)
+
+#define AW88399_CRC_END_ADDR_START_BIT (0)
+#define AW88399_CRC_END_ADDR_BITS_LEN (12)
+#define AW88399_CRC_END_ADDR_MASK \
+ (~(((1<<AW88399_CRC_END_ADDR_BITS_LEN)-1) << AW88399_CRC_END_ADDR_START_BIT))
+
+#define AW88399_CRC_CODE_EN_START_BIT (13)
+#define AW88399_CRC_CODE_EN_BITS_LEN (1)
+#define AW88399_CRC_CODE_EN_MASK \
+ (~(((1<<AW88399_CRC_CODE_EN_BITS_LEN)-1) << AW88399_CRC_CODE_EN_START_BIT))
+
+#define AW88399_CRC_CODE_EN_DISABLE (0)
+#define AW88399_CRC_CODE_EN_DISABLE_VALUE \
+ (AW88399_CRC_CODE_EN_DISABLE << AW88399_CRC_CODE_EN_START_BIT)
+
+#define AW88399_CRC_CODE_EN_ENABLE (1)
+#define AW88399_CRC_CODE_EN_ENABLE_VALUE \
+ (AW88399_CRC_CODE_EN_ENABLE << AW88399_CRC_CODE_EN_START_BIT)
+
+#define AW88399_CRC_CFG_EN_START_BIT (12)
+#define AW88399_CRC_CFG_EN_BITS_LEN (1)
+#define AW88399_CRC_CFG_EN_MASK \
+ (~(((1<<AW88399_CRC_CFG_EN_BITS_LEN)-1) << AW88399_CRC_CFG_EN_START_BIT))
+
+#define AW88399_CRC_CFG_EN_DISABLE (0)
+#define AW88399_CRC_CFG_EN_DISABLE_VALUE \
+ (AW88399_CRC_CFG_EN_DISABLE << AW88399_CRC_CFG_EN_START_BIT)
+
+#define AW88399_CRC_CFG_EN_ENABLE (1)
+#define AW88399_CRC_CFG_EN_ENABLE_VALUE \
+ (AW88399_CRC_CFG_EN_ENABLE << AW88399_CRC_CFG_EN_START_BIT)
+
+#define AW88399_OCDS_START_BIT (3)
+#define AW88399_OCDS_OC (1)
+#define AW88399_OCDS_OC_VALUE \
+ (AW88399_OCDS_OC << AW88399_OCDS_START_BIT)
+
+#define AW88399_NOCLKS_START_BIT (5)
+#define AW88399_NOCLKS_NO_CLOCK (1)
+#define AW88399_NOCLKS_NO_CLOCK_VALUE \
+ (AW88399_NOCLKS_NO_CLOCK << AW88399_NOCLKS_START_BIT)
+
+#define AW88399_SWS_START_BIT (8)
+#define AW88399_SWS_SWITCHING (1)
+#define AW88399_SWS_SWITCHING_VALUE \
+ (AW88399_SWS_SWITCHING << AW88399_SWS_START_BIT)
+
+#define AW88399_BSTS_START_BIT (9)
+#define AW88399_BSTS_FINISHED (1)
+#define AW88399_BSTS_FINISHED_VALUE \
+ (AW88399_BSTS_FINISHED << AW88399_BSTS_START_BIT)
+
+#define AW88399_UVLS_START_BIT (14)
+#define AW88399_UVLS_NORMAL (0)
+#define AW88399_UVLS_NORMAL_VALUE \
+ (AW88399_UVLS_NORMAL << AW88399_UVLS_START_BIT)
+
+#define AW88399_BSTOCS_START_BIT (11)
+#define AW88399_BSTOCS_OVER_CURRENT (1)
+#define AW88399_BSTOCS_OVER_CURRENT_VALUE \
+ (AW88399_BSTOCS_OVER_CURRENT << AW88399_BSTOCS_START_BIT)
+
+#define AW88399_OTHS_START_BIT (1)
+#define AW88399_OTHS_OT (1)
+#define AW88399_OTHS_OT_VALUE \
+ (AW88399_OTHS_OT << AW88399_OTHS_START_BIT)
+
+#define AW88399_PLLS_START_BIT (0)
+#define AW88399_PLLS_LOCKED (1)
+#define AW88399_PLLS_LOCKED_VALUE \
+ (AW88399_PLLS_LOCKED << AW88399_PLLS_START_BIT)
+
+#define AW88399_CLKS_START_BIT (4)
+#define AW88399_CLKS_STABLE (1)
+#define AW88399_CLKS_STABLE_VALUE \
+ (AW88399_CLKS_STABLE << AW88399_CLKS_START_BIT)
+
+#define AW88399_BIT_PLL_CHECK \
+ (AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE)
+
+#define AW88399_BIT_SYSST_CHECK_MASK \
+ (~(AW88399_UVLS_NORMAL_VALUE | \
+ AW88399_BSTOCS_OVER_CURRENT_VALUE | \
+ AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_SWS_SWITCHING_VALUE | \
+ AW88399_NOCLKS_NO_CLOCK_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_OCDS_OC_VALUE | \
+ AW88399_OTHS_OT_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE))
+
+#define AW88399_BIT_SYSST_NOSWS_CHECK \
+ (AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE)
+
+#define AW88399_BIT_SYSST_SWS_CHECK \
+ (AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE | \
+ AW88399_SWS_SWITCHING_VALUE)
+
+#define AW88399_CCO_MUX_START_BIT (14)
+#define AW88399_CCO_MUX_BITS_LEN (1)
+#define AW88399_CCO_MUX_MASK \
+ (~(((1<<AW88399_CCO_MUX_BITS_LEN)-1) << AW88399_CCO_MUX_START_BIT))
+
+#define AW88399_CCO_MUX_DIVIDED (0)
+#define AW88399_CCO_MUX_DIVIDED_VALUE \
+ (AW88399_CCO_MUX_DIVIDED << AW88399_CCO_MUX_START_BIT)
+
+#define AW88399_CCO_MUX_BYPASS (1)
+#define AW88399_CCO_MUX_BYPASS_VALUE \
+ (AW88399_CCO_MUX_BYPASS << AW88399_CCO_MUX_START_BIT)
+
+#define AW88399_NOISE_GATE_EN_START_BIT (13)
+#define AW88399_NOISE_GATE_EN_BITS_LEN (1)
+#define AW88399_NOISE_GATE_EN_MASK \
+ (~(((1<<AW88399_NOISE_GATE_EN_BITS_LEN)-1) << AW88399_NOISE_GATE_EN_START_BIT))
+
+#define AW88399_WDT_CNT_START_BIT (0)
+#define AW88399_WDT_CNT_BITS_LEN (8)
+#define AW88399_WDT_CNT_MASK \
+ (~(((1<<AW88399_WDT_CNT_BITS_LEN)-1) << AW88399_WDT_CNT_START_BIT))
+
+#define AW88399_REABS_START_BIT (3)
+#define AW88399_REABS_BITS_LEN (1)
+#define AW88399_REABS_MASK \
+ (~(((1<<AW88399_REABS_BITS_LEN)-1) << AW88399_REABS_START_BIT))
+
+#define AW88399_DSP_VOL_START_BIT (8)
+#define AW88399_DSP_VOL_BITS_LEN (8)
+#define AW88399_DSP_VOL_MASK \
+ (~(((1<<AW88399_DSP_VOL_BITS_LEN)-1) << AW88399_DSP_VOL_START_BIT))
+
+#define AW883XX_DSP_NG_EN_START (13)
+#define AW883XX_DSP_NG_EN_LEN (1)
+#define AW883XX_DSP_NG_EN_MASK \
+ (~(((1 << AW883XX_DSP_NG_EN_LEN) - 1) << AW883XX_DSP_NG_EN_START))
+#define AW883XX_DSP_NG_EN_DISABLE (0)
+#define AW883XX_DSP_NG_EN_DISABLE_VALUE \
+ (AW883XX_DSP_NG_EN_DISABLE << AW883XX_DSP_NG_EN_START)
+
+#define AW88399_VOLUME_STEP_DB (64)
+#define AW88399_VOL_DEFAULT_VALUE (0)
+#define AW88399_DSP_ODD_NUM_BIT_TEST (0x5555)
+#define AW88399_EF_ISN_GESLP_SIGN_MASK (~(1 << 9))
+#define AW88399_EF_ISN_GESLP_SIGN_NEG (0xfe00)
+
+#define AW88399_EF_VSN_GESLP_SIGN_MASK (~(1 << 9))
+#define AW88399_EF_VSN_GESLP_SIGN_NEG (0xfe00)
+
+#define AW88399_TEM4_SIGN_MASK (~(1 << 5))
+#define AW88399_TEM4_SIGN_NEG (0xffc0)
+
+#define AW88399_ICABLK_FACTOR (1)
+#define AW88399_VCABLK_FACTOR (1)
+#define AW88399_VCABLK_DAC_FACTOR (2)
+
+#define AW88399_VCALB_ADJ_FACTOR (12)
+#define AW88399_VCALB_ACCURACY (1 << 12)
+
+#define AW88399_ISCAL_FACTOR (3125)
+#define AW88399_VSCAL_FACTOR (18875)
+#define AW88399_ISCAL_DAC_FACTOR (3125)
+#define AW88399_VSCAL_DAC_FACTOR (12600)
+#define AW88399_CABL_BASE_VALUE (1000)
+
+#define AW88399_DEV_DEFAULT_CH (0)
+#define AW88399_DEV_DSP_CHECK_MAX (5)
+#define AW88399_MAX_RAM_WRITE_BYTE_SIZE (128)
+#define AW88399_DSP_RE_SHIFT (12)
+#define AW88399_CALI_RE_MAX (15000)
+#define AW88399_CALI_RE_MIN (4000)
+#define AW_FW_ADDR_LEN (4)
+#define AW88399_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
+#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
+#define AW88399_CRC_CHECK_PASS_VAL (0x4)
+
+#define AW88399_CRC_CFG_BASE_ADDR (0xD80)
+#define AW88399_CRC_FW_BASE_ADDR (0x4C0)
+#define AW88399_ACF_FILE "aw88399_acf.bin"
+#define AW88399_DEV_SYSST_CHECK_MAX (10)
+#define AW88399_CHIP_ID 0x2183
+
+#define AW88399_START_RETRIES (5)
+#define AW88399_START_WORK_DELAY_MS (0)
+
+enum {
+ AW_EF_AND_CHECK = 0,
+ AW_EF_OR_CHECK,
+};
+
+enum {
+ AW88399_DEV_VDSEL_DAC = 0,
+ AW88399_DEV_VDSEL_VSENSE = 32,
+};
+
+enum {
+ AW88399_DSP_CRC_NA = 0,
+ AW88399_DSP_CRC_OK = 1,
+};
+
+enum {
+ AW88399_DSP_FW_UPDATE_OFF = 0,
+ AW88399_DSP_FW_UPDATE_ON = 1,
+};
+
+enum {
+ AW88399_FORCE_UPDATE_OFF = 0,
+ AW88399_FORCE_UPDATE_ON = 1,
+};
+
+enum {
+ AW88399_1000_US = 1000,
+ AW88399_2000_US = 2000,
+ AW88399_3000_US = 3000,
+ AW88399_4000_US = 4000,
+};
+
+enum AW88399_DEV_STATUS {
+ AW88399_DEV_PW_OFF = 0,
+ AW88399_DEV_PW_ON,
+};
+
+enum AW88399_DEV_FW_STATUS {
+ AW88399_DEV_FW_FAILED = 0,
+ AW88399_DEV_FW_OK,
+};
+
+enum AW88399_DEV_MEMCLK {
+ AW88399_DEV_MEMCLK_OSC = 0,
+ AW88399_DEV_MEMCLK_PLL = 1,
+};
+
+enum AW88399_DEV_DSP_CFG {
+ AW88399_DEV_DSP_WORK = 0,
+ AW88399_DEV_DSP_BYPASS = 1,
+};
+
+enum {
+ AW88399_NOT_RCV_MODE = 0,
+ AW88399_RCV_MODE = 1,
+};
+
+enum {
+ AW88399_SYNC_START = 0,
+ AW88399_ASYNC_START,
+};
+
+struct aw_device;
+struct aw_container;
+struct aw_cali_desc;
+struct gpio_desc;
+struct i2c_client;
+struct regmap;
+
+struct aw88399 {
+ struct aw_device *aw_pa;
+ struct mutex lock;
+ struct gpio_desc *reset_gpio;
+ struct delayed_work start_work;
+ struct regmap *regmap;
+ struct aw_container *aw_cfg;
+
+ unsigned int check_val;
+ unsigned int crc_init_val;
+ unsigned int vcalb_init_val;
+ unsigned int dither_st;
+ bool bsts_unreliable;
+ bool fw_needs_reload;
+};
+
+int aw_dev_check_syspll(struct aw_device *aw_dev);
+void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable);
+int aw_dev_get_dsp_status(struct aw_device *aw_dev);
+int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value);
+int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc);
+int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name);
+void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute);
+void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel);
+void aw88399_hw_reset(struct aw88399 *aw88399);
+int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap);
+extern const struct regmap_config aw88399_remap_config;
+int aw88399_request_firmware_file(struct aw88399 *aw88399);
+void aw88399_start(struct aw88399 *aw88399, bool sync_start);
+void aw88399_startup_work(struct work_struct *work);
+int aw88399_stop(struct aw_device *aw_dev);
+
+#endif /* __SOUND_AW88399_H */
diff --git a/include/sound/control.h b/include/sound/control.h
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -7,6 +7,7 @@
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*/
+#include <linux/rwsem.h>
#include <linux/wait.h>
#include <linux/nospec.h>
#include <sound/asound.h>
@@ -167,6 +168,8 @@ snd_ctl_find_id_mixer(struct snd_card *card, const char *name)
int snd_ctl_create(struct snd_card *card);
+extern struct rw_semaphore snd_ioctl_rwsem;
+
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
#ifdef CONFIG_COMPAT
diff --git a/include/sound/core.h b/include/sound/core.h
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -108,8 +108,8 @@ struct snd_card {
char longname[80]; /* name of this soundcard */
char irq_descr[32]; /* Interrupt description */
char mixername[80]; /* mixer name */
- char components[128]; /* card components delimited with
- space */
+ char *components; /* card components, space-delimited */
+ unsigned int components_alloc_size; /* current allocation size of components */
struct module *module; /* top-level module */
void *private_data; /* private data for soundcard */
diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h
--- a/include/sound/hda_codec.h
+++ b/include/sound/hda_codec.h
@@ -256,6 +256,7 @@ struct hda_codec {
unsigned int link_down_at_suspend:1; /* link down at runtime suspend */
unsigned int relaxed_resume:1; /* don't resume forcibly for jack */
unsigned int forced_resume:1; /* forced resume for jack */
+ unsigned int acomp_requested_resume:1; /* resume requested by acomp */
unsigned int no_stream_clean_at_suspend:1; /* do not clean streams at suspend */
unsigned int ctl_dev_id:1; /* old control element id build behaviour */
unsigned int eld_jack_detect:1; /* Machine jack-detection by ELD */
diff --git a/include/sound/hda_regmap.h b/include/sound/hda_regmap.h
--- a/include/sound/hda_regmap.h
+++ b/include/sound/hda_regmap.h
@@ -69,11 +69,14 @@ void snd_hdac_regmap_sync(struct hdac_device *codec);
/**
* snd_hdac_regmap_write - Write a verb with caching
+ * @codec: HD-audio codec base device
* @nid: codec NID
- * @reg: verb to write
+ * @verb: verb to write
* @val: value to write
*
* For writing an amp value, use snd_hdac_regmap_update_amp().
+ *
+ * Returns: %0 if successful or a negative error code.
*/
static inline int
snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
@@ -85,13 +88,16 @@ snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
}
/**
- * snd_hda_regmap_update - Update a verb value with caching
+ * snd_hdac_regmap_update - Update a verb value with caching
+ * @codec: HD-audio codec
* @nid: codec NID
* @verb: verb to update
* @mask: bit mask to update
* @val: value to update
*
* For updating an amp value, use snd_hdac_regmap_update_amp().
+ *
+ * Returns: %0 if successful or a negative error code.
*/
static inline int
snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
@@ -104,12 +110,15 @@ snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
}
/**
- * snd_hda_regmap_read - Read a verb with caching
+ * snd_hdac_regmap_read - Read a verb with caching
+ * @codec: HD-audio codec
* @nid: codec NID
* @verb: verb to read
* @val: pointer to store the value
*
* For reading an amp value, use snd_hda_regmap_get_amp().
+ *
+ * Returns: %0 if successful or a negative error code.
*/
static inline int
snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
@@ -125,12 +134,12 @@ snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
* @codec: HD-audio codec
* @nid: NID to read the AMP value
* @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @index: the index value (only for input direction)
- * @val: the pointer to store the value
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
*
* Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
- * Returns the value or a negative error.
+ *
+ * Returns: the value or a negative error.
*/
static inline int
snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
@@ -148,13 +157,14 @@ snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
* @codec: HD-audio codec
* @nid: NID to read the AMP value
* @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
* @idx: the index value (only for input direction)
* @mask: bit mask to set
* @val: the bits value to set
*
* Update the AMP value with a bit mask.
- * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
+ *
+ * Returns: 0 if the value is unchanged, 1 if changed, or a negative error.
*/
static inline int
snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
@@ -169,13 +179,12 @@ snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
* snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
* @codec: HD-audio codec
* @nid: NID to read the AMP value
- * @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @index: the index value (only for input direction)
- * @val: the pointer to store the value
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
*
* Read stereo AMP values. The lower byte is left, the upper byte is right.
- * Returns the value or a negative error.
+ *
+ * Returns: the value or a negative error.
*/
static inline int
snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
@@ -192,14 +201,15 @@ snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
* snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
* @codec: HD-audio codec
* @nid: NID to read the AMP value
- * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
* @idx: the index value (only for input direction)
* @mask: bit mask to set
* @val: the bits value to set
*
* Update the stereo AMP value with a bit mask.
* The lower byte is left, the upper byte is right.
- * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
+ *
+ * Returns: 0 if the value is unchanged, 1 if changed, or a negative error.
*/
static inline int
snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -145,61 +145,60 @@ struct snd_pcm_ops {
#define SNDRV_PCM_RATE_8000_768000 (SNDRV_PCM_RATE_8000_384000|\
SNDRV_PCM_RATE_705600|\
SNDRV_PCM_RATE_768000)
-#define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt)
-#define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8)
-#define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8)
-#define SNDRV_PCM_FMTBIT_S16_LE _SNDRV_PCM_FMTBIT(S16_LE)
-#define SNDRV_PCM_FMTBIT_S16_BE _SNDRV_PCM_FMTBIT(S16_BE)
-#define SNDRV_PCM_FMTBIT_U16_LE _SNDRV_PCM_FMTBIT(U16_LE)
-#define SNDRV_PCM_FMTBIT_U16_BE _SNDRV_PCM_FMTBIT(U16_BE)
-#define SNDRV_PCM_FMTBIT_S24_LE _SNDRV_PCM_FMTBIT(S24_LE)
-#define SNDRV_PCM_FMTBIT_S24_BE _SNDRV_PCM_FMTBIT(S24_BE)
-#define SNDRV_PCM_FMTBIT_U24_LE _SNDRV_PCM_FMTBIT(U24_LE)
-#define SNDRV_PCM_FMTBIT_U24_BE _SNDRV_PCM_FMTBIT(U24_BE)
+#define SNDRV_PCM_FMTBIT_S8 (1ULL << SNDRV_PCM_FORMAT_S8)
+#define SNDRV_PCM_FMTBIT_U8 (1ULL << SNDRV_PCM_FORMAT_U8)
+#define SNDRV_PCM_FMTBIT_S16_LE (1ULL << SNDRV_PCM_FORMAT_S16_LE)
+#define SNDRV_PCM_FMTBIT_S16_BE (1ULL << SNDRV_PCM_FORMAT_S16_BE)
+#define SNDRV_PCM_FMTBIT_U16_LE (1ULL << SNDRV_PCM_FORMAT_U16_LE)
+#define SNDRV_PCM_FMTBIT_U16_BE (1ULL << SNDRV_PCM_FORMAT_U16_BE)
+#define SNDRV_PCM_FMTBIT_S24_LE (1ULL << SNDRV_PCM_FORMAT_S24_LE)
+#define SNDRV_PCM_FMTBIT_S24_BE (1ULL << SNDRV_PCM_FORMAT_S24_BE)
+#define SNDRV_PCM_FMTBIT_U24_LE (1ULL << SNDRV_PCM_FORMAT_U24_LE)
+#define SNDRV_PCM_FMTBIT_U24_BE (1ULL << SNDRV_PCM_FORMAT_U24_BE)
// For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
// available bit count in most significant bit. It's for the case of so-called 'left-justified' or
// `right-padding` sample which has less width than 32 bit.
-#define SNDRV_PCM_FMTBIT_S32_LE _SNDRV_PCM_FMTBIT(S32_LE)
-#define SNDRV_PCM_FMTBIT_S32_BE _SNDRV_PCM_FMTBIT(S32_BE)
-#define SNDRV_PCM_FMTBIT_U32_LE _SNDRV_PCM_FMTBIT(U32_LE)
-#define SNDRV_PCM_FMTBIT_U32_BE _SNDRV_PCM_FMTBIT(U32_BE)
-#define SNDRV_PCM_FMTBIT_FLOAT_LE _SNDRV_PCM_FMTBIT(FLOAT_LE)
-#define SNDRV_PCM_FMTBIT_FLOAT_BE _SNDRV_PCM_FMTBIT(FLOAT_BE)
-#define SNDRV_PCM_FMTBIT_FLOAT64_LE _SNDRV_PCM_FMTBIT(FLOAT64_LE)
-#define SNDRV_PCM_FMTBIT_FLOAT64_BE _SNDRV_PCM_FMTBIT(FLOAT64_BE)
-#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE _SNDRV_PCM_FMTBIT(IEC958_SUBFRAME_LE)
-#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE _SNDRV_PCM_FMTBIT(IEC958_SUBFRAME_BE)
-#define SNDRV_PCM_FMTBIT_MU_LAW _SNDRV_PCM_FMTBIT(MU_LAW)
-#define SNDRV_PCM_FMTBIT_A_LAW _SNDRV_PCM_FMTBIT(A_LAW)
-#define SNDRV_PCM_FMTBIT_IMA_ADPCM _SNDRV_PCM_FMTBIT(IMA_ADPCM)
-#define SNDRV_PCM_FMTBIT_MPEG _SNDRV_PCM_FMTBIT(MPEG)
-#define SNDRV_PCM_FMTBIT_GSM _SNDRV_PCM_FMTBIT(GSM)
-#define SNDRV_PCM_FMTBIT_S20_LE _SNDRV_PCM_FMTBIT(S20_LE)
-#define SNDRV_PCM_FMTBIT_U20_LE _SNDRV_PCM_FMTBIT(U20_LE)
-#define SNDRV_PCM_FMTBIT_S20_BE _SNDRV_PCM_FMTBIT(S20_BE)
-#define SNDRV_PCM_FMTBIT_U20_BE _SNDRV_PCM_FMTBIT(U20_BE)
-#define SNDRV_PCM_FMTBIT_SPECIAL _SNDRV_PCM_FMTBIT(SPECIAL)
-#define SNDRV_PCM_FMTBIT_S24_3LE _SNDRV_PCM_FMTBIT(S24_3LE)
-#define SNDRV_PCM_FMTBIT_U24_3LE _SNDRV_PCM_FMTBIT(U24_3LE)
-#define SNDRV_PCM_FMTBIT_S24_3BE _SNDRV_PCM_FMTBIT(S24_3BE)
-#define SNDRV_PCM_FMTBIT_U24_3BE _SNDRV_PCM_FMTBIT(U24_3BE)
-#define SNDRV_PCM_FMTBIT_S20_3LE _SNDRV_PCM_FMTBIT(S20_3LE)
-#define SNDRV_PCM_FMTBIT_U20_3LE _SNDRV_PCM_FMTBIT(U20_3LE)
-#define SNDRV_PCM_FMTBIT_S20_3BE _SNDRV_PCM_FMTBIT(S20_3BE)
-#define SNDRV_PCM_FMTBIT_U20_3BE _SNDRV_PCM_FMTBIT(U20_3BE)
-#define SNDRV_PCM_FMTBIT_S18_3LE _SNDRV_PCM_FMTBIT(S18_3LE)
-#define SNDRV_PCM_FMTBIT_U18_3LE _SNDRV_PCM_FMTBIT(U18_3LE)
-#define SNDRV_PCM_FMTBIT_S18_3BE _SNDRV_PCM_FMTBIT(S18_3BE)
-#define SNDRV_PCM_FMTBIT_U18_3BE _SNDRV_PCM_FMTBIT(U18_3BE)
-#define SNDRV_PCM_FMTBIT_G723_24 _SNDRV_PCM_FMTBIT(G723_24)
-#define SNDRV_PCM_FMTBIT_G723_24_1B _SNDRV_PCM_FMTBIT(G723_24_1B)
-#define SNDRV_PCM_FMTBIT_G723_40 _SNDRV_PCM_FMTBIT(G723_40)
-#define SNDRV_PCM_FMTBIT_G723_40_1B _SNDRV_PCM_FMTBIT(G723_40_1B)
-#define SNDRV_PCM_FMTBIT_DSD_U8 _SNDRV_PCM_FMTBIT(DSD_U8)
-#define SNDRV_PCM_FMTBIT_DSD_U16_LE _SNDRV_PCM_FMTBIT(DSD_U16_LE)
-#define SNDRV_PCM_FMTBIT_DSD_U32_LE _SNDRV_PCM_FMTBIT(DSD_U32_LE)
-#define SNDRV_PCM_FMTBIT_DSD_U16_BE _SNDRV_PCM_FMTBIT(DSD_U16_BE)
-#define SNDRV_PCM_FMTBIT_DSD_U32_BE _SNDRV_PCM_FMTBIT(DSD_U32_BE)
+#define SNDRV_PCM_FMTBIT_S32_LE (1ULL << SNDRV_PCM_FORMAT_S32_LE)
+#define SNDRV_PCM_FMTBIT_S32_BE (1ULL << SNDRV_PCM_FORMAT_S32_BE)
+#define SNDRV_PCM_FMTBIT_U32_LE (1ULL << SNDRV_PCM_FORMAT_U32_LE)
+#define SNDRV_PCM_FMTBIT_U32_BE (1ULL << SNDRV_PCM_FORMAT_U32_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_BE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE)
+#define SNDRV_PCM_FMTBIT_MU_LAW (1ULL << SNDRV_PCM_FORMAT_MU_LAW)
+#define SNDRV_PCM_FMTBIT_A_LAW (1ULL << SNDRV_PCM_FORMAT_A_LAW)
+#define SNDRV_PCM_FMTBIT_IMA_ADPCM (1ULL << SNDRV_PCM_FORMAT_IMA_ADPCM)
+#define SNDRV_PCM_FMTBIT_MPEG (1ULL << SNDRV_PCM_FORMAT_MPEG)
+#define SNDRV_PCM_FMTBIT_GSM (1ULL << SNDRV_PCM_FORMAT_GSM)
+#define SNDRV_PCM_FMTBIT_S20_LE (1ULL << SNDRV_PCM_FORMAT_S20_LE)
+#define SNDRV_PCM_FMTBIT_U20_LE (1ULL << SNDRV_PCM_FORMAT_U20_LE)
+#define SNDRV_PCM_FMTBIT_S20_BE (1ULL << SNDRV_PCM_FORMAT_S20_BE)
+#define SNDRV_PCM_FMTBIT_U20_BE (1ULL << SNDRV_PCM_FORMAT_U20_BE)
+#define SNDRV_PCM_FMTBIT_SPECIAL (1ULL << SNDRV_PCM_FORMAT_SPECIAL)
+#define SNDRV_PCM_FMTBIT_S24_3LE (1ULL << SNDRV_PCM_FORMAT_S24_3LE)
+#define SNDRV_PCM_FMTBIT_U24_3LE (1ULL << SNDRV_PCM_FORMAT_U24_3LE)
+#define SNDRV_PCM_FMTBIT_S24_3BE (1ULL << SNDRV_PCM_FORMAT_S24_3BE)
+#define SNDRV_PCM_FMTBIT_U24_3BE (1ULL << SNDRV_PCM_FORMAT_U24_3BE)
+#define SNDRV_PCM_FMTBIT_S20_3LE (1ULL << SNDRV_PCM_FORMAT_S20_3LE)
+#define SNDRV_PCM_FMTBIT_U20_3LE (1ULL << SNDRV_PCM_FORMAT_U20_3LE)
+#define SNDRV_PCM_FMTBIT_S20_3BE (1ULL << SNDRV_PCM_FORMAT_S20_3BE)
+#define SNDRV_PCM_FMTBIT_U20_3BE (1ULL << SNDRV_PCM_FORMAT_U20_3BE)
+#define SNDRV_PCM_FMTBIT_S18_3LE (1ULL << SNDRV_PCM_FORMAT_S18_3LE)
+#define SNDRV_PCM_FMTBIT_U18_3LE (1ULL << SNDRV_PCM_FORMAT_U18_3LE)
+#define SNDRV_PCM_FMTBIT_S18_3BE (1ULL << SNDRV_PCM_FORMAT_S18_3BE)
+#define SNDRV_PCM_FMTBIT_U18_3BE (1ULL << SNDRV_PCM_FORMAT_U18_3BE)
+#define SNDRV_PCM_FMTBIT_G723_24 (1ULL << SNDRV_PCM_FORMAT_G723_24)
+#define SNDRV_PCM_FMTBIT_G723_24_1B (1ULL << SNDRV_PCM_FORMAT_G723_24_1B)
+#define SNDRV_PCM_FMTBIT_G723_40 (1ULL << SNDRV_PCM_FORMAT_G723_40)
+#define SNDRV_PCM_FMTBIT_G723_40_1B (1ULL << SNDRV_PCM_FORMAT_G723_40_1B)
+#define SNDRV_PCM_FMTBIT_DSD_U8 (1ULL << SNDRV_PCM_FORMAT_DSD_U8)
+#define SNDRV_PCM_FMTBIT_DSD_U16_LE (1ULL << SNDRV_PCM_FORMAT_DSD_U16_LE)
+#define SNDRV_PCM_FMTBIT_DSD_U32_LE (1ULL << SNDRV_PCM_FORMAT_DSD_U32_LE)
+#define SNDRV_PCM_FMTBIT_DSD_U16_BE (1ULL << SNDRV_PCM_FORMAT_DSD_U16_BE)
+#define SNDRV_PCM_FMTBIT_DSD_U32_BE (1ULL << SNDRV_PCM_FORMAT_DSD_U32_BE)
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE
@@ -228,11 +227,10 @@ struct snd_pcm_ops {
#define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_BE
#endif
-#define _SNDRV_PCM_SUBFMTBIT(fmt) BIT((__force int)SNDRV_PCM_SUBFORMAT_##fmt)
-#define SNDRV_PCM_SUBFMTBIT_STD _SNDRV_PCM_SUBFMTBIT(STD)
-#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX _SNDRV_PCM_SUBFMTBIT(MSBITS_MAX)
-#define SNDRV_PCM_SUBFMTBIT_MSBITS_20 _SNDRV_PCM_SUBFMTBIT(MSBITS_20)
-#define SNDRV_PCM_SUBFMTBIT_MSBITS_24 _SNDRV_PCM_SUBFMTBIT(MSBITS_24)
+#define SNDRV_PCM_SUBFMTBIT_STD (1U << SNDRV_PCM_SUBFORMAT_STD)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX (1U << SNDRV_PCM_SUBFORMAT_MSBITS_MAX)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_20 (1U << SNDRV_PCM_SUBFORMAT_MSBITS_20)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_24 (1U << SNDRV_PCM_SUBFORMAT_MSBITS_24)
struct snd_pcm_file {
struct snd_pcm_substream *substream;
@@ -1515,7 +1513,7 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
*/
static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
{
- return 1ULL << (__force int) pcm_format;
+ return 1ULL << pcm_format;
}
/**
@@ -1523,9 +1521,7 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
* @f: the iterator variable in snd_pcm_format_t type
*/
#define pcm_for_each_format(f) \
- for ((f) = SNDRV_PCM_FORMAT_FIRST; \
- (__force int)(f) <= (__force int)SNDRV_PCM_FORMAT_LAST; \
- (f) = (__force snd_pcm_format_t)((__force int)(f) + 1))
+ for ((f) = SNDRV_PCM_FORMAT_FIRST; (f) <= SNDRV_PCM_FORMAT_LAST; (f)++)
/* printk helpers */
#define pcm_err(pcm, fmt, args...) \
diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h
--- a/include/sound/pcm_params.h
+++ b/include/sound/pcm_params.h
@@ -71,7 +71,7 @@ static inline void snd_mask_set(struct snd_mask *mask, unsigned int val)
static inline void snd_mask_set_format(struct snd_mask *mask,
snd_pcm_format_t format)
{
- snd_mask_set(mask, (__force unsigned int)format);
+ snd_mask_set(mask, format);
}
static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val)
@@ -132,7 +132,7 @@ static inline int snd_mask_test(const struct snd_mask *mask, unsigned int val)
static inline int snd_mask_test_format(const struct snd_mask *mask,
snd_pcm_format_t format)
{
- return snd_mask_test(mask, (__force unsigned int)format);
+ return snd_mask_test(mask, format);
}
static inline int snd_mask_single(const struct snd_mask *mask)
@@ -302,8 +302,7 @@ static inline int snd_interval_eq(const struct snd_interval *i1, const struct sn
*/
static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
{
- return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p,
- SNDRV_PCM_HW_PARAM_ACCESS));
+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_ACCESS));
}
/**
@@ -312,8 +311,7 @@ static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
*/
static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
{
- return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p,
- SNDRV_PCM_HW_PARAM_FORMAT));
+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_FORMAT));
}
/**
@@ -323,8 +321,7 @@ static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
static inline snd_pcm_subformat_t
params_subformat(const struct snd_pcm_hw_params *p)
{
- return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p,
- SNDRV_PCM_HW_PARAM_SUBFORMAT));
+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_SUBFORMAT));
}
/**
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -176,8 +176,9 @@ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
/* main midi functions */
int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info);
-int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
- int mode, struct snd_rawmidi_file *rfile);
+int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice,
+ int mode, struct snd_rawmidi_file *rfile,
+ int depth);
int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile);
int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_params *params);
@@ -191,6 +192,15 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream,
long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream,
const unsigned char *buf, long count);
+/* non-nested version */
+static inline int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi,
+ int subdevice,
+ int mode,
+ struct snd_rawmidi_file *rfile)
+{
+ return snd_rawmidi_kernel_open_nested(rmidi, subdevice, mode, rfile, 0);
+}
+
/* set up the tied devices */
static inline void snd_rawmidi_tie_devices(struct snd_rawmidi *r1,
struct snd_rawmidi *r2)
diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h
--- a/include/sound/seq_virmidi.h
+++ b/include/sound/seq_virmidi.h
@@ -46,7 +46,6 @@ struct snd_virmidi_dev {
int client; /* created/attached client */
int port; /* created/attached port */
unsigned int flags; /* SNDRV_VIRMIDI_* */
- rwlock_t filelist_lock;
struct rw_semaphore filelist_sem;
struct list_head filelist;
};
diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h
--- a/include/uapi/sound/asequencer.h
+++ b/include/uapi/sound/asequencer.h
@@ -308,16 +308,6 @@ struct snd_seq_ump_event {
};
};
-/*
- * bounce event - stored as variable size data
- */
-struct snd_seq_event_bounce {
- int err;
- struct snd_seq_event event;
- /* external data follows here. */
-};
-
-
/* system information */
struct snd_seq_system_info {
int queues; /* maximum queues count */
@@ -348,10 +338,10 @@ struct snd_seq_running_info {
/* client types */
-typedef int __bitwise snd_seq_client_type_t;
-#define NO_CLIENT ((__force snd_seq_client_type_t) 0)
-#define USER_CLIENT ((__force snd_seq_client_type_t) 1)
-#define KERNEL_CLIENT ((__force snd_seq_client_type_t) 2)
+typedef int snd_seq_client_type_t;
+#define NO_CLIENT 0
+#define USER_CLIENT 1
+#define KERNEL_CLIENT 2
/* event filter flags */
#define SNDRV_SEQ_FILTER_BROADCAST (1U<<0) /* accept broadcast messages */
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -169,72 +169,72 @@ enum {
SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE,
};
-typedef int __bitwise snd_pcm_access_t;
-#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) /* interleaved mmap */
-#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) /* noninterleaved mmap */
-#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) /* complex mmap */
-#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) /* readi/writei */
-#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) /* readn/writen */
+typedef int snd_pcm_access_t;
+#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED 0 /* interleaved mmap */
+#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED 1 /* noninterleaved mmap */
+#define SNDRV_PCM_ACCESS_MMAP_COMPLEX 2 /* complex mmap */
+#define SNDRV_PCM_ACCESS_RW_INTERLEAVED 3 /* readi/writei */
+#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED 4 /* readn/writen */
#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED
-typedef int __bitwise snd_pcm_format_t;
-#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0)
-#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1)
-#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2)
-#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3)
-#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4)
-#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5)
-#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) /* low three bytes */
-#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */
-#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */
-#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */
+typedef int snd_pcm_format_t;
+#define SNDRV_PCM_FORMAT_S8 0
+#define SNDRV_PCM_FORMAT_U8 1
+#define SNDRV_PCM_FORMAT_S16_LE 2
+#define SNDRV_PCM_FORMAT_S16_BE 3
+#define SNDRV_PCM_FORMAT_U16_LE 4
+#define SNDRV_PCM_FORMAT_U16_BE 5
+#define SNDRV_PCM_FORMAT_S24_LE 6 /* low three bytes */
+#define SNDRV_PCM_FORMAT_S24_BE 7 /* low three bytes */
+#define SNDRV_PCM_FORMAT_U24_LE 8 /* low three bytes */
+#define SNDRV_PCM_FORMAT_U24_BE 9 /* low three bytes */
/*
* For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
* available bit count in most significant bit. It's for the case of so-called 'left-justified' or
* `right-padding` sample which has less width than 32 bit.
*/
-#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
-#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
-#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
-#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13)
-#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
-#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
-#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
-#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
-#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) /* IEC-958 subframe, Little Endian */
-#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) /* IEC-958 subframe, Big Endian */
-#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20)
-#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21)
-#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22)
-#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23)
-#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24)
-#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */
-#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */
-#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */
-#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_S32_LE 10
+#define SNDRV_PCM_FORMAT_S32_BE 11
+#define SNDRV_PCM_FORMAT_U32_LE 12
+#define SNDRV_PCM_FORMAT_U32_BE 13
+#define SNDRV_PCM_FORMAT_FLOAT_LE 14 /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+#define SNDRV_PCM_FORMAT_FLOAT_BE 15 /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+#define SNDRV_PCM_FORMAT_FLOAT64_LE 16 /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+#define SNDRV_PCM_FORMAT_FLOAT64_BE 17 /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE 18 /* IEC-958 subframe, Little Endian */
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE 19 /* IEC-958 subframe, Big Endian */
+#define SNDRV_PCM_FORMAT_MU_LAW 20
+#define SNDRV_PCM_FORMAT_A_LAW 21
+#define SNDRV_PCM_FORMAT_IMA_ADPCM 22
+#define SNDRV_PCM_FORMAT_MPEG 23
+#define SNDRV_PCM_FORMAT_GSM 24
+#define SNDRV_PCM_FORMAT_S20_LE 25 /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_S20_BE 26 /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_U20_LE 27 /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_U20_BE 28 /* in four bytes, LSB justified */
/* gap in the numbering for a future standard linear format */
-#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31)
-#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */
-#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */
-#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
-#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
-#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
-#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
-#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
-#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */
-#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */
-#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */
+#define SNDRV_PCM_FORMAT_SPECIAL 31
+#define SNDRV_PCM_FORMAT_S24_3LE 32 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S24_3BE 33 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U24_3LE 34 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U24_3BE 35 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S20_3LE 36 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S20_3BE 37 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U20_3LE 38 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U20_3BE 39 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S18_3LE 40 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S18_3BE 41 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U18_3LE 42 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U18_3BE 43 /* in three bytes */
+#define SNDRV_PCM_FORMAT_G723_24 44 /* 8 samples in 3 bytes */
+#define SNDRV_PCM_FORMAT_G723_24_1B 45 /* 1 sample in 1 byte */
+#define SNDRV_PCM_FORMAT_G723_40 46 /* 8 Samples in 5 bytes */
+#define SNDRV_PCM_FORMAT_G723_40_1B 47 /* 1 sample in 1 byte */
+#define SNDRV_PCM_FORMAT_DSD_U8 48 /* DSD, 1-byte samples DSD (x8) */
+#define SNDRV_PCM_FORMAT_DSD_U16_LE 49 /* DSD, 2-byte samples DSD (x16), little endian */
+#define SNDRV_PCM_FORMAT_DSD_U32_LE 50 /* DSD, 4-byte samples DSD (x32), little endian */
+#define SNDRV_PCM_FORMAT_DSD_U16_BE 51 /* DSD, 2-byte samples DSD (x16), big endian */
+#define SNDRV_PCM_FORMAT_DSD_U32_BE 52 /* DSD, 4-byte samples DSD (x32), big endian */
#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE
#define SNDRV_PCM_FORMAT_FIRST SNDRV_PCM_FORMAT_S8
@@ -265,11 +265,11 @@ typedef int __bitwise snd_pcm_format_t;
#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE
#endif
-typedef int __bitwise snd_pcm_subformat_t;
-#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0)
-#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX ((__force snd_pcm_subformat_t) 1)
-#define SNDRV_PCM_SUBFORMAT_MSBITS_20 ((__force snd_pcm_subformat_t) 2)
-#define SNDRV_PCM_SUBFORMAT_MSBITS_24 ((__force snd_pcm_subformat_t) 3)
+typedef int snd_pcm_subformat_t;
+#define SNDRV_PCM_SUBFORMAT_STD 0
+#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX 1
+#define SNDRV_PCM_SUBFORMAT_MSBITS_20 2
+#define SNDRV_PCM_SUBFORMAT_MSBITS_24 3
#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_MSBITS_24
#define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */
@@ -303,16 +303,16 @@ typedef int __bitwise snd_pcm_subformat_t;
#define __SND_STRUCT_TIME64
#endif
-typedef int __bitwise snd_pcm_state_t;
-#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */
-#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */
-#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) /* stream is ready to start */
-#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) /* stream is running */
-#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) /* stream reached an xrun */
-#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) /* stream is draining */
-#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) /* stream is paused */
-#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) /* hardware is suspended */
-#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) /* hardware is disconnected */
+typedef int snd_pcm_state_t;
+#define SNDRV_PCM_STATE_OPEN 0 /* stream is open */
+#define SNDRV_PCM_STATE_SETUP 1 /* stream has a setup */
+#define SNDRV_PCM_STATE_PREPARED 2 /* stream is ready to start */
+#define SNDRV_PCM_STATE_RUNNING 3 /* stream is running */
+#define SNDRV_PCM_STATE_XRUN 4 /* stream reached an xrun */
+#define SNDRV_PCM_STATE_DRAINING 5 /* stream is draining */
+#define SNDRV_PCM_STATE_PAUSED 6 /* stream is paused */
+#define SNDRV_PCM_STATE_SUSPENDED 7 /* hardware is suspended */
+#define SNDRV_PCM_STATE_DISCONNECTED 8 /* hardware is disconnected */
#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED
enum {
@@ -1058,7 +1058,7 @@ struct snd_timer_tread {
* *
****************************************************************************/
-#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9)
+#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
struct snd_ctl_card_info {
int card; /* card number */
@@ -1072,24 +1072,43 @@ struct snd_ctl_card_info {
unsigned char components[128]; /* card components / fine identification, delimited with one space (AC97 etc..) */
};
-typedef int __bitwise snd_ctl_elem_type_t;
-#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) /* invalid */
-#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) /* boolean type */
-#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) /* integer type */
-#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) /* enumerated type */
-#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) /* byte array */
-#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) /* IEC958 (S/PDIF) setup */
-#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) /* 64-bit integer type */
+/*
+ * Card components can exceed the fixed 128 bytes in snd_ctl_card_info.
+ * Use SNDRV_CTL_IOCTL_CARD_BYTES with type SND_CTL_CARD_BTYPE_COMPONENTS
+ * to retrieve the full string.
+ */
+
+/* Type values for struct snd_ctl_card_bytes::type */
+enum {
+ SND_CTL_CARD_BTYPE_COMPONENTS = 1, /* full card components string */
+};
+
+struct snd_ctl_card_bytes {
+ __u32 type; /* SND_CTL_CARD_BTYPE_* */
+ __u32 data_allocated; /* size of @data buffer in bytes */
+ __u32 data_len; /* in/out: actual data length in bytes */
+ __u32 reserved; /* explicit pad */
+ __u64 data; /* user buffer (pointer stored as __u64) */
+};
+
+typedef int snd_ctl_elem_type_t;
+#define SNDRV_CTL_ELEM_TYPE_NONE 0 /* invalid */
+#define SNDRV_CTL_ELEM_TYPE_BOOLEAN 1 /* boolean type */
+#define SNDRV_CTL_ELEM_TYPE_INTEGER 2 /* integer type */
+#define SNDRV_CTL_ELEM_TYPE_ENUMERATED 3 /* enumerated type */
+#define SNDRV_CTL_ELEM_TYPE_BYTES 4 /* byte array */
+#define SNDRV_CTL_ELEM_TYPE_IEC958 5 /* IEC958 (S/PDIF) setup */
+#define SNDRV_CTL_ELEM_TYPE_INTEGER64 6 /* 64-bit integer type */
#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64
-typedef int __bitwise snd_ctl_elem_iface_t;
-#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) /* global control */
-#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) /* hardware dependent device */
-#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) /* virtual mixer device */
-#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) /* PCM device */
-#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) /* RawMidi device */
-#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) /* timer device */
-#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) /* sequencer client */
+typedef int snd_ctl_elem_iface_t;
+#define SNDRV_CTL_ELEM_IFACE_CARD 0 /* global control */
+#define SNDRV_CTL_ELEM_IFACE_HWDEP 1 /* hardware dependent device */
+#define SNDRV_CTL_ELEM_IFACE_MIXER 2 /* virtual mixer device */
+#define SNDRV_CTL_ELEM_IFACE_PCM 3 /* PCM device */
+#define SNDRV_CTL_ELEM_IFACE_RAWMIDI 4 /* RawMidi device */
+#define SNDRV_CTL_ELEM_IFACE_TIMER 5 /* timer device */
+#define SNDRV_CTL_ELEM_IFACE_SEQUENCER 6 /* sequencer client */
#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER
#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0)
@@ -1198,6 +1217,7 @@ struct snd_ctl_tlv {
#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
+#define SNDRV_CTL_IOCTL_CARD_BYTES _IOWR('U', 0x02, struct snd_ctl_card_bytes)
#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h
--- a/include/uapi/sound/firewire.h
+++ b/include/uapi/sound/firewire.h
@@ -79,11 +79,12 @@ struct snd_firewire_event_motu_register_dsp_change {
*
* @type: Fixed to SNDRV_FIREWIRE_EVENT_FF400_MESSAGE.
* @message_count: The number of messages.
+ * @messages: Array of @message_count messages
* @messages.message: The messages expressing hardware knob operation.
* @messages.tstamp: The isochronous cycle at which the request subaction of asynchronous
- * transaction was sent to deliver the message. It has 16 bit unsigned integer
+ * transaction was sent to deliver the message. It has 16-bit unsigned integer
* value. The higher 3 bits of value expresses the lower three bits of second
- * field in the format of CYCLE_TIME, up to 7. The rest 13 bits expresses cycle
+ * field in the format of CYCLE_TIME, up to 7. The remaining 13 bits express cycle
* field up to 7999.
*
* The structure expresses message transmitted by Fireface 400 when operating hardware knob.
@@ -191,8 +192,9 @@ struct snd_firewire_motu_register_dsp_meter {
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_ALIGNED_INPUT_COUNT (SNDRV_FIREWIRE_MOTU_REGISTER_DSP_INPUT_COUNT + 2)
/**
- * snd_firewire_motu_register_dsp_parameter - the container for parameters of DSP controlled
- * by register access.
+ * struct snd_firewire_motu_register_dsp_parameter - the container for parameters
+ * of DSP controlled by register access.
+ * @mixer: aggregate of @mixer.source and @mixer.output
* @mixer.source.gain: The gain of source to mixer.
* @mixer.source.pan: The L/R balance of source to mixer.
* @mixer.source.flag: The flag of source to mixer, including mute, solo.
@@ -200,21 +202,25 @@ struct snd_firewire_motu_register_dsp_meter {
* Audio Express.
* @mixer.source.paired_width: The width of paired source to mixer, only for 4 pre and
* Audio Express.
+ * @mixer.output: FIXME
* @mixer.output.paired_volume: The volume of paired output from mixer.
* @mixer.output.paired_flag: The flag of paired output from mixer.
+ * @output: output parameters
* @output.main_paired_volume: The volume of paired main output.
* @output.hp_paired_volume: The volume of paired hp output.
* @output.hp_paired_assignment: The source assigned to paired hp output.
- * @output.reserved: Padding for 32 bit alignment for future extension.
+ * @output.reserved: Padding for 32-bit alignment for future extension.
+ * @line_input: line input parameters
* @line_input.boost_flag: The flags of boost for line inputs, only for 828mk2 and Traveler.
* @line_input.nominal_level_flag: The flags of nominal level for line inputs, only for 828mk2 and
* Traveler.
- * @line_input.reserved: Padding for 32 bit alignment for future extension.
+ * @line_input.reserved: Padding for 32-bit alignment for future extension.
+ * @input: input parameters
* @input.gain_and_invert: The value including gain and invert for input, only for Ultralite, 4 pre
* and Audio Express.
* @input.flag: The flag of input; e.g. jack detection, phantom power, and pad, only for Ultralite,
* 4 pre and Audio express.
- * @reserved: Padding so that the size of structure is kept to 512 byte, but for future extension.
+ * @reserved: Padding so that the size of structure is kept to 512 bytes, but for future extension.
*
* The structure expresses the set of parameters for DSP controlled by register access.
*/
@@ -272,8 +278,8 @@ struct snd_firewire_motu_register_dsp_parameter {
* controlled by command
* @data: Signal level meters. The mapping between position and signal channel is model-dependent.
*
- * The structure expresses the part of DSP status for hardware meter. The 32 bit storage is
- * estimated to include IEEE 764 32 bit single precision floating point (binary32) value. It is
+ * The structure expresses the part of DSP status for hardware meter. The 32-bit storage is
+ * estimated to include IEEE 764 32-bit single precision floating point (binary32) value. It is
* expected to be linear value (not logarithm) for audio signal level between 0.0 and +1.0.
*/
struct snd_firewire_motu_command_dsp_meter {
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -693,7 +693,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct snd_card *card;
struct atmel_ac97c *chip;
- struct resource *regs;
+ void __iomem *regs;
struct clk *pclk;
static const struct snd_ac97_bus_ops ops = {
.write = atmel_ac97c_write,
@@ -702,42 +702,34 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
int retval;
int irq;
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- dev_dbg(&pdev->dev, "no memory resource\n");
- return -ENXIO;
- }
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_dbg(&pdev->dev, "could not get irq: %d\n", irq);
+ if (irq < 0)
return irq;
- }
- pclk = clk_get(&pdev->dev, "ac97_clk");
+ pclk = devm_clk_get_enabled(&pdev->dev, "ac97_clk");
if (IS_ERR(pclk)) {
dev_dbg(&pdev->dev, "no peripheral clock\n");
return PTR_ERR(pclk);
}
- retval = clk_prepare_enable(pclk);
- if (retval)
- goto err_prepare_enable;
- retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
+ retval = snd_devm_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
SNDRV_DEFAULT_STR1, THIS_MODULE,
sizeof(struct atmel_ac97c), &card);
if (retval) {
dev_dbg(&pdev->dev, "could not create sound card device\n");
- goto err_snd_card_new;
+ return retval;
}
chip = get_chip(card);
- retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
- if (retval) {
- dev_dbg(&pdev->dev, "unable to request irq %d\n", irq);
- goto err_request_irq;
- }
+ retval = devm_request_irq(&pdev->dev, irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
+ if (retval)
+ return retval;
+
chip->irq = irq;
spin_lock_init(&chip->lock);
@@ -749,13 +741,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
chip->card = card;
chip->pclk = pclk;
chip->pdev = pdev;
- chip->regs = ioremap(regs->start, resource_size(regs));
-
- if (!chip->regs) {
- dev_dbg(&pdev->dev, "could not remap register memory\n");
- retval = -ENOMEM;
- goto err_ioremap;
- }
+ chip->regs = regs;
chip->reset_pin = devm_gpiod_get_index(dev, "ac97", 2, GPIOD_OUT_HIGH);
if (IS_ERR(chip->reset_pin))
@@ -770,25 +756,25 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
if (retval) {
dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
- goto err_ac97_bus;
+ return retval;
}
retval = atmel_ac97c_mixer_new(chip);
if (retval) {
dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
- goto err_ac97_bus;
+ return retval;
}
retval = atmel_ac97c_pcm_new(chip);
if (retval) {
dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
- goto err_ac97_bus;
+ return retval;
}
retval = snd_card_register(card);
if (retval) {
dev_dbg(&pdev->dev, "could not register sound card\n");
- goto err_ac97_bus;
+ return retval;
}
platform_set_drvdata(pdev, card);
@@ -797,18 +783,6 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
chip->regs, irq);
return 0;
-
-err_ac97_bus:
- iounmap(chip->regs);
-err_ioremap:
- free_irq(irq, chip);
-err_request_irq:
- snd_card_free(card);
-err_snd_card_new:
- clk_disable_unprepare(pclk);
-err_prepare_enable:
- clk_put(pclk);
- return retval;
}
static int atmel_ac97c_suspend(struct device *pdev)
@@ -839,13 +813,6 @@ static void atmel_ac97c_remove(struct platform_device *pdev)
ac97c_writel(chip, CAMR, 0);
ac97c_writel(chip, COMR, 0);
ac97c_writel(chip, MR, 0);
-
- clk_disable_unprepare(chip->pclk);
- clk_put(chip->pclk);
- iounmap(chip->regs);
- free_irq(chip->irq, chip);
-
- snd_card_free(card);
}
static struct platform_driver atmel_ac97c_driver = {
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -1393,17 +1393,17 @@ static long snd_compr_ioctl_compat(struct file *file, unsigned int cmd,
#endif
static const struct file_operations snd_compr_file_ops = {
- .owner = THIS_MODULE,
- .open = snd_compr_open,
- .release = snd_compr_free,
- .write = snd_compr_write,
- .read = snd_compr_read,
- .unlocked_ioctl = snd_compr_ioctl,
+ .owner = THIS_MODULE,
+ .open = snd_compr_open,
+ .release = snd_compr_free,
+ .write = snd_compr_write,
+ .read = snd_compr_read,
+ .unlocked_ioctl = snd_compr_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = snd_compr_ioctl_compat,
+ .compat_ioctl = snd_compr_ioctl_compat,
#endif
- .mmap = snd_compr_mmap,
- .poll = snd_compr_poll,
+ .mmap = snd_compr_mmap,
+ .poll = snd_compr_poll,
};
static int snd_compress_dev_register(struct snd_device *device)
diff --git a/sound/core/control.c b/sound/core/control.c
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -38,7 +38,7 @@ struct snd_kctl_ioctl {
snd_kctl_ioctl_func_t fioctl;
};
-static DECLARE_RWSEM(snd_ioctl_rwsem);
+DECLARE_RWSEM(snd_ioctl_rwsem);
static DECLARE_RWSEM(snd_ctl_layer_rwsem);
static LIST_HEAD(snd_control_ioctls);
#ifdef CONFIG_COMPAT
@@ -55,9 +55,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
struct snd_ctl_file *ctl;
int i, err;
- err = stream_open(inode, file);
- if (err < 0)
- return err;
+ stream_open(inode, file);
card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
if (!card) {
@@ -65,12 +63,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
goto __error1;
}
err = snd_card_file_add(card, file);
- if (err < 0) {
- err = -ENODEV;
+ if (err < 0)
goto __error1;
- }
if (!try_module_get(card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
@@ -876,23 +872,81 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
{
struct snd_ctl_card_info *info __free(kfree) =
kzalloc(sizeof(*info), GFP_KERNEL);
+ ssize_t n;
if (! info)
return -ENOMEM;
+
+ static_assert(sizeof(info->components) >= 2);
+
scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
+ const char *components = card->components;
+
+ if (!components)
+ components = "";
+
info->card = card->number;
strscpy(info->id, card->id, sizeof(info->id));
strscpy(info->driver, card->driver, sizeof(info->driver));
strscpy(info->name, card->shortname, sizeof(info->name));
strscpy(info->longname, card->longname, sizeof(info->longname));
strscpy(info->mixername, card->mixername, sizeof(info->mixername));
- strscpy(info->components, card->components, sizeof(info->components));
+ n = strscpy(info->components, components, sizeof(info->components));
+ if (n < 0) // mark the truncation with '>' before NULL terminator
+ info->components[sizeof(info->components) - 2] = '>';
}
if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info)))
return -EFAULT;
return 0;
}
+static int snd_ctl_card_bytes(struct snd_card *card,
+ struct snd_ctl_card_bytes *info,
+ unsigned int __user *data_len_out)
+{
+ unsigned int data_len;
+
+ switch (info->type) {
+ case SND_CTL_CARD_BTYPE_COMPONENTS:
+ scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
+ const char *components = card->components;
+
+ if (!components)
+ components = "";
+
+ data_len = strlen(components) + 1;
+
+ if (!info->data || info->data_allocated == 0)
+ break;
+
+ if (info->data_allocated < data_len)
+ return -ENOMEM;
+
+ if (copy_to_user(u64_to_user_ptr(info->data), components, data_len))
+ return -EFAULT;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (put_user(data_len, data_len_out))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int snd_ctl_card_bytes_user(struct snd_card *card,
+ struct snd_ctl_card_bytes __user *_info)
+{
+ struct snd_ctl_card_bytes info;
+
+ if (copy_from_user(&info, _info, sizeof(info)))
+ return -EFAULT;
+
+ return snd_ctl_card_bytes(card, &info, &_info->data_len);
+}
+
static int snd_ctl_elem_list(struct snd_card *card,
struct snd_ctl_elem_list *list)
{
@@ -1990,6 +2044,8 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
case SNDRV_CTL_IOCTL_CARD_INFO:
return snd_ctl_card_info(card, ctl, cmd, argp);
+ case SNDRV_CTL_IOCTL_CARD_BYTES:
+ return snd_ctl_card_bytes_user(card, argp);
case SNDRV_CTL_IOCTL_ELEM_LIST:
return snd_ctl_elem_list_user(card, argp);
case SNDRV_CTL_IOCTL_ELEM_INFO:
@@ -2339,16 +2395,15 @@ EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer);
* INIT PART
*/
-static const struct file_operations snd_ctl_f_ops =
-{
- .owner = THIS_MODULE,
- .read = snd_ctl_read,
- .open = snd_ctl_open,
- .release = snd_ctl_release,
- .poll = snd_ctl_poll,
- .unlocked_ioctl = snd_ctl_ioctl,
- .compat_ioctl = snd_ctl_ioctl_compat,
- .fasync = snd_ctl_fasync,
+static const struct file_operations snd_ctl_f_ops = {
+ .owner = THIS_MODULE,
+ .read = snd_ctl_read,
+ .open = snd_ctl_open,
+ .release = snd_ctl_release,
+ .poll = snd_ctl_poll,
+ .unlocked_ioctl = snd_ctl_ioctl,
+ .compat_ioctl = snd_ctl_ioctl_compat,
+ .fasync = snd_ctl_fasync,
};
/* call lops under rwsems; called from snd_ctl_dev_*() below() */
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -226,8 +226,8 @@ static int copy_ctl_value_from_user(struct snd_card *card,
if (type < 0)
return type;
- if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
- type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+ type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@@ -236,7 +236,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
data->value.integer.value[i] = val;
}
} else {
- size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
+ size = get_elem_size(type, count);
if (size < 0) {
dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
return -EINVAL;
@@ -259,8 +259,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
struct snd_ctl_elem_value32 __user *data32 = userdata;
int i, size;
- if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
- type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+ type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@@ -269,7 +269,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
return -EFAULT;
}
} else {
- size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
+ size = get_elem_size(type, count);
if (copy_to_user(valuep, data->value.bytes.data, size))
return -EFAULT;
}
@@ -417,7 +417,7 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
break;
}
return snd_ctl_elem_add(file, data, replace);
-}
+}
enum {
SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32),
@@ -446,6 +446,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
switch (cmd) {
case SNDRV_CTL_IOCTL_PVERSION:
case SNDRV_CTL_IOCTL_CARD_INFO:
+ case SNDRV_CTL_IOCTL_CARD_BYTES:
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
case SNDRV_CTL_IOCTL_POWER:
case SNDRV_CTL_IOCTL_POWER_STATE:
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -87,7 +87,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
if (!try_module_get(hw->card->module)) {
snd_card_unref(hw->card);
- return -EFAULT;
+ return -ENODEV;
}
init_waitqueue_entry(&wait, current);
@@ -323,18 +323,17 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
*/
-static const struct file_operations snd_hwdep_f_ops =
-{
- .owner = THIS_MODULE,
- .llseek = snd_hwdep_llseek,
- .read = snd_hwdep_read,
- .write = snd_hwdep_write,
- .open = snd_hwdep_open,
- .release = snd_hwdep_release,
- .poll = snd_hwdep_poll,
- .unlocked_ioctl = snd_hwdep_ioctl,
- .compat_ioctl = snd_hwdep_ioctl_compat,
- .mmap = snd_hwdep_mmap,
+static const struct file_operations snd_hwdep_f_ops = {
+ .owner = THIS_MODULE,
+ .llseek = snd_hwdep_llseek,
+ .read = snd_hwdep_read,
+ .write = snd_hwdep_write,
+ .open = snd_hwdep_open,
+ .release = snd_hwdep_release,
+ .poll = snd_hwdep_poll,
+ .unlocked_ioctl = snd_hwdep_ioctl,
+ .compat_ioctl = snd_hwdep_ioctl_compat,
+ .mmap = snd_hwdep_mmap,
};
static void snd_hwdep_free(struct snd_hwdep *hwdep)
diff --git a/sound/core/info.c b/sound/core/info.c
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -78,7 +78,7 @@ static int alloc_info_private(struct snd_info_entry *entry,
if (!entry || !entry->p)
return -ENODEV;
if (!try_module_get(entry->module))
- return -EFAULT;
+ return -ENODEV;
data = kzalloc_obj(*data);
if (!data) {
module_put(entry->module);
diff --git a/sound/core/init.c b/sound/core/init.c
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -466,20 +466,19 @@ static int snd_disconnect_fasync(int fd, struct file *file, int on)
return -ENODEV;
}
-static const struct file_operations snd_shutdown_f_ops =
-{
- .owner = THIS_MODULE,
- .llseek = snd_disconnect_llseek,
- .read = snd_disconnect_read,
- .write = snd_disconnect_write,
- .release = snd_disconnect_release,
- .poll = snd_disconnect_poll,
- .unlocked_ioctl = snd_disconnect_ioctl,
+static const struct file_operations snd_shutdown_f_ops = {
+ .owner = THIS_MODULE,
+ .llseek = snd_disconnect_llseek,
+ .read = snd_disconnect_read,
+ .write = snd_disconnect_write,
+ .release = snd_disconnect_release,
+ .poll = snd_disconnect_poll,
+ .unlocked_ioctl = snd_disconnect_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = snd_disconnect_ioctl,
+ .compat_ioctl = snd_disconnect_ioctl,
#endif
- .mmap = snd_disconnect_mmap,
- .fasync = snd_disconnect_fasync
+ .mmap = snd_disconnect_mmap,
+ .fasync = snd_disconnect_fasync
};
/**
@@ -592,6 +591,9 @@ static int snd_card_do_free(struct snd_card *card)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
#endif
snd_device_free_all(card);
+ kfree(card->components);
+ card->components = NULL;
+ card->components_alloc_size = 0;
if (card->private_free)
card->private_free(card);
#ifdef CONFIG_SND_CTL_DEBUG
@@ -725,7 +727,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
int len, loops;
bool is_default = false;
char *id;
-
+
copy_valid_id_string(card, src, nid);
id = card->id;
@@ -1034,21 +1036,44 @@ int __init snd_card_info_init(void)
*
* Return: Zero otherwise a negative error code.
*/
-
+
int snd_component_add(struct snd_card *card, const char *component)
{
char *ptr;
int len = strlen(component);
+ unsigned int cur_len, need_len;
- ptr = strstr(card->components, component);
- if (ptr != NULL) {
- if (ptr[len] == '\0' || ptr[len] == ' ') /* already there */
- return 1;
+ guard(rwsem_write)(&snd_ioctl_rwsem);
+
+ if (card->components) {
+ ptr = strstr(card->components, component);
+ if (ptr) {
+ if (ptr[len] == '\0' || ptr[len] == ' ') /* already there */
+ return 1;
+ }
+ cur_len = strlen(card->components) + 1;
+ } else {
+ cur_len = 0;
}
- if (strlen(card->components) + 1 + len + 1 > sizeof(card->components)) {
+
+ need_len = cur_len + len + 1;
+ if (need_len > 512) {
snd_BUG();
return -ENOMEM;
}
+
+ if (need_len > card->components_alloc_size) {
+ unsigned int new_alloc = roundup(need_len, 32);
+
+ ptr = krealloc(card->components, new_alloc, GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+ if (!card->components)
+ ptr[0] = '\0';
+ card->components = ptr;
+ card->components_alloc_size = new_alloc;
+ }
+
if (card->components[0] != '\0')
strcat(card->components, " ");
strcat(card->components, component);
diff --git a/sound/core/jack.c b/sound/core/jack.c
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -303,41 +303,41 @@ static ssize_t jack_type_read(struct file *file,
}
static const struct file_operations jack_type_fops = {
- .open = simple_open,
- .read = jack_type_read,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = jack_type_read,
+ .llseek = default_llseek,
};
#endif
static const struct file_operations sw_inject_enable_fops = {
- .open = simple_open,
- .read = sw_inject_enable_read,
- .write = sw_inject_enable_write,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = sw_inject_enable_read,
+ .write = sw_inject_enable_write,
+ .llseek = default_llseek,
};
static const struct file_operations jackin_inject_fops = {
- .open = simple_open,
- .write = jackin_inject_write,
- .llseek = default_llseek,
+ .open = simple_open,
+ .write = jackin_inject_write,
+ .llseek = default_llseek,
};
static const struct file_operations jack_kctl_id_fops = {
- .open = simple_open,
- .read = jack_kctl_id_read,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = jack_kctl_id_read,
+ .llseek = default_llseek,
};
static const struct file_operations jack_kctl_mask_bits_fops = {
- .open = simple_open,
- .read = jack_kctl_mask_bits_read,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = jack_kctl_mask_bits_read,
+ .llseek = default_llseek,
};
static const struct file_operations jack_kctl_status_fops = {
- .open = simple_open,
- .read = jack_kctl_status_read,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = jack_kctl_status_read,
+ .llseek = default_llseek,
};
static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack,
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -30,9 +30,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
struct snd_mixer_oss_file *fmixer;
int err;
- err = nonseekable_open(inode, file);
- if (err < 0)
- return err;
+ nonseekable_open(inode, file);
card = snd_lookup_oss_minor_data(iminor(inode),
SNDRV_OSS_DEVICE_TYPE_MIXER);
@@ -60,7 +58,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
kfree(fmixer);
snd_card_file_remove(card, file);
snd_card_unref(card);
- return -EFAULT;
+ return -ENODEV;
}
snd_card_unref(card);
return 0;
@@ -407,13 +405,12 @@ static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd,
* REGISTRATION PART
*/
-static const struct file_operations snd_mixer_oss_f_ops =
-{
- .owner = THIS_MODULE,
- .open = snd_mixer_oss_open,
- .release = snd_mixer_oss_release,
- .unlocked_ioctl = snd_mixer_oss_ioctl,
- .compat_ioctl = snd_mixer_oss_ioctl_compat,
+static const struct file_operations snd_mixer_oss_f_ops = {
+ .owner = THIS_MODULE,
+ .open = snd_mixer_oss_open,
+ .release = snd_mixer_oss_release,
+ .unlocked_ioctl = snd_mixer_oss_ioctl,
+ .compat_ioctl = snd_mixer_oss_ioctl_compat,
};
/*
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -879,11 +879,11 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
_snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
snd_mask_none(&mask);
if (atomic_read(&substream->mmap_count))
- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
else {
- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
if (!direct)
- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
}
err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
if (err < 0) {
@@ -909,7 +909,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
else
sformat = snd_pcm_plug_slave_format(format, sformat_mask);
- if ((__force int)sformat < 0 ||
+ if (sformat < 0 ||
!snd_mask_test_format(sformat_mask, sformat)) {
pcm_for_each_format(sformat) {
if (snd_mask_test_format(sformat_mask, sformat) &&
@@ -921,7 +921,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
goto failure;
}
format_found:
- err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0);
+ err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
if (err < 0)
goto failure;
@@ -930,9 +930,9 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
} else {
_snd_pcm_hw_params_any(params);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
- (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
+ SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
- (__force int)snd_pcm_oss_format_from(runtime->oss.format), 0);
+ snd_pcm_oss_format_from(runtime->oss.format), 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
runtime->oss.channels, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
@@ -1875,7 +1875,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
for (fmt = 0; fmt < 32; ++fmt) {
if (snd_mask_test(format_mask, fmt)) {
- int f = snd_pcm_oss_format_to((__force snd_pcm_format_t)fmt);
+ int f = snd_pcm_oss_format_to(fmt);
if (f >= 0)
formats |= f;
}
@@ -2495,9 +2495,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
int nonblock;
wait_queue_entry_t wait;
- err = nonseekable_open(inode, file);
- if (err < 0)
- return err;
+ nonseekable_open(inode, file);
pcm = snd_lookup_oss_minor_data(iminor(inode),
SNDRV_OSS_DEVICE_TYPE_PCM);
@@ -2509,7 +2507,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
if (err < 0)
goto __error1;
if (!try_module_get(pcm->card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
@@ -3129,17 +3127,16 @@ static inline void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
* ENTRY functions
*/
-static const struct file_operations snd_pcm_oss_f_reg =
-{
- .owner = THIS_MODULE,
- .read = snd_pcm_oss_read,
- .write = snd_pcm_oss_write,
- .open = snd_pcm_oss_open,
- .release = snd_pcm_oss_release,
- .poll = snd_pcm_oss_poll,
- .unlocked_ioctl = snd_pcm_oss_ioctl,
- .compat_ioctl = snd_pcm_oss_ioctl_compat,
- .mmap = snd_pcm_oss_mmap,
+static const struct file_operations snd_pcm_oss_f_reg = {
+ .owner = THIS_MODULE,
+ .read = snd_pcm_oss_read,
+ .write = snd_pcm_oss_write,
+ .open = snd_pcm_oss_open,
+ .release = snd_pcm_oss_release,
+ .poll = snd_pcm_oss_poll,
+ .unlocked_ioctl = snd_pcm_oss_ioctl,
+ .compat_ioctl = snd_pcm_oss_ioctl_compat,
+ .mmap = snd_pcm_oss_mmap,
};
static void register_oss_dsp(struct snd_pcm *pcm, int index)
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -272,13 +272,13 @@ static int snd_pcm_plug_formats(const struct snd_mask *mask,
SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE |
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
- snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW);
+ snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW);
if (formats.bits[0] & lower_32_bits(linfmts))
formats.bits[0] |= lower_32_bits(linfmts);
if (formats.bits[1] & upper_32_bits(linfmts))
formats.bits[1] |= upper_32_bits(linfmts);
- return snd_mask_test(&formats, (__force int)format);
+ return snd_mask_test(&formats, format);
}
static const snd_pcm_format_t preferred_formats[] = {
@@ -307,20 +307,20 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
{
int i;
- if (snd_mask_test(format_mask, (__force int)format))
+ if (snd_mask_test(format_mask, format))
return format;
if (!snd_pcm_plug_formats(format_mask, format))
- return (__force snd_pcm_format_t)-EINVAL;
+ return -EINVAL;
if (snd_pcm_format_linear(format)) {
unsigned int width = snd_pcm_format_width(format);
int unsignd = snd_pcm_format_unsigned(format) > 0;
int big = snd_pcm_format_big_endian(format) > 0;
unsigned int badness, best = -1;
- snd_pcm_format_t best_format = (__force snd_pcm_format_t)-1;
+ snd_pcm_format_t best_format = -1;
for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) {
snd_pcm_format_t f = preferred_formats[i];
unsigned int w;
- if (!snd_mask_test(format_mask, (__force int)f))
+ if (!snd_mask_test(format_mask, f))
continue;
w = snd_pcm_format_width(f);
if (w >= width)
@@ -334,21 +334,21 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
best = badness;
}
}
- if ((__force int)best_format >= 0)
+ if (best_format >= 0)
return best_format;
else
- return (__force snd_pcm_format_t)-EINVAL;
+ return -EINVAL;
} else {
switch (format) {
case SNDRV_PCM_FORMAT_MU_LAW:
for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
snd_pcm_format_t format1 = preferred_formats[i];
- if (snd_mask_test(format_mask, (__force int)format1))
+ if (snd_mask_test(format_mask, format1))
return format1;
}
fallthrough;
default:
- return (__force snd_pcm_format_t)-EINVAL;
+ return -EINVAL;
}
}
}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -211,11 +211,9 @@ static const char * const snd_pcm_format_names[] = {
*/
const char *snd_pcm_format_name(snd_pcm_format_t format)
{
- unsigned int format_num = (__force unsigned int)format;
-
- if (format_num >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format_num])
+ if (format >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format])
return "Unknown";
- return snd_pcm_format_names[format_num];
+ return snd_pcm_format_names[format];
}
EXPORT_SYMBOL_GPL(snd_pcm_format_name);
@@ -275,12 +273,12 @@ static const char *snd_pcm_stream_name(int stream)
static const char *snd_pcm_access_name(snd_pcm_access_t access)
{
- return snd_pcm_access_names[(__force int)access];
+ return snd_pcm_access_names[access];
}
static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
{
- return snd_pcm_subformat_names[(__force int)subformat];
+ return snd_pcm_subformat_names[subformat];
}
static const char *snd_pcm_tstamp_mode_name(int mode)
@@ -290,7 +288,7 @@ static const char *snd_pcm_tstamp_mode_name(int mode)
static const char *snd_pcm_state_name(snd_pcm_state_t state)
{
- return snd_pcm_state_names[(__force int)state];
+ return snd_pcm_state_names[state];
}
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -24,15 +24,12 @@ struct pcm_format_data {
unsigned char silence[8]; /* silence data to fill */
};
-/* we do lots of calculations on snd_pcm_format_t; shut up sparse */
-#define INT __force int
-
static bool valid_format(snd_pcm_format_t format)
{
- return (INT)format >= 0 && (INT)format <= (INT)SNDRV_PCM_FORMAT_LAST;
+ return format >= 0 && format <= SNDRV_PCM_FORMAT_LAST;
}
-static const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
+static const struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
[SNDRV_PCM_FORMAT_S8] = {
.width = 8, .phys = 8, .le = -1, .signd = 1,
.silence = {},
@@ -251,7 +248,7 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
- val = pcm_formats[(INT)format].signd;
+ val = pcm_formats[format].signd;
if (val < 0)
return -EINVAL;
return val;
@@ -300,7 +297,7 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
- val = pcm_formats[(INT)format].le;
+ val = pcm_formats[format].le;
if (val < 0)
return -EINVAL;
return val;
@@ -337,7 +334,7 @@ int snd_pcm_format_width(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
- val = pcm_formats[(INT)format].width;
+ val = pcm_formats[format].width;
if (!val)
return -EINVAL;
return val;
@@ -356,7 +353,7 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
- val = pcm_formats[(INT)format].phys;
+ val = pcm_formats[format].phys;
if (!val)
return -EINVAL;
return val;
@@ -390,9 +387,9 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
{
if (!valid_format(format))
return NULL;
- if (! pcm_formats[(INT)format].phys)
+ if (! pcm_formats[format].phys)
return NULL;
- return pcm_formats[(INT)format].silence;
+ return pcm_formats[format].silence;
}
EXPORT_SYMBOL(snd_pcm_format_silence_64);
@@ -416,12 +413,12 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
return -EINVAL;
if (samples == 0)
return 0;
- width = pcm_formats[(INT)format].phys; /* physical width */
+ width = pcm_formats[format].phys; /* physical width */
if (!width)
return -EINVAL;
- pat = pcm_formats[(INT)format].silence;
+ pat = pcm_formats[format].silence;
/* signed or 1 byte data */
- if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
+ if (pcm_formats[format].signd == 1 || width <= 8) {
unsigned int bytes = samples * width / 8;
memset(data, *pat, bytes);
return 0;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -257,7 +257,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
}
/* macro for simplified cast */
-#define PARAM_MASK_BIT(b) (1U << (__force int)(b))
+#define PARAM_MASK_BIT(b) (1U << (b))
static bool hw_support_mmap(struct snd_pcm_substream *substream)
{
@@ -489,7 +489,7 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
params->msbits = snd_interval_value(i);
m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
if (snd_mask_single(m)) {
- snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m);
+ snd_pcm_format_t format = snd_mask_min(m);
params->msbits = snd_pcm_format_width(format);
}
}
@@ -497,13 +497,13 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
if (params->msbits) {
m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
if (snd_mask_single(m)) {
- snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m);
+ snd_pcm_format_t format = snd_mask_min(m);
if (snd_pcm_format_linear(format) &&
snd_pcm_format_width(format) != params->msbits) {
m_rw = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT);
snd_mask_reset(m_rw,
- (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
+ SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
if (snd_mask_empty(m_rw))
return -EINVAL;
}
@@ -1252,7 +1252,7 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
runtime->trigger_master = NULL;
}
-#define ACTION_ARG_IGNORE (__force snd_pcm_state_t)0
+#define ACTION_ARG_IGNORE 0
struct action_ops {
int (*pre_action)(struct snd_pcm_substream *substream,
@@ -1637,7 +1637,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
/*
* pause callbacks: pass boolean (to start pause or resume) as state argument
*/
-#define pause_pushed(state) (__force bool)(state)
+#define pause_pushed(state) (bool)(state)
static int snd_pcm_pre_pause(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
@@ -1709,14 +1709,14 @@ static const struct action_ops snd_pcm_action_pause = {
static int snd_pcm_pause(struct snd_pcm_substream *substream, bool push)
{
return snd_pcm_action(&snd_pcm_action_pause, substream,
- (__force snd_pcm_state_t)push);
+ (snd_pcm_state_t)push);
}
static int snd_pcm_pause_lock_irq(struct snd_pcm_substream *substream,
bool push)
{
return snd_pcm_action_lock_irq(&snd_pcm_action_pause, substream,
- (__force snd_pcm_state_t)push);
+ (snd_pcm_state_t)push);
}
#ifdef CONFIG_PM
@@ -1984,7 +1984,7 @@ static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
snd_pcm_state_t cur_state = snd_pcm_get_state(substream);
- int f_flags = (__force int)state;
+ int f_flags = state;
if (cur_state == SNDRV_PCM_STATE_OPEN ||
cur_state == SNDRV_PCM_STATE_DISCONNECTED)
@@ -2052,7 +2052,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
substream,
- (__force snd_pcm_state_t)f_flags);
+ (snd_pcm_state_t)f_flags);
}
/*
@@ -2463,7 +2463,7 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
if (bits <= 0)
continue; /* ignore invalid formats */
if ((unsigned)bits < i->min || (unsigned)bits > i->max)
- snd_mask_reset(&m, (__force unsigned)k);
+ snd_mask_reset(&m, k);
}
return snd_mask_refine(mask, &m);
}
@@ -2545,16 +2545,16 @@ static int snd_pcm_hw_rule_subformats(struct snd_pcm_hw_params *params,
snd_mask_none(&m);
/* All PCMs support at least the default STD subformat. */
- snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_STD);
+ snd_mask_set(&m, SNDRV_PCM_SUBFORMAT_STD);
pcm_for_each_format(f) {
- if (!snd_mask_test(fmask, (__force unsigned)f))
+ if (!snd_mask_test(fmask, f))
continue;
if (f == SNDRV_PCM_FORMAT_S32_LE && *subformats)
m.bits[0] |= *subformats;
else if (snd_pcm_format_linear(f))
- snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
+ snd_mask_set(&m, SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
}
return snd_mask_refine(sfmask, &m);
@@ -2882,9 +2882,10 @@ static int snd_pcm_open_file(struct file *file,
static int snd_pcm_playback_open(struct inode *inode, struct file *file)
{
struct snd_pcm *pcm;
- int err = nonseekable_open(inode, file);
- if (err < 0)
- return err;
+ int err;
+
+ nonseekable_open(inode, file);
+
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
@@ -2896,9 +2897,10 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
static int snd_pcm_capture_open(struct inode *inode, struct file *file)
{
struct snd_pcm *pcm;
- int err = nonseekable_open(inode, file);
- if (err < 0)
- return err;
+ int err;
+
+ nonseekable_open(inode, file);
+
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_CAPTURE);
err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
@@ -2920,7 +2922,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
if (err < 0)
goto __error1;
if (!try_module_get(pcm->card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
init_waitqueue_entry(&wait, current);
@@ -3916,6 +3918,8 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
if (substream == NULL)
return VM_FAULT_SIGBUS;
runtime = substream->runtime;
+ if (runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
+ return VM_FAULT_SIGBUS;
offset = vmf->pgoff << PAGE_SHIFT;
dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
if (offset > dma_bytes - PAGE_SIZE)
@@ -4256,29 +4260,29 @@ static unsigned long snd_pcm_get_unmapped_area(struct file *file,
const struct file_operations snd_pcm_f_ops[2] = {
{
- .owner = THIS_MODULE,
- .write = snd_pcm_write,
- .write_iter = snd_pcm_writev,
- .open = snd_pcm_playback_open,
- .release = snd_pcm_release,
- .poll = snd_pcm_poll,
- .unlocked_ioctl = snd_pcm_ioctl,
- .compat_ioctl = snd_pcm_ioctl_compat,
- .mmap = snd_pcm_mmap,
- .fasync = snd_pcm_fasync,
- .get_unmapped_area = snd_pcm_get_unmapped_area,
+ .owner = THIS_MODULE,
+ .write = snd_pcm_write,
+ .write_iter = snd_pcm_writev,
+ .open = snd_pcm_playback_open,
+ .release = snd_pcm_release,
+ .poll = snd_pcm_poll,
+ .unlocked_ioctl = snd_pcm_ioctl,
+ .compat_ioctl = snd_pcm_ioctl_compat,
+ .mmap = snd_pcm_mmap,
+ .fasync = snd_pcm_fasync,
+ .get_unmapped_area = snd_pcm_get_unmapped_area,
},
{
- .owner = THIS_MODULE,
- .read = snd_pcm_read,
- .read_iter = snd_pcm_readv,
- .open = snd_pcm_capture_open,
- .release = snd_pcm_release,
- .poll = snd_pcm_poll,
- .unlocked_ioctl = snd_pcm_ioctl,
- .compat_ioctl = snd_pcm_ioctl_compat,
- .mmap = snd_pcm_mmap,
- .fasync = snd_pcm_fasync,
- .get_unmapped_area = snd_pcm_get_unmapped_area,
+ .owner = THIS_MODULE,
+ .read = snd_pcm_read,
+ .read_iter = snd_pcm_readv,
+ .open = snd_pcm_capture_open,
+ .release = snd_pcm_release,
+ .poll = snd_pcm_poll,
+ .unlocked_ioctl = snd_pcm_ioctl,
+ .compat_ioctl = snd_pcm_ioctl_compat,
+ .mmap = snd_pcm_mmap,
+ .fasync = snd_pcm_fasync,
+ .get_unmapped_area = snd_pcm_get_unmapped_area,
}
};
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -408,9 +408,10 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
return 0;
}
-/* called from sound/core/seq/seq_midi.c */
-int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
- int mode, struct snd_rawmidi_file *rfile)
+/* called from sound/core/seq/seq_midi.c and sound/core/ump.c */
+int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice,
+ int mode, struct snd_rawmidi_file *rfile,
+ int depth)
{
int err;
@@ -419,13 +420,14 @@ int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
if (!try_module_get(rmidi->card->module))
return -ENXIO;
- guard(mutex)(&rmidi->open_mutex);
+ mutex_lock_nested(&rmidi->open_mutex, depth);
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
if (err < 0)
module_put(rmidi->card->module);
+ mutex_unlock(&rmidi->open_mutex);
return err;
}
-EXPORT_SYMBOL(snd_rawmidi_kernel_open);
+EXPORT_SYMBOL(snd_rawmidi_kernel_open_nested);
static int snd_rawmidi_open(struct inode *inode, struct file *file)
{
@@ -441,9 +443,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
return -EINVAL; /* invalid combination */
- err = stream_open(inode, file);
- if (err < 0)
- return err;
+ stream_open(inode, file);
if (maj == snd_major) {
rmidi = snd_lookup_minor_data(iminor(inode),
@@ -1784,14 +1784,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
*/
static const struct file_operations snd_rawmidi_f_ops = {
- .owner = THIS_MODULE,
- .read = snd_rawmidi_read,
- .write = snd_rawmidi_write,
- .open = snd_rawmidi_open,
- .release = snd_rawmidi_release,
- .poll = snd_rawmidi_poll,
- .unlocked_ioctl = snd_rawmidi_ioctl,
- .compat_ioctl = snd_rawmidi_ioctl_compat,
+ .owner = THIS_MODULE,
+ .read = snd_rawmidi_read,
+ .write = snd_rawmidi_write,
+ .open = snd_rawmidi_open,
+ .release = snd_rawmidi_release,
+ .poll = snd_rawmidi_poll,
+ .unlocked_ioctl = snd_rawmidi_ioctl,
+ .compat_ioctl = snd_rawmidi_ioctl_compat,
};
static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -206,17 +206,16 @@ odev_poll(struct file *file, poll_table * wait)
* registration of sequencer minor device
*/
-static const struct file_operations seq_oss_f_ops =
-{
- .owner = THIS_MODULE,
- .read = odev_read,
- .write = odev_write,
- .open = odev_open,
- .release = odev_release,
- .poll = odev_poll,
- .unlocked_ioctl = odev_ioctl,
- .compat_ioctl = odev_ioctl_compat,
- .llseek = noop_llseek,
+static const struct file_operations seq_oss_f_ops = {
+ .owner = THIS_MODULE,
+ .read = odev_read,
+ .write = odev_write,
+ .open = odev_open,
+ .release = odev_release,
+ .poll = odev_poll,
+ .unlocked_ioctl = odev_ioctl,
+ .compat_ioctl = odev_ioctl_compat,
+ .llseek = noop_llseek,
};
static int __init
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -59,7 +59,7 @@ static DEFINE_MUTEX(register_mutex);
* client table
*/
static char clienttablock[SNDRV_SEQ_MAX_CLIENTS];
-static struct snd_seq_client *clienttab[SNDRV_SEQ_MAX_CLIENTS];
+static struct snd_seq_client __rcu *clienttab[SNDRV_SEQ_MAX_CLIENTS];
static struct snd_seq_usage client_usage;
/*
@@ -95,15 +95,23 @@ static inline int snd_seq_write_pool_allocated(struct snd_seq_client *client)
return snd_seq_total_cells(client->pool) > 0;
}
-/* return pointer to client structure for specified id */
-static struct snd_seq_client *clientptr(int clientid)
+/* return pointer to client structure for specified id; call under RCU read-lock */
+static struct snd_seq_client *__clientptr(int clientid)
{
if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
clientid);
return NULL;
}
- return clienttab[clientid];
+ return rcu_dereference_check(clienttab[clientid],
+ lockdep_is_held(&clients_lock));
+}
+
+/* return pointer to client structure for specified id */
+static struct snd_seq_client *clientptr(int clientid)
+{
+ guard(rcu)();
+ return __clientptr(clientid);
}
static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
@@ -115,8 +123,8 @@ static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
clientid);
return NULL;
}
- scoped_guard(spinlock_irqsave, &clients_lock) {
- client = clientptr(clientid);
+ scoped_guard(rcu) {
+ client = __clientptr(clientid);
if (client)
return snd_seq_client_ref(client);
if (clienttablock[clientid])
@@ -150,8 +158,8 @@ static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
snd_seq_device_load_drivers();
}
}
- scoped_guard(spinlock_irqsave, &clients_lock) {
- client = clientptr(clientid);
+ scoped_guard(rcu) {
+ client = __clientptr(clientid);
if (client)
return snd_seq_client_ref(client);
}
@@ -212,7 +220,6 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
}
client->type = NO_CLIENT;
snd_use_lock_init(&client->use_lock);
- rwlock_init(&client->ports_lock);
mutex_init(&client->ports_mutex);
INIT_LIST_HEAD(&client->ports_list_head);
mutex_init(&client->ioctl_mutex);
@@ -224,14 +231,17 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
c < SNDRV_SEQ_MAX_CLIENTS;
c++) {
- if (clienttab[c] || clienttablock[c])
+ if (rcu_access_pointer(clienttab[c]) || clienttablock[c])
continue;
- clienttab[client->number = c] = client;
+ client->number = c;
+ rcu_assign_pointer(clienttab[c], client);
return client;
}
} else {
- if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
- clienttab[client->number = client_index] = client;
+ if (rcu_access_pointer(clienttab[client_index]) == NULL &&
+ !clienttablock[client_index]) {
+ client->number = client_index;
+ rcu_assign_pointer(clienttab[client_index], client);
return client;
}
}
@@ -249,10 +259,16 @@ static int seq_free_client1(struct snd_seq_client *client)
return 0;
scoped_guard(spinlock_irq, &clients_lock) {
clienttablock[client->number] = 1;
- clienttab[client->number] = NULL;
+ rcu_assign_pointer(clienttab[client->number], NULL);
}
snd_seq_delete_all_ports(client);
snd_seq_queue_client_leave(client->number);
+ /* the client has been unpublished from the table; wait for a grace
+ * period so that lockless readers (snd_seq_client_use_ptr()) that
+ * observed the old pointer can no longer take a new use_lock
+ * reference, then drain the outstanding references before freeing
+ */
+ synchronize_rcu();
snd_use_lock_sync(&client->use_lock);
if (client->pool)
snd_seq_pool_delete(&client->pool);
@@ -296,11 +312,8 @@ static int snd_seq_open(struct inode *inode, struct file *file)
int c, mode; /* client id */
struct snd_seq_client *client;
struct snd_seq_user_client *user;
- int err;
- err = stream_open(inode, file);
- if (err < 0)
- return err;
+ stream_open(inode, file);
scoped_guard(mutex, &register_mutex) {
client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
@@ -517,9 +530,8 @@ static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event)
* Return the error event.
*
* If the receiver client is a user client, the original event is
- * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. If
- * the original event is also variable length, the external data is
- * copied after the event record.
+ * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. The
+ * external data of a variable length event is not copied along.
* If the receiver client is a kernel client, the original event is
* quoted in SNDRV_SEQ_EVENT_KERNEL_ERROR, since this requires no extra
* kmalloc.
@@ -724,10 +736,11 @@ static int __deliver_to_subscribers(struct snd_seq_client *client,
/* lock list */
if (atomic)
- read_lock(&grp->list_lock);
+ rcu_read_lock();
else
down_read_nested(&grp->list_mutex, hop);
- list_for_each_entry(subs, &grp->list_head, src_list) {
+ hlist_for_each_entry_rcu(subs, &grp->list_head, src_list,
+ lockdep_is_held(&grp->list_mutex)) {
/* both ports ready? */
if (atomic_read(&subs->ref_count) != 2)
continue;
@@ -748,7 +761,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client,
memcpy(event, &event_saved, saved_size);
}
if (atomic)
- read_unlock(&grp->list_lock);
+ rcu_read_unlock();
else
up_read(&grp->list_mutex);
memcpy(event, &event_saved, saved_size);
@@ -1945,7 +1958,7 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
{
struct snd_seq_query_subs *subs = arg;
struct snd_seq_port_subs_info *group;
- struct list_head *p;
+ struct hlist_node *p;
int i;
struct snd_seq_client *cptr __free(snd_seq_client) =
@@ -1972,15 +1985,15 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
/* search for the subscriber */
subs->num_subs = group->count;
i = 0;
- list_for_each(p, &group->list_head) {
+ hlist_for_each(p, &group->list_head) {
if (i++ == subs->index) {
/* found! */
struct snd_seq_subscribers *s;
if (subs->type == SNDRV_SEQ_QUERY_SUBS_READ) {
- s = list_entry(p, struct snd_seq_subscribers, src_list);
+ s = hlist_entry(p, struct snd_seq_subscribers, src_list);
subs->addr = s->info.dest;
} else {
- s = list_entry(p, struct snd_seq_subscribers, dest_list);
+ s = hlist_entry(p, struct snd_seq_subscribers, dest_list);
subs->addr = s->info.sender;
}
subs->flags = s->info.flags;
@@ -2536,19 +2549,19 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
struct snd_seq_port_subs_info *group,
int is_src, char *msg)
{
- struct list_head *p;
+ struct hlist_node *p;
struct snd_seq_subscribers *s;
int count = 0;
guard(rwsem_read)(&group->list_mutex);
- if (list_empty(&group->list_head))
+ if (hlist_empty(&group->list_head))
return;
snd_iprintf(buffer, msg);
- list_for_each(p, &group->list_head) {
+ hlist_for_each(p, &group->list_head) {
if (is_src)
- s = list_entry(p, struct snd_seq_subscribers, src_list);
+ s = hlist_entry(p, struct snd_seq_subscribers, src_list);
else
- s = list_entry(p, struct snd_seq_subscribers, dest_list);
+ s = hlist_entry(p, struct snd_seq_subscribers, dest_list);
if (count++)
snd_iprintf(buffer, ", ");
snd_iprintf(buffer, "%d:%d",
@@ -2670,16 +2683,15 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
* REGISTRATION PART
*/
-static const struct file_operations snd_seq_f_ops =
-{
- .owner = THIS_MODULE,
- .read = snd_seq_read,
- .write = snd_seq_write,
- .open = snd_seq_open,
- .release = snd_seq_release,
- .poll = snd_seq_poll,
- .unlocked_ioctl = snd_seq_ioctl,
- .compat_ioctl = snd_seq_ioctl_compat,
+static const struct file_operations snd_seq_f_ops = {
+ .owner = THIS_MODULE,
+ .read = snd_seq_read,
+ .write = snd_seq_write,
+ .open = snd_seq_open,
+ .release = snd_seq_release,
+ .poll = snd_seq_poll,
+ .unlocked_ioctl = snd_seq_ioctl,
+ .compat_ioctl = snd_seq_ioctl_compat,
};
static struct device *seq_dev;
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -49,7 +49,6 @@ struct snd_seq_client {
/* ports */
int num_ports; /* number of ports */
struct list_head ports_list_head;
- rwlock_t ports_lock;
struct mutex ports_mutex;
struct mutex ioctl_mutex;
int convert32; /* convert 32->64bit */
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -48,8 +48,8 @@ struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
if (client == NULL)
return NULL;
- guard(read_lock)(&client->ports_lock);
- list_for_each_entry(port, &client->ports_list_head, list) {
+ guard(rcu)();
+ list_for_each_entry_rcu(port, &client->ports_list_head, list) {
if (port->addr.port == num) {
if (port->closing)
break; /* deleting now */
@@ -71,8 +71,8 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
num = pinfo->addr.port;
found = NULL;
- guard(read_lock)(&client->ports_lock);
- list_for_each_entry(port, &client->ports_list_head, list) {
+ guard(rcu)();
+ list_for_each_entry_rcu(port, &client->ports_list_head, list) {
if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) &&
!check_inactive)
continue; /* skip inactive ports */
@@ -98,10 +98,9 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
/* initialize snd_seq_port_subs_info */
static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
{
- INIT_LIST_HEAD(&grp->list_head);
+ INIT_HLIST_HEAD(&grp->list_head);
grp->count = 0;
grp->exclusive = 0;
- rwlock_init(&grp->list_lock);
init_rwsem(&grp->list_mutex);
grp->open = NULL;
grp->close = NULL;
@@ -154,7 +153,6 @@ int snd_seq_insert_port(struct snd_seq_client *client, int port,
num = max(port, 0);
guard(mutex)(&client->ports_mutex);
- guard(write_lock_irq)(&client->ports_lock);
struct list_head *insert_before = &client->ports_list_head;
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port)
@@ -166,12 +164,13 @@ int snd_seq_insert_port(struct snd_seq_client *client, int port,
if (port < 0) /* auto-probe mode */
num = p->addr.port + 1;
}
- /* insert the new port */
- list_add_tail(&new_port->list, insert_before);
- client->num_ports++;
+ /* finish initializing the port before publishing it to RCU readers */
new_port->addr.port = num; /* store the port number in the port */
if (!new_port->name[0])
sprintf(new_port->name, "port-%d", num);
+ /* insert the new port */
+ list_add_tail_rcu(&new_port->list, insert_before);
+ client->num_ports++;
return num;
}
@@ -202,12 +201,12 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
bool is_src, bool ack);
static inline struct snd_seq_subscribers *
-get_subscriber(struct list_head *p, bool is_src)
+get_subscriber(struct hlist_node *p, bool is_src)
{
if (is_src)
- return list_entry(p, struct snd_seq_subscribers, src_list);
+ return hlist_entry(p, struct snd_seq_subscribers, src_list);
else
- return list_entry(p, struct snd_seq_subscribers, dest_list);
+ return hlist_entry(p, struct snd_seq_subscribers, dest_list);
}
/*
@@ -219,9 +218,9 @@ static void clear_subscriber_list(struct snd_seq_client *client,
struct snd_seq_port_subs_info *grp,
int is_src)
{
- struct list_head *p, *n;
+ struct hlist_node *p, *n;
- list_for_each_safe(p, n, &grp->list_head) {
+ hlist_for_each_safe(p, n, &grp->list_head) {
struct snd_seq_subscribers *subs;
subs = get_subscriber(p, is_src);
@@ -238,13 +237,13 @@ static void clear_subscriber_list(struct snd_seq_client *client,
* remove the subscriber info
*/
if (atomic_dec_and_test(&subs->ref_count))
- kfree(subs);
+ kfree_rcu(subs, rcu);
continue;
}
/* ok we got the connected port */
delete_and_unsubscribe_port(c, aport, subs, !is_src, true);
- kfree(subs);
+ kfree_rcu(subs, rcu);
}
}
@@ -254,7 +253,13 @@ static int port_delete(struct snd_seq_client *client,
{
/* set closing flag and wait for all port access are gone */
port->closing = 1;
- snd_use_lock_sync(&port->use_lock);
+ /* the port has already been unlinked from the client's port list;
+ * wait for a grace period so that RCU readers still traversing the
+ * list can no longer take a new use_lock reference, then drain the
+ * outstanding references before freeing
+ */
+ synchronize_rcu();
+ snd_use_lock_sync(&port->use_lock);
/* clear subscribers info */
clear_subscriber_list(client, port, &port->c_src, true);
@@ -277,11 +282,10 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
struct snd_seq_client_port *found = NULL, *p;
scoped_guard(mutex, &client->ports_mutex) {
- guard(write_lock_irq)(&client->ports_lock);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
/* ok found. delete from the list at first */
- list_del(&p->list);
+ list_del_rcu(&p->list);
client->num_ports--;
found = p;
break;
@@ -297,26 +301,16 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
/* delete the all ports belonging to the given client */
int snd_seq_delete_all_ports(struct snd_seq_client *client)
{
- struct list_head deleted_list;
struct snd_seq_client_port *port, *tmp;
-
- /* move the port list to deleted_list, and
- * clear the port list in the client data.
+
+ /* unlink and delete each port; port_delete() waits for an RCU grace
+ * period before draining the port, so concurrent lockless readers can
+ * no longer take a new use_lock reference on it
*/
guard(mutex)(&client->ports_mutex);
- scoped_guard(write_lock_irq, &client->ports_lock) {
- if (!list_empty(&client->ports_list_head)) {
- list_add(&deleted_list, &client->ports_list_head);
- list_del_init(&client->ports_list_head);
- } else {
- INIT_LIST_HEAD(&deleted_list);
- }
- client->num_ports = 0;
- }
-
- /* remove each port in deleted_list */
- list_for_each_entry_safe(port, tmp, &deleted_list, list) {
- list_del(&port->list);
+ list_for_each_entry_safe(port, tmp, &client->ports_list_head, list) {
+ list_del_rcu(&port->list);
+ client->num_ports--;
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
port_delete(client, port);
}
@@ -499,20 +493,20 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
bool is_src, bool exclusive, bool ack)
{
struct snd_seq_port_subs_info *grp;
- struct list_head *p;
+ struct hlist_node *p;
struct snd_seq_subscribers *s;
int err;
grp = is_src ? &port->c_src : &port->c_dest;
guard(rwsem_write)(&grp->list_mutex);
if (exclusive) {
- if (!list_empty(&grp->list_head))
+ if (!hlist_empty(&grp->list_head))
return -EBUSY;
} else {
if (grp->exclusive)
return -EBUSY;
/* check whether already exists */
- list_for_each(p, &grp->list_head) {
+ hlist_for_each(p, &grp->list_head) {
s = get_subscriber(p, is_src);
if (match_subs_info(&subs->info, &s->info))
return -EBUSY;
@@ -526,11 +520,10 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
}
/* add to list */
- guard(write_lock_irq)(&grp->list_lock);
if (is_src)
- list_add_tail(&subs->src_list, &grp->list_head);
+ hlist_add_tail_rcu(&subs->src_list, &grp->list_head);
else
- list_add_tail(&subs->dest_list, &grp->list_head);
+ hlist_add_tail_rcu(&subs->dest_list, &grp->list_head);
grp->exclusive = exclusive;
atomic_inc(&subs->ref_count);
@@ -544,17 +537,15 @@ static void __delete_and_unsubscribe_port(struct snd_seq_client *client,
bool is_src, bool ack)
{
struct snd_seq_port_subs_info *grp;
- struct list_head *list;
+ struct hlist_node *list;
bool empty;
grp = is_src ? &port->c_src : &port->c_dest;
list = is_src ? &subs->src_list : &subs->dest_list;
- scoped_guard(write_lock_irq, &grp->list_lock) {
- empty = list_empty(list);
- if (!empty)
- list_del_init(list);
- grp->exclusive = 0;
- }
+ empty = hlist_unhashed(list);
+ if (!empty)
+ hlist_del_init_rcu(list);
+ grp->exclusive = 0;
if (!empty)
unsubscribe_port(client, port, grp, &subs->info, ack);
@@ -590,8 +581,8 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
subs->info = *info;
atomic_set(&subs->ref_count, 0);
- INIT_LIST_HEAD(&subs->src_list);
- INIT_LIST_HEAD(&subs->dest_list);
+ INIT_HLIST_NODE(&subs->src_list);
+ INIT_HLIST_NODE(&subs->dest_list);
exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE);
@@ -612,7 +603,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
delete_and_unsubscribe_port(src_client, src_port, subs, true,
connector->number != src_client->number);
error:
- kfree(subs);
+ kfree_rcu(subs, rcu);
return err;
}
@@ -633,7 +624,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
*/
scoped_guard(rwsem_write, &dest->list_mutex) {
/* look for the connection */
- list_for_each_entry(subs, &dest->list_head, dest_list) {
+ hlist_for_each_entry(subs, &dest->list_head, dest_list) {
if (match_subs_info(info, &subs->info)) {
__delete_and_unsubscribe_port(dest_client, dest_port,
subs, false,
@@ -648,7 +639,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
delete_and_unsubscribe_port(src_client, src_port, subs, true,
connector->number != src_client->number);
- kfree(subs);
+ kfree_rcu(subs, rcu);
return 0;
}
@@ -662,7 +653,7 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
int err = -ENOENT;
guard(rwsem_read)(&src_grp->list_mutex);
- list_for_each_entry(s, &src_grp->list_head, src_list) {
+ hlist_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) {
*subs = s->info;
err = 0;
diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h
--- a/sound/core/seq/seq_ports.h
+++ b/sound/core/seq/seq_ports.h
@@ -28,17 +28,17 @@
struct snd_seq_subscribers {
struct snd_seq_port_subscribe info; /* additional info */
- struct list_head src_list; /* link of sources */
- struct list_head dest_list; /* link of destinations */
+ struct hlist_node src_list; /* link of sources */
+ struct hlist_node dest_list; /* link of destinations */
atomic_t ref_count;
+ struct rcu_head rcu; /* for deferred free */
};
struct snd_seq_port_subs_info {
- struct list_head list_head; /* list of subscribed ports */
+ struct hlist_head list_head; /* list of subscribed ports */
unsigned int count; /* count of subscribers */
unsigned int exclusive: 1; /* exclusive mode */
struct rw_semaphore list_mutex;
- rwlock_t list_lock;
int (*open)(void *private_data, struct snd_seq_port_subscribe *info);
int (*close)(void *private_data, struct snd_seq_port_subscribe *info);
};
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c
--- a/sound/core/seq/seq_ump_client.c
+++ b/sound/core/seq/seq_ump_client.c
@@ -37,8 +37,11 @@ struct seq_ump_client {
struct snd_ump_endpoint *ump; /* assigned endpoint */
int seq_client; /* sequencer client id */
int opened[2]; /* current opens for each direction */
- rwlock_t output_lock; /* protects out_rfile output access */
struct snd_rawmidi_file out_rfile; /* rawmidi for output */
+ /* RCU-protected shadow of out_rfile.output for the delivery hot path;
+ * out_rfile itself is only touched by open/close under open_mutex
+ */
+ struct snd_rawmidi_substream __rcu *out_substream;
struct seq_ump_input_buffer input; /* input parser context */
void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
struct work_struct group_notify_work; /* FB change notification */
@@ -89,8 +92,8 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
unsigned char type;
int len;
- guard(read_lock_irqsave)(&client->output_lock);
- substream = client->out_rfile.output;
+ guard(rcu)();
+ substream = rcu_dereference(client->out_substream);
if (!substream)
return -ENODEV;
if (!snd_seq_ev_is_ump(ev))
@@ -108,19 +111,22 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
static int seq_ump_client_open(struct seq_ump_client *client, int dir)
{
struct snd_ump_endpoint *ump = client->ump;
- struct snd_rawmidi_file rfile = {};
int err;
guard(mutex)(&ump->open_mutex);
if (dir == STR_OUT && !client->opened[dir]) {
+ /* out_rfile is only accessed under open_mutex; the delivery
+ * path reads out_substream via RCU, so open into out_rfile
+ * directly and publish the substream afterwards
+ */
err = snd_rawmidi_kernel_open(&ump->core, 0,
SNDRV_RAWMIDI_LFLG_OUTPUT |
SNDRV_RAWMIDI_LFLG_APPEND,
- &rfile);
+ &client->out_rfile);
if (err < 0)
return err;
- scoped_guard(write_lock_irqsave, &client->output_lock)
- client->out_rfile = rfile;
+ rcu_assign_pointer(client->out_substream,
+ client->out_rfile.output);
}
client->opened[dir]++;
return 0;
@@ -130,17 +136,18 @@ static int seq_ump_client_open(struct seq_ump_client *client, int dir)
static int seq_ump_client_close(struct seq_ump_client *client, int dir)
{
struct snd_ump_endpoint *ump = client->ump;
- struct snd_rawmidi_file rfile = {};
guard(mutex)(&ump->open_mutex);
if (!--client->opened[dir]) {
- if (dir == STR_OUT) {
- scoped_guard(write_lock_irqsave, &client->output_lock) {
- rfile = client->out_rfile;
- client->out_rfile = (struct snd_rawmidi_file){};
- }
- if (rfile.rmidi)
- snd_rawmidi_kernel_release(&rfile);
+ if (dir == STR_OUT && client->out_rfile.rmidi) {
+ rcu_assign_pointer(client->out_substream, NULL);
+ /* wait for a grace period so that no reader in the
+ * delivery path is still writing to the substream
+ * before it is released
+ */
+ synchronize_rcu();
+ snd_rawmidi_kernel_release(&client->out_rfile);
+ client->out_rfile = (struct snd_rawmidi_file){};
}
}
return 0;
@@ -480,7 +487,6 @@ static int snd_seq_ump_probe(struct snd_seq_device *dev)
INIT_WORK(&client->group_notify_work, handle_group_notify);
client->ump = ump;
- rwlock_init(&client->output_lock);
client->seq_client =
snd_seq_create_kernel_client(card, ump->core.device,
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -78,10 +78,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
int len;
if (atomic)
- read_lock(&rdev->filelist_lock);
+ rcu_read_lock();
else
down_read(&rdev->filelist_sem);
- list_for_each_entry(vmidi, &rdev->filelist, list) {
+ list_for_each_entry_rcu(vmidi, &rdev->filelist, list,
+ lockdep_is_held(&rdev->filelist_sem)) {
if (!READ_ONCE(vmidi->trigger))
continue;
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
@@ -96,7 +97,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
}
}
if (atomic)
- read_unlock(&rdev->filelist_lock);
+ rcu_read_unlock();
else
up_read(&rdev->filelist_sem);
@@ -200,8 +201,7 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
vmidi->port = rdev->port;
runtime->private_data = vmidi;
scoped_guard(rwsem_write, &rdev->filelist_sem) {
- guard(write_lock_irq)(&rdev->filelist_lock);
- list_add_tail(&vmidi->list, &rdev->filelist);
+ list_add_tail_rcu(&vmidi->list, &rdev->filelist);
}
vmidi->rdev = rdev;
return 0;
@@ -243,9 +243,13 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
struct snd_virmidi *vmidi = substream->runtime->private_data;
scoped_guard(rwsem_write, &rdev->filelist_sem) {
- guard(write_lock_irq)(&rdev->filelist_lock);
- list_del(&vmidi->list);
+ list_del_rcu(&vmidi->list);
}
+ /* wait for a grace period so that lockless readers in the atomic
+ * delivery path (snd_virmidi_dev_receive_event()) are no longer
+ * traversing this entry before its parser and memory are freed
+ */
+ synchronize_rcu();
snd_midi_event_free(vmidi->parser);
substream->runtime->private_data = NULL;
kfree(vmidi);
@@ -508,7 +512,6 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
rdev->device = device;
rdev->client = -1;
init_rwsem(&rdev->filelist_sem);
- rwlock_init(&rdev->filelist_lock);
INIT_LIST_HEAD(&rdev->filelist);
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
rmidi->private_data = rdev;
diff --git a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -167,11 +167,10 @@ static int snd_open(struct inode *inode, struct file *file)
return err;
}
-static const struct file_operations snd_fops =
-{
- .owner = THIS_MODULE,
- .open = snd_open,
- .llseek = noop_llseek,
+static const struct file_operations snd_fops = {
+ .owner = THIS_MODULE,
+ .open = snd_open,
+ .llseek = noop_llseek,
};
#ifdef CONFIG_SND_DYNAMIC_MINORS
@@ -358,7 +357,7 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
struct snd_minor *mptr;
guard(mutex)(&sound_mutex);
- for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
+ for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
mptr = snd_minors[minor];
if (!mptr)
continue;
@@ -395,15 +394,21 @@ int __init snd_minor_info_init(void)
static int __init alsa_sound_init(void)
{
+ int err;
+
snd_major = major;
snd_ecards_limit = cards_limit;
- if (register_chrdev(major, "alsa", &snd_fops)) {
+
+ err = register_chrdev(major, "alsa", &snd_fops);
+ if (err < 0) {
pr_err("ALSA core: unable to register native major device number %d\n", major);
- return -EIO;
+ return err;
}
- if (snd_info_init() < 0) {
+
+ err = snd_info_init();
+ if (err < 0) {
unregister_chrdev(major, "alsa");
- return -ENOMEM;
+ return err;
}
#ifdef CONFIG_SND_DEBUG
diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c
--- a/sound/core/sound_kunit.c
+++ b/sound/core/sound_kunit.c
@@ -17,8 +17,8 @@
.name = #fmt, \
}
-#define WRONG_FORMAT_1 (__force snd_pcm_format_t)((__force int)SNDRV_PCM_FORMAT_LAST + 1)
-#define WRONG_FORMAT_2 (__force snd_pcm_format_t)-1
+#define WRONG_FORMAT_1 (SNDRV_PCM_FORMAT_LAST + 1)
+#define WRONG_FORMAT_2 -1
#define VALID_NAME "ValidName"
#define NAME_W_SPEC_CHARS "In%v@1id name"
diff --git a/sound/core/timer.c b/sound/core/timer.c
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1546,11 +1546,8 @@ static int realloc_user_queue(struct snd_timer_user *tu, int size)
static int snd_timer_user_open(struct inode *inode, struct file *file)
{
struct snd_timer_user *tu;
- int err;
- err = stream_open(inode, file);
- if (err < 0)
- return err;
+ stream_open(inode, file);
tu = kzalloc_obj(*tu);
if (tu == NULL)
@@ -2176,9 +2173,9 @@ static long snd_utimer_ioctl(struct file *file, unsigned int ioctl, unsigned lon
}
static const struct file_operations snd_utimer_fops = {
- .llseek = noop_llseek,
- .release = snd_utimer_release,
- .unlocked_ioctl = snd_utimer_ioctl,
+ .llseek = noop_llseek,
+ .release = snd_utimer_release,
+ .unlocked_ioctl = snd_utimer_ioctl,
};
static int snd_utimer_start(struct snd_timer *t)
@@ -2530,16 +2527,15 @@ static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait)
#define snd_timer_user_ioctl_compat NULL
#endif
-static const struct file_operations snd_timer_f_ops =
-{
- .owner = THIS_MODULE,
- .read = snd_timer_user_read,
- .open = snd_timer_user_open,
- .release = snd_timer_user_release,
- .poll = snd_timer_user_poll,
- .unlocked_ioctl = snd_timer_user_ioctl,
- .compat_ioctl = snd_timer_user_ioctl_compat,
- .fasync = snd_timer_user_fasync,
+static const struct file_operations snd_timer_f_ops = {
+ .owner = THIS_MODULE,
+ .read = snd_timer_user_read,
+ .open = snd_timer_user_open,
+ .release = snd_timer_user_release,
+ .poll = snd_timer_user_poll,
+ .unlocked_ioctl = snd_timer_user_ioctl,
+ .compat_ioctl = snd_timer_user_ioctl_compat,
+ .fasync = snd_timer_user_fasync,
};
/* unregister the system timer */
diff --git a/sound/core/ump.c b/sound/core/ump.c
--- a/sound/core/ump.c
+++ b/sound/core/ump.c
@@ -1157,10 +1157,11 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
return -ENODEV;
if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
if (!ump->legacy_out_opens) {
- err = snd_rawmidi_kernel_open(&ump->core, 0,
- SNDRV_RAWMIDI_LFLG_OUTPUT |
- SNDRV_RAWMIDI_LFLG_APPEND,
- &ump->legacy_out_rfile);
+ err = snd_rawmidi_kernel_open_nested(&ump->core, 0,
+ SNDRV_RAWMIDI_LFLG_OUTPUT |
+ SNDRV_RAWMIDI_LFLG_APPEND,
+ &ump->legacy_out_rfile,
+ SINGLE_DEPTH_NESTING);
if (err < 0)
return err;
}
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -23,6 +23,7 @@
#include <linux/wait.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/hrtimer.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
@@ -55,7 +56,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
module_param_array(pcm_notify, int, NULL, 0444);
MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
module_param_array(timer_source, charp, NULL, 0444);
-MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default].");
+MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default], 'hrtimer' for high-resolution timer.");
#define NO_PITCH 100000
@@ -161,8 +162,11 @@ struct loopback_pcm {
unsigned int period_size_frac; /* period size in jiffies ticks */
unsigned int last_drift;
unsigned long last_jiffies;
- /* If jiffies timer is used */
+ /* If jiffies / hrtimer is used */
struct timer_list timer;
+#ifdef CONFIG_HIGH_RES_TIMERS
+ struct hrtimer hrtimer;
+#endif
/* size of per channel buffer in case of non-interleaved access */
unsigned int channel_buf_n;
@@ -232,6 +236,31 @@ static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+/* call in cable->lock */
+static int loopback_hrtimer_start(struct loopback_pcm *dpcm)
+{
+ unsigned long tick;
+ unsigned int rate_shift = get_rate_shift(dpcm);
+
+ if (rate_shift != dpcm->pcm_rate_shift) {
+ dpcm->pcm_rate_shift = rate_shift;
+ dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
+ }
+ if (dpcm->period_size_frac <= dpcm->irq_pos) {
+ dpcm->irq_pos %= dpcm->period_size_frac;
+ dpcm->period_update_pending = 1;
+ }
+ tick = dpcm->period_size_frac - dpcm->irq_pos;
+ tick = DIV_ROUND_UP(tick, dpcm->pcm_bps);
+ hrtimer_start(&dpcm->hrtimer,
+ ns_to_ktime(div_u64((u64)tick * NSEC_PER_SEC, HZ)),
+ HRTIMER_MODE_REL_SOFT);
+
+ return 0;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_start(struct loopback_pcm *dpcm)
{
@@ -270,6 +299,16 @@ static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+/* call in cable->lock */
+static inline int loopback_hrtimer_stop(struct loopback_pcm *dpcm)
+{
+ hrtimer_try_to_cancel(&dpcm->hrtimer);
+
+ return 0;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_stop(struct loopback_pcm *dpcm)
{
@@ -300,6 +339,15 @@ static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static inline int loopback_hrtimer_stop_sync(struct loopback_pcm *dpcm)
+{
+ hrtimer_cancel(&dpcm->hrtimer);
+
+ return 0;
+}
+#endif
+
/* call in loopback->cable_lock */
static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
{
@@ -734,6 +782,30 @@ static void loopback_jiffies_timer_function(struct timer_list *t)
snd_pcm_period_elapsed(dpcm->substream);
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static enum hrtimer_restart loopback_hrtimer_function(struct hrtimer *t)
+{
+ struct loopback_pcm *dpcm = container_of(t, struct loopback_pcm, hrtimer);
+ bool period_elapsed = false;
+
+ scoped_guard(spinlock_irqsave, &dpcm->cable->lock) {
+ if (loopback_jiffies_timer_pos_update(dpcm->cable) &
+ (1 << dpcm->substream->stream)) {
+ loopback_hrtimer_start(dpcm);
+ if (dpcm->period_update_pending) {
+ dpcm->period_update_pending = 0;
+ period_elapsed = true;
+ }
+ }
+ }
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(dpcm->substream);
+
+ return HRTIMER_NORESTART;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime,
unsigned long resolution)
@@ -907,6 +979,21 @@ static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm,
snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires);
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static void loopback_hrtimer_dpcm_info(struct loopback_pcm *dpcm,
+ struct snd_info_buffer *buffer)
+{
+ snd_iprintf(buffer, " update_pending:\t%u\n",
+ dpcm->period_update_pending);
+ snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos);
+ snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac);
+ snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n",
+ dpcm->last_jiffies, jiffies);
+ snd_iprintf(buffer, " timer_expires:\t%llu\n",
+ ktime_to_ns(hrtimer_get_expires(&dpcm->hrtimer)));
+}
+#endif
+
static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm,
struct snd_info_buffer *buffer)
{
@@ -1097,6 +1184,26 @@ static const struct loopback_ops loopback_jiffies_timer_ops = {
.dpcm_info = loopback_jiffies_timer_dpcm_info,
};
+#ifdef CONFIG_HIGH_RES_TIMERS
+static int loopback_hrtimer_open(struct loopback_pcm *dpcm)
+{
+ hrtimer_setup(&dpcm->hrtimer, loopback_hrtimer_function,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+
+ return 0;
+}
+
+static const struct loopback_ops loopback_hrtimer_ops = {
+ .open = loopback_hrtimer_open,
+ .start = loopback_hrtimer_start,
+ .stop = loopback_hrtimer_stop,
+ .stop_sync = loopback_hrtimer_stop_sync,
+ .close_substream = loopback_hrtimer_stop_sync,
+ .pos_update = loopback_jiffies_timer_pos_update,
+ .dpcm_info = loopback_hrtimer_dpcm_info,
+};
+#endif
+
static int loopback_parse_timer_id(const char *str,
struct snd_timer_id *tid)
{
@@ -1274,7 +1381,12 @@ static int loopback_open(struct snd_pcm_substream *substream)
spin_lock_init(&cable->lock);
snd_refcount_init(&cable->stop_count);
cable->hw = loopback_pcm_hardware;
- if (loopback->timer_source)
+#ifdef CONFIG_HIGH_RES_TIMERS
+ if (loopback->timer_source && !strcmp(loopback->timer_source, "hrtimer"))
+ cable->ops = &loopback_hrtimer_ops;
+ else
+#endif
+ if (loopback->timer_source && loopback->timer_source[0])
cable->ops = &loopback_snd_timer_ops;
else
cable->ops = &loopback_jiffies_timer_ops;
@@ -1491,7 +1603,7 @@ static int loopback_format_info(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = (__force int)SNDRV_PCM_FORMAT_LAST;
+ uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST;
uinfo->value.integer.step = 1;
return 0;
}
@@ -1502,7 +1614,7 @@ static int loopback_format_get(struct snd_kcontrol *kcontrol,
struct loopback *loopback = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] =
- (__force int)loopback->setup[kcontrol->id.subdevice]
+ loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].format;
return 0;
}
@@ -1556,7 +1668,7 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol,
static int loopback_access_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- const char * const texts[] = {"Interleaved", "Non-interleaved"};
+ static const char * const texts[] = {"Interleaved", "Non-interleaved"};
return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -100,6 +100,7 @@ struct dummy_timer_ops {
int (*prepare)(struct snd_pcm_substream *);
int (*start)(struct snd_pcm_substream *);
int (*stop)(struct snd_pcm_substream *);
+ int (*sync_stop)(struct snd_pcm_substream *);
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
};
@@ -285,6 +286,14 @@ static int dummy_systimer_stop(struct snd_pcm_substream *substream)
return 0;
}
+static int dummy_systimer_sync_stop(struct snd_pcm_substream *substream)
+{
+ struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
+
+ timer_delete_sync(&dpcm->timer);
+ return 0;
+}
+
static int dummy_systimer_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -341,7 +350,10 @@ static int dummy_systimer_create(struct snd_pcm_substream *substream)
static void dummy_systimer_free(struct snd_pcm_substream *substream)
{
- kfree(substream->runtime->private_data);
+ struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
+
+ timer_shutdown_sync(&dpcm->timer);
+ kfree(dpcm);
}
static const struct dummy_timer_ops dummy_systimer_ops = {
@@ -350,6 +362,7 @@ static const struct dummy_timer_ops dummy_systimer_ops = {
.prepare = dummy_systimer_prepare,
.start = dummy_systimer_start,
.stop = dummy_systimer_stop,
+ .sync_stop = dummy_systimer_sync_stop,
.pointer = dummy_systimer_pointer,
};
@@ -407,9 +420,12 @@ static int dummy_hrtimer_stop(struct snd_pcm_substream *substream)
return 0;
}
-static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm)
+static int dummy_hrtimer_sync_stop(struct snd_pcm_substream *substream)
{
+ struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
+
hrtimer_cancel(&dpcm->timer);
+ return 0;
}
static snd_pcm_uframes_t
@@ -435,7 +451,6 @@ static int dummy_hrtimer_prepare(struct snd_pcm_substream *substream)
long sec;
unsigned long nsecs;
- dummy_hrtimer_sync(dpcm);
period = runtime->period_size;
rate = runtime->rate;
sec = period / rate;
@@ -463,7 +478,7 @@ static int dummy_hrtimer_create(struct snd_pcm_substream *substream)
static void dummy_hrtimer_free(struct snd_pcm_substream *substream)
{
struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
- dummy_hrtimer_sync(dpcm);
+
kfree(dpcm);
}
@@ -473,6 +488,7 @@ static const struct dummy_timer_ops dummy_hrtimer_ops = {
.prepare = dummy_hrtimer_prepare,
.start = dummy_hrtimer_start,
.stop = dummy_hrtimer_stop,
+ .sync_stop = dummy_hrtimer_sync_stop,
.pointer = dummy_hrtimer_pointer,
};
@@ -495,6 +511,13 @@ static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return -EINVAL;
}
+static int dummy_pcm_sync_stop(struct snd_pcm_substream *substream)
+{
+ if (get_dummy_ops(substream)->sync_stop)
+ return get_dummy_ops(substream)->sync_stop(substream);
+ return 0;
+}
+
static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
{
return get_dummy_ops(substream)->prepare(substream);
@@ -646,6 +669,7 @@ static const struct snd_pcm_ops dummy_pcm_ops = {
.hw_params = dummy_pcm_hw_params,
.prepare = dummy_pcm_prepare,
.trigger = dummy_pcm_trigger,
+ .sync_stop = dummy_pcm_sync_stop,
.pointer = dummy_pcm_pointer,
};
@@ -655,6 +679,7 @@ static const struct snd_pcm_ops dummy_pcm_ops_no_buf = {
.hw_params = dummy_pcm_hw_params,
.prepare = dummy_pcm_prepare,
.trigger = dummy_pcm_trigger,
+ .sync_stop = dummy_pcm_sync_stop,
.pointer = dummy_pcm_pointer,
.copy = dummy_pcm_copy,
.fill_silence = dummy_pcm_silence,
diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c
--- a/sound/hda/codecs/ca0132.c
+++ b/sound/hda/codecs/ca0132.c
@@ -5788,7 +5788,8 @@ static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = MIC_BOOST_NUM_OF_STEPS;
if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS)
uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1;
- sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx);
+ snprintf(namestr, sizeof(namestr), "%d %s",
+ (uinfo->value.enumerated.item * 10), sfx);
strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -5840,9 +5841,9 @@ static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX;
if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX)
uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1;
- sprintf(namestr, "%s %s",
- ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
- sfx);
+ snprintf(namestr, sizeof(namestr), "%s %s",
+ ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
+ sfx);
strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -5894,8 +5895,8 @@ static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX;
if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX)
uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1;
- sprintf(namestr, "%s",
- ae5_filter_presets[uinfo->value.enumerated.item].name);
+ snprintf(namestr, sizeof(namestr), "%s",
+ ae5_filter_presets[uinfo->value.enumerated.item].name);
strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -6632,7 +6633,7 @@ static int ca0132_alt_add_effect_slider(struct hda_codec *codec, hda_nid_t nid,
struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
- sprintf(namestr, "FX: %s %s Volume", pfx, dirstr[dir]);
+ snprintf(namestr, sizeof(namestr), "FX: %s %s Volume", pfx, dirstr[dir]);
knew.tlv.c = NULL;
@@ -6671,9 +6672,9 @@ static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
* prefix to OutFX or InFX enable controls.
*/
if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID))
- sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]);
+ snprintf(namestr, sizeof(namestr), "FX: %s %s Switch", pfx, dirstr[dir]);
else
- sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
+ snprintf(namestr, sizeof(namestr), "%s %s Switch", pfx, dirstr[dir]);
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
}
@@ -8530,10 +8531,9 @@ static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k)
static bool ca0132_download_dsp_images(struct hda_codec *codec)
{
- bool dsp_loaded = false;
struct ca0132_spec *spec = codec->spec;
const struct dsp_image_seg *dsp_os_image;
- const struct firmware *fw_entry = NULL;
+ const struct firmware *fw_entry __free(firmware) = NULL;
/*
* Alternate firmwares for different variants. The Recon3Di apparently
* can use the default firmware, but I'll leave the option in case
@@ -8573,15 +8573,10 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) {
codec_err(codec, "ca0132 DSP load image failed\n");
- goto exit_download;
+ return false;
}
- dsp_loaded = dspload_wait_loaded(codec);
-
-exit_download:
- release_firmware(fw_entry);
-
- return dsp_loaded;
+ return dspload_wait_loaded(codec);
}
static void ca0132_download_dsp(struct hda_codec *codec)
@@ -9634,6 +9629,7 @@ static void ca0132_free(struct hda_codec *codec)
#endif
kfree(spec->spec_init_verbs);
kfree(codec->spec);
+ codec->spec = NULL;
}
static void dbpro_free(struct hda_codec *codec)
@@ -9644,6 +9640,7 @@ static void dbpro_free(struct hda_codec *codec)
kfree(spec->spec_init_verbs);
kfree(codec->spec);
+ codec->spec = NULL;
}
static void ca0132_config(struct hda_codec *codec)
diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c
--- a/sound/hda/codecs/cm9825.c
+++ b/sound/hda/codecs/cm9825.c
@@ -15,7 +15,8 @@
enum {
QUIRK_CM_STD = 0x0,
- QUIRK_GENE_TWL7_SSID = 0x160dc000
+ QUIRK_GENE_TWL7_SSID = 0x160dc000,
+ QUIRK_IBP_SSID = 0x15bd3275
};
/* CM9825 Offset Definitions */
@@ -40,13 +41,19 @@ enum {
#define CM9825_VERB_SET_GAD 0x7b4
#define CM9825_VERB_SET_TMOD 0x7b5
#define CM9825_VERB_SET_SNR 0x7b6
+#define CM9825_VERB_SET_OMTP 0x7ef
+#define CM9825_VERB_READ_OMTP 0xfec
struct cmi_spec {
struct hda_gen_spec gen;
const struct hda_verb *chip_d0_verbs;
const struct hda_verb *chip_d3_verbs;
+ const struct hda_verb *chip_playback_start_verbs;
+ const struct hda_verb *chip_playback_stop_verbs;
const struct hda_verb *chip_hp_present_verbs;
const struct hda_verb *chip_hp_remove_verbs;
+ const struct hda_verb *chip_lineout_present_verbs;
+ const struct hda_verb *chip_lineout_remove_verbs;
struct hda_codec *codec;
struct delayed_work unsol_inputs_work;
struct delayed_work unsol_lineout_work;
@@ -193,6 +200,94 @@ static const struct hda_verb cm9825_gene_twl7_playback_stop_verbs[] = {
{}
};
+/*
+ * To save power, AD/CLK is turned off.
+ */
+static const struct hda_verb cm9825_ibp_d3_verbs[] = {
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_PLL, 0x01},
+ {0x43, CM9825_VERB_SET_NEG, 0xc2},
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_VNEG, 0x50},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {0x43, CM9825_VERB_SET_PDNEG, 0x04},
+ {0x43, CM9825_VERB_SET_CDALR, 0xf6},
+ {0x43, CM9825_VERB_SET_OTP, 0xcd},
+ {}
+};
+
+/*
+ * D0 configuration: enable PLL/CLK/ADC/DAC and optimize performance
+ */
+static const struct hda_verb cm9825_ibp_d0_verbs[] = {
+ {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+ {0x43, CM9825_VERB_SET_SNR, 0x38},
+ {0x43, CM9825_VERB_SET_PLL, 0x00},
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {0x43, CM9825_VERB_SET_VNEG, 0x56},
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_DACTRL, 0x00},
+ {0x43, CM9825_VERB_SET_PDNEG, 0x0c},
+ {0x43, CM9825_VERB_SET_CDALR, 0xf4},
+ {0x43, CM9825_VERB_SET_OTP, 0xcd},
+ {0x43, CM9825_VERB_SET_MTCBA, 0x61},
+ {0x43, CM9825_VERB_SET_OCP, 0x33},
+ {0x43, CM9825_VERB_SET_GAD, 0x07},
+ {0x43, CM9825_VERB_SET_TMOD, 0x26},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0xa0, 0x2d},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 0x2d},
+ {0x43, CM9825_VERB_SET_HPF_1, 0x40},
+ {0x43, CM9825_VERB_SET_HPF_2, 0x40},
+ {}
+};
+
+/*
+ * Enable mbias, ADC.
+ */
+static const struct hda_verb cm9825_ibp_lineout_present_verbs[] = {
+ {0x43, CM9825_VERB_SET_ADCL, 0x8c},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x10},
+ {}
+};
+
+/*
+ * Disable mbias, ADC.
+ */
+static const struct hda_verb cm9825_ibp_lineout_remove_verbs[] = {
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {}
+};
+
+/*
+ * Turn on the DAC (widget NID 0x43) in the playback path by writing
+ * a sequence of vendor-specific verbs.
+ */
+static const struct hda_verb cm9825_ibp_playback_start_verbs[] = {
+ {0x43, CM9825_VERB_SET_DACL, 0xaa},
+ {0x43, CM9825_VERB_SET_D2S, 0xf2},
+ {0x43, CM9825_VERB_SET_VDO, 0xc4},
+ {0x43, CM9825_VERB_SET_SNR, 0x30},
+ {}
+};
+
+/*
+ * Shut down the playback path. The order differs slightly from the
+ * enable sequence, likely to avoid audible pop noise when powering
+ * down the output stage.
+ */
+static const struct hda_verb cm9825_ibp_playback_stop_verbs[] = {
+ {0x43, CM9825_VERB_SET_VDO, 0xc0},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_VDO, 0x80},
+ {0x43, CM9825_VERB_SET_SNR, 0x38},
+ {}
+};
+
static void cm9825_update_jk_plug_status(struct hda_codec *codec, hda_nid_t nid)
{
struct cmi_spec *spec = codec->spec;
@@ -232,6 +327,23 @@ static void cm9825_unsol_lineout_delayed(struct work_struct *work)
struct cmi_spec *spec =
container_of(to_delayed_work(work), struct cmi_spec,
unsol_lineout_work);
+ hda_nid_t line_out_pin = spec->gen.autocfg.line_out_pins[0];
+ bool line_out_jack_plugin = false;
+
+ line_out_jack_plugin = snd_hda_jack_detect(spec->codec, line_out_pin);
+
+ codec_dbg(spec->codec, "lineout_jack_plugin %d, lineout_pin 0x%X\n",
+ (int)line_out_jack_plugin, line_out_pin);
+
+ if (!line_out_jack_plugin) {
+ /* Jack plugout */
+ snd_hda_sequence_write(spec->codec,
+ spec->chip_lineout_remove_verbs);
+ } else {
+ /* Jack plugin */
+ snd_hda_sequence_write(spec->codec,
+ spec->chip_lineout_present_verbs);
+ }
cm9825_update_jk_plug_status(spec->codec,
spec->gen.autocfg.line_out_pins[0]);
@@ -362,12 +474,10 @@ static void cm9825_playback_pcm_hook(struct hda_pcm_stream *hinfo,
switch (action) {
case HDA_GEN_PCM_ACT_PREPARE:
- snd_hda_sequence_write(spec->codec,
- cm9825_gene_twl7_playback_start_verbs);
+ snd_hda_sequence_write(codec, spec->chip_playback_start_verbs);
break;
case HDA_GEN_PCM_ACT_CLEANUP:
- snd_hda_sequence_write(spec->codec,
- cm9825_gene_twl7_playback_stop_verbs);
+ snd_hda_sequence_write(codec, spec->chip_playback_stop_verbs);
break;
default:
return;
@@ -471,7 +581,8 @@ static int cm9825_resume(struct hda_codec *codec)
if (codec->core.subsystem_id == QUIRK_CM_STD)
cm9825_cm_std_resume(codec);
- else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+ else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID ||
+ codec->core.subsystem_id == QUIRK_IBP_SSID) {
snd_hda_codec_init(codec);
snd_hda_sequence_write(codec, spec->chip_d0_verbs);
}
@@ -487,6 +598,7 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
struct cmi_spec *spec;
struct auto_pin_cfg *cfg;
int err = 0;
+ unsigned int val;
spec = kzalloc_obj(*spec);
if (spec == NULL)
@@ -523,9 +635,33 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
spec->chip_d0_verbs = cm9825_gene_twl7_d0_verbs;
spec->chip_d3_verbs = cm9825_gene_twl7_d3_verbs;
spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+ spec->chip_playback_start_verbs =
+ cm9825_gene_twl7_playback_start_verbs;
+ spec->chip_playback_stop_verbs =
+ cm9825_gene_twl7_playback_stop_verbs;
/* Internal fixed device, Rear, Mic-in, 3.5mm */
snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100);
break;
+ case QUIRK_IBP_SSID:
+ snd_hda_codec_set_name(codec, "CM9825 IBP");
+ spec->chip_d0_verbs = cm9825_ibp_d0_verbs;
+ spec->chip_d3_verbs = cm9825_ibp_d3_verbs;
+ spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+ spec->chip_lineout_present_verbs =
+ cm9825_ibp_lineout_present_verbs;
+ spec->chip_lineout_remove_verbs =
+ cm9825_ibp_lineout_remove_verbs;
+ spec->chip_playback_start_verbs =
+ cm9825_ibp_playback_start_verbs;
+ spec->chip_playback_stop_verbs = cm9825_ibp_playback_stop_verbs;
+
+ /* OMTP */
+ val =
+ snd_hda_codec_read(codec, 0x46, 0, CM9825_VERB_READ_OMTP,
+ 0x0);
+ snd_hda_codec_write(codec, 0x46, 0, CM9825_VERB_SET_OMTP,
+ (val >> 24) & 0x7f);
+ break;
default:
err = -ENXIO;
break;
diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
--- a/sound/hda/codecs/conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -292,6 +292,7 @@ enum {
CXT_PINCFG_TOP_SPEAKER,
CXT_FIXUP_HP_A_U,
CXT_FIXUP_ACER_SWIFT_HP,
+ CXT_FIXUP_HUAWEI_MATEBOOK_HP,
};
/* for hda_fixup_thinkpad_acpi() */
@@ -451,7 +452,8 @@ static void olpc_xo_update_mic_pins(struct hda_codec *codec)
if (!spec->dc_enable) {
/* disable DC bias path and pin for port F */
update_mic_pin(codec, 0x1e, 0);
- snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
+ if (spec->dc_mode_path)
+ snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
/* update port B (ext mic) and C (int mic) */
/* OLPC defers mic widget control until when capture is
@@ -487,7 +489,8 @@ static void olpc_xo_update_mic_pins(struct hda_codec *codec)
update_mic_pin(codec, 0x1b, 0);
/* enable DC bias path and pin */
update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
- snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
+ if (spec->dc_mode_path)
+ snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
}
}
@@ -1033,6 +1036,13 @@ static const struct hda_fixup cxt_fixups[] = {
{ }
},
},
+ [CXT_FIXUP_HUAWEI_MATEBOOK_HP] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x18, 0x03211020 }, /* Headphone */
+ { }
+ },
+ },
};
static const struct hda_quirk cxt5045_fixups[] = {
@@ -1097,6 +1107,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x837b, "HP ProBook 440 G5", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
@@ -1133,6 +1144,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad/Ideapad", CXT_FIXUP_LENOVO_XPAD_ACPI),
+ SND_PCI_QUIRK(0x19e5, 0x3289, "Huawei Matebook", CXT_FIXUP_HUAWEI_MATEBOOK_HP),
SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
SND_PCI_QUIRK(0x1d05, 0x3012, "MECHREVO Wujie 15X Pro", CXT_FIXUP_HEADSET_MIC),
diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c
--- a/sound/hda/codecs/generic.c
+++ b/sound/hda/codecs/generic.c
@@ -2695,30 +2695,13 @@ static const struct snd_kcontrol_new out_jack_mode_enum = {
.put = out_jack_mode_put,
};
-static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx)
-{
- struct hda_gen_spec *spec = codec->spec;
- const struct snd_kcontrol_new *kctl;
- int i;
-
- snd_array_for_each(&spec->kctls, i, kctl) {
- if (!strcmp(kctl->name, name) && kctl->index == idx)
- return true;
- }
- return false;
-}
-
static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
char *name, size_t name_len)
{
struct hda_gen_spec *spec = codec->spec;
- int idx = 0;
- snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx);
- strlcat(name, " Jack Mode", name_len);
-
- for (; find_kctl_name(codec, name, idx); idx++)
- ;
+ snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len);
+ hda_append_suffix(name, " Jack Mode", name_len);
}
static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
@@ -5695,7 +5678,7 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
break;
}
}
- strlcat(str, sfx, len);
+ hda_append_suffix(str, sfx, len);
}
/* copy PCM stream info from @default_str, and override non-NULL entries
diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c
--- a/sound/hda/codecs/hdmi/hdmi.c
+++ b/sound/hda/codecs/hdmi/hdmi.c
@@ -2236,8 +2236,10 @@ void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
/* skip notification during system suspend (but not in runtime PM);
* the state will be updated at resume
*/
- if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
+ if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ codec->acomp_requested_resume = 1;
return;
+ }
snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id);
}
@@ -2346,6 +2348,7 @@ static const struct hda_device_id snd_hda_id_generichdmi[] = {
HDA_CODEC_ID_MODEL(0x1d179f8e, "KX-7000 HDMI/DP", MODEL_GF),
HDA_CODEC_ID_MODEL(0x1d179f8f, "KX-7000 HDMI/DP", MODEL_GF),
HDA_CODEC_ID_MODEL(0x1d179f90, "KX-7000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x4c545020, "Lisuan HDMI/DP", MODEL_GENERIC),
HDA_CODEC_ID_MODEL(0x67663d82, "Arise 82 HDMI/DP", MODEL_GF),
HDA_CODEC_ID_MODEL(0x67663d83, "Arise 83 HDMI/DP", MODEL_GF),
HDA_CODEC_ID_MODEL(0x67663d84, "Arise 84 HDMI/DP", MODEL_GF),
diff --git a/sound/hda/codecs/helpers/razer_blade16_2025.c b/sound/hda/codecs/helpers/razer_blade16_2025.c
new file mode 100644
--- /dev/null
+++ b/sound/hda/codecs/helpers/razer_blade16_2025.c
@@ -0,0 +1,820 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Razer Blade 16 (2025) external smart-amplifier programming and fixup,
+ * to be included from the codec driver.
+ *
+ * The internal speakers are driven by an external smart amplifier whose
+ * crossover, voicing and protection live in a DSP reached over a vendor
+ * coef mailbox on NID 0x20. These tables hold the programming captured
+ * from the Windows driver, reduced to the NID-0x20 traffic this machine
+ * needs (everything else the HDA parser rebuilds).
+ *
+ * Each entry is either a plain codec coef write or a mailbox write:
+ * strobe == 0: coef[addr] = lo
+ * strobe != 0: amp[addr] = (hi << 16) | lo, with the bank selected on
+ * port 0x89 and the write committed by the strobe opcode.
+ */
+
+struct alc298_razer_blade16_2025_op {
+ u16 bank; /* mailbox bank (port 0x89); unused for a plain coef */
+ u16 addr; /* mailbox register, or plain coef index */
+ u16 hi; /* mailbox high word; unused for a plain coef */
+ u16 lo; /* mailbox low word, or plain coef value */
+ u16 strobe; /* mailbox commit opcode; 0 marks a plain coef write */
+};
+
+/* program the external DSP at init; the amp is woken/parked separately */
+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_init[] = {
+ { 0x0000, 0xf102, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xf103, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc000, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xea00, 0x0000, 0x0047, 0xb031 },
+ { 0x0000, 0xf20d, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xf212, 0x0000, 0x003e, 0xb031 },
+ { 0x0000, 0xc001, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xc003, 0x0000, 0x0022, 0xb031 },
+ { 0x0000, 0xc004, 0x0000, 0x0044, 0xb031 },
+ { 0x0000, 0xc005, 0x0000, 0x0044, 0xb031 },
+ { 0x0000, 0xc007, 0x0000, 0x0064, 0xb031 },
+ { 0x0000, 0xc00e, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xf223, 0x0000, 0x007f, 0xb031 },
+ { 0x0000, 0xf224, 0x0000, 0x00db, 0xb031 },
+ { 0x0000, 0xf225, 0x0000, 0x00ee, 0xb031 },
+ { 0x0000, 0xf226, 0x0000, 0x003f, 0xb031 },
+ { 0x0000, 0xf227, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xf21a, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xf242, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xc120, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xc125, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xc321, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xc200, 0x0000, 0x00d8, 0xb031 },
+ { 0x0000, 0xc201, 0x0000, 0x0027, 0xb031 },
+ { 0x0000, 0xc202, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xc400, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc401, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xc402, 0x0000, 0x00e0, 0xb031 },
+ { 0x0000, 0xc403, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc404, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xc406, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xc407, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xc408, 0x0000, 0x003f, 0xb031 },
+ { 0x0000, 0xc300, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc125, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xdf00, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xdf5f, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xdf60, 0x0000, 0x00a7, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x0084, 0xb031 },
+ { 0x0000, 0xc206, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xf10a, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xf104, 0x0000, 0x00f4, 0xb031 },
+ { 0x0000, 0xf105, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x00e0, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 },
+ { 0x0000, 0xf104, 0x0000, 0x00f4, 0xb031 },
+ { 0x0000, 0xf105, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x0065, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 },
+ { 0x0000, 0xf104, 0x0000, 0x00f7, 0xb031 },
+ { 0x0000, 0xf105, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 },
+ { 0x0000, 0xf104, 0x0000, 0x00f7, 0xb031 },
+ { 0x0000, 0xf105, 0x0000, 0x0031, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 },
+ { 0x0000, 0xe706, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xe707, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xe806, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xe807, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xce04, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xce05, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xce06, 0x0000, 0x0031, 0xb031 },
+ { 0x0000, 0xce07, 0x0000, 0x00b4, 0xb031 },
+ { 0x0000, 0xcf04, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xcf05, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xcf06, 0x0000, 0x0031, 0xb031 },
+ { 0x0000, 0xcf07, 0x0000, 0x00b4, 0xb031 },
+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xc130, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xe000, 0x0000, 0x00a8, 0xb031 },
+ { 0x4100, 0x1888, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc121, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xea00, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xca00, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xca02, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xca12, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xed00, 0x0000, 0x0090, 0xb031 },
+ { 0x0000, 0xcc2c, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc2d, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xcc2e, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xcc2f, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xcd2c, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd2d, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xcd2e, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xcd2f, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xcc24, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc25, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xcc26, 0x0000, 0x00eb, 0xb031 },
+ { 0x0000, 0xcc27, 0x0000, 0x0085, 0xb031 },
+ { 0x0000, 0xcd24, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd25, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xcd26, 0x0000, 0x00eb, 0xb031 },
+ { 0x0000, 0xcd27, 0x0000, 0x0085, 0xb031 },
+ { 0x0000, 0xcc20, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc21, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc22, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xcd20, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd21, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd22, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xcc16, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xcc17, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd16, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xcd17, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc29, 0x0000, 0x005d, 0xb031 },
+ { 0x0000, 0xcc2a, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xcd29, 0x0000, 0x005d, 0xb031 },
+ { 0x0000, 0xcd2a, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xcc31, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xcc32, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc33, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc34, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd31, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xcd32, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd33, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd34, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc36, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xcc37, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcc38, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcc39, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcd36, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xcd37, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcd38, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcd39, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcc09, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc0a, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xcc0b, 0x0000, 0x007c, 0xb031 },
+ { 0x0000, 0xcc0c, 0x0000, 0x005b, 0xb031 },
+ { 0x0000, 0xcd09, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd0a, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xcd0b, 0x0000, 0x007c, 0xb031 },
+ { 0x0000, 0xcd0c, 0x0000, 0x005b, 0xb031 },
+ { 0x0000, 0xcc0e, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc0f, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xcc10, 0x0000, 0x003e, 0xb031 },
+ { 0x0000, 0xcc11, 0x0000, 0x002d, 0xb031 },
+ { 0x0000, 0xcd0e, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd0f, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xcd10, 0x0000, 0x003e, 0xb031 },
+ { 0x0000, 0xcd11, 0x0000, 0x002d, 0xb031 },
+ { 0x0000, 0xccd6, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xccd7, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xcdd6, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcdd7, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xccd8, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xccd9, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xcdd8, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcdd9, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xccda, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xccdb, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xcdda, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcddb, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xc320, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xc321, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xe604, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xdd00, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xdc19, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdc1a, 0x0000, 0x006a, 0xb031 },
+ { 0x0000, 0xdc1b, 0x0000, 0x00aa, 0xb031 },
+ { 0x0000, 0xdc1c, 0x0000, 0x00ab, 0xb031 },
+ { 0x0000, 0xdc1d, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdc1e, 0x0000, 0x0027, 0xb031 },
+ { 0x0000, 0xdc1f, 0x0000, 0x0062, 0xb031 },
+ { 0x0000, 0xdc20, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xde19, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xde1a, 0x0000, 0x006a, 0xb031 },
+ { 0x0000, 0xde1b, 0x0000, 0x00aa, 0xb031 },
+ { 0x0000, 0xde1c, 0x0000, 0x00ab, 0xb031 },
+ { 0x0000, 0xde1d, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xde1e, 0x0000, 0x0027, 0xb031 },
+ { 0x0000, 0xde1f, 0x0000, 0x0062, 0xb031 },
+ { 0x0000, 0xde20, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xdb32, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdd32, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdb33, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xdd33, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xdb34, 0x0000, 0x001a, 0xb031 },
+ { 0x0000, 0xdd34, 0x0000, 0x001a, 0xb031 },
+ { 0x0000, 0xdb15, 0x0000, 0x00ef, 0xb031 },
+ { 0x0000, 0xdd15, 0x0000, 0x00ef, 0xb031 },
+ { 0x0000, 0xdb17, 0x0000, 0x003f, 0xb031 },
+ { 0x0000, 0xdd17, 0x0000, 0x003f, 0xb031 },
+ { 0x0000, 0xdb94, 0x0000, 0x0070, 0xb031 },
+ { 0x0000, 0xdd94, 0x0000, 0x0070, 0xb031 },
+ { 0x0000, 0xdb19, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xdd19, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x001c, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xdb04, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xdb05, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xdd04, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xdd05, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xdbbb, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xdbbc, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xdbbd, 0x0000, 0x00f3, 0xb031 },
+ { 0x0000, 0xdbbe, 0x0000, 0x00cf, 0xb031 },
+ { 0x0000, 0xddbb, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xddbc, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xddbd, 0x0000, 0x00f3, 0xb031 },
+ { 0x0000, 0xddbe, 0x0000, 0x00cf, 0xb031 },
+ { 0x0000, 0xdb01, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xdd01, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xdb08, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xdd08, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xdc52, 0x0000, 0x00ef, 0xb031 },
+ { 0x0000, 0xde52, 0x0000, 0x00ef, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 },
+ { 0x0000, 0xdf0a, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdf0b, 0x0000, 0x007f, 0xb031 },
+ { 0x0000, 0xc851, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xc951, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xdf01, 0x0000, 0x0073, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 },
+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xebcb, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeb10, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb11, 0x0000, 0x00bb, 0xb031 },
+ { 0x0000, 0xeb12, 0x0000, 0x00ab, 0xb031 },
+ { 0x0000, 0xeb13, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xeb14, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb15, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xeb16, 0x0000, 0x0069, 0xb031 },
+ { 0x0000, 0xeb21, 0x0000, 0x0011, 0xb031 },
+ { 0x0000, 0xeb22, 0x0000, 0x00c2, 0xb031 },
+ { 0x0000, 0xeb23, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeb24, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb25, 0x0000, 0x00bd, 0xb031 },
+ { 0x0000, 0xeb26, 0x0000, 0x0055, 0xb031 },
+ { 0x0000, 0xeb27, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xeb28, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb29, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xeb2a, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xeb2b, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xeb30, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb31, 0x0000, 0x004f, 0xb031 },
+ { 0x0000, 0xeb32, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xeb33, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xeb34, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb35, 0x0000, 0x00bb, 0xb031 },
+ { 0x0000, 0xeb36, 0x0000, 0x0024, 0xb031 },
+ { 0x0000, 0xeb37, 0x0000, 0x0068, 0xb031 },
+ { 0x0000, 0xeb40, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb41, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xeb42, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xeb43, 0x0000, 0x00e8, 0xb031 },
+ { 0x0000, 0xeb44, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb45, 0x0000, 0x004f, 0xb031 },
+ { 0x0000, 0xeb46, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xeb47, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xeb48, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb49, 0x0000, 0x00c5, 0xb031 },
+ { 0x0000, 0xeb4a, 0x0000, 0x0032, 0xb031 },
+ { 0x0000, 0xeb4b, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeb50, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb51, 0x0000, 0x008a, 0xb031 },
+ { 0x0000, 0xeb52, 0x0000, 0x00b4, 0xb031 },
+ { 0x0000, 0xeb53, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xeb54, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb55, 0x0000, 0x007d, 0xb031 },
+ { 0x0000, 0xeb56, 0x0000, 0x00d9, 0xb031 },
+ { 0x0000, 0xeb57, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xeb60, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xeb61, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xeb62, 0x0000, 0x00b5, 0xb031 },
+ { 0x0000, 0xeb63, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb64, 0x0000, 0x00fa, 0xb031 },
+ { 0x0000, 0xeb65, 0x0000, 0x0086, 0xb031 },
+ { 0x0000, 0xeb66, 0x0000, 0x00a8, 0xb031 },
+ { 0x0000, 0xeb67, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xeb68, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xeb69, 0x0000, 0x009a, 0xb031 },
+ { 0x0000, 0xeb6a, 0x0000, 0x002f, 0xb031 },
+ { 0x0000, 0xeb6b, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xebb6, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeb70, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xeb71, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xeb72, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xeb73, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xeb74, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xeb75, 0x0000, 0x0050, 0xb031 },
+ { 0x0000, 0xeb76, 0x0000, 0x002c, 0xb031 },
+ { 0x0000, 0xeb77, 0x0000, 0x0050, 0xb031 },
+ { 0x0000, 0xeb80, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb81, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xeb82, 0x0000, 0x0016, 0xb031 },
+ { 0x0000, 0xeb83, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xeb84, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xeb85, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xeb86, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xeb87, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xeb88, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb89, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xeb8a, 0x0000, 0x0016, 0xb031 },
+ { 0x0000, 0xeb8b, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xebb8, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeb90, 0x0000, 0x00fc, 0xb031 },
+ { 0x0000, 0xeb91, 0x0000, 0x008b, 0xb031 },
+ { 0x0000, 0xeb92, 0x0000, 0x00bd, 0xb031 },
+ { 0x0000, 0xeb93, 0x0000, 0x0064, 0xb031 },
+ { 0x0000, 0xeb94, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xeb95, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xeb96, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xeb97, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xeba0, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeba1, 0x0000, 0x0091, 0xb031 },
+ { 0x0000, 0xeba2, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xeba3, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeba4, 0x0000, 0x00f6, 0xb031 },
+ { 0x0000, 0xeba5, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeba6, 0x0000, 0x0093, 0xb031 },
+ { 0x0000, 0xeba7, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xeba8, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xeba9, 0x0000, 0x0087, 0xb031 },
+ { 0x0000, 0xebaa, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xebab, 0x0000, 0x006c, 0xb031 },
+ { 0x0000, 0xebc3, 0x0000, 0x00ff, 0xb031 },
+ { 0x0000, 0xebc4, 0x0000, 0x00fc, 0xb031 },
+ { 0x0000, 0xeb00, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xeb01, 0x0000, 0x00a9, 0xb031 },
+ { 0x0000, 0xeb02, 0x0000, 0x00df, 0xb031 },
+ { 0x0000, 0xeb03, 0x0000, 0x007b, 0xb031 },
+ { 0x0000, 0xeb05, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xeb06, 0x0000, 0x005a, 0xb031 },
+ { 0x0000, 0xeb07, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xebc0, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xd0cb, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xd0b0, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xd010, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd011, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xd012, 0x0000, 0x0092, 0xb031 },
+ { 0x0000, 0xd013, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd014, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd015, 0x0000, 0x00f6, 0xb031 },
+ { 0x0000, 0xd016, 0x0000, 0x0072, 0xb031 },
+ { 0x0000, 0xd017, 0x0000, 0x00b0, 0xb031 },
+ { 0x0000, 0xd020, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd021, 0x0000, 0x00fb, 0xb031 },
+ { 0x0000, 0xd022, 0x0000, 0x0037, 0xb031 },
+ { 0x0000, 0xd023, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd024, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd025, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xd026, 0x0000, 0x0090, 0xb031 },
+ { 0x0000, 0xd027, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xd028, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd029, 0x0000, 0x00fb, 0xb031 },
+ { 0x0000, 0xd02a, 0x0000, 0x0037, 0xb031 },
+ { 0x0000, 0xd02b, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd0c3, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd0c4, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xd0c0, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xce6a, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xce63, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xce64, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 },
+ { 0x0000, 0xdb04, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xdb05, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xcc00, 0x0000, 0x00c1, 0xb031 },
+ { 0x0000, 0xca02, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xca00, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xca62, 0x0000, 0x0077, 0xb031 },
+ { 0x0000, 0xca65, 0x0000, 0x0082, 0xb031 },
+ { 0x0000, 0xca68, 0x0000, 0x00c2, 0xb031 },
+ { 0x0000, 0xca75, 0x0000, 0x003a, 0xb031 },
+ { 0x0000, 0xca7b, 0x0000, 0x006f, 0xb031 },
+ { 0x0000, 0xca00, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xca02, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc860, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc861, 0x0000, 0x00e5, 0xb031 },
+ { 0x0000, 0xc862, 0x0000, 0x00eb, 0xb031 },
+ { 0x0000, 0xc863, 0x0000, 0x00c6, 0xb031 },
+ { 0x0000, 0xc864, 0x0000, 0x00ba, 0xb031 },
+ { 0x0000, 0xc865, 0x0000, 0x0061, 0xb031 },
+ { 0x0000, 0xc867, 0x0000, 0x0017, 0xb031 },
+ { 0x0000, 0xc868, 0x0000, 0x00ed, 0xb031 },
+ { 0x0000, 0xc869, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xc86a, 0x0000, 0x008a, 0xb031 },
+ { 0x0000, 0xc86b, 0x0000, 0x00e2, 0xb031 },
+ { 0x0000, 0xc875, 0x0000, 0x003a, 0xb031 },
+ { 0x0000, 0xc87b, 0x0000, 0x006f, 0xb031 },
+ { 0x0000, 0xc836, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc8a0, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc833, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xc834, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xc83f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc83e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc83a, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xc83b, 0x0000, 0x0089, 0xb031 },
+ { 0x0000, 0xc830, 0x0000, 0x0013, 0xb031 },
+ { 0x0000, 0xc826, 0x0000, 0x00d1, 0xb031 },
+ { 0x0000, 0xc890, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc823, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc824, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xc82f, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xc82e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc820, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xc816, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc880, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xc813, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc814, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc81f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc81e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc81a, 0x0000, 0x0066, 0xb031 },
+ { 0x0000, 0xc81b, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc810, 0x0000, 0x000d, 0xb031 },
+ { 0x0000, 0xc846, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc8d0, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc844, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc84f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc84e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc84a, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc84b, 0x0000, 0x0056, 0xb031 },
+ { 0x0000, 0xc800, 0x0000, 0x00b0, 0xb031 },
+ { 0x0000, 0xc851, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xc500, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc501, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc502, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xc503, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc504, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xc505, 0x0000, 0x00da, 0xb031 },
+ { 0x0000, 0xc506, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc507, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc510, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xc511, 0x0000, 0x00da, 0xb031 },
+ { 0x0000, 0xc512, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc513, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc514, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc515, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc516, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xc517, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc518, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xc541, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xd250, 0x0000, 0x0087, 0xb031 },
+ { 0x0000, 0xd251, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xd264, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 },
+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xecb0, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xec10, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec11, 0x0000, 0x00bb, 0xb031 },
+ { 0x0000, 0xec12, 0x0000, 0x00ab, 0xb031 },
+ { 0x0000, 0xec13, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xec14, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec15, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xec16, 0x0000, 0x0069, 0xb031 },
+ { 0x0000, 0xec21, 0x0000, 0x0011, 0xb031 },
+ { 0x0000, 0xec22, 0x0000, 0x00c2, 0xb031 },
+ { 0x0000, 0xec23, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xec24, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec25, 0x0000, 0x00bd, 0xb031 },
+ { 0x0000, 0xec26, 0x0000, 0x0055, 0xb031 },
+ { 0x0000, 0xec27, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xec28, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec29, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xec2a, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xec2b, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xecb2, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xec30, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec31, 0x0000, 0x004f, 0xb031 },
+ { 0x0000, 0xec32, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xec33, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xec34, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec35, 0x0000, 0x00bb, 0xb031 },
+ { 0x0000, 0xec36, 0x0000, 0x0024, 0xb031 },
+ { 0x0000, 0xec37, 0x0000, 0x0068, 0xb031 },
+ { 0x0000, 0xec40, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec41, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xec42, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xec43, 0x0000, 0x00e8, 0xb031 },
+ { 0x0000, 0xec44, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec45, 0x0000, 0x004f, 0xb031 },
+ { 0x0000, 0xec46, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xec47, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xec48, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec49, 0x0000, 0x00c5, 0xb031 },
+ { 0x0000, 0xec4a, 0x0000, 0x0032, 0xb031 },
+ { 0x0000, 0xec4b, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xecb4, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xec50, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec51, 0x0000, 0x008a, 0xb031 },
+ { 0x0000, 0xec52, 0x0000, 0x00b4, 0xb031 },
+ { 0x0000, 0xec53, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xec54, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec55, 0x0000, 0x007d, 0xb031 },
+ { 0x0000, 0xec56, 0x0000, 0x00d9, 0xb031 },
+ { 0x0000, 0xec57, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xec60, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xec61, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xec62, 0x0000, 0x00b5, 0xb031 },
+ { 0x0000, 0xec63, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec64, 0x0000, 0x00fa, 0xb031 },
+ { 0x0000, 0xec65, 0x0000, 0x0086, 0xb031 },
+ { 0x0000, 0xec66, 0x0000, 0x00a8, 0xb031 },
+ { 0x0000, 0xec67, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xec68, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xec69, 0x0000, 0x009a, 0xb031 },
+ { 0x0000, 0xec6a, 0x0000, 0x002f, 0xb031 },
+ { 0x0000, 0xec6b, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xecb6, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xec70, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xec71, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xec72, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xec73, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xec74, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xec75, 0x0000, 0x0050, 0xb031 },
+ { 0x0000, 0xec76, 0x0000, 0x002c, 0xb031 },
+ { 0x0000, 0xec77, 0x0000, 0x0050, 0xb031 },
+ { 0x0000, 0xec80, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec81, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xec82, 0x0000, 0x0016, 0xb031 },
+ { 0x0000, 0xec83, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xec84, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xec85, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xec86, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xec87, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xec88, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec89, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xec8a, 0x0000, 0x0016, 0xb031 },
+ { 0x0000, 0xec8b, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xecb8, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xec90, 0x0000, 0x00fc, 0xb031 },
+ { 0x0000, 0xec91, 0x0000, 0x008b, 0xb031 },
+ { 0x0000, 0xec92, 0x0000, 0x00bd, 0xb031 },
+ { 0x0000, 0xec93, 0x0000, 0x0064, 0xb031 },
+ { 0x0000, 0xec94, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xec95, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xec96, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xec97, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xeca0, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeca1, 0x0000, 0x0091, 0xb031 },
+ { 0x0000, 0xeca2, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xeca3, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeca4, 0x0000, 0x00f6, 0xb031 },
+ { 0x0000, 0xeca5, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeca6, 0x0000, 0x0093, 0xb031 },
+ { 0x0000, 0xeca7, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xeca8, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xeca9, 0x0000, 0x0087, 0xb031 },
+ { 0x0000, 0xecaa, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xecab, 0x0000, 0x006c, 0xb031 },
+ { 0x0000, 0xebc3, 0x0000, 0x00ff, 0xb031 },
+ { 0x0000, 0xebc4, 0x0000, 0x00fc, 0xb031 },
+ { 0x0000, 0xec00, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xec01, 0x0000, 0x00a9, 0xb031 },
+ { 0x0000, 0xec02, 0x0000, 0x00df, 0xb031 },
+ { 0x0000, 0xec03, 0x0000, 0x007b, 0xb031 },
+ { 0x0000, 0xec05, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xec06, 0x0000, 0x005a, 0xb031 },
+ { 0x0000, 0xec07, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xebc0, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xd1b0, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xd110, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd111, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xd112, 0x0000, 0x0092, 0xb031 },
+ { 0x0000, 0xd113, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd114, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd115, 0x0000, 0x00f6, 0xb031 },
+ { 0x0000, 0xd116, 0x0000, 0x0072, 0xb031 },
+ { 0x0000, 0xd117, 0x0000, 0x00b0, 0xb031 },
+ { 0x0000, 0xd120, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd121, 0x0000, 0x00fb, 0xb031 },
+ { 0x0000, 0xd122, 0x0000, 0x0037, 0xb031 },
+ { 0x0000, 0xd123, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd124, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd125, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xd126, 0x0000, 0x0090, 0xb031 },
+ { 0x0000, 0xd127, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xd128, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd129, 0x0000, 0x00fb, 0xb031 },
+ { 0x0000, 0xd12a, 0x0000, 0x0037, 0xb031 },
+ { 0x0000, 0xd12b, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd0c3, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd0c4, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xd0c0, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xce63, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xce64, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 },
+ { 0x0000, 0xdd04, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xdd05, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xca12, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xca82, 0x0000, 0x0077, 0xb031 },
+ { 0x0000, 0xca85, 0x0000, 0x0082, 0xb031 },
+ { 0x0000, 0xca88, 0x0000, 0x00c2, 0xb031 },
+ { 0x0000, 0xca95, 0x0000, 0x003a, 0xb031 },
+ { 0x0000, 0xca9b, 0x0000, 0x006f, 0xb031 },
+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xca12, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc960, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc961, 0x0000, 0x00e5, 0xb031 },
+ { 0x0000, 0xc962, 0x0000, 0x00eb, 0xb031 },
+ { 0x0000, 0xc963, 0x0000, 0x00c6, 0xb031 },
+ { 0x0000, 0xc964, 0x0000, 0x00ba, 0xb031 },
+ { 0x0000, 0xc965, 0x0000, 0x0061, 0xb031 },
+ { 0x0000, 0xc967, 0x0000, 0x0017, 0xb031 },
+ { 0x0000, 0xc968, 0x0000, 0x00ed, 0xb031 },
+ { 0x0000, 0xc969, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xc96a, 0x0000, 0x008a, 0xb031 },
+ { 0x0000, 0xc96b, 0x0000, 0x00e2, 0xb031 },
+ { 0x0000, 0xc975, 0x0000, 0x003a, 0xb031 },
+ { 0x0000, 0xc97b, 0x0000, 0x006f, 0xb031 },
+ { 0x0000, 0xc936, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc9a0, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc933, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xc934, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xc93f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc93e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc93a, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xc93b, 0x0000, 0x0089, 0xb031 },
+ { 0x0000, 0xc930, 0x0000, 0x0013, 0xb031 },
+ { 0x0000, 0xc926, 0x0000, 0x00d1, 0xb031 },
+ { 0x0000, 0xc990, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc923, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc924, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xc92f, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xc92e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc920, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xc916, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc980, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xc913, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc914, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc91f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc91e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc91a, 0x0000, 0x0066, 0xb031 },
+ { 0x0000, 0xc91b, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc910, 0x0000, 0x000d, 0xb031 },
+ { 0x0000, 0xc946, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc9d0, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc944, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc94f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc94e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc94a, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc94b, 0x0000, 0x0056, 0xb031 },
+ { 0x0000, 0xc951, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xc600, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc601, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc602, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xc603, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc604, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xc605, 0x0000, 0x00da, 0xb031 },
+ { 0x0000, 0xc606, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc607, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc610, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xc611, 0x0000, 0x00da, 0xb031 },
+ { 0x0000, 0xc612, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc613, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc614, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc615, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc616, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xc617, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc618, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xc541, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xc802, 0x0000, 0x00d2, 0xb031 },
+ { 0x0000, 0xc902, 0x0000, 0x00d2, 0xb031 },
+ { 0x0000, 0xc800, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd250, 0x0000, 0x0087, 0xb031 },
+ { 0x0000, 0xd252, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xd264, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xdf00, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xdbb5, 0x0041, 0xd27f, 0xb037 },
+ { 0x0000, 0xddb5, 0x0040, 0x6e3b, 0xb037 },
+ { 0x0000, 0xdb93, 0x0000, 0x009e, 0xb033 },
+ { 0x0000, 0xdd93, 0x0000, 0x009e, 0xb033 },
+ { 0x0000, 0xdb12, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xdd12, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xdb08, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xdd08, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 },
+ { 0x0000, 0x0010, 0x0000, 0x0f21, 0x0000 },
+};
+
+/* wake the amp (ea00=0x43, c121=0x0b, f109=0xe0) */
+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_wake[] = {
+ { 0x0000, 0xea00, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xc121, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x00e0, 0xb031 },
+};
+
+/* park the amp (ea00=0x47, c121=0x0a, f109=0xa0) */
+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_sleep[] = {
+ { 0x0000, 0xea00, 0x0000, 0x0047, 0xb031 },
+ { 0x0000, 0xc121, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x00a0, 0xb031 },
+};
+
+/*
+ * Razer Blade 16 (2025): Realtek ALC298 driving an external smart amp.
+ * Crossover, voicing and speaker protection live in an external DSP
+ * reached over a vendor-coef mailbox on NID 0x20; the captured DSP
+ * programming is in the tables above. NID 0x14, the BIOS-disabled
+ * tweeter pin, is re-exposed via a pin-config override so the parser
+ * drives it as a normal internal speaker (shared volume/mute, auto-mute
+ * on headphone insertion).
+ *
+ * alc298_razer_blade16_2025_apply() runs one op-table: a plain coef write
+ * (strobe == 0) goes through alc_write_coef_idx(), while a mailbox op
+ * selects a bank and streams four PROC_COEF words (addr/hi/lo/commit)
+ * into a single coef index (0x23) on NID 0x20 to reach the external DSP
+ * -- that one-index/many-words form is why it cannot be expressed as an
+ * alc_process_coef_fw() table (one value per index).
+ */
+static void alc298_razer_blade16_2025_apply(struct hda_codec *codec,
+ const struct alc298_razer_blade16_2025_op *seq,
+ int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (!seq[i].strobe) {
+ alc_write_coef_idx(codec, seq[i].addr, seq[i].lo);
+ continue;
+ }
+ alc_write_coef_idx(codec, 0x89, seq[i].bank);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x23);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].addr);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].hi);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].lo);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].strobe);
+ }
+}
+
+static void alc298_razer_blade16_2025_pcm_hook(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream,
+ int action)
+{
+ /* power the external amp only while a stream is running */
+ switch (action) {
+ case HDA_GEN_PCM_ACT_PREPARE:
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_wake,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_wake));
+ break;
+ case HDA_GEN_PCM_ACT_CLEANUP:
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_sleep,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_sleep));
+ break;
+ }
+}
+
+static void alc298_fixup_razer_blade16_2025(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /*
+ * Pin every output to a fixed converter so the routing does not
+ * rely on the generic parser's DAC-allocation heuristics: without
+ * a fixed assignment the parser brings up only one speaker pin and
+ * leaves the other silent, and the allocation could change between
+ * kernel versions. Both speaker pins share DAC 0x03 through mixer
+ * 0x0d: that is the only converter that drives the woofer (NID
+ * 0x17) on this machine -- feeding it from DAC 0x02 or the digital
+ * converter 0x06 leaves the woofer silent. Both pins carry the
+ * same stereo stream and the external amp does the crossover.
+ * Headphone NID 0x21 keeps DAC 0x02.
+ */
+ static const hda_nid_t preferred_pairs[] = {
+ 0x21, 0x02,
+ 0x14, 0x03,
+ 0x17, 0x03,
+ 0
+ };
+ struct alc_spec *spec = codec->spec;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.preferred_dacs = preferred_pairs;
+ break;
+ case HDA_FIXUP_ACT_PROBE:
+ spec->gen.pcm_playback_hook = alc298_razer_blade16_2025_pcm_hook;
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ /*
+ * Wake the amp, program its DSP at boot and on resume, then
+ * park it. It is woken again for playback and parked
+ * afterwards from the pcm_playback_hook.
+ */
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_wake,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_wake));
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_init,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_init));
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_sleep,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_sleep));
+ break;
+ }
+}
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -296,7 +296,8 @@ static void alc282_init(struct hda_codec *codec)
msleep(100);
/* Headphone capless set to normal mode */
- alc_write_coef_idx(codec, 0x78, coef78);
+ if (coef78 != -1)
+ alc_write_coef_idx(codec, 0x78, coef78);
}
static void alc282_shutup(struct hda_codec *codec)
@@ -333,7 +334,8 @@ static void alc282_shutup(struct hda_codec *codec)
alc_auto_setup_eapd(codec, false);
alc_shutup_pins(codec);
- alc_write_coef_idx(codec, 0x78, coef78);
+ if (coef78 != -1)
+ alc_write_coef_idx(codec, 0x78, coef78);
}
static const struct coef_fw alc283_coefs[] = {
@@ -585,15 +587,19 @@ static void alc285_hp_init(struct hda_codec *codec)
alc_write_coefex_idx(codec, 0x58, 0x00, 0xf888); /* HP depop procedure start */
val = alc_read_coefex_idx(codec, 0x58, 0x00);
- for (i = 0; i < 20 && val & 0x8000; i++) {
+ for (i = 0; i < 20 && val != -1 && val & 0x8000; i++) {
msleep(50);
val = alc_read_coefex_idx(codec, 0x58, 0x00);
} /* Wait for depop procedure finish */
- alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */
- alc_update_coef_idx(codec, 0x38, 1<<4, coef38);
- alc_update_coef_idx(codec, 0x0d, 0x110, coef0d);
- alc_update_coef_idx(codec, 0x36, 3<<13, coef36);
+ if (val != -1)
+ alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */
+ if (coef38 != -1)
+ alc_update_coef_idx(codec, 0x38, 1<<4, coef38);
+ if (coef0d != -1)
+ alc_update_coef_idx(codec, 0x0d, 0x110, coef0d);
+ if (coef36 != -1)
+ alc_update_coef_idx(codec, 0x36, 3<<13, coef36);
msleep(50);
alc_update_coef_idx(codec, 0x4a, 1<<15, 0);
@@ -858,7 +864,7 @@ static void alc294_hp_init(struct hda_codec *codec)
/* Wait for depop procedure finish */
val = alc_read_coefex_idx(codec, 0x58, 0x01);
- for (i = 0; i < 20 && val & 0x0080; i++) {
+ for (i = 0; i < 20 && val != -1 && val & 0x0080; i++) {
msleep(50);
val = alc_read_coefex_idx(codec, 0x58, 0x01);
}
@@ -1392,6 +1398,15 @@ static void alc245_fixup_hp_gpio_led(struct hda_codec *codec,
alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
}
+static void alc245_fixup_minisforum_jack_detect(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ if (action == HDA_FIXUP_ACT_INIT)
+ /* Clear Reset HP JD while preserving the other coefficient bits. */
+ alc_update_coef_idx(codec, 0x4a, BIT(15), 0);
+}
+
/* turn on/off mic-mute LED per capture hook via VREF change */
static int vref_micmute_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
@@ -2557,6 +2572,13 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
}
}
+static void alc285_lenovo_dac_rename(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_BUILD)
+ rename_ctl(codec, "Line Out Playback Volume",
+ "Headphone Playback Volume");
+}
static void alc290_fixup_mono_speakers(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3262,6 +3284,36 @@ static void find_cirrus_companion_amps(struct hda_codec *cdc)
comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count);
}
+static void aw88399_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(cdc, action, "i2c", "AWDZ8399", "-%s:00-aw88399-hda.%d", 2);
+}
+
+static void alc287_fixup_legion_16iax10h_aw88399(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /*
+ * Force DAC 0x02 for the bass speaker 0x17, as the default 0x06 lacks volume controls.
+ */
+ static const hda_nid_t conn[] = { 0x02 };
+ struct alc_spec *spec = codec->spec;
+
+ alc269_fixup_limit_int_mic_boost(codec, fix, action);
+ alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
+ alc_fixup_headset_jack(codec, fix, action);
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.suppress_auto_mic = 1;
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ spec->gen.multiout.max_channels = 2;
+ spec->gen.pcm_rec[0]->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 2;
+ break;
+ }
+}
+
static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
@@ -3357,6 +3409,9 @@ static void alc287_fixup_acer_micmute_led(struct hda_codec *codec,
/* for alc285_fixup_ideapad_s740_coef() */
#include "../helpers/ideapad_s740.c"
+/* for alc298_fixup_razer_blade16_2025() */
+#include "../helpers/razer_blade16_2025.c"
+
static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
@@ -3939,6 +3994,7 @@ enum {
ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572,
ALC269_FIXUP_ACER_AC700,
ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
+ ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST,
ALC269VB_FIXUP_ASUS_ZENBOOK,
ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A,
ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -4007,6 +4063,7 @@ enum {
ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC295_FIXUP_DISABLE_DAC3,
ALC285_FIXUP_SPEAKER2_TO_DAC1,
+ ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1,
ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1,
ALC285_FIXUP_ASUS_HEADSET_MIC,
ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS,
@@ -4076,7 +4133,6 @@ enum {
ALC294_FIXUP_ASUS_ALLY,
ALC294_FIXUP_ASUS_ALLY_PINS,
ALC294_FIXUP_ASUS_ALLY_VERBS,
- ALC294_FIXUP_ASUS_ALLY_SPEAKER,
ALC294_FIXUP_ASUS_HPE,
ALC294_FIXUP_ASUS_COEF_1B,
ALC294_FIXUP_ASUS_GX502_HP,
@@ -4101,6 +4157,8 @@ enum {
ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS,
ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS,
ALC298_FIXUP_LG_GRAM_STYLE_14,
+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS,
+ ALC298_FIXUP_RAZER_BLADE16_2025,
ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -4118,7 +4176,6 @@ enum {
ALC269_FIXUP_LEMOTE_A190X,
ALC256_FIXUP_INTEL_NUC8_RUGGED,
ALC233_FIXUP_INTEL_NUC8_DMIC,
- ALC233_FIXUP_INTEL_NUC8_BOOST,
ALC256_FIXUP_INTEL_NUC10,
ALC255_FIXUP_XIAOMI_HEADSET_MIC,
ALC274_FIXUP_HP_MIC,
@@ -4149,6 +4206,7 @@ enum {
ALC298_FIXUP_LENOVO_C940_DUET7,
ALC287_FIXUP_LENOVO_YOGA_BOOK_9I,
ALC287_FIXUP_LENOVO_YOGA_PRO7,
+ ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK,
ALC287_FIXUP_13S_GEN2_SPEAKERS,
ALC256_FIXUP_SET_COEF_DEFAULTS,
ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
@@ -4193,7 +4251,6 @@ enum {
ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD,
ALC2XX_FIXUP_HEADSET_MIC,
ALC289_FIXUP_DELL_CS35L41_SPI_2,
- ALC294_FIXUP_CS35L41_I2C_2,
ALC256_FIXUP_ACER_SFG16_MICMUTE_LED,
ALC256_FIXUP_HEADPHONE_AMP_VOL,
ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX,
@@ -4207,6 +4264,7 @@ enum {
ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318,
ALC256_FIXUP_CHROME_BOOK,
ALC245_FIXUP_CLEVO_NOISY_MIC,
+ ALC245_FIXUP_MINISFORUM_JACK_DETECT,
ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
ALC233_FIXUP_MEDION_MTL_SPK,
ALC233_FIXUP_STARLABS_STARFIGHTER,
@@ -4216,7 +4274,6 @@ enum {
ALC274_FIXUP_HP_AIO_BIND_DACS,
ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2,
ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC,
- ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1,
ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK,
ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE,
@@ -4236,6 +4293,10 @@ enum {
ALC236_FIXUP_DELL_HP_POP_NOISE,
ALC274_FIXUP_HP_89E9_GPIO,
ALC274_FIXUP_HP_VERBS,
+ ALC287_FIXUP_AW88399_I2C_2,
+ ALC287_FIXUP_LENOVO_LEGION_AW88399,
+ ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET,
+ ALC285_LENOVO_DAC_RENAME,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -4273,6 +4334,20 @@ static void alc287_fixup_lenovo_yoga_book_9i(struct hda_codec *codec,
}
static const struct hda_fixup alc269_fixups[] = {
+ [ALC298_FIXUP_RAZER_BLADE16_2025_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x90170121 }, /* tweeter as internal speaker, seq 1 */
+ { 0x17, 0x90170120 }, /* woofer as internal speaker, seq 0 */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC298_FIXUP_RAZER_BLADE16_2025,
+ },
+ [ALC298_FIXUP_RAZER_BLADE16_2025] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc298_fixup_razer_blade16_2025,
+ },
[ALC233_FIXUP_WUJIE_SPEAKERS] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -4713,6 +4788,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chain_id = ALC271_FIXUP_DMIC,
},
[ALC269_FIXUP_LIMIT_INT_MIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost
+ },
+ [ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_limit_int_mic_boost,
.chained = true,
@@ -5088,11 +5167,7 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic,
.chained = true,
- .chain_id = ALC233_FIXUP_INTEL_NUC8_BOOST,
- },
- [ALC233_FIXUP_INTEL_NUC8_BOOST] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc269_fixup_limit_int_mic_boost
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
},
[ALC255_FIXUP_DELL_SPK_NOISE] = {
.type = HDA_FIXUP_FUNC,
@@ -5153,6 +5228,10 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC285_FIXUP_SPEAKER2_TO_DAC1] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_speaker2_to_dac1,
+ },
+ [ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
.chained = true,
.chain_id = ALC269_FIXUP_THINKPAD_ACPI
},
@@ -5672,11 +5751,7 @@ static const struct hda_fixup alc269_fixups[] = {
{ }
},
.chained = true,
- .chain_id = ALC294_FIXUP_ASUS_ALLY_SPEAKER
- },
- [ALC294_FIXUP_ASUS_ALLY_SPEAKER] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc285_fixup_speaker2_to_dac1,
+ .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1
},
[ALC285_FIXUP_THINKPAD_X1_GEN7] = {
.type = HDA_FIXUP_FUNC,
@@ -6223,6 +6298,16 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_LENOVO_XPAD_ACPI,
},
+ [ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_jack,
+ .chained = true,
+ /* Same as ALC285_FIXUP_THINKPAD_HEADSET_JACK, except that the
+ * mute LEDs are driven through ideapad_laptop rather than
+ * thinkpad_acpi.
+ */
+ .chain_id = ALC287_FIXUP_LENOVO_YOGA_PRO7,
+ },
[ALC623_FIXUP_LENOVO_THINKSTATION_P340] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_no_shutup,
@@ -6662,10 +6747,6 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC289_FIXUP_DUAL_SPK
},
- [ALC294_FIXUP_CS35L41_I2C_2] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = cs35l41_fixup_i2c_two,
- },
[ALC256_FIXUP_ACER_SFG16_MICMUTE_LED] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc256_fixup_acer_sfg16_micmute_led,
@@ -6738,6 +6819,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
},
+ [ALC245_FIXUP_MINISFORUM_JACK_DETECT] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_minisforum_jack_detect,
+ },
[ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -6758,6 +6843,8 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC233_FIXUP_STARLABS_STARFIGHTER] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc233_fixup_starlabs_starfighter,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
},
[ALC294_FIXUP_BASS_SPEAKER_15] = {
.type = HDA_FIXUP_FUNC,
@@ -6785,11 +6872,7 @@ static const struct hda_fixup alc269_fixups[] = {
{ }
},
.chained = true,
- .chain_id = ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1
- },
- [ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc285_fixup_speaker2_to_dac1,
+ .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1
},
[ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC] = {
.type = HDA_FIXUP_FUNC,
@@ -6907,6 +6990,26 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC274_FIXUP_HP_89E9_GPIO,
},
+ [ALC287_FIXUP_AW88399_I2C_2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = aw88399_fixup_i2c_two,
+ },
+ [ALC287_FIXUP_LENOVO_LEGION_AW88399] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc287_fixup_legion_16iax10h_aw88399,
+ .chained = true,
+ .chain_id = ALC287_FIXUP_AW88399_I2C_2,
+ },
+ [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_jack,
+ .chained = true,
+ .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
+ },
+ [ALC285_LENOVO_DAC_RENAME] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_lenovo_dac_rename,
+ },
};
static const struct hda_quirk alc269_fixup_tbl[] = {
@@ -6960,8 +7063,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x159e, "Acer Nitro 5 AN515-46", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x1616, "Acer Aspire A515-57", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
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, 0x166c, "Acer Predator PH16-71", ALC2XX_FIXUP_HEADSET_MIC),
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),
@@ -6970,6 +7075,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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),
+ SND_PCI_QUIRK(0x1025, 0x1909, "Acer Nitro ANV16-42", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
@@ -7154,10 +7260,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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),
SND_PCI_QUIRK(0x103c, 0x85f0, "HP Laptop 15-dw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x85f3, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8603, "HP Omen 17-cb0xxx", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x860c, "HP ZBook 17 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ SND_PCI_QUIRK(0x103c, 0x864f, "HP Laptop 15-dy0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
@@ -7268,6 +7376,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a05, "HP Dragonfly Folio G3 2-in-1", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a06, "HP Dragonfly Folio G3 2-in-1", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8a0e, "HP Pavilion Laptop 15-eh2xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a1b, "HP 255 15.6 inch G9 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8a1f, "HP Laptop 14s-dr5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
@@ -7359,10 +7468,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX),
- SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX),
SND_PCI_QUIRK(0x103c, 0x8c21, "HP Pavilion Plus Laptop 14-ey0XXX", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x8c2d, "HP Victus 15-fa1xxx (MB 8C2D)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8c3f, "HP Victus 15-fa1xxx (MB 8C3F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
@@ -7511,6 +7621,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f57, "HP Trekker G7JC", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f62, "HP ZBook 8 G2a 16W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f7e, "HP Messi", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f94, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED),
SND_PCI_QUIRK(0x103c, 0x8f95, "HP ZBook 8 G2a 16", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED),
SND_PCI_QUIRK(0x1043, 0x1024, "ASUS Zephyrus G14 2025", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
@@ -7518,6 +7629,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
+ SND_PCI_QUIRK(0x1043, 0x1044, "ASUS GA403UM", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x106f, "ASUS VivoBook X515UA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
@@ -7525,16 +7637,15 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK),
SND_PCI_QUIRK(0x1043, 0x10a4, "ASUS TP3407SA", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x10c4, "ASUS Vivobook S14 S5406SA", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x10d3, "ASUS K6500ZC", ALC294_FIXUP_ASUS_SPK),
SND_PCI_QUIRK(0x1043, 0x1154, "ASUS TP3607SH", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x1194, "ASUS UM3406KA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
- HDA_CODEC_QUIRK(0x1043, 0x1204, "ASUS Strix G16 G615JMR", ALC287_FIXUP_TXNW2781_I2C_ASUS),
- SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
- HDA_CODEC_QUIRK(0x1043, 0x1214, "ASUS ROG Strix G615LP", ALC287_FIXUP_TXNW2781_I2C_ASUS),
- SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TXNW2781_I2C_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TXNW2781_I2C_ASUS),
SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
@@ -7583,7 +7694,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
- SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC294_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1970, "ASUS UX550VE", ALC289_FIXUP_ASUS_GA401),
@@ -7594,7 +7705,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x19f4, "ASUS UM3405GA", ALC294_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x1043, 0x1a63, "ASUS UX3405MA", ALC294_FIXUP_ASUS_SPI_HEADSET_MIC),
- SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1a8e, "ASUS G712LWS", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B),
@@ -7623,6 +7734,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15),
SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1e3e, "ASUS VivoBook M515DA/X515DAP", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1e1f, "ASUS Vivobook 15 X1504VAP", ALC2XX_FIXUP_HEADSET_MIC),
@@ -7634,8 +7746,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RC72LA", ALC287_FIXUP_ASUS_ALLY_X),
SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2),
- HDA_CODEC_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1),
- SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
@@ -7846,7 +7957,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
- SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
@@ -7862,7 +7973,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
- SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x225c, "Lenovo ThinkPad X1 Carbon 6th Gen", ALC285_LENOVO_DAC_RENAME),
+ SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2288, "Thinkpad X390", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
@@ -7937,7 +8049,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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),
+ SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_YOGA_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 */
HDA_CODEC_QUIRK(0x17aa, 0x38a7, "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),
@@ -7972,6 +8084,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38b8, "Yoga S780-14.5 proX AMD YC Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38b9, "Yoga S780-14.5 proX AMD LX Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C),
+ HDA_CODEC_QUIRK(0x17aa, 0x3926, "Legion Pro 5 16ADR10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ /* Legion R9000P ADR10 shares PCI SSID 17aa:38bb with Yoga S780-14.5 Air AMD quad AAC;
+ * use codec SSID to distinguish them
+ */
+ HDA_CODEC_QUIRK(0x17aa, 0x3927, "Legion R9000P ADR10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3928, "Legion R9000P ADR10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C),
@@ -7989,7 +8107,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38df, "Yoga Y990 Intel YC Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C),
- SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
/* Legion 7 15ASH11 shares PCI SSID 17aa:38f9 with Thinkbook 16P Gen5;
* use codec SSID to distinguish them
*/
@@ -7999,7 +8116,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38fc, "Lenovo Yoga Pro 7 15ASH11", ALC287_FIXUP_LENOVO_YOGA_PRO7),
SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
- SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ HDA_CODEC_QUIRK(0x17aa, 0x3906, "Legion Pro 7i 16IAX10H / Y9000P IAX10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3907, "Legion Pro 7i 16IAX10H / Y9000P IAX10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET),
SND_PCI_QUIRK(0x17aa, 0x3911, "Lenovo Yoga Pro 7 14IAH10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x3912, "Lenovo Xiaoxin 14 GT", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC),
@@ -8007,14 +8126,19 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3929, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x392b, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ HDA_CODEC_QUIRK(0x17aa, 0x3936, "Legion R9000P ADR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3937, "Legion R9000P ADR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3938, "Legion Pro 7 16AFR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3939, "Legion Pro 7 16AFR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ SND_PCI_QUIRK(0x17aa, 0x393e, "Lenovo ThinkBook 14 G8+ IPH", ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK),
HDA_CODEC_QUIRK(0x17aa, 0x394c, "Lenovo Yoga Slim 7 14AGP11", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
- SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
- SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK),
@@ -8027,7 +8151,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x505f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x5062, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x508b, "Thinkpad X12 Gen 1", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
- SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
@@ -8041,9 +8165,14 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1854, 0x0489, "LG gram 16 (16Z90R-A)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x1854, 0x0490, "LG Gram Style 14 (14Z90RS)", ALC298_FIXUP_LG_GRAM_STYLE_14),
+ SND_PCI_QUIRK(0x1854, 0x0554, "LG gram 16 (16Z90TR)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1a58, 0x2023, "Razer Blade 16 (2025)",
+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS),
+ SND_PCI_QUIRK(0x1a58, 0x300e, "Razer Blade 16 (2025)",
+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS),
SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
@@ -8078,13 +8207,17 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK),
SND_PCI_QUIRK(0x1e50, 0x7007, "Positivo DN50E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1e50, 0x7036, "Acer Gadget E10 ETBook", ALC233_FIXUP_WUJIE_SPEAKERS),
SND_PCI_QUIRK(0x1e50, 0x7038, "Positivo DN140", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1ee7, 0x2081, "HONOR MRB-XXX M1020", ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO),
+ SND_PCI_QUIRK(0x1f4c, 0xb020, "Minisforum AI X1 Pro",
+ ALC245_FIXUP_MINISFORUM_JACK_DETECT),
SND_PCI_QUIRK(0x1f4c, 0xe001, "Minisforum V3 (SE)", ALC245_FIXUP_BASS_HP_DAC),
SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2039, 0x0001, "Inspur S14-G1", ALC295_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x2145, 0x0001, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER),
SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13),
SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
@@ -8095,6 +8228,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX),
SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME),
SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK),
+ SND_PCI_QUIRK(0x2782, 0xa128, "Positivo N15RPE-S", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2782, 0xa212, "Lunnen Ground 14", ALC269VC_FIXUP_LUNNEN_GROUND_14),
SND_PCI_QUIRK(0x7017, 0x2014, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER),
SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
@@ -8168,6 +8302,7 @@ static const struct hda_quirk alc269_fixup_vendor_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo XPAD", ALC269_FIXUP_LENOVO_XPAD_ACPI),
SND_PCI_QUIRK_VENDOR(0x19e5, "Huawei Matebook", ALC255_FIXUP_MIC_MUTE_LED),
+ SND_PCI_QUIRK_VENDOR(0x2145, "Star Labs", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
{}
};
@@ -8307,6 +8442,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"},
{.id = ALC245_FIXUP_BASS_HP_DAC, .name = "alc245-fixup-bass-hp-dac"},
{.id = ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO, .name = "alc256-honor-mrb-xxx-m1020-audio"},
+ {.id = ALC287_FIXUP_LENOVO_LEGION_AW88399, .name = "alc287-lenovo-legion-aw88399"},
{}
};
#define ALC225_STANDARD_PINS \
@@ -8912,6 +9048,7 @@ static int alc269_probe(struct hda_codec *codec, const struct hda_device_id *id)
spec->init_hook = alc256_init;
spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
if (codec->core.vendor_id == 0x10ec0236 &&
+ codec->bus->pci &&
codec->bus->pci->vendor != PCI_VENDOR_ID_AMD)
spec->en_3kpull_low = false;
break;
diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c
--- a/sound/hda/codecs/realtek/alc662.c
+++ b/sound/hda/codecs/realtek/alc662.c
@@ -325,6 +325,7 @@ enum {
ALC897_FIXUP_UNIS_H3C_X500S,
ALC897_FIXUP_HEADSET_MIC_PIN3,
ALC662_FIXUP_CSL_GPIO,
+ ALC897_FIXUP_BEELINK_SER6_AMP,
};
static const struct hda_fixup alc662_fixups[] = {
@@ -782,6 +783,10 @@ static const struct hda_fixup alc662_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc662_fixup_csl_amp,
},
+ [ALC897_FIXUP_BEELINK_SER6_AMP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio4,
+ },
};
static const struct hda_quirk alc662_fixup_tbl[] = {
@@ -853,6 +858,7 @@ static const struct hda_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
SND_PCI_QUIRK(0x1e63, 0x6d9a, "F+ FLAPTOP r", ALC897_FIXUP_HP_HSMIC_VERB),
+ SND_PCI_QUIRK(0x1f66, 0x0202, "Beelink SER6 Max 6900", ALC897_FIXUP_BEELINK_SER6_AMP),
#if 0
/* Below is a quirk table taken from the old code.
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
--- a/sound/hda/codecs/side-codecs/Kconfig
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -13,6 +13,24 @@ config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
Documentation/dev-tools/kunit/.
If in doubt, say "N".
+config SND_HDA_SCODEC_AW88399
+ tristate
+ select SND_HDA_GENERIC
+
+config SND_HDA_SCODEC_AW88399_I2C
+ tristate "Build AW88399 HD-audio side codec support for I2C Bus"
+ depends on I2C
+ depends on ACPI
+ depends on SND_SOC
+ select SND_HDA_SCODEC_AW88399
+ select SND_SOC_AW88399_LIB
+ help
+ Say Y or M here to include AW88399 I2C HD-audio side codec support
+ in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+ depends on SND_HDA=y && SND_HDA_SCODEC_AW88399_I2C=m
+
config SND_HDA_SCODEC_CS35L41
tristate
select SND_HDA_GENERIC
diff --git a/sound/hda/codecs/side-codecs/Makefile b/sound/hda/codecs/side-codecs/Makefile
--- a/sound/hda/codecs/side-codecs/Makefile
+++ b/sound/hda/codecs/side-codecs/Makefile
@@ -3,6 +3,8 @@ subdir-ccflags-y += -I$(src)/../../common
snd-hda-cirrus-scodec-y := cirrus_scodec.o
snd-hda-cirrus-scodec-test-y := cirrus_scodec_test.o
+snd-hda-scodec-aw88399-y := aw88399_hda.o
+snd-hda-scodec-aw88399-i2c-y := aw88399_hda_i2c.o
snd-hda-scodec-cs35l41-y := cs35l41_hda.o cs35l41_hda_property.o
snd-hda-scodec-cs35l41-i2c-y := cs35l41_hda_i2c.o
snd-hda-scodec-cs35l41-spi-y := cs35l41_hda_spi.o
@@ -16,6 +18,8 @@ snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o
obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o
+obj-$(CONFIG_SND_HDA_SCODEC_AW88399) += snd-hda-scodec-aw88399.o
+obj-$(CONFIG_SND_HDA_SCODEC_AW88399_I2C) += snd-hda-scodec-aw88399-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.c b/sound/hda/codecs/side-codecs/aw88399_hda.c
new file mode 100644
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// AW88399 HDA side codec driver
+//
+// Based on cs35l41_hda.c and aw88399.c
+//
+
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <sound/hda_codec.h>
+#include "../generic.h"
+#include "hda_component.h"
+#include "aw88399_hda.h"
+
+#define AW88399_HDA_I2C_BASE_ADDR 0x34
+
+static void aw88399_hda_playback_hook(struct device *dev, int action)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ struct aw88399 *core = aw88399->core;
+ int ret = 0;
+
+ dev_dbg(aw88399->dev, "Playback action: %d\n", action);
+
+ switch (action) {
+ case HDA_GEN_PCM_ACT_OPEN:
+ pm_runtime_get_sync(dev);
+ aw88399->playing = true;
+ break;
+ case HDA_GEN_PCM_ACT_PREPARE:
+ if (core)
+ aw88399_start(core, AW88399_SYNC_START);
+ break;
+ case HDA_GEN_PCM_ACT_CLEANUP:
+ if (aw88399->aw_dev)
+ ret = aw88399_stop(aw88399->aw_dev);
+ if (ret)
+ dev_err(aw88399->dev, "Failed to stop amplifier: %d\n", ret);
+ break;
+ case HDA_GEN_PCM_ACT_CLOSE:
+ if (aw88399->aw_dev)
+ aw88399_stop(aw88399->aw_dev);
+ aw88399->playing = false;
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ break;
+ default:
+ dev_warn(aw88399->dev, "Unsupported action: %d\n", action);
+ break;
+ }
+}
+
+static int aw88399_hda_bind(struct device *dev, struct device *master, void *master_data)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+
+ comp = hda_component_from_index(parent, aw88399->index);
+ if (!comp)
+ return -EINVAL;
+
+ if (comp->dev)
+ return -EBUSY;
+
+ comp->dev = dev;
+
+ strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+
+ comp->playback_hook = aw88399_hda_playback_hook;
+
+ dev_info(aw88399->dev,
+ "AW88399 Bound - SSID: %s, channel: %d\n",
+ aw88399->acpi_subsystem_id, aw88399->channel);
+
+ return 0;
+}
+
+static void aw88399_hda_unbind(struct device *dev, struct device *master, void *master_data)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+
+ comp = hda_component_from_index(parent, aw88399->index);
+ if (comp && (comp->dev == dev))
+ memset(comp, 0, sizeof(*comp));
+
+ dev_dbg(aw88399->dev, "Unbound from HDA codec\n");
+}
+
+static const struct component_ops aw88399_hda_comp_ops = {
+ .bind = aw88399_hda_bind,
+ .unbind = aw88399_hda_unbind,
+};
+
+static int aw88399_hda_index_from_i2c(struct aw88399_hda *aw88399)
+{
+ return to_i2c_client(aw88399->dev)->addr - AW88399_HDA_I2C_BASE_ADDR;
+}
+
+static int aw88399_hda_init(struct aw88399_hda *aw88399)
+{
+ struct device *dev = aw88399->dev;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct aw88399 *core;
+ int ret;
+
+ core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return -ENOMEM;
+
+ mutex_init(&core->lock);
+ core->reset_gpio = aw88399->reset_gpio;
+ core->regmap = aw88399->regmap;
+ core->bsts_unreliable = aw88399->bsts_unreliable;
+
+ aw88399_hw_reset(core);
+
+ ret = aw88399_init(core, i2c, aw88399->regmap);
+ if (ret)
+ return ret;
+
+ /* Set channel BEFORE loading firmware so ACF parser sees correct value */
+ if (core->aw_pa)
+ aw88399_dev_set_channel(core, aw88399->channel);
+
+ ret = aw88399_request_firmware_file(core);
+ if (ret)
+ return ret;
+
+ aw88399->core = core;
+ aw88399->aw_dev = core->aw_pa;
+
+ return 0;
+}
+
+static int aw88399_swap_channels(struct aw88399_hda *aw88399)
+{
+ /*
+ * Certain Lenovo Legion laptops have their
+ * I2C wiring reversed: 0x34 is physically the right speaker,
+ * 0x35 is the left. Swap channels to correct L/R assignment.
+ * This is a model-specific hardware wiring issue, not a driver bug.
+ */
+ aw88399->channel = 1 - aw88399->channel;
+ dev_dbg(aw88399->dev,
+ "Channel swap applied: index %d -> channel %d\n",
+ aw88399->index, aw88399->channel);
+ return 0;
+}
+
+static int aw88399_skip_bsts_check(struct aw88399_hda *aw88399)
+{
+ /*
+ * BSTS (boost-finished) status bit does not reliably report on
+ * some hardware. On certain Lenovo Legion laptops, both amps
+ * report BSTS=0 (boost not finished) during normal playback
+ * despite clean audio output. Skip BSTS in the startup status
+ * check to avoid false init failures.
+ */
+ aw88399->bsts_unreliable = true;
+ dev_dbg(aw88399->dev, "BSTS status check disabled\n");
+ return 0;
+}
+
+static int aw88399_apply_legion_quirks(struct aw88399_hda *aw88399)
+{
+ aw88399_swap_channels(aw88399);
+ aw88399_skip_bsts_check(aw88399);
+ return 0;
+}
+
+struct aw88399_prop_model {
+ const char *ssid;
+ int (*apply_prop)(struct aw88399_hda *aw88399);
+};
+
+static const struct aw88399_prop_model aw88399_prop_model_table[] = {
+ { "17AA3906", aw88399_apply_legion_quirks },
+ { "17AA3907", aw88399_apply_legion_quirks },
+ { "17AA3927", aw88399_apply_legion_quirks },
+ { "17AA3928", aw88399_apply_legion_quirks },
+ { "17AA3936", aw88399_apply_legion_quirks },
+ { "17AA3937", aw88399_apply_legion_quirks },
+ { "17AA3938", aw88399_apply_legion_quirks },
+ { "17AA3939", aw88399_apply_legion_quirks },
+ { }
+};
+
+static int aw88399_hda_acpi_probe(struct aw88399_hda *aw88399)
+{
+ struct acpi_device *adev;
+ const char *sub;
+ const struct aw88399_prop_model *model;
+
+ aw88399->index = aw88399_hda_index_from_i2c(aw88399);
+ aw88399->channel = aw88399->index;
+ aw88399->acpi_subsystem_id = NULL;
+
+ adev = acpi_dev_get_first_match_dev("AWDZ8399", NULL, -1);
+ if (!adev) {
+ dev_err(aw88399->dev, "Failed to find an ACPI device for AWDZ8399\n");
+ return -ENODEV;
+ }
+
+ struct device *physdev __free(put_device) =
+ get_device(acpi_get_first_physical_node(adev));
+ acpi_dev_put(adev);
+ if (!physdev)
+ return -ENODEV;
+
+ sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
+ if (IS_ERR_OR_NULL(sub))
+ return 0;
+
+ aw88399->acpi_subsystem_id = devm_kstrdup(aw88399->dev, sub, GFP_KERNEL);
+ kfree(sub);
+ if (!aw88399->acpi_subsystem_id)
+ return -ENOMEM;
+
+ for (model = aw88399_prop_model_table; model->ssid; model++) {
+ if (!strcasecmp(model->ssid, aw88399->acpi_subsystem_id)) {
+ dev_info(aw88399->dev,
+ "Applying properties for SSID %s\n",
+ aw88399->acpi_subsystem_id);
+ return model->apply_prop(aw88399);
+ }
+ }
+
+ return 0;
+}
+
+int aw88399_hda_probe(struct device *dev, struct regmap *regmap)
+{
+ struct aw88399_hda *aw88399;
+ int ret;
+
+ aw88399 = devm_kzalloc(dev, sizeof(*aw88399), GFP_KERNEL);
+ if (!aw88399)
+ return -ENOMEM;
+
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to obtain regmap\n");
+
+ aw88399->dev = dev;
+ aw88399->regmap = regmap;
+ dev_set_drvdata(dev, aw88399);
+
+ aw88399->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(aw88399->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(aw88399->reset_gpio),
+ "Failed to get reset GPIO\n");
+
+ ret = aw88399_hda_acpi_probe(aw88399);
+ if (ret)
+ return dev_err_probe(dev, ret, "ACPI probe failed\n");
+
+ ret = aw88399_hda_init(aw88399);
+ if (ret)
+ return dev_err_probe(dev, ret, "Chip initialization failed\n");
+
+ /* Enable runtime PM */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = component_add(dev, &aw88399_hda_comp_ops);
+ if (ret) {
+ pm_runtime_disable(dev);
+ return dev_err_probe(dev, ret, "Failed to register component\n");
+ }
+
+ dev_info(dev, "AW88399 HDA side codec registered successfully\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_probe, "SND_HDA_SCODEC_AW88399");
+
+void aw88399_hda_remove(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+ pm_runtime_disable(dev);
+
+ if (aw88399->aw_dev)
+ aw88399_stop(aw88399->aw_dev);
+
+ component_del(dev, &aw88399_hda_comp_ops);
+
+ dev_dbg(aw88399->dev, "AW88399 HDA side codec removed\n");
+}
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_remove, "SND_HDA_SCODEC_AW88399");
+
+static int aw88399_hda_runtime_suspend(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+ dev_dbg(aw88399->dev, "Runtime suspend\n");
+
+ if (aw88399->aw_dev && aw88399->playing)
+ aw88399_stop(aw88399->aw_dev);
+
+ return 0;
+}
+
+static int aw88399_hda_runtime_resume(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+ dev_dbg(aw88399->dev, "Runtime resume\n");
+
+ if (aw88399->core && aw88399->aw_dev && aw88399->playing)
+ aw88399_start(aw88399->core, AW88399_SYNC_START);
+
+ return 0;
+}
+
+static int aw88399_hda_system_suspend(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ int ret;
+
+ dev_dbg(aw88399->dev, "System suspend\n");
+
+ if (aw88399->aw_dev && aw88399->playing)
+ aw88399_stop(aw88399->aw_dev);
+
+ if (aw88399->core)
+ aw88399->core->fw_needs_reload = true;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ dev_err(aw88399->dev, "Runtime force suspend failed: %d\n", ret);
+
+ return ret;
+}
+
+static int aw88399_hda_system_resume(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ int ret;
+
+ dev_dbg(aw88399->dev, "System resume\n");
+
+ if (aw88399->aw_dev)
+ aw88399_hw_reset(aw88399->core);
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ dev_err(aw88399->dev, "Runtime force resume failed: %d\n", ret);
+
+ return ret;
+}
+
+const struct dev_pm_ops aw88399_hda_pm_ops = {
+ RUNTIME_PM_OPS(aw88399_hda_runtime_suspend, aw88399_hda_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(aw88399_hda_system_suspend, aw88399_hda_system_resume)
+};
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_pm_ops, "SND_HDA_SCODEC_AW88399");
+
+MODULE_DESCRIPTION("AW88399 HDA driver");
+MODULE_AUTHOR("Yakov Till <yakov.till@gmail.com>");
+MODULE_AUTHOR("Marco Giunta <marco_giunta@outlook.it>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("aw88399_acf.bin");
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.h b/sound/hda/codecs/side-codecs/aw88399_hda.h
new file mode 100644
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * AW88399 HDA side codec driver
+ */
+
+#ifndef __AW88399_HDA_H__
+#define __AW88399_HDA_H__
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <sound/aw88399.h>
+
+struct aw88399;
+struct aw_device;
+
+struct aw88399_hda {
+ struct device *dev;
+ struct regmap *regmap;
+ struct gpio_desc *reset_gpio;
+ struct aw_device *aw_dev;
+ struct aw88399 *core;
+ bool bsts_unreliable;
+
+ const char *acpi_subsystem_id;
+ int index;
+ int channel;
+
+ bool playing;
+};
+
+int aw88399_hda_probe(struct device *dev, struct regmap *regmap);
+void aw88399_hda_remove(struct device *dev);
+
+extern const struct dev_pm_ops aw88399_hda_pm_ops;
+
+#endif /* __AW88399_HDA_H__ */
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c b/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c
new file mode 100644
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// AW88399 HDA I2C driver
+//
+// Based on cs35l41_hda_i2c.c
+//
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "aw88399_hda.h"
+
+static int aw88399_hda_i2c_probe(struct i2c_client *clt)
+{
+ if (!strstr(dev_name(&clt->dev), "AWDZ8399"))
+ return -ENODEV;
+
+ return aw88399_hda_probe(&clt->dev,
+ devm_regmap_init_i2c(clt, &aw88399_remap_config));
+}
+
+static void aw88399_hda_i2c_remove(struct i2c_client *clt)
+{
+ aw88399_hda_remove(&clt->dev);
+}
+
+static const struct i2c_device_id aw88399_hda_i2c_id[] = {
+ { .name = "aw88399-hda" },
+ { }
+};
+
+static const struct acpi_device_id aw88399_acpi_hda_match[] = {
+ { "AWDZ8399", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, aw88399_acpi_hda_match);
+
+static struct i2c_driver aw88399_hda_i2c_driver = {
+ .driver = {
+ .name = "aw88399-hda",
+ .acpi_match_table = aw88399_acpi_hda_match,
+ .pm = &aw88399_hda_pm_ops,
+ },
+ .probe = aw88399_hda_i2c_probe,
+ .remove = aw88399_hda_i2c_remove,
+ .id_table = aw88399_hda_i2c_id,
+};
+module_i2c_driver(aw88399_hda_i2c_driver);
+
+MODULE_DESCRIPTION("HDA AW88399 I2C driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_AW88399");
+MODULE_AUTHOR("Yakov Till <yakov.till@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
--- a/sound/hda/codecs/side-codecs/cs35l41_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c
@@ -170,6 +170,7 @@ static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41,
char *s, c;
int ret = 0;
+ *firmware = NULL;
if (spkid > -1 && ssid && amp_name)
*filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART,
dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
@@ -528,8 +529,8 @@ static int cs35l41_read_tuning_params(struct cs35l41_hda *cs35l41, const struct
static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_filename)
{
- const struct firmware *tuning_param_file = NULL;
- char *tuning_param_filename = NULL;
+ const struct firmware *tuning_param_file __free(firmware) = NULL;
+ char *tuning_param_filename __free(kfree) = NULL;
int ret;
ret = cs35l41_request_tuning_param_file(cs35l41, tuning_filename, &tuning_param_file,
@@ -548,19 +549,16 @@ static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_
cs35l41_set_default_tuning_params(cs35l41);
}
- release_firmware(tuning_param_file);
- kfree(tuning_param_filename);
-
return ret;
}
static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
{
- const struct firmware *coeff_firmware = NULL;
- const struct firmware *wmfw_firmware = NULL;
+ const struct firmware *coeff_firmware __free(firmware) = NULL;
+ const struct firmware *wmfw_firmware __free(firmware) = NULL;
struct cs_dsp *dsp = &cs35l41->cs_dsp;
- char *coeff_filename = NULL;
- char *wmfw_filename = NULL;
+ char *coeff_filename __free(kfree) = NULL;
+ char *wmfw_filename __free(kfree) = NULL;
int ret;
if (!cs35l41->halo_initialized) {
@@ -592,20 +590,13 @@ static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename,
cs35l41_hda_fw_ids[cs35l41->firmware_type]);
- if (ret)
- goto err;
+ if (ret) {
+ cs35l41_set_default_tuning_params(cs35l41);
+ return ret;
+ }
cs35l41_hda_apply_calibration(cs35l41);
-
-err:
- if (ret)
- cs35l41_set_default_tuning_params(cs35l41);
- release_firmware(wmfw_firmware);
- release_firmware(coeff_firmware);
- kfree(wmfw_filename);
- kfree(coeff_filename);
-
- return ret;
+ return 0;
}
static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41)
@@ -1924,7 +1915,6 @@ int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev,
static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
{
struct acpi_device *adev;
- struct device *physdev;
struct spi_device *spi;
const char *sub;
int ret;
@@ -1936,7 +1926,8 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
}
cs35l41->dacpi = adev;
- physdev = get_device(acpi_get_first_physical_node(adev));
+ struct device *physdev __free(put_device) =
+ get_device(acpi_get_first_physical_node(adev));
if (!physdev) {
acpi_dev_put(adev);
return -ENODEV;
@@ -1954,13 +1945,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
}
ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id);
- if (ret) {
- put_device(physdev);
+ if (ret)
return ret;
- }
out:
- put_device(physdev);
-
cs35l41->bypass_fw = false;
if (cs35l41->control_bus == SPI) {
spi = to_spi_device(cs35l41->dev);
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c
--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c
@@ -527,18 +527,6 @@ static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
base_name, NULL, NULL, "bin");
}
-static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
- char *wmfw_filename,
- const struct firmware *coeff_firmware,
- char *coeff_filename)
-{
- release_firmware(wmfw_firmware);
- kfree(wmfw_filename);
-
- release_firmware(coeff_firmware);
- kfree(coeff_filename);
-}
-
static int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
{
int ret;
@@ -561,10 +549,10 @@ static int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
{
- const struct firmware *coeff_firmware = NULL;
- const struct firmware *wmfw_firmware = NULL;
- char *coeff_filename = NULL;
- char *wmfw_filename = NULL;
+ const struct firmware *coeff_firmware __free(firmware) = NULL;
+ const struct firmware *wmfw_firmware __free(firmware) = NULL;
+ char *coeff_filename __free(kfree) = NULL;
+ char *wmfw_filename __free(kfree) = NULL;
unsigned int preloaded_fw_ver;
bool firmware_missing;
int ret;
@@ -606,14 +594,14 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
if (firmware_missing) {
if (!wmfw_firmware) {
dev_err(cs35l56->base.dev, ".%s file required but not found\n", "wmfw");
- goto err_fw_release;
+ return;
} else if (!coeff_firmware) {
dev_err(cs35l56->base.dev, ".%s file required but not found\n", "bin");
- goto err_fw_release;
+ return;
}
}
- mutex_lock(&cs35l56->base.irq_lock);
+ guard(mutex)(&cs35l56->base.irq_lock);
/*
* If the firmware hasn't been patched it must be shutdown before
@@ -624,14 +612,14 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
ret = cs35l56_firmware_shutdown(&cs35l56->base);
if (ret)
- goto err;
+ return;
}
ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,
coeff_firmware, coeff_filename, "misc");
if (ret) {
dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);
- goto err;
+ return;
}
if (wmfw_filename)
@@ -679,11 +667,6 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
err_powered_up:
if (!cs35l56->base.fw_patched)
cs_dsp_power_down(&cs35l56->cs_dsp);
-err:
- mutex_unlock(&cs35l56->base.irq_lock);
-err_fw_release:
- cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,
- coeff_firmware, coeff_filename);
}
static void cs35l56_hda_dsp_work(struct work_struct *work)
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
--- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@@ -88,7 +88,6 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
{
struct gpio_desc *speaker_id;
struct acpi_device *adev;
- struct device *physdev;
LIST_HEAD(resources);
const char *sub;
uint32_t subid;
@@ -101,7 +100,8 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
return -ENODEV;
}
- physdev = get_device(acpi_get_first_physical_node(adev));
+ struct device *physdev __free(put_device) =
+ get_device(acpi_get_first_physical_node(adev));
ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
if (ret < 0) {
dev_err(p->dev, "Failed to get ACPI resource.\n");
@@ -151,14 +151,12 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
end_2563:
acpi_dev_free_resource_list(&resources);
strscpy(p->dev_name, hid, sizeof(p->dev_name));
- put_device(physdev);
acpi_dev_put(adev);
return 0;
err:
dev_err(p->dev, "read acpi error, ret: %d\n", ret);
- put_device(physdev);
acpi_dev_put(adev);
return ret;
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -328,7 +328,6 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
{
struct tasdevice_priv *p = tas_hda->priv;
struct acpi_device *adev;
- struct device *physdev;
u32 values[HDA_MAX_COMPONENTS];
const char *property;
size_t nval;
@@ -341,7 +340,9 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
}
strscpy(p->dev_name, hid, sizeof(p->dev_name));
- physdev = get_device(acpi_get_first_physical_node(adev));
+
+ struct device *physdev __free(put_device) =
+ get_device(acpi_get_first_physical_node(adev));
acpi_dev_put(adev);
if (!physdev)
return -ENODEV;
@@ -381,13 +382,11 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
goto err;
}
}
- put_device(physdev);
return 0;
+
err:
dev_err(p->dev, "read acpi error, ret: %d\n", ret);
- put_device(physdev);
-
return ret;
}
diff --git a/sound/hda/common/auto_parser.c b/sound/hda/common/auto_parser.c
--- a/sound/hda/common/auto_parser.c
+++ b/sound/hda/common/auto_parser.c
@@ -601,9 +601,9 @@ static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
return -1;
}
-/* get a unique suffix or an index number */
+/* get a unique suffix */
static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
- int num_pins, int *indexp)
+ int num_pins)
{
static const char * const channel_sfx[] = {
" Front", " Surround", " CLFE", " Side"
@@ -615,11 +615,8 @@ static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
return NULL;
if (num_pins == 1)
return "";
- if (num_pins > ARRAY_SIZE(channel_sfx)) {
- if (indexp)
- *indexp = i;
+ if (num_pins > ARRAY_SIZE(channel_sfx))
return "";
- }
return channel_sfx[i];
}
@@ -638,27 +635,9 @@ static const char *check_output_pfx(struct hda_codec *codec, hda_nid_t nid)
return "";
}
-static int get_hp_label_index(struct hda_codec *codec, hda_nid_t nid,
- const hda_nid_t *pins, int num_pins)
-{
- int i, j, idx = 0;
-
- const char *pfx = check_output_pfx(codec, nid);
-
- i = find_idx_in_nid_list(nid, pins, num_pins);
- if (i < 0)
- return -1;
- for (j = 0; j < i; j++)
- if (pfx == check_output_pfx(codec, pins[j]))
- idx++;
-
- return idx;
-}
-
static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
const struct auto_pin_cfg *cfg,
- const char *name, char *label, int maxlen,
- int *indexp)
+ const char *name, char *label, int maxlen)
{
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int attr = snd_hda_get_input_pin_attr(def_conf);
@@ -671,19 +650,11 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
if (cfg) {
/* try to give a unique suffix if needed */
- sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
- indexp);
+ sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs);
+ if (!sfx)
+ sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs);
if (!sfx)
- sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
- indexp);
- if (!sfx) {
- /* don't add channel suffix for Headphone controls */
- int idx = get_hp_label_index(codec, nid, cfg->hp_pins,
- cfg->hp_outs);
- if (idx >= 0 && indexp)
- *indexp = idx;
sfx = "";
- }
}
snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
return 1;
@@ -699,7 +670,6 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
* @cfg: the parsed pin configuration
* @label: the string buffer to store
* @maxlen: the max length of string buffer (including termination)
- * @indexp: the pointer to return the index number (for multiple ctls)
*
* Get a label for the given pin. This function works for both input and
* output pins. When @cfg is given as non-NULL, the function tries to get
@@ -708,47 +678,33 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
* This function tries to give a unique label string for the pin as much as
* possible. For example, when the multiple line-outs are present, it adds
* the channel suffix like "Front", "Surround", etc (only when @cfg is given).
- * If no unique name with a suffix is available and @indexp is non-NULL, the
- * index number is stored in the pointer.
*/
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
const struct auto_pin_cfg *cfg,
- char *label, int maxlen, int *indexp)
+ char *label, int maxlen)
{
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
const char *name = NULL;
int i;
bool hdmi;
- if (indexp)
- *indexp = 0;
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
return 0;
switch (get_defcfg_device(def_conf)) {
case AC_JACK_LINE_OUT:
return fill_audio_out_name(codec, nid, cfg, "Line Out",
- label, maxlen, indexp);
+ label, maxlen);
case AC_JACK_SPEAKER:
return fill_audio_out_name(codec, nid, cfg, "Speaker",
- label, maxlen, indexp);
+ label, maxlen);
case AC_JACK_HP_OUT:
return fill_audio_out_name(codec, nid, cfg, "Headphone",
- label, maxlen, indexp);
+ label, maxlen);
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
hdmi = is_hdmi_cfg(def_conf);
name = hdmi ? "HDMI" : "SPDIF";
- if (cfg && indexp)
- for (i = 0; i < cfg->dig_outs; i++) {
- hda_nid_t pin = cfg->dig_out_pins[i];
- unsigned int c;
- if (pin == nid)
- break;
- c = snd_hda_codec_get_pincfg(codec, pin);
- if (hdmi == is_hdmi_cfg(c))
- (*indexp)++;
- }
break;
default:
if (cfg) {
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -39,6 +39,12 @@ static int call_exec_verb(struct hda_bus *bus, struct hda_codec *codec,
int err;
CLASS(snd_hda_power_pm, pm)(codec);
+ if (pm.err < 0 && !bus->core.chip_init) {
+ codec_warn(codec,
+ "Failed to send cmd 0x%x ret=[%d], hda control stopped\n",
+ cmd, pm.err);
+ return pm.err;
+ }
guard(mutex)(&bus->core.cmd_mutex);
if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
bus->no_response_fallback = 1;
@@ -2969,8 +2975,11 @@ static void hda_codec_pm_complete(struct device *dev)
dev->power.power_state = PMSG_RESUME;
if (pm_runtime_suspended(dev) && (codec->jackpoll_interval ||
- hda_codec_need_resume(codec) || codec->forced_resume))
+ hda_codec_need_resume(codec) || codec->forced_resume ||
+ codec->acomp_requested_resume)) {
+ codec->acomp_requested_resume = 0;
pm_request_resume(dev);
+ }
}
static int hda_codec_pm_suspend(struct device *dev)
@@ -3372,7 +3381,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
for (; knew->name; knew++) {
struct snd_kcontrol *kctl;
int addr = 0, idx = 0;
- if (knew->iface == (__force snd_ctl_elem_iface_t)-1)
+ if (knew->iface == -1)
continue; /* skip this codec private value */
for (;;) {
kctl = snd_ctl_new1(knew, codec);
diff --git a/sound/hda/common/hda_auto_parser.h b/sound/hda/common/hda_auto_parser.h
--- a/sound/hda/common/hda_auto_parser.h
+++ b/sound/hda/common/hda_auto_parser.h
@@ -46,7 +46,7 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
int input);
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
const struct auto_pin_cfg *cfg,
- char *label, int maxlen, int *indexp);
+ char *label, int maxlen);
enum {
INPUT_PIN_ATTR_UNUSED, /* pin not connected */
diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h
--- a/sound/hda/common/hda_local.h
+++ b/sound/hda/common/hda_local.h
@@ -723,4 +723,11 @@ void snd_hda_codec_display_power(struct hda_codec *codec, bool enable);
#define codec_dbg(codec, fmt, args...) \
dev_dbg(hda_codec_dev(codec), fmt, ##args)
+/* append a suffix string safely; equivalent with strlcat() */
+static inline void hda_append_suffix(char *str, const char *suffix, size_t size)
+{
+ size_t len = strnlen(str, size);
+ strscpy(str + len, suffix, size - len);
+}
+
#endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/hda/common/jack.c b/sound/hda/common/jack.c
--- a/sound/hda/common/jack.c
+++ b/sound/hda/common/jack.c
@@ -612,10 +612,10 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
if (base_name)
strscpy(name, base_name, sizeof(name));
else
- snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL);
+ snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name));
if (phantom_jack)
/* Example final name: "Internal Mic Phantom Jack" */
- strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
+ hda_append_suffix(name, " Phantom", sizeof(name));
err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL);
if (err < 0)
return err;
diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
--- a/sound/hda/controllers/intel.c
+++ b/sound/hda/controllers/intel.c
@@ -100,6 +100,8 @@ enum {
#define ATIHDMI_NUM_CAPTURE 0
#define ATIHDMI_NUM_PLAYBACK 8
+/* Hygon HD Audio controller */
+#define PCI_DEVICE_ID_HYGON_18H_M05H_HDA 0x14a9
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -241,6 +243,7 @@ enum {
AZX_DRIVER_ZHAOXIN,
AZX_DRIVER_ZHAOXINHDMI,
AZX_DRIVER_LOONGSON,
+ AZX_DRIVER_HYGON,
AZX_DRIVER_GENERIC,
AZX_NUM_DRIVERS, /* keep this as last entry */
};
@@ -360,6 +363,7 @@ static const char * const driver_short_names[] = {
[AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin",
[AZX_DRIVER_ZHAOXINHDMI] = "HDA Zhaoxin HDMI",
[AZX_DRIVER_LOONGSON] = "HDA Loongson",
+ [AZX_DRIVER_HYGON] = "HDA Hygon",
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
@@ -1926,6 +1930,10 @@ static int azx_first_init(struct azx *chip)
if (chip->driver_type == AZX_DRIVER_ZHAOXINHDMI)
bus->polling_mode = 1;
+ if (chip->driver_type == AZX_DRIVER_HYGON &&
+ chip->pci->device == PCI_DEVICE_ID_HYGON_18H_M05H_HDA)
+ bus->access_sdnctl_in_dword = 1;
+
bus->remap_addr = pcim_iomap_region(pci, 0, "ICH HD audio");
if (IS_ERR(bus->remap_addr))
return PTR_ERR(bus->remap_addr);
@@ -2189,6 +2197,15 @@ static int azx_probe(struct pci_dev *pci,
dev_warn(&pci->dev, "dmic_detect option is deprecated, pass snd-intel-dspcfg.dsp_driver=1 option instead\n");
}
+ /* A sanity check against wild device binding;
+ * here the range 0x200 is enough for the registers used at probe,
+ * but it doesn't mean covering all HD-audio registers
+ */
+ if (pci_resource_len(pci, 0) < 0x200) {
+ dev_err(&pci->dev, "Too small PCI BAR0\n");
+ return -EINVAL;
+ }
+
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0) {
@@ -2381,7 +2398,7 @@ static int azx_probe_continue(struct azx *chip)
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (patch[dev] && *patch[dev]) {
- const struct firmware *fw = NULL;
+ const struct firmware *fw __free(firmware) = NULL;
dev_info(&pci->dev, "Applying patch firmware '%s'\n",
patch[dev]);
@@ -2390,7 +2407,6 @@ static int azx_probe_continue(struct azx *chip)
"Cannot load firmware, continue without patching\n");
} else {
err = snd_hda_load_patch(&chip->bus, fw->size, fw->data);
- release_firmware(fw);
if (err < 0)
goto out_free;
}
@@ -2838,6 +2854,11 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
{ PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI),
.driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
+ /* Hygon HDAudio */
+ { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_HDA),
+ .driver_data = AZX_DRIVER_HYGON | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_NO_MSI },
+ /* Lisuan HD-audio */
+ { PCI_DEVICE(0x4c54, 0x5010), .driver_data = AZX_DRIVER_GENERIC },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/hda/core/controller.c b/sound/hda/core/controller.c
--- a/sound/hda/core/controller.c
+++ b/sound/hda/core/controller.c
@@ -511,7 +511,10 @@ void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus)
{
unsigned long timeout;
- snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
+ else
+ snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
timeout = jiffies + msecs_to_jiffies(100);
while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout))
@@ -576,7 +579,10 @@ static void azx_int_disable(struct hdac_bus *bus)
/* disable interrupts in stream descriptor */
list_for_each_entry(azx_dev, &bus->stream_list, list)
- snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_INT_MASK, 0);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0);
/* disable SIE for all streams & disable controller CIE and GIE */
snd_hdac_chip_writel(bus, INTCTL, 0);
@@ -682,6 +688,11 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
handled |= 1 << azx_dev->index;
+ if (sd_status & (SD_INT_FIFO_ERR | SD_INT_DESC_ERR)) {
+ dev_warn_ratelimited(bus->dev,
+ "stream %u dma error: 0x%02x\n",
+ azx_dev->index, sd_status);
+ }
if ((!azx_dev->substream && !azx_dev->cstream) ||
!azx_dev->running || !(sd_status & SD_INT_COMPLETE))
continue;
@@ -713,7 +724,7 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
BDL_SIZE, &s->bdl);
num_streams++;
if (err < 0)
- return -ENOMEM;
+ goto error_bdl;
}
if (WARN_ON(!num_streams))
@@ -722,12 +733,24 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
err = snd_dma_alloc_pages(dma_type, bus->dev,
num_streams * 8, &bus->posbuf);
if (err < 0)
- return -ENOMEM;
+ goto error_bdl;
list_for_each_entry(s, &bus->stream_list, list)
s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8);
/* single page (at least 4096 bytes) must suffice for both ringbuffes */
- return snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb);
+ err = snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb);
+ if (err < 0)
+ goto error_posbuf;
+ return 0;
+
+error_posbuf:
+ snd_dma_free_pages(&bus->posbuf);
+error_bdl:
+ list_for_each_entry(s, &bus->stream_list, list) {
+ if (s->bdl.area)
+ snd_dma_free_pages(&s->bdl);
+ }
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages);
diff --git a/sound/hda/core/device.c b/sound/hda/core/device.c
--- a/sound/hda/core/device.c
+++ b/sound/hda/core/device.c
@@ -664,6 +664,7 @@ static const struct hda_vendor_id hda_vendor_ids[] = {
{ 0x1af4, "QEMU" },
{ 0x1fa8, "Senarytech" },
{ 0x434d, "C-Media" },
+ { 0x4c54, "Lisuan" },
{ 0x8086, "Intel" },
{ 0x8384, "SigmaTel" },
{} /* terminator */
@@ -766,7 +767,7 @@ unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subfor
params_set_format(&params, snd_hdac_format_normalize(format));
snd_mask_set(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT),
- (__force unsigned int)subformat);
+ subformat);
bits = snd_pcm_hw_params_bits(&params);
if (maxbits)
diff --git a/sound/hda/core/hda_bus_type.c b/sound/hda/core/hda_bus_type.c
--- a/sound/hda/core/hda_bus_type.c
+++ b/sound/hda/core/hda_bus_type.c
@@ -39,10 +39,7 @@ EXPORT_SYMBOL_GPL(hdac_get_device_id);
static int hdac_codec_match(struct hdac_device *dev, const struct hdac_driver *drv)
{
- if (hdac_get_device_id(dev, drv))
- return 1;
- else
- return 0;
+ return !!hdac_get_device_id(dev, drv);
}
static int hda_bus_match(struct device *dev, const struct device_driver *drv)
@@ -59,9 +56,7 @@ static int hda_bus_match(struct device *dev, const struct device_driver *drv)
*/
if (hdrv->match)
return hdrv->match(hdev, hdrv);
- else
- return hdac_codec_match(hdev, hdrv);
- return 1;
+ return hdac_codec_match(hdev, hdrv);
}
static int hda_uevent(const struct device *dev, struct kobj_uevent_env *env)
diff --git a/sound/hda/core/stream.c b/sound/hda/core/stream.c
--- a/sound/hda/core/stream.c
+++ b/sound/hda/core/stream.c
@@ -146,8 +146,12 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev)
stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream);
else
stripe_ctl = 0;
- snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
- stripe_ctl);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
+ stripe_ctl);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
+ stripe_ctl);
}
/* set DMA start and interrupt mask */
if (bus->access_sdnctl_in_dword)
@@ -166,11 +170,22 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_start);
*/
static void snd_hdac_stream_clear(struct hdac_stream *azx_dev)
{
- snd_hdac_stream_updateb(azx_dev, SD_CTL,
- SD_CTL_DMA_START | SD_INT_MASK, 0);
- snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
- if (azx_dev->stripe)
- snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
+ struct hdac_bus *bus = azx_dev->bus;
+
+ if (bus->access_sdnctl_in_dword) {
+ snd_hdac_stream_updatel(azx_dev, SD_CTL,
+ SD_CTL_DMA_START | SD_INT_MASK, 0);
+ snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+ if (azx_dev->stripe)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
+ } else {
+ snd_hdac_stream_updateb(azx_dev, SD_CTL,
+ SD_CTL_DMA_START | SD_INT_MASK, 0);
+ snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+ if (azx_dev->stripe)
+ snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
+ }
+
azx_dev->running = false;
}
@@ -225,12 +240,16 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev)
{
unsigned char val;
int dma_run_state;
+ struct hdac_bus *bus = azx_dev->bus;
snd_hdac_stream_clear(azx_dev);
dma_run_state = snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START;
- snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET);
/* wait for hardware to report that the stream entered reset */
snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, (val & SD_CTL_STREAM_RESET), 3, 300);
@@ -238,7 +257,10 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev)
if (azx_dev->bus->dma_stop_delay && dma_run_state)
udelay(azx_dev->bus->dma_stop_delay);
- snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0);
/* wait for hardware to report that the stream is out of reset */
snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, !(val & SD_CTL_STREAM_RESET), 3, 300);
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -367,7 +367,8 @@ static int snd_msnd_init_sma(struct snd_msnd *chip)
static int upload_dsp_code(struct snd_card *card)
{
struct snd_msnd *chip = card->private_data;
- const struct firmware *init_fw = NULL, *perm_fw = NULL;
+ const struct firmware *init_fw __free(firmware) = NULL;
+ const struct firmware *perm_fw __free(firmware) = NULL;
int err;
outb(HPBLKSEL_0, chip->io + HP_BLKS);
@@ -375,28 +376,21 @@ static int upload_dsp_code(struct snd_card *card)
err = request_firmware(&init_fw, INITCODEFILE, card->dev);
if (err < 0) {
dev_err(card->dev, LOGNAME ": Error loading " INITCODEFILE);
- goto cleanup1;
+ return err;
}
err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
if (err < 0) {
dev_err(card->dev, LOGNAME ": Error loading " PERMCODEFILE);
- goto cleanup;
+ return err;
}
memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
dev_warn(card->dev, LOGNAME ": Error uploading to DSP\n");
- err = -ENODEV;
- goto cleanup;
+ return -ENODEV;
}
dev_info(card->dev, LOGNAME ": DSP firmware uploaded\n");
- err = 0;
-
-cleanup:
- release_firmware(perm_fw);
-cleanup1:
- release_firmware(init_fw);
- return err;
+ return 0;
}
#ifdef MSND_CLASSIC
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -526,7 +526,7 @@ static int upload_dma_data(struct soundscape *s, const unsigned char *data,
static int sscape_upload_bootblock(struct snd_card *card)
{
struct soundscape *sscape = get_card_soundscape(card);
- const struct firmware *init_fw = NULL;
+ const struct firmware *init_fw __free(firmware) = NULL;
int data = 0;
int ret;
@@ -537,8 +537,6 @@ static int sscape_upload_bootblock(struct snd_card *card)
}
ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
- release_firmware(init_fw);
-
guard(spinlock_irqsave)(&sscape->lock);
if (ret == 0)
data = host_read_ctrl_unsafe(sscape->io_base, 100);
@@ -562,7 +560,7 @@ static int sscape_upload_bootblock(struct snd_card *card)
static int sscape_upload_microcode(struct snd_card *card, int version)
{
struct soundscape *sscape = get_card_soundscape(card);
- const struct firmware *init_fw = NULL;
+ const struct firmware *init_fw __free(firmware) = NULL;
char name[14];
int err;
@@ -579,8 +577,6 @@ static int sscape_upload_microcode(struct snd_card *card, int version)
dev_info(card->dev, "sscape: MIDI firmware loaded %zu KBs\n",
init_fw->size >> 10);
- release_firmware(init_fw);
-
return err;
}
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -232,41 +232,32 @@ snd_wavefront_fx_start (snd_wavefront_t *dev)
{
unsigned int i;
int err;
- const struct firmware *firmware = NULL;
+ const struct firmware *firmware __free(firmware) = NULL;
if (dev->fx_initialized)
return 0;
err = request_firmware(&firmware, "yamaha/yss225_registers.bin",
dev->card->dev);
- if (err < 0) {
- err = -1;
- goto out;
- }
+ if (err < 0)
+ return -1;
for (i = 0; i + 1 < firmware->size; i += 2) {
if (firmware->data[i] >= 8 && firmware->data[i] < 16) {
outb(firmware->data[i + 1],
dev->base + firmware->data[i]);
} else if (firmware->data[i] == WAIT_IDLE) {
- if (!wavefront_fx_idle(dev)) {
- err = -1;
- goto out;
- }
+ if (!wavefront_fx_idle(dev))
+ return -1;
} else {
dev_err(dev->card->dev,
"invalid address in register data\n");
- err = -1;
- goto out;
+ return -1;
}
}
dev->fx_initialized = 1;
- err = 0;
-
-out:
- release_firmware(firmware);
- return err;
+ return 0;
}
MODULE_FIRMWARE("yamaha/yss225_registers.bin");
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -2053,7 +2053,7 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
const unsigned char *buf;
int len, err;
int section_cnt_downloaded = 0;
- const struct firmware *firmware;
+ const struct firmware *firmware __free(firmware) = NULL;
err = request_firmware(&firmware, path, dev->card->dev);
if (err < 0) {
@@ -2108,11 +2108,9 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
section_cnt_downloaded++;
}
- release_firmware(firmware);
return 0;
failure:
- release_firmware(firmware);
dev_err(dev->card->dev, "firmware download failed!!!\n");
return 1;
}
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -280,7 +280,7 @@ static void print_hwparams(struct snd_pcm_substream *substream,
snd_pcm_format_width(params_format(p)) / 8);
}
-#define INVALID_FORMAT (__force snd_pcm_format_t)(-1)
+#define INVALID_FORMAT -1
static const snd_pcm_format_t hpi_to_alsa_formats[] = {
INVALID_FORMAT, /* INVALID */
diff --git a/sound/pci/asihpi/hpidspcd.c b/sound/pci/asihpi/hpidspcd.c
--- a/sound/pci/asihpi/hpidspcd.c
+++ b/sound/pci/asihpi/hpidspcd.c
@@ -23,7 +23,7 @@ struct dsp_code_private {
short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
u32 *os_error_code)
{
- const struct firmware *firmware;
+ const struct firmware *firmware __free(firmware) = NULL;
struct pci_dev *dev = os_data;
struct code_header header;
char fw_name[20];
@@ -37,11 +37,11 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
if (err || !firmware) {
dev_err(&dev->dev, "%d, request_firmware failed for %s\n",
err, fw_name);
- goto error1;
+ goto error;
}
if (firmware->size < sizeof(header)) {
dev_err(&dev->dev, "Header size too small %s\n", fw_name);
- goto error2;
+ goto error;
}
memcpy(&header, firmware->data, sizeof(header));
@@ -51,7 +51,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
dev_err(&dev->dev,
"Invalid firmware header size %d != file %zd\n",
header.size, firmware->size);
- goto error2;
+ goto error;
}
if (HPI_VER_MAJOR(header.version) != HPI_VER_MAJOR(HPI_VER)) {
@@ -59,7 +59,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
dev_err(&dev->dev,
"Incompatible firmware version DSP image %X != Driver %X\n",
header.version, HPI_VER);
- goto error2;
+ goto error;
}
if (header.version != HPI_VER) {
@@ -72,19 +72,17 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
dsp_code->pvt = kmalloc_obj(*dsp_code->pvt);
if (!dsp_code->pvt) {
err_ret = HPI_ERROR_MEMORY_ALLOC;
- goto error2;
+ goto error;
}
dsp_code->pvt->dev = dev;
- dsp_code->pvt->firmware = firmware;
+ dsp_code->pvt->firmware = no_free_ptr(firmware);
dsp_code->header = header;
dsp_code->block_length = header.size / sizeof(u32);
dsp_code->word_count = sizeof(header) / sizeof(u32);
return 0;
-error2:
- release_firmware(firmware);
-error1:
+error:
dsp_code->block_length = 0;
return err_ret;
}
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -385,8 +385,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
memlen = pci_resource_len(pci_dev, idx);
pci.ap_mem_base[idx] =
- ioremap(pci_resource_start(pci_dev, idx),
- memlen);
+ pcim_iomap(pci_dev, idx, memlen);
if (!pci.ap_mem_base[idx]) {
HPI_DEBUG_LOG(ERROR,
"ioremap failed, aborting\n");
@@ -509,13 +508,6 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
return 0;
err:
- while (--idx >= 0) {
- if (pci.ap_mem_base[idx]) {
- iounmap(pci.ap_mem_base[idx]);
- pci.ap_mem_base[idx] = NULL;
- }
- }
-
if (adapter.p_buffer) {
adapter.buffer_size = 0;
vfree(adapter.p_buffer);
@@ -527,14 +519,11 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
void asihpi_adapter_remove(struct pci_dev *pci_dev)
{
- int idx;
struct hpi_message hm;
struct hpi_response hr;
struct hpi_adapter *pa;
- struct hpi_pci pci;
pa = pci_get_drvdata(pci_dev);
- pci = pa->adapter->pci;
/* Disable IRQ generation on DSP side */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
@@ -550,10 +539,6 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
hm.adapter_index = pa->adapter->index;
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
- /* unmap PCI memory space, mapped during device init. */
- for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx)
- iounmap(pci.ap_mem_base[idx]);
-
if (pa->irq)
free_irq(pa->irq, pa);
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -387,7 +387,7 @@ static int load_firmware(struct snd_cs46xx *chip,
unsigned int nums, fwlen, fwsize;
const __le32 *fwdat;
struct dsp_module_desc *module = NULL;
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
char fw_path[32];
sprintf(fw_path, "cs46xx/%s", fw_name);
@@ -395,10 +395,8 @@ static int load_firmware(struct snd_cs46xx *chip,
if (err < 0)
return err;
fwsize = fw->size / 4;
- if (fwsize < 2) {
- err = -EINVAL;
- goto error;
- }
+ if (fwsize < 2)
+ return -EINVAL;
err = -ENOMEM;
module = kzalloc_obj(*module);
@@ -454,14 +452,12 @@ static int load_firmware(struct snd_cs46xx *chip,
}
*module_ret = module;
- release_firmware(fw);
return 0;
error_inval:
err = -EINVAL;
error:
free_module_desc(module);
- release_firmware(fw);
return err;
}
@@ -500,22 +496,18 @@ MODULE_FIRMWARE("cs46xx/ba1");
static int load_firmware(struct snd_cs46xx *chip)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int i, size, err;
err = request_firmware(&fw, "cs46xx/ba1", &chip->pci->dev);
if (err < 0)
return err;
- if (fw->size != sizeof(*chip->ba1)) {
- err = -EINVAL;
- goto error;
- }
+ if (fw->size != sizeof(*chip->ba1))
+ return -EINVAL;
chip->ba1 = vmalloc(sizeof(*chip->ba1));
- if (!chip->ba1) {
- err = -ENOMEM;
- goto error;
- }
+ if (!chip->ba1)
+ return -ENOMEM;
memcpy_le32(chip->ba1, fw->data, sizeof(*chip->ba1));
@@ -524,11 +516,9 @@ static int load_firmware(struct snd_cs46xx *chip)
for (i = 0; i < BA1_MEMORY_COUNT; i++)
size += chip->ba1->memory[i].size;
if (size > BA1_DWORD_SIZE * 4)
- err = -EINVAL;
+ return -EINVAL;
- error:
- release_firmware(fw);
- return err;
+ return 0;
}
static __maybe_unused int snd_cs46xx_download_image(struct snd_cs46xx *chip)
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -990,7 +990,7 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
i < icode->gpr_list_control_count) {
memset(gctl, 0, sizeof(*gctl));
id = &ctl->kcontrol->id;
- gctl->id.iface = (__force int)id->iface;
+ gctl->id.iface = id->iface;
strscpy(gctl->id.name, id->name, sizeof(gctl->id.name));
gctl->id.index = id->index;
gctl->id.device = id->device;
@@ -1156,7 +1156,7 @@ static void
snd_emu10k1_init_mono_control2(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval, int defval_hr)
{
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 1;
if (high_res_gpr_volume) {
@@ -1180,7 +1180,7 @@ static void
snd_emu10k1_init_stereo_control2(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval, int defval_hr)
{
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 2;
if (high_res_gpr_volume) {
@@ -1205,7 +1205,7 @@ static void
snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval)
{
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 1;
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
@@ -1218,7 +1218,7 @@ static void
snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval)
{
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 2;
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
@@ -1542,7 +1542,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
* Process tone control
*/
ctl = &controls[nctl + 0];
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, "Tone Control - Bass");
ctl->vcount = 2;
ctl->count = 10;
@@ -1551,7 +1551,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
ctl->value[0] = ctl->value[1] = 20;
ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
ctl = &controls[nctl + 1];
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, "Tone Control - Treble");
ctl->vcount = 2;
ctl->count = 10;
@@ -2137,7 +2137,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
* Process tone control
*/
ctl = &controls[i + 0];
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, "Tone Control - Bass");
ctl->vcount = 2;
ctl->count = 10;
@@ -2147,7 +2147,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
ctl->tlv = snd_emu10k1_bass_treble_db_scale;
ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
ctl = &controls[i + 1];
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, "Tone Control - Treble");
ctl->vcount = 2;
ctl->count = 10;
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -1980,7 +1980,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
__maybe_unused unsigned ioport_size;
__maybe_unused unsigned iomem2_size;
struct snd_korg1212 *korg1212 = card->private_data;
- const struct firmware *dsp_code;
+ const struct firmware *dsp_code __free(firmware) = NULL;
err = pcim_enable_device(pci);
if (err < 0)
@@ -2147,10 +2147,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
korg1212->dma_dsp = snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV,
dsp_code->size);
- if (!korg1212->dma_dsp) {
- release_firmware(dsp_code);
+ if (!korg1212->dma_dsp)
return -ENOMEM;
- }
K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n",
korg1212->dma_dsp->area, korg1212->dma_dsp->addr, dsp_code->size,
@@ -2158,8 +2156,6 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
memcpy(korg1212->dma_dsp->area, dsp_code->data, dsp_code->size);
- release_firmware(dsp_code);
-
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0);
if (rc)
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -560,12 +560,11 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
"miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
};
char path[32];
-
- const struct firmware *fw_entry;
int i, err;
for (i = 0; i < 3; i++) {
sprintf(path, "mixart/%s", fw_files[i]);
+ const struct firmware *fw_entry __free(firmware) = NULL;
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
dev_err(&mgr->pci->dev,
"miXart: can't load firmware %s\n", path);
@@ -573,7 +572,6 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
}
/* fake hwdep dsp record */
err = mixart_dsp_load(mgr, i, fw_entry);
- release_firmware(fw_entry);
if (err < 0)
return err;
mgr->dsp_loaded |= 1 << i;
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -367,7 +367,6 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
};
char path[32];
- const struct firmware *fw_entry;
int i, err;
int fw_set = mgr->fw_file_set;
@@ -375,6 +374,7 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
if (!fw_files[fw_set][i])
continue;
sprintf(path, "pcxhr/%s", fw_files[fw_set][i]);
+ const struct firmware *fw_entry __free(firmware) = NULL;
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
dev_err(&mgr->pci->dev,
"pcxhr: can't load firmware %s\n",
@@ -383,7 +383,6 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
}
/* fake hwdep dsp record */
err = pcxhr_dsp_load(mgr, i, fw_entry);
- release_firmware(fw_entry);
if (err < 0)
return err;
mgr->dsp_loaded |= 1 << i;
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1260,16 +1260,16 @@ static int sis_chip_create(struct snd_card *card,
sis->irq = -1;
sis->ioport = pci_resource_start(pci, 0);
- rc = pcim_request_all_regions(pci, "SiS7019");
+ rc = pcim_request_region(pci, 0, "SiS7019");
if (rc) {
- dev_err(&pci->dev, "unable request regions\n");
+ dev_err(&pci->dev, "unable request I/O region\n");
return rc;
}
- sis->ioaddr = devm_ioremap(&pci->dev, pci_resource_start(pci, 1), 0x4000);
- if (!sis->ioaddr) {
+ sis->ioaddr = pcim_iomap_region(pci, 1, "SiS7019");
+ if (IS_ERR(sis->ioaddr)) {
dev_err(&pci->dev, "unable to remap MMIO, aborting\n");
- return -EIO;
+ return PTR_ERR(sis->ioaddr);
}
rc = sis_alloc_suspend(sis);
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -518,8 +518,9 @@ static const struct snd_kcontrol_new snd_aica_pcmvolume_control = {
static int load_aica_firmware(void)
{
int err;
- const struct firmware *fw_entry;
spu_reset();
+
+ const struct firmware *fw_entry __free(firmware) = NULL;
err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
if (unlikely(err))
return err;
@@ -527,7 +528,6 @@ static int load_aica_firmware(void)
spu_disable();
spu_memload(0, fw_entry->data, fw_entry->size);
spu_enable();
- release_firmware(fw_entry);
return err;
}
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -726,6 +726,10 @@ config SND_SOC_AW87390
sound quality, which is a new high efficiency, low
noise, constant large volume, 6th Smart K audio amplifier.
+config SND_SOC_AW88399_LIB
+ tristate
+ select SND_SOC_AW88395_LIB
+
config SND_SOC_AW88399
tristate "Soc Audio for awinic aw88399"
depends on I2C
@@ -733,6 +737,7 @@ config SND_SOC_AW88399
select REGMAP_I2C
select GPIOLIB
select SND_SOC_AW88395_LIB
+ select SND_SOC_AW88399_LIB
help
This option enables support for aw88399 Smart PA.
The awinic AW88399 is an I2S/TDM input, high efficiency
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -55,6 +55,7 @@ snd-soc-aw88395-y := aw88395/aw88395.o
snd-soc-aw88166-y := aw88166.o
snd-soc-aw88261-y := aw88261.o
snd-soc-aw88399-y := aw88399.o
+snd-soc-aw88399-lib-y := aw88399-lib.o
snd-soc-bd28623-y := bd28623.o
snd-soc-bt-sco-y := bt-sco.o
snd-soc-chv3-codec-y := chv3-codec.o
@@ -496,6 +497,7 @@ obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o
obj-$(CONFIG_SND_SOC_AW88166) +=snd-soc-aw88166.o
obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o
obj-$(CONFIG_SND_SOC_AW88399) += snd-soc-aw88399.o
+obj-$(CONFIG_SND_SOC_AW88399_LIB) += snd-soc-aw88399-lib.o
obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o
diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c
new file mode 100644
--- /dev/null
+++ b/sound/soc/codecs/aw88399-lib.c
@@ -0,0 +1,1411 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88399-lib.c -- AW88399 Common functions for ASoC and HDA audio drivers
+//
+// Copyright (c) 2023 AWINIC Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/minmax.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/aw88399.h>
+#include "aw88395/aw88395_device.h"
+
+const struct regmap_config aw88399_remap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88399_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+EXPORT_SYMBOL_GPL(aw88399_remap_config);
+
+static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ int ret;
+
+ if (pwd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, &reg_val);
+ if (ret)
+ dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
+ else
+ *int_status = reg_val;
+
+ dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status);
+}
+
+static void aw_dev_clear_int_status(struct aw_device *aw_dev)
+{
+ u16 int_status;
+
+ /* read int status and clear */
+ aw_dev_get_int_status(aw_dev, &int_status);
+ /* make sure int status is clear */
+ aw_dev_get_int_status(aw_dev, &int_status);
+ if (int_status)
+ dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status);
+}
+
+static int aw_dev_get_iis_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) {
+ dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aw_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode1 iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int aw_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88399_CCO_MUX_MASK);
+ if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) {
+ dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
+ return -EPERM;
+ }
+
+ /* change mode2 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int aw_dev_check_syspll(struct aw_device *aw_dev)
+{
+ int ret;
+
+ ret = aw_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+ ret = aw_dev_check_mode2_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 check iis failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw_dev_check_syspll);
+
+static int aw_dev_check_sysst(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int check_val;
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if (reg_val & (~AW88399_NOISE_GATE_EN_MASK))
+ check_val = AW88399_BIT_SYSST_NOSWS_CHECK;
+ else
+ check_val = AW88399_BIT_SYSST_SWS_CHECK;
+
+ /*
+ * On some hardware the BSTS (boost-finished) status bit does not
+ * reliably assert even when audio output is working normally.
+ * Allow per-instance bypass when flagged by the side-codec driver.
+ */
+ if (aw88399->bsts_unreliable)
+ check_val &= ~AW88399_BSTS_FINISHED_VALUE;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) {
+ dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x",
+ i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ int ret;
+
+ if (amppd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable)
+{
+ int ret;
+
+ if (is_enable)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed\n", __func__);
+}
+EXPORT_SYMBOL_GPL(aw_dev_dsp_enable);
+
+static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk)
+{
+ uint16_t icalkh_val, icalkl_val, icalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, &reg_val);
+ if (ret)
+ return ret;
+ icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, &reg_val);
+ if (ret)
+ return ret;
+ icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ icalk_val = icalkh_val & icalkl_val;
+ else
+ icalk_val = icalkh_val | icalkl_val;
+
+ if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK))
+ icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG;
+ *icalk = (int16_t)icalk_val;
+
+ return 0;
+}
+
+static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
+{
+ uint16_t vcalkh_val, vcalkl_val, vcalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ vcalk_val = vcalkh_val & vcalkl_val;
+ else
+ vcalk_val = vcalkh_val | vcalkl_val;
+
+ if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK)
+ vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG;
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
+{
+ uint16_t vcalkh_val, vcalkl_val, vcalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, &reg_val);
+ if (ret)
+ return ret;
+ vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+ vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) &
+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
+ else
+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) |
+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
+
+ if (vcalk_val & (~AW88399_TEM4_SIGN_MASK))
+ vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG;
+
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw_dev_set_vcalb(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int vsense_select, vsense_value;
+ int32_t ical_k, vcal_k, vcalb;
+ int16_t icalk, vcalk;
+ uint16_t reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value);
+ if (ret)
+ return ret;
+
+ vsense_select = vsense_value & (~AW88399_VDSEL_MASK);
+
+ ret = aw88399_dev_get_icalk(aw88399, &icalk);
+ if (ret) {
+ dev_err(aw_dev->dev, "get icalk failed\n");
+ return ret;
+ }
+
+ ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE;
+
+ switch (vsense_select) {
+ case AW88399_DEV_VDSEL_VSENSE:
+ ret = aw88399_dev_get_vcalk(aw88399, &vcalk);
+ vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE;
+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR *
+ ical_k / vcal_k * aw88399->vcalb_init_val;
+ break;
+ case AW88399_DEV_VDSEL_DAC:
+ ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk);
+ vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE;
+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR /
+ AW88399_ISCAL_DAC_FACTOR * ical_k /
+ vcal_k * aw88399->vcalb_init_val;
+ break;
+ default:
+ dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ return ret;
+
+ vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR;
+ reg_val = (uint32_t)vcalb;
+
+ regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val);
+
+ return 0;
+}
+
+int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ uint16_t re_lbits, re_hbits;
+ u32 cali_re;
+ int ret;
+
+ if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) ||
+ (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN))
+ return -EINVAL;
+
+ cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
+ aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT);
+
+ re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT;
+ re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT;
+
+ ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits);
+ if (ret) {
+ dev_err(aw_dev->dev, "set cali re error");
+ return ret;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits);
+ if (ret)
+ dev_err(aw_dev->dev, "set cali re error");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw_dev_update_cali_re);
+
+static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
+{
+ uint16_t check_val, fw_len_val;
+ unsigned int reg_val;
+ int ret;
+
+ /* calculate fw_end_addr */
+ fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR;
+
+ /* write fw_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_END_ADDR_MASK, fw_len_val);
+ if (ret)
+ return ret;
+ /* enable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE);
+
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+
+ /* read crc check result */
+ regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
+
+ /* disable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x",
+ __func__, check_val, AW88399_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
+{
+ uint16_t check_val, cfg_len_val;
+ unsigned int reg_val;
+ int ret;
+
+ /* calculate cfg end addr */
+ cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR;
+
+ /* write cfg_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_END_ADDR_MASK, cfg_len_val);
+ if (ret)
+ return ret;
+
+ /* enable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE);
+ if (ret)
+ return ret;
+
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+
+ /* read crc check result */
+ ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
+
+ /* disable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x",
+ check_val, AW88399_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_hw_crc_check(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_fw_crc_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw_crc_check failed\n");
+ goto crc_check_failed;
+ }
+
+ ret = aw_dev_cfg_crc_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "cfg_crc_check failed\n");
+ goto crc_check_failed;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
+
+ return ret;
+
+crc_check_failed:
+ regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
+ return ret;
+}
+
+static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+ int ret;
+
+ if (flag)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG,
+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+int aw_dev_get_dsp_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, &reg_val);
+ if (ret)
+ return ret;
+ if (!(reg_val & (~AW88399_WDT_CNT_MASK)))
+ return -EPERM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw_dev_get_dsp_status);
+
+static int aw_dev_dsp_check(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ switch (aw_dev->dsp_cfg) {
+ case AW88399_DEV_DSP_BYPASS:
+ dev_dbg(aw_dev->dev, "dsp bypass");
+ ret = 0;
+ break;
+ case AW88399_DEV_DSP_WORK:
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_dsp_enable(aw_dev, true);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) {
+ ret = aw_dev_get_dsp_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ }
+ }
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int reg_value;
+ u16 real_value;
+ int ret;
+
+ real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, &reg_value);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
+
+ real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK);
+
+ ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw_dev_set_volume);
+
+static void aw_dev_fade_in(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ u16 fade_in_vol = desc->ctl_volume;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_in_time == 0) {
+ aw_dev_set_volume(aw_dev, fade_in_vol);
+ return;
+ }
+
+ for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+ aw_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
+ }
+
+ if (i != fade_in_vol)
+ aw_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw_dev_fade_out(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_out_time == 0) {
+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) {
+ aw_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+
+ if (i != AW88399_MUTE_VOL) {
+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+}
+
+void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+ if (is_mute) {
+ aw_dev_fade_out(aw_dev);
+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE);
+ aw_dev_fade_in(aw_dev);
+ }
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_mute);
+
+static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ if (dither)
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE);
+}
+
+static int aw88399_dev_start(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88399_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ aw88399_dev_set_dither(aw88399, false);
+
+ /* power on */
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+
+ ret = aw_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw_dev_amppd(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw_dev_check_sysst(aw88399);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed");
+ goto sysst_check_fail;
+ }
+
+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) {
+ ret = aw_dev_hw_crc_check(aw88399);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp crc check failed");
+ goto crc_check_fail;
+ }
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_set_vcalb(aw88399);
+ aw_dev_update_cali_re(&aw_dev->cali_desc);
+
+ ret = aw_dev_dsp_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp status check failed");
+ goto dsp_check_fail;
+ }
+ } else {
+ dev_dbg(aw_dev->dev, "start pa with dsp bypass");
+ }
+
+ /* enable tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, true);
+
+ if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE)
+ aw88399_dev_set_dither(aw88399, true);
+
+ /* close mute */
+ aw88399_dev_mute(aw_dev, false);
+ /* clear inturrupt */
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88399_DEV_PW_ON;
+
+ return 0;
+
+dsp_check_fail:
+crc_check_fail:
+ aw_dev_dsp_enable(aw_dev, false);
+sysst_check_fail:
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev_amppd(aw_dev, true);
+pll_check_fail:
+ aw_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88399_DEV_PW_OFF;
+
+ return ret;
+}
+
+static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len, unsigned short base)
+{
+ u32 tmp_len;
+ int i, ret;
+
+ ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) {
+ tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE);
+ ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG,
+ &data[i], tmp_len);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ u32 dsp_ra;
+ int ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA,
+ &dsp_ra, AW_DSP_32_DATA);
+ if (ret) {
+ dev_err(aw_dev->dev, "read ra error");
+ return ret;
+ }
+
+ cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra,
+ AW88399_DSP_RE_SHIFT);
+
+ return 0;
+}
+
+static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ dev_dbg(aw_dev->dev, "dsp config len:%d", len);
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "dsp config data is null or len is 0");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR);
+ if (ret)
+ return ret;
+
+ aw_dev->dsp_cfg_len = len;
+
+ ret = aw_dev_get_ra(&aw_dev->cali_desc);
+
+ return ret;
+}
+
+static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ dev_dbg(aw_dev->dev, "dsp firmware len:%d", len);
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "dsp firmware data is null or len is 0");
+ return -EINVAL;
+ }
+
+ aw_dev->dsp_fw_len = len;
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR);
+
+ return ret;
+}
+
+static int aw_dev_check_sram(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+
+ /* read dsp_rom_check_reg */
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, &reg_val, AW_DSP_16_DATA);
+ if (reg_val != AW88399_DSP_ROM_CHECK_DATA) {
+ dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]",
+ reg_val, AW88399_DSP_ROM_CHECK_DATA);
+ return -EPERM;
+ }
+
+ /* check dsp_cfg_base_addr */
+ aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR,
+ AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA);
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, &reg_val, AW_DSP_16_DATA);
+ if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) {
+ dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
+ reg_val, AW88399_DSP_ODD_NUM_BIT_TEST);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
+{
+ int ret;
+
+ switch (flag) {
+ case AW88399_DEV_MEMCLK_PLL:
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_MEM_CLKSEL_MASK,
+ AW88399_MEM_CLKSEL_DAPHCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select pll failed");
+ break;
+ case AW88399_DEV_MEMCLK_OSC:
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_MEM_CLKSEL_MASK,
+ AW88399_MEM_CLKSEL_OSCCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select OSC failed");
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag);
+ break;
+ }
+}
+
+static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev)
+{
+ struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, &reg_val);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+ return;
+ }
+ if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE)
+ profctrl_desc->cur_mode = AW88399_RCV_MODE;
+ else
+ profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE;
+}
+
+static int aw_dev_update_reg_container(struct aw88399 *aw88399,
+ unsigned char *data, unsigned int len)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ u16 read_vol, reg_val;
+ int data_len, i, ret;
+ int16_t *reg_data;
+ u8 reg_addr;
+
+ reg_data = (int16_t *)data;
+ data_len = len >> 1;
+
+ if (data_len & 0x1) {
+ dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data_len; i += 2) {
+ reg_addr = reg_data[i];
+ reg_val = reg_data[i + 1];
+
+ if (reg_addr == AW88399_DSPVCALB_REG) {
+ aw88399->vcalb_init_val = reg_val;
+ continue;
+ }
+
+ if (reg_addr == AW88399_SYSCTRL_REG) {
+ if (reg_val & (~AW88399_DSPBY_MASK))
+ aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS;
+ else
+ aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK;
+
+ reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK |
+ AW88399_DSPBY_MASK);
+ reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE |
+ AW88399_DSPBY_BYPASS_VALUE);
+ }
+
+ if (reg_addr == AW88399_I2SCTRL3_REG) {
+ reg_val &= AW88399_I2STXEN_MASK;
+ reg_val |= AW88399_I2STXEN_DISABLE_VALUE;
+ }
+
+ if (reg_addr == AW88399_SYSCTRL2_REG) {
+ read_vol = (reg_val & (~AW88399_VOL_MASK)) >>
+ AW88399_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume = read_vol;
+ }
+
+ if (reg_addr == AW88399_DBGCTRL_REG) {
+ if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE)
+ aw88399->check_val = AW_EF_OR_CHECK;
+ else
+ aw88399->check_val = AW_EF_AND_CHECK;
+
+ aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK);
+ }
+
+ if (reg_addr == AW88399_CRCCTRL_REG)
+ aw88399->crc_init_val = reg_val;
+
+ ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
+ if (ret)
+ return ret;
+ }
+
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+
+ aw_dev_get_cur_mode_st(aw_dev);
+
+ if (aw_dev->prof_cur != aw_dev->prof_index)
+ vol_desc->ctl_volume = 0;
+ else
+ aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
+
+ return 0;
+}
+
+static int aw_dev_reg_update(struct aw88399 *aw88399,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ if (!len || !data) {
+ dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_update_reg_container(aw88399, data, len);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "reg update failed");
+
+ return ret;
+}
+
+int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
+{
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ struct aw_prof_desc *prof_desc;
+
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
+ index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ *prof_name = prof_info->prof_name_list[prof_desc->id];
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_get_prof_name);
+
+static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index,
+ struct aw_prof_desc **prof_desc)
+{
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
+ __func__, index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ *prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ return 0;
+}
+
+static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ if ((aw_dev->prof_cur == aw_dev->prof_index) &&
+ (force_up_en == AW88399_FORCE_UPDATE_OFF)) {
+ dev_dbg(aw_dev->dev, "scene no change, not update");
+ return 0;
+ }
+
+ if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) {
+ dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status);
+ return -EPERM;
+ }
+
+ ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
+ if (ret)
+ return ret;
+
+ /* update reg */
+ sec_desc = prof_index_desc->sec_desc;
+ ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data,
+ sec_desc[AW88395_DATA_TYPE_REG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update reg failed");
+ return ret;
+ }
+
+ aw88399_dev_mute(aw_dev, true);
+
+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK)
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
+
+ ret = aw_dev_check_sram(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "check sram failed");
+ goto error;
+ }
+
+ if (up_dsp_fw_en) {
+ dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver);
+ ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data,
+ sec_desc[AW88395_DATA_TYPE_DSP_FW].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update dsp fw failed");
+ goto error;
+ }
+ }
+
+ /* update dsp config */
+ ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data,
+ sec_desc[AW88395_DATA_TYPE_DSP_CFG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update dsp cfg failed");
+ goto error;
+ }
+
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+
+error:
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+ return ret;
+}
+
+static void aw88399_start_pa(struct aw88399 *aw88399)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88399_START_RETRIES; i++) {
+ ret = aw88399_dev_start(aw88399);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i);
+ ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "fw update failed");
+ continue;
+ }
+ } else {
+ dev_dbg(aw88399->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+void aw88399_startup_work(struct work_struct *work)
+{
+ struct aw88399 *aw88399 =
+ container_of(work, struct aw88399, start_work.work);
+
+ mutex_lock(&aw88399->lock);
+ aw88399_start_pa(aw88399);
+ mutex_unlock(&aw88399->lock);
+}
+EXPORT_SYMBOL_GPL(aw88399_startup_work);
+
+void aw88399_start(struct aw88399 *aw88399, bool sync_start)
+{
+ int ret;
+
+ if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK)
+ return;
+
+ if (aw88399->aw_pa->status == AW88399_DEV_PW_ON)
+ return;
+
+ ret = aw88399_dev_fw_update(aw88399, aw88399->fw_needs_reload ?
+ AW88399_DSP_FW_UPDATE_ON : AW88399_DSP_FW_UPDATE_OFF, true);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "fw update failed.");
+ return;
+ }
+
+ aw88399->fw_needs_reload = false;
+
+ if (sync_start == AW88399_SYNC_START)
+ aw88399_start_pa(aw88399);
+ else
+ queue_delayed_work(system_dfl_wq,
+ &aw88399->start_work,
+ AW88399_START_WORK_DELAY_MS);
+}
+EXPORT_SYMBOL_GPL(aw88399_start);
+
+static int aw_dev_check_sysint(struct aw_device *aw_dev)
+{
+ u16 reg_val;
+
+ aw_dev_get_int_status(aw_dev, &reg_val);
+ if (reg_val & AW88399_BIT_SYSINT_CHECK) {
+ dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int aw88399_stop(struct aw_device *aw_dev)
+{
+ struct aw_sec_data_desc *dsp_cfg =
+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG];
+ struct aw_sec_data_desc *dsp_fw =
+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW];
+ int int_st;
+
+ if (aw_dev->status == AW88399_DEV_PW_OFF) {
+ dev_dbg(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88399_DEV_PW_OFF;
+
+ aw88399_dev_mute(aw_dev, true);
+ usleep_range(AW88399_4000_US, AW88399_4000_US + 100);
+
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
+
+ int_st = aw_dev_check_sysint(aw_dev);
+
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_amppd(aw_dev, true);
+
+ if (int_st) {
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
+ aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len);
+ aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len);
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+ }
+
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw88399_stop);
+
+static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw_dev acf parse failed");
+ return -EINVAL;
+ }
+ aw_dev->fade_in_time = AW88399_1000_US / 10;
+ aw_dev->fade_out_time = AW88399_1000_US >> 1;
+ aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id;
+ aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id;
+
+ ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ aw88399_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
+
+ /* enable amppd */
+ aw_dev_amppd(aw_dev, true);
+
+ /* close dsp */
+ aw_dev_dsp_enable(aw_dev, false);
+ /* set power down */
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+int aw88399_request_firmware_file(struct aw88399 *aw88399)
+{
+ const struct firmware *cont = NULL;
+ int ret;
+
+ aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE);
+ return ret;
+ }
+
+ dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88399_ACF_FILE, cont ? cont->size : 0);
+
+ aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev,
+ struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL);
+ if (!aw88399->aw_cfg) {
+ release_firmware(cont);
+ return -ENOMEM;
+ }
+ aw88399->aw_cfg->len = (int)cont->size;
+ memcpy(aw88399->aw_cfg->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE);
+ return ret;
+ }
+
+ mutex_lock(&aw88399->lock);
+ /* aw device init */
+ ret = aw88399_dev_init(aw88399, aw88399->aw_cfg);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "dev init failed");
+ mutex_unlock(&aw88399->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw88399_request_firmware_file);
+
+void aw88399_hw_reset(struct aw88399 *aw88399)
+{
+ if (aw88399->reset_gpio) {
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 0);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ }
+}
+EXPORT_SYMBOL_GPL(aw88399_hw_reset);
+
+static void aw88399_parse_channel_dt(struct aw_device *aw_dev)
+{
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value;
+ int ret;
+
+ ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value);
+ if (ret) {
+ /*
+ * On ACPI systems, DT properties don't exist. Derive channel
+ * from I2C address: 0x34 -> channel 0 (left), 0x35 -> channel 1 (right)
+ */
+ aw_dev->channel = aw_dev->i2c->addr - 0x34;
+ dev_dbg(aw_dev->dev,
+ "DT channel property not found, using I2C address-based channel %d (addr 0x%02x)\n",
+ aw_dev->channel, aw_dev->i2c->addr);
+ return;
+ }
+ aw_dev->channel = channel_value;
+}
+
+int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ ret = regmap_read(regmap, AW88399_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+ return ret;
+ }
+ if (chip_id != AW88399_CHIP_ID) {
+ dev_err(&i2c->dev, "unsupported device");
+ return -ENXIO;
+ }
+ dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+ aw88399->aw_pa = aw_dev;
+
+ aw_dev->i2c = i2c;
+ aw_dev->dev = &i2c->dev;
+ aw_dev->regmap = regmap;
+ mutex_init(&aw_dev->dsp_lock);
+
+ aw_dev->chip_id = chip_id;
+ aw_dev->acf = NULL;
+ aw_dev->prof_info.prof_desc = NULL;
+ aw_dev->prof_info.count = 0;
+ aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
+ aw_dev->channel = AW88399_DEV_DEFAULT_CH;
+ aw_dev->fw_status = AW88399_DEV_FW_FAILED;
+
+ aw_dev->fade_step = AW88399_VOLUME_STEP_DB;
+ aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE;
+
+ aw88399_parse_channel_dt(aw_dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw88399_init);
+
+void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel)
+{
+ aw88399->aw_pa->channel = channel;
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_set_channel);
+
+MODULE_DESCRIPTION("AW88399 common device library");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
--- a/sound/soc/codecs/aw88399.c
+++ b/sound/soc/codecs/aw88399.c
@@ -10,1217 +10,12 @@
#include <linux/crc32.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
-#include <linux/firmware.h>
-#include <linux/minmax.h>
#include <linux/regmap.h>
#include <linux/sort.h>
#include <sound/soc.h>
#include "aw88399.h"
#include "aw88395/aw88395_device.h"
-static const struct regmap_config aw88399_remap_config = {
- .val_bits = 16,
- .reg_bits = 8,
- .max_register = AW88399_REG_MAX,
- .reg_format_endian = REGMAP_ENDIAN_LITTLE,
- .val_format_endian = REGMAP_ENDIAN_BIG,
-};
-
-static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
-{
- int ret;
-
- if (pwd)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, &reg_val);
- if (ret)
- dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
- else
- *int_status = reg_val;
-
- dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status);
-}
-
-static void aw_dev_clear_int_status(struct aw_device *aw_dev)
-{
- u16 int_status;
-
- /* read int status and clear */
- aw_dev_get_int_status(aw_dev, &int_status);
- /* make sure int status is clear */
- aw_dev_get_int_status(aw_dev, &int_status);
- if (int_status)
- dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status);
-}
-
-static int aw_dev_get_iis_status(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
- if (ret)
- return ret;
- if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) {
- dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int aw_dev_check_mode1_pll(struct aw_device *aw_dev)
-{
- int ret, i;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode1 iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- return 0;
- }
- }
-
- return -EPERM;
-}
-
-static int aw_dev_check_mode2_pll(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret, i;
-
- ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, &reg_val);
- if (ret)
- return ret;
-
- reg_val &= (~AW88399_CCO_MUX_MASK);
- if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) {
- dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
- return -EPERM;
- }
-
- /* change mode2 */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
- ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE);
- if (ret)
- return ret;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- break;
- }
- }
-
- /* change mode1 */
- regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
- ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE);
- if (ret == 0) {
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- break;
- }
- }
- }
-
- return ret;
-}
-
-static int aw_dev_check_syspll(struct aw_device *aw_dev)
-{
- int ret;
-
- ret = aw_dev_check_mode1_pll(aw_dev);
- if (ret) {
- dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
- ret = aw_dev_check_mode2_pll(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 check iis failed");
- return ret;
- }
- }
-
- return 0;
-}
-
-static int aw_dev_check_sysst(struct aw_device *aw_dev)
-{
- unsigned int check_val;
- unsigned int reg_val;
- int ret, i;
-
- ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, &reg_val);
- if (ret)
- return ret;
-
- if (reg_val & (~AW88399_NOISE_GATE_EN_MASK))
- check_val = AW88399_BIT_SYSST_NOSWS_CHECK;
- else
- check_val = AW88399_BIT_SYSST_SWS_CHECK;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
- if (ret)
- return ret;
-
- if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) {
- dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x",
- i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- return 0;
- }
- }
-
- return -EPERM;
-}
-
-static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
-{
- int ret;
-
- if (amppd)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable)
-{
- int ret;
-
- if (is_enable)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed\n", __func__);
-}
-
-static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk)
-{
- uint16_t icalkh_val, icalkl_val, icalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, &reg_val);
- if (ret)
- return ret;
- icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, &reg_val);
- if (ret)
- return ret;
- icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- icalk_val = icalkh_val & icalkl_val;
- else
- icalk_val = icalkh_val | icalkl_val;
-
- if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK))
- icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG;
- *icalk = (int16_t)icalk_val;
-
- return 0;
-}
-
-static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
-{
- uint16_t vcalkh_val, vcalkl_val, vcalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, &reg_val);
- if (ret)
- return ret;
-
- vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, &reg_val);
- if (ret)
- return ret;
-
- vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- vcalk_val = vcalkh_val & vcalkl_val;
- else
- vcalk_val = vcalkh_val | vcalkl_val;
-
- if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK)
- vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG;
- *vcalk = (int16_t)vcalk_val;
-
- return 0;
-}
-
-static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
-{
- uint16_t vcalkh_val, vcalkl_val, vcalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, &reg_val);
- if (ret)
- return ret;
- vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, &reg_val);
- if (ret)
- return ret;
- vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) &
- (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
- else
- vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) |
- (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
-
- if (vcalk_val & (~AW88399_TEM4_SIGN_MASK))
- vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG;
-
- *vcalk = (int16_t)vcalk_val;
-
- return 0;
-}
-
-static int aw_dev_set_vcalb(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int vsense_select, vsense_value;
- int32_t ical_k, vcal_k, vcalb;
- int16_t icalk, vcalk;
- uint16_t reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value);
- if (ret)
- return ret;
-
- vsense_select = vsense_value & (~AW88399_VDSEL_MASK);
-
- ret = aw88399_dev_get_icalk(aw88399, &icalk);
- if (ret) {
- dev_err(aw_dev->dev, "get icalk failed\n");
- return ret;
- }
-
- ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE;
-
- switch (vsense_select) {
- case AW88399_DEV_VDSEL_VSENSE:
- ret = aw88399_dev_get_vcalk(aw88399, &vcalk);
- vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE;
- vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR *
- ical_k / vcal_k * aw88399->vcalb_init_val;
- break;
- case AW88399_DEV_VDSEL_DAC:
- ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk);
- vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE;
- vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR /
- AW88399_ISCAL_DAC_FACTOR * ical_k /
- vcal_k * aw88399->vcalb_init_val;
- break;
- default:
- dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__);
- ret = -EINVAL;
- break;
- }
- if (ret)
- return ret;
-
- vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR;
- reg_val = (uint32_t)vcalb;
-
- regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val);
-
- return 0;
-}
-
-static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc)
-{
- struct aw_device *aw_dev =
- container_of(cali_desc, struct aw_device, cali_desc);
- uint16_t re_lbits, re_hbits;
- u32 cali_re;
- int ret;
-
- if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) ||
- (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN))
- return -EINVAL;
-
- cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
- aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT);
-
- re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT;
- re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT;
-
- ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits);
- if (ret) {
- dev_err(aw_dev->dev, "set cali re error");
- return ret;
- }
-
- ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits);
- if (ret)
- dev_err(aw_dev->dev, "set cali re error");
-
- return ret;
-}
-
-static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
-{
- uint16_t check_val, fw_len_val;
- unsigned int reg_val;
- int ret;
-
- /* calculate fw_end_addr */
- fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR;
-
- /* write fw_end_addr to crc_end_addr */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_END_ADDR_MASK, fw_len_val);
- if (ret)
- return ret;
- /* enable fw crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE);
-
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
-
- /* read crc check result */
- regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
- if (ret)
- return ret;
-
- check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
-
- /* disable fw crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE);
- if (ret)
- return ret;
-
- if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
- dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x",
- __func__, check_val, AW88399_CRC_CHECK_PASS_VAL);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
-{
- uint16_t check_val, cfg_len_val;
- unsigned int reg_val;
- int ret;
-
- /* calculate cfg end addr */
- cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR;
-
- /* write cfg_end_addr to crc_end_addr */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_END_ADDR_MASK, cfg_len_val);
- if (ret)
- return ret;
-
- /* enable cfg crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE);
- if (ret)
- return ret;
-
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
-
- /* read crc check result */
- ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
- if (ret)
- return ret;
-
- check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
-
- /* disable cfg crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE);
- if (ret)
- return ret;
-
- if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
- dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x",
- check_val, AW88399_CRC_CHECK_PASS_VAL);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int aw_dev_hw_crc_check(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- int ret;
-
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE);
- if (ret)
- return ret;
-
- ret = aw_dev_fw_crc_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "fw_crc_check failed\n");
- goto crc_check_failed;
- }
-
- ret = aw_dev_cfg_crc_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "cfg_crc_check failed\n");
- goto crc_check_failed;
- }
-
- ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val);
- if (ret)
- return ret;
-
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
-
- return ret;
-
-crc_check_failed:
- regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
- return ret;
-}
-
-static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
-{
- int ret;
-
- if (flag)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG,
- ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static int aw_dev_get_dsp_status(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, &reg_val);
- if (ret)
- return ret;
- if (!(reg_val & (~AW88399_WDT_CNT_MASK)))
- return -EPERM;
-
- return 0;
-}
-
-static int aw_dev_dsp_check(struct aw_device *aw_dev)
-{
- int ret, i;
-
- switch (aw_dev->dsp_cfg) {
- case AW88399_DEV_DSP_BYPASS:
- dev_dbg(aw_dev->dev, "dsp bypass");
- ret = 0;
- break;
- case AW88399_DEV_DSP_WORK:
- aw_dev_dsp_enable(aw_dev, false);
- aw_dev_dsp_enable(aw_dev, true);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) {
- ret = aw_dev_get_dsp_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- }
- }
- break;
- default:
- dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
-{
- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
- unsigned int reg_value;
- u16 real_value;
- int ret;
-
- real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL);
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, &reg_value);
- if (ret)
- return ret;
-
- dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
-
- real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK);
-
- ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value);
-
- return ret;
-}
-
-static void aw_dev_fade_in(struct aw_device *aw_dev)
-{
- struct aw_volume_desc *desc = &aw_dev->volume_desc;
- u16 fade_in_vol = desc->ctl_volume;
- int fade_step = aw_dev->fade_step;
- int i;
-
- if (fade_step == 0 || aw_dev->fade_in_time == 0) {
- aw_dev_set_volume(aw_dev, fade_in_vol);
- return;
- }
-
- for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
- aw_dev_set_volume(aw_dev, i);
- usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
- }
-
- if (i != fade_in_vol)
- aw_dev_set_volume(aw_dev, fade_in_vol);
-}
-
-static void aw_dev_fade_out(struct aw_device *aw_dev)
-{
- struct aw_volume_desc *desc = &aw_dev->volume_desc;
- int fade_step = aw_dev->fade_step;
- int i;
-
- if (fade_step == 0 || aw_dev->fade_out_time == 0) {
- aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
- return;
- }
-
- for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) {
- aw_dev_set_volume(aw_dev, i);
- usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
- }
-
- if (i != AW88399_MUTE_VOL) {
- aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
- usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
- }
-}
-
-static void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute)
-{
- if (is_mute) {
- aw_dev_fade_out(aw_dev);
- regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE);
- } else {
- regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE);
- aw_dev_fade_in(aw_dev);
- }
-}
-
-static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
-
- if (dither)
- regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE);
- else
- regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE);
-}
-
-static int aw88399_dev_start(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- int ret;
-
- if (aw_dev->status == AW88399_DEV_PW_ON) {
- dev_dbg(aw_dev->dev, "already power on");
- return 0;
- }
-
- aw88399_dev_set_dither(aw88399, false);
-
- /* power on */
- aw_dev_pwd(aw_dev, false);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
-
- ret = aw_dev_check_syspll(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "pll check failed cannot start");
- goto pll_check_fail;
- }
-
- /* amppd on */
- aw_dev_amppd(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 50);
-
- /* check i2s status */
- ret = aw_dev_check_sysst(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "sysst check failed");
- goto sysst_check_fail;
- }
-
- if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) {
- ret = aw_dev_hw_crc_check(aw88399);
- if (ret) {
- dev_err(aw_dev->dev, "dsp crc check failed");
- goto crc_check_fail;
- }
- aw_dev_dsp_enable(aw_dev, false);
- aw_dev_set_vcalb(aw88399);
- aw_dev_update_cali_re(&aw_dev->cali_desc);
-
- ret = aw_dev_dsp_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "dsp status check failed");
- goto dsp_check_fail;
- }
- } else {
- dev_dbg(aw_dev->dev, "start pa with dsp bypass");
- }
-
- /* enable tx feedback */
- aw_dev_i2s_tx_enable(aw_dev, true);
-
- if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE)
- aw88399_dev_set_dither(aw88399, true);
-
- /* close mute */
- aw88399_dev_mute(aw_dev, false);
- /* clear inturrupt */
- aw_dev_clear_int_status(aw_dev);
- aw_dev->status = AW88399_DEV_PW_ON;
-
- return 0;
-
-dsp_check_fail:
-crc_check_fail:
- aw_dev_dsp_enable(aw_dev, false);
-sysst_check_fail:
- aw_dev_clear_int_status(aw_dev);
- aw_dev_amppd(aw_dev, true);
-pll_check_fail:
- aw_dev_pwd(aw_dev, true);
- aw_dev->status = AW88399_DEV_PW_OFF;
-
- return ret;
-}
-
-static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len, unsigned short base)
-{
- u32 tmp_len;
- int i, ret;
-
- ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base);
- if (ret)
- return ret;
-
- for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) {
- tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE);
- ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG,
- &data[i], tmp_len);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
-{
- struct aw_device *aw_dev =
- container_of(cali_desc, struct aw_device, cali_desc);
- u32 dsp_ra;
- int ret;
-
- ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA,
- &dsp_ra, AW_DSP_32_DATA);
- if (ret) {
- dev_err(aw_dev->dev, "read ra error");
- return ret;
- }
-
- cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra,
- AW88399_DSP_RE_SHIFT);
-
- return 0;
-}
-
-static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- dev_dbg(aw_dev->dev, "dsp config len:%d", len);
-
- if (!len || !data) {
- dev_err(aw_dev->dev, "dsp config data is null or len is 0");
- return -EINVAL;
- }
-
- ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR);
- if (ret)
- return ret;
-
- aw_dev->dsp_cfg_len = len;
-
- ret = aw_dev_get_ra(&aw_dev->cali_desc);
-
- return ret;
-}
-
-static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- dev_dbg(aw_dev->dev, "dsp firmware len:%d", len);
-
- if (!len || !data) {
- dev_err(aw_dev->dev, "dsp firmware data is null or len is 0");
- return -EINVAL;
- }
-
- aw_dev->dsp_fw_len = len;
- ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR);
-
- return ret;
-}
-
-static int aw_dev_check_sram(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
-
- /* read dsp_rom_check_reg */
- aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, &reg_val, AW_DSP_16_DATA);
- if (reg_val != AW88399_DSP_ROM_CHECK_DATA) {
- dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]",
- reg_val, AW88399_DSP_ROM_CHECK_DATA);
- return -EPERM;
- }
-
- /* check dsp_cfg_base_addr */
- aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR,
- AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA);
- aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, &reg_val, AW_DSP_16_DATA);
- if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) {
- dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
- reg_val, AW88399_DSP_ODD_NUM_BIT_TEST);
- return -EPERM;
- }
-
- return 0;
-}
-
-static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
-{
- int ret;
-
- switch (flag) {
- case AW88399_DEV_MEMCLK_PLL:
- ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_MEM_CLKSEL_MASK,
- AW88399_MEM_CLKSEL_DAPHCLK_VALUE);
- if (ret)
- dev_err(aw_dev->dev, "memclk select pll failed");
- break;
- case AW88399_DEV_MEMCLK_OSC:
- ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_MEM_CLKSEL_MASK,
- AW88399_MEM_CLKSEL_OSCCLK_VALUE);
- if (ret)
- dev_err(aw_dev->dev, "memclk select OSC failed");
- break;
- default:
- dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag);
- break;
- }
-}
-
-static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev)
-{
- struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, &reg_val);
- if (ret) {
- dev_dbg(aw_dev->dev, "%s failed", __func__);
- return;
- }
- if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE)
- profctrl_desc->cur_mode = AW88399_RCV_MODE;
- else
- profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE;
-}
-
-static int aw_dev_update_reg_container(struct aw88399 *aw88399,
- unsigned char *data, unsigned int len)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
- u16 read_vol, reg_val;
- int data_len, i, ret;
- int16_t *reg_data;
- u8 reg_addr;
-
- reg_data = (int16_t *)data;
- data_len = len >> 1;
-
- if (data_len & 0x1) {
- dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
- return -EINVAL;
- }
-
- for (i = 0; i < data_len; i += 2) {
- reg_addr = reg_data[i];
- reg_val = reg_data[i + 1];
-
- if (reg_addr == AW88399_DSPVCALB_REG) {
- aw88399->vcalb_init_val = reg_val;
- continue;
- }
-
- if (reg_addr == AW88399_SYSCTRL_REG) {
- if (reg_val & (~AW88399_DSPBY_MASK))
- aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS;
- else
- aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK;
-
- reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK |
- AW88399_DSPBY_MASK);
- reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE |
- AW88399_DSPBY_BYPASS_VALUE);
- }
-
- if (reg_addr == AW88399_I2SCTRL3_REG) {
- reg_val &= AW88399_I2STXEN_MASK;
- reg_val |= AW88399_I2STXEN_DISABLE_VALUE;
- }
-
- if (reg_addr == AW88399_SYSCTRL2_REG) {
- read_vol = (reg_val & (~AW88399_VOL_MASK)) >>
- AW88399_VOL_START_BIT;
- aw_dev->volume_desc.init_volume = read_vol;
- }
-
- if (reg_addr == AW88399_DBGCTRL_REG) {
- if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE)
- aw88399->check_val = AW_EF_OR_CHECK;
- else
- aw88399->check_val = AW_EF_AND_CHECK;
-
- aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK);
- }
-
- if (reg_addr == AW88399_CRCCTRL_REG)
- aw88399->crc_init_val = reg_val;
-
- ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
- if (ret)
- return ret;
- }
-
- aw_dev_pwd(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
-
- aw_dev_get_cur_mode_st(aw_dev);
-
- if (aw_dev->prof_cur != aw_dev->prof_index)
- vol_desc->ctl_volume = 0;
- else
- aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
-
- return 0;
-}
-
-static int aw_dev_reg_update(struct aw88399 *aw88399,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- if (!len || !data) {
- dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0");
- return -EINVAL;
- }
-
- ret = aw_dev_update_reg_container(aw88399, data, len);
- if (ret)
- dev_err(aw88399->aw_pa->dev, "reg update failed");
-
- return ret;
-}
-
-static int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
-{
- struct aw_prof_info *prof_info = &aw_dev->prof_info;
- struct aw_prof_desc *prof_desc;
-
- if ((index >= aw_dev->prof_info.count) || (index < 0)) {
- dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
- index, aw_dev->prof_info.count);
- return -EINVAL;
- }
-
- prof_desc = &aw_dev->prof_info.prof_desc[index];
-
- *prof_name = prof_info->prof_name_list[prof_desc->id];
-
- return 0;
-}
-
-static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index,
- struct aw_prof_desc **prof_desc)
-{
- if ((index >= aw_dev->prof_info.count) || (index < 0)) {
- dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
- __func__, index, aw_dev->prof_info.count);
- return -EINVAL;
- }
-
- *prof_desc = &aw_dev->prof_info.prof_desc[index];
-
- return 0;
-}
-
-static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- struct aw_prof_desc *prof_index_desc;
- struct aw_sec_data_desc *sec_desc;
- char *prof_name;
- int ret;
-
- if ((aw_dev->prof_cur == aw_dev->prof_index) &&
- (force_up_en == AW88399_FORCE_UPDATE_OFF)) {
- dev_dbg(aw_dev->dev, "scene no change, not update");
- return 0;
- }
-
- if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) {
- dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status);
- return -EPERM;
- }
-
- ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
- if (ret)
- return ret;
-
- dev_dbg(aw_dev->dev, "start update %s", prof_name);
-
- ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
- if (ret)
- return ret;
-
- /* update reg */
- sec_desc = prof_index_desc->sec_desc;
- ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data,
- sec_desc[AW88395_DATA_TYPE_REG].len);
- if (ret) {
- dev_err(aw_dev->dev, "update reg failed");
- return ret;
- }
-
- aw88399_dev_mute(aw_dev, true);
-
- if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK)
- aw_dev_dsp_enable(aw_dev, false);
-
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
-
- ret = aw_dev_check_sram(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "check sram failed");
- goto error;
- }
-
- if (up_dsp_fw_en) {
- dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver);
- ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data,
- sec_desc[AW88395_DATA_TYPE_DSP_FW].len);
- if (ret) {
- dev_err(aw_dev->dev, "update dsp fw failed");
- goto error;
- }
- }
-
- /* update dsp config */
- ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data,
- sec_desc[AW88395_DATA_TYPE_DSP_CFG].len);
- if (ret) {
- dev_err(aw_dev->dev, "update dsp cfg failed");
- goto error;
- }
-
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
-
- aw_dev->prof_cur = aw_dev->prof_index;
-
- return 0;
-
-error:
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
- return ret;
-}
-
-static void aw88399_start_pa(struct aw88399 *aw88399)
-{
- int ret, i;
-
- for (i = 0; i < AW88399_START_RETRIES; i++) {
- ret = aw88399_dev_start(aw88399);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i);
- ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "fw update failed");
- continue;
- }
- } else {
- dev_dbg(aw88399->aw_pa->dev, "start success\n");
- break;
- }
- }
-}
-
-static void aw88399_startup_work(struct work_struct *work)
-{
- struct aw88399 *aw88399 =
- container_of(work, struct aw88399, start_work.work);
-
- mutex_lock(&aw88399->lock);
- aw88399_start_pa(aw88399);
- mutex_unlock(&aw88399->lock);
-}
-
-static void aw88399_start(struct aw88399 *aw88399, bool sync_start)
-{
- int ret;
-
- if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK)
- return;
-
- if (aw88399->aw_pa->status == AW88399_DEV_PW_ON)
- return;
-
- ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "fw update failed.");
- return;
- }
-
- if (sync_start == AW88399_SYNC_START)
- aw88399_start_pa(aw88399);
- else
- queue_delayed_work(system_dfl_wq,
- &aw88399->start_work,
- AW88399_START_WORK_DELAY_MS);
-}
-
-static int aw_dev_check_sysint(struct aw_device *aw_dev)
-{
- u16 reg_val;
-
- aw_dev_get_int_status(aw_dev, &reg_val);
- if (reg_val & AW88399_BIT_SYSINT_CHECK) {
- dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int aw88399_stop(struct aw_device *aw_dev)
-{
- struct aw_sec_data_desc *dsp_cfg =
- &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG];
- struct aw_sec_data_desc *dsp_fw =
- &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW];
- int int_st;
-
- if (aw_dev->status == AW88399_DEV_PW_OFF) {
- dev_dbg(aw_dev->dev, "already power off");
- return 0;
- }
-
- aw_dev->status = AW88399_DEV_PW_OFF;
-
- aw88399_dev_mute(aw_dev, true);
- usleep_range(AW88399_4000_US, AW88399_4000_US + 100);
-
- aw_dev_i2s_tx_enable(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
-
- int_st = aw_dev_check_sysint(aw_dev);
-
- aw_dev_dsp_enable(aw_dev, false);
-
- aw_dev_amppd(aw_dev, true);
-
- if (int_st) {
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
- aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len);
- aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len);
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
- }
-
- aw_dev_pwd(aw_dev, true);
-
- return 0;
-}
-
static struct snd_soc_dai_driver aw88399_dai[] = {
{
.name = "aw88399-aif",
@@ -1869,86 +664,6 @@ static int aw88399_calib_set(struct snd_kcontrol *kcontrol,
return 0;
}
-static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- int ret;
-
- ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
- if (ret) {
- dev_err(aw_dev->dev, "aw_dev acf parse failed");
- return -EINVAL;
- }
- aw_dev->fade_in_time = AW88399_1000_US / 10;
- aw_dev->fade_out_time = AW88399_1000_US >> 1;
- aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id;
- aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id;
-
- ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON);
- if (ret) {
- dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
- return ret;
- }
-
- aw88399_dev_mute(aw_dev, true);
-
- /* close tx feedback */
- aw_dev_i2s_tx_enable(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
-
- /* enable amppd */
- aw_dev_amppd(aw_dev, true);
-
- /* close dsp */
- aw_dev_dsp_enable(aw_dev, false);
- /* set power down */
- aw_dev_pwd(aw_dev, true);
-
- return 0;
-}
-
-static int aw88399_request_firmware_file(struct aw88399 *aw88399)
-{
- const struct firmware *cont = NULL;
- int ret;
-
- aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED;
-
- ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE);
- return ret;
- }
-
- dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n",
- AW88399_ACF_FILE, cont ? cont->size : 0);
-
- aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev,
- struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw88399->aw_cfg) {
- release_firmware(cont);
- return -ENOMEM;
- }
- aw88399->aw_cfg->len = (int)cont->size;
- memcpy(aw88399->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
-
- ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE);
- return ret;
- }
-
- mutex_lock(&aw88399->lock);
- /* aw device init */
- ret = aw88399_dev_init(aw88399, aw88399->aw_cfg);
- if (ret)
- dev_err(aw88399->aw_pa->dev, "dev init failed");
- mutex_unlock(&aw88399->lock);
-
- return ret;
-}
-
static const struct snd_kcontrol_new aw88399_controls[] = {
SOC_SINGLE_EXT("PCM Playback Volume", AW88399_SYSCTRL2_REG,
6, AW88399_MUTE_VOL, 0, aw88399_volume_get,
@@ -2040,70 +755,6 @@ static const struct snd_soc_component_driver soc_codec_dev_aw88399 = {
.num_controls = ARRAY_SIZE(aw88399_controls),
};
-static void aw88399_hw_reset(struct aw88399 *aw88399)
-{
- if (aw88399->reset_gpio) {
- gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- gpiod_set_value_cansleep(aw88399->reset_gpio, 0);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- }
-}
-
-static void aw88399_parse_channel_dt(struct aw_device *aw_dev)
-{
- struct device_node *np = aw_dev->dev->of_node;
- u32 channel_value;
-
- of_property_read_u32(np, "awinic,audio-channel", &channel_value);
- aw_dev->channel = channel_value;
-}
-
-static int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap)
-{
- struct aw_device *aw_dev;
- unsigned int chip_id;
- int ret;
-
- ret = regmap_read(regmap, AW88399_ID_REG, &chip_id);
- if (ret) {
- dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
- return ret;
- }
- if (chip_id != AW88399_CHIP_ID) {
- dev_err(&i2c->dev, "unsupported device");
- return -ENXIO;
- }
- dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
-
- aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
- if (!aw_dev)
- return -ENOMEM;
- aw88399->aw_pa = aw_dev;
-
- aw_dev->i2c = i2c;
- aw_dev->dev = &i2c->dev;
- aw_dev->regmap = regmap;
- mutex_init(&aw_dev->dsp_lock);
-
- aw_dev->chip_id = chip_id;
- aw_dev->acf = NULL;
- aw_dev->prof_info.prof_desc = NULL;
- aw_dev->prof_info.count = 0;
- aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
- aw_dev->channel = AW88399_DEV_DEFAULT_CH;
- aw_dev->fw_status = AW88399_DEV_FW_FAILED;
-
- aw_dev->fade_step = AW88399_VOLUME_STEP_DB;
- aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE;
-
- aw88399_parse_channel_dt(aw_dev);
-
- return 0;
-}
-
static int aw88399_i2c_probe(struct i2c_client *i2c)
{
struct aw88399 *aw88399;
diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h
--- a/sound/soc/codecs/aw88399.h
+++ b/sound/soc/codecs/aw88399.h
@@ -10,512 +10,10 @@
#ifndef __AW88399_H__
#define __AW88399_H__
-/* registers list */
-#define AW88399_ID_REG (0x00)
-#define AW88399_SYSST_REG (0x01)
-#define AW88399_SYSINT_REG (0x02)
-#define AW88399_SYSINTM_REG (0x03)
-#define AW88399_SYSCTRL_REG (0x04)
-#define AW88399_SYSCTRL2_REG (0x05)
-#define AW88399_I2SCTRL1_REG (0x06)
-#define AW88399_I2SCTRL2_REG (0x07)
-#define AW88399_I2SCTRL3_REG (0x08)
-#define AW88399_DACCFG1_REG (0x09)
-#define AW88399_DACCFG2_REG (0x0A)
-#define AW88399_DACCFG3_REG (0x0B)
-#define AW88399_DACCFG4_REG (0x0C)
-#define AW88399_DACCFG5_REG (0x0D)
-#define AW88399_DACCFG6_REG (0x0E)
-#define AW88399_DACCFG7_REG (0x0F)
-#define AW88399_MPDCFG1_REG (0x10)
-#define AW88399_MPDCFG2_REG (0x11)
-#define AW88399_MPDCFG3_REG (0x12)
-#define AW88399_MPDCFG4_REG (0x13)
-#define AW88399_PWMCTRL1_REG (0x14)
-#define AW88399_PWMCTRL2_REG (0x15)
-#define AW88399_PWMCTRL3_REG (0x16)
-#define AW88399_I2SCFG1_REG (0x17)
-#define AW88399_DBGCTRL_REG (0x18)
-#define AW88399_HAGCST_REG (0x20)
-#define AW88399_VBAT_REG (0x21)
-#define AW88399_TEMP_REG (0x22)
-#define AW88399_PVDD_REG (0x23)
-#define AW88399_ISNDAT_REG (0x24)
-#define AW88399_VSNDAT_REG (0x25)
-#define AW88399_I2SINT_REG (0x26)
-#define AW88399_I2SCAPCNT_REG (0x27)
-#define AW88399_ANASTA1_REG (0x28)
-#define AW88399_ANASTA2_REG (0x29)
-#define AW88399_ANASTA3_REG (0x2A)
-#define AW88399_TESTDET_REG (0x2B)
-#define AW88399_DSMCFG1_REG (0x30)
-#define AW88399_DSMCFG2_REG (0x31)
-#define AW88399_DSMCFG3_REG (0x32)
-#define AW88399_DSMCFG4_REG (0x33)
-#define AW88399_DSMCFG5_REG (0x34)
-#define AW88399_DSMCFG6_REG (0x35)
-#define AW88399_DSMCFG7_REG (0x36)
-#define AW88399_DSMCFG8_REG (0x37)
-#define AW88399_TESTIN_REG (0x38)
-#define AW88399_TESTOUT_REG (0x39)
-#define AW88399_MEMTEST_REG (0x3A)
-#define AW88399_VSNCTRL1_REG (0x3B)
-#define AW88399_ISNCTRL1_REG (0x3C)
-#define AW88399_ISNCTRL2_REG (0x3D)
-#define AW88399_DSPMADD_REG (0x40)
-#define AW88399_DSPMDAT_REG (0x41)
-#define AW88399_WDT_REG (0x42)
-#define AW88399_ACR1_REG (0x43)
-#define AW88399_ACR2_REG (0x44)
-#define AW88399_ASR1_REG (0x45)
-#define AW88399_ASR2_REG (0x46)
-#define AW88399_DSPCFG_REG (0x47)
-#define AW88399_ASR3_REG (0x48)
-#define AW88399_ASR4_REG (0x49)
-#define AW88399_DSPVCALB_REG (0x4A)
-#define AW88399_CRCCTRL_REG (0x4B)
-#define AW88399_DSPDBG1_REG (0x4C)
-#define AW88399_DSPDBG2_REG (0x4D)
-#define AW88399_DSPDBG3_REG (0x4E)
-#define AW88399_PLLCTRL1_REG (0x50)
-#define AW88399_PLLCTRL2_REG (0x51)
-#define AW88399_PLLCTRL3_REG (0x52)
-#define AW88399_CDACTRL1_REG (0x53)
-#define AW88399_CDACTRL2_REG (0x54)
-#define AW88399_CDACTRL3_REG (0x55)
-#define AW88399_SADCCTRL1_REG (0x56)
-#define AW88399_SADCCTRL2_REG (0x57)
-#define AW88399_BOPCTRL1_REG (0x58)
-#define AW88399_BOPCTRL2_REG (0x5A)
-#define AW88399_BOPCTRL3_REG (0x5B)
-#define AW88399_BOPCTRL4_REG (0x5C)
-#define AW88399_BOPCTRL5_REG (0x5D)
-#define AW88399_BOPCTRL6_REG (0x5E)
-#define AW88399_BOPCTRL7_REG (0x5F)
-#define AW88399_BSTCTRL1_REG (0x60)
-#define AW88399_BSTCTRL2_REG (0x61)
-#define AW88399_BSTCTRL3_REG (0x62)
-#define AW88399_BSTCTRL4_REG (0x63)
-#define AW88399_BSTCTRL5_REG (0x64)
-#define AW88399_BSTCTRL6_REG (0x65)
-#define AW88399_BSTCTRL7_REG (0x66)
-#define AW88399_BSTCTRL8_REG (0x67)
-#define AW88399_BSTCTRL9_REG (0x68)
-#define AW88399_BSTCTRL10_REG (0x69)
-#define AW88399_CPCTRL_REG (0x6A)
-#define AW88399_EFWH_REG (0x6C)
-#define AW88399_EFWM2_REG (0x6D)
-#define AW88399_EFWM1_REG (0x6E)
-#define AW88399_EFWL_REG (0x6F)
-#define AW88399_TESTCTRL1_REG (0x70)
-#define AW88399_TESTCTRL2_REG (0x71)
-#define AW88399_EFCTRL1_REG (0x72)
-#define AW88399_EFCTRL2_REG (0x73)
-#define AW88399_EFRH4_REG (0x74)
-#define AW88399_EFRH3_REG (0x75)
-#define AW88399_EFRH2_REG (0x76)
-#define AW88399_EFRH1_REG (0x77)
-#define AW88399_EFRL4_REG (0x78)
-#define AW88399_EFRL3_REG (0x79)
-#define AW88399_EFRL2_REG (0x7A)
-#define AW88399_EFRL1_REG (0x7B)
-#define AW88399_TM_REG (0x7C)
-#define AW88399_TM2_REG (0x7D)
-
-#define AW88399_REG_MAX (0x7E)
-#define AW88399_MUTE_VOL (1023)
-
-#define AW88399_DSP_CFG_ADDR (0x9B00)
-#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68)
-#define AW88399_DSP_FW_ADDR (0x8980)
-#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40)
-#define AW88399_DSP_ROM_CHECK_DATA (0x4638)
-
-#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000))
-#define AW88399_CALI_RE_HBITS_SHIFT (16)
-
-#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF))
-#define AW88399_CALI_RE_LBITS_SHIFT (0)
-
-#define AW88399_I2STXEN_START_BIT (9)
-#define AW88399_I2STXEN_BITS_LEN (1)
-#define AW88399_I2STXEN_MASK \
- (~(((1<<AW88399_I2STXEN_BITS_LEN)-1) << AW88399_I2STXEN_START_BIT))
-
-#define AW88399_I2STXEN_DISABLE (0)
-#define AW88399_I2STXEN_DISABLE_VALUE \
- (AW88399_I2STXEN_DISABLE << AW88399_I2STXEN_START_BIT)
-
-#define AW88399_I2STXEN_ENABLE (1)
-#define AW88399_I2STXEN_ENABLE_VALUE \
- (AW88399_I2STXEN_ENABLE << AW88399_I2STXEN_START_BIT)
-
-#define AW88399_VOL_START_BIT (0)
-#define AW88399_VOL_BITS_LEN (10)
-#define AW88399_VOL_MASK \
- (~(((1<<AW88399_VOL_BITS_LEN)-1) << AW88399_VOL_START_BIT))
-
-#define AW88399_PWDN_START_BIT (0)
-#define AW88399_PWDN_BITS_LEN (1)
-#define AW88399_PWDN_MASK \
- (~(((1<<AW88399_PWDN_BITS_LEN)-1) << AW88399_PWDN_START_BIT))
-
-#define AW88399_PWDN_POWER_DOWN (1)
-#define AW88399_PWDN_POWER_DOWN_VALUE \
- (AW88399_PWDN_POWER_DOWN << AW88399_PWDN_START_BIT)
-
-#define AW88399_PWDN_WORKING (0)
-#define AW88399_PWDN_WORKING_VALUE \
- (AW88399_PWDN_WORKING << AW88399_PWDN_START_BIT)
-
-#define AW88399_DSPBY_START_BIT (2)
-#define AW88399_DSPBY_BITS_LEN (1)
-#define AW88399_DSPBY_MASK \
- (~(((1<<AW88399_DSPBY_BITS_LEN)-1) << AW88399_DSPBY_START_BIT))
-
-#define AW88399_DSPBY_WORKING (0)
-#define AW88399_DSPBY_WORKING_VALUE \
- (AW88399_DSPBY_WORKING << AW88399_DSPBY_START_BIT)
-
-#define AW88399_DSPBY_BYPASS (1)
-#define AW88399_DSPBY_BYPASS_VALUE \
- (AW88399_DSPBY_BYPASS << AW88399_DSPBY_START_BIT)
-
-#define AW88399_MEM_CLKSEL_START_BIT (3)
-#define AW88399_MEM_CLKSEL_BITS_LEN (1)
-#define AW88399_MEM_CLKSEL_MASK \
- (~(((1<<AW88399_MEM_CLKSEL_BITS_LEN)-1) << AW88399_MEM_CLKSEL_START_BIT))
-
-#define AW88399_MEM_CLKSEL_OSCCLK (0)
-#define AW88399_MEM_CLKSEL_OSCCLK_VALUE \
- (AW88399_MEM_CLKSEL_OSCCLK << AW88399_MEM_CLKSEL_START_BIT)
-
-#define AW88399_MEM_CLKSEL_DAPHCLK (1)
-#define AW88399_MEM_CLKSEL_DAPHCLK_VALUE \
- (AW88399_MEM_CLKSEL_DAPHCLK << AW88399_MEM_CLKSEL_START_BIT)
-
-#define AW88399_DITHER_EN_START_BIT (15)
-#define AW88399_DITHER_EN_BITS_LEN (1)
-#define AW88399_DITHER_EN_MASK \
- (~(((1<<AW88399_DITHER_EN_BITS_LEN)-1) << AW88399_DITHER_EN_START_BIT))
-
-#define AW88399_DITHER_EN_DISABLE (0)
-#define AW88399_DITHER_EN_DISABLE_VALUE \
- (AW88399_DITHER_EN_DISABLE << AW88399_DITHER_EN_START_BIT)
-
-#define AW88399_DITHER_EN_ENABLE (1)
-#define AW88399_DITHER_EN_ENABLE_VALUE \
- (AW88399_DITHER_EN_ENABLE << AW88399_DITHER_EN_START_BIT)
-
-#define AW88399_HMUTE_START_BIT (8)
-#define AW88399_HMUTE_BITS_LEN (1)
-#define AW88399_HMUTE_MASK \
- (~(((1<<AW88399_HMUTE_BITS_LEN)-1) << AW88399_HMUTE_START_BIT))
-
-#define AW88399_HMUTE_DISABLE (0)
-#define AW88399_HMUTE_DISABLE_VALUE \
- (AW88399_HMUTE_DISABLE << AW88399_HMUTE_START_BIT)
-
-#define AW88399_HMUTE_ENABLE (1)
-#define AW88399_HMUTE_ENABLE_VALUE \
- (AW88399_HMUTE_ENABLE << AW88399_HMUTE_START_BIT)
-
-#define AW88399_EF_DBMD_START_BIT (2)
-#define AW88399_EF_DBMD_BITS_LEN (1)
-#define AW88399_EF_DBMD_MASK \
- (~(((1<<AW88399_EF_DBMD_BITS_LEN)-1) << AW88399_EF_DBMD_START_BIT))
-
-#define AW88399_EF_DBMD_OR (1)
-#define AW88399_EF_DBMD_OR_VALUE \
- (AW88399_EF_DBMD_OR << AW88399_EF_DBMD_START_BIT)
-
-#define AW88399_VDSEL_START_BIT (5)
-#define AW88399_VDSEL_BITS_LEN (1)
-#define AW88399_VDSEL_MASK \
- (~(((1<<AW88399_VDSEL_BITS_LEN)-1) << AW88399_VDSEL_START_BIT))
-
-#define AW88399_EF_ISN_GESLP_H_START_BIT (0)
-#define AW88399_EF_ISN_GESLP_H_BITS_LEN (10)
-#define AW88399_EF_ISN_GESLP_H_MASK \
- (~(((1<<AW88399_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_H_START_BIT))
-
-/* EF_VSN_GESLP_H bit 9:0 (EFRH3 0x75) */
-#define AW88399_EF_VSN_GESLP_H_START_BIT (0)
-#define AW88399_EF_VSN_GESLP_H_BITS_LEN (10)
-#define AW88399_EF_VSN_GESLP_H_MASK \
- (~(((1<<AW88399_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_H_START_BIT))
-
-#define AW88399_EF_ISN_GESLP_L_START_BIT (0)
-#define AW88399_EF_ISN_GESLP_L_BITS_LEN (10)
-#define AW88399_EF_ISN_GESLP_L_MASK \
- (~(((1<<AW88399_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_L_START_BIT))
-
-/* EF_VSN_GESLP_L bit 9:0 (EFRL3 0x79) */
-#define AW88399_EF_VSN_GESLP_L_START_BIT (0)
-#define AW88399_EF_VSN_GESLP_L_BITS_LEN (10)
-#define AW88399_EF_VSN_GESLP_L_MASK \
- (~(((1<<AW88399_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_L_START_BIT))
-
-#define AW88399_INTERNAL_VSN_TRIM_H_START_BIT (9)
-#define AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN (6)
-#define AW88399_INTERNAL_VSN_TRIM_H_MASK \
- (~(((1<<AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_H_START_BIT))
-
-#define AW88399_INTERNAL_VSN_TRIM_L_START_BIT (9)
-#define AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN (6)
-#define AW88399_INTERNAL_VSN_TRIM_L_MASK \
- (~(((1<<AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_L_START_BIT))
-
-#define AW88399_RCV_MODE_START_BIT (7)
-#define AW88399_RCV_MODE_BITS_LEN (1)
-#define AW88399_RCV_MODE_MASK \
- (~(((1<<AW88399_RCV_MODE_BITS_LEN)-1) << AW88399_RCV_MODE_START_BIT))
-
-#define AW88399_CLKI_START_BIT (4)
-#define AW88399_NOCLKI_START_BIT (5)
-#define AW88399_PLLI_START_BIT (0)
-#define AW88399_PLLI_INT_VALUE (1)
-#define AW88399_PLLI_INT_INTERRUPT \
- (AW88399_PLLI_INT_VALUE << AW88399_PLLI_START_BIT)
-
-#define AW88399_CLKI_INT_VALUE (1)
-#define AW88399_CLKI_INT_INTERRUPT \
- (AW88399_CLKI_INT_VALUE << AW88399_CLKI_START_BIT)
-
-#define AW88399_NOCLKI_INT_VALUE (1)
-#define AW88399_NOCLKI_INT_INTERRUPT \
- (AW88399_NOCLKI_INT_VALUE << AW88399_NOCLKI_START_BIT)
-
-#define AW88399_BIT_SYSINT_CHECK \
- (AW88399_PLLI_INT_INTERRUPT | \
- AW88399_CLKI_INT_INTERRUPT | \
- AW88399_NOCLKI_INT_INTERRUPT)
-
-#define AW88399_CRC_CHECK_START_BIT (12)
-#define AW88399_CRC_CHECK_BITS_LEN (3)
-#define AW88399_CRC_CHECK_BITS_MASK \
- (~(((1<<AW88399_CRC_CHECK_BITS_LEN)-1) << AW88399_CRC_CHECK_START_BIT))
-
-#define AW88399_RCV_MODE_RECEIVER (1)
-#define AW88399_RCV_MODE_RECEIVER_VALUE \
- (AW88399_RCV_MODE_RECEIVER << AW88399_RCV_MODE_START_BIT)
-
-#define AW88399_AMPPD_START_BIT (1)
-#define AW88399_AMPPD_BITS_LEN (1)
-#define AW88399_AMPPD_MASK \
- (~(((1<<AW88399_AMPPD_BITS_LEN)-1) << AW88399_AMPPD_START_BIT))
-
-#define AW88399_AMPPD_WORKING (0)
-#define AW88399_AMPPD_WORKING_VALUE \
- (AW88399_AMPPD_WORKING << AW88399_AMPPD_START_BIT)
-
-#define AW88399_AMPPD_POWER_DOWN (1)
-#define AW88399_AMPPD_POWER_DOWN_VALUE \
- (AW88399_AMPPD_POWER_DOWN << AW88399_AMPPD_START_BIT)
-
-#define AW88399_RAM_CG_BYP_START_BIT (0)
-#define AW88399_RAM_CG_BYP_BITS_LEN (1)
-#define AW88399_RAM_CG_BYP_MASK \
- (~(((1<<AW88399_RAM_CG_BYP_BITS_LEN)-1) << AW88399_RAM_CG_BYP_START_BIT))
-
-#define AW88399_RAM_CG_BYP_WORK (0)
-#define AW88399_RAM_CG_BYP_WORK_VALUE \
- (AW88399_RAM_CG_BYP_WORK << AW88399_RAM_CG_BYP_START_BIT)
-
-#define AW88399_RAM_CG_BYP_BYPASS (1)
-#define AW88399_RAM_CG_BYP_BYPASS_VALUE \
- (AW88399_RAM_CG_BYP_BYPASS << AW88399_RAM_CG_BYP_START_BIT)
-
-#define AW88399_CRC_END_ADDR_START_BIT (0)
-#define AW88399_CRC_END_ADDR_BITS_LEN (12)
-#define AW88399_CRC_END_ADDR_MASK \
- (~(((1<<AW88399_CRC_END_ADDR_BITS_LEN)-1) << AW88399_CRC_END_ADDR_START_BIT))
-
-#define AW88399_CRC_CODE_EN_START_BIT (13)
-#define AW88399_CRC_CODE_EN_BITS_LEN (1)
-#define AW88399_CRC_CODE_EN_MASK \
- (~(((1<<AW88399_CRC_CODE_EN_BITS_LEN)-1) << AW88399_CRC_CODE_EN_START_BIT))
-
-#define AW88399_CRC_CODE_EN_DISABLE (0)
-#define AW88399_CRC_CODE_EN_DISABLE_VALUE \
- (AW88399_CRC_CODE_EN_DISABLE << AW88399_CRC_CODE_EN_START_BIT)
-
-#define AW88399_CRC_CODE_EN_ENABLE (1)
-#define AW88399_CRC_CODE_EN_ENABLE_VALUE \
- (AW88399_CRC_CODE_EN_ENABLE << AW88399_CRC_CODE_EN_START_BIT)
-
-#define AW88399_CRC_CFG_EN_START_BIT (12)
-#define AW88399_CRC_CFG_EN_BITS_LEN (1)
-#define AW88399_CRC_CFG_EN_MASK \
- (~(((1<<AW88399_CRC_CFG_EN_BITS_LEN)-1) << AW88399_CRC_CFG_EN_START_BIT))
-
-#define AW88399_CRC_CFG_EN_DISABLE (0)
-#define AW88399_CRC_CFG_EN_DISABLE_VALUE \
- (AW88399_CRC_CFG_EN_DISABLE << AW88399_CRC_CFG_EN_START_BIT)
-
-#define AW88399_CRC_CFG_EN_ENABLE (1)
-#define AW88399_CRC_CFG_EN_ENABLE_VALUE \
- (AW88399_CRC_CFG_EN_ENABLE << AW88399_CRC_CFG_EN_START_BIT)
-
-#define AW88399_OCDS_START_BIT (3)
-#define AW88399_OCDS_OC (1)
-#define AW88399_OCDS_OC_VALUE \
- (AW88399_OCDS_OC << AW88399_OCDS_START_BIT)
-
-#define AW88399_NOCLKS_START_BIT (5)
-#define AW88399_NOCLKS_NO_CLOCK (1)
-#define AW88399_NOCLKS_NO_CLOCK_VALUE \
- (AW88399_NOCLKS_NO_CLOCK << AW88399_NOCLKS_START_BIT)
-
-#define AW88399_SWS_START_BIT (8)
-#define AW88399_SWS_SWITCHING (1)
-#define AW88399_SWS_SWITCHING_VALUE \
- (AW88399_SWS_SWITCHING << AW88399_SWS_START_BIT)
-
-#define AW88399_BSTS_START_BIT (9)
-#define AW88399_BSTS_FINISHED (1)
-#define AW88399_BSTS_FINISHED_VALUE \
- (AW88399_BSTS_FINISHED << AW88399_BSTS_START_BIT)
-
-#define AW88399_UVLS_START_BIT (14)
-#define AW88399_UVLS_NORMAL (0)
-#define AW88399_UVLS_NORMAL_VALUE \
- (AW88399_UVLS_NORMAL << AW88399_UVLS_START_BIT)
-
-#define AW88399_BSTOCS_START_BIT (11)
-#define AW88399_BSTOCS_OVER_CURRENT (1)
-#define AW88399_BSTOCS_OVER_CURRENT_VALUE \
- (AW88399_BSTOCS_OVER_CURRENT << AW88399_BSTOCS_START_BIT)
-
-#define AW88399_OTHS_START_BIT (1)
-#define AW88399_OTHS_OT (1)
-#define AW88399_OTHS_OT_VALUE \
- (AW88399_OTHS_OT << AW88399_OTHS_START_BIT)
-
-#define AW88399_PLLS_START_BIT (0)
-#define AW88399_PLLS_LOCKED (1)
-#define AW88399_PLLS_LOCKED_VALUE \
- (AW88399_PLLS_LOCKED << AW88399_PLLS_START_BIT)
-
-#define AW88399_CLKS_START_BIT (4)
-#define AW88399_CLKS_STABLE (1)
-#define AW88399_CLKS_STABLE_VALUE \
- (AW88399_CLKS_STABLE << AW88399_CLKS_START_BIT)
-
-#define AW88399_BIT_PLL_CHECK \
- (AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE)
-
-#define AW88399_BIT_SYSST_CHECK_MASK \
- (~(AW88399_UVLS_NORMAL_VALUE | \
- AW88399_BSTOCS_OVER_CURRENT_VALUE | \
- AW88399_BSTS_FINISHED_VALUE | \
- AW88399_SWS_SWITCHING_VALUE | \
- AW88399_NOCLKS_NO_CLOCK_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_OCDS_OC_VALUE | \
- AW88399_OTHS_OT_VALUE | \
- AW88399_PLLS_LOCKED_VALUE))
-
-#define AW88399_BIT_SYSST_NOSWS_CHECK \
- (AW88399_BSTS_FINISHED_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE)
-
-#define AW88399_BIT_SYSST_SWS_CHECK \
- (AW88399_BSTS_FINISHED_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE | \
- AW88399_SWS_SWITCHING_VALUE)
-
-#define AW88399_CCO_MUX_START_BIT (14)
-#define AW88399_CCO_MUX_BITS_LEN (1)
-#define AW88399_CCO_MUX_MASK \
- (~(((1<<AW88399_CCO_MUX_BITS_LEN)-1) << AW88399_CCO_MUX_START_BIT))
-
-#define AW88399_CCO_MUX_DIVIDED (0)
-#define AW88399_CCO_MUX_DIVIDED_VALUE \
- (AW88399_CCO_MUX_DIVIDED << AW88399_CCO_MUX_START_BIT)
-
-#define AW88399_CCO_MUX_BYPASS (1)
-#define AW88399_CCO_MUX_BYPASS_VALUE \
- (AW88399_CCO_MUX_BYPASS << AW88399_CCO_MUX_START_BIT)
-
-#define AW88399_NOISE_GATE_EN_START_BIT (13)
-#define AW88399_NOISE_GATE_EN_BITS_LEN (1)
-#define AW88399_NOISE_GATE_EN_MASK \
- (~(((1<<AW88399_NOISE_GATE_EN_BITS_LEN)-1) << AW88399_NOISE_GATE_EN_START_BIT))
-
-#define AW88399_WDT_CNT_START_BIT (0)
-#define AW88399_WDT_CNT_BITS_LEN (8)
-#define AW88399_WDT_CNT_MASK \
- (~(((1<<AW88399_WDT_CNT_BITS_LEN)-1) << AW88399_WDT_CNT_START_BIT))
-
-#define AW88399_REABS_START_BIT (3)
-#define AW88399_REABS_BITS_LEN (1)
-#define AW88399_REABS_MASK \
- (~(((1<<AW88399_REABS_BITS_LEN)-1) << AW88399_REABS_START_BIT))
-
-#define AW88399_DSP_VOL_START_BIT (8)
-#define AW88399_DSP_VOL_BITS_LEN (8)
-#define AW88399_DSP_VOL_MASK \
- (~(((1<<AW88399_DSP_VOL_BITS_LEN)-1) << AW88399_DSP_VOL_START_BIT))
-
-#define AW883XX_DSP_NG_EN_START (13)
-#define AW883XX_DSP_NG_EN_LEN (1)
-#define AW883XX_DSP_NG_EN_MASK \
- (~(((1 << AW883XX_DSP_NG_EN_LEN) - 1) << AW883XX_DSP_NG_EN_START))
-#define AW883XX_DSP_NG_EN_DISABLE (0)
-#define AW883XX_DSP_NG_EN_DISABLE_VALUE \
- (AW883XX_DSP_NG_EN_DISABLE << AW883XX_DSP_NG_EN_START)
-
-#define AW88399_VOLUME_STEP_DB (64)
-#define AW88399_VOL_DEFAULT_VALUE (0)
-#define AW88399_DSP_ODD_NUM_BIT_TEST (0x5555)
-#define AW88399_EF_ISN_GESLP_SIGN_MASK (~(1 << 9))
-#define AW88399_EF_ISN_GESLP_SIGN_NEG (0xfe00)
-
-#define AW88399_EF_VSN_GESLP_SIGN_MASK (~(1 << 9))
-#define AW88399_EF_VSN_GESLP_SIGN_NEG (0xfe00)
-
-#define AW88399_TEM4_SIGN_MASK (~(1 << 5))
-#define AW88399_TEM4_SIGN_NEG (0xffc0)
-
-#define AW88399_ICABLK_FACTOR (1)
-#define AW88399_VCABLK_FACTOR (1)
-#define AW88399_VCABLK_DAC_FACTOR (2)
-
-#define AW88399_VCALB_ADJ_FACTOR (12)
-#define AW88399_VCALB_ACCURACY (1 << 12)
-
-#define AW88399_ISCAL_FACTOR (3125)
-#define AW88399_VSCAL_FACTOR (18875)
-#define AW88399_ISCAL_DAC_FACTOR (3125)
-#define AW88399_VSCAL_DAC_FACTOR (12600)
-#define AW88399_CABL_BASE_VALUE (1000)
-
-#define AW88399_DEV_DEFAULT_CH (0)
-#define AW88399_DEV_DSP_CHECK_MAX (5)
-#define AW88399_MAX_RAM_WRITE_BYTE_SIZE (128)
-#define AW88399_DSP_RE_SHIFT (12)
-#define AW88399_CALI_RE_MAX (15000)
-#define AW88399_CALI_RE_MIN (4000)
-#define AW_FW_ADDR_LEN (4)
-#define AW88399_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
-#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
-#define AW88399_CRC_CHECK_PASS_VAL (0x4)
-
-#define AW88399_CRC_CFG_BASE_ADDR (0xD80)
-#define AW88399_CRC_FW_BASE_ADDR (0x4C0)
-#define AW88399_ACF_FILE "aw88399_acf.bin"
-#define AW88399_DEV_SYSST_CHECK_MAX (10)
-#define AW88399_CHIP_ID 0x2183
+#include <sound/aw88399.h>
#define AW88399_I2C_NAME "aw88399"
-#define AW88399_START_RETRIES (5)
-#define AW88399_START_WORK_DELAY_MS (0)
-
#define AW88399_RATES (SNDRV_PCM_RATE_8000_48000 | \
SNDRV_PCM_RATE_96000)
#define AW88399_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -550,80 +48,4 @@
.put = profile_set, \
}
-enum {
- AW_EF_AND_CHECK = 0,
- AW_EF_OR_CHECK,
-};
-
-enum {
- AW88399_DEV_VDSEL_DAC = 0,
- AW88399_DEV_VDSEL_VSENSE = 32,
-};
-
-enum {
- AW88399_DSP_CRC_NA = 0,
- AW88399_DSP_CRC_OK = 1,
-};
-
-enum {
- AW88399_DSP_FW_UPDATE_OFF = 0,
- AW88399_DSP_FW_UPDATE_ON = 1,
-};
-
-enum {
- AW88399_FORCE_UPDATE_OFF = 0,
- AW88399_FORCE_UPDATE_ON = 1,
-};
-
-enum {
- AW88399_1000_US = 1000,
- AW88399_2000_US = 2000,
- AW88399_3000_US = 3000,
- AW88399_4000_US = 4000,
-};
-
-enum AW88399_DEV_STATUS {
- AW88399_DEV_PW_OFF = 0,
- AW88399_DEV_PW_ON,
-};
-
-enum AW88399_DEV_FW_STATUS {
- AW88399_DEV_FW_FAILED = 0,
- AW88399_DEV_FW_OK,
-};
-
-enum AW88399_DEV_MEMCLK {
- AW88399_DEV_MEMCLK_OSC = 0,
- AW88399_DEV_MEMCLK_PLL = 1,
-};
-
-enum AW88399_DEV_DSP_CFG {
- AW88399_DEV_DSP_WORK = 0,
- AW88399_DEV_DSP_BYPASS = 1,
-};
-
-enum {
- AW88399_NOT_RCV_MODE = 0,
- AW88399_RCV_MODE = 1,
-};
-
-enum {
- AW88399_SYNC_START = 0,
- AW88399_ASYNC_START,
-};
-
-struct aw88399 {
- struct aw_device *aw_pa;
- struct mutex lock;
- struct gpio_desc *reset_gpio;
- struct delayed_work start_work;
- struct regmap *regmap;
- struct aw_container *aw_cfg;
-
- unsigned int check_val;
- unsigned int crc_init_val;
- unsigned int vcalb_init_val;
- unsigned int dither_st;
-};
-
-#endif
+#endif /* __AW88399_H__ */
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -1849,16 +1849,26 @@ static int tasdev_load_blk(struct tasdevice_priv *tas_priv,
}
}
if (ret == -EAGAIN) {
- if (block->nr_retry > 0)
+ if (block->nr_retry > 0) {
+ /* Give the hardware time to stabilize before
+ * next block re-transmission attempt.
+ */
+ usleep_range(2000, 2500);
continue;
+ }
} else if (ret < 0) /*err in current device, skip it*/
break;
if (block->is_pchksum_present) {
ret = tasdev_block_chksum(tas_priv, block, chn);
if (ret == -EAGAIN) {
- if (block->nr_retry > 0)
+ if (block->nr_retry > 0) {
+ /* Give the bus time to recover after
+ * a checksum mismatch error.
+ */
+ usleep_range(2000, 2500);
continue;
+ }
} else if (ret < 0) /*err in current device, skip it*/
break;
}
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -1118,7 +1118,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt);
- priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
+ priv->asrc_format = asrc_fmt;
if (ret) {
/* Fallback to old binding; translate to asrc_format */
ret = of_property_read_u32(asrc_np, "fsl,asrc-width",
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -1358,7 +1358,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
}
ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt);
- asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
+ asrc->asrc_format = asrc_fmt;
if (ret) {
ret = of_property_read_u32(np, "fsl,asrc-width", &width);
if (ret) {
diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c
--- a/sound/soc/fsl/fsl_asrc_m2m.c
+++ b/sound/soc/fsl/fsl_asrc_m2m.c
@@ -367,13 +367,13 @@ static int fsl_asrc_m2m_comp_set_params(struct snd_compr_stream *stream,
if (ret)
return -EINVAL;
- if (pcm_format_to_bits((__force snd_pcm_format_t)params->codec.format) & cap.fmt_in)
- pair->sample_format[IN] = (__force snd_pcm_format_t)params->codec.format;
+ if (pcm_format_to_bits(params->codec.format) & cap.fmt_in)
+ pair->sample_format[IN] = params->codec.format;
else
return -EINVAL;
- if (pcm_format_to_bits((__force snd_pcm_format_t)params->codec.pcm_format) & cap.fmt_out)
- pair->sample_format[OUT] = (__force snd_pcm_format_t)params->codec.pcm_format;
+ if (pcm_format_to_bits(params->codec.pcm_format) & cap.fmt_out)
+ pair->sample_format[OUT] = params->codec.pcm_format;
else
return -EINVAL;
@@ -600,7 +600,7 @@ static int fsl_asrc_m2m_fill_codec_caps(struct fsl_asrc *asrc,
cap.rate_in,
cap.rate_in_count * sizeof(__u32));
codec->descriptor[j].num_sample_rates = cap.rate_in_count;
- codec->descriptor[j].formats = (__force __u32)k;
+ codec->descriptor[j].formats = k;
codec->descriptor[j].pcm_formats = cap.fmt_out;
codec->descriptor[j].src.out_sample_rate_min = cap.rate_out[0];
codec->descriptor[j].src.out_sample_rate_max =
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -2227,7 +2227,7 @@ static int fsl_easrc_probe(struct platform_device *pdev)
}
ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt);
- easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
+ easrc->asrc_format = asrc_fmt;
if (ret) {
dev_err(dev, "failed to asrc format\n");
return ret;
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -503,8 +503,8 @@ static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream,
return ret;
}
- access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |
- 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+ access = 1ULL << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |
+ 1ULL << SNDRV_PCM_ACCESS_RW_INTERLEAVED;
ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
access);
if (ret) {
@@ -532,8 +532,8 @@ static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substrea
return ret;
}
- access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |
- 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
+ access = 1ULL << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |
+ 1ULL << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
access);
if (ret) {
diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
--- a/sound/soc/fsl/imx-card.c
+++ b/sound/soc/fsl/imx-card.c
@@ -531,7 +531,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
snd_mask_none(mask);
- snd_mask_set(mask, (__force unsigned int)data->asrc_format);
+ snd_mask_set(mask, data->asrc_format);
return 0;
}
@@ -684,7 +684,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
}
ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt);
- data->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
+ data->asrc_format = asrc_fmt;
if (ret) {
/* Fallback to old binding; translate to asrc_format */
ret = of_property_read_u32(args.np, "fsl,asrc-width", &width);
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
--- a/sound/soc/intel/avs/probes.c
+++ b/sound/soc/intel/avs/probes.c
@@ -144,7 +144,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
if (ret < 0)
return ret;
- bps = snd_pcm_format_physical_width((__force snd_pcm_format_t)params->codec.format);
+ bps = snd_pcm_format_physical_width(params->codec.format);
if (bps < 0)
return bps;
format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate);
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -172,7 +172,7 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S32_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
@@ -184,7 +184,7 @@ static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -99,7 +99,7 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* fix BE i2s format to S32_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
return 0;
@@ -112,7 +112,7 @@ static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
return 0;
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366.c
+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c
@@ -387,7 +387,7 @@ static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, fmt);
diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
--- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c
+++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
@@ -623,7 +623,7 @@ static int mt8188_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to 32bit, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
diff --git a/sound/soc/mediatek/mt8189/mt8189-nau8825.c b/sound/soc/mediatek/mt8189/mt8189-nau8825.c
--- a/sound/soc/mediatek/mt8189/mt8189-nau8825.c
+++ b/sound/soc/mediatek/mt8189/mt8189-nau8825.c
@@ -174,7 +174,7 @@ static int mt8189_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* fix BE i2s format to 32bit, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
--- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -382,7 +382,7 @@ static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
--- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c
+++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
@@ -387,7 +387,7 @@ static int mt8195_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
@@ -650,7 +650,7 @@ static int mt8195_etdm_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
diff --git a/sound/soc/mediatek/mt8196/mt8196-nau8825.c b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
--- a/sound/soc/mediatek/mt8196/mt8196-nau8825.c
+++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
@@ -180,7 +180,7 @@ static int mt8196_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* fix BE i2s format to 32bit, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
return 0;
diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c
--- a/sound/soc/meson/meson-codec-glue.c
+++ b/sound/soc/meson/meson-codec-glue.c
@@ -74,7 +74,7 @@ int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
data->params.rate_min = params_rate(params);
data->params.rate_max = params_rate(params);
- data->params.formats = 1ULL << (__force int) params_format(params);
+ data->params.formats = 1ULL << params_format(params);
data->params.channels_min = params_channels(params);
data->params.channels_max = params_channels(params);
data->params.sig_bits = dai->driver->playback.sig_bits;
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -1840,6 +1840,7 @@ static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x)
int rval = D_INTR_GETRVAL(x);
#endif
+#ifdef DBRI_DEBUG
if (channel == D_INTR_CMD) {
dprintk(D_CMD, "INTR: Command: %-5s Value:%d\n",
cmds[command], val);
@@ -1847,6 +1848,7 @@ static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x)
dprintk(D_INT, "INTR: Chan:%d Code:%d Val:%#x\n",
channel, code, rval);
}
+#endif
switch (code) {
case D_INTR_CMDI:
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -194,23 +194,20 @@ static int usb6fire_fw_ezusb_upload(
int ret;
u8 data;
struct usb_device *device = interface_to_usbdev(intf);
- const struct firmware *fw = NULL;
- struct ihex_record *rec = kmalloc_obj(struct ihex_record);
+ struct ihex_record *rec __free(kfree) = kmalloc_obj(struct ihex_record);
if (!rec)
return -ENOMEM;
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, fwname, &device->dev);
if (ret < 0) {
- kfree(rec);
dev_err(&intf->dev,
"error requesting ezusb firmware %s.\n", fwname);
return ret;
}
ret = usb6fire_fw_ihex_init(fw, rec);
if (ret < 0) {
- kfree(rec);
- release_firmware(fw);
dev_err(&intf->dev,
"error validating ezusb firmware %s.\n", fwname);
return ret;
@@ -219,8 +216,6 @@ static int usb6fire_fw_ezusb_upload(
data = 0x01; /* stop ezusb cpu */
ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
if (ret) {
- kfree(rec);
- release_firmware(fw);
dev_err(&intf->dev,
"unable to upload ezusb firmware %s: begin message.\n",
fwname);
@@ -231,8 +226,6 @@ static int usb6fire_fw_ezusb_upload(
ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
rec->data, rec->len);
if (ret) {
- kfree(rec);
- release_firmware(fw);
dev_err(&intf->dev,
"unable to upload ezusb firmware %s: data urb.\n",
fwname);
@@ -240,8 +233,6 @@ static int usb6fire_fw_ezusb_upload(
}
}
- release_firmware(fw);
- kfree(rec);
if (postdata) { /* write data after firmware has been uploaded */
ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
postdata, postlen);
@@ -270,19 +261,18 @@ static int usb6fire_fw_fpga_upload(
int ret;
int i;
struct usb_device *device = interface_to_usbdev(intf);
- u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
+ u8 *buffer __free(kfree) = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
const char *c;
const char *end;
- const struct firmware *fw;
if (!buffer)
return -ENOMEM;
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, fwname, &device->dev);
if (ret < 0) {
dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
fwname);
- kfree(buffer);
return -EIO;
}
@@ -291,8 +281,6 @@ static int usb6fire_fw_fpga_upload(
ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
if (ret) {
- kfree(buffer);
- release_firmware(fw);
dev_err(&intf->dev,
"unable to upload fpga firmware: begin urb.\n");
return ret;
@@ -304,15 +292,11 @@ static int usb6fire_fw_fpga_upload(
ret = usb6fire_fw_fpga_write(device, buffer, i);
if (ret < 0) {
- release_firmware(fw);
- kfree(buffer);
dev_err(&intf->dev,
"unable to upload fpga firmware: fw urb.\n");
return ret;
}
}
- release_firmware(fw);
- kfree(buffer);
ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
if (ret) {
diff --git a/sound/usb/card.c b/sound/usb/card.c
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -715,7 +715,7 @@ static void snd_usb_init_quirk_flags(int idx, struct snd_usb_audio *chip)
/* old style option found: the position-based integer value */
if (quirk_flags[idx] &&
- !kstrtou32(quirk_flags[idx], 0, &chip->quirk_flags)) {
+ !kstrtou64(quirk_flags[idx], 0, &chip->quirk_flags)) {
snd_usb_apply_flag_dbg("module param", chip, chip->quirk_flags);
return;
}
@@ -905,6 +905,40 @@ static int try_to_register_card(struct snd_usb_audio *chip, int ifnum)
return 0;
}
+static void usb_audio_disconnect_components(struct snd_usb_audio *chip)
+{
+ struct snd_usb_stream *as;
+ struct snd_usb_endpoint *ep;
+ struct usb_mixer_interface *mixer;
+ struct list_head *p;
+
+ /* release the pcm resources */
+ list_for_each_entry(as, &chip->pcm_list, list) {
+ snd_usb_stream_disconnect(as);
+ }
+ /* release the endpoint resources */
+ list_for_each_entry(ep, &chip->ep_list, list) {
+ snd_usb_endpoint_release(ep);
+ }
+ /* release the midi resources */
+ list_for_each(p, &chip->midi_list) {
+ snd_usbmidi_disconnect(p);
+ }
+ snd_usb_midi_v2_disconnect_all(chip);
+ /*
+ * Nice to check quirk && quirk->shares_media_device and
+ * then call the snd_media_device_delete(). Don't have
+ * access to the quirk here. snd_media_device_delete()
+ * accesses mixer_list
+ */
+ snd_media_device_delete(chip);
+
+ /* release mixer resources */
+ list_for_each_entry(mixer, &chip->mixer_list, list) {
+ snd_usb_mixer_disconnect(mixer);
+ }
+}
+
/*
* probe the active usb device
*
@@ -1077,8 +1111,10 @@ static int usb_audio_probe(struct usb_interface *intf,
* decrement before memory is possibly returned.
*/
atomic_dec(&chip->active);
- if (!chip->num_interfaces)
+ if (!chip->num_interfaces) {
+ usb_audio_disconnect_components(chip);
snd_card_free(chip->card);
+ }
}
return err;
}
@@ -1091,48 +1127,18 @@ static bool __usb_audio_disconnect(struct usb_interface *intf,
struct snd_usb_audio *chip,
struct snd_card *card)
{
- struct list_head *p;
-
guard(mutex)(&register_mutex);
if (platform_ops && platform_ops->disconnect_cb)
platform_ops->disconnect_cb(chip);
if (atomic_inc_return(&chip->shutdown) == 1) {
- struct snd_usb_stream *as;
- struct snd_usb_endpoint *ep;
- struct usb_mixer_interface *mixer;
-
/* wait until all pending tasks done;
* they are protected by snd_usb_lock_shutdown()
*/
snd_refcount_sync(&chip->usage_count);
snd_card_disconnect(card);
- /* release the pcm resources */
- list_for_each_entry(as, &chip->pcm_list, list) {
- snd_usb_stream_disconnect(as);
- }
- /* release the endpoint resources */
- list_for_each_entry(ep, &chip->ep_list, list) {
- snd_usb_endpoint_release(ep);
- }
- /* release the midi resources */
- list_for_each(p, &chip->midi_list) {
- snd_usbmidi_disconnect(p);
- }
- snd_usb_midi_v2_disconnect_all(chip);
- /*
- * Nice to check quirk && quirk->shares_media_device and
- * then call the snd_media_device_delete(). Don't have
- * access to the quirk here. snd_media_device_delete()
- * accesses mixer_list
- */
- snd_media_device_delete(chip);
-
- /* release mixer resources */
- list_for_each_entry(mixer, &chip->mixer_list, list) {
- snd_usb_mixer_disconnect(mixer);
- }
+ usb_audio_disconnect_components(chip);
}
if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND)
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -600,7 +600,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
const struct audioformat *fmt, int rate)
{
- int cur_rate, prev_rate;
+ int cur_rate, prev_rate = 0;
int clock;
/* First, try to find a valid clock. This may trigger
@@ -625,9 +625,12 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
return clock;
}
- prev_rate = get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock);
- if (prev_rate == rate)
- goto validation;
+ if (!(chip->quirk_flags & QUIRK_FLAG_ALWAYS_SET_RATE)) {
+ prev_rate = get_sample_rate_v2v3(chip, fmt->iface,
+ fmt->altsetting, clock);
+ if (prev_rate == rate)
+ goto validation;
+ }
cur_rate = snd_usb_set_sample_rate_v2v3(chip, fmt, clock, rate);
if (cur_rate < 0) {
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -1237,7 +1237,10 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
/* try to use enough URBs to contain an entire ALSA buffer */
max_urbs = min((unsigned) MAX_URBS,
MAX_QUEUE * packs_per_ms / urb_packs);
- ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods);
+ if (chip->quirk_flags & QUIRK_FLAG_PLAYBACK_URB_FIXUP)
+ ep->nurbs = MAX_URBS;
+ else
+ ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods);
}
if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
@@ -1262,6 +1265,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
goto out_of_memory;
u->urb->pipe = ep->pipe;
u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ if (chip->quirk_flags & QUIRK_FLAG_PLAYBACK_URB_FIXUP)
+ u->urb->transfer_flags |= URB_ISO_ASAP;
u->urb->interval = 1 << ep->datainterval;
u->urb->context = u;
u->urb->complete = snd_complete_urb;
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -505,6 +505,19 @@ static const struct usbmix_connector_map gigabyte_b450_connector_map[] = {
{}
};
+/* Audient iD14: FU 12 advertises Volume on only 4 of its 6 logical channels
+ * and sits on the monitor mixer branch, but it is traced through to the
+ * Speaker output terminal and gets named "Speaker Playback Volume". Userspace
+ * then adopts it as the stream's hardware volume, and any setting below 0 dB
+ * attenuates some channels but not others (20 dB imbalance at 80%). Give it a
+ * non-standard name so that it is no longer taken for the stream's master
+ * volume, while remaining reachable for anyone who wants the monitor gain.
+ */
+static const struct usbmix_name_map audient_id14_map[] = {
+ { 12, "Monitor Mix Playback" }, /* FU, partial coverage */
+ {}
+};
+
/*
* Control map entries
*/
@@ -588,6 +601,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
.id = USB_ID(0x2573, 0x0008),
.map = maya44_map,
},
+ {
+ /* Audient iD14 */
+ .id = USB_ID(0x2708, 0x0008),
+ .map = audient_id14_map,
+ },
{
/* KEF X300A */
.id = USB_ID(0x27ac, 0x1000),
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -3920,6 +3920,7 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer)
#define SND_DJM_450_IDX 0x5
#define SND_DJM_A9_IDX 0x6
#define SND_DJM_V10_IDX 0x7
+#define SND_DJM_S11_IDX 0x8
#define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \
.name = _name, \
@@ -4260,6 +4261,21 @@ static const struct snd_djm_ctl snd_djm_ctls_v10[] = {
// playback channels are fixed and controlled by hardware knobs on the mixer
};
+// DJM-S11
+static const u16 snd_djm_opts_s11_cap1[] = {
+ 0x0100, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d };
+static const u16 snd_djm_opts_s11_cap2[] = {
+ 0x0200, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d };
+static const u16 snd_djm_opts_s11_cap3[] = {
+ 0x0307, 0x0308, 0x0309, 0x030a, 0x030d, 0x0311, 0x0312 };
+
+static const struct snd_djm_ctl snd_djm_ctls_s11[] = {
+ SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+ SND_DJM_CTL("Input 1 Capture Switch", s11_cap1, 1, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Input 2 Capture Switch", s11_cap2, 1, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Input 3 Capture Switch", s11_cap3, 3, SND_DJM_WINDEX_CAP)
+};
+
static const struct snd_djm_device snd_djm_devices[] = {
[SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2),
[SND_DJM_750_IDX] = SND_DJM_DEVICE(750),
@@ -4269,6 +4285,7 @@ static const struct snd_djm_device snd_djm_devices[] = {
[SND_DJM_450_IDX] = SND_DJM_DEVICE(450),
[SND_DJM_A9_IDX] = SND_DJM_DEVICE(a9),
[SND_DJM_V10_IDX] = SND_DJM_DEVICE(v10),
+ [SND_DJM_S11_IDX] = SND_DJM_DEVICE(s11),
};
static int snd_djm_controls_info(struct snd_kcontrol *kctl,
@@ -4573,6 +4590,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x2b73, 0x0034): /* Pioneer DJ DJM-V10 */
err = snd_djm_controls_create(mixer, SND_DJM_V10_IDX);
break;
+ case USB_ID(0x2b73, 0x0037): /* Pioneer DJ DJM-S11 */
+ err = snd_djm_controls_create(mixer, SND_DJM_S11_IDX);
+ break;
case USB_ID(0x03f0, 0x0269): /* HP TB Dock G2 */
err = hp_dock_mixer_create(mixer);
break;
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3320,6 +3320,73 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+{
+ /*
+ * Pioneer DJ / AlphaTheta DJM-S11
+ */
+ USB_DEVICE(0x2b73, 0x0037),
+ QUIRK_DRIVER_INFO {
+ QUIRK_DATA_COMPOSITE {
+ {
+ QUIRK_DATA_STANDARD_MIXER(0)
+ },
+ {
+ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 14,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x01,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_ASYNC,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 48000 },
+ .clock = 1,
+ .fmt_type = UAC_FORMAT_TYPE_I
+ }
+ },
+ {
+ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 10,
+ .iface = 2,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x82,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_ASYNC |
+ USB_ENDPOINT_USAGE_IMPLICIT_FB,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 48000 },
+ .clock = 1,
+ .fmt_type = UAC_FORMAT_TYPE_I
+ }
+ },
+ {
+ /* Audio Control (unknown purpose) */
+ .ifnum = 3,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 4,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ /* HID */
+ .ifnum = 5,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ QUIRK_COMPOSITE_END
+ }
+ }
+},
/*
* MacroSilicon MS2100/MS2106 based AV capture cards
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2145,7 +2145,7 @@ struct usb_string_match {
struct usb_audio_quirk_flags_table {
u32 id;
- u32 flags;
+ u64 flags;
const struct usb_string_match *usb_string_match;
};
@@ -2314,7 +2314,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
DEVICE_FLG(0x0661, 0x0883, /* iBasso DC04 Ultra */
QUIRK_FLAG_DSD_RAW),
DEVICE_FLG(0x0666, 0x0880, /* SPACETOUCH USB Audio */
- QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
+ QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY |
+ QUIRK_FLAG_CTL_MSG_DELAY_5M),
DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */
@@ -2337,6 +2338,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */
QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ DEVICE_FLG(0x0a73, 0x003a, /* Mackie DLZ Creator XS */
+ QUIRK_FLAG_ALWAYS_SET_RATE),
DEVICE_FLG(0x0b05, 0x18a6, /* ASUSTek Computer, Inc. */
QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE),
DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */
@@ -2432,6 +2435,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(0x1e0b, 0xd01e, /* Generic USB Audio Device */
+ QUIRK_FLAG_PLAYBACK_URB_FIXUP),
DEVICE_FLG(0x1ff7, 0x0f81, /* SC13A Webcam */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
@@ -2528,6 +2533,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_ALIGN_TRANSFER),
DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x84ef, 0x002a, /* Valeton GP-200 */
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
DEVICE_FLG(0x84ef, 0x0082, /* Hotone Audio Pulze Mini */
QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL | QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL),
@@ -2641,18 +2648,12 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL),
QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY),
QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN),
+ QUIRK_STRING_ENTRY(PLAYBACK_URB_FIXUP),
+ QUIRK_STRING_ENTRY(ALWAYS_SET_RATE),
NULL
};
-const char *snd_usb_quirk_flag_find_name(unsigned long index)
-{
- if (index >= ARRAY_SIZE(snd_usb_audio_quirk_flag_names))
- return NULL;
-
- return snd_usb_audio_quirk_flag_names[index];
-}
-
-u32 snd_usb_quirk_flags_from_name(const char *name)
+static u64 snd_usb_quirk_flags_from_name(const char *name)
{
int i;
@@ -2661,7 +2662,7 @@ u32 snd_usb_quirk_flags_from_name(const char *name)
for (i = 0; snd_usb_audio_quirk_flag_names[i]; i++) {
if (strcasecmp(name, snd_usb_audio_quirk_flag_names[i]) == 0)
- return BIT_U32(i);
+ return BIT_U64(i);
}
return 0;
@@ -2719,7 +2720,7 @@ void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip,
{
u16 chip_vid = USB_ID_VENDOR(chip->usb_id);
u16 chip_pid = USB_ID_PRODUCT(chip->usb_id);
- u32 mask_flags, unmask_flags, bit;
+ u64 mask_flags, unmask_flags, bit;
char *p, *field, *flag;
bool is_unmask;
u16 vid, pid;
@@ -2773,7 +2774,7 @@ void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip,
is_unmask = false;
}
- if (!kstrtou32(flag, 16, &bit)) {
+ if (!kstrtou64(flag, 16, &bit)) {
if (is_unmask)
unmask_flags |= bit;
else
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -56,7 +56,4 @@ void snd_usb_init_quirk_flags_table(struct snd_usb_audio *chip);
void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip,
const char *str);
-const char *snd_usb_quirk_flag_find_name(unsigned long flag);
-u32 snd_usb_quirk_flags_from_name(const char *name);
-
#endif /* __USBAUDIO_QUIRKS_H */
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -44,7 +44,7 @@ struct snd_usb_audio {
atomic_t active;
atomic_t shutdown;
struct snd_refcount usage_count;
- unsigned int quirk_flags;
+ u64 quirk_flags;
unsigned int need_delayed_register:1; /* warn for delayed registration */
int num_interfaces;
int last_iface;
@@ -254,6 +254,16 @@ extern bool snd_usb_skip_validation;
* check being non-fatal and only disabling GET_CUR instead of the whole mixer.
* The current volume will then be provided by the internal cache that stores
* the last set volume
+ * QUIRK_FLAG_PLAYBACK_URB_FIXUP
+ * Set URB_ISO_ASAP flag for isochronous URBs and force nurbs to MAX_URBS.
+ * This is needed for devices that exhibit boot-time audio stuttering due
+ * to insufficient buffer depth combined with xHCI scheduling variability.
+ * The larger buffer (MAX_URBS = 12, ~64ms) absorbs system scheduling
+ * jitter during boot, while URB_ISO_ASAP ensures consistent xHCI scheduling.
+ * QUIRK_FLAG_ALWAYS_SET_RATE:
+ * Issue SET_CUR for the sample rate even when the clock already reports the
+ * requested rate. A device advertising a single rate is otherwise never sent
+ * the request at all, and some require it before streaming will start.
*/
enum {
@@ -288,10 +298,12 @@ enum {
QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28,
QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29,
QUIRK_TYPE_MIXER_GET_CUR_BROKEN = 30,
+ QUIRK_TYPE_PLAYBACK_URB_FIXUP = 31,
+ QUIRK_TYPE_ALWAYS_SET_RATE = 32,
/* Please also edit snd_usb_audio_quirk_flag_names */
};
-#define QUIRK_FLAG(x) BIT_U32(QUIRK_TYPE_ ## x)
+#define QUIRK_FLAG(x) BIT_U64(QUIRK_TYPE_ ## x)
#define QUIRK_FLAG_GET_SAMPLE_RATE QUIRK_FLAG(GET_SAMPLE_RATE)
#define QUIRK_FLAG_SHARE_MEDIA_DEVICE QUIRK_FLAG(SHARE_MEDIA_DEVICE)
@@ -324,5 +336,7 @@ enum {
#define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL)
#define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY QUIRK_FLAG(IFB_SILENCE_ON_EMPTY)
#define QUIRK_FLAG_MIXER_GET_CUR_BROKEN QUIRK_FLAG(MIXER_GET_CUR_BROKEN)
+#define QUIRK_FLAG_PLAYBACK_URB_FIXUP QUIRK_FLAG(PLAYBACK_URB_FIXUP)
+#define QUIRK_FLAG_ALWAYS_SET_RATE QUIRK_FLAG(ALWAYS_SET_RATE)
#endif /* __USBAUDIO_H */
diff --git a/sound/usb/usx2y/us144mkii_pcm.h b/sound/usb/usx2y/us144mkii_pcm.h
--- a/sound/usb/usx2y/us144mkii_pcm.h
+++ b/sound/usb/usx2y/us144mkii_pcm.h
@@ -7,7 +7,7 @@
#include "us144mkii.h"
/**
- * tascam_pcm_hw - Hardware capabilities for TASCAM US-144MKII PCM.
+ * var tascam_pcm_hw - Hardware capabilities for TASCAM US-144MKII PCM.
*
* Defines the supported PCM formats, rates, channels, and buffer/period sizes
* for the TASCAM US-144MKII audio interface.
@@ -15,14 +15,14 @@
extern const struct snd_pcm_hardware tascam_pcm_hw;
/**
- * tascam_playback_ops - ALSA PCM operations for playback.
+ * var tascam_playback_ops - ALSA PCM operations for playback.
*
* This structure defines the callback functions for playback stream operations.
*/
extern const struct snd_pcm_ops tascam_playback_ops;
/**
- * tascam_capture_ops - ALSA PCM operations for capture.
+ * var tascam_capture_ops - ALSA PCM operations for capture.
*
* This structure defines the callback functions for capture stream operations.
*/
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -167,7 +167,6 @@ static int usx2y_urb_submit(struct snd_usx2y_substream *subs, struct urb *urb, i
if (!urb)
return -ENODEV;
urb->start_frame = frame + NRURBS * nr_of_packs(); // let hcd do rollover sanity checks
- urb->hcpriv = NULL;
urb->dev = subs->usx2y->dev; /* we need to set this at each time */
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {