2022-04-06 12:11:21

by Mauro Carvalho Chehab

[permalink] [raw]
Subject: [PATCH v3 0/3] Make headphone work on Huawei Matebook D15

At Huawei Matebook D15 two different GPIOs are used to control the output:
- gpio0 controls the speaker output;
- gpio1 controls the headphone output.

Changing both at the same time cause spurious events that are mis-interpreted
as input events, causing troubles on apps. So, a delay is needed before turning
on such gpios.

With this patch, plugging a headphone causes a jack event to trigger the speaker
supply, powering down the speaker and powering up the headphone output.
Removing the headphone also triggers the power supply, powering up the speaker
and powering down the headphone.

---

v3:
- add a patch changing GPIO quirk speaker naming. Patch 2 got rebased on the top of it.

Mauro Carvalho Chehab (2):
ASoC: Intel: sof_es8336: support a separate gpio to control headphone
ASoC: Intel: sof_es8336: Huawei Matebook D15 uses a headphone gpio

Pierre-Louis Bossart (1):
ASoC: Intel: sof_es8336: simplify speaker gpio naming

sound/soc/intel/boards/sof_es8336.c | 97 +++++++++++++++++++++--------
1 file changed, 72 insertions(+), 25 deletions(-)

--
2.35.1



2022-04-06 12:30:55

by Mauro Carvalho Chehab

[permalink] [raw]
Subject: [PATCH v3 2/3] ASoC: Intel: sof_es8336: support a separate gpio to control headphone

Some devices may use both gpio0 and gpio1 to independently switch
the speaker and the headphone.

Add support for that.

Acked-by: Hans de Goede <[email protected]>
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
---

See [PATCH v3 0/3] at: https://lore.kernel.org/all/[email protected]/

sound/soc/intel/boards/sof_es8336.c | 59 ++++++++++++++++++++++++-----
1 file changed, 49 insertions(+), 10 deletions(-)

diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index e4829a376b79..d15a58666cc6 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -30,6 +30,7 @@
#define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK BIT(4)
#define SOF_ES8336_ENABLE_DMIC BIT(5)
#define SOF_ES8336_JD_INVERTED BIT(6)
+#define SOF_ES8336_HEADPHONE_GPIO BIT(7)

static unsigned long quirk;

@@ -39,7 +40,7 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override");

struct sof_es8336_private {
struct device *codec_dev;
- struct gpio_desc *gpio_speakers;
+ struct gpio_desc *gpio_speakers, *gpio_headphone;
struct snd_soc_jack jack;
struct list_head hdmi_pcm_list;
bool speaker_en;
@@ -51,15 +52,27 @@ struct sof_hdmi_pcm {
int device;
};

-static const struct acpi_gpio_params speakers_enable_gpio0 = { 0, 0, true };
+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", &speakers_enable_gpio0, 1 },
+ { "speakers-enable-gpios", &enable_gpio0, 1 },
{ }
};

-static const struct acpi_gpio_params speakers_enable_gpio1 = { 1, 0, true };
static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = {
- { "speakers-enable-gpios", &speakers_enable_gpio1, 1 },
+ { "speakers-enable-gpios", &enable_gpio1, 1 },
+};
+
+static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = {
+ { "speakers-enable-gpios", &enable_gpio0, 1 },
+ { "headphone-enable-gpios", &enable_gpio1, 1 },
+ { }
+};
+
+static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = {
+ { "speakers-enable-gpios", &enable_gpio1, 1 },
+ { "headphone-enable-gpios", &enable_gpio0, 1 },
{ }
};

@@ -73,6 +86,8 @@ 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");
}
@@ -83,13 +98,24 @@ 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);
+
if (SND_SOC_DAPM_EVENT_ON(event))
- priv->speaker_en = false;
- else
- priv->speaker_en = true;
+ msleep(70);

gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en);

+ if (!(quirk & SOF_ES8336_HEADPHONE_GPIO))
+ return 0;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ msleep(70);
+
+ gpiod_set_value_cansleep(priv->gpio_headphone, priv->speaker_en);
+
return 0;
}

@@ -114,7 +140,7 @@ static const struct snd_soc_dapm_route sof_es8316_audio_map[] = {

/*
* There is no separate speaker output instead the speakers are muxed to
- * the HP outputs. The mux is controlled by the "Speaker Power" supply.
+ * the HP outputs. The mux is controlled Speaker and/or headphone switch.
*/
{"Speaker", NULL, "HPOL"},
{"Speaker", NULL, "HPOR"},
@@ -233,8 +259,14 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id)
{
quirk = (unsigned long)id->driver_data;

- if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK)
+ 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;
+ }

return 1;
}
@@ -592,6 +624,13 @@ static int sof_es8336_probe(struct platform_device *pdev)
goto err_put_codec;
}

+ priv->gpio_headphone = gpiod_get_optional(codec_dev, "headphone-enable", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpio_headphone)) {
+ ret = dev_err_probe(dev, PTR_ERR(priv->gpio_headphone),
+ "could not get headphone-enable GPIO\n");
+ goto err_put_codec;
+ }
+
INIT_LIST_HEAD(&priv->hdmi_pcm_list);

snd_soc_card_set_drvdata(card, priv);
--
2.35.1