aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2005-04-07 09:53:20 -0400
committerJaroslav Kysela <perex@suse.cz>2005-05-29 03:58:28 -0400
commit5f0dccf8500b0cc2ff247f626bc249bc184fd184 (patch)
treeef8402fe29a0d5559ead12085cf1c927fa72670f
parent55911694bf5edf15328dc6558fa3f432d52015ee (diff)
[ALSA] Add CM9780 support, fix CM9761 SPDIF
AC97 Codec - Added CM9780 patch - Fix the SPDIF support on CM9761/CM9780 - Allow the generic enum callback to pass any number (not power of 2) as the value mask Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/ac97/ac97_codec.c17
-rw-r--r--sound/pci/ac97/ac97_patch.c143
-rw-r--r--sound/pci/ac97/ac97_patch.h1
3 files changed, 137 insertions, 24 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 4ece2053bb13..61549b1eb59a 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -120,6 +120,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
120{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, 120{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL },
121{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, 121{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL },
122{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, 122{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL },
123{ 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL },
123{ 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL }, 124{ 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL },
124{ 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL }, 125{ 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL },
125{ 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL }, 126{ 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL },
@@ -462,12 +463,14 @@ int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u
462{ 463{
463 ac97_t *ac97 = snd_kcontrol_chip(kcontrol); 464 ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
464 struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; 465 struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
465 unsigned short val; 466 unsigned short val, bitmask;
466 467
468 for (bitmask = 1; bitmask > e->mask; bitmask <<= 1)
469 ;
467 val = snd_ac97_read_cache(ac97, e->reg); 470 val = snd_ac97_read_cache(ac97, e->reg);
468 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1); 471 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
469 if (e->shift_l != e->shift_r) 472 if (e->shift_l != e->shift_r)
470 ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1); 473 ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1);
471 474
472 return 0; 475 return 0;
473} 476}
@@ -477,17 +480,19 @@ int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u
477 ac97_t *ac97 = snd_kcontrol_chip(kcontrol); 480 ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
478 struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; 481 struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
479 unsigned short val; 482 unsigned short val;
480 unsigned short mask; 483 unsigned short mask, bitmask;
481 484
485 for (bitmask = 1; bitmask > e->mask; bitmask <<= 1)
486 ;
482 if (ucontrol->value.enumerated.item[0] > e->mask - 1) 487 if (ucontrol->value.enumerated.item[0] > e->mask - 1)
483 return -EINVAL; 488 return -EINVAL;
484 val = ucontrol->value.enumerated.item[0] << e->shift_l; 489 val = ucontrol->value.enumerated.item[0] << e->shift_l;
485 mask = (e->mask - 1) << e->shift_l; 490 mask = (bitmask - 1) << e->shift_l;
486 if (e->shift_l != e->shift_r) { 491 if (e->shift_l != e->shift_r) {
487 if (ucontrol->value.enumerated.item[1] > e->mask - 1) 492 if (ucontrol->value.enumerated.item[1] > e->mask - 1)
488 return -EINVAL; 493 return -EINVAL;
489 val |= ucontrol->value.enumerated.item[1] << e->shift_r; 494 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
490 mask |= (e->mask - 1) << e->shift_r; 495 mask |= (bitmask - 1) << e->shift_r;
491 } 496 }
492 return snd_ac97_update_bits(ac97, e->reg, mask, val); 497 return snd_ac97_update_bits(ac97, e->reg, mask, val);
493} 498}
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 13c34a5d8206..473840d431b3 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -2087,12 +2087,13 @@ int patch_cm9739(ac97_t * ac97)
2087} 2087}
2088 2088
2089#define AC97_CM9761_MULTI_CHAN 0x64 2089#define AC97_CM9761_MULTI_CHAN 0x64
2090#define AC97_CM9761_FUNC 0x66
2090#define AC97_CM9761_SPDIF_CTRL 0x6c 2091#define AC97_CM9761_SPDIF_CTRL 0x6c
2091 2092
2092static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 2093static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
2093{ 2094{
2094 ac97_t *ac97 = snd_kcontrol_chip(kcontrol); 2095 ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
2095 if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x0400) 2096 if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x0400)
2096 ucontrol->value.integer.value[0] = 1; 2097 ucontrol->value.integer.value[0] = 1;
2097 else 2098 else
2098 ucontrol->value.integer.value[0] = 0; 2099 ucontrol->value.integer.value[0] = 0;
@@ -2106,14 +2107,14 @@ static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_el
2106 { 0x0008, 0x0400 }, /* off, on */ 2107 { 0x0008, 0x0400 }, /* off, on */
2107 { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ 2108 { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */
2108 }; 2109 };
2109 return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x0408, 2110 return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408,
2110 vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); 2111 vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]);
2111} 2112}
2112 2113
2113static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 2114static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
2114{ 2115{
2115 ac97_t *ac97 = snd_kcontrol_chip(kcontrol); 2116 ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
2116 if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) 2117 if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x1000)
2117 ucontrol->value.integer.value[0] = 1; 2118 ucontrol->value.integer.value[0] = 1;
2118 else 2119 else
2119 ucontrol->value.integer.value[0] = 0; 2120 ucontrol->value.integer.value[0] = 0;
@@ -2129,7 +2130,7 @@ static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_ele
2129 { 0x2000, 0x1880 }, /* off, on */ 2130 { 0x2000, 0x1880 }, /* off, on */
2130 { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ 2131 { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */
2131 }; 2132 };
2132 return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3880, 2133 return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880,
2133 vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); 2134 vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]);
2134} 2135}
2135 2136
@@ -2152,6 +2153,70 @@ static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = {
2152 }, 2153 },
2153}; 2154};
2154 2155
2156static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
2157{
2158 static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" };
2159
2160 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2161 uinfo->count = 1;
2162 uinfo->value.enumerated.items = 3;
2163 if (uinfo->value.enumerated.item > 2)
2164 uinfo->value.enumerated.item = 2;
2165 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2166 return 0;
2167}
2168
2169static int cm9761_spdif_out_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
2170{
2171 ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
2172
2173 if (ac97->regs[AC97_CM9761_FUNC] & 0x1)
2174 ucontrol->value.enumerated.item[0] = 2; /* SPDIF-loopback */
2175 else if (ac97->regs[AC97_CM9761_SPDIF_CTRL] & 0x2)
2176 ucontrol->value.enumerated.item[0] = 1; /* ADC loopback */
2177 else
2178 ucontrol->value.enumerated.item[0] = 0; /* AC-link */
2179 return 0;
2180}
2181
2182static int cm9761_spdif_out_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
2183{
2184 ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
2185
2186 if (ucontrol->value.enumerated.item[0] == 2)
2187 return snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0x1);
2188 snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0);
2189 return snd_ac97_update_bits(ac97, AC97_CM9761_SPDIF_CTRL, 0x2,
2190 ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0);
2191}
2192
2193static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" };
2194static const struct ac97_enum cm9761_dac_clock_enum =
2195 AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock);
2196
2197static const snd_kcontrol_new_t snd_ac97_cm9761_controls_spdif[] = {
2198 { /* BIT 1: SPDIFS */
2199 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2200 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
2201 .info = cm9761_spdif_out_source_info,
2202 .get = cm9761_spdif_out_source_get,
2203 .put = cm9761_spdif_out_source_put,
2204 },
2205 /* BIT 2: IG_SPIV */
2206 AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9761_SPDIF_CTRL, 2, 1, 0),
2207 /* BIT 3: SPI2F */
2208 AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9761_SPDIF_CTRL, 3, 1, 0),
2209 /* BIT 4: SPI2SDI */
2210 AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9761_SPDIF_CTRL, 4, 1, 0),
2211 /* BIT 9-10: DAC_CTL */
2212 AC97_ENUM("DAC Clock Source", cm9761_dac_clock_enum),
2213};
2214
2215static int patch_cm9761_post_spdif(ac97_t * ac97)
2216{
2217 return patch_build_controls(ac97, snd_ac97_cm9761_controls_spdif, ARRAY_SIZE(snd_ac97_cm9761_controls_spdif));
2218}
2219
2155static int patch_cm9761_specific(ac97_t * ac97) 2220static int patch_cm9761_specific(ac97_t * ac97)
2156{ 2221{
2157 return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); 2222 return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls));
@@ -2159,7 +2224,7 @@ static int patch_cm9761_specific(ac97_t * ac97)
2159 2224
2160static struct snd_ac97_build_ops patch_cm9761_ops = { 2225static struct snd_ac97_build_ops patch_cm9761_ops = {
2161 .build_specific = patch_cm9761_specific, 2226 .build_specific = patch_cm9761_specific,
2162 .build_post_spdif = patch_cm9739_post_spdif /* hope it's identical... */ 2227 .build_post_spdif = patch_cm9761_post_spdif
2163}; 2228};
2164 2229
2165int patch_cm9761(ac97_t *ac97) 2230int patch_cm9761(ac97_t *ac97)
@@ -2193,24 +2258,25 @@ int patch_cm9761(ac97_t *ac97)
2193 /* to be sure: we overwrite the ext status bits */ 2258 /* to be sure: we overwrite the ext status bits */
2194 snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); 2259 snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0);
2195 /* Don't set 0x0200 here. This results in the silent analog output */ 2260 /* Don't set 0x0200 here. This results in the silent analog output */
2196 snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009); 2261 snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0001); /* enable spdif-in */
2197 ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ 2262 ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
2198 2263
2199 /* set-up multi channel */ 2264 /* set-up multi channel */
2200 /* bit 15: pc master beep off 2265 /* bit 15: pc master beep off
2201 * bit 14: ?? 2266 * bit 14: pin47 = EAPD/SPDIF
2202 * bit 13: vref ctl [= cm9739] 2267 * bit 13: vref ctl [= cm9739]
2203 * bit 12: center/mic [= cm9739] (reverted on rev B) 2268 * bit 12: CLFE control (reverted on rev B)
2204 * bit 11: ?? (mic/center/lfe) (reverted on rev B) 2269 * bit 11: Mic/center share (reverted on rev B)
2205 * bit 10: suddound/line [= cm9739] 2270 * bit 10: suddound/line share
2206 * bit 9: mix 2 surround 2271 * bit 9: Analog-in mix -> surround
2207 * bit 8: ? 2272 * bit 8: Analog-in mix -> CLFE
2208 * bit 7: ?? (mic/center/lfe) 2273 * bit 7: Mic/LFE share (mic/center/lfe)
2209 * bit 4: ?? (front) 2274 * bit 5: vref select (9761A)
2210 * bit 3: ?? (line-in/rear share) (revereted with rev B) 2275 * bit 4: front control
2211 * bit 2: ?? (surround) 2276 * bit 3: surround control (revereted with rev B)
2212 * bit 1: front mic 2277 * bit 2: front mic
2213 * bit 0: mic boost 2278 * bit 1: stereo mic
2279 * bit 0: mic boost level (0=20dB, 1=30dB)
2214 */ 2280 */
2215 2281
2216#if 0 2282#if 0
@@ -2230,6 +2296,47 @@ int patch_cm9761(ac97_t *ac97)
2230 return 0; 2296 return 0;
2231} 2297}
2232 2298
2299#define AC97_CM9780_SIDE 0x60
2300#define AC97_CM9780_JACK 0x62
2301#define AC97_CM9780_MIXER 0x64
2302#define AC97_CM9780_MULTI_CHAN 0x66
2303#define AC97_CM9780_SPDIF 0x6c
2304
2305static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" };
2306static const struct ac97_enum cm9780_ch_select_enum =
2307 AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select);
2308static const snd_kcontrol_new_t cm9780_controls[] = {
2309 AC97_DOUBLE("Side Playback Switch", AC97_CM9780_SIDE, 15, 7, 1, 1),
2310 AC97_DOUBLE("Side Playback Volume", AC97_CM9780_SIDE, 8, 0, 31, 0),
2311 AC97_ENUM("Side Playback Route", cm9780_ch_select_enum),
2312};
2313
2314static int patch_cm9780_specific(ac97_t *ac97)
2315{
2316 return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls));
2317}
2318
2319static struct snd_ac97_build_ops patch_cm9780_ops = {
2320 .build_specific = patch_cm9780_specific,
2321 .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */
2322};
2323
2324int patch_cm9780(ac97_t *ac97)
2325{
2326 unsigned short val;
2327
2328 ac97->build_ops = &patch_cm9780_ops;
2329
2330 /* enable spdif */
2331 if (ac97->ext_id & AC97_EI_SPDIF) {
2332 ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
2333 val = snd_ac97_read(ac97, AC97_CM9780_SPDIF);
2334 val |= 0x1; /* SPDI_EN */
2335 snd_ac97_write_cache(ac97, AC97_CM9780_SPDIF, val);
2336 }
2337
2338 return 0;
2339}
2233 2340
2234/* 2341/*
2235 * VIA VT1616 codec 2342 * VIA VT1616 codec
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 6db51c96f5d0..7b7377d0f2ae 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -54,6 +54,7 @@ int patch_alc850(ac97_t * ac97);
54int patch_cm9738(ac97_t * ac97); 54int patch_cm9738(ac97_t * ac97);
55int patch_cm9739(ac97_t * ac97); 55int patch_cm9739(ac97_t * ac97);
56int patch_cm9761(ac97_t * ac97); 56int patch_cm9761(ac97_t * ac97);
57int patch_cm9780(ac97_t * ac97);
57int patch_vt1616(ac97_t * ac97); 58int patch_vt1616(ac97_t * ac97);
58int patch_it2646(ac97_t * ac97); 59int patch_it2646(ac97_t * ac97);
59int mpatch_si3036(ac97_t * ac97); 60int mpatch_si3036(ac97_t * ac97);