Add mute control. This makes the mute button on laptops that use
authorkettenis <kettenis@openbsd.org>
Sat, 15 Jul 2023 13:35:17 +0000 (13:35 +0000)
committerkettenis <kettenis@openbsd.org>
Sat, 15 Jul 2023 13:35:17 +0000 (13:35 +0000)
tascodec(4) work.

ok tobhe@

sys/dev/fdt/tascodec.c

index 572847c..1c63afd 100644 (file)
@@ -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 <kettenis@openbsd.org>
  *
@@ -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;
 }