.. | .. |
---|
| 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 = { |
---|