From c4655e343abe6882bbdbec2160f4c2b6eaa5c2a8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 29 Nov 2022 17:29:29 -0600 Subject: [PATCH 01/13] ASoC: es83xx: add ACPI DSM helper module Most of the ES83xx codec configuration is exposed in the DSDT table and accessible via a _DSM method. Start adding basic definitions and helpers to dump the information. Reviewed-by: Mauro Carvalho Chehab Co-developed-by: David Yang Signed-off-by: David Yang Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/es83xx-dsm-common.c | 88 ++++++ sound/soc/codecs/es83xx-dsm-common.h | 396 +++++++++++++++++++++++++++ 4 files changed, 491 insertions(+) create mode 100644 sound/soc/codecs/es83xx-dsm-common.c create mode 100644 sound/soc/codecs/es83xx-dsm-common.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3429419ca6945e..998785f4b4c24b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1076,13 +1076,18 @@ config SND_SOC_ES7134 config SND_SOC_ES7241 tristate "Everest Semi ES7241 CODEC" +config SND_SOC_ES83XX_DSM_COMMON + tristate + config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" depends on I2C + select SND_SOC_ES83XX_DSM_COMMON if ACPI config SND_SOC_ES8326 tristate "Everest Semi ES8326 CODEC" depends on I2C + select SND_SOC_ES83XX_DSM_COMMON if ACPI config SND_SOC_ES8328 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 2078bb0d981ec8..f53baa2b956519 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -116,6 +116,7 @@ snd-soc-da9055-objs := da9055.o snd-soc-dmic-objs := dmic.o snd-soc-es7134-objs := es7134.o snd-soc-es7241-objs := es7241.o +snd-soc-es83xx-dsm-common-objs := es83xx-dsm-common.o snd-soc-es8316-objs := es8316.o snd-soc-es8326-objs := es8326.o snd-soc-es8328-objs := es8328.o @@ -505,6 +506,7 @@ obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o +obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON) += snd-soc-es83xx-dsm-common.o obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o diff --git a/sound/soc/codecs/es83xx-dsm-common.c b/sound/soc/codecs/es83xx-dsm-common.c new file mode 100644 index 00000000000000..86b8313ebcc438 --- /dev/null +++ b/sound/soc/codecs/es83xx-dsm-common.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright (c) Intel Corporation, 2022 +// Copyright Everest Semiconductor Co.,Ltd + +#include +#include +#include "es83xx-dsm-common.h" + +/* UUID ("a9800c04-e016-343e-41f4-6bcce70f4332") */ +static const guid_t es83xx_dsm_guid = + GUID_INIT(0xa9800c04, 0xe016, 0x343e, + 0x41, 0xf4, 0x6b, 0xcc, 0xe7, 0x0f, 0x43, 0x32); + +#define ES83xx_DSM_REVID 1 + +static int es83xx_dsm(struct device *dev, int arg, int *value) +{ + acpi_handle dhandle; + union acpi_object *obj; + int ret = 0; + + dhandle = ACPI_HANDLE(dev); + if (!dhandle) + return -ENOENT; + + obj = acpi_evaluate_dsm(dhandle, &es83xx_dsm_guid, ES83xx_DSM_REVID, + arg, NULL); + if (!obj) { + dev_err(dev, "%s: acpi_evaluate_dsm() failed\n", __func__); + ret = -EINVAL; + goto out; + } + + if (obj->type != ACPI_TYPE_INTEGER) { + dev_err(dev, "%s: object is not ACPI_TYPE_INTEGER\n", __func__); + ret = -EINVAL; + goto err; + } + + *value = obj->integer.value; +err: + ACPI_FREE(obj); +out: + return ret; +} + +int es83xx_dsm_dump(struct device *dev) +{ + int value; + int ret; + + ret = es83xx_dsm(dev, PLATFORM_MAINMIC_TYPE_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_MAINMIC_TYPE %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_HPMIC_TYPE_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_HPMIC_TYPE %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_SPK_TYPE_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_SPK_TYPE %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_HPDET_INV_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_HPDET_INV %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_PCM_TYPE_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_PCM_TYPE %#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_MIC_DE_POP_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "PLATFORM_MIC_DE_POP %#x\n", value); + + return 0; +} +EXPORT_SYMBOL_GPL(es83xx_dsm_dump); + +MODULE_DESCRIPTION("Everest Semi ES83xx DSM helpers"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es83xx-dsm-common.h b/sound/soc/codecs/es83xx-dsm-common.h new file mode 100644 index 00000000000000..5c33c329bd88e4 --- /dev/null +++ b/sound/soc/codecs/es83xx-dsm-common.h @@ -0,0 +1,396 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Intel Corporation, 2022 + * Copyright Everest Semiconductor Co.,Ltd + */ + +/* Definitions extracted from ASL file provided at + * https://github.com/thesofproject/linux/files/9398723/ESSX8326.zip + */ + +#ifndef _ES83XX_DSM_COMMON_H +#define _ES83XX_DSM_COMMON_H + +/*************************************************** + * DSM arguments * + ***************************************************/ + +#define PLATFORM_MAINMIC_TYPE_ARG 0x00 +#define PLATFORM_HPMIC_TYPE_ARG 0x01 +#define PLATFORM_SPK_TYPE_ARG 0x02 +#define PLATFORM_HPDET_INV_ARG 0x03 +#define PLATFORM_PCM_TYPE_ARG 0x04 + +#define PLATFORM_MIC_DE_POP_ARG 0x06 +#define PLATFORM_CODEC_TYPE_ARG 0x0E +#define PLATFORM_BUS_SLOT_ARG 0x0F + +#define HP_CODEC_LINEIN_PGA_GAIN_ARG 0x10 +#define MAIN_CODEC_LINEIN_PGA_GAIN_ARG 0x20 + +#define HP_CODEC_D2SEPGA_GAIN_ARG 0x11 +#define MAIN_CODEC_D2SEPGA_GAIN_ARG 0x21 + +#define HP_CODEC_ADC_VOLUME_ARG 0x12 +#define MAIN_CODEC_ADC_VOLUME_ARG 0x22 + +#define HP_CODEC_ADC_ALC_ENABLE_ARG 0x13 +#define MAIN_CODEC_ADC_ALC_ENABLE_ARG 0x23 + +#define HP_CODEC_ADC_ALC_TARGET_LEVEL_ARG 0x14 +#define MAIN_CODEC_ADC_ALC_TARGET_LEVEL_ARG 0x24 + +#define HP_CODEC_ADC_ALC_MAXGAIN_ARG 0x15 +#define MAIN_CODEC_ADC_ALC_MAXGAIN_ARG 0x25 + +#define HP_CODEC_ADC_ALC_MINGAIN_ARG 0x16 +#define MAIN_CODEC_ADC_ALC_MINGAIN_ARG 0x26 + +#define HP_CODEC_ADC_ALC_HLDTIME_ARG 0x17 +#define MAIN_CODEC_ADC_ALC_HLDTIME_ARG 0x27 + +#define HP_CODEC_ADC_ALC_DCYTIME_ARG 0x18 +#define MAIN_CODEC_ADC_ALC_DCYTIME_ARG 0x28 + +#define HP_CODEC_ADC_ALC_ATKTIME_ARG 0x19 +#define MAIN_CODEC_ADC_ALC_ATKTIME_ARG 0x29 + +#define HP_CODEC_ADC_ALC_NGTYPE_ARG 0x1a +#define MAIN_CODEC_ADC_ALC_NGTYPE_ARG 0x2a + +#define HP_CODEC_ADC_ALC_NGTHLD_ARG 0x1b +#define MAIN_CODEC_ADC_ALC_NGTHLD_ARG 0x2b + +#define MAIN_CODEC_ADC_GUI_STEP_ARG 0x2c +#define MAIN_CODEC_ADC_GUI_GAIN_RANGE_ARG 0x2c + +#define HEADPHONE_DUMMY_REMOVE_ENABLE_ARG 0x2e + +#define HP_CODEC_DAC_HPMIX_HIGAIN_ARG 0x40 +#define SPK_CODEC_DAC_HPMIX_HIGAIN_ARG 0x50 + +#define HP_CODEC_DAC_HPMIX_VOLUME_ARG 0x41 +#define SPK_CODEC_DAC_HPMIX_VOLUME_ARG 0x51 + +#define HP_CODEC_DAC_HPOUT_VOLUME_ARG 0x42 +#define SPK_CODEC_DAC_HPOUT_VOLUME_ARG 0x52 + +#define HP_CODEC_LDAC_VOLUME_ARG 0x44 +#define HP_CODEC_RDAC_VOLUME_ARG 0x54 + +#define SPK_CODEC_LDAC_VOLUME_ARG 0x45 +#define SPK_CODEC_RDAC_VOLUME_ARG 0x55 + +#define HP_CODEC_DAC_AUTOMUTE_ARG 0x46 +#define SPK_CODEC_DAC_AUTOMUTE_ARG 0x56 + +#define HP_CODEC_DAC_MONO_ARG 0x4A +#define SPK_CODEC_DAC_MONO_ARG 0x5A + +#define HP_CTL_IO_LEVEL_ARG 0x4B +#define SPK_CTL_IO_LEVEL_ARG 0x5B + +#define CODEC_GPIO0_FUNC_ARG 0x80 +#define CODEC_GPIO1_FUNC_ARG 0x81 +#define CODEC_GPIO2_FUNC_ARG 0x82 +#define CODEC_GPIO3_FUNC_ARG 0x83 +#define CODEC_GPIO4_FUNC_ARG 0x84 + +#define PLATFORM_MCLK_LRCK_FREQ_ARG 0x85 + +/*************************************************** + * Values for arguments * + ***************************************************/ + +/* Main and HP Mic */ +#define PLATFORM_MIC_DMIC_HIGH_LEVEL 0xAA +#define PLATFORM_MIC_DMIC_LOW_LEVEL 0x55 +#define PLATFORM_MIC_AMIC_LIN1RIN1 0xBB +#define PLATFORM_MIC_AMIC_LIN2RIN2 0xCC + +/* Speaker */ +#define PLATFORM_SPK_NONE 0x00 +#define PLATFORM_SPK_MONO 0x01 +#define PLATFORM_SPK_STEREO 0x02 + +/* Jack Detection */ +#define PLATFORM_HPDET_NORMAL 0x00 +#define PLATFORM_HPDET_INVERTED 0x01 + +/* PCM type (Port number + protocol) */ +/* + * RETURNED VALUE = 0x00, PCM PORT0, I2S + * 0x01, PCM PORT0, LJ + * 0x02, PCM PORT0, RJ + * 0x03, PCM PORT0, DSP-A + * 0x04, PCM PORT0, DSP-B + * 0x10, PCM PORT1, I2S + * 0x11, PCM PORT1, LJ + * 0x12, PCM PORT1, RJ + * 0x13, PCM PORT1, DSP-A + * 0x14, PCM PORT1, DSP-B + * 0xFF, Use default + * + * This is not used in Linux (defined by topology) and in + * Windows it's always DSP-A + */ + +/* Depop */ +#define PLATFORM_MIC_DE_POP_OFF 0x00 +#define PLATFORM_MIC_DE_POP_ON 0x01 + +/* Codec type */ +#define PLATFORM_CODEC_8316 16 +#define PLATFORM_CODEC_8326 26 +#define PLATFORM_CODEC_8336 36 +#define PLATFORM_CODEC_8395 95 +#define PLATFORM_CODEC_8396 96 + +/* Bus slot (on the host) */ +/* BIT[3:0] FOR BUS NUMBER, BIT[7:4] FOR SLOT NUMBER + * BIT[3:0] 0 for I2S0, 1 for IS21, 2 for I2S2. + * + * On Intel platforms this refers to SSP0..2. This information + * is not really useful for Linux, the information is already + * inferred from NHLT but can be used to double-check NHLT + */ + +/* Volume - Gain */ +#define LINEIN_GAIN_0db 0x00 /* gain = 0db */ +#define LINEIN_GAIN_3db 0x01 /* gain = +3db */ +#define LINEIN_GAIN_6db 0x02 /* gain = +6db */ +#define LINEIN_GAIN_9db 0x03 /* gain = +9db */ +#define LINEIN_GAIN_12db 0x04 /* gain = +12db */ +#define LINEIN_GAIN_15db 0x05 /* gain = +15db */ +#define LINEIN_GAIN_18db 0x06 /* gain = +18db */ +#define LINEIN_GAIN_21db 0x07 /* gain = +21db */ +#define LINEIN_GAIN_24db 0x08 /* gain = +24db */ +#define LINEIN_GAIN_27db 0x09 /* gain = +27db */ +#define LINEIN_GAIN_30db 0x0a /* gain = +30db */ + +#define ADC_GUI_STEP_3db 0x03 /* gain = +3db */ +#define ADC_GUI_STEP_6db 0x06 /* gain = +6db */ +#define ADC_GUI_STEP_10db 0x0a /* gain = +10db */ + +#define D2SEPGA_GAIN_0db 0x00 /* gain = 0db */ +#define D2SEPGA_GAIN_15db 0x01 /* gain = +15db */ + +/* ADC volume: base = 0db, -0.5db/setp, 0xc0 <-> -96db */ + +#define ADC_ALC_DISABLE 0x00 +#define ADC_ALC_ENABLE 0x01 + +#define ADC_ALC_TARGET_LEVEL_m16_5db 0x00 /* gain = -16.5db */ +#define ADC_ALC_TARGET_LEVEL_m15db 0x01 /* gain = -15db */ +#define ADC_ALC_TARGET_LEVEL_m13_5db 0x02 /* gain = -13.5db */ +#define ADC_ALC_TARGET_LEVEL_m12db 0x03 /* gain = -12db */ +#define ADC_ALC_TARGET_LEVEL_m10_5db 0x04 /* gain = -10.5db */ +#define ADC_ALC_TARGET_LEVEL_m9db 0x05 /* gain = -9db */ +#define ADC_ALC_TARGET_LEVEL_m7_5db 0x06 /* gain = -7.5db */ +#define ADC_ALC_TARGET_LEVEL_m6db 0x07 /* gain = -6db */ +#define ADC_ALC_TARGET_LEVEL_m4_5db 0x08 /* gain = -4.5db */ +#define ADC_ALC_TARGET_LEVEL_m_3db 0x09 /* gain = -3db */ +#define ADC_ALC_TARGET_LEVEL_m1_5db 0x0a /* gain = -1.5db */ + +#define ADC_ALC_MAXGAIN_m6_5db 0x00 /* gain = -6.5db */ +#define ADC_ALC_MAXGAIN_m5db 0x01 /* gain = -5db */ +#define ADC_ALC_MAXGAIN_m3_5db 0x02 /* gain = -3.5db */ +#define ADC_ALC_MAXGAIN_m2db 0x03 /* gain = -2db */ +#define ADC_ALC_MAXGAIN_m0_5db 0x04 /* gain = -0.5db */ +#define ADC_ALC_MAXGAIN_1db 0x05 /* gain = +1db */ +#define ADC_ALC_MAXGAIN_2_5db 0x06 /* gain = +2.5db */ +#define ADC_ALC_MAXGAIN_4db 0x07 /* gain = +4db */ +#define ADC_ALC_MAXGAIN_5_5db 0x08 /* gain = +5.5db */ +#define ADC_ALC_MAXGAIN_7db 0x09 /* gain = +7db */ +#define ADC_ALC_MAXGAIN_8_5db 0x0a /* gain = +8.5db */ +#define ADC_ALC_MAXGAIN_10db 0x0b /* gain = +10db */ +#define ADC_ALC_MAXGAIN_11_5db 0x0c /* gain = +11.5db */ +#define ADC_ALC_MAXGAIN_13db 0x0d /* gain = +13db */ +#define ADC_ALC_MAXGAIN_14_5db 0x0e /* gain = +14.5db */ +#define ADC_ALC_MAXGAIN_16db 0x0f /* gain = +16db */ +#define ADC_ALC_MAXGAIN_17_5db 0x10 /* gain = +17.5db */ +#define ADC_ALC_MAXGAIN_19db 0x11 /* gain = +19db */ +#define ADC_ALC_MAXGAIN_20_5db 0x12 /* gain = +20.5db */ +#define ADC_ALC_MAXGAIN_22db 0x13 /* gain = +22db */ +#define ADC_ALC_MAXGAIN_23_5db 0x14 /* gain = +23.5db */ +#define ADC_ALC_MAXGAIN_25db 0x15 /* gain = +25db */ +#define ADC_ALC_MAXGAIN_26_5db 0x16 /* gain = +26.5db */ +#define ADC_ALC_MAXGAIN_28db 0x17 /* gain = +28db */ +#define ADC_ALC_MAXGAIN_29_5db 0x18 /* gain = +29.5db */ +#define ADC_ALC_MAXGAIN_31db 0x19 /* gain = +31db */ +#define ADC_ALC_MAXGAIN_32_5db 0x1a /* gain = +32.5db */ +#define ADC_ALC_MAXGAIN_34db 0x1b /* gain = +34db */ +#define ADC_ALC_MAXGAIN_35_5db 0x1c /* gain = +35.5db */ + +#define ADC_ALC_MINGAIN_m12db 0x00 /* gain = -12db */ +#define ADC_ALC_MINGAIN_m10_5db 0x01 /* gain = -10.5db */ +#define ADC_ALC_MINGAIN_m9db 0x02 /* gain = -9db */ +#define ADC_ALC_MINGAIN_m7_5db 0x03 /* gain = -7.5db */ +#define ADC_ALC_MINGAIN_m6db 0x04 /* gain = -6db */ +#define ADC_ALC_MINGAIN_m4_51db 0x05 /* gain = -4.51db */ +#define ADC_ALC_MINGAIN_m3db 0x06 /* gain = -3db */ +#define ADC_ALC_MINGAIN_m1_5db 0x07 /* gain = -1.5db */ +#define ADC_ALC_MINGAIN_0db 0x08 /* gain = 0db */ +#define ADC_ALC_MINGAIN_1_5db 0x09 /* gain = +1.5db */ +#define ADC_ALC_MINGAIN_3db 0x0a /* gain = +3db */ +#define ADC_ALC_MINGAIN_4_5db 0x0b /* gain = +4.5db */ +#define ADC_ALC_MINGAIN_6db 0x0c /* gain = +6db */ +#define ADC_ALC_MINGAIN_7_5db 0x0d /* gain = +7.5db */ +#define ADC_ALC_MINGAIN_9db 0x0e /* gain = +9db */ +#define ADC_ALC_MINGAIN_10_5db 0x0f /* gain = +10.5db */ +#define ADC_ALC_MINGAIN_12db 0x10 /* gain = +12db */ +#define ADC_ALC_MINGAIN_13_5db 0x11 /* gain = +13.5db */ +#define ADC_ALC_MINGAIN_15db 0x12 /* gain = +15db */ +#define ADC_ALC_MINGAIN_16_5db 0x13 /* gain = +16.5db */ +#define ADC_ALC_MINGAIN_18db 0x14 /* gain = +18db */ +#define ADC_ALC_MINGAIN_19_5db 0x15 /* gain = +19.5db */ +#define ADC_ALC_MINGAIN_21db 0x16 /* gain = +21db */ +#define ADC_ALC_MINGAIN_22_5db 0x17 /* gain = +22.5db */ +#define ADC_ALC_MINGAIN_24db 0x18 /* gain = +24db */ +#define ADC_ALC_MINGAIN_25_5db 0x19 /* gain = +25.5db */ +#define ADC_ALC_MINGAIN_27db 0x1a /* gain = +27db */ +#define ADC_ALC_MINGAIN_28_5db 0x1b /* gain = +28.5db */ +#define ADC_ALC_MINGAIN_30db 0x1c /* gain = +30db */ + +/* ADC volume: step 1dB */ + +/* ALC Hold, Decay, Attack */ +#define ADC_ALC_HLDTIME_0_US 0x00 +#define ADC_ALC_HLDTIME_0000266_US 0x01 //time = 2.67ms +#define ADC_ALC_HLDTIME_0000533_US 0x02 //time = 5.33ms +#define ADC_ALC_HLDTIME_0001066_US 0x03 //time = 10.66ms +#define ADC_ALC_HLDTIME_0002132_US 0x04 //time = 21.32ms +#define ADC_ALC_HLDTIME_0004264_US 0x05 //time = 42.64ms +#define ADC_ALC_HLDTIME_0008538_US 0x06 //time = 85.38ms +#define ADC_ALC_HLDTIME_0017076_US 0x07 //time = 170.76ms +#define ADC_ALC_HLDTIME_0034152_US 0x08 //time = 341.52ms +#define ADC_ALC_HLDTIME_0680000_US 0x09 //time = 0.68s +#define ADC_ALC_HLDTIME_1360000_US 0x0a //time = 1.36s + +#define ADC_ALC_DCYTIME_000410_US 0x00 //time = 410us +#define ADC_ALC_DCYTIME_000820_US 0x01 //time = 820us +#define ADC_ALC_DCYTIME_001640_US 0x02 //time = 1.64ms +#define ADC_ALC_DCYTIME_003280_US 0x03 //time = 3.28ms +#define ADC_ALC_DCYTIME_006560_US 0x04 //time = 6.56ms +#define ADC_ALC_DCYTIME_013120_US 0x05 //time = 13.12ms +#define ADC_ALC_DCYTIME_026240_US 0x06 //time = 26.24ms +#define ADC_ALC_DCYTIME_058480_US 0x07 //time = 52.48ms +#define ADC_ALC_DCYTIME_104960_US 0x08 //time = 104.96ms +#define ADC_ALC_DCYTIME_209920_US 0x09 //time = 209.92ms +#define ADC_ALC_DCYTIME_420000_US 0x0a //time = 420ms + +#define ADC_ALC_ATKTIME_000104_US 0x00 //time = 104us +#define ADC_ALC_ATKTIME_000208_US 0x01 //time = 208us +#define ADC_ALC_ATKTIME_000416_US 0x02 //time = 416ms +#define ADC_ALC_ATKTIME_003832_US 0x03 //time = 832ms +#define ADC_ALC_ATKTIME_001664_US 0x04 //time = 1.664ms +#define ADC_ALC_ATKTIME_003328_US 0x05 //time = 3.328ms +#define ADC_ALC_ATKTIME_006656_US 0x06 //time = 6.656ms +#define ADC_ALC_ATKTIME_013312_US 0x07 //time = 13.312ms +#define ADC_ALC_ATKTIME_026624_US 0x08 //time = 26.624ms +#define ADC_ALC_ATKTIME_053248_US 0x09 //time = 53.248ms +#define ADC_ALC_ATKTIME_106496_US 0x0a //time = 106.496ms + +/* ALC Noise Gate */ +#define ADC_ALC_NGTYPE_DISABLE 0x00 //noise gate disable +#define ADC_ALC_NGTYPE_ENABLE_HOLD 0x01 //noise gate enable, hold gain type +#define ADC_ALC_NGTYPE_ENABLE_MUTE 0x03 //noise gate enable, mute type + +#define ADC_ALC_NGTHLD_m76_5db 0x00 /* Threshold = -76.5db */ +#define ADC_ALC_NGTHLD_m75db 0x01 /* Threshold = -75db */ +#define ADC_ALC_NGTHLD_m73_5db 0x02 /* Threshold = -73.5db */ +#define ADC_ALC_NGTHLD_m72db 0x03 /* Threshold = -72db */ +#define ADC_ALC_NGTHLD_m70_5db 0x04 /* Threshold = -70.5db */ +#define ADC_ALC_NGTHLD_m69db 0x05 /* Threshold = -69db */ +#define ADC_ALC_NGTHLD_m67_5db 0x06 /* Threshold = -67.5db */ +#define ADC_ALC_NGTHLD_m66db 0x07 /* Threshold = -66db */ +#define ADC_ALC_NGTHLD_m64_5db 0x08 /* Threshold = -64.5db */ +#define ADC_ALC_NGTHLD_m63db 0x09 /* Threshold = -63db */ +#define ADC_ALC_NGTHLD_m61_5db 0x0a /* Threshold = -61.5db */ +#define ADC_ALC_NGTHLD_m60db 0x0b /* Threshold = -60db */ +#define ADC_ALC_NGTHLD_m58_5db 0x0c /* Threshold = -58.5db */ +#define ADC_ALC_NGTHLD_m57db 0x0d /* Threshold = -57db */ +#define ADC_ALC_NGTHLD_m55_5db 0x0e /* Threshold = -55.5db */ +#define ADC_ALC_NGTHLD_m54db 0x0f /* Threshold = -54db */ +#define ADC_ALC_NGTHLD_m52_5db 0x10 /* Threshold = -52.5db */ +#define ADC_ALC_NGTHLD_m51db 0x11 /* Threshold = -51db */ +#define ADC_ALC_NGTHLD_m49_5db 0x12 /* Threshold = -49.5db */ +#define ADC_ALC_NGTHLD_m48db 0x13 /* Threshold = -48db */ +#define ADC_ALC_NGTHLD_m46_5db 0x14 /* Threshold = -46.5db */ +#define ADC_ALC_NGTHLD_m45db 0x15 /* Threshold = -45db */ +#define ADC_ALC_NGTHLD_m43_5db 0x16 /* Threshold = -43.5db */ +#define ADC_ALC_NGTHLD_m42db 0x17 /* Threshold = -42db */ +#define ADC_ALC_NGTHLD_m40_5db 0x18 /* Threshold = -40.5db */ +#define ADC_ALC_NGTHLD_m39db 0x19 /* Threshold = -39db */ +#define ADC_ALC_NGTHLD_m37_5db 0x1a /* Threshold = -37.5db */ +#define ADC_ALC_NGTHLD_m36db 0x1b /* Threshold = -36db */ +#define ADC_ALC_NGTHLD_m34_5db 0x1c /* Threshold = -34.5db */ +#define ADC_ALC_NGTHLD_m33db 0x1d /* Threshold = -33db */ +#define ADC_ALC_NGTHLD_m31_5db 0x1e /* Threshold = -31.5db */ +#define ADC_ALC_NGTHLD_m30db 0x1f /* Threshold = -30db */ + +/* Headphone dummy - Windows Specific flag, not needed for Linux */ + +/* HPMIX HIGAIN and VOLUME */ +#define DAC_HPMIX_HIGAIN_0db 0x00 /* gain = 0db */ +#define DAC_HPMIX_HIGAIN_m6db 0x88 /* gain = -6db */ + +#define DAC_HPMIX_VOLUME_m12db 0x00 /* volume = -12db */ +#define DAC_HPMIX_VOLUME_m10_5db 0x11 /* volume = -10.5db */ +#define DAC_HPMIX_VOLUME_m9db 0x22 /* volume = -9db */ +#define DAC_HPMIX_VOLUME_m7_5db 0x33 /* volume = -7.5db */ +#define DAC_HPMIX_VOLUME_m6db 0x44 /* volume = -6db */ +#define DAC_HPMIX_VOLUME_m4_5db 0x88 /* volume = -4.5db */ +#define DAC_HPMIX_VOLUME_m3db 0x99 /* volume = -3db */ +#define DAC_HPMIX_VOLUME_m1_5db 0xaa /* volume = -1.5db */ +#define DAC_HPMIX_VOLUME_0db 0xbb /* volume = 0db */ + +/* HPOUT VOLUME */ +#define DAC_HPOUT_VOLUME_0db 0x00 /* volume = 0db */ +#define DAC_HPOUT_VOLUME_m12db 0x11 /* volume = -12db */ +#define DAC_HPOUT_VOLUME_m24db 0x22 /* volume = -24db */ +#define DAC_HPOUT_VOLUME_m48db 0x33 /* volume = -48db */ + +/* LDAC/RDAC volume = 0db, -0.5db/setp, 0xc0 <-> -96db */ + +/* Automute */ +#define DAC_AUTOMUTE_NONE 0x00 /* no automute */ +#define DAC_AUTOMUTE_DIGITAL 0x01 /* digital mute */ +#define DAC_AUTOMUTE_ANALOG 0x02 /* analog mute */ + +/* Mono - Windows specific, on Linux the information comes from DAI/topology */ +#define HEADPHONE_MONO 0x01 /* on channel */ +#define HEADPHONE_STEREO 0x00 /* stereo */ + +/* Speaker and headphone GPIO control */ +#define GPIO_CTL_IO_LEVEL_LOW 0x00 /* low level enable */ +#define GPIO_CTL_IO_LEVEL_HIGH 0x01 /* high level enable */ + +/* GPIO */ +/* FIXME: for ES8396, no need to use */ + +/* Platform clocks */ +/* + * BCLK AND MCLK FREQ + * BIT[7:4] MCLK FREQ + * 0 - 19.2MHz + * 1 - 24MHz + * 2 - 12.288MHz + * F - Default for 19.2MHz + * + * BIT[3:0] BCLK FREQ + * 0 - 4.8MHz + * 1 - 2.4MHz + * 2 - 2.304MHz + * 3 - 3.072MHz + * 4 - 4.096MHz + * F - Default for 4.8MHz + */ + +#if IS_ENABLED(CONFIG_ACPI) +int es83xx_dsm_dump(struct device *dev); +#else +static inline int es83xx_dsm_dump(struct device *dev) { return 0; }; +#endif + +#endif From 94e49c42571dfdaadaf93dd3159611dd5a26656a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 29 Nov 2022 17:38:53 -0600 Subject: [PATCH 02/13] ASoC: es8316: use _DSM to invert jack detection Read jack detection information from _DSM and pre-set value. The value may be overridden with a property set by the machine driver. [mchehab: only override JD inverted from _DSM if quirks is enabled] Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/es8316.c | 15 ++++++++++-- sound/soc/codecs/es83xx-dsm-common.c | 36 ++++------------------------ sound/soc/codecs/es83xx-dsm-common.h | 4 ++-- 3 files changed, 20 insertions(+), 35 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index e53b2856d6250b..daccf643c2f414 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -22,6 +22,7 @@ #include #include #include "es8316.h" +#include "es83xx-dsm-common.h" /* In slave mode at single speed, the codec is documented as accepting 5 * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on @@ -689,8 +690,10 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component, * guarantee that the bytchr-es8316 driver, which might set this * property, will probe before us. */ - es8316->jd_inverted = device_property_read_bool(component->dev, - "everest,jack-detect-inverted"); + + if (device_property_read_bool(component->dev, + "everest,jack-detect-inverted")) + es8316->jd_inverted = true; mutex_lock(&es8316->lock); @@ -862,6 +865,14 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client) if (es8316 == NULL) return -ENOMEM; + /* read jack information from _DSM */ + ret = es83xx_dsm_jack_inverted(dev); + if (ret < 0) + dev_warn(dev, "%s: Could not get jack detection information with ACPI _DSM method\n", + __func__); + else + es8316->jd_inverted = ret; + i2c_set_clientdata(i2c_client, es8316); es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); diff --git a/sound/soc/codecs/es83xx-dsm-common.c b/sound/soc/codecs/es83xx-dsm-common.c index 86b8313ebcc438..e5ab599ac2c656 100644 --- a/sound/soc/codecs/es83xx-dsm-common.c +++ b/sound/soc/codecs/es83xx-dsm-common.c @@ -45,44 +45,18 @@ static int es83xx_dsm(struct device *dev, int arg, int *value) return ret; } -int es83xx_dsm_dump(struct device *dev) +int es83xx_dsm_jack_inverted(struct device *dev) { int value; int ret; - ret = es83xx_dsm(dev, PLATFORM_MAINMIC_TYPE_ARG, &value); + ret = es83xx_dsm(dev, PLATFORM_HPDET_INV_ARG, &value); if (ret < 0) return ret; - dev_info(dev, "PLATFORM_MAINMIC_TYPE %#x\n", value); - - ret = es83xx_dsm(dev, PLATFORM_HPMIC_TYPE_ARG, &value); - if (ret < 0) - return ret; - dev_info(dev, "PLATFORM_HPMIC_TYPE %#x\n", value); - - ret = es83xx_dsm(dev, PLATFORM_SPK_TYPE_ARG, &value); - if (ret < 0) - return ret; - dev_info(dev, "PLATFORM_SPK_TYPE %#x\n", value); - - ret = es83xx_dsm(dev, PLATFORM_HPDET_INV_ARG, &value); - if (ret < 0) - return ret; - dev_info(dev, "PLATFORM_HPDET_INV %#x\n", value); - - ret = es83xx_dsm(dev, PLATFORM_PCM_TYPE_ARG, &value); - if (ret < 0) - return ret; - dev_info(dev, "PLATFORM_PCM_TYPE %#x\n", value); - - ret = es83xx_dsm(dev, PLATFORM_MIC_DE_POP_ARG, &value); - if (ret < 0) - return ret; - dev_info(dev, "PLATFORM_MIC_DE_POP %#x\n", value); - - return 0; + dev_info(dev, "HP jack detect inverted %d\n", value); + return value; } -EXPORT_SYMBOL_GPL(es83xx_dsm_dump); +EXPORT_SYMBOL_GPL(es83xx_dsm_jack_inverted); MODULE_DESCRIPTION("Everest Semi ES83xx DSM helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es83xx-dsm-common.h b/sound/soc/codecs/es83xx-dsm-common.h index 5c33c329bd88e4..32f20e1fdbf2df 100644 --- a/sound/soc/codecs/es83xx-dsm-common.h +++ b/sound/soc/codecs/es83xx-dsm-common.h @@ -388,9 +388,9 @@ */ #if IS_ENABLED(CONFIG_ACPI) -int es83xx_dsm_dump(struct device *dev); +int es83xx_dsm_jack_inverted(struct device *dev); #else -static inline int es83xx_dsm_dump(struct device *dev) { return 0; }; +static inline int es83xx_dsm_jack_inverted(struct device *dev) { return 0; } #endif #endif From 60adcaba2466befddaa1176ccadc3fc7a7946856 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 7 Dec 2022 14:52:24 -0600 Subject: [PATCH 03/13] ASoC: es8326: use _DSM to invert jack detection Read jack detection information from _DSM and pre-set value. The value may be overridden with a property set by the machine driver. [mchehab: only override JD inverted from _DSM if quirks is enabled] Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/es8326.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index fa890f6205e2a8..3266d6e2639a27 100755 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -17,6 +17,7 @@ #include #include #include "es8326.h" +#include "es83xx-dsm-common.h" struct es8326_priv { struct clk *mclk; @@ -907,8 +908,9 @@ static int es8326_probe(struct snd_soc_component *component) int ret; es8326->component = component; - es8326->jd_inverted = device_property_read_bool(component->dev, - "everest,jack-detect-inverted"); + if (device_property_read_bool(component->dev, + "everest,jack-detect-inverted")) + es8326->jd_inverted = true; ret = device_property_read_u8(component->dev, "everest,mic1-src", &es8326->mic1_src); if (ret != 0) { @@ -1020,6 +1022,7 @@ static const struct snd_soc_component_driver soc_component_dev_es8326 = { static int es8326_i2c_probe(struct i2c_client *i2c) { + struct device *dev = &i2c->dev; struct es8326_priv *es8326; int ret; @@ -1027,6 +1030,14 @@ static int es8326_i2c_probe(struct i2c_client *i2c) if (!es8326) return -ENOMEM; + /* read jack information from _DSM */ + ret = es83xx_dsm_jack_inverted(dev); + if (ret < 0) + dev_warn(dev, "%s: Could not get jack detection information with ACPI _DSM method\n", + __func__); + else + es8326->jd_inverted = ret; + i2c_set_clientdata(i2c, es8326); es8326->i2c = i2c; mutex_init(&es8326->lock); From c0e14435914f2594e298915b462813eaabae412a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 20 Dec 2022 02:45:36 -0300 Subject: [PATCH 04/13] ASoC: es83xx: dump debug info for _DSM ACPI data The ACPI entry for es83xx should contain its configuration at _DSM. It is helpful to debug problems by looking on its contents. So, add a debug function that outputs its contents as read by the Kernel. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/codecs/es8316.c | 2 + sound/soc/codecs/es8326.c | 2 + sound/soc/codecs/es83xx-dsm-common.c | 242 +++++++++++++++++++++++++++ sound/soc/codecs/es83xx-dsm-common.h | 2 + 4 files changed, 248 insertions(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index daccf643c2f414..37985b79677011 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -865,6 +865,8 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client) if (es8316 == NULL) return -ENOMEM; + es83xx_dsm_dump(dev); + /* read jack information from _DSM */ ret = es83xx_dsm_jack_inverted(dev); if (ret < 0) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 3266d6e2639a27..8e95a502721e04 100755 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -1030,6 +1030,8 @@ static int es8326_i2c_probe(struct i2c_client *i2c) if (!es8326) return -ENOMEM; + es83xx_dsm_dump(dev); + /* read jack information from _DSM */ ret = es83xx_dsm_jack_inverted(dev); if (ret < 0) diff --git a/sound/soc/codecs/es83xx-dsm-common.c b/sound/soc/codecs/es83xx-dsm-common.c index e5ab599ac2c656..f7b1d0e41ca786 100644 --- a/sound/soc/codecs/es83xx-dsm-common.c +++ b/sound/soc/codecs/es83xx-dsm-common.c @@ -45,6 +45,248 @@ static int es83xx_dsm(struct device *dev, int arg, int *value) return ret; } +void es83xx_dsm_dump(struct device *dev) +{ + int value; + int ret; + + /* + * The _DSM method returns 0xff if the argument is not handled. + */ + dev_dbg(dev, "=========== EM83XX ACPI _DSM TABLE DUMP ==========="); + + ret = es83xx_dsm(dev, PLATFORM_MAINMIC_TYPE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_MAINMIC_TYPE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_HPMIC_TYPE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_HPMIC_TYPE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_SPK_TYPE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_SPK_TYPE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_HPDET_INV_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_HPDET_INV_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_PCM_TYPE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_PCM_TYPE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_MIC_DE_POP_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_MIC_DE_POP_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_CODEC_TYPE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_CODEC_TYPE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_BUS_SLOT_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_BUS_SLOT_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_LINEIN_PGA_GAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_LINEIN_PGA_GAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_LINEIN_PGA_GAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_LINEIN_PGA_GAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_D2SEPGA_GAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_D2SEPGA_GAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_D2SEPGA_GAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_D2SEPGA_GAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_ENABLE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_ENABLE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_ENABLE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_ENABLE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_TARGET_LEVEL_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_TARGET_LEVEL_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_TARGET_LEVEL_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_TARGET_LEVEL_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_MAXGAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_MAXGAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_MAXGAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_MAXGAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_MINGAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_MINGAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_MINGAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_MINGAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_HLDTIME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_HLDTIME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_HLDTIME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_HLDTIME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_DCYTIME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_DCYTIME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_DCYTIME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_DCYTIME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_ATKTIME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_ATKTIME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_ATKTIME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_ATKTIME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_NGTYPE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_NGTYPE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_NGTYPE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_NGTYPE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_ADC_ALC_NGTHLD_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_ADC_ALC_NGTHLD_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_ALC_NGTHLD_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_ALC_NGTHLD_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_GUI_STEP_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_GUI_STEP_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, MAIN_CODEC_ADC_GUI_GAIN_RANGE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "MAIN_CODEC_ADC_GUI_GAIN_RANGE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HEADPHONE_DUMMY_REMOVE_ENABLE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HEADPHONE_DUMMY_REMOVE_ENABLE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_DAC_HPMIX_HIGAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_DAC_HPMIX_HIGAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, SPK_CODEC_DAC_HPMIX_HIGAIN_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "SPK_CODEC_DAC_HPMIX_HIGAIN_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_DAC_HPMIX_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_DAC_HPMIX_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, SPK_CODEC_DAC_HPMIX_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "SPK_CODEC_DAC_HPMIX_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_DAC_HPOUT_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_DAC_HPOUT_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, SPK_CODEC_DAC_HPOUT_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "SPK_CODEC_DAC_HPOUT_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_LDAC_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_LDAC_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_RDAC_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_RDAC_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, SPK_CODEC_LDAC_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "SPK_CODEC_LDAC_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, SPK_CODEC_RDAC_VOLUME_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "SPK_CODEC_RDAC_VOLUME_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_DAC_AUTOMUTE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_DAC_AUTOMUTE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, SPK_CODEC_DAC_AUTOMUTE_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "SPK_CODEC_DAC_AUTOMUTE_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CODEC_DAC_MONO_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CODEC_DAC_MONO_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, SPK_CODEC_DAC_MONO_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "SPK_CODEC_DAC_MONO_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, HP_CTL_IO_LEVEL_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "HP_CTL_IO_LEVEL_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, SPK_CTL_IO_LEVEL_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "SPK_CTL_IO_LEVEL_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, CODEC_GPIO0_FUNC_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "CODEC_GPIO0_FUNC_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, CODEC_GPIO1_FUNC_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "CODEC_GPIO1_FUNC_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, CODEC_GPIO2_FUNC_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "CODEC_GPIO2_FUNC_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, CODEC_GPIO3_FUNC_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "CODEC_GPIO3_FUNC_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, CODEC_GPIO4_FUNC_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "CODEC_GPIO4_FUNC_ARG=%#x\n", value); + + ret = es83xx_dsm(dev, PLATFORM_MCLK_LRCK_FREQ_ARG, &value); + if (ret >= 0 && value != 0xff) + dev_dbg(dev, "PLATFORM_MCLK_LRCK_FREQ_ARG=%#x\n", value); + + dev_dbg(dev, "==================================================="); +} +EXPORT_SYMBOL_GPL(es83xx_dsm_dump); + int es83xx_dsm_jack_inverted(struct device *dev) { int value; diff --git a/sound/soc/codecs/es83xx-dsm-common.h b/sound/soc/codecs/es83xx-dsm-common.h index 32f20e1fdbf2df..3d9567df1fe4c4 100644 --- a/sound/soc/codecs/es83xx-dsm-common.h +++ b/sound/soc/codecs/es83xx-dsm-common.h @@ -388,8 +388,10 @@ */ #if IS_ENABLED(CONFIG_ACPI) +void es83xx_dsm_dump(struct device *dev); int es83xx_dsm_jack_inverted(struct device *dev); #else +static inline void es83xx_dsm_dump(struct device *dev) {}; static inline int es83xx_dsm_jack_inverted(struct device *dev) { return 0; } #endif From 2d30bed483399fc9d28895437b48bc93eecc7b1a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 20 Dec 2022 04:55:34 -0300 Subject: [PATCH 05/13] ASoC: es83xx: add logic to detect GPIO levels The enable GPIOs can either be low or high level activated. Add a logic to detect it from _DSM. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/codecs/es83xx-dsm-common.c | 33 ++++++++++++++++++++++++++++ sound/soc/codecs/es83xx-dsm-common.h | 3 +++ 2 files changed, 36 insertions(+) diff --git a/sound/soc/codecs/es83xx-dsm-common.c b/sound/soc/codecs/es83xx-dsm-common.c index f7b1d0e41ca786..29c3eeee7ef42e 100644 --- a/sound/soc/codecs/es83xx-dsm-common.c +++ b/sound/soc/codecs/es83xx-dsm-common.c @@ -300,5 +300,38 @@ int es83xx_dsm_jack_inverted(struct device *dev) } EXPORT_SYMBOL_GPL(es83xx_dsm_jack_inverted); +int es83xx_dsm_is_gpio_level_low(struct device *dev, bool is_spk) +{ + int value; + int ret; + const char *type; + + if (is_spk) { + type = "Speaker"; + ret = es83xx_dsm(dev, SPK_CTL_IO_LEVEL_ARG, &value); + } else { + type = "Headphone"; + ret = es83xx_dsm(dev, HP_CTL_IO_LEVEL_ARG, &value); + } + + if (ret < 0) { + dev_err(dev, "%s: Can't read I/O ctl level argument\n", type); + return ret; + } + + switch (value) { + case GPIO_CTL_IO_LEVEL_HIGH: + case 0xff: + return 0; + case GPIO_CTL_IO_LEVEL_LOW: + return 1; + default: + dev_err(dev, "%s: invalid I/O ctl level argument (%d)\n", + type, value); + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(es83xx_dsm_is_gpio_level_low); + MODULE_DESCRIPTION("Everest Semi ES83xx DSM helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es83xx-dsm-common.h b/sound/soc/codecs/es83xx-dsm-common.h index 3d9567df1fe4c4..b1e4bdef85a707 100644 --- a/sound/soc/codecs/es83xx-dsm-common.h +++ b/sound/soc/codecs/es83xx-dsm-common.h @@ -390,9 +390,12 @@ #if IS_ENABLED(CONFIG_ACPI) void es83xx_dsm_dump(struct device *dev); int es83xx_dsm_jack_inverted(struct device *dev); +int es83xx_dsm_is_gpio_level_low(struct device *dev, bool is_spk); + #else static inline void es83xx_dsm_dump(struct device *dev) {}; static inline int es83xx_dsm_jack_inverted(struct device *dev) { return 0; } +static inline int es83xx_dsm_is_gpio_level_low(struct device *dev, bool is_spk) { return 0; } #endif #endif From 349bfdd88be5cad29a0ec0cd9a825e871c5cff5c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 20 Dec 2022 13:40:19 +0000 Subject: [PATCH 06/13] ASoC: es83xx: add logic to detect microphone type The _DSM method has an entry to detect the microphone type, and where they're attached. Add support for checking it. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/codecs/es83xx-dsm-common.c | 33 ++++++++++++++++++++++++++++ sound/soc/codecs/es83xx-dsm-common.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/sound/soc/codecs/es83xx-dsm-common.c b/sound/soc/codecs/es83xx-dsm-common.c index 29c3eeee7ef42e..e162b14d1a2e94 100644 --- a/sound/soc/codecs/es83xx-dsm-common.c +++ b/sound/soc/codecs/es83xx-dsm-common.c @@ -333,5 +333,38 @@ int es83xx_dsm_is_gpio_level_low(struct device *dev, bool is_spk) } EXPORT_SYMBOL_GPL(es83xx_dsm_is_gpio_level_low); +int es83xx_dsm_mic_type(struct device *dev, bool is_main) +{ + int value; + int ret; + const char *type; + + if (is_main) { + type = "main"; + ret = es83xx_dsm(dev, PLATFORM_MAINMIC_TYPE_ARG, &value); + } else { + type = "headset"; + ret = es83xx_dsm(dev, PLATFORM_HPMIC_TYPE_ARG, &value); + } + + if (ret < 0) { + dev_err(dev, "Can't read %s microphone type\n", type); + return ret; + } + + switch (value) { + case PLATFORM_MIC_DMIC_HIGH_LEVEL: + case PLATFORM_MIC_DMIC_LOW_LEVEL: + case PLATFORM_MIC_AMIC_LIN1RIN1: + case PLATFORM_MIC_AMIC_LIN2RIN2: + return value; + default: + dev_err(dev, "Invalid value for %s microphone type (%d)\n", + type, value); + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(es83xx_dsm_mic_type); + MODULE_DESCRIPTION("Everest Semi ES83xx DSM helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es83xx-dsm-common.h b/sound/soc/codecs/es83xx-dsm-common.h index b1e4bdef85a707..041a809e600b10 100644 --- a/sound/soc/codecs/es83xx-dsm-common.h +++ b/sound/soc/codecs/es83xx-dsm-common.h @@ -391,11 +391,13 @@ void es83xx_dsm_dump(struct device *dev); int es83xx_dsm_jack_inverted(struct device *dev); int es83xx_dsm_is_gpio_level_low(struct device *dev, bool is_spk); +int es83xx_dsm_mic_type(struct device *dev, bool is_main); #else static inline void es83xx_dsm_dump(struct device *dev) {}; static inline int es83xx_dsm_jack_inverted(struct device *dev) { return 0; } static inline int es83xx_dsm_is_gpio_level_low(struct device *dev, bool is_spk) { return 0; } +static inline int es83xx_dsm_mic_type(struct device *dev, bool is_main) { return 0; } #endif #endif From ea8b0a62f8301aa7d292617ee6d4407a4e12c103 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 20 Dec 2022 05:06:40 -0300 Subject: [PATCH 07/13] ASoC: es8336: autodetect GPIO enable levels for speaker and headphone Now that we can read GPIO enable level from ACPI _DSM, use it to properly set the right GPIO levels. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/intel/boards/sof_es8336.c | 106 +++++++++++++++------------- 1 file changed, 57 insertions(+), 49 deletions(-) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index c1fcc156a5752c..0a445550bdb5cd 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -20,6 +20,7 @@ #include #include #include "hda_dsp_common.h" +#include "../../codecs/es83xx-dsm-common.h" /* jd-inv + terminating entry */ #define MAX_NO_PROPS 2 @@ -48,7 +49,6 @@ #define SOF_ES8336_ENABLE_DMIC BIT(5) #define SOF_ES8336_JD_INVERTED BIT(6) -#define SOF_ES8336_HEADPHONE_GPIO BIT(7) #define SOC_ES8336_HEADSET_MIC1 BIT(8) static unsigned long quirk; @@ -64,6 +64,9 @@ struct sof_es8336_private { struct list_head hdmi_pcm_list; bool speaker_en; struct delayed_work pcm_pop_work; + + struct acpi_gpio_params enable_spk_gpio, enable_hp_gpio; + struct acpi_gpio_mapping gpio_mapping[3]; }; struct sof_hdmi_pcm { @@ -72,30 +75,6 @@ struct sof_hdmi_pcm { int device; }; -static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true }; -static const struct acpi_gpio_params enable_gpio1 = { 1, 0, true }; - -static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = { - { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, - { } -}; - -static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = { - { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, -}; - -static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = { - { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, - { "headphone-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, - { } -}; - -static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = { - { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, - { "headphone-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, - { } -}; - static void log_quirks(struct device *dev) { dev_info(dev, "quirk mask %#lx\n", quirk); @@ -104,8 +83,6 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk DMIC enabled\n"); if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) dev_info(dev, "Speakers GPIO1 quirk enabled\n"); - if (quirk & SOF_ES8336_HEADPHONE_GPIO) - dev_info(dev, "quirk headphone GPIO enabled\n"); if (quirk & SOF_ES8336_JD_INVERTED) dev_info(dev, "quirk JD inverted enabled\n"); if (quirk & SOC_ES8336_HEADSET_MIC1) @@ -118,10 +95,7 @@ static void pcm_pop_work_events(struct work_struct *work) container_of(work, struct sof_es8336_private, pcm_pop_work.work); gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en); - - if (quirk & SOF_ES8336_HEADPHONE_GPIO) - gpiod_set_value_cansleep(priv->gpio_headphone, priv->speaker_en); - + gpiod_set_value_cansleep(priv->gpio_headphone, !priv->speaker_en); } static int sof_8336_trigger(struct snd_pcm_substream *substream, int cmd) @@ -139,10 +113,11 @@ static int sof_8336_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: - if (priv->speaker_en == false) + if (priv->speaker_en == true) if (substream->stream == 0) { cancel_delayed_work(&priv->pcm_pop_work); - gpiod_set_value_cansleep(priv->gpio_speakers, true); + gpiod_set_value_cansleep(priv->gpio_speakers, 0); + gpiod_set_value_cansleep(priv->gpio_headphone, 0); } break; default: @@ -158,10 +133,10 @@ static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, struct snd_soc_card *card = w->dapm->card; struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); - if (priv->speaker_en == !SND_SOC_DAPM_EVENT_ON(event)) + if (priv->speaker_en == SND_SOC_DAPM_EVENT_ON(event)) return 0; - priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event); + priv->speaker_en = SND_SOC_DAPM_EVENT_ON(event); queue_delayed_work(system_wq, &priv->pcm_pop_work, msecs_to_jiffies(70)); return 0; @@ -346,7 +321,7 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), DMI_MATCH(DMI_BOARD_NAME, "BOHB-WAX9-PCB-B2"), }, - .driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO | + .driver_data = (void *)(SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | SOC_ES8336_HEADSET_MIC1) }, {} @@ -598,7 +573,6 @@ static int sof_es8336_probe(struct platform_device *pdev) struct acpi_device *adev; struct snd_soc_dai_link *dai_links; struct device *codec_dev; - const struct acpi_gpio_mapping *gpio_mapping; unsigned int cnt = 0; int dmic_be_num = 0; int hdmi_num = 3; @@ -717,30 +691,64 @@ static int sof_es8336_probe(struct platform_device *pdev) } } - /* get speaker enable GPIO */ - if (quirk & SOF_ES8336_HEADPHONE_GPIO) { - if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) - gpio_mapping = acpi_enable_both_gpios; - else - gpio_mapping = acpi_enable_both_gpios_rev_order; - } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) { - gpio_mapping = acpi_speakers_enable_gpio1; + if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) { + priv->enable_spk_gpio.crs_entry_index = 1; + priv->enable_hp_gpio.crs_entry_index = 0; } else { - gpio_mapping = acpi_speakers_enable_gpio0; + priv->enable_spk_gpio.crs_entry_index = 0; + priv->enable_hp_gpio.crs_entry_index = 1; } - ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping); + ret = es83xx_dsm_is_gpio_level_low(priv->codec_dev, true); + if (ret < 0) { + put_device(codec_dev); + return ret; + } else if (ret > 0) { + priv->enable_spk_gpio.active_low = true; + } else { + priv->enable_spk_gpio.active_low = false; + } + + ret = es83xx_dsm_is_gpio_level_low(priv->codec_dev, false); + if (ret < 0) { + put_device(codec_dev); + return ret; + } else if (ret > 0) { + priv->enable_hp_gpio.active_low = true; + } else { + priv->enable_hp_gpio.active_low = false; + } + + priv->gpio_mapping[0].name = "speakers-enable-gpios"; + priv->gpio_mapping[0].data = &priv->enable_spk_gpio; + priv->gpio_mapping[0].size = 1; + priv->gpio_mapping[0].quirks = ACPI_GPIO_QUIRK_ONLY_GPIOIO; + + priv->gpio_mapping[1].name = "headphone-enable-gpios"; + priv->gpio_mapping[1].data = &priv->enable_hp_gpio; + priv->gpio_mapping[1].size = 1; + priv->gpio_mapping[1].quirks = ACPI_GPIO_QUIRK_ONLY_GPIOIO; + + dev_info(codec_dev, "speaker gpio %d active %s, headphone gpio %d active %s\n", + priv->enable_spk_gpio.crs_entry_index, + priv->enable_spk_gpio.active_low ? "low" : "high", + priv->enable_hp_gpio.crs_entry_index, + priv->enable_hp_gpio.active_low ? "low" : "high"); + + ret = devm_acpi_dev_add_driver_gpios(codec_dev, priv->gpio_mapping); if (ret) dev_warn(codec_dev, "unable to add GPIO mapping table\n"); - priv->gpio_speakers = gpiod_get_optional(codec_dev, "speakers-enable", GPIOD_OUT_LOW); + priv->gpio_speakers = gpiod_get_optional(codec_dev, "speakers-enable", + priv->enable_spk_gpio.active_low ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH); if (IS_ERR(priv->gpio_speakers)) { ret = dev_err_probe(dev, PTR_ERR(priv->gpio_speakers), "could not get speakers-enable GPIO\n"); goto err_put_codec; } - priv->gpio_headphone = gpiod_get_optional(codec_dev, "headphone-enable", GPIOD_OUT_LOW); + priv->gpio_headphone = gpiod_get_optional(codec_dev, "headphone-enable", + priv->enable_hp_gpio.active_low ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH); if (IS_ERR(priv->gpio_headphone)) { ret = dev_err_probe(dev, PTR_ERR(priv->gpio_headphone), "could not get headphone-enable GPIO\n"); From 035abffff02b3984694460f1b51ce41194fa5c47 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 29 Dec 2023 16:47:14 +0000 Subject: [PATCH 08/13] ASoC: es8336: allow overriding _DSM for enable on low/high Sometimes, the ACPI _DSM may not have a valuet set for enable on low/high. So, a call to auto-detect it via: es83xx_dsm(dev, SPK_CTL_IO_LEVEL_ARG, &value); and: es83xx_dsm(dev, HP_CTL_IO_LEVEL_ARG, &value); returns 0xff. By default, when this is not defined, the logic sets to GPIO_CTL_IO_LEVEL_HIGH, which matches the expected behavior. However, at least on Huawei Matebook D15 (BOHB-WAX9), setting them both to GPIO_CTL_IO_LEVEL_HIGH is wrong. So, add a quirk to ignore BIOS value for such fields. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/intel/boards/sof_es8336.c | 57 ++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index 0a445550bdb5cd..d5b8662fbef64e 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -50,6 +50,9 @@ #define SOF_ES8336_ENABLE_DMIC BIT(5) #define SOF_ES8336_JD_INVERTED BIT(6) #define SOC_ES8336_HEADSET_MIC1 BIT(8) +#define SOF_ES8336_OVERRIDE_DSM_LOW_HIGH BIT(9) +#define SOF_ES8336_SPK_EN_LOW BIT(10) +#define SOF_ES8336_HP_EN_LOW BIT(11) static unsigned long quirk; @@ -87,6 +90,12 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk JD inverted enabled\n"); if (quirk & SOC_ES8336_HEADSET_MIC1) dev_info(dev, "quirk headset at mic1 port enabled\n"); + if (quirk & SOF_ES8336_OVERRIDE_DSM_LOW_HIGH) { + dev_info(dev, "quirk speaker enabled on %s\n", + quirk & SOF_ES8336_SPK_EN_LOW ? "low" : "high"); + dev_info(dev, "quirk headset enabled on %s\n", + quirk & SOF_ES8336_HP_EN_LOW ? "low" : "high"); + } } static void pcm_pop_work_events(struct work_struct *work) @@ -322,7 +331,10 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "BOHB-WAX9-PCB-B2"), }, .driver_data = (void *)(SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | - SOC_ES8336_HEADSET_MIC1) + SOC_ES8336_HEADSET_MIC1 | + SOF_ES8336_OVERRIDE_DSM_LOW_HIGH | + SOF_ES8336_HP_EN_LOW) + }, {} }; @@ -699,24 +711,35 @@ static int sof_es8336_probe(struct platform_device *pdev) priv->enable_hp_gpio.crs_entry_index = 1; } - ret = es83xx_dsm_is_gpio_level_low(priv->codec_dev, true); - if (ret < 0) { - put_device(codec_dev); - return ret; - } else if (ret > 0) { - priv->enable_spk_gpio.active_low = true; + /* + * On some devices, _DSM is not reliable for + * Speader/headsed active on low/high. So, allow overriding + * it via a quirk. + */ + if (quirk & SOF_ES8336_OVERRIDE_DSM_LOW_HIGH) { + priv->enable_spk_gpio.active_low = quirk & SOF_ES8336_SPK_EN_LOW ? true : false; + priv->enable_hp_gpio.active_low = quirk & SOF_ES8336_HP_EN_LOW ? true : false; } else { - priv->enable_spk_gpio.active_low = false; - } + /* Use _DSM data to set active_low state */ + ret = es83xx_dsm_is_gpio_level_low(priv->codec_dev, true); + if (ret < 0) { + put_device(codec_dev); + return ret; + } else if (ret > 0) { + priv->enable_spk_gpio.active_low = true; + } else { + priv->enable_spk_gpio.active_low = false; + } - ret = es83xx_dsm_is_gpio_level_low(priv->codec_dev, false); - if (ret < 0) { - put_device(codec_dev); - return ret; - } else if (ret > 0) { - priv->enable_hp_gpio.active_low = true; - } else { - priv->enable_hp_gpio.active_low = false; + ret = es83xx_dsm_is_gpio_level_low(priv->codec_dev, false); + if (ret < 0) { + put_device(codec_dev); + return ret; + } else if (ret > 0) { + priv->enable_hp_gpio.active_low = true; + } else { + priv->enable_hp_gpio.active_low = false; + } } priv->gpio_mapping[0].name = "speakers-enable-gpios"; From 28c8986c1b364bd21ae84721349d29ec762d1676 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 31 Dec 2023 10:00:28 +0000 Subject: [PATCH 09/13] AsoC: es8336: move card_dev init to happen earlier at probe We need that to retrieve data from _DSM table, on an early check at the driver probe time. So, move the code to the beginning of the function. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/intel/boards/sof_es8336.c | 35 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index d5b8662fbef64e..c3ef7fe006465f 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -597,6 +597,17 @@ static int sof_es8336_probe(struct platform_device *pdev) card = &sof_es8336_card; card->dev = dev; + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (!adev) { + dev_err(dev, "Error cannot find '%s' dev\n", mach->id); + return -ENXIO; + } + codec_dev = acpi_get_first_physical_node(adev); + acpi_dev_put(adev); + if (!codec_dev) + return -EPROBE_DEFER; + priv->codec_dev = get_device(codec_dev); + if (pdev->id_entry && pdev->id_entry->driver_data) quirk = (unsigned long)pdev->id_entry->driver_data; @@ -656,25 +667,13 @@ static int sof_es8336_probe(struct platform_device *pdev) sof_es8336_card.dai_link = dai_links; /* fixup codec name based on HID */ - adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); - if (adev) { - snprintf(codec_name, sizeof(codec_name), - "i2c-%s", acpi_dev_name(adev)); - dai_links[0].codecs->name = codec_name; - - /* also fixup codec dai name if relevant */ - if (!strncmp(mach->id, "ESSX8326", SND_ACPI_I2C_ID_LEN)) - dai_links[0].codecs->dai_name = "ES8326 HiFi"; - } else { - dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; - } + snprintf(codec_name, sizeof(codec_name), + "i2c-%s", acpi_dev_name(adev)); + dai_links[0].codecs->name = codec_name; - codec_dev = acpi_get_first_physical_node(adev); - acpi_dev_put(adev); - if (!codec_dev) - return -EPROBE_DEFER; - priv->codec_dev = get_device(codec_dev); + /* also fixup codec dai name if relevant */ + if (!strncmp(mach->id, "ESSX8326", SND_ACPI_I2C_ID_LEN)) + dai_links[0].codecs->dai_name = "ES8326 HiFi"; ret = snd_soc_fixup_dai_links_platform_name(&sof_es8336_card, mach->mach_params.platform); From 772a4f9bfebe528c24f7d3abf490e50b096abc05 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 20 Dec 2022 13:40:19 +0000 Subject: [PATCH 10/13] ASoC: es8336: autodetect analog microphone ports Use the _DSM data to fill the analog microphone ports, removing another quirk. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/intel/boards/sof_es8336.c | 62 ++++++++++++++++------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index c3ef7fe006465f..0ec24806fdde59 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -49,7 +49,6 @@ #define SOF_ES8336_ENABLE_DMIC BIT(5) #define SOF_ES8336_JD_INVERTED BIT(6) -#define SOC_ES8336_HEADSET_MIC1 BIT(8) #define SOF_ES8336_OVERRIDE_DSM_LOW_HIGH BIT(9) #define SOF_ES8336_SPK_EN_LOW BIT(10) #define SOF_ES8336_HP_EN_LOW BIT(11) @@ -70,6 +69,8 @@ struct sof_es8336_private { struct acpi_gpio_params enable_spk_gpio, enable_hp_gpio; struct acpi_gpio_mapping gpio_mapping[3]; + struct snd_soc_dapm_route mic_map[2]; + int num_routes; }; struct sof_hdmi_pcm { @@ -88,8 +89,6 @@ static void log_quirks(struct device *dev) dev_info(dev, "Speakers GPIO1 quirk enabled\n"); if (quirk & SOF_ES8336_JD_INVERTED) dev_info(dev, "quirk JD inverted enabled\n"); - if (quirk & SOC_ES8336_HEADSET_MIC1) - dev_info(dev, "quirk headset at mic1 port enabled\n"); if (quirk & SOF_ES8336_OVERRIDE_DSM_LOW_HIGH) { dev_info(dev, "quirk speaker enabled on %s\n", quirk & SOF_ES8336_SPK_EN_LOW ? "low" : "high"); @@ -179,16 +178,6 @@ static const struct snd_soc_dapm_route sof_es8316_audio_map[] = { {"Speaker", NULL, "Speaker Power"}, }; -static const struct snd_soc_dapm_route sof_es8316_headset_mic2_map[] = { - {"MIC1", NULL, "Internal Mic"}, - {"MIC2", NULL, "Headset Mic"}, -}; - -static const struct snd_soc_dapm_route sof_es8316_headset_mic1_map[] = { - {"MIC2", NULL, "Internal Mic"}, - {"MIC1", NULL, "Headset Mic"}, -}; - static const struct snd_soc_dapm_route dmic_map[] = { /* digital mics */ {"DMic", NULL, "SoC DMIC"}, @@ -256,21 +245,15 @@ static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; struct snd_soc_card *card = runtime->card; struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); - const struct snd_soc_dapm_route *custom_map; - int num_routes; - int ret; + int i, ret; card->dapm.idle_bias_off = true; - if (quirk & SOC_ES8336_HEADSET_MIC1) { - custom_map = sof_es8316_headset_mic1_map; - num_routes = ARRAY_SIZE(sof_es8316_headset_mic1_map); - } else { - custom_map = sof_es8316_headset_mic2_map; - num_routes = ARRAY_SIZE(sof_es8316_headset_mic2_map); - } + for (i = 0; i < priv->num_routes; i++) + dev_info(card->dev, "%s is %s\n", + priv->mic_map[i].source, priv->mic_map[i].sink); - ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(&card->dapm, priv->mic_map, priv->num_routes); if (ret) return ret; @@ -331,7 +314,6 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "BOHB-WAX9-PCB-B2"), }, .driver_data = (void *)(SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | - SOC_ES8336_HEADSET_MIC1 | SOF_ES8336_OVERRIDE_DSM_LOW_HIGH | SOF_ES8336_HP_EN_LOW) @@ -638,8 +620,32 @@ static int sof_es8336_probe(struct platform_device *pdev) } } - if (mach->mach_params.dmic_num) - quirk |= SOF_ES8336_ENABLE_DMIC; + /* + * Check if DMIC is not enabled, as the _DSM table may be + * reporting a non-existent AMIC. + */ + if (!(quirk & SOF_ES8336_ENABLE_DMIC)) { + ret = es83xx_dsm_mic_type(priv->codec_dev, true); + if (ret == PLATFORM_MIC_AMIC_LIN1RIN1) { + priv->mic_map[priv->num_routes].sink = "MIC1"; + priv->mic_map[priv->num_routes].source = "Internal Mic"; + priv->num_routes++; + } else if (ret == PLATFORM_MIC_AMIC_LIN2RIN2) { + priv->mic_map[priv->num_routes].sink = "MIC2"; + priv->mic_map[priv->num_routes].source = "Internal Mic"; + } + } + + ret = es83xx_dsm_mic_type(priv->codec_dev, false); + if (ret == PLATFORM_MIC_AMIC_LIN1RIN1) { + priv->mic_map[priv->num_routes].sink = "MIC1"; + priv->mic_map[priv->num_routes].source = "Headset Mic"; + priv->num_routes++; + } else if (ret == PLATFORM_MIC_AMIC_LIN2RIN2) { + priv->mic_map[priv->num_routes].sink = "MIC2"; + priv->mic_map[priv->num_routes].source = "Headset Mic"; + priv->num_routes++; + } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n", @@ -648,7 +654,7 @@ static int sof_es8336_probe(struct platform_device *pdev) } log_quirks(dev); - if (quirk & SOF_ES8336_ENABLE_DMIC) + if (quirk & SOF_ES8336_ENABLE_DMIC || mach->mach_params.dmic_num > 0) dmic_be_num = 2; /* compute number of dai links */ From de66690ed09312123c3ee2bbffd96712288b7115 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Dec 2022 09:56:50 +0000 Subject: [PATCH 11/13] ASoC: es8336: ensure that GPIOs will be set at start streaming As the headphone could be plugged or unplugged any time, including when not streaming, and the stop/suspend events may be turning GPIOs to disable both headphones and speakers, let the delayed workqueue to be called every time Speaker supply event happens. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/intel/boards/sof_es8336.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index 0ec24806fdde59..c14591276a138f 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -141,12 +141,9 @@ static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, struct snd_soc_card *card = w->dapm->card; struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); - if (priv->speaker_en == SND_SOC_DAPM_EVENT_ON(event)) - return 0; - priv->speaker_en = SND_SOC_DAPM_EVENT_ON(event); - queue_delayed_work(system_wq, &priv->pcm_pop_work, msecs_to_jiffies(70)); + return 0; } From 1e44863012513d559ff0650dbf97fb5306b27fdb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 30 Dec 2023 15:43:22 +0000 Subject: [PATCH 12/13] ASoC: es8336: don't invert jack detection on Huawei D15 Despite what DSM reports, jack detection is not inverted on this device. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/codecs/es8316.c | 3 +++ sound/soc/intel/boards/sof_es8336.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 37985b79677011..6d48eb99071d4d 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -694,6 +694,9 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component, if (device_property_read_bool(component->dev, "everest,jack-detect-inverted")) es8316->jd_inverted = true; + if (device_property_read_bool(component->dev, + "everest,jack-detect-not-inverted")) + es8316->jd_inverted = false; mutex_lock(&es8316->lock); diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index c14591276a138f..cf0992da621c02 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -52,6 +52,7 @@ #define SOF_ES8336_OVERRIDE_DSM_LOW_HIGH BIT(9) #define SOF_ES8336_SPK_EN_LOW BIT(10) #define SOF_ES8336_HP_EN_LOW BIT(11) +#define SOF_ES8336_JD_NOT_INVERTED BIT(12) static unsigned long quirk; @@ -311,6 +312,7 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "BOHB-WAX9-PCB-B2"), }, .driver_data = (void *)(SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_NOT_INVERTED | SOF_ES8336_OVERRIDE_DSM_LOW_HIGH | SOF_ES8336_HP_EN_LOW) @@ -687,6 +689,9 @@ static int sof_es8336_probe(struct platform_device *pdev) if (quirk & SOF_ES8336_JD_INVERTED) props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted"); + else if (quirk & SOF_ES8336_JD_NOT_INVERTED) + props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-not-inverted"); + if (cnt) { fwnode = fwnode_create_software_node(props, NULL); From 64af6a25275f0c41dcc613653fa788e36a925703 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 30 Dec 2023 20:26:26 +0000 Subject: [PATCH 13/13] ASoC: es8336: Add support for Huawei Matebook 14 2021 This notebook also requires quirks as BIOS is incorrect for speaker/headset GPIOs. According with _DSM: [ 4.027413] es8316 i2c-ESSX8336:00: PLATFORM_HPDET_INV_ARG=0x1 However, jack is not inverted on this device. The speaker/headphone output on this device is: speaker gpio 0 active high, headphone gpio 1 active low However, _DSM reports only: [ 4.030564] es8316 i2c-ESSX8336:00: SPK_CTL_IO_LEVEL_ARG=0x1 Missing information about headphone active on low. Signed-off-by: Mauro Carvalho Chehab --- sound/soc/intel/boards/sof_es8336.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index cf0992da621c02..3a8b5d19b452e5 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -308,7 +308,7 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = { { .callback = sof_es8336_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), + DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), /* Matebook D15 2020 */ DMI_MATCH(DMI_BOARD_NAME, "BOHB-WAX9-PCB-B2"), }, .driver_data = (void *)(SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | @@ -316,6 +316,17 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = { SOF_ES8336_OVERRIDE_DSM_LOW_HIGH | SOF_ES8336_HP_EN_LOW) + }, + { + .callback = sof_es8336_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), /* Matebook 14 2021 */ + DMI_MATCH(DMI_BOARD_NAME, "NBD-WXX9-PCB-B3"), + }, + .driver_data = (void *)(SOF_ES8336_JD_NOT_INVERTED | + SOF_ES8336_OVERRIDE_DSM_LOW_HIGH| + SOF_ES8336_HP_EN_LOW) + }, {} };