From 2a9d985ddb78cc1d2eb72f75310a88cc57a0be2a Mon Sep 17 00:00:00 2001 From: kettenis Date: Sat, 15 Jul 2023 13:35:17 +0000 Subject: [PATCH] Add mute control. This makes the mute button on laptops that use tascodec(4) work. ok tobhe@ --- sys/dev/fdt/tascodec.c | 44 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/sys/dev/fdt/tascodec.c b/sys/dev/fdt/tascodec.c index 572847c22ff..1c63afd3990 100644 --- a/sys/dev/fdt/tascodec.c +++ b/sys/dev/fdt/tascodec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tascodec.c,v 1.6 2023/02/04 20:04:20 kettenis Exp $ */ +/* $OpenBSD: tascodec.c,v 1.7 2023/07/15 13:35:17 kettenis Exp $ */ /* * Copyright (c) 2022 Mark Kettenis * @@ -35,6 +35,7 @@ #define PWR_CTL 0x02 #define PWR_CTL_ISNS_PD (1 << 3) #define PWR_CTL_VSNS_PD (1 << 2) +#define PWR_CTL_MODE_MASK (3 << 0) #define PWR_CTL_MODE_ACTIVE (0 << 0) #define PWR_CTL_MODE_MUTE (1 << 0) #define PWR_CTL_MODE_SHUTDOWN (2 << 0) @@ -66,6 +67,7 @@ struct tascodec_softc { struct dai_device sc_dai; uint8_t sc_dvc; + uint8_t sc_mute; }; int tascodec_match(struct device *, void *, void *); @@ -138,6 +140,7 @@ tascodec_attach(struct device *parent, struct device *self, void *aux) /* Set volume to a reasonable level. */ sc->sc_dvc = PB_CFG2_DVC_PCM_30DB; + sc->sc_mute = PWR_CTL_MODE_ACTIVE; tascodec_write(sc, PB_CFG2, sc->sc_dvc); /* Default to stereo downmix mode for now. */ @@ -244,6 +247,7 @@ tascodec_set_tdm_slot(void *cookie, int slot) */ enum { TASCODEC_MASTER_VOL, + TASCODEC_MASTER_MUTE, TASCODEC_OUTPUT_CLASS }; @@ -252,6 +256,7 @@ tascodec_set_port(void *priv, mixer_ctrl_t *mc) { struct tascodec_softc *sc = priv; u_char level; + uint8_t mode; switch (mc->dev) { case TASCODEC_MASTER_VOL: @@ -259,6 +264,19 @@ tascodec_set_port(void *priv, mixer_ctrl_t *mc) sc->sc_dvc = (PB_CFG2_DVC_PCM_MIN * (255 - level)) / 255; tascodec_write(sc, PB_CFG2, sc->sc_dvc); return 0; + + case TASCODEC_MASTER_MUTE: + sc->sc_mute = mc->un.ord ? + PWR_CTL_MODE_MUTE : PWR_CTL_MODE_ACTIVE; + mode = tascodec_read(sc, PWR_CTL); + if ((mode & PWR_CTL_MODE_MASK) == PWR_CTL_MODE_ACTIVE || + (mode & PWR_CTL_MODE_MASK) == PWR_CTL_MODE_MUTE) { + mode &= ~PWR_CTL_MODE_MASK; + mode |= sc->sc_mute; + tascodec_write(sc, PWR_CTL, mode); + } + return 0; + } return EINVAL; @@ -276,6 +294,10 @@ tascodec_get_port(void *priv, mixer_ctrl_t *mc) level = 255 - ((255 * sc->sc_dvc) / PB_CFG2_DVC_PCM_MIN); mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = level; return 0; + + case TASCODEC_MASTER_MUTE: + mc->un.ord = (sc->sc_mute == PWR_CTL_MODE_MUTE); + return 0; } return EINVAL; @@ -287,7 +309,8 @@ tascodec_query_devinfo(void *priv, mixer_devinfo_t *di) switch (di->index) { case TASCODEC_MASTER_VOL: di->mixer_class = TASCODEC_OUTPUT_CLASS; - di->next = di->prev = AUDIO_MIXER_LAST; + di->prev = AUDIO_MIXER_LAST; + di->next = TASCODEC_MASTER_MUTE; strlcpy(di->label.name, AudioNmaster, sizeof(di->label.name)); di->type = AUDIO_MIXER_VALUE; di->un.v.num_channels = 1; @@ -295,6 +318,21 @@ tascodec_query_devinfo(void *priv, mixer_devinfo_t *di) sizeof(di->un.v.units.name)); return 0; + case TASCODEC_MASTER_MUTE: + di->mixer_class = TASCODEC_OUTPUT_CLASS; + di->prev = TASCODEC_MASTER_VOL; + di->next = AUDIO_MIXER_LAST; + strlcpy(di->label.name, AudioNmute, sizeof(di->label.name)); + di->type = AUDIO_MIXER_ENUM; + di->un.e.num_mem = 2; + di->un.e.member[0].ord = 0; + strlcpy(di->un.e.member[0].label.name, AudioNoff, + MAX_AUDIO_DEV_LEN); + di->un.e.member[1].ord = 1; + strlcpy(di->un.e.member[1].label.name, AudioNon, + MAX_AUDIO_DEV_LEN); + return 0; + case TASCODEC_OUTPUT_CLASS: di->mixer_class = TASCODEC_OUTPUT_CLASS; di->next = di->prev = AUDIO_MIXER_LAST; @@ -313,7 +351,7 @@ tascodec_trigger_output(void *cookie, void *start, void *end, int blksize, struct tascodec_softc *sc = cookie; tascodec_write(sc, PWR_CTL, - PWR_CTL_ISNS_PD | PWR_CTL_VSNS_PD | PWR_CTL_MODE_ACTIVE); + PWR_CTL_ISNS_PD | PWR_CTL_VSNS_PD | sc->sc_mute); return 0; } -- 2.20.1