1 From 01c84e09a331a3b4c29c1cd5ce364c91577c7cea Mon Sep 17 00:00:00 2001
2 From: Matthias Reichl <hias@horus.com>
3 Date: Sun, 22 Jan 2017 12:49:37 +0100
4 Subject: [PATCH] ASoC: Add driver for Cirrus Logic Audio Card
6 Note: due to problems with deferred probing of regulators
7 the following softdep should be added to a modprobe.d file
9 softdep arizona-spi pre: arizona-ldo1
11 Signed-off-by: Matthias Reichl <hias@horus.com>
13 arch/arm/boot/dts/overlays/Makefile | 1 +
14 arch/arm/boot/dts/overlays/README | 6 +
15 .../dts/overlays/rpi-cirrus-wm5102-overlay.dts | 146 +++
16 sound/soc/bcm/Kconfig | 9 +
17 sound/soc/bcm/Makefile | 2 +
18 sound/soc/bcm/rpi-cirrus.c | 1003 ++++++++++++++++++++
19 6 files changed, 1167 insertions(+)
20 create mode 100644 arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
21 create mode 100644 sound/soc/bcm/rpi-cirrus.c
23 --- a/arch/arm/boot/dts/overlays/Makefile
24 +++ b/arch/arm/boot/dts/overlays/Makefile
25 @@ -68,6 +68,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
29 + rpi-cirrus-wm5102.dtbo \
33 --- a/arch/arm/boot/dts/overlays/README
34 +++ b/arch/arm/boot/dts/overlays/README
35 @@ -995,6 +995,12 @@ Load: dtoverlay=rpi-backlight
39 +Name: rpi-cirrus-wm5102
40 +Info: Configures the Cirrus Logic Audio Card
41 +Load: dtoverlay=rpi-cirrus-wm5102
46 Info: Configures the RPi DAC audio card
47 Load: dtoverlay=rpi-dac
49 +++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
51 +// Definitions for the Cirrus Logic Audio Card
54 +#include <dt-bindings/pinctrl/bcm2835.h>
55 +#include <dt-bindings/gpio/gpio.h>
56 +#include <dt-bindings/mfd/arizona.h>
59 + compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
71 + wlf_pins: wlf_pins {
72 + brcm,pins = <17 22 27 8>;
74 + BCM2835_FSEL_GPIO_OUT
75 + BCM2835_FSEL_GPIO_OUT
76 + BCM2835_FSEL_GPIO_IN
77 + BCM2835_FSEL_GPIO_OUT
86 + rpi_cirrus_reg_1v8: rpi_cirrus_reg_1v8 {
87 + compatible = "regulator-fixed";
88 + regulator-name = "RPi-Cirrus 1v8";
89 + regulator-min-microvolt = <1800000>;
90 + regulator-max-microvolt = <1800000>;
91 + regulator-always-on;
99 + #address-cells = <1>;
104 + status = "disabled";
108 + status = "disabled";
112 + compatible = "wlf,wm5102";
115 + spi-max-frequency = <500000>;
117 + interrupt-parent = <&gpio>;
118 + interrupts = <27 8>;
119 + interrupt-controller;
120 + #interrupt-cells = <2>;
125 + LDOVDD-supply = <&rpi_cirrus_reg_1v8>;
126 + AVDD-supply = <&rpi_cirrus_reg_1v8>;
127 + DBVDD1-supply = <&rpi_cirrus_reg_1v8>;
128 + DBVDD2-supply = <&vdd_3v3_reg>;
129 + DBVDD3-supply = <&vdd_3v3_reg>;
130 + CPVDD-supply = <&rpi_cirrus_reg_1v8>;
131 + SPKVDDL-supply = <&vdd_5v0_reg>;
132 + SPKVDDR-supply = <&vdd_5v0_reg>;
133 + DCVDD-supply = <&arizona_ldo1>;
135 + wlf,reset = <&gpio 17 GPIO_ACTIVE_HIGH>;
136 + wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>;
137 + wlf,gpio-defaults = <
144 + wlf,micd-configs = <0 1 0>;
146 + ARIZONA_DMIC_MICVDD
147 + ARIZONA_DMIC_MICBIAS2
148 + ARIZONA_DMIC_MICVDD
149 + ARIZONA_DMIC_MICVDD
152 + ARIZONA_INMODE_DIFF
153 + ARIZONA_INMODE_DMIC
155 + ARIZONA_INMODE_DIFF
159 + arizona_ldo1: ldo1 {
160 + regulator-name = "LDO1";
161 + // default constraints as in
163 + regulator-min-microvolt = <1200000>;
164 + regulator-max-microvolt = <1800000>;
174 + #address-cells = <1>;
178 + compatible = "wlf,wm8804";
181 + PVDD-supply = <&vdd_3v3_reg>;
182 + DVDD-supply = <&vdd_3v3_reg>;
183 + wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>;
191 + compatible = "wlf,rpi-cirrus";
192 + i2s-controller = <&i2s>;
197 --- a/sound/soc/bcm/Kconfig
198 +++ b/sound/soc/bcm/Kconfig
199 @@ -45,6 +45,15 @@ config SND_BCM2708_SOC_HIFIBERRY_AMP
201 Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
203 +config SND_BCM2708_SOC_RPI_CIRRUS
204 + tristate "Support for Cirrus Logic Audio Card"
205 + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
206 + select SND_SOC_WM5102
207 + select SND_SOC_WM8804
209 + Say Y or M if you want to add support for the Wolfson and
210 + Cirrus Logic audio cards.
212 config SND_BCM2708_SOC_RPI_DAC
213 tristate "Support for RPi-DAC"
214 depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
215 --- a/sound/soc/bcm/Makefile
216 +++ b/sound/soc/bcm/Makefile
217 @@ -16,6 +16,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
218 snd-soc-hifiberry-digi-objs := hifiberry_digi.o
219 snd-soc-justboom-dac-objs := justboom-dac.o
220 snd-soc-justboom-digi-objs := justboom-digi.o
221 +snd-soc-rpi-cirrus-objs := rpi-cirrus.o
222 snd-soc-rpi-dac-objs := rpi-dac.o
223 snd-soc-rpi-proto-objs := rpi-proto.o
224 snd-soc-iqaudio-dac-objs := iqaudio-dac.o
225 @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
226 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
227 obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
228 obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o
229 +obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
230 obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
231 obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
232 obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
234 +++ b/sound/soc/bcm/rpi-cirrus.c
237 + * ASoC machine driver for Cirrus Logic Audio Card
238 + * (with WM5102 and WM8804 codecs)
240 + * Copyright 2015-2017 Matthias Reichl <hias@horus.com>
242 + * Based on rpi-cirrus-sound-pi driver (c) Wolfson / Cirrus Logic Inc.
244 + * This program is free software; you can redistribute it and/or modify
245 + * it under the terms of the GNU General Public License version 2 as
246 + * published by the Free Software Foundation.
249 +#include <linux/module.h>
250 +#include <linux/mutex.h>
251 +#include <linux/slab.h>
252 +#include <linux/list.h>
253 +#include <linux/delay.h>
254 +#include <sound/pcm_params.h>
256 +#include <linux/mfd/arizona/registers.h>
258 +#include "../codecs/wm5102.h"
259 +#include "../codecs/wm8804.h"
261 +#define WM8804_CLKOUT_HZ 12000000
263 +#define RPI_CIRRUS_DEFAULT_RATE 44100
264 +#define WM5102_MAX_SYSCLK_1 49152000 /* max sysclk for 4K family */
265 +#define WM5102_MAX_SYSCLK_2 45158400 /* max sysclk for 11.025K family */
267 +static inline unsigned int calc_sysclk(unsigned int rate)
269 + return (rate % 4000) ? WM5102_MAX_SYSCLK_2 : WM5102_MAX_SYSCLK_1;
277 +struct rpi_cirrus_priv {
278 + /* mutex for synchronzing FLL1 access with DAPM */
280 + unsigned int card_rate;
281 + int sync_path_enable;
282 + int fll1_freq; /* negative means RefClock in spdif rx case */
284 + /* track hw params/free for substreams */
285 + unsigned int params_set;
286 + unsigned int min_rate_idx, max_rate_idx;
287 + unsigned char iec958_status[4];
290 +/* helper functions */
291 +static inline struct snd_soc_pcm_runtime *get_wm5102_runtime(
292 + struct snd_soc_card *card) {
293 + return snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM5102].name);
296 +static inline struct snd_soc_pcm_runtime *get_wm8804_runtime(
297 + struct snd_soc_card *card) {
298 + return snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM8804].name);
303 + unsigned int value;
307 +static struct rate_info min_rates[] = {
310 + { 44100, "44.1kHz"}
313 +#define NUM_MIN_RATES ARRAY_SIZE(min_rates)
315 +static int rpi_cirrus_min_rate_info(struct snd_kcontrol *kcontrol,
316 + struct snd_ctl_elem_info *uinfo)
318 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
320 + uinfo->value.enumerated.items = NUM_MIN_RATES;
322 + if (uinfo->value.enumerated.item >= NUM_MIN_RATES)
323 + uinfo->value.enumerated.item = NUM_MIN_RATES - 1;
324 + strcpy(uinfo->value.enumerated.name,
325 + min_rates[uinfo->value.enumerated.item].text);
329 +static int rpi_cirrus_min_rate_get(struct snd_kcontrol *kcontrol,
330 + struct snd_ctl_elem_value *ucontrol)
332 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
333 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
335 + ucontrol->value.enumerated.item[0] = priv->min_rate_idx;
339 +static int rpi_cirrus_min_rate_put(struct snd_kcontrol *kcontrol,
340 + struct snd_ctl_elem_value *ucontrol)
342 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
343 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
346 + if (priv->min_rate_idx != ucontrol->value.enumerated.item[0]) {
348 + priv->min_rate_idx = ucontrol->value.enumerated.item[0];
354 +static struct rate_info max_rates[] = {
360 +#define NUM_MAX_RATES ARRAY_SIZE(max_rates)
362 +static int rpi_cirrus_max_rate_info(struct snd_kcontrol *kcontrol,
363 + struct snd_ctl_elem_info *uinfo)
365 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
367 + uinfo->value.enumerated.items = NUM_MAX_RATES;
368 + if (uinfo->value.enumerated.item >= NUM_MAX_RATES)
369 + uinfo->value.enumerated.item = NUM_MAX_RATES - 1;
370 + strcpy(uinfo->value.enumerated.name,
371 + max_rates[uinfo->value.enumerated.item].text);
375 +static int rpi_cirrus_max_rate_get(struct snd_kcontrol *kcontrol,
376 + struct snd_ctl_elem_value *ucontrol)
378 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
379 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
381 + ucontrol->value.enumerated.item[0] = priv->max_rate_idx;
385 +static int rpi_cirrus_max_rate_put(struct snd_kcontrol *kcontrol,
386 + struct snd_ctl_elem_value *ucontrol)
388 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
389 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
392 + if (priv->max_rate_idx != ucontrol->value.enumerated.item[0]) {
394 + priv->max_rate_idx = ucontrol->value.enumerated.item[0];
400 +static int rpi_cirrus_spdif_info(struct snd_kcontrol *kcontrol,
401 + struct snd_ctl_elem_info *uinfo)
403 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
408 +static int rpi_cirrus_spdif_playback_get(struct snd_kcontrol *kcontrol,
409 + struct snd_ctl_elem_value *ucontrol)
411 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
412 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
415 + for (i = 0; i < 4; i++)
416 + ucontrol->value.iec958.status[i] = priv->iec958_status[i];
421 +static int rpi_cirrus_spdif_playback_put(struct snd_kcontrol *kcontrol,
422 + struct snd_ctl_elem_value *ucontrol)
424 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
425 + struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
426 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
427 + unsigned char *stat = priv->iec958_status;
428 + unsigned char *ctrl_stat = ucontrol->value.iec958.status;
430 + int i, changed = 0;
432 + for (i = 0; i < 4; i++) {
433 + mask = (i == 3) ? 0x3f : 0xff;
434 + if ((ctrl_stat[i] & mask) != (stat[i] & mask)) {
436 + stat[i] = ctrl_stat[i] & mask;
437 + snd_soc_update_bits(wm8804_codec,
438 + WM8804_SPDTX1 + i, mask, stat[i]);
445 +static int rpi_cirrus_spdif_mask_get(struct snd_kcontrol *kcontrol,
446 + struct snd_ctl_elem_value *ucontrol)
448 + ucontrol->value.iec958.status[0] = 0xff;
449 + ucontrol->value.iec958.status[1] = 0xff;
450 + ucontrol->value.iec958.status[2] = 0xff;
451 + ucontrol->value.iec958.status[3] = 0x3f;
456 +static int rpi_cirrus_spdif_capture_get(struct snd_kcontrol *kcontrol,
457 + struct snd_ctl_elem_value *ucontrol)
459 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
460 + struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
464 + for (i = 0; i < 4; i++) {
465 + mask = (i == 3) ? 0x3f : 0xff;
466 + ucontrol->value.iec958.status[i] =
467 + snd_soc_read(wm8804_codec, WM8804_RXCHAN1 + i) & mask;
473 +#define SPDIF_FLAG_CTRL(desc, reg, bit, invert) \
475 + .access = SNDRV_CTL_ELEM_ACCESS_READ \
476 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
477 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
478 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) \
480 + .info = snd_ctl_boolean_mono_info, \
481 + .get = rpi_cirrus_spdif_status_flag_get, \
483 + (bit) | ((reg) << 8) | ((invert) << 16) \
486 +static int rpi_cirrus_spdif_status_flag_get(struct snd_kcontrol *kcontrol,
487 + struct snd_ctl_elem_value *ucontrol)
489 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
490 + struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
492 + unsigned int bit = kcontrol->private_value & 0xff;
493 + unsigned int reg = (kcontrol->private_value >> 8) & 0xff;
494 + unsigned int invert = (kcontrol->private_value >> 16) & 0xff;
496 + bool flag = snd_soc_read(wm8804_codec, reg) & (1 << bit);
498 + ucontrol->value.integer.value[0] = invert ? !flag : flag;
503 +static const char * const recovered_frequency_texts[] = {
510 +#define NUM_RECOVERED_FREQUENCIES \
511 + ARRAY_SIZE(recovered_frequency_texts)
513 +static int rpi_cirrus_recovered_frequency_info(struct snd_kcontrol *kcontrol,
514 + struct snd_ctl_elem_info *uinfo)
516 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
518 + uinfo->value.enumerated.items = NUM_RECOVERED_FREQUENCIES;
519 + if (uinfo->value.enumerated.item >= NUM_RECOVERED_FREQUENCIES)
520 + uinfo->value.enumerated.item = NUM_RECOVERED_FREQUENCIES - 1;
521 + strcpy(uinfo->value.enumerated.name,
522 + recovered_frequency_texts[uinfo->value.enumerated.item]);
526 +static int rpi_cirrus_recovered_frequency_get(struct snd_kcontrol *kcontrol,
527 + struct snd_ctl_elem_value *ucontrol)
529 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
530 + struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
532 + ucontrol->value.enumerated.item[0] =
533 + (snd_soc_read(wm8804_codec, WM8804_SPDSTAT) >> 4) & 0x03;
537 +static const struct snd_kcontrol_new rpi_cirrus_controls[] = {
539 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
540 + .name = "Min Sample Rate",
541 + .info = rpi_cirrus_min_rate_info,
542 + .get = rpi_cirrus_min_rate_get,
543 + .put = rpi_cirrus_min_rate_put,
546 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
547 + .name = "Max Sample Rate",
548 + .info = rpi_cirrus_max_rate_info,
549 + .get = rpi_cirrus_max_rate_get,
550 + .put = rpi_cirrus_max_rate_put,
553 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
554 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
555 + .info = rpi_cirrus_spdif_info,
556 + .get = rpi_cirrus_spdif_playback_get,
557 + .put = rpi_cirrus_spdif_playback_put,
560 + .access = SNDRV_CTL_ELEM_ACCESS_READ
561 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
562 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
563 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
564 + .info = rpi_cirrus_spdif_info,
565 + .get = rpi_cirrus_spdif_capture_get,
568 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
569 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
570 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
571 + .info = rpi_cirrus_spdif_info,
572 + .get = rpi_cirrus_spdif_mask_get,
575 + .access = SNDRV_CTL_ELEM_ACCESS_READ
576 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
577 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
578 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE)
579 + "Recovered Frequency",
580 + .info = rpi_cirrus_recovered_frequency_info,
581 + .get = rpi_cirrus_recovered_frequency_get,
583 + SPDIF_FLAG_CTRL("Audio", WM8804_SPDSTAT, 0, 1),
584 + SPDIF_FLAG_CTRL("Non-PCM", WM8804_SPDSTAT, 1, 0),
585 + SPDIF_FLAG_CTRL("Copyright", WM8804_SPDSTAT, 2, 1),
586 + SPDIF_FLAG_CTRL("De-Emphasis", WM8804_SPDSTAT, 3, 0),
587 + SPDIF_FLAG_CTRL("Lock", WM8804_SPDSTAT, 6, 1),
588 + SPDIF_FLAG_CTRL("Invalid", WM8804_INTSTAT, 1, 0),
589 + SPDIF_FLAG_CTRL("TransErr", WM8804_INTSTAT, 3, 0),
592 +static const char * const linein_micbias_texts[] = {
596 +static SOC_ENUM_SINGLE_VIRT_DECL(linein_micbias_enum,
597 + linein_micbias_texts);
599 +static const struct snd_kcontrol_new linein_micbias_mux =
600 + SOC_DAPM_ENUM("Route", linein_micbias_enum);
602 +static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w,
603 + struct snd_kcontrol *kcontrol, int event);
605 +const struct snd_soc_dapm_widget rpi_cirrus_dapm_widgets[] = {
606 + SND_SOC_DAPM_MIC("DMIC", NULL),
607 + SND_SOC_DAPM_MIC("Headset Mic", NULL),
608 + SND_SOC_DAPM_INPUT("Line Input"),
609 + SND_SOC_DAPM_MIC("Line Input with Micbias", NULL),
610 + SND_SOC_DAPM_MUX("Line Input Micbias", SND_SOC_NOPM, 0, 0,
611 + &linein_micbias_mux),
612 + SND_SOC_DAPM_INPUT("dummy SPDIF in"),
613 + SND_SOC_DAPM_PGA_E("dummy SPDIFRX", SND_SOC_NOPM, 0, 0, NULL, 0,
614 + rpi_cirrus_spdif_rx_enable_event,
615 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
616 + SND_SOC_DAPM_INPUT("Dummy Input"),
617 + SND_SOC_DAPM_OUTPUT("Dummy Output"),
620 +const struct snd_soc_dapm_route rpi_cirrus_dapm_routes[] = {
621 + { "IN1L", NULL, "Headset Mic" },
622 + { "IN1R", NULL, "Headset Mic" },
623 + { "Headset Mic", NULL, "MICBIAS1" },
625 + { "IN2L", NULL, "DMIC" },
626 + { "IN2R", NULL, "DMIC" },
627 + { "DMIC", NULL, "MICBIAS2" },
629 + { "IN3L", NULL, "Line Input Micbias" },
630 + { "IN3R", NULL, "Line Input Micbias" },
632 + { "Line Input Micbias", "off", "Line Input" },
633 + { "Line Input Micbias", "on", "Line Input with Micbias" },
635 + /* Make sure MICVDD is enabled, otherwise we get noise */
636 + { "Line Input", NULL, "MICVDD" },
637 + { "Line Input with Micbias", NULL, "MICBIAS3" },
639 + /* Dummy routes to check whether SPDIF RX is enabled or not */
640 + {"dummy SPDIFRX", NULL, "dummy SPDIF in"},
641 + {"AIFTX", NULL, "dummy SPDIFRX"},
644 + * Dummy routes to keep wm5102 from staying off on
645 + * playback/capture if all mixers are off.
647 + { "Dummy Output", NULL, "AIF1RX1" },
648 + { "Dummy Output", NULL, "AIF1RX2" },
649 + { "AIF1TX1", NULL, "Dummy Input" },
650 + { "AIF1TX2", NULL, "Dummy Input" },
653 +static int rpi_cirrus_clear_flls(struct snd_soc_card *card,
654 + struct snd_soc_codec *wm5102_codec) {
658 + ret1 = snd_soc_codec_set_pll(wm5102_codec,
659 + WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0);
660 + ret2 = snd_soc_codec_set_pll(wm5102_codec,
661 + WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0);
664 + dev_warn(card->dev,
665 + "setting FLL1 to zero failed: %d\n", ret1);
669 + dev_warn(card->dev,
670 + "setting FLL1_REFCLK to zero failed: %d\n", ret2);
676 +static int rpi_cirrus_set_fll(struct snd_soc_card *card,
677 + struct snd_soc_codec *wm5102_codec, unsigned int clk_freq)
679 + int ret = snd_soc_codec_set_pll(wm5102_codec,
681 + ARIZONA_CLK_SRC_MCLK1,
685 + dev_err(card->dev, "Failed to set FLL1 to %d: %d\n",
688 + usleep_range(1000, 2000);
692 +static int rpi_cirrus_set_fll_refclk(struct snd_soc_card *card,
693 + struct snd_soc_codec *wm5102_codec,
694 + unsigned int clk_freq, unsigned int aif2_freq)
696 + int ret = snd_soc_codec_set_pll(wm5102_codec,
697 + WM5102_FLL1_REFCLK,
698 + ARIZONA_CLK_SRC_MCLK1,
703 + "Failed to set FLL1_REFCLK to %d: %d\n",
708 + ret = snd_soc_codec_set_pll(wm5102_codec,
710 + ARIZONA_CLK_SRC_AIF2BCLK,
711 + aif2_freq, clk_freq);
714 + "Failed to set FLL1 with Sync Clock %d to %d: %d\n",
715 + aif2_freq, clk_freq, ret);
717 + usleep_range(1000, 2000);
721 +static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w,
722 + struct snd_kcontrol *kcontrol, int event)
724 + struct snd_soc_card *card = w->dapm->card;
725 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
726 + struct snd_soc_codec *wm5102_codec = get_wm5102_runtime(card)->codec;
728 + unsigned int clk_freq, aif2_freq;
732 + case SND_SOC_DAPM_POST_PMU:
733 + mutex_lock(&priv->lock);
735 + /* Enable sync path in case of SPDIF capture use case */
737 + clk_freq = calc_sysclk(priv->card_rate);
738 + aif2_freq = 64 * priv->card_rate;
741 + "spdif_rx: changing FLL1 to use Ref Clock clk: %d spdif: %d\n",
742 + clk_freq, aif2_freq);
744 + ret = rpi_cirrus_clear_flls(card, wm5102_codec);
746 + dev_err(card->dev, "spdif_rx: failed to clear FLLs\n");
750 + ret = rpi_cirrus_set_fll_refclk(card, wm5102_codec,
751 + clk_freq, aif2_freq);
754 + dev_err(card->dev, "spdif_rx: failed to set FLLs\n");
758 + /* set to negative to indicate we're doing spdif rx */
759 + priv->fll1_freq = -clk_freq;
760 + priv->sync_path_enable = 1;
763 + case SND_SOC_DAPM_POST_PMD:
764 + mutex_lock(&priv->lock);
765 + priv->sync_path_enable = 0;
773 + mutex_unlock(&priv->lock);
777 +static int rpi_cirrus_set_bias_level(struct snd_soc_card *card,
778 + struct snd_soc_dapm_context *dapm,
779 + enum snd_soc_bias_level level)
781 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
782 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
783 + struct snd_soc_codec *wm5102_codec = wm5102_runtime->codec;
786 + unsigned int clk_freq;
788 + if (dapm->dev != wm5102_runtime->codec_dai->dev)
792 + case SND_SOC_BIAS_PREPARE:
793 + if (dapm->bias_level == SND_SOC_BIAS_ON)
796 + mutex_lock(&priv->lock);
798 + if (!priv->sync_path_enable) {
799 + clk_freq = calc_sysclk(priv->card_rate);
802 + "set_bias: changing FLL1 from %d to %d\n",
803 + priv->fll1_freq, clk_freq);
805 + ret = rpi_cirrus_set_fll(card, wm5102_codec, clk_freq);
808 + "set_bias: Failed to set FLL1\n");
810 + priv->fll1_freq = clk_freq;
812 + mutex_unlock(&priv->lock);
821 +static int rpi_cirrus_set_bias_level_post(struct snd_soc_card *card,
822 + struct snd_soc_dapm_context *dapm,
823 + enum snd_soc_bias_level level)
825 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
826 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
827 + struct snd_soc_codec *wm5102_codec = wm5102_runtime->codec;
829 + if (dapm->dev != wm5102_runtime->codec_dai->dev)
833 + case SND_SOC_BIAS_STANDBY:
834 + mutex_lock(&priv->lock);
837 + "set_bias_post: changing FLL1 from %d to off\n",
840 + if (rpi_cirrus_clear_flls(card, wm5102_codec))
842 + "set_bias_post: failed to clear FLLs\n");
844 + priv->fll1_freq = 0;
846 + mutex_unlock(&priv->lock);
856 +static int rpi_cirrus_set_wm8804_pll(struct snd_soc_card *card,
857 + struct snd_soc_dai *wm8804_dai, unsigned int rate)
862 + unsigned int clk_freq = rate * 256;
864 + ret = snd_soc_dai_set_pll(wm8804_dai, 0, 0,
865 + WM8804_CLKOUT_HZ, clk_freq);
868 + "Failed to set WM8804 PLL to %d: %d\n", clk_freq, ret);
872 + /* Set MCLK as PLL Output */
873 + ret = snd_soc_dai_set_sysclk(wm8804_dai,
874 + WM8804_TX_CLKSRC_PLL, clk_freq, 0);
877 + "Failed to set MCLK as PLL Output: %d\n", ret);
884 +static int rpi_cirrus_startup(struct snd_pcm_substream *substream)
886 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
887 + struct snd_soc_card *card = rtd->card;
888 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
889 + unsigned int min_rate = min_rates[priv->min_rate_idx].value;
890 + unsigned int max_rate = max_rates[priv->max_rate_idx].value;
892 + if (min_rate || max_rate) {
894 + max_rate = UINT_MAX;
897 + "startup: limiting rate to %u-%u\n",
898 + min_rate, max_rate);
900 + snd_pcm_hw_constraint_minmax(substream->runtime,
901 + SNDRV_PCM_HW_PARAM_RATE, min_rate, max_rate);
907 +static struct snd_soc_pcm_stream rpi_cirrus_dai_link2_params = {
908 + .formats = SNDRV_PCM_FMTBIT_S24_LE,
911 + .rate_min = RPI_CIRRUS_DEFAULT_RATE,
912 + .rate_max = RPI_CIRRUS_DEFAULT_RATE,
915 +static int rpi_cirrus_hw_params(struct snd_pcm_substream *substream,
916 + struct snd_pcm_hw_params *params)
918 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
919 + struct snd_soc_card *card = rtd->card;
920 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
921 + struct snd_soc_dai *bcm_i2s_dai = rtd->cpu_dai;
922 + struct snd_soc_codec *wm5102_codec = rtd->codec;
923 + struct snd_soc_dai *wm8804_dai = get_wm8804_runtime(card)->codec_dai;
927 + unsigned int width = snd_pcm_format_physical_width(
928 + params_format(params));
929 + unsigned int rate = params_rate(params);
930 + unsigned int clk_freq = calc_sysclk(rate);
932 + mutex_lock(&priv->lock);
934 + dev_dbg(card->dev, "hw_params: setting rate to %d\n", rate);
936 + ret = snd_soc_dai_set_bclk_ratio(bcm_i2s_dai, 2 * width);
938 + dev_err(card->dev, "set_bclk_ratio failed: %d\n", ret);
942 + ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0x03, 0x03, 2, width);
944 + dev_err(card->dev, "set_tdm_slot failed: %d\n", ret);
948 + /* WM8804 supports sample rates from 32k only */
949 + if (rate >= 32000) {
950 + ret = rpi_cirrus_set_wm8804_pll(card, wm8804_dai, rate);
955 + ret = snd_soc_codec_set_sysclk(wm5102_codec,
956 + ARIZONA_CLK_SYSCLK,
957 + ARIZONA_CLK_SRC_FLL1,
961 + dev_err(card->dev, "Failed to set SYSCLK: %d\n", ret);
965 + if ((priv->fll1_freq > 0) && (priv->fll1_freq != clk_freq)) {
967 + "hw_params: changing FLL1 from %d to %d\n",
968 + priv->fll1_freq, clk_freq);
970 + if (rpi_cirrus_clear_flls(card, wm5102_codec)) {
971 + dev_err(card->dev, "hw_params: failed to clear FLLs\n");
975 + if (rpi_cirrus_set_fll(card, wm5102_codec, clk_freq)) {
976 + dev_err(card->dev, "hw_params: failed to set FLL\n");
980 + priv->fll1_freq = clk_freq;
983 + priv->card_rate = rate;
984 + rpi_cirrus_dai_link2_params.rate_min = rate;
985 + rpi_cirrus_dai_link2_params.rate_max = rate;
987 + priv->params_set |= 1 << substream->stream;
990 + mutex_unlock(&priv->lock);
995 +static int rpi_cirrus_hw_free(struct snd_pcm_substream *substream)
997 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
998 + struct snd_soc_card *card = rtd->card;
999 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
1000 + struct snd_soc_codec *wm5102_codec = rtd->codec;
1002 + unsigned int old_params_set = priv->params_set;
1004 + priv->params_set &= ~(1 << substream->stream);
1006 + /* disable sysclk if this was the last open stream */
1007 + if (priv->params_set == 0 && old_params_set) {
1008 + dev_dbg(card->dev,
1009 + "hw_free: Setting SYSCLK to Zero\n");
1011 + ret = snd_soc_codec_set_sysclk(wm5102_codec,
1012 + ARIZONA_CLK_SYSCLK,
1013 + ARIZONA_CLK_SRC_FLL1,
1015 + SND_SOC_CLOCK_IN);
1017 + dev_err(card->dev,
1018 + "hw_free: Failed to set SYSCLK to Zero: %d\n",
1024 +static int rpi_cirrus_init_wm5102(struct snd_soc_pcm_runtime *rtd)
1026 + struct snd_soc_codec *codec = rtd->codec;
1029 + /* no 32kHz input, derive it from sysclk if needed */
1030 + snd_soc_update_bits(codec,
1031 + ARIZONA_CLOCK_32K_1, ARIZONA_CLK_32K_SRC_MASK, 2);
1033 + if (rpi_cirrus_clear_flls(rtd->card, codec))
1034 + dev_warn(rtd->card->dev,
1035 + "init_wm5102: failed to clear FLLs\n");
1037 + ret = snd_soc_codec_set_sysclk(codec,
1038 + ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1,
1039 + 0, SND_SOC_CLOCK_IN);
1041 + dev_err(rtd->card->dev,
1042 + "Failed to set SYSCLK to Zero: %d\n", ret);
1049 +static int rpi_cirrus_init_wm8804(struct snd_soc_pcm_runtime *rtd)
1051 + struct snd_soc_codec *codec = rtd->codec;
1052 + struct snd_soc_dai *codec_dai = rtd->codec_dai;
1053 + struct snd_soc_card *card = rtd->card;
1054 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
1055 + unsigned int mask;
1058 + for (i = 0; i < 4; i++) {
1059 + mask = (i == 3) ? 0x3f : 0xff;
1060 + priv->iec958_status[i] =
1061 + snd_soc_read(codec, WM8804_SPDTX1 + i) & mask;
1064 + /* Setup for 256fs */
1065 + ret = snd_soc_dai_set_clkdiv(codec_dai,
1066 + WM8804_MCLK_DIV, WM8804_MCLKDIV_256FS);
1068 + dev_err(card->dev,
1069 + "init_wm8804: Failed to set MCLK_DIV to 256fs: %d\n",
1074 + /* Output OSC on CLKOUT */
1075 + ret = snd_soc_dai_set_sysclk(codec_dai,
1076 + WM8804_CLKOUT_SRC_OSCCLK, WM8804_CLKOUT_HZ, 0);
1078 + dev_err(card->dev,
1079 + "init_wm8804: Failed to set CLKOUT as OSC Frequency: %d\n",
1082 + /* Init PLL with default samplerate */
1083 + ret = rpi_cirrus_set_wm8804_pll(card, codec_dai,
1084 + RPI_CIRRUS_DEFAULT_RATE);
1086 + dev_err(card->dev,
1087 + "init_wm8804: Failed to setup PLL for %dHz: %d\n",
1088 + RPI_CIRRUS_DEFAULT_RATE, ret);
1093 +static struct snd_soc_ops rpi_cirrus_ops = {
1094 + .startup = rpi_cirrus_startup,
1095 + .hw_params = rpi_cirrus_hw_params,
1096 + .hw_free = rpi_cirrus_hw_free,
1099 +static struct snd_soc_dai_link rpi_cirrus_dai[] = {
1102 + .stream_name = "WM5102 AiFi",
1103 + .codec_dai_name = "wm5102-aif1",
1104 + .codec_name = "wm5102-codec",
1105 + .dai_fmt = SND_SOC_DAIFMT_I2S
1106 + | SND_SOC_DAIFMT_NB_NF
1107 + | SND_SOC_DAIFMT_CBM_CFM,
1108 + .ops = &rpi_cirrus_ops,
1109 + .init = rpi_cirrus_init_wm5102,
1112 + .name = "WM5102 SPDIF",
1113 + .stream_name = "SPDIF Tx/Rx",
1114 + .cpu_dai_name = "wm5102-aif2",
1115 + .codec_dai_name = "wm8804-spdif",
1116 + .codec_name = "wm8804.1-003b",
1117 + .dai_fmt = SND_SOC_DAIFMT_I2S
1118 + | SND_SOC_DAIFMT_NB_NF
1119 + | SND_SOC_DAIFMT_CBM_CFM,
1120 + .ignore_suspend = 1,
1121 + .params = &rpi_cirrus_dai_link2_params,
1122 + .init = rpi_cirrus_init_wm8804,
1127 +static int rpi_cirrus_late_probe(struct snd_soc_card *card)
1129 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
1130 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
1131 + struct snd_soc_pcm_runtime *wm8804_runtime = get_wm8804_runtime(card);
1134 + dev_dbg(card->dev, "iec958_bits: %02x %02x %02x %02x\n",
1135 + priv->iec958_status[0],
1136 + priv->iec958_status[1],
1137 + priv->iec958_status[2],
1138 + priv->iec958_status[3]);
1140 + ret = snd_soc_dai_set_sysclk(
1141 + wm5102_runtime->codec_dai, ARIZONA_CLK_SYSCLK, 0, 0);
1143 + dev_err(card->dev,
1144 + "Failed to set WM5102 codec dai clk domain: %d\n", ret);
1148 + ret = snd_soc_dai_set_sysclk(
1149 + wm8804_runtime->cpu_dai, ARIZONA_CLK_SYSCLK, 0, 0);
1151 + dev_err(card->dev,
1152 + "Failed to set WM8804 codec dai clk domain: %d\n", ret);
1157 +/* audio machine driver */
1158 +static struct snd_soc_card rpi_cirrus_card = {
1159 + .name = "RPi-Cirrus",
1160 + .driver_name = "RPiCirrus",
1161 + .owner = THIS_MODULE,
1162 + .dai_link = rpi_cirrus_dai,
1163 + .num_links = ARRAY_SIZE(rpi_cirrus_dai),
1164 + .late_probe = rpi_cirrus_late_probe,
1165 + .controls = rpi_cirrus_controls,
1166 + .num_controls = ARRAY_SIZE(rpi_cirrus_controls),
1167 + .dapm_widgets = rpi_cirrus_dapm_widgets,
1168 + .num_dapm_widgets = ARRAY_SIZE(rpi_cirrus_dapm_widgets),
1169 + .dapm_routes = rpi_cirrus_dapm_routes,
1170 + .num_dapm_routes = ARRAY_SIZE(rpi_cirrus_dapm_routes),
1171 + .set_bias_level = rpi_cirrus_set_bias_level,
1172 + .set_bias_level_post = rpi_cirrus_set_bias_level_post,
1175 +static int rpi_cirrus_probe(struct platform_device *pdev)
1178 + struct rpi_cirrus_priv *priv;
1179 + struct device_node *i2s_node;
1181 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1185 + priv->min_rate_idx = 1; /* min samplerate 32kHz */
1186 + priv->card_rate = RPI_CIRRUS_DEFAULT_RATE;
1188 + mutex_init(&priv->lock);
1190 + snd_soc_card_set_drvdata(&rpi_cirrus_card, priv);
1192 + if (!pdev->dev.of_node)
1195 + i2s_node = of_parse_phandle(
1196 + pdev->dev.of_node, "i2s-controller", 0);
1198 + dev_err(&pdev->dev, "i2s-controller missing in DT\n");
1202 + rpi_cirrus_dai[DAI_WM5102].cpu_of_node = i2s_node;
1203 + rpi_cirrus_dai[DAI_WM5102].platform_of_node = i2s_node;
1205 + rpi_cirrus_card.dev = &pdev->dev;
1207 + ret = devm_snd_soc_register_card(&pdev->dev, &rpi_cirrus_card);
1209 + if (ret == -EPROBE_DEFER)
1210 + dev_dbg(&pdev->dev,
1211 + "register card requested probe deferral\n");
1213 + dev_err(&pdev->dev,
1214 + "Failed to register card: %d\n", ret);
1220 +static const struct of_device_id rpi_cirrus_of_match[] = {
1221 + { .compatible = "wlf,rpi-cirrus", },
1224 +MODULE_DEVICE_TABLE(of, rpi_cirrus_of_match);
1226 +static struct platform_driver rpi_cirrus_driver = {
1228 + .name = "snd-rpi-cirrus",
1229 + .of_match_table = of_match_ptr(rpi_cirrus_of_match),
1231 + .probe = rpi_cirrus_probe,
1234 +module_platform_driver(rpi_cirrus_driver);
1236 +MODULE_AUTHOR("Matthias Reichl <hias@horus.com>");
1237 +MODULE_DESCRIPTION("ASoC driver for Cirrus Logic Audio Card");
1238 +MODULE_LICENSE("GPL");