11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 3c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 41da177e4SLinus Torvalds * Routines for Sound Blaster mixer control 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 76cbbfe1cSTakashi Iwai #include <linux/io.h> 81da177e4SLinus Torvalds #include <linux/delay.h> 91da177e4SLinus Torvalds #include <linux/time.h> 101da177e4SLinus Torvalds #include <sound/core.h> 111da177e4SLinus Torvalds #include <sound/sb.h> 121da177e4SLinus Torvalds #include <sound/control.h> 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #undef IO_DEBUG 151da177e4SLinus Torvalds 16029d64b0STakashi Iwai void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data) 171da177e4SLinus Torvalds { 181da177e4SLinus Torvalds outb(reg, SBP(chip, MIXER_ADDR)); 191da177e4SLinus Torvalds udelay(10); 201da177e4SLinus Torvalds outb(data, SBP(chip, MIXER_DATA)); 211da177e4SLinus Torvalds udelay(10); 221da177e4SLinus Torvalds #ifdef IO_DEBUG 2399b359baSTakashi Iwai snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data); 241da177e4SLinus Torvalds #endif 251da177e4SLinus Torvalds } 261da177e4SLinus Torvalds 27029d64b0STakashi Iwai unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg) 281da177e4SLinus Torvalds { 291da177e4SLinus Torvalds unsigned char result; 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds outb(reg, SBP(chip, MIXER_ADDR)); 321da177e4SLinus Torvalds udelay(10); 331da177e4SLinus Torvalds result = inb(SBP(chip, MIXER_DATA)); 341da177e4SLinus Torvalds udelay(10); 351da177e4SLinus Torvalds #ifdef IO_DEBUG 3699b359baSTakashi Iwai snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result); 371da177e4SLinus Torvalds #endif 381da177e4SLinus Torvalds return result; 391da177e4SLinus Torvalds } 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* 421da177e4SLinus Torvalds * Single channel mixer element 431da177e4SLinus Torvalds */ 441da177e4SLinus Torvalds 45029d64b0STakashi Iwai static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 501da177e4SLinus Torvalds uinfo->count = 1; 511da177e4SLinus Torvalds uinfo->value.integer.min = 0; 521da177e4SLinus Torvalds uinfo->value.integer.max = mask; 531da177e4SLinus Torvalds return 0; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 56029d64b0STakashi Iwai static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 571da177e4SLinus Torvalds { 58029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 591da177e4SLinus Torvalds unsigned long flags; 601da177e4SLinus Torvalds int reg = kcontrol->private_value & 0xff; 611da177e4SLinus Torvalds int shift = (kcontrol->private_value >> 16) & 0xff; 621da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 631da177e4SLinus Torvalds unsigned char val; 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 661da177e4SLinus Torvalds val = (snd_sbmixer_read(sb, reg) >> shift) & mask; 671da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 681da177e4SLinus Torvalds ucontrol->value.integer.value[0] = val; 691da177e4SLinus Torvalds return 0; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 72029d64b0STakashi Iwai static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 731da177e4SLinus Torvalds { 74029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 751da177e4SLinus Torvalds unsigned long flags; 761da177e4SLinus Torvalds int reg = kcontrol->private_value & 0xff; 771da177e4SLinus Torvalds int shift = (kcontrol->private_value >> 16) & 0x07; 781da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 791da177e4SLinus Torvalds int change; 801da177e4SLinus Torvalds unsigned char val, oval; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds val = (ucontrol->value.integer.value[0] & mask) << shift; 831da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 841da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, reg); 851da177e4SLinus Torvalds val = (oval & ~(mask << shift)) | val; 861da177e4SLinus Torvalds change = val != oval; 871da177e4SLinus Torvalds if (change) 881da177e4SLinus Torvalds snd_sbmixer_write(sb, reg, val); 891da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 901da177e4SLinus Torvalds return change; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds /* 941da177e4SLinus Torvalds * Double channel mixer element 951da177e4SLinus Torvalds */ 961da177e4SLinus Torvalds 97029d64b0STakashi Iwai static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 981da177e4SLinus Torvalds { 991da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 1021da177e4SLinus Torvalds uinfo->count = 2; 1031da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1041da177e4SLinus Torvalds uinfo->value.integer.max = mask; 1051da177e4SLinus Torvalds return 0; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 108029d64b0STakashi Iwai static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1091da177e4SLinus Torvalds { 110029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 1111da177e4SLinus Torvalds unsigned long flags; 1121da177e4SLinus Torvalds int left_reg = kcontrol->private_value & 0xff; 1131da177e4SLinus Torvalds int right_reg = (kcontrol->private_value >> 8) & 0xff; 1141da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x07; 1151da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 19) & 0x07; 1161da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1171da177e4SLinus Torvalds unsigned char left, right; 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1201da177e4SLinus Torvalds left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask; 1211da177e4SLinus Torvalds right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask; 1221da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1231da177e4SLinus Torvalds ucontrol->value.integer.value[0] = left; 1241da177e4SLinus Torvalds ucontrol->value.integer.value[1] = right; 1251da177e4SLinus Torvalds return 0; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 128029d64b0STakashi Iwai static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1291da177e4SLinus Torvalds { 130029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 1311da177e4SLinus Torvalds unsigned long flags; 1321da177e4SLinus Torvalds int left_reg = kcontrol->private_value & 0xff; 1331da177e4SLinus Torvalds int right_reg = (kcontrol->private_value >> 8) & 0xff; 1341da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x07; 1351da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 19) & 0x07; 1361da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1371da177e4SLinus Torvalds int change; 1381da177e4SLinus Torvalds unsigned char left, right, oleft, oright; 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds left = (ucontrol->value.integer.value[0] & mask) << left_shift; 1411da177e4SLinus Torvalds right = (ucontrol->value.integer.value[1] & mask) << right_shift; 1421da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1431da177e4SLinus Torvalds if (left_reg == right_reg) { 1441da177e4SLinus Torvalds oleft = snd_sbmixer_read(sb, left_reg); 1451da177e4SLinus Torvalds left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right; 1461da177e4SLinus Torvalds change = left != oleft; 1471da177e4SLinus Torvalds if (change) 1481da177e4SLinus Torvalds snd_sbmixer_write(sb, left_reg, left); 1491da177e4SLinus Torvalds } else { 1501da177e4SLinus Torvalds oleft = snd_sbmixer_read(sb, left_reg); 1511da177e4SLinus Torvalds oright = snd_sbmixer_read(sb, right_reg); 1521da177e4SLinus Torvalds left = (oleft & ~(mask << left_shift)) | left; 1531da177e4SLinus Torvalds right = (oright & ~(mask << right_shift)) | right; 1541da177e4SLinus Torvalds change = left != oleft || right != oright; 1551da177e4SLinus Torvalds if (change) { 1561da177e4SLinus Torvalds snd_sbmixer_write(sb, left_reg, left); 1571da177e4SLinus Torvalds snd_sbmixer_write(sb, right_reg, right); 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1611da177e4SLinus Torvalds return change; 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds /* 1651da177e4SLinus Torvalds * DT-019x / ALS-007 capture/input switch 1661da177e4SLinus Torvalds */ 1671da177e4SLinus Torvalds 168029d64b0STakashi Iwai static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 1691da177e4SLinus Torvalds { 1706b9e1288STakashi Iwai static const char * const texts[5] = { 1711da177e4SLinus Torvalds "CD", "Mic", "Line", "Synth", "Master" 1721da177e4SLinus Torvalds }; 1731da177e4SLinus Torvalds 1746b9e1288STakashi Iwai return snd_ctl_enum_info(uinfo, 1, 5, texts); 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 177029d64b0STakashi Iwai static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1781da177e4SLinus Torvalds { 179029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 1801da177e4SLinus Torvalds unsigned long flags; 1811da177e4SLinus Torvalds unsigned char oval; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1841da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 1851da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1861da177e4SLinus Torvalds switch (oval & 0x07) { 1871da177e4SLinus Torvalds case SB_DT019X_CAP_CD: 1881da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 1891da177e4SLinus Torvalds break; 1901da177e4SLinus Torvalds case SB_DT019X_CAP_MIC: 1911da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 1921da177e4SLinus Torvalds break; 1931da177e4SLinus Torvalds case SB_DT019X_CAP_LINE: 1941da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 1951da177e4SLinus Torvalds break; 1961da177e4SLinus Torvalds case SB_DT019X_CAP_MAIN: 1971da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 4; 1981da177e4SLinus Torvalds break; 1991da177e4SLinus Torvalds /* To record the synth on these cards you must record the main. */ 2001da177e4SLinus Torvalds /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */ 2011da177e4SLinus Torvalds /* duplicate case labels if left uncommented. */ 2021da177e4SLinus Torvalds /* case SB_DT019X_CAP_SYNTH: 2031da177e4SLinus Torvalds * ucontrol->value.enumerated.item[0] = 3; 2041da177e4SLinus Torvalds * break; 2051da177e4SLinus Torvalds */ 2061da177e4SLinus Torvalds default: 2071da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 4; 2081da177e4SLinus Torvalds break; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds return 0; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 213029d64b0STakashi Iwai static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2141da177e4SLinus Torvalds { 215029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 2161da177e4SLinus Torvalds unsigned long flags; 2171da177e4SLinus Torvalds int change; 2181da177e4SLinus Torvalds unsigned char nval, oval; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds if (ucontrol->value.enumerated.item[0] > 4) 2211da177e4SLinus Torvalds return -EINVAL; 2221da177e4SLinus Torvalds switch (ucontrol->value.enumerated.item[0]) { 2231da177e4SLinus Torvalds case 0: 2241da177e4SLinus Torvalds nval = SB_DT019X_CAP_CD; 2251da177e4SLinus Torvalds break; 2261da177e4SLinus Torvalds case 1: 2271da177e4SLinus Torvalds nval = SB_DT019X_CAP_MIC; 2281da177e4SLinus Torvalds break; 2291da177e4SLinus Torvalds case 2: 2301da177e4SLinus Torvalds nval = SB_DT019X_CAP_LINE; 2311da177e4SLinus Torvalds break; 2321da177e4SLinus Torvalds case 3: 2331da177e4SLinus Torvalds nval = SB_DT019X_CAP_SYNTH; 2341da177e4SLinus Torvalds break; 2351da177e4SLinus Torvalds case 4: 2361da177e4SLinus Torvalds nval = SB_DT019X_CAP_MAIN; 2371da177e4SLinus Torvalds break; 2381da177e4SLinus Torvalds default: 2391da177e4SLinus Torvalds nval = SB_DT019X_CAP_MAIN; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 2421da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 2431da177e4SLinus Torvalds change = nval != oval; 2441da177e4SLinus Torvalds if (change) 2451da177e4SLinus Torvalds snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval); 2461da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 2471da177e4SLinus Torvalds return change; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* 251ce71bfd1SAndreas Mohr * ALS4000 mono recording control switch 252ce71bfd1SAndreas Mohr */ 253ce71bfd1SAndreas Mohr 254ce71bfd1SAndreas Mohr static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol, 255ce71bfd1SAndreas Mohr struct snd_ctl_elem_info *uinfo) 256ce71bfd1SAndreas Mohr { 2576b9e1288STakashi Iwai static const char * const texts[3] = { 258ce71bfd1SAndreas Mohr "L chan only", "R chan only", "L ch/2 + R ch/2" 259ce71bfd1SAndreas Mohr }; 260ce71bfd1SAndreas Mohr 2616b9e1288STakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 262ce71bfd1SAndreas Mohr } 263ce71bfd1SAndreas Mohr 264ce71bfd1SAndreas Mohr static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol, 265ce71bfd1SAndreas Mohr struct snd_ctl_elem_value *ucontrol) 266ce71bfd1SAndreas Mohr { 267ce71bfd1SAndreas Mohr struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 268ce71bfd1SAndreas Mohr unsigned long flags; 269ce71bfd1SAndreas Mohr unsigned char oval; 270ce71bfd1SAndreas Mohr 271ce71bfd1SAndreas Mohr spin_lock_irqsave(&sb->mixer_lock, flags); 272ce71bfd1SAndreas Mohr oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL); 273ce71bfd1SAndreas Mohr spin_unlock_irqrestore(&sb->mixer_lock, flags); 274ce71bfd1SAndreas Mohr oval >>= 6; 275ce71bfd1SAndreas Mohr if (oval > 2) 276ce71bfd1SAndreas Mohr oval = 2; 277ce71bfd1SAndreas Mohr 278ce71bfd1SAndreas Mohr ucontrol->value.enumerated.item[0] = oval; 279ce71bfd1SAndreas Mohr return 0; 280ce71bfd1SAndreas Mohr } 281ce71bfd1SAndreas Mohr 282ce71bfd1SAndreas Mohr static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol, 283ce71bfd1SAndreas Mohr struct snd_ctl_elem_value *ucontrol) 284ce71bfd1SAndreas Mohr { 285ce71bfd1SAndreas Mohr struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 286ce71bfd1SAndreas Mohr unsigned long flags; 287ce71bfd1SAndreas Mohr int change; 288ce71bfd1SAndreas Mohr unsigned char nval, oval; 289ce71bfd1SAndreas Mohr 290ce71bfd1SAndreas Mohr if (ucontrol->value.enumerated.item[0] > 2) 291ce71bfd1SAndreas Mohr return -EINVAL; 292ce71bfd1SAndreas Mohr spin_lock_irqsave(&sb->mixer_lock, flags); 293ce71bfd1SAndreas Mohr oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL); 294ce71bfd1SAndreas Mohr 295ce71bfd1SAndreas Mohr nval = (oval & ~(3 << 6)) 296ce71bfd1SAndreas Mohr | (ucontrol->value.enumerated.item[0] << 6); 297ce71bfd1SAndreas Mohr change = nval != oval; 298ce71bfd1SAndreas Mohr if (change) 299ce71bfd1SAndreas Mohr snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval); 300ce71bfd1SAndreas Mohr spin_unlock_irqrestore(&sb->mixer_lock, flags); 301ce71bfd1SAndreas Mohr return change; 302ce71bfd1SAndreas Mohr } 303ce71bfd1SAndreas Mohr 304ce71bfd1SAndreas Mohr /* 3051da177e4SLinus Torvalds * SBPRO input multiplexer 3061da177e4SLinus Torvalds */ 3071da177e4SLinus Torvalds 308029d64b0STakashi Iwai static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 3091da177e4SLinus Torvalds { 3106b9e1288STakashi Iwai static const char * const texts[3] = { 3111da177e4SLinus Torvalds "Mic", "CD", "Line" 3121da177e4SLinus Torvalds }; 3131da177e4SLinus Torvalds 3146b9e1288STakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds 318029d64b0STakashi Iwai static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3191da177e4SLinus Torvalds { 320029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 3211da177e4SLinus Torvalds unsigned long flags; 3221da177e4SLinus Torvalds unsigned char oval; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 3251da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 3261da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 3271da177e4SLinus Torvalds switch ((oval >> 0x01) & 0x03) { 3281da177e4SLinus Torvalds case SB_DSP_MIXS_CD: 3291da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 3301da177e4SLinus Torvalds break; 3311da177e4SLinus Torvalds case SB_DSP_MIXS_LINE: 3321da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 3331da177e4SLinus Torvalds break; 3341da177e4SLinus Torvalds default: 3351da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 3361da177e4SLinus Torvalds break; 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds return 0; 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds 341029d64b0STakashi Iwai static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3421da177e4SLinus Torvalds { 343029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 3441da177e4SLinus Torvalds unsigned long flags; 3451da177e4SLinus Torvalds int change; 3461da177e4SLinus Torvalds unsigned char nval, oval; 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds if (ucontrol->value.enumerated.item[0] > 2) 3491da177e4SLinus Torvalds return -EINVAL; 3501da177e4SLinus Torvalds switch (ucontrol->value.enumerated.item[0]) { 3511da177e4SLinus Torvalds case 1: 3521da177e4SLinus Torvalds nval = SB_DSP_MIXS_CD; 3531da177e4SLinus Torvalds break; 3541da177e4SLinus Torvalds case 2: 3551da177e4SLinus Torvalds nval = SB_DSP_MIXS_LINE; 3561da177e4SLinus Torvalds break; 3571da177e4SLinus Torvalds default: 3581da177e4SLinus Torvalds nval = SB_DSP_MIXS_MIC; 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds nval <<= 1; 3611da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 3621da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 3631da177e4SLinus Torvalds nval |= oval & ~0x06; 3641da177e4SLinus Torvalds change = nval != oval; 3651da177e4SLinus Torvalds if (change) 3661da177e4SLinus Torvalds snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval); 3671da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 3681da177e4SLinus Torvalds return change; 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /* 3721da177e4SLinus Torvalds * SB16 input switch 3731da177e4SLinus Torvalds */ 3741da177e4SLinus Torvalds 375029d64b0STakashi Iwai static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 3761da177e4SLinus Torvalds { 3771da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 3781da177e4SLinus Torvalds uinfo->count = 4; 3791da177e4SLinus Torvalds uinfo->value.integer.min = 0; 3801da177e4SLinus Torvalds uinfo->value.integer.max = 1; 3811da177e4SLinus Torvalds return 0; 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds 384029d64b0STakashi Iwai static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3851da177e4SLinus Torvalds { 386029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 3871da177e4SLinus Torvalds unsigned long flags; 3881da177e4SLinus Torvalds int reg1 = kcontrol->private_value & 0xff; 3891da177e4SLinus Torvalds int reg2 = (kcontrol->private_value >> 8) & 0xff; 3901da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x0f; 3911da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 24) & 0x0f; 3921da177e4SLinus Torvalds unsigned char val1, val2; 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 3951da177e4SLinus Torvalds val1 = snd_sbmixer_read(sb, reg1); 3961da177e4SLinus Torvalds val2 = snd_sbmixer_read(sb, reg2); 3971da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 3981da177e4SLinus Torvalds ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01; 3991da177e4SLinus Torvalds ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01; 4001da177e4SLinus Torvalds ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01; 4011da177e4SLinus Torvalds ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01; 4021da177e4SLinus Torvalds return 0; 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds 405029d64b0STakashi Iwai static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4061da177e4SLinus Torvalds { 407029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 4081da177e4SLinus Torvalds unsigned long flags; 4091da177e4SLinus Torvalds int reg1 = kcontrol->private_value & 0xff; 4101da177e4SLinus Torvalds int reg2 = (kcontrol->private_value >> 8) & 0xff; 4111da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x0f; 4121da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 24) & 0x0f; 4131da177e4SLinus Torvalds int change; 4141da177e4SLinus Torvalds unsigned char val1, val2, oval1, oval2; 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 4171da177e4SLinus Torvalds oval1 = snd_sbmixer_read(sb, reg1); 4181da177e4SLinus Torvalds oval2 = snd_sbmixer_read(sb, reg2); 4191da177e4SLinus Torvalds val1 = oval1 & ~((1 << left_shift) | (1 << right_shift)); 4201da177e4SLinus Torvalds val2 = oval2 & ~((1 << left_shift) | (1 << right_shift)); 4211da177e4SLinus Torvalds val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift; 4221da177e4SLinus Torvalds val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift; 4231da177e4SLinus Torvalds val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift; 4241da177e4SLinus Torvalds val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift; 4251da177e4SLinus Torvalds change = val1 != oval1 || val2 != oval2; 4261da177e4SLinus Torvalds if (change) { 4271da177e4SLinus Torvalds snd_sbmixer_write(sb, reg1, val1); 4281da177e4SLinus Torvalds snd_sbmixer_write(sb, reg2, val2); 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 4311da177e4SLinus Torvalds return change; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds /* 4361da177e4SLinus Torvalds */ 4371da177e4SLinus Torvalds /* 4381da177e4SLinus Torvalds */ 439029d64b0STakashi Iwai int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value) 4401da177e4SLinus Torvalds { 441029d64b0STakashi Iwai static struct snd_kcontrol_new newctls[] = { 4421da177e4SLinus Torvalds [SB_MIX_SINGLE] = { 4431da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4441da177e4SLinus Torvalds .info = snd_sbmixer_info_single, 4451da177e4SLinus Torvalds .get = snd_sbmixer_get_single, 4461da177e4SLinus Torvalds .put = snd_sbmixer_put_single, 4471da177e4SLinus Torvalds }, 4481da177e4SLinus Torvalds [SB_MIX_DOUBLE] = { 4491da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4501da177e4SLinus Torvalds .info = snd_sbmixer_info_double, 4511da177e4SLinus Torvalds .get = snd_sbmixer_get_double, 4521da177e4SLinus Torvalds .put = snd_sbmixer_put_double, 4531da177e4SLinus Torvalds }, 4541da177e4SLinus Torvalds [SB_MIX_INPUT_SW] = { 4551da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4561da177e4SLinus Torvalds .info = snd_sb16mixer_info_input_sw, 4571da177e4SLinus Torvalds .get = snd_sb16mixer_get_input_sw, 4581da177e4SLinus Torvalds .put = snd_sb16mixer_put_input_sw, 4591da177e4SLinus Torvalds }, 4601da177e4SLinus Torvalds [SB_MIX_CAPTURE_PRO] = { 4611da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4621da177e4SLinus Torvalds .info = snd_sb8mixer_info_mux, 4631da177e4SLinus Torvalds .get = snd_sb8mixer_get_mux, 4641da177e4SLinus Torvalds .put = snd_sb8mixer_put_mux, 4651da177e4SLinus Torvalds }, 4661da177e4SLinus Torvalds [SB_MIX_CAPTURE_DT019X] = { 4671da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4681da177e4SLinus Torvalds .info = snd_dt019x_input_sw_info, 4691da177e4SLinus Torvalds .get = snd_dt019x_input_sw_get, 4701da177e4SLinus Torvalds .put = snd_dt019x_input_sw_put, 4711da177e4SLinus Torvalds }, 472ce71bfd1SAndreas Mohr [SB_MIX_MONO_CAPTURE_ALS4K] = { 473ce71bfd1SAndreas Mohr .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 474ce71bfd1SAndreas Mohr .info = snd_als4k_mono_capture_route_info, 475ce71bfd1SAndreas Mohr .get = snd_als4k_mono_capture_route_get, 476ce71bfd1SAndreas Mohr .put = snd_als4k_mono_capture_route_put, 477ce71bfd1SAndreas Mohr }, 4781da177e4SLinus Torvalds }; 479029d64b0STakashi Iwai struct snd_kcontrol *ctl; 4801da177e4SLinus Torvalds int err; 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds ctl = snd_ctl_new1(&newctls[type], chip); 4831da177e4SLinus Torvalds if (! ctl) 4841da177e4SLinus Torvalds return -ENOMEM; 4851da177e4SLinus Torvalds strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); 4861da177e4SLinus Torvalds ctl->id.index = index; 4871da177e4SLinus Torvalds ctl->private_value = value; 488bcc54f9aSDave Jones if ((err = snd_ctl_add(chip->card, ctl)) < 0) 4891da177e4SLinus Torvalds return err; 4901da177e4SLinus Torvalds return 0; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds /* 4941da177e4SLinus Torvalds * SB 2.0 specific mixer elements 4951da177e4SLinus Torvalds */ 4961da177e4SLinus Torvalds 49774c2b45bSKrzysztof Helt static struct sbmix_elem snd_sb20_controls[] = { 49874c2b45bSKrzysztof Helt SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7), 49974c2b45bSKrzysztof Helt SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3), 50074c2b45bSKrzysztof Helt SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7), 50174c2b45bSKrzysztof Helt SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7) 5021da177e4SLinus Torvalds }; 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds static unsigned char snd_sb20_init_values[][2] = { 5051da177e4SLinus Torvalds { SB_DSP20_MASTER_DEV, 0 }, 5061da177e4SLinus Torvalds { SB_DSP20_FM_DEV, 0 }, 5071da177e4SLinus Torvalds }; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /* 5101da177e4SLinus Torvalds * SB Pro specific mixer elements 5111da177e4SLinus Torvalds */ 51274c2b45bSKrzysztof Helt static struct sbmix_elem snd_sbpro_controls[] = { 51374c2b45bSKrzysztof Helt SB_DOUBLE("Master Playback Volume", 51474c2b45bSKrzysztof Helt SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7), 51574c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Volume", 51674c2b45bSKrzysztof Helt SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7), 51774c2b45bSKrzysztof Helt SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1), 51874c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Volume", 51974c2b45bSKrzysztof Helt SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7), 52074c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7), 52174c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Volume", 52274c2b45bSKrzysztof Helt SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7), 52374c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3), 5241da177e4SLinus Torvalds { 5251da177e4SLinus Torvalds .name = "Capture Source", 5261da177e4SLinus Torvalds .type = SB_MIX_CAPTURE_PRO 52774c2b45bSKrzysztof Helt }, 52874c2b45bSKrzysztof Helt SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1), 52974c2b45bSKrzysztof Helt SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1) 5301da177e4SLinus Torvalds }; 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds static unsigned char snd_sbpro_init_values[][2] = { 5331da177e4SLinus Torvalds { SB_DSP_MASTER_DEV, 0 }, 5341da177e4SLinus Torvalds { SB_DSP_PCM_DEV, 0 }, 5351da177e4SLinus Torvalds { SB_DSP_FM_DEV, 0 }, 5361da177e4SLinus Torvalds }; 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds /* 5391da177e4SLinus Torvalds * SB16 specific mixer elements 5401da177e4SLinus Torvalds */ 54174c2b45bSKrzysztof Helt static struct sbmix_elem snd_sb16_controls[] = { 54274c2b45bSKrzysztof Helt SB_DOUBLE("Master Playback Volume", 54374c2b45bSKrzysztof Helt SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), 54474c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Volume", 54574c2b45bSKrzysztof Helt SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31), 54674c2b45bSKrzysztof Helt SB16_INPUT_SW("Synth Capture Route", 54774c2b45bSKrzysztof Helt SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5), 54874c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Volume", 54974c2b45bSKrzysztof Helt SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31), 55074c2b45bSKrzysztof Helt SB16_INPUT_SW("CD Capture Route", 55174c2b45bSKrzysztof Helt SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1), 55274c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Switch", 55374c2b45bSKrzysztof Helt SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), 55474c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Volume", 55574c2b45bSKrzysztof Helt SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31), 55674c2b45bSKrzysztof Helt SB16_INPUT_SW("Mic Capture Route", 55774c2b45bSKrzysztof Helt SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0), 55874c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), 55974c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), 56074c2b45bSKrzysztof Helt SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), 56174c2b45bSKrzysztof Helt SB_DOUBLE("Capture Volume", 56274c2b45bSKrzysztof Helt SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), 56374c2b45bSKrzysztof Helt SB_DOUBLE("Playback Volume", 56474c2b45bSKrzysztof Helt SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), 56574c2b45bSKrzysztof Helt SB16_INPUT_SW("Line Capture Route", 56674c2b45bSKrzysztof Helt SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3), 56774c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Switch", 56874c2b45bSKrzysztof Helt SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), 56974c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Volume", 57074c2b45bSKrzysztof Helt SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), 57174c2b45bSKrzysztof Helt SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), 57274c2b45bSKrzysztof Helt SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1), 57374c2b45bSKrzysztof Helt SB_DOUBLE("Tone Control - Bass", 57474c2b45bSKrzysztof Helt SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), 57574c2b45bSKrzysztof Helt SB_DOUBLE("Tone Control - Treble", 57674c2b45bSKrzysztof Helt SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15) 5771da177e4SLinus Torvalds }; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds static unsigned char snd_sb16_init_values[][2] = { 5801da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 0, 0 }, 5811da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 1, 0 }, 5821da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 0, 0 }, 5831da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 1, 0 }, 5841da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 0, 0 }, 5851da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 1, 0 }, 5861da177e4SLinus Torvalds { SB_DSP4_INPUT_LEFT, 0 }, 5871da177e4SLinus Torvalds { SB_DSP4_INPUT_RIGHT, 0 }, 5881da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 5891da177e4SLinus Torvalds { SB_DSP4_SPEAKER_DEV, 0 }, 5901da177e4SLinus Torvalds }; 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds /* 5931da177e4SLinus Torvalds * DT019x specific mixer elements 5941da177e4SLinus Torvalds */ 59574c2b45bSKrzysztof Helt static struct sbmix_elem snd_dt019x_controls[] = { 59674c2b45bSKrzysztof Helt /* ALS4000 below has some parts which we might be lacking, 59774c2b45bSKrzysztof Helt * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ 59874c2b45bSKrzysztof Helt SB_DOUBLE("Master Playback Volume", 59974c2b45bSKrzysztof Helt SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15), 60074c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Switch", 60174c2b45bSKrzysztof Helt SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), 60274c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Volume", 60374c2b45bSKrzysztof Helt SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15), 60474c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Switch", 60574c2b45bSKrzysztof Helt SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), 60674c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Volume", 60774c2b45bSKrzysztof Helt SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15), 60874c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Switch", 60974c2b45bSKrzysztof Helt SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), 61074c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Volume", 61174c2b45bSKrzysztof Helt SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15), 61274c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), 61374c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7), 61474c2b45bSKrzysztof Helt SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7), 61574c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Switch", 61674c2b45bSKrzysztof Helt SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), 61774c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Volume", 61874c2b45bSKrzysztof Helt SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15), 6191da177e4SLinus Torvalds { 6201da177e4SLinus Torvalds .name = "Capture Source", 6211da177e4SLinus Torvalds .type = SB_MIX_CAPTURE_DT019X 62274c2b45bSKrzysztof Helt } 6231da177e4SLinus Torvalds }; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds static unsigned char snd_dt019x_init_values[][2] = { 6261da177e4SLinus Torvalds { SB_DT019X_MASTER_DEV, 0 }, 6271da177e4SLinus Torvalds { SB_DT019X_PCM_DEV, 0 }, 6281da177e4SLinus Torvalds { SB_DT019X_SYNTH_DEV, 0 }, 6291da177e4SLinus Torvalds { SB_DT019X_CD_DEV, 0 }, 6301da177e4SLinus Torvalds { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */ 6311da177e4SLinus Torvalds { SB_DT019X_LINE_DEV, 0 }, 6321da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 6331da177e4SLinus Torvalds { SB_DT019X_OUTPUT_SW2, 0 }, 6341da177e4SLinus Torvalds { SB_DT019X_CAPTURE_SW, 0x06 }, 6351da177e4SLinus Torvalds }; 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds /* 6381da177e4SLinus Torvalds * ALS4000 specific mixer elements 6391da177e4SLinus Torvalds */ 64074c2b45bSKrzysztof Helt static struct sbmix_elem snd_als4000_controls[] = { 64174c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Switch", 64274c2b45bSKrzysztof Helt SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), 64374c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Switch", 64474c2b45bSKrzysztof Helt SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), 64574c2b45bSKrzysztof Helt SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03), 64674c2b45bSKrzysztof Helt SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1), 64774c2b45bSKrzysztof Helt { 648ce71bfd1SAndreas Mohr .name = "Master Mono Capture Route", 649ce71bfd1SAndreas Mohr .type = SB_MIX_MONO_CAPTURE_ALS4K 65074c2b45bSKrzysztof Helt }, 65174c2b45bSKrzysztof Helt SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1), 65274c2b45bSKrzysztof Helt SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01), 65374c2b45bSKrzysztof Helt SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01), 654ce71bfd1SAndreas Mohr SB_SINGLE("Digital Loopback Switch", 65574c2b45bSKrzysztof Helt SB_ALS4000_CR3_CONFIGURATION, 7, 0x01), 656ba7301c7SAndreas Mohr /* FIXME: functionality of 3D controls might be swapped, I didn't find 657ba7301c7SAndreas Mohr * a description of how to identify what is supposed to be what */ 65874c2b45bSKrzysztof Helt SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07), 659ba7301c7SAndreas Mohr /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ 66074c2b45bSKrzysztof Helt SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03), 661ba7301c7SAndreas Mohr /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, 662ba7301c7SAndreas Mohr * but what ALSA 3D attribute is that actually? "Center", "Depth", 663ba7301c7SAndreas Mohr * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ 66474c2b45bSKrzysztof Helt SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f), 66574c2b45bSKrzysztof Helt SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01), 666ce71bfd1SAndreas Mohr SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", 66774c2b45bSKrzysztof Helt SB_ALS4000_FMDAC, 5, 0x01), 66844456d37SOlaf Hering #ifdef NOT_AVAILABLE 66974c2b45bSKrzysztof Helt SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01), 67074c2b45bSKrzysztof Helt SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f), 6711da177e4SLinus Torvalds #endif 6721da177e4SLinus Torvalds }; 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds static unsigned char snd_als4000_init_values[][2] = { 6751da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 0, 0 }, 6761da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 1, 0 }, 6771da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 0, 0 }, 6781da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 1, 0 }, 6791da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 0, 0 }, 6801da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 1, 0 }, 6811da177e4SLinus Torvalds { SB_DSP4_SPEAKER_DEV, 0 }, 6821da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 6831da177e4SLinus Torvalds { SB_DSP4_INPUT_LEFT, 0 }, 6841da177e4SLinus Torvalds { SB_DSP4_INPUT_RIGHT, 0 }, 6851da177e4SLinus Torvalds { SB_DT019X_OUTPUT_SW2, 0 }, 6861da177e4SLinus Torvalds { SB_ALS4000_MIC_IN_GAIN, 0 }, 6871da177e4SLinus Torvalds }; 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds /* 6901da177e4SLinus Torvalds */ 691029d64b0STakashi Iwai static int snd_sbmixer_init(struct snd_sb *chip, 69274c2b45bSKrzysztof Helt struct sbmix_elem *controls, 6931da177e4SLinus Torvalds int controls_count, 6941da177e4SLinus Torvalds unsigned char map[][2], 6951da177e4SLinus Torvalds int map_count, 6961da177e4SLinus Torvalds char *name) 6971da177e4SLinus Torvalds { 6981da177e4SLinus Torvalds unsigned long flags; 699029d64b0STakashi Iwai struct snd_card *card = chip->card; 7001da177e4SLinus Torvalds int idx, err; 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds /* mixer reset */ 7031da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 7041da177e4SLinus Torvalds snd_sbmixer_write(chip, 0x00, 0x00); 7051da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds /* mute and zero volume channels */ 7081da177e4SLinus Torvalds for (idx = 0; idx < map_count; idx++) { 7091da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 7101da177e4SLinus Torvalds snd_sbmixer_write(chip, map[idx][0], map[idx][1]); 7111da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds for (idx = 0; idx < controls_count; idx++) { 71574c2b45bSKrzysztof Helt err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]); 71674c2b45bSKrzysztof Helt if (err < 0) 7171da177e4SLinus Torvalds return err; 7181da177e4SLinus Torvalds } 7191da177e4SLinus Torvalds snd_component_add(card, name); 7201da177e4SLinus Torvalds strcpy(card->mixername, name); 7211da177e4SLinus Torvalds return 0; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 724029d64b0STakashi Iwai int snd_sbmixer_new(struct snd_sb *chip) 7251da177e4SLinus Torvalds { 726029d64b0STakashi Iwai struct snd_card *card; 7271da177e4SLinus Torvalds int err; 7281da177e4SLinus Torvalds 729622207dcSTakashi Iwai if (snd_BUG_ON(!chip || !chip->card)) 730622207dcSTakashi Iwai return -EINVAL; 7311da177e4SLinus Torvalds 7321da177e4SLinus Torvalds card = chip->card; 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds switch (chip->hardware) { 7351da177e4SLinus Torvalds case SB_HW_10: 7361da177e4SLinus Torvalds return 0; /* no mixer chip on SB1.x */ 7371da177e4SLinus Torvalds case SB_HW_20: 7381da177e4SLinus Torvalds case SB_HW_201: 7391da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7401da177e4SLinus Torvalds snd_sb20_controls, 7411da177e4SLinus Torvalds ARRAY_SIZE(snd_sb20_controls), 7421da177e4SLinus Torvalds snd_sb20_init_values, 7431da177e4SLinus Torvalds ARRAY_SIZE(snd_sb20_init_values), 7441da177e4SLinus Torvalds "CTL1335")) < 0) 7451da177e4SLinus Torvalds return err; 7461da177e4SLinus Torvalds break; 7471da177e4SLinus Torvalds case SB_HW_PRO: 748ad8decb7SKrzysztof Helt case SB_HW_JAZZ16: 7491da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7501da177e4SLinus Torvalds snd_sbpro_controls, 7511da177e4SLinus Torvalds ARRAY_SIZE(snd_sbpro_controls), 7521da177e4SLinus Torvalds snd_sbpro_init_values, 7531da177e4SLinus Torvalds ARRAY_SIZE(snd_sbpro_init_values), 7541da177e4SLinus Torvalds "CTL1345")) < 0) 7551da177e4SLinus Torvalds return err; 7561da177e4SLinus Torvalds break; 7571da177e4SLinus Torvalds case SB_HW_16: 7581da177e4SLinus Torvalds case SB_HW_ALS100: 759621887aeSTakashi Iwai case SB_HW_CS5530: 7601da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7611da177e4SLinus Torvalds snd_sb16_controls, 7621da177e4SLinus Torvalds ARRAY_SIZE(snd_sb16_controls), 7631da177e4SLinus Torvalds snd_sb16_init_values, 7641da177e4SLinus Torvalds ARRAY_SIZE(snd_sb16_init_values), 7651da177e4SLinus Torvalds "CTL1745")) < 0) 7661da177e4SLinus Torvalds return err; 7671da177e4SLinus Torvalds break; 7681da177e4SLinus Torvalds case SB_HW_ALS4000: 76974c2b45bSKrzysztof Helt /* use only the first 16 controls from SB16 */ 77074c2b45bSKrzysztof Helt err = snd_sbmixer_init(chip, 77174c2b45bSKrzysztof Helt snd_sb16_controls, 77274c2b45bSKrzysztof Helt 16, 77374c2b45bSKrzysztof Helt snd_sb16_init_values, 77474c2b45bSKrzysztof Helt ARRAY_SIZE(snd_sb16_init_values), 77574c2b45bSKrzysztof Helt "ALS4000"); 77674c2b45bSKrzysztof Helt if (err < 0) 77774c2b45bSKrzysztof Helt return err; 7781da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7791da177e4SLinus Torvalds snd_als4000_controls, 7801da177e4SLinus Torvalds ARRAY_SIZE(snd_als4000_controls), 7811da177e4SLinus Torvalds snd_als4000_init_values, 7821da177e4SLinus Torvalds ARRAY_SIZE(snd_als4000_init_values), 7831da177e4SLinus Torvalds "ALS4000")) < 0) 7841da177e4SLinus Torvalds return err; 7851da177e4SLinus Torvalds break; 7861da177e4SLinus Torvalds case SB_HW_DT019X: 787665ebe92SDan Carpenter err = snd_sbmixer_init(chip, 7881da177e4SLinus Torvalds snd_dt019x_controls, 7891da177e4SLinus Torvalds ARRAY_SIZE(snd_dt019x_controls), 7901da177e4SLinus Torvalds snd_dt019x_init_values, 7911da177e4SLinus Torvalds ARRAY_SIZE(snd_dt019x_init_values), 792665ebe92SDan Carpenter "DT019X"); 793665ebe92SDan Carpenter if (err < 0) 794665ebe92SDan Carpenter return err; 7951da177e4SLinus Torvalds break; 7961da177e4SLinus Torvalds default: 7971da177e4SLinus Torvalds strcpy(card->mixername, "???"); 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds return 0; 8001da177e4SLinus Torvalds } 8015bdb6a16STakashi Iwai 8025bdb6a16STakashi Iwai #ifdef CONFIG_PM 8035bdb6a16STakashi Iwai static unsigned char sb20_saved_regs[] = { 8045bdb6a16STakashi Iwai SB_DSP20_MASTER_DEV, 8055bdb6a16STakashi Iwai SB_DSP20_PCM_DEV, 8065bdb6a16STakashi Iwai SB_DSP20_FM_DEV, 8075bdb6a16STakashi Iwai SB_DSP20_CD_DEV, 8085bdb6a16STakashi Iwai }; 8095bdb6a16STakashi Iwai 8105bdb6a16STakashi Iwai static unsigned char sbpro_saved_regs[] = { 8115bdb6a16STakashi Iwai SB_DSP_MASTER_DEV, 8125bdb6a16STakashi Iwai SB_DSP_PCM_DEV, 8135bdb6a16STakashi Iwai SB_DSP_PLAYBACK_FILT, 8145bdb6a16STakashi Iwai SB_DSP_FM_DEV, 8155bdb6a16STakashi Iwai SB_DSP_CD_DEV, 8165bdb6a16STakashi Iwai SB_DSP_LINE_DEV, 8175bdb6a16STakashi Iwai SB_DSP_MIC_DEV, 8185bdb6a16STakashi Iwai SB_DSP_CAPTURE_SOURCE, 8195bdb6a16STakashi Iwai SB_DSP_CAPTURE_FILT, 8205bdb6a16STakashi Iwai }; 8215bdb6a16STakashi Iwai 8225bdb6a16STakashi Iwai static unsigned char sb16_saved_regs[] = { 8235bdb6a16STakashi Iwai SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 8245bdb6a16STakashi Iwai SB_DSP4_3DSE, 8255bdb6a16STakashi Iwai SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1, 8265bdb6a16STakashi Iwai SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1, 8275bdb6a16STakashi Iwai SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 8285bdb6a16STakashi Iwai SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 8295bdb6a16STakashi Iwai SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 8305bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 8315bdb6a16STakashi Iwai SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 8325bdb6a16STakashi Iwai SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1, 8335bdb6a16STakashi Iwai SB_DSP4_MIC_DEV, 8345bdb6a16STakashi Iwai SB_DSP4_SPEAKER_DEV, 8355bdb6a16STakashi Iwai SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 8365bdb6a16STakashi Iwai SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 8375bdb6a16STakashi Iwai SB_DSP4_MIC_AGC 8385bdb6a16STakashi Iwai }; 8395bdb6a16STakashi Iwai 8405bdb6a16STakashi Iwai static unsigned char dt019x_saved_regs[] = { 8415bdb6a16STakashi Iwai SB_DT019X_MASTER_DEV, 8425bdb6a16STakashi Iwai SB_DT019X_PCM_DEV, 8435bdb6a16STakashi Iwai SB_DT019X_SYNTH_DEV, 8445bdb6a16STakashi Iwai SB_DT019X_CD_DEV, 8455bdb6a16STakashi Iwai SB_DT019X_MIC_DEV, 8465bdb6a16STakashi Iwai SB_DT019X_SPKR_DEV, 8475bdb6a16STakashi Iwai SB_DT019X_LINE_DEV, 8485bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 8495bdb6a16STakashi Iwai SB_DT019X_OUTPUT_SW2, 8505bdb6a16STakashi Iwai SB_DT019X_CAPTURE_SW, 8515bdb6a16STakashi Iwai }; 8525bdb6a16STakashi Iwai 8535bdb6a16STakashi Iwai static unsigned char als4000_saved_regs[] = { 854ce71bfd1SAndreas Mohr /* please verify in dsheet whether regs to be added 855ce71bfd1SAndreas Mohr are actually real H/W or just dummy */ 8565bdb6a16STakashi Iwai SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 8575bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 8585bdb6a16STakashi Iwai SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 8595bdb6a16STakashi Iwai SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 8605bdb6a16STakashi Iwai SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 8615bdb6a16STakashi Iwai SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 8625bdb6a16STakashi Iwai SB_DSP4_MIC_DEV, 8635bdb6a16STakashi Iwai SB_DSP4_SPEAKER_DEV, 8645bdb6a16STakashi Iwai SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 8655bdb6a16STakashi Iwai SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 8665bdb6a16STakashi Iwai SB_DT019X_OUTPUT_SW2, 8675bdb6a16STakashi Iwai SB_ALS4000_MONO_IO_CTRL, 8685bdb6a16STakashi Iwai SB_ALS4000_MIC_IN_GAIN, 869ce71bfd1SAndreas Mohr SB_ALS4000_FMDAC, 8705bdb6a16STakashi Iwai SB_ALS4000_3D_SND_FX, 8715bdb6a16STakashi Iwai SB_ALS4000_3D_TIME_DELAY, 872ce71bfd1SAndreas Mohr SB_ALS4000_CR3_CONFIGURATION, 8735bdb6a16STakashi Iwai }; 8745bdb6a16STakashi Iwai 8755bdb6a16STakashi Iwai static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) 8765bdb6a16STakashi Iwai { 8775bdb6a16STakashi Iwai unsigned char *val = chip->saved_regs; 878622207dcSTakashi Iwai if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) 879622207dcSTakashi Iwai return; 8805bdb6a16STakashi Iwai for (; num_regs; num_regs--) 8815bdb6a16STakashi Iwai *val++ = snd_sbmixer_read(chip, *regs++); 8825bdb6a16STakashi Iwai } 8835bdb6a16STakashi Iwai 8845bdb6a16STakashi Iwai static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) 8855bdb6a16STakashi Iwai { 8865bdb6a16STakashi Iwai unsigned char *val = chip->saved_regs; 887622207dcSTakashi Iwai if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) 888622207dcSTakashi Iwai return; 8895bdb6a16STakashi Iwai for (; num_regs; num_regs--) 8905bdb6a16STakashi Iwai snd_sbmixer_write(chip, *regs++, *val++); 8915bdb6a16STakashi Iwai } 8925bdb6a16STakashi Iwai 8935bdb6a16STakashi Iwai void snd_sbmixer_suspend(struct snd_sb *chip) 8945bdb6a16STakashi Iwai { 8955bdb6a16STakashi Iwai switch (chip->hardware) { 8965bdb6a16STakashi Iwai case SB_HW_20: 8975bdb6a16STakashi Iwai case SB_HW_201: 8985bdb6a16STakashi Iwai save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 8995bdb6a16STakashi Iwai break; 9005bdb6a16STakashi Iwai case SB_HW_PRO: 901ad8decb7SKrzysztof Helt case SB_HW_JAZZ16: 9025bdb6a16STakashi Iwai save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 9035bdb6a16STakashi Iwai break; 9045bdb6a16STakashi Iwai case SB_HW_16: 9055bdb6a16STakashi Iwai case SB_HW_ALS100: 906621887aeSTakashi Iwai case SB_HW_CS5530: 9075bdb6a16STakashi Iwai save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 9085bdb6a16STakashi Iwai break; 9095bdb6a16STakashi Iwai case SB_HW_ALS4000: 9105bdb6a16STakashi Iwai save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 9115bdb6a16STakashi Iwai break; 9125bdb6a16STakashi Iwai case SB_HW_DT019X: 9135bdb6a16STakashi Iwai save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 9145bdb6a16STakashi Iwai break; 9155bdb6a16STakashi Iwai default: 9165bdb6a16STakashi Iwai break; 9175bdb6a16STakashi Iwai } 9185bdb6a16STakashi Iwai } 9195bdb6a16STakashi Iwai 9205bdb6a16STakashi Iwai void snd_sbmixer_resume(struct snd_sb *chip) 9215bdb6a16STakashi Iwai { 9225bdb6a16STakashi Iwai switch (chip->hardware) { 9235bdb6a16STakashi Iwai case SB_HW_20: 9245bdb6a16STakashi Iwai case SB_HW_201: 9255bdb6a16STakashi Iwai restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 9265bdb6a16STakashi Iwai break; 9275bdb6a16STakashi Iwai case SB_HW_PRO: 928ad8decb7SKrzysztof Helt case SB_HW_JAZZ16: 9295bdb6a16STakashi Iwai restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 9305bdb6a16STakashi Iwai break; 9315bdb6a16STakashi Iwai case SB_HW_16: 9325bdb6a16STakashi Iwai case SB_HW_ALS100: 933621887aeSTakashi Iwai case SB_HW_CS5530: 9345bdb6a16STakashi Iwai restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 9355bdb6a16STakashi Iwai break; 9365bdb6a16STakashi Iwai case SB_HW_ALS4000: 9375bdb6a16STakashi Iwai restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 9385bdb6a16STakashi Iwai break; 9395bdb6a16STakashi Iwai case SB_HW_DT019X: 9405bdb6a16STakashi Iwai restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 9415bdb6a16STakashi Iwai break; 9425bdb6a16STakashi Iwai default: 9435bdb6a16STakashi Iwai break; 9445bdb6a16STakashi Iwai } 9455bdb6a16STakashi Iwai } 9465bdb6a16STakashi Iwai #endif 947