Commit efb1a2d3 authored by Mark Brown's avatar Mark Brown

ALSA/ASoC/SOF/Intel: improve support for ES8336-based platforms

Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

This patchset adds a number of improvements for ES8336-based Intel
platforms, which are not well supported at all in Linux. Since
Christmas 2021, we've seen dozens of reports of broken audio [1].

The fundamental problem is that those platforms were built for Windows
but using an I2S codec - instead of the HDaudio traditional
solution. As a result, we are missing all the usual information needed
to configure the audio card (which I2S, what configuration, DMICs or
not, etc). The situation is similar to Baytrail with all possible
permutations enabled.

Some of the information can be discovered by checking the contents of
the 'NHLT' ACPI table. This helps discover at run-time which SSP to
use, and the number of microphones present. This NHLT-based solution
helps remove quirks that were added earlier.

Unfortunately, there are still a number of platform properties that
are not described by ACPI, just as GPIOs used for speakers, jack
detection inversion, etc. For some case, quirks are still provided in
the machine drivers.

Additional work will likely be needed, e.g. to detect which MCLK needs
to be used, refine the UCM settings, add the ES8326 codec driver, but
this is a first-step towards an 'out of the box' experience on Intel
platforms.

This patchset touches the sound/hda/intel-nhlt parts but should IMHO
be merged in the ASoC tree.

I would like to acknowledge the help of Nikolai Kostrigin, Mauro
Carvalho Chehab, Huajun Li, David Yang (@yangxiaohua2009) and other
GitHub testers.

[1] https://github.com/thesofproject/linux/issues?q=is%3Aissue+is%3Aopen+label%3A%22codec+ES8336%22
parents 31ef579d fe0596a0
...@@ -18,6 +18,13 @@ enum nhlt_link_type { ...@@ -18,6 +18,13 @@ enum nhlt_link_type {
NHLT_LINK_INVALID NHLT_LINK_INVALID
}; };
enum nhlt_device_type {
NHLT_DEVICE_BT = 0,
NHLT_DEVICE_DMIC = 1,
NHLT_DEVICE_I2S = 4,
NHLT_DEVICE_INVALID
};
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
struct wav_fmt { struct wav_fmt {
...@@ -41,13 +48,6 @@ struct wav_fmt_ext { ...@@ -41,13 +48,6 @@ struct wav_fmt_ext {
u8 sub_fmt[16]; u8 sub_fmt[16];
} __packed; } __packed;
enum nhlt_device_type {
NHLT_DEVICE_BT = 0,
NHLT_DEVICE_DMIC = 1,
NHLT_DEVICE_I2S = 4,
NHLT_DEVICE_INVALID
};
struct nhlt_specific_cfg { struct nhlt_specific_cfg {
u32 size; u32 size;
u8 caps[]; u8 caps[];
...@@ -133,6 +133,9 @@ void intel_nhlt_free(struct nhlt_acpi_table *addr); ...@@ -133,6 +133,9 @@ void intel_nhlt_free(struct nhlt_acpi_table *addr);
int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt); int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt);
bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, u8 link_type); bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, u8 link_type);
int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type);
struct nhlt_specific_cfg * struct nhlt_specific_cfg *
intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt, intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
u32 bus_id, u8 link_type, u8 vbps, u8 bps, u32 bus_id, u8 link_type, u8 vbps, u8 bps,
...@@ -163,6 +166,11 @@ static inline bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, ...@@ -163,6 +166,11 @@ static inline bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt,
return false; return false;
} }
static inline int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type)
{
return 0;
}
static inline struct nhlt_specific_cfg * static inline struct nhlt_specific_cfg *
intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt, intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
u32 bus_id, u8 link_type, u8 vbps, u8 bps, u32 bus_id, u8 link_type, u8 vbps, u8 bps,
......
...@@ -60,9 +60,11 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) ...@@ -60,9 +60,11 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
* @acpi_ipc_irq_index: used for BYT-CR detection * @acpi_ipc_irq_index: used for BYT-CR detection
* @platform: string used for HDAudio codec support * @platform: string used for HDAudio codec support
* @codec_mask: used for HDAudio support * @codec_mask: used for HDAudio support
* @dmic_num: number of SoC- or chipset-attached PDM digital microphones
* @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver * @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver
* @link_mask: links enabled on the board * @link_mask: SoundWire links enabled on the board
* @links: array of link _ADR descriptors, null terminated * @links: array of SoundWire link _ADR descriptors, null terminated
* @i2s_link_mask: I2S/TDM links enabled on the board
* @num_dai_drivers: number of elements in @dai_drivers * @num_dai_drivers: number of elements in @dai_drivers
* @dai_drivers: pointer to dai_drivers, used e.g. in nocodec mode * @dai_drivers: pointer to dai_drivers, used e.g. in nocodec mode
*/ */
...@@ -74,6 +76,7 @@ struct snd_soc_acpi_mach_params { ...@@ -74,6 +76,7 @@ struct snd_soc_acpi_mach_params {
bool common_hdmi_codec_drv; bool common_hdmi_codec_drv;
u32 link_mask; u32 link_mask;
const struct snd_soc_acpi_link_adr *links; const struct snd_soc_acpi_link_adr *links;
u32 i2s_link_mask;
u32 num_dai_drivers; u32 num_dai_drivers;
struct snd_soc_dai_driver *dai_drivers; struct snd_soc_dai_driver *dai_drivers;
}; };
...@@ -122,6 +125,24 @@ struct snd_soc_acpi_link_adr { ...@@ -122,6 +125,24 @@ struct snd_soc_acpi_link_adr {
const struct snd_soc_acpi_adr_device *adr_d; const struct snd_soc_acpi_adr_device *adr_d;
}; };
/*
* when set the topology uses the -ssp<N> suffix, where N is determined based on
* BIOS or DMI information
*/
#define SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER BIT(0)
/*
* when more than one SSP is reported in the link mask, use the most significant.
* This choice was found to be valid on platforms with ES8336 codecs.
*/
#define SND_SOC_ACPI_TPLG_INTEL_SSP_MSB BIT(1)
/*
* when set the topology uses the -dmic<N>ch suffix, where N is determined based on
* BIOS or DMI information
*/
#define SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER BIT(2)
/** /**
* snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
* related to the hardware, except for the firmware and topology file names. * related to the hardware, except for the firmware and topology file names.
...@@ -143,6 +164,7 @@ struct snd_soc_acpi_link_adr { ...@@ -143,6 +164,7 @@ struct snd_soc_acpi_link_adr {
* @pdata: intended for platform data or machine specific-ops. This structure * @pdata: intended for platform data or machine specific-ops. This structure
* is not constant since this field may be updated at run-time * is not constant since this field may be updated at run-time
* @sof_tplg_filename: Sound Open Firmware topology file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled
* @tplg_quirk_mask: quirks to select different topology files dynamically
*/ */
/* Descriptor for SST ASoC machine driver */ /* Descriptor for SST ASoC machine driver */
struct snd_soc_acpi_mach { struct snd_soc_acpi_mach {
...@@ -158,6 +180,7 @@ struct snd_soc_acpi_mach { ...@@ -158,6 +180,7 @@ struct snd_soc_acpi_mach {
void *pdata; void *pdata;
struct snd_soc_acpi_mach_params mach_params; struct snd_soc_acpi_mach_params mach_params;
const char *sof_tplg_filename; const char *sof_tplg_filename;
const u32 tplg_quirk_mask;
}; };
#define SND_SOC_ACPI_MAX_CODECS 3 #define SND_SOC_ACPI_MAX_CODECS 3
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <sound/core.h> #include <sound/core.h>
#include <sound/intel-dsp-config.h> #include <sound/intel-dsp-config.h>
#include <sound/intel-nhlt.h> #include <sound/intel-nhlt.h>
#include <sound/soc-acpi.h>
static int dsp_driver; static int dsp_driver;
...@@ -31,7 +32,12 @@ struct config_entry { ...@@ -31,7 +32,12 @@ struct config_entry {
u16 device; u16 device;
u8 acpi_hid[ACPI_ID_LEN]; u8 acpi_hid[ACPI_ID_LEN];
const struct dmi_system_id *dmi_table; const struct dmi_system_id *dmi_table;
u8 codec_hid[ACPI_ID_LEN]; const struct snd_soc_acpi_codecs *codec_hid;
};
static const struct snd_soc_acpi_codecs __maybe_unused essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
}; };
/* /*
...@@ -77,7 +83,7 @@ static const struct config_entry config_table[] = { ...@@ -77,7 +83,7 @@ static const struct config_entry config_table[] = {
{ {
.flags = FLAG_SOF, .flags = FLAG_SOF,
.device = 0x5a98, .device = 0x5a98,
.codec_hid = "ESSX8336", .codec_hid = &essx_83x6,
}, },
#endif #endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
...@@ -163,7 +169,7 @@ static const struct config_entry config_table[] = { ...@@ -163,7 +169,7 @@ static const struct config_entry config_table[] = {
{ {
.flags = FLAG_SOF, .flags = FLAG_SOF,
.device = 0x3198, .device = 0x3198,
.codec_hid = "ESSX8336", .codec_hid = &essx_83x6,
}, },
#endif #endif
...@@ -193,6 +199,11 @@ static const struct config_entry config_table[] = { ...@@ -193,6 +199,11 @@ static const struct config_entry config_table[] = {
{} {}
} }
}, },
{
.flags = FLAG_SOF,
.device = 0x09dc8,
.codec_hid = &essx_83x6,
},
{ {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
.device = 0x9dc8, .device = 0x9dc8,
...@@ -251,7 +262,7 @@ static const struct config_entry config_table[] = { ...@@ -251,7 +262,7 @@ static const struct config_entry config_table[] = {
{ {
.flags = FLAG_SOF, .flags = FLAG_SOF,
.device = 0x02c8, .device = 0x02c8,
.codec_hid = "ESSX8336", .codec_hid = &essx_83x6,
}, },
{ {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
...@@ -280,7 +291,7 @@ static const struct config_entry config_table[] = { ...@@ -280,7 +291,7 @@ static const struct config_entry config_table[] = {
{ {
.flags = FLAG_SOF, .flags = FLAG_SOF,
.device = 0x06c8, .device = 0x06c8,
.codec_hid = "ESSX8336", .codec_hid = &essx_83x6,
}, },
{ {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
...@@ -327,7 +338,7 @@ static const struct config_entry config_table[] = { ...@@ -327,7 +338,7 @@ static const struct config_entry config_table[] = {
{ {
.flags = FLAG_SOF, .flags = FLAG_SOF,
.device = 0x4dc8, .device = 0x4dc8,
.codec_hid = "ESSX8336", .codec_hid = &essx_83x6,
}, },
{ {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
...@@ -353,7 +364,7 @@ static const struct config_entry config_table[] = { ...@@ -353,7 +364,7 @@ static const struct config_entry config_table[] = {
{ {
.flags = FLAG_SOF, .flags = FLAG_SOF,
.device = 0xa0c8, .device = 0xa0c8,
.codec_hid = "ESSX8336", .codec_hid = &essx_83x6,
}, },
{ {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
...@@ -414,8 +425,15 @@ static const struct config_entry *snd_intel_dsp_find_config ...@@ -414,8 +425,15 @@ static const struct config_entry *snd_intel_dsp_find_config
continue; continue;
if (table->dmi_table && !dmi_check_system(table->dmi_table)) if (table->dmi_table && !dmi_check_system(table->dmi_table))
continue; continue;
if (table->codec_hid[0] && !acpi_dev_present(table->codec_hid, NULL, -1)) if (table->codec_hid) {
continue; int i;
for (i = 0; i < table->codec_hid->num_codecs; i++)
if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
break;
if (i == table->codec_hid->num_codecs)
continue;
}
return table; return table;
} }
return NULL; return NULL;
......
...@@ -130,6 +130,28 @@ bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, u8 link_type) ...@@ -130,6 +130,28 @@ bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, u8 link_type)
} }
EXPORT_SYMBOL(intel_nhlt_has_endpoint_type); EXPORT_SYMBOL(intel_nhlt_has_endpoint_type);
int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type)
{
struct nhlt_endpoint *epnt;
int ssp_mask = 0;
int i;
if (!nhlt || (device_type != NHLT_DEVICE_BT && device_type != NHLT_DEVICE_I2S))
return 0;
epnt = (struct nhlt_endpoint *)nhlt->desc;
for (i = 0; i < nhlt->endpoint_count; i++) {
if (epnt->linktype == NHLT_LINK_SSP && epnt->device_type == device_type) {
/* for SSP the virtual bus id is the SSP port */
ssp_mask |= BIT(epnt->virtual_bus_id);
}
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
}
return ssp_mask;
}
EXPORT_SYMBOL(intel_nhlt_ssp_endpoint_mask);
static struct nhlt_specific_cfg * static struct nhlt_specific_cfg *
nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch, nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch,
u32 rate, u8 vbps, u8 bps) u32 rate, u8 vbps, u8 bps)
......
...@@ -530,12 +530,13 @@ config SND_SOC_INTEL_SOF_PCM512x_MACH ...@@ -530,12 +530,13 @@ config SND_SOC_INTEL_SOF_PCM512x_MACH
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_SOF_ES8336_MACH config SND_SOC_INTEL_SOF_ES8336_MACH
tristate "SOF with ES8336 codec in I2S mode" tristate "SOF with ES8336 or ES8326 codec in I2S mode"
depends on I2C && ACPI depends on I2C && ACPI
depends on MFD_INTEL_LPSS || COMPILE_TEST depends on MFD_INTEL_LPSS || COMPILE_TEST
depends on GPIOLIB || COMPILE_TEST depends on GPIOLIB || COMPILE_TEST
depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC
select SND_SOC_ES8316 select SND_SOC_ES8316
select SND_SOC_ES8326
select SND_SOC_DMIC select SND_SOC_DMIC
select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_INTEL_HDA_DSP_COMMON
help help
......
...@@ -535,7 +535,6 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) ...@@ -535,7 +535,6 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
if (IS_ERR(priv->mclk)) if (IS_ERR(priv->mclk))
return dev_err_probe(dev, PTR_ERR(priv->mclk), "clk_get pmc_plt_clk_3 failed\n"); return dev_err_probe(dev, PTR_ERR(priv->mclk), "clk_get pmc_plt_clk_3 failed\n");
/* get speaker enable GPIO */
codec_dev = acpi_get_first_physical_node(adev); codec_dev = acpi_get_first_physical_node(adev);
if (!codec_dev) if (!codec_dev)
return -EPROBE_DEFER; return -EPROBE_DEFER;
...@@ -561,6 +560,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) ...@@ -561,6 +560,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
} }
} }
/* get speaker enable GPIO */
devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios);
priv->speaker_en_gpio = priv->speaker_en_gpio =
gpiod_get_optional(codec_dev, "speaker-enable", gpiod_get_optional(codec_dev, "speaker-enable",
......
...@@ -21,11 +21,15 @@ ...@@ -21,11 +21,15 @@
#include <sound/soc-acpi.h> #include <sound/soc-acpi.h>
#include "hda_dsp_common.h" #include "hda_dsp_common.h"
/* jd-inv + terminating entry */
#define MAX_NO_PROPS 2
#define SOF_ES8336_SSP_CODEC(quirk) ((quirk) & GENMASK(3, 0)) #define SOF_ES8336_SSP_CODEC(quirk) ((quirk) & GENMASK(3, 0))
#define SOF_ES8336_SSP_CODEC_MASK (GENMASK(3, 0)) #define SOF_ES8336_SSP_CODEC_MASK (GENMASK(3, 0))
#define SOF_ES8336_TGL_GPIO_QUIRK BIT(4) #define SOF_ES8336_TGL_GPIO_QUIRK BIT(4)
#define SOF_ES8336_ENABLE_DMIC BIT(5) #define SOF_ES8336_ENABLE_DMIC BIT(5)
#define SOF_ES8336_JD_INVERTED BIT(6)
static unsigned long quirk; static unsigned long quirk;
...@@ -63,7 +67,14 @@ static const struct acpi_gpio_mapping *gpio_mapping = acpi_es8336_gpios; ...@@ -63,7 +67,14 @@ static const struct acpi_gpio_mapping *gpio_mapping = acpi_es8336_gpios;
static void log_quirks(struct device *dev) static void log_quirks(struct device *dev)
{ {
dev_info(dev, "quirk SSP%ld", SOF_ES8336_SSP_CODEC(quirk)); dev_info(dev, "quirk mask %#lx\n", quirk);
dev_info(dev, "quirk SSP%ld\n", SOF_ES8336_SSP_CODEC(quirk));
if (quirk & SOF_ES8336_ENABLE_DMIC)
dev_info(dev, "quirk DMIC enabled\n");
if (quirk & SOF_ES8336_TGL_GPIO_QUIRK)
dev_info(dev, "quirk TGL GPIO enabled\n");
if (quirk & SOF_ES8336_JD_INVERTED)
dev_info(dev, "quirk JD inverted enabled\n");
} }
static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
...@@ -228,32 +239,25 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id) ...@@ -228,32 +239,25 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id)
return 1; return 1;
} }
/*
* this table should only be used to add GPIO or jack-detection quirks
* that cannot be detected from ACPI tables. The SSP and DMIC
* information are providing by the platform driver and are aligned
* with the topology used.
*
* If the GPIO support is missing, the quirk parameter can be used to
* enable speakers. In that case it's recommended to keep the SSP and DMIC
* information consistent, overriding the SSP and DMIC can only be done
* if the topology file is modified as well.
*/
static const struct dmi_system_id sof_es8336_quirk_table[] = { static const struct dmi_system_id sof_es8336_quirk_table[] = {
{
.callback = sof_es8336_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "CHUWI Innovation And Technology"),
DMI_MATCH(DMI_BOARD_NAME, "Hi10 X"),
},
.driver_data = (void *)SOF_ES8336_SSP_CODEC(2)
},
{ {
.callback = sof_es8336_quirk_cb, .callback = sof_es8336_quirk_cb,
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "IP3 tech"), DMI_MATCH(DMI_SYS_VENDOR, "IP3 tech"),
DMI_MATCH(DMI_BOARD_NAME, "WN1"), DMI_MATCH(DMI_BOARD_NAME, "WN1"),
}, },
.driver_data = (void *)(SOF_ES8336_SSP_CODEC(0) | .driver_data = (void *)(SOF_ES8336_TGL_GPIO_QUIRK)
SOF_ES8336_TGL_GPIO_QUIRK |
SOF_ES8336_ENABLE_DMIC)
},
{
.callback = sof_es8336_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
DMI_MATCH(DMI_BOARD_NAME, "BOHB-WAX9-PCB-B2"),
},
.driver_data = (void *)SOF_ES8336_SSP_CODEC(0)
}, },
{} {}
}; };
...@@ -288,7 +292,7 @@ static struct snd_soc_dai_link_component platform_component[] = { ...@@ -288,7 +292,7 @@ static struct snd_soc_dai_link_component platform_component[] = {
} }
}; };
SND_SOC_DAILINK_DEF(ssp1_codec, SND_SOC_DAILINK_DEF(es8336_codec,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi"))); DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi")));
static struct snd_soc_dai_link_component dmic_component[] = { static struct snd_soc_dai_link_component dmic_component[] = {
...@@ -352,8 +356,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, ...@@ -352,8 +356,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
goto devm_err; goto devm_err;
links[id].id = id; links[id].id = id;
links[id].codecs = ssp1_codec; links[id].codecs = es8336_codec;
links[id].num_codecs = ARRAY_SIZE(ssp1_codec); links[id].num_codecs = ARRAY_SIZE(es8336_codec);
links[id].platforms = platform_component; links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].init = sof_es8316_init; links[id].init = sof_es8316_init;
...@@ -455,6 +459,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, ...@@ -455,6 +459,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
return NULL; return NULL;
} }
static char soc_components[30];
/* i2c-<HID>:00 with HID being 8 chars */ /* i2c-<HID>:00 with HID being 8 chars */
static char codec_name[SND_ACPI_I2C_ID_LEN]; static char codec_name[SND_ACPI_I2C_ID_LEN];
...@@ -463,10 +469,13 @@ static int sof_es8336_probe(struct platform_device *pdev) ...@@ -463,10 +469,13 @@ static int sof_es8336_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct snd_soc_card *card; struct snd_soc_card *card;
struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
struct property_entry props[MAX_NO_PROPS] = {};
struct sof_es8336_private *priv; struct sof_es8336_private *priv;
struct fwnode_handle *fwnode;
struct acpi_device *adev; struct acpi_device *adev;
struct snd_soc_dai_link *dai_links; struct snd_soc_dai_link *dai_links;
struct device *codec_dev; struct device *codec_dev;
unsigned int cnt = 0;
int dmic_be_num = 0; int dmic_be_num = 0;
int hdmi_num = 3; int hdmi_num = 3;
int ret; int ret;
...@@ -478,11 +487,33 @@ static int sof_es8336_probe(struct platform_device *pdev) ...@@ -478,11 +487,33 @@ static int sof_es8336_probe(struct platform_device *pdev)
card = &sof_es8336_card; card = &sof_es8336_card;
card->dev = dev; card->dev = dev;
if (!dmi_check_system(sof_es8336_quirk_table)) /* check GPIO DMI quirks */
quirk = SOF_ES8336_SSP_CODEC(2); dmi_check_system(sof_es8336_quirk_table);
if (quirk & SOF_ES8336_ENABLE_DMIC) if (!mach->mach_params.i2s_link_mask) {
dmic_be_num = 2; dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n");
} else {
/*
* Set configuration based on platform NHLT.
* In this machine driver, we can only support one SSP for the
* ES8336 link, the else-if below are intentional.
* In some cases multiple SSPs can be reported by NHLT, starting MSB-first
* seems to pick the right connection.
*/
unsigned long ssp = 0;
if (mach->mach_params.i2s_link_mask & BIT(2))
ssp = SOF_ES8336_SSP_CODEC(2);
else if (mach->mach_params.i2s_link_mask & BIT(1))
ssp = SOF_ES8336_SSP_CODEC(1);
else if (mach->mach_params.i2s_link_mask & BIT(0))
ssp = SOF_ES8336_SSP_CODEC(0);
quirk |= ssp;
}
if (mach->mach_params.dmic_num)
quirk |= SOF_ES8336_ENABLE_DMIC;
if (quirk_override != -1) { if (quirk_override != -1) {
dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n", dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n",
...@@ -491,6 +522,9 @@ static int sof_es8336_probe(struct platform_device *pdev) ...@@ -491,6 +522,9 @@ static int sof_es8336_probe(struct platform_device *pdev)
} }
log_quirks(dev); log_quirks(dev);
if (quirk & SOF_ES8336_ENABLE_DMIC)
dmic_be_num = 2;
sof_es8336_card.num_links += dmic_be_num + hdmi_num; sof_es8336_card.num_links += dmic_be_num + hdmi_num;
dai_links = sof_card_dai_links_create(dev, dai_links = sof_card_dai_links_create(dev,
SOF_ES8336_SSP_CODEC(quirk), SOF_ES8336_SSP_CODEC(quirk),
...@@ -507,6 +541,13 @@ static int sof_es8336_probe(struct platform_device *pdev) ...@@ -507,6 +541,13 @@ static int sof_es8336_probe(struct platform_device *pdev)
"i2c-%s", acpi_dev_name(adev)); "i2c-%s", acpi_dev_name(adev));
put_device(&adev->dev); put_device(&adev->dev);
dai_links[0].codecs->name = codec_name; 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;
} }
ret = snd_soc_fixup_dai_links_platform_name(&sof_es8336_card, ret = snd_soc_fixup_dai_links_platform_name(&sof_es8336_card,
...@@ -514,38 +555,64 @@ static int sof_es8336_probe(struct platform_device *pdev) ...@@ -514,38 +555,64 @@ static int sof_es8336_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
/* get speaker enable GPIO */ codec_dev = acpi_get_first_physical_node(adev);
codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, codec_name);
if (!codec_dev) if (!codec_dev)
return -EPROBE_DEFER; return -EPROBE_DEFER;
priv->codec_dev = get_device(codec_dev);
if (quirk & SOF_ES8336_JD_INVERTED)
props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted");
if (cnt) {
fwnode = fwnode_create_software_node(props, NULL);
if (IS_ERR(fwnode)) {
put_device(codec_dev);
return PTR_ERR(fwnode);
}
ret = device_add_software_node(codec_dev, to_software_node(fwnode));
fwnode_handle_put(fwnode);
if (ret) {
put_device(codec_dev);
return ret;
}
}
/* get speaker enable GPIO */
ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping); ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping);
if (ret) if (ret)
dev_warn(codec_dev, "unable to add GPIO mapping table\n"); dev_warn(codec_dev, "unable to add GPIO mapping table\n");
priv->gpio_pa = gpiod_get(codec_dev, "pa-enable", GPIOD_OUT_LOW); priv->gpio_pa = gpiod_get_optional(codec_dev, "pa-enable", GPIOD_OUT_LOW);
if (IS_ERR(priv->gpio_pa)) { if (IS_ERR(priv->gpio_pa)) {
ret = PTR_ERR(priv->gpio_pa); ret = dev_err_probe(dev, PTR_ERR(priv->gpio_pa),
dev_err(codec_dev, "%s, could not get pa-enable: %d\n", "could not get pa-enable GPIO\n");
__func__, ret); goto err_put_codec;
goto err;
} }
priv->codec_dev = codec_dev;
INIT_LIST_HEAD(&priv->hdmi_pcm_list); INIT_LIST_HEAD(&priv->hdmi_pcm_list);
snd_soc_card_set_drvdata(card, priv); snd_soc_card_set_drvdata(card, priv);
if (mach->mach_params.dmic_num > 0) {
snprintf(soc_components, sizeof(soc_components),
"cfg-dmics:%d", mach->mach_params.dmic_num);
card->components = soc_components;
}
ret = devm_snd_soc_register_card(dev, card); ret = devm_snd_soc_register_card(dev, card);
if (ret) { if (ret) {
gpiod_put(priv->gpio_pa); gpiod_put(priv->gpio_pa);
dev_err(dev, "snd_soc_register_card failed: %d\n", ret); dev_err(dev, "snd_soc_register_card failed: %d\n", ret);
goto err; goto err_put_codec;
} }
platform_set_drvdata(pdev, &sof_es8336_card); platform_set_drvdata(pdev, &sof_es8336_card);
return 0; return 0;
err: err_put_codec:
device_remove_software_node(priv->codec_dev);
put_device(codec_dev); put_device(codec_dev);
return ret; return ret;
} }
...@@ -556,6 +623,7 @@ static int sof_es8336_remove(struct platform_device *pdev) ...@@ -556,6 +623,7 @@ static int sof_es8336_remove(struct platform_device *pdev)
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
gpiod_put(priv->gpio_pa); gpiod_put(priv->gpio_pa);
device_remove_software_node(priv->codec_dev);
put_device(priv->codec_dev); put_device(priv->codec_dev);
return 0; return 0;
......
...@@ -41,6 +41,11 @@ static struct snd_soc_acpi_mach *apl_quirk(void *arg) ...@@ -41,6 +41,11 @@ static struct snd_soc_acpi_mach *apl_quirk(void *arg)
return mach; return mach;
} }
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
static const struct snd_soc_acpi_codecs bxt_codecs = { static const struct snd_soc_acpi_codecs bxt_codecs = {
.num_codecs = 1, .num_codecs = 1,
.codecs = {"MX98357A"} .codecs = {"MX98357A"}
...@@ -78,9 +83,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { ...@@ -78,9 +83,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
.sof_tplg_filename = "sof-apl-tdf8532.tplg", .sof_tplg_filename = "sof-apl-tdf8532.tplg",
}, },
{ {
.id = "ESSX8336", .comp_ids = &essx_83x6,
.drv_name = "sof-essx8336", .drv_name = "sof-essx8336",
.sof_tplg_filename = "sof-apl-es8336.tplg", .sof_tplg_filename = "sof-apl-es8336", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
}, },
{}, {},
}; };
......
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
#include <sound/soc-acpi.h> #include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h> #include <sound/soc-acpi-intel-match.h>
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
static const struct snd_soc_acpi_codecs rt1011_spk_codecs = { static const struct snd_soc_acpi_codecs rt1011_spk_codecs = {
.num_codecs = 1, .num_codecs = 1,
.codecs = {"10EC1011"} .codecs = {"10EC1011"}
...@@ -76,9 +81,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { ...@@ -76,9 +81,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = {
.sof_tplg_filename = "sof-cml-da7219-max98390.tplg", .sof_tplg_filename = "sof-cml-da7219-max98390.tplg",
}, },
{ {
.id = "ESSX8336", .comp_ids = &essx_83x6,
.drv_name = "sof-essx8336", .drv_name = "sof-essx8336",
.sof_tplg_filename = "sof-cml-es8336.tplg", .sof_tplg_filename = "sof-cml-es8336", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
}, },
{}, {},
}; };
......
...@@ -11,6 +11,11 @@ ...@@ -11,6 +11,11 @@
#include "../skylake/skl.h" #include "../skylake/skl.h"
#include "soc-acpi-intel-sdw-mockup-match.h" #include "soc-acpi-intel-sdw-mockup-match.h"
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
static struct skl_machine_pdata cnl_pdata = { static struct skl_machine_pdata cnl_pdata = {
.use_tplg_pcm = true, .use_tplg_pcm = true,
}; };
...@@ -23,6 +28,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { ...@@ -23,6 +28,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
.pdata = &cnl_pdata, .pdata = &cnl_pdata,
.sof_tplg_filename = "sof-cnl-rt274.tplg", .sof_tplg_filename = "sof-cnl-rt274.tplg",
}, },
{
.comp_ids = &essx_83x6,
.drv_name = "sof-essx8336",
/* cnl and cml are identical */
.sof_tplg_filename = "sof-cml-es8336", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
{}, {},
}; };
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines);
......
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
#include <sound/soc-acpi.h> #include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h> #include <sound/soc-acpi-intel-match.h>
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
static const struct snd_soc_acpi_codecs glk_codecs = { static const struct snd_soc_acpi_codecs glk_codecs = {
.num_codecs = 1, .num_codecs = 1,
.codecs = {"MX98357A"} .codecs = {"MX98357A"}
...@@ -53,9 +58,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { ...@@ -53,9 +58,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = {
.sof_tplg_filename = "sof-glk-cs42l42.tplg", .sof_tplg_filename = "sof-glk-cs42l42.tplg",
}, },
{ {
.id = "ESSX8336", .comp_ids = &essx_83x6,
.drv_name = "sof-essx8336", .drv_name = "sof-essx8336",
.sof_tplg_filename = "sof-glk-es8336.tplg", .sof_tplg_filename = "sof-glk-es8336", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
}, },
{}, {},
}; };
......
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
#include <sound/soc-acpi.h> #include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h> #include <sound/soc-acpi-intel-match.h>
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
static const struct snd_soc_acpi_codecs jsl_7219_98373_codecs = { static const struct snd_soc_acpi_codecs jsl_7219_98373_codecs = {
.num_codecs = 1, .num_codecs = 1,
.codecs = {"MX98373"} .codecs = {"MX98373"}
...@@ -81,9 +86,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { ...@@ -81,9 +86,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
.sof_tplg_filename = "sof-jsl-cs42l42-mx98360a.tplg", .sof_tplg_filename = "sof-jsl-cs42l42-mx98360a.tplg",
}, },
{ {
.id = "ESSX8336", .comp_ids = &essx_83x6,
.drv_name = "sof-essx8336", .drv_name = "sof-essx8336",
.sof_tplg_filename = "sof-jsl-es8336.tplg", .sof_tplg_filename = "sof-jsl-es8336", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
}, },
{}, {},
}; };
......
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
#include <sound/soc-acpi-intel-match.h> #include <sound/soc-acpi-intel-match.h>
#include "soc-acpi-intel-sdw-mockup-match.h" #include "soc-acpi-intel-sdw-mockup-match.h"
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
static const struct snd_soc_acpi_codecs tgl_codecs = { static const struct snd_soc_acpi_codecs tgl_codecs = {
.num_codecs = 1, .num_codecs = 1,
.codecs = {"MX98357A"} .codecs = {"MX98357A"}
...@@ -391,9 +396,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { ...@@ -391,9 +396,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
.sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg", .sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg",
}, },
{ {
.id = "ESSX8336", .comp_ids = &essx_83x6,
.drv_name = "sof-essx8336", .drv_name = "sof-essx8336",
.sof_tplg_filename = "sof-tgl-es8336.tplg", .sof_tplg_filename = "sof-tgl-es8336", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
}, },
{ {
.id = "10EC1308", .id = "10EC1308",
......
...@@ -432,11 +432,9 @@ static char *hda_model; ...@@ -432,11 +432,9 @@ static char *hda_model;
module_param(hda_model, charp, 0444); module_param(hda_model, charp, 0444);
MODULE_PARM_DESC(hda_model, "Use the given HDA board model."); MODULE_PARM_DESC(hda_model, "Use the given HDA board model.");
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) static int dmic_num_override = -1;
static int hda_dmic_num = -1; module_param_named(dmic_num, dmic_num_override, int, 0444);
module_param_named(dmic_num, hda_dmic_num, int, 0444);
MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number"); MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number");
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI); static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI);
...@@ -644,24 +642,54 @@ static int hda_init(struct snd_sof_dev *sdev) ...@@ -644,24 +642,54 @@ static int hda_init(struct snd_sof_dev *sdev)
return ret; return ret;
} }
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) static int check_dmic_num(struct snd_sof_dev *sdev)
static int check_nhlt_dmic(struct snd_sof_dev *sdev)
{ {
struct nhlt_acpi_table *nhlt; struct nhlt_acpi_table *nhlt;
int dmic_num; int dmic_num = 0;
nhlt = intel_nhlt_init(sdev->dev); nhlt = intel_nhlt_init(sdev->dev);
if (nhlt) { if (nhlt) {
dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt); dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt);
intel_nhlt_free(nhlt); intel_nhlt_free(nhlt);
if (dmic_num >= 1 && dmic_num <= 4)
return dmic_num;
} }
return 0; /* allow for module parameter override */
if (dmic_num_override != -1) {
dev_dbg(sdev->dev,
"overriding DMICs detected in NHLT tables %d by kernel param %d\n",
dmic_num, dmic_num_override);
dmic_num = dmic_num_override;
}
if (dmic_num < 0 || dmic_num > 4) {
dev_dbg(sdev->dev, "invalid dmic_number %d\n", dmic_num);
dmic_num = 0;
}
return dmic_num;
} }
static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
{
struct nhlt_acpi_table *nhlt;
int ssp_mask = 0;
nhlt = intel_nhlt_init(sdev->dev);
if (!nhlt)
return ssp_mask;
if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP)) {
ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S);
if (ssp_mask)
dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask);
}
intel_nhlt_free(nhlt);
return ssp_mask;
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
static const char *fixup_tplg_name(struct snd_sof_dev *sdev, static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
const char *sof_tplg_filename, const char *sof_tplg_filename,
const char *idisp_str, const char *idisp_str,
...@@ -697,16 +725,8 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev, ...@@ -697,16 +725,8 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev,
const char *dmic_str; const char *dmic_str;
int dmic_num; int dmic_num;
/* first check NHLT for DMICs */ /* first check for DMICs (using NHLT or module parameter) */
dmic_num = check_nhlt_dmic(sdev); dmic_num = check_dmic_num(sdev);
/* allow for module parameter override */
if (hda_dmic_num != -1) {
dev_dbg(sdev->dev,
"overriding DMICs detected in NHLT tables %d by kernel param %d\n",
dmic_num, hda_dmic_num);
dmic_num = hda_dmic_num;
}
switch (dmic_num) { switch (dmic_num) {
case 1: case 1:
...@@ -1373,9 +1393,12 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) ...@@ -1373,9 +1393,12 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
struct snd_sof_pdata *sof_pdata = sdev->pdata; struct snd_sof_pdata *sof_pdata = sdev->pdata;
const struct sof_dev_desc *desc = sof_pdata->desc; const struct sof_dev_desc *desc = sof_pdata->desc;
struct snd_soc_acpi_mach *mach; struct snd_soc_acpi_mach *mach;
const char *tplg_filename;
mach = snd_soc_acpi_find_machine(desc->machines); mach = snd_soc_acpi_find_machine(desc->machines);
if (mach) { if (mach) {
bool add_extension = false;
/* /*
* If tplg file name is overridden, use it instead of * If tplg file name is overridden, use it instead of
* the one set in mach table * the one set in mach table
...@@ -1383,10 +1406,65 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) ...@@ -1383,10 +1406,65 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
if (!sof_pdata->tplg_filename) if (!sof_pdata->tplg_filename)
sof_pdata->tplg_filename = mach->sof_tplg_filename; sof_pdata->tplg_filename = mach->sof_tplg_filename;
/* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev);
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
mach->mach_params.dmic_num) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d%s",
sof_pdata->tplg_filename,
"-dmic",
mach->mach_params.dmic_num,
"ch");
if (!tplg_filename)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
add_extension = true;
}
if (mach->link_mask) { if (mach->link_mask) {
mach->mach_params.links = mach->links; mach->mach_params.links = mach->links;
mach->mach_params.link_mask = mach->link_mask; mach->mach_params.link_mask = mach->link_mask;
} }
/* report SSP link mask to machine driver */
mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev);
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
mach->mach_params.i2s_link_mask) {
int ssp_num;
if (hweight_long(mach->mach_params.i2s_link_mask) > 1 &&
!(mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_MSB))
dev_warn(sdev->dev, "More than one SSP exposed by NHLT, choosing MSB\n");
/* fls returns 1-based results, SSPs indices are 0-based */
ssp_num = fls(mach->mach_params.i2s_link_mask) - 1;
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d",
sof_pdata->tplg_filename,
"-ssp",
ssp_num);
if (!tplg_filename)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
add_extension = true;
}
if (add_extension) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s",
sof_pdata->tplg_filename,
".tplg");
if (!tplg_filename)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
}
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment