-/* $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>
*
#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)
struct dai_device sc_dai;
uint8_t sc_dvc;
+ uint8_t sc_mute;
};
int tascodec_match(struct device *, void *, void *);
/* 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. */
*/
enum {
TASCODEC_MASTER_VOL,
+ TASCODEC_MASTER_MUTE,
TASCODEC_OUTPUT_CLASS
};
{
struct tascodec_softc *sc = priv;
u_char level;
+ uint8_t mode;
switch (mc->dev) {
case TASCODEC_MASTER_VOL:
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;
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;
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;
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;
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;
}