1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * CMI (C-Media) codec extensions. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/ddi.h> 32 #include <sys/sunddi.h> 33 #include <sys/audio/audio_driver.h> 34 #include <sys/audio/ac97.h> 35 #include <sys/note.h> 36 #include "ac97_impl.h" 37 38 /* 39 * C-Media 9739 part is weird. Instead of having independent volume 40 * controls for each of the channels, it uses a single master volume 41 * and just provides mute support for the other bits. It does this 42 * for PCM volume as well, so we can't use it either. Ugh. It also 43 * has an optional 30 dB mic boost. Apparently the 9761 behaves in 44 * much the same fashion as the 9739. 45 * 46 * C-Media 9738 is a more or less typical 4CH device according to the 47 * datasheet. It however supports jack retasking allowing the line in 48 * jack to function as a surround output. Google suggests that the 49 * volume controls on this part are about as busted as on the other 50 * parts. So, we just use synthetic volume for it. 51 * 52 * C-Media 9780 is largely a mystery (ENODATASHEET). 53 */ 54 55 56 #define CMI_TASK_REGISTER 0x5A /* 9738 jack retasking */ 57 #define CTR_F2R 0x2000 /* front routed to rear */ 58 #define CTR_S2LNI 0x0400 /* surround to line in */ 59 60 #define CMI_MULTICH_REGISTER 0x64 /* 9739 and 9761a */ 61 #define CMR_PCBSW 0x8000 /* PC Beep volume bypass */ 62 #define CMR_P47 0x4000 /* configure P47 function */ 63 #define CMR_REFCTL 0x2000 /* enable vref output */ 64 #define CMR_CLCTL 0x1000 /* center/lfe output enable */ 65 #define CMR_S2LNI 0x0400 /* surround to line in */ 66 #define CMR_MIX2S 0x0200 /* analog input pass to surround */ 67 #define CMR_BSTSEL 0x0001 /* micboost use 30dB */ 68 69 static void 70 cmi_set_micboost(ac97_ctrl_t *actrl, uint64_t value) 71 { 72 ac97_t *ac = actrl->actrl_ac97; 73 74 ac_wr(ac, AC97_INTERRUPT_PAGING_REGISTER, 0); /* select page 0 */ 75 switch (value) { 76 case 0x1: 77 /* 0db */ 78 ac_clr(ac, AC97_MIC_VOLUME_REGISTER, MICVR_20dB_BOOST); 79 ac_clr(ac, CMI_MULTICH_REGISTER, CMR_BSTSEL); 80 break; 81 case 0x2: 82 /* 20dB */ 83 ac_set(ac, AC97_MIC_VOLUME_REGISTER, MICVR_20dB_BOOST); 84 ac_clr(ac, CMI_MULTICH_REGISTER, CMR_BSTSEL); 85 break; 86 case 0x4: 87 /* 30dB */ 88 ac_set(ac, AC97_MIC_VOLUME_REGISTER, MICVR_20dB_BOOST); 89 ac_set(ac, CMI_MULTICH_REGISTER, CMR_BSTSEL); 90 break; 91 } 92 } 93 94 static void 95 cmi_set_linein_func(ac97_ctrl_t *actrl, uint64_t value) 96 { 97 ac97_t *ac = actrl->actrl_ac97; 98 99 ac_wr(ac, AC97_INTERRUPT_PAGING_REGISTER, 0); /* select page 0 */ 100 if (value & 2) { 101 ac_set(ac, CMI_MULTICH_REGISTER, CMR_S2LNI); 102 } else { 103 ac_clr(ac, CMI_MULTICH_REGISTER, CMR_S2LNI); 104 } 105 } 106 107 static void 108 cmi_set_mic_func(ac97_ctrl_t *actrl, uint64_t value) 109 { 110 ac97_t *ac = actrl->actrl_ac97; 111 112 ac_wr(ac, AC97_INTERRUPT_PAGING_REGISTER, 0); /* select page 0 */ 113 if (value & 2) { 114 ac_set(ac, CMI_MULTICH_REGISTER, CMR_CLCTL); 115 } else { 116 ac_clr(ac, CMI_MULTICH_REGISTER, CMR_CLCTL); 117 } 118 } 119 120 static void 121 cmi_setup_micboost(ac97_t *ac) 122 { 123 ac97_ctrl_t *ctrl; 124 125 static const char *values[] = { 126 AUDIO_VALUE_OFF, /* 0dB */ 127 AUDIO_VALUE_MEDIUM, /* 20dB */ 128 AUDIO_VALUE_HIGH, /* 30dB */ 129 NULL 130 }; 131 ac97_ctrl_probe_t cpt = { 132 AUDIO_CTRL_ID_MICBOOST, 1, 0xf, 0xf, AUDIO_CTRL_TYPE_ENUM, 133 AC97_FLAGS | AUDIO_CTRL_FLAG_REC, 0, cmi_set_micboost, 134 NULL, 0, values }; 135 136 ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_MICBOOST); 137 if (ctrl) { 138 if (ctrl->actrl_initval) { 139 /* 20dB by default */ 140 cpt.cp_initval = 1; 141 } 142 } 143 144 ac_add_control(ac, &cpt); 145 } 146 147 static const char *cmi_linein_funcs[] = { 148 AUDIO_PORT_LINEIN, 149 AUDIO_PORT_SURROUND, 150 NULL 151 }; 152 153 static const char *cmi_mic_funcs[] = { 154 AUDIO_PORT_MIC, 155 AUDIO_PORT_CENLFE, 156 NULL 157 }; 158 159 static void 160 cmi_setup_jack_funcs(ac97_t *ac) 161 { 162 ac97_ctrl_probe_t cp; 163 int ival; 164 165 ac97_ctrl_probe_t linein_cpt = { 166 AUDIO_CTRL_ID_JACK1, 1, 3, 3, AUDIO_CTRL_TYPE_ENUM, AC97_FLAGS, 167 0, cmi_set_linein_func, NULL, 0, cmi_linein_funcs 168 }; 169 ac97_ctrl_probe_t mic_cpt = { 170 AUDIO_CTRL_ID_JACK2, 1, 3, 3, AUDIO_CTRL_TYPE_ENUM, AC97_FLAGS, 171 0, cmi_set_mic_func, NULL, 0, cmi_mic_funcs 172 }; 173 174 bcopy(&linein_cpt, &cp, sizeof (cp)); 175 ival = ac_get_prop(ac, AC97_PROP_LINEIN_FUNC, 0); 176 if ((ival >= 1) && (ival <= 2)) { 177 cp.cp_initval = ival; 178 } 179 ac_add_control(ac, &cp); 180 181 bcopy(&mic_cpt, &cp, sizeof (cp)); 182 ival = ac_get_prop(ac, AC97_PROP_MIC_FUNC, 0); 183 if ((ival >= 1) && (ival <= 2)) { 184 cp.cp_initval = ival; 185 } 186 ac_add_control(ac, &cp); 187 } 188 189 static void 190 cmi_set_linein_func_9738(ac97_ctrl_t *actrl, uint64_t value) 191 { 192 ac97_t *ac = actrl->actrl_ac97; 193 194 if (value & 2) { 195 ac_set(ac, CMI_TASK_REGISTER, CTR_S2LNI); 196 } else { 197 ac_clr(ac, CMI_TASK_REGISTER, CTR_S2LNI); 198 } 199 } 200 201 static void 202 cmi_set_spread_9738(ac97_ctrl_t *actrl, uint64_t value) 203 { 204 ac97_t *ac = actrl->actrl_ac97; 205 206 if (value) { 207 ac_set(ac, CMI_TASK_REGISTER, CTR_F2R); 208 } else { 209 ac_clr(ac, CMI_TASK_REGISTER, CTR_F2R); 210 } 211 } 212 213 static void 214 cmi_setup_jack_func_9738(ac97_t *ac) 215 { 216 ac97_ctrl_probe_t cp; 217 int ival; 218 219 ac97_ctrl_probe_t linein_cpt = { 220 AUDIO_CTRL_ID_JACK1, 1, 3, 3, AUDIO_CTRL_TYPE_ENUM, AC97_FLAGS, 221 0, cmi_set_linein_func_9738, NULL, 0, cmi_linein_funcs 222 }; 223 ac97_ctrl_probe_t spread_cpt = { 224 AUDIO_CTRL_ID_SPREAD, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN, 225 AC97_FLAGS, 0, cmi_set_spread_9738, 226 }; 227 228 bcopy(&linein_cpt, &cp, sizeof (cp)); 229 ival = ac_get_prop(ac, AC97_PROP_LINEIN_FUNC, 0); 230 if ((ival >= 1) && (ival <= 2)) { 231 cp.cp_initval = ival; 232 } 233 ac_add_control(ac, &cp); 234 235 bcopy(&spread_cpt, &cp, sizeof (cp)); 236 ival = ac_get_prop(ac, AC97_PROP_SPREAD, -1); 237 if ((ival >= 0) && (ival <= 1)) { 238 cp.cp_initval = ival; 239 } 240 ac_add_control(ac, &cp); 241 } 242 243 244 static void 245 cmi_setup_volume(ac97_t *ac) 246 { 247 ac97_ctrl_t *ctrl; 248 249 /* 250 * These CMI parts seem to be really weird. They don't have 251 * *any* functioning volume controls on them (mute only) apart 252 * from the record and monitor sources (excluding PCM). I 253 * don't understand why not. We just eliminate all of the 254 * volume controls and replace with a soft volume control. 255 * Its not an ideal situation, but I don't know what else I 256 * can do about it. 257 */ 258 ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_VOLUME); 259 if (ctrl) { 260 ac97_control_remove(ctrl); 261 } 262 ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_FRONT); 263 if (ctrl) { 264 ac97_control_remove(ctrl); 265 } 266 ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_SURROUND); 267 if (ctrl) { 268 ac97_control_remove(ctrl); 269 } 270 ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_CENTER); 271 if (ctrl) { 272 ac97_control_remove(ctrl); 273 } 274 ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_LFE); 275 if (ctrl) { 276 ac97_control_remove(ctrl); 277 } 278 279 /* make sure we have disabled mute and attenuation on physical ctrls */ 280 ac_wr(ac, AC97_INTERRUPT_PAGING_REGISTER, 0); /* select page 0 */ 281 ac_wr(ac, AC97_PCM_OUT_VOLUME_REGISTER, 0); 282 ac_wr(ac, AC97_MASTER_VOLUME_REGISTER, 0); 283 ac_wr(ac, AC97_EXTENDED_C_LFE_VOLUME_REGISTER, 0); 284 ac_wr(ac, AC97_EXTENDED_LRS_VOLUME_REGISTER, 0); 285 286 /* 287 * NB: This is probably not the best way to do this, because 288 * it will make overriding this hard for drivers that desire 289 * to. Fortunately, we don't think any drivers that want to 290 * override or fine tune AC'97 controls (i.e. creative cards) 291 * use these C-Media codecs. 292 */ 293 (void) audio_dev_add_soft_volume(ac_get_dev(ac)); 294 } 295 296 void 297 cmi9739_init(ac97_t *ac) 298 { 299 cmi_setup_volume(ac); 300 cmi_setup_micboost(ac); 301 cmi_setup_jack_funcs(ac); 302 } 303 304 void 305 cmi9761_init(ac97_t *ac) 306 { 307 cmi_setup_volume(ac); 308 cmi_setup_micboost(ac); 309 cmi_setup_jack_funcs(ac); 310 } 311 312 void 313 cmi9738_init(ac97_t *ac) 314 { 315 cmi_setup_volume(ac); 316 cmi_setup_jack_func_9738(ac); 317 } 318