Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Geoffrey D. Bennett and committed by
Takashi Iwai
d5ca9ad5 da0713ff

+179
+179
sound/usb/mixer_scarlett2.c
··· 541 541 SCARLETT2_CONFIG_PCM_INPUT_SWITCH, 542 542 SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN, 543 543 SCARLETT2_CONFIG_BLUETOOTH_VOLUME, 544 + SCARLETT2_CONFIG_SPDIF_MODE, 544 545 SCARLETT2_CONFIG_COUNT 545 546 }; 546 547 ··· 755 754 756 755 [SCARLETT2_CONFIG_TALKBACK_MAP] = { 757 756 .offset = 0xb0, .size = 16, .activate = 10 }, 757 + 758 + [SCARLETT2_CONFIG_SPDIF_MODE] = { 759 + .offset = 0x94, .size = 8, .activate = 6 }, 758 760 } 759 761 }; 760 762 ··· 981 977 982 978 [SCARLETT2_CONFIG_STANDALONE_SWITCH] = { 983 979 .offset = 0x8d, .size = 8, .activate = 6 }, 980 + 981 + [SCARLETT2_CONFIG_SPDIF_MODE] = { 982 + .offset = 0x9e, .size = 8, .activate = 4 }, 984 983 } 985 984 }; 986 985 ··· 1154 1147 /* has a Bluetooth module with volume control */ 1155 1148 u8 has_bluetooth; 1156 1149 1150 + /* S/PDIF Source/Digital I/O mode control */ 1151 + const char * const spdif_mode_control_name; 1152 + const u8 *spdif_mode_values; 1153 + const char * const *spdif_mode_texts; 1154 + 1157 1155 /* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected 1158 1156 * internally to the analogue 7/8 outputs 1159 1157 */ ··· 1267 1255 u8 standalone_switch; 1268 1256 u8 power_status; 1269 1257 u8 bluetooth_volume; 1258 + u8 spdif_mode; 1270 1259 u8 meter_level_map[SCARLETT2_MAX_METERS]; 1271 1260 struct snd_kcontrol *sync_ctl; 1272 1261 struct snd_kcontrol *master_vol_ctl; ··· 1595 1582 } 1596 1583 }; 1597 1584 1585 + static const u8 scarlett2_spdif_s18i8_gen3_values[] = { 0, 2, 0xff }; 1586 + 1587 + static const char * const scarlett2_spdif_s18i8_gen3_texts[] = { 1588 + "RCA", 1589 + "Optical", 1590 + NULL 1591 + }; 1592 + 1598 1593 static const struct scarlett2_device_info s18i8_gen3_info = { 1599 1594 .config_set = &scarlett2_config_set_gen3c, 1600 1595 .has_speaker_switching = 1, ··· 1611 1590 .air_input_count = 4, 1612 1591 .phantom_count = 2, 1613 1592 .inputs_per_phantom = 2, 1593 + 1594 + .spdif_mode_control_name = "S/PDIF Mode Capture Enum", 1595 + .spdif_mode_values = scarlett2_spdif_s18i8_gen3_values, 1596 + .spdif_mode_texts = scarlett2_spdif_s18i8_gen3_texts, 1614 1597 1615 1598 .line_out_remap_enable = 1, 1616 1599 .line_out_remap = { 0, 1, 6, 7, 2, 3, 4, 5 }, ··· 1686 1661 } 1687 1662 }; 1688 1663 1664 + static const u8 scarlett2_spdif_s18i20_gen3_values[] = { 0, 6, 1, 0xff }; 1665 + 1666 + static const char * const scarlett2_spdif_s18i20_gen3_texts[] = { 1667 + "S/PDIF RCA", 1668 + "S/PDIF Optical", 1669 + "Dual ADAT", 1670 + NULL 1671 + }; 1672 + 1689 1673 static const struct scarlett2_device_info s18i20_gen3_info = { 1690 1674 .config_set = &scarlett2_config_set_gen3c, 1691 1675 .has_speaker_switching = 1, ··· 1704 1670 .air_input_count = 8, 1705 1671 .phantom_count = 2, 1706 1672 .inputs_per_phantom = 4, 1673 + 1674 + .spdif_mode_control_name = "Digital I/O Mode Capture Enum", 1675 + .spdif_mode_values = scarlett2_spdif_s18i20_gen3_values, 1676 + .spdif_mode_texts = scarlett2_spdif_s18i20_gen3_texts, 1707 1677 1708 1678 .line_out_descrs = { 1709 1679 "Monitor 1 L", ··· 2057 2019 } 2058 2020 }; 2059 2021 2022 + static const u8 scarlett2_spdif_clarett_values[] = { 0, 1, 2, 0xff }; 2023 + 2024 + static const char * const scarlett2_spdif_clarett_texts[] = { 2025 + "None", 2026 + "Optical", 2027 + "RCA", 2028 + NULL 2029 + }; 2030 + 2060 2031 static const struct scarlett2_device_info clarett_4pre_info = { 2061 2032 .config_set = &scarlett2_config_set_clarett, 2062 2033 .level_input_count = 2, 2063 2034 .air_input_count = 4, 2035 + 2036 + .spdif_mode_control_name = "S/PDIF Source Capture Enum", 2037 + .spdif_mode_values = scarlett2_spdif_clarett_values, 2038 + .spdif_mode_texts = scarlett2_spdif_clarett_texts, 2064 2039 2065 2040 .line_out_descrs = { 2066 2041 "Monitor L", ··· 2126 2075 .config_set = &scarlett2_config_set_clarett, 2127 2076 .level_input_count = 2, 2128 2077 .air_input_count = 8, 2078 + 2079 + .spdif_mode_control_name = "S/PDIF Source Capture Enum", 2080 + .spdif_mode_values = scarlett2_spdif_clarett_values, 2081 + .spdif_mode_texts = scarlett2_spdif_clarett_texts, 2129 2082 2130 2083 .line_out_descrs = { 2131 2084 "Monitor L", ··· 7940 7885 &private->bluetooth_volume_ctl); 7941 7886 } 7942 7887 7888 + /*** S/PDIF Mode Controls ***/ 7889 + 7890 + static int scarlett2_update_spdif_mode(struct usb_mixer_interface *mixer) 7891 + { 7892 + struct scarlett2_data *private = mixer->private_data; 7893 + int err, i; 7894 + u8 mode; 7895 + const u8 *mode_values = private->info->spdif_mode_values; 7896 + 7897 + if (!private->info->spdif_mode_control_name) 7898 + return 0; 7899 + 7900 + err = scarlett2_usb_get_config(mixer, SCARLETT2_CONFIG_SPDIF_MODE, 7901 + 1, &mode); 7902 + if (err < 0) 7903 + return err; 7904 + 7905 + private->spdif_mode = 0; 7906 + 7907 + for (i = 0; *mode_values != 0xff; i++, mode_values++) 7908 + if (*mode_values == mode) { 7909 + private->spdif_mode = i; 7910 + break; 7911 + } 7912 + 7913 + return 0; 7914 + } 7915 + 7916 + static int scarlett2_spdif_mode_ctl_info(struct snd_kcontrol *kctl, 7917 + struct snd_ctl_elem_info *uinfo) 7918 + { 7919 + struct usb_mixer_elem_info *elem = kctl->private_data; 7920 + struct scarlett2_data *private = elem->head.mixer->private_data; 7921 + const char * const *mode_texts = private->info->spdif_mode_texts; 7922 + int count = 0; 7923 + 7924 + while (*mode_texts++) 7925 + count++; 7926 + 7927 + return snd_ctl_enum_info(uinfo, 1, count, 7928 + private->info->spdif_mode_texts); 7929 + } 7930 + 7931 + static int scarlett2_spdif_mode_ctl_get(struct snd_kcontrol *kctl, 7932 + struct snd_ctl_elem_value *ucontrol) 7933 + { 7934 + struct usb_mixer_elem_info *elem = kctl->private_data; 7935 + struct scarlett2_data *private = elem->head.mixer->private_data; 7936 + 7937 + ucontrol->value.enumerated.item[0] = private->spdif_mode; 7938 + return 0; 7939 + } 7940 + 7941 + static int scarlett2_spdif_mode_ctl_put(struct snd_kcontrol *kctl, 7942 + struct snd_ctl_elem_value *ucontrol) 7943 + { 7944 + struct usb_mixer_elem_info *elem = kctl->private_data; 7945 + struct usb_mixer_interface *mixer = elem->head.mixer; 7946 + struct scarlett2_data *private = mixer->private_data; 7947 + int oval, val, err = 0; 7948 + int i; 7949 + 7950 + mutex_lock(&private->data_mutex); 7951 + 7952 + oval = private->spdif_mode; 7953 + val = ucontrol->value.enumerated.item[0]; 7954 + 7955 + if (val < 0) { 7956 + err = -EINVAL; 7957 + goto unlock; 7958 + } 7959 + 7960 + for (i = 0; i <= val; i++) 7961 + if (private->info->spdif_mode_values[i] == 0xff) { 7962 + err = -EINVAL; 7963 + goto unlock; 7964 + } 7965 + 7966 + if (oval == val) 7967 + goto unlock; 7968 + 7969 + private->spdif_mode = val; 7970 + 7971 + err = scarlett2_usb_set_config( 7972 + mixer, SCARLETT2_CONFIG_SPDIF_MODE, 0, 7973 + private->info->spdif_mode_values[val]); 7974 + if (!err) 7975 + err = 1; 7976 + 7977 + unlock: 7978 + mutex_unlock(&private->data_mutex); 7979 + return err; 7980 + } 7981 + 7982 + static const struct snd_kcontrol_new scarlett2_spdif_mode_ctl = { 7983 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7984 + .name = "", 7985 + .info = scarlett2_spdif_mode_ctl_info, 7986 + .get = scarlett2_spdif_mode_ctl_get, 7987 + .put = scarlett2_spdif_mode_ctl_put, 7988 + }; 7989 + 7990 + static int scarlett2_add_spdif_mode_ctl(struct usb_mixer_interface *mixer) 7991 + { 7992 + struct scarlett2_data *private = mixer->private_data; 7993 + 7994 + if (!private->info->spdif_mode_control_name) 7995 + return 0; 7996 + 7997 + return scarlett2_add_new_ctl(mixer, &scarlett2_spdif_mode_ctl, 7998 + 0, 1, 7999 + private->info->spdif_mode_control_name, 8000 + NULL); 8001 + } 8002 + 7943 8003 /*** Notification Handlers ***/ 7944 8004 7945 8005 /* Notify on sync change */ ··· 8967 8797 if (err < 0) 8968 8798 return err; 8969 8799 8800 + err = scarlett2_update_spdif_mode(mixer); 8801 + if (err < 0) 8802 + return err; 8803 + 8970 8804 err = scarlett2_update_mix(mixer); 8971 8805 if (err < 0) 8972 8806 return err; ··· 9100 8926 9101 8927 /* Create the Bluetooth volume control */ 9102 8928 err = scarlett2_add_bluetooth_volume_ctl(mixer); 8929 + if (err < 0) 8930 + return err; 8931 + 8932 + /* Create the S/PDIF mode control */ 8933 + err = scarlett2_add_spdif_mode_ctl(mixer); 9103 8934 if (err < 0) 9104 8935 return err; 9105 8936