xref: /OK3568_Linux_fs/kernel/sound/usb/6fire/control.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Linux driver for TerraTec DMX 6Fire USB
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Mixer control
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
8*4882a593Smuzhiyun  * Created:	Jan 01, 2011
9*4882a593Smuzhiyun  * Copyright:	(C) Torsten Schenk
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Thanks to:
12*4882a593Smuzhiyun  * - Holger Ruckdeschel: he found out how to control individual channel
13*4882a593Smuzhiyun  *   volumes and introduced mute switch
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <sound/control.h>
18*4882a593Smuzhiyun #include <sound/tlv.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "control.h"
21*4882a593Smuzhiyun #include "comm.h"
22*4882a593Smuzhiyun #include "chip.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static const char * const opt_coax_texts[2] = { "Optical", "Coax" };
25*4882a593Smuzhiyun static const char * const line_phono_texts[2] = { "Line", "Phono" };
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * data that needs to be sent to device. sets up card internal stuff.
29*4882a593Smuzhiyun  * values dumped from windows driver and filtered by trial'n'error.
30*4882a593Smuzhiyun  */
31*4882a593Smuzhiyun static const struct {
32*4882a593Smuzhiyun 	u8 type;
33*4882a593Smuzhiyun 	u8 reg;
34*4882a593Smuzhiyun 	u8 value;
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun init_data[] = {
37*4882a593Smuzhiyun 	{ 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 }, { 0x22, 0x01, 0x01 },
38*4882a593Smuzhiyun 	{ 0x20, 0x01, 0x08 }, { 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 },
39*4882a593Smuzhiyun 	{ 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
40*4882a593Smuzhiyun 	{ 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
41*4882a593Smuzhiyun 	{ 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
42*4882a593Smuzhiyun 	{ 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
43*4882a593Smuzhiyun 	{ 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
44*4882a593Smuzhiyun 	{ 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
45*4882a593Smuzhiyun 	{ 0 } /* TERMINATING ENTRY */
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
49*4882a593Smuzhiyun /* values to write to soundcard register for all samplerates */
50*4882a593Smuzhiyun static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
51*4882a593Smuzhiyun static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0);
54*4882a593Smuzhiyun static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun enum {
57*4882a593Smuzhiyun 	DIGITAL_THRU_ONLY_SAMPLERATE = 3
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun 
usb6fire_control_output_vol_update(struct control_runtime * rt)60*4882a593Smuzhiyun static void usb6fire_control_output_vol_update(struct control_runtime *rt)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = rt->chip->comm;
63*4882a593Smuzhiyun 	int i;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	if (comm_rt)
66*4882a593Smuzhiyun 		for (i = 0; i < 6; i++)
67*4882a593Smuzhiyun 			if (!(rt->ovol_updated & (1 << i))) {
68*4882a593Smuzhiyun 				comm_rt->write8(comm_rt, 0x12, 0x0f + i,
69*4882a593Smuzhiyun 					180 - rt->output_vol[i]);
70*4882a593Smuzhiyun 				rt->ovol_updated |= 1 << i;
71*4882a593Smuzhiyun 			}
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
usb6fire_control_output_mute_update(struct control_runtime * rt)74*4882a593Smuzhiyun static void usb6fire_control_output_mute_update(struct control_runtime *rt)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = rt->chip->comm;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	if (comm_rt)
79*4882a593Smuzhiyun 		comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
usb6fire_control_input_vol_update(struct control_runtime * rt)82*4882a593Smuzhiyun static void usb6fire_control_input_vol_update(struct control_runtime *rt)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = rt->chip->comm;
85*4882a593Smuzhiyun 	int i;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (comm_rt)
88*4882a593Smuzhiyun 		for (i = 0; i < 2; i++)
89*4882a593Smuzhiyun 			if (!(rt->ivol_updated & (1 << i))) {
90*4882a593Smuzhiyun 				comm_rt->write8(comm_rt, 0x12, 0x1c + i,
91*4882a593Smuzhiyun 					rt->input_vol[i] & 0x3f);
92*4882a593Smuzhiyun 				rt->ivol_updated |= 1 << i;
93*4882a593Smuzhiyun 			}
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
usb6fire_control_line_phono_update(struct control_runtime * rt)96*4882a593Smuzhiyun static void usb6fire_control_line_phono_update(struct control_runtime *rt)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = rt->chip->comm;
99*4882a593Smuzhiyun 	if (comm_rt) {
100*4882a593Smuzhiyun 		comm_rt->write8(comm_rt, 0x22, 0x02, rt->line_phono_switch);
101*4882a593Smuzhiyun 		comm_rt->write8(comm_rt, 0x21, 0x02, rt->line_phono_switch);
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
usb6fire_control_opt_coax_update(struct control_runtime * rt)105*4882a593Smuzhiyun static void usb6fire_control_opt_coax_update(struct control_runtime *rt)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = rt->chip->comm;
108*4882a593Smuzhiyun 	if (comm_rt) {
109*4882a593Smuzhiyun 		comm_rt->write8(comm_rt, 0x22, 0x00, rt->opt_coax_switch);
110*4882a593Smuzhiyun 		comm_rt->write8(comm_rt, 0x21, 0x00, rt->opt_coax_switch);
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
usb6fire_control_set_rate(struct control_runtime * rt,int rate)114*4882a593Smuzhiyun static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	int ret;
117*4882a593Smuzhiyun 	struct usb_device *device = rt->chip->dev;
118*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = rt->chip->comm;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (rate < 0 || rate >= CONTROL_N_RATES)
121*4882a593Smuzhiyun 		return -EINVAL;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	ret = usb_set_interface(device, 1, rates_altsetting[rate]);
124*4882a593Smuzhiyun 	if (ret < 0)
125*4882a593Smuzhiyun 		return ret;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* set soundcard clock */
128*4882a593Smuzhiyun 	ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
129*4882a593Smuzhiyun 			rates_6fire_vh[rate]);
130*4882a593Smuzhiyun 	if (ret < 0)
131*4882a593Smuzhiyun 		return ret;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	return 0;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
usb6fire_control_set_channels(struct control_runtime * rt,int n_analog_out,int n_analog_in,bool spdif_out,bool spdif_in)136*4882a593Smuzhiyun static int usb6fire_control_set_channels(
137*4882a593Smuzhiyun 	struct control_runtime *rt, int n_analog_out,
138*4882a593Smuzhiyun 	int n_analog_in, bool spdif_out, bool spdif_in)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	int ret;
141*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = rt->chip->comm;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/* enable analog inputs and outputs
144*4882a593Smuzhiyun 	 * (one bit per stereo-channel) */
145*4882a593Smuzhiyun 	ret = comm_rt->write16(comm_rt, 0x02, 0x02,
146*4882a593Smuzhiyun 			(1 << (n_analog_out / 2)) - 1,
147*4882a593Smuzhiyun 			(1 << (n_analog_in / 2)) - 1);
148*4882a593Smuzhiyun 	if (ret < 0)
149*4882a593Smuzhiyun 		return ret;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* disable digital inputs and outputs */
152*4882a593Smuzhiyun 	/* TODO: use spdif_x to enable/disable digital channels */
153*4882a593Smuzhiyun 	ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
154*4882a593Smuzhiyun 	if (ret < 0)
155*4882a593Smuzhiyun 		return ret;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	return 0;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
usb6fire_control_streaming_update(struct control_runtime * rt)160*4882a593Smuzhiyun static int usb6fire_control_streaming_update(struct control_runtime *rt)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = rt->chip->comm;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (comm_rt) {
165*4882a593Smuzhiyun 		if (!rt->usb_streaming && rt->digital_thru_switch)
166*4882a593Smuzhiyun 			usb6fire_control_set_rate(rt,
167*4882a593Smuzhiyun 				DIGITAL_THRU_ONLY_SAMPLERATE);
168*4882a593Smuzhiyun 		return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
169*4882a593Smuzhiyun 			(rt->usb_streaming ? 0x01 : 0x00) |
170*4882a593Smuzhiyun 			(rt->digital_thru_switch ? 0x08 : 0x00));
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 	return -EINVAL;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
usb6fire_control_output_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)175*4882a593Smuzhiyun static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol,
176*4882a593Smuzhiyun 		struct snd_ctl_elem_info *uinfo)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
179*4882a593Smuzhiyun 	uinfo->count = 2;
180*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
181*4882a593Smuzhiyun 	uinfo->value.integer.max = 180;
182*4882a593Smuzhiyun 	return 0;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
usb6fire_control_output_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)185*4882a593Smuzhiyun static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
186*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
189*4882a593Smuzhiyun 	unsigned int ch = kcontrol->private_value;
190*4882a593Smuzhiyun 	int changed = 0;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	if (ch > 4) {
193*4882a593Smuzhiyun 		dev_err(&rt->chip->dev->dev,
194*4882a593Smuzhiyun 			"Invalid channel in volume control.");
195*4882a593Smuzhiyun 		return -EINVAL;
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) {
199*4882a593Smuzhiyun 		rt->output_vol[ch] = ucontrol->value.integer.value[0];
200*4882a593Smuzhiyun 		rt->ovol_updated &= ~(1 << ch);
201*4882a593Smuzhiyun 		changed = 1;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 	if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) {
204*4882a593Smuzhiyun 		rt->output_vol[ch + 1] = ucontrol->value.integer.value[1];
205*4882a593Smuzhiyun 		rt->ovol_updated &= ~(2 << ch);
206*4882a593Smuzhiyun 		changed = 1;
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if (changed)
210*4882a593Smuzhiyun 		usb6fire_control_output_vol_update(rt);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	return changed;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
usb6fire_control_output_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)215*4882a593Smuzhiyun static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
216*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
219*4882a593Smuzhiyun 	unsigned int ch = kcontrol->private_value;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	if (ch > 4) {
222*4882a593Smuzhiyun 		dev_err(&rt->chip->dev->dev,
223*4882a593Smuzhiyun 			"Invalid channel in volume control.");
224*4882a593Smuzhiyun 		return -EINVAL;
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = rt->output_vol[ch];
228*4882a593Smuzhiyun 	ucontrol->value.integer.value[1] = rt->output_vol[ch + 1];
229*4882a593Smuzhiyun 	return 0;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
usb6fire_control_output_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)232*4882a593Smuzhiyun static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
233*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
236*4882a593Smuzhiyun 	unsigned int ch = kcontrol->private_value;
237*4882a593Smuzhiyun 	u8 old = rt->output_mute;
238*4882a593Smuzhiyun 	u8 value = 0;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	if (ch > 4) {
241*4882a593Smuzhiyun 		dev_err(&rt->chip->dev->dev,
242*4882a593Smuzhiyun 			"Invalid channel in volume control.");
243*4882a593Smuzhiyun 		return -EINVAL;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	rt->output_mute &= ~(3 << ch);
247*4882a593Smuzhiyun 	if (ucontrol->value.integer.value[0])
248*4882a593Smuzhiyun 		value |= 1;
249*4882a593Smuzhiyun 	if (ucontrol->value.integer.value[1])
250*4882a593Smuzhiyun 		value |= 2;
251*4882a593Smuzhiyun 	rt->output_mute |= value << ch;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	if (rt->output_mute != old)
254*4882a593Smuzhiyun 		usb6fire_control_output_mute_update(rt);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	return rt->output_mute != old;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
usb6fire_control_output_mute_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)259*4882a593Smuzhiyun static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
260*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
263*4882a593Smuzhiyun 	unsigned int ch = kcontrol->private_value;
264*4882a593Smuzhiyun 	u8 value = rt->output_mute >> ch;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	if (ch > 4) {
267*4882a593Smuzhiyun 		dev_err(&rt->chip->dev->dev,
268*4882a593Smuzhiyun 			"Invalid channel in volume control.");
269*4882a593Smuzhiyun 		return -EINVAL;
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = 1 & value;
273*4882a593Smuzhiyun 	value >>= 1;
274*4882a593Smuzhiyun 	ucontrol->value.integer.value[1] = 1 & value;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return 0;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
usb6fire_control_input_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)279*4882a593Smuzhiyun static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol,
280*4882a593Smuzhiyun 		struct snd_ctl_elem_info *uinfo)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
283*4882a593Smuzhiyun 	uinfo->count = 2;
284*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
285*4882a593Smuzhiyun 	uinfo->value.integer.max = 30;
286*4882a593Smuzhiyun 	return 0;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
usb6fire_control_input_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)289*4882a593Smuzhiyun static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
290*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
293*4882a593Smuzhiyun 	int changed = 0;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
296*4882a593Smuzhiyun 		rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
297*4882a593Smuzhiyun 		rt->ivol_updated &= ~(1 << 0);
298*4882a593Smuzhiyun 		changed = 1;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 	if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
301*4882a593Smuzhiyun 		rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
302*4882a593Smuzhiyun 		rt->ivol_updated &= ~(1 << 1);
303*4882a593Smuzhiyun 		changed = 1;
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	if (changed)
307*4882a593Smuzhiyun 		usb6fire_control_input_vol_update(rt);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	return changed;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
usb6fire_control_input_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)312*4882a593Smuzhiyun static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
313*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = rt->input_vol[0] + 15;
318*4882a593Smuzhiyun 	ucontrol->value.integer.value[1] = rt->input_vol[1] + 15;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	return 0;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
usb6fire_control_line_phono_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)323*4882a593Smuzhiyun static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
324*4882a593Smuzhiyun 		struct snd_ctl_elem_info *uinfo)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 2, line_phono_texts);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
usb6fire_control_line_phono_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)329*4882a593Smuzhiyun static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
330*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
333*4882a593Smuzhiyun 	int changed = 0;
334*4882a593Smuzhiyun 	if (rt->line_phono_switch != ucontrol->value.integer.value[0]) {
335*4882a593Smuzhiyun 		rt->line_phono_switch = ucontrol->value.integer.value[0];
336*4882a593Smuzhiyun 		usb6fire_control_line_phono_update(rt);
337*4882a593Smuzhiyun 		changed = 1;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 	return changed;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
usb6fire_control_line_phono_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)342*4882a593Smuzhiyun static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
343*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
346*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = rt->line_phono_switch;
347*4882a593Smuzhiyun 	return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
usb6fire_control_opt_coax_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)350*4882a593Smuzhiyun static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
351*4882a593Smuzhiyun 		struct snd_ctl_elem_info *uinfo)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 2, opt_coax_texts);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
usb6fire_control_opt_coax_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)356*4882a593Smuzhiyun static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
357*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
360*4882a593Smuzhiyun 	int changed = 0;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (rt->opt_coax_switch != ucontrol->value.enumerated.item[0]) {
363*4882a593Smuzhiyun 		rt->opt_coax_switch = ucontrol->value.enumerated.item[0];
364*4882a593Smuzhiyun 		usb6fire_control_opt_coax_update(rt);
365*4882a593Smuzhiyun 		changed = 1;
366*4882a593Smuzhiyun 	}
367*4882a593Smuzhiyun 	return changed;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
usb6fire_control_opt_coax_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)370*4882a593Smuzhiyun static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol,
371*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
374*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = rt->opt_coax_switch;
375*4882a593Smuzhiyun 	return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
usb6fire_control_digital_thru_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)378*4882a593Smuzhiyun static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
379*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
382*4882a593Smuzhiyun 	int changed = 0;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
385*4882a593Smuzhiyun 		rt->digital_thru_switch = ucontrol->value.integer.value[0];
386*4882a593Smuzhiyun 		usb6fire_control_streaming_update(rt);
387*4882a593Smuzhiyun 		changed = 1;
388*4882a593Smuzhiyun 	}
389*4882a593Smuzhiyun 	return changed;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
usb6fire_control_digital_thru_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)392*4882a593Smuzhiyun static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
393*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
396*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = rt->digital_thru_switch;
397*4882a593Smuzhiyun 	return 0;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun static const struct snd_kcontrol_new vol_elements[] = {
401*4882a593Smuzhiyun 	{
402*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
403*4882a593Smuzhiyun 		.name = "Analog Playback Volume",
404*4882a593Smuzhiyun 		.index = 0,
405*4882a593Smuzhiyun 		.private_value = 0,
406*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
407*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
408*4882a593Smuzhiyun 		.info = usb6fire_control_output_vol_info,
409*4882a593Smuzhiyun 		.get = usb6fire_control_output_vol_get,
410*4882a593Smuzhiyun 		.put = usb6fire_control_output_vol_put,
411*4882a593Smuzhiyun 		.tlv = { .p = tlv_output }
412*4882a593Smuzhiyun 	},
413*4882a593Smuzhiyun 	{
414*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
415*4882a593Smuzhiyun 		.name = "Analog Playback Volume",
416*4882a593Smuzhiyun 		.index = 1,
417*4882a593Smuzhiyun 		.private_value = 2,
418*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
419*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
420*4882a593Smuzhiyun 		.info = usb6fire_control_output_vol_info,
421*4882a593Smuzhiyun 		.get = usb6fire_control_output_vol_get,
422*4882a593Smuzhiyun 		.put = usb6fire_control_output_vol_put,
423*4882a593Smuzhiyun 		.tlv = { .p = tlv_output }
424*4882a593Smuzhiyun 	},
425*4882a593Smuzhiyun 	{
426*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
427*4882a593Smuzhiyun 		.name = "Analog Playback Volume",
428*4882a593Smuzhiyun 		.index = 2,
429*4882a593Smuzhiyun 		.private_value = 4,
430*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
431*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
432*4882a593Smuzhiyun 		.info = usb6fire_control_output_vol_info,
433*4882a593Smuzhiyun 		.get = usb6fire_control_output_vol_get,
434*4882a593Smuzhiyun 		.put = usb6fire_control_output_vol_put,
435*4882a593Smuzhiyun 		.tlv = { .p = tlv_output }
436*4882a593Smuzhiyun 	},
437*4882a593Smuzhiyun 	{}
438*4882a593Smuzhiyun };
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun static const struct snd_kcontrol_new mute_elements[] = {
441*4882a593Smuzhiyun 	{
442*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
443*4882a593Smuzhiyun 		.name = "Analog Playback Switch",
444*4882a593Smuzhiyun 		.index = 0,
445*4882a593Smuzhiyun 		.private_value = 0,
446*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
447*4882a593Smuzhiyun 		.info = snd_ctl_boolean_stereo_info,
448*4882a593Smuzhiyun 		.get = usb6fire_control_output_mute_get,
449*4882a593Smuzhiyun 		.put = usb6fire_control_output_mute_put,
450*4882a593Smuzhiyun 	},
451*4882a593Smuzhiyun 	{
452*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
453*4882a593Smuzhiyun 		.name = "Analog Playback Switch",
454*4882a593Smuzhiyun 		.index = 1,
455*4882a593Smuzhiyun 		.private_value = 2,
456*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
457*4882a593Smuzhiyun 		.info = snd_ctl_boolean_stereo_info,
458*4882a593Smuzhiyun 		.get = usb6fire_control_output_mute_get,
459*4882a593Smuzhiyun 		.put = usb6fire_control_output_mute_put,
460*4882a593Smuzhiyun 	},
461*4882a593Smuzhiyun 	{
462*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
463*4882a593Smuzhiyun 		.name = "Analog Playback Switch",
464*4882a593Smuzhiyun 		.index = 2,
465*4882a593Smuzhiyun 		.private_value = 4,
466*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
467*4882a593Smuzhiyun 		.info = snd_ctl_boolean_stereo_info,
468*4882a593Smuzhiyun 		.get = usb6fire_control_output_mute_get,
469*4882a593Smuzhiyun 		.put = usb6fire_control_output_mute_put,
470*4882a593Smuzhiyun 	},
471*4882a593Smuzhiyun 	{}
472*4882a593Smuzhiyun };
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun static const struct snd_kcontrol_new elements[] = {
475*4882a593Smuzhiyun 	{
476*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
477*4882a593Smuzhiyun 		.name = "Line/Phono Capture Route",
478*4882a593Smuzhiyun 		.index = 0,
479*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
480*4882a593Smuzhiyun 		.info = usb6fire_control_line_phono_info,
481*4882a593Smuzhiyun 		.get = usb6fire_control_line_phono_get,
482*4882a593Smuzhiyun 		.put = usb6fire_control_line_phono_put
483*4882a593Smuzhiyun 	},
484*4882a593Smuzhiyun 	{
485*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
486*4882a593Smuzhiyun 		.name = "Opt/Coax Capture Route",
487*4882a593Smuzhiyun 		.index = 0,
488*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
489*4882a593Smuzhiyun 		.info = usb6fire_control_opt_coax_info,
490*4882a593Smuzhiyun 		.get = usb6fire_control_opt_coax_get,
491*4882a593Smuzhiyun 		.put = usb6fire_control_opt_coax_put
492*4882a593Smuzhiyun 	},
493*4882a593Smuzhiyun 	{
494*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
495*4882a593Smuzhiyun 		.name = "Digital Thru Playback Route",
496*4882a593Smuzhiyun 		.index = 0,
497*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
498*4882a593Smuzhiyun 		.info = snd_ctl_boolean_mono_info,
499*4882a593Smuzhiyun 		.get = usb6fire_control_digital_thru_get,
500*4882a593Smuzhiyun 		.put = usb6fire_control_digital_thru_put
501*4882a593Smuzhiyun 	},
502*4882a593Smuzhiyun 	{
503*4882a593Smuzhiyun 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
504*4882a593Smuzhiyun 		.name = "Analog Capture Volume",
505*4882a593Smuzhiyun 		.index = 0,
506*4882a593Smuzhiyun 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
507*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_TLV_READ,
508*4882a593Smuzhiyun 		.info = usb6fire_control_input_vol_info,
509*4882a593Smuzhiyun 		.get = usb6fire_control_input_vol_get,
510*4882a593Smuzhiyun 		.put = usb6fire_control_input_vol_put,
511*4882a593Smuzhiyun 		.tlv = { .p = tlv_input }
512*4882a593Smuzhiyun 	},
513*4882a593Smuzhiyun 	{}
514*4882a593Smuzhiyun };
515*4882a593Smuzhiyun 
usb6fire_control_add_virtual(struct control_runtime * rt,struct snd_card * card,char * name,const struct snd_kcontrol_new * elems)516*4882a593Smuzhiyun static int usb6fire_control_add_virtual(
517*4882a593Smuzhiyun 	struct control_runtime *rt,
518*4882a593Smuzhiyun 	struct snd_card *card,
519*4882a593Smuzhiyun 	char *name,
520*4882a593Smuzhiyun 	const struct snd_kcontrol_new *elems)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	int ret;
523*4882a593Smuzhiyun 	int i;
524*4882a593Smuzhiyun 	struct snd_kcontrol *vmaster =
525*4882a593Smuzhiyun 		snd_ctl_make_virtual_master(name, tlv_output);
526*4882a593Smuzhiyun 	struct snd_kcontrol *control;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	if (!vmaster)
529*4882a593Smuzhiyun 		return -ENOMEM;
530*4882a593Smuzhiyun 	ret = snd_ctl_add(card, vmaster);
531*4882a593Smuzhiyun 	if (ret < 0)
532*4882a593Smuzhiyun 		return ret;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	i = 0;
535*4882a593Smuzhiyun 	while (elems[i].name) {
536*4882a593Smuzhiyun 		control = snd_ctl_new1(&elems[i], rt);
537*4882a593Smuzhiyun 		if (!control)
538*4882a593Smuzhiyun 			return -ENOMEM;
539*4882a593Smuzhiyun 		ret = snd_ctl_add(card, control);
540*4882a593Smuzhiyun 		if (ret < 0)
541*4882a593Smuzhiyun 			return ret;
542*4882a593Smuzhiyun 		ret = snd_ctl_add_follower(vmaster, control);
543*4882a593Smuzhiyun 		if (ret < 0)
544*4882a593Smuzhiyun 			return ret;
545*4882a593Smuzhiyun 		i++;
546*4882a593Smuzhiyun 	}
547*4882a593Smuzhiyun 	return 0;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
usb6fire_control_init(struct sfire_chip * chip)550*4882a593Smuzhiyun int usb6fire_control_init(struct sfire_chip *chip)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun 	int i;
553*4882a593Smuzhiyun 	int ret;
554*4882a593Smuzhiyun 	struct control_runtime *rt = kzalloc(sizeof(struct control_runtime),
555*4882a593Smuzhiyun 			GFP_KERNEL);
556*4882a593Smuzhiyun 	struct comm_runtime *comm_rt = chip->comm;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	if (!rt)
559*4882a593Smuzhiyun 		return -ENOMEM;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	rt->chip = chip;
562*4882a593Smuzhiyun 	rt->update_streaming = usb6fire_control_streaming_update;
563*4882a593Smuzhiyun 	rt->set_rate = usb6fire_control_set_rate;
564*4882a593Smuzhiyun 	rt->set_channels = usb6fire_control_set_channels;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	i = 0;
567*4882a593Smuzhiyun 	while (init_data[i].type) {
568*4882a593Smuzhiyun 		comm_rt->write8(comm_rt, init_data[i].type, init_data[i].reg,
569*4882a593Smuzhiyun 				init_data[i].value);
570*4882a593Smuzhiyun 		i++;
571*4882a593Smuzhiyun 	}
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	usb6fire_control_opt_coax_update(rt);
574*4882a593Smuzhiyun 	usb6fire_control_line_phono_update(rt);
575*4882a593Smuzhiyun 	usb6fire_control_output_vol_update(rt);
576*4882a593Smuzhiyun 	usb6fire_control_output_mute_update(rt);
577*4882a593Smuzhiyun 	usb6fire_control_input_vol_update(rt);
578*4882a593Smuzhiyun 	usb6fire_control_streaming_update(rt);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	ret = usb6fire_control_add_virtual(rt, chip->card,
581*4882a593Smuzhiyun 		"Master Playback Volume", vol_elements);
582*4882a593Smuzhiyun 	if (ret) {
583*4882a593Smuzhiyun 		dev_err(&chip->dev->dev, "cannot add control.\n");
584*4882a593Smuzhiyun 		kfree(rt);
585*4882a593Smuzhiyun 		return ret;
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 	ret = usb6fire_control_add_virtual(rt, chip->card,
588*4882a593Smuzhiyun 		"Master Playback Switch", mute_elements);
589*4882a593Smuzhiyun 	if (ret) {
590*4882a593Smuzhiyun 		dev_err(&chip->dev->dev, "cannot add control.\n");
591*4882a593Smuzhiyun 		kfree(rt);
592*4882a593Smuzhiyun 		return ret;
593*4882a593Smuzhiyun 	}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	i = 0;
596*4882a593Smuzhiyun 	while (elements[i].name) {
597*4882a593Smuzhiyun 		ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
598*4882a593Smuzhiyun 		if (ret < 0) {
599*4882a593Smuzhiyun 			kfree(rt);
600*4882a593Smuzhiyun 			dev_err(&chip->dev->dev, "cannot add control.\n");
601*4882a593Smuzhiyun 			return ret;
602*4882a593Smuzhiyun 		}
603*4882a593Smuzhiyun 		i++;
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	chip->control = rt;
607*4882a593Smuzhiyun 	return 0;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun 
usb6fire_control_abort(struct sfire_chip * chip)610*4882a593Smuzhiyun void usb6fire_control_abort(struct sfire_chip *chip)
611*4882a593Smuzhiyun {}
612*4882a593Smuzhiyun 
usb6fire_control_destroy(struct sfire_chip * chip)613*4882a593Smuzhiyun void usb6fire_control_destroy(struct sfire_chip *chip)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun 	kfree(chip->control);
616*4882a593Smuzhiyun 	chip->control = NULL;
617*4882a593Smuzhiyun }
618