17979b1cfSJérôme Duval /* 27979b1cfSJérôme Duval * AC97 interface 37979b1cfSJérôme Duval * 47979b1cfSJérôme Duval * Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de> 57979b1cfSJérôme Duval * Copyright (c) 2008, Jérôme Duval 67979b1cfSJérôme Duval * 77979b1cfSJérôme Duval * All rights reserved. 87979b1cfSJérôme Duval * Redistribution and use in source and binary forms, with or without modification, 97979b1cfSJérôme Duval * are permitted provided that the following conditions are met: 107979b1cfSJérôme Duval * 117979b1cfSJérôme Duval * - Redistributions of source code must retain the above copyright notice, 127979b1cfSJérôme Duval * this list of conditions and the following disclaimer. 137979b1cfSJérôme Duval * - Redistributions in binary form must reproduce the above copyright notice, 147979b1cfSJérôme Duval * this list of conditions and the following disclaimer in the documentation 157979b1cfSJérôme Duval * and/or other materials provided with the distribution. 167979b1cfSJérôme Duval * 177979b1cfSJérôme Duval * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 187979b1cfSJérôme Duval * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 197979b1cfSJérôme Duval * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 207979b1cfSJérôme Duval * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 217979b1cfSJérôme Duval * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 227979b1cfSJérôme Duval * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 237979b1cfSJérôme Duval * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247979b1cfSJérôme Duval * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 257979b1cfSJérôme Duval * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 267979b1cfSJérôme Duval * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277979b1cfSJérôme Duval * 287979b1cfSJérôme Duval */ 297979b1cfSJérôme Duval #include <KernelExport.h> 307979b1cfSJérôme Duval #include <OS.h> 317979b1cfSJérôme Duval #include <stdio.h> 327979b1cfSJérôme Duval #include <stdlib.h> 337979b1cfSJérôme Duval #include <MediaDefs.h> 347979b1cfSJérôme Duval #include "ac97.h" 357979b1cfSJérôme Duval 367979b1cfSJérôme Duval #define LOG(x) dprintf x 377979b1cfSJérôme Duval 387979b1cfSJérôme Duval #define B_UTF8_REGISTERED "\xC2\xAE" 397979b1cfSJérôme Duval 407979b1cfSJérôme Duval bool ac97_reg_is_valid(ac97_dev *dev, uint8 reg); 417979b1cfSJérôme Duval void ac97_amp_enable(ac97_dev *dev, bool onoff); 427979b1cfSJérôme Duval void ac97_dump_capabilities(ac97_dev *dev); 437979b1cfSJérôme Duval void ac97_detect_capabilities(ac97_dev *dev); 447979b1cfSJérôme Duval void ac97_detect_rates(ac97_dev *dev); 457979b1cfSJérôme Duval void ac97_update_register_cache(ac97_dev *dev); 467979b1cfSJérôme Duval 477979b1cfSJérôme Duval const char * stereo_enhancement_technique[] = 487979b1cfSJérôme Duval { 497979b1cfSJérôme Duval "No 3D Stereo Enhancement", 507979b1cfSJérôme Duval "Analog Devices", 517979b1cfSJérôme Duval "Creative Technology", 527979b1cfSJérôme Duval "National Semiconductor", 537979b1cfSJérôme Duval "Yamaha", 547979b1cfSJérôme Duval "BBE Sound", 557979b1cfSJérôme Duval "Crystal Semiconductor", 567979b1cfSJérôme Duval "Qsound Labs", 577979b1cfSJérôme Duval "Spatializer Audio Laboratories", 587979b1cfSJérôme Duval "SRS Labs", 597979b1cfSJérôme Duval "Platform Tech", 607979b1cfSJérôme Duval "AKM Semiconductor", 617979b1cfSJérôme Duval "Aureal", 627979b1cfSJérôme Duval "Aztech Labs", 637979b1cfSJérôme Duval "Binaura", 647979b1cfSJérôme Duval "ESS Technology", 657979b1cfSJérôme Duval "Harman International", 667979b1cfSJérôme Duval "Nvidea", 677979b1cfSJérôme Duval "Philips", 687979b1cfSJérôme Duval "Texas Instruments", 697979b1cfSJérôme Duval "VLSI Technology", 707979b1cfSJérôme Duval "TriTech", 717979b1cfSJérôme Duval "Realtek", 727979b1cfSJérôme Duval "Samsung", 737979b1cfSJérôme Duval "Wolfson Microelectronics", 747979b1cfSJérôme Duval "Delta Integration", 757979b1cfSJérôme Duval "SigmaTel", 767979b1cfSJérôme Duval "KS Waves", 777979b1cfSJérôme Duval "Rockwell", 787979b1cfSJérôme Duval "Unknown (29)", 797979b1cfSJérôme Duval "Unknown (30)", 807979b1cfSJérôme Duval "Unknown (31)" 817979b1cfSJérôme Duval }; 827979b1cfSJérôme Duval 837979b1cfSJérôme Duval void default_init(ac97_dev *dev); 847979b1cfSJérôme Duval void ad1819_init(ac97_dev *dev); 857979b1cfSJérôme Duval void ad1881_init(ac97_dev *dev); 867979b1cfSJérôme Duval void ad1885_init(ac97_dev *dev); 877979b1cfSJérôme Duval void ad1886_init(ac97_dev *dev); 887979b1cfSJérôme Duval void ad1980_init(ac97_dev *dev); 897979b1cfSJérôme Duval void ad1981b_init(ac97_dev *dev); 907979b1cfSJérôme Duval void alc650_init(ac97_dev *dev); 917979b1cfSJérôme Duval void stac9708_init(ac97_dev *dev); 927979b1cfSJérôme Duval void stac9721_init(ac97_dev *dev); 937979b1cfSJérôme Duval void stac9744_init(ac97_dev *dev); 947979b1cfSJérôme Duval void stac9756_init(ac97_dev *dev); 957979b1cfSJérôme Duval void tr28028_init(ac97_dev *dev); 967979b1cfSJérôme Duval void wm9701_init(ac97_dev *dev); 977979b1cfSJérôme Duval void wm9703_init(ac97_dev *dev); 987979b1cfSJérôme Duval void wm9704_init(ac97_dev *dev); 997979b1cfSJérôme Duval 1007979b1cfSJérôme Duval bool ad1819_set_rate(ac97_dev *dev, uint8 reg, uint32 rate); 1017979b1cfSJérôme Duval bool ad1819_get_rate(ac97_dev *dev, uint8 reg, uint32 *rate); 1027979b1cfSJérôme Duval 1037979b1cfSJérôme Duval typedef struct 1047979b1cfSJérôme Duval { 1057979b1cfSJérôme Duval uint32 id; 1067979b1cfSJérôme Duval uint32 mask; 1077979b1cfSJérôme Duval codec_init init; 1087979b1cfSJérôme Duval const char *info; 1097979b1cfSJérôme Duval } codec_table; 1107979b1cfSJérôme Duval 1117979b1cfSJérôme Duval codec_table codecs[] = 1127979b1cfSJérôme Duval { 1137979b1cfSJérôme Duval { CODEC_ID_AD1819, 0xffffffff, ad1819_init, "Analog Devices AD1819A, AD1819B SoundPort"B_UTF8_REGISTERED }, 1147979b1cfSJérôme Duval { CODEC_ID_AD1881, 0xffffffff, ad1881_init, "Analog Devices AD1881 SoundMAX"B_UTF8_REGISTERED }, 1157979b1cfSJérôme Duval { CODEC_ID_AD1881A, 0xffffffff, ad1881_init, "Analog Devices AD1881A SoundMAX"B_UTF8_REGISTERED }, 1167979b1cfSJérôme Duval { CODEC_ID_AD1885, 0xffffffff, ad1885_init, "Analog Devices AD1885 SoundMAX"B_UTF8_REGISTERED }, 1177979b1cfSJérôme Duval { CODEC_ID_AD1886, 0xffffffff, ad1886_init, "Analog Devices AD1886 SoundMAX"B_UTF8_REGISTERED }, 1187979b1cfSJérôme Duval { CODEC_ID_AD1886A, 0xffffffff, ad1881_init, "Analog Devices AD1886A SoundMAX"B_UTF8_REGISTERED }, 1197979b1cfSJérôme Duval { CODEC_ID_AD1887, 0xffffffff, ad1881_init, "Analog Devices AD1887 SoundMAX"B_UTF8_REGISTERED }, 1207979b1cfSJérôme Duval { CODEC_ID_AD1888, 0xffffffff, ad1881_init, "Analog Devices AD1888 SoundMAX"B_UTF8_REGISTERED }, 1217979b1cfSJérôme Duval { CODEC_ID_AD1980, 0xffffffff, ad1980_init, "Analog Devices AD1980 SoundMAX"B_UTF8_REGISTERED }, 1227979b1cfSJérôme Duval { 0x41445371, 0xffffffff, default_init, "Analog Devices 0x41445371 (???)" }, 1237979b1cfSJérôme Duval { 0x41445372, 0xffffffff, default_init, "Analog Devices AD1981A SoundMAX"B_UTF8_REGISTERED }, 1247979b1cfSJérôme Duval { CODEC_ID_AD1981B, 0xffffffff, ad1981b_init, "Analog Devices AD1981B SoundMAX"B_UTF8_REGISTERED }, 1257979b1cfSJérôme Duval { CODEC_ID_AD1985, 0xffffffff, default_init, "Analog Devices AD1985 SoundMAX"B_UTF8_REGISTERED }, 1267979b1cfSJérôme Duval { CODEC_ID_AD1986, 0xffffffff, default_init, "Analog Devices AD1986 SoundMAX"B_UTF8_REGISTERED }, 1277979b1cfSJérôme Duval { CODEC_ID_AK4540, 0xffffffff, default_init, "Asahi Kasei AK4540" }, 1287979b1cfSJérôme Duval { CODEC_ID_AK4542, 0xffffffff, default_init, "Asahi Kasei AK4542" }, 1297979b1cfSJérôme Duval { CODEC_ID_AK4543, 0xffffffff, default_init, "Asahi Kasei AK4543" }, 1307979b1cfSJérôme Duval { 0x414c4320, 0xfffffff0, default_init, "Avance Logic (Realtek) ALC100/ALC100P, RL5383/RL5522" }, 1317979b1cfSJérôme Duval { 0x414c4730, 0xffffffff, default_init, "Avance Logic (Realtek) ALC101" }, 1327979b1cfSJérôme Duval { CODEC_ID_ALC201A, 0xffffffff, default_init, "Avance Logic (Realtek) ALC200/ALC200A, ALC201/ALC201A" }, /* 0x4710 = ALC201A */ 1337979b1cfSJérôme Duval { 0x414c4720, 0xffffffff, alc650_init, "Avance Logic (Realtek) ALC650" }, /* 0x4720 = ALC650 */ 1347979b1cfSJérôme Duval { 0x414c4740, 0xffffffff, default_init, "Avance Logic (Realtek) ALC202/ALC202A" }, 1357979b1cfSJérôme Duval { 0x434d4941, 0xffffffff, default_init, "C-Media CMI9738" }, 1367979b1cfSJérôme Duval { 0x434d4961, 0xffffffff, default_init, "C-Media CMI9739" }, 1377979b1cfSJérôme Duval { 0x43525900, 0xffffffff, default_init, "Cirrus Logic CS4297" }, 1387979b1cfSJérôme Duval { 0x43525903, 0xffffffff, default_init, "Cirrus Logic CS4297" }, 1397979b1cfSJérôme Duval { 0x43525913, 0xffffffff, default_init, "Cirrus Logic CS4297A" }, 1407979b1cfSJérôme Duval { 0x43525914, 0xffffffff, default_init, "Cirrus Logic CS4297B" }, 1417979b1cfSJérôme Duval { 0x43525923, 0xffffffff, default_init, "Cirrus Logic CS4294C" }, 1427979b1cfSJérôme Duval { 0x4352592b, 0xffffffff, default_init, "Cirrus Logic CS4298C" }, 1437979b1cfSJérôme Duval { CODEC_ID_CS4299A, 0xffffffff, default_init, "Cirrus Logic CS4299A" }, 1447979b1cfSJérôme Duval { CODEC_ID_CS4299C, 0xffffffff, default_init, "Cirrus Logic CS4299C" }, 1457979b1cfSJérôme Duval { CODEC_ID_CS4299D, 0xffffffff, default_init, "Cirrus Logic CS4299D" }, 1467979b1cfSJérôme Duval { 0x43525941, 0xffffffff, default_init, "Cirrus Logic CS4201A" }, 1477979b1cfSJérôme Duval { 0x43525951, 0xffffffff, default_init, "Cirrus Logic CS4205A" }, 1487979b1cfSJérôme Duval { 0x43525961, 0xffffffff, default_init, "Cirrus Logic CS4291A" }, 1497979b1cfSJérôme Duval { 0x45838308, 0xffffffff, default_init, "ESS Technology ES1921" }, 1500db19308SJérôme Duval { 0x49434501, 0xffffffff, default_init, "ICEnsemble ICE1230" }, 1517979b1cfSJérôme Duval { 0x49434511, 0xffffffff, default_init, "ICEnsemble ICE1232" }, 1520db19308SJérôme Duval { 0x49434514, 0xffffffff, default_init, "ICEnsemble ICE1232A" }, 1530db19308SJérôme Duval { 0x49434551, 0xffffffff, default_init, "Via Technologies VT1616" }, /* rebranded from ICEnsemble */ 1540db19308SJérôme Duval { 0x49544520, 0xffffffff, default_init, "Integrated Technology Express ITE2226E" }, 1550db19308SJérôme Duval { 0x49544560, 0xffffffff, default_init, "Integrated Technology Express ITE2646E" }, 1567979b1cfSJérôme Duval { 0x4e534331, 0xffffffff, default_init, "National Semiconductor LM4549" }, 1577979b1cfSJérôme Duval { CODEC_ID_STAC9700,0xffffffff, default_init, "SigmaTel STAC9700/9783/9784" }, 1587979b1cfSJérôme Duval { CODEC_ID_STAC9704,0xffffffff, default_init, "SigmaTel STAC9701/03, STAC9704/07, STAC9705 (???)" }, 1597979b1cfSJérôme Duval { CODEC_ID_STAC9705,0xffffffff, default_init, "SigmaTel STAC9704 (???)" }, 1607979b1cfSJérôme Duval { CODEC_ID_STAC9708,0xffffffff, stac9708_init, "SigmaTel STAC9708/9711" }, 1617979b1cfSJérôme Duval { CODEC_ID_STAC9721,0xffffffff, stac9721_init, "SigmaTel STAC9721/9723" }, 1627979b1cfSJérôme Duval { CODEC_ID_STAC9744,0xffffffff, stac9744_init, "SigmaTel STAC9744" }, 1637979b1cfSJérôme Duval { CODEC_ID_STAC9752,0xffffffff, default_init, "SigmaTel STAC9752/53" }, 1647979b1cfSJérôme Duval { CODEC_ID_STAC9756,0xffffffff, stac9756_init, "SigmaTel STAC9756/9757" }, 1657979b1cfSJérôme Duval { CODEC_ID_STAC9766,0xffffffff, default_init, "SigmaTel STAC9766/67" }, 1667979b1cfSJérôme Duval { 0x53494c22, 0xffffffff, default_init, "Silicon Laboratory Si3036" }, 1677979b1cfSJérôme Duval { 0x53494c23, 0xffffffff, default_init, "Silicon Laboratory Si3038" }, 1680db19308SJérôme Duval { 0x54524103, 0xffffffff, default_init, "TriTech TR28023" }, 1697979b1cfSJérôme Duval { 0x54524106, 0xffffffff, default_init, "TriTech TR28026" }, 1707979b1cfSJérôme Duval { 0x54524108, 0xffffffff, tr28028_init, "TriTech TR28028" }, 1717979b1cfSJérôme Duval { 0x54524123, 0xffffffff, default_init, "TriTech TR28602" }, 1720db19308SJérôme Duval { 0x56494161, 0xffffffff, default_init, "Via Technologies VIA1612A" }, 1730db19308SJérôme Duval { 0x56494170, 0xffffffff, default_init, "Via Technologies VIA1617A" }, 1747979b1cfSJérôme Duval { 0x574d4c00, 0xffffffff, wm9701_init, "Wolfson WM9701A" }, 1757979b1cfSJérôme Duval { 0x574d4c03, 0xffffffff, wm9703_init, "Wolfson WM9703/9704" }, 1767979b1cfSJérôme Duval { 0x574d4c04, 0xffffffff, wm9704_init, "Wolfson WM9704 (quad)" }, 1770db19308SJérôme Duval { 0x574d4c05, 0xffffffff, wm9703_init, "Wolfson WM9705/WM9710" }, 1780db19308SJérôme Duval { 0x574d4d09, 0xffffffff, default_init, "Wolfson WM9709" }, 1790db19308SJérôme Duval { 0x574d4c12, 0xffffffff, default_init, "Wolfson WM9711/12" }, 1800db19308SJérôme Duval { 0x574d4c13, 0xffffffff, default_init, "Wolfson WM9713/14" }, 1810db19308SJérôme Duval { 0x57454301, 0xffffffff, default_init, "Wolfson W83971D" }, 1827979b1cfSJérôme Duval /* Vendors only: */ 1837979b1cfSJérôme Duval { 0x41445300, 0xffffff00, default_init, "Analog Devices" }, 1847979b1cfSJérôme Duval { 0x414b4d00, 0xffffff00, default_init, "Asahi Kasei" }, 1857979b1cfSJérôme Duval { 0x414c4700, 0xffffff00, default_init, "Avance Logic (Realtek)" }, 1867979b1cfSJérôme Duval { 0x434d4900, 0xffffff00, default_init, "C-Media" }, 1877979b1cfSJérôme Duval { 0x43525900, 0xffffff00, default_init, "Cirrus Logic" }, 1887979b1cfSJérôme Duval { 0x45838300, 0xffffff00, default_init, "ESS Technology" }, 1897979b1cfSJérôme Duval { 0x49434500, 0xffffff00, default_init, "ICEnsemble" }, 1900db19308SJérôme Duval { 0x49544500, 0xffffff00, default_init, "ITE, Inc." }, 1917979b1cfSJérôme Duval { 0x4e534300, 0xffffff00, default_init, "National Semiconductor" }, 1927979b1cfSJérôme Duval { 0x83847600, 0xffffff00, default_init, "SigmaTel" }, 1937979b1cfSJérôme Duval { 0x53494c00, 0xffffff00, default_init, "Silicon Laboratory" }, 1947979b1cfSJérôme Duval { 0x54524100, 0xffffff00, default_init, "TriTech" }, 1950db19308SJérôme Duval { 0x56494100, 0xffffff00, default_init, "VIA Technologies" }, 1967979b1cfSJérôme Duval { 0x574d4c00, 0xffffff00, default_init, "Wolfson" }, 1970db19308SJérôme Duval { 0x594d4800, 0xffffff00, default_init, "Yamaha" }, 1987979b1cfSJérôme Duval { 0x00000000, 0x00000000, default_init, "Unknown" } /* must be last one, matches every codec */ 1997979b1cfSJérôme Duval }; 2007979b1cfSJérôme Duval 2017979b1cfSJérôme Duval codec_table *find_codec_table(uint32 codecid); 2027979b1cfSJérôme Duval 2037979b1cfSJérôme Duval codec_table * 2047979b1cfSJérôme Duval find_codec_table(uint32 codecid) 2057979b1cfSJérôme Duval { 2067979b1cfSJérôme Duval codec_table *codec; 2077979b1cfSJérôme Duval for (codec = codecs; codec->id; codec++) 2087979b1cfSJérôme Duval if ((codec->id & codec->mask) == (codecid & codec->mask)) 2097979b1cfSJérôme Duval break; 2107979b1cfSJérôme Duval return codec; 2117979b1cfSJérôme Duval } 2127979b1cfSJérôme Duval 2137979b1cfSJérôme Duval void 2147979b1cfSJérôme Duval ac97_attach(ac97_dev **_dev, codec_reg_read reg_read, codec_reg_write reg_write, void *cookie, 2157979b1cfSJérôme Duval ushort subvendor_id, ushort subsystem_id) 2167979b1cfSJérôme Duval { 2177979b1cfSJérôme Duval ac97_dev *dev; 2187979b1cfSJérôme Duval codec_table *codec; 2197979b1cfSJérôme Duval int i; 2207979b1cfSJérôme Duval 2217979b1cfSJérôme Duval *_dev = dev = (ac97_dev *) malloc(sizeof(ac97_dev)); 2227979b1cfSJérôme Duval dev->cookie = cookie; 2237979b1cfSJérôme Duval dev->reg_read = reg_read; 2247979b1cfSJérôme Duval dev->reg_write = reg_write; 2257979b1cfSJérôme Duval dev->set_rate = 0; 2267979b1cfSJérôme Duval dev->get_rate = 0; 2277979b1cfSJérôme Duval dev->clock = 48000; /* default clock on non-broken motherboards */ 2287979b1cfSJérôme Duval dev->min_vsr = 0x0001; 2297979b1cfSJérôme Duval dev->max_vsr = 0xffff; 2307979b1cfSJérôme Duval dev->reversed_eamp_polarity = false; 2317979b1cfSJérôme Duval dev->capabilities = 0; 2327979b1cfSJérôme Duval 2337979b1cfSJérôme Duval dev->subsystem = (subvendor_id << 16) | subsystem_id; 2347979b1cfSJérôme Duval 2357979b1cfSJérôme Duval if (dev->subsystem == 0x161f202f 2367979b1cfSJérôme Duval || dev->subsystem == 0x161f203a 237*8ddc0909SJérôme Duval || dev->subsystem == 0x161f203e 2387979b1cfSJérôme Duval || dev->subsystem == 0x161f204c 2397979b1cfSJérôme Duval || dev->subsystem == 0x104d8144 2407979b1cfSJérôme Duval || dev->subsystem == 0x104d8197 2417979b1cfSJérôme Duval || dev->subsystem == 0x104d81c0 2427979b1cfSJérôme Duval || dev->subsystem == 0x104d81c5 2437979b1cfSJérôme Duval || dev->subsystem == 0x103c3089 2447979b1cfSJérôme Duval || dev->subsystem == 0x103c309a 2457979b1cfSJérôme Duval || dev->subsystem == 0x10338213 2467979b1cfSJérôme Duval || dev->subsystem == 0x103382be) { 2477979b1cfSJérôme Duval dev->reversed_eamp_polarity = true; 2487979b1cfSJérôme Duval } 2497979b1cfSJérôme Duval 2507979b1cfSJérôme Duval /* reset the codec */ 2517979b1cfSJérôme Duval LOG(("codec reset\n")); 2527979b1cfSJérôme Duval ac97_reg_uncached_write(dev, AC97_RESET, 0x0000); 2537979b1cfSJérôme Duval for (i = 0; i < 500; i++) { 2547979b1cfSJérôme Duval if ((ac97_reg_uncached_read(dev, AC97_POWERDOWN) & 0xf) == 0xf) 2557979b1cfSJérôme Duval break; 2567979b1cfSJérôme Duval snooze(1000); 2577979b1cfSJérôme Duval } 2587979b1cfSJérôme Duval 2597979b1cfSJérôme Duval dev->codec_id = ((uint32)reg_read(cookie, AC97_VENDOR_ID1) << 16) | reg_read(cookie, AC97_VENDOR_ID2); 2607979b1cfSJérôme Duval codec = find_codec_table(dev->codec_id); 2617979b1cfSJérôme Duval dev->codec_info = codec->info; 2627979b1cfSJérôme Duval dev->init = codec->init; 2637979b1cfSJérôme Duval 2647979b1cfSJérôme Duval dev->codec_3d_stereo_enhancement = stereo_enhancement_technique[(ac97_reg_cached_read(dev, AC97_RESET) >> 10) & 31]; 2657979b1cfSJérôme Duval 2667979b1cfSJérôme Duval /* setup register cache */ 2677979b1cfSJérôme Duval ac97_update_register_cache(dev); 2687979b1cfSJérôme Duval 2697979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_EXTENDED_STAT_CTRL, 1, 1); // enable variable rate audio 2707979b1cfSJérôme Duval 2717979b1cfSJérôme Duval ac97_detect_capabilities(dev); 2727979b1cfSJérôme Duval 2737979b1cfSJérôme Duval dev->init(dev); 2747979b1cfSJérôme Duval ac97_amp_enable(dev, true); 2757979b1cfSJérôme Duval 2767979b1cfSJérôme Duval /* set mixer defaults, enabled Line-out sources are PCM-out, CD-in, Line-in */ 2777979b1cfSJérôme Duval ac97_reg_update(dev, AC97_CENTER_LFE_VOLUME, 0x0000); /* set LFE & center volume 0dB */ 2787979b1cfSJérôme Duval ac97_reg_update(dev, AC97_SURR_VOLUME, 0x0000); /* set surround volume 0dB */ 2797979b1cfSJérôme Duval ac97_reg_update(dev, AC97_MASTER_VOLUME, 0x0000); /* set master output 0dB */ 2807979b1cfSJérôme Duval ac97_reg_update(dev, AC97_AUX_OUT_VOLUME, 0x0000); /* set aux output 0dB */ 2817979b1cfSJérôme Duval ac97_reg_update(dev, AC97_MONO_VOLUME, 0x0000); /* set mono output 0dB */ 2827979b1cfSJérôme Duval ac97_reg_update(dev, AC97_PCM_OUT_VOLUME, 0x0808); /* enable pcm-out */ 2837979b1cfSJérôme Duval ac97_reg_update(dev, AC97_CD_VOLUME, 0x0808); /* enable cd-in */ 2847979b1cfSJérôme Duval ac97_reg_update(dev, AC97_LINE_IN_VOLUME, 0x0808); /* enable line-in */ 2857979b1cfSJérôme Duval 2867979b1cfSJérôme Duval /* set record line in */ 2877979b1cfSJérôme Duval ac97_reg_update(dev, AC97_RECORD_SELECT, 0x0404); 2887979b1cfSJérôme Duval 2890db19308SJérôme Duval LOG(("codec vendor id = %#08lx\n", dev->codec_id)); 2900db19308SJérôme Duval LOG(("codec description = %s\n", dev->codec_info)); 2910db19308SJérôme Duval LOG(("codec 3d enhancement = %s\n", dev->codec_3d_stereo_enhancement)); 2920db19308SJérôme Duval 2937979b1cfSJérôme Duval ac97_dump_capabilities(dev); 2947979b1cfSJérôme Duval } 2957979b1cfSJérôme Duval 2967979b1cfSJérôme Duval void 2977979b1cfSJérôme Duval ac97_detach(ac97_dev *dev) 2987979b1cfSJérôme Duval { 2997979b1cfSJérôme Duval /* Mute everything */ 3007979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_CENTER_LFE_VOLUME, 0x8000, 0x8000); 3017979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_SURR_VOLUME, 0x8000, 0x8000); 3027979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_MASTER_VOLUME, 0x8000, 0x8000); 3037979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_AUX_OUT_VOLUME, 0x8000, 0x8000); 3047979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_MONO_VOLUME, 0x8000, 0x8000); 3057979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_PCM_OUT_VOLUME, 0x8000, 0x8000); 3067979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_CD_VOLUME, 0x8000, 0x8000); 3077979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_LINE_IN_VOLUME, 0x8000, 0x8000); 3087979b1cfSJérôme Duval 3097979b1cfSJérôme Duval ac97_amp_enable(dev, false); 3107979b1cfSJérôme Duval 3117979b1cfSJérôme Duval free(dev); 3127979b1cfSJérôme Duval } 3137979b1cfSJérôme Duval 3147979b1cfSJérôme Duval void 3157979b1cfSJérôme Duval ac97_suspend(ac97_dev *dev) 3167979b1cfSJérôme Duval { 3177979b1cfSJérôme Duval ac97_amp_enable(dev, false); 3187979b1cfSJérôme Duval } 3197979b1cfSJérôme Duval 3207979b1cfSJérôme Duval void 3217979b1cfSJérôme Duval ac97_resume(ac97_dev *dev) 3227979b1cfSJérôme Duval { 3237979b1cfSJérôme Duval ac97_amp_enable(dev, true); 3247979b1cfSJérôme Duval } 3257979b1cfSJérôme Duval 3267979b1cfSJérôme Duval void 3277979b1cfSJérôme Duval ac97_reg_cached_write(ac97_dev *dev, uint8 reg, uint16 value) 3287979b1cfSJérôme Duval { 3297979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 3307979b1cfSJérôme Duval return; 3317979b1cfSJérôme Duval dev->reg_write(dev->cookie, reg, value); 3327979b1cfSJérôme Duval dev->reg_cache[reg] = value; 3337979b1cfSJérôme Duval } 3347979b1cfSJérôme Duval 3357979b1cfSJérôme Duval uint16 3367979b1cfSJérôme Duval ac97_reg_cached_read(ac97_dev *dev, uint8 reg) 3377979b1cfSJérôme Duval { 3387979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 3397979b1cfSJérôme Duval return 0; 3407979b1cfSJérôme Duval return dev->reg_cache[reg]; 3417979b1cfSJérôme Duval } 3427979b1cfSJérôme Duval 3437979b1cfSJérôme Duval void 3447979b1cfSJérôme Duval ac97_reg_uncached_write(ac97_dev *dev, uint8 reg, uint16 value) 3457979b1cfSJérôme Duval { 3467979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 3477979b1cfSJérôme Duval return; 3487979b1cfSJérôme Duval dev->reg_write(dev->cookie, reg, value); 3497979b1cfSJérôme Duval } 3507979b1cfSJérôme Duval 3517979b1cfSJérôme Duval uint16 3527979b1cfSJérôme Duval ac97_reg_uncached_read(ac97_dev *dev, uint8 reg) 3537979b1cfSJérôme Duval { 3547979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 3557979b1cfSJérôme Duval return 0; 3567979b1cfSJérôme Duval return dev->reg_read(dev->cookie, reg); 3577979b1cfSJérôme Duval } 3587979b1cfSJérôme Duval 3597979b1cfSJérôme Duval bool 3607979b1cfSJérôme Duval ac97_reg_update(ac97_dev *dev, uint8 reg, uint16 value) 3617979b1cfSJérôme Duval { 3627979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 3637979b1cfSJérôme Duval return false; 3647979b1cfSJérôme Duval if (ac97_reg_cached_read(dev, reg) == value) 3657979b1cfSJérôme Duval return false; 3667979b1cfSJérôme Duval ac97_reg_cached_write(dev, reg, value); 3677979b1cfSJérôme Duval return true; 3687979b1cfSJérôme Duval } 3697979b1cfSJérôme Duval 3707979b1cfSJérôme Duval bool 3717979b1cfSJérôme Duval ac97_reg_update_bits(ac97_dev *dev, uint8 reg, uint16 mask, uint16 value) 3727979b1cfSJérôme Duval { 3737979b1cfSJérôme Duval uint16 old; 3747979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 3757979b1cfSJérôme Duval return false; 3767979b1cfSJérôme Duval old = ac97_reg_cached_read(dev, reg); 3777979b1cfSJérôme Duval value &= mask; 3787979b1cfSJérôme Duval value |= (old & ~mask); 3797979b1cfSJérôme Duval if (old == value) 3807979b1cfSJérôme Duval return false; 3817979b1cfSJérôme Duval ac97_reg_cached_write(dev, reg, value); 3827979b1cfSJérôme Duval return true; 3837979b1cfSJérôme Duval } 3847979b1cfSJérôme Duval 3857979b1cfSJérôme Duval void 3867979b1cfSJérôme Duval ac97_update_register_cache(ac97_dev *dev) 3877979b1cfSJérôme Duval { 3887979b1cfSJérôme Duval int reg; 3897979b1cfSJérôme Duval for (reg = 0; reg <= 0x7e; reg += 2) 3907979b1cfSJérôme Duval dev->reg_cache[reg] = ac97_reg_uncached_read(dev, reg); 3917979b1cfSJérôme Duval } 3927979b1cfSJérôme Duval 3937979b1cfSJérôme Duval bool 3947979b1cfSJérôme Duval ac97_set_rate(ac97_dev *dev, uint8 reg, uint32 rate) 3957979b1cfSJérôme Duval { 3967979b1cfSJérôme Duval uint32 value; 3977979b1cfSJérôme Duval uint32 old; 3987979b1cfSJérôme Duval 3997979b1cfSJérôme Duval if (dev->set_rate) 4007979b1cfSJérôme Duval return dev->set_rate(dev, reg, rate); 4017979b1cfSJérôme Duval 4027979b1cfSJérôme Duval value = (uint32)((rate * 48000ULL) / dev->clock); /* need 64 bit calculation for rates 96000 or higher */ 4037979b1cfSJérôme Duval 4047979b1cfSJérôme Duval LOG(("ac97_set_rate: clock = %ld, rate = %ld, value = %ld\n", dev->clock, rate, value)); 4057979b1cfSJérôme Duval 4067979b1cfSJérôme Duval /* if double rate audio is currently enabled, divide value by 2 */ 4077979b1cfSJérôme Duval if (ac97_reg_cached_read(dev, AC97_EXTENDED_STAT_CTRL) & 0x0002) 4087979b1cfSJérôme Duval value /= 2; 4097979b1cfSJérôme Duval 4107979b1cfSJérôme Duval if (value < dev->min_vsr || value > dev->max_vsr) 4117979b1cfSJérôme Duval return false; 4127979b1cfSJérôme Duval 4137979b1cfSJérôme Duval old = ac97_reg_cached_read(dev, reg); 4147979b1cfSJérôme Duval ac97_reg_cached_write(dev, reg, value); 4157979b1cfSJérôme Duval if (value != ac97_reg_uncached_read(dev, reg)) { 4167979b1cfSJérôme Duval LOG(("ac97_set_rate failed, new rate %d\n", ac97_reg_uncached_read(dev, reg))); 4177979b1cfSJérôme Duval ac97_reg_cached_write(dev, reg, old); 4187979b1cfSJérôme Duval return false; 4197979b1cfSJérôme Duval } 4207979b1cfSJérôme Duval LOG(("ac97_set_rate done\n")); 4217979b1cfSJérôme Duval return true; 4227979b1cfSJérôme Duval } 4237979b1cfSJérôme Duval 4247979b1cfSJérôme Duval bool 4257979b1cfSJérôme Duval ac97_get_rate(ac97_dev *dev, uint8 reg, uint32 *rate) 4267979b1cfSJérôme Duval { 4277979b1cfSJérôme Duval uint32 value; 4287979b1cfSJérôme Duval 4297979b1cfSJérôme Duval if (dev->get_rate) 4307979b1cfSJérôme Duval return dev->get_rate(dev, reg, rate); 4317979b1cfSJérôme Duval 4327979b1cfSJérôme Duval value = ac97_reg_cached_read(dev, reg); 4337979b1cfSJérôme Duval if (value == 0) 4347979b1cfSJérôme Duval return false; 4357979b1cfSJérôme Duval 4367979b1cfSJérôme Duval /* if double rate audio is currently enabled, multiply value by 2 */ 4377979b1cfSJérôme Duval if (ac97_reg_cached_read(dev, AC97_EXTENDED_STAT_CTRL) & 0x0002) 4387979b1cfSJérôme Duval value *= 2; 4397979b1cfSJérôme Duval 4407979b1cfSJérôme Duval *rate = (uint32)((value * (uint64)dev->clock) / 48000); /* need 64 bit calculation to avoid overflow*/ 4417979b1cfSJérôme Duval return true; 4427979b1cfSJérôme Duval } 4437979b1cfSJérôme Duval 4447979b1cfSJérôme Duval void 4457979b1cfSJérôme Duval ac97_set_clock(ac97_dev *dev, uint32 clock) 4467979b1cfSJérôme Duval { 4477979b1cfSJérôme Duval LOG(("ac97_set_clock: clock = %ld\n", clock)); 4487979b1cfSJérôme Duval dev->clock = clock; 4497979b1cfSJérôme Duval ac97_detect_rates(dev); 4507979b1cfSJérôme Duval ac97_dump_capabilities(dev); 4517979b1cfSJérôme Duval } 4527979b1cfSJérôme Duval 4537979b1cfSJérôme Duval void 4547979b1cfSJérôme Duval ac97_detect_capabilities(ac97_dev *dev) 4557979b1cfSJérôme Duval { 4567979b1cfSJérôme Duval uint16 val; 4577979b1cfSJérôme Duval 4587979b1cfSJérôme Duval val = ac97_reg_cached_read(dev, AC97_RESET); 4597979b1cfSJérôme Duval if (val & 0x0001) 4607979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_MIC; 4617979b1cfSJérôme Duval if (val & 0x0004) 4627979b1cfSJérôme Duval dev->capabilities |= CAP_BASS_TREBLE_CTRL; 4637979b1cfSJérôme Duval if (val & 0x0008) 4647979b1cfSJérôme Duval dev->capabilities |= CAP_SIMULATED_STEREO; 4657979b1cfSJérôme Duval if (val & 0x0010) 4667979b1cfSJérôme Duval dev->capabilities |= CAP_HEADPHONE_OUT; 4677979b1cfSJérôme Duval if (val & 0x0020) 4687979b1cfSJérôme Duval dev->capabilities |= CAP_LAUDNESS; 4697979b1cfSJérôme Duval if (val & 0x0040) 4707979b1cfSJérôme Duval dev->capabilities |= CAP_DAC_18BIT; 4717979b1cfSJérôme Duval if (val & 0x0080) 4727979b1cfSJérôme Duval dev->capabilities |= CAP_DAC_20BIT; 4737979b1cfSJérôme Duval if (val & 0x0100) 4747979b1cfSJérôme Duval dev->capabilities |= CAP_ADC_18BIT; 4757979b1cfSJérôme Duval if (val & 0x0200) 4767979b1cfSJérôme Duval dev->capabilities |= CAP_ADC_20BIT; 4777979b1cfSJérôme Duval if (val & 0x7C00) 4787979b1cfSJérôme Duval dev->capabilities |= CAP_3D_ENHANCEMENT; 4797979b1cfSJérôme Duval 4807979b1cfSJérôme Duval val = ac97_reg_cached_read(dev, AC97_EXTENDED_ID); 4817979b1cfSJérôme Duval if (val & EXID_VRA) 4827979b1cfSJérôme Duval dev->capabilities |= CAP_VARIABLE_PCM; 4837979b1cfSJérôme Duval if (val & EXID_DRA) 4847979b1cfSJérôme Duval dev->capabilities |= CAP_DOUBLE_PCM; 4857979b1cfSJérôme Duval if (val & EXID_SPDIF) 4867979b1cfSJérôme Duval dev->capabilities |= CAP_SPDIF; 4877979b1cfSJérôme Duval if (val & EXID_VRM) 4887979b1cfSJérôme Duval dev->capabilities |= CAP_VARIABLE_MIC; 4897979b1cfSJérôme Duval if (val & EXID_CDAC) 4907979b1cfSJérôme Duval dev->capabilities |= CAP_CENTER_DAC; 4917979b1cfSJérôme Duval if (val & EXID_SDAC) 4927979b1cfSJérôme Duval dev->capabilities |= CAP_SURR_DAC; 4937979b1cfSJérôme Duval if (val & EXID_LDAC) 4947979b1cfSJérôme Duval dev->capabilities |= CAP_LFE_DAC; 4957979b1cfSJérôme Duval if (val & EXID_AMAP) 4967979b1cfSJérôme Duval dev->capabilities |= CAP_AMAP; 4977979b1cfSJérôme Duval if ((val & (EXID_REV0 | EXID_REV1)) == 0) 4987979b1cfSJérôme Duval dev->capabilities |= CAP_REV21; 4997979b1cfSJérôme Duval if ((val & (EXID_REV0 | EXID_REV1)) == EXID_REV0) 5007979b1cfSJérôme Duval dev->capabilities |= CAP_REV22; 5017979b1cfSJérôme Duval if ((val & (EXID_REV0 | EXID_REV1)) == EXID_REV1) 5027979b1cfSJérôme Duval dev->capabilities |= CAP_REV23; 5037979b1cfSJérôme Duval 5047979b1cfSJérôme Duval ac97_detect_rates(dev); 5057979b1cfSJérôme Duval } 5067979b1cfSJérôme Duval 5077979b1cfSJérôme Duval void 5087979b1cfSJérôme Duval ac97_detect_rates(ac97_dev *dev) 5097979b1cfSJérôme Duval { 5107979b1cfSJérôme Duval uint32 oldrate; 5117979b1cfSJérôme Duval 5127979b1cfSJérôme Duval dev->capabilities &= ~CAP_PCM_RATE_MASK; 5137979b1cfSJérôme Duval 5147979b1cfSJérôme Duval if (!ac97_get_rate(dev, AC97_PCM_FRONT_DAC_RATE, &oldrate)) 5157979b1cfSJérôme Duval oldrate = 48000; 5167979b1cfSJérôme Duval 5177979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 20000)) 5187979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_CONTINUOUS; 5197979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 8000)) 5207979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_8000; 5217979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 11025)) 5227979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_11025; 5237979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 12000)) 5247979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_12000; 5257979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 16000)) 5267979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_16000; 5277979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 22050)) 5287979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_22050; 5297979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 24000)) 5307979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_24000; 5317979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 32000)) 5327979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_32000; 5337979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 44100)) 5347979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_44100; 5357979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 48000)) 5367979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_48000; 5377979b1cfSJérôme Duval 5387979b1cfSJérôme Duval if (dev->capabilities & CAP_DOUBLE_PCM) { 5397979b1cfSJérôme Duval // enable double rate mode 5407979b1cfSJérôme Duval if (ac97_reg_update_bits(dev, AC97_EXTENDED_STAT_CTRL, 0x0002, 0x0002)) { 5417979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 88200)) 5427979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_88200; 5437979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 96000)) 5447979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_96000; 5457979b1cfSJérôme Duval // disable double rate mode 5467979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_EXTENDED_STAT_CTRL, 0x0002, 0x0000); 5477979b1cfSJérôme Duval } 5487979b1cfSJérôme Duval } 5497979b1cfSJérôme Duval 5507979b1cfSJérôme Duval ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, oldrate); 5517979b1cfSJérôme Duval } 5527979b1cfSJérôme Duval 5537979b1cfSJérôme Duval void 5547979b1cfSJérôme Duval ac97_dump_capabilities(ac97_dev *dev) 5557979b1cfSJérôme Duval { 5567979b1cfSJérôme Duval LOG(("AC97 capabilities:\n")); 5577979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_MIC)) 5587979b1cfSJérôme Duval LOG(("CAP_PCM_MIC\n")); 5597979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_BASS_TREBLE_CTRL)) 5607979b1cfSJérôme Duval LOG(("CAP_BASS_TREBLE_CTRL\n")); 5617979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_SIMULATED_STEREO)) 5627979b1cfSJérôme Duval LOG(("CAP_SIMULATED_STEREO\n")); 5637979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_HEADPHONE_OUT)) 5647979b1cfSJérôme Duval LOG(("CAP_HEADPHONE_OUT\n")); 5657979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_LAUDNESS)) 5667979b1cfSJérôme Duval LOG(("CAP_LAUDNESS\n")); 5677979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_DAC_18BIT)) 5687979b1cfSJérôme Duval LOG(("CAP_DAC_18BIT\n")); 5697979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_DAC_20BIT)) 5707979b1cfSJérôme Duval LOG(("CAP_DAC_20BIT\n")); 5717979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_ADC_18BIT)) 5727979b1cfSJérôme Duval LOG(("CAP_ADC_18BIT\n")); 5737979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_ADC_20BIT)) 5747979b1cfSJérôme Duval LOG(("CAP_ADC_20BIT\n")); 5757979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_3D_ENHANCEMENT)) 5767979b1cfSJérôme Duval LOG(("CAP_3D_ENHANCEMENT\n")); 5777979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_VARIABLE_PCM)) 5787979b1cfSJérôme Duval LOG(("CAP_VARIABLE_PCM\n")); 5797979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_DOUBLE_PCM)) 5807979b1cfSJérôme Duval LOG(("CAP_DOUBLE_PCM\n")); 5817979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_VARIABLE_MIC)) 5827979b1cfSJérôme Duval LOG(("CAP_VARIABLE_MIC\n")); 5837979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_CENTER_DAC)) 5847979b1cfSJérôme Duval LOG(("CAP_CENTER_DAC\n")); 5857979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_SURR_DAC)) 5867979b1cfSJérôme Duval LOG(("CAP_SURR_DAC\n")); 5877979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_LFE_DAC)) 5887979b1cfSJérôme Duval LOG(("CAP_LFE_DAC\n")); 5897979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_AMAP)) 5907979b1cfSJérôme Duval LOG(("CAP_AMAP\n")); 5917979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_REV21)) 5927979b1cfSJérôme Duval LOG(("CAP_REV21\n")); 5937979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_REV22)) 5947979b1cfSJérôme Duval LOG(("CAP_REV22\n")); 5957979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_REV23)) 5967979b1cfSJérôme Duval LOG(("CAP_REV23\n")); 5977979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_CONTINUOUS)) 5987979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_CONTINUOUS\n")); 5997979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_8000)) 6007979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_8000\n")); 6017979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_11025)) 6027979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_11025\n")); 6037979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_12000)) 6047979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_12000\n")); 6057979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_16000)) 6067979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_16000\n")); 6077979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_22050)) 6087979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_22050\n")); 6097979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_24000)) 6107979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_24000\n")); 6117979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_32000)) 6127979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_32000\n")); 6137979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_44100)) 6147979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_44100\n")); 6157979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_48000)) 6167979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_48000\n")); 6177979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_88200)) 6187979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_88200\n")); 6197979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_96000)) 6207979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_96000\n")); 6217979b1cfSJérôme Duval } 6227979b1cfSJérôme Duval 6237979b1cfSJérôme Duval bool 6247979b1cfSJérôme Duval ac97_has_capability(ac97_dev *dev, uint64 cap) 6257979b1cfSJérôme Duval { 6267979b1cfSJérôme Duval // return (dev->capabilities & cap); // does not work because of 64 bit to integer trucation 6277979b1cfSJérôme Duval return (dev->capabilities & cap) != 0; 6287979b1cfSJérôme Duval } 6297979b1cfSJérôme Duval 6307979b1cfSJérôme Duval /************************************************* 6317979b1cfSJérôme Duval * Codec specific initialization, etc. 6327979b1cfSJérôme Duval */ 6337979b1cfSJérôme Duval 6347979b1cfSJérôme Duval bool 6357979b1cfSJérôme Duval ac97_reg_is_valid(ac97_dev *dev, uint8 reg) 6367979b1cfSJérôme Duval { 6377979b1cfSJérôme Duval if (reg & 1) 6387979b1cfSJérôme Duval return false; 6397979b1cfSJérôme Duval if (reg > 0x7e) 6407979b1cfSJérôme Duval return false; 6417979b1cfSJérôme Duval 6427979b1cfSJérôme Duval switch (dev->codec_id) { 6437979b1cfSJérôme Duval case CODEC_ID_AK4540: 6447979b1cfSJérôme Duval case CODEC_ID_AK4542: 6457979b1cfSJérôme Duval if (reg < 0x1e || reg == 0x20 || reg == 0x26 || reg > 0x7a) 6467979b1cfSJérôme Duval return true; 6477979b1cfSJérôme Duval return false; 6487979b1cfSJérôme Duval 6497979b1cfSJérôme Duval case CODEC_ID_AD1819: 6507979b1cfSJérôme Duval case CODEC_ID_AD1881: 6517979b1cfSJérôme Duval case CODEC_ID_AD1881A: 6527979b1cfSJérôme Duval if (reg < 0x3a || reg > 0x6e) 6537979b1cfSJérôme Duval return true; 6547979b1cfSJérôme Duval return false; 6557979b1cfSJérôme Duval 6567979b1cfSJérôme Duval case CODEC_ID_AD1885: 6577979b1cfSJérôme Duval case CODEC_ID_AD1886: 6587979b1cfSJérôme Duval case CODEC_ID_AD1886A: 6597979b1cfSJérôme Duval case CODEC_ID_AD1887: 6607979b1cfSJérôme Duval if (reg < 0x3c || reg == 0x5a || reg > 0x6e) 6617979b1cfSJérôme Duval return true; 6627979b1cfSJérôme Duval return false; 6637979b1cfSJérôme Duval 6647979b1cfSJérôme Duval case CODEC_ID_STAC9700: 6657979b1cfSJérôme Duval case CODEC_ID_STAC9704: 6667979b1cfSJérôme Duval case CODEC_ID_STAC9705: 6677979b1cfSJérôme Duval case CODEC_ID_STAC9708: 6687979b1cfSJérôme Duval case CODEC_ID_STAC9721: 6697979b1cfSJérôme Duval case CODEC_ID_STAC9744: 6707979b1cfSJérôme Duval case CODEC_ID_STAC9756: 6717979b1cfSJérôme Duval if (reg < 0x3c || reg > 0x58) 6727979b1cfSJérôme Duval return true; 6737979b1cfSJérôme Duval return false; 6747979b1cfSJérôme Duval 6757979b1cfSJérôme Duval default: 6767979b1cfSJérôme Duval return true; 6777979b1cfSJérôme Duval } 6787979b1cfSJérôme Duval } 6797979b1cfSJérôme Duval 6807979b1cfSJérôme Duval void ac97_amp_enable(ac97_dev *dev, bool yesno) 6817979b1cfSJérôme Duval { 6827979b1cfSJérôme Duval switch (dev->codec_id) { 6837979b1cfSJérôme Duval case CODEC_ID_CS4299A: 6847979b1cfSJérôme Duval case CODEC_ID_CS4299C: 6857979b1cfSJérôme Duval case CODEC_ID_CS4299D: 6867979b1cfSJérôme Duval LOG(("cs4299_amp_enable\n")); 6877979b1cfSJérôme Duval if (yesno) 6887979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x68, 0x8004); 6897979b1cfSJérôme Duval else 6907979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x68, 0); 6917979b1cfSJérôme Duval break; 6927979b1cfSJérôme Duval 6937979b1cfSJérôme Duval default: 6947979b1cfSJérôme Duval LOG(("ac97_amp_enable, reverse eamp = %d\n", dev->reversed_eamp_polarity)); 6957979b1cfSJérôme Duval LOG(("powerdown register was = %#04x\n", ac97_reg_uncached_read(dev, AC97_POWERDOWN))); 6967979b1cfSJérôme Duval if (dev->reversed_eamp_polarity) 6977979b1cfSJérôme Duval yesno = !yesno; 6987979b1cfSJérôme Duval if (yesno) 6997979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_POWERDOWN, ac97_reg_uncached_read(dev, AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */ 7007979b1cfSJérôme Duval else 7017979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_POWERDOWN, ac97_reg_uncached_read(dev, AC97_POWERDOWN) | 0x8000); /* switch off */ 7027979b1cfSJérôme Duval LOG(("powerdown register is = %#04x\n", ac97_reg_uncached_read(dev, AC97_POWERDOWN))); 7037979b1cfSJérôme Duval break; 7047979b1cfSJérôme Duval } 7057979b1cfSJérôme Duval } 7067979b1cfSJérôme Duval 7077979b1cfSJérôme Duval bool 7087979b1cfSJérôme Duval ad1819_set_rate(ac97_dev *dev, uint8 reg, uint32 rate) 7097979b1cfSJérôme Duval { 7107979b1cfSJérôme Duval uint32 value; 7117979b1cfSJérôme Duval 7127979b1cfSJérôme Duval value = (uint32)((rate * 48000ULL) / dev->clock); /* need 64 bit calculation for rates 96000 or higher */ 7137979b1cfSJérôme Duval 7147979b1cfSJérôme Duval LOG(("ad1819_set_rate: clock = %ld, rate = %ld, value = %ld\n", dev->clock, rate, value)); 7157979b1cfSJérôme Duval 7167979b1cfSJérôme Duval if (value < 0x1B58 || value > 0xBB80) 7177979b1cfSJérôme Duval return false; 7187979b1cfSJérôme Duval 7197979b1cfSJérôme Duval switch (reg) { 7207979b1cfSJérôme Duval case AC97_PCM_FRONT_DAC_RATE: 7217979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SAMPLE_RATE_0, value); 7227979b1cfSJérôme Duval return true; 7237979b1cfSJérôme Duval 7247979b1cfSJérôme Duval case AC97_PCM_L_R_ADC_RATE: 7257979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SAMPLE_RATE_1, value); 7267979b1cfSJérôme Duval return true; 7277979b1cfSJérôme Duval 7287979b1cfSJérôme Duval default: 7297979b1cfSJérôme Duval return false; 7307979b1cfSJérôme Duval } 7317979b1cfSJérôme Duval } 7327979b1cfSJérôme Duval 7337979b1cfSJérôme Duval bool 7347979b1cfSJérôme Duval ad1819_get_rate(ac97_dev *dev, uint8 reg, uint32 *rate) 7357979b1cfSJérôme Duval { 7367979b1cfSJérôme Duval uint32 value; 7377979b1cfSJérôme Duval 7387979b1cfSJérôme Duval switch (reg) { 7397979b1cfSJérôme Duval case AC97_PCM_FRONT_DAC_RATE: 7407979b1cfSJérôme Duval value = ac97_reg_cached_read(dev, AC97_AD_SAMPLE_RATE_0); 7417979b1cfSJérôme Duval break; 7427979b1cfSJérôme Duval 7437979b1cfSJérôme Duval case AC97_PCM_L_R_ADC_RATE: 7447979b1cfSJérôme Duval value = ac97_reg_cached_read(dev, AC97_AD_SAMPLE_RATE_1); 7457979b1cfSJérôme Duval break; 7467979b1cfSJérôme Duval 7477979b1cfSJérôme Duval default: 7487979b1cfSJérôme Duval return false; 7497979b1cfSJérôme Duval } 7507979b1cfSJérôme Duval 7517979b1cfSJérôme Duval *rate = (uint32)((value * (uint64)dev->clock) / 48000); /* need 64 bit calculation to avoid overflow*/ 7527979b1cfSJérôme Duval return true; 7537979b1cfSJérôme Duval } 7547979b1cfSJérôme Duval 7557979b1cfSJérôme Duval 7567979b1cfSJérôme Duval void default_init(ac97_dev *dev) 7577979b1cfSJérôme Duval { 7587979b1cfSJérôme Duval LOG(("default_init\n")); 7597979b1cfSJérôme Duval } 7607979b1cfSJérôme Duval 7617979b1cfSJérôme Duval void ad1819_init(ac97_dev *dev) 7627979b1cfSJérôme Duval { 7637979b1cfSJérôme Duval LOG(("ad1819_init\n")); 7647979b1cfSJérôme Duval 7657979b1cfSJérôme Duval /* Default config for system with single AD1819 codec */ 7667979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SERIAL_CONFIG, 0x7000); 7677979b1cfSJérôme Duval ac97_update_register_cache(dev); 7687979b1cfSJérôme Duval 7697979b1cfSJérôme Duval /* The AD1819 chip has proprietary sample rate controls 7707979b1cfSJérôme Duval * Setup sample rate 0 generator for DAC, 7717979b1cfSJérôme Duval * Setup sample rate 1 generator for ADC, 7727979b1cfSJérôme Duval * ARSR=1, DRSR=0, ALSR=1, DLSR=0 7737979b1cfSJérôme Duval */ 7747979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_MISC_CONTROL, 0x0101); 7757979b1cfSJérôme Duval /* connect special rate set/get functions */ 7767979b1cfSJérôme Duval dev->set_rate = ad1819_set_rate; 7777979b1cfSJérôme Duval dev->get_rate = ad1819_get_rate; 7787979b1cfSJérôme Duval ac97_detect_rates(dev); 7797979b1cfSJérôme Duval ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 48000); 7807979b1cfSJérôme Duval ac97_set_rate(dev, AC97_PCM_L_R_ADC_RATE, 48000); 7817979b1cfSJérôme Duval } 7827979b1cfSJérôme Duval 7837979b1cfSJérôme Duval void ad1881_init(ac97_dev *dev) 7847979b1cfSJérôme Duval { 7857979b1cfSJérôme Duval LOG(("ad1881_init\n")); 7867979b1cfSJérôme Duval 7877979b1cfSJérôme Duval /* Default config for system with single AD1819 codec, 7887979b1cfSJérôme Duval * BROKEN on systems with master & slave codecs */ 7897979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SERIAL_CONFIG, 0x7000); 7907979b1cfSJérôme Duval ac97_update_register_cache(dev); 7917979b1cfSJérôme Duval 7927979b1cfSJérôme Duval /* Setup DAC and ADC rate generator assignments compatible with AC97 */ 7937979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_MISC_CONTROL, 0x0404); 7947979b1cfSJérôme Duval 7957979b1cfSJérôme Duval /* Setup variable frame rate limits */ 7967979b1cfSJérôme Duval dev->min_vsr = 0x1B58; /* 7kHz */ 7977979b1cfSJérôme Duval dev->max_vsr = 0xBB80; /* 48kHz */ 7987979b1cfSJérôme Duval } 7997979b1cfSJérôme Duval 8007979b1cfSJérôme Duval void ad1885_init(ac97_dev *dev) 8017979b1cfSJérôme Duval { 8027979b1cfSJérôme Duval LOG(("ad1885_init\n")); 8037979b1cfSJérôme Duval ad1881_init(dev); 8047979b1cfSJérôme Duval 8057979b1cfSJérôme Duval /* disable jack sense 0 and 1 (JS0, JS1) to turn off automatic mute */ 8067979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_JACK_SENSE, ac97_reg_cached_read(dev, AC97_AD_JACK_SENSE) | 0x0300); 8077979b1cfSJérôme Duval } 8087979b1cfSJérôme Duval 8097979b1cfSJérôme Duval void ad1886_init(ac97_dev *dev) 8107979b1cfSJérôme Duval { 8117979b1cfSJérôme Duval LOG(("ad1886_init\n")); 8127979b1cfSJérôme Duval ad1881_init(dev); 8137979b1cfSJérôme Duval 8147979b1cfSJérôme Duval /* change jack sense to always activate outputs*/ 8157979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_JACK_SENSE, 0x0010); 8167979b1cfSJérôme Duval /* change SPDIF to a valid value */ 8177979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_SPDIF_CONTROL, 0x2a20); 8187979b1cfSJérôme Duval } 8197979b1cfSJérôme Duval 8207979b1cfSJérôme Duval void ad1980_init(ac97_dev *dev) 8217979b1cfSJérôme Duval { 8227979b1cfSJérôme Duval LOG(("ad1980_init\n")); 8237979b1cfSJérôme Duval 8247979b1cfSJérôme Duval /* Select only master codec, 8257979b1cfSJérôme Duval * SPDIF and DAC are linked 8267979b1cfSJérôme Duval */ 8277979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SERIAL_CONFIG, 0x1001); 8287979b1cfSJérôme Duval ac97_update_register_cache(dev); 8297979b1cfSJérôme Duval 8307979b1cfSJérôme Duval /* Select Line-out driven with mixer data (not surround data) 8317979b1cfSJérôme Duval * Select Headphone-out driven with mixer data (not surround data), 8327979b1cfSJérôme Duval * LOSEL = 0, HPSEL = 1 8337979b1cfSJérôme Duval * XXX this one needs to be changed to support surround out 8347979b1cfSJérôme Duval */ 8357979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_MISC_CONTROL, 0x0400); 8367979b1cfSJérôme Duval } 8377979b1cfSJérôme Duval 8387979b1cfSJérôme Duval void ad1981b_init(ac97_dev *dev) 8397979b1cfSJérôme Duval { 8407979b1cfSJérôme Duval LOG(("ad1981b_init\n")); 8417979b1cfSJérôme Duval if (dev->subsystem == 0x103c0934 8427979b1cfSJérôme Duval || dev->subsystem == 0x103c006d 8437979b1cfSJérôme Duval || dev->subsystem == 0x103c088c 8447979b1cfSJérôme Duval || dev->subsystem == 0x103c0890 8457979b1cfSJérôme Duval || dev->subsystem == 0x103c0934 8467979b1cfSJérôme Duval || dev->subsystem == 0x103c0938 8477979b1cfSJérôme Duval || dev->subsystem == 0x103c0944 8487979b1cfSJérôme Duval || dev->subsystem == 0x103c099c 8497979b1cfSJérôme Duval || dev->subsystem == 0x101402d9) { 8507979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_JACK_SENSE, 8517979b1cfSJérôme Duval ac97_reg_cached_read(dev, AC97_AD_JACK_SENSE) | 0x0800); 8527979b1cfSJérôme Duval } 8537979b1cfSJérôme Duval } 8547979b1cfSJérôme Duval 8557979b1cfSJérôme Duval void alc650_init(ac97_dev *dev) 8567979b1cfSJérôme Duval { 8577979b1cfSJérôme Duval LOG(("alc650_init\n")); 8587979b1cfSJérôme Duval 8597979b1cfSJérôme Duval /* Enable Surround, LFE and Center downmix into Line-out, 8607979b1cfSJérôme Duval * Set Surround-out as duplicated Line-out. 8617979b1cfSJérôme Duval */ 8627979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_ALC650_MULTI_CHAN_CTRL, 0x0007); 8637979b1cfSJérôme Duval 8647979b1cfSJérôme Duval /* Set Surround DAC Volume to 0dB 8657979b1cfSJérôme Duval * Set Center/LFE DAC Volume to 0dB 8667979b1cfSJérôme Duval * (but both should already be set, as these are hardware reset defaults) 8677979b1cfSJérôme Duval */ 8687979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_ALC650_SURR_VOLUME, 0x0808); 8697979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_ALC650_CEN_LFE_VOLUME, 0x0808); 8707979b1cfSJérôme Duval } 8717979b1cfSJérôme Duval 8727979b1cfSJérôme Duval void stac9708_init(ac97_dev *dev) 8737979b1cfSJérôme Duval { 8747979b1cfSJérôme Duval LOG(("stac9708_init\n")); 8757979b1cfSJérôme Duval /* ALSA initializes some registers that according to the 8767979b1cfSJérôme Duval * documentation for this codec do not exist. If the 8777979b1cfSJérôme Duval * following doesn't work, we may need to do that, too. 8787979b1cfSJérôme Duval */ 8797979b1cfSJérôme Duval /* The Analog Special reg is at 0x6C, other codecs have it at 0x6E */ 8807979b1cfSJérôme Duval /* Set Analog Special to default (DAC/ADC -6dB disabled) */ 8817979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x6C, 0x0000); 8827979b1cfSJérôme Duval /* Set Multi Channel to default */ 8837979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0000); 8847979b1cfSJérôme Duval } 8857979b1cfSJérôme Duval 8867979b1cfSJérôme Duval void stac9721_init(ac97_dev *dev) 8877979b1cfSJérôme Duval { 8887979b1cfSJérôme Duval LOG(("stac9721_init\n")); 8897979b1cfSJérôme Duval /* Set Analog Special to default (DAC/ADC -6dB disabled) */ 8907979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x6E, 0x0000); 8917979b1cfSJérôme Duval /* Enable register 0x72 */ 8927979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x70, 0xabba); 8937979b1cfSJérôme Duval /* Set Analog Current to -50% */ 8947979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0002); 8957979b1cfSJérôme Duval /* Set Multi Channel to default */ 8967979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0000); 8977979b1cfSJérôme Duval /* Enable register 0x78 */ 8987979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x76, 0xabba); 8997979b1cfSJérôme Duval /* Set Clock Access to default */ 9007979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x78, 0x0000); 9017979b1cfSJérôme Duval } 9027979b1cfSJérôme Duval 9037979b1cfSJérôme Duval void stac9744_init(ac97_dev *dev) 9047979b1cfSJérôme Duval { 9057979b1cfSJérôme Duval LOG(("stac9744_init\n")); 9067979b1cfSJérôme Duval /* Set Analog Special to default (DAC/ADC -6dB disabled) */ 9077979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x6E, 0x0000); 9087979b1cfSJérôme Duval /* Enable register 0x72 */ 9097979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x70, 0xabba); 9107979b1cfSJérôme Duval /* Set Analog Current to -50% */ 9117979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0002); 9127979b1cfSJérôme Duval /* Set Multi Channel to default */ 9137979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0000); 9147979b1cfSJérôme Duval /* Enable register 0x78 */ 9157979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x76, 0xabba); 9167979b1cfSJérôme Duval /* Set Clock Access to default */ 9177979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x78, 0x0000); 9187979b1cfSJérôme Duval } 9197979b1cfSJérôme Duval 9207979b1cfSJérôme Duval void stac9756_init(ac97_dev *dev) 9217979b1cfSJérôme Duval { 9227979b1cfSJérôme Duval LOG(("stac9756_init\n")); 9237979b1cfSJérôme Duval /* Set Analog Special to default (AC97 all-mix, DAC/ADC -6dB disabled) */ 9247979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x6E, 0x1000); 9257979b1cfSJérôme Duval /* Enable register 0x72 */ 9267979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x70, 0xabba); 9277979b1cfSJérôme Duval /* Set Analog Current to -50% */ 9287979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0002); 9297979b1cfSJérôme Duval /* Set Multi Channel to default */ 9307979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0000); 9317979b1cfSJérôme Duval /* Enable register 0x78 */ 9327979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x76, 0xabba); 9337979b1cfSJérôme Duval /* Set Clock Access to default */ 9347979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x78, 0x0000); 9357979b1cfSJérôme Duval } 9367979b1cfSJérôme Duval 9377979b1cfSJérôme Duval void tr28028_init(ac97_dev *dev) 9387979b1cfSJérôme Duval { 9397979b1cfSJérôme Duval LOG(("tr28028_init\n")); 9407979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_POWERDOWN, 0x0300); 9417979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_POWERDOWN, 0x0000); 9427979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_SURR_VOLUME, 0x0000); 9437979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_SPDIF_CONTROL, 0x0000); 9447979b1cfSJérôme Duval } 9457979b1cfSJérôme Duval 9467979b1cfSJérôme Duval void wm9701_init(ac97_dev *dev) 9477979b1cfSJérôme Duval { 9487979b1cfSJérôme Duval LOG(("wm9701_init\n")); 9497979b1cfSJérôme Duval /* ALSA writes some of these registers, but the codec 9507979b1cfSJérôme Duval * documentation states explicitly that 0x38 and 0x70 to 0x74 9517979b1cfSJérôme Duval * are not used in the WM9701A 9527979b1cfSJérôme Duval */ 9537979b1cfSJérôme Duval 9547979b1cfSJérôme Duval /* DVD noise patch (?) */ 9557979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x5a, 0x0200); 9567979b1cfSJérôme Duval } 9577979b1cfSJérôme Duval 9587979b1cfSJérôme Duval void wm9703_init(ac97_dev *dev) 9597979b1cfSJérôme Duval { 9607979b1cfSJérôme Duval LOG(("wm9703_init\n")); 9617979b1cfSJérôme Duval /* Set front mixer value to unmuted */ 9627979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0808); 9637979b1cfSJérôme Duval /* Disable loopback, etc */ 9647979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_GENERAL_PURPOSE, 0x8000); 9657979b1cfSJérôme Duval } 9667979b1cfSJérôme Duval 9677979b1cfSJérôme Duval void wm9704_init(ac97_dev *dev) 9687979b1cfSJérôme Duval { 9697979b1cfSJérôme Duval LOG(("wm9704_init\n")); 9707979b1cfSJérôme Duval /* Set read DAC value to unmuted */ 9717979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x70, 0x0808); 9727979b1cfSJérôme Duval /* Set front mixer value to unmuted */ 9737979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0808); 9747979b1cfSJérôme Duval /* Set rear mixer value to unmuted */ 9757979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0808); 9767979b1cfSJérôme Duval /* DVD noise patch (?) */ 9777979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x5a, 0x0200); 9787979b1cfSJérôme Duval } 9797979b1cfSJérôme Duval 9807979b1cfSJérôme Duval const ac97_source_info source_info[] = { 9817979b1cfSJérôme Duval { "Recording", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO|B_MIX_RECORDMUX, 100, AC97_RECORD_GAIN, 0x8000, 4, 0, 1, 0, 0.0, 22.5, 1.5 }, 9827979b1cfSJérôme Duval { "Master", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 101, AC97_MASTER_VOLUME, 0x8000, 5, 0, 1, 1,-46.5, 0.0, 1.5 }, 9837979b1cfSJérôme Duval //{ "Bass/Treble", B_MIX_GAIN|B_MIX_STEREO, 102, AC97_MASTER_TONE, 0x0f0f, 4, 0, 1, 1,-12.0, 10.5, 1.5 }, 9847979b1cfSJérôme Duval //{ "Aux Out", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 103, AC97_AUX_OUT_VOLUME, 0x8000, 5, 0, 1, 1,-46.5, 0.0, 1.5 }, 9857979b1cfSJérôme Duval { "PCM Out", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 104, AC97_PCM_OUT_VOLUME, 0x8808, 5, 0, 1, 1,-34.5, 12.0, 1.5 }, 9867979b1cfSJérôme Duval { "CD", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 105, AC97_CD_VOLUME, 0x8808, 5, 0, 1, 1,-34.5, 12.0, 1.5 }, 9877979b1cfSJérôme Duval { "Aux In", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 106, AC97_AUX_IN_VOLUME, 0x8808, 5, 0, 1, 1,-34.5, 12.0, 1.5 }, 9887979b1cfSJérôme Duval { "TAD", B_MIX_GAIN|B_MIX_MUTE|B_MIX_MONO, 107, AC97_PHONE_VOLUME, 0x8008, 5, 0, 1, 1,-34.5, 12.0, 1.5 }, 9897979b1cfSJérôme Duval { "Mic", B_MIX_GAIN|B_MIX_MUTE|B_MIX_MONO|B_MIX_MICBOOST, 108, AC97_MIC_VOLUME, 0x8008, 5, 0, 1, 1,-34.5, 12.0, 1.5 }, 9907979b1cfSJérôme Duval { "Line In", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 109, AC97_LINE_IN_VOLUME, 0x8808, 5, 0, 1, 1,-34.5, 12.0, 1.5 }, 9917979b1cfSJérôme Duval //{ "Center/Lfe", B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 111, AC97_CENTER_LFE_VOLUME, 0x8080, 5, 0, 1, 1,-46.5, 0.0, 1.5 }, 9927979b1cfSJérôme Duval { "Center/Lfe" /* should be "Surround" but no */, B_MIX_GAIN|B_MIX_MUTE|B_MIX_STEREO, 110, AC97_SURR_VOLUME, 0x8080, 5, 0, 1, 1,-46.5, 0.0, 1.5 } 9937979b1cfSJérôme Duval }; 9947979b1cfSJérôme Duval 9957979b1cfSJérôme Duval const int32 source_info_size = (sizeof(source_info)/sizeof(source_info[0])); 996