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

Configure Feed

Select the types of activity you want to include in your feed.

ALSA: ctxfi: Add support for dedicated RCA switching

Add feature to support switching between the dedicated RCA output and
the 7.1ch Front output. This is required for hardware that utilizes
separate DAC circuits for RCA and 7.1ch channels.

Changes:
- Add dedicated_rca capability flag
- Add "Analog Playback Route" mixer control
- Implement logic to swap DAO inputs between RCA and Front ports

Signed-off-by: Harin Lee <me@harin.net>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20251124180501.2760421-6-me@harin.net

authored by

Harin Lee and committed by
Takashi Iwai
9b4a2273 a2dbaeb5

+111 -5
+31 -2
sound/pci/ctxfi/ctatc.c
··· 987 987 return hw->capabilities(hw); 988 988 } 989 989 990 + static void atc_dedicated_rca_select(struct ct_atc *atc) 991 + { 992 + struct dao *dao; 993 + struct ct_mixer *mixer = atc->mixer; 994 + struct rsc *rscs[2] = {NULL}; 995 + 996 + dao = container_of(atc->daios[atc->rca_state ? RCA : LINEO1], 997 + struct dao, daio); 998 + dao->ops->clear_left_input(dao); 999 + dao->ops->clear_right_input(dao); 1000 + 1001 + mixer->get_output_ports(mixer, MIX_WAVE_FRONT, &rscs[0], &rscs[1]); 1002 + dao = container_of(atc->daios[atc->rca_state ? LINEO1 : RCA], 1003 + struct dao, daio); 1004 + dao->ops->set_left_input(dao, rscs[0]); 1005 + dao->ops->set_right_input(dao, rscs[1]); 1006 + } 1007 + 990 1008 static int atc_output_switch_get(struct ct_atc *atc) 991 1009 { 992 1010 struct hw *hw = atc->hw; ··· 1104 1086 static int atc_mic_unmute(struct ct_atc *atc, unsigned char state) 1105 1087 { 1106 1088 return atc_daio_unmute(atc, state, MIC); 1089 + } 1090 + 1091 + static int atc_rca_unmute(struct ct_atc *atc, unsigned char state) 1092 + { 1093 + return atc_daio_unmute(atc, state, RCA); 1107 1094 } 1108 1095 1109 1096 static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) ··· 1326 1303 dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n", 1327 1304 atc->chip_name, atc->model_name, 1328 1305 vendor_id, device_id); 1306 + atc->rca_state = 0; 1329 1307 return 0; 1330 1308 } 1331 1309 ··· 1424 1400 daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; 1425 1401 da_desc.msr = atc->msr; 1426 1402 for (i = 0; i < NUM_DAIOTYP; i++) { 1427 - if ((i == MIC) && !cap.dedicated_mic) 1403 + if (((i == MIC) && !cap.dedicated_mic) || ((i == RCA) && !cap.dedicated_rca)) 1428 1404 continue; 1429 1405 da_desc.type = (atc->model != CTSB073X) ? i : 1430 1406 ((i == SPDIFIO) ? SPDIFI1 : i); 1431 - da_desc.output = i < LINEIM; 1407 + da_desc.output = (i < LINEIM) || (i == RCA); 1432 1408 err = daio_mgr->get_daio(daio_mgr, &da_desc, 1433 1409 (struct daio **)&atc->daios[i]); 1434 1410 if (err) { ··· 1534 1510 dao->ops->set_left_input(dao, rscs[0]); 1535 1511 dao->ops->set_right_input(dao, rscs[1]); 1536 1512 } 1513 + 1514 + if (cap.dedicated_rca) 1515 + atc_dedicated_rca_select(atc); 1537 1516 1538 1517 dai = container_of(atc->daios[LINEIM], struct dai, daio); 1539 1518 atc_connect_dai(atc->rsc_mgrs[SRC], dai, ··· 1670 1643 .line_rear_unmute = atc_line_rear_unmute, 1671 1644 .line_in_unmute = atc_line_in_unmute, 1672 1645 .mic_unmute = atc_mic_unmute, 1646 + .rca_unmute = atc_rca_unmute, 1673 1647 .spdif_out_unmute = atc_spdif_out_unmute, 1674 1648 .spdif_in_unmute = atc_spdif_in_unmute, 1675 1649 .spdif_out_get_status = atc_spdif_out_get_status, 1676 1650 .spdif_out_set_status = atc_spdif_out_set_status, 1677 1651 .spdif_out_passthru = atc_spdif_out_passthru, 1678 1652 .capabilities = atc_capabilities, 1653 + .dedicated_rca_select = atc_dedicated_rca_select, 1679 1654 .output_switch_get = atc_output_switch_get, 1680 1655 .output_switch_put = atc_output_switch_put, 1681 1656 .mic_source_switch_get = atc_mic_source_switch_get,
+4
sound/pci/ctxfi/ctatc.h
··· 82 82 const char *chip_name; 83 83 const char *model_name; 84 84 85 + unsigned char rca_state; /* 0 = dedicated RCA, 1 = 7.1ch Front */ 86 + 85 87 struct ct_vm *vm; /* device virtual memory manager for this card */ 86 88 int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); 87 89 void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); ··· 115 113 int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state); 116 114 int (*line_in_unmute)(struct ct_atc *atc, unsigned char state); 117 115 int (*mic_unmute)(struct ct_atc *atc, unsigned char state); 116 + int (*rca_unmute)(struct ct_atc *atc, unsigned char state); 118 117 int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state); 119 118 int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state); 120 119 int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status); 121 120 int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status); 122 121 int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state); 123 122 struct capabilities (*capabilities)(struct ct_atc *atc); 123 + void (*dedicated_rca_select)(struct ct_atc *atc); 124 124 int (*output_switch_get)(struct ct_atc *atc); 125 125 int (*output_switch_put)(struct ct_atc *atc, int position); 126 126 int (*mic_source_switch_get)(struct ct_atc *atc);
+2
sound/pci/ctxfi/ctdaio.c
··· 45 45 [LINEO4] = {.left = 0x70, .right = 0x71}, 46 46 [LINEIM] = {.left = 0x45, .right = 0xc5}, 47 47 [MIC] = {.left = 0x55, .right = 0xd5}, 48 + [RCA] = {.left = 0x30, .right = 0x31}, 48 49 [SPDIFOO] = {.left = 0x00, .right = 0x01}, 49 50 [SPDIFIO] = {.left = 0x05, .right = 0x85}, 50 51 }; ··· 124 123 case LINEO4: return 6; 125 124 case LINEIM: return 4; 126 125 case MIC: return 5; 126 + case RCA: return 3; 127 127 default: return -EINVAL; 128 128 } 129 129 default:
+1
sound/pci/ctxfi/ctdaio.h
··· 31 31 LINEIM, 32 32 SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */ 33 33 MIC, /* Dedicated mic on Titanium HD */ 34 + RCA, 34 35 SPDIFI1, /* S/PDIF In on internal Drive Bay */ 35 36 NUM_DAIOTYP 36 37 };
+1
sound/pci/ctxfi/cthardware.h
··· 62 62 struct capabilities { 63 63 unsigned int digit_io_switch:1; 64 64 unsigned int dedicated_mic:1; 65 + unsigned int dedicated_rca:1; 65 66 unsigned int output_switch:1; 66 67 unsigned int mic_source_switch:1; 67 68 };
+1
sound/pci/ctxfi/cthw20k1.c
··· 1775 1775 /* SB073x and Vista compatible cards have no digit IO switch */ 1776 1776 cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA); 1777 1777 cap.dedicated_mic = 0; 1778 + cap.dedicated_rca = 0; 1778 1779 cap.output_switch = 0; 1779 1780 cap.mic_source_switch = 0; 1780 1781
+1
sound/pci/ctxfi/cthw20k2.c
··· 1930 1930 1931 1931 cap.digit_io_switch = 0; 1932 1932 cap.dedicated_mic = hw->model == CTSB1270; 1933 + cap.dedicated_rca = 0; 1933 1934 cap.output_switch = hw->model == CTSB1270; 1934 1935 cap.mic_source_switch = hw->model == CTSB1270; 1935 1936
+70 -3
sound/pci/ctxfi/ctmixer.c
··· 547 547 atc->mic_unmute(atc, state); 548 548 else if (MIXER_SPDIFI_C_S == type) 549 549 atc->spdif_in_unmute(atc, state); 550 - else if (MIXER_WAVEF_P_S == type) 551 - atc->line_front_unmute(atc, state); 550 + else if (MIXER_WAVEF_P_S == type) { 551 + if (cap.dedicated_rca) { 552 + atc->rca_unmute(atc, atc->rca_state ? 0 : state); 553 + atc->line_front_unmute(atc, atc->rca_state ? state : 0); 554 + } else { 555 + atc->line_front_unmute(atc, state); 556 + } 557 + } 552 558 else if (MIXER_WAVES_P_S == type) 553 559 atc->line_surround_unmute(atc, state); 554 560 else if (MIXER_WAVEC_P_S == type) ··· 616 610 .info = ct_alsa_mix_switch_info, 617 611 .get = ct_alsa_mix_switch_get, 618 612 .put = ct_alsa_mix_switch_put 613 + }; 614 + 615 + static int dedicated_rca_info(struct snd_kcontrol *kcontrol, 616 + struct snd_ctl_elem_info *info) 617 + { 618 + static const char *const names[2] = { 619 + "RCA", "Front" 620 + }; 621 + 622 + return snd_ctl_enum_info(info, 1, 2, names); 623 + } 624 + 625 + static int dedicated_rca_get(struct snd_kcontrol *kcontrol, 626 + struct snd_ctl_elem_value *ucontrol) 627 + { 628 + struct ct_atc *atc = snd_kcontrol_chip(kcontrol); 629 + 630 + ucontrol->value.enumerated.item[0] = atc->rca_state; 631 + return 0; 632 + } 633 + 634 + static int dedicated_rca_put(struct snd_kcontrol *kcontrol, 635 + struct snd_ctl_elem_value *ucontrol) 636 + { 637 + struct ct_atc *atc = snd_kcontrol_chip(kcontrol); 638 + unsigned int rca_state = ucontrol->value.enumerated.item[0]; 639 + unsigned char state; 640 + 641 + if (rca_state > 1) 642 + return -EINVAL; 643 + 644 + if (rca_state == atc->rca_state) 645 + return 0; 646 + 647 + state = get_switch_state(atc->mixer, MIXER_WAVEF_P_S); 648 + do_switch(atc, MIXER_WAVEF_P_S, 0); 649 + 650 + atc->rca_state = rca_state; 651 + atc->dedicated_rca_select(atc); 652 + 653 + do_switch(atc, MIXER_WAVEF_P_S, state); 654 + 655 + return 1; 656 + } 657 + 658 + static struct snd_kcontrol_new rca_ctl = { 659 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 660 + .name = "Analog Playback Route", 661 + .info = dedicated_rca_info, 662 + .get = dedicated_rca_get, 663 + .put = dedicated_rca_put, 619 664 }; 620 665 621 666 static int ct_spdif_info(struct snd_kcontrol *kcontrol, ··· 841 784 if (err) 842 785 return err; 843 786 } 844 - atc->line_front_unmute(atc, 1); 787 + 788 + if (cap.dedicated_rca) { 789 + err = ct_mixer_kcontrol_new(mixer, &rca_ctl); 790 + if (err) 791 + return err; 792 + 793 + atc->line_front_unmute(atc, 0); 794 + atc->rca_unmute(atc, 1); 795 + } else { 796 + atc->line_front_unmute(atc, 1); 797 + } 845 798 set_switch_state(mixer, MIXER_WAVEF_P_S, 1); 846 799 atc->line_surround_unmute(atc, 0); 847 800 set_switch_state(mixer, MIXER_WAVES_P_S, 0);