]> git.itanic.dy.fi Git - linux-stable/commitdiff
ASoC: Intel: bytcr_wm5102: Add BYT_WM5102_OUT_MAP quirk
authorHans de Goede <hdegoede@redhat.com>
Wed, 25 Oct 2023 14:35:12 +0000 (16:35 +0200)
committerMark Brown <broonie@kernel.org>
Wed, 25 Oct 2023 16:21:13 +0000 (17:21 +0100)
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>
sound/soc/intel/boards/bytcr_wm5102.c

index 05a07b25e0f2447f1a645569e78bfc3adb1ec252..5425f757c2bb94a5b4c747fb4d74f25c67604e4f 100644 (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,