Skip to content

Commit d5ca9ad

Browse files
geoffreybennetttiwai
authored andcommitted
ALSA: scarlett2: Add S/PDIF source selection controls
Add S/PDIF Source/Digital I/O Mode selection controls for the Scarlett 3rd Gen 18i8/18i20 and Clarett 4Pre/8Pre interfaces. These models have both coax S/PDIF and optical inputs, and the optical inputs are switchable between being used as S/PDIF and ADAT inputs. The Scarlett 3rd Gen 18i20 also has a "Dual ADAT" mode for 8-channel audio at 88.2/96kHz. Signed-off-by: Geoffrey D. Bennett <g@b4.vu> Link: https://lore.kernel.org/r/Zj8zCTjzPsTDENN+@m.b4.vu Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent da0713f commit d5ca9ad

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

sound/usb/mixer_scarlett2.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ enum {
541541
SCARLETT2_CONFIG_PCM_INPUT_SWITCH,
542542
SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN,
543543
SCARLETT2_CONFIG_BLUETOOTH_VOLUME,
544+
SCARLETT2_CONFIG_SPDIF_MODE,
544545
SCARLETT2_CONFIG_COUNT
545546
};
546547

@@ -754,6 +755,9 @@ static const struct scarlett2_config_set scarlett2_config_set_gen3c = {
754755

755756
[SCARLETT2_CONFIG_TALKBACK_MAP] = {
756757
.offset = 0xb0, .size = 16, .activate = 10 },
758+
759+
[SCARLETT2_CONFIG_SPDIF_MODE] = {
760+
.offset = 0x94, .size = 8, .activate = 6 },
757761
}
758762
};
759763

@@ -977,6 +981,9 @@ static const struct scarlett2_config_set scarlett2_config_set_clarett = {
977981

978982
[SCARLETT2_CONFIG_STANDALONE_SWITCH] = {
979983
.offset = 0x8d, .size = 8, .activate = 6 },
984+
985+
[SCARLETT2_CONFIG_SPDIF_MODE] = {
986+
.offset = 0x9e, .size = 8, .activate = 4 },
980987
}
981988
};
982989

@@ -1147,6 +1154,11 @@ struct scarlett2_device_info {
11471154
/* has a Bluetooth module with volume control */
11481155
u8 has_bluetooth;
11491156

1157+
/* S/PDIF Source/Digital I/O mode control */
1158+
const char * const spdif_mode_control_name;
1159+
const u8 *spdif_mode_values;
1160+
const char * const *spdif_mode_texts;
1161+
11501162
/* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected
11511163
* internally to the analogue 7/8 outputs
11521164
*/
@@ -1255,6 +1267,7 @@ struct scarlett2_data {
12551267
u8 standalone_switch;
12561268
u8 power_status;
12571269
u8 bluetooth_volume;
1270+
u8 spdif_mode;
12581271
u8 meter_level_map[SCARLETT2_MAX_METERS];
12591272
struct snd_kcontrol *sync_ctl;
12601273
struct snd_kcontrol *master_vol_ctl;
@@ -1582,6 +1595,14 @@ static const struct scarlett2_device_info s8i6_gen3_info = {
15821595
}
15831596
};
15841597

1598+
static const u8 scarlett2_spdif_s18i8_gen3_values[] = { 0, 2, 0xff };
1599+
1600+
static const char * const scarlett2_spdif_s18i8_gen3_texts[] = {
1601+
"RCA",
1602+
"Optical",
1603+
NULL
1604+
};
1605+
15851606
static const struct scarlett2_device_info s18i8_gen3_info = {
15861607
.config_set = &scarlett2_config_set_gen3c,
15871608
.has_speaker_switching = 1,
@@ -1591,6 +1612,10 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
15911612
.phantom_count = 2,
15921613
.inputs_per_phantom = 2,
15931614

1615+
.spdif_mode_control_name = "S/PDIF Mode Capture Enum",
1616+
.spdif_mode_values = scarlett2_spdif_s18i8_gen3_values,
1617+
.spdif_mode_texts = scarlett2_spdif_s18i8_gen3_texts,
1618+
15941619
.line_out_remap_enable = 1,
15951620
.line_out_remap = { 0, 1, 6, 7, 2, 3, 4, 5 },
15961621
.line_out_unmap = { 0, 1, 4, 5, 6, 7, 2, 3 },
@@ -1661,6 +1686,15 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
16611686
}
16621687
};
16631688

