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/es8316.c b/sound/soc/codecs/es8316.c index e53b2856d6250b..6d48eb99071d4d 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,13 @@ 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; + if (device_property_read_bool(component->dev, + "everest,jack-detect-not-inverted")) + es8316->jd_inverted = false; mutex_lock(&es8316->lock); @@ -862,6 +868,16 @@ 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) + 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/es8326.c b/sound/soc/codecs/es8326.c index fa890f6205e2a8..8e95a502721e04 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,16 @@ 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) + 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); diff --git a/sound/soc/codecs/es83xx-dsm-common.c b/sound/soc/codecs/es83xx-dsm-common.c new file mode 100644 index 00000000000000..e162b14d1a2e94 --- /dev/null +++ b/sound/soc/codecs/es83xx-dsm-common.c @@ -0,0 +1,370 @@ +// 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; +} + +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; + int ret; + + ret = es83xx_dsm(dev, PLATFORM_HPDET_INV_ARG, &value); + if (ret < 0) + return ret; + dev_info(dev, "HP jack detect inverted %d\n", value); + return value; +} +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); + +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 new file mode 100644 index 00000000000000..041a809e600b10 --- /dev/null +++ b/sound/soc/codecs/es83xx-dsm-common.h @@ -0,0 +1,403 @@ +/* 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) +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 diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index c1fcc156a5752c..3a8b5d19b452e5 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,8 +49,10 @@ #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) +#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; @@ -64,6 +67,11 @@ 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 snd_soc_dapm_route mic_map[2]; + int num_routes; }; struct sof_hdmi_pcm { @@ -72,30 +80,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,12 +88,14 @@ 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) - 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) @@ -118,10 +104,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 +122,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,12 +142,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); - + priv->speaker_en = SND_SOC_DAPM_EVENT_ON(event); queue_delayed_work(system_wq, &priv->pcm_pop_work, msecs_to_jiffies(70)); + return 0; } @@ -195,16 +176,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"}, @@ -272,21 +243,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; @@ -343,11 +308,25 @@ 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_HEADPHONE_GPIO | - SOC_ES8336_HEADSET_MIC1) + .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) + + }, + { + .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) + }, {} }; @@ -598,7 +577,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; @@ -611,6 +589,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; @@ -641,8 +630,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", @@ -651,7 +664,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 */ @@ -670,25 +683,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); @@ -699,6 +700,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); @@ -717,30 +721,75 @@ 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 { + priv->enable_spk_gpio.crs_entry_index = 0; + priv->enable_hp_gpio.crs_entry_index = 1; + } + + /* + * 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 { - gpio_mapping = acpi_speakers_enable_gpio0; + /* 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 = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping); + 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");