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