1689+
static const u8 scarlett2_spdif_s18i20_gen3_values[] = { 0, 6, 1, 0xff };
1690+
1691+
static const char * const scarlett2_spdif_s18i20_gen3_texts[] = {
1692+
"S/PDIF RCA",
1693+
"S/PDIF Optical",
1694+
"Dual ADAT",
1695+
NULL
1696+
};
1697+
16641698
static const struct scarlett2_device_info s18i20_gen3_info = {
16651699
.config_set = &scarlett2_config_set_gen3c,
16661700
.has_speaker_switching = 1,
@@ -1671,6 +1705,10 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
16711705
.phantom_count = 2,
16721706
.inputs_per_phantom = 4,
16731707

1708+
.spdif_mode_control_name = "Digital I/O Mode Capture Enum",
1709+
.spdif_mode_values = scarlett2_spdif_s18i20_gen3_values,
1710+
.spdif_mode_texts = scarlett2_spdif_s18i20_gen3_texts,
1711+
16741712
.line_out_descrs = {
16751713
"Monitor 1 L",
16761714
"Monitor 1 R",
@@ -2019,11 +2057,24 @@ static const struct scarlett2_device_info clarett_2pre_info = {
20192057
}
20202058
};
20212059

2060+
static const u8 scarlett2_spdif_clarett_values[] = { 0, 1, 2, 0xff };
2061+
2062+
static const char * const scarlett2_spdif_clarett_texts[] = {
2063+
"None",
2064+
"Optical",
2065+
"RCA",
2066+
NULL
2067+
};
2068+
20222069
static const struct scarlett2_device_info clarett_4pre_info = {
20232070
.config_set = &scarlett2_config_set_clarett,
20242071
.level_input_count = 2,
20252072
.air_input_count = 4,
20262073

2074+
.spdif_mode_control_name = "S/PDIF Source Capture Enum",
2075+
.spdif_mode_values = scarlett2_spdif_clarett_values,
2076+
.spdif_mode_texts = scarlett2_spdif_clarett_texts,
2077+
20272078
.line_out_descrs = {
20282079
"Monitor L",
20292080
"Monitor R",
@@ -2076,6 +2127,10 @@ static const struct scarlett2_device_info clarett_8pre_info = {
20762127
.level_input_count = 2,
20772128
.air_input_count = 8,
20782129

2130+
.spdif_mode_control_name = "S/PDIF Source Capture Enum",
2131+
.spdif_mode_values = scarlett2_spdif_clarett_values,
2132+
.spdif_mode_texts = scarlett2_spdif_clarett_texts,
2133+
20792134
.line_out_descrs = {
20802135
"Monitor L",
20812136
"Monitor R",
@@ -7885,6 +7940,121 @@ static int scarlett2_add_bluetooth_volume_ctl(
78857940
&private->bluetooth_volume_ctl);
78867941
}
78877942

7943+
/*** S/PDIF Mode Controls ***/
7944+
7945+
static int scarlett2_update_spdif_mode(struct usb_mixer_interface *mixer)
7946+
{
7947+
struct scarlett2_data *private = mixer->private_data;
7948+
int err, i;
7949+
u8 mode;
7950+
const u8 *mode_values = private->info->spdif_mode_values;
7951+
7952+
if (!private->info->spdif_mode_control_name)
7953+
return 0;
7954+
7955+
err = scarlett2_usb_get_config(mixer, SCARLETT2_CONFIG_SPDIF_MODE,
7956+
1, &mode);
7957+
if (err < 0)
7958+
return err;
7959+
7960+
private->spdif_mode = 0;
7961+
7962+
for (i = 0; *mode_values != 0xff; i++, mode_values++)
7963+
if (*mode_values == mode) {
7964+
private->spdif_mode = i;
7965+
break;
7966+
}
7967+
7968+
return 0;
7969+
}
7970+
7971+
static int scarlett2_spdif_mode_ctl_info(struct snd_kcontrol *kctl,
7972+
struct snd_ctl_elem_info *uinfo)
7973+
{
7974+
struct usb_mixer_elem_info *elem = kctl->private_data;
7975+
struct scarlett2_data *private = elem->head.mixer->private_data;
7976+
const char * const *mode_texts = private->info->spdif_mode_texts;
7977+
int count = 0;
7978+
7979+
while (*mode_texts++)
7980+
count++;
7981+
7982+
return snd_ctl_enum_info(uinfo, 1, count,
7983+
private->info->spdif_mode_texts);
7984+
}
7985+
7986+
static int scarlett2_spdif_mode_ctl_get(struct snd_kcontrol *kctl,
7987+
struct snd_ctl_elem_value *ucontrol)
7988+
{
7989+
struct usb_mixer_elem_info *elem = kctl->private_data;
7990+
struct scarlett2_data *private = elem->head.mixer->private_data;
7991+
7992+
ucontrol->value.enumerated.item[0] = private->spdif_mode;
7993+
return 0;
7994+
}
7995+
7996+
static int scarlett2_spdif_mode_ctl_put(struct snd_kcontrol *kctl,
7997+
struct snd_ctl_elem_value *ucontrol)
7998+
{
7999+
struct usb_mixer_elem_info *elem = kctl->private_data;
8000+
struct usb_mixer_interface *mixer = elem->head.mixer;
8001+
struct scarlett2_data *private = mixer->private_data;
8002+
int oval, val, err = 0;
8003+
int i;
8004+
8005+
mutex_lock(&private->data_mutex);
8006+
8007+
oval = private->spdif_mode;
8008+
val = ucontrol->value.enumerated.item[0];
8009+
8010+
if (val < 0) {
8011+
err = -EINVAL;
8012+
goto unlock;
8013+
}
8014+
8015+
for (i = 0; i <= val; i++)
8016+
if (private->info->spdif_mode_values[i] == 0xff) {
8017+
err = -EINVAL;
8018+
goto unlock;
8019+
}
8020+
8021+
if (oval == val)
8022+
goto unlock;
8023+
8024+
private->spdif_mode = val;
8025+
8026+
err = scarlett2_usb_set_config(
8027+
mixer, SCARLETT2_CONFIG_SPDIF_MODE, 0,
8028+
private->info->spdif_mode_values[val]);
8029+
if (!err)
8030+
err = 1;
8031+
8032+
unlock:
8033+
mutex_unlock(&private->data_mutex);
8034+
return err;
8035+
}
8036+
8037+
static const struct snd_kcontrol_new scarlett2_spdif_mode_ctl = {
8038+
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8039+
.name = "",
8040+
.info = scarlett2_spdif_mode_ctl_info,
8041+
.get = scarlett2_spdif_mode_ctl_get,
8042+
.put = scarlett2_spdif_mode_ctl_put,
8043+
};
8044+
8045+
static int scarlett2_add_spdif_mode_ctl(struct usb_mixer_interface *mixer)
8046+
{
8047+
struct scarlett2_data *private = mixer->private_data;
8048+
8049+
if (!private->info->spdif_mode_control_name)
8050+
return 0;
8051+
8052+
return scarlett2_add_new_ctl(mixer, &scarlett2_spdif_mode_ctl,
8053+
0, 1,
8054+
private->info->spdif_mode_control_name,
8055+
NULL);
8056+
}
8057+
78888058
/*** Notification Handlers ***/
78898059

78908060
/* Notify on sync change */
@@ -8797,6 +8967,10 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
87978967
if (err < 0)
87988968
return err;
87998969

8970+
err = scarlett2_update_spdif_mode(mixer);
8971+
if (err < 0)
8972+
return err;
8973+
88008974
err = scarlett2_update_mix(mixer);
88018975
if (err < 0)
88028976
return err;
@@ -8929,6 +9103,11 @@ static int snd_scarlett2_controls_create(
89299103
if (err < 0)
89309104
return err;
89319105

9106+
/* Create the S/PDIF mode control */
9107+
err = scarlett2_add_spdif_mode_ctl(mixer);
9108+
if (err < 0)
9109+
return err;
9110+
89329111
/* Set the access mode of controls disabled during
89339112
* autogain/phantom power switching.
89349113
*/

0 commit comments

Comments
 (0)