ASoC: Intel: bytcr_wm5102: Add BYT_WM5102_OUT_MAP quirk

Some x86 WM5102 designs don't use the SPK pins for speaker output
instead they use the HPOUT2L + HPOUT2R for the speakers.

Add an BYT_WM5102_OUT_MAP quirk mechanism to allow selecting
between 2 output maps, one for the speakers on the SPK output pins
and one for the speakers on the HPOUT2 pins.

The new HPOUT2 map is enabled by default on CHT because this is used on
the Lenovo Yoga Tab 3 YT3-X90 model which is the only Cherry Trail design
currently supported. If different CHT designs turn up which need different
output maps we can add DMI quirks to select a different map later.

The userspace UCM profile also needs to know about this so
setup a components string with this info too.

While at it also drop the unused "Line Out" route.

Acked-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20231025143513.291753-4-hdegoede@redhat.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Hans de Goede 2023-10-25 16:35:12 +02:00 committed by Mark Brown
parent bce4b014cc
commit c556d202be
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0

View file

@ -10,6 +10,7 @@
*/
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/init.h>
@ -37,10 +38,17 @@ struct byt_wm5102_private {
int mclk_freq;
};
/* Bits 0-15 are reserved for things like an input-map */
/* Bits 0-3 are reserved for the input-map */
#define BYT_WM5102_OUT_MAP GENMASK(7, 4)
#define BYT_WM5102_SSP2 BIT(16)
#define BYT_WM5102_MCLK_19_2MHZ BIT(17)
/* Note these values are pre-shifted for easy use of setting quirks */
enum {
BYT_WM5102_SPK_SPK_MAP = FIELD_PREP_CONST(BYT_WM5102_OUT_MAP, 0),
BYT_WM5102_SPK_HPOUT2_MAP = FIELD_PREP_CONST(BYT_WM5102_OUT_MAP, 1),
};
static unsigned long quirk;
static int quirk_override = -1;
@ -49,6 +57,20 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override");
static void log_quirks(struct device *dev)
{
switch (quirk & BYT_WM5102_OUT_MAP) {
case BYT_WM5102_SPK_SPK_MAP:
dev_info_once(dev, "quirk SPK_SPK_MAP enabled\n");
break;
case BYT_WM5102_SPK_HPOUT2_MAP:
dev_info_once(dev, "quirk SPK_HPOUT2_MAP enabled\n");
break;
default:
dev_warn_once(dev, "quirk sets invalid output map: 0x%lx, defaulting to SPK_SPK_MAP\n",
quirk & BYT_WM5102_OUT_MAP);
quirk &= ~BYT_WM5102_OUT_MAP;
quirk |= BYT_WM5102_SPK_SPK_MAP;
break;
}
if (quirk & BYT_WM5102_SSP2)
dev_info_once(dev, "quirk SSP2 enabled");
if (quirk & BYT_WM5102_MCLK_19_2MHZ)
@ -164,12 +186,6 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = {
{"Headset Mic", NULL, "Platform Clock"},
{"Internal Mic", NULL, "Platform Clock"},
{"Speaker", NULL, "Platform Clock"},
{"Line Out", NULL, "Platform Clock"},
{"Speaker", NULL, "SPKOUTLP"},
{"Speaker", NULL, "SPKOUTLN"},
{"Speaker", NULL, "SPKOUTRP"},
{"Speaker", NULL, "SPKOUTRN"},
{"Speaker", NULL, "Speaker VDD"},
{"Headphone", NULL, "HPOUT1L"},
@ -203,6 +219,18 @@ static const struct snd_soc_dapm_route bytcr_wm5102_ssp2_map[] = {
{"ssp2 Rx", NULL, "AIF1 Capture"},
};
static const struct snd_soc_dapm_route byt_wm5102_spk_spk_map[] = {
{"Speaker", NULL, "SPKOUTLP"},
{"Speaker", NULL, "SPKOUTLN"},
{"Speaker", NULL, "SPKOUTRP"},
{"Speaker", NULL, "SPKOUTRN"},
};
static const struct snd_soc_dapm_route byt_wm5102_spk_hpout2_map[] = {
{"Speaker", NULL, "HPOUT2L"},
{"Speaker", NULL, "HPOUT2R"},
};
static const struct snd_kcontrol_new byt_wm5102_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
@ -243,6 +271,20 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
return ret;
}
switch (quirk & BYT_WM5102_OUT_MAP) {
case BYT_WM5102_SPK_SPK_MAP:
custom_map = byt_wm5102_spk_spk_map;
num_routes = ARRAY_SIZE(byt_wm5102_spk_spk_map);
break;
case BYT_WM5102_SPK_HPOUT2_MAP:
custom_map = byt_wm5102_spk_hpout2_map;
num_routes = ARRAY_SIZE(byt_wm5102_spk_hpout2_map);
break;
}
ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
if (ret)
return ret;
if (quirk & BYT_WM5102_SSP2) {
custom_map = bytcr_wm5102_ssp2_map;
num_routes = ARRAY_SIZE(bytcr_wm5102_ssp2_map);
@ -434,8 +476,11 @@ static struct snd_soc_card byt_wm5102_card = {
.fully_routed = true,
};
static char byt_wm5102_components[64]; /* = "cfg-spk:* cfg-int-mic:* cfg-hs-mic:* ..." */
static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
{
static const char * const out_map_name[] = { "spk", "hpout2" };
char codec_name[SND_ACPI_I2C_ID_LEN];
struct device *dev = &pdev->dev;
struct byt_wm5102_private *priv;
@ -493,8 +538,13 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
}
if (soc_intel_is_cht()) {
/* On CHT default to SSP2 */
quirk = BYT_WM5102_SSP2 | BYT_WM5102_MCLK_19_2MHZ;
/*
* CHT always uses SSP2 and 19.2 MHz; and
* the one currently supported CHT design uses HPOUT2 as
* speaker output.
*/
quirk = BYT_WM5102_SSP2 | BYT_WM5102_MCLK_19_2MHZ |
BYT_WM5102_SPK_HPOUT2_MAP;
}
if (quirk_override != -1) {
dev_info_once(dev, "Overriding quirk 0x%lx => 0x%x\n",
@ -503,6 +553,10 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
}
log_quirks(dev);
snprintf(byt_wm5102_components, sizeof(byt_wm5102_components),
"cfg-spk:%s", out_map_name[FIELD_GET(BYT_WM5102_OUT_MAP, quirk)]);
byt_wm5102_card.components = byt_wm5102_components;
/* find index of codec dai */
for (i = 0; i < ARRAY_SIZE(byt_wm5102_dais); i++) {
if (!strcmp(byt_wm5102_dais[i].codecs->name,