diff options
| -rw-r--r-- | sound/pci/pcxhr/Makefile | 2 | ||||
| -rw-r--r-- | sound/pci/pcxhr/pcxhr_mix22.c | 820 | ||||
| -rw-r--r-- | sound/pci/pcxhr/pcxhr_mix22.h | 56 | ||||
| -rw-r--r-- | sound/pci/pcxhr/pcxhr_mixer.c | 556 |
4 files changed, 1259 insertions, 175 deletions
diff --git a/sound/pci/pcxhr/Makefile b/sound/pci/pcxhr/Makefile index 10473c05918d..b06128e918ca 100644 --- a/sound/pci/pcxhr/Makefile +++ b/sound/pci/pcxhr/Makefile | |||
| @@ -1,2 +1,2 @@ | |||
| 1 | snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o | 1 | snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o |
| 2 | obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o | 2 | obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o |
diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c new file mode 100644 index 000000000000..ff019126b672 --- /dev/null +++ b/sound/pci/pcxhr/pcxhr_mix22.c | |||
| @@ -0,0 +1,820 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Digigram pcxhr compatible soundcards | ||
| 3 | * | ||
| 4 | * mixer interface for stereo cards | ||
| 5 | * | ||
| 6 | * Copyright (c) 2004 by Digigram <alsa@digigram.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/io.h> | ||
| 25 | #include <sound/core.h> | ||
| 26 | #include <sound/control.h> | ||
| 27 | #include <sound/tlv.h> | ||
| 28 | #include <sound/asoundef.h> | ||
| 29 | #include "pcxhr.h" | ||
| 30 | #include "pcxhr_core.h" | ||
| 31 | #include "pcxhr_mix22.h" | ||
| 32 | |||
| 33 | |||
| 34 | /* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */ | ||
| 35 | #define PCXHR_DSP_RESET 0x20 | ||
| 36 | #define PCXHR_XLX_CFG 0x24 | ||
| 37 | #define PCXHR_XLX_RUER 0x28 | ||
| 38 | #define PCXHR_XLX_DATA 0x2C | ||
| 39 | #define PCXHR_XLX_STATUS 0x30 | ||
| 40 | #define PCXHR_XLX_LOFREQ 0x34 | ||
| 41 | #define PCXHR_XLX_HIFREQ 0x38 | ||
| 42 | #define PCXHR_XLX_CSUER 0x3C | ||
| 43 | #define PCXHR_XLX_SELMIC 0x40 | ||
| 44 | |||
| 45 | #define PCXHR_DSP 2 | ||
| 46 | |||
| 47 | /* byte access only ! */ | ||
| 48 | #define PCXHR_INPB(mgr, x) inb((mgr)->port[PCXHR_DSP] + (x)) | ||
| 49 | #define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x)) | ||
| 50 | |||
| 51 | |||
| 52 | /* values for PCHR_DSP_RESET register */ | ||
| 53 | #define PCXHR_DSP_RESET_DSP 0x01 | ||
| 54 | #define PCXHR_DSP_RESET_MUTE 0x02 | ||
| 55 | #define PCXHR_DSP_RESET_CODEC 0x08 | ||
| 56 | |||
| 57 | /* values for PCHR_XLX_CFG register */ | ||
| 58 | #define PCXHR_CFG_SYNCDSP_MASK 0x80 | ||
| 59 | #define PCXHR_CFG_DEPENDENCY_MASK 0x60 | ||
| 60 | #define PCXHR_CFG_INDEPENDANT_SEL 0x00 | ||
| 61 | #define PCXHR_CFG_MASTER_SEL 0x40 | ||
| 62 | #define PCXHR_CFG_SLAVE_SEL 0x20 | ||
| 63 | #define PCXHR_CFG_DATA_UER1_SEL_MASK 0x10 /* 0 (UER0), 1(UER1) */ | ||
| 64 | #define PCXHR_CFG_DATAIN_SEL_MASK 0x08 /* 0 (ana), 1 (UER) */ | ||
| 65 | #define PCXHR_CFG_SRC_MASK 0x04 /* 0 (Bypass), 1 (SRC Actif) */ | ||
| 66 | #define PCXHR_CFG_CLOCK_UER1_SEL_MASK 0x02 /* 0 (UER0), 1(UER1) */ | ||
| 67 | #define PCXHR_CFG_CLOCKIN_SEL_MASK 0x01 /* 0 (internal), 1 (AES/EBU) */ | ||
| 68 | |||
| 69 | /* values for PCHR_XLX_DATA register */ | ||
| 70 | #define PCXHR_DATA_CODEC 0x80 | ||
| 71 | #define AKM_POWER_CONTROL_CMD 0xA007 | ||
| 72 | #define AKM_RESET_ON_CMD 0xA100 | ||
| 73 | #define AKM_RESET_OFF_CMD 0xA103 | ||
| 74 | #define AKM_CLOCK_INF_55K_CMD 0xA240 | ||
| 75 | #define AKM_CLOCK_SUP_55K_CMD 0xA24D | ||
| 76 | #define AKM_MUTE_CMD 0xA38D | ||
| 77 | #define AKM_UNMUTE_CMD 0xA30D | ||
| 78 | #define AKM_LEFT_LEVEL_CMD 0xA600 | ||
| 79 | #define AKM_RIGHT_LEVEL_CMD 0xA700 | ||
| 80 | |||
| 81 | /* values for PCHR_XLX_STATUS register - READ */ | ||
| 82 | #define PCXHR_STAT_SRC_LOCK 0x01 | ||
| 83 | #define PCXHR_STAT_LEVEL_IN 0x02 | ||
| 84 | #define PCXHR_STAT_MIC_CAPS 0x10 | ||
| 85 | /* values for PCHR_XLX_STATUS register - WRITE */ | ||
| 86 | #define PCXHR_STAT_FREQ_SYNC_MASK 0x01 | ||
| 87 | #define PCXHR_STAT_FREQ_UER1_MASK 0x02 | ||
| 88 | #define PCXHR_STAT_FREQ_SAVE_MASK 0x80 | ||
| 89 | |||
| 90 | /* values for PCHR_XLX_CSUER register */ | ||
| 91 | #define PCXHR_SUER1_BIT_U_READ_MASK 0x80 | ||
| 92 | #define PCXHR_SUER1_BIT_C_READ_MASK 0x40 | ||
| 93 | #define PCXHR_SUER1_DATA_PRESENT_MASK 0x20 | ||
| 94 | #define PCXHR_SUER1_CLOCK_PRESENT_MASK 0x10 | ||
| 95 | #define PCXHR_SUER_BIT_U_READ_MASK 0x08 | ||
| 96 | #define PCXHR_SUER_BIT_C_READ_MASK 0x04 | ||
| 97 | #define PCXHR_SUER_DATA_PRESENT_MASK 0x02 | ||
| 98 | #define PCXHR_SUER_CLOCK_PRESENT_MASK 0x01 | ||
| 99 | |||
| 100 | #define PCXHR_SUER_BIT_U_WRITE_MASK 0x02 | ||
| 101 | #define PCXHR_SUER_BIT_C_WRITE_MASK 0x01 | ||
| 102 | |||
| 103 | /* values for PCXHR_XLX_SELMIC register - WRITE */ | ||
| 104 | #define PCXHR_SELMIC_PREAMPLI_OFFSET 2 | ||
| 105 | #define PCXHR_SELMIC_PREAMPLI_MASK 0x0C | ||
| 106 | #define PCXHR_SELMIC_PHANTOM_ALIM 0x80 | ||
| 107 | |||
| 108 | |||
| 109 | static const unsigned char g_hr222_p_level[] = { | ||
| 110 | 0x00, /* [000] -49.5 dB: AKM[000] = -1.#INF dB (mute) */ | ||
| 111 | 0x01, /* [001] -49.0 dB: AKM[001] = -48.131 dB (diff=0.86920 dB) */ | ||
| 112 | 0x01, /* [002] -48.5 dB: AKM[001] = -48.131 dB (diff=0.36920 dB) */ | ||
| 113 | 0x01, /* [003] -48.0 dB: AKM[001] = -48.131 dB (diff=0.13080 dB) */ | ||
| 114 | 0x01, /* [004] -47.5 dB: AKM[001] = -48.131 dB (diff=0.63080 dB) */ | ||
| 115 | 0x01, /* [005] -46.5 dB: AKM[001] = -48.131 dB (diff=1.63080 dB) */ | ||
| 116 | 0x01, /* [006] -47.0 dB: AKM[001] = -48.131 dB (diff=1.13080 dB) */ | ||
| 117 | 0x01, /* [007] -46.0 dB: AKM[001] = -48.131 dB (diff=2.13080 dB) */ | ||
| 118 | 0x01, /* [008] -45.5 dB: AKM[001] = -48.131 dB (diff=2.63080 dB) */ | ||
| 119 | 0x02, /* [009] -45.0 dB: AKM[002] = -42.110 dB (diff=2.88980 dB) */ | ||
| 120 | 0x02, /* [010] -44.5 dB: AKM[002] = -42.110 dB (diff=2.38980 dB) */ | ||
| 121 | 0x02, /* [011] -44.0 dB: AKM[002] = -42.110 dB (diff=1.88980 dB) */ | ||
| 122 | 0x02, /* [012] -43.5 dB: AKM[002] = -42.110 dB (diff=1.38980 dB) */ | ||
| 123 | 0x02, /* [013] -43.0 dB: AKM[002] = -42.110 dB (diff=0.88980 dB) */ | ||
| 124 | 0x02, /* [014] -42.5 dB: AKM[002] = -42.110 dB (diff=0.38980 dB) */ | ||
| 125 | 0x02, /* [015] -42.0 dB: AKM[002] = -42.110 dB (diff=0.11020 dB) */ | ||
| 126 | 0x02, /* [016] -41.5 dB: AKM[002] = -42.110 dB (diff=0.61020 dB) */ | ||
| 127 | 0x02, /* [017] -41.0 dB: AKM[002] = -42.110 dB (diff=1.11020 dB) */ | ||
| 128 | 0x02, /* [018] -40.5 dB: AKM[002] = -42.110 dB (diff=1.61020 dB) */ | ||
| 129 | 0x03, /* [019] -40.0 dB: AKM[003] = -38.588 dB (diff=1.41162 dB) */ | ||
| 130 | 0x03, /* [020] -39.5 dB: AKM[003] = -38.588 dB (diff=0.91162 dB) */ | ||
| 131 | 0x03, /* [021] -39.0 dB: AKM[003] = -38.588 dB (diff=0.41162 dB) */ | ||
| 132 | 0x03, /* [022] -38.5 dB: AKM[003] = -38.588 dB (diff=0.08838 dB) */ | ||
| 133 | 0x03, /* [023] -38.0 dB: AKM[003] = -38.588 dB (diff=0.58838 dB) */ | ||
| 134 | 0x03, /* [024] -37.5 dB: AKM[003] = -38.588 dB (diff=1.08838 dB) */ | ||
| 135 | 0x04, /* [025] -37.0 dB: AKM[004] = -36.090 dB (diff=0.91040 dB) */ | ||
| 136 | 0x04, /* [026] -36.5 dB: AKM[004] = -36.090 dB (diff=0.41040 dB) */ | ||
| 137 | 0x04, /* [027] -36.0 dB: AKM[004] = -36.090 dB (diff=0.08960 dB) */ | ||
| 138 | 0x04, /* [028] -35.5 dB: AKM[004] = -36.090 dB (diff=0.58960 dB) */ | ||
| 139 | 0x05, /* [029] -35.0 dB: AKM[005] = -34.151 dB (diff=0.84860 dB) */ | ||
| 140 | 0x05, /* [030] -34.5 dB: AKM[005] = -34.151 dB (diff=0.34860 dB) */ | ||
| 141 | 0x05, /* [031] -34.0 dB: AKM[005] = -34.151 dB (diff=0.15140 dB) */ | ||
| 142 | 0x05, /* [032] -33.5 dB: AKM[005] = -34.151 dB (diff=0.65140 dB) */ | ||
| 143 | 0x06, /* [033] -33.0 dB: AKM[006] = -32.568 dB (diff=0.43222 dB) */ | ||
| 144 | 0x06, /* [034] -32.5 dB: AKM[006] = -32.568 dB (diff=0.06778 dB) */ | ||
| 145 | 0x06, /* [035] -32.0 dB: AKM[006] = -32.568 dB (diff=0.56778 dB) */ | ||
| 146 | 0x07, /* [036] -31.5 dB: AKM[007] = -31.229 dB (diff=0.27116 dB) */ | ||
| 147 | 0x07, /* [037] -31.0 dB: AKM[007] = -31.229 dB (diff=0.22884 dB) */ | ||
| 148 | 0x08, /* [038] -30.5 dB: AKM[008] = -30.069 dB (diff=0.43100 dB) */ | ||
| 149 | 0x08, /* [039] -30.0 dB: AKM[008] = -30.069 dB (diff=0.06900 dB) */ | ||
| 150 | 0x09, /* [040] -29.5 dB: AKM[009] = -29.046 dB (diff=0.45405 dB) */ | ||
| 151 | 0x09, /* [041] -29.0 dB: AKM[009] = -29.046 dB (diff=0.04595 dB) */ | ||
| 152 | 0x0a, /* [042] -28.5 dB: AKM[010] = -28.131 dB (diff=0.36920 dB) */ | ||
| 153 | 0x0a, /* [043] -28.0 dB: AKM[010] = -28.131 dB (diff=0.13080 dB) */ | ||
| 154 | 0x0b, /* [044] -27.5 dB: AKM[011] = -27.303 dB (diff=0.19705 dB) */ | ||
| 155 | 0x0b, /* [045] -27.0 dB: AKM[011] = -27.303 dB (diff=0.30295 dB) */ | ||
| 156 | 0x0c, /* [046] -26.5 dB: AKM[012] = -26.547 dB (diff=0.04718 dB) */ | ||
| 157 | 0x0d, /* [047] -26.0 dB: AKM[013] = -25.852 dB (diff=0.14806 dB) */ | ||
| 158 | 0x0e, /* [048] -25.5 dB: AKM[014] = -25.208 dB (diff=0.29176 dB) */ | ||
| 159 | 0x0e, /* [049] -25.0 dB: AKM[014] = -25.208 dB (diff=0.20824 dB) */ | ||
| 160 | 0x0f, /* [050] -24.5 dB: AKM[015] = -24.609 dB (diff=0.10898 dB) */ | ||
| 161 | 0x10, /* [051] -24.0 dB: AKM[016] = -24.048 dB (diff=0.04840 dB) */ | ||
| 162 | 0x11, /* [052] -23.5 dB: AKM[017] = -23.522 dB (diff=0.02183 dB) */ | ||
| 163 | 0x12, /* [053] -23.0 dB: AKM[018] = -23.025 dB (diff=0.02535 dB) */ | ||
| 164 | 0x13, /* [054] -22.5 dB: AKM[019] = -22.556 dB (diff=0.05573 dB) */ | ||
| 165 | 0x14, /* [055] -22.0 dB: AKM[020] = -22.110 dB (diff=0.11020 dB) */ | ||
| 166 | 0x15, /* [056] -21.5 dB: AKM[021] = -21.686 dB (diff=0.18642 dB) */ | ||
| 167 | 0x17, /* [057] -21.0 dB: AKM[023] = -20.896 dB (diff=0.10375 dB) */ | ||
| 168 | 0x18, /* [058] -20.5 dB: AKM[024] = -20.527 dB (diff=0.02658 dB) */ | ||
| 169 | 0x1a, /* [059] -20.0 dB: AKM[026] = -19.831 dB (diff=0.16866 dB) */ | ||
| 170 | 0x1b, /* [060] -19.5 dB: AKM[027] = -19.504 dB (diff=0.00353 dB) */ | ||
| 171 | 0x1d, /* [061] -19.0 dB: AKM[029] = -18.883 dB (diff=0.11716 dB) */ | ||
| 172 | 0x1e, /* [062] -18.5 dB: AKM[030] = -18.588 dB (diff=0.08838 dB) */ | ||
| 173 | 0x20, /* [063] -18.0 dB: AKM[032] = -18.028 dB (diff=0.02780 dB) */ | ||
| 174 | 0x22, /* [064] -17.5 dB: AKM[034] = -17.501 dB (diff=0.00123 dB) */ | ||
| 175 | 0x24, /* [065] -17.0 dB: AKM[036] = -17.005 dB (diff=0.00475 dB) */ | ||
| 176 | 0x26, /* [066] -16.5 dB: AKM[038] = -16.535 dB (diff=0.03513 dB) */ | ||
| 177 | 0x28, /* [067] -16.0 dB: AKM[040] = -16.090 dB (diff=0.08960 dB) */ | ||
| 178 | 0x2b, /* [068] -15.5 dB: AKM[043] = -15.461 dB (diff=0.03857 dB) */ | ||
| 179 | 0x2d, /* [069] -15.0 dB: AKM[045] = -15.067 dB (diff=0.06655 dB) */ | ||
| 180 | 0x30, /* [070] -14.5 dB: AKM[048] = -14.506 dB (diff=0.00598 dB) */ | ||
| 181 | 0x33, /* [071] -14.0 dB: AKM[051] = -13.979 dB (diff=0.02060 dB) */ | ||
| 182 | 0x36, /* [072] -13.5 dB: AKM[054] = -13.483 dB (diff=0.01707 dB) */ | ||
| 183 | 0x39, /* [073] -13.0 dB: AKM[057] = -13.013 dB (diff=0.01331 dB) */ | ||
| 184 | 0x3c, /* [074] -12.5 dB: AKM[060] = -12.568 dB (diff=0.06778 dB) */ | ||
| 185 | 0x40, /* [075] -12.0 dB: AKM[064] = -12.007 dB (diff=0.00720 dB) */ | ||
| 186 | 0x44, /* [076] -11.5 dB: AKM[068] = -11.481 dB (diff=0.01937 dB) */ | ||
| 187 | 0x48, /* [077] -11.0 dB: AKM[072] = -10.984 dB (diff=0.01585 dB) */ | ||
| 188 | 0x4c, /* [078] -10.5 dB: AKM[076] = -10.515 dB (diff=0.01453 dB) */ | ||
| 189 | 0x51, /* [079] -10.0 dB: AKM[081] = -9.961 dB (diff=0.03890 dB) */ | ||
| 190 | 0x55, /* [080] -9.5 dB: AKM[085] = -9.542 dB (diff=0.04243 dB) */ | ||
| 191 | 0x5a, /* [081] -9.0 dB: AKM[090] = -9.046 dB (diff=0.04595 dB) */ | ||
| 192 | 0x60, /* [082] -8.5 dB: AKM[096] = -8.485 dB (diff=0.01462 dB) */ | ||
| 193 | 0x66, /* [083] -8.0 dB: AKM[102] = -7.959 dB (diff=0.04120 dB) */ | ||
| 194 | 0x6c, /* [084] -7.5 dB: AKM[108] = -7.462 dB (diff=0.03767 dB) */ | ||
| 195 | 0x72, /* [085] -7.0 dB: AKM[114] = -6.993 dB (diff=0.00729 dB) */ | ||
| 196 | 0x79, /* [086] -6.5 dB: AKM[121] = -6.475 dB (diff=0.02490 dB) */ | ||
| 197 | 0x80, /* [087] -6.0 dB: AKM[128] = -5.987 dB (diff=0.01340 dB) */ | ||
| 198 | 0x87, /* [088] -5.5 dB: AKM[135] = -5.524 dB (diff=0.02413 dB) */ | ||
| 199 | 0x8f, /* [089] -5.0 dB: AKM[143] = -5.024 dB (diff=0.02408 dB) */ | ||
| 200 | 0x98, /* [090] -4.5 dB: AKM[152] = -4.494 dB (diff=0.00607 dB) */ | ||
| 201 | 0xa1, /* [091] -4.0 dB: AKM[161] = -3.994 dB (diff=0.00571 dB) */ | ||
| 202 | 0xaa, /* [092] -3.5 dB: AKM[170] = -3.522 dB (diff=0.02183 dB) */ | ||
| 203 | 0xb5, /* [093] -3.0 dB: AKM[181] = -2.977 dB (diff=0.02277 dB) */ | ||
| 204 | 0xbf, /* [094] -2.5 dB: AKM[191] = -2.510 dB (diff=0.01014 dB) */ | ||
| 205 | 0xcb, /* [095] -2.0 dB: AKM[203] = -1.981 dB (diff=0.01912 dB) */ | ||
| 206 | 0xd7, /* [096] -1.5 dB: AKM[215] = -1.482 dB (diff=0.01797 dB) */ | ||
| 207 | 0xe3, /* [097] -1.0 dB: AKM[227] = -1.010 dB (diff=0.01029 dB) */ | ||
| 208 | 0xf1, /* [098] -0.5 dB: AKM[241] = -0.490 dB (diff=0.00954 dB) */ | ||
| 209 | 0xff, /* [099] +0.0 dB: AKM[255] = +0.000 dB (diff=0.00000 dB) */ | ||
| 210 | }; | ||
| 211 | |||
| 212 | |||
| 213 | static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data) | ||
| 214 | { | ||
| 215 | unsigned short mask = 0x8000; | ||
| 216 | /* activate access to codec registers */ | ||
| 217 | PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ); | ||
| 218 | |||
| 219 | while (mask) { | ||
| 220 | PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, | ||
| 221 | data & mask ? PCXHR_DATA_CODEC : 0); | ||
| 222 | mask >>= 1; | ||
| 223 | } | ||
| 224 | /* termiate access to codec registers */ | ||
| 225 | PCXHR_INPB(mgr, PCXHR_XLX_RUER); | ||
| 226 | } | ||
| 227 | |||
| 228 | |||
| 229 | static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr, | ||
| 230 | int idx, int level) | ||
| 231 | { | ||
| 232 | unsigned short cmd; | ||
| 233 | if (idx > 1 || | ||
| 234 | level < 0 || | ||
| 235 | level >= ARRAY_SIZE(g_hr222_p_level)) | ||
| 236 | return -EINVAL; | ||
| 237 | |||
| 238 | if (idx == 0) | ||
| 239 | cmd = AKM_LEFT_LEVEL_CMD; | ||
| 240 | else | ||
| 241 | cmd = AKM_RIGHT_LEVEL_CMD; | ||
| 242 | |||
| 243 | /* conversion from PmBoardCodedLevel to AKM nonlinear programming */ | ||
| 244 | cmd += g_hr222_p_level[level]; | ||
| 245 | |||
| 246 | hr222_config_akm(mgr, cmd); | ||
| 247 | return 0; | ||
| 248 | } | ||
| 249 | |||
| 250 | |||
| 251 | static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr, | ||
| 252 | int level_l, int level_r, int level_mic) | ||
| 253 | { | ||
| 254 | /* program all input levels at the same time */ | ||
| 255 | unsigned int data; | ||
| 256 | int i; | ||
| 257 | |||
| 258 | if (!mgr->capture_chips) | ||
| 259 | return -EINVAL; /* no PCX22 */ | ||
| 260 | |||
| 261 | data = ((level_mic & 0xff) << 24); /* micro is mono, but apply */ | ||
| 262 | data |= ((level_mic & 0xff) << 16); /* level on both channels */ | ||
| 263 | data |= ((level_r & 0xff) << 8); /* line input right channel */ | ||
| 264 | data |= (level_l & 0xff); /* line input left channel */ | ||
| 265 | |||
| 266 | PCXHR_INPB(mgr, PCXHR_XLX_DATA); /* activate input codec */ | ||
| 267 | /* send 32 bits (4 x 8 bits) */ | ||
| 268 | for (i = 0; i < 32; i++, data <<= 1) { | ||
| 269 | PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, | ||
| 270 | (data & 0x80000000) ? PCXHR_DATA_CODEC : 0); | ||
| 271 | } | ||
| 272 | PCXHR_INPB(mgr, PCXHR_XLX_RUER); /* close input level codec */ | ||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | |||
| 276 | static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level); | ||
| 277 | |||
| 278 | int hr222_sub_init(struct pcxhr_mgr *mgr) | ||
| 279 | { | ||
| 280 | unsigned char reg; | ||
| 281 | |||
| 282 | mgr->board_has_analog = 1; /* analog always available */ | ||
| 283 | mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK; | ||
| 284 | |||
| 285 | reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); | ||
| 286 | if (reg & PCXHR_STAT_MIC_CAPS) | ||
| 287 | mgr->board_has_mic = 1; /* microphone available */ | ||
| 288 | snd_printdd("MIC input available = %d\n", mgr->board_has_mic); | ||
| 289 | |||
| 290 | /* reset codec */ | ||
| 291 | PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, | ||
| 292 | PCXHR_DSP_RESET_DSP); | ||
| 293 | msleep(5); | ||
| 294 | PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, | ||
| 295 | PCXHR_DSP_RESET_DSP | | ||
| 296 | PCXHR_DSP_RESET_MUTE | | ||
| 297 | PCXHR_DSP_RESET_CODEC); | ||
| 298 | msleep(5); | ||
| 299 | |||
| 300 | /* config AKM */ | ||
| 301 | hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD); | ||
| 302 | hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); | ||
| 303 | hr222_config_akm(mgr, AKM_UNMUTE_CMD); | ||
| 304 | hr222_config_akm(mgr, AKM_RESET_OFF_CMD); | ||
| 305 | |||
| 306 | /* init micro boost */ | ||
| 307 | hr222_micro_boost(mgr, 0); | ||
| 308 | |||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | |||
| 313 | /* calc PLL register */ | ||
| 314 | /* TODO : there is a very similar fct in pcxhr.c */ | ||
| 315 | static int hr222_pll_freq_register(unsigned int freq, | ||
| 316 | unsigned int *pllreg, | ||
| 317 | unsigned int *realfreq) | ||
| 318 | { | ||
| 319 | unsigned int reg; | ||
| 320 | |||
| 321 | if (freq < 6900 || freq > 219000) | ||
| 322 | return -EINVAL; | ||
| 323 | reg = (28224000 * 2) / freq; | ||
| 324 | reg = (reg - 1) / 2; | ||
| 325 | if (reg < 0x100) | ||
| 326 | *pllreg = reg + 0xC00; | ||
| 327 | else if (reg < 0x200) | ||
| 328 | *pllreg = reg + 0x800; | ||
| 329 | else if (reg < 0x400) | ||
| 330 | *pllreg = reg & 0x1ff; | ||
| 331 | else if (reg < 0x800) { | ||
| 332 | *pllreg = ((reg >> 1) & 0x1ff) + 0x200; | ||
| 333 | reg &= ~1; | ||
| 334 | } else { | ||
| 335 | *pllreg = ((reg >> 2) & 0x1ff) + 0x400; | ||
| 336 | reg &= ~3; | ||
| 337 | } | ||
| 338 | if (realfreq) | ||
| 339 | *realfreq = (28224000 / (reg + 1)); | ||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | int hr222_sub_set_clock(struct pcxhr_mgr *mgr, | ||
| 344 | unsigned int rate, | ||
| 345 | int *changed) | ||
| 346 | { | ||
| 347 | unsigned int speed, pllreg = 0; | ||
| 348 | int err; | ||
| 349 | unsigned realfreq = rate; | ||
| 350 | |||
| 351 | switch (mgr->use_clock_type) { | ||
| 352 | case HR22_CLOCK_TYPE_INTERNAL: | ||
| 353 | err = hr222_pll_freq_register(rate, &pllreg, &realfreq); | ||
| 354 | if (err) | ||
| 355 | return err; | ||
| 356 | |||
| 357 | mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK | | ||
| 358 | PCXHR_CFG_CLOCK_UER1_SEL_MASK); | ||
| 359 | break; | ||
| 360 | case HR22_CLOCK_TYPE_AES_SYNC: | ||
| 361 | mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK; | ||
| 362 | mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK; | ||
| 363 | break; | ||
| 364 | case HR22_CLOCK_TYPE_AES_1: | ||
| 365 | if (!mgr->board_has_aes1) | ||
| 366 | return -EINVAL; | ||
| 367 | |||
| 368 | mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK | | ||
| 369 | PCXHR_CFG_CLOCK_UER1_SEL_MASK); | ||
| 370 | break; | ||
| 371 | default: | ||
| 372 | return -EINVAL; | ||
| 373 | } | ||
| 374 | hr222_config_akm(mgr, AKM_MUTE_CMD); | ||
| 375 | |||
| 376 | if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) { | ||
| 377 | PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8); | ||
| 378 | PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff); | ||
| 379 | } | ||
| 380 | |||
| 381 | /* set clock source */ | ||
| 382 | PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg); | ||
| 383 | |||
| 384 | /* codec speed modes */ | ||
| 385 | speed = rate < 55000 ? 0 : 1; | ||
| 386 | if (mgr->codec_speed != speed) { | ||
| 387 | mgr->codec_speed = speed; | ||
| 388 | if (speed == 0) | ||
| 389 | hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); | ||
| 390 | else | ||
| 391 | hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD); | ||
| 392 | } | ||
| 393 | |||
| 394 | mgr->sample_rate_real = realfreq; | ||
| 395 | mgr->cur_clock_type = mgr->use_clock_type; | ||
| 396 | |||
| 397 | if (changed) | ||
| 398 | *changed = 1; | ||
| 399 | |||
| 400 | hr222_config_akm(mgr, AKM_UNMUTE_CMD); | ||
| 401 | |||
| 402 | snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n", | ||
| 403 | rate, realfreq, pllreg); | ||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 407 | int hr222_get_external_clock(struct pcxhr_mgr *mgr, | ||
| 408 | enum pcxhr_clock_type clock_type, | ||
| 409 | int *sample_rate) | ||
| 410 | { | ||
| 411 | int rate, calc_rate = 0; | ||
| 412 | unsigned int ticks; | ||
| 413 | unsigned char mask, reg; | ||
| 414 | |||
| 415 | if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) { | ||
| 416 | |||
| 417 | mask = (PCXHR_SUER_CLOCK_PRESENT_MASK | | ||
| 418 | PCXHR_SUER_DATA_PRESENT_MASK); | ||
| 419 | reg = PCXHR_STAT_FREQ_SYNC_MASK; | ||
| 420 | |||
| 421 | } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) { | ||
| 422 | |||
| 423 | mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK | | ||
| 424 | PCXHR_SUER1_DATA_PRESENT_MASK); | ||
| 425 | reg = PCXHR_STAT_FREQ_UER1_MASK; | ||
| 426 | |||
| 427 | } else { | ||
| 428 | snd_printdd("get_external_clock : type %d not supported\n", | ||
| 429 | clock_type); | ||
| 430 | return -EINVAL; /* other clocks not supported */ | ||
| 431 | } | ||
| 432 | |||
| 433 | if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) { | ||
| 434 | snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type); | ||
| 435 | *sample_rate = 0; | ||
| 436 | return 0; /* no external clock locked */ | ||
| 437 | } | ||
| 438 | |||
| 439 | PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */ | ||
| 440 | |||
| 441 | /* save the measured clock frequency */ | ||
| 442 | reg |= PCXHR_STAT_FREQ_SAVE_MASK; | ||
| 443 | |||
| 444 | if (mgr->last_reg_stat != reg) { | ||
| 445 | udelay(500); /* wait min 2 cycles of lowest freq (8000) */ | ||
| 446 | mgr->last_reg_stat = reg; | ||
| 447 | } | ||
| 448 | |||
| 449 | PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */ | ||
| 450 | |||
| 451 | /* get the frequency */ | ||
| 452 | ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG); | ||
| 453 | ticks = (ticks & 0x03) << 8; | ||
| 454 | ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET); | ||
| 455 | |||
| 456 | if (ticks != 0) | ||
| 457 | calc_rate = 28224000 / ticks; | ||
| 458 | /* rounding */ | ||
| 459 | if (calc_rate > 184200) | ||
| 460 | rate = 192000; | ||
| 461 | else if (calc_rate > 152200) | ||
| 462 | rate = 176400; | ||
| 463 | else if (calc_rate > 112000) | ||
| 464 | rate = 128000; | ||
| 465 | else if (calc_rate > 92100) | ||
| 466 | rate = 96000; | ||
| 467 | else if (calc_rate > 76100) | ||
| 468 | rate = 88200; | ||
| 469 | else if (calc_rate > 56000) | ||
| 470 | rate = 64000; | ||
| 471 | else if (calc_rate > 46050) | ||
| 472 | rate = 48000; | ||
| 473 | else if (calc_rate > 38050) | ||
| 474 | rate = 44100; | ||
| 475 | else if (calc_rate > 28000) | ||
| 476 | rate = 32000; | ||
| 477 | else if (calc_rate > 23025) | ||
| 478 | rate = 24000; | ||
| 479 | else if (calc_rate > 19025) | ||
| 480 | rate = 22050; | ||
| 481 | else if (calc_rate > 14000) | ||
| 482 | rate = 16000; | ||
| 483 | else if (calc_rate > 11512) | ||
| 484 | rate = 12000; | ||
| 485 | else if (calc_rate > 9512) | ||
| 486 | rate = 11025; | ||
| 487 | else if (calc_rate > 7000) | ||
| 488 | rate = 8000; | ||
| 489 | else | ||
| 490 | rate = 0; | ||
| 491 | |||
| 492 | snd_printdd("External clock is at %d Hz (measured %d Hz)\n", | ||
| 493 | rate, calc_rate); | ||
| 494 | *sample_rate = rate; | ||
| 495 | return 0; | ||
| 496 | } | ||
| 497 | |||
| 498 | |||
| 499 | int hr222_update_analog_audio_level(struct snd_pcxhr *chip, | ||
| 500 | int is_capture, int channel) | ||
| 501 | { | ||
| 502 | snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n", | ||
| 503 | is_capture ? "capture" : "playback", channel); | ||
| 504 | if (is_capture) { | ||
| 505 | int level_l, level_r, level_mic; | ||
| 506 | /* we have to update all levels */ | ||
| 507 | if (chip->analog_capture_active) { | ||
| 508 | level_l = chip->analog_capture_volume[0]; | ||
| 509 | level_r = chip->analog_capture_volume[1]; | ||
| 510 | } else { | ||
| 511 | level_l = HR222_LINE_CAPTURE_LEVEL_MIN; | ||
| 512 | level_r = HR222_LINE_CAPTURE_LEVEL_MIN; | ||
| 513 | } | ||
| 514 | if (chip->mic_active) | ||
| 515 | level_mic = chip->mic_volume; | ||
| 516 | else | ||
| 517 | level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN; | ||
| 518 | return hr222_set_hw_capture_level(chip->mgr, | ||
| 519 | level_l, level_r, level_mic); | ||
| 520 | } else { | ||
| 521 | int vol; | ||
| 522 | if (chip->analog_playback_active[channel]) | ||
| 523 | vol = chip->analog_playback_volume[channel]; | ||
| 524 | else | ||
| 525 | vol = HR222_LINE_PLAYBACK_LEVEL_MIN; | ||
| 526 | return hr222_set_hw_playback_level(chip->mgr, channel, vol); | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | |||
| 531 | /*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/ | ||
| 532 | #define SOURCE_LINE 0 | ||
| 533 | #define SOURCE_DIGITAL 1 | ||
| 534 | #define SOURCE_DIGISRC 2 | ||
| 535 | #define SOURCE_MIC 3 | ||
| 536 | #define SOURCE_LINEMIC 4 | ||
| 537 | |||
| 538 | int hr222_set_audio_source(struct snd_pcxhr *chip) | ||
| 539 | { | ||
| 540 | int digital = 0; | ||
| 541 | /* default analog source */ | ||
| 542 | chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK | | ||
| 543 | PCXHR_CFG_DATAIN_SEL_MASK | | ||
| 544 | PCXHR_CFG_DATA_UER1_SEL_MASK); | ||
| 545 | |||
| 546 | if (chip->audio_capture_source == SOURCE_DIGISRC) { | ||
| 547 | chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK; | ||
| 548 | digital = 1; | ||
| 549 | } else { | ||
| 550 | if (chip->audio_capture_source == SOURCE_DIGITAL) | ||
| 551 | digital = 1; | ||
| 552 | } | ||
| 553 | if (digital) { | ||
| 554 | chip->mgr->xlx_cfg |= PCXHR_CFG_DATAIN_SEL_MASK; | ||
| 555 | if (chip->mgr->board_has_aes1) { | ||
| 556 | /* get data from the AES1 plug */ | ||
| 557 | chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK; | ||
| 558 | } | ||
| 559 | /* chip->mic_active = 0; */ | ||
| 560 | /* chip->analog_capture_active = 0; */ | ||
| 561 | } else { | ||
| 562 | int update_lvl = 0; | ||
| 563 | chip->analog_capture_active = 0; | ||
| 564 | chip->mic_active = 0; | ||
| 565 | if (chip->audio_capture_source == SOURCE_LINE || | ||
| 566 | chip->audio_capture_source == SOURCE_LINEMIC) { | ||
| 567 | if (chip->analog_capture_active == 0) | ||
| 568 | update_lvl = 1; | ||
| 569 | chip->analog_capture_active = 1; | ||
| 570 | } | ||
| 571 | if (chip->audio_capture_source == SOURCE_MIC || | ||
| 572 | chip->audio_capture_source == SOURCE_LINEMIC) { | ||
| 573 | if (chip->mic_active == 0) | ||
| 574 | update_lvl = 1; | ||
| 575 | chip->mic_active = 1; | ||
| 576 | } | ||
| 577 | if (update_lvl) { | ||
| 578 | /* capture: update all 3 mutes/unmutes with one call */ | ||
| 579 | hr222_update_analog_audio_level(chip, 1, 0); | ||
| 580 | } | ||
| 581 | } | ||
| 582 | /* set the source infos (max 3 bits modified) */ | ||
| 583 | PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg); | ||
| 584 | return 0; | ||
| 585 | } | ||
| 586 | |||
| 587 | |||
| 588 | int hr222_iec958_capture_byte(struct snd_pcxhr *chip, | ||
| 589 | int aes_idx, unsigned char *aes_bits) | ||
| 590 | { | ||
| 591 | unsigned char idx = (unsigned char)(aes_idx * 8); | ||
| 592 | unsigned char temp = 0; | ||
| 593 | unsigned char mask = chip->mgr->board_has_aes1 ? | ||
| 594 | PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK; | ||
| 595 | int i; | ||
| 596 | for (i = 0; i < 8; i++) { | ||
| 597 | PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */ | ||
| 598 | temp <<= 1; | ||
| 599 | if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask) | ||
| 600 | temp |= 1; | ||
| 601 | } | ||
| 602 | snd_printdd("read iec958 AES %d byte %d = 0x%x\n", | ||
| 603 | chip->chip_idx, aes_idx, temp); | ||
| 604 | *aes_bits = temp; | ||
| 605 | return 0; | ||
| 606 | } | ||
| 607 | |||
| 608 | |||
| 609 | int hr222_iec958_update_byte(struct snd_pcxhr *chip, | ||
| 610 | int aes_idx, unsigned char aes_bits) | ||
| 611 | { | ||
| 612 | int i; | ||
| 613 | unsigned char new_bits = aes_bits; | ||
| 614 | unsigned char old_bits = chip->aes_bits[aes_idx]; | ||
| 615 | unsigned char idx = (unsigned char)(aes_idx * 8); | ||
| 616 | for (i = 0; i < 8; i++) { | ||
| 617 | if ((old_bits & 0x01) != (new_bits & 0x01)) { | ||
| 618 | /* idx < 192 */ | ||
| 619 | PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx); | ||
| 620 | /* write C and U bit */ | ||
| 621 | PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ? | ||
| 622 | PCXHR_SUER_BIT_C_WRITE_MASK : 0); | ||
| 623 | } | ||
| 624 | idx++; | ||
| 625 | old_bits >>= 1; | ||
| 626 | new_bits >>= 1; | ||
| 627 | } | ||
| 628 | chip->aes_bits[aes_idx] = aes_bits; | ||
| 629 | return 0; | ||
| 630 | } | ||
| 631 | |||
| 632 | static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level) | ||
| 633 | { | ||
| 634 | unsigned char boost_mask; | ||
| 635 | boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET); | ||
| 636 | if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK)) | ||
| 637 | return; /* only values form 0 to 3 accepted */ | ||
| 638 | |||
| 639 | mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK; | ||
| 640 | mgr->xlx_selmic |= boost_mask; | ||
| 641 | |||
| 642 | PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); | ||
| 643 | |||
| 644 | snd_printdd("hr222_micro_boost : set %x\n", boost_mask); | ||
| 645 | } | ||
| 646 | |||
| 647 | static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power) | ||
| 648 | { | ||
| 649 | if (power) | ||
| 650 | mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM; | ||
| 651 | else | ||
| 652 | mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM; | ||
| 653 | |||
| 654 | PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); | ||
| 655 | |||
| 656 | snd_printdd("hr222_phantom_power : set %d\n", power); | ||
| 657 | } | ||
| 658 | |||
| 659 | |||
| 660 | /* mic level */ | ||
| 661 | static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650); | ||
| 662 | |||
| 663 | static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol, | ||
| 664 | struct snd_ctl_elem_info *uinfo) | ||
| 665 | { | ||
| 666 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 667 | uinfo->count = 1; | ||
| 668 | uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */ | ||
| 669 | /* gains from 9 dB to 31.5 dB not recommended; use micboost instead */ | ||
| 670 | uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /* +7 dB */ | ||
| 671 | return 0; | ||
| 672 | } | ||
| 673 | |||
| 674 | static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol, | ||
| 675 | struct snd_ctl_elem_value *ucontrol) | ||
| 676 | { | ||
| 677 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
| 678 | mutex_lock(&chip->mgr->mixer_mutex); | ||
| 679 | ucontrol->value.integer.value[0] = chip->mic_volume; | ||
| 680 | mutex_unlock(&chip->mgr->mixer_mutex); | ||
| 681 | return 0; | ||
| 682 | } | ||
| 683 | |||
| 684 | static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol, | ||
| 685 | struct snd_ctl_elem_value *ucontrol) | ||
| 686 | { | ||
| 687 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
| 688 | int changed = 0; | ||
| 689 | mutex_lock(&chip->mgr->mixer_mutex); | ||
| 690 | if (chip->mic_volume != ucontrol->value.integer.value[0]) { | ||
| 691 | changed = 1; | ||
| 692 | chip->mic_volume = ucontrol->value.integer.value[0]; | ||
| 693 | hr222_update_analog_audio_level(chip, 1, 0); | ||
| 694 | } | ||
| 695 | mutex_unlock(&chip->mgr->mixer_mutex); | ||
| 696 | return changed; | ||
| 697 | } | ||
| 698 | |||
| 699 | static struct snd_kcontrol_new hr222_control_mic_level = { | ||
| 700 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 701 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 702 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
| 703 | .name = "Mic Capture Volume", | ||
| 704 | .info = hr222_mic_vol_info, | ||
| 705 | .get = hr222_mic_vol_get, | ||
| 706 | .put = hr222_mic_vol_put, | ||
| 707 | .tlv = { .p = db_scale_mic_hr222 }, | ||
| 708 | }; | ||
| 709 | |||
| 710 | |||
| 711 | /* mic boost level */ | ||
| 712 | static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400); | ||
| 713 | |||
| 714 | static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol, | ||
| 715 | struct snd_ctl_elem_info *uinfo) | ||
| 716 | { | ||
| 717 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 718 | uinfo->count = 1; | ||
| 719 | uinfo->value.integer.min = 0; /* 0 dB */ | ||
| 720 | uinfo->value.integer.max = 3; /* 54 dB */ | ||
| 721 | return 0; | ||
| 722 | } | ||
| 723 | |||
| 724 | static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol, | ||
| 725 | struct snd_ctl_elem_value *ucontrol) | ||
| 726 | { | ||
| 727 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
| 728 | mutex_lock(&chip->mgr->mixer_mutex); | ||
| 729 | ucontrol->value.integer.value[0] = chip->mic_boost; | ||
| 730 | mutex_unlock(&chip->mgr->mixer_mutex); | ||
| 731 | return 0; | ||
| 732 | } | ||
| 733 | |||
| 734 | static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol, | ||
| 735 | struct snd_ctl_elem_value *ucontrol) | ||
| 736 | { | ||
| 737 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
| 738 | int changed = 0; | ||
| 739 | mutex_lock(&chip->mgr->mixer_mutex); | ||
| 740 | if (chip->mic_boost != ucontrol->value.integer.value[0]) { | ||
| 741 | changed = 1; | ||
| 742 | chip->mic_boost = ucontrol->value.integer.value[0]; | ||
| 743 | hr222_micro_boost(chip->mgr, chip->mic_boost); | ||
| 744 | } | ||
| 745 | mutex_unlock(&chip->mgr->mixer_mutex); | ||
| 746 | return changed; | ||
| 747 | } | ||
| 748 | |||
| 749 | static struct snd_kcontrol_new hr222_control_mic_boost = { | ||
| 750 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 751 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 752 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
| 753 | .name = "MicBoost Capture Volume", | ||
| 754 | .info = hr222_mic_boost_info, | ||
| 755 | .get = hr222_mic_boost_get, | ||
| 756 | .put = hr222_mic_boost_put, | ||
| 757 | .tlv = { .p = db_scale_micboost_hr222 }, | ||
| 758 | }; | ||
| 759 | |||
| 760 | |||
| 761 | /******************* Phantom power switch *******************/ | ||
| 762 | #define hr222_phantom_power_info snd_ctl_boolean_mono_info | ||
| 763 | |||
| 764 | static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol, | ||
| 765 | struct snd_ctl_elem_value *ucontrol) | ||
| 766 | { | ||
| 767 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
| 768 | mutex_lock(&chip->mgr->mixer_mutex); | ||
| 769 | ucontrol->value.integer.value[0] = chip->phantom_power; | ||
| 770 | mutex_unlock(&chip->mgr->mixer_mutex); | ||
| 771 | return 0; | ||
| 772 | } | ||
| 773 | |||
| 774 | static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol, | ||
| 775 | struct snd_ctl_elem_value *ucontrol) | ||
| 776 | { | ||
| 777 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
| 778 | int power, changed = 0; | ||
| 779 | |||
| 780 | mutex_lock(&chip->mgr->mixer_mutex); | ||
| 781 | power = !!ucontrol->value.integer.value[0]; | ||
| 782 | if (chip->phantom_power != power) { | ||
| 783 | hr222_phantom_power(chip->mgr, power); | ||
| 784 | chip->phantom_power = power; | ||
| 785 | changed = 1; | ||
| 786 | } | ||
| 787 | mutex_unlock(&chip->mgr->mixer_mutex); | ||
| 788 | return changed; | ||
| 789 | } | ||
| 790 | |||
| 791 | static struct snd_kcontrol_new hr222_phantom_power_switch = { | ||
| 792 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 793 | .name = "Phantom Power Switch", | ||
| 794 | .info = hr222_phantom_power_info, | ||
| 795 | .get = hr222_phantom_power_get, | ||
| 796 | .put = hr222_phantom_power_put, | ||
| 797 | }; | ||
| 798 | |||
| 799 | |||
| 800 | int hr222_add_mic_controls(struct snd_pcxhr *chip) | ||
| 801 | { | ||
| 802 | int err; | ||
| 803 | if (!chip->mgr->board_has_mic) | ||
| 804 | return 0; | ||
| 805 | |||
| 806 | /* controls */ | ||
| 807 | err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level, | ||
| 808 | chip)); | ||
| 809 | if (err < 0) | ||
| 810 | return err; | ||
| 811 | |||
| 812 | err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost, | ||
| 813 | chip)); | ||
| 814 | if (err < 0) | ||
| 815 | return err; | ||
| 816 | |||
| 817 | err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch, | ||
| 818 | chip)); | ||
| 819 | return err; | ||
| 820 | } | ||
diff --git a/sound/pci/pcxhr/pcxhr_mix22.h b/sound/pci/pcxhr/pcxhr_mix22.h new file mode 100644 index 000000000000..6b318b2f0100 --- /dev/null +++ b/sound/pci/pcxhr/pcxhr_mix22.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Digigram pcxhr compatible soundcards | ||
| 3 | * | ||
| 4 | * low level interface with interrupt ans message handling | ||
| 5 | * | ||
| 6 | * Copyright (c) 2004 by Digigram <alsa@digigram.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __SOUND_PCXHR_MIX22_H | ||
| 24 | #define __SOUND_PCXHR_MIX22_H | ||
| 25 | |||
| 26 | struct pcxhr_mgr; | ||
| 27 | |||
| 28 | int hr222_sub_init(struct pcxhr_mgr *mgr); | ||
| 29 | int hr222_sub_set_clock(struct pcxhr_mgr *mgr, unsigned int rate, | ||
| 30 | int *changed); | ||
| 31 | int hr222_get_external_clock(struct pcxhr_mgr *mgr, | ||
| 32 | enum pcxhr_clock_type clock_type, | ||
| 33 | int *sample_rate); | ||
| 34 | |||
| 35 | #define HR222_LINE_PLAYBACK_LEVEL_MIN 0 /* -25.5 dB */ | ||
| 36 | #define HR222_LINE_PLAYBACK_ZERO_LEVEL 51 /* 0.0 dB */ | ||
| 37 | #define HR222_LINE_PLAYBACK_LEVEL_MAX 99 /* +24.0 dB */ | ||
| 38 | |||
| 39 | #define HR222_LINE_CAPTURE_LEVEL_MIN 0 /* -111.5 dB */ | ||
| 40 | #define HR222_LINE_CAPTURE_ZERO_LEVEL 223 /* 0.0 dB */ | ||
| 41 | #define HR222_LINE_CAPTURE_LEVEL_MAX 255 /* +16 dB */ | ||
| 42 | #define HR222_MICRO_CAPTURE_LEVEL_MIN 0 /* -98.5 dB */ | ||
| 43 | #define HR222_MICRO_CAPTURE_LEVEL_MAX 210 /* +6.5 dB */ | ||
| 44 | |||
| 45 | int hr222_update_analog_audio_level(struct snd_pcxhr *chip, | ||
| 46 | int is_capture, | ||
| 47 | int channel); | ||
| 48 | int hr222_set_audio_source(struct snd_pcxhr *chip); | ||
| 49 | int hr222_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, | ||
| 50 | unsigned char *aes_bits); | ||
| 51 | int hr222_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, | ||
| 52 | unsigned char aes_bits); | ||
| 53 | |||
| 54 | int hr222_add_mic_controls(struct snd_pcxhr *chip); | ||
| 55 | |||
| 56 | #endif /* __SOUND_PCXHR_MIX22_H */ | ||
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index aabc7bc5321e..2436e374586f 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c | |||
| @@ -33,20 +33,24 @@ | |||
| 33 | #include <sound/tlv.h> | 33 | #include <sound/tlv.h> |
| 34 | #include <sound/asoundef.h> | 34 | #include <sound/asoundef.h> |
| 35 | #include "pcxhr_mixer.h" | 35 | #include "pcxhr_mixer.h" |
| 36 | #include "pcxhr_mix22.h" | ||
| 36 | 37 | ||
| 38 | #define PCXHR_LINE_CAPTURE_LEVEL_MIN 0 /* -112.0 dB */ | ||
| 39 | #define PCXHR_LINE_CAPTURE_LEVEL_MAX 255 /* +15.5 dB */ | ||
| 40 | #define PCXHR_LINE_CAPTURE_ZERO_LEVEL 224 /* 0.0 dB ( 0 dBu -> 0 dBFS ) */ | ||
| 37 | 41 | ||
| 38 | #define PCXHR_ANALOG_CAPTURE_LEVEL_MIN 0 /* -96.0 dB */ | 42 | #define PCXHR_LINE_PLAYBACK_LEVEL_MIN 0 /* -104.0 dB */ |
| 39 | #define PCXHR_ANALOG_CAPTURE_LEVEL_MAX 255 /* +31.5 dB */ | 43 | #define PCXHR_LINE_PLAYBACK_LEVEL_MAX 128 /* +24.0 dB */ |
| 40 | #define PCXHR_ANALOG_CAPTURE_ZERO_LEVEL 224 /* +16.0 dB ( +31.5 dB - fix level +15.5 dB ) */ | 44 | #define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104 /* 0.0 dB ( 0 dBFS -> 0 dBu ) */ |
| 41 | 45 | ||
| 42 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MIN 0 /* -128.0 dB */ | 46 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550); |
| 43 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ | ||
| 44 | #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ | ||
| 45 | |||
| 46 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 3150); | ||
| 47 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); | 47 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); |
| 48 | 48 | ||
| 49 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) | 49 | static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600); |
| 50 | static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400); | ||
| 51 | |||
| 52 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, | ||
| 53 | int is_capture, int channel) | ||
| 50 | { | 54 | { |
| 51 | int err, vol; | 55 | int err, vol; |
| 52 | struct pcxhr_rmh rmh; | 56 | struct pcxhr_rmh rmh; |
| @@ -60,15 +64,17 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_captur | |||
| 60 | if (chip->analog_playback_active[channel]) | 64 | if (chip->analog_playback_active[channel]) |
| 61 | vol = chip->analog_playback_volume[channel]; | 65 | vol = chip->analog_playback_volume[channel]; |
| 62 | else | 66 | else |
| 63 | vol = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; | 67 | vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN; |
| 64 | rmh.cmd[2] = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX - vol; /* playback analog levels are inversed */ | 68 | /* playback analog levels are inversed */ |
| 69 | rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol; | ||
| 65 | } | 70 | } |
| 66 | rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ | 71 | rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ |
| 67 | rmh.cmd_len = 3; | 72 | rmh.cmd_len = 3; |
| 68 | err = pcxhr_send_msg(chip->mgr, &rmh); | 73 | err = pcxhr_send_msg(chip->mgr, &rmh); |
| 69 | if (err < 0) { | 74 | if (err < 0) { |
| 70 | snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d) " | 75 | snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)" |
| 71 | "is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err); | 76 | " is_capture(%d) err(%x)\n", |
| 77 | chip->chip_idx, is_capture, err); | ||
| 72 | return -EINVAL; | 78 | return -EINVAL; |
| 73 | } | 79 | } |
| 74 | return 0; | 80 | return 0; |
| @@ -80,14 +86,34 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_captur | |||
| 80 | static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, | 86 | static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, |
| 81 | struct snd_ctl_elem_info *uinfo) | 87 | struct snd_ctl_elem_info *uinfo) |
| 82 | { | 88 | { |
| 89 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
| 90 | |||
| 83 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 91 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
| 84 | uinfo->count = 2; | 92 | uinfo->count = 2; |
| 85 | if (kcontrol->private_value == 0) { /* playback */ | 93 | if (kcontrol->private_value == 0) { /* playback */ |
| 86 | uinfo->value.integer.min = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; /* -128 dB */ | 94 | if (chip->mgr->is_hr_stereo) { |
| 87 | uinfo->value.integer.max = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX; /* 0 dB */ | 95 | uinfo->value.integer.min = |
| 96 | HR222_LINE_PLAYBACK_LEVEL_MIN; /* -25 dB */ | ||
| 97 | uinfo->value.integer.max = | ||
| 98 | HR222_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ | ||
| 99 | } else { | ||
| 100 | uinfo->value.integer.min = | ||
| 101 | PCXHR_LINE_PLAYBACK_LEVEL_MIN; /*-104 dB */ | ||
| 102 | uinfo->value.integer.max = | ||
| 103 | PCXHR_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ | ||
| 104 | } | ||
| 88 | } else { /* capture */ | 105 | } else { /* capture */ |
| 89 | uinfo->value.integer.min = PCXHR_ANALOG_CAPTURE_LEVEL_MIN; /* -96 dB */ | 106 | if (chip->mgr->is_hr_stereo) { |
| 90 | uinfo->value.integer.max = PCXHR_ANALOG_CAPTURE_LEVEL_MAX; /* 31.5 dB */ | 107 | uinfo->value.integer.min = |
| 108 | HR222_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ | ||
| 109 | uinfo->value.integer.max = | ||
| 110 | HR222_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ | ||
| 111 | } else { | ||
| 112 | uinfo->value.integer.min = | ||
| 113 | PCXHR_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ | ||
| 114 | uinfo->value.integer.max = | ||
| 115 | PCXHR_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ | ||
| 116 | } | ||
| 91 | } | 117 | } |
| 92 | return 0; | 118 | return 0; |
| 93 | } | 119 | } |
| @@ -98,11 +124,11 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, | |||
| 98 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | 124 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
| 99 | mutex_lock(&chip->mgr->mixer_mutex); | 125 | mutex_lock(&chip->mgr->mixer_mutex); |
| 100 | if (kcontrol->private_value == 0) { /* playback */ | 126 | if (kcontrol->private_value == 0) { /* playback */ |
| 101 | ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; | 127 | ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; |
| 102 | ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; | 128 | ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; |
| 103 | } else { /* capture */ | 129 | } else { /* capture */ |
| 104 | ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; | 130 | ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; |
| 105 | ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; | 131 | ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; |
| 106 | } | 132 | } |
| 107 | mutex_unlock(&chip->mgr->mixer_mutex); | 133 | mutex_unlock(&chip->mgr->mixer_mutex); |
| 108 | return 0; | 134 | return 0; |
| @@ -123,18 +149,35 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, | |||
| 123 | &chip->analog_capture_volume[i] : | 149 | &chip->analog_capture_volume[i] : |
| 124 | &chip->analog_playback_volume[i]; | 150 | &chip->analog_playback_volume[i]; |
| 125 | if (is_capture) { | 151 | if (is_capture) { |
| 126 | if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN || | 152 | if (chip->mgr->is_hr_stereo) { |
| 127 | new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX) | 153 | if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN || |
| 128 | continue; | 154 | new_volume > HR222_LINE_CAPTURE_LEVEL_MAX) |
| 155 | continue; | ||
| 156 | } else { | ||
| 157 | if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN || | ||
| 158 | new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX) | ||
| 159 | continue; | ||
| 160 | } | ||
| 129 | } else { | 161 | } else { |
| 130 | if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN || | 162 | if (chip->mgr->is_hr_stereo) { |
| 131 | new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX) | 163 | if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN || |
| 132 | continue; | 164 | new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX) |
| 165 | continue; | ||
| 166 | } else { | ||
| 167 | if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN || | ||
| 168 | new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX) | ||
| 169 | continue; | ||
| 170 | } | ||
| 133 | } | 171 | } |
| 134 | if (*stored_volume != new_volume) { | 172 | if (*stored_volume != new_volume) { |
| 135 | *stored_volume = new_volume; | 173 | *stored_volume = new_volume; |
| 136 | changed = 1; | 174 | changed = 1; |
| 137 | pcxhr_update_analog_audio_level(chip, is_capture, i); | 175 | if (chip->mgr->is_hr_stereo) |
| 176 | hr222_update_analog_audio_level(chip, | ||
| 177 | is_capture, i); | ||
| 178 | else | ||
| 179 | pcxhr_update_analog_audio_level(chip, | ||
| 180 | is_capture, i); | ||
| 138 | } | 181 | } |
| 139 | } | 182 | } |
| 140 | mutex_unlock(&chip->mgr->mixer_mutex); | 183 | mutex_unlock(&chip->mgr->mixer_mutex); |
| @@ -153,6 +196,7 @@ static struct snd_kcontrol_new pcxhr_control_analog_level = { | |||
| 153 | }; | 196 | }; |
| 154 | 197 | ||
| 155 | /* shared */ | 198 | /* shared */ |
| 199 | |||
| 156 | #define pcxhr_sw_info snd_ctl_boolean_stereo_info | 200 | #define pcxhr_sw_info snd_ctl_boolean_stereo_info |
| 157 | 201 | ||
| 158 | static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, | 202 | static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, |
| @@ -180,7 +224,10 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, | |||
| 180 | !!ucontrol->value.integer.value[i]; | 224 | !!ucontrol->value.integer.value[i]; |
| 181 | changed = 1; | 225 | changed = 1; |
| 182 | /* update playback levels */ | 226 | /* update playback levels */ |
| 183 | pcxhr_update_analog_audio_level(chip, 0, i); | 227 | if (chip->mgr->is_hr_stereo) |
| 228 | hr222_update_analog_audio_level(chip, 0, i); | ||
| 229 | else | ||
| 230 | pcxhr_update_analog_audio_level(chip, 0, i); | ||
| 184 | } | 231 | } |
| 185 | } | 232 | } |
| 186 | mutex_unlock(&chip->mgr->mixer_mutex); | 233 | mutex_unlock(&chip->mgr->mixer_mutex); |
| @@ -251,7 +298,8 @@ static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) | |||
| 251 | #define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 | 298 | #define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 |
| 252 | #define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 | 299 | #define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 |
| 253 | 300 | ||
| 254 | static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, int channel) | 301 | static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, |
| 302 | int capture, int channel) | ||
| 255 | { | 303 | { |
| 256 | int err; | 304 | int err; |
| 257 | struct pcxhr_rmh rmh; | 305 | struct pcxhr_rmh rmh; |
| @@ -264,18 +312,20 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, in | |||
| 264 | 312 | ||
| 265 | pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); | 313 | pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); |
| 266 | /* add channel mask */ | 314 | /* add channel mask */ |
| 267 | pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio)); | 315 | pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, |
| 268 | /* TODO : if mask (3 << pipe->first_audio) is used, left and right channel | 316 | 1 << (channel + pipe->first_audio)); |
| 269 | * will be programmed to the same params | 317 | /* TODO : if mask (3 << pipe->first_audio) is used, left and right |
| 270 | */ | 318 | * channel will be programmed to the same params */ |
| 271 | if (capture) { | 319 | if (capture) { |
| 272 | rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; | 320 | rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; |
| 273 | /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled (capture pipe level) */ | 321 | /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled |
| 322 | * (capture pipe level) */ | ||
| 274 | rmh.cmd[2] = chip->digital_capture_volume[channel]; | 323 | rmh.cmd[2] = chip->digital_capture_volume[channel]; |
| 275 | } else { | 324 | } else { |
| 276 | rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1; | 325 | rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | |
| 277 | /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL not yet | 326 | VALID_AUDIO_IO_MUTE_MONITOR_1; |
| 278 | * handled (playback pipe level) | 327 | /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL |
| 328 | * not yet handled (playback pipe level) | ||
| 279 | */ | 329 | */ |
| 280 | rmh.cmd[2] = chip->monitoring_volume[channel] << 10; | 330 | rmh.cmd[2] = chip->monitoring_volume[channel] << 10; |
| 281 | if (chip->monitoring_active[channel] == 0) | 331 | if (chip->monitoring_active[channel] == 0) |
| @@ -284,8 +334,8 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, in | |||
| 284 | rmh.cmd_len = 3; | 334 | rmh.cmd_len = 3; |
| 285 | 335 | ||
| 286 | err = pcxhr_send_msg(chip->mgr, &rmh); | 336 | err = pcxhr_send_msg(chip->mgr, &rmh); |
| 287 | if(err<0) { | 337 | if (err < 0) { |
| 288 | snd_printk(KERN_DEBUG "error update_audio_level card(%d) err(%x)\n", | 338 | snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n", |
| 289 | chip->chip_idx, err); | 339 | chip->chip_idx, err); |
| 290 | return -EINVAL; | 340 | return -EINVAL; |
| 291 | } | 341 | } |
| @@ -309,15 +359,15 @@ static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, | |||
| 309 | struct snd_ctl_elem_value *ucontrol) | 359 | struct snd_ctl_elem_value *ucontrol) |
| 310 | { | 360 | { |
| 311 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | 361 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
| 312 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ | 362 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ |
| 313 | int *stored_volume; | 363 | int *stored_volume; |
| 314 | int is_capture = kcontrol->private_value; | 364 | int is_capture = kcontrol->private_value; |
| 315 | 365 | ||
| 316 | mutex_lock(&chip->mgr->mixer_mutex); | 366 | mutex_lock(&chip->mgr->mixer_mutex); |
| 317 | if (is_capture) | 367 | if (is_capture) /* digital capture */ |
| 318 | stored_volume = chip->digital_capture_volume; /* digital capture */ | 368 | stored_volume = chip->digital_capture_volume; |
| 319 | else | 369 | else /* digital playback */ |
| 320 | stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ | 370 | stored_volume = chip->digital_playback_volume[idx]; |
| 321 | ucontrol->value.integer.value[0] = stored_volume[0]; | 371 | ucontrol->value.integer.value[0] = stored_volume[0]; |
| 322 | ucontrol->value.integer.value[1] = stored_volume[1]; | 372 | ucontrol->value.integer.value[1] = stored_volume[1]; |
| 323 | mutex_unlock(&chip->mgr->mixer_mutex); | 373 | mutex_unlock(&chip->mgr->mixer_mutex); |
| @@ -328,7 +378,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
| 328 | struct snd_ctl_elem_value *ucontrol) | 378 | struct snd_ctl_elem_value *ucontrol) |
| 329 | { | 379 | { |
| 330 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | 380 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
| 331 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ | 381 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ |
| 332 | int changed = 0; | 382 | int changed = 0; |
| 333 | int is_capture = kcontrol->private_value; | 383 | int is_capture = kcontrol->private_value; |
| 334 | int *stored_volume; | 384 | int *stored_volume; |
| @@ -384,7 +434,8 @@ static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, | |||
| 384 | return 0; | 434 | return 0; |
| 385 | } | 435 | } |
| 386 | 436 | ||
| 387 | static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 437 | static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, |
| 438 | struct snd_ctl_elem_value *ucontrol) | ||
| 388 | { | 439 | { |
| 389 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | 440 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
| 390 | int changed = 0; | 441 | int changed = 0; |
| @@ -444,8 +495,8 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, | |||
| 444 | if (chip->monitoring_volume[i] != | 495 | if (chip->monitoring_volume[i] != |
| 445 | ucontrol->value.integer.value[i]) { | 496 | ucontrol->value.integer.value[i]) { |
| 446 | chip->monitoring_volume[i] = | 497 | chip->monitoring_volume[i] = |
| 447 | !!ucontrol->value.integer.value[i]; | 498 | ucontrol->value.integer.value[i]; |
| 448 | if(chip->monitoring_active[i]) | 499 | if (chip->monitoring_active[i]) |
| 449 | /* update monitoring volume and mute */ | 500 | /* update monitoring volume and mute */ |
| 450 | /* do only when monitoring is unmuted */ | 501 | /* do only when monitoring is unmuted */ |
| 451 | pcxhr_update_audio_pipe_level(chip, 0, i); | 502 | pcxhr_update_audio_pipe_level(chip, 0, i); |
| @@ -460,7 +511,7 @@ static struct snd_kcontrol_new pcxhr_control_monitor_vol = { | |||
| 460 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 511 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 461 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | 512 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 462 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | 513 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
| 463 | .name = "Monitoring Volume", | 514 | .name = "Monitoring Playback Volume", |
| 464 | .info = pcxhr_digital_vol_info, /* shared */ | 515 | .info = pcxhr_digital_vol_info, /* shared */ |
| 465 | .get = pcxhr_monitor_vol_get, | 516 | .get = pcxhr_monitor_vol_get, |
| 466 | .put = pcxhr_monitor_vol_put, | 517 | .put = pcxhr_monitor_vol_put, |
| @@ -511,7 +562,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, | |||
| 511 | 562 | ||
| 512 | static struct snd_kcontrol_new pcxhr_control_monitor_sw = { | 563 | static struct snd_kcontrol_new pcxhr_control_monitor_sw = { |
| 513 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 564 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 514 | .name = "Monitoring Switch", | 565 | .name = "Monitoring Playback Switch", |
| 515 | .info = pcxhr_sw_info, /* shared */ | 566 | .info = pcxhr_sw_info, /* shared */ |
| 516 | .get = pcxhr_monitor_sw_get, | 567 | .get = pcxhr_monitor_sw_get, |
| 517 | .put = pcxhr_monitor_sw_put | 568 | .put = pcxhr_monitor_sw_put |
| @@ -533,7 +584,7 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) | |||
| 533 | struct pcxhr_rmh rmh; | 584 | struct pcxhr_rmh rmh; |
| 534 | unsigned int mask, reg; | 585 | unsigned int mask, reg; |
| 535 | unsigned int codec; | 586 | unsigned int codec; |
| 536 | int err, use_src, changed; | 587 | int err, changed; |
| 537 | 588 | ||
| 538 | switch (chip->chip_idx) { | 589 | switch (chip->chip_idx) { |
| 539 | case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; | 590 | case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; |
| @@ -542,13 +593,10 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) | |||
| 542 | case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; | 593 | case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; |
| 543 | default: return -EINVAL; | 594 | default: return -EINVAL; |
| 544 | } | 595 | } |
| 545 | reg = 0; /* audio source from analog plug */ | ||
| 546 | use_src = 0; /* do not activate codec SRC */ | ||
| 547 | |||
| 548 | if (chip->audio_capture_source != 0) { | 596 | if (chip->audio_capture_source != 0) { |
| 549 | reg = mask; /* audio source from digital plug */ | 597 | reg = mask; /* audio source from digital plug */ |
| 550 | if (chip->audio_capture_source == 2) | 598 | } else { |
| 551 | use_src = 1; | 599 | reg = 0; /* audio source from analog plug */ |
| 552 | } | 600 | } |
| 553 | /* set the input source */ | 601 | /* set the input source */ |
| 554 | pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); | 602 | pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); |
| @@ -560,29 +608,61 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) | |||
| 560 | if (err) | 608 | if (err) |
| 561 | return err; | 609 | return err; |
| 562 | } | 610 | } |
| 563 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set codec SRC on off */ | 611 | if (chip->mgr->board_aes_in_192k) { |
| 564 | rmh.cmd_len = 3; | 612 | int i; |
| 565 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; | 613 | unsigned int src_config = 0xC0; |
| 566 | rmh.cmd[1] = codec; | 614 | /* update all src configs with one call */ |
| 567 | rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54); | 615 | for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) { |
| 568 | err = pcxhr_send_msg(chip->mgr, &rmh); | 616 | if (chip->mgr->chip[i]->audio_capture_source == 2) |
| 569 | if(err) | 617 | src_config |= (1 << (3 - i)); |
| 570 | return err; | 618 | } |
| 571 | rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49); | 619 | /* set codec SRC on off */ |
| 572 | err = pcxhr_send_msg(chip->mgr, &rmh); | 620 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); |
| 621 | rmh.cmd_len = 2; | ||
| 622 | rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC; | ||
| 623 | rmh.cmd[1] = src_config; | ||
| 624 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
| 625 | } else { | ||
| 626 | int use_src = 0; | ||
| 627 | if (chip->audio_capture_source == 2) | ||
| 628 | use_src = 1; | ||
| 629 | /* set codec SRC on off */ | ||
| 630 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); | ||
| 631 | rmh.cmd_len = 3; | ||
| 632 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; | ||
| 633 | rmh.cmd[1] = codec; | ||
| 634 | rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | | ||
| 635 | (use_src ? 0x41 : 0x54)); | ||
| 636 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
| 637 | if (err) | ||
| 638 | return err; | ||
| 639 | rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | | ||
| 640 | (use_src ? 0x41 : 0x49)); | ||
| 641 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
| 642 | } | ||
| 573 | return err; | 643 | return err; |
| 574 | } | 644 | } |
| 575 | 645 | ||
| 576 | static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, | 646 | static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, |
| 577 | struct snd_ctl_elem_info *uinfo) | 647 | struct snd_ctl_elem_info *uinfo) |
| 578 | { | 648 | { |
| 579 | static char *texts[3] = {"Analog", "Digital", "Digi+SRC"}; | 649 | static const char *texts[5] = { |
| 650 | "Line", "Digital", "Digi+SRC", "Mic", "Line+Mic" | ||
| 651 | }; | ||
| 652 | int i; | ||
| 653 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
| 580 | 654 | ||
| 655 | i = 2; /* no SRC, no Mic available */ | ||
| 656 | if (chip->mgr->board_has_aes1) { | ||
| 657 | i = 3; /* SRC available */ | ||
| 658 | if (chip->mgr->board_has_mic) | ||
| 659 | i = 5; /* Mic and MicroMix available */ | ||
| 660 | } | ||
| 581 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 661 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
| 582 | uinfo->count = 1; | 662 | uinfo->count = 1; |
| 583 | uinfo->value.enumerated.items = 3; | 663 | uinfo->value.enumerated.items = i; |
| 584 | if (uinfo->value.enumerated.item > 2) | 664 | if (uinfo->value.enumerated.item > (i-1)) |
| 585 | uinfo->value.enumerated.item = 2; | 665 | uinfo->value.enumerated.item = i-1; |
| 586 | strcpy(uinfo->value.enumerated.name, | 666 | strcpy(uinfo->value.enumerated.name, |
| 587 | texts[uinfo->value.enumerated.item]); | 667 | texts[uinfo->value.enumerated.item]); |
| 588 | return 0; | 668 | return 0; |
| @@ -601,13 +681,21 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, | |||
| 601 | { | 681 | { |
| 602 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | 682 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
| 603 | int ret = 0; | 683 | int ret = 0; |
| 604 | 684 | int i = 2; /* no SRC, no Mic available */ | |
| 605 | if (ucontrol->value.enumerated.item[0] >= 3) | 685 | if (chip->mgr->board_has_aes1) { |
| 686 | i = 3; /* SRC available */ | ||
| 687 | if (chip->mgr->board_has_mic) | ||
| 688 | i = 5; /* Mic and MicroMix available */ | ||
| 689 | } | ||
| 690 | if (ucontrol->value.enumerated.item[0] >= i) | ||
| 606 | return -EINVAL; | 691 | return -EINVAL; |
| 607 | mutex_lock(&chip->mgr->mixer_mutex); | 692 | mutex_lock(&chip->mgr->mixer_mutex); |
| 608 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { | 693 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { |
| 609 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; | 694 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; |
| 610 | pcxhr_set_audio_source(chip); | 695 | if (chip->mgr->is_hr_stereo) |
| 696 | hr222_set_audio_source(chip); | ||
| 697 | else | ||
| 698 | pcxhr_set_audio_source(chip); | ||
| 611 | ret = 1; | 699 | ret = 1; |
| 612 | } | 700 | } |
| 613 | mutex_unlock(&chip->mgr->mixer_mutex); | 701 | mutex_unlock(&chip->mgr->mixer_mutex); |
| @@ -626,25 +714,46 @@ static struct snd_kcontrol_new pcxhr_control_audio_src = { | |||
| 626 | /* | 714 | /* |
| 627 | * clock type selection | 715 | * clock type selection |
| 628 | * enum pcxhr_clock_type { | 716 | * enum pcxhr_clock_type { |
| 629 | * PCXHR_CLOCK_TYPE_INTERNAL = 0, | 717 | * PCXHR_CLOCK_TYPE_INTERNAL = 0, |
| 630 | * PCXHR_CLOCK_TYPE_WORD_CLOCK, | 718 | * PCXHR_CLOCK_TYPE_WORD_CLOCK, |
| 631 | * PCXHR_CLOCK_TYPE_AES_SYNC, | 719 | * PCXHR_CLOCK_TYPE_AES_SYNC, |
| 632 | * PCXHR_CLOCK_TYPE_AES_1, | 720 | * PCXHR_CLOCK_TYPE_AES_1, |
| 633 | * PCXHR_CLOCK_TYPE_AES_2, | 721 | * PCXHR_CLOCK_TYPE_AES_2, |
| 634 | * PCXHR_CLOCK_TYPE_AES_3, | 722 | * PCXHR_CLOCK_TYPE_AES_3, |
| 635 | * PCXHR_CLOCK_TYPE_AES_4, | 723 | * PCXHR_CLOCK_TYPE_AES_4, |
| 636 | * }; | 724 | * PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, |
| 725 | * HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, | ||
| 726 | * HR22_CLOCK_TYPE_AES_SYNC, | ||
| 727 | * HR22_CLOCK_TYPE_AES_1, | ||
| 728 | * HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, | ||
| 729 | * }; | ||
| 637 | */ | 730 | */ |
| 638 | 731 | ||
| 639 | static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, | 732 | static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, |
| 640 | struct snd_ctl_elem_info *uinfo) | 733 | struct snd_ctl_elem_info *uinfo) |
| 641 | { | 734 | { |
| 642 | static char *texts[7] = { | 735 | static const char *textsPCXHR[7] = { |
| 643 | "Internal", "WordClock", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" | 736 | "Internal", "WordClock", "AES Sync", |
| 737 | "AES 1", "AES 2", "AES 3", "AES 4" | ||
| 738 | }; | ||
| 739 | static const char *textsHR22[3] = { | ||
| 740 | "Internal", "AES Sync", "AES 1" | ||
| 644 | }; | 741 | }; |
| 742 | const char **texts; | ||
| 645 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | 743 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
| 646 | int clock_items = 3 + mgr->capture_chips; | 744 | int clock_items = 2; /* at least Internal and AES Sync clock */ |
| 647 | 745 | if (mgr->board_has_aes1) { | |
| 746 | clock_items += mgr->capture_chips; /* add AES x */ | ||
| 747 | if (!mgr->is_hr_stereo) | ||
| 748 | clock_items += 1; /* add word clock */ | ||
| 749 | } | ||
| 750 | if (mgr->is_hr_stereo) { | ||
| 751 | texts = textsHR22; | ||
| 752 | snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1)); | ||
| 753 | } else { | ||
| 754 | texts = textsPCXHR; | ||
| 755 | snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1)); | ||
| 756 | } | ||
| 648 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 757 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
| 649 | uinfo->count = 1; | 758 | uinfo->count = 1; |
| 650 | uinfo->value.enumerated.items = clock_items; | 759 | uinfo->value.enumerated.items = clock_items; |
| @@ -667,9 +776,13 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, | |||
| 667 | struct snd_ctl_elem_value *ucontrol) | 776 | struct snd_ctl_elem_value *ucontrol) |
| 668 | { | 777 | { |
| 669 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | 778 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
| 670 | unsigned int clock_items = 3 + mgr->capture_chips; | ||
| 671 | int rate, ret = 0; | 779 | int rate, ret = 0; |
| 672 | 780 | unsigned int clock_items = 2; /* at least Internal and AES Sync clock */ | |
| 781 | if (mgr->board_has_aes1) { | ||
| 782 | clock_items += mgr->capture_chips; /* add AES x */ | ||
| 783 | if (!mgr->is_hr_stereo) | ||
| 784 | clock_items += 1; /* add word clock */ | ||
| 785 | } | ||
| 673 | if (ucontrol->value.enumerated.item[0] >= clock_items) | 786 | if (ucontrol->value.enumerated.item[0] >= clock_items) |
| 674 | return -EINVAL; | 787 | return -EINVAL; |
| 675 | mutex_lock(&mgr->mixer_mutex); | 788 | mutex_lock(&mgr->mixer_mutex); |
| @@ -677,7 +790,8 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, | |||
| 677 | mutex_lock(&mgr->setup_mutex); | 790 | mutex_lock(&mgr->setup_mutex); |
| 678 | mgr->use_clock_type = ucontrol->value.enumerated.item[0]; | 791 | mgr->use_clock_type = ucontrol->value.enumerated.item[0]; |
| 679 | if (mgr->use_clock_type) | 792 | if (mgr->use_clock_type) |
| 680 | pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate); | 793 | pcxhr_get_external_clock(mgr, mgr->use_clock_type, |
| 794 | &rate); | ||
| 681 | else | 795 | else |
| 682 | rate = mgr->sample_rate; | 796 | rate = mgr->sample_rate; |
| 683 | if (rate) { | 797 | if (rate) { |
| @@ -686,7 +800,7 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, | |||
| 686 | mgr->sample_rate = rate; | 800 | mgr->sample_rate = rate; |
| 687 | } | 801 | } |
| 688 | mutex_unlock(&mgr->setup_mutex); | 802 | mutex_unlock(&mgr->setup_mutex); |
| 689 | ret = 1; /* return 1 even if the set was not done. ok ? */ | 803 | ret = 1; /* return 1 even if the set was not done. ok ? */ |
| 690 | } | 804 | } |
| 691 | mutex_unlock(&mgr->mixer_mutex); | 805 | mutex_unlock(&mgr->mixer_mutex); |
| 692 | return ret; | 806 | return ret; |
| @@ -747,14 +861,16 @@ static struct snd_kcontrol_new pcxhr_control_clock_rate = { | |||
| 747 | /* | 861 | /* |
| 748 | * IEC958 status bits | 862 | * IEC958 status bits |
| 749 | */ | 863 | */ |
| 750 | static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 864 | static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, |
| 865 | struct snd_ctl_elem_info *uinfo) | ||
| 751 | { | 866 | { |
| 752 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | 867 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
| 753 | uinfo->count = 1; | 868 | uinfo->count = 1; |
| 754 | return 0; | 869 | return 0; |
| 755 | } | 870 | } |
| 756 | 871 | ||
| 757 | static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits) | 872 | static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, |
| 873 | int aes_idx, unsigned char *aes_bits) | ||
| 758 | { | 874 | { |
| 759 | int i, err; | 875 | int i, err; |
| 760 | unsigned char temp; | 876 | unsigned char temp; |
| @@ -763,39 +879,61 @@ static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsign | |||
| 763 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); | 879 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); |
| 764 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; | 880 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; |
| 765 | switch (chip->chip_idx) { | 881 | switch (chip->chip_idx) { |
| 766 | case 0: rmh.cmd[1] = CS8420_01_CS; break; /* use CS8416_01_CS for AES SYNC plug */ | 882 | /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */ |
| 883 | case 0: rmh.cmd[1] = CS8420_01_CS; break; | ||
| 767 | case 1: rmh.cmd[1] = CS8420_23_CS; break; | 884 | case 1: rmh.cmd[1] = CS8420_23_CS; break; |
| 768 | case 2: rmh.cmd[1] = CS8420_45_CS; break; | 885 | case 2: rmh.cmd[1] = CS8420_45_CS; break; |
| 769 | case 3: rmh.cmd[1] = CS8420_67_CS; break; | 886 | case 3: rmh.cmd[1] = CS8420_67_CS; break; |
| 770 | default: return -EINVAL; | 887 | default: return -EINVAL; |
| 771 | } | 888 | } |
| 772 | switch (aes_idx) { | 889 | if (chip->mgr->board_aes_in_192k) { |
| 773 | case 0: rmh.cmd[2] = CS8420_CSB0; break; /* use CS8416_CSBx for AES SYNC plug */ | 890 | switch (aes_idx) { |
| 774 | case 1: rmh.cmd[2] = CS8420_CSB1; break; | 891 | case 0: rmh.cmd[2] = CS8416_CSB0; break; |
| 775 | case 2: rmh.cmd[2] = CS8420_CSB2; break; | 892 | case 1: rmh.cmd[2] = CS8416_CSB1; break; |
| 776 | case 3: rmh.cmd[2] = CS8420_CSB3; break; | 893 | case 2: rmh.cmd[2] = CS8416_CSB2; break; |
| 777 | case 4: rmh.cmd[2] = CS8420_CSB4; break; | 894 | case 3: rmh.cmd[2] = CS8416_CSB3; break; |
| 778 | default: return -EINVAL; | 895 | case 4: rmh.cmd[2] = CS8416_CSB4; break; |
| 896 | default: return -EINVAL; | ||
| 897 | } | ||
| 898 | } else { | ||
| 899 | switch (aes_idx) { | ||
| 900 | /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */ | ||
| 901 | case 0: rmh.cmd[2] = CS8420_CSB0; break; | ||
| 902 | case 1: rmh.cmd[2] = CS8420_CSB1; break; | ||
| 903 | case 2: rmh.cmd[2] = CS8420_CSB2; break; | ||
| 904 | case 3: rmh.cmd[2] = CS8420_CSB3; break; | ||
| 905 | case 4: rmh.cmd[2] = CS8420_CSB4; break; | ||
| 906 | default: return -EINVAL; | ||
| 907 | } | ||
| 779 | } | 908 | } |
| 780 | rmh.cmd[1] &= 0x0fffff; /* size and code the chip id for the fpga */ | 909 | /* size and code the chip id for the fpga */ |
| 781 | rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; /* chip signature + map for spi read */ | 910 | rmh.cmd[1] &= 0x0fffff; |
| 911 | /* chip signature + map for spi read */ | ||
| 912 | rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; | ||
| 782 | rmh.cmd_len = 3; | 913 | rmh.cmd_len = 3; |
| 783 | err = pcxhr_send_msg(chip->mgr, &rmh); | 914 | err = pcxhr_send_msg(chip->mgr, &rmh); |
| 784 | if (err) | 915 | if (err) |
| 785 | return err; | 916 | return err; |
| 786 | temp = 0; | 917 | |
| 787 | for (i = 0; i < 8; i++) { | 918 | if (chip->mgr->board_aes_in_192k) { |
| 788 | /* attention : reversed bit order (not with CS8416_01_CS) */ | 919 | temp = (unsigned char)rmh.stat[1]; |
| 789 | temp <<= 1; | 920 | } else { |
| 790 | if (rmh.stat[1] & (1 << i)) | 921 | temp = 0; |
| 791 | temp |= 1; | 922 | /* reversed bit order (not with CS8416_01_CS) */ |
| 923 | for (i = 0; i < 8; i++) { | ||
| 924 | temp <<= 1; | ||
| 925 | if (rmh.stat[1] & (1 << i)) | ||
| 926 | temp |= 1; | ||
| 927 | } | ||
| 792 | } | 928 | } |
| 793 | snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); | 929 | snd_printdd("read iec958 AES %d byte %d = 0x%x\n", |
| 930 | chip->chip_idx, aes_idx, temp); | ||
| 794 | *aes_bits = temp; | 931 | *aes_bits = temp; |
| 795 | return 0; | 932 | return 0; |
| 796 | } | 933 | } |
| 797 | 934 | ||
| 798 | static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 935 | static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, |
| 936 | struct snd_ctl_elem_value *ucontrol) | ||
| 799 | { | 937 | { |
| 800 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | 938 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
| 801 | unsigned char aes_bits; | 939 | unsigned char aes_bits; |
| @@ -806,7 +944,12 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
| 806 | if (kcontrol->private_value == 0) /* playback */ | 944 | if (kcontrol->private_value == 0) /* playback */ |
| 807 | aes_bits = chip->aes_bits[i]; | 945 | aes_bits = chip->aes_bits[i]; |
| 808 | else { /* capture */ | 946 | else { /* capture */ |
| 809 | err = pcxhr_iec958_capture_byte(chip, i, &aes_bits); | 947 | if (chip->mgr->is_hr_stereo) |
| 948 | err = hr222_iec958_capture_byte(chip, i, | ||
| 949 | &aes_bits); | ||
| 950 | else | ||
| 951 | err = pcxhr_iec958_capture_byte(chip, i, | ||
| 952 | &aes_bits); | ||
| 810 | if (err) | 953 | if (err) |
| 811 | break; | 954 | break; |
| 812 | } | 955 | } |
| @@ -825,7 +968,8 @@ static int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol, | |||
| 825 | return 0; | 968 | return 0; |
| 826 | } | 969 | } |
| 827 | 970 | ||
| 828 | static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits) | 971 | static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, |
| 972 | int aes_idx, unsigned char aes_bits) | ||
| 829 | { | 973 | { |
| 830 | int i, err, cmd; | 974 | int i, err, cmd; |
| 831 | unsigned char new_bits = aes_bits; | 975 | unsigned char new_bits = aes_bits; |
| @@ -834,12 +978,12 @@ static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigne | |||
| 834 | 978 | ||
| 835 | for (i = 0; i < 8; i++) { | 979 | for (i = 0; i < 8; i++) { |
| 836 | if ((old_bits & 0x01) != (new_bits & 0x01)) { | 980 | if ((old_bits & 0x01) != (new_bits & 0x01)) { |
| 837 | cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ | 981 | cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ |
| 838 | if(chip->chip_idx > 3) | 982 | if (chip->chip_idx > 3) |
| 839 | /* new bit used if chip_idx>3 (PCX1222HR) */ | 983 | /* new bit used if chip_idx>3 (PCX1222HR) */ |
| 840 | cmd |= 1 << 22; | 984 | cmd |= 1 << 22; |
| 841 | cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ | 985 | cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ |
| 842 | cmd |= (new_bits & 0x01) << 23; /* add bit value */ | 986 | cmd |= (new_bits & 0x01) << 23; /* add bit value */ |
| 843 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); | 987 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); |
| 844 | rmh.cmd[0] |= IO_NUM_REG_CUER; | 988 | rmh.cmd[0] |= IO_NUM_REG_CUER; |
| 845 | rmh.cmd[1] = cmd; | 989 | rmh.cmd[1] = cmd; |
| @@ -867,7 +1011,12 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, | |||
| 867 | mutex_lock(&chip->mgr->mixer_mutex); | 1011 | mutex_lock(&chip->mgr->mixer_mutex); |
| 868 | for (i = 0; i < 5; i++) { | 1012 | for (i = 0; i < 5; i++) { |
| 869 | if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { | 1013 | if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { |
| 870 | pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]); | 1014 | if (chip->mgr->is_hr_stereo) |
| 1015 | hr222_iec958_update_byte(chip, i, | ||
| 1016 | ucontrol->value.iec958.status[i]); | ||
| 1017 | else | ||
| 1018 | pcxhr_iec958_update_byte(chip, i, | ||
| 1019 | ucontrol->value.iec958.status[i]); | ||
| 871 | changed = 1; | 1020 | changed = 1; |
| 872 | } | 1021 | } |
| 873 | } | 1022 | } |
| @@ -917,29 +1066,53 @@ static void pcxhr_init_audio_levels(struct snd_pcxhr *chip) | |||
| 917 | /* at boot time the digital volumes are unmuted 0dB */ | 1066 | /* at boot time the digital volumes are unmuted 0dB */ |
| 918 | for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { | 1067 | for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { |
| 919 | chip->digital_playback_active[j][i] = 1; | 1068 | chip->digital_playback_active[j][i] = 1; |
| 920 | chip->digital_playback_volume[j][i] = PCXHR_DIGITAL_ZERO_LEVEL; | 1069 | chip->digital_playback_volume[j][i] = |
| 1070 | PCXHR_DIGITAL_ZERO_LEVEL; | ||
| 921 | } | 1071 | } |
| 922 | /* after boot, only two bits are set on the uer interface */ | 1072 | /* after boot, only two bits are set on the uer |
| 923 | chip->aes_bits[0] = IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_FS_48000; | 1073 | * interface |
| 924 | /* only for test purpose, remove later */ | 1074 | */ |
| 1075 | chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL | | ||
| 1076 | IEC958_AES0_PRO_FS_48000); | ||
| 925 | #ifdef CONFIG_SND_DEBUG | 1077 | #ifdef CONFIG_SND_DEBUG |
| 926 | /* analog volumes for playback (is LEVEL_MIN after boot) */ | 1078 | /* analog volumes for playback |
| 1079 | * (is LEVEL_MIN after boot) | ||
| 1080 | */ | ||
| 927 | chip->analog_playback_active[i] = 1; | 1081 | chip->analog_playback_active[i] = 1; |
| 928 | chip->analog_playback_volume[i] = PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL; | 1082 | if (chip->mgr->is_hr_stereo) |
| 929 | pcxhr_update_analog_audio_level(chip, 0, i); | 1083 | chip->analog_playback_volume[i] = |
| 1084 | HR222_LINE_PLAYBACK_ZERO_LEVEL; | ||
| 1085 | else { | ||
| 1086 | chip->analog_playback_volume[i] = | ||
| 1087 | PCXHR_LINE_PLAYBACK_ZERO_LEVEL; | ||
| 1088 | pcxhr_update_analog_audio_level(chip, 0, i); | ||
| 1089 | } | ||
| 930 | #endif | 1090 | #endif |
| 931 | /* test end */ | 1091 | /* stereo cards need to be initialised after boot */ |
| 1092 | if (chip->mgr->is_hr_stereo) | ||
| 1093 | hr222_update_analog_audio_level(chip, 0, i); | ||
| 932 | } | 1094 | } |
| 933 | if (chip->nb_streams_capt) { | 1095 | if (chip->nb_streams_capt) { |
| 934 | /* at boot time the digital volumes are unmuted 0dB */ | 1096 | /* at boot time the digital volumes are unmuted 0dB */ |
| 935 | chip->digital_capture_volume[i] = PCXHR_DIGITAL_ZERO_LEVEL; | 1097 | chip->digital_capture_volume[i] = |
| 936 | /* only for test purpose, remove later */ | 1098 | PCXHR_DIGITAL_ZERO_LEVEL; |
| 1099 | chip->analog_capture_active = 1; | ||
| 937 | #ifdef CONFIG_SND_DEBUG | 1100 | #ifdef CONFIG_SND_DEBUG |
| 938 | /* analog volumes for playback (is LEVEL_MIN after boot) */ | 1101 | /* analog volumes for playback |
| 939 | chip->analog_capture_volume[i] = PCXHR_ANALOG_CAPTURE_ZERO_LEVEL; | 1102 | * (is LEVEL_MIN after boot) |
| 940 | pcxhr_update_analog_audio_level(chip, 1, i); | 1103 | */ |
| 1104 | if (chip->mgr->is_hr_stereo) | ||
| 1105 | chip->analog_capture_volume[i] = | ||
| 1106 | HR222_LINE_CAPTURE_ZERO_LEVEL; | ||
| 1107 | else { | ||
| 1108 | chip->analog_capture_volume[i] = | ||
| 1109 | PCXHR_LINE_CAPTURE_ZERO_LEVEL; | ||
| 1110 | pcxhr_update_analog_audio_level(chip, 1, i); | ||
| 1111 | } | ||
| 941 | #endif | 1112 | #endif |
| 942 | /* test end */ | 1113 | /* stereo cards need to be initialised after boot */ |
| 1114 | if (chip->mgr->is_hr_stereo) | ||
| 1115 | hr222_update_analog_audio_level(chip, 1, i); | ||
| 943 | } | 1116 | } |
| 944 | } | 1117 | } |
| 945 | 1118 | ||
| @@ -963,90 +1136,125 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) | |||
| 963 | temp = pcxhr_control_analog_level; | 1136 | temp = pcxhr_control_analog_level; |
| 964 | temp.name = "Master Playback Volume"; | 1137 | temp.name = "Master Playback Volume"; |
| 965 | temp.private_value = 0; /* playback */ | 1138 | temp.private_value = 0; /* playback */ |
| 966 | temp.tlv.p = db_scale_analog_playback; | 1139 | if (mgr->is_hr_stereo) |
| 967 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | 1140 | temp.tlv.p = db_scale_a_hr222_playback; |
| 1141 | else | ||
| 1142 | temp.tlv.p = db_scale_analog_playback; | ||
| 1143 | err = snd_ctl_add(chip->card, | ||
| 1144 | snd_ctl_new1(&temp, chip)); | ||
| 1145 | if (err < 0) | ||
| 968 | return err; | 1146 | return err; |
| 1147 | |||
| 969 | /* output mute controls */ | 1148 | /* output mute controls */ |
| 970 | if ((err = snd_ctl_add(chip->card, | 1149 | err = snd_ctl_add(chip->card, |
| 971 | snd_ctl_new1(&pcxhr_control_output_switch, | 1150 | snd_ctl_new1(&pcxhr_control_output_switch, |
| 972 | chip))) < 0) | 1151 | chip)); |
| 1152 | if (err < 0) | ||
| 973 | return err; | 1153 | return err; |
| 974 | 1154 | ||
| 975 | temp = snd_pcxhr_pcm_vol; | 1155 | temp = snd_pcxhr_pcm_vol; |
| 976 | temp.name = "PCM Playback Volume"; | 1156 | temp.name = "PCM Playback Volume"; |
| 977 | temp.count = PCXHR_PLAYBACK_STREAMS; | 1157 | temp.count = PCXHR_PLAYBACK_STREAMS; |
| 978 | temp.private_value = 0; /* playback */ | 1158 | temp.private_value = 0; /* playback */ |
| 979 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | 1159 | err = snd_ctl_add(chip->card, |
| 1160 | snd_ctl_new1(&temp, chip)); | ||
| 1161 | if (err < 0) | ||
| 980 | return err; | 1162 | return err; |
| 981 | 1163 | ||
| 982 | if ((err = snd_ctl_add(chip->card, | 1164 | err = snd_ctl_add(chip->card, |
| 983 | snd_ctl_new1(&pcxhr_control_pcm_switch, | 1165 | snd_ctl_new1(&pcxhr_control_pcm_switch, chip)); |
| 984 | chip))) < 0) | 1166 | if (err < 0) |
| 985 | return err; | 1167 | return err; |
| 986 | 1168 | ||
| 987 | /* IEC958 controls */ | 1169 | /* IEC958 controls */ |
| 988 | if ((err = snd_ctl_add(chip->card, | 1170 | err = snd_ctl_add(chip->card, |
| 989 | snd_ctl_new1(&pcxhr_control_playback_iec958_mask, | 1171 | snd_ctl_new1(&pcxhr_control_playback_iec958_mask, |
| 990 | chip))) < 0) | 1172 | chip)); |
| 1173 | if (err < 0) | ||
| 991 | return err; | 1174 | return err; |
| 992 | if ((err = snd_ctl_add(chip->card, | 1175 | |
| 993 | snd_ctl_new1(&pcxhr_control_playback_iec958, | 1176 | err = snd_ctl_add(chip->card, |
| 994 | chip))) < 0) | 1177 | snd_ctl_new1(&pcxhr_control_playback_iec958, |
| 1178 | chip)); | ||
| 1179 | if (err < 0) | ||
| 995 | return err; | 1180 | return err; |
| 996 | } | 1181 | } |
| 997 | if (chip->nb_streams_capt) { | 1182 | if (chip->nb_streams_capt) { |
| 998 | /* analog input level control only on first two chips !*/ | 1183 | /* analog input level control */ |
| 999 | temp = pcxhr_control_analog_level; | 1184 | temp = pcxhr_control_analog_level; |
| 1000 | temp.name = "Master Capture Volume"; | 1185 | temp.name = "Line Capture Volume"; |
| 1001 | temp.private_value = 1; /* capture */ | 1186 | temp.private_value = 1; /* capture */ |
| 1002 | temp.tlv.p = db_scale_analog_capture; | 1187 | if (mgr->is_hr_stereo) |
| 1003 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | 1188 | temp.tlv.p = db_scale_a_hr222_capture; |
| 1189 | else | ||
| 1190 | temp.tlv.p = db_scale_analog_capture; | ||
| 1191 | |||
| 1192 | err = snd_ctl_add(chip->card, | ||
| 1193 | snd_ctl_new1(&temp, chip)); | ||
| 1194 | if (err < 0) | ||
| 1004 | return err; | 1195 | return err; |
| 1005 | 1196 | ||
| 1006 | temp = snd_pcxhr_pcm_vol; | 1197 | temp = snd_pcxhr_pcm_vol; |
| 1007 | temp.name = "PCM Capture Volume"; | 1198 | temp.name = "PCM Capture Volume"; |
| 1008 | temp.count = 1; | 1199 | temp.count = 1; |
| 1009 | temp.private_value = 1; /* capture */ | 1200 | temp.private_value = 1; /* capture */ |
| 1010 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | 1201 | |
| 1202 | err = snd_ctl_add(chip->card, | ||
| 1203 | snd_ctl_new1(&temp, chip)); | ||
| 1204 | if (err < 0) | ||
| 1011 | return err; | 1205 | return err; |
| 1206 | |||
| 1012 | /* Audio source */ | 1207 | /* Audio source */ |
| 1013 | if ((err = snd_ctl_add(chip->card, | 1208 | err = snd_ctl_add(chip->card, |
| 1014 | snd_ctl_new1(&pcxhr_control_audio_src, | 1209 | snd_ctl_new1(&pcxhr_control_audio_src, chip)); |
| 1015 | chip))) < 0) | 1210 | if (err < 0) |
| 1016 | return err; | 1211 | return err; |
| 1212 | |||
| 1017 | /* IEC958 controls */ | 1213 | /* IEC958 controls */ |
| 1018 | if ((err = snd_ctl_add(chip->card, | 1214 | err = snd_ctl_add(chip->card, |
| 1019 | snd_ctl_new1(&pcxhr_control_capture_iec958_mask, | 1215 | snd_ctl_new1(&pcxhr_control_capture_iec958_mask, |
| 1020 | chip))) < 0) | 1216 | chip)); |
| 1217 | if (err < 0) | ||
| 1021 | return err; | 1218 | return err; |
| 1022 | if ((err = snd_ctl_add(chip->card, | 1219 | |
| 1023 | snd_ctl_new1(&pcxhr_control_capture_iec958, | 1220 | err = snd_ctl_add(chip->card, |
| 1024 | chip))) < 0) | 1221 | snd_ctl_new1(&pcxhr_control_capture_iec958, |
| 1222 | chip)); | ||
| 1223 | if (err < 0) | ||
| 1025 | return err; | 1224 | return err; |
| 1225 | |||
| 1226 | if (mgr->is_hr_stereo) { | ||
| 1227 | err = hr222_add_mic_controls(chip); | ||
| 1228 | if (err < 0) | ||
| 1229 | return err; | ||
| 1230 | } | ||
| 1026 | } | 1231 | } |
| 1027 | /* monitoring only if playback and capture device available */ | 1232 | /* monitoring only if playback and capture device available */ |
| 1028 | if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { | 1233 | if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { |
| 1029 | /* monitoring */ | 1234 | /* monitoring */ |
| 1030 | if ((err = snd_ctl_add(chip->card, | 1235 | err = snd_ctl_add(chip->card, |
| 1031 | snd_ctl_new1(&pcxhr_control_monitor_vol, | 1236 | snd_ctl_new1(&pcxhr_control_monitor_vol, chip)); |
| 1032 | chip))) < 0) | 1237 | if (err < 0) |
| 1033 | return err; | 1238 | return err; |
| 1034 | if ((err = snd_ctl_add(chip->card, | 1239 | |
| 1035 | snd_ctl_new1(&pcxhr_control_monitor_sw, | 1240 | err = snd_ctl_add(chip->card, |
| 1036 | chip))) < 0) | 1241 | snd_ctl_new1(&pcxhr_control_monitor_sw, chip)); |
| 1242 | if (err < 0) | ||
| 1037 | return err; | 1243 | return err; |
| 1038 | } | 1244 | } |
| 1039 | 1245 | ||
| 1040 | if (i == 0) { | 1246 | if (i == 0) { |
| 1041 | /* clock mode only one control per pcxhr */ | 1247 | /* clock mode only one control per pcxhr */ |
| 1042 | if ((err = snd_ctl_add(chip->card, | 1248 | err = snd_ctl_add(chip->card, |
| 1043 | snd_ctl_new1(&pcxhr_control_clock_type, | 1249 | snd_ctl_new1(&pcxhr_control_clock_type, mgr)); |
| 1044 | mgr))) < 0) | 1250 | if (err < 0) |
| 1045 | return err; | 1251 | return err; |
| 1046 | /* non standard control used to scan the external clock presence/frequencies */ | 1252 | /* non standard control used to scan |
| 1047 | if ((err = snd_ctl_add(chip->card, | 1253 | * the external clock presence/frequencies |
| 1048 | snd_ctl_new1(&pcxhr_control_clock_rate, | 1254 | */ |
| 1049 | mgr))) < 0) | 1255 | err = snd_ctl_add(chip->card, |
| 1256 | snd_ctl_new1(&pcxhr_control_clock_rate, mgr)); | ||
| 1257 | if (err < 0) | ||
| 1050 | return err; | 1258 | return err; |
| 1051 | } | 1259 | } |
| 1052 | 1260 | ||
