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
10static 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
19static 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
34static 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
50static const 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
69int 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}
83