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