1 /* 2 * wm8940.c -- WM8940 ALSA Soc Audio driver 3 * 4 * Author: Jonathan Cameron <jic23@cam.ac.uk> 5 * 6 * Based on wm8510.c 7 * Copyright 2006 Wolfson Microelectronics PLC. 8 * Author: Liam Girdwood <lrg@slimlogic.co.uk> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 * Not currently handled: 15 * Notch filter control 16 * AUXMode (inverting vs mixer) 17 * No means to obtain current gain if alc enabled. 18 * No use made of gpio 19 * Fast VMID discharge for power down 20 * Soft Start 21 * DLR and ALR Swaps not enabled 22 * Digital Sidetone not supported 23 */ 24 #include <linux/module.h> 25 #include <linux/moduleparam.h> 26 #include <linux/kernel.h> 27 #include <linux/init.h> 28 #include <linux/delay.h> 29 #include <linux/pm.h> 30 #include <linux/i2c.h> 31 #include <linux/regmap.h> 32 #include <linux/slab.h> 33 #include <sound/core.h> 34 #include <sound/pcm.h> 35 #include <sound/pcm_params.h> 36 #include <sound/soc.h> 37 #include <sound/initval.h> 38 #include <sound/tlv.h> 39 40 #include "wm8940.h" 41 42 struct wm8940_priv { 43 unsigned int sysclk; 44 struct regmap *regmap; 45 }; 46 47 static bool wm8940_volatile_register(struct device *dev, unsigned int reg) 48 { 49 switch (reg) { 50 case WM8940_SOFTRESET: 51 return true; 52 default: 53 return false; 54 } 55 } 56 57 static bool wm8940_readable_register(struct device *dev, unsigned int reg) 58 { 59 switch (reg) { 60 case WM8940_SOFTRESET: 61 case WM8940_POWER1: 62 case WM8940_POWER2: 63 case WM8940_POWER3: 64 case WM8940_IFACE: 65 case WM8940_COMPANDINGCTL: 66 case WM8940_CLOCK: 67 case WM8940_ADDCNTRL: 68 case WM8940_GPIO: 69 case WM8940_CTLINT: 70 case WM8940_DAC: 71 case WM8940_DACVOL: 72 case WM8940_ADC: 73 case WM8940_ADCVOL: 74 case WM8940_NOTCH1: 75 case WM8940_NOTCH2: 76 case WM8940_NOTCH3: 77 case WM8940_NOTCH4: 78 case WM8940_NOTCH5: 79 case WM8940_NOTCH6: 80 case WM8940_NOTCH7: 81 case WM8940_NOTCH8: 82 case WM8940_DACLIM1: 83 case WM8940_DACLIM2: 84 case WM8940_ALC1: 85 case WM8940_ALC2: 86 case WM8940_ALC3: 87 case WM8940_NOISEGATE: 88 case WM8940_PLLN: 89 case WM8940_PLLK1: 90 case WM8940_PLLK2: 91 case WM8940_PLLK3: 92 case WM8940_ALC4: 93 case WM8940_INPUTCTL: 94 case WM8940_PGAGAIN: 95 case WM8940_ADCBOOST: 96 case WM8940_OUTPUTCTL: 97 case WM8940_SPKMIX: 98 case WM8940_SPKVOL: 99 case WM8940_MONOMIX: 100 return true; 101 default: 102 return false; 103 } 104 } 105 106 static const struct reg_default wm8940_reg_defaults[] = { 107 { 0x1, 0x0000 }, /* Power 1 */ 108 { 0x2, 0x0000 }, /* Power 2 */ 109 { 0x3, 0x0000 }, /* Power 3 */ 110 { 0x4, 0x0010 }, /* Interface Control */ 111 { 0x5, 0x0000 }, /* Companding Control */ 112 { 0x6, 0x0140 }, /* Clock Control */ 113 { 0x7, 0x0000 }, /* Additional Controls */ 114 { 0x8, 0x0000 }, /* GPIO Control */ 115 { 0x9, 0x0002 }, /* Auto Increment Control */ 116 { 0xa, 0x0000 }, /* DAC Control */ 117 { 0xb, 0x00FF }, /* DAC Volume */ 118 119 { 0xe, 0x0100 }, /* ADC Control */ 120 { 0xf, 0x00FF }, /* ADC Volume */ 121 { 0x10, 0x0000 }, /* Notch Filter 1 Control 1 */ 122 { 0x11, 0x0000 }, /* Notch Filter 1 Control 2 */ 123 { 0x12, 0x0000 }, /* Notch Filter 2 Control 1 */ 124 { 0x13, 0x0000 }, /* Notch Filter 2 Control 2 */ 125 { 0x14, 0x0000 }, /* Notch Filter 3 Control 1 */ 126 { 0x15, 0x0000 }, /* Notch Filter 3 Control 2 */ 127 { 0x16, 0x0000 }, /* Notch Filter 4 Control 1 */ 128 { 0x17, 0x0000 }, /* Notch Filter 4 Control 2 */ 129 { 0x18, 0x0032 }, /* DAC Limit Control 1 */ 130 { 0x19, 0x0000 }, /* DAC Limit Control 2 */ 131 132 { 0x20, 0x0038 }, /* ALC Control 1 */ 133 { 0x21, 0x000B }, /* ALC Control 2 */ 134 { 0x22, 0x0032 }, /* ALC Control 3 */ 135 { 0x23, 0x0000 }, /* Noise Gate */ 136 { 0x24, 0x0041 }, /* PLLN */ 137 { 0x25, 0x000C }, /* PLLK1 */ 138 { 0x26, 0x0093 }, /* PLLK2 */ 139 { 0x27, 0x00E9 }, /* PLLK3 */ 140 141 { 0x2a, 0x0030 }, /* ALC Control 4 */ 142 143 { 0x2c, 0x0002 }, /* Input Control */ 144 { 0x2d, 0x0050 }, /* PGA Gain */ 145 146 { 0x2f, 0x0002 }, /* ADC Boost Control */ 147 148 { 0x31, 0x0002 }, /* Output Control */ 149 { 0x32, 0x0000 }, /* Speaker Mixer Control */ 150 151 { 0x36, 0x0079 }, /* Speaker Volume */ 152 153 { 0x38, 0x0000 }, /* Mono Mixer Control */ 154 }; 155 156 static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; 157 static SOC_ENUM_SINGLE_DECL(wm8940_adc_companding_enum, 158 WM8940_COMPANDINGCTL, 1, wm8940_companding); 159 static SOC_ENUM_SINGLE_DECL(wm8940_dac_companding_enum, 160 WM8940_COMPANDINGCTL, 3, wm8940_companding); 161 162 static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"}; 163 static SOC_ENUM_SINGLE_DECL(wm8940_alc_mode_enum, 164 WM8940_ALC3, 8, wm8940_alc_mode_text); 165 166 static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"}; 167 static SOC_ENUM_SINGLE_DECL(wm8940_mic_bias_level_enum, 168 WM8940_INPUTCTL, 8, wm8940_mic_bias_level_text); 169 170 static const char *wm8940_filter_mode_text[] = {"Audio", "Application"}; 171 static SOC_ENUM_SINGLE_DECL(wm8940_filter_mode_enum, 172 WM8940_ADC, 7, wm8940_filter_mode_text); 173 174 static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1); 175 static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0); 176 static DECLARE_TLV_DB_SCALE(wm8940_pga_vol_tlv, -1200, 75, 0); 177 static DECLARE_TLV_DB_SCALE(wm8940_alc_min_tlv, -1200, 600, 0); 178 static DECLARE_TLV_DB_SCALE(wm8940_alc_max_tlv, 675, 600, 0); 179 static DECLARE_TLV_DB_SCALE(wm8940_alc_tar_tlv, -2250, 50, 0); 180 static DECLARE_TLV_DB_SCALE(wm8940_lim_boost_tlv, 0, 100, 0); 181 static DECLARE_TLV_DB_SCALE(wm8940_lim_thresh_tlv, -600, 100, 0); 182 static DECLARE_TLV_DB_SCALE(wm8940_adc_tlv, -12750, 50, 1); 183 static DECLARE_TLV_DB_SCALE(wm8940_capture_boost_vol_tlv, 0, 2000, 0); 184 185 static const struct snd_kcontrol_new wm8940_snd_controls[] = { 186 SOC_SINGLE("Digital Loopback Switch", WM8940_COMPANDINGCTL, 187 6, 1, 0), 188 SOC_ENUM("DAC Companding", wm8940_dac_companding_enum), 189 SOC_ENUM("ADC Companding", wm8940_adc_companding_enum), 190 191 SOC_ENUM("ALC Mode", wm8940_alc_mode_enum), 192 SOC_SINGLE("ALC Switch", WM8940_ALC1, 8, 1, 0), 193 SOC_SINGLE_TLV("ALC Capture Max Gain", WM8940_ALC1, 194 3, 7, 1, wm8940_alc_max_tlv), 195 SOC_SINGLE_TLV("ALC Capture Min Gain", WM8940_ALC1, 196 0, 7, 0, wm8940_alc_min_tlv), 197 SOC_SINGLE_TLV("ALC Capture Target", WM8940_ALC2, 198 0, 14, 0, wm8940_alc_tar_tlv), 199 SOC_SINGLE("ALC Capture Hold", WM8940_ALC2, 4, 10, 0), 200 SOC_SINGLE("ALC Capture Decay", WM8940_ALC3, 4, 10, 0), 201 SOC_SINGLE("ALC Capture Attach", WM8940_ALC3, 0, 10, 0), 202 SOC_SINGLE("ALC ZC Switch", WM8940_ALC4, 1, 1, 0), 203 SOC_SINGLE("ALC Capture Noise Gate Switch", WM8940_NOISEGATE, 204 3, 1, 0), 205 SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8940_NOISEGATE, 206 0, 7, 0), 207 208 SOC_SINGLE("DAC Playback Limiter Switch", WM8940_DACLIM1, 8, 1, 0), 209 SOC_SINGLE("DAC Playback Limiter Attack", WM8940_DACLIM1, 0, 9, 0), 210 SOC_SINGLE("DAC Playback Limiter Decay", WM8940_DACLIM1, 4, 11, 0), 211 SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8940_DACLIM2, 212 4, 9, 1, wm8940_lim_thresh_tlv), 213 SOC_SINGLE_TLV("DAC Playback Limiter Boost", WM8940_DACLIM2, 214 0, 12, 0, wm8940_lim_boost_tlv), 215 216 SOC_SINGLE("Capture PGA ZC Switch", WM8940_PGAGAIN, 7, 1, 0), 217 SOC_SINGLE_TLV("Capture PGA Volume", WM8940_PGAGAIN, 218 0, 63, 0, wm8940_pga_vol_tlv), 219 SOC_SINGLE_TLV("Digital Playback Volume", WM8940_DACVOL, 220 0, 255, 0, wm8940_adc_tlv), 221 SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL, 222 0, 255, 0, wm8940_adc_tlv), 223 SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum), 224 SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST, 225 8, 1, 0, wm8940_capture_boost_vol_tlv), 226 SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL, 227 0, 63, 0, wm8940_spk_vol_tlv), 228 SOC_SINGLE("Speaker Playback Switch", WM8940_SPKVOL, 6, 1, 1), 229 230 SOC_SINGLE_TLV("Speaker Mixer Line Bypass Volume", WM8940_SPKVOL, 231 8, 1, 1, wm8940_att_tlv), 232 SOC_SINGLE("Speaker Playback ZC Switch", WM8940_SPKVOL, 7, 1, 0), 233 234 SOC_SINGLE("Mono Out Switch", WM8940_MONOMIX, 6, 1, 1), 235 SOC_SINGLE_TLV("Mono Mixer Line Bypass Volume", WM8940_MONOMIX, 236 7, 1, 1, wm8940_att_tlv), 237 238 SOC_SINGLE("High Pass Filter Switch", WM8940_ADC, 8, 1, 0), 239 SOC_ENUM("High Pass Filter Mode", wm8940_filter_mode_enum), 240 SOC_SINGLE("High Pass Filter Cut Off", WM8940_ADC, 4, 7, 0), 241 SOC_SINGLE("ADC Inversion Switch", WM8940_ADC, 0, 1, 0), 242 SOC_SINGLE("DAC Inversion Switch", WM8940_DAC, 0, 1, 0), 243 SOC_SINGLE("DAC Auto Mute Switch", WM8940_DAC, 2, 1, 0), 244 SOC_SINGLE("ZC Timeout Clock Switch", WM8940_ADDCNTRL, 0, 1, 0), 245 }; 246 247 static const struct snd_kcontrol_new wm8940_speaker_mixer_controls[] = { 248 SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_SPKMIX, 1, 1, 0), 249 SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_SPKMIX, 5, 1, 0), 250 SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_SPKMIX, 0, 1, 0), 251 }; 252 253 static const struct snd_kcontrol_new wm8940_mono_mixer_controls[] = { 254 SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_MONOMIX, 1, 1, 0), 255 SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_MONOMIX, 2, 1, 0), 256 SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_MONOMIX, 0, 1, 0), 257 }; 258 259 static DECLARE_TLV_DB_SCALE(wm8940_boost_vol_tlv, -1500, 300, 1); 260 static const struct snd_kcontrol_new wm8940_input_boost_controls[] = { 261 SOC_DAPM_SINGLE("Mic PGA Switch", WM8940_PGAGAIN, 6, 1, 1), 262 SOC_DAPM_SINGLE_TLV("Aux Volume", WM8940_ADCBOOST, 263 0, 7, 0, wm8940_boost_vol_tlv), 264 SOC_DAPM_SINGLE_TLV("Mic Volume", WM8940_ADCBOOST, 265 4, 7, 0, wm8940_boost_vol_tlv), 266 }; 267 268 static const struct snd_kcontrol_new wm8940_micpga_controls[] = { 269 SOC_DAPM_SINGLE("AUX Switch", WM8940_INPUTCTL, 2, 1, 0), 270 SOC_DAPM_SINGLE("MICP Switch", WM8940_INPUTCTL, 0, 1, 0), 271 SOC_DAPM_SINGLE("MICN Switch", WM8940_INPUTCTL, 1, 1, 0), 272 }; 273 274 static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = { 275 SND_SOC_DAPM_MIXER("Speaker Mixer", WM8940_POWER3, 2, 0, 276 &wm8940_speaker_mixer_controls[0], 277 ARRAY_SIZE(wm8940_speaker_mixer_controls)), 278 SND_SOC_DAPM_MIXER("Mono Mixer", WM8940_POWER3, 3, 0, 279 &wm8940_mono_mixer_controls[0], 280 ARRAY_SIZE(wm8940_mono_mixer_controls)), 281 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8940_POWER3, 0, 0), 282 283 SND_SOC_DAPM_PGA("SpkN Out", WM8940_POWER3, 5, 0, NULL, 0), 284 SND_SOC_DAPM_PGA("SpkP Out", WM8940_POWER3, 6, 0, NULL, 0), 285 SND_SOC_DAPM_PGA("Mono Out", WM8940_POWER3, 7, 0, NULL, 0), 286 SND_SOC_DAPM_OUTPUT("MONOOUT"), 287 SND_SOC_DAPM_OUTPUT("SPKOUTP"), 288 SND_SOC_DAPM_OUTPUT("SPKOUTN"), 289 290 SND_SOC_DAPM_PGA("Aux Input", WM8940_POWER1, 6, 0, NULL, 0), 291 SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8940_POWER2, 0, 0), 292 SND_SOC_DAPM_MIXER("Mic PGA", WM8940_POWER2, 2, 0, 293 &wm8940_micpga_controls[0], 294 ARRAY_SIZE(wm8940_micpga_controls)), 295 SND_SOC_DAPM_MIXER("Boost Mixer", WM8940_POWER2, 4, 0, 296 &wm8940_input_boost_controls[0], 297 ARRAY_SIZE(wm8940_input_boost_controls)), 298 SND_SOC_DAPM_MICBIAS("Mic Bias", WM8940_POWER1, 4, 0), 299 300 SND_SOC_DAPM_INPUT("MICN"), 301 SND_SOC_DAPM_INPUT("MICP"), 302 SND_SOC_DAPM_INPUT("AUX"), 303 }; 304 305 static const struct snd_soc_dapm_route wm8940_dapm_routes[] = { 306 /* Mono output mixer */ 307 {"Mono Mixer", "PCM Playback Switch", "DAC"}, 308 {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, 309 {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, 310 311 /* Speaker output mixer */ 312 {"Speaker Mixer", "PCM Playback Switch", "DAC"}, 313 {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, 314 {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, 315 316 /* Outputs */ 317 {"Mono Out", NULL, "Mono Mixer"}, 318 {"MONOOUT", NULL, "Mono Out"}, 319 {"SpkN Out", NULL, "Speaker Mixer"}, 320 {"SpkP Out", NULL, "Speaker Mixer"}, 321 {"SPKOUTN", NULL, "SpkN Out"}, 322 {"SPKOUTP", NULL, "SpkP Out"}, 323 324 /* Microphone PGA */ 325 {"Mic PGA", "MICN Switch", "MICN"}, 326 {"Mic PGA", "MICP Switch", "MICP"}, 327 {"Mic PGA", "AUX Switch", "AUX"}, 328 329 /* Boost Mixer */ 330 {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, 331 {"Boost Mixer", "Mic Volume", "MICP"}, 332 {"Boost Mixer", "Aux Volume", "Aux Input"}, 333 334 {"ADC", NULL, "Boost Mixer"}, 335 }; 336 337 #define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0); 338 339 static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, 340 unsigned int fmt) 341 { 342 struct snd_soc_codec *codec = codec_dai->codec; 343 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFE67; 344 u16 clk = snd_soc_read(codec, WM8940_CLOCK) & 0x1fe; 345 346 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 347 case SND_SOC_DAIFMT_CBM_CFM: 348 clk |= 1; 349 break; 350 case SND_SOC_DAIFMT_CBS_CFS: 351 break; 352 default: 353 return -EINVAL; 354 } 355 snd_soc_write(codec, WM8940_CLOCK, clk); 356 357 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 358 case SND_SOC_DAIFMT_I2S: 359 iface |= (2 << 3); 360 break; 361 case SND_SOC_DAIFMT_LEFT_J: 362 iface |= (1 << 3); 363 break; 364 case SND_SOC_DAIFMT_RIGHT_J: 365 break; 366 case SND_SOC_DAIFMT_DSP_A: 367 iface |= (3 << 3); 368 break; 369 case SND_SOC_DAIFMT_DSP_B: 370 iface |= (3 << 3) | (1 << 7); 371 break; 372 } 373 374 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 375 case SND_SOC_DAIFMT_NB_NF: 376 break; 377 case SND_SOC_DAIFMT_NB_IF: 378 iface |= (1 << 7); 379 break; 380 case SND_SOC_DAIFMT_IB_NF: 381 iface |= (1 << 8); 382 break; 383 case SND_SOC_DAIFMT_IB_IF: 384 iface |= (1 << 8) | (1 << 7); 385 break; 386 } 387 388 snd_soc_write(codec, WM8940_IFACE, iface); 389 390 return 0; 391 } 392 393 static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, 394 struct snd_pcm_hw_params *params, 395 struct snd_soc_dai *dai) 396 { 397 struct snd_soc_codec *codec = dai->codec; 398 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F; 399 u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1; 400 u16 companding = snd_soc_read(codec, 401 WM8940_COMPANDINGCTL) & 0xFFDF; 402 int ret; 403 404 /* LoutR control */ 405 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE 406 && params_channels(params) == 2) 407 iface |= (1 << 9); 408 409 switch (params_rate(params)) { 410 case 8000: 411 addcntrl |= (0x5 << 1); 412 break; 413 case 11025: 414 addcntrl |= (0x4 << 1); 415 break; 416 case 16000: 417 addcntrl |= (0x3 << 1); 418 break; 419 case 22050: 420 addcntrl |= (0x2 << 1); 421 break; 422 case 32000: 423 addcntrl |= (0x1 << 1); 424 break; 425 case 44100: 426 case 48000: 427 break; 428 } 429 ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl); 430 if (ret) 431 goto error_ret; 432 433 switch (params_width(params)) { 434 case 8: 435 companding = companding | (1 << 5); 436 break; 437 case 16: 438 break; 439 case 20: 440 iface |= (1 << 5); 441 break; 442 case 24: 443 iface |= (2 << 5); 444 break; 445 case 32: 446 iface |= (3 << 5); 447 break; 448 } 449 ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding); 450 if (ret) 451 goto error_ret; 452 ret = snd_soc_write(codec, WM8940_IFACE, iface); 453 454 error_ret: 455 return ret; 456 } 457 458 static int wm8940_mute(struct snd_soc_dai *dai, int mute) 459 { 460 struct snd_soc_codec *codec = dai->codec; 461 u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf; 462 463 if (mute) 464 mute_reg |= 0x40; 465 466 return snd_soc_write(codec, WM8940_DAC, mute_reg); 467 } 468 469 static int wm8940_set_bias_level(struct snd_soc_codec *codec, 470 enum snd_soc_bias_level level) 471 { 472 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec); 473 u16 val; 474 u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0; 475 int ret = 0; 476 477 switch (level) { 478 case SND_SOC_BIAS_ON: 479 /* ensure bufioen and biasen */ 480 pwr_reg |= (1 << 2) | (1 << 3); 481 /* Enable thermal shutdown */ 482 val = snd_soc_read(codec, WM8940_OUTPUTCTL); 483 ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2); 484 if (ret) 485 break; 486 /* set vmid to 75k */ 487 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); 488 break; 489 case SND_SOC_BIAS_PREPARE: 490 /* ensure bufioen and biasen */ 491 pwr_reg |= (1 << 2) | (1 << 3); 492 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); 493 break; 494 case SND_SOC_BIAS_STANDBY: 495 if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { 496 ret = regcache_sync(wm8940->regmap); 497 if (ret < 0) { 498 dev_err(codec->dev, "Failed to sync cache: %d\n", ret); 499 return ret; 500 } 501 } 502 503 /* ensure bufioen and biasen */ 504 pwr_reg |= (1 << 2) | (1 << 3); 505 /* set vmid to 300k for standby */ 506 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2); 507 break; 508 case SND_SOC_BIAS_OFF: 509 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg); 510 break; 511 } 512 513 return ret; 514 } 515 516 struct pll_ { 517 unsigned int pre_scale:2; 518 unsigned int n:4; 519 unsigned int k; 520 }; 521 522 static struct pll_ pll_div; 523 524 /* The size in bits of the pll divide multiplied by 10 525 * to allow rounding later */ 526 #define FIXED_PLL_SIZE ((1 << 24) * 10) 527 static void pll_factors(unsigned int target, unsigned int source) 528 { 529 unsigned long long Kpart; 530 unsigned int K, Ndiv, Nmod; 531 /* The left shift ist to avoid accuracy loss when right shifting */ 532 Ndiv = target / source; 533 534 if (Ndiv > 12) { 535 source <<= 1; 536 /* Multiply by 2 */ 537 pll_div.pre_scale = 0; 538 Ndiv = target / source; 539 } else if (Ndiv < 3) { 540 source >>= 2; 541 /* Divide by 4 */ 542 pll_div.pre_scale = 3; 543 Ndiv = target / source; 544 } else if (Ndiv < 6) { 545 source >>= 1; 546 /* divide by 2 */ 547 pll_div.pre_scale = 2; 548 Ndiv = target / source; 549 } else 550 pll_div.pre_scale = 1; 551 552 if ((Ndiv < 6) || (Ndiv > 12)) 553 printk(KERN_WARNING 554 "WM8940 N value %d outwith recommended range!d\n", 555 Ndiv); 556 557 pll_div.n = Ndiv; 558 Nmod = target % source; 559 Kpart = FIXED_PLL_SIZE * (long long)Nmod; 560 561 do_div(Kpart, source); 562 563 K = Kpart & 0xFFFFFFFF; 564 565 /* Check if we need to round */ 566 if ((K % 10) >= 5) 567 K += 5; 568 569 /* Move down to proper range now rounding is done */ 570 K /= 10; 571 572 pll_div.k = K; 573 } 574 575 /* Untested at the moment */ 576 static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, 577 int source, unsigned int freq_in, unsigned int freq_out) 578 { 579 struct snd_soc_codec *codec = codec_dai->codec; 580 u16 reg; 581 582 /* Turn off PLL */ 583 reg = snd_soc_read(codec, WM8940_POWER1); 584 snd_soc_write(codec, WM8940_POWER1, reg & 0x1df); 585 586 if (freq_in == 0 || freq_out == 0) { 587 /* Clock CODEC directly from MCLK */ 588 reg = snd_soc_read(codec, WM8940_CLOCK); 589 snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff); 590 /* Pll power down */ 591 snd_soc_write(codec, WM8940_PLLN, (1 << 7)); 592 return 0; 593 } 594 595 /* Pll is followed by a frequency divide by 4 */ 596 pll_factors(freq_out*4, freq_in); 597 if (pll_div.k) 598 snd_soc_write(codec, WM8940_PLLN, 599 (pll_div.pre_scale << 4) | pll_div.n | (1 << 6)); 600 else /* No factional component */ 601 snd_soc_write(codec, WM8940_PLLN, 602 (pll_div.pre_scale << 4) | pll_div.n); 603 snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18); 604 snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); 605 snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); 606 /* Enable the PLL */ 607 reg = snd_soc_read(codec, WM8940_POWER1); 608 snd_soc_write(codec, WM8940_POWER1, reg | 0x020); 609 610 /* Run CODEC from PLL instead of MCLK */ 611 reg = snd_soc_read(codec, WM8940_CLOCK); 612 snd_soc_write(codec, WM8940_CLOCK, reg | 0x100); 613 614 return 0; 615 } 616 617 static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai, 618 int clk_id, unsigned int freq, int dir) 619 { 620 struct snd_soc_codec *codec = codec_dai->codec; 621 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec); 622 623 switch (freq) { 624 case 11289600: 625 case 12000000: 626 case 12288000: 627 case 16934400: 628 case 18432000: 629 wm8940->sysclk = freq; 630 return 0; 631 } 632 return -EINVAL; 633 } 634 635 static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, 636 int div_id, int div) 637 { 638 struct snd_soc_codec *codec = codec_dai->codec; 639 u16 reg; 640 int ret = 0; 641 642 switch (div_id) { 643 case WM8940_BCLKDIV: 644 reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFE3; 645 ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2)); 646 break; 647 case WM8940_MCLKDIV: 648 reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F; 649 ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5)); 650 break; 651 case WM8940_OPCLKDIV: 652 reg = snd_soc_read(codec, WM8940_GPIO) & 0xFFCF; 653 ret = snd_soc_write(codec, WM8940_GPIO, reg | (div << 4)); 654 break; 655 } 656 return ret; 657 } 658 659 #define WM8940_RATES SNDRV_PCM_RATE_8000_48000 660 661 #define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 662 SNDRV_PCM_FMTBIT_S16_LE | \ 663 SNDRV_PCM_FMTBIT_S20_3LE | \ 664 SNDRV_PCM_FMTBIT_S24_LE | \ 665 SNDRV_PCM_FMTBIT_S32_LE) 666 667 static const struct snd_soc_dai_ops wm8940_dai_ops = { 668 .hw_params = wm8940_i2s_hw_params, 669 .set_sysclk = wm8940_set_dai_sysclk, 670 .digital_mute = wm8940_mute, 671 .set_fmt = wm8940_set_dai_fmt, 672 .set_clkdiv = wm8940_set_dai_clkdiv, 673 .set_pll = wm8940_set_dai_pll, 674 }; 675 676 static struct snd_soc_dai_driver wm8940_dai = { 677 .name = "wm8940-hifi", 678 .playback = { 679 .stream_name = "Playback", 680 .channels_min = 1, 681 .channels_max = 2, 682 .rates = WM8940_RATES, 683 .formats = WM8940_FORMATS, 684 }, 685 .capture = { 686 .stream_name = "Capture", 687 .channels_min = 1, 688 .channels_max = 2, 689 .rates = WM8940_RATES, 690 .formats = WM8940_FORMATS, 691 }, 692 .ops = &wm8940_dai_ops, 693 .symmetric_rates = 1, 694 }; 695 696 static int wm8940_probe(struct snd_soc_codec *codec) 697 { 698 struct wm8940_setup_data *pdata = codec->dev->platform_data; 699 int ret; 700 u16 reg; 701 702 ret = wm8940_reset(codec); 703 if (ret < 0) { 704 dev_err(codec->dev, "Failed to issue reset\n"); 705 return ret; 706 } 707 708 snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); 709 710 ret = snd_soc_write(codec, WM8940_POWER1, 0x180); 711 if (ret < 0) 712 return ret; 713 714 if (!pdata) 715 dev_warn(codec->dev, "No platform data supplied\n"); 716 else { 717 reg = snd_soc_read(codec, WM8940_OUTPUTCTL); 718 ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); 719 if (ret < 0) 720 return ret; 721 } 722 723 return ret; 724 } 725 726 static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { 727 .probe = wm8940_probe, 728 .set_bias_level = wm8940_set_bias_level, 729 .suspend_bias_off = true, 730 731 .controls = wm8940_snd_controls, 732 .num_controls = ARRAY_SIZE(wm8940_snd_controls), 733 .dapm_widgets = wm8940_dapm_widgets, 734 .num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets), 735 .dapm_routes = wm8940_dapm_routes, 736 .num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes), 737 }; 738 739 static const struct regmap_config wm8940_regmap = { 740 .reg_bits = 8, 741 .val_bits = 16, 742 743 .max_register = WM8940_MONOMIX, 744 .reg_defaults = wm8940_reg_defaults, 745 .num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults), 746 747 .readable_reg = wm8940_readable_register, 748 .volatile_reg = wm8940_volatile_register, 749 }; 750 751 static int wm8940_i2c_probe(struct i2c_client *i2c, 752 const struct i2c_device_id *id) 753 { 754 struct wm8940_priv *wm8940; 755 int ret; 756 757 wm8940 = devm_kzalloc(&i2c->dev, sizeof(struct wm8940_priv), 758 GFP_KERNEL); 759 if (wm8940 == NULL) 760 return -ENOMEM; 761 762 wm8940->regmap = devm_regmap_init_i2c(i2c, &wm8940_regmap); 763 if (IS_ERR(wm8940->regmap)) 764 return PTR_ERR(wm8940->regmap); 765 766 i2c_set_clientdata(i2c, wm8940); 767 768 ret = snd_soc_register_codec(&i2c->dev, 769 &soc_codec_dev_wm8940, &wm8940_dai, 1); 770 771 return ret; 772 } 773 774 static int wm8940_i2c_remove(struct i2c_client *client) 775 { 776 snd_soc_unregister_codec(&client->dev); 777 778 return 0; 779 } 780 781 static const struct i2c_device_id wm8940_i2c_id[] = { 782 { "wm8940", 0 }, 783 { } 784 }; 785 MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id); 786 787 static struct i2c_driver wm8940_i2c_driver = { 788 .driver = { 789 .name = "wm8940", 790 }, 791 .probe = wm8940_i2c_probe, 792 .remove = wm8940_i2c_remove, 793 .id_table = wm8940_i2c_id, 794 }; 795 796 module_i2c_driver(wm8940_i2c_driver); 797 798 MODULE_DESCRIPTION("ASoC WM8940 driver"); 799 MODULE_AUTHOR("Jonathan Cameron"); 800 MODULE_LICENSE("GPL"); 801