12142 lines
418 KiB
Diff
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, ®ister_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(¶ms, snd_hdac_format_normalize(format));
|
|
snd_mask_set(hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT),
|
|
- (__force unsigned int)subformat);
|
|
+ subformat);
|
|
|
|
bits = snd_pcm_hw_params_bits(¶ms);
|
|
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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
|
|
+
|
|
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_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, ®_val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
|
|
+
|
|
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_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, ®_val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
|
|
+
|
|
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_val);
|
|
- if (ret)
|
|
- return ret;
|
|
- icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
|
|
-
|
|
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_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, ®_val);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
|
|
-
|
|
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_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, ®_val);
|
|
- if (ret)
|
|
- return ret;
|
|
- vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
|
|
-
|
|
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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)(®ister_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) {
|