xref: /linux/sound/drivers/opl4/opl4_mixer.c (revision 05a54fa773284d1a7923cdfdd8f0c8dabb98bd26)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * OPL4 mixer functions
4  * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de>
5  */
6 
7 #include "opl4_local.h"
8 #include <sound/control.h>
9 
10 static int snd_opl4_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11 {
12 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13 	uinfo->count = 2;
14 	uinfo->value.integer.min = 0;
15 	uinfo->value.integer.max = 7;
16 	return 0;
17 }
18 
19 static int snd_opl4_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
20 {
21 	struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
22 	u8 reg = kcontrol->private_value;
23 	u8 value;
24 
25 	guard(spinlock_irqsave)(&opl4->reg_lock);
26 	value = snd_opl4_read(opl4, reg);
27 	ucontrol->value.integer.value[0] = 7 - (value & 7);
28 	ucontrol->value.integer.value[1] = 7 - ((value >> 3) & 7);
29 	return 0;
30 }
31 
32 static int snd_opl4_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
33 {
34 	struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
35 	u8 reg = kcontrol->private_value;
36 	u8 value, old_value;
37 
38 	value = (7 - (ucontrol->value.integer.value[0] & 7)) |
39 		((7 - (ucontrol->value.integer.value[1] & 7)) << 3);
40 	guard(spinlock_irqsave)(&opl4->reg_lock);
41 	old_value = snd_opl4_read(opl4, reg);
42 	snd_opl4_write(opl4, reg, value);
43 	return value != old_value;
44 }
45 
46 static const struct snd_kcontrol_new snd_opl4_controls[] = {
47 	{
48 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
49 		.name = "FM Playback Volume",
50 		.info = snd_opl4_ctl_info,
51 		.get = snd_opl4_ctl_get,
52 		.put = snd_opl4_ctl_put,
53 		.private_value = OPL4_REG_MIX_CONTROL_FM
54 	},
55 	{
56 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
57 		.name = "Wavetable Playback Volume",
58 		.info = snd_opl4_ctl_info,
59 		.get = snd_opl4_ctl_get,
60 		.put = snd_opl4_ctl_put,
61 		.private_value = OPL4_REG_MIX_CONTROL_PCM
62 	}
63 };
64 
65 int snd_opl4_create_mixer(struct snd_opl4 *opl4)
66 {
67 	struct snd_card *card = opl4->card;
68 	int i, err;
69 
70 	strcat(card->mixername, ",OPL4");
71 
72 	for (i = 0; i < 2; ++i) {
73 		err = snd_ctl_add(card, snd_ctl_new1(&snd_opl4_controls[i], opl4));
74 		if (err < 0)
75 			return err;
76 	}
77 	return 0;
78 }
79