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

ALSA: ice1724 - Add ESI Maya44 support

Added the support for ESI Maya44 board to ice1724 driver.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

+958 -2
+2 -1
Documentation/sound/alsa/ALSA-Configuration.txt
··· 925 925 * Onkyo SE-90PCI 926 926 * Onkyo SE-200PCI 927 927 * ESI Juli@ 928 + * ESI Maya44 928 929 * Hercules Fortissimo IV 929 930 * EGO-SYS WaveTerminal 192M 930 931 ··· 934 933 prodigy71xt, prodigy71hifi, prodigyhd2, prodigy192, 935 934 juli, aureon51, aureon71, universe, ap192, k8x800, 936 935 phase22, phase28, ms300, av710, se200pci, se90pci, 937 - fortissimo4, sn25p, WT192M 936 + fortissimo4, sn25p, WT192M, maya44 938 937 939 938 This module supports multiple cards and autoprobe. 940 939
+163
Documentation/sound/alsa/README.maya44
··· 1 + NOTE: The following is the original document of Rainer's patch that the 2 + current maya44 code based on. Some contents might be obsoleted, but I 3 + keep here as reference -- tiwai 4 + 5 + ---------------------------------------------------------------- 6 + 7 + STATE OF DEVELOPMENT: 8 + 9 + This driver is being developed on the initiative of Piotr Makowski (oponek@gmail.com) and financed by Lars Bergmann. 10 + Development is carried out by Rainer Zimmermann (mail@lightshed.de). 11 + 12 + ESI provided a sample Maya44 card for the development work. 13 + 14 + However, unfortunately it has turned out difficult to get detailed programming information, so I (Rainer Zimmermann) had to find out some card-specific information by experiment and conjecture. Some information (in particular, several GPIO bits) is still missing. 15 + 16 + This is the first testing version of the Maya44 driver released to the alsa-devel mailing list (Feb 5, 2008). 17 + 18 + 19 + The following functions work, as tested by Rainer Zimmermann and Piotr Makowski: 20 + 21 + - playback and capture at all sampling rates 22 + - input/output level 23 + - crossmixing 24 + - line/mic switch 25 + - phantom power switch 26 + - analogue monitor a.k.a bypass 27 + 28 + 29 + The following functions *should* work, but are not fully tested: 30 + 31 + - Channel 3+4 analogue - S/PDIF input switching 32 + - S/PDIF output 33 + - all inputs/outputs on the M/IO/DIO extension card 34 + - internal/external clock selection 35 + 36 + 37 + *In particular, we would appreciate testing of these functions by anyone who has access to an M/IO/DIO extension card.* 38 + 39 + 40 + Things that do not seem to work: 41 + 42 + - The level meters ("multi track") in 'alsamixer' do not seem to react to signals in (if this is a bug, it would probably be in the existing ICE1724 code). 43 + 44 + - Ardour 2.1 seems to work only via JACK, not using ALSA directly or via OSS. This still needs to be tracked down. 45 + 46 + 47 + DRIVER DETAILS: 48 + 49 + the following files were added: 50 + 51 + pci/ice1724/maya44.c - Maya44 specific code 52 + pci/ice1724/maya44.h 53 + pci/ice1724/ice1724.patch 54 + pci/ice1724/ice1724.h.patch - PROPOSED patch to ice1724.h (see SAMPLING RATES) 55 + i2c/other/wm8776.c - low-level access routines for Wolfson WM8776 codecs 56 + include/wm8776.h 57 + 58 + 59 + Note that the wm8776.c code is meant to be card-independent and does not actually register the codec with the ALSA infrastructure. 60 + This is done in maya44.c, mainly because some of the WM8776 controls are used in Maya44-specific ways, and should be named appropriately. 61 + 62 + 63 + the following files were created in pci/ice1724, simply #including the corresponding file from the alsa-kernel tree: 64 + 65 + wtm.h 66 + vt1720_mobo.h 67 + revo.h 68 + prodigy192.h 69 + pontis.h 70 + phase.h 71 + maya44.h 72 + juli.h 73 + aureon.h 74 + amp.h 75 + envy24ht.h 76 + se.h 77 + prodigy_hifi.h 78 + 79 + 80 + *I hope this is the correct way to do things.* 81 + 82 + 83 + SAMPLING RATES: 84 + 85 + The Maya44 card (or more exactly, the Wolfson WM8776 codecs) allow a maximum sampling rate of 192 kHz for playback and 92 kHz for capture. 86 + 87 + As the ICE1724 chip only allows one global sampling rate, this is handled as follows: 88 + 89 + * setting the sampling rate on any open PCM device on the maya44 card will always set the *global* sampling rate for all playback and capture channels. 90 + 91 + * In the current state of the driver, setting rates of up to 192 kHz is permitted even for capture devices. 92 + 93 + *AVOID CAPTURING AT RATES ABOVE 96kHz*, even though it may appear to work. The codec cannot actually capture at such rates, meaning poor quality. 94 + 95 + 96 + I propose some additional code for limiting the sampling rate when setting on a capture pcm device. However because of the global sampling rate, this logic would be somewhat problematic. 97 + 98 + The proposed code (currently deactivated) is in ice1712.h.patch, ice1724.c and maya44.c (in pci/ice1712). 99 + 100 + 101 + SOUND DEVICES: 102 + 103 + PCM devices correspond to inputs/outputs as follows (assuming Maya44 is card #0): 104 + 105 + hw:0,0 input - stereo, analog input 1+2 106 + hw:0,0 output - stereo, analog output 1+2 107 + hw:0,1 input - stereo, analog input 3+4 OR S/PDIF input 108 + hw:0,1 output - stereo, analog output 3+4 (and SPDIF out) 109 + 110 + 111 + NAMING OF MIXER CONTROLS: 112 + 113 + (for more information about the signal flow, please refer to the block diagram on p.24 of the ESI Maya44 manual, or in the ESI windows software). 114 + 115 + 116 + PCM: (digital) output level for channel 1+2 117 + PCM 1: same for channel 3+4 118 + 119 + Mic Phantom+48V: switch for +48V phantom power for electrostatic microphones on input 1/2. 120 + Make sure this is not turned on while any other source is connected to input 1/2. 121 + It might damage the source and/or the maya44 card. 122 + 123 + Mic/Line input: if switch is is on, input jack 1/2 is microphone input (mono), otherwise line input (stereo). 124 + 125 + Bypass: analogue bypass from ADC input to output for channel 1+2. Same as "Monitor" in the windows driver. 126 + Bypass 1: same for channel 3+4. 127 + 128 + Crossmix: cross-mixer from channels 1+2 to channels 3+4 129 + Crossmix 1: cross-mixer from channels 3+4 to channels 1+2 130 + 131 + IEC958 Output: switch for S/PDIF output. 132 + This is not supported by the ESI windows driver. 133 + S/PDIF should output the same signal as channel 3+4. [untested!] 134 + 135 + 136 + Digitial output selectors: 137 + 138 + These switches allow a direct digital routing from the ADCs to the DACs. 139 + Each switch determines where the digital input data to one of the DACs comes from. 140 + They are not supported by the ESI windows driver. 141 + For normal operation, they should all be set to "PCM out". 142 + 143 + H/W: Output source channel 1 144 + H/W 1: Output source channel 2 145 + H/W 2: Output source channel 3 146 + H/W 3: Output source channel 4 147 + 148 + H/W 4 ... H/W 9: unknown function, left in to enable testing. 149 + Possibly some of these control S/PDIF output(s). 150 + If these turn out to be unused, they will go away in later driver versions. 151 + 152 + Selectable values for each of the digital output selectors are: 153 + "PCM out" -> DAC output of the corresponding channel (default setting) 154 + "Input 1"... 155 + "Input 4" -> direct routing from ADC output of the selected input channel 156 + 157 + 158 + -------- 159 + 160 + Feb 14, 2008 161 + Rainer Zimmermann 162 + mail@lightshed.de 163 +
+1 -1
sound/pci/ice1712/Makefile
··· 5 5 6 6 snd-ice17xx-ak4xxx-objs := ak4xxx.o 7 7 snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o 8 - snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o 8 + snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o 9 9 10 10 # Toplevel Module Dependency 11 11 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
+3
sound/pci/ice1712/ice1724.c
··· 49 49 #include "prodigy192.h" 50 50 #include "prodigy_hifi.h" 51 51 #include "juli.h" 52 + #include "maya44.h" 52 53 #include "phase.h" 53 54 #include "wtm.h" 54 55 #include "se.h" ··· 66 65 PRODIGY192_DEVICE_DESC 67 66 PRODIGY_HIFI_DEVICE_DESC 68 67 JULI_DEVICE_DESC 68 + MAYA44_DEVICE_DESC 69 69 PHASE_DEVICE_DESC 70 70 WTM_DEVICE_DESC 71 71 SE_DEVICE_DESC ··· 2127 2125 snd_vt1724_prodigy_hifi_cards, 2128 2126 snd_vt1724_prodigy192_cards, 2129 2127 snd_vt1724_juli_cards, 2128 + snd_vt1724_maya44_cards, 2130 2129 snd_vt1724_phase_cards, 2131 2130 snd_vt1724_wtm_cards, 2132 2131 snd_vt1724_se_cards,
+779
sound/pci/ice1712/maya44.c
··· 1 + /* 2 + * ALSA driver for ICEnsemble VT1724 (Envy24HT) 3 + * 4 + * Lowlevel functions for ESI Maya44 cards 5 + * 6 + * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de> 7 + * Based on the patches by Rainer Zimmermann <mail@lightshed.de> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License 20 + * along with this program; if not, write to the Free Software 21 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 + * 23 + */ 24 + 25 + #include <linux/init.h> 26 + #include <linux/slab.h> 27 + #include <linux/io.h> 28 + #include <sound/core.h> 29 + #include <sound/control.h> 30 + #include <sound/pcm.h> 31 + #include <sound/tlv.h> 32 + 33 + #include "ice1712.h" 34 + #include "envy24ht.h" 35 + #include "maya44.h" 36 + 37 + /* WM8776 register indexes */ 38 + #define WM8776_REG_HEADPHONE_L 0x00 39 + #define WM8776_REG_HEADPHONE_R 0x01 40 + #define WM8776_REG_HEADPHONE_MASTER 0x02 41 + #define WM8776_REG_DAC_ATTEN_L 0x03 42 + #define WM8776_REG_DAC_ATTEN_R 0x04 43 + #define WM8776_REG_DAC_ATTEN_MASTER 0x05 44 + #define WM8776_REG_DAC_PHASE 0x06 45 + #define WM8776_REG_DAC_CONTROL 0x07 46 + #define WM8776_REG_DAC_MUTE 0x08 47 + #define WM8776_REG_DAC_DEEMPH 0x09 48 + #define WM8776_REG_DAC_IF_CONTROL 0x0a 49 + #define WM8776_REG_ADC_IF_CONTROL 0x0b 50 + #define WM8776_REG_MASTER_MODE_CONTROL 0x0c 51 + #define WM8776_REG_POWERDOWN 0x0d 52 + #define WM8776_REG_ADC_ATTEN_L 0x0e 53 + #define WM8776_REG_ADC_ATTEN_R 0x0f 54 + #define WM8776_REG_ADC_ALC1 0x10 55 + #define WM8776_REG_ADC_ALC2 0x11 56 + #define WM8776_REG_ADC_ALC3 0x12 57 + #define WM8776_REG_ADC_NOISE_GATE 0x13 58 + #define WM8776_REG_ADC_LIMITER 0x14 59 + #define WM8776_REG_ADC_MUX 0x15 60 + #define WM8776_REG_OUTPUT_MUX 0x16 61 + #define WM8776_REG_RESET 0x17 62 + 63 + #define WM8776_NUM_REGS 0x18 64 + 65 + /* clock ratio identifiers for snd_wm8776_set_rate() */ 66 + #define WM8776_CLOCK_RATIO_128FS 0 67 + #define WM8776_CLOCK_RATIO_192FS 1 68 + #define WM8776_CLOCK_RATIO_256FS 2 69 + #define WM8776_CLOCK_RATIO_384FS 3 70 + #define WM8776_CLOCK_RATIO_512FS 4 71 + #define WM8776_CLOCK_RATIO_768FS 5 72 + 73 + enum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS }; 74 + enum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES }; 75 + 76 + struct snd_wm8776 { 77 + unsigned char addr; 78 + unsigned short regs[WM8776_NUM_REGS]; 79 + unsigned char volumes[WM_NUM_VOLS][2]; 80 + unsigned int switch_bits; 81 + }; 82 + 83 + struct snd_maya44 { 84 + struct snd_ice1712 *ice; 85 + struct snd_wm8776 wm[2]; 86 + struct mutex mutex; 87 + }; 88 + 89 + 90 + /* write the given register and save the data to the cache */ 91 + static void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm, 92 + unsigned char reg, unsigned short val) 93 + { 94 + /* 95 + * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB 96 + * of the address field 97 + */ 98 + snd_vt1724_write_i2c(ice, wm->addr, 99 + (reg << 1) | ((val >> 8) & 1), 100 + val & 0xff); 101 + wm->regs[reg] = val; 102 + } 103 + 104 + /* 105 + * update the given register with and/or mask and save the data to the cache 106 + */ 107 + static int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm, 108 + unsigned char reg, 109 + unsigned short mask, unsigned short val) 110 + { 111 + val |= wm->regs[reg] & ~mask; 112 + if (val != wm->regs[reg]) { 113 + wm8776_write(ice, wm, reg, val); 114 + return 1; 115 + } 116 + return 0; 117 + } 118 + 119 + 120 + /* 121 + * WM8776 volume controls 122 + */ 123 + 124 + struct maya_vol_info { 125 + unsigned int maxval; /* volume range: 0..maxval */ 126 + unsigned char regs[2]; /* left and right registers */ 127 + unsigned short mask; /* value mask */ 128 + unsigned short offset; /* zero-value offset */ 129 + unsigned short mute; /* mute bit */ 130 + unsigned short update; /* update bits */ 131 + unsigned char mux_bits[2]; /* extra bits for ADC mute */ 132 + }; 133 + 134 + static struct maya_vol_info vol_info[WM_NUM_VOLS] = { 135 + [WM_VOL_HP] = { 136 + .maxval = 80, 137 + .regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R }, 138 + .mask = 0x7f, 139 + .offset = 0x30, 140 + .mute = 0x00, 141 + .update = 0x180, /* update and zero-cross enable */ 142 + }, 143 + [WM_VOL_DAC] = { 144 + .maxval = 255, 145 + .regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R }, 146 + .mask = 0xff, 147 + .offset = 0x01, 148 + .mute = 0x00, 149 + .update = 0x100, /* zero-cross enable */ 150 + }, 151 + [WM_VOL_ADC] = { 152 + .maxval = 91, 153 + .regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R }, 154 + .mask = 0xff, 155 + .offset = 0xa5, 156 + .mute = 0xa5, 157 + .update = 0x100, /* update */ 158 + .mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */ 159 + }, 160 + }; 161 + 162 + /* 163 + * dB tables 164 + */ 165 + /* headphone output: mute, -73..+6db (1db step) */ 166 + static const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1); 167 + /* DAC output: mute, -127..0db (0.5db step) */ 168 + static const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1); 169 + /* ADC gain: mute, -21..+24db (0.5db step) */ 170 + static const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1); 171 + 172 + static int maya_vol_info(struct snd_kcontrol *kcontrol, 173 + struct snd_ctl_elem_info *uinfo) 174 + { 175 + unsigned int idx = kcontrol->private_value; 176 + struct maya_vol_info *vol = &vol_info[idx]; 177 + 178 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 179 + uinfo->count = 2; 180 + uinfo->value.integer.min = 0; 181 + uinfo->value.integer.max = vol->maxval; 182 + return 0; 183 + } 184 + 185 + static int maya_vol_get(struct snd_kcontrol *kcontrol, 186 + struct snd_ctl_elem_value *ucontrol) 187 + { 188 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 189 + struct snd_wm8776 *wm = 190 + &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; 191 + unsigned int idx = kcontrol->private_value; 192 + 193 + mutex_lock(&chip->mutex); 194 + ucontrol->value.integer.value[0] = wm->volumes[idx][0]; 195 + ucontrol->value.integer.value[1] = wm->volumes[idx][1]; 196 + mutex_unlock(&chip->mutex); 197 + return 0; 198 + } 199 + 200 + static int maya_vol_put(struct snd_kcontrol *kcontrol, 201 + struct snd_ctl_elem_value *ucontrol) 202 + { 203 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 204 + struct snd_wm8776 *wm = 205 + &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; 206 + unsigned int idx = kcontrol->private_value; 207 + struct maya_vol_info *vol = &vol_info[idx]; 208 + unsigned int val, data; 209 + int ch, changed = 0; 210 + 211 + mutex_lock(&chip->mutex); 212 + for (ch = 0; ch < 2; ch++) { 213 + val = ucontrol->value.integer.value[ch]; 214 + if (val > vol->maxval) 215 + val = vol->maxval; 216 + if (val == wm->volumes[idx][ch]) 217 + continue; 218 + if (!val) 219 + data = vol->mute; 220 + else 221 + data = (val - 1) + vol->offset; 222 + data |= vol->update; 223 + changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch], 224 + vol->mask | vol->update, data); 225 + if (vol->mux_bits[ch]) 226 + wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX, 227 + vol->mux_bits[ch], 228 + val ? 0 : vol->mux_bits[ch]); 229 + wm->volumes[idx][ch] = val; 230 + } 231 + mutex_unlock(&chip->mutex); 232 + return changed; 233 + } 234 + 235 + /* 236 + * WM8776 switch controls 237 + */ 238 + 239 + #define COMPOSE_SW_VAL(idx, reg, mask) ((idx) | ((reg) << 8) | ((mask) << 16)) 240 + #define GET_SW_VAL_IDX(val) ((val) & 0xff) 241 + #define GET_SW_VAL_REG(val) (((val) >> 8) & 0xff) 242 + #define GET_SW_VAL_MASK(val) (((val) >> 16) & 0xff) 243 + 244 + #define maya_sw_info snd_ctl_boolean_mono_info 245 + 246 + static int maya_sw_get(struct snd_kcontrol *kcontrol, 247 + struct snd_ctl_elem_value *ucontrol) 248 + { 249 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 250 + struct snd_wm8776 *wm = 251 + &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; 252 + unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); 253 + 254 + ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1; 255 + return 0; 256 + } 257 + 258 + static int maya_sw_put(struct snd_kcontrol *kcontrol, 259 + struct snd_ctl_elem_value *ucontrol) 260 + { 261 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 262 + struct snd_wm8776 *wm = 263 + &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; 264 + unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); 265 + unsigned int mask, val; 266 + int changed; 267 + 268 + mutex_lock(&chip->mutex); 269 + mask = 1 << idx; 270 + wm->switch_bits &= ~mask; 271 + val = ucontrol->value.integer.value[0]; 272 + if (val) 273 + wm->switch_bits |= mask; 274 + mask = GET_SW_VAL_MASK(kcontrol->private_value); 275 + changed = wm8776_write_bits(chip->ice, wm, 276 + GET_SW_VAL_REG(kcontrol->private_value), 277 + mask, val ? mask : 0); 278 + mutex_unlock(&chip->mutex); 279 + return changed; 280 + } 281 + 282 + /* 283 + * GPIO pins (known ones for maya44) 284 + */ 285 + #define GPIO_PHANTOM_OFF 2 286 + #define GPIO_MIC_RELAY 4 287 + #define GPIO_SPDIF_IN_INV 5 288 + #define GPIO_MUST_BE_0 7 289 + 290 + /* 291 + * GPIO switch controls 292 + */ 293 + 294 + #define COMPOSE_GPIO_VAL(shift, inv) ((shift) | ((inv) << 8)) 295 + #define GET_GPIO_VAL_SHIFT(val) ((val) & 0xff) 296 + #define GET_GPIO_VAL_INV(val) (((val) >> 8) & 1) 297 + 298 + static int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask, 299 + unsigned int bits) 300 + { 301 + unsigned int data; 302 + data = snd_ice1712_gpio_read(ice); 303 + if ((data & mask) == bits) 304 + return 0; 305 + snd_ice1712_gpio_write(ice, (data & ~mask) | bits); 306 + return 1; 307 + } 308 + 309 + #define maya_gpio_sw_info snd_ctl_boolean_mono_info 310 + 311 + static int maya_gpio_sw_get(struct snd_kcontrol *kcontrol, 312 + struct snd_ctl_elem_value *ucontrol) 313 + { 314 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 315 + unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); 316 + unsigned int val; 317 + 318 + val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1; 319 + if (GET_GPIO_VAL_INV(kcontrol->private_value)) 320 + val = !val; 321 + ucontrol->value.integer.value[0] = val; 322 + return 0; 323 + } 324 + 325 + static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol, 326 + struct snd_ctl_elem_value *ucontrol) 327 + { 328 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 329 + unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); 330 + unsigned int val, mask; 331 + int changed; 332 + 333 + mutex_lock(&chip->mutex); 334 + mask = 1 << shift; 335 + val = ucontrol->value.integer.value[0]; 336 + if (GET_GPIO_VAL_INV(kcontrol->private_value)) 337 + val = !val; 338 + val = val ? mask : 0; 339 + changed = maya_set_gpio_bits(chip->ice, mask, val); 340 + mutex_unlock(&chip->mutex); 341 + return changed; 342 + } 343 + 344 + /* 345 + * capture source selection 346 + */ 347 + 348 + /* known working input slots (0-4) */ 349 + #define MAYA_LINE_IN 1 /* in-2 */ 350 + #define MAYA_MIC_IN 4 /* in-5 */ 351 + 352 + static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) 353 + { 354 + wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX, 355 + 0x1f, 1 << line); 356 + } 357 + 358 + static int maya_rec_src_info(struct snd_kcontrol *kcontrol, 359 + struct snd_ctl_elem_info *uinfo) 360 + { 361 + static char *texts[] = { "Line", "Mic" }; 362 + 363 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 364 + uinfo->count = 1; 365 + uinfo->value.enumerated.items = ARRAY_SIZE(texts); 366 + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 367 + uinfo->value.enumerated.item = 368 + uinfo->value.enumerated.items - 1; 369 + strcpy(uinfo->value.enumerated.name, 370 + texts[uinfo->value.enumerated.item]); 371 + return 0; 372 + } 373 + 374 + static int maya_rec_src_get(struct snd_kcontrol *kcontrol, 375 + struct snd_ctl_elem_value *ucontrol) 376 + { 377 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 378 + int sel; 379 + 380 + if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY)) 381 + sel = 1; 382 + else 383 + sel = 0; 384 + ucontrol->value.enumerated.item[0] = sel; 385 + return 0; 386 + } 387 + 388 + static int maya_rec_src_put(struct snd_kcontrol *kcontrol, 389 + struct snd_ctl_elem_value *ucontrol) 390 + { 391 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 392 + int sel = ucontrol->value.enumerated.item[0]; 393 + int changed; 394 + 395 + mutex_lock(&chip->mutex); 396 + changed = maya_set_gpio_bits(chip->ice, GPIO_MIC_RELAY, 397 + sel ? GPIO_MIC_RELAY : 0); 398 + wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); 399 + mutex_unlock(&chip->mutex); 400 + return changed; 401 + } 402 + 403 + /* 404 + * Maya44 routing switch settings have different meanings than the standard 405 + * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c). 406 + */ 407 + static int maya_pb_route_info(struct snd_kcontrol *kcontrol, 408 + struct snd_ctl_elem_info *uinfo) 409 + { 410 + static char *texts[] = { 411 + "PCM Out", /* 0 */ 412 + "Input 1", "Input 2", "Input 3", "Input 4" 413 + }; 414 + 415 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 416 + uinfo->count = 1; 417 + uinfo->value.enumerated.items = ARRAY_SIZE(texts); 418 + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) 419 + uinfo->value.enumerated.item = 420 + uinfo->value.enumerated.items - 1; 421 + strcpy(uinfo->value.enumerated.name, 422 + texts[uinfo->value.enumerated.item]); 423 + return 0; 424 + } 425 + 426 + static int maya_pb_route_shift(int idx) 427 + { 428 + static const unsigned char shift[10] = 429 + { 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 }; 430 + return shift[idx % 10]; 431 + } 432 + 433 + static int maya_pb_route_get(struct snd_kcontrol *kcontrol, 434 + struct snd_ctl_elem_value *ucontrol) 435 + { 436 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 437 + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 438 + ucontrol->value.enumerated.item[0] = 439 + snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx)); 440 + return 0; 441 + } 442 + 443 + static int maya_pb_route_put(struct snd_kcontrol *kcontrol, 444 + struct snd_ctl_elem_value *ucontrol) 445 + { 446 + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 447 + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 448 + return snd_ice1724_put_route_val(chip->ice, 449 + ucontrol->value.enumerated.item[0], 450 + maya_pb_route_shift(idx)); 451 + } 452 + 453 + 454 + /* 455 + * controls to be added 456 + */ 457 + 458 + static struct snd_kcontrol_new maya_controls[] __devinitdata = { 459 + { 460 + .name = "Crossmix Playback Volume", 461 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 462 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 463 + SNDRV_CTL_ELEM_ACCESS_TLV_READ, 464 + .info = maya_vol_info, 465 + .get = maya_vol_get, 466 + .put = maya_vol_put, 467 + .tlv = { .p = db_scale_hp }, 468 + .private_value = WM_VOL_HP, 469 + .count = 2, 470 + }, 471 + { 472 + .name = "PCM Playback Volume", 473 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 474 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 475 + SNDRV_CTL_ELEM_ACCESS_TLV_READ, 476 + .info = maya_vol_info, 477 + .get = maya_vol_get, 478 + .put = maya_vol_put, 479 + .tlv = { .p = db_scale_dac }, 480 + .private_value = WM_VOL_DAC, 481 + .count = 2, 482 + }, 483 + { 484 + .name = "Line Capture Volume", 485 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 486 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 487 + SNDRV_CTL_ELEM_ACCESS_TLV_READ, 488 + .info = maya_vol_info, 489 + .get = maya_vol_get, 490 + .put = maya_vol_put, 491 + .tlv = { .p = db_scale_adc }, 492 + .private_value = WM_VOL_ADC, 493 + .count = 2, 494 + }, 495 + { 496 + .name = "PCM Playback Switch", 497 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 498 + .info = maya_sw_info, 499 + .get = maya_sw_get, 500 + .put = maya_sw_put, 501 + .private_value = COMPOSE_SW_VAL(WM_SW_DAC, 502 + WM8776_REG_OUTPUT_MUX, 0x01), 503 + .count = 2, 504 + }, 505 + { 506 + .name = "Bypass Playback Switch", 507 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 508 + .info = maya_sw_info, 509 + .get = maya_sw_get, 510 + .put = maya_sw_put, 511 + .private_value = COMPOSE_SW_VAL(WM_SW_BYPASS, 512 + WM8776_REG_OUTPUT_MUX, 0x04), 513 + .count = 2, 514 + }, 515 + { 516 + .name = "Capture Source", 517 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 518 + .info = maya_rec_src_info, 519 + .get = maya_rec_src_get, 520 + .put = maya_rec_src_put, 521 + }, 522 + { 523 + .name = "Mic Phantom Power Switch", 524 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 525 + .info = maya_gpio_sw_info, 526 + .get = maya_gpio_sw_get, 527 + .put = maya_gpio_sw_put, 528 + .private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1), 529 + }, 530 + { 531 + .name = "SPDIF Capture Switch", 532 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 533 + .info = maya_gpio_sw_info, 534 + .get = maya_gpio_sw_get, 535 + .put = maya_gpio_sw_put, 536 + .private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1), 537 + }, 538 + { 539 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 540 + .name = "H/W Playback Route", 541 + .info = maya_pb_route_info, 542 + .get = maya_pb_route_get, 543 + .put = maya_pb_route_put, 544 + .count = 4, /* FIXME: do controls 5-9 have any meaning? */ 545 + }, 546 + }; 547 + 548 + static int __devinit maya44_add_controls(struct snd_ice1712 *ice) 549 + { 550 + int err, i; 551 + 552 + for (i = 0; i < ARRAY_SIZE(maya_controls); i++) { 553 + err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i], 554 + ice->spec)); 555 + if (err < 0) 556 + return err; 557 + } 558 + return 0; 559 + } 560 + 561 + 562 + /* 563 + * initialize a wm8776 chip 564 + */ 565 + static void __devinit wm8776_init(struct snd_ice1712 *ice, 566 + struct snd_wm8776 *wm, unsigned int addr) 567 + { 568 + static const unsigned short inits_wm8776[] = { 569 + 0x02, 0x100, /* R2: headphone L+R muted + update */ 570 + 0x05, 0x100, /* R5: DAC output L+R muted + update */ 571 + 0x06, 0x000, /* R6: DAC output phase normal */ 572 + 0x07, 0x091, /* R7: DAC enable zero cross detection, 573 + normal output */ 574 + 0x08, 0x000, /* R8: DAC soft mute off */ 575 + 0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */ 576 + 0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */ 577 + 0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit, 578 + highpass filter enabled */ 579 + 0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */ 580 + 0x0d, 0x000, /* R13: all power up */ 581 + 0x0e, 0x100, /* R14: ADC left muted, 582 + enable zero cross detection */ 583 + 0x0f, 0x100, /* R15: ADC right muted, 584 + enable zero cross detection */ 585 + /* R16: ALC...*/ 586 + 0x11, 0x000, /* R17: disable ALC */ 587 + /* R18: ALC...*/ 588 + /* R19: noise gate...*/ 589 + 0x15, 0x000, /* R21: ADC input mux init, mute all inputs */ 590 + 0x16, 0x001, /* R22: output mux, select DAC */ 591 + 0xff, 0xff 592 + }; 593 + 594 + const unsigned short *ptr; 595 + unsigned char reg; 596 + unsigned short data; 597 + 598 + wm->addr = addr; 599 + /* enable DAC output; mute bypass, aux & all inputs */ 600 + wm->switch_bits = (1 << WM_SW_DAC); 601 + 602 + ptr = inits_wm8776; 603 + while (*ptr != 0xff) { 604 + reg = *ptr++; 605 + data = *ptr++; 606 + wm8776_write(ice, wm, reg, data); 607 + } 608 + } 609 + 610 + 611 + /* 612 + * change the rate on the WM8776 codecs. 613 + * this assumes that the VT17xx's rate is changed by the calling function. 614 + * NOTE: even though the WM8776's are running in slave mode and rate 615 + * selection is automatic, we need to call snd_wm8776_set_rate() here 616 + * to make sure some flags are set correctly. 617 + */ 618 + static void set_rate(struct snd_ice1712 *ice, unsigned int rate) 619 + { 620 + struct snd_maya44 *chip = ice->spec; 621 + unsigned int ratio, adc_ratio, val; 622 + int i; 623 + 624 + switch (rate) { 625 + case 192000: 626 + ratio = WM8776_CLOCK_RATIO_128FS; 627 + break; 628 + case 176400: 629 + ratio = WM8776_CLOCK_RATIO_128FS; 630 + break; 631 + case 96000: 632 + ratio = WM8776_CLOCK_RATIO_256FS; 633 + break; 634 + case 88200: 635 + ratio = WM8776_CLOCK_RATIO_384FS; 636 + break; 637 + case 48000: 638 + ratio = WM8776_CLOCK_RATIO_512FS; 639 + break; 640 + case 44100: 641 + ratio = WM8776_CLOCK_RATIO_512FS; 642 + break; 643 + case 32000: 644 + ratio = WM8776_CLOCK_RATIO_768FS; 645 + break; 646 + case 0: 647 + /* no hint - S/PDIF input is master, simply return */ 648 + return; 649 + default: 650 + snd_BUG(); 651 + return; 652 + } 653 + 654 + /* 655 + * this currently sets the same rate for ADC and DAC, but limits 656 + * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC 657 + * oversampling to 64x, as recommended by WM8776 datasheet. 658 + * Setting the rate is not really necessary in slave mode. 659 + */ 660 + adc_ratio = ratio; 661 + if (adc_ratio < WM8776_CLOCK_RATIO_256FS) 662 + adc_ratio = WM8776_CLOCK_RATIO_256FS; 663 + 664 + val = adc_ratio; 665 + if (adc_ratio == WM8776_CLOCK_RATIO_256FS) 666 + val |= 8; 667 + val |= ratio << 4; 668 + 669 + mutex_lock(&chip->mutex); 670 + for (i = 0; i < 2; i++) 671 + wm8776_write_bits(ice, &chip->wm[i], 672 + WM8776_REG_MASTER_MODE_CONTROL, 673 + 0x180, val); 674 + mutex_unlock(&chip->mutex); 675 + } 676 + 677 + /* 678 + * supported sample rates (to override the default one) 679 + */ 680 + 681 + static unsigned int rates[] = { 682 + 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 683 + }; 684 + 685 + /* playback rates: 32..192 kHz */ 686 + static struct snd_pcm_hw_constraint_list dac_rates = { 687 + .count = ARRAY_SIZE(rates), 688 + .list = rates, 689 + .mask = 0 690 + }; 691 + 692 + 693 + /* 694 + * chip addresses on I2C bus 695 + */ 696 + static unsigned char wm8776_addr[2] __devinitdata = { 697 + 0x34, 0x36, /* codec 0 & 1 */ 698 + }; 699 + 700 + /* 701 + * initialize the chip 702 + */ 703 + static int __devinit maya44_init(struct snd_ice1712 *ice) 704 + { 705 + int i; 706 + struct snd_maya44 *chip; 707 + 708 + chip = kzalloc(sizeof(*chip), GFP_KERNEL); 709 + if (!chip) 710 + return -ENOMEM; 711 + mutex_init(&chip->mutex); 712 + chip->ice = ice; 713 + ice->spec = chip; 714 + 715 + /* initialise codecs */ 716 + ice->num_total_dacs = 4; 717 + ice->num_total_adcs = 4; 718 + ice->akm_codecs = 0; 719 + 720 + for (i = 0; i < 2; i++) { 721 + wm8776_init(ice, &chip->wm[i], wm8776_addr[i]); 722 + wm8776_select_input(chip, i, MAYA_LINE_IN); 723 + } 724 + 725 + /* set card specific rates */ 726 + ice->hw_rates = &dac_rates; 727 + 728 + /* register change rate notifier */ 729 + ice->gpio.set_pro_rate = set_rate; 730 + 731 + /* RDMA1 (2nd input channel) is used for ADC by default */ 732 + ice->force_rdma1 = 1; 733 + 734 + /* have an own routing control */ 735 + ice->own_routing = 1; 736 + 737 + return 0; 738 + } 739 + 740 + 741 + /* 742 + * Maya44 boards don't provide the EEPROM data except for the vendor IDs. 743 + * hence the driver needs to sets up it properly. 744 + */ 745 + 746 + static unsigned char maya44_eeprom[] __devinitdata = { 747 + [ICE_EEP2_SYSCONF] = 0x45, 748 + /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ 749 + [ICE_EEP2_ACLINK] = 0x80, 750 + /* I2S */ 751 + [ICE_EEP2_I2S] = 0xf8, 752 + /* vol, 96k, 24bit, 192k */ 753 + [ICE_EEP2_SPDIF] = 0xc3, 754 + /* enable spdif out, spdif out supp, spdif-in, ext spdif out */ 755 + [ICE_EEP2_GPIO_DIR] = 0xff, 756 + [ICE_EEP2_GPIO_DIR1] = 0xff, 757 + [ICE_EEP2_GPIO_DIR2] = 0xff, 758 + [ICE_EEP2_GPIO_MASK] = 0/*0x9f*/, 759 + [ICE_EEP2_GPIO_MASK1] = 0/*0xff*/, 760 + [ICE_EEP2_GPIO_MASK2] = 0/*0x7f*/, 761 + [ICE_EEP2_GPIO_STATE] = (1 << GPIO_PHANTOM_OFF) | 762 + (1 << GPIO_SPDIF_IN_INV), 763 + [ICE_EEP2_GPIO_STATE1] = 0x00, 764 + [ICE_EEP2_GPIO_STATE2] = 0x00, 765 + }; 766 + 767 + /* entry point */ 768 + struct snd_ice1712_card_info snd_vt1724_maya44_cards[] __devinitdata = { 769 + { 770 + .subvendor = VT1724_SUBDEVICE_MAYA44, 771 + .name = "ESI Maya44", 772 + .model = "maya44", 773 + .chip_init = maya44_init, 774 + .build_controls = maya44_add_controls, 775 + .eeprom_size = sizeof(maya44_eeprom), 776 + .eeprom_data = maya44_eeprom, 777 + }, 778 + { } /* terminator */ 779 + };
+10
sound/pci/ice1712/maya44.h
··· 1 + #ifndef __SOUND_MAYA44_H 2 + #define __SOUND_MAYA44_H 3 + 4 + #define MAYA44_DEVICE_DESC "{ESI,Maya44}," 5 + 6 + #define VT1724_SUBDEVICE_MAYA44 0x34315441 /* Maya44 */ 7 + 8 + extern struct snd_ice1712_card_info snd_vt1724_maya44_cards[]; 9 + 10 + #endif /* __SOUND_MAYA44_H */