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