162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * OPL4 mixer functions
462306a36Sopenharmony_ci * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "opl4_local.h"
862306a36Sopenharmony_ci#include <sound/control.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistatic int snd_opl4_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1162306a36Sopenharmony_ci{
1262306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1362306a36Sopenharmony_ci	uinfo->count = 2;
1462306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
1562306a36Sopenharmony_ci	uinfo->value.integer.max = 7;
1662306a36Sopenharmony_ci	return 0;
1762306a36Sopenharmony_ci}
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int snd_opl4_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
2262306a36Sopenharmony_ci	unsigned long flags;
2362306a36Sopenharmony_ci	u8 reg = kcontrol->private_value;
2462306a36Sopenharmony_ci	u8 value;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	spin_lock_irqsave(&opl4->reg_lock, flags);
2762306a36Sopenharmony_ci	value = snd_opl4_read(opl4, reg);
2862306a36Sopenharmony_ci	spin_unlock_irqrestore(&opl4->reg_lock, flags);
2962306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = 7 - (value & 7);
3062306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = 7 - ((value >> 3) & 7);
3162306a36Sopenharmony_ci	return 0;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int snd_opl4_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct snd_opl4 *opl4 = snd_kcontrol_chip(kcontrol);
3762306a36Sopenharmony_ci	unsigned long flags;
3862306a36Sopenharmony_ci	u8 reg = kcontrol->private_value;
3962306a36Sopenharmony_ci	u8 value, old_value;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	value = (7 - (ucontrol->value.integer.value[0] & 7)) |
4262306a36Sopenharmony_ci		((7 - (ucontrol->value.integer.value[1] & 7)) << 3);
4362306a36Sopenharmony_ci	spin_lock_irqsave(&opl4->reg_lock, flags);
4462306a36Sopenharmony_ci	old_value = snd_opl4_read(opl4, reg);
4562306a36Sopenharmony_ci	snd_opl4_write(opl4, reg, value);
4662306a36Sopenharmony_ci	spin_unlock_irqrestore(&opl4->reg_lock, flags);
4762306a36Sopenharmony_ci	return value != old_value;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_opl4_controls[] = {
5162306a36Sopenharmony_ci	{
5262306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5362306a36Sopenharmony_ci		.name = "FM Playback Volume",
5462306a36Sopenharmony_ci		.info = snd_opl4_ctl_info,
5562306a36Sopenharmony_ci		.get = snd_opl4_ctl_get,
5662306a36Sopenharmony_ci		.put = snd_opl4_ctl_put,
5762306a36Sopenharmony_ci		.private_value = OPL4_REG_MIX_CONTROL_FM
5862306a36Sopenharmony_ci	},
5962306a36Sopenharmony_ci	{
6062306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6162306a36Sopenharmony_ci		.name = "Wavetable Playback Volume",
6262306a36Sopenharmony_ci		.info = snd_opl4_ctl_info,
6362306a36Sopenharmony_ci		.get = snd_opl4_ctl_get,
6462306a36Sopenharmony_ci		.put = snd_opl4_ctl_put,
6562306a36Sopenharmony_ci		.private_value = OPL4_REG_MIX_CONTROL_PCM
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ciint snd_opl4_create_mixer(struct snd_opl4 *opl4)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct snd_card *card = opl4->card;
7262306a36Sopenharmony_ci	int i, err;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	strcat(card->mixername, ",OPL4");
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	for (i = 0; i < 2; ++i) {
7762306a36Sopenharmony_ci		err = snd_ctl_add(card, snd_ctl_new1(&snd_opl4_controls[i], opl4));
7862306a36Sopenharmony_ci		if (err < 0)
7962306a36Sopenharmony_ci			return err;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci	return 0;
8262306a36Sopenharmony_ci}
83