xref: /openbmc/linux/sound/usb/mixer_scarlett.c (revision ff630b6a)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
276b188c4SChris J Arges /*
376b188c4SChris J Arges  *   Scarlett Driver for ALSA
476b188c4SChris J Arges  *
576b188c4SChris J Arges  *   Copyright (c) 2013 by Tobias Hoffmann
676b188c4SChris J Arges  *   Copyright (c) 2013 by Robin Gareus <robin at gareus.org>
776b188c4SChris J Arges  *   Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de>
876b188c4SChris J Arges  *   Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com>
976b188c4SChris J Arges  *
1076b188c4SChris J Arges  *   Many codes borrowed from audio.c by
1176b188c4SChris J Arges  *	    Alan Cox (alan at lxorguk.ukuu.org.uk)
1276b188c4SChris J Arges  *	    Thomas Sailer (sailer at ife.ee.ethz.ch)
1376b188c4SChris J Arges  *
1476b188c4SChris J Arges  *   Code cleanup:
1576b188c4SChris J Arges  *   David Henningsson <david.henningsson at canonical.com>
1676b188c4SChris J Arges  */
1776b188c4SChris J Arges 
1876b188c4SChris J Arges /*
1976b188c4SChris J Arges  * Rewritten and extended to support more models, e.g. Scarlett 18i8.
2076b188c4SChris J Arges  *
2176b188c4SChris J Arges  * Auto-detection via UAC2 is not feasible to properly discover the vast
2276b188c4SChris J Arges  * majority of features. It's related to both Linux/ALSA's UAC2 as well as
2376b188c4SChris J Arges  * Focusrite's implementation of it. Eventually quirks may be sufficient but
24*ff630b6aSgushengxian  * right now it's a major headache to work around these things.
2576b188c4SChris J Arges  *
2676b188c4SChris J Arges  * NB. Neither the OSX nor the win driver provided by Focusrite performs
2776b188c4SChris J Arges  * discovery, they seem to operate the same as this driver.
2876b188c4SChris J Arges  */
2976b188c4SChris J Arges 
3076b188c4SChris J Arges /* Mixer Interface for the Focusrite Scarlett 18i6 audio interface.
3176b188c4SChris J Arges  *
3276b188c4SChris J Arges  * The protocol was reverse engineered by looking at communication between
3376b188c4SChris J Arges  * Scarlett MixControl (v 1.2.128.0) and the Focusrite(R) Scarlett 18i6
3476b188c4SChris J Arges  * (firmware v305) using wireshark and usbmon in January 2013.
3576b188c4SChris J Arges  * Extended in July 2013.
3676b188c4SChris J Arges  *
3776b188c4SChris J Arges  * this mixer gives complete access to all features of the device:
3876b188c4SChris J Arges  *  - change Impedance of inputs (Line-in, Mic / Instrument, Hi-Z)
3976b188c4SChris J Arges  *  - select clock source
4076b188c4SChris J Arges  *  - dynamic input to mixer-matrix assignment
4176b188c4SChris J Arges  *  - 18 x 6 mixer-matrix gain stages
4276b188c4SChris J Arges  *  - bus routing & volume control
4376b188c4SChris J Arges  *  - automatic re-initialization on connect if device was power-cycled
4476b188c4SChris J Arges  *
4576b188c4SChris J Arges  * USB URB commands overview (bRequest = 0x01 = UAC2_CS_CUR)
4676b188c4SChris J Arges  * wIndex
4776b188c4SChris J Arges  * 0x01 Analog Input line/instrument impedance switch, wValue=0x0901 +
4876b188c4SChris J Arges  *      channel, data=Line/Inst (2bytes)
4976b188c4SChris J Arges  *      pad (-10dB) switch, wValue=0x0b01 + channel, data=Off/On (2bytes)
5076b188c4SChris J Arges  *      ?? wValue=0x0803/04, ?? (2bytes)
5176b188c4SChris J Arges  * 0x0a Master Volume, wValue=0x0200+bus[0:all + only 1..4?] data(2bytes)
5276b188c4SChris J Arges  *      Bus Mute/Unmute wValue=0x0100+bus[0:all + only 1..4?], data(2bytes)
5376b188c4SChris J Arges  * 0x28 Clock source, wValue=0x0100, data={1:int,2:spdif,3:adat} (1byte)
5476b188c4SChris J Arges  * 0x29 Set Sample-rate, wValue=0x0100, data=sample-rate(4bytes)
5576b188c4SChris J Arges  * 0x32 Mixer mux, wValue=0x0600 + mixer-channel, data=input-to-connect(2bytes)
5676b188c4SChris J Arges  * 0x33 Output mux, wValue=bus, data=input-to-connect(2bytes)
5776b188c4SChris J Arges  * 0x34 Capture mux, wValue=0...18, data=input-to-connect(2bytes)
5876b188c4SChris J Arges  * 0x3c Matrix Mixer gains, wValue=mixer-node  data=gain(2bytes)
5976b188c4SChris J Arges  *      ?? [sometimes](4bytes, e.g 0x000003be 0x000003bf ...03ff)
6076b188c4SChris J Arges  *
6176b188c4SChris J Arges  * USB reads: (i.e. actually issued by original software)
6276b188c4SChris J Arges  * 0x01 wValue=0x0901+channel (1byte!!), wValue=0x0b01+channed (1byte!!)
6376b188c4SChris J Arges  * 0x29 wValue=0x0100 sample-rate(4bytes)
6476b188c4SChris J Arges  *      wValue=0x0200 ?? 1byte (only once)
6576b188c4SChris J Arges  * 0x2a wValue=0x0100 ?? 4bytes, sample-rate2 ??
6676b188c4SChris J Arges  *
6776b188c4SChris J Arges  * USB reads with bRequest = 0x03 = UAC2_CS_MEM
6876b188c4SChris J Arges  * 0x3c wValue=0x0002 1byte: sync status (locked=1)
6976b188c4SChris J Arges  *      wValue=0x0000 18*2byte: peak meter (inputs)
7076b188c4SChris J Arges  *      wValue=0x0001 8(?)*2byte: peak meter (mix)
7176b188c4SChris J Arges  *      wValue=0x0003 6*2byte: peak meter (pcm/daw)
7276b188c4SChris J Arges  *
7376b188c4SChris J Arges  * USB write with bRequest = 0x03
7476b188c4SChris J Arges  * 0x3c Save settings to hardware: wValue=0x005a, data=0xa5
7576b188c4SChris J Arges  *
7676b188c4SChris J Arges  *
7776b188c4SChris J Arges  * <ditaa>
7876b188c4SChris J Arges  *  /--------------\    18chn            6chn    /--------------\
7976b188c4SChris J Arges  *  | Hardware  in +--+-------\        /------+--+ ALSA PCM out |
8076b188c4SChris J Arges  *  \--------------/  |       |        |      |  \--------------/
8176b188c4SChris J Arges  *                    |       |        |      |
8276b188c4SChris J Arges  *                    |       v        v      |
8376b188c4SChris J Arges  *                    |   +---------------+   |
8476b188c4SChris J Arges  *                    |    \ Matrix  Mux /    |
8576b188c4SChris J Arges  *                    |     +-----+-----+     |
8676b188c4SChris J Arges  *                    |           |           |
8776b188c4SChris J Arges  *                    |           | 18chn     |
8876b188c4SChris J Arges  *                    |           v           |
8976b188c4SChris J Arges  *                    |     +-----------+     |
9076b188c4SChris J Arges  *                    |     | Mixer     |     |
9176b188c4SChris J Arges  *                    |     |    Matrix |     |
9276b188c4SChris J Arges  *                    |     |           |     |
9376b188c4SChris J Arges  *                    |     | 18x6 Gain |     |
9476b188c4SChris J Arges  *                    |     |   stages  |     |
9576b188c4SChris J Arges  *                    |     +-----+-----+     |
9676b188c4SChris J Arges  *                    |           |           |
9776b188c4SChris J Arges  *                    |           |           |
9876b188c4SChris J Arges  *                    | 18chn     | 6chn      | 6chn
9976b188c4SChris J Arges  *                    v           v           v
10076b188c4SChris J Arges  *                    =========================
10176b188c4SChris J Arges  *             +---------------+     +--—------------+
10276b188c4SChris J Arges  *              \ Output  Mux /       \ Capture Mux /
10376b188c4SChris J Arges  *               +-----+-----+         +-----+-----+
10476b188c4SChris J Arges  *                     |                     |
10576b188c4SChris J Arges  *                     | 6chn                |
10676b188c4SChris J Arges  *                     v                     |
10776b188c4SChris J Arges  *              +-------------+              |
10876b188c4SChris J Arges  *              | Master Gain |              |
10976b188c4SChris J Arges  *              +------+------+              |
11076b188c4SChris J Arges  *                     |                     |
11176b188c4SChris J Arges  *                     | 6chn                | 18chn
11276b188c4SChris J Arges  *                     | (3 stereo pairs)    |
11376b188c4SChris J Arges  *  /--------------\   |                     |   /--------------\
11476b188c4SChris J Arges  *  | Hardware out |<--/                     \-->| ALSA PCM  in |
11576b188c4SChris J Arges  *  \--------------/                             \--------------/
11676b188c4SChris J Arges  * </ditaa>
11776b188c4SChris J Arges  *
11876b188c4SChris J Arges  */
11976b188c4SChris J Arges 
12076b188c4SChris J Arges #include <linux/slab.h>
12176b188c4SChris J Arges #include <linux/usb.h>
12276b188c4SChris J Arges #include <linux/usb/audio-v2.h>
12376b188c4SChris J Arges 
12476b188c4SChris J Arges #include <sound/core.h>
12576b188c4SChris J Arges #include <sound/control.h>
12676b188c4SChris J Arges #include <sound/tlv.h>
12776b188c4SChris J Arges 
12876b188c4SChris J Arges #include "usbaudio.h"
12976b188c4SChris J Arges #include "mixer.h"
13076b188c4SChris J Arges #include "helper.h"
13176b188c4SChris J Arges #include "power.h"
13276b188c4SChris J Arges 
13376b188c4SChris J Arges #include "mixer_scarlett.h"
13476b188c4SChris J Arges 
13576b188c4SChris J Arges /* some gui mixers can't handle negative ctl values */
13676b188c4SChris J Arges #define SND_SCARLETT_LEVEL_BIAS 128
13776b188c4SChris J Arges #define SND_SCARLETT_MATRIX_IN_MAX 18
13876b188c4SChris J Arges #define SND_SCARLETT_CONTROLS_MAX 10
13976b188c4SChris J Arges #define SND_SCARLETT_OFFSETS_MAX 5
14076b188c4SChris J Arges 
14176b188c4SChris J Arges enum {
14276b188c4SChris J Arges 	SCARLETT_OUTPUTS,
14376b188c4SChris J Arges 	SCARLETT_SWITCH_IMPEDANCE,
14476b188c4SChris J Arges 	SCARLETT_SWITCH_PAD,
145bf2aa5caSJens Verwiebe 	SCARLETT_SWITCH_GAIN,
14676b188c4SChris J Arges };
14776b188c4SChris J Arges 
14876b188c4SChris J Arges enum {
14976b188c4SChris J Arges 	SCARLETT_OFFSET_PCM = 0,
15076b188c4SChris J Arges 	SCARLETT_OFFSET_ANALOG = 1,
15176b188c4SChris J Arges 	SCARLETT_OFFSET_SPDIF = 2,
15276b188c4SChris J Arges 	SCARLETT_OFFSET_ADAT = 3,
15376b188c4SChris J Arges 	SCARLETT_OFFSET_MIX = 4,
15476b188c4SChris J Arges };
15576b188c4SChris J Arges 
15676b188c4SChris J Arges struct scarlett_mixer_elem_enum_info {
15776b188c4SChris J Arges 	int start;
15876b188c4SChris J Arges 	int len;
15976b188c4SChris J Arges 	int offsets[SND_SCARLETT_OFFSETS_MAX];
16076b188c4SChris J Arges 	char const * const *names;
16176b188c4SChris J Arges };
16276b188c4SChris J Arges 
16376b188c4SChris J Arges struct scarlett_mixer_control {
16476b188c4SChris J Arges 	unsigned char num;
16576b188c4SChris J Arges 	unsigned char type;
16676b188c4SChris J Arges 	const char *name;
16776b188c4SChris J Arges };
16876b188c4SChris J Arges 
16976b188c4SChris J Arges struct scarlett_device_info {
17076b188c4SChris J Arges 	int matrix_in;
17176b188c4SChris J Arges 	int matrix_out;
17276b188c4SChris J Arges 	int input_len;
17376b188c4SChris J Arges 	int output_len;
17476b188c4SChris J Arges 
17576b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info opt_master;
17676b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info opt_matrix;
17776b188c4SChris J Arges 
17876b188c4SChris J Arges 	/* initial values for matrix mux */
17976b188c4SChris J Arges 	int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX];
18076b188c4SChris J Arges 
18176b188c4SChris J Arges 	int num_controls;	/* number of items in controls */
18276b188c4SChris J Arges 	const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX];
18376b188c4SChris J Arges };
18476b188c4SChris J Arges 
18576b188c4SChris J Arges /********************** Enum Strings *************************/
18676b188c4SChris J Arges 
18776b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_pad = {
18876b188c4SChris J Arges 	.start = 0,
18976b188c4SChris J Arges 	.len = 2,
19076b188c4SChris J Arges 	.offsets = {},
19176b188c4SChris J Arges 	.names = (char const * const []){
19276b188c4SChris J Arges 		"0dB", "-10dB"
19376b188c4SChris J Arges 	}
19476b188c4SChris J Arges };
19576b188c4SChris J Arges 
196bf2aa5caSJens Verwiebe static const struct scarlett_mixer_elem_enum_info opt_gain = {
197bf2aa5caSJens Verwiebe 	.start = 0,
198bf2aa5caSJens Verwiebe 	.len = 2,
199bf2aa5caSJens Verwiebe 	.offsets = {},
200bf2aa5caSJens Verwiebe 	.names = (char const * const []){
201bf2aa5caSJens Verwiebe 		"Lo", "Hi"
202bf2aa5caSJens Verwiebe 	}
203bf2aa5caSJens Verwiebe };
204bf2aa5caSJens Verwiebe 
20576b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_impedance = {
20676b188c4SChris J Arges 	.start = 0,
20776b188c4SChris J Arges 	.len = 2,
20876b188c4SChris J Arges 	.offsets = {},
20976b188c4SChris J Arges 	.names = (char const * const []){
21076b188c4SChris J Arges 		"Line", "Hi-Z"
21176b188c4SChris J Arges 	}
21276b188c4SChris J Arges };
21376b188c4SChris J Arges 
21476b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_clock = {
21576b188c4SChris J Arges 	.start = 1,
21676b188c4SChris J Arges 	.len = 3,
21776b188c4SChris J Arges 	.offsets = {},
21876b188c4SChris J Arges 	.names = (char const * const []){
21976b188c4SChris J Arges 		"Internal", "SPDIF", "ADAT"
22076b188c4SChris J Arges 	}
22176b188c4SChris J Arges };
22276b188c4SChris J Arges 
22376b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_sync = {
22476b188c4SChris J Arges 	.start = 0,
22576b188c4SChris J Arges 	.len = 2,
22676b188c4SChris J Arges 	.offsets = {},
22776b188c4SChris J Arges 	.names = (char const * const []){
22876b188c4SChris J Arges 		"No Lock", "Locked"
22976b188c4SChris J Arges 	}
23076b188c4SChris J Arges };
23176b188c4SChris J Arges 
scarlett_ctl_switch_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)23276b188c4SChris J Arges static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl,
23376b188c4SChris J Arges 		struct snd_ctl_elem_info *uinfo)
23476b188c4SChris J Arges {
23576b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
23676b188c4SChris J Arges 
23776b188c4SChris J Arges 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
23876b188c4SChris J Arges 	uinfo->count = elem->channels;
23976b188c4SChris J Arges 	uinfo->value.integer.min = 0;
24076b188c4SChris J Arges 	uinfo->value.integer.max = 1;
24176b188c4SChris J Arges 	return 0;
24276b188c4SChris J Arges }
24376b188c4SChris J Arges 
scarlett_ctl_switch_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)24476b188c4SChris J Arges static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl,
24576b188c4SChris J Arges 		struct snd_ctl_elem_value *ucontrol)
24676b188c4SChris J Arges {
24776b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
24876b188c4SChris J Arges 	int i, err, val;
24976b188c4SChris J Arges 
25076b188c4SChris J Arges 	for (i = 0; i < elem->channels; i++) {
25176b188c4SChris J Arges 		err = snd_usb_get_cur_mix_value(elem, i, i, &val);
25276b188c4SChris J Arges 		if (err < 0)
25376b188c4SChris J Arges 			return err;
25476b188c4SChris J Arges 
25576b188c4SChris J Arges 		val = !val; /* invert mute logic for mixer */
25676b188c4SChris J Arges 		ucontrol->value.integer.value[i] = val;
25776b188c4SChris J Arges 	}
25876b188c4SChris J Arges 
25976b188c4SChris J Arges 	return 0;
26076b188c4SChris J Arges }
26176b188c4SChris J Arges 
scarlett_ctl_switch_put(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)26276b188c4SChris J Arges static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl,
26376b188c4SChris J Arges 		struct snd_ctl_elem_value *ucontrol)
26476b188c4SChris J Arges {
26576b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
26676b188c4SChris J Arges 	int i, changed = 0;
26776b188c4SChris J Arges 	int err, oval, val;
26876b188c4SChris J Arges 
26976b188c4SChris J Arges 	for (i = 0; i < elem->channels; i++) {
27076b188c4SChris J Arges 		err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
27176b188c4SChris J Arges 		if (err < 0)
27276b188c4SChris J Arges 			return err;
27376b188c4SChris J Arges 
27476b188c4SChris J Arges 		val = ucontrol->value.integer.value[i];
27576b188c4SChris J Arges 		val = !val;
27676b188c4SChris J Arges 		if (oval != val) {
27776b188c4SChris J Arges 			err = snd_usb_set_cur_mix_value(elem, i, i, val);
27876b188c4SChris J Arges 			if (err < 0)
27976b188c4SChris J Arges 				return err;
28076b188c4SChris J Arges 
28176b188c4SChris J Arges 			changed = 1;
28276b188c4SChris J Arges 		}
28376b188c4SChris J Arges 	}
28476b188c4SChris J Arges 
28576b188c4SChris J Arges 	return changed;
28676b188c4SChris J Arges }
28776b188c4SChris J Arges 
scarlett_ctl_resume(struct usb_mixer_elem_list * list)288b61f90eaSTakashi Iwai static int scarlett_ctl_resume(struct usb_mixer_elem_list *list)
289b61f90eaSTakashi Iwai {
2908c558076STakashi Iwai 	struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list);
291b61f90eaSTakashi Iwai 	int i;
292b61f90eaSTakashi Iwai 
293b61f90eaSTakashi Iwai 	for (i = 0; i < elem->channels; i++)
294b61f90eaSTakashi Iwai 		if (elem->cached & (1 << i))
295b61f90eaSTakashi Iwai 			snd_usb_set_cur_mix_value(elem, i, i,
296b61f90eaSTakashi Iwai 						  elem->cache_val[i]);
297b61f90eaSTakashi Iwai 	return 0;
298b61f90eaSTakashi Iwai }
299b61f90eaSTakashi Iwai 
scarlett_ctl_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)30076b188c4SChris J Arges static int scarlett_ctl_info(struct snd_kcontrol *kctl,
30176b188c4SChris J Arges 			     struct snd_ctl_elem_info *uinfo)
30276b188c4SChris J Arges {
30376b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
30476b188c4SChris J Arges 
30576b188c4SChris J Arges 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
30676b188c4SChris J Arges 	uinfo->count = elem->channels;
30776b188c4SChris J Arges 	uinfo->value.integer.min = 0;
30876b188c4SChris J Arges 	uinfo->value.integer.max = (int)kctl->private_value +
30976b188c4SChris J Arges 		SND_SCARLETT_LEVEL_BIAS;
31076b188c4SChris J Arges 	uinfo->value.integer.step = 1;
31176b188c4SChris J Arges 	return 0;
31276b188c4SChris J Arges }
31376b188c4SChris J Arges 
scarlett_ctl_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)31476b188c4SChris J Arges static int scarlett_ctl_get(struct snd_kcontrol *kctl,
31576b188c4SChris J Arges 			    struct snd_ctl_elem_value *ucontrol)
31676b188c4SChris J Arges {
31776b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
31876b188c4SChris J Arges 	int i, err, val;
31976b188c4SChris J Arges 
32076b188c4SChris J Arges 	for (i = 0; i < elem->channels; i++) {
32176b188c4SChris J Arges 		err = snd_usb_get_cur_mix_value(elem, i, i, &val);
32276b188c4SChris J Arges 		if (err < 0)
32376b188c4SChris J Arges 			return err;
32476b188c4SChris J Arges 
32576b188c4SChris J Arges 		val = clamp(val / 256, -128, (int)kctl->private_value) +
32676b188c4SChris J Arges 				    SND_SCARLETT_LEVEL_BIAS;
32776b188c4SChris J Arges 		ucontrol->value.integer.value[i] = val;
32876b188c4SChris J Arges 	}
32976b188c4SChris J Arges 
33076b188c4SChris J Arges 	return 0;
33176b188c4SChris J Arges }
33276b188c4SChris J Arges 
scarlett_ctl_put(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)33376b188c4SChris J Arges static int scarlett_ctl_put(struct snd_kcontrol *kctl,
33476b188c4SChris J Arges 			    struct snd_ctl_elem_value *ucontrol)
33576b188c4SChris J Arges {
33676b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
33776b188c4SChris J Arges 	int i, changed = 0;
33876b188c4SChris J Arges 	int err, oval, val;
33976b188c4SChris J Arges 
34076b188c4SChris J Arges 	for (i = 0; i < elem->channels; i++) {
34176b188c4SChris J Arges 		err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
34276b188c4SChris J Arges 		if (err < 0)
34376b188c4SChris J Arges 			return err;
34476b188c4SChris J Arges 
34576b188c4SChris J Arges 		val = ucontrol->value.integer.value[i] -
34676b188c4SChris J Arges 			SND_SCARLETT_LEVEL_BIAS;
34776b188c4SChris J Arges 		val = val * 256;
34876b188c4SChris J Arges 		if (oval != val) {
34976b188c4SChris J Arges 			err = snd_usb_set_cur_mix_value(elem, i, i, val);
35076b188c4SChris J Arges 			if (err < 0)
35176b188c4SChris J Arges 				return err;
35276b188c4SChris J Arges 
35376b188c4SChris J Arges 			changed = 1;
35476b188c4SChris J Arges 		}
35576b188c4SChris J Arges 	}
35676b188c4SChris J Arges 
35776b188c4SChris J Arges 	return changed;
35876b188c4SChris J Arges }
35976b188c4SChris J Arges 
scarlett_generate_name(int i,char * dst,int offsets[])36076b188c4SChris J Arges static void scarlett_generate_name(int i, char *dst, int offsets[])
36176b188c4SChris J Arges {
36276b188c4SChris J Arges 	if (i > offsets[SCARLETT_OFFSET_MIX])
36376b188c4SChris J Arges 		sprintf(dst, "Mix %c",
36476b188c4SChris J Arges 			'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1));
36576b188c4SChris J Arges 	else if (i > offsets[SCARLETT_OFFSET_ADAT])
36676b188c4SChris J Arges 		sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]);
36776b188c4SChris J Arges 	else if (i > offsets[SCARLETT_OFFSET_SPDIF])
36876b188c4SChris J Arges 		sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]);
36976b188c4SChris J Arges 	else if (i > offsets[SCARLETT_OFFSET_ANALOG])
37076b188c4SChris J Arges 		sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]);
37176b188c4SChris J Arges 	else if (i > offsets[SCARLETT_OFFSET_PCM])
37276b188c4SChris J Arges 		sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]);
37376b188c4SChris J Arges 	else
37476b188c4SChris J Arges 		sprintf(dst, "Off");
37576b188c4SChris J Arges }
37676b188c4SChris J Arges 
scarlett_ctl_enum_dynamic_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)37776b188c4SChris J Arges static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl,
37876b188c4SChris J Arges 					  struct snd_ctl_elem_info *uinfo)
37976b188c4SChris J Arges {
38076b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
38176b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
38276b188c4SChris J Arges 	unsigned int items = opt->len;
38376b188c4SChris J Arges 
38476b188c4SChris J Arges 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
38576b188c4SChris J Arges 	uinfo->count = elem->channels;
38676b188c4SChris J Arges 	uinfo->value.enumerated.items = items;
38776b188c4SChris J Arges 
38876b188c4SChris J Arges 	if (uinfo->value.enumerated.item >= items)
38976b188c4SChris J Arges 		uinfo->value.enumerated.item = items - 1;
39076b188c4SChris J Arges 
39176b188c4SChris J Arges 	/* generate name dynamically based on item number and offset info */
39276b188c4SChris J Arges 	scarlett_generate_name(uinfo->value.enumerated.item,
39376b188c4SChris J Arges 			       uinfo->value.enumerated.name,
39476b188c4SChris J Arges 			       opt->offsets);
39576b188c4SChris J Arges 
39676b188c4SChris J Arges 	return 0;
39776b188c4SChris J Arges }
39876b188c4SChris J Arges 
scarlett_ctl_enum_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)39976b188c4SChris J Arges static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl,
40076b188c4SChris J Arges 				  struct snd_ctl_elem_info *uinfo)
40176b188c4SChris J Arges {
40276b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
40376b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
40476b188c4SChris J Arges 
40576b188c4SChris J Arges 	return snd_ctl_enum_info(uinfo, elem->channels, opt->len,
40676b188c4SChris J Arges 				 (const char * const *)opt->names);
40776b188c4SChris J Arges }
40876b188c4SChris J Arges 
scarlett_ctl_enum_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)40976b188c4SChris J Arges static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl,
41076b188c4SChris J Arges 				 struct snd_ctl_elem_value *ucontrol)
41176b188c4SChris J Arges {
41276b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
41376b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
41476b188c4SChris J Arges 	int err, val;
41576b188c4SChris J Arges 
41676b188c4SChris J Arges 	err = snd_usb_get_cur_mix_value(elem, 0, 0, &val);
41776b188c4SChris J Arges 	if (err < 0)
41876b188c4SChris J Arges 		return err;
41976b188c4SChris J Arges 
42076b188c4SChris J Arges 	val = clamp(val - opt->start, 0, opt->len-1);
42176b188c4SChris J Arges 
42276b188c4SChris J Arges 	ucontrol->value.enumerated.item[0] = val;
42376b188c4SChris J Arges 
42476b188c4SChris J Arges 	return 0;
42576b188c4SChris J Arges }
42676b188c4SChris J Arges 
scarlett_ctl_enum_put(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)42776b188c4SChris J Arges static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl,
42876b188c4SChris J Arges 				 struct snd_ctl_elem_value *ucontrol)
42976b188c4SChris J Arges {
43076b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
43176b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
43276b188c4SChris J Arges 	int err, oval, val;
43376b188c4SChris J Arges 
43476b188c4SChris J Arges 	err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval);
43576b188c4SChris J Arges 	if (err < 0)
43676b188c4SChris J Arges 		return err;
43776b188c4SChris J Arges 
43876b188c4SChris J Arges 	val = ucontrol->value.integer.value[0];
43976b188c4SChris J Arges 	val = val + opt->start;
44076b188c4SChris J Arges 	if (val != oval) {
44176b188c4SChris J Arges 		snd_usb_set_cur_mix_value(elem, 0, 0, val);
44276b188c4SChris J Arges 		return 1;
44376b188c4SChris J Arges 	}
44476b188c4SChris J Arges 	return 0;
44576b188c4SChris J Arges }
44676b188c4SChris J Arges 
scarlett_ctl_enum_resume(struct usb_mixer_elem_list * list)447b61f90eaSTakashi Iwai static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list)
448b61f90eaSTakashi Iwai {
4498c558076STakashi Iwai 	struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list);
450b61f90eaSTakashi Iwai 
451b61f90eaSTakashi Iwai 	if (elem->cached)
452b61f90eaSTakashi Iwai 		snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val);
453b61f90eaSTakashi Iwai 	return 0;
454b61f90eaSTakashi Iwai }
455b61f90eaSTakashi Iwai 
scarlett_ctl_meter_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)45676b188c4SChris J Arges static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
45776b188c4SChris J Arges 				  struct snd_ctl_elem_value *ucontrol)
45876b188c4SChris J Arges {
45976b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
4603360b84bSTakashi Iwai 	struct snd_usb_audio *chip = elem->head.mixer->chip;
46176b188c4SChris J Arges 	unsigned char buf[2 * MAX_CHANNELS] = {0, };
46276b188c4SChris J Arges 	int wValue = (elem->control << 8) | elem->idx_off;
4633360b84bSTakashi Iwai 	int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
46476b188c4SChris J Arges 	int err;
46576b188c4SChris J Arges 
46676b188c4SChris J Arges 	err = snd_usb_ctl_msg(chip->dev,
46776b188c4SChris J Arges 				usb_rcvctrlpipe(chip->dev, 0),
46876b188c4SChris J Arges 				UAC2_CS_MEM,
46976b188c4SChris J Arges 				USB_RECIP_INTERFACE | USB_TYPE_CLASS |
47076b188c4SChris J Arges 				USB_DIR_IN, wValue, idx, buf, elem->channels);
47176b188c4SChris J Arges 	if (err < 0)
47276b188c4SChris J Arges 		return err;
47376b188c4SChris J Arges 
47476b188c4SChris J Arges 	ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1);
47576b188c4SChris J Arges 	return 0;
47676b188c4SChris J Arges }
47776b188c4SChris J Arges 
47804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_switch = {
47976b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
48076b188c4SChris J Arges 	.name = "",
48176b188c4SChris J Arges 	.info = scarlett_ctl_switch_info,
48276b188c4SChris J Arges 	.get =  scarlett_ctl_switch_get,
48376b188c4SChris J Arges 	.put =  scarlett_ctl_switch_put,
48476b188c4SChris J Arges };
48576b188c4SChris J Arges 
48676b188c4SChris J Arges static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0);
48776b188c4SChris J Arges 
48804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl = {
48976b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
49076b188c4SChris J Arges 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
49176b188c4SChris J Arges 		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
49276b188c4SChris J Arges 	.name = "",
49376b188c4SChris J Arges 	.info = scarlett_ctl_info,
49476b188c4SChris J Arges 	.get =  scarlett_ctl_get,
49576b188c4SChris J Arges 	.put =  scarlett_ctl_put,
49676b188c4SChris J Arges 	.private_value = 6,  /* max value */
49776b188c4SChris J Arges 	.tlv = { .p = db_scale_scarlett_gain }
49876b188c4SChris J Arges };
49976b188c4SChris J Arges 
50004bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_master = {
50176b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
50276b188c4SChris J Arges 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
50376b188c4SChris J Arges 		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
50476b188c4SChris J Arges 	.name = "",
50576b188c4SChris J Arges 	.info = scarlett_ctl_info,
50676b188c4SChris J Arges 	.get =  scarlett_ctl_get,
50776b188c4SChris J Arges 	.put =  scarlett_ctl_put,
50876b188c4SChris J Arges 	.private_value = 6,  /* max value */
50976b188c4SChris J Arges 	.tlv = { .p = db_scale_scarlett_gain }
51076b188c4SChris J Arges };
51176b188c4SChris J Arges 
51204bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_enum = {
51376b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
51476b188c4SChris J Arges 	.name = "",
51576b188c4SChris J Arges 	.info = scarlett_ctl_enum_info,
51676b188c4SChris J Arges 	.get =  scarlett_ctl_enum_get,
51776b188c4SChris J Arges 	.put =  scarlett_ctl_enum_put,
51876b188c4SChris J Arges };
51976b188c4SChris J Arges 
52004bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
52176b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
52276b188c4SChris J Arges 	.name = "",
52376b188c4SChris J Arges 	.info = scarlett_ctl_enum_dynamic_info,
52476b188c4SChris J Arges 	.get =  scarlett_ctl_enum_get,
52576b188c4SChris J Arges 	.put =  scarlett_ctl_enum_put,
52676b188c4SChris J Arges };
52776b188c4SChris J Arges 
52804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_sync = {
52976b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
53076b188c4SChris J Arges 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
53176b188c4SChris J Arges 	.name = "",
53276b188c4SChris J Arges 	.info = scarlett_ctl_enum_info,
53376b188c4SChris J Arges 	.get =  scarlett_ctl_meter_get,
53476b188c4SChris J Arges };
53576b188c4SChris J Arges 
add_new_ctl(struct usb_mixer_interface * mixer,const struct snd_kcontrol_new * ncontrol,usb_mixer_elem_resume_func_t resume,int index,int offset,int num,int val_type,int channels,const char * name,const struct scarlett_mixer_elem_enum_info * opt,struct usb_mixer_elem_info ** elem_ret)53676b188c4SChris J Arges static int add_new_ctl(struct usb_mixer_interface *mixer,
53776b188c4SChris J Arges 		       const struct snd_kcontrol_new *ncontrol,
538b61f90eaSTakashi Iwai 		       usb_mixer_elem_resume_func_t resume,
53976b188c4SChris J Arges 		       int index, int offset, int num,
54076b188c4SChris J Arges 		       int val_type, int channels, const char *name,
54176b188c4SChris J Arges 		       const struct scarlett_mixer_elem_enum_info *opt,
54276b188c4SChris J Arges 		       struct usb_mixer_elem_info **elem_ret
54376b188c4SChris J Arges )
54476b188c4SChris J Arges {
54576b188c4SChris J Arges 	struct snd_kcontrol *kctl;
54676b188c4SChris J Arges 	struct usb_mixer_elem_info *elem;
54776b188c4SChris J Arges 	int err;
54876b188c4SChris J Arges 
54976b188c4SChris J Arges 	elem = kzalloc(sizeof(*elem), GFP_KERNEL);
55076b188c4SChris J Arges 	if (!elem)
55176b188c4SChris J Arges 		return -ENOMEM;
55276b188c4SChris J Arges 
5533360b84bSTakashi Iwai 	elem->head.mixer = mixer;
554b61f90eaSTakashi Iwai 	elem->head.resume = resume;
55576b188c4SChris J Arges 	elem->control = offset;
55676b188c4SChris J Arges 	elem->idx_off = num;
5573360b84bSTakashi Iwai 	elem->head.id = index;
55876b188c4SChris J Arges 	elem->val_type = val_type;
55976b188c4SChris J Arges 
56076b188c4SChris J Arges 	elem->channels = channels;
56176b188c4SChris J Arges 
56276b188c4SChris J Arges 	/* add scarlett_mixer_elem_enum_info struct */
56376b188c4SChris J Arges 	elem->private_data = (void *)opt;
56476b188c4SChris J Arges 
56576b188c4SChris J Arges 	kctl = snd_ctl_new1(ncontrol, elem);
56676b188c4SChris J Arges 	if (!kctl) {
56776b188c4SChris J Arges 		kfree(elem);
56876b188c4SChris J Arges 		return -ENOMEM;
56976b188c4SChris J Arges 	}
57076b188c4SChris J Arges 	kctl->private_free = snd_usb_mixer_elem_free;
57176b188c4SChris J Arges 
57275b1a8f9SJoe Perches 	strscpy(kctl->id.name, name, sizeof(kctl->id.name));
57376b188c4SChris J Arges 
574b61f90eaSTakashi Iwai 	err = snd_usb_mixer_add_control(&elem->head, kctl);
57576b188c4SChris J Arges 	if (err < 0)
57676b188c4SChris J Arges 		return err;
57776b188c4SChris J Arges 
57876b188c4SChris J Arges 	if (elem_ret)
57976b188c4SChris J Arges 		*elem_ret = elem;
58076b188c4SChris J Arges 
58176b188c4SChris J Arges 	return 0;
58276b188c4SChris J Arges }
58376b188c4SChris J Arges 
add_output_ctls(struct usb_mixer_interface * mixer,int index,const char * name,const struct scarlett_device_info * info)58476b188c4SChris J Arges static int add_output_ctls(struct usb_mixer_interface *mixer,
58576b188c4SChris J Arges 			   int index, const char *name,
58676b188c4SChris J Arges 			   const struct scarlett_device_info *info)
58776b188c4SChris J Arges {
58876b188c4SChris J Arges 	int err;
58976b188c4SChris J Arges 	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
59076b188c4SChris J Arges 	struct usb_mixer_elem_info *elem;
59176b188c4SChris J Arges 
59276b188c4SChris J Arges 	/* Add mute switch */
59376b188c4SChris J Arges 	snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch",
59476b188c4SChris J Arges 		index + 1, name);
595b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
596b61f90eaSTakashi Iwai 			  scarlett_ctl_resume, 0x0a, 0x01,
59776b188c4SChris J Arges 			  2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
59876b188c4SChris J Arges 	if (err < 0)
59976b188c4SChris J Arges 		return err;
60076b188c4SChris J Arges 
60176b188c4SChris J Arges 	/* Add volume control and initialize to 0 */
60276b188c4SChris J Arges 	snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume",
60376b188c4SChris J Arges 		index + 1, name);
604b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
605b61f90eaSTakashi Iwai 			  scarlett_ctl_resume, 0x0a, 0x02,
60676b188c4SChris J Arges 			  2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
60776b188c4SChris J Arges 	if (err < 0)
60876b188c4SChris J Arges 		return err;
60976b188c4SChris J Arges 
61076b188c4SChris J Arges 	/* Add L channel source playback enumeration */
61176b188c4SChris J Arges 	snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum",
61276b188c4SChris J Arges 		index + 1, name);
613b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
614b61f90eaSTakashi Iwai 			  scarlett_ctl_enum_resume, 0x33, 0x00,
61576b188c4SChris J Arges 			  2*index, USB_MIXER_S16, 1, mx, &info->opt_master,
61676b188c4SChris J Arges 			  &elem);
61776b188c4SChris J Arges 	if (err < 0)
61876b188c4SChris J Arges 		return err;
61976b188c4SChris J Arges 
62076b188c4SChris J Arges 	/* Add R channel source playback enumeration */
62176b188c4SChris J Arges 	snprintf(mx, sizeof(mx), "Master %dR (%s) Source Playback Enum",
62276b188c4SChris J Arges 		index + 1, name);
623b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
624b61f90eaSTakashi Iwai 			  scarlett_ctl_enum_resume, 0x33, 0x00,
62576b188c4SChris J Arges 			  2*index+1, USB_MIXER_S16, 1, mx, &info->opt_master,
62676b188c4SChris J Arges 			  &elem);
62776b188c4SChris J Arges 	if (err < 0)
62876b188c4SChris J Arges 		return err;
62976b188c4SChris J Arges 
63076b188c4SChris J Arges 	return 0;
63176b188c4SChris J Arges }
63276b188c4SChris J Arges 
63376b188c4SChris J Arges /********************** device-specific config *************************/
63476b188c4SChris J Arges 
63576b188c4SChris J Arges /*  untested...  */
636a01df925STakashi Iwai static const struct scarlett_device_info s6i6_info = {
63776b188c4SChris J Arges 	.matrix_in = 18,
63876b188c4SChris J Arges 	.matrix_out = 8,
63976b188c4SChris J Arges 	.input_len = 6,
64076b188c4SChris J Arges 	.output_len = 6,
64176b188c4SChris J Arges 
64276b188c4SChris J Arges 	.opt_master = {
64376b188c4SChris J Arges 		.start = -1,
64476b188c4SChris J Arges 		.len = 27,
64576b188c4SChris J Arges 		.offsets = {0, 12, 16, 18, 18},
64676b188c4SChris J Arges 		.names = NULL
64776b188c4SChris J Arges 	},
64876b188c4SChris J Arges 
64976b188c4SChris J Arges 	.opt_matrix = {
65076b188c4SChris J Arges 		.start = -1,
65176b188c4SChris J Arges 		.len = 19,
65276b188c4SChris J Arges 		.offsets = {0, 12, 16, 18, 18},
65376b188c4SChris J Arges 		.names = NULL
65476b188c4SChris J Arges 	},
65576b188c4SChris J Arges 
656c99b9e85SChris J Arges 	.num_controls = 9,
65776b188c4SChris J Arges 	.controls = {
65876b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
65976b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
66076b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
66176b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
66276b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
66376b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
66476b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
665bf2aa5caSJens Verwiebe 		{ .num = 3, .type = SCARLETT_SWITCH_GAIN, .name = NULL},
666bf2aa5caSJens Verwiebe 		{ .num = 4, .type = SCARLETT_SWITCH_GAIN, .name = NULL},
66776b188c4SChris J Arges 	},
66876b188c4SChris J Arges 
66976b188c4SChris J Arges 	.matrix_mux_init = {
67076b188c4SChris J Arges 		12, 13, 14, 15,                 /* Analog -> 1..4 */
67176b188c4SChris J Arges 		16, 17,                          /* SPDIF -> 5,6 */
67276b188c4SChris J Arges 		0, 1, 2, 3, 4, 5, 6, 7,     /* PCM[1..12] -> 7..18 */
67376b188c4SChris J Arges 		8, 9, 10, 11
67476b188c4SChris J Arges 	}
67576b188c4SChris J Arges };
67676b188c4SChris J Arges 
67776b188c4SChris J Arges /*  untested...  */
678a01df925STakashi Iwai static const struct scarlett_device_info s8i6_info = {
67976b188c4SChris J Arges 	.matrix_in = 18,
68076b188c4SChris J Arges 	.matrix_out = 6,
68176b188c4SChris J Arges 	.input_len = 8,
68276b188c4SChris J Arges 	.output_len = 6,
68376b188c4SChris J Arges 
68476b188c4SChris J Arges 	.opt_master = {
68576b188c4SChris J Arges 		.start = -1,
68676b188c4SChris J Arges 		.len = 25,
68776b188c4SChris J Arges 		.offsets = {0, 12, 16, 18, 18},
68876b188c4SChris J Arges 		.names = NULL
68976b188c4SChris J Arges 	},
69076b188c4SChris J Arges 
69176b188c4SChris J Arges 	.opt_matrix = {
69276b188c4SChris J Arges 		.start = -1,
69376b188c4SChris J Arges 		.len = 19,
69476b188c4SChris J Arges 		.offsets = {0, 12, 16, 18, 18},
69576b188c4SChris J Arges 		.names = NULL
69676b188c4SChris J Arges 	},
69776b188c4SChris J Arges 
69876b188c4SChris J Arges 	.num_controls = 7,
69976b188c4SChris J Arges 	.controls = {
70076b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
70176b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
70276b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
70376b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
70476b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
70576b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
70676b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
70776b188c4SChris J Arges 	},
70876b188c4SChris J Arges 
70976b188c4SChris J Arges 	.matrix_mux_init = {
71076b188c4SChris J Arges 		12, 13, 14, 15,                 /* Analog -> 1..4 */
71176b188c4SChris J Arges 		16, 17,                          /* SPDIF -> 5,6 */
71276b188c4SChris J Arges 		0, 1, 2, 3, 4, 5, 6, 7,     /* PCM[1..12] -> 7..18 */
71376b188c4SChris J Arges 		8, 9, 10, 11
71476b188c4SChris J Arges 	}
71576b188c4SChris J Arges };
71676b188c4SChris J Arges 
717a01df925STakashi Iwai static const struct scarlett_device_info s18i6_info = {
71876b188c4SChris J Arges 	.matrix_in = 18,
71976b188c4SChris J Arges 	.matrix_out = 6,
72076b188c4SChris J Arges 	.input_len = 18,
72176b188c4SChris J Arges 	.output_len = 6,
72276b188c4SChris J Arges 
72376b188c4SChris J Arges 	.opt_master = {
72476b188c4SChris J Arges 		.start = -1,
72576b188c4SChris J Arges 		.len = 31,
72676b188c4SChris J Arges 		.offsets = {0, 6, 14, 16, 24},
72776b188c4SChris J Arges 		.names = NULL,
72876b188c4SChris J Arges 	},
72976b188c4SChris J Arges 
73076b188c4SChris J Arges 	.opt_matrix = {
73176b188c4SChris J Arges 		.start = -1,
73276b188c4SChris J Arges 		.len = 25,
73376b188c4SChris J Arges 		.offsets = {0, 6, 14, 16, 24},
73476b188c4SChris J Arges 		.names = NULL,
73576b188c4SChris J Arges 	},
73676b188c4SChris J Arges 
73776b188c4SChris J Arges 	.num_controls = 5,
73876b188c4SChris J Arges 	.controls = {
73976b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
74076b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
74176b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
74276b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
74376b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
74476b188c4SChris J Arges 	},
74576b188c4SChris J Arges 
74676b188c4SChris J Arges 	.matrix_mux_init = {
74776b188c4SChris J Arges 		 6,  7,  8,  9, 10, 11, 12, 13, /* Analog -> 1..8 */
74876b188c4SChris J Arges 		16, 17, 18, 19, 20, 21,     /* ADAT[1..6] -> 9..14 */
74976b188c4SChris J Arges 		14, 15,                          /* SPDIF -> 15,16 */
75076b188c4SChris J Arges 		0, 1                          /* PCM[1,2] -> 17,18 */
75176b188c4SChris J Arges 	}
75276b188c4SChris J Arges };
75376b188c4SChris J Arges 
754a01df925STakashi Iwai static const struct scarlett_device_info s18i8_info = {
75576b188c4SChris J Arges 	.matrix_in = 18,
75676b188c4SChris J Arges 	.matrix_out = 8,
75776b188c4SChris J Arges 	.input_len = 18,
75876b188c4SChris J Arges 	.output_len = 8,
75976b188c4SChris J Arges 
76076b188c4SChris J Arges 	.opt_master = {
76176b188c4SChris J Arges 		.start = -1,
76276b188c4SChris J Arges 		.len = 35,
76376b188c4SChris J Arges 		.offsets = {0, 8, 16, 18, 26},
76476b188c4SChris J Arges 		.names = NULL
76576b188c4SChris J Arges 	},
76676b188c4SChris J Arges 
76776b188c4SChris J Arges 	.opt_matrix = {
76876b188c4SChris J Arges 		.start = -1,
76976b188c4SChris J Arges 		.len = 27,
77076b188c4SChris J Arges 		.offsets = {0, 8, 16, 18, 26},
77176b188c4SChris J Arges 		.names = NULL
77276b188c4SChris J Arges 	},
77376b188c4SChris J Arges 
77476b188c4SChris J Arges 	.num_controls = 10,
77576b188c4SChris J Arges 	.controls = {
77676b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
77776b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" },
77876b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" },
77976b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
78076b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
78176b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
78276b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
78376b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
78476b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
78576b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
78676b188c4SChris J Arges 	},
78776b188c4SChris J Arges 
78876b188c4SChris J Arges 	.matrix_mux_init = {
78976b188c4SChris J Arges 		 8,  9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */
79076b188c4SChris J Arges 		18, 19, 20, 21, 22, 23,     /* ADAT[1..6] -> 9..14 */
79176b188c4SChris J Arges 		16, 17,                          /* SPDIF -> 15,16 */
79276b188c4SChris J Arges 		0, 1                          /* PCM[1,2] -> 17,18 */
79376b188c4SChris J Arges 	}
79476b188c4SChris J Arges };
79576b188c4SChris J Arges 
796a01df925STakashi Iwai static const struct scarlett_device_info s18i20_info = {
79776b188c4SChris J Arges 	.matrix_in = 18,
79876b188c4SChris J Arges 	.matrix_out = 8,
79976b188c4SChris J Arges 	.input_len = 18,
80076b188c4SChris J Arges 	.output_len = 20,
80176b188c4SChris J Arges 
80276b188c4SChris J Arges 	.opt_master = {
80376b188c4SChris J Arges 		.start = -1,
80476b188c4SChris J Arges 		.len = 47,
80576b188c4SChris J Arges 		.offsets = {0, 20, 28, 30, 38},
80676b188c4SChris J Arges 		.names = NULL
80776b188c4SChris J Arges 	},
80876b188c4SChris J Arges 
80976b188c4SChris J Arges 	.opt_matrix = {
81076b188c4SChris J Arges 		.start = -1,
81176b188c4SChris J Arges 		.len = 39,
81276b188c4SChris J Arges 		.offsets = {0, 20, 28, 30, 38},
81376b188c4SChris J Arges 		.names = NULL
81476b188c4SChris J Arges 	},
81576b188c4SChris J Arges 
81676b188c4SChris J Arges 	.num_controls = 10,
81776b188c4SChris J Arges 	.controls = {
81876b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
81976b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" },
82076b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" },
82176b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" },
82276b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" },
82376b188c4SChris J Arges 		{ .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
82476b188c4SChris J Arges 		{ .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" },
82576b188c4SChris J Arges 		{ .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" },
82676b188c4SChris J Arges 		{ .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" },
82776b188c4SChris J Arges 		{ .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" },
82876b188c4SChris J Arges 		/*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
82976b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
83076b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
83176b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
83276b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
83376b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/
83476b188c4SChris J Arges 	},
83576b188c4SChris J Arges 
83676b188c4SChris J Arges 	.matrix_mux_init = {
83776b188c4SChris J Arges 		20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */
83876b188c4SChris J Arges 		30, 31, 32, 33, 34, 35,     /* ADAT[1..6] -> 9..14 */
83976b188c4SChris J Arges 		28, 29,                          /* SPDIF -> 15,16 */
84076b188c4SChris J Arges 		0, 1                          /* PCM[1,2] -> 17,18 */
84176b188c4SChris J Arges 	}
84276b188c4SChris J Arges };
84376b188c4SChris J Arges 
84476b188c4SChris J Arges 
scarlett_controls_create_generic(struct usb_mixer_interface * mixer,const struct scarlett_device_info * info)84576b188c4SChris J Arges static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer,
846a01df925STakashi Iwai 	const struct scarlett_device_info *info)
84776b188c4SChris J Arges {
84876b188c4SChris J Arges 	int i, err;
84976b188c4SChris J Arges 	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
85076b188c4SChris J Arges 	const struct scarlett_mixer_control *ctl;
85176b188c4SChris J Arges 	struct usb_mixer_elem_info *elem;
85276b188c4SChris J Arges 
85376b188c4SChris J Arges 	/* create master switch and playback volume */
854b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
855b61f90eaSTakashi Iwai 			  scarlett_ctl_resume, 0x0a, 0x01, 0,
85676b188c4SChris J Arges 			  USB_MIXER_S16, 1, "Master Playback Switch", NULL,
85776b188c4SChris J Arges 			  &elem);
85876b188c4SChris J Arges 	if (err < 0)
85976b188c4SChris J Arges 		return err;
86076b188c4SChris J Arges 
861b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
862b61f90eaSTakashi Iwai 			  scarlett_ctl_resume, 0x0a, 0x02, 0,
86376b188c4SChris J Arges 			  USB_MIXER_S16, 1, "Master Playback Volume", NULL,
86476b188c4SChris J Arges 			  &elem);
86576b188c4SChris J Arges 	if (err < 0)
86676b188c4SChris J Arges 		return err;
86776b188c4SChris J Arges 
86876b188c4SChris J Arges 	/* iterate through controls in info struct and create each one */
86976b188c4SChris J Arges 	for (i = 0; i < info->num_controls; i++) {
87076b188c4SChris J Arges 		ctl = &info->controls[i];
87176b188c4SChris J Arges 
87276b188c4SChris J Arges 		switch (ctl->type) {
87376b188c4SChris J Arges 		case SCARLETT_OUTPUTS:
87476b188c4SChris J Arges 			err = add_output_ctls(mixer, ctl->num, ctl->name, info);
87576b188c4SChris J Arges 			if (err < 0)
87676b188c4SChris J Arges 				return err;
87776b188c4SChris J Arges 			break;
87876b188c4SChris J Arges 		case SCARLETT_SWITCH_IMPEDANCE:
87976b188c4SChris J Arges 			sprintf(mx, "Input %d Impedance Switch", ctl->num);
880b61f90eaSTakashi Iwai 			err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
881b61f90eaSTakashi Iwai 					  scarlett_ctl_enum_resume, 0x01,
88276b188c4SChris J Arges 					  0x09, ctl->num, USB_MIXER_S16, 1, mx,
88376b188c4SChris J Arges 					  &opt_impedance, &elem);
88476b188c4SChris J Arges 			if (err < 0)
88576b188c4SChris J Arges 				return err;
88676b188c4SChris J Arges 			break;
88776b188c4SChris J Arges 		case SCARLETT_SWITCH_PAD:
88876b188c4SChris J Arges 			sprintf(mx, "Input %d Pad Switch", ctl->num);
889b61f90eaSTakashi Iwai 			err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
890b61f90eaSTakashi Iwai 					  scarlett_ctl_enum_resume, 0x01,
89176b188c4SChris J Arges 					  0x0b, ctl->num, USB_MIXER_S16, 1, mx,
89276b188c4SChris J Arges 					  &opt_pad, &elem);
89376b188c4SChris J Arges 			if (err < 0)
89476b188c4SChris J Arges 				return err;
89576b188c4SChris J Arges 			break;
896bf2aa5caSJens Verwiebe 		case SCARLETT_SWITCH_GAIN:
897bf2aa5caSJens Verwiebe 			sprintf(mx, "Input %d Gain Switch", ctl->num);
898bf2aa5caSJens Verwiebe 			err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
899bf2aa5caSJens Verwiebe 					  scarlett_ctl_enum_resume, 0x01,
900bf2aa5caSJens Verwiebe 					  0x08, ctl->num, USB_MIXER_S16, 1, mx,
901bf2aa5caSJens Verwiebe 					  &opt_gain, &elem);
902bf2aa5caSJens Verwiebe 			if (err < 0)
903bf2aa5caSJens Verwiebe 				return err;
904bf2aa5caSJens Verwiebe 			break;
90576b188c4SChris J Arges 		}
90676b188c4SChris J Arges 	}
90776b188c4SChris J Arges 
90876b188c4SChris J Arges 	return 0;
90976b188c4SChris J Arges }
91076b188c4SChris J Arges 
91176b188c4SChris J Arges /*
91276b188c4SChris J Arges  * Create and initialize a mixer for the Focusrite(R) Scarlett
91376b188c4SChris J Arges  */
snd_scarlett_controls_create(struct usb_mixer_interface * mixer)91476b188c4SChris J Arges int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
91576b188c4SChris J Arges {
91676b188c4SChris J Arges 	int err, i, o;
91776b188c4SChris J Arges 	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
918a01df925STakashi Iwai 	const struct scarlett_device_info *info;
91976b188c4SChris J Arges 	struct usb_mixer_elem_info *elem;
92076b188c4SChris J Arges 	static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' };
92176b188c4SChris J Arges 
92276b188c4SChris J Arges 	/* only use UAC_VERSION_2 */
92376b188c4SChris J Arges 	if (!mixer->protocol)
92476b188c4SChris J Arges 		return 0;
92576b188c4SChris J Arges 
92676b188c4SChris J Arges 	switch (mixer->chip->usb_id) {
92776b188c4SChris J Arges 	case USB_ID(0x1235, 0x8012):
92876b188c4SChris J Arges 		info = &s6i6_info;
92976b188c4SChris J Arges 		break;
93076b188c4SChris J Arges 	case USB_ID(0x1235, 0x8002):
93176b188c4SChris J Arges 		info = &s8i6_info;
93276b188c4SChris J Arges 		break;
93376b188c4SChris J Arges 	case USB_ID(0x1235, 0x8004):
93476b188c4SChris J Arges 		info = &s18i6_info;
93576b188c4SChris J Arges 		break;
93676b188c4SChris J Arges 	case USB_ID(0x1235, 0x8014):
93776b188c4SChris J Arges 		info = &s18i8_info;
93876b188c4SChris J Arges 		break;
93976b188c4SChris J Arges 	case USB_ID(0x1235, 0x800c):
94076b188c4SChris J Arges 		info = &s18i20_info;
94176b188c4SChris J Arges 		break;
94276b188c4SChris J Arges 	default: /* device not (yet) supported */
94376b188c4SChris J Arges 		return -EINVAL;
94476b188c4SChris J Arges 	}
94576b188c4SChris J Arges 
94676b188c4SChris J Arges 	/* generic function to create controls */
94776b188c4SChris J Arges 	err = scarlett_controls_create_generic(mixer, info);
94876b188c4SChris J Arges 	if (err < 0)
94976b188c4SChris J Arges 		return err;
95076b188c4SChris J Arges 
95176b188c4SChris J Arges 	/* setup matrix controls */
95276b188c4SChris J Arges 	for (i = 0; i < info->matrix_in; i++) {
95376b188c4SChris J Arges 		snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route",
95476b188c4SChris J Arges 			 i+1);
955b61f90eaSTakashi Iwai 		err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
956b61f90eaSTakashi Iwai 				  scarlett_ctl_enum_resume, 0x32,
95776b188c4SChris J Arges 				  0x06, i, USB_MIXER_S16, 1, mx,
95876b188c4SChris J Arges 				  &info->opt_matrix, &elem);
95976b188c4SChris J Arges 		if (err < 0)
96076b188c4SChris J Arges 			return err;
96176b188c4SChris J Arges 
96276b188c4SChris J Arges 		for (o = 0; o < info->matrix_out; o++) {
96376b188c4SChris J Arges 			sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1,
96476b188c4SChris J Arges 				o+'A');
965b61f90eaSTakashi Iwai 			err = add_new_ctl(mixer, &usb_scarlett_ctl,
966b61f90eaSTakashi Iwai 					  scarlett_ctl_resume, 0x3c, 0x00,
96776b188c4SChris J Arges 					  (i << 3) + (o & 0x07), USB_MIXER_S16,
96876b188c4SChris J Arges 					  1, mx, NULL, &elem);
96976b188c4SChris J Arges 			if (err < 0)
97076b188c4SChris J Arges 				return err;
97176b188c4SChris J Arges 
97276b188c4SChris J Arges 		}
97376b188c4SChris J Arges 	}
97476b188c4SChris J Arges 
97576b188c4SChris J Arges 	for (i = 0; i < info->input_len; i++) {
97676b188c4SChris J Arges 		snprintf(mx, sizeof(mx), "Input Source %02d Capture Route",
97776b188c4SChris J Arges 			 i+1);
978b61f90eaSTakashi Iwai 		err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
979b61f90eaSTakashi Iwai 				  scarlett_ctl_enum_resume, 0x34,
98076b188c4SChris J Arges 				  0x00, i, USB_MIXER_S16, 1, mx,
98176b188c4SChris J Arges 				  &info->opt_master, &elem);
98276b188c4SChris J Arges 		if (err < 0)
98376b188c4SChris J Arges 			return err;
98476b188c4SChris J Arges 	}
98576b188c4SChris J Arges 
98676b188c4SChris J Arges 	/* val_len == 1 needed here */
987b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
988b61f90eaSTakashi Iwai 			  scarlett_ctl_enum_resume, 0x28, 0x01, 0,
98976b188c4SChris J Arges 			  USB_MIXER_U8, 1, "Sample Clock Source",
99076b188c4SChris J Arges 			  &opt_clock, &elem);
99176b188c4SChris J Arges 	if (err < 0)
99276b188c4SChris J Arges 		return err;
99376b188c4SChris J Arges 
99476b188c4SChris J Arges 	/* val_len == 1 and UAC2_CS_MEM */
995b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2,
99676b188c4SChris J Arges 			  USB_MIXER_U8, 1, "Sample Clock Sync Status",
99776b188c4SChris J Arges 			  &opt_sync, &elem);
99876b188c4SChris J Arges 	if (err < 0)
99976b188c4SChris J Arges 		return err;
100076b188c4SChris J Arges 
100176b188c4SChris J Arges 	/* initialize sampling rate to 48000 */
100276b188c4SChris J Arges 	err = snd_usb_ctl_msg(mixer->chip->dev,
100376b188c4SChris J Arges 		usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
100476b188c4SChris J Arges 		USB_RECIP_INTERFACE | USB_TYPE_CLASS |
100576b188c4SChris J Arges 		USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
100676b188c4SChris J Arges 		(0x29 << 8), sample_rate_buffer, 4);
100776b188c4SChris J Arges 	if (err < 0)
100876b188c4SChris J Arges 		return err;
100976b188c4SChris J Arges 
101076b188c4SChris J Arges 	return err;
101176b188c4SChris J Arges }
1012