18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   Scarlett Driver for ALSA
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *   Copyright (c) 2013 by Tobias Hoffmann
68c2ecf20Sopenharmony_ci *   Copyright (c) 2013 by Robin Gareus <robin at gareus.org>
78c2ecf20Sopenharmony_ci *   Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de>
88c2ecf20Sopenharmony_ci *   Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *   Many codes borrowed from audio.c by
118c2ecf20Sopenharmony_ci *	    Alan Cox (alan at lxorguk.ukuu.org.uk)
128c2ecf20Sopenharmony_ci *	    Thomas Sailer (sailer at ife.ee.ethz.ch)
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *   Code cleanup:
158c2ecf20Sopenharmony_ci *   David Henningsson <david.henningsson at canonical.com>
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/*
198c2ecf20Sopenharmony_ci * Rewritten and extended to support more models, e.g. Scarlett 18i8.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Auto-detection via UAC2 is not feasible to properly discover the vast
228c2ecf20Sopenharmony_ci * majority of features. It's related to both Linux/ALSA's UAC2 as well as
238c2ecf20Sopenharmony_ci * Focusrite's implementation of it. Eventually quirks may be sufficient but
248c2ecf20Sopenharmony_ci * right now it's a major headache to work arount these things.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * NB. Neither the OSX nor the win driver provided by Focusrite performs
278c2ecf20Sopenharmony_ci * discovery, they seem to operate the same as this driver.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* Mixer Interface for the Focusrite Scarlett 18i6 audio interface.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * The protocol was reverse engineered by looking at communication between
338c2ecf20Sopenharmony_ci * Scarlett MixControl (v 1.2.128.0) and the Focusrite(R) Scarlett 18i6
348c2ecf20Sopenharmony_ci * (firmware v305) using wireshark and usbmon in January 2013.
358c2ecf20Sopenharmony_ci * Extended in July 2013.
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * this mixer gives complete access to all features of the device:
388c2ecf20Sopenharmony_ci *  - change Impedance of inputs (Line-in, Mic / Instrument, Hi-Z)
398c2ecf20Sopenharmony_ci *  - select clock source
408c2ecf20Sopenharmony_ci *  - dynamic input to mixer-matrix assignment
418c2ecf20Sopenharmony_ci *  - 18 x 6 mixer-matrix gain stages
428c2ecf20Sopenharmony_ci *  - bus routing & volume control
438c2ecf20Sopenharmony_ci *  - automatic re-initialization on connect if device was power-cycled
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci * USB URB commands overview (bRequest = 0x01 = UAC2_CS_CUR)
468c2ecf20Sopenharmony_ci * wIndex
478c2ecf20Sopenharmony_ci * 0x01 Analog Input line/instrument impedance switch, wValue=0x0901 +
488c2ecf20Sopenharmony_ci *      channel, data=Line/Inst (2bytes)
498c2ecf20Sopenharmony_ci *      pad (-10dB) switch, wValue=0x0b01 + channel, data=Off/On (2bytes)
508c2ecf20Sopenharmony_ci *      ?? wValue=0x0803/04, ?? (2bytes)
518c2ecf20Sopenharmony_ci * 0x0a Master Volume, wValue=0x0200+bus[0:all + only 1..4?] data(2bytes)
528c2ecf20Sopenharmony_ci *      Bus Mute/Unmute wValue=0x0100+bus[0:all + only 1..4?], data(2bytes)
538c2ecf20Sopenharmony_ci * 0x28 Clock source, wValue=0x0100, data={1:int,2:spdif,3:adat} (1byte)
548c2ecf20Sopenharmony_ci * 0x29 Set Sample-rate, wValue=0x0100, data=sample-rate(4bytes)
558c2ecf20Sopenharmony_ci * 0x32 Mixer mux, wValue=0x0600 + mixer-channel, data=input-to-connect(2bytes)
568c2ecf20Sopenharmony_ci * 0x33 Output mux, wValue=bus, data=input-to-connect(2bytes)
578c2ecf20Sopenharmony_ci * 0x34 Capture mux, wValue=0...18, data=input-to-connect(2bytes)
588c2ecf20Sopenharmony_ci * 0x3c Matrix Mixer gains, wValue=mixer-node  data=gain(2bytes)
598c2ecf20Sopenharmony_ci *      ?? [sometimes](4bytes, e.g 0x000003be 0x000003bf ...03ff)
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * USB reads: (i.e. actually issued by original software)
628c2ecf20Sopenharmony_ci * 0x01 wValue=0x0901+channel (1byte!!), wValue=0x0b01+channed (1byte!!)
638c2ecf20Sopenharmony_ci * 0x29 wValue=0x0100 sample-rate(4bytes)
648c2ecf20Sopenharmony_ci *      wValue=0x0200 ?? 1byte (only once)
658c2ecf20Sopenharmony_ci * 0x2a wValue=0x0100 ?? 4bytes, sample-rate2 ??
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci * USB reads with bRequest = 0x03 = UAC2_CS_MEM
688c2ecf20Sopenharmony_ci * 0x3c wValue=0x0002 1byte: sync status (locked=1)
698c2ecf20Sopenharmony_ci *      wValue=0x0000 18*2byte: peak meter (inputs)
708c2ecf20Sopenharmony_ci *      wValue=0x0001 8(?)*2byte: peak meter (mix)
718c2ecf20Sopenharmony_ci *      wValue=0x0003 6*2byte: peak meter (pcm/daw)
728c2ecf20Sopenharmony_ci *
738c2ecf20Sopenharmony_ci * USB write with bRequest = 0x03
748c2ecf20Sopenharmony_ci * 0x3c Save settings to hardware: wValue=0x005a, data=0xa5
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci *
778c2ecf20Sopenharmony_ci * <ditaa>
788c2ecf20Sopenharmony_ci *  /--------------\    18chn            6chn    /--------------\
798c2ecf20Sopenharmony_ci *  | Hardware  in +--+-------\        /------+--+ ALSA PCM out |
808c2ecf20Sopenharmony_ci *  \--------------/  |       |        |      |  \--------------/
818c2ecf20Sopenharmony_ci *                    |       |        |      |
828c2ecf20Sopenharmony_ci *                    |       v        v      |
838c2ecf20Sopenharmony_ci *                    |   +---------------+   |
848c2ecf20Sopenharmony_ci *                    |    \ Matrix  Mux /    |
858c2ecf20Sopenharmony_ci *                    |     +-----+-----+     |
868c2ecf20Sopenharmony_ci *                    |           |           |
878c2ecf20Sopenharmony_ci *                    |           | 18chn     |
888c2ecf20Sopenharmony_ci *                    |           v           |
898c2ecf20Sopenharmony_ci *                    |     +-----------+     |
908c2ecf20Sopenharmony_ci *                    |     | Mixer     |     |
918c2ecf20Sopenharmony_ci *                    |     |    Matrix |     |
928c2ecf20Sopenharmony_ci *                    |     |           |     |
938c2ecf20Sopenharmony_ci *                    |     | 18x6 Gain |     |
948c2ecf20Sopenharmony_ci *                    |     |   stages  |     |
958c2ecf20Sopenharmony_ci *                    |     +-----+-----+     |
968c2ecf20Sopenharmony_ci *                    |           |           |
978c2ecf20Sopenharmony_ci *                    |           |           |
988c2ecf20Sopenharmony_ci *                    | 18chn     | 6chn      | 6chn
998c2ecf20Sopenharmony_ci *                    v           v           v
1008c2ecf20Sopenharmony_ci *                    =========================
1018c2ecf20Sopenharmony_ci *             +---------------+     +--—------------+
1028c2ecf20Sopenharmony_ci *              \ Output  Mux /       \ Capture Mux /
1038c2ecf20Sopenharmony_ci *               +-----+-----+         +-----+-----+
1048c2ecf20Sopenharmony_ci *                     |                     |
1058c2ecf20Sopenharmony_ci *                     | 6chn                |
1068c2ecf20Sopenharmony_ci *                     v                     |
1078c2ecf20Sopenharmony_ci *              +-------------+              |
1088c2ecf20Sopenharmony_ci *              | Master Gain |              |
1098c2ecf20Sopenharmony_ci *              +------+------+              |
1108c2ecf20Sopenharmony_ci *                     |                     |
1118c2ecf20Sopenharmony_ci *                     | 6chn                | 18chn
1128c2ecf20Sopenharmony_ci *                     | (3 stereo pairs)    |
1138c2ecf20Sopenharmony_ci *  /--------------\   |                     |   /--------------\
1148c2ecf20Sopenharmony_ci *  | Hardware out |<--/                     \-->| ALSA PCM  in |
1158c2ecf20Sopenharmony_ci *  \--------------/                             \--------------/
1168c2ecf20Sopenharmony_ci * </ditaa>
1178c2ecf20Sopenharmony_ci *
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#include <linux/slab.h>
1218c2ecf20Sopenharmony_ci#include <linux/usb.h>
1228c2ecf20Sopenharmony_ci#include <linux/usb/audio-v2.h>
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci#include <sound/core.h>
1258c2ecf20Sopenharmony_ci#include <sound/control.h>
1268c2ecf20Sopenharmony_ci#include <sound/tlv.h>
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#include "usbaudio.h"
1298c2ecf20Sopenharmony_ci#include "mixer.h"
1308c2ecf20Sopenharmony_ci#include "helper.h"
1318c2ecf20Sopenharmony_ci#include "power.h"
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#include "mixer_scarlett.h"
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/* some gui mixers can't handle negative ctl values */
1368c2ecf20Sopenharmony_ci#define SND_SCARLETT_LEVEL_BIAS 128
1378c2ecf20Sopenharmony_ci#define SND_SCARLETT_MATRIX_IN_MAX 18
1388c2ecf20Sopenharmony_ci#define SND_SCARLETT_CONTROLS_MAX 10
1398c2ecf20Sopenharmony_ci#define SND_SCARLETT_OFFSETS_MAX 5
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cienum {
1428c2ecf20Sopenharmony_ci	SCARLETT_OUTPUTS,
1438c2ecf20Sopenharmony_ci	SCARLETT_SWITCH_IMPEDANCE,
1448c2ecf20Sopenharmony_ci	SCARLETT_SWITCH_PAD,
1458c2ecf20Sopenharmony_ci	SCARLETT_SWITCH_GAIN,
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cienum {
1498c2ecf20Sopenharmony_ci	SCARLETT_OFFSET_PCM = 0,
1508c2ecf20Sopenharmony_ci	SCARLETT_OFFSET_ANALOG = 1,
1518c2ecf20Sopenharmony_ci	SCARLETT_OFFSET_SPDIF = 2,
1528c2ecf20Sopenharmony_ci	SCARLETT_OFFSET_ADAT = 3,
1538c2ecf20Sopenharmony_ci	SCARLETT_OFFSET_MIX = 4,
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistruct scarlett_mixer_elem_enum_info {
1578c2ecf20Sopenharmony_ci	int start;
1588c2ecf20Sopenharmony_ci	int len;
1598c2ecf20Sopenharmony_ci	int offsets[SND_SCARLETT_OFFSETS_MAX];
1608c2ecf20Sopenharmony_ci	char const * const *names;
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistruct scarlett_mixer_control {
1648c2ecf20Sopenharmony_ci	unsigned char num;
1658c2ecf20Sopenharmony_ci	unsigned char type;
1668c2ecf20Sopenharmony_ci	const char *name;
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistruct scarlett_device_info {
1708c2ecf20Sopenharmony_ci	int matrix_in;
1718c2ecf20Sopenharmony_ci	int matrix_out;
1728c2ecf20Sopenharmony_ci	int input_len;
1738c2ecf20Sopenharmony_ci	int output_len;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	struct scarlett_mixer_elem_enum_info opt_master;
1768c2ecf20Sopenharmony_ci	struct scarlett_mixer_elem_enum_info opt_matrix;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* initial values for matrix mux */
1798c2ecf20Sopenharmony_ci	int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX];
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	int num_controls;	/* number of items in controls */
1828c2ecf20Sopenharmony_ci	const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX];
1838c2ecf20Sopenharmony_ci};
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/********************** Enum Strings *************************/
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic const struct scarlett_mixer_elem_enum_info opt_pad = {
1888c2ecf20Sopenharmony_ci	.start = 0,
1898c2ecf20Sopenharmony_ci	.len = 2,
1908c2ecf20Sopenharmony_ci	.offsets = {},
1918c2ecf20Sopenharmony_ci	.names = (char const * const []){
1928c2ecf20Sopenharmony_ci		"0dB", "-10dB"
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci};
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic const struct scarlett_mixer_elem_enum_info opt_gain = {
1978c2ecf20Sopenharmony_ci	.start = 0,
1988c2ecf20Sopenharmony_ci	.len = 2,
1998c2ecf20Sopenharmony_ci	.offsets = {},
2008c2ecf20Sopenharmony_ci	.names = (char const * const []){
2018c2ecf20Sopenharmony_ci		"Lo", "Hi"
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci};
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic const struct scarlett_mixer_elem_enum_info opt_impedance = {
2068c2ecf20Sopenharmony_ci	.start = 0,
2078c2ecf20Sopenharmony_ci	.len = 2,
2088c2ecf20Sopenharmony_ci	.offsets = {},
2098c2ecf20Sopenharmony_ci	.names = (char const * const []){
2108c2ecf20Sopenharmony_ci		"Line", "Hi-Z"
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci};
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic const struct scarlett_mixer_elem_enum_info opt_clock = {
2158c2ecf20Sopenharmony_ci	.start = 1,
2168c2ecf20Sopenharmony_ci	.len = 3,
2178c2ecf20Sopenharmony_ci	.offsets = {},
2188c2ecf20Sopenharmony_ci	.names = (char const * const []){
2198c2ecf20Sopenharmony_ci		"Internal", "SPDIF", "ADAT"
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci};
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic const struct scarlett_mixer_elem_enum_info opt_sync = {
2248c2ecf20Sopenharmony_ci	.start = 0,
2258c2ecf20Sopenharmony_ci	.len = 2,
2268c2ecf20Sopenharmony_ci	.offsets = {},
2278c2ecf20Sopenharmony_ci	.names = (char const * const []){
2288c2ecf20Sopenharmony_ci		"No Lock", "Locked"
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci};
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int scarlett_ctl_switch_info(struct snd_kcontrol *kctl,
2338c2ecf20Sopenharmony_ci		struct snd_ctl_elem_info *uinfo)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
2388c2ecf20Sopenharmony_ci	uinfo->count = elem->channels;
2398c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
2408c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 1;
2418c2ecf20Sopenharmony_ci	return 0;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int scarlett_ctl_switch_get(struct snd_kcontrol *kctl,
2458c2ecf20Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
2488c2ecf20Sopenharmony_ci	int i, err, val;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	for (i = 0; i < elem->channels; i++) {
2518c2ecf20Sopenharmony_ci		err = snd_usb_get_cur_mix_value(elem, i, i, &val);
2528c2ecf20Sopenharmony_ci		if (err < 0)
2538c2ecf20Sopenharmony_ci			return err;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		val = !val; /* invert mute logic for mixer */
2568c2ecf20Sopenharmony_ci		ucontrol->value.integer.value[i] = val;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return 0;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic int scarlett_ctl_switch_put(struct snd_kcontrol *kctl,
2638c2ecf20Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
2668c2ecf20Sopenharmony_ci	int i, changed = 0;
2678c2ecf20Sopenharmony_ci	int err, oval, val;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	for (i = 0; i < elem->channels; i++) {
2708c2ecf20Sopenharmony_ci		err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
2718c2ecf20Sopenharmony_ci		if (err < 0)
2728c2ecf20Sopenharmony_ci			return err;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		val = ucontrol->value.integer.value[i];
2758c2ecf20Sopenharmony_ci		val = !val;
2768c2ecf20Sopenharmony_ci		if (oval != val) {
2778c2ecf20Sopenharmony_ci			err = snd_usb_set_cur_mix_value(elem, i, i, val);
2788c2ecf20Sopenharmony_ci			if (err < 0)
2798c2ecf20Sopenharmony_ci				return err;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci			changed = 1;
2828c2ecf20Sopenharmony_ci		}
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return changed;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic int scarlett_ctl_resume(struct usb_mixer_elem_list *list)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list);
2918c2ecf20Sopenharmony_ci	int i;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	for (i = 0; i < elem->channels; i++)
2948c2ecf20Sopenharmony_ci		if (elem->cached & (1 << i))
2958c2ecf20Sopenharmony_ci			snd_usb_set_cur_mix_value(elem, i, i,
2968c2ecf20Sopenharmony_ci						  elem->cache_val[i]);
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic int scarlett_ctl_info(struct snd_kcontrol *kctl,
3018c2ecf20Sopenharmony_ci			     struct snd_ctl_elem_info *uinfo)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3068c2ecf20Sopenharmony_ci	uinfo->count = elem->channels;
3078c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
3088c2ecf20Sopenharmony_ci	uinfo->value.integer.max = (int)kctl->private_value +
3098c2ecf20Sopenharmony_ci		SND_SCARLETT_LEVEL_BIAS;
3108c2ecf20Sopenharmony_ci	uinfo->value.integer.step = 1;
3118c2ecf20Sopenharmony_ci	return 0;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int scarlett_ctl_get(struct snd_kcontrol *kctl,
3158c2ecf20Sopenharmony_ci			    struct snd_ctl_elem_value *ucontrol)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
3188c2ecf20Sopenharmony_ci	int i, err, val;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	for (i = 0; i < elem->channels; i++) {
3218c2ecf20Sopenharmony_ci		err = snd_usb_get_cur_mix_value(elem, i, i, &val);
3228c2ecf20Sopenharmony_ci		if (err < 0)
3238c2ecf20Sopenharmony_ci			return err;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		val = clamp(val / 256, -128, (int)kctl->private_value) +
3268c2ecf20Sopenharmony_ci				    SND_SCARLETT_LEVEL_BIAS;
3278c2ecf20Sopenharmony_ci		ucontrol->value.integer.value[i] = val;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	return 0;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic int scarlett_ctl_put(struct snd_kcontrol *kctl,
3348c2ecf20Sopenharmony_ci			    struct snd_ctl_elem_value *ucontrol)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
3378c2ecf20Sopenharmony_ci	int i, changed = 0;
3388c2ecf20Sopenharmony_ci	int err, oval, val;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	for (i = 0; i < elem->channels; i++) {
3418c2ecf20Sopenharmony_ci		err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
3428c2ecf20Sopenharmony_ci		if (err < 0)
3438c2ecf20Sopenharmony_ci			return err;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		val = ucontrol->value.integer.value[i] -
3468c2ecf20Sopenharmony_ci			SND_SCARLETT_LEVEL_BIAS;
3478c2ecf20Sopenharmony_ci		val = val * 256;
3488c2ecf20Sopenharmony_ci		if (oval != val) {
3498c2ecf20Sopenharmony_ci			err = snd_usb_set_cur_mix_value(elem, i, i, val);
3508c2ecf20Sopenharmony_ci			if (err < 0)
3518c2ecf20Sopenharmony_ci				return err;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci			changed = 1;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	return changed;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic void scarlett_generate_name(int i, char *dst, int offsets[])
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	if (i > offsets[SCARLETT_OFFSET_MIX])
3638c2ecf20Sopenharmony_ci		sprintf(dst, "Mix %c",
3648c2ecf20Sopenharmony_ci			'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1));
3658c2ecf20Sopenharmony_ci	else if (i > offsets[SCARLETT_OFFSET_ADAT])
3668c2ecf20Sopenharmony_ci		sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]);
3678c2ecf20Sopenharmony_ci	else if (i > offsets[SCARLETT_OFFSET_SPDIF])
3688c2ecf20Sopenharmony_ci		sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]);
3698c2ecf20Sopenharmony_ci	else if (i > offsets[SCARLETT_OFFSET_ANALOG])
3708c2ecf20Sopenharmony_ci		sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]);
3718c2ecf20Sopenharmony_ci	else if (i > offsets[SCARLETT_OFFSET_PCM])
3728c2ecf20Sopenharmony_ci		sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]);
3738c2ecf20Sopenharmony_ci	else
3748c2ecf20Sopenharmony_ci		sprintf(dst, "Off");
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl,
3788c2ecf20Sopenharmony_ci					  struct snd_ctl_elem_info *uinfo)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
3818c2ecf20Sopenharmony_ci	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
3828c2ecf20Sopenharmony_ci	unsigned int items = opt->len;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3858c2ecf20Sopenharmony_ci	uinfo->count = elem->channels;
3868c2ecf20Sopenharmony_ci	uinfo->value.enumerated.items = items;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (uinfo->value.enumerated.item >= items)
3898c2ecf20Sopenharmony_ci		uinfo->value.enumerated.item = items - 1;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* generate name dynamically based on item number and offset info */
3928c2ecf20Sopenharmony_ci	scarlett_generate_name(uinfo->value.enumerated.item,
3938c2ecf20Sopenharmony_ci			       uinfo->value.enumerated.name,
3948c2ecf20Sopenharmony_ci			       opt->offsets);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	return 0;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int scarlett_ctl_enum_info(struct snd_kcontrol *kctl,
4008c2ecf20Sopenharmony_ci				  struct snd_ctl_elem_info *uinfo)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
4038c2ecf20Sopenharmony_ci	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, elem->channels, opt->len,
4068c2ecf20Sopenharmony_ci				 (const char * const *)opt->names);
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic int scarlett_ctl_enum_get(struct snd_kcontrol *kctl,
4108c2ecf20Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
4138c2ecf20Sopenharmony_ci	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
4148c2ecf20Sopenharmony_ci	int err, val;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	err = snd_usb_get_cur_mix_value(elem, 0, 0, &val);
4178c2ecf20Sopenharmony_ci	if (err < 0)
4188c2ecf20Sopenharmony_ci		return err;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	val = clamp(val - opt->start, 0, opt->len-1);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = val;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	return 0;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic int scarlett_ctl_enum_put(struct snd_kcontrol *kctl,
4288c2ecf20Sopenharmony_ci				 struct snd_ctl_elem_value *ucontrol)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
4318c2ecf20Sopenharmony_ci	struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
4328c2ecf20Sopenharmony_ci	int err, oval, val;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval);
4358c2ecf20Sopenharmony_ci	if (err < 0)
4368c2ecf20Sopenharmony_ci		return err;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0];
4398c2ecf20Sopenharmony_ci	val = val + opt->start;
4408c2ecf20Sopenharmony_ci	if (val != oval) {
4418c2ecf20Sopenharmony_ci		snd_usb_set_cur_mix_value(elem, 0, 0, val);
4428c2ecf20Sopenharmony_ci		return 1;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci	return 0;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (elem->cached)
4528c2ecf20Sopenharmony_ci		snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val);
4538c2ecf20Sopenharmony_ci	return 0;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
4578c2ecf20Sopenharmony_ci				  struct snd_ctl_elem_value *ucontrol)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
4608c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
4618c2ecf20Sopenharmony_ci	unsigned char buf[2 * MAX_CHANNELS] = {0, };
4628c2ecf20Sopenharmony_ci	int wValue = (elem->control << 8) | elem->idx_off;
4638c2ecf20Sopenharmony_ci	int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
4648c2ecf20Sopenharmony_ci	int err;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	err = snd_usb_ctl_msg(chip->dev,
4678c2ecf20Sopenharmony_ci				usb_rcvctrlpipe(chip->dev, 0),
4688c2ecf20Sopenharmony_ci				UAC2_CS_MEM,
4698c2ecf20Sopenharmony_ci				USB_RECIP_INTERFACE | USB_TYPE_CLASS |
4708c2ecf20Sopenharmony_ci				USB_DIR_IN, wValue, idx, buf, elem->channels);
4718c2ecf20Sopenharmony_ci	if (err < 0)
4728c2ecf20Sopenharmony_ci		return err;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1);
4758c2ecf20Sopenharmony_ci	return 0;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new usb_scarlett_ctl_switch = {
4798c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4808c2ecf20Sopenharmony_ci	.name = "",
4818c2ecf20Sopenharmony_ci	.info = scarlett_ctl_switch_info,
4828c2ecf20Sopenharmony_ci	.get =  scarlett_ctl_switch_get,
4838c2ecf20Sopenharmony_ci	.put =  scarlett_ctl_switch_put,
4848c2ecf20Sopenharmony_ci};
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new usb_scarlett_ctl = {
4898c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4908c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
4918c2ecf20Sopenharmony_ci		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
4928c2ecf20Sopenharmony_ci	.name = "",
4938c2ecf20Sopenharmony_ci	.info = scarlett_ctl_info,
4948c2ecf20Sopenharmony_ci	.get =  scarlett_ctl_get,
4958c2ecf20Sopenharmony_ci	.put =  scarlett_ctl_put,
4968c2ecf20Sopenharmony_ci	.private_value = 6,  /* max value */
4978c2ecf20Sopenharmony_ci	.tlv = { .p = db_scale_scarlett_gain }
4988c2ecf20Sopenharmony_ci};
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new usb_scarlett_ctl_master = {
5018c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5028c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
5038c2ecf20Sopenharmony_ci		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
5048c2ecf20Sopenharmony_ci	.name = "",
5058c2ecf20Sopenharmony_ci	.info = scarlett_ctl_info,
5068c2ecf20Sopenharmony_ci	.get =  scarlett_ctl_get,
5078c2ecf20Sopenharmony_ci	.put =  scarlett_ctl_put,
5088c2ecf20Sopenharmony_ci	.private_value = 6,  /* max value */
5098c2ecf20Sopenharmony_ci	.tlv = { .p = db_scale_scarlett_gain }
5108c2ecf20Sopenharmony_ci};
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new usb_scarlett_ctl_enum = {
5138c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5148c2ecf20Sopenharmony_ci	.name = "",
5158c2ecf20Sopenharmony_ci	.info = scarlett_ctl_enum_info,
5168c2ecf20Sopenharmony_ci	.get =  scarlett_ctl_enum_get,
5178c2ecf20Sopenharmony_ci	.put =  scarlett_ctl_enum_put,
5188c2ecf20Sopenharmony_ci};
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
5218c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5228c2ecf20Sopenharmony_ci	.name = "",
5238c2ecf20Sopenharmony_ci	.info = scarlett_ctl_enum_dynamic_info,
5248c2ecf20Sopenharmony_ci	.get =  scarlett_ctl_enum_get,
5258c2ecf20Sopenharmony_ci	.put =  scarlett_ctl_enum_put,
5268c2ecf20Sopenharmony_ci};
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new usb_scarlett_ctl_sync = {
5298c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5308c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
5318c2ecf20Sopenharmony_ci	.name = "",
5328c2ecf20Sopenharmony_ci	.info = scarlett_ctl_enum_info,
5338c2ecf20Sopenharmony_ci	.get =  scarlett_ctl_meter_get,
5348c2ecf20Sopenharmony_ci};
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic int add_new_ctl(struct usb_mixer_interface *mixer,
5378c2ecf20Sopenharmony_ci		       const struct snd_kcontrol_new *ncontrol,
5388c2ecf20Sopenharmony_ci		       usb_mixer_elem_resume_func_t resume,
5398c2ecf20Sopenharmony_ci		       int index, int offset, int num,
5408c2ecf20Sopenharmony_ci		       int val_type, int channels, const char *name,
5418c2ecf20Sopenharmony_ci		       const struct scarlett_mixer_elem_enum_info *opt,
5428c2ecf20Sopenharmony_ci		       struct usb_mixer_elem_info **elem_ret
5438c2ecf20Sopenharmony_ci)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	struct snd_kcontrol *kctl;
5468c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem;
5478c2ecf20Sopenharmony_ci	int err;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	elem = kzalloc(sizeof(*elem), GFP_KERNEL);
5508c2ecf20Sopenharmony_ci	if (!elem)
5518c2ecf20Sopenharmony_ci		return -ENOMEM;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	elem->head.mixer = mixer;
5548c2ecf20Sopenharmony_ci	elem->head.resume = resume;
5558c2ecf20Sopenharmony_ci	elem->control = offset;
5568c2ecf20Sopenharmony_ci	elem->idx_off = num;
5578c2ecf20Sopenharmony_ci	elem->head.id = index;
5588c2ecf20Sopenharmony_ci	elem->val_type = val_type;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	elem->channels = channels;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	/* add scarlett_mixer_elem_enum_info struct */
5638c2ecf20Sopenharmony_ci	elem->private_data = (void *)opt;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	kctl = snd_ctl_new1(ncontrol, elem);
5668c2ecf20Sopenharmony_ci	if (!kctl) {
5678c2ecf20Sopenharmony_ci		kfree(elem);
5688c2ecf20Sopenharmony_ci		return -ENOMEM;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci	kctl->private_free = snd_usb_mixer_elem_free;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	err = snd_usb_mixer_add_control(&elem->head, kctl);
5758c2ecf20Sopenharmony_ci	if (err < 0)
5768c2ecf20Sopenharmony_ci		return err;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (elem_ret)
5798c2ecf20Sopenharmony_ci		*elem_ret = elem;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	return 0;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int add_output_ctls(struct usb_mixer_interface *mixer,
5858c2ecf20Sopenharmony_ci			   int index, const char *name,
5868c2ecf20Sopenharmony_ci			   const struct scarlett_device_info *info)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	int err;
5898c2ecf20Sopenharmony_ci	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
5908c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/* Add mute switch */
5938c2ecf20Sopenharmony_ci	snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch",
5948c2ecf20Sopenharmony_ci		index + 1, name);
5958c2ecf20Sopenharmony_ci	err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
5968c2ecf20Sopenharmony_ci			  scarlett_ctl_resume, 0x0a, 0x01,
5978c2ecf20Sopenharmony_ci			  2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
5988c2ecf20Sopenharmony_ci	if (err < 0)
5998c2ecf20Sopenharmony_ci		return err;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	/* Add volume control and initialize to 0 */
6028c2ecf20Sopenharmony_ci	snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume",
6038c2ecf20Sopenharmony_ci		index + 1, name);
6048c2ecf20Sopenharmony_ci	err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
6058c2ecf20Sopenharmony_ci			  scarlett_ctl_resume, 0x0a, 0x02,
6068c2ecf20Sopenharmony_ci			  2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
6078c2ecf20Sopenharmony_ci	if (err < 0)
6088c2ecf20Sopenharmony_ci		return err;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/* Add L channel source playback enumeration */
6118c2ecf20Sopenharmony_ci	snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum",
6128c2ecf20Sopenharmony_ci		index + 1, name);
6138c2ecf20Sopenharmony_ci	err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
6148c2ecf20Sopenharmony_ci			  scarlett_ctl_enum_resume, 0x33, 0x00,
6158c2ecf20Sopenharmony_ci			  2*index, USB_MIXER_S16, 1, mx, &info->opt_master,
6168c2ecf20Sopenharmony_ci			  &elem);
6178c2ecf20Sopenharmony_ci	if (err < 0)
6188c2ecf20Sopenharmony_ci		return err;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	/* Add R channel source playback enumeration */
6218c2ecf20Sopenharmony_ci	snprintf(mx, sizeof(mx), "Master %dR (%s) Source Playback Enum",
6228c2ecf20Sopenharmony_ci		index + 1, name);
6238c2ecf20Sopenharmony_ci	err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
6248c2ecf20Sopenharmony_ci			  scarlett_ctl_enum_resume, 0x33, 0x00,
6258c2ecf20Sopenharmony_ci			  2*index+1, USB_MIXER_S16, 1, mx, &info->opt_master,
6268c2ecf20Sopenharmony_ci			  &elem);
6278c2ecf20Sopenharmony_ci	if (err < 0)
6288c2ecf20Sopenharmony_ci		return err;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	return 0;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci/********************** device-specific config *************************/
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci/*  untested...  */
6368c2ecf20Sopenharmony_cistatic const struct scarlett_device_info s6i6_info = {
6378c2ecf20Sopenharmony_ci	.matrix_in = 18,
6388c2ecf20Sopenharmony_ci	.matrix_out = 8,
6398c2ecf20Sopenharmony_ci	.input_len = 6,
6408c2ecf20Sopenharmony_ci	.output_len = 6,
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	.opt_master = {
6438c2ecf20Sopenharmony_ci		.start = -1,
6448c2ecf20Sopenharmony_ci		.len = 27,
6458c2ecf20Sopenharmony_ci		.offsets = {0, 12, 16, 18, 18},
6468c2ecf20Sopenharmony_ci		.names = NULL
6478c2ecf20Sopenharmony_ci	},
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	.opt_matrix = {
6508c2ecf20Sopenharmony_ci		.start = -1,
6518c2ecf20Sopenharmony_ci		.len = 19,
6528c2ecf20Sopenharmony_ci		.offsets = {0, 12, 16, 18, 18},
6538c2ecf20Sopenharmony_ci		.names = NULL
6548c2ecf20Sopenharmony_ci	},
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	.num_controls = 9,
6578c2ecf20Sopenharmony_ci	.controls = {
6588c2ecf20Sopenharmony_ci		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
6598c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
6608c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
6618c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
6628c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
6638c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
6648c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
6658c2ecf20Sopenharmony_ci		{ .num = 3, .type = SCARLETT_SWITCH_GAIN, .name = NULL},
6668c2ecf20Sopenharmony_ci		{ .num = 4, .type = SCARLETT_SWITCH_GAIN, .name = NULL},
6678c2ecf20Sopenharmony_ci	},
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	.matrix_mux_init = {
6708c2ecf20Sopenharmony_ci		12, 13, 14, 15,                 /* Analog -> 1..4 */
6718c2ecf20Sopenharmony_ci		16, 17,                          /* SPDIF -> 5,6 */
6728c2ecf20Sopenharmony_ci		0, 1, 2, 3, 4, 5, 6, 7,     /* PCM[1..12] -> 7..18 */
6738c2ecf20Sopenharmony_ci		8, 9, 10, 11
6748c2ecf20Sopenharmony_ci	}
6758c2ecf20Sopenharmony_ci};
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci/*  untested...  */
6788c2ecf20Sopenharmony_cistatic const struct scarlett_device_info s8i6_info = {
6798c2ecf20Sopenharmony_ci	.matrix_in = 18,
6808c2ecf20Sopenharmony_ci	.matrix_out = 6,
6818c2ecf20Sopenharmony_ci	.input_len = 8,
6828c2ecf20Sopenharmony_ci	.output_len = 6,
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	.opt_master = {
6858c2ecf20Sopenharmony_ci		.start = -1,
6868c2ecf20Sopenharmony_ci		.len = 25,
6878c2ecf20Sopenharmony_ci		.offsets = {0, 12, 16, 18, 18},
6888c2ecf20Sopenharmony_ci		.names = NULL
6898c2ecf20Sopenharmony_ci	},
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	.opt_matrix = {
6928c2ecf20Sopenharmony_ci		.start = -1,
6938c2ecf20Sopenharmony_ci		.len = 19,
6948c2ecf20Sopenharmony_ci		.offsets = {0, 12, 16, 18, 18},
6958c2ecf20Sopenharmony_ci		.names = NULL
6968c2ecf20Sopenharmony_ci	},
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	.num_controls = 7,
6998c2ecf20Sopenharmony_ci	.controls = {
7008c2ecf20Sopenharmony_ci		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
7018c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
7028c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
7038c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
7048c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
7058c2ecf20Sopenharmony_ci		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
7068c2ecf20Sopenharmony_ci		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
7078c2ecf20Sopenharmony_ci	},
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	.matrix_mux_init = {
7108c2ecf20Sopenharmony_ci		12, 13, 14, 15,                 /* Analog -> 1..4 */
7118c2ecf20Sopenharmony_ci		16, 17,                          /* SPDIF -> 5,6 */
7128c2ecf20Sopenharmony_ci		0, 1, 2, 3, 4, 5, 6, 7,     /* PCM[1..12] -> 7..18 */
7138c2ecf20Sopenharmony_ci		8, 9, 10, 11
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci};
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic const struct scarlett_device_info s18i6_info = {
7188c2ecf20Sopenharmony_ci	.matrix_in = 18,
7198c2ecf20Sopenharmony_ci	.matrix_out = 6,
7208c2ecf20Sopenharmony_ci	.input_len = 18,
7218c2ecf20Sopenharmony_ci	.output_len = 6,
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	.opt_master = {
7248c2ecf20Sopenharmony_ci		.start = -1,
7258c2ecf20Sopenharmony_ci		.len = 31,
7268c2ecf20Sopenharmony_ci		.offsets = {0, 6, 14, 16, 24},
7278c2ecf20Sopenharmony_ci		.names = NULL,
7288c2ecf20Sopenharmony_ci	},
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	.opt_matrix = {
7318c2ecf20Sopenharmony_ci		.start = -1,
7328c2ecf20Sopenharmony_ci		.len = 25,
7338c2ecf20Sopenharmony_ci		.offsets = {0, 6, 14, 16, 24},
7348c2ecf20Sopenharmony_ci		.names = NULL,
7358c2ecf20Sopenharmony_ci	},
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	.num_controls = 5,
7388c2ecf20Sopenharmony_ci	.controls = {
7398c2ecf20Sopenharmony_ci		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
7408c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
7418c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
7428c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
7438c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
7448c2ecf20Sopenharmony_ci	},
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	.matrix_mux_init = {
7478c2ecf20Sopenharmony_ci		 6,  7,  8,  9, 10, 11, 12, 13, /* Analog -> 1..8 */
7488c2ecf20Sopenharmony_ci		16, 17, 18, 19, 20, 21,     /* ADAT[1..6] -> 9..14 */
7498c2ecf20Sopenharmony_ci		14, 15,                          /* SPDIF -> 15,16 */
7508c2ecf20Sopenharmony_ci		0, 1                          /* PCM[1,2] -> 17,18 */
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci};
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic const struct scarlett_device_info s18i8_info = {
7558c2ecf20Sopenharmony_ci	.matrix_in = 18,
7568c2ecf20Sopenharmony_ci	.matrix_out = 8,
7578c2ecf20Sopenharmony_ci	.input_len = 18,
7588c2ecf20Sopenharmony_ci	.output_len = 8,
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	.opt_master = {
7618c2ecf20Sopenharmony_ci		.start = -1,
7628c2ecf20Sopenharmony_ci		.len = 35,
7638c2ecf20Sopenharmony_ci		.offsets = {0, 8, 16, 18, 26},
7648c2ecf20Sopenharmony_ci		.names = NULL
7658c2ecf20Sopenharmony_ci	},
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	.opt_matrix = {
7688c2ecf20Sopenharmony_ci		.start = -1,
7698c2ecf20Sopenharmony_ci		.len = 27,
7708c2ecf20Sopenharmony_ci		.offsets = {0, 8, 16, 18, 26},
7718c2ecf20Sopenharmony_ci		.names = NULL
7728c2ecf20Sopenharmony_ci	},
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	.num_controls = 10,
7758c2ecf20Sopenharmony_ci	.controls = {
7768c2ecf20Sopenharmony_ci		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
7778c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" },
7788c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" },
7798c2ecf20Sopenharmony_ci		{ .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
7808c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
7818c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
7828c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
7838c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
7848c2ecf20Sopenharmony_ci		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
7858c2ecf20Sopenharmony_ci		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
7868c2ecf20Sopenharmony_ci	},
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	.matrix_mux_init = {
7898c2ecf20Sopenharmony_ci		 8,  9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */
7908c2ecf20Sopenharmony_ci		18, 19, 20, 21, 22, 23,     /* ADAT[1..6] -> 9..14 */
7918c2ecf20Sopenharmony_ci		16, 17,                          /* SPDIF -> 15,16 */
7928c2ecf20Sopenharmony_ci		0, 1                          /* PCM[1,2] -> 17,18 */
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci};
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic const struct scarlett_device_info s18i20_info = {
7978c2ecf20Sopenharmony_ci	.matrix_in = 18,
7988c2ecf20Sopenharmony_ci	.matrix_out = 8,
7998c2ecf20Sopenharmony_ci	.input_len = 18,
8008c2ecf20Sopenharmony_ci	.output_len = 20,
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	.opt_master = {
8038c2ecf20Sopenharmony_ci		.start = -1,
8048c2ecf20Sopenharmony_ci		.len = 47,
8058c2ecf20Sopenharmony_ci		.offsets = {0, 20, 28, 30, 38},
8068c2ecf20Sopenharmony_ci		.names = NULL
8078c2ecf20Sopenharmony_ci	},
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	.opt_matrix = {
8108c2ecf20Sopenharmony_ci		.start = -1,
8118c2ecf20Sopenharmony_ci		.len = 39,
8128c2ecf20Sopenharmony_ci		.offsets = {0, 20, 28, 30, 38},
8138c2ecf20Sopenharmony_ci		.names = NULL
8148c2ecf20Sopenharmony_ci	},
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	.num_controls = 10,
8178c2ecf20Sopenharmony_ci	.controls = {
8188c2ecf20Sopenharmony_ci		{ .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
8198c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" },
8208c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" },
8218c2ecf20Sopenharmony_ci		{ .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" },
8228c2ecf20Sopenharmony_ci		{ .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" },
8238c2ecf20Sopenharmony_ci		{ .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
8248c2ecf20Sopenharmony_ci		{ .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" },
8258c2ecf20Sopenharmony_ci		{ .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" },
8268c2ecf20Sopenharmony_ci		{ .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" },
8278c2ecf20Sopenharmony_ci		{ .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" },
8288c2ecf20Sopenharmony_ci		/*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
8298c2ecf20Sopenharmony_ci		{ .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
8308c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
8318c2ecf20Sopenharmony_ci		{ .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
8328c2ecf20Sopenharmony_ci		{ .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
8338c2ecf20Sopenharmony_ci		{ .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/
8348c2ecf20Sopenharmony_ci	},
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	.matrix_mux_init = {
8378c2ecf20Sopenharmony_ci		20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */
8388c2ecf20Sopenharmony_ci		30, 31, 32, 33, 34, 35,     /* ADAT[1..6] -> 9..14 */
8398c2ecf20Sopenharmony_ci		28, 29,                          /* SPDIF -> 15,16 */
8408c2ecf20Sopenharmony_ci		0, 1                          /* PCM[1,2] -> 17,18 */
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci};
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_cistatic int scarlett_controls_create_generic(struct usb_mixer_interface *mixer,
8468c2ecf20Sopenharmony_ci	const struct scarlett_device_info *info)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	int i, err;
8498c2ecf20Sopenharmony_ci	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
8508c2ecf20Sopenharmony_ci	const struct scarlett_mixer_control *ctl;
8518c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	/* create master switch and playback volume */
8548c2ecf20Sopenharmony_ci	err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
8558c2ecf20Sopenharmony_ci			  scarlett_ctl_resume, 0x0a, 0x01, 0,
8568c2ecf20Sopenharmony_ci			  USB_MIXER_S16, 1, "Master Playback Switch", NULL,
8578c2ecf20Sopenharmony_ci			  &elem);
8588c2ecf20Sopenharmony_ci	if (err < 0)
8598c2ecf20Sopenharmony_ci		return err;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
8628c2ecf20Sopenharmony_ci			  scarlett_ctl_resume, 0x0a, 0x02, 0,
8638c2ecf20Sopenharmony_ci			  USB_MIXER_S16, 1, "Master Playback Volume", NULL,
8648c2ecf20Sopenharmony_ci			  &elem);
8658c2ecf20Sopenharmony_ci	if (err < 0)
8668c2ecf20Sopenharmony_ci		return err;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	/* iterate through controls in info struct and create each one */
8698c2ecf20Sopenharmony_ci	for (i = 0; i < info->num_controls; i++) {
8708c2ecf20Sopenharmony_ci		ctl = &info->controls[i];
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci		switch (ctl->type) {
8738c2ecf20Sopenharmony_ci		case SCARLETT_OUTPUTS:
8748c2ecf20Sopenharmony_ci			err = add_output_ctls(mixer, ctl->num, ctl->name, info);
8758c2ecf20Sopenharmony_ci			if (err < 0)
8768c2ecf20Sopenharmony_ci				return err;
8778c2ecf20Sopenharmony_ci			break;
8788c2ecf20Sopenharmony_ci		case SCARLETT_SWITCH_IMPEDANCE:
8798c2ecf20Sopenharmony_ci			sprintf(mx, "Input %d Impedance Switch", ctl->num);
8808c2ecf20Sopenharmony_ci			err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
8818c2ecf20Sopenharmony_ci					  scarlett_ctl_enum_resume, 0x01,
8828c2ecf20Sopenharmony_ci					  0x09, ctl->num, USB_MIXER_S16, 1, mx,
8838c2ecf20Sopenharmony_ci					  &opt_impedance, &elem);
8848c2ecf20Sopenharmony_ci			if (err < 0)
8858c2ecf20Sopenharmony_ci				return err;
8868c2ecf20Sopenharmony_ci			break;
8878c2ecf20Sopenharmony_ci		case SCARLETT_SWITCH_PAD:
8888c2ecf20Sopenharmony_ci			sprintf(mx, "Input %d Pad Switch", ctl->num);
8898c2ecf20Sopenharmony_ci			err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
8908c2ecf20Sopenharmony_ci					  scarlett_ctl_enum_resume, 0x01,
8918c2ecf20Sopenharmony_ci					  0x0b, ctl->num, USB_MIXER_S16, 1, mx,
8928c2ecf20Sopenharmony_ci					  &opt_pad, &elem);
8938c2ecf20Sopenharmony_ci			if (err < 0)
8948c2ecf20Sopenharmony_ci				return err;
8958c2ecf20Sopenharmony_ci			break;
8968c2ecf20Sopenharmony_ci		case SCARLETT_SWITCH_GAIN:
8978c2ecf20Sopenharmony_ci			sprintf(mx, "Input %d Gain Switch", ctl->num);
8988c2ecf20Sopenharmony_ci			err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
8998c2ecf20Sopenharmony_ci					  scarlett_ctl_enum_resume, 0x01,
9008c2ecf20Sopenharmony_ci					  0x08, ctl->num, USB_MIXER_S16, 1, mx,
9018c2ecf20Sopenharmony_ci					  &opt_gain, &elem);
9028c2ecf20Sopenharmony_ci			if (err < 0)
9038c2ecf20Sopenharmony_ci				return err;
9048c2ecf20Sopenharmony_ci			break;
9058c2ecf20Sopenharmony_ci		}
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	return 0;
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci/*
9128c2ecf20Sopenharmony_ci * Create and initialize a mixer for the Focusrite(R) Scarlett
9138c2ecf20Sopenharmony_ci */
9148c2ecf20Sopenharmony_ciint snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	int err, i, o;
9178c2ecf20Sopenharmony_ci	char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
9188c2ecf20Sopenharmony_ci	const struct scarlett_device_info *info;
9198c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem;
9208c2ecf20Sopenharmony_ci	static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' };
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	/* only use UAC_VERSION_2 */
9238c2ecf20Sopenharmony_ci	if (!mixer->protocol)
9248c2ecf20Sopenharmony_ci		return 0;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	switch (mixer->chip->usb_id) {
9278c2ecf20Sopenharmony_ci	case USB_ID(0x1235, 0x8012):
9288c2ecf20Sopenharmony_ci		info = &s6i6_info;
9298c2ecf20Sopenharmony_ci		break;
9308c2ecf20Sopenharmony_ci	case USB_ID(0x1235, 0x8002):
9318c2ecf20Sopenharmony_ci		info = &s8i6_info;
9328c2ecf20Sopenharmony_ci		break;
9338c2ecf20Sopenharmony_ci	case USB_ID(0x1235, 0x8004):
9348c2ecf20Sopenharmony_ci		info = &s18i6_info;
9358c2ecf20Sopenharmony_ci		break;
9368c2ecf20Sopenharmony_ci	case USB_ID(0x1235, 0x8014):
9378c2ecf20Sopenharmony_ci		info = &s18i8_info;
9388c2ecf20Sopenharmony_ci		break;
9398c2ecf20Sopenharmony_ci	case USB_ID(0x1235, 0x800c):
9408c2ecf20Sopenharmony_ci		info = &s18i20_info;
9418c2ecf20Sopenharmony_ci		break;
9428c2ecf20Sopenharmony_ci	default: /* device not (yet) supported */
9438c2ecf20Sopenharmony_ci		return -EINVAL;
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	/* generic function to create controls */
9478c2ecf20Sopenharmony_ci	err = scarlett_controls_create_generic(mixer, info);
9488c2ecf20Sopenharmony_ci	if (err < 0)
9498c2ecf20Sopenharmony_ci		return err;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	/* setup matrix controls */
9528c2ecf20Sopenharmony_ci	for (i = 0; i < info->matrix_in; i++) {
9538c2ecf20Sopenharmony_ci		snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route",
9548c2ecf20Sopenharmony_ci			 i+1);
9558c2ecf20Sopenharmony_ci		err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
9568c2ecf20Sopenharmony_ci				  scarlett_ctl_enum_resume, 0x32,
9578c2ecf20Sopenharmony_ci				  0x06, i, USB_MIXER_S16, 1, mx,
9588c2ecf20Sopenharmony_ci				  &info->opt_matrix, &elem);
9598c2ecf20Sopenharmony_ci		if (err < 0)
9608c2ecf20Sopenharmony_ci			return err;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		for (o = 0; o < info->matrix_out; o++) {
9638c2ecf20Sopenharmony_ci			sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1,
9648c2ecf20Sopenharmony_ci				o+'A');
9658c2ecf20Sopenharmony_ci			err = add_new_ctl(mixer, &usb_scarlett_ctl,
9668c2ecf20Sopenharmony_ci					  scarlett_ctl_resume, 0x3c, 0x00,
9678c2ecf20Sopenharmony_ci					  (i << 3) + (o & 0x07), USB_MIXER_S16,
9688c2ecf20Sopenharmony_ci					  1, mx, NULL, &elem);
9698c2ecf20Sopenharmony_ci			if (err < 0)
9708c2ecf20Sopenharmony_ci				return err;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci		}
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	for (i = 0; i < info->input_len; i++) {
9768c2ecf20Sopenharmony_ci		snprintf(mx, sizeof(mx), "Input Source %02d Capture Route",
9778c2ecf20Sopenharmony_ci			 i+1);
9788c2ecf20Sopenharmony_ci		err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
9798c2ecf20Sopenharmony_ci				  scarlett_ctl_enum_resume, 0x34,
9808c2ecf20Sopenharmony_ci				  0x00, i, USB_MIXER_S16, 1, mx,
9818c2ecf20Sopenharmony_ci				  &info->opt_master, &elem);
9828c2ecf20Sopenharmony_ci		if (err < 0)
9838c2ecf20Sopenharmony_ci			return err;
9848c2ecf20Sopenharmony_ci	}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	/* val_len == 1 needed here */
9878c2ecf20Sopenharmony_ci	err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
9888c2ecf20Sopenharmony_ci			  scarlett_ctl_enum_resume, 0x28, 0x01, 0,
9898c2ecf20Sopenharmony_ci			  USB_MIXER_U8, 1, "Sample Clock Source",
9908c2ecf20Sopenharmony_ci			  &opt_clock, &elem);
9918c2ecf20Sopenharmony_ci	if (err < 0)
9928c2ecf20Sopenharmony_ci		return err;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	/* val_len == 1 and UAC2_CS_MEM */
9958c2ecf20Sopenharmony_ci	err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2,
9968c2ecf20Sopenharmony_ci			  USB_MIXER_U8, 1, "Sample Clock Sync Status",
9978c2ecf20Sopenharmony_ci			  &opt_sync, &elem);
9988c2ecf20Sopenharmony_ci	if (err < 0)
9998c2ecf20Sopenharmony_ci		return err;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	/* initialize sampling rate to 48000 */
10028c2ecf20Sopenharmony_ci	err = snd_usb_ctl_msg(mixer->chip->dev,
10038c2ecf20Sopenharmony_ci		usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
10048c2ecf20Sopenharmony_ci		USB_RECIP_INTERFACE | USB_TYPE_CLASS |
10058c2ecf20Sopenharmony_ci		USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
10068c2ecf20Sopenharmony_ci		(0x29 << 8), sample_rate_buffer, 4);
10078c2ecf20Sopenharmony_ci	if (err < 0)
10088c2ecf20Sopenharmony_ci		return err;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	return err;
10118c2ecf20Sopenharmony_ci}
1012