1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation.  All rights reserved. */
3 
4 #include <sound/core.h>
5 #include <sound/control.h>
6 #include <sound/tlv.h>
7 #include <sound/asoundef.h>
8 
9 #include "bcm2835.h"
10 
11 /* volume maximum and minimum in terms of 0.01dB */
12 #define CTRL_VOL_MAX 400
13 #define CTRL_VOL_MIN -10239 /* originally -10240 */
14 
bcm2835_audio_set_chip_ctls(struct bcm2835_chip * chip)15 static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
16 {
17 	int i, err = 0;
18 
19 	/* change ctls for all substreams */
20 	for (i = 0; i < MAX_SUBSTREAMS; i++) {
21 		if (chip->alsa_stream[i]) {
22 			err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
23 			if (err < 0)
24 				break;
25 		}
26 	}
27 	return err;
28 }
29 
snd_bcm2835_ctl_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)30 static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
31 				struct snd_ctl_elem_info *uinfo)
32 {
33 	if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
34 		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
35 		uinfo->count = 1;
36 		uinfo->value.integer.min = CTRL_VOL_MIN;
37 		uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
38 	} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
39 		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
40 		uinfo->count = 1;
41 		uinfo->value.integer.min = 0;
42 		uinfo->value.integer.max = 1;
43 	} else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
44 		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
45 		uinfo->count = 1;
46 		uinfo->value.integer.min = 0;
47 		uinfo->value.integer.max = AUDIO_DEST_MAX - 1;
48 	}
49 	return 0;
50 }
51 
snd_bcm2835_ctl_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)52 static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
53 			       struct snd_ctl_elem_value *ucontrol)
54 {
55 	struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
56 
57 	mutex_lock(&chip->audio_mutex);
58 
59 	if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
60 		ucontrol->value.integer.value[0] = chip->volume;
61 	else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
62 		ucontrol->value.integer.value[0] = chip->mute;
63 	else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
64 		ucontrol->value.integer.value[0] = chip->dest;
65 
66 	mutex_unlock(&chip->audio_mutex);
67 	return 0;
68 }
69 
snd_bcm2835_ctl_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)70 static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
71 			       struct snd_ctl_elem_value *ucontrol)
72 {
73 	struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
74 	int val, *valp;
75 	int changed = 0;
76 
77 	if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
78 		valp = &chip->volume;
79 	else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
80 		valp = &chip->mute;
81 	else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
82 		valp = &chip->dest;
83 	else
84 		return -EINVAL;
85 
86 	val = ucontrol->value.integer.value[0];
87 	mutex_lock(&chip->audio_mutex);
88 	if (val != *valp) {
89 		*valp = val;
90 		changed = 1;
91 		if (bcm2835_audio_set_chip_ctls(chip))
92 			dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
93 	}
94 	mutex_unlock(&chip->audio_mutex);
95 	return changed;
96 }
97 
98 static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
99 
100 static const struct snd_kcontrol_new snd_bcm2835_ctl[] = {
101 	{
102 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
103 		.name = "PCM Playback Volume",
104 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
105 		.private_value = PCM_PLAYBACK_VOLUME,
106 		.info = snd_bcm2835_ctl_info,
107 		.get = snd_bcm2835_ctl_get,
108 		.put = snd_bcm2835_ctl_put,
109 		.tlv = {.p = snd_bcm2835_db_scale}
110 	},
111 	{
112 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
113 		.name = "PCM Playback Switch",
114 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
115 		.private_value = PCM_PLAYBACK_MUTE,
116 		.info = snd_bcm2835_ctl_info,
117 		.get = snd_bcm2835_ctl_get,
118 		.put = snd_bcm2835_ctl_put,
119 	},
120 };
121 
snd_bcm2835_spdif_default_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)122 static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
123 					  struct snd_ctl_elem_info *uinfo)
124 {
125 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
126 	uinfo->count = 1;
127 	return 0;
128 }
129 
snd_bcm2835_spdif_default_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)130 static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
131 					 struct snd_ctl_elem_value *ucontrol)
132 {
133 	struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
134 	int i;
135 
136 	mutex_lock(&chip->audio_mutex);
137 
138 	for (i = 0; i < 4; i++)
139 		ucontrol->value.iec958.status[i] =
140 			(chip->spdif_status >> (i * 8)) & 0xff;
141 
142 	mutex_unlock(&chip->audio_mutex);
143 	return 0;
144 }
145 
snd_bcm2835_spdif_default_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)146 static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
147 					 struct snd_ctl_elem_value *ucontrol)
148 {
149 	struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
150 	unsigned int val = 0;
151 	int i, change;
152 
153 	mutex_lock(&chip->audio_mutex);
154 
155 	for (i = 0; i < 4; i++)
156 		val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
157 
158 	change = val != chip->spdif_status;
159 	chip->spdif_status = val;
160 
161 	mutex_unlock(&chip->audio_mutex);
162 	return change;
163 }
164 
snd_bcm2835_spdif_mask_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)165 static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
166 				       struct snd_ctl_elem_info *uinfo)
167 {
168 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
169 	uinfo->count = 1;
170 	return 0;
171 }
172 
snd_bcm2835_spdif_mask_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)173 static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
174 				      struct snd_ctl_elem_value *ucontrol)
175 {
176 	/*
177 	 * bcm2835 supports only consumer mode and sets all other format flags
178 	 * automatically. So the only thing left is signalling non-audio content
179 	 */
180 	ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
181 	return 0;
182 }
183 
184 static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
185 	{
186 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
187 		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
188 		.info = snd_bcm2835_spdif_default_info,
189 		.get = snd_bcm2835_spdif_default_get,
190 		.put = snd_bcm2835_spdif_default_put
191 	},
192 	{
193 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
194 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
195 		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
196 		.info = snd_bcm2835_spdif_mask_info,
197 		.get = snd_bcm2835_spdif_mask_get,
198 	},
199 };
200 
create_ctls(struct bcm2835_chip * chip,size_t size,const struct snd_kcontrol_new * kctls)201 static int create_ctls(struct bcm2835_chip *chip, size_t size,
202 		       const struct snd_kcontrol_new *kctls)
203 {
204 	int i, err;
205 
206 	for (i = 0; i < size; i++) {
207 		err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
208 		if (err < 0)
209 			return err;
210 	}
211 	return 0;
212 }
213 
snd_bcm2835_new_headphones_ctl(struct bcm2835_chip * chip)214 int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
215 {
216 	strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
217 	return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl),
218 			   snd_bcm2835_ctl);
219 }
220 
snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip * chip)221 int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
222 {
223 	int err;
224 
225 	strscpy(chip->card->mixername, "Broadcom Mixer", sizeof(chip->card->mixername));
226 	err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
227 	if (err < 0)
228 		return err;
229 	return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
230 			   snd_bcm2835_spdif);
231 }
232 
233