aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ac97/ac97_patch.c
diff options
context:
space:
mode:
authorRandy Cushman <rcushman_linux@earthlink.net>2006-12-22 06:44:25 -0500
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:02:46 -0500
commit67e9f4b68c9d1820132c559c0f9b296dafdf631e (patch)
tree4b51b76112e0e218774970d0a2d3c522252f7128 /sound/pci/ac97/ac97_patch.c
parent6428ea1b733e4795209ff272be32732ec152594a (diff)
[ALSA] ac97 - fix various issues with AD1986/AD1986A support
Previously, ac97_codec.c was coded to support AD1986 and AD1986A CODECs using code written for the AD1985 CODEC. This allowed the LINE_OUT and HEADPHONE jacks to function properly, however register differences between the CODECs prevented line and microphone inputs from functioning. Specifically, this patch fixes issues with the following mixer controls: 'V_REFOUT', 'Spread Front to Surround and Center/LFE', 'Exchange Front/Surround', 'Surround Jack Mode', and 'Channel Mode'. This patch removes the undocumented AD1888 control 'High Pass Filter Enable' and adds the new control 'Exchange Mic/Line In'. Signed-off-by: Randy Cushman <rcushman_linux@earthlink.net> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/ac97/ac97_patch.c')
-rw-r--r--sound/pci/ac97/ac97_patch.c367
1 files changed, 366 insertions, 1 deletions
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index bd27531a0f0e..f5b4b44bbdab 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -1626,7 +1626,7 @@ int patch_ad1886(struct snd_ac97 * ac97)
1626 return 0; 1626 return 0;
1627} 1627}
1628 1628
1629/* MISC bits */ 1629/* MISC bits (AD1888/AD1980/AD1985 register 0x76) */
1630#define AC97_AD198X_MBC 0x0003 /* mic boost */ 1630#define AC97_AD198X_MBC 0x0003 /* mic boost */
1631#define AC97_AD198X_MBC_20 0x0000 /* +20dB */ 1631#define AC97_AD198X_MBC_20 0x0000 /* +20dB */
1632#define AC97_AD198X_MBC_10 0x0001 /* +10dB */ 1632#define AC97_AD198X_MBC_10 0x0001 /* +10dB */
@@ -1650,6 +1650,83 @@ int patch_ad1886(struct snd_ac97 * ac97)
1650#define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */ 1650#define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */
1651#define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */ 1651#define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */
1652 1652
1653/* MISC 1 bits (AD1986 register 0x76) */
1654#define AC97_AD1986_MBC 0x0003 /* mic boost */
1655#define AC97_AD1986_MBC_20 0x0000 /* +20dB */
1656#define AC97_AD1986_MBC_10 0x0001 /* +10dB */
1657#define AC97_AD1986_MBC_30 0x0002 /* +30dB */
1658#define AC97_AD1986_LISEL0 0x0004 /* LINE_IN select bit 0 */
1659#define AC97_AD1986_LISEL1 0x0008 /* LINE_IN select bit 1 */
1660#define AC97_AD1986_LISEL_MASK (AC97_AD1986_LISEL1 | AC97_AD1986_LISEL0)
1661#define AC97_AD1986_LISEL_LI 0x0000 /* LINE_IN pins as LINE_IN source */
1662#define AC97_AD1986_LISEL_SURR 0x0004 /* SURROUND pins as LINE_IN source */
1663#define AC97_AD1986_LISEL_MIC 0x0008 /* MIC_1/2 pins as LINE_IN source */
1664#define AC97_AD1986_SRU 0x0010 /* sample rate unlock */
1665#define AC97_AD1986_SOSEL 0x0020 /* SURROUND_OUT amplifiers input sel */
1666#define AC97_AD1986_2MIC 0x0040 /* 2-channel mic select */
1667#define AC97_AD1986_SPRD 0x0080 /* SPREAD enable */
1668#define AC97_AD1986_DMIX0 0x0100 /* downmix mode: */
1669 /* 0 = 6-to-4, 1 = 6-to-2 downmix */
1670#define AC97_AD1986_DMIX1 0x0200 /* downmix mode: 1 = enabled */
1671#define AC97_AD1986_CLDIS 0x0800 /* center/lfe disable */
1672#define AC97_AD1986_SODIS 0x1000 /* SURROUND_OUT disable */
1673#define AC97_AD1986_MSPLT 0x2000 /* mute split (read only 1) */
1674#define AC97_AD1986_AC97NC 0x4000 /* AC97 no compatible mode (r/o 1) */
1675#define AC97_AD1986_DACZ 0x8000 /* DAC zero-fill mode */
1676
1677/* MISC 2 bits (AD1986 register 0x70) */
1678#define AC97_AD_MISC2 0x70 /* Misc Control Bits 2 (AD1986) */
1679
1680#define AC97_AD1986_CVREF0 0x0004 /* C/LFE VREF_OUT 2.25V */
1681#define AC97_AD1986_CVREF1 0x0008 /* C/LFE VREF_OUT 0V */
1682#define AC97_AD1986_CVREF2 0x0010 /* C/LFE VREF_OUT 3.7V */
1683#define AC97_AD1986_CVREF_MASK \
1684 (AC97_AD1986_CVREF2 | AC97_AD1986_CVREF1 | AC97_AD1986_CVREF0)
1685#define AC97_AD1986_JSMAP 0x0020 /* Jack Sense Mapping 1 = alternate */
1686#define AC97_AD1986_MMDIS 0x0080 /* Mono Mute Disable */
1687#define AC97_AD1986_MVREF0 0x0400 /* MIC VREF_OUT 2.25V */
1688#define AC97_AD1986_MVREF1 0x0800 /* MIC VREF_OUT 0V */
1689#define AC97_AD1986_MVREF2 0x1000 /* MIC VREF_OUT 3.7V */
1690#define AC97_AD1986_MVREF_MASK \
1691 (AC97_AD1986_MVREF2 | AC97_AD1986_MVREF1 | AC97_AD1986_MVREF0)
1692
1693/* MISC 3 bits (AD1986 register 0x7a) */
1694#define AC97_AD_MISC3 0x7a /* Misc Control Bits 3 (AD1986) */
1695
1696#define AC97_AD1986_MMIX 0x0004 /* Mic Mix, left/right */
1697#define AC97_AD1986_GPO 0x0008 /* General Purpose Out */
1698#define AC97_AD1986_LOHPEN 0x0010 /* LINE_OUT headphone drive */
1699#define AC97_AD1986_LVREF0 0x0100 /* LINE_OUT VREF_OUT 2.25V */
1700#define AC97_AD1986_LVREF1 0x0200 /* LINE_OUT VREF_OUT 0V */
1701#define AC97_AD1986_LVREF2 0x0400 /* LINE_OUT VREF_OUT 3.7V */
1702#define AC97_AD1986_LVREF_MASK \
1703 (AC97_AD1986_LVREF2 | AC97_AD1986_LVREF1 | AC97_AD1986_LVREF0)
1704#define AC97_AD1986_JSINVA 0x0800 /* Jack Sense Invert SENSE_A */
1705#define AC97_AD1986_LOSEL 0x1000 /* LINE_OUT amplifiers input select */
1706#define AC97_AD1986_HPSEL0 0x2000 /* Headphone amplifiers */
1707 /* input select Surround DACs */
1708#define AC97_AD1986_HPSEL1 0x4000 /* Headphone amplifiers input */
1709 /* select C/LFE DACs */
1710#define AC97_AD1986_JSINVB 0x8000 /* Jack Sense Invert SENSE_B */
1711
1712/* Serial Config bits (AD1986 register 0x74) (incomplete) */
1713#define AC97_AD1986_OMS0 0x0100 /* Optional Mic Selector bit 0 */
1714#define AC97_AD1986_OMS1 0x0200 /* Optional Mic Selector bit 1 */
1715#define AC97_AD1986_OMS2 0x0400 /* Optional Mic Selector bit 2 */
1716#define AC97_AD1986_OMS_MASK \
1717 (AC97_AD1986_OMS2 | AC97_AD1986_OMS1 | AC97_AD1986_OMS0)
1718#define AC97_AD1986_OMS_M 0x0000 /* MIC_1/2 pins are MIC sources */
1719#define AC97_AD1986_OMS_L 0x0100 /* LINE_IN pins are MIC sources */
1720#define AC97_AD1986_OMS_C 0x0200 /* Center/LFE pins are MCI sources */
1721#define AC97_AD1986_OMS_MC 0x0400 /* Mix of MIC and C/LFE pins */
1722 /* are MIC sources */
1723#define AC97_AD1986_OMS_ML 0x0500 /* MIX of MIC and LINE_IN pins */
1724 /* are MIC sources */
1725#define AC97_AD1986_OMS_LC 0x0600 /* MIX of LINE_IN and C/LFE pins */
1726 /* are MIC sources */
1727#define AC97_AD1986_OMS_MLC 0x0700 /* MIX of MIC, LINE_IN, C/LFE pins */
1728 /* are MIC sources */
1729
1653 1730
1654static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 1731static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1655{ 1732{
@@ -2105,6 +2182,294 @@ int patch_ad1985(struct snd_ac97 * ac97)
2105 return 0; 2182 return 0;
2106} 2183}
2107 2184
2185static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol,
2186 struct snd_ctl_elem_info *uinfo)
2187{
2188 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
2189 uinfo->count = 1;
2190 uinfo->value.integer.min = 0;
2191 uinfo->value.integer.max = 1;
2192 return 0;
2193}
2194
2195static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol,
2196 struct snd_ctl_elem_value *ucontrol)
2197{
2198 struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
2199 unsigned short val;
2200
2201 val = ac97->regs[AC97_AD_MISC3];
2202 ucontrol->value.integer.value[0] = (val & AC97_AD1986_LOSEL) != 0;
2203 return 0;
2204}
2205
2206static int snd_ac97_ad1986_lososel_put(struct snd_kcontrol *kcontrol,
2207 struct snd_ctl_elem_value *ucontrol)
2208{
2209 struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
2210 int ret0;
2211 int ret1;
2212 int sprd = (ac97->regs[AC97_AD_MISC] & AC97_AD1986_SPRD) != 0;
2213
2214 ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC3, AC97_AD1986_LOSEL,
2215 ucontrol->value.integer.value[0] != 0
2216 ? AC97_AD1986_LOSEL : 0);
2217 if (ret0 < 0)
2218 return ret0;
2219
2220 /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
2221 ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
2222 (ucontrol->value.integer.value[0] != 0
2223 || sprd)
2224 ? AC97_AD1986_SOSEL : 0);
2225 if (ret1 < 0)
2226 return ret1;
2227
2228 return (ret0 > 0 || ret1 > 0) ? 1 : 0;
2229}
2230
2231static int snd_ac97_ad1986_spread_get(struct snd_kcontrol *kcontrol,
2232 struct snd_ctl_elem_value *ucontrol)
2233{
2234 struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
2235 unsigned short val;
2236
2237 val = ac97->regs[AC97_AD_MISC];
2238 ucontrol->value.integer.value[0] = (val & AC97_AD1986_SPRD) != 0;
2239 return 0;
2240}
2241
2242static int snd_ac97_ad1986_spread_put(struct snd_kcontrol *kcontrol,
2243 struct snd_ctl_elem_value *ucontrol)
2244{
2245 struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
2246 int ret0;
2247 int ret1;
2248 int sprd = (ac97->regs[AC97_AD_MISC3] & AC97_AD1986_LOSEL) != 0;
2249
2250 ret0 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SPRD,
2251 ucontrol->value.integer.value[0] != 0
2252 ? AC97_AD1986_SPRD : 0);
2253 if (ret0 < 0)
2254 return ret0;
2255
2256 /* SOSEL is set to values of "Spread" or "Exchange F/S" controls */
2257 ret1 = snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD1986_SOSEL,
2258 (ucontrol->value.integer.value[0] != 0
2259 || sprd)
2260 ? AC97_AD1986_SOSEL : 0);
2261 if (ret1 < 0)
2262 return ret1;
2263
2264 return (ret0 > 0 || ret1 > 0) ? 1 : 0;
2265}
2266
2267static int snd_ac97_ad1986_miclisel_get(struct snd_kcontrol *kcontrol,
2268 struct snd_ctl_elem_value *ucontrol)
2269{
2270 struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
2271
2272 ucontrol->value.integer.value[0] = ac97->spec.ad18xx.swap_mic_linein;
2273 return 0;
2274}
2275
2276static int snd_ac97_ad1986_miclisel_put(struct snd_kcontrol *kcontrol,
2277 struct snd_ctl_elem_value *ucontrol)
2278{
2279 struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
2280 unsigned char swap = ucontrol->value.integer.value[0] != 0;
2281
2282 if (swap != ac97->spec.ad18xx.swap_mic_linein) {
2283 ac97->spec.ad18xx.swap_mic_linein = swap;
2284 if (ac97->build_ops->update_jacks)
2285 ac97->build_ops->update_jacks(ac97);
2286 return 1;
2287 }
2288 return 0;
2289}
2290
2291static int snd_ac97_ad1986_vrefout_get(struct snd_kcontrol *kcontrol,
2292 struct snd_ctl_elem_value *ucontrol)
2293{
2294 /* Use MIC_1/2 V_REFOUT as the "get" value */
2295 struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
2296 unsigned short val;
2297 unsigned short reg = ac97->regs[AC97_AD_MISC2];
2298 if ((reg & AC97_AD1986_MVREF0) != 0)
2299 val = 2;
2300 else if ((reg & AC97_AD1986_MVREF1) != 0)
2301 val = 3;
2302 else if ((reg & AC97_AD1986_MVREF2) != 0)
2303 val = 1;
2304 else
2305 val = 0;
2306 ucontrol->value.enumerated.item[0] = val;
2307 return 0;
2308}
2309
2310static int snd_ac97_ad1986_vrefout_put(struct snd_kcontrol *kcontrol,
2311 struct snd_ctl_elem_value *ucontrol)
2312{
2313 struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
2314 unsigned short cval;
2315 unsigned short lval;
2316 unsigned short mval;
2317 int cret;
2318 int lret;
2319 int mret;
2320
2321 switch (ucontrol->value.enumerated.item[0])
2322 {
2323 case 0: /* High-Z */
2324 cval = 0;
2325 lval = 0;
2326 mval = 0;
2327 break;
2328 case 1: /* 3.7 V */
2329 cval = AC97_AD1986_CVREF2;
2330 lval = AC97_AD1986_LVREF2;
2331 mval = AC97_AD1986_MVREF2;
2332 break;
2333 case 2: /* 2.25 V */
2334 cval = AC97_AD1986_CVREF0;
2335 lval = AC97_AD1986_LVREF0;
2336 mval = AC97_AD1986_MVREF0;
2337 break;
2338 case 3: /* 0 V */
2339 cval = AC97_AD1986_CVREF1;
2340 lval = AC97_AD1986_LVREF1;
2341 mval = AC97_AD1986_MVREF1;
2342 break;
2343 default:
2344 return -EINVAL;
2345 }
2346
2347 cret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
2348 AC97_AD1986_CVREF_MASK, cval);
2349 if (cret < 0)
2350 return cret;
2351 lret = snd_ac97_update_bits(ac97, AC97_AD_MISC3,
2352 AC97_AD1986_LVREF_MASK, lval);
2353 if (lret < 0)
2354 return lret;
2355 mret = snd_ac97_update_bits(ac97, AC97_AD_MISC2,
2356 AC97_AD1986_MVREF_MASK, mval);
2357 if (mret < 0)
2358 return mret;
2359
2360 return (cret > 0 || lret > 0 || mret > 0) ? 1 : 0;
2361}
2362
2363static const struct snd_kcontrol_new snd_ac97_ad1986_controls[] = {
2364 AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0),
2365 {
2366 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2367 .name = "Exchange Front/Surround",
2368 .info = snd_ac97_ad1986_bool_info,
2369 .get = snd_ac97_ad1986_lososel_get,
2370 .put = snd_ac97_ad1986_lososel_put
2371 },
2372 {
2373 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2374 .name = "Exchange Mic/Line In",
2375 .info = snd_ac97_ad1986_bool_info,
2376 .get = snd_ac97_ad1986_miclisel_get,
2377 .put = snd_ac97_ad1986_miclisel_put
2378 },
2379 {
2380 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2381 .name = "Spread Front to Surround and Center/LFE",
2382 .info = snd_ac97_ad1986_bool_info,
2383 .get = snd_ac97_ad1986_spread_get,
2384 .put = snd_ac97_ad1986_spread_put
2385 },
2386 {
2387 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2388 .name = "Downmix",
2389 .info = snd_ac97_ad1888_downmix_info,
2390 .get = snd_ac97_ad1888_downmix_get,
2391 .put = snd_ac97_ad1888_downmix_put
2392 },
2393 {
2394 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2395 .name = "V_REFOUT",
2396 .info = snd_ac97_ad1985_vrefout_info,
2397 .get = snd_ac97_ad1986_vrefout_get,
2398 .put = snd_ac97_ad1986_vrefout_put
2399 },
2400 AC97_SURROUND_JACK_MODE_CTL,
2401 AC97_CHANNEL_MODE_CTL,
2402
2403 AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
2404 AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0)
2405};
2406
2407static void ad1986_update_jacks(struct snd_ac97 *ac97)
2408{
2409 unsigned short misc_val = 0;
2410 unsigned short ser_val;
2411
2412 /* disable SURROUND and CENTER/LFE if not surround mode */
2413 if (! is_surround_on(ac97))
2414 misc_val |= AC97_AD1986_SODIS;
2415 if (! is_clfe_on(ac97))
2416 misc_val |= AC97_AD1986_CLDIS;
2417
2418 /* select line input (default=LINE_IN, SURROUND or MIC_1/2) */
2419 if (is_shared_linein(ac97))
2420 misc_val |= AC97_AD1986_LISEL_SURR;
2421 else if (ac97->spec.ad18xx.swap_mic_linein != 0)
2422 misc_val |= AC97_AD1986_LISEL_MIC;
2423 snd_ac97_update_bits(ac97, AC97_AD_MISC,
2424 AC97_AD1986_SODIS | AC97_AD1986_CLDIS |
2425 AC97_AD1986_LISEL_MASK,
2426 misc_val);
2427
2428 /* select microphone input (MIC_1/2, Center/LFE or LINE_IN) */
2429 if (is_shared_micin(ac97))
2430 ser_val = AC97_AD1986_OMS_C;
2431 else if (ac97->spec.ad18xx.swap_mic_linein != 0)
2432 ser_val = AC97_AD1986_OMS_L;
2433 else
2434 ser_val = AC97_AD1986_OMS_M;
2435 snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG,
2436 AC97_AD1986_OMS_MASK,
2437 ser_val);
2438}
2439
2440static int patch_ad1986_specific(struct snd_ac97 *ac97)
2441{
2442 int err;
2443
2444 if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
2445 return err;
2446
2447 return patch_build_controls(ac97, snd_ac97_ad1986_controls,
2448 ARRAY_SIZE(snd_ac97_ad1985_controls));
2449}
2450
2451static struct snd_ac97_build_ops patch_ad1986_build_ops = {
2452 .build_post_spdif = patch_ad198x_post_spdif,
2453 .build_specific = patch_ad1986_specific,
2454#ifdef CONFIG_PM
2455 .resume = ad18xx_resume,
2456#endif
2457 .update_jacks = ad1986_update_jacks,
2458};
2459
2460int patch_ad1986(struct snd_ac97 * ac97)
2461{
2462 patch_ad1881(ac97);
2463 ac97->build_ops = &patch_ad1986_build_ops;
2464 ac97->flags |= AC97_STEREO_MUTES;
2465
2466 /* update current jack configuration */
2467 ad1986_update_jacks(ac97);
2468
2469 return 0;
2470}
2471
2472
2108/* 2473/*
2109 * realtek ALC65x/850 codecs 2474 * realtek ALC65x/850 codecs
2110 */ 2475 */