1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * wm8776.c -- WM8776 ALSA SoC Audio driver 4 * 5 * Copyright 2009-12 Wolfson Microelectronics plc 6 * 7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 8 * 9 * TODO: Input ALC/limiter support 10 */ 11 12 #include <linux/module.h> 13 #include <linux/moduleparam.h> 14 #include <linux/init.h> 15 #include <linux/delay.h> 16 #include <linux/pm.h> 17 #include <linux/i2c.h> 18 #include <linux/of_device.h> 19 #include <linux/regmap.h> 20 #include <linux/spi/spi.h> 21 #include <linux/slab.h> 22 #include <sound/core.h> 23 #include <sound/pcm.h> 24 #include <sound/pcm_params.h> 25 #include <sound/soc.h> 26 #include <sound/initval.h> 27 #include <sound/tlv.h> 28 29 #include "wm8776.h" 30 31 enum wm8776_chip_type { 32 WM8775 = 1, 33 WM8776, 34 }; 35 36 /* codec private data */ 37 struct wm8776_priv { 38 struct regmap *regmap; 39 int sysclk[2]; 40 }; 41 42 static const struct reg_default wm8776_reg_defaults[] = { 43 { 0, 0x79 }, 44 { 1, 0x79 }, 45 { 2, 0x79 }, 46 { 3, 0xff }, 47 { 4, 0xff }, 48 { 5, 0xff }, 49 { 6, 0x00 }, 50 { 7, 0x90 }, 51 { 8, 0x00 }, 52 { 9, 0x00 }, 53 { 10, 0x22 }, 54 { 11, 0x22 }, 55 { 12, 0x22 }, 56 { 13, 0x08 }, 57 { 14, 0xcf }, 58 { 15, 0xcf }, 59 { 16, 0x7b }, 60 { 17, 0x00 }, 61 { 18, 0x32 }, 62 { 19, 0x00 }, 63 { 20, 0xa6 }, 64 { 21, 0x01 }, 65 { 22, 0x01 }, 66 }; 67 68 static bool wm8776_volatile(struct device *dev, unsigned int reg) 69 { 70 switch (reg) { 71 case WM8776_RESET: 72 return true; 73 default: 74 return false; 75 } 76 } 77 78 static int wm8776_reset(struct snd_soc_component *component) 79 { 80 return snd_soc_component_write(component, WM8776_RESET, 0); 81 } 82 83 static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1); 84 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); 85 static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1); 86 87 static const struct snd_kcontrol_new wm8776_snd_controls[] = { 88 SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8776_HPLVOL, WM8776_HPRVOL, 89 0, 127, 0, hp_tlv), 90 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8776_DACLVOL, WM8776_DACRVOL, 91 0, 255, 0, dac_tlv), 92 SOC_SINGLE("Digital Playback ZC Switch", WM8776_DACCTRL1, 0, 1, 0), 93 94 SOC_SINGLE("Deemphasis Switch", WM8776_DACCTRL2, 0, 1, 0), 95 96 SOC_DOUBLE_R_TLV("Capture Volume", WM8776_ADCLVOL, WM8776_ADCRVOL, 97 0, 255, 0, adc_tlv), 98 SOC_DOUBLE("Capture Switch", WM8776_ADCMUX, 7, 6, 1, 1), 99 SOC_DOUBLE_R("Capture ZC Switch", WM8776_ADCLVOL, WM8776_ADCRVOL, 8, 1, 0), 100 SOC_SINGLE("Capture HPF Switch", WM8776_ADCIFCTRL, 8, 1, 1), 101 }; 102 103 static const struct snd_kcontrol_new inmix_controls[] = { 104 SOC_DAPM_SINGLE("AIN1 Switch", WM8776_ADCMUX, 0, 1, 0), 105 SOC_DAPM_SINGLE("AIN2 Switch", WM8776_ADCMUX, 1, 1, 0), 106 SOC_DAPM_SINGLE("AIN3 Switch", WM8776_ADCMUX, 2, 1, 0), 107 SOC_DAPM_SINGLE("AIN4 Switch", WM8776_ADCMUX, 3, 1, 0), 108 SOC_DAPM_SINGLE("AIN5 Switch", WM8776_ADCMUX, 4, 1, 0), 109 }; 110 111 static const struct snd_kcontrol_new outmix_controls[] = { 112 SOC_DAPM_SINGLE("DAC Switch", WM8776_OUTMUX, 0, 1, 0), 113 SOC_DAPM_SINGLE("AUX Switch", WM8776_OUTMUX, 1, 1, 0), 114 SOC_DAPM_SINGLE("Bypass Switch", WM8776_OUTMUX, 2, 1, 0), 115 }; 116 117 static const struct snd_soc_dapm_widget wm8776_dapm_widgets[] = { 118 SND_SOC_DAPM_INPUT("AUX"), 119 120 SND_SOC_DAPM_INPUT("AIN1"), 121 SND_SOC_DAPM_INPUT("AIN2"), 122 SND_SOC_DAPM_INPUT("AIN3"), 123 SND_SOC_DAPM_INPUT("AIN4"), 124 SND_SOC_DAPM_INPUT("AIN5"), 125 126 SND_SOC_DAPM_MIXER("Input Mixer", WM8776_PWRDOWN, 6, 1, 127 inmix_controls, ARRAY_SIZE(inmix_controls)), 128 129 SND_SOC_DAPM_ADC("ADC", "Capture", WM8776_PWRDOWN, 1, 1), 130 SND_SOC_DAPM_DAC("DAC", "Playback", WM8776_PWRDOWN, 2, 1), 131 132 SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, 133 outmix_controls, ARRAY_SIZE(outmix_controls)), 134 135 SND_SOC_DAPM_PGA("Headphone PGA", WM8776_PWRDOWN, 3, 1, NULL, 0), 136 137 SND_SOC_DAPM_OUTPUT("VOUT"), 138 139 SND_SOC_DAPM_OUTPUT("HPOUTL"), 140 SND_SOC_DAPM_OUTPUT("HPOUTR"), 141 }; 142 143 static const struct snd_soc_dapm_route routes[] = { 144 { "Input Mixer", "AIN1 Switch", "AIN1" }, 145 { "Input Mixer", "AIN2 Switch", "AIN2" }, 146 { "Input Mixer", "AIN3 Switch", "AIN3" }, 147 { "Input Mixer", "AIN4 Switch", "AIN4" }, 148 { "Input Mixer", "AIN5 Switch", "AIN5" }, 149 150 { "ADC", NULL, "Input Mixer" }, 151 152 { "Output Mixer", "DAC Switch", "DAC" }, 153 { "Output Mixer", "AUX Switch", "AUX" }, 154 { "Output Mixer", "Bypass Switch", "Input Mixer" }, 155 156 { "VOUT", NULL, "Output Mixer" }, 157 158 { "Headphone PGA", NULL, "Output Mixer" }, 159 160 { "HPOUTL", NULL, "Headphone PGA" }, 161 { "HPOUTR", NULL, "Headphone PGA" }, 162 }; 163 164 static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 165 { 166 struct snd_soc_component *component = dai->component; 167 int reg, iface, master; 168 169 switch (dai->driver->id) { 170 case WM8776_DAI_DAC: 171 reg = WM8776_DACIFCTRL; 172 master = 0x80; 173 break; 174 case WM8776_DAI_ADC: 175 reg = WM8776_ADCIFCTRL; 176 master = 0x100; 177 break; 178 default: 179 return -EINVAL; 180 } 181 182 iface = 0; 183 184 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 185 case SND_SOC_DAIFMT_CBM_CFM: 186 break; 187 case SND_SOC_DAIFMT_CBS_CFS: 188 master = 0; 189 break; 190 default: 191 return -EINVAL; 192 } 193 194 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 195 case SND_SOC_DAIFMT_I2S: 196 iface |= 0x0002; 197 break; 198 case SND_SOC_DAIFMT_RIGHT_J: 199 break; 200 case SND_SOC_DAIFMT_LEFT_J: 201 iface |= 0x0001; 202 break; 203 default: 204 return -EINVAL; 205 } 206 207 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 208 case SND_SOC_DAIFMT_NB_NF: 209 break; 210 case SND_SOC_DAIFMT_IB_IF: 211 iface |= 0x00c; 212 break; 213 case SND_SOC_DAIFMT_IB_NF: 214 iface |= 0x008; 215 break; 216 case SND_SOC_DAIFMT_NB_IF: 217 iface |= 0x004; 218 break; 219 default: 220 return -EINVAL; 221 } 222 223 /* Finally, write out the values */ 224 snd_soc_component_update_bits(component, reg, 0xf, iface); 225 snd_soc_component_update_bits(component, WM8776_MSTRCTRL, 0x180, master); 226 227 return 0; 228 } 229 230 static int mclk_ratios[] = { 231 128, 232 192, 233 256, 234 384, 235 512, 236 768, 237 }; 238 239 static int wm8776_hw_params(struct snd_pcm_substream *substream, 240 struct snd_pcm_hw_params *params, 241 struct snd_soc_dai *dai) 242 { 243 struct snd_soc_component *component = dai->component; 244 struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component); 245 int iface_reg, iface; 246 int ratio_shift, master; 247 int i; 248 249 switch (dai->driver->id) { 250 case WM8776_DAI_DAC: 251 iface_reg = WM8776_DACIFCTRL; 252 master = 0x80; 253 ratio_shift = 4; 254 break; 255 case WM8776_DAI_ADC: 256 iface_reg = WM8776_ADCIFCTRL; 257 master = 0x100; 258 ratio_shift = 0; 259 break; 260 default: 261 return -EINVAL; 262 } 263 264 /* Set word length */ 265 switch (params_width(params)) { 266 case 16: 267 iface = 0; 268 break; 269 case 20: 270 iface = 0x10; 271 break; 272 case 24: 273 iface = 0x20; 274 break; 275 case 32: 276 iface = 0x30; 277 break; 278 default: 279 dev_err(component->dev, "Unsupported sample size: %i\n", 280 params_width(params)); 281 return -EINVAL; 282 } 283 284 /* Only need to set MCLK/LRCLK ratio if we're master */ 285 if (snd_soc_component_read32(component, WM8776_MSTRCTRL) & master) { 286 for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) { 287 if (wm8776->sysclk[dai->driver->id] / params_rate(params) 288 == mclk_ratios[i]) 289 break; 290 } 291 292 if (i == ARRAY_SIZE(mclk_ratios)) { 293 dev_err(component->dev, 294 "Unable to configure MCLK ratio %d/%d\n", 295 wm8776->sysclk[dai->driver->id], params_rate(params)); 296 return -EINVAL; 297 } 298 299 dev_dbg(component->dev, "MCLK is %dfs\n", mclk_ratios[i]); 300 301 snd_soc_component_update_bits(component, WM8776_MSTRCTRL, 302 0x7 << ratio_shift, i << ratio_shift); 303 } else { 304 dev_dbg(component->dev, "DAI in slave mode\n"); 305 } 306 307 snd_soc_component_update_bits(component, iface_reg, 0x30, iface); 308 309 return 0; 310 } 311 312 static int wm8776_mute(struct snd_soc_dai *dai, int mute) 313 { 314 struct snd_soc_component *component = dai->component; 315 316 return snd_soc_component_write(component, WM8776_DACMUTE, !!mute); 317 } 318 319 static int wm8776_set_sysclk(struct snd_soc_dai *dai, 320 int clk_id, unsigned int freq, int dir) 321 { 322 struct snd_soc_component *component = dai->component; 323 struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component); 324 325 if (WARN_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk))) 326 return -EINVAL; 327 328 wm8776->sysclk[dai->driver->id] = freq; 329 330 return 0; 331 } 332 333 static int wm8776_set_bias_level(struct snd_soc_component *component, 334 enum snd_soc_bias_level level) 335 { 336 struct wm8776_priv *wm8776 = snd_soc_component_get_drvdata(component); 337 338 switch (level) { 339 case SND_SOC_BIAS_ON: 340 break; 341 case SND_SOC_BIAS_PREPARE: 342 break; 343 case SND_SOC_BIAS_STANDBY: 344 if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { 345 regcache_sync(wm8776->regmap); 346 347 /* Disable the global powerdown; DAPM does the rest */ 348 snd_soc_component_update_bits(component, WM8776_PWRDOWN, 1, 0); 349 } 350 351 break; 352 case SND_SOC_BIAS_OFF: 353 snd_soc_component_update_bits(component, WM8776_PWRDOWN, 1, 1); 354 break; 355 } 356 357 return 0; 358 } 359 360 #define WM8776_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 361 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 362 363 static const struct snd_soc_dai_ops wm8776_dac_ops = { 364 .digital_mute = wm8776_mute, 365 .hw_params = wm8776_hw_params, 366 .set_fmt = wm8776_set_fmt, 367 .set_sysclk = wm8776_set_sysclk, 368 }; 369 370 static const struct snd_soc_dai_ops wm8776_adc_ops = { 371 .hw_params = wm8776_hw_params, 372 .set_fmt = wm8776_set_fmt, 373 .set_sysclk = wm8776_set_sysclk, 374 }; 375 376 static struct snd_soc_dai_driver wm8776_dai[] = { 377 { 378 .name = "wm8776-hifi-playback", 379 .id = WM8776_DAI_DAC, 380 .playback = { 381 .stream_name = "Playback", 382 .channels_min = 2, 383 .channels_max = 2, 384 .rates = SNDRV_PCM_RATE_CONTINUOUS, 385 .rate_min = 32000, 386 .rate_max = 192000, 387 .formats = WM8776_FORMATS, 388 }, 389 .ops = &wm8776_dac_ops, 390 }, 391 { 392 .name = "wm8776-hifi-capture", 393 .id = WM8776_DAI_ADC, 394 .capture = { 395 .stream_name = "Capture", 396 .channels_min = 2, 397 .channels_max = 2, 398 .rates = SNDRV_PCM_RATE_CONTINUOUS, 399 .rate_min = 32000, 400 .rate_max = 96000, 401 .formats = WM8776_FORMATS, 402 }, 403 .ops = &wm8776_adc_ops, 404 }, 405 }; 406 407 static int wm8776_probe(struct snd_soc_component *component) 408 { 409 int ret = 0; 410 411 ret = wm8776_reset(component); 412 if (ret < 0) { 413 dev_err(component->dev, "Failed to issue reset: %d\n", ret); 414 return ret; 415 } 416 417 /* Latch the update bits; right channel only since we always 418 * update both. */ 419 snd_soc_component_update_bits(component, WM8776_HPRVOL, 0x100, 0x100); 420 snd_soc_component_update_bits(component, WM8776_DACRVOL, 0x100, 0x100); 421 422 return ret; 423 } 424 425 static const struct snd_soc_component_driver soc_component_dev_wm8776 = { 426 .probe = wm8776_probe, 427 .set_bias_level = wm8776_set_bias_level, 428 .controls = wm8776_snd_controls, 429 .num_controls = ARRAY_SIZE(wm8776_snd_controls), 430 .dapm_widgets = wm8776_dapm_widgets, 431 .num_dapm_widgets = ARRAY_SIZE(wm8776_dapm_widgets), 432 .dapm_routes = routes, 433 .num_dapm_routes = ARRAY_SIZE(routes), 434 .suspend_bias_off = 1, 435 .idle_bias_on = 1, 436 .use_pmdown_time = 1, 437 .endianness = 1, 438 .non_legacy_dai_naming = 1, 439 }; 440 441 static const struct of_device_id wm8776_of_match[] = { 442 { .compatible = "wlf,wm8776", }, 443 { } 444 }; 445 MODULE_DEVICE_TABLE(of, wm8776_of_match); 446 447 static const struct regmap_config wm8776_regmap = { 448 .reg_bits = 7, 449 .val_bits = 9, 450 .max_register = WM8776_RESET, 451 452 .reg_defaults = wm8776_reg_defaults, 453 .num_reg_defaults = ARRAY_SIZE(wm8776_reg_defaults), 454 .cache_type = REGCACHE_RBTREE, 455 456 .volatile_reg = wm8776_volatile, 457 }; 458 459 #if defined(CONFIG_SPI_MASTER) 460 static int wm8776_spi_probe(struct spi_device *spi) 461 { 462 struct wm8776_priv *wm8776; 463 int ret; 464 465 wm8776 = devm_kzalloc(&spi->dev, sizeof(struct wm8776_priv), 466 GFP_KERNEL); 467 if (wm8776 == NULL) 468 return -ENOMEM; 469 470 wm8776->regmap = devm_regmap_init_spi(spi, &wm8776_regmap); 471 if (IS_ERR(wm8776->regmap)) 472 return PTR_ERR(wm8776->regmap); 473 474 spi_set_drvdata(spi, wm8776); 475 476 ret = devm_snd_soc_register_component(&spi->dev, 477 &soc_component_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai)); 478 479 return ret; 480 } 481 482 static struct spi_driver wm8776_spi_driver = { 483 .driver = { 484 .name = "wm8776", 485 .of_match_table = wm8776_of_match, 486 }, 487 .probe = wm8776_spi_probe, 488 }; 489 #endif /* CONFIG_SPI_MASTER */ 490 491 #if IS_ENABLED(CONFIG_I2C) 492 static int wm8776_i2c_probe(struct i2c_client *i2c, 493 const struct i2c_device_id *id) 494 { 495 struct wm8776_priv *wm8776; 496 int ret; 497 498 wm8776 = devm_kzalloc(&i2c->dev, sizeof(struct wm8776_priv), 499 GFP_KERNEL); 500 if (wm8776 == NULL) 501 return -ENOMEM; 502 503 wm8776->regmap = devm_regmap_init_i2c(i2c, &wm8776_regmap); 504 if (IS_ERR(wm8776->regmap)) 505 return PTR_ERR(wm8776->regmap); 506 507 i2c_set_clientdata(i2c, wm8776); 508 509 ret = devm_snd_soc_register_component(&i2c->dev, 510 &soc_component_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai)); 511 512 return ret; 513 } 514 515 static const struct i2c_device_id wm8776_i2c_id[] = { 516 { "wm8775", WM8775 }, 517 { "wm8776", WM8776 }, 518 { } 519 }; 520 MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id); 521 522 static struct i2c_driver wm8776_i2c_driver = { 523 .driver = { 524 .name = "wm8776", 525 .of_match_table = wm8776_of_match, 526 }, 527 .probe = wm8776_i2c_probe, 528 .id_table = wm8776_i2c_id, 529 }; 530 #endif 531 532 static int __init wm8776_modinit(void) 533 { 534 int ret = 0; 535 #if IS_ENABLED(CONFIG_I2C) 536 ret = i2c_add_driver(&wm8776_i2c_driver); 537 if (ret != 0) { 538 printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n", 539 ret); 540 } 541 #endif 542 #if defined(CONFIG_SPI_MASTER) 543 ret = spi_register_driver(&wm8776_spi_driver); 544 if (ret != 0) { 545 printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n", 546 ret); 547 } 548 #endif 549 return ret; 550 } 551 module_init(wm8776_modinit); 552 553 static void __exit wm8776_exit(void) 554 { 555 #if IS_ENABLED(CONFIG_I2C) 556 i2c_del_driver(&wm8776_i2c_driver); 557 #endif 558 #if defined(CONFIG_SPI_MASTER) 559 spi_unregister_driver(&wm8776_spi_driver); 560 #endif 561 } 562 module_exit(wm8776_exit); 563 564 MODULE_DESCRIPTION("ASoC WM8776 driver"); 565 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 566 MODULE_LICENSE("GPL"); 567