1 /* 2 * wm8770.c -- WM8770 ALSA SoC Audio driver 3 * 4 * Copyright 2010 Wolfson Microelectronics plc 5 * 6 * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/moduleparam.h> 15 #include <linux/init.h> 16 #include <linux/delay.h> 17 #include <linux/of_device.h> 18 #include <linux/pm.h> 19 #include <linux/platform_device.h> 20 #include <linux/spi/spi.h> 21 #include <linux/regulator/consumer.h> 22 #include <linux/slab.h> 23 #include <sound/core.h> 24 #include <sound/pcm.h> 25 #include <sound/pcm_params.h> 26 #include <sound/soc.h> 27 #include <sound/initval.h> 28 #include <sound/tlv.h> 29 30 #include "wm8770.h" 31 32 #define WM8770_NUM_SUPPLIES 3 33 static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = { 34 "AVDD1", 35 "AVDD2", 36 "DVDD" 37 }; 38 39 static const u16 wm8770_reg_defs[WM8770_CACHEREGNUM] = { 40 0x7f, 0x7f, 0x7f, 0x7f, 41 0x7f, 0x7f, 0x7f, 0x7f, 42 0x7f, 0xff, 0xff, 0xff, 43 0xff, 0xff, 0xff, 0xff, 44 0xff, 0xff, 0, 0x90, 0, 45 0, 0x22, 0x22, 0x3e, 46 0xc, 0xc, 0x100, 0x189, 47 0x189, 0x8770 48 }; 49 50 struct wm8770_priv { 51 enum snd_soc_control_type control_type; 52 struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES]; 53 struct notifier_block disable_nb[WM8770_NUM_SUPPLIES]; 54 struct snd_soc_codec *codec; 55 int sysclk; 56 }; 57 58 static int vout12supply_event(struct snd_soc_dapm_widget *w, 59 struct snd_kcontrol *kcontrol, int event); 60 static int vout34supply_event(struct snd_soc_dapm_widget *w, 61 struct snd_kcontrol *kcontrol, int event); 62 63 /* 64 * We can't use the same notifier block for more than one supply and 65 * there's no way I can see to get from a callback to the caller 66 * except container_of(). 67 */ 68 #define WM8770_REGULATOR_EVENT(n) \ 69 static int wm8770_regulator_event_##n(struct notifier_block *nb, \ 70 unsigned long event, void *data) \ 71 { \ 72 struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \ 73 disable_nb[n]); \ 74 if (event & REGULATOR_EVENT_DISABLE) { \ 75 wm8770->codec->cache_sync = 1; \ 76 } \ 77 return 0; \ 78 } 79 80 WM8770_REGULATOR_EVENT(0) 81 WM8770_REGULATOR_EVENT(1) 82 WM8770_REGULATOR_EVENT(2) 83 84 static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 100, 0); 85 static const DECLARE_TLV_DB_SCALE(dac_dig_tlv, -12750, 50, 1); 86 static const DECLARE_TLV_DB_SCALE(dac_alg_tlv, -12700, 100, 1); 87 88 static const char *dac_phase_text[][2] = { 89 { "DAC1 Normal", "DAC1 Inverted" }, 90 { "DAC2 Normal", "DAC2 Inverted" }, 91 { "DAC3 Normal", "DAC3 Inverted" }, 92 { "DAC4 Normal", "DAC4 Inverted" }, 93 }; 94 95 static const struct soc_enum dac_phase[] = { 96 SOC_ENUM_DOUBLE(WM8770_DACPHASE, 0, 1, 2, dac_phase_text[0]), 97 SOC_ENUM_DOUBLE(WM8770_DACPHASE, 2, 3, 2, dac_phase_text[1]), 98 SOC_ENUM_DOUBLE(WM8770_DACPHASE, 4, 5, 2, dac_phase_text[2]), 99 SOC_ENUM_DOUBLE(WM8770_DACPHASE, 6, 7, 2, dac_phase_text[3]), 100 }; 101 102 static const struct snd_kcontrol_new wm8770_snd_controls[] = { 103 /* global DAC playback controls */ 104 SOC_SINGLE_TLV("DAC Playback Volume", WM8770_MSDIGVOL, 0, 255, 0, 105 dac_dig_tlv), 106 SOC_SINGLE("DAC Playback Switch", WM8770_DACMUTE, 4, 1, 1), 107 SOC_SINGLE("DAC Playback ZC Switch", WM8770_DACCTRL1, 0, 1, 0), 108 109 /* global VOUT playback controls */ 110 SOC_SINGLE_TLV("VOUT Playback Volume", WM8770_MSALGVOL, 0, 127, 0, 111 dac_alg_tlv), 112 SOC_SINGLE("VOUT Playback ZC Switch", WM8770_MSALGVOL, 7, 1, 0), 113 114 /* VOUT1/2/3/4 specific controls */ 115 SOC_DOUBLE_R_TLV("VOUT1 Playback Volume", WM8770_VOUT1LVOL, 116 WM8770_VOUT1RVOL, 0, 127, 0, dac_alg_tlv), 117 SOC_DOUBLE_R("VOUT1 Playback ZC Switch", WM8770_VOUT1LVOL, 118 WM8770_VOUT1RVOL, 7, 1, 0), 119 SOC_DOUBLE_R_TLV("VOUT2 Playback Volume", WM8770_VOUT2LVOL, 120 WM8770_VOUT2RVOL, 0, 127, 0, dac_alg_tlv), 121 SOC_DOUBLE_R("VOUT2 Playback ZC Switch", WM8770_VOUT2LVOL, 122 WM8770_VOUT2RVOL, 7, 1, 0), 123 SOC_DOUBLE_R_TLV("VOUT3 Playback Volume", WM8770_VOUT3LVOL, 124 WM8770_VOUT3RVOL, 0, 127, 0, dac_alg_tlv), 125 SOC_DOUBLE_R("VOUT3 Playback ZC Switch", WM8770_VOUT3LVOL, 126 WM8770_VOUT3RVOL, 7, 1, 0), 127 SOC_DOUBLE_R_TLV("VOUT4 Playback Volume", WM8770_VOUT4LVOL, 128 WM8770_VOUT4RVOL, 0, 127, 0, dac_alg_tlv), 129 SOC_DOUBLE_R("VOUT4 Playback ZC Switch", WM8770_VOUT4LVOL, 130 WM8770_VOUT4RVOL, 7, 1, 0), 131 132 /* DAC1/2/3/4 specific controls */ 133 SOC_DOUBLE_R_TLV("DAC1 Playback Volume", WM8770_DAC1LVOL, 134 WM8770_DAC1RVOL, 0, 255, 0, dac_dig_tlv), 135 SOC_SINGLE("DAC1 Deemphasis Switch", WM8770_DACCTRL2, 0, 1, 0), 136 SOC_ENUM("DAC1 Phase", dac_phase[0]), 137 SOC_DOUBLE_R_TLV("DAC2 Playback Volume", WM8770_DAC2LVOL, 138 WM8770_DAC2RVOL, 0, 255, 0, dac_dig_tlv), 139 SOC_SINGLE("DAC2 Deemphasis Switch", WM8770_DACCTRL2, 1, 1, 0), 140 SOC_ENUM("DAC2 Phase", dac_phase[1]), 141 SOC_DOUBLE_R_TLV("DAC3 Playback Volume", WM8770_DAC3LVOL, 142 WM8770_DAC3RVOL, 0, 255, 0, dac_dig_tlv), 143 SOC_SINGLE("DAC3 Deemphasis Switch", WM8770_DACCTRL2, 2, 1, 0), 144 SOC_ENUM("DAC3 Phase", dac_phase[2]), 145 SOC_DOUBLE_R_TLV("DAC4 Playback Volume", WM8770_DAC4LVOL, 146 WM8770_DAC4RVOL, 0, 255, 0, dac_dig_tlv), 147 SOC_SINGLE("DAC4 Deemphasis Switch", WM8770_DACCTRL2, 3, 1, 0), 148 SOC_ENUM("DAC4 Phase", dac_phase[3]), 149 150 /* ADC specific controls */ 151 SOC_DOUBLE_R_TLV("Capture Volume", WM8770_ADCLCTRL, WM8770_ADCRCTRL, 152 0, 31, 0, adc_tlv), 153 SOC_DOUBLE_R("Capture Switch", WM8770_ADCLCTRL, WM8770_ADCRCTRL, 154 5, 1, 1), 155 156 /* other controls */ 157 SOC_SINGLE("ADC 128x Oversampling Switch", WM8770_MSTRCTRL, 3, 1, 0), 158 SOC_SINGLE("ADC Highpass Filter Switch", WM8770_IFACECTRL, 8, 1, 1) 159 }; 160 161 static const char *ain_text[] = { 162 "AIN1", "AIN2", "AIN3", "AIN4", 163 "AIN5", "AIN6", "AIN7", "AIN8" 164 }; 165 166 static const struct soc_enum ain_enum = 167 SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text); 168 169 static const struct snd_kcontrol_new ain_mux = 170 SOC_DAPM_ENUM("Capture Mux", ain_enum); 171 172 static const struct snd_kcontrol_new vout1_mix_controls[] = { 173 SOC_DAPM_SINGLE("DAC1 Switch", WM8770_OUTMUX1, 0, 1, 0), 174 SOC_DAPM_SINGLE("AUX1 Switch", WM8770_OUTMUX1, 1, 1, 0), 175 SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 2, 1, 0) 176 }; 177 178 static const struct snd_kcontrol_new vout2_mix_controls[] = { 179 SOC_DAPM_SINGLE("DAC2 Switch", WM8770_OUTMUX1, 3, 1, 0), 180 SOC_DAPM_SINGLE("AUX2 Switch", WM8770_OUTMUX1, 4, 1, 0), 181 SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 5, 1, 0) 182 }; 183 184 static const struct snd_kcontrol_new vout3_mix_controls[] = { 185 SOC_DAPM_SINGLE("DAC3 Switch", WM8770_OUTMUX2, 0, 1, 0), 186 SOC_DAPM_SINGLE("AUX3 Switch", WM8770_OUTMUX2, 1, 1, 0), 187 SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 2, 1, 0) 188 }; 189 190 static const struct snd_kcontrol_new vout4_mix_controls[] = { 191 SOC_DAPM_SINGLE("DAC4 Switch", WM8770_OUTMUX2, 3, 1, 0), 192 SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 4, 1, 0) 193 }; 194 195 static const struct snd_soc_dapm_widget wm8770_dapm_widgets[] = { 196 SND_SOC_DAPM_INPUT("AUX1"), 197 SND_SOC_DAPM_INPUT("AUX2"), 198 SND_SOC_DAPM_INPUT("AUX3"), 199 200 SND_SOC_DAPM_INPUT("AIN1"), 201 SND_SOC_DAPM_INPUT("AIN2"), 202 SND_SOC_DAPM_INPUT("AIN3"), 203 SND_SOC_DAPM_INPUT("AIN4"), 204 SND_SOC_DAPM_INPUT("AIN5"), 205 SND_SOC_DAPM_INPUT("AIN6"), 206 SND_SOC_DAPM_INPUT("AIN7"), 207 SND_SOC_DAPM_INPUT("AIN8"), 208 209 SND_SOC_DAPM_MUX("Capture Mux", WM8770_ADCMUX, 8, 1, &ain_mux), 210 211 SND_SOC_DAPM_ADC("ADC", "Capture", WM8770_PWDNCTRL, 1, 1), 212 213 SND_SOC_DAPM_DAC("DAC1", "Playback", WM8770_PWDNCTRL, 2, 1), 214 SND_SOC_DAPM_DAC("DAC2", "Playback", WM8770_PWDNCTRL, 3, 1), 215 SND_SOC_DAPM_DAC("DAC3", "Playback", WM8770_PWDNCTRL, 4, 1), 216 SND_SOC_DAPM_DAC("DAC4", "Playback", WM8770_PWDNCTRL, 5, 1), 217 218 SND_SOC_DAPM_SUPPLY("VOUT12 Supply", SND_SOC_NOPM, 0, 0, 219 vout12supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 220 SND_SOC_DAPM_SUPPLY("VOUT34 Supply", SND_SOC_NOPM, 0, 0, 221 vout34supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 222 223 SND_SOC_DAPM_MIXER("VOUT1 Mixer", SND_SOC_NOPM, 0, 0, 224 vout1_mix_controls, ARRAY_SIZE(vout1_mix_controls)), 225 SND_SOC_DAPM_MIXER("VOUT2 Mixer", SND_SOC_NOPM, 0, 0, 226 vout2_mix_controls, ARRAY_SIZE(vout2_mix_controls)), 227 SND_SOC_DAPM_MIXER("VOUT3 Mixer", SND_SOC_NOPM, 0, 0, 228 vout3_mix_controls, ARRAY_SIZE(vout3_mix_controls)), 229 SND_SOC_DAPM_MIXER("VOUT4 Mixer", SND_SOC_NOPM, 0, 0, 230 vout4_mix_controls, ARRAY_SIZE(vout4_mix_controls)), 231 232 SND_SOC_DAPM_OUTPUT("VOUT1"), 233 SND_SOC_DAPM_OUTPUT("VOUT2"), 234 SND_SOC_DAPM_OUTPUT("VOUT3"), 235 SND_SOC_DAPM_OUTPUT("VOUT4") 236 }; 237 238 static const struct snd_soc_dapm_route wm8770_intercon[] = { 239 { "Capture Mux", "AIN1", "AIN1" }, 240 { "Capture Mux", "AIN2", "AIN2" }, 241 { "Capture Mux", "AIN3", "AIN3" }, 242 { "Capture Mux", "AIN4", "AIN4" }, 243 { "Capture Mux", "AIN5", "AIN5" }, 244 { "Capture Mux", "AIN6", "AIN6" }, 245 { "Capture Mux", "AIN7", "AIN7" }, 246 { "Capture Mux", "AIN8", "AIN8" }, 247 248 { "ADC", NULL, "Capture Mux" }, 249 250 { "VOUT1 Mixer", NULL, "VOUT12 Supply" }, 251 { "VOUT1 Mixer", "DAC1 Switch", "DAC1" }, 252 { "VOUT1 Mixer", "AUX1 Switch", "AUX1" }, 253 { "VOUT1 Mixer", "Bypass Switch", "Capture Mux" }, 254 255 { "VOUT2 Mixer", NULL, "VOUT12 Supply" }, 256 { "VOUT2 Mixer", "DAC2 Switch", "DAC2" }, 257 { "VOUT2 Mixer", "AUX2 Switch", "AUX2" }, 258 { "VOUT2 Mixer", "Bypass Switch", "Capture Mux" }, 259 260 { "VOUT3 Mixer", NULL, "VOUT34 Supply" }, 261 { "VOUT3 Mixer", "DAC3 Switch", "DAC3" }, 262 { "VOUT3 Mixer", "AUX3 Switch", "AUX3" }, 263 { "VOUT3 Mixer", "Bypass Switch", "Capture Mux" }, 264 265 { "VOUT4 Mixer", NULL, "VOUT34 Supply" }, 266 { "VOUT4 Mixer", "DAC4 Switch", "DAC4" }, 267 { "VOUT4 Mixer", "Bypass Switch", "Capture Mux" }, 268 269 { "VOUT1", NULL, "VOUT1 Mixer" }, 270 { "VOUT2", NULL, "VOUT2 Mixer" }, 271 { "VOUT3", NULL, "VOUT3 Mixer" }, 272 { "VOUT4", NULL, "VOUT4 Mixer" } 273 }; 274 275 static int vout12supply_event(struct snd_soc_dapm_widget *w, 276 struct snd_kcontrol *kcontrol, int event) 277 { 278 struct snd_soc_codec *codec; 279 280 codec = w->codec; 281 282 switch (event) { 283 case SND_SOC_DAPM_PRE_PMU: 284 snd_soc_update_bits(codec, WM8770_OUTMUX1, 0x180, 0); 285 break; 286 case SND_SOC_DAPM_POST_PMD: 287 snd_soc_update_bits(codec, WM8770_OUTMUX1, 0x180, 0x180); 288 break; 289 } 290 291 return 0; 292 } 293 294 static int vout34supply_event(struct snd_soc_dapm_widget *w, 295 struct snd_kcontrol *kcontrol, int event) 296 { 297 struct snd_soc_codec *codec; 298 299 codec = w->codec; 300 301 switch (event) { 302 case SND_SOC_DAPM_PRE_PMU: 303 snd_soc_update_bits(codec, WM8770_OUTMUX2, 0x180, 0); 304 break; 305 case SND_SOC_DAPM_POST_PMD: 306 snd_soc_update_bits(codec, WM8770_OUTMUX2, 0x180, 0x180); 307 break; 308 } 309 310 return 0; 311 } 312 313 static int wm8770_reset(struct snd_soc_codec *codec) 314 { 315 return snd_soc_write(codec, WM8770_RESET, 0); 316 } 317 318 static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 319 { 320 struct snd_soc_codec *codec; 321 int iface, master; 322 323 codec = dai->codec; 324 325 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 326 case SND_SOC_DAIFMT_CBM_CFM: 327 master = 0x100; 328 break; 329 case SND_SOC_DAIFMT_CBS_CFS: 330 master = 0; 331 break; 332 default: 333 return -EINVAL; 334 } 335 336 iface = 0; 337 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 338 case SND_SOC_DAIFMT_I2S: 339 iface |= 0x2; 340 break; 341 case SND_SOC_DAIFMT_RIGHT_J: 342 break; 343 case SND_SOC_DAIFMT_LEFT_J: 344 iface |= 0x1; 345 break; 346 default: 347 return -EINVAL; 348 } 349 350 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 351 case SND_SOC_DAIFMT_NB_NF: 352 break; 353 case SND_SOC_DAIFMT_IB_IF: 354 iface |= 0xc; 355 break; 356 case SND_SOC_DAIFMT_IB_NF: 357 iface |= 0x8; 358 break; 359 case SND_SOC_DAIFMT_NB_IF: 360 iface |= 0x4; 361 break; 362 default: 363 return -EINVAL; 364 } 365 366 snd_soc_update_bits(codec, WM8770_IFACECTRL, 0xf, iface); 367 snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x100, master); 368 369 return 0; 370 } 371 372 static const int mclk_ratios[] = { 373 128, 374 192, 375 256, 376 384, 377 512, 378 768 379 }; 380 381 static int wm8770_hw_params(struct snd_pcm_substream *substream, 382 struct snd_pcm_hw_params *params, 383 struct snd_soc_dai *dai) 384 { 385 struct snd_soc_codec *codec; 386 struct wm8770_priv *wm8770; 387 int i; 388 int iface; 389 int shift; 390 int ratio; 391 392 codec = dai->codec; 393 wm8770 = snd_soc_codec_get_drvdata(codec); 394 395 iface = 0; 396 switch (params_format(params)) { 397 case SNDRV_PCM_FORMAT_S16_LE: 398 break; 399 case SNDRV_PCM_FORMAT_S20_3LE: 400 iface |= 0x10; 401 break; 402 case SNDRV_PCM_FORMAT_S24_LE: 403 iface |= 0x20; 404 break; 405 case SNDRV_PCM_FORMAT_S32_LE: 406 iface |= 0x30; 407 break; 408 } 409 410 switch (substream->stream) { 411 case SNDRV_PCM_STREAM_PLAYBACK: 412 i = 0; 413 shift = 4; 414 break; 415 case SNDRV_PCM_STREAM_CAPTURE: 416 i = 2; 417 shift = 0; 418 break; 419 default: 420 return -EINVAL; 421 } 422 423 /* Only need to set MCLK/LRCLK ratio if we're master */ 424 if (snd_soc_read(codec, WM8770_MSTRCTRL) & 0x100) { 425 for (; i < ARRAY_SIZE(mclk_ratios); ++i) { 426 ratio = wm8770->sysclk / params_rate(params); 427 if (ratio == mclk_ratios[i]) 428 break; 429 } 430 431 if (i == ARRAY_SIZE(mclk_ratios)) { 432 dev_err(codec->dev, 433 "Unable to configure MCLK ratio %d/%d\n", 434 wm8770->sysclk, params_rate(params)); 435 return -EINVAL; 436 } 437 438 dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]); 439 440 snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x7 << shift, 441 i << shift); 442 } 443 444 snd_soc_update_bits(codec, WM8770_IFACECTRL, 0x30, iface); 445 446 return 0; 447 } 448 449 static int wm8770_mute(struct snd_soc_dai *dai, int mute) 450 { 451 struct snd_soc_codec *codec; 452 453 codec = dai->codec; 454 return snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 455 !!mute << 4); 456 } 457 458 static int wm8770_set_sysclk(struct snd_soc_dai *dai, 459 int clk_id, unsigned int freq, int dir) 460 { 461 struct snd_soc_codec *codec; 462 struct wm8770_priv *wm8770; 463 464 codec = dai->codec; 465 wm8770 = snd_soc_codec_get_drvdata(codec); 466 wm8770->sysclk = freq; 467 return 0; 468 } 469 470 static void wm8770_sync_cache(struct snd_soc_codec *codec) 471 { 472 int i; 473 u16 *cache; 474 475 if (!codec->cache_sync) 476 return; 477 478 codec->cache_only = 0; 479 cache = codec->reg_cache; 480 for (i = 0; i < codec->driver->reg_cache_size; i++) { 481 if (i == WM8770_RESET || cache[i] == wm8770_reg_defs[i]) 482 continue; 483 snd_soc_write(codec, i, cache[i]); 484 } 485 codec->cache_sync = 0; 486 } 487 488 static int wm8770_set_bias_level(struct snd_soc_codec *codec, 489 enum snd_soc_bias_level level) 490 { 491 int ret; 492 struct wm8770_priv *wm8770; 493 494 wm8770 = snd_soc_codec_get_drvdata(codec); 495 496 switch (level) { 497 case SND_SOC_BIAS_ON: 498 break; 499 case SND_SOC_BIAS_PREPARE: 500 break; 501 case SND_SOC_BIAS_STANDBY: 502 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { 503 ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies), 504 wm8770->supplies); 505 if (ret) { 506 dev_err(codec->dev, 507 "Failed to enable supplies: %d\n", 508 ret); 509 return ret; 510 } 511 wm8770_sync_cache(codec); 512 /* global powerup */ 513 snd_soc_write(codec, WM8770_PWDNCTRL, 0); 514 } 515 break; 516 case SND_SOC_BIAS_OFF: 517 /* global powerdown */ 518 snd_soc_write(codec, WM8770_PWDNCTRL, 1); 519 regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), 520 wm8770->supplies); 521 break; 522 } 523 524 codec->dapm.bias_level = level; 525 return 0; 526 } 527 528 #define WM8770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ 529 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 530 531 static struct snd_soc_dai_ops wm8770_dai_ops = { 532 .digital_mute = wm8770_mute, 533 .hw_params = wm8770_hw_params, 534 .set_fmt = wm8770_set_fmt, 535 .set_sysclk = wm8770_set_sysclk, 536 }; 537 538 static struct snd_soc_dai_driver wm8770_dai = { 539 .name = "wm8770-hifi", 540 .playback = { 541 .stream_name = "Playback", 542 .channels_min = 2, 543 .channels_max = 2, 544 .rates = SNDRV_PCM_RATE_8000_192000, 545 .formats = WM8770_FORMATS 546 }, 547 .capture = { 548 .stream_name = "Capture", 549 .channels_min = 2, 550 .channels_max = 2, 551 .rates = SNDRV_PCM_RATE_8000_96000, 552 .formats = WM8770_FORMATS 553 }, 554 .ops = &wm8770_dai_ops, 555 .symmetric_rates = 1 556 }; 557 558 #ifdef CONFIG_PM 559 static int wm8770_suspend(struct snd_soc_codec *codec, pm_message_t state) 560 { 561 wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF); 562 return 0; 563 } 564 565 static int wm8770_resume(struct snd_soc_codec *codec) 566 { 567 wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 568 return 0; 569 } 570 #else 571 #define wm8770_suspend NULL 572 #define wm8770_resume NULL 573 #endif 574 575 static int wm8770_probe(struct snd_soc_codec *codec) 576 { 577 struct wm8770_priv *wm8770; 578 int ret; 579 int i; 580 581 wm8770 = snd_soc_codec_get_drvdata(codec); 582 wm8770->codec = codec; 583 584 codec->dapm.idle_bias_off = 1; 585 586 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type); 587 if (ret < 0) { 588 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 589 return ret; 590 } 591 592 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) 593 wm8770->supplies[i].supply = wm8770_supply_names[i]; 594 595 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8770->supplies), 596 wm8770->supplies); 597 if (ret) { 598 dev_err(codec->dev, "Failed to request supplies: %d\n", ret); 599 return ret; 600 } 601 602 wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0; 603 wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1; 604 wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2; 605 606 /* This should really be moved into the regulator core */ 607 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) { 608 ret = regulator_register_notifier(wm8770->supplies[i].consumer, 609 &wm8770->disable_nb[i]); 610 if (ret) { 611 dev_err(codec->dev, 612 "Failed to register regulator notifier: %d\n", 613 ret); 614 } 615 } 616 617 ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies), 618 wm8770->supplies); 619 if (ret) { 620 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 621 goto err_reg_get; 622 } 623 624 ret = wm8770_reset(codec); 625 if (ret < 0) { 626 dev_err(codec->dev, "Failed to issue reset: %d\n", ret); 627 goto err_reg_enable; 628 } 629 630 wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 631 632 /* latch the volume update bits */ 633 snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100); 634 snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100); 635 snd_soc_update_bits(codec, WM8770_VOUT1RVOL, 0x100, 0x100); 636 snd_soc_update_bits(codec, WM8770_VOUT2RVOL, 0x100, 0x100); 637 snd_soc_update_bits(codec, WM8770_VOUT3RVOL, 0x100, 0x100); 638 snd_soc_update_bits(codec, WM8770_VOUT4RVOL, 0x100, 0x100); 639 snd_soc_update_bits(codec, WM8770_DAC1RVOL, 0x100, 0x100); 640 snd_soc_update_bits(codec, WM8770_DAC2RVOL, 0x100, 0x100); 641 snd_soc_update_bits(codec, WM8770_DAC3RVOL, 0x100, 0x100); 642 snd_soc_update_bits(codec, WM8770_DAC4RVOL, 0x100, 0x100); 643 644 /* mute all DACs */ 645 snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10); 646 647 snd_soc_add_controls(codec, wm8770_snd_controls, 648 ARRAY_SIZE(wm8770_snd_controls)); 649 snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets, 650 ARRAY_SIZE(wm8770_dapm_widgets)); 651 snd_soc_dapm_add_routes(&codec->dapm, wm8770_intercon, 652 ARRAY_SIZE(wm8770_intercon)); 653 return 0; 654 655 err_reg_enable: 656 regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); 657 err_reg_get: 658 regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); 659 return ret; 660 } 661 662 static int wm8770_remove(struct snd_soc_codec *codec) 663 { 664 struct wm8770_priv *wm8770; 665 int i; 666 667 wm8770 = snd_soc_codec_get_drvdata(codec); 668 wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF); 669 670 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i) 671 regulator_unregister_notifier(wm8770->supplies[i].consumer, 672 &wm8770->disable_nb[i]); 673 regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); 674 return 0; 675 } 676 677 static struct snd_soc_codec_driver soc_codec_dev_wm8770 = { 678 .probe = wm8770_probe, 679 .remove = wm8770_remove, 680 .suspend = wm8770_suspend, 681 .resume = wm8770_resume, 682 .set_bias_level = wm8770_set_bias_level, 683 .reg_cache_size = ARRAY_SIZE(wm8770_reg_defs), 684 .reg_word_size = sizeof (u16), 685 .reg_cache_default = wm8770_reg_defs 686 }; 687 688 static const struct of_device_id wm8770_of_match[] = { 689 { .compatible = "wlf,wm8770", }, 690 { } 691 }; 692 MODULE_DEVICE_TABLE(of, wm8770_of_match); 693 694 #if defined(CONFIG_SPI_MASTER) 695 static int __devinit wm8770_spi_probe(struct spi_device *spi) 696 { 697 struct wm8770_priv *wm8770; 698 int ret; 699 700 wm8770 = kzalloc(sizeof(struct wm8770_priv), GFP_KERNEL); 701 if (!wm8770) 702 return -ENOMEM; 703 704 wm8770->control_type = SND_SOC_SPI; 705 spi_set_drvdata(spi, wm8770); 706 707 ret = snd_soc_register_codec(&spi->dev, 708 &soc_codec_dev_wm8770, &wm8770_dai, 1); 709 if (ret < 0) 710 kfree(wm8770); 711 return ret; 712 } 713 714 static int __devexit wm8770_spi_remove(struct spi_device *spi) 715 { 716 snd_soc_unregister_codec(&spi->dev); 717 kfree(spi_get_drvdata(spi)); 718 return 0; 719 } 720 721 static struct spi_driver wm8770_spi_driver = { 722 .driver = { 723 .name = "wm8770", 724 .owner = THIS_MODULE, 725 .of_match_table = wm8770_of_match, 726 }, 727 .probe = wm8770_spi_probe, 728 .remove = __devexit_p(wm8770_spi_remove) 729 }; 730 #endif 731 732 static int __init wm8770_modinit(void) 733 { 734 int ret = 0; 735 736 #if defined(CONFIG_SPI_MASTER) 737 ret = spi_register_driver(&wm8770_spi_driver); 738 if (ret) { 739 printk(KERN_ERR "Failed to register wm8770 SPI driver: %d\n", 740 ret); 741 } 742 #endif 743 return ret; 744 } 745 module_init(wm8770_modinit); 746 747 static void __exit wm8770_exit(void) 748 { 749 #if defined(CONFIG_SPI_MASTER) 750 spi_unregister_driver(&wm8770_spi_driver); 751 #endif 752 } 753 module_exit(wm8770_exit); 754 755 MODULE_DESCRIPTION("ASoC WM8770 driver"); 756 MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); 757 MODULE_LICENSE("GPL"); 758