Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / sound / drivers / opl4 / opl4_mixer.c
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         unsigned long flags;
23         u8 reg = kcontrol->private_value;
24         u8 value;
25
26         spin_lock_irqsave(&opl4->reg_lock, flags);
27         value = snd_opl4_read(opl4, reg);
28         spin_unlock_irqrestore(&opl4->reg_lock, flags);
29         ucontrol->value.integer.value[0] = 7 - (value & 7);
30         ucontrol->value.integer.value[1] = 7 - ((value >> 3) & 7);
31         return 0;
32 }
33
34 static int snd_opl4_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
35 {
36         struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
37         unsigned long flags;
38         u8 reg = kcontrol->private_value;
39         u8 value, old_value;
40
41         value = (7 - (ucontrol->value.integer.value[0] & 7)) |
42                 ((7 - (ucontrol->value.integer.value[1] & 7)) << 3);
43         spin_lock_irqsave(&opl4->reg_lock, flags);
44         old_value = snd_opl4_read(opl4, reg);
45         snd_opl4_write(opl4, reg, value);
46         spin_unlock_irqrestore(&opl4->reg_lock, flags);
47         return value != old_value;
48 }
49
50 static struct snd_kcontrol_new snd_opl4_controls[] = {
51         {
52                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
53                 .name = "FM Playback Volume",
54                 .info = snd_opl4_ctl_info,
55                 .get = snd_opl4_ctl_get,
56                 .put = snd_opl4_ctl_put,
57                 .private_value = OPL4_REG_MIX_CONTROL_FM
58         },
59         {
60                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
61                 .name = "Wavetable Playback Volume",
62                 .info = snd_opl4_ctl_info,
63                 .get = snd_opl4_ctl_get,
64                 .put = snd_opl4_ctl_put,
65                 .private_value = OPL4_REG_MIX_CONTROL_PCM
66         }
67 };
68
69 int snd_opl4_create_mixer(struct snd_opl4 *opl4)
70 {
71         struct snd_card *card = opl4->card;
72         int i, err;
73
74         strcat(card->mixername, ",OPL4");
75
76         for (i = 0; i < 2; ++i) {
77                 err = snd_ctl_add(card, snd_ctl_new1(&snd_opl4_controls[i], opl4));
78                 if (err < 0)
79                         return err;
80         }
81         return 0;
82 }