1*7979b1cfSJérôme Duval /* 2*7979b1cfSJérôme Duval * AC97 interface 3*7979b1cfSJérôme Duval * 4*7979b1cfSJérôme Duval * Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de> 5*7979b1cfSJérôme Duval * Copyright (c) 2008, Jérôme Duval 6*7979b1cfSJérôme Duval * 7*7979b1cfSJérôme Duval * All rights reserved. 8*7979b1cfSJérôme Duval * Redistribution and use in source and binary forms, with or without modification, 9*7979b1cfSJérôme Duval * are permitted provided that the following conditions are met: 10*7979b1cfSJérôme Duval * 11*7979b1cfSJérôme Duval * - Redistributions of source code must retain the above copyright notice, 12*7979b1cfSJérôme Duval * this list of conditions and the following disclaimer. 13*7979b1cfSJérôme Duval * - Redistributions in binary form must reproduce the above copyright notice, 14*7979b1cfSJérôme Duval * this list of conditions and the following disclaimer in the documentation 15*7979b1cfSJérôme Duval * and/or other materials provided with the distribution. 16*7979b1cfSJérôme Duval * 17*7979b1cfSJérôme Duval * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18*7979b1cfSJérôme Duval * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19*7979b1cfSJérôme Duval * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20*7979b1cfSJérôme Duval * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 21*7979b1cfSJérôme Duval * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22*7979b1cfSJérôme Duval * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23*7979b1cfSJérôme Duval * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24*7979b1cfSJérôme Duval * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25*7979b1cfSJérôme Duval * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26*7979b1cfSJérôme Duval * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*7979b1cfSJérôme Duval * 28*7979b1cfSJérôme Duval */ 29*7979b1cfSJérôme Duval #include <KernelExport.h> 30*7979b1cfSJérôme Duval #include <OS.h> 31*7979b1cfSJérôme Duval #include <stdio.h> 32*7979b1cfSJérôme Duval #include <stdlib.h> 33*7979b1cfSJérôme Duval #include <MediaDefs.h> 34*7979b1cfSJérôme Duval #include "ac97.h" 35*7979b1cfSJérôme Duval 36*7979b1cfSJérôme Duval #define LOG(x) dprintf x 37*7979b1cfSJérôme Duval 38*7979b1cfSJérôme Duval #define B_UTF8_REGISTERED "\xC2\xAE" 39*7979b1cfSJérôme Duval 40*7979b1cfSJérôme Duval bool ac97_reg_is_valid(ac97_dev *dev, uint8 reg); 41*7979b1cfSJérôme Duval void ac97_amp_enable(ac97_dev *dev, bool onoff); 42*7979b1cfSJérôme Duval void ac97_dump_capabilities(ac97_dev *dev); 43*7979b1cfSJérôme Duval void ac97_detect_capabilities(ac97_dev *dev); 44*7979b1cfSJérôme Duval void ac97_detect_rates(ac97_dev *dev); 45*7979b1cfSJérôme Duval void ac97_update_register_cache(ac97_dev *dev); 46*7979b1cfSJérôme Duval 47*7979b1cfSJérôme Duval const char * stereo_enhancement_technique[] = 48*7979b1cfSJérôme Duval { 49*7979b1cfSJérôme Duval "No 3D Stereo Enhancement", 50*7979b1cfSJérôme Duval "Analog Devices", 51*7979b1cfSJérôme Duval "Creative Technology", 52*7979b1cfSJérôme Duval "National Semiconductor", 53*7979b1cfSJérôme Duval "Yamaha", 54*7979b1cfSJérôme Duval "BBE Sound", 55*7979b1cfSJérôme Duval "Crystal Semiconductor", 56*7979b1cfSJérôme Duval "Qsound Labs", 57*7979b1cfSJérôme Duval "Spatializer Audio Laboratories", 58*7979b1cfSJérôme Duval "SRS Labs", 59*7979b1cfSJérôme Duval "Platform Tech", 60*7979b1cfSJérôme Duval "AKM Semiconductor", 61*7979b1cfSJérôme Duval "Aureal", 62*7979b1cfSJérôme Duval "Aztech Labs", 63*7979b1cfSJérôme Duval "Binaura", 64*7979b1cfSJérôme Duval "ESS Technology", 65*7979b1cfSJérôme Duval "Harman International", 66*7979b1cfSJérôme Duval "Nvidea", 67*7979b1cfSJérôme Duval "Philips", 68*7979b1cfSJérôme Duval "Texas Instruments", 69*7979b1cfSJérôme Duval "VLSI Technology", 70*7979b1cfSJérôme Duval "TriTech", 71*7979b1cfSJérôme Duval "Realtek", 72*7979b1cfSJérôme Duval "Samsung", 73*7979b1cfSJérôme Duval "Wolfson Microelectronics", 74*7979b1cfSJérôme Duval "Delta Integration", 75*7979b1cfSJérôme Duval "SigmaTel", 76*7979b1cfSJérôme Duval "KS Waves", 77*7979b1cfSJérôme Duval "Rockwell", 78*7979b1cfSJérôme Duval "Unknown (29)", 79*7979b1cfSJérôme Duval "Unknown (30)", 80*7979b1cfSJérôme Duval "Unknown (31)" 81*7979b1cfSJérôme Duval }; 82*7979b1cfSJérôme Duval 83*7979b1cfSJérôme Duval void default_init(ac97_dev *dev); 84*7979b1cfSJérôme Duval void ad1819_init(ac97_dev *dev); 85*7979b1cfSJérôme Duval void ad1881_init(ac97_dev *dev); 86*7979b1cfSJérôme Duval void ad1885_init(ac97_dev *dev); 87*7979b1cfSJérôme Duval void ad1886_init(ac97_dev *dev); 88*7979b1cfSJérôme Duval void ad1980_init(ac97_dev *dev); 89*7979b1cfSJérôme Duval void ad1981b_init(ac97_dev *dev); 90*7979b1cfSJérôme Duval void alc650_init(ac97_dev *dev); 91*7979b1cfSJérôme Duval void stac9708_init(ac97_dev *dev); 92*7979b1cfSJérôme Duval void stac9721_init(ac97_dev *dev); 93*7979b1cfSJérôme Duval void stac9744_init(ac97_dev *dev); 94*7979b1cfSJérôme Duval void stac9756_init(ac97_dev *dev); 95*7979b1cfSJérôme Duval void tr28028_init(ac97_dev *dev); 96*7979b1cfSJérôme Duval void wm9701_init(ac97_dev *dev); 97*7979b1cfSJérôme Duval void wm9703_init(ac97_dev *dev); 98*7979b1cfSJérôme Duval void wm9704_init(ac97_dev *dev); 99*7979b1cfSJérôme Duval 100*7979b1cfSJérôme Duval bool ad1819_set_rate(ac97_dev *dev, uint8 reg, uint32 rate); 101*7979b1cfSJérôme Duval bool ad1819_get_rate(ac97_dev *dev, uint8 reg, uint32 *rate); 102*7979b1cfSJérôme Duval 103*7979b1cfSJérôme Duval typedef struct 104*7979b1cfSJérôme Duval { 105*7979b1cfSJérôme Duval uint32 id; 106*7979b1cfSJérôme Duval uint32 mask; 107*7979b1cfSJérôme Duval codec_init init; 108*7979b1cfSJérôme Duval const char *info; 109*7979b1cfSJérôme Duval } codec_table; 110*7979b1cfSJérôme Duval 111*7979b1cfSJérôme Duval codec_table codecs[] = 112*7979b1cfSJérôme Duval { 113*7979b1cfSJérôme Duval { CODEC_ID_AD1819, 0xffffffff, ad1819_init, "Analog Devices AD1819A, AD1819B SoundPort"B_UTF8_REGISTERED }, 114*7979b1cfSJérôme Duval { CODEC_ID_AD1881, 0xffffffff, ad1881_init, "Analog Devices AD1881 SoundMAX"B_UTF8_REGISTERED }, 115*7979b1cfSJérôme Duval { CODEC_ID_AD1881A, 0xffffffff, ad1881_init, "Analog Devices AD1881A SoundMAX"B_UTF8_REGISTERED }, 116*7979b1cfSJérôme Duval { CODEC_ID_AD1885, 0xffffffff, ad1885_init, "Analog Devices AD1885 SoundMAX"B_UTF8_REGISTERED }, 117*7979b1cfSJérôme Duval { CODEC_ID_AD1886, 0xffffffff, ad1886_init, "Analog Devices AD1886 SoundMAX"B_UTF8_REGISTERED }, 118*7979b1cfSJérôme Duval { CODEC_ID_AD1886A, 0xffffffff, ad1881_init, "Analog Devices AD1886A SoundMAX"B_UTF8_REGISTERED }, 119*7979b1cfSJérôme Duval { CODEC_ID_AD1887, 0xffffffff, ad1881_init, "Analog Devices AD1887 SoundMAX"B_UTF8_REGISTERED }, 120*7979b1cfSJérôme Duval { CODEC_ID_AD1888, 0xffffffff, ad1881_init, "Analog Devices AD1888 SoundMAX"B_UTF8_REGISTERED }, 121*7979b1cfSJérôme Duval { CODEC_ID_AD1980, 0xffffffff, ad1980_init, "Analog Devices AD1980 SoundMAX"B_UTF8_REGISTERED }, 122*7979b1cfSJérôme Duval { 0x41445371, 0xffffffff, default_init, "Analog Devices 0x41445371 (???)" }, 123*7979b1cfSJérôme Duval { 0x41445372, 0xffffffff, default_init, "Analog Devices AD1981A SoundMAX"B_UTF8_REGISTERED }, 124*7979b1cfSJérôme Duval { CODEC_ID_AD1981B, 0xffffffff, ad1981b_init, "Analog Devices AD1981B SoundMAX"B_UTF8_REGISTERED }, 125*7979b1cfSJérôme Duval { CODEC_ID_AD1985, 0xffffffff, default_init, "Analog Devices AD1985 SoundMAX"B_UTF8_REGISTERED }, 126*7979b1cfSJérôme Duval { CODEC_ID_AD1986, 0xffffffff, default_init, "Analog Devices AD1986 SoundMAX"B_UTF8_REGISTERED }, 127*7979b1cfSJérôme Duval { CODEC_ID_AK4540, 0xffffffff, default_init, "Asahi Kasei AK4540" }, 128*7979b1cfSJérôme Duval { CODEC_ID_AK4542, 0xffffffff, default_init, "Asahi Kasei AK4542" }, 129*7979b1cfSJérôme Duval { CODEC_ID_AK4543, 0xffffffff, default_init, "Asahi Kasei AK4543" }, 130*7979b1cfSJérôme Duval { 0x414c4320, 0xfffffff0, default_init, "Avance Logic (Realtek) ALC100/ALC100P, RL5383/RL5522" }, 131*7979b1cfSJérôme Duval { 0x414c4730, 0xffffffff, default_init, "Avance Logic (Realtek) ALC101" }, 132*7979b1cfSJérôme Duval { CODEC_ID_ALC201A, 0xffffffff, default_init, "Avance Logic (Realtek) ALC200/ALC200A, ALC201/ALC201A" }, /* 0x4710 = ALC201A */ 133*7979b1cfSJérôme Duval { 0x414c4720, 0xffffffff, alc650_init, "Avance Logic (Realtek) ALC650" }, /* 0x4720 = ALC650 */ 134*7979b1cfSJérôme Duval { 0x414c4740, 0xffffffff, default_init, "Avance Logic (Realtek) ALC202/ALC202A" }, 135*7979b1cfSJérôme Duval { 0x434d4941, 0xffffffff, default_init, "C-Media CMI9738" }, 136*7979b1cfSJérôme Duval { 0x434d4961, 0xffffffff, default_init, "C-Media CMI9739" }, 137*7979b1cfSJérôme Duval { 0x43525900, 0xffffffff, default_init, "Cirrus Logic CS4297" }, 138*7979b1cfSJérôme Duval { 0x43525903, 0xffffffff, default_init, "Cirrus Logic CS4297" }, 139*7979b1cfSJérôme Duval { 0x43525913, 0xffffffff, default_init, "Cirrus Logic CS4297A" }, 140*7979b1cfSJérôme Duval { 0x43525914, 0xffffffff, default_init, "Cirrus Logic CS4297B" }, 141*7979b1cfSJérôme Duval { 0x43525923, 0xffffffff, default_init, "Cirrus Logic CS4294C" }, 142*7979b1cfSJérôme Duval { 0x4352592b, 0xffffffff, default_init, "Cirrus Logic CS4298C" }, 143*7979b1cfSJérôme Duval { CODEC_ID_CS4299A, 0xffffffff, default_init, "Cirrus Logic CS4299A" }, 144*7979b1cfSJérôme Duval { CODEC_ID_CS4299C, 0xffffffff, default_init, "Cirrus Logic CS4299C" }, 145*7979b1cfSJérôme Duval { CODEC_ID_CS4299D, 0xffffffff, default_init, "Cirrus Logic CS4299D" }, 146*7979b1cfSJérôme Duval { 0x43525941, 0xffffffff, default_init, "Cirrus Logic CS4201A" }, 147*7979b1cfSJérôme Duval { 0x43525951, 0xffffffff, default_init, "Cirrus Logic CS4205A" }, 148*7979b1cfSJérôme Duval { 0x43525961, 0xffffffff, default_init, "Cirrus Logic CS4291A" }, 149*7979b1cfSJérôme Duval { 0x45838308, 0xffffffff, default_init, "ESS Technology ES1921" }, 150*7979b1cfSJérôme Duval { 0x49434511, 0xffffffff, default_init, "ICEnsemble ICE1232" }, 151*7979b1cfSJérôme Duval { 0x4e534331, 0xffffffff, default_init, "National Semiconductor LM4549" }, 152*7979b1cfSJérôme Duval { CODEC_ID_STAC9700,0xffffffff, default_init, "SigmaTel STAC9700/9783/9784" }, 153*7979b1cfSJérôme Duval { CODEC_ID_STAC9704,0xffffffff, default_init, "SigmaTel STAC9701/03, STAC9704/07, STAC9705 (???)" }, 154*7979b1cfSJérôme Duval { CODEC_ID_STAC9705,0xffffffff, default_init, "SigmaTel STAC9704 (???)" }, 155*7979b1cfSJérôme Duval { CODEC_ID_STAC9708,0xffffffff, stac9708_init, "SigmaTel STAC9708/9711" }, 156*7979b1cfSJérôme Duval { CODEC_ID_STAC9721,0xffffffff, stac9721_init, "SigmaTel STAC9721/9723" }, 157*7979b1cfSJérôme Duval { CODEC_ID_STAC9744,0xffffffff, stac9744_init, "SigmaTel STAC9744" }, 158*7979b1cfSJérôme Duval { CODEC_ID_STAC9752,0xffffffff, default_init, "SigmaTel STAC9752/53" }, 159*7979b1cfSJérôme Duval { CODEC_ID_STAC9756,0xffffffff, stac9756_init, "SigmaTel STAC9756/9757" }, 160*7979b1cfSJérôme Duval { CODEC_ID_STAC9766,0xffffffff, default_init, "SigmaTel STAC9766/67" }, 161*7979b1cfSJérôme Duval { 0x53494c22, 0xffffffff, default_init, "Silicon Laboratory Si3036" }, 162*7979b1cfSJérôme Duval { 0x53494c23, 0xffffffff, default_init, "Silicon Laboratory Si3038" }, 163*7979b1cfSJérôme Duval { 0x54524103, 0xffffffff, default_init, "TriTech TR?????" }, 164*7979b1cfSJérôme Duval { 0x54524106, 0xffffffff, default_init, "TriTech TR28026" }, 165*7979b1cfSJérôme Duval { 0x54524108, 0xffffffff, tr28028_init, "TriTech TR28028" }, 166*7979b1cfSJérôme Duval { 0x54524123, 0xffffffff, default_init, "TriTech TR28602" }, 167*7979b1cfSJérôme Duval { 0x574d4c00, 0xffffffff, wm9701_init, "Wolfson WM9701A" }, 168*7979b1cfSJérôme Duval { 0x574d4c03, 0xffffffff, wm9703_init, "Wolfson WM9703/9704" }, 169*7979b1cfSJérôme Duval { 0x574d4c04, 0xffffffff, wm9704_init, "Wolfson WM9704 (quad)" }, 170*7979b1cfSJérôme Duval /* Vendors only: */ 171*7979b1cfSJérôme Duval { 0x41445300, 0xffffff00, default_init, "Analog Devices" }, 172*7979b1cfSJérôme Duval { 0x414b4d00, 0xffffff00, default_init, "Asahi Kasei" }, 173*7979b1cfSJérôme Duval { 0x414c4700, 0xffffff00, default_init, "Avance Logic (Realtek)" }, 174*7979b1cfSJérôme Duval { 0x434d4900, 0xffffff00, default_init, "C-Media" }, 175*7979b1cfSJérôme Duval { 0x43525900, 0xffffff00, default_init, "Cirrus Logic" }, 176*7979b1cfSJérôme Duval { 0x45838300, 0xffffff00, default_init, "ESS Technology" }, 177*7979b1cfSJérôme Duval { 0x49434500, 0xffffff00, default_init, "ICEnsemble" }, 178*7979b1cfSJérôme Duval { 0x4e534300, 0xffffff00, default_init, "National Semiconductor" }, 179*7979b1cfSJérôme Duval { 0x83847600, 0xffffff00, default_init, "SigmaTel" }, 180*7979b1cfSJérôme Duval { 0x53494c00, 0xffffff00, default_init, "Silicon Laboratory" }, 181*7979b1cfSJérôme Duval { 0x54524100, 0xffffff00, default_init, "TriTech" }, 182*7979b1cfSJérôme Duval { 0x574d4c00, 0xffffff00, default_init, "Wolfson" }, 183*7979b1cfSJérôme Duval { 0x00000000, 0x00000000, default_init, "Unknown" } /* must be last one, matches every codec */ 184*7979b1cfSJérôme Duval }; 185*7979b1cfSJérôme Duval 186*7979b1cfSJérôme Duval codec_table *find_codec_table(uint32 codecid); 187*7979b1cfSJérôme Duval 188*7979b1cfSJérôme Duval codec_table * 189*7979b1cfSJérôme Duval find_codec_table(uint32 codecid) 190*7979b1cfSJérôme Duval { 191*7979b1cfSJérôme Duval codec_table *codec; 192*7979b1cfSJérôme Duval for (codec = codecs; codec->id; codec++) 193*7979b1cfSJérôme Duval if ((codec->id & codec->mask) == (codecid & codec->mask)) 194*7979b1cfSJérôme Duval break; 195*7979b1cfSJérôme Duval return codec; 196*7979b1cfSJérôme Duval } 197*7979b1cfSJérôme Duval 198*7979b1cfSJérôme Duval void 199*7979b1cfSJérôme Duval ac97_attach(ac97_dev **_dev, codec_reg_read reg_read, codec_reg_write reg_write, void *cookie, 200*7979b1cfSJérôme Duval ushort subvendor_id, ushort subsystem_id) 201*7979b1cfSJérôme Duval { 202*7979b1cfSJérôme Duval ac97_dev *dev; 203*7979b1cfSJérôme Duval codec_table *codec; 204*7979b1cfSJérôme Duval int i; 205*7979b1cfSJérôme Duval 206*7979b1cfSJérôme Duval *_dev = dev = (ac97_dev *) malloc(sizeof(ac97_dev)); 207*7979b1cfSJérôme Duval dev->cookie = cookie; 208*7979b1cfSJérôme Duval dev->reg_read = reg_read; 209*7979b1cfSJérôme Duval dev->reg_write = reg_write; 210*7979b1cfSJérôme Duval dev->set_rate = 0; 211*7979b1cfSJérôme Duval dev->get_rate = 0; 212*7979b1cfSJérôme Duval dev->clock = 48000; /* default clock on non-broken motherboards */ 213*7979b1cfSJérôme Duval dev->min_vsr = 0x0001; 214*7979b1cfSJérôme Duval dev->max_vsr = 0xffff; 215*7979b1cfSJérôme Duval dev->reversed_eamp_polarity = false; 216*7979b1cfSJérôme Duval dev->capabilities = 0; 217*7979b1cfSJérôme Duval 218*7979b1cfSJérôme Duval dev->subsystem = (subvendor_id << 16) | subsystem_id; 219*7979b1cfSJérôme Duval 220*7979b1cfSJérôme Duval if (dev->subsystem == 0x161f202f 221*7979b1cfSJérôme Duval || dev->subsystem == 0x161f203a 222*7979b1cfSJérôme Duval || dev->subsystem == 0x161f204c 223*7979b1cfSJérôme Duval || dev->subsystem == 0x104d8144 224*7979b1cfSJérôme Duval || dev->subsystem == 0x104d8197 225*7979b1cfSJérôme Duval || dev->subsystem == 0x104d81c0 226*7979b1cfSJérôme Duval || dev->subsystem == 0x104d81c5 227*7979b1cfSJérôme Duval || dev->subsystem == 0x103c3089 228*7979b1cfSJérôme Duval || dev->subsystem == 0x103c309a 229*7979b1cfSJérôme Duval || dev->subsystem == 0x10338213 230*7979b1cfSJérôme Duval || dev->subsystem == 0x103382be) { 231*7979b1cfSJérôme Duval dev->reversed_eamp_polarity = true; 232*7979b1cfSJérôme Duval } 233*7979b1cfSJérôme Duval 234*7979b1cfSJérôme Duval /* reset the codec */ 235*7979b1cfSJérôme Duval LOG(("codec reset\n")); 236*7979b1cfSJérôme Duval ac97_reg_uncached_write(dev, AC97_RESET, 0x0000); 237*7979b1cfSJérôme Duval for (i = 0; i < 500; i++) { 238*7979b1cfSJérôme Duval if ((ac97_reg_uncached_read(dev, AC97_POWERDOWN) & 0xf) == 0xf) 239*7979b1cfSJérôme Duval break; 240*7979b1cfSJérôme Duval snooze(1000); 241*7979b1cfSJérôme Duval } 242*7979b1cfSJérôme Duval 243*7979b1cfSJérôme Duval dev->codec_id = ((uint32)reg_read(cookie, AC97_VENDOR_ID1) << 16) | reg_read(cookie, AC97_VENDOR_ID2); 244*7979b1cfSJérôme Duval codec = find_codec_table(dev->codec_id); 245*7979b1cfSJérôme Duval dev->codec_info = codec->info; 246*7979b1cfSJérôme Duval dev->init = codec->init; 247*7979b1cfSJérôme Duval 248*7979b1cfSJérôme Duval dev->codec_3d_stereo_enhancement = stereo_enhancement_technique[(ac97_reg_cached_read(dev, AC97_RESET) >> 10) & 31]; 249*7979b1cfSJérôme Duval 250*7979b1cfSJérôme Duval /* setup register cache */ 251*7979b1cfSJérôme Duval ac97_update_register_cache(dev); 252*7979b1cfSJérôme Duval 253*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_EXTENDED_STAT_CTRL, 1, 1); // enable variable rate audio 254*7979b1cfSJérôme Duval 255*7979b1cfSJérôme Duval ac97_detect_capabilities(dev); 256*7979b1cfSJérôme Duval 257*7979b1cfSJérôme Duval dev->init(dev); 258*7979b1cfSJérôme Duval ac97_amp_enable(dev, true); 259*7979b1cfSJérôme Duval 260*7979b1cfSJérôme Duval /* set mixer defaults, enabled Line-out sources are PCM-out, CD-in, Line-in */ 261*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_CENTER_LFE_VOLUME, 0x0000); /* set LFE & center volume 0dB */ 262*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_SURR_VOLUME, 0x0000); /* set surround volume 0dB */ 263*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_MASTER_VOLUME, 0x0000); /* set master output 0dB */ 264*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_AUX_OUT_VOLUME, 0x0000); /* set aux output 0dB */ 265*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_MONO_VOLUME, 0x0000); /* set mono output 0dB */ 266*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_PCM_OUT_VOLUME, 0x0808); /* enable pcm-out */ 267*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_CD_VOLUME, 0x0808); /* enable cd-in */ 268*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_LINE_IN_VOLUME, 0x0808); /* enable line-in */ 269*7979b1cfSJérôme Duval 270*7979b1cfSJérôme Duval /* set record line in */ 271*7979b1cfSJérôme Duval ac97_reg_update(dev, AC97_RECORD_SELECT, 0x0404); 272*7979b1cfSJérôme Duval 273*7979b1cfSJérôme Duval ac97_dump_capabilities(dev); 274*7979b1cfSJérôme Duval } 275*7979b1cfSJérôme Duval 276*7979b1cfSJérôme Duval void 277*7979b1cfSJérôme Duval ac97_detach(ac97_dev *dev) 278*7979b1cfSJérôme Duval { 279*7979b1cfSJérôme Duval /* Mute everything */ 280*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_CENTER_LFE_VOLUME, 0x8000, 0x8000); 281*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_SURR_VOLUME, 0x8000, 0x8000); 282*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_MASTER_VOLUME, 0x8000, 0x8000); 283*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_AUX_OUT_VOLUME, 0x8000, 0x8000); 284*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_MONO_VOLUME, 0x8000, 0x8000); 285*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_PCM_OUT_VOLUME, 0x8000, 0x8000); 286*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_CD_VOLUME, 0x8000, 0x8000); 287*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_LINE_IN_VOLUME, 0x8000, 0x8000); 288*7979b1cfSJérôme Duval 289*7979b1cfSJérôme Duval ac97_amp_enable(dev, false); 290*7979b1cfSJérôme Duval 291*7979b1cfSJérôme Duval free(dev); 292*7979b1cfSJérôme Duval } 293*7979b1cfSJérôme Duval 294*7979b1cfSJérôme Duval void 295*7979b1cfSJérôme Duval ac97_suspend(ac97_dev *dev) 296*7979b1cfSJérôme Duval { 297*7979b1cfSJérôme Duval ac97_amp_enable(dev, false); 298*7979b1cfSJérôme Duval } 299*7979b1cfSJérôme Duval 300*7979b1cfSJérôme Duval void 301*7979b1cfSJérôme Duval ac97_resume(ac97_dev *dev) 302*7979b1cfSJérôme Duval { 303*7979b1cfSJérôme Duval ac97_amp_enable(dev, true); 304*7979b1cfSJérôme Duval } 305*7979b1cfSJérôme Duval 306*7979b1cfSJérôme Duval void 307*7979b1cfSJérôme Duval ac97_reg_cached_write(ac97_dev *dev, uint8 reg, uint16 value) 308*7979b1cfSJérôme Duval { 309*7979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 310*7979b1cfSJérôme Duval return; 311*7979b1cfSJérôme Duval dev->reg_write(dev->cookie, reg, value); 312*7979b1cfSJérôme Duval dev->reg_cache[reg] = value; 313*7979b1cfSJérôme Duval } 314*7979b1cfSJérôme Duval 315*7979b1cfSJérôme Duval uint16 316*7979b1cfSJérôme Duval ac97_reg_cached_read(ac97_dev *dev, uint8 reg) 317*7979b1cfSJérôme Duval { 318*7979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 319*7979b1cfSJérôme Duval return 0; 320*7979b1cfSJérôme Duval return dev->reg_cache[reg]; 321*7979b1cfSJérôme Duval } 322*7979b1cfSJérôme Duval 323*7979b1cfSJérôme Duval void 324*7979b1cfSJérôme Duval ac97_reg_uncached_write(ac97_dev *dev, uint8 reg, uint16 value) 325*7979b1cfSJérôme Duval { 326*7979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 327*7979b1cfSJérôme Duval return; 328*7979b1cfSJérôme Duval dev->reg_write(dev->cookie, reg, value); 329*7979b1cfSJérôme Duval } 330*7979b1cfSJérôme Duval 331*7979b1cfSJérôme Duval uint16 332*7979b1cfSJérôme Duval ac97_reg_uncached_read(ac97_dev *dev, uint8 reg) 333*7979b1cfSJérôme Duval { 334*7979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 335*7979b1cfSJérôme Duval return 0; 336*7979b1cfSJérôme Duval return dev->reg_read(dev->cookie, reg); 337*7979b1cfSJérôme Duval } 338*7979b1cfSJérôme Duval 339*7979b1cfSJérôme Duval bool 340*7979b1cfSJérôme Duval ac97_reg_update(ac97_dev *dev, uint8 reg, uint16 value) 341*7979b1cfSJérôme Duval { 342*7979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 343*7979b1cfSJérôme Duval return false; 344*7979b1cfSJérôme Duval if (ac97_reg_cached_read(dev, reg) == value) 345*7979b1cfSJérôme Duval return false; 346*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, reg, value); 347*7979b1cfSJérôme Duval return true; 348*7979b1cfSJérôme Duval } 349*7979b1cfSJérôme Duval 350*7979b1cfSJérôme Duval bool 351*7979b1cfSJérôme Duval ac97_reg_update_bits(ac97_dev *dev, uint8 reg, uint16 mask, uint16 value) 352*7979b1cfSJérôme Duval { 353*7979b1cfSJérôme Duval uint16 old; 354*7979b1cfSJérôme Duval if (!ac97_reg_is_valid(dev, reg)) 355*7979b1cfSJérôme Duval return false; 356*7979b1cfSJérôme Duval old = ac97_reg_cached_read(dev, reg); 357*7979b1cfSJérôme Duval value &= mask; 358*7979b1cfSJérôme Duval value |= (old & ~mask); 359*7979b1cfSJérôme Duval if (old == value) 360*7979b1cfSJérôme Duval return false; 361*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, reg, value); 362*7979b1cfSJérôme Duval return true; 363*7979b1cfSJérôme Duval } 364*7979b1cfSJérôme Duval 365*7979b1cfSJérôme Duval void 366*7979b1cfSJérôme Duval ac97_update_register_cache(ac97_dev *dev) 367*7979b1cfSJérôme Duval { 368*7979b1cfSJérôme Duval int reg; 369*7979b1cfSJérôme Duval for (reg = 0; reg <= 0x7e; reg += 2) 370*7979b1cfSJérôme Duval dev->reg_cache[reg] = ac97_reg_uncached_read(dev, reg); 371*7979b1cfSJérôme Duval } 372*7979b1cfSJérôme Duval 373*7979b1cfSJérôme Duval bool 374*7979b1cfSJérôme Duval ac97_set_rate(ac97_dev *dev, uint8 reg, uint32 rate) 375*7979b1cfSJérôme Duval { 376*7979b1cfSJérôme Duval uint32 value; 377*7979b1cfSJérôme Duval uint32 old; 378*7979b1cfSJérôme Duval 379*7979b1cfSJérôme Duval if (dev->set_rate) 380*7979b1cfSJérôme Duval return dev->set_rate(dev, reg, rate); 381*7979b1cfSJérôme Duval 382*7979b1cfSJérôme Duval value = (uint32)((rate * 48000ULL) / dev->clock); /* need 64 bit calculation for rates 96000 or higher */ 383*7979b1cfSJérôme Duval 384*7979b1cfSJérôme Duval LOG(("ac97_set_rate: clock = %ld, rate = %ld, value = %ld\n", dev->clock, rate, value)); 385*7979b1cfSJérôme Duval 386*7979b1cfSJérôme Duval /* if double rate audio is currently enabled, divide value by 2 */ 387*7979b1cfSJérôme Duval if (ac97_reg_cached_read(dev, AC97_EXTENDED_STAT_CTRL) & 0x0002) 388*7979b1cfSJérôme Duval value /= 2; 389*7979b1cfSJérôme Duval 390*7979b1cfSJérôme Duval if (value < dev->min_vsr || value > dev->max_vsr) 391*7979b1cfSJérôme Duval return false; 392*7979b1cfSJérôme Duval 393*7979b1cfSJérôme Duval old = ac97_reg_cached_read(dev, reg); 394*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, reg, value); 395*7979b1cfSJérôme Duval if (value != ac97_reg_uncached_read(dev, reg)) { 396*7979b1cfSJérôme Duval LOG(("ac97_set_rate failed, new rate %d\n", ac97_reg_uncached_read(dev, reg))); 397*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, reg, old); 398*7979b1cfSJérôme Duval return false; 399*7979b1cfSJérôme Duval } 400*7979b1cfSJérôme Duval LOG(("ac97_set_rate done\n")); 401*7979b1cfSJérôme Duval return true; 402*7979b1cfSJérôme Duval } 403*7979b1cfSJérôme Duval 404*7979b1cfSJérôme Duval bool 405*7979b1cfSJérôme Duval ac97_get_rate(ac97_dev *dev, uint8 reg, uint32 *rate) 406*7979b1cfSJérôme Duval { 407*7979b1cfSJérôme Duval uint32 value; 408*7979b1cfSJérôme Duval 409*7979b1cfSJérôme Duval if (dev->get_rate) 410*7979b1cfSJérôme Duval return dev->get_rate(dev, reg, rate); 411*7979b1cfSJérôme Duval 412*7979b1cfSJérôme Duval value = ac97_reg_cached_read(dev, reg); 413*7979b1cfSJérôme Duval if (value == 0) 414*7979b1cfSJérôme Duval return false; 415*7979b1cfSJérôme Duval 416*7979b1cfSJérôme Duval /* if double rate audio is currently enabled, multiply value by 2 */ 417*7979b1cfSJérôme Duval if (ac97_reg_cached_read(dev, AC97_EXTENDED_STAT_CTRL) & 0x0002) 418*7979b1cfSJérôme Duval value *= 2; 419*7979b1cfSJérôme Duval 420*7979b1cfSJérôme Duval *rate = (uint32)((value * (uint64)dev->clock) / 48000); /* need 64 bit calculation to avoid overflow*/ 421*7979b1cfSJérôme Duval return true; 422*7979b1cfSJérôme Duval } 423*7979b1cfSJérôme Duval 424*7979b1cfSJérôme Duval void 425*7979b1cfSJérôme Duval ac97_set_clock(ac97_dev *dev, uint32 clock) 426*7979b1cfSJérôme Duval { 427*7979b1cfSJérôme Duval LOG(("ac97_set_clock: clock = %ld\n", clock)); 428*7979b1cfSJérôme Duval dev->clock = clock; 429*7979b1cfSJérôme Duval ac97_detect_rates(dev); 430*7979b1cfSJérôme Duval ac97_dump_capabilities(dev); 431*7979b1cfSJérôme Duval } 432*7979b1cfSJérôme Duval 433*7979b1cfSJérôme Duval void 434*7979b1cfSJérôme Duval ac97_detect_capabilities(ac97_dev *dev) 435*7979b1cfSJérôme Duval { 436*7979b1cfSJérôme Duval uint16 val; 437*7979b1cfSJérôme Duval 438*7979b1cfSJérôme Duval val = ac97_reg_cached_read(dev, AC97_RESET); 439*7979b1cfSJérôme Duval if (val & 0x0001) 440*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_MIC; 441*7979b1cfSJérôme Duval if (val & 0x0004) 442*7979b1cfSJérôme Duval dev->capabilities |= CAP_BASS_TREBLE_CTRL; 443*7979b1cfSJérôme Duval if (val & 0x0008) 444*7979b1cfSJérôme Duval dev->capabilities |= CAP_SIMULATED_STEREO; 445*7979b1cfSJérôme Duval if (val & 0x0010) 446*7979b1cfSJérôme Duval dev->capabilities |= CAP_HEADPHONE_OUT; 447*7979b1cfSJérôme Duval if (val & 0x0020) 448*7979b1cfSJérôme Duval dev->capabilities |= CAP_LAUDNESS; 449*7979b1cfSJérôme Duval if (val & 0x0040) 450*7979b1cfSJérôme Duval dev->capabilities |= CAP_DAC_18BIT; 451*7979b1cfSJérôme Duval if (val & 0x0080) 452*7979b1cfSJérôme Duval dev->capabilities |= CAP_DAC_20BIT; 453*7979b1cfSJérôme Duval if (val & 0x0100) 454*7979b1cfSJérôme Duval dev->capabilities |= CAP_ADC_18BIT; 455*7979b1cfSJérôme Duval if (val & 0x0200) 456*7979b1cfSJérôme Duval dev->capabilities |= CAP_ADC_20BIT; 457*7979b1cfSJérôme Duval if (val & 0x7C00) 458*7979b1cfSJérôme Duval dev->capabilities |= CAP_3D_ENHANCEMENT; 459*7979b1cfSJérôme Duval 460*7979b1cfSJérôme Duval val = ac97_reg_cached_read(dev, AC97_EXTENDED_ID); 461*7979b1cfSJérôme Duval if (val & EXID_VRA) 462*7979b1cfSJérôme Duval dev->capabilities |= CAP_VARIABLE_PCM; 463*7979b1cfSJérôme Duval if (val & EXID_DRA) 464*7979b1cfSJérôme Duval dev->capabilities |= CAP_DOUBLE_PCM; 465*7979b1cfSJérôme Duval if (val & EXID_SPDIF) 466*7979b1cfSJérôme Duval dev->capabilities |= CAP_SPDIF; 467*7979b1cfSJérôme Duval if (val & EXID_VRM) 468*7979b1cfSJérôme Duval dev->capabilities |= CAP_VARIABLE_MIC; 469*7979b1cfSJérôme Duval if (val & EXID_CDAC) 470*7979b1cfSJérôme Duval dev->capabilities |= CAP_CENTER_DAC; 471*7979b1cfSJérôme Duval if (val & EXID_SDAC) 472*7979b1cfSJérôme Duval dev->capabilities |= CAP_SURR_DAC; 473*7979b1cfSJérôme Duval if (val & EXID_LDAC) 474*7979b1cfSJérôme Duval dev->capabilities |= CAP_LFE_DAC; 475*7979b1cfSJérôme Duval if (val & EXID_AMAP) 476*7979b1cfSJérôme Duval dev->capabilities |= CAP_AMAP; 477*7979b1cfSJérôme Duval if ((val & (EXID_REV0 | EXID_REV1)) == 0) 478*7979b1cfSJérôme Duval dev->capabilities |= CAP_REV21; 479*7979b1cfSJérôme Duval if ((val & (EXID_REV0 | EXID_REV1)) == EXID_REV0) 480*7979b1cfSJérôme Duval dev->capabilities |= CAP_REV22; 481*7979b1cfSJérôme Duval if ((val & (EXID_REV0 | EXID_REV1)) == EXID_REV1) 482*7979b1cfSJérôme Duval dev->capabilities |= CAP_REV23; 483*7979b1cfSJérôme Duval 484*7979b1cfSJérôme Duval ac97_detect_rates(dev); 485*7979b1cfSJérôme Duval } 486*7979b1cfSJérôme Duval 487*7979b1cfSJérôme Duval void 488*7979b1cfSJérôme Duval ac97_detect_rates(ac97_dev *dev) 489*7979b1cfSJérôme Duval { 490*7979b1cfSJérôme Duval uint32 oldrate; 491*7979b1cfSJérôme Duval 492*7979b1cfSJérôme Duval dev->capabilities &= ~CAP_PCM_RATE_MASK; 493*7979b1cfSJérôme Duval 494*7979b1cfSJérôme Duval if (!ac97_get_rate(dev, AC97_PCM_FRONT_DAC_RATE, &oldrate)) 495*7979b1cfSJérôme Duval oldrate = 48000; 496*7979b1cfSJérôme Duval 497*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 20000)) 498*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_CONTINUOUS; 499*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 8000)) 500*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_8000; 501*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 11025)) 502*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_11025; 503*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 12000)) 504*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_12000; 505*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 16000)) 506*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_16000; 507*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 22050)) 508*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_22050; 509*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 24000)) 510*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_24000; 511*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 32000)) 512*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_32000; 513*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 44100)) 514*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_44100; 515*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 48000)) 516*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_48000; 517*7979b1cfSJérôme Duval 518*7979b1cfSJérôme Duval if (dev->capabilities & CAP_DOUBLE_PCM) { 519*7979b1cfSJérôme Duval // enable double rate mode 520*7979b1cfSJérôme Duval if (ac97_reg_update_bits(dev, AC97_EXTENDED_STAT_CTRL, 0x0002, 0x0002)) { 521*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 88200)) 522*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_88200; 523*7979b1cfSJérôme Duval if (ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 96000)) 524*7979b1cfSJérôme Duval dev->capabilities |= CAP_PCM_RATE_96000; 525*7979b1cfSJérôme Duval // disable double rate mode 526*7979b1cfSJérôme Duval ac97_reg_update_bits(dev, AC97_EXTENDED_STAT_CTRL, 0x0002, 0x0000); 527*7979b1cfSJérôme Duval } 528*7979b1cfSJérôme Duval } 529*7979b1cfSJérôme Duval 530*7979b1cfSJérôme Duval ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, oldrate); 531*7979b1cfSJérôme Duval } 532*7979b1cfSJérôme Duval 533*7979b1cfSJérôme Duval void 534*7979b1cfSJérôme Duval ac97_dump_capabilities(ac97_dev *dev) 535*7979b1cfSJérôme Duval { 536*7979b1cfSJérôme Duval LOG(("AC97 capabilities:\n")); 537*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_MIC)) 538*7979b1cfSJérôme Duval LOG(("CAP_PCM_MIC\n")); 539*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_BASS_TREBLE_CTRL)) 540*7979b1cfSJérôme Duval LOG(("CAP_BASS_TREBLE_CTRL\n")); 541*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_SIMULATED_STEREO)) 542*7979b1cfSJérôme Duval LOG(("CAP_SIMULATED_STEREO\n")); 543*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_HEADPHONE_OUT)) 544*7979b1cfSJérôme Duval LOG(("CAP_HEADPHONE_OUT\n")); 545*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_LAUDNESS)) 546*7979b1cfSJérôme Duval LOG(("CAP_LAUDNESS\n")); 547*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_DAC_18BIT)) 548*7979b1cfSJérôme Duval LOG(("CAP_DAC_18BIT\n")); 549*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_DAC_20BIT)) 550*7979b1cfSJérôme Duval LOG(("CAP_DAC_20BIT\n")); 551*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_ADC_18BIT)) 552*7979b1cfSJérôme Duval LOG(("CAP_ADC_18BIT\n")); 553*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_ADC_20BIT)) 554*7979b1cfSJérôme Duval LOG(("CAP_ADC_20BIT\n")); 555*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_3D_ENHANCEMENT)) 556*7979b1cfSJérôme Duval LOG(("CAP_3D_ENHANCEMENT\n")); 557*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_VARIABLE_PCM)) 558*7979b1cfSJérôme Duval LOG(("CAP_VARIABLE_PCM\n")); 559*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_DOUBLE_PCM)) 560*7979b1cfSJérôme Duval LOG(("CAP_DOUBLE_PCM\n")); 561*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_VARIABLE_MIC)) 562*7979b1cfSJérôme Duval LOG(("CAP_VARIABLE_MIC\n")); 563*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_CENTER_DAC)) 564*7979b1cfSJérôme Duval LOG(("CAP_CENTER_DAC\n")); 565*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_SURR_DAC)) 566*7979b1cfSJérôme Duval LOG(("CAP_SURR_DAC\n")); 567*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_LFE_DAC)) 568*7979b1cfSJérôme Duval LOG(("CAP_LFE_DAC\n")); 569*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_AMAP)) 570*7979b1cfSJérôme Duval LOG(("CAP_AMAP\n")); 571*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_REV21)) 572*7979b1cfSJérôme Duval LOG(("CAP_REV21\n")); 573*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_REV22)) 574*7979b1cfSJérôme Duval LOG(("CAP_REV22\n")); 575*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_REV23)) 576*7979b1cfSJérôme Duval LOG(("CAP_REV23\n")); 577*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_CONTINUOUS)) 578*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_CONTINUOUS\n")); 579*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_8000)) 580*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_8000\n")); 581*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_11025)) 582*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_11025\n")); 583*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_12000)) 584*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_12000\n")); 585*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_16000)) 586*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_16000\n")); 587*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_22050)) 588*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_22050\n")); 589*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_24000)) 590*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_24000\n")); 591*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_32000)) 592*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_32000\n")); 593*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_44100)) 594*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_44100\n")); 595*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_48000)) 596*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_48000\n")); 597*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_88200)) 598*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_88200\n")); 599*7979b1cfSJérôme Duval if (ac97_has_capability(dev, CAP_PCM_RATE_96000)) 600*7979b1cfSJérôme Duval LOG(("CAP_PCM_RATE_96000\n")); 601*7979b1cfSJérôme Duval } 602*7979b1cfSJérôme Duval 603*7979b1cfSJérôme Duval bool 604*7979b1cfSJérôme Duval ac97_has_capability(ac97_dev *dev, uint64 cap) 605*7979b1cfSJérôme Duval { 606*7979b1cfSJérôme Duval // return (dev->capabilities & cap); // does not work because of 64 bit to integer trucation 607*7979b1cfSJérôme Duval return (dev->capabilities & cap) != 0; 608*7979b1cfSJérôme Duval } 609*7979b1cfSJérôme Duval 610*7979b1cfSJérôme Duval /************************************************* 611*7979b1cfSJérôme Duval * Codec specific initialization, etc. 612*7979b1cfSJérôme Duval */ 613*7979b1cfSJérôme Duval 614*7979b1cfSJérôme Duval bool 615*7979b1cfSJérôme Duval ac97_reg_is_valid(ac97_dev *dev, uint8 reg) 616*7979b1cfSJérôme Duval { 617*7979b1cfSJérôme Duval if (reg & 1) 618*7979b1cfSJérôme Duval return false; 619*7979b1cfSJérôme Duval if (reg > 0x7e) 620*7979b1cfSJérôme Duval return false; 621*7979b1cfSJérôme Duval 622*7979b1cfSJérôme Duval switch (dev->codec_id) { 623*7979b1cfSJérôme Duval case CODEC_ID_AK4540: 624*7979b1cfSJérôme Duval case CODEC_ID_AK4542: 625*7979b1cfSJérôme Duval if (reg < 0x1e || reg == 0x20 || reg == 0x26 || reg > 0x7a) 626*7979b1cfSJérôme Duval return true; 627*7979b1cfSJérôme Duval return false; 628*7979b1cfSJérôme Duval 629*7979b1cfSJérôme Duval case CODEC_ID_AD1819: 630*7979b1cfSJérôme Duval case CODEC_ID_AD1881: 631*7979b1cfSJérôme Duval case CODEC_ID_AD1881A: 632*7979b1cfSJérôme Duval if (reg < 0x3a || reg > 0x6e) 633*7979b1cfSJérôme Duval return true; 634*7979b1cfSJérôme Duval return false; 635*7979b1cfSJérôme Duval 636*7979b1cfSJérôme Duval case CODEC_ID_AD1885: 637*7979b1cfSJérôme Duval case CODEC_ID_AD1886: 638*7979b1cfSJérôme Duval case CODEC_ID_AD1886A: 639*7979b1cfSJérôme Duval case CODEC_ID_AD1887: 640*7979b1cfSJérôme Duval if (reg < 0x3c || reg == 0x5a || reg > 0x6e) 641*7979b1cfSJérôme Duval return true; 642*7979b1cfSJérôme Duval return false; 643*7979b1cfSJérôme Duval 644*7979b1cfSJérôme Duval case CODEC_ID_STAC9700: 645*7979b1cfSJérôme Duval case CODEC_ID_STAC9704: 646*7979b1cfSJérôme Duval case CODEC_ID_STAC9705: 647*7979b1cfSJérôme Duval case CODEC_ID_STAC9708: 648*7979b1cfSJérôme Duval case CODEC_ID_STAC9721: 649*7979b1cfSJérôme Duval case CODEC_ID_STAC9744: 650*7979b1cfSJérôme Duval case CODEC_ID_STAC9756: 651*7979b1cfSJérôme Duval if (reg < 0x3c || reg > 0x58) 652*7979b1cfSJérôme Duval return true; 653*7979b1cfSJérôme Duval return false; 654*7979b1cfSJérôme Duval 655*7979b1cfSJérôme Duval default: 656*7979b1cfSJérôme Duval return true; 657*7979b1cfSJérôme Duval } 658*7979b1cfSJérôme Duval } 659*7979b1cfSJérôme Duval 660*7979b1cfSJérôme Duval void ac97_amp_enable(ac97_dev *dev, bool yesno) 661*7979b1cfSJérôme Duval { 662*7979b1cfSJérôme Duval switch (dev->codec_id) { 663*7979b1cfSJérôme Duval case CODEC_ID_CS4299A: 664*7979b1cfSJérôme Duval case CODEC_ID_CS4299C: 665*7979b1cfSJérôme Duval case CODEC_ID_CS4299D: 666*7979b1cfSJérôme Duval LOG(("cs4299_amp_enable\n")); 667*7979b1cfSJérôme Duval if (yesno) 668*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x68, 0x8004); 669*7979b1cfSJérôme Duval else 670*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x68, 0); 671*7979b1cfSJérôme Duval break; 672*7979b1cfSJérôme Duval 673*7979b1cfSJérôme Duval default: 674*7979b1cfSJérôme Duval LOG(("ac97_amp_enable, reverse eamp = %d\n", dev->reversed_eamp_polarity)); 675*7979b1cfSJérôme Duval LOG(("powerdown register was = %#04x\n", ac97_reg_uncached_read(dev, AC97_POWERDOWN))); 676*7979b1cfSJérôme Duval if (dev->reversed_eamp_polarity) 677*7979b1cfSJérôme Duval yesno = !yesno; 678*7979b1cfSJérôme Duval if (yesno) 679*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_POWERDOWN, ac97_reg_uncached_read(dev, AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */ 680*7979b1cfSJérôme Duval else 681*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_POWERDOWN, ac97_reg_uncached_read(dev, AC97_POWERDOWN) | 0x8000); /* switch off */ 682*7979b1cfSJérôme Duval LOG(("powerdown register is = %#04x\n", ac97_reg_uncached_read(dev, AC97_POWERDOWN))); 683*7979b1cfSJérôme Duval break; 684*7979b1cfSJérôme Duval } 685*7979b1cfSJérôme Duval } 686*7979b1cfSJérôme Duval 687*7979b1cfSJérôme Duval bool 688*7979b1cfSJérôme Duval ad1819_set_rate(ac97_dev *dev, uint8 reg, uint32 rate) 689*7979b1cfSJérôme Duval { 690*7979b1cfSJérôme Duval uint32 value; 691*7979b1cfSJérôme Duval 692*7979b1cfSJérôme Duval value = (uint32)((rate * 48000ULL) / dev->clock); /* need 64 bit calculation for rates 96000 or higher */ 693*7979b1cfSJérôme Duval 694*7979b1cfSJérôme Duval LOG(("ad1819_set_rate: clock = %ld, rate = %ld, value = %ld\n", dev->clock, rate, value)); 695*7979b1cfSJérôme Duval 696*7979b1cfSJérôme Duval if (value < 0x1B58 || value > 0xBB80) 697*7979b1cfSJérôme Duval return false; 698*7979b1cfSJérôme Duval 699*7979b1cfSJérôme Duval switch (reg) { 700*7979b1cfSJérôme Duval case AC97_PCM_FRONT_DAC_RATE: 701*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SAMPLE_RATE_0, value); 702*7979b1cfSJérôme Duval return true; 703*7979b1cfSJérôme Duval 704*7979b1cfSJérôme Duval case AC97_PCM_L_R_ADC_RATE: 705*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SAMPLE_RATE_1, value); 706*7979b1cfSJérôme Duval return true; 707*7979b1cfSJérôme Duval 708*7979b1cfSJérôme Duval default: 709*7979b1cfSJérôme Duval return false; 710*7979b1cfSJérôme Duval } 711*7979b1cfSJérôme Duval } 712*7979b1cfSJérôme Duval 713*7979b1cfSJérôme Duval bool 714*7979b1cfSJérôme Duval ad1819_get_rate(ac97_dev *dev, uint8 reg, uint32 *rate) 715*7979b1cfSJérôme Duval { 716*7979b1cfSJérôme Duval uint32 value; 717*7979b1cfSJérôme Duval 718*7979b1cfSJérôme Duval switch (reg) { 719*7979b1cfSJérôme Duval case AC97_PCM_FRONT_DAC_RATE: 720*7979b1cfSJérôme Duval value = ac97_reg_cached_read(dev, AC97_AD_SAMPLE_RATE_0); 721*7979b1cfSJérôme Duval break; 722*7979b1cfSJérôme Duval 723*7979b1cfSJérôme Duval case AC97_PCM_L_R_ADC_RATE: 724*7979b1cfSJérôme Duval value = ac97_reg_cached_read(dev, AC97_AD_SAMPLE_RATE_1); 725*7979b1cfSJérôme Duval break; 726*7979b1cfSJérôme Duval 727*7979b1cfSJérôme Duval default: 728*7979b1cfSJérôme Duval return false; 729*7979b1cfSJérôme Duval } 730*7979b1cfSJérôme Duval 731*7979b1cfSJérôme Duval *rate = (uint32)((value * (uint64)dev->clock) / 48000); /* need 64 bit calculation to avoid overflow*/ 732*7979b1cfSJérôme Duval return true; 733*7979b1cfSJérôme Duval } 734*7979b1cfSJérôme Duval 735*7979b1cfSJérôme Duval 736*7979b1cfSJérôme Duval void default_init(ac97_dev *dev) 737*7979b1cfSJérôme Duval { 738*7979b1cfSJérôme Duval LOG(("default_init\n")); 739*7979b1cfSJérôme Duval } 740*7979b1cfSJérôme Duval 741*7979b1cfSJérôme Duval void ad1819_init(ac97_dev *dev) 742*7979b1cfSJérôme Duval { 743*7979b1cfSJérôme Duval LOG(("ad1819_init\n")); 744*7979b1cfSJérôme Duval 745*7979b1cfSJérôme Duval /* Default config for system with single AD1819 codec */ 746*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SERIAL_CONFIG, 0x7000); 747*7979b1cfSJérôme Duval ac97_update_register_cache(dev); 748*7979b1cfSJérôme Duval 749*7979b1cfSJérôme Duval /* The AD1819 chip has proprietary sample rate controls 750*7979b1cfSJérôme Duval * Setup sample rate 0 generator for DAC, 751*7979b1cfSJérôme Duval * Setup sample rate 1 generator for ADC, 752*7979b1cfSJérôme Duval * ARSR=1, DRSR=0, ALSR=1, DLSR=0 753*7979b1cfSJérôme Duval */ 754*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_MISC_CONTROL, 0x0101); 755*7979b1cfSJérôme Duval /* connect special rate set/get functions */ 756*7979b1cfSJérôme Duval dev->set_rate = ad1819_set_rate; 757*7979b1cfSJérôme Duval dev->get_rate = ad1819_get_rate; 758*7979b1cfSJérôme Duval ac97_detect_rates(dev); 759*7979b1cfSJérôme Duval ac97_set_rate(dev, AC97_PCM_FRONT_DAC_RATE, 48000); 760*7979b1cfSJérôme Duval ac97_set_rate(dev, AC97_PCM_L_R_ADC_RATE, 48000); 761*7979b1cfSJérôme Duval } 762*7979b1cfSJérôme Duval 763*7979b1cfSJérôme Duval void ad1881_init(ac97_dev *dev) 764*7979b1cfSJérôme Duval { 765*7979b1cfSJérôme Duval LOG(("ad1881_init\n")); 766*7979b1cfSJérôme Duval 767*7979b1cfSJérôme Duval /* Default config for system with single AD1819 codec, 768*7979b1cfSJérôme Duval * BROKEN on systems with master & slave codecs */ 769*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SERIAL_CONFIG, 0x7000); 770*7979b1cfSJérôme Duval ac97_update_register_cache(dev); 771*7979b1cfSJérôme Duval 772*7979b1cfSJérôme Duval /* Setup DAC and ADC rate generator assignments compatible with AC97 */ 773*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_MISC_CONTROL, 0x0404); 774*7979b1cfSJérôme Duval 775*7979b1cfSJérôme Duval /* Setup variable frame rate limits */ 776*7979b1cfSJérôme Duval dev->min_vsr = 0x1B58; /* 7kHz */ 777*7979b1cfSJérôme Duval dev->max_vsr = 0xBB80; /* 48kHz */ 778*7979b1cfSJérôme Duval } 779*7979b1cfSJérôme Duval 780*7979b1cfSJérôme Duval void ad1885_init(ac97_dev *dev) 781*7979b1cfSJérôme Duval { 782*7979b1cfSJérôme Duval LOG(("ad1885_init\n")); 783*7979b1cfSJérôme Duval ad1881_init(dev); 784*7979b1cfSJérôme Duval 785*7979b1cfSJérôme Duval /* disable jack sense 0 and 1 (JS0, JS1) to turn off automatic mute */ 786*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_JACK_SENSE, ac97_reg_cached_read(dev, AC97_AD_JACK_SENSE) | 0x0300); 787*7979b1cfSJérôme Duval } 788*7979b1cfSJérôme Duval 789*7979b1cfSJérôme Duval void ad1886_init(ac97_dev *dev) 790*7979b1cfSJérôme Duval { 791*7979b1cfSJérôme Duval LOG(("ad1886_init\n")); 792*7979b1cfSJérôme Duval ad1881_init(dev); 793*7979b1cfSJérôme Duval 794*7979b1cfSJérôme Duval /* change jack sense to always activate outputs*/ 795*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_JACK_SENSE, 0x0010); 796*7979b1cfSJérôme Duval /* change SPDIF to a valid value */ 797*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_SPDIF_CONTROL, 0x2a20); 798*7979b1cfSJérôme Duval } 799*7979b1cfSJérôme Duval 800*7979b1cfSJérôme Duval void ad1980_init(ac97_dev *dev) 801*7979b1cfSJérôme Duval { 802*7979b1cfSJérôme Duval LOG(("ad1980_init\n")); 803*7979b1cfSJérôme Duval 804*7979b1cfSJérôme Duval /* Select only master codec, 805*7979b1cfSJérôme Duval * SPDIF and DAC are linked 806*7979b1cfSJérôme Duval */ 807*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_SERIAL_CONFIG, 0x1001); 808*7979b1cfSJérôme Duval ac97_update_register_cache(dev); 809*7979b1cfSJérôme Duval 810*7979b1cfSJérôme Duval /* Select Line-out driven with mixer data (not surround data) 811*7979b1cfSJérôme Duval * Select Headphone-out driven with mixer data (not surround data), 812*7979b1cfSJérôme Duval * LOSEL = 0, HPSEL = 1 813*7979b1cfSJérôme Duval * XXX this one needs to be changed to support surround out 814*7979b1cfSJérôme Duval */ 815*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_MISC_CONTROL, 0x0400); 816*7979b1cfSJérôme Duval } 817*7979b1cfSJérôme Duval 818*7979b1cfSJérôme Duval void ad1981b_init(ac97_dev *dev) 819*7979b1cfSJérôme Duval { 820*7979b1cfSJérôme Duval LOG(("ad1981b_init\n")); 821*7979b1cfSJérôme Duval if (dev->subsystem == 0x103c0934 822*7979b1cfSJérôme Duval || dev->subsystem == 0x103c006d 823*7979b1cfSJérôme Duval || dev->subsystem == 0x103c088c 824*7979b1cfSJérôme Duval || dev->subsystem == 0x103c0890 825*7979b1cfSJérôme Duval || dev->subsystem == 0x103c0934 826*7979b1cfSJérôme Duval || dev->subsystem == 0x103c0938 827*7979b1cfSJérôme Duval || dev->subsystem == 0x103c0944 828*7979b1cfSJérôme Duval || dev->subsystem == 0x103c099c 829*7979b1cfSJérôme Duval || dev->subsystem == 0x101402d9) { 830*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_AD_JACK_SENSE, 831*7979b1cfSJérôme Duval ac97_reg_cached_read(dev, AC97_AD_JACK_SENSE) | 0x0800); 832*7979b1cfSJérôme Duval } 833*7979b1cfSJérôme Duval } 834*7979b1cfSJérôme Duval 835*7979b1cfSJérôme Duval void alc650_init(ac97_dev *dev) 836*7979b1cfSJérôme Duval { 837*7979b1cfSJérôme Duval LOG(("alc650_init\n")); 838*7979b1cfSJérôme Duval 839*7979b1cfSJérôme Duval /* Enable Surround, LFE and Center downmix into Line-out, 840*7979b1cfSJérôme Duval * Set Surround-out as duplicated Line-out. 841*7979b1cfSJérôme Duval */ 842*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_ALC650_MULTI_CHAN_CTRL, 0x0007); 843*7979b1cfSJérôme Duval 844*7979b1cfSJérôme Duval /* Set Surround DAC Volume to 0dB 845*7979b1cfSJérôme Duval * Set Center/LFE DAC Volume to 0dB 846*7979b1cfSJérôme Duval * (but both should already be set, as these are hardware reset defaults) 847*7979b1cfSJérôme Duval */ 848*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_ALC650_SURR_VOLUME, 0x0808); 849*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_ALC650_CEN_LFE_VOLUME, 0x0808); 850*7979b1cfSJérôme Duval } 851*7979b1cfSJérôme Duval 852*7979b1cfSJérôme Duval void stac9708_init(ac97_dev *dev) 853*7979b1cfSJérôme Duval { 854*7979b1cfSJérôme Duval LOG(("stac9708_init\n")); 855*7979b1cfSJérôme Duval /* ALSA initializes some registers that according to the 856*7979b1cfSJérôme Duval * documentation for this codec do not exist. If the 857*7979b1cfSJérôme Duval * following doesn't work, we may need to do that, too. 858*7979b1cfSJérôme Duval */ 859*7979b1cfSJérôme Duval /* The Analog Special reg is at 0x6C, other codecs have it at 0x6E */ 860*7979b1cfSJérôme Duval /* Set Analog Special to default (DAC/ADC -6dB disabled) */ 861*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x6C, 0x0000); 862*7979b1cfSJérôme Duval /* Set Multi Channel to default */ 863*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0000); 864*7979b1cfSJérôme Duval } 865*7979b1cfSJérôme Duval 866*7979b1cfSJérôme Duval void stac9721_init(ac97_dev *dev) 867*7979b1cfSJérôme Duval { 868*7979b1cfSJérôme Duval LOG(("stac9721_init\n")); 869*7979b1cfSJérôme Duval /* Set Analog Special to default (DAC/ADC -6dB disabled) */ 870*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x6E, 0x0000); 871*7979b1cfSJérôme Duval /* Enable register 0x72 */ 872*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x70, 0xabba); 873*7979b1cfSJérôme Duval /* Set Analog Current to -50% */ 874*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0002); 875*7979b1cfSJérôme Duval /* Set Multi Channel to default */ 876*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0000); 877*7979b1cfSJérôme Duval /* Enable register 0x78 */ 878*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x76, 0xabba); 879*7979b1cfSJérôme Duval /* Set Clock Access to default */ 880*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x78, 0x0000); 881*7979b1cfSJérôme Duval } 882*7979b1cfSJérôme Duval 883*7979b1cfSJérôme Duval void stac9744_init(ac97_dev *dev) 884*7979b1cfSJérôme Duval { 885*7979b1cfSJérôme Duval LOG(("stac9744_init\n")); 886*7979b1cfSJérôme Duval /* Set Analog Special to default (DAC/ADC -6dB disabled) */ 887*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x6E, 0x0000); 888*7979b1cfSJérôme Duval /* Enable register 0x72 */ 889*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x70, 0xabba); 890*7979b1cfSJérôme Duval /* Set Analog Current to -50% */ 891*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0002); 892*7979b1cfSJérôme Duval /* Set Multi Channel to default */ 893*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0000); 894*7979b1cfSJérôme Duval /* Enable register 0x78 */ 895*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x76, 0xabba); 896*7979b1cfSJérôme Duval /* Set Clock Access to default */ 897*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x78, 0x0000); 898*7979b1cfSJérôme Duval } 899*7979b1cfSJérôme Duval 900*7979b1cfSJérôme Duval void stac9756_init(ac97_dev *dev) 901*7979b1cfSJérôme Duval { 902*7979b1cfSJérôme Duval LOG(("stac9756_init\n")); 903*7979b1cfSJérôme Duval /* Set Analog Special to default (AC97 all-mix, DAC/ADC -6dB disabled) */ 904*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x6E, 0x1000); 905*7979b1cfSJérôme Duval /* Enable register 0x72 */ 906*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x70, 0xabba); 907*7979b1cfSJérôme Duval /* Set Analog Current to -50% */ 908*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0002); 909*7979b1cfSJérôme Duval /* Set Multi Channel to default */ 910*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0000); 911*7979b1cfSJérôme Duval /* Enable register 0x78 */ 912*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x76, 0xabba); 913*7979b1cfSJérôme Duval /* Set Clock Access to default */ 914*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x78, 0x0000); 915*7979b1cfSJérôme Duval } 916*7979b1cfSJérôme Duval 917*7979b1cfSJérôme Duval void tr28028_init(ac97_dev *dev) 918*7979b1cfSJérôme Duval { 919*7979b1cfSJérôme Duval LOG(("tr28028_init\n")); 920*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_POWERDOWN, 0x0300); 921*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_POWERDOWN, 0x0000); 922*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_SURR_VOLUME, 0x0000); 923*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_SPDIF_CONTROL, 0x0000); 924*7979b1cfSJérôme Duval } 925*7979b1cfSJérôme Duval 926*7979b1cfSJérôme Duval void wm9701_init(ac97_dev *dev) 927*7979b1cfSJérôme Duval { 928*7979b1cfSJérôme Duval LOG(("wm9701_init\n")); 929*7979b1cfSJérôme Duval /* ALSA writes some of these registers, but the codec 930*7979b1cfSJérôme Duval * documentation states explicitly that 0x38 and 0x70 to 0x74 931*7979b1cfSJérôme Duval * are not used in the WM9701A 932*7979b1cfSJérôme Duval */ 933*7979b1cfSJérôme Duval 934*7979b1cfSJérôme Duval /* DVD noise patch (?) */ 935*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x5a, 0x0200); 936*7979b1cfSJérôme Duval } 937*7979b1cfSJérôme Duval 938*7979b1cfSJérôme Duval void wm9703_init(ac97_dev *dev) 939*7979b1cfSJérôme Duval { 940*7979b1cfSJérôme Duval LOG(("wm9703_init\n")); 941*7979b1cfSJérôme Duval /* Set front mixer value to unmuted */ 942*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0808); 943*7979b1cfSJérôme Duval /* Disable loopback, etc */ 944*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, AC97_GENERAL_PURPOSE, 0x8000); 945*7979b1cfSJérôme Duval } 946*7979b1cfSJérôme Duval 947*7979b1cfSJérôme Duval void wm9704_init(ac97_dev *dev) 948*7979b1cfSJérôme Duval { 949*7979b1cfSJérôme Duval LOG(("wm9704_init\n")); 950*7979b1cfSJérôme Duval /* Set read DAC value to unmuted */ 951*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x70, 0x0808); 952*7979b1cfSJérôme Duval /* Set front mixer value to unmuted */ 953*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x72, 0x0808); 954*7979b1cfSJérôme Duval /* Set rear mixer value to unmuted */ 955*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x74, 0x0808); 956*7979b1cfSJérôme Duval /* DVD noise patch (?) */ 957*7979b1cfSJérôme Duval ac97_reg_cached_write(dev, 0x5a, 0x0200); 958*7979b1cfSJérôme Duval } 959*7979b1cfSJérôme Duval 960*7979b1cfSJérôme Duval const ac97_source_info source_info[] = { 961*7979b1cfSJé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 }, 962*7979b1cfSJé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 }, 963*7979b1cfSJé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 }, 964*7979b1cfSJé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 }, 965*7979b1cfSJé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 }, 966*7979b1cfSJé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 }, 967*7979b1cfSJé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 }, 968*7979b1cfSJé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 }, 969*7979b1cfSJé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 }, 970*7979b1cfSJé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 }, 971*7979b1cfSJé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 }, 972*7979b1cfSJé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 } 973*7979b1cfSJérôme Duval }; 974*7979b1cfSJérôme Duval 975*7979b1cfSJérôme Duval const int32 source_info_size = (sizeof(source_info)/sizeof(source_info[0])); 976