| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * wm8974.c -- WM8974 ALSA Soc Audio driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2006-2009 Wolfson Microelectronics PLC. |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Liam Girdwood <Liam.Girdwood@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 | 8 | */ |
|---|
| 12 | 9 | |
|---|
| 13 | 10 | #include <linux/clk.h> |
|---|
| 14 | 11 | #include <linux/module.h> |
|---|
| 15 | | -#include <linux/moduleparam.h> |
|---|
| 16 | 12 | #include <linux/kernel.h> |
|---|
| 17 | 13 | #include <linux/init.h> |
|---|
| 18 | 14 | #include <linux/delay.h> |
|---|
| .. | .. |
|---|
| 192 | 188 | |
|---|
| 193 | 189 | /* Boost mixer */ |
|---|
| 194 | 190 | static const struct snd_kcontrol_new wm8974_boost_mixer[] = { |
|---|
| 195 | | -SOC_DAPM_SINGLE("Aux Switch", WM8974_INPPGA, 6, 1, 0), |
|---|
| 191 | +SOC_DAPM_SINGLE("Aux Switch", WM8974_INPPGA, 6, 1, 1), |
|---|
| 196 | 192 | }; |
|---|
| 197 | 193 | |
|---|
| 198 | 194 | /* Input PGA */ |
|---|
| .. | .. |
|---|
| 201 | 197 | SOC_DAPM_SINGLE("MicN Switch", WM8974_INPUT, 1, 1, 0), |
|---|
| 202 | 198 | SOC_DAPM_SINGLE("MicP Switch", WM8974_INPUT, 0, 1, 0), |
|---|
| 203 | 199 | }; |
|---|
| 204 | | - |
|---|
| 205 | | -/* AUX Input boost vol */ |
|---|
| 206 | | -static const struct snd_kcontrol_new wm8974_aux_boost_controls = |
|---|
| 207 | | -SOC_DAPM_SINGLE("Aux Volume", WM8974_ADCBOOST, 0, 7, 0); |
|---|
| 208 | | - |
|---|
| 209 | | -/* Mic Input boost vol */ |
|---|
| 210 | | -static const struct snd_kcontrol_new wm8974_mic_boost_controls = |
|---|
| 211 | | -SOC_DAPM_SINGLE("Mic Volume", WM8974_ADCBOOST, 4, 7, 0); |
|---|
| 212 | 200 | |
|---|
| 213 | 201 | static const struct snd_soc_dapm_widget wm8974_dapm_widgets[] = { |
|---|
| 214 | 202 | SND_SOC_DAPM_MIXER("Speaker Mixer", WM8974_POWER3, 2, 0, |
|---|
| .. | .. |
|---|
| 332 | 320 | |
|---|
| 333 | 321 | if (freq_in == 0 || freq_out == 0) { |
|---|
| 334 | 322 | /* Clock CODEC directly from MCLK */ |
|---|
| 335 | | - reg = snd_soc_component_read32(component, WM8974_CLOCK); |
|---|
| 323 | + reg = snd_soc_component_read(component, WM8974_CLOCK); |
|---|
| 336 | 324 | snd_soc_component_write(component, WM8974_CLOCK, reg & 0x0ff); |
|---|
| 337 | 325 | |
|---|
| 338 | 326 | /* Turn off PLL */ |
|---|
| 339 | | - reg = snd_soc_component_read32(component, WM8974_POWER1); |
|---|
| 327 | + reg = snd_soc_component_read(component, WM8974_POWER1); |
|---|
| 340 | 328 | snd_soc_component_write(component, WM8974_POWER1, reg & 0x1df); |
|---|
| 341 | 329 | return 0; |
|---|
| 342 | 330 | } |
|---|
| .. | .. |
|---|
| 347 | 335 | snd_soc_component_write(component, WM8974_PLLK1, pll_div.k >> 18); |
|---|
| 348 | 336 | snd_soc_component_write(component, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff); |
|---|
| 349 | 337 | snd_soc_component_write(component, WM8974_PLLK3, pll_div.k & 0x1ff); |
|---|
| 350 | | - reg = snd_soc_component_read32(component, WM8974_POWER1); |
|---|
| 338 | + reg = snd_soc_component_read(component, WM8974_POWER1); |
|---|
| 351 | 339 | snd_soc_component_write(component, WM8974_POWER1, reg | 0x020); |
|---|
| 352 | 340 | |
|---|
| 353 | 341 | /* Run CODEC from PLL instead of MCLK */ |
|---|
| 354 | | - reg = snd_soc_component_read32(component, WM8974_CLOCK); |
|---|
| 342 | + reg = snd_soc_component_read(component, WM8974_CLOCK); |
|---|
| 355 | 343 | snd_soc_component_write(component, WM8974_CLOCK, reg | 0x100); |
|---|
| 356 | 344 | |
|---|
| 357 | 345 | return 0; |
|---|
| .. | .. |
|---|
| 368 | 356 | |
|---|
| 369 | 357 | switch (div_id) { |
|---|
| 370 | 358 | case WM8974_OPCLKDIV: |
|---|
| 371 | | - reg = snd_soc_component_read32(component, WM8974_GPIO) & 0x1cf; |
|---|
| 359 | + reg = snd_soc_component_read(component, WM8974_GPIO) & 0x1cf; |
|---|
| 372 | 360 | snd_soc_component_write(component, WM8974_GPIO, reg | div); |
|---|
| 373 | 361 | break; |
|---|
| 374 | 362 | case WM8974_MCLKDIV: |
|---|
| 375 | | - reg = snd_soc_component_read32(component, WM8974_CLOCK) & 0x11f; |
|---|
| 363 | + reg = snd_soc_component_read(component, WM8974_CLOCK) & 0x11f; |
|---|
| 376 | 364 | snd_soc_component_write(component, WM8974_CLOCK, reg | div); |
|---|
| 377 | 365 | break; |
|---|
| 378 | 366 | case WM8974_BCLKDIV: |
|---|
| 379 | | - reg = snd_soc_component_read32(component, WM8974_CLOCK) & 0x1e3; |
|---|
| 367 | + reg = snd_soc_component_read(component, WM8974_CLOCK) & 0x1e3; |
|---|
| 380 | 368 | snd_soc_component_write(component, WM8974_CLOCK, reg | div); |
|---|
| 381 | 369 | break; |
|---|
| 382 | 370 | default: |
|---|
| .. | .. |
|---|
| 464 | 452 | { |
|---|
| 465 | 453 | struct snd_soc_component *component = codec_dai->component; |
|---|
| 466 | 454 | u16 iface = 0; |
|---|
| 467 | | - u16 clk = snd_soc_component_read32(component, WM8974_CLOCK) & 0x1fe; |
|---|
| 455 | + u16 clk = snd_soc_component_read(component, WM8974_CLOCK) & 0x1fe; |
|---|
| 468 | 456 | |
|---|
| 469 | 457 | /* set master/slave audio interface */ |
|---|
| 470 | 458 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
|---|
| .. | .. |
|---|
| 488 | 476 | iface |= 0x0008; |
|---|
| 489 | 477 | break; |
|---|
| 490 | 478 | case SND_SOC_DAIFMT_DSP_A: |
|---|
| 479 | + if ((fmt & SND_SOC_DAIFMT_INV_MASK) == SND_SOC_DAIFMT_IB_IF || |
|---|
| 480 | + (fmt & SND_SOC_DAIFMT_INV_MASK) == SND_SOC_DAIFMT_NB_IF) { |
|---|
| 481 | + return -EINVAL; |
|---|
| 482 | + } |
|---|
| 491 | 483 | iface |= 0x00018; |
|---|
| 492 | 484 | break; |
|---|
| 493 | 485 | default: |
|---|
| .. | .. |
|---|
| 522 | 514 | { |
|---|
| 523 | 515 | struct snd_soc_component *component = dai->component; |
|---|
| 524 | 516 | struct wm8974_priv *priv = snd_soc_component_get_drvdata(component); |
|---|
| 525 | | - u16 iface = snd_soc_component_read32(component, WM8974_IFACE) & 0x19f; |
|---|
| 526 | | - u16 adn = snd_soc_component_read32(component, WM8974_ADD) & 0x1f1; |
|---|
| 517 | + u16 iface = snd_soc_component_read(component, WM8974_IFACE) & 0x19f; |
|---|
| 518 | + u16 adn = snd_soc_component_read(component, WM8974_ADD) & 0x1f1; |
|---|
| 527 | 519 | int err; |
|---|
| 528 | 520 | |
|---|
| 529 | 521 | priv->fs = params_rate(params); |
|---|
| .. | .. |
|---|
| 573 | 565 | return 0; |
|---|
| 574 | 566 | } |
|---|
| 575 | 567 | |
|---|
| 576 | | -static int wm8974_mute(struct snd_soc_dai *dai, int mute) |
|---|
| 568 | +static int wm8974_mute(struct snd_soc_dai *dai, int mute, int direction) |
|---|
| 577 | 569 | { |
|---|
| 578 | 570 | struct snd_soc_component *component = dai->component; |
|---|
| 579 | | - u16 mute_reg = snd_soc_component_read32(component, WM8974_DAC) & 0xffbf; |
|---|
| 571 | + u16 mute_reg = snd_soc_component_read(component, WM8974_DAC) & 0xffbf; |
|---|
| 580 | 572 | |
|---|
| 581 | 573 | if (mute) |
|---|
| 582 | 574 | snd_soc_component_write(component, WM8974_DAC, mute_reg | 0x40); |
|---|
| .. | .. |
|---|
| 589 | 581 | static int wm8974_set_bias_level(struct snd_soc_component *component, |
|---|
| 590 | 582 | enum snd_soc_bias_level level) |
|---|
| 591 | 583 | { |
|---|
| 592 | | - u16 power1 = snd_soc_component_read32(component, WM8974_POWER1) & ~0x3; |
|---|
| 584 | + u16 power1 = snd_soc_component_read(component, WM8974_POWER1) & ~0x3; |
|---|
| 593 | 585 | |
|---|
| 594 | 586 | switch (level) { |
|---|
| 595 | 587 | case SND_SOC_BIAS_ON: |
|---|
| .. | .. |
|---|
| 628 | 620 | { |
|---|
| 629 | 621 | struct snd_soc_component *component = dai->component; |
|---|
| 630 | 622 | struct wm8974_priv *priv = snd_soc_component_get_drvdata(component); |
|---|
| 631 | | - u16 power1 = snd_soc_component_read32(component, WM8974_POWER1); |
|---|
| 623 | + u16 power1 = snd_soc_component_read(component, WM8974_POWER1); |
|---|
| 632 | 624 | |
|---|
| 633 | 625 | clk_prepare_enable(priv->mclk_in); |
|---|
| 634 | 626 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
|---|
| .. | .. |
|---|
| 644 | 636 | { |
|---|
| 645 | 637 | struct snd_soc_component *component = dai->component; |
|---|
| 646 | 638 | struct wm8974_priv *priv = snd_soc_component_get_drvdata(component); |
|---|
| 647 | | - u16 power1 = snd_soc_component_read32(component, WM8974_POWER1); |
|---|
| 639 | + u16 power1 = snd_soc_component_read(component, WM8974_POWER1); |
|---|
| 648 | 640 | |
|---|
| 649 | 641 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
|---|
| 650 | 642 | power1 &= ~0x10; |
|---|
| .. | .. |
|---|
| 660 | 652 | |
|---|
| 661 | 653 | static const struct snd_soc_dai_ops wm8974_ops = { |
|---|
| 662 | 654 | .hw_params = wm8974_pcm_hw_params, |
|---|
| 663 | | - .digital_mute = wm8974_mute, |
|---|
| 655 | + .mute_stream = wm8974_mute, |
|---|
| 664 | 656 | .set_fmt = wm8974_set_dai_fmt, |
|---|
| 665 | 657 | .set_clkdiv = wm8974_set_dai_clkdiv, |
|---|
| 666 | 658 | .set_pll = wm8974_set_dai_pll, |
|---|
| 667 | 659 | .set_sysclk = wm8974_set_dai_sysclk, |
|---|
| 668 | 660 | .startup = wm8974_startup, |
|---|
| 669 | 661 | .shutdown = wm8974_shutdown, |
|---|
| 662 | + .no_capture_mute = 1, |
|---|
| 670 | 663 | }; |
|---|
| 671 | 664 | |
|---|
| 672 | 665 | static struct snd_soc_dai_driver wm8974_dai = { |
|---|