xref: /openbmc/linux/sound/usb/mixer_scarlett.c (revision c942fddf)
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
2476b188c4SChris J Arges  * right now it's a major headache to work arount 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,
14576b188c4SChris J Arges };
14676b188c4SChris J Arges 
14776b188c4SChris J Arges enum {
14876b188c4SChris J Arges 	SCARLETT_OFFSET_PCM = 0,
14976b188c4SChris J Arges 	SCARLETT_OFFSET_ANALOG = 1,
15076b188c4SChris J Arges 	SCARLETT_OFFSET_SPDIF = 2,
15176b188c4SChris J Arges 	SCARLETT_OFFSET_ADAT = 3,
15276b188c4SChris J Arges 	SCARLETT_OFFSET_MIX = 4,
15376b188c4SChris J Arges };
15476b188c4SChris J Arges 
15576b188c4SChris J Arges struct scarlett_mixer_elem_enum_info {
15676b188c4SChris J Arges 	int start;
15776b188c4SChris J Arges 	int len;
15876b188c4SChris J Arges 	int offsets[SND_SCARLETT_OFFSETS_MAX];
15976b188c4SChris J Arges 	char const * const *names;
16076b188c4SChris J Arges };
16176b188c4SChris J Arges 
16276b188c4SChris J Arges struct scarlett_mixer_control {
16376b188c4SChris J Arges 	unsigned char num;
16476b188c4SChris J Arges 	unsigned char type;
16576b188c4SChris J Arges 	const char *name;
16676b188c4SChris J Arges };
16776b188c4SChris J Arges 
16876b188c4SChris J Arges struct scarlett_device_info {
16976b188c4SChris J Arges 	int matrix_in;
17076b188c4SChris J Arges 	int matrix_out;
17176b188c4SChris J Arges 	int input_len;
17276b188c4SChris J Arges 	int output_len;
17376b188c4SChris J Arges 
17476b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info opt_master;
17576b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info opt_matrix;
17676b188c4SChris J Arges 
17776b188c4SChris J Arges 	/* initial values for matrix mux */
17876b188c4SChris J Arges 	int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX];
17976b188c4SChris J Arges 
18076b188c4SChris J Arges 	int num_controls;	/* number of items in controls */
18176b188c4SChris J Arges 	const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX];
18276b188c4SChris J Arges };
18376b188c4SChris J Arges 
18476b188c4SChris J Arges /********************** Enum Strings *************************/
18576b188c4SChris J Arges 
18676b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_pad = {
18776b188c4SChris J Arges 	.start = 0,
18876b188c4SChris J Arges 	.len = 2,
18976b188c4SChris J Arges 	.offsets = {},
19076b188c4SChris J Arges 	.names = (char const * const []){
19176b188c4SChris J Arges 		"0dB", "-10dB"
19276b188c4SChris J Arges 	}
19376b188c4SChris J Arges };
19476b188c4SChris J Arges 
19576b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_impedance = {
19676b188c4SChris J Arges 	.start = 0,
19776b188c4SChris J Arges 	.len = 2,
19876b188c4SChris J Arges 	.offsets = {},
19976b188c4SChris J Arges 	.names = (char const * const []){
20076b188c4SChris J Arges 		"Line", "Hi-Z"
20176b188c4SChris J Arges 	}
20276b188c4SChris J Arges };
20376b188c4SChris J Arges 
20476b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_clock = {
20576b188c4SChris J Arges 	.start = 1,
20676b188c4SChris J Arges 	.len = 3,
20776b188c4SChris J Arges 	.offsets = {},
20876b188c4SChris J Arges 	.names = (char const * const []){
20976b188c4SChris J Arges 		"Internal", "SPDIF", "ADAT"
21076b188c4SChris J Arges 	}
21176b188c4SChris J Arges };
21276b188c4SChris J Arges 
21376b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_sync = {
21476b188c4SChris J Arges 	.start = 0,
21576b188c4SChris J Arges 	.len = 2,
21676b188c4SChris J Arges 	.offsets = {},
21776b188c4SChris J Arges 	.names = (char const * const []){
21876b188c4SChris J Arges 		"No Lock", "Locked"
21976b188c4SChris J Arges 	}
22076b188c4SChris J Arges };
22176b188c4SChris J Arges 
22276b188c4SChris J Arges static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl,
22376b188c4SChris J Arges 		struct snd_ctl_elem_info *uinfo)
22476b188c4SChris J Arges {
22576b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
22676b188c4SChris J Arges 
22776b188c4SChris J Arges 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
22876b188c4SChris J Arges 	uinfo->count = elem->channels;
22976b188c4SChris J Arges 	uinfo->value.integer.min = 0;
23076b188c4SChris J Arges 	uinfo->value.integer.max = 1;
23176b188c4SChris J Arges 	return 0;
23276b188c4SChris J Arges }
23376b188c4SChris J Arges 
23476b188c4SChris J Arges static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl,
23576b188c4SChris J Arges 		struct snd_ctl_elem_value *ucontrol)
23676b188c4SChris J Arges {
23776b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
23876b188c4SChris J Arges 	int i, err, val;
23976b188c4SChris J Arges 
24076b188c4SChris J Arges 	for (i = 0; i < elem->channels; i++) {
24176b188c4SChris J Arges 		err = snd_usb_get_cur_mix_value(elem, i, i, &val);
24276b188c4SChris J Arges 		if (err < 0)
24376b188c4SChris J Arges 			return err;
24476b188c4SChris J Arges 
24576b188c4SChris J Arges 		val = !val; /* invert mute logic for mixer */
24676b188c4SChris J Arges 		ucontrol->value.integer.value[i] = val;
24776b188c4SChris J Arges 	}
24876b188c4SChris J Arges 
24976b188c4SChris J Arges 	return 0;
25076b188c4SChris J Arges }
25176b188c4SChris J Arges 
25276b188c4SChris J Arges static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl,
25376b188c4SChris J Arges 		struct snd_ctl_elem_value *ucontrol)
25476b188c4SChris J Arges {
25576b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
25676b188c4SChris J Arges 	int i, changed = 0;
25776b188c4SChris J Arges 	int err, oval, val;
25876b188c4SChris J Arges 
25976b188c4SChris J Arges 	for (i = 0; i < elem->channels; i++) {
26076b188c4SChris J Arges 		err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
26176b188c4SChris J Arges 		if (err < 0)
26276b188c4SChris J Arges 			return err;
26376b188c4SChris J Arges 
26476b188c4SChris J Arges 		val = ucontrol->value.integer.value[i];
26576b188c4SChris J Arges 		val = !val;
26676b188c4SChris J Arges 		if (oval != val) {
26776b188c4SChris J Arges 			err = snd_usb_set_cur_mix_value(elem, i, i, val);
26876b188c4SChris J Arges 			if (err < 0)
26976b188c4SChris J Arges 				return err;
27076b188c4SChris J Arges 
27176b188c4SChris J Arges 			changed = 1;
27276b188c4SChris J Arges 		}
27376b188c4SChris J Arges 	}
27476b188c4SChris J Arges 
27576b188c4SChris J Arges 	return changed;
27676b188c4SChris J Arges }
27776b188c4SChris J Arges 
278b61f90eaSTakashi Iwai static int scarlett_ctl_resume(struct usb_mixer_elem_list *list)
279b61f90eaSTakashi Iwai {
2808c558076STakashi Iwai 	struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list);
281b61f90eaSTakashi Iwai 	int i;
282b61f90eaSTakashi Iwai 
283b61f90eaSTakashi Iwai 	for (i = 0; i < elem->channels; i++)
284b61f90eaSTakashi Iwai 		if (elem->cached & (1 << i))
285b61f90eaSTakashi Iwai 			snd_usb_set_cur_mix_value(elem, i, i,
286b61f90eaSTakashi Iwai 						  elem->cache_val[i]);
287b61f90eaSTakashi Iwai 	return 0;
288b61f90eaSTakashi Iwai }
289b61f90eaSTakashi Iwai 
29076b188c4SChris J Arges static int scarlett_ctl_info(struct snd_kcontrol *kctl,
29176b188c4SChris J Arges 			     struct snd_ctl_elem_info *uinfo)
29276b188c4SChris J Arges {
29376b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
29476b188c4SChris J Arges 
29576b188c4SChris J Arges 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
29676b188c4SChris J Arges 	uinfo->count = elem->channels;
29776b188c4SChris J Arges 	uinfo->value.integer.min = 0;
29876b188c4SChris J Arges 	uinfo->value.integer.max = (int)kctl->private_value +
29976b188c4SChris J Arges 		SND_SCARLETT_LEVEL_BIAS;
30076b188c4SChris J Arges 	uinfo->value.integer.step = 1;
30176b188c4SChris J Arges 	return 0;
30276b188c4SChris J Arges }
30376b188c4SChris J Arges 
30476b188c4SChris J Arges static int scarlett_ctl_get(struct snd_kcontrol *kctl,
30576b188c4SChris J Arges 			    struct snd_ctl_elem_value *ucontrol)
30676b188c4SChris J Arges {
30776b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
30876b188c4SChris J Arges 	int i, err, val;
30976b188c4SChris J Arges 
31076b188c4SChris J Arges 	for (i = 0; i < elem->channels; i++) {
31176b188c4SChris J Arges 		err = snd_usb_get_cur_mix_value(elem, i, i, &val);
31276b188c4SChris J Arges 		if (err < 0)
31376b188c4SChris J Arges 			return err;
31476b188c4SChris J Arges 
31576b188c4SChris J Arges 		val = clamp(val / 256, -128, (int)kctl->private_value) +
31676b188c4SChris J Arges 				    SND_SCARLETT_LEVEL_BIAS;
31776b188c4SChris J Arges 		ucontrol->value.integer.value[i] = val;
31876b188c4SChris J Arges 	}
31976b188c4SChris J Arges 
32076b188c4SChris J Arges 	return 0;
32176b188c4SChris J Arges }
32276b188c4SChris J Arges 
32376b188c4SChris J Arges static int scarlett_ctl_put(struct snd_kcontrol *kctl,
32476b188c4SChris J Arges 			    struct snd_ctl_elem_value *ucontrol)
32576b188c4SChris J Arges {
32676b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
32776b188c4SChris J Arges 	int i, changed = 0;
32876b188c4SChris J Arges 	int err, oval, val;
32976b188c4SChris J Arges 
33076b188c4SChris J Arges 	for (i = 0; i < elem->channels; i++) {
33176b188c4SChris J Arges 		err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
33276b188c4SChris J Arges 		if (err < 0)
33376b188c4SChris J Arges 			return err;
33476b188c4SChris J Arges 
33576b188c4SChris J Arges 		val = ucontrol->value.integer.value[i] -
33676b188c4SChris J Arges 			SND_SCARLETT_LEVEL_BIAS;
33776b188c4SChris J Arges 		val = val * 256;
33876b188c4SChris J Arges 		if (oval != val) {
33976b188c4SChris J Arges 			err = snd_usb_set_cur_mix_value(elem, i, i, val);
34076b188c4SChris J Arges 			if (err < 0)
34176b188c4SChris J Arges 				return err;
34276b188c4SChris J Arges 
34376b188c4SChris J Arges 			changed = 1;
34476b188c4SChris J Arges 		}
34576b188c4SChris J Arges 	}
34676b188c4SChris J Arges 
34776b188c4SChris J Arges 	return changed;
34876b188c4SChris J Arges }
34976b188c4SChris J Arges 
35076b188c4SChris J Arges static void scarlett_generate_name(int i, char *dst, int offsets[])
35176b188c4SChris J Arges {
35276b188c4SChris J Arges 	if (i > offsets[SCARLETT_OFFSET_MIX])
35376b188c4SChris J Arges 		sprintf(dst, "Mix %c",
35476b188c4SChris J Arges 			'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1));
35576b188c4SChris J Arges 	else if (i > offsets[SCARLETT_OFFSET_ADAT])
35676b188c4SChris J Arges 		sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]);
35776b188c4SChris J Arges 	else if (i > offsets[SCARLETT_OFFSET_SPDIF])
35876b188c4SChris J Arges 		sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]);
35976b188c4SChris J Arges 	else if (i > offsets[SCARLETT_OFFSET_ANALOG])
36076b188c4SChris J Arges 		sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]);
36176b188c4SChris J Arges 	else if (i > offsets[SCARLETT_OFFSET_PCM])
36276b188c4SChris J Arges 		sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]);
36376b188c4SChris J Arges 	else
36476b188c4SChris J Arges 		sprintf(dst, "Off");
36576b188c4SChris J Arges }
36676b188c4SChris J Arges 
36776b188c4SChris J Arges static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl,
36876b188c4SChris J Arges 					  struct snd_ctl_elem_info *uinfo)
36976b188c4SChris J Arges {
37076b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
37176b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
37276b188c4SChris J Arges 	unsigned int items = opt->len;
37376b188c4SChris J Arges 
37476b188c4SChris J Arges 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
37576b188c4SChris J Arges 	uinfo->count = elem->channels;
37676b188c4SChris J Arges 	uinfo->value.enumerated.items = items;
37776b188c4SChris J Arges 
37876b188c4SChris J Arges 	if (uinfo->value.enumerated.item >= items)
37976b188c4SChris J Arges 		uinfo->value.enumerated.item = items - 1;
38076b188c4SChris J Arges 
38176b188c4SChris J Arges 	/* generate name dynamically based on item number and offset info */
38276b188c4SChris J Arges 	scarlett_generate_name(uinfo->value.enumerated.item,
38376b188c4SChris J Arges 			       uinfo->value.enumerated.name,
38476b188c4SChris J Arges 			       opt->offsets);
38576b188c4SChris J Arges 
38676b188c4SChris J Arges 	return 0;
38776b188c4SChris J Arges }
38876b188c4SChris J Arges 
38976b188c4SChris J Arges static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl,
39076b188c4SChris J Arges 				  struct snd_ctl_elem_info *uinfo)
39176b188c4SChris J Arges {
39276b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
39376b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
39476b188c4SChris J Arges 
39576b188c4SChris J Arges 	return snd_ctl_enum_info(uinfo, elem->channels, opt->len,
39676b188c4SChris J Arges 				 (const char * const *)opt->names);
39776b188c4SChris J Arges }
39876b188c4SChris J Arges 
39976b188c4SChris J Arges static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl,
40076b188c4SChris J Arges 				 struct snd_ctl_elem_value *ucontrol)
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 	int err, val;
40576b188c4SChris J Arges 
40676b188c4SChris J Arges 	err = snd_usb_get_cur_mix_value(elem, 0, 0, &val);
40776b188c4SChris J Arges 	if (err < 0)
40876b188c4SChris J Arges 		return err;
40976b188c4SChris J Arges 
41076b188c4SChris J Arges 	val = clamp(val - opt->start, 0, opt->len-1);
41176b188c4SChris J Arges 
41276b188c4SChris J Arges 	ucontrol->value.enumerated.item[0] = val;
41376b188c4SChris J Arges 
41476b188c4SChris J Arges 	return 0;
41576b188c4SChris J Arges }
41676b188c4SChris J Arges 
41776b188c4SChris J Arges static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl,
41876b188c4SChris J Arges 				 struct snd_ctl_elem_value *ucontrol)
41976b188c4SChris J Arges {
42076b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
42176b188c4SChris J Arges 	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
42276b188c4SChris J Arges 	int err, oval, val;
42376b188c4SChris J Arges 
42476b188c4SChris J Arges 	err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval);
42576b188c4SChris J Arges 	if (err < 0)
42676b188c4SChris J Arges 		return err;
42776b188c4SChris J Arges 
42876b188c4SChris J Arges 	val = ucontrol->value.integer.value[0];
42976b188c4SChris J Arges 	val = val + opt->start;
43076b188c4SChris J Arges 	if (val != oval) {
43176b188c4SChris J Arges 		snd_usb_set_cur_mix_value(elem, 0, 0, val);
43276b188c4SChris J Arges 		return 1;
43376b188c4SChris J Arges 	}
43476b188c4SChris J Arges 	return 0;
43576b188c4SChris J Arges }
43676b188c4SChris J Arges 
437b61f90eaSTakashi Iwai static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list)
438b61f90eaSTakashi Iwai {
4398c558076STakashi Iwai 	struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list);
440b61f90eaSTakashi Iwai 
441b61f90eaSTakashi Iwai 	if (elem->cached)
442b61f90eaSTakashi Iwai 		snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val);
443b61f90eaSTakashi Iwai 	return 0;
444b61f90eaSTakashi Iwai }
445b61f90eaSTakashi Iwai 
44676b188c4SChris J Arges static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
44776b188c4SChris J Arges 				  struct snd_ctl_elem_value *ucontrol)
44876b188c4SChris J Arges {
44976b188c4SChris J Arges 	struct usb_mixer_elem_info *elem = kctl->private_data;
4503360b84bSTakashi Iwai 	struct snd_usb_audio *chip = elem->head.mixer->chip;
45176b188c4SChris J Arges 	unsigned char buf[2 * MAX_CHANNELS] = {0, };
45276b188c4SChris J Arges 	int wValue = (elem->control << 8) | elem->idx_off;
4533360b84bSTakashi Iwai 	int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
45476b188c4SChris J Arges 	int err;
45576b188c4SChris J Arges 
45676b188c4SChris J Arges 	err = snd_usb_ctl_msg(chip->dev,
45776b188c4SChris J Arges 				usb_rcvctrlpipe(chip->dev, 0),
45876b188c4SChris J Arges 				UAC2_CS_MEM,
45976b188c4SChris J Arges 				USB_RECIP_INTERFACE | USB_TYPE_CLASS |
46076b188c4SChris J Arges 				USB_DIR_IN, wValue, idx, buf, elem->channels);
46176b188c4SChris J Arges 	if (err < 0)
46276b188c4SChris J Arges 		return err;
46376b188c4SChris J Arges 
46476b188c4SChris J Arges 	ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1);
46576b188c4SChris J Arges 	return 0;
46676b188c4SChris J Arges }
46776b188c4SChris J Arges 
46804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_switch = {
46976b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
47076b188c4SChris J Arges 	.name = "",
47176b188c4SChris J Arges 	.info = scarlett_ctl_switch_info,
47276b188c4SChris J Arges 	.get =  scarlett_ctl_switch_get,
47376b188c4SChris J Arges 	.put =  scarlett_ctl_switch_put,
47476b188c4SChris J Arges };
47576b188c4SChris J Arges 
47676b188c4SChris J Arges static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0);
47776b188c4SChris J Arges 
47804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl = {
47976b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
48076b188c4SChris J Arges 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
48176b188c4SChris J Arges 		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
48276b188c4SChris J Arges 	.name = "",
48376b188c4SChris J Arges 	.info = scarlett_ctl_info,
48476b188c4SChris J Arges 	.get =  scarlett_ctl_get,
48576b188c4SChris J Arges 	.put =  scarlett_ctl_put,
48676b188c4SChris J Arges 	.private_value = 6,  /* max value */
48776b188c4SChris J Arges 	.tlv = { .p = db_scale_scarlett_gain }
48876b188c4SChris J Arges };
48976b188c4SChris J Arges 
49004bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_master = {
49176b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
49276b188c4SChris J Arges 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
49376b188c4SChris J Arges 		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
49476b188c4SChris J Arges 	.name = "",
49576b188c4SChris J Arges 	.info = scarlett_ctl_info,
49676b188c4SChris J Arges 	.get =  scarlett_ctl_get,
49776b188c4SChris J Arges 	.put =  scarlett_ctl_put,
49876b188c4SChris J Arges 	.private_value = 6,  /* max value */
49976b188c4SChris J Arges 	.tlv = { .p = db_scale_scarlett_gain }
50076b188c4SChris J Arges };
50176b188c4SChris J Arges 
50204bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_enum = {
50376b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
50476b188c4SChris J Arges 	.name = "",
50576b188c4SChris J Arges 	.info = scarlett_ctl_enum_info,
50676b188c4SChris J Arges 	.get =  scarlett_ctl_enum_get,
50776b188c4SChris J Arges 	.put =  scarlett_ctl_enum_put,
50876b188c4SChris J Arges };
50976b188c4SChris J Arges 
51004bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
51176b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
51276b188c4SChris J Arges 	.name = "",
51376b188c4SChris J Arges 	.info = scarlett_ctl_enum_dynamic_info,
51476b188c4SChris J Arges 	.get =  scarlett_ctl_enum_get,
51576b188c4SChris J Arges 	.put =  scarlett_ctl_enum_put,
51676b188c4SChris J Arges };
51776b188c4SChris J Arges 
51804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_sync = {
51976b188c4SChris J Arges 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
52076b188c4SChris J Arges 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
52176b188c4SChris J Arges 	.name = "",
52276b188c4SChris J Arges 	.info = scarlett_ctl_enum_info,
52376b188c4SChris J Arges 	.get =  scarlett_ctl_meter_get,
52476b188c4SChris J Arges };
52576b188c4SChris J Arges 
52676b188c4SChris J Arges static int add_new_ctl(struct usb_mixer_interface *mixer,
52776b188c4SChris J Arges 		       const struct snd_kcontrol_new *ncontrol,
528b61f90eaSTakashi Iwai 		       usb_mixer_elem_resume_func_t resume,
52976b188c4SChris J Arges 		       int index, int offset, int num,
53076b188c4SChris J Arges 		       int val_type, int channels, const char *name,
53176b188c4SChris J Arges 		       const struct scarlett_mixer_elem_enum_info *opt,
53276b188c4SChris J Arges 		       struct usb_mixer_elem_info **elem_ret
53376b188c4SChris J Arges )
53476b188c4SChris J Arges {
53576b188c4SChris J Arges 	struct snd_kcontrol *kctl;
53676b188c4SChris J Arges 	struct usb_mixer_elem_info *elem;
53776b188c4SChris J Arges 	int err;
53876b188c4SChris J Arges 
53976b188c4SChris J Arges 	elem = kzalloc(sizeof(*elem), GFP_KERNEL);
54076b188c4SChris J Arges 	if (!elem)
54176b188c4SChris J Arges 		return -ENOMEM;
54276b188c4SChris J Arges 
5433360b84bSTakashi Iwai 	elem->head.mixer = mixer;
544b61f90eaSTakashi Iwai 	elem->head.resume = resume;
54576b188c4SChris J Arges 	elem->control = offset;
54676b188c4SChris J Arges 	elem->idx_off = num;
5473360b84bSTakashi Iwai 	elem->head.id = index;
54876b188c4SChris J Arges 	elem->val_type = val_type;
54976b188c4SChris J Arges 
55076b188c4SChris J Arges 	elem->channels = channels;
55176b188c4SChris J Arges 
55276b188c4SChris J Arges 	/* add scarlett_mixer_elem_enum_info struct */
55376b188c4SChris J Arges 	elem->private_data = (void *)opt;
55476b188c4SChris J Arges 
55576b188c4SChris J Arges 	kctl = snd_ctl_new1(ncontrol, elem);
55676b188c4SChris J Arges 	if (!kctl) {
55776b188c4SChris J Arges 		kfree(elem);
55876b188c4SChris J Arges 		return -ENOMEM;
55976b188c4SChris J Arges 	}
56076b188c4SChris J Arges 	kctl->private_free = snd_usb_mixer_elem_free;
56176b188c4SChris J Arges 
56276b188c4SChris J Arges 	strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
56376b188c4SChris J Arges 
564b61f90eaSTakashi Iwai 	err = snd_usb_mixer_add_control(&elem->head, kctl);
56576b188c4SChris J Arges 	if (err < 0)
56676b188c4SChris J Arges 		return err;
56776b188c4SChris J Arges 
56876b188c4SChris J Arges 	if (elem_ret)
56976b188c4SChris J Arges 		*elem_ret = elem;
57076b188c4SChris J Arges 
57176b188c4SChris J Arges 	return 0;
57276b188c4SChris J Arges }
57376b188c4SChris J Arges 
57476b188c4SChris J Arges static int add_output_ctls(struct usb_mixer_interface *mixer,
57576b188c4SChris J Arges 			   int index, const char *name,
57676b188c4SChris J Arges 			   const struct scarlett_device_info *info)
57776b188c4SChris J Arges {
57876b188c4SChris J Arges 	int err;
57976b188c4SChris J Arges 	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
58076b188c4SChris J Arges 	struct usb_mixer_elem_info *elem;
58176b188c4SChris J Arges 
58276b188c4SChris J Arges 	/* Add mute switch */
58376b188c4SChris J Arges 	snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch",
58476b188c4SChris J Arges 		index + 1, name);
585b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
586b61f90eaSTakashi Iwai 			  scarlett_ctl_resume, 0x0a, 0x01,
58776b188c4SChris J Arges 			  2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
58876b188c4SChris J Arges 	if (err < 0)
58976b188c4SChris J Arges 		return err;
59076b188c4SChris J Arges 
59176b188c4SChris J Arges 	/* Add volume control and initialize to 0 */
59276b188c4SChris J Arges 	snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume",
59376b188c4SChris J Arges 		index + 1, name);
594b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
595b61f90eaSTakashi Iwai 			  scarlett_ctl_resume, 0x0a, 0x02,
59676b188c4SChris J Arges 			  2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
59776b188c4SChris J Arges 	if (err < 0)
59876b188c4SChris J Arges 		return err;
59976b188c4SChris J Arges 
60076b188c4SChris J Arges 	/* Add L channel source playback enumeration */
60176b188c4SChris J Arges 	snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum",
60276b188c4SChris J Arges 		index + 1, name);
603b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
604b61f90eaSTakashi Iwai 			  scarlett_ctl_enum_resume, 0x33, 0x00,
60576b188c4SChris J Arges 			  2*index, USB_MIXER_S16, 1, mx, &info->opt_master,
60676b188c4SChris J Arges 			  &elem);
60776b188c4SChris J Arges 	if (err < 0)
60876b188c4SChris J Arges 		return err;
60976b188c4SChris J Arges 
61076b188c4SChris J Arges 	/* Add R channel source playback enumeration */
61176b188c4SChris J Arges 	snprintf(mx, sizeof(mx), "Master %dR (%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+1, 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 	return 0;
62176b188c4SChris J Arges }
62276b188c4SChris J Arges 
62376b188c4SChris J Arges /********************** device-specific config *************************/
62476b188c4SChris J Arges 
62576b188c4SChris J Arges /*  untested...  */
62676b188c4SChris J Arges static struct scarlett_device_info s6i6_info = {
62776b188c4SChris J Arges 	.matrix_in = 18,
62876b188c4SChris J Arges 	.matrix_out = 8,
62976b188c4SChris J Arges 	.input_len = 6,
63076b188c4SChris J Arges 	.output_len = 6,
63176b188c4SChris J Arges 
63276b188c4SChris J Arges 	.opt_master = {
63376b188c4SChris J Arges 		.start = -1,
63476b188c4SChris J Arges 		.len = 27,
63576b188c4SChris J Arges 		.offsets = {0, 12, 16, 18, 18},
63676b188c4SChris J Arges 		.names = NULL
63776b188c4SChris J Arges 	},
63876b188c4SChris J Arges 
63976b188c4SChris J Arges 	.opt_matrix = {
64076b188c4SChris J Arges 		.start = -1,
64176b188c4SChris J Arges 		.len = 19,
64276b188c4SChris J Arges 		.offsets = {0, 12, 16, 18, 18},
64376b188c4SChris J Arges 		.names = NULL
64476b188c4SChris J Arges 	},
64576b188c4SChris J Arges 
646c99b9e85SChris J Arges 	.num_controls = 9,
64776b188c4SChris J Arges 	.controls = {
64876b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
64976b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
65076b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
65176b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
65276b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
65376b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
65476b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
65576b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
65676b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
65776b188c4SChris J Arges 	},
65876b188c4SChris J Arges 
65976b188c4SChris J Arges 	.matrix_mux_init = {
66076b188c4SChris J Arges 		12, 13, 14, 15,                 /* Analog -> 1..4 */
66176b188c4SChris J Arges 		16, 17,                          /* SPDIF -> 5,6 */
66276b188c4SChris J Arges 		0, 1, 2, 3, 4, 5, 6, 7,     /* PCM[1..12] -> 7..18 */
66376b188c4SChris J Arges 		8, 9, 10, 11
66476b188c4SChris J Arges 	}
66576b188c4SChris J Arges };
66676b188c4SChris J Arges 
66776b188c4SChris J Arges /*  untested...  */
66876b188c4SChris J Arges static struct scarlett_device_info s8i6_info = {
66976b188c4SChris J Arges 	.matrix_in = 18,
67076b188c4SChris J Arges 	.matrix_out = 6,
67176b188c4SChris J Arges 	.input_len = 8,
67276b188c4SChris J Arges 	.output_len = 6,
67376b188c4SChris J Arges 
67476b188c4SChris J Arges 	.opt_master = {
67576b188c4SChris J Arges 		.start = -1,
67676b188c4SChris J Arges 		.len = 25,
67776b188c4SChris J Arges 		.offsets = {0, 12, 16, 18, 18},
67876b188c4SChris J Arges 		.names = NULL
67976b188c4SChris J Arges 	},
68076b188c4SChris J Arges 
68176b188c4SChris J Arges 	.opt_matrix = {
68276b188c4SChris J Arges 		.start = -1,
68376b188c4SChris J Arges 		.len = 19,
68476b188c4SChris J Arges 		.offsets = {0, 12, 16, 18, 18},
68576b188c4SChris J Arges 		.names = NULL
68676b188c4SChris J Arges 	},
68776b188c4SChris J Arges 
68876b188c4SChris J Arges 	.num_controls = 7,
68976b188c4SChris J Arges 	.controls = {
69076b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
69176b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
69276b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
69376b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
69476b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
69576b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
69676b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
69776b188c4SChris J Arges 	},
69876b188c4SChris J Arges 
69976b188c4SChris J Arges 	.matrix_mux_init = {
70076b188c4SChris J Arges 		12, 13, 14, 15,                 /* Analog -> 1..4 */
70176b188c4SChris J Arges 		16, 17,                          /* SPDIF -> 5,6 */
70276b188c4SChris J Arges 		0, 1, 2, 3, 4, 5, 6, 7,     /* PCM[1..12] -> 7..18 */
70376b188c4SChris J Arges 		8, 9, 10, 11
70476b188c4SChris J Arges 	}
70576b188c4SChris J Arges };
70676b188c4SChris J Arges 
70776b188c4SChris J Arges static struct scarlett_device_info s18i6_info = {
70876b188c4SChris J Arges 	.matrix_in = 18,
70976b188c4SChris J Arges 	.matrix_out = 6,
71076b188c4SChris J Arges 	.input_len = 18,
71176b188c4SChris J Arges 	.output_len = 6,
71276b188c4SChris J Arges 
71376b188c4SChris J Arges 	.opt_master = {
71476b188c4SChris J Arges 		.start = -1,
71576b188c4SChris J Arges 		.len = 31,
71676b188c4SChris J Arges 		.offsets = {0, 6, 14, 16, 24},
71776b188c4SChris J Arges 		.names = NULL,
71876b188c4SChris J Arges 	},
71976b188c4SChris J Arges 
72076b188c4SChris J Arges 	.opt_matrix = {
72176b188c4SChris J Arges 		.start = -1,
72276b188c4SChris J Arges 		.len = 25,
72376b188c4SChris J Arges 		.offsets = {0, 6, 14, 16, 24},
72476b188c4SChris J Arges 		.names = NULL,
72576b188c4SChris J Arges 	},
72676b188c4SChris J Arges 
72776b188c4SChris J Arges 	.num_controls = 5,
72876b188c4SChris J Arges 	.controls = {
72976b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
73076b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
73176b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
73276b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
73376b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
73476b188c4SChris J Arges 	},
73576b188c4SChris J Arges 
73676b188c4SChris J Arges 	.matrix_mux_init = {
73776b188c4SChris J Arges 		 6,  7,  8,  9, 10, 11, 12, 13, /* Analog -> 1..8 */
73876b188c4SChris J Arges 		16, 17, 18, 19, 20, 21,     /* ADAT[1..6] -> 9..14 */
73976b188c4SChris J Arges 		14, 15,                          /* SPDIF -> 15,16 */
74076b188c4SChris J Arges 		0, 1                          /* PCM[1,2] -> 17,18 */
74176b188c4SChris J Arges 	}
74276b188c4SChris J Arges };
74376b188c4SChris J Arges 
74476b188c4SChris J Arges static struct scarlett_device_info s18i8_info = {
74576b188c4SChris J Arges 	.matrix_in = 18,
74676b188c4SChris J Arges 	.matrix_out = 8,
74776b188c4SChris J Arges 	.input_len = 18,
74876b188c4SChris J Arges 	.output_len = 8,
74976b188c4SChris J Arges 
75076b188c4SChris J Arges 	.opt_master = {
75176b188c4SChris J Arges 		.start = -1,
75276b188c4SChris J Arges 		.len = 35,
75376b188c4SChris J Arges 		.offsets = {0, 8, 16, 18, 26},
75476b188c4SChris J Arges 		.names = NULL
75576b188c4SChris J Arges 	},
75676b188c4SChris J Arges 
75776b188c4SChris J Arges 	.opt_matrix = {
75876b188c4SChris J Arges 		.start = -1,
75976b188c4SChris J Arges 		.len = 27,
76076b188c4SChris J Arges 		.offsets = {0, 8, 16, 18, 26},
76176b188c4SChris J Arges 		.names = NULL
76276b188c4SChris J Arges 	},
76376b188c4SChris J Arges 
76476b188c4SChris J Arges 	.num_controls = 10,
76576b188c4SChris J Arges 	.controls = {
76676b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
76776b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" },
76876b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" },
76976b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
77076b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
77176b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
77276b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
77376b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
77476b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
77576b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
77676b188c4SChris J Arges 	},
77776b188c4SChris J Arges 
77876b188c4SChris J Arges 	.matrix_mux_init = {
77976b188c4SChris J Arges 		 8,  9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */
78076b188c4SChris J Arges 		18, 19, 20, 21, 22, 23,     /* ADAT[1..6] -> 9..14 */
78176b188c4SChris J Arges 		16, 17,                          /* SPDIF -> 15,16 */
78276b188c4SChris J Arges 		0, 1                          /* PCM[1,2] -> 17,18 */
78376b188c4SChris J Arges 	}
78476b188c4SChris J Arges };
78576b188c4SChris J Arges 
78676b188c4SChris J Arges static struct scarlett_device_info s18i20_info = {
78776b188c4SChris J Arges 	.matrix_in = 18,
78876b188c4SChris J Arges 	.matrix_out = 8,
78976b188c4SChris J Arges 	.input_len = 18,
79076b188c4SChris J Arges 	.output_len = 20,
79176b188c4SChris J Arges 
79276b188c4SChris J Arges 	.opt_master = {
79376b188c4SChris J Arges 		.start = -1,
79476b188c4SChris J Arges 		.len = 47,
79576b188c4SChris J Arges 		.offsets = {0, 20, 28, 30, 38},
79676b188c4SChris J Arges 		.names = NULL
79776b188c4SChris J Arges 	},
79876b188c4SChris J Arges 
79976b188c4SChris J Arges 	.opt_matrix = {
80076b188c4SChris J Arges 		.start = -1,
80176b188c4SChris J Arges 		.len = 39,
80276b188c4SChris J Arges 		.offsets = {0, 20, 28, 30, 38},
80376b188c4SChris J Arges 		.names = NULL
80476b188c4SChris J Arges 	},
80576b188c4SChris J Arges 
80676b188c4SChris J Arges 	.num_controls = 10,
80776b188c4SChris J Arges 	.controls = {
80876b188c4SChris J Arges 		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
80976b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" },
81076b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" },
81176b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" },
81276b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" },
81376b188c4SChris J Arges 		{ .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
81476b188c4SChris J Arges 		{ .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" },
81576b188c4SChris J Arges 		{ .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" },
81676b188c4SChris J Arges 		{ .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" },
81776b188c4SChris J Arges 		{ .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" },
81876b188c4SChris J Arges 		/*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
81976b188c4SChris J Arges 		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
82076b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
82176b188c4SChris J Arges 		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
82276b188c4SChris J Arges 		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
82376b188c4SChris J Arges 		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/
82476b188c4SChris J Arges 	},
82576b188c4SChris J Arges 
82676b188c4SChris J Arges 	.matrix_mux_init = {
82776b188c4SChris J Arges 		20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */
82876b188c4SChris J Arges 		30, 31, 32, 33, 34, 35,     /* ADAT[1..6] -> 9..14 */
82976b188c4SChris J Arges 		28, 29,                          /* SPDIF -> 15,16 */
83076b188c4SChris J Arges 		0, 1                          /* PCM[1,2] -> 17,18 */
83176b188c4SChris J Arges 	}
83276b188c4SChris J Arges };
83376b188c4SChris J Arges 
83476b188c4SChris J Arges 
83576b188c4SChris J Arges static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer,
83676b188c4SChris J Arges 	struct scarlett_device_info *info)
83776b188c4SChris J Arges {
83876b188c4SChris J Arges 	int i, err;
83976b188c4SChris J Arges 	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
84076b188c4SChris J Arges 	const struct scarlett_mixer_control *ctl;
84176b188c4SChris J Arges 	struct usb_mixer_elem_info *elem;
84276b188c4SChris J Arges 
84376b188c4SChris J Arges 	/* create master switch and playback volume */
844b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
845b61f90eaSTakashi Iwai 			  scarlett_ctl_resume, 0x0a, 0x01, 0,
84676b188c4SChris J Arges 			  USB_MIXER_S16, 1, "Master Playback Switch", NULL,
84776b188c4SChris J Arges 			  &elem);
84876b188c4SChris J Arges 	if (err < 0)
84976b188c4SChris J Arges 		return err;
85076b188c4SChris J Arges 
851b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
852b61f90eaSTakashi Iwai 			  scarlett_ctl_resume, 0x0a, 0x02, 0,
85376b188c4SChris J Arges 			  USB_MIXER_S16, 1, "Master Playback Volume", NULL,
85476b188c4SChris J Arges 			  &elem);
85576b188c4SChris J Arges 	if (err < 0)
85676b188c4SChris J Arges 		return err;
85776b188c4SChris J Arges 
85876b188c4SChris J Arges 	/* iterate through controls in info struct and create each one */
85976b188c4SChris J Arges 	for (i = 0; i < info->num_controls; i++) {
86076b188c4SChris J Arges 		ctl = &info->controls[i];
86176b188c4SChris J Arges 
86276b188c4SChris J Arges 		switch (ctl->type) {
86376b188c4SChris J Arges 		case SCARLETT_OUTPUTS:
86476b188c4SChris J Arges 			err = add_output_ctls(mixer, ctl->num, ctl->name, info);
86576b188c4SChris J Arges 			if (err < 0)
86676b188c4SChris J Arges 				return err;
86776b188c4SChris J Arges 			break;
86876b188c4SChris J Arges 		case SCARLETT_SWITCH_IMPEDANCE:
86976b188c4SChris J Arges 			sprintf(mx, "Input %d Impedance Switch", ctl->num);
870b61f90eaSTakashi Iwai 			err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
871b61f90eaSTakashi Iwai 					  scarlett_ctl_enum_resume, 0x01,
87276b188c4SChris J Arges 					  0x09, ctl->num, USB_MIXER_S16, 1, mx,
87376b188c4SChris J Arges 					  &opt_impedance, &elem);
87476b188c4SChris J Arges 			if (err < 0)
87576b188c4SChris J Arges 				return err;
87676b188c4SChris J Arges 			break;
87776b188c4SChris J Arges 		case SCARLETT_SWITCH_PAD:
87876b188c4SChris J Arges 			sprintf(mx, "Input %d Pad Switch", ctl->num);
879b61f90eaSTakashi Iwai 			err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
880b61f90eaSTakashi Iwai 					  scarlett_ctl_enum_resume, 0x01,
88176b188c4SChris J Arges 					  0x0b, ctl->num, USB_MIXER_S16, 1, mx,
88276b188c4SChris J Arges 					  &opt_pad, &elem);
88376b188c4SChris J Arges 			if (err < 0)
88476b188c4SChris J Arges 				return err;
88576b188c4SChris J Arges 			break;
88676b188c4SChris J Arges 		}
88776b188c4SChris J Arges 	}
88876b188c4SChris J Arges 
88976b188c4SChris J Arges 	return 0;
89076b188c4SChris J Arges }
89176b188c4SChris J Arges 
89276b188c4SChris J Arges /*
89376b188c4SChris J Arges  * Create and initialize a mixer for the Focusrite(R) Scarlett
89476b188c4SChris J Arges  */
89576b188c4SChris J Arges int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
89676b188c4SChris J Arges {
89776b188c4SChris J Arges 	int err, i, o;
89876b188c4SChris J Arges 	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
89976b188c4SChris J Arges 	struct scarlett_device_info *info;
90076b188c4SChris J Arges 	struct usb_mixer_elem_info *elem;
90176b188c4SChris J Arges 	static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' };
90276b188c4SChris J Arges 
90376b188c4SChris J Arges 	/* only use UAC_VERSION_2 */
90476b188c4SChris J Arges 	if (!mixer->protocol)
90576b188c4SChris J Arges 		return 0;
90676b188c4SChris J Arges 
90776b188c4SChris J Arges 	switch (mixer->chip->usb_id) {
90876b188c4SChris J Arges 	case USB_ID(0x1235, 0x8012):
90976b188c4SChris J Arges 		info = &s6i6_info;
91076b188c4SChris J Arges 		break;
91176b188c4SChris J Arges 	case USB_ID(0x1235, 0x8002):
91276b188c4SChris J Arges 		info = &s8i6_info;
91376b188c4SChris J Arges 		break;
91476b188c4SChris J Arges 	case USB_ID(0x1235, 0x8004):
91576b188c4SChris J Arges 		info = &s18i6_info;
91676b188c4SChris J Arges 		break;
91776b188c4SChris J Arges 	case USB_ID(0x1235, 0x8014):
91876b188c4SChris J Arges 		info = &s18i8_info;
91976b188c4SChris J Arges 		break;
92076b188c4SChris J Arges 	case USB_ID(0x1235, 0x800c):
92176b188c4SChris J Arges 		info = &s18i20_info;
92276b188c4SChris J Arges 		break;
92376b188c4SChris J Arges 	default: /* device not (yet) supported */
92476b188c4SChris J Arges 		return -EINVAL;
92576b188c4SChris J Arges 	}
92676b188c4SChris J Arges 
92776b188c4SChris J Arges 	/* generic function to create controls */
92876b188c4SChris J Arges 	err = scarlett_controls_create_generic(mixer, info);
92976b188c4SChris J Arges 	if (err < 0)
93076b188c4SChris J Arges 		return err;
93176b188c4SChris J Arges 
93276b188c4SChris J Arges 	/* setup matrix controls */
93376b188c4SChris J Arges 	for (i = 0; i < info->matrix_in; i++) {
93476b188c4SChris J Arges 		snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route",
93576b188c4SChris J Arges 			 i+1);
936b61f90eaSTakashi Iwai 		err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
937b61f90eaSTakashi Iwai 				  scarlett_ctl_enum_resume, 0x32,
93876b188c4SChris J Arges 				  0x06, i, USB_MIXER_S16, 1, mx,
93976b188c4SChris J Arges 				  &info->opt_matrix, &elem);
94076b188c4SChris J Arges 		if (err < 0)
94176b188c4SChris J Arges 			return err;
94276b188c4SChris J Arges 
94376b188c4SChris J Arges 		for (o = 0; o < info->matrix_out; o++) {
94476b188c4SChris J Arges 			sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1,
94576b188c4SChris J Arges 				o+'A');
946b61f90eaSTakashi Iwai 			err = add_new_ctl(mixer, &usb_scarlett_ctl,
947b61f90eaSTakashi Iwai 					  scarlett_ctl_resume, 0x3c, 0x00,
94876b188c4SChris J Arges 					  (i << 3) + (o & 0x07), USB_MIXER_S16,
94976b188c4SChris J Arges 					  1, mx, NULL, &elem);
95076b188c4SChris J Arges 			if (err < 0)
95176b188c4SChris J Arges 				return err;
95276b188c4SChris J Arges 
95376b188c4SChris J Arges 		}
95476b188c4SChris J Arges 	}
95576b188c4SChris J Arges 
95676b188c4SChris J Arges 	for (i = 0; i < info->input_len; i++) {
95776b188c4SChris J Arges 		snprintf(mx, sizeof(mx), "Input Source %02d Capture Route",
95876b188c4SChris J Arges 			 i+1);
959b61f90eaSTakashi Iwai 		err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
960b61f90eaSTakashi Iwai 				  scarlett_ctl_enum_resume, 0x34,
96176b188c4SChris J Arges 				  0x00, i, USB_MIXER_S16, 1, mx,
96276b188c4SChris J Arges 				  &info->opt_master, &elem);
96376b188c4SChris J Arges 		if (err < 0)
96476b188c4SChris J Arges 			return err;
96576b188c4SChris J Arges 	}
96676b188c4SChris J Arges 
96776b188c4SChris J Arges 	/* val_len == 1 needed here */
968b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
969b61f90eaSTakashi Iwai 			  scarlett_ctl_enum_resume, 0x28, 0x01, 0,
97076b188c4SChris J Arges 			  USB_MIXER_U8, 1, "Sample Clock Source",
97176b188c4SChris J Arges 			  &opt_clock, &elem);
97276b188c4SChris J Arges 	if (err < 0)
97376b188c4SChris J Arges 		return err;
97476b188c4SChris J Arges 
97576b188c4SChris J Arges 	/* val_len == 1 and UAC2_CS_MEM */
976b61f90eaSTakashi Iwai 	err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2,
97776b188c4SChris J Arges 			  USB_MIXER_U8, 1, "Sample Clock Sync Status",
97876b188c4SChris J Arges 			  &opt_sync, &elem);
97976b188c4SChris J Arges 	if (err < 0)
98076b188c4SChris J Arges 		return err;
98176b188c4SChris J Arges 
98276b188c4SChris J Arges 	/* initialize sampling rate to 48000 */
98376b188c4SChris J Arges 	err = snd_usb_ctl_msg(mixer->chip->dev,
98476b188c4SChris J Arges 		usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
98576b188c4SChris J Arges 		USB_RECIP_INTERFACE | USB_TYPE_CLASS |
98676b188c4SChris J Arges 		USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
98776b188c4SChris J Arges 		(0x29 << 8), sample_rate_buffer, 4);
98876b188c4SChris J Arges 	if (err < 0)
98976b188c4SChris J Arges 		return err;
99076b188c4SChris J Arges 
99176b188c4SChris J Arges 	return err;
99276b188c4SChris J Arges }
993