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