xref: /openbmc/linux/sound/drivers/pcsp/pcsp_mixer.c (revision 2eccd408)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
29ab4d072SStas Sergeev /*
39ab4d072SStas Sergeev  * PC-Speaker driver for Linux
49ab4d072SStas Sergeev  *
59ab4d072SStas Sergeev  * Mixer implementation.
69ab4d072SStas Sergeev  * Copyright (C) 2001-2008  Stas Sergeev
79ab4d072SStas Sergeev  */
89ab4d072SStas Sergeev 
99ab4d072SStas Sergeev #include <sound/core.h>
109ab4d072SStas Sergeev #include <sound/control.h>
119ab4d072SStas Sergeev #include "pcsp.h"
129ab4d072SStas Sergeev 
139ab4d072SStas Sergeev 
pcsp_enable_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)149ab4d072SStas Sergeev static int pcsp_enable_info(struct snd_kcontrol *kcontrol,
159ab4d072SStas Sergeev 			    struct snd_ctl_elem_info *uinfo)
169ab4d072SStas Sergeev {
179ab4d072SStas Sergeev 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
189ab4d072SStas Sergeev 	uinfo->count = 1;
199ab4d072SStas Sergeev 	uinfo->value.integer.min = 0;
209ab4d072SStas Sergeev 	uinfo->value.integer.max = 1;
219ab4d072SStas Sergeev 	return 0;
229ab4d072SStas Sergeev }
239ab4d072SStas Sergeev 
pcsp_enable_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)249ab4d072SStas Sergeev static int pcsp_enable_get(struct snd_kcontrol *kcontrol,
259ab4d072SStas Sergeev 			   struct snd_ctl_elem_value *ucontrol)
269ab4d072SStas Sergeev {
279ab4d072SStas Sergeev 	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
289ab4d072SStas Sergeev 	ucontrol->value.integer.value[0] = chip->enable;
299ab4d072SStas Sergeev 	return 0;
309ab4d072SStas Sergeev }
319ab4d072SStas Sergeev 
pcsp_enable_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)329ab4d072SStas Sergeev static int pcsp_enable_put(struct snd_kcontrol *kcontrol,
339ab4d072SStas Sergeev 			   struct snd_ctl_elem_value *ucontrol)
349ab4d072SStas Sergeev {
359ab4d072SStas Sergeev 	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
369ab4d072SStas Sergeev 	int changed = 0;
379ab4d072SStas Sergeev 	int enab = ucontrol->value.integer.value[0];
389ab4d072SStas Sergeev 	if (enab != chip->enable) {
399ab4d072SStas Sergeev 		chip->enable = enab;
409ab4d072SStas Sergeev 		changed = 1;
419ab4d072SStas Sergeev 	}
429ab4d072SStas Sergeev 	return changed;
439ab4d072SStas Sergeev }
449ab4d072SStas Sergeev 
pcsp_treble_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)459ab4d072SStas Sergeev static int pcsp_treble_info(struct snd_kcontrol *kcontrol,
469ab4d072SStas Sergeev 			    struct snd_ctl_elem_info *uinfo)
479ab4d072SStas Sergeev {
489ab4d072SStas Sergeev 	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
499ab4d072SStas Sergeev 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
509ab4d072SStas Sergeev 	uinfo->count = 1;
519ab4d072SStas Sergeev 	uinfo->value.enumerated.items = chip->max_treble + 1;
529ab4d072SStas Sergeev 	if (uinfo->value.enumerated.item > chip->max_treble)
539ab4d072SStas Sergeev 		uinfo->value.enumerated.item = chip->max_treble;
545a641bcdSRandy Dunlap 	sprintf(uinfo->value.enumerated.name, "%lu",
55b3b778b3STakashi Iwai 		(unsigned long)PCSP_CALC_RATE(uinfo->value.enumerated.item));
569ab4d072SStas Sergeev 	return 0;
579ab4d072SStas Sergeev }
589ab4d072SStas Sergeev 
pcsp_treble_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)599ab4d072SStas Sergeev static int pcsp_treble_get(struct snd_kcontrol *kcontrol,
609ab4d072SStas Sergeev 			   struct snd_ctl_elem_value *ucontrol)
619ab4d072SStas Sergeev {
629ab4d072SStas Sergeev 	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
639ab4d072SStas Sergeev 	ucontrol->value.enumerated.item[0] = chip->treble;
649ab4d072SStas Sergeev 	return 0;
659ab4d072SStas Sergeev }
669ab4d072SStas Sergeev 
pcsp_treble_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)679ab4d072SStas Sergeev static int pcsp_treble_put(struct snd_kcontrol *kcontrol,
689ab4d072SStas Sergeev 			   struct snd_ctl_elem_value *ucontrol)
699ab4d072SStas Sergeev {
709ab4d072SStas Sergeev 	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
719ab4d072SStas Sergeev 	int changed = 0;
729ab4d072SStas Sergeev 	int treble = ucontrol->value.enumerated.item[0];
739ab4d072SStas Sergeev 	if (treble != chip->treble) {
749ab4d072SStas Sergeev 		chip->treble = treble;
759ab4d072SStas Sergeev #if PCSP_DEBUG
76b71207e9SStas Sergeev 		printk(KERN_INFO "PCSP: rate set to %li\n", PCSP_RATE());
779ab4d072SStas Sergeev #endif
789ab4d072SStas Sergeev 		changed = 1;
799ab4d072SStas Sergeev 	}
809ab4d072SStas Sergeev 	return changed;
819ab4d072SStas Sergeev }
829ab4d072SStas Sergeev 
pcsp_pcspkr_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)839ab4d072SStas Sergeev static int pcsp_pcspkr_info(struct snd_kcontrol *kcontrol,
849ab4d072SStas Sergeev 			    struct snd_ctl_elem_info *uinfo)
859ab4d072SStas Sergeev {
869ab4d072SStas Sergeev 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
879ab4d072SStas Sergeev 	uinfo->count = 1;
889ab4d072SStas Sergeev 	uinfo->value.integer.min = 0;
899ab4d072SStas Sergeev 	uinfo->value.integer.max = 1;
909ab4d072SStas Sergeev 	return 0;
919ab4d072SStas Sergeev }
929ab4d072SStas Sergeev 
pcsp_pcspkr_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)939ab4d072SStas Sergeev static int pcsp_pcspkr_get(struct snd_kcontrol *kcontrol,
949ab4d072SStas Sergeev 			   struct snd_ctl_elem_value *ucontrol)
959ab4d072SStas Sergeev {
969ab4d072SStas Sergeev 	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
979ab4d072SStas Sergeev 	ucontrol->value.integer.value[0] = chip->pcspkr;
989ab4d072SStas Sergeev 	return 0;
999ab4d072SStas Sergeev }
1009ab4d072SStas Sergeev 
pcsp_pcspkr_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1019ab4d072SStas Sergeev static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol,
1029ab4d072SStas Sergeev 			   struct snd_ctl_elem_value *ucontrol)
1039ab4d072SStas Sergeev {
1049ab4d072SStas Sergeev 	struct snd_pcsp *chip = snd_kcontrol_chip(kcontrol);
1059ab4d072SStas Sergeev 	int changed = 0;
1069ab4d072SStas Sergeev 	int spkr = ucontrol->value.integer.value[0];
1079ab4d072SStas Sergeev 	if (spkr != chip->pcspkr) {
1089ab4d072SStas Sergeev 		chip->pcspkr = spkr;
1099ab4d072SStas Sergeev 		changed = 1;
1109ab4d072SStas Sergeev 	}
1119ab4d072SStas Sergeev 	return changed;
1129ab4d072SStas Sergeev }
1139ab4d072SStas Sergeev 
1149ab4d072SStas Sergeev #define PCSP_MIXER_CONTROL(ctl_type, ctl_name) \
1159ab4d072SStas Sergeev { \
1169ab4d072SStas Sergeev 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER, \
1179ab4d072SStas Sergeev 	.name =		ctl_name, \
1189ab4d072SStas Sergeev 	.info =		pcsp_##ctl_type##_info, \
1199ab4d072SStas Sergeev 	.get =		pcsp_##ctl_type##_get, \
1209ab4d072SStas Sergeev 	.put =		pcsp_##ctl_type##_put, \
1219ab4d072SStas Sergeev }
1229ab4d072SStas Sergeev 
1232eccd408STakashi Iwai static const struct snd_kcontrol_new snd_pcsp_controls_pcm[] = {
1249ab4d072SStas Sergeev 	PCSP_MIXER_CONTROL(enable, "Master Playback Switch"),
1259ab4d072SStas Sergeev 	PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"),
126bcc2c6b7SStas Sergeev };
127bcc2c6b7SStas Sergeev 
1282eccd408STakashi Iwai static const struct snd_kcontrol_new snd_pcsp_controls_spkr[] = {
129d355c82aSJaroslav Kysela 	PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"),
1309ab4d072SStas Sergeev };
1319ab4d072SStas Sergeev 
snd_pcsp_ctls_add(struct snd_pcsp * chip,const struct snd_kcontrol_new * ctls,int num)132fbbb01a1SBill Pemberton static int snd_pcsp_ctls_add(struct snd_pcsp *chip,
1332eccd408STakashi Iwai 			     const struct snd_kcontrol_new *ctls, int num)
1349ab4d072SStas Sergeev {
1359ab4d072SStas Sergeev 	int i, err;
136bcc2c6b7SStas Sergeev 	struct snd_card *card = chip->card;
137bcc2c6b7SStas Sergeev 	for (i = 0; i < num; i++) {
138bcc2c6b7SStas Sergeev 		err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip));
1399ab4d072SStas Sergeev 		if (err < 0)
1409ab4d072SStas Sergeev 			return err;
1419ab4d072SStas Sergeev 	}
142bcc2c6b7SStas Sergeev 	return 0;
143bcc2c6b7SStas Sergeev }
144bcc2c6b7SStas Sergeev 
snd_pcsp_new_mixer(struct snd_pcsp * chip,int nopcm)145fbbb01a1SBill Pemberton int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm)
146bcc2c6b7SStas Sergeev {
147bcc2c6b7SStas Sergeev 	int err;
148bcc2c6b7SStas Sergeev 	struct snd_card *card = chip->card;
149bcc2c6b7SStas Sergeev 
150bcc2c6b7SStas Sergeev 	if (!nopcm) {
151bcc2c6b7SStas Sergeev 		err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm,
152bcc2c6b7SStas Sergeev 			ARRAY_SIZE(snd_pcsp_controls_pcm));
153bcc2c6b7SStas Sergeev 		if (err < 0)
154bcc2c6b7SStas Sergeev 			return err;
155bcc2c6b7SStas Sergeev 	}
156bcc2c6b7SStas Sergeev 	err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr,
157bcc2c6b7SStas Sergeev 		ARRAY_SIZE(snd_pcsp_controls_spkr));
158bcc2c6b7SStas Sergeev 	if (err < 0)
159bcc2c6b7SStas Sergeev 		return err;
1609ab4d072SStas Sergeev 
1619ab4d072SStas Sergeev 	strcpy(card->mixername, "PC-Speaker");
1629ab4d072SStas Sergeev 
1639ab4d072SStas Sergeev 	return 0;
1649ab4d072SStas Sergeev }
165