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_codec *codec = dai->codec; 375 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F; 376 u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1; 377 u16 companding = snd_soc_read(codec, 378 WM8940_COMPANDINGCTL) & 0xFFDF; 379 int ret; 380 381 /* LoutR control */ 382 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE 383 && params_channels(params) == 2) 384 iface |= (1 << 9); 385 386 switch (params_rate(params)) { 387 case 8000: 388 addcntrl |= (0x5 << 1); 389 break; 390 case 11025: 391 addcntrl |= (0x4 << 1); 392 break; 393 case 16000: 394 addcntrl |= (0x3 << 1); 395 break; 396 case 22050: 397 addcntrl |= (0x2 << 1); 398 break; 399 case 32000: 400 addcntrl |= (0x1 << 1); 401 break; 402 case 44100: 403 case 48000: 404 break; 405 } 406 ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl); 407 if (ret) 408 goto error_ret; 409 410 switch (params_format(params)) { 411 case SNDRV_PCM_FORMAT_S8: 412 companding = companding | (1 << 5); 413 break; 414 case SNDRV_PCM_FORMAT_S16_LE: 415 break; 416 case SNDRV_PCM_FORMAT_S20_3LE: 417 iface |= (1 << 5); 418 break; 419 case SNDRV_PCM_FORMAT_S24_LE: 420 iface |= (2 << 5); 421 break; 422 case SNDRV_PCM_FORMAT_S32_LE: 423 iface |= (3 << 5); 424 break; 425 } 426 ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding); 427 if (ret) 428 goto error_ret; 429 ret = snd_soc_write(codec, WM8940_IFACE, iface); 430 431 error_ret: 432 return ret; 433 } 434 435 static int wm8940_mute(struct snd_soc_dai *dai, int mute) 436 { 437 struct snd_soc_codec *codec = dai->codec; 438 u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf; 439 440 if (mute) 441 mute_reg |= 0x40; 442 443 return snd_soc_write(codec, WM8940_DAC, mute_reg); 444 } 445 446 static int wm8940_set_bias_level(struct snd_soc_codec *codec, 447 enum snd_soc_bias_level level) 448 { 449 u16 val; 450 u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0; 451 int ret = 0; 452 453 switch (level) { 454 case SND_SOC_BIAS_ON: 455 /* ensure bufioen and biasen */ 456 pwr_reg |= (1 << 2) | (1 << 3); 457 /* Enable thermal shutdown */ 458 val = snd_soc_read(codec, WM8940_OUTPUTCTL); 459 ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2); 460 if (ret) 461 break; 462 /* set vmid to 75k */ 463 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); 464 break; 465 case SND_SOC_BIAS_PREPARE: 466 /* ensure bufioen and biasen */ 467 pwr_reg |= (1 << 2) | (1 << 3); 468 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); 469 break; 470 case SND_SOC_BIAS_STANDBY: 471 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { 472 ret = snd_soc_cache_sync(codec); 473 if (ret < 0) { 474 dev_err(codec->dev, "Failed to sync cache: %d\n", ret); 475 return ret; 476 } 477 } 478 479 /* ensure bufioen and biasen */ 480 pwr_reg |= (1 << 2) | (1 << 3); 481 /* set vmid to 300k for standby */ 482 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2); 483 break; 484 case SND_SOC_BIAS_OFF: 485 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg); 486 break; 487 } 488 489 codec->dapm.bias_level = level; 490 491 return ret; 492 } 493 494 struct pll_ { 495 unsigned int pre_scale:2; 496 unsigned int n:4; 497 unsigned int k; 498 }; 499 500 static struct pll_ pll_div; 501 502 /* The size in bits of the pll divide multiplied by 10 503 * to allow rounding later */ 504 #define FIXED_PLL_SIZE ((1 << 24) * 10) 505 static void pll_factors(unsigned int target, unsigned int source) 506 { 507 unsigned long long Kpart; 508 unsigned int K, Ndiv, Nmod; 509 /* The left shift ist to avoid accuracy loss when right shifting */ 510 Ndiv = target / source; 511 512 if (Ndiv > 12) { 513 source <<= 1; 514 /* Multiply by 2 */ 515 pll_div.pre_scale = 0; 516 Ndiv = target / source; 517 } else if (Ndiv < 3) { 518 source >>= 2; 519 /* Divide by 4 */ 520 pll_div.pre_scale = 3; 521 Ndiv = target / source; 522 } else if (Ndiv < 6) { 523 source >>= 1; 524 /* divide by 2 */ 525 pll_div.pre_scale = 2; 526 Ndiv = target / source; 527 } else 528 pll_div.pre_scale = 1; 529 530 if ((Ndiv < 6) || (Ndiv > 12)) 531 printk(KERN_WARNING 532 "WM8940 N value %d outwith recommended range!d\n", 533 Ndiv); 534 535 pll_div.n = Ndiv; 536 Nmod = target % source; 537 Kpart = FIXED_PLL_SIZE * (long long)Nmod; 538 539 do_div(Kpart, source); 540 541 K = Kpart & 0xFFFFFFFF; 542 543 /* Check if we need to round */ 544 if ((K % 10) >= 5) 545 K += 5; 546 547 /* Move down to proper range now rounding is done */ 548 K /= 10; 549 550 pll_div.k = K; 551 } 552 553 /* Untested at the moment */ 554 static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, 555 int source, unsigned int freq_in, unsigned int freq_out) 556 { 557 struct snd_soc_codec *codec = codec_dai->codec; 558 u16 reg; 559 560 /* Turn off PLL */ 561 reg = snd_soc_read(codec, WM8940_POWER1); 562 snd_soc_write(codec, WM8940_POWER1, reg & 0x1df); 563 564 if (freq_in == 0 || freq_out == 0) { 565 /* Clock CODEC directly from MCLK */ 566 reg = snd_soc_read(codec, WM8940_CLOCK); 567 snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff); 568 /* Pll power down */ 569 snd_soc_write(codec, WM8940_PLLN, (1 << 7)); 570 return 0; 571 } 572 573 /* Pll is followed by a frequency divide by 4 */ 574 pll_factors(freq_out*4, freq_in); 575 if (pll_div.k) 576 snd_soc_write(codec, WM8940_PLLN, 577 (pll_div.pre_scale << 4) | pll_div.n | (1 << 6)); 578 else /* No factional component */ 579 snd_soc_write(codec, WM8940_PLLN, 580 (pll_div.pre_scale << 4) | pll_div.n); 581 snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18); 582 snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); 583 snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); 584 /* Enable the PLL */ 585 reg = snd_soc_read(codec, WM8940_POWER1); 586 snd_soc_write(codec, WM8940_POWER1, reg | 0x020); 587 588 /* Run CODEC from PLL instead of MCLK */ 589 reg = snd_soc_read(codec, WM8940_CLOCK); 590 snd_soc_write(codec, WM8940_CLOCK, reg | 0x100); 591 592 return 0; 593 } 594 595 static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai, 596 int clk_id, unsigned int freq, int dir) 597 { 598 struct snd_soc_codec *codec = codec_dai->codec; 599 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec); 600 601 switch (freq) { 602 case 11289600: 603 case 12000000: 604 case 12288000: 605 case 16934400: 606 case 18432000: 607 wm8940->sysclk = freq; 608 return 0; 609 } 610 return -EINVAL; 611 } 612 613 static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, 614 int div_id, int div) 615 { 616 struct snd_soc_codec *codec = codec_dai->codec; 617 u16 reg; 618 int ret = 0; 619 620 switch (div_id) { 621 case WM8940_BCLKDIV: 622 reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFE3; 623 ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2)); 624 break; 625 case WM8940_MCLKDIV: 626 reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F; 627 ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5)); 628 break; 629 case WM8940_OPCLKDIV: 630 reg = snd_soc_read(codec, WM8940_GPIO) & 0xFFCF; 631 ret = snd_soc_write(codec, WM8940_GPIO, reg | (div << 4)); 632 break; 633 } 634 return ret; 635 } 636 637 #define WM8940_RATES SNDRV_PCM_RATE_8000_48000 638 639 #define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 640 SNDRV_PCM_FMTBIT_S16_LE | \ 641 SNDRV_PCM_FMTBIT_S20_3LE | \ 642 SNDRV_PCM_FMTBIT_S24_LE | \ 643 SNDRV_PCM_FMTBIT_S32_LE) 644 645 static const struct snd_soc_dai_ops wm8940_dai_ops = { 646 .hw_params = wm8940_i2s_hw_params, 647 .set_sysclk = wm8940_set_dai_sysclk, 648 .digital_mute = wm8940_mute, 649 .set_fmt = wm8940_set_dai_fmt, 650 .set_clkdiv = wm8940_set_dai_clkdiv, 651 .set_pll = wm8940_set_dai_pll, 652 }; 653 654 static struct snd_soc_dai_driver wm8940_dai = { 655 .name = "wm8940-hifi", 656 .playback = { 657 .stream_name = "Playback", 658 .channels_min = 1, 659 .channels_max = 2, 660 .rates = WM8940_RATES, 661 .formats = WM8940_FORMATS, 662 }, 663 .capture = { 664 .stream_name = "Capture", 665 .channels_min = 1, 666 .channels_max = 2, 667 .rates = WM8940_RATES, 668 .formats = WM8940_FORMATS, 669 }, 670 .ops = &wm8940_dai_ops, 671 .symmetric_rates = 1, 672 }; 673 674 static int wm8940_suspend(struct snd_soc_codec *codec) 675 { 676 return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); 677 } 678 679 static int wm8940_resume(struct snd_soc_codec *codec) 680 { 681 wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 682 return 0; 683 } 684 685 static int wm8940_probe(struct snd_soc_codec *codec) 686 { 687 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec); 688 struct wm8940_setup_data *pdata = codec->dev->platform_data; 689 int ret; 690 u16 reg; 691 692 ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type); 693 if (ret < 0) { 694 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 695 return ret; 696 } 697 698 ret = wm8940_reset(codec); 699 if (ret < 0) { 700 dev_err(codec->dev, "Failed to issue reset\n"); 701 return ret; 702 } 703 704 wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 705 706 ret = snd_soc_write(codec, WM8940_POWER1, 0x180); 707 if (ret < 0) 708 return ret; 709 710 if (!pdata) 711 dev_warn(codec->dev, "No platform data supplied\n"); 712 else { 713 reg = snd_soc_read(codec, WM8940_OUTPUTCTL); 714 ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); 715 if (ret < 0) 716 return ret; 717 } 718 719 ret = snd_soc_add_codec_controls(codec, wm8940_snd_controls, 720 ARRAY_SIZE(wm8940_snd_controls)); 721 if (ret) 722 return ret; 723 ret = wm8940_add_widgets(codec); 724 return ret; 725 } 726 727 static int wm8940_remove(struct snd_soc_codec *codec) 728 { 729 wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); 730 return 0; 731 } 732 733 static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { 734 .probe = wm8940_probe, 735 .remove = wm8940_remove, 736 .suspend = wm8940_suspend, 737 .resume = wm8940_resume, 738 .set_bias_level = wm8940_set_bias_level, 739 .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults), 740 .reg_word_size = sizeof(u16), 741 .reg_cache_default = wm8940_reg_defaults, 742 .volatile_register = wm8940_volatile_register, 743 }; 744 745 static __devinit int wm8940_i2c_probe(struct i2c_client *i2c, 746 const struct i2c_device_id *id) 747 { 748 struct wm8940_priv *wm8940; 749 int ret; 750 751 wm8940 = devm_kzalloc(&i2c->dev, sizeof(struct wm8940_priv), 752 GFP_KERNEL); 753 if (wm8940 == NULL) 754 return -ENOMEM; 755 756 i2c_set_clientdata(i2c, wm8940); 757 wm8940->control_type = SND_SOC_I2C; 758 759 ret = snd_soc_register_codec(&i2c->dev, 760 &soc_codec_dev_wm8940, &wm8940_dai, 1); 761 762 return ret; 763 } 764 765 static __devexit int wm8940_i2c_remove(struct i2c_client *client) 766 { 767 snd_soc_unregister_codec(&client->dev); 768 769 return 0; 770 } 771 772 static const struct i2c_device_id wm8940_i2c_id[] = { 773 { "wm8940", 0 }, 774 { } 775 }; 776 MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id); 777 778 static struct i2c_driver wm8940_i2c_driver = { 779 .driver = { 780 .name = "wm8940", 781 .owner = THIS_MODULE, 782 }, 783 .probe = wm8940_i2c_probe, 784 .remove = __devexit_p(wm8940_i2c_remove), 785 .id_table = wm8940_i2c_id, 786 }; 787 788 static int __init wm8940_modinit(void) 789 { 790 int ret = 0; 791 ret = i2c_add_driver(&wm8940_i2c_driver); 792 if (ret != 0) { 793 printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n", 794 ret); 795 } 796 return ret; 797 } 798 module_init(wm8940_modinit); 799 800 static void __exit wm8940_exit(void) 801 { 802 i2c_del_driver(&wm8940_i2c_driver); 803 } 804 module_exit(wm8940_exit); 805 806 MODULE_DESCRIPTION("ASoC WM8940 driver"); 807 MODULE_AUTHOR("Jonathan Cameron"); 808 MODULE_LICENSE("GPL"); 809