1 /* 2 * stac9766.c -- ALSA SoC STAC9766 codec support 3 * 4 * Copyright 2009 Jon Smirl, Digispeaker 5 * Author: Jon Smirl <jonsmirl@gmail.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or (at your 10 * option) any later version. 11 * 12 * Features:- 13 * 14 * o Support for AC97 Codec, S/PDIF 15 */ 16 17 #include <linux/init.h> 18 #include <linux/slab.h> 19 #include <linux/module.h> 20 #include <linux/device.h> 21 #include <linux/regmap.h> 22 #include <sound/core.h> 23 #include <sound/pcm.h> 24 #include <sound/ac97_codec.h> 25 #include <sound/initval.h> 26 #include <sound/pcm_params.h> 27 #include <sound/soc.h> 28 #include <sound/tlv.h> 29 30 #define STAC9766_VENDOR_ID 0x83847666 31 #define STAC9766_VENDOR_ID_MASK 0xffffffff 32 33 #define AC97_STAC_DA_CONTROL 0x6A 34 #define AC97_STAC_ANALOG_SPECIAL 0x6E 35 #define AC97_STAC_STEREO_MIC 0x78 36 37 static const struct reg_default stac9766_reg_defaults[] = { 38 { 0x02, 0x8000 }, 39 { 0x04, 0x8000 }, 40 { 0x06, 0x8000 }, 41 { 0x0a, 0x0000 }, 42 { 0x0c, 0x8008 }, 43 { 0x0e, 0x8008 }, 44 { 0x10, 0x8808 }, 45 { 0x12, 0x8808 }, 46 { 0x14, 0x8808 }, 47 { 0x16, 0x8808 }, 48 { 0x18, 0x8808 }, 49 { 0x1a, 0x0000 }, 50 { 0x1c, 0x8000 }, 51 { 0x20, 0x0000 }, 52 { 0x22, 0x0000 }, 53 { 0x28, 0x0a05 }, 54 { 0x2c, 0xbb80 }, 55 { 0x32, 0xbb80 }, 56 { 0x3a, 0x2000 }, 57 { 0x3e, 0x0100 }, 58 { 0x4c, 0x0300 }, 59 { 0x4e, 0xffff }, 60 { 0x50, 0x0000 }, 61 { 0x52, 0x0000 }, 62 { 0x54, 0x0000 }, 63 { 0x6a, 0x0000 }, 64 { 0x6e, 0x1000 }, 65 { 0x72, 0x0000 }, 66 { 0x78, 0x0000 }, 67 }; 68 69 static const struct regmap_config stac9766_regmap_config = { 70 .reg_bits = 16, 71 .reg_stride = 2, 72 .val_bits = 16, 73 .max_register = 0x78, 74 .cache_type = REGCACHE_RBTREE, 75 76 .volatile_reg = regmap_ac97_default_volatile, 77 78 .reg_defaults = stac9766_reg_defaults, 79 .num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults), 80 }; 81 82 static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", 83 "Line", "Stereo Mix", "Mono Mix", "Phone"}; 84 static const char *stac9766_mono_mux[] = {"Mix", "Mic"}; 85 static const char *stac9766_mic_mux[] = {"Mic1", "Mic2"}; 86 static const char *stac9766_SPDIF_mux[] = {"PCM", "ADC Record"}; 87 static const char *stac9766_popbypass_mux[] = {"Normal", "Bypass Mixer"}; 88 static const char *stac9766_record_all_mux[] = {"All analog", 89 "Analog plus DAC"}; 90 static const char *stac9766_boost1[] = {"0dB", "10dB"}; 91 static const char *stac9766_boost2[] = {"0dB", "20dB"}; 92 static const char *stac9766_stereo_mic[] = {"Off", "On"}; 93 94 static SOC_ENUM_DOUBLE_DECL(stac9766_record_enum, 95 AC97_REC_SEL, 8, 0, stac9766_record_mux); 96 static SOC_ENUM_SINGLE_DECL(stac9766_mono_enum, 97 AC97_GENERAL_PURPOSE, 9, stac9766_mono_mux); 98 static SOC_ENUM_SINGLE_DECL(stac9766_mic_enum, 99 AC97_GENERAL_PURPOSE, 8, stac9766_mic_mux); 100 static SOC_ENUM_SINGLE_DECL(stac9766_SPDIF_enum, 101 AC97_STAC_DA_CONTROL, 1, stac9766_SPDIF_mux); 102 static SOC_ENUM_SINGLE_DECL(stac9766_popbypass_enum, 103 AC97_GENERAL_PURPOSE, 15, stac9766_popbypass_mux); 104 static SOC_ENUM_SINGLE_DECL(stac9766_record_all_enum, 105 AC97_STAC_ANALOG_SPECIAL, 12, 106 stac9766_record_all_mux); 107 static SOC_ENUM_SINGLE_DECL(stac9766_boost1_enum, 108 AC97_MIC, 6, stac9766_boost1); /* 0/10dB */ 109 static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum, 110 AC97_STAC_ANALOG_SPECIAL, 2, stac9766_boost2); /* 0/20dB */ 111 static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum, 112 AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic); 113 114 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(master_tlv, -4650, 150, 0); 115 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(record_tlv, 0, 150, 0); 116 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(beep_tlv, -4500, 300, 0); 117 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mix_tlv, -3450, 150, 0); 118 119 static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { 120 SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv), 121 SOC_SINGLE("Speaker Switch", AC97_MASTER, 15, 1, 1), 122 SOC_DOUBLE_TLV("Headphone Volume", AC97_HEADPHONE, 8, 0, 31, 1, 123 master_tlv), 124 SOC_SINGLE("Headphone Switch", AC97_HEADPHONE, 15, 1, 1), 125 SOC_SINGLE_TLV("Mono Out Volume", AC97_MASTER_MONO, 0, 31, 1, 126 master_tlv), 127 SOC_SINGLE("Mono Out Switch", AC97_MASTER_MONO, 15, 1, 1), 128 129 SOC_DOUBLE_TLV("Record Volume", AC97_REC_GAIN, 8, 0, 15, 0, record_tlv), 130 SOC_SINGLE("Record Switch", AC97_REC_GAIN, 15, 1, 1), 131 132 133 SOC_SINGLE_TLV("Beep Volume", AC97_PC_BEEP, 1, 15, 1, beep_tlv), 134 SOC_SINGLE("Beep Switch", AC97_PC_BEEP, 15, 1, 1), 135 SOC_SINGLE("Beep Frequency", AC97_PC_BEEP, 5, 127, 1), 136 SOC_SINGLE_TLV("Phone Volume", AC97_PHONE, 0, 31, 1, mix_tlv), 137 SOC_SINGLE("Phone Switch", AC97_PHONE, 15, 1, 1), 138 139 SOC_ENUM("Mic Boost1", stac9766_boost1_enum), 140 SOC_ENUM("Mic Boost2", stac9766_boost2_enum), 141 SOC_SINGLE_TLV("Mic Volume", AC97_MIC, 0, 31, 1, mix_tlv), 142 SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1), 143 SOC_ENUM("Stereo Mic", stac9766_stereo_mic_enum), 144 145 SOC_DOUBLE_TLV("Line Volume", AC97_LINE, 8, 0, 31, 1, mix_tlv), 146 SOC_SINGLE("Line Switch", AC97_LINE, 15, 1, 1), 147 SOC_DOUBLE_TLV("CD Volume", AC97_CD, 8, 0, 31, 1, mix_tlv), 148 SOC_SINGLE("CD Switch", AC97_CD, 15, 1, 1), 149 SOC_DOUBLE_TLV("AUX Volume", AC97_AUX, 8, 0, 31, 1, mix_tlv), 150 SOC_SINGLE("AUX Switch", AC97_AUX, 15, 1, 1), 151 SOC_DOUBLE_TLV("Video Volume", AC97_VIDEO, 8, 0, 31, 1, mix_tlv), 152 SOC_SINGLE("Video Switch", AC97_VIDEO, 15, 1, 1), 153 154 SOC_DOUBLE_TLV("DAC Volume", AC97_PCM, 8, 0, 31, 1, mix_tlv), 155 SOC_SINGLE("DAC Switch", AC97_PCM, 15, 1, 1), 156 SOC_SINGLE("Loopback Test Switch", AC97_GENERAL_PURPOSE, 7, 1, 0), 157 SOC_SINGLE("3D Volume", AC97_3D_CONTROL, 3, 2, 1), 158 SOC_SINGLE("3D Switch", AC97_GENERAL_PURPOSE, 13, 1, 0), 159 160 SOC_ENUM("SPDIF Mux", stac9766_SPDIF_enum), 161 SOC_ENUM("Mic1/2 Mux", stac9766_mic_enum), 162 SOC_ENUM("Record All Mux", stac9766_record_all_enum), 163 SOC_ENUM("Record Mux", stac9766_record_enum), 164 SOC_ENUM("Mono Mux", stac9766_mono_enum), 165 SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum), 166 }; 167 168 static int ac97_analog_prepare(struct snd_pcm_substream *substream, 169 struct snd_soc_dai *dai) 170 { 171 struct snd_soc_codec *codec = dai->codec; 172 struct snd_pcm_runtime *runtime = substream->runtime; 173 unsigned short reg; 174 175 /* enable variable rate audio, disable SPDIF output */ 176 snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x1); 177 178 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 179 reg = AC97_PCM_FRONT_DAC_RATE; 180 else 181 reg = AC97_PCM_LR_ADC_RATE; 182 183 return snd_soc_write(codec, reg, runtime->rate); 184 } 185 186 static int ac97_digital_prepare(struct snd_pcm_substream *substream, 187 struct snd_soc_dai *dai) 188 { 189 struct snd_soc_codec *codec = dai->codec; 190 struct snd_pcm_runtime *runtime = substream->runtime; 191 unsigned short reg; 192 193 snd_soc_write(codec, AC97_SPDIF, 0x2002); 194 195 /* Enable VRA and SPDIF out */ 196 snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x5); 197 198 reg = AC97_PCM_FRONT_DAC_RATE; 199 200 return snd_soc_write(codec, reg, runtime->rate); 201 } 202 203 static int stac9766_set_bias_level(struct snd_soc_codec *codec, 204 enum snd_soc_bias_level level) 205 { 206 switch (level) { 207 case SND_SOC_BIAS_ON: /* full On */ 208 case SND_SOC_BIAS_PREPARE: /* partial On */ 209 case SND_SOC_BIAS_STANDBY: /* Off, with power */ 210 snd_soc_write(codec, AC97_POWERDOWN, 0x0000); 211 break; 212 case SND_SOC_BIAS_OFF: /* Off, without power */ 213 /* disable everything including AC link */ 214 snd_soc_write(codec, AC97_POWERDOWN, 0xffff); 215 break; 216 } 217 return 0; 218 } 219 220 static int stac9766_codec_resume(struct snd_soc_codec *codec) 221 { 222 struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); 223 224 return snd_ac97_reset(ac97, true, STAC9766_VENDOR_ID, 225 STAC9766_VENDOR_ID_MASK); 226 } 227 228 static const struct snd_soc_dai_ops stac9766_dai_ops_analog = { 229 .prepare = ac97_analog_prepare, 230 }; 231 232 static const struct snd_soc_dai_ops stac9766_dai_ops_digital = { 233 .prepare = ac97_digital_prepare, 234 }; 235 236 static struct snd_soc_dai_driver stac9766_dai[] = { 237 { 238 .name = "stac9766-hifi-analog", 239 240 /* stream cababilities */ 241 .playback = { 242 .stream_name = "stac9766 analog", 243 .channels_min = 1, 244 .channels_max = 2, 245 .rates = SNDRV_PCM_RATE_8000_48000, 246 .formats = SND_SOC_STD_AC97_FMTS, 247 }, 248 .capture = { 249 .stream_name = "stac9766 analog", 250 .channels_min = 1, 251 .channels_max = 2, 252 .rates = SNDRV_PCM_RATE_8000_48000, 253 .formats = SND_SOC_STD_AC97_FMTS, 254 }, 255 /* alsa ops */ 256 .ops = &stac9766_dai_ops_analog, 257 }, 258 { 259 .name = "stac9766-hifi-IEC958", 260 261 /* stream cababilities */ 262 .playback = { 263 .stream_name = "stac9766 IEC958", 264 .channels_min = 1, 265 .channels_max = 2, 266 .rates = SNDRV_PCM_RATE_32000 | \ 267 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, 268 .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE, 269 }, 270 /* alsa ops */ 271 .ops = &stac9766_dai_ops_digital, 272 } 273 }; 274 275 static int stac9766_codec_probe(struct snd_soc_codec *codec) 276 { 277 struct snd_ac97 *ac97; 278 struct regmap *regmap; 279 int ret; 280 281 ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID, 282 STAC9766_VENDOR_ID_MASK); 283 if (IS_ERR(ac97)) 284 return PTR_ERR(ac97); 285 286 regmap = regmap_init_ac97(ac97, &stac9766_regmap_config); 287 if (IS_ERR(regmap)) { 288 ret = PTR_ERR(regmap); 289 goto err_free_ac97; 290 } 291 292 snd_soc_codec_init_regmap(codec, regmap); 293 snd_soc_codec_set_drvdata(codec, ac97); 294 295 return 0; 296 err_free_ac97: 297 snd_soc_free_ac97_codec(ac97); 298 return ret; 299 } 300 301 static int stac9766_codec_remove(struct snd_soc_codec *codec) 302 { 303 struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); 304 305 snd_soc_codec_exit_regmap(codec); 306 snd_soc_free_ac97_codec(ac97); 307 return 0; 308 } 309 310 static const struct snd_soc_codec_driver soc_codec_dev_stac9766 = { 311 .component_driver = { 312 .controls = stac9766_snd_ac97_controls, 313 .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), 314 }, 315 .set_bias_level = stac9766_set_bias_level, 316 .suspend_bias_off = true, 317 .probe = stac9766_codec_probe, 318 .remove = stac9766_codec_remove, 319 .resume = stac9766_codec_resume, 320 }; 321 322 static int stac9766_probe(struct platform_device *pdev) 323 { 324 return snd_soc_register_codec(&pdev->dev, 325 &soc_codec_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai)); 326 } 327 328 static int stac9766_remove(struct platform_device *pdev) 329 { 330 snd_soc_unregister_codec(&pdev->dev); 331 return 0; 332 } 333 334 static struct platform_driver stac9766_codec_driver = { 335 .driver = { 336 .name = "stac9766-codec", 337 }, 338 339 .probe = stac9766_probe, 340 .remove = stac9766_remove, 341 }; 342 343 module_platform_driver(stac9766_codec_driver); 344 345 MODULE_DESCRIPTION("ASoC stac9766 driver"); 346 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>"); 347 MODULE_LICENSE("GPL"); 348