lantiq: fix broadcasts and vlans in two iface mode
[oweals/openwrt.git] / target / linux / brcm2708 / patches-4.9 / 0144-ASoC-Add-driver-for-Cirrus-Logic-Audio-Card.patch
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
5
6 Note: due to problems with deferred probing of regulators
7 the following softdep should be added to a modprobe.d file
8
9 softdep arizona-spi pre: arizona-ldo1
10
11 Signed-off-by: Matthias Reichl <hias@horus.com>
12 ---
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
22
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) += \
26         qca7000.dtbo \
27         raspidac3.dtbo \
28         rpi-backlight.dtbo \
29 +       rpi-cirrus-wm5102.dtbo \
30         rpi-dac.dtbo \
31         rpi-display.dtbo \
32         rpi-ft5406.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
36  Params: <None>
37  
38  
39 +Name:   rpi-cirrus-wm5102
40 +Info:   Configures the Cirrus Logic Audio Card
41 +Load:   dtoverlay=rpi-cirrus-wm5102
42 +Params: <None>
43 +
44 +
45  Name:   rpi-dac
46  Info:   Configures the RPi DAC audio card
47  Load:   dtoverlay=rpi-dac
48 --- /dev/null
49 +++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
50 @@ -0,0 +1,146 @@
51 +// Definitions for the Cirrus Logic Audio Card
52 +/dts-v1/;
53 +/plugin/;
54 +#include <dt-bindings/pinctrl/bcm2835.h>
55 +#include <dt-bindings/gpio/gpio.h>
56 +#include <dt-bindings/mfd/arizona.h>
57 +
58 +/ {
59 +       compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
60 +
61 +       fragment@0 {
62 +               target = <&i2s>;
63 +               __overlay__ {
64 +                       status = "okay";
65 +               };
66 +       };
67 +
68 +       fragment@1 {
69 +               target = <&gpio>;
70 +               __overlay__ {
71 +                       wlf_pins: wlf_pins {
72 +                               brcm,pins = <17 22 27 8>;
73 +                               brcm,function = <
74 +                                       BCM2835_FSEL_GPIO_OUT
75 +                                       BCM2835_FSEL_GPIO_OUT
76 +                                       BCM2835_FSEL_GPIO_IN
77 +                                       BCM2835_FSEL_GPIO_OUT
78 +                               >;
79 +                       };
80 +               };
81 +       };
82 +
83 +       fragment@2 {
84 +               target-path = "/";
85 +               __overlay__ {
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;
92 +                       };
93 +               };
94 +       };
95 +
96 +       fragment@3 {
97 +               target = <&spi0>;
98 +               __overlay__ {
99 +                       #address-cells = <1>;
100 +                       #size-cells = <0>;
101 +                       status = "okay";
102 +
103 +                       spidev@0{
104 +                               status = "disabled";
105 +                       };
106 +
107 +                       spidev@1{
108 +                               status = "disabled";
109 +                       };
110 +
111 +                       wm5102@1{
112 +                               compatible = "wlf,wm5102";
113 +                               reg = <1>;
114 +
115 +                               spi-max-frequency = <500000>;
116 +
117 +                               interrupt-parent = <&gpio>;
118 +                               interrupts = <27 8>;
119 +                               interrupt-controller;
120 +                               #interrupt-cells = <2>;
121 +
122 +                               gpio-controller;
123 +                               #gpio-cells = <2>;
124 +
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>;
134 +
135 +                               wlf,reset = <&gpio 17 GPIO_ACTIVE_HIGH>;
136 +                               wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>;
137 +                               wlf,gpio-defaults = <
138 +                                       ARIZONA_GP_DEFAULT
139 +                                       ARIZONA_GP_DEFAULT
140 +                                       ARIZONA_GP_DEFAULT
141 +                                       ARIZONA_GP_DEFAULT
142 +                                       ARIZONA_GP_DEFAULT
143 +                               >;
144 +                               wlf,micd-configs = <0 1 0>;
145 +                               wlf,dmic-ref = <
146 +                                       ARIZONA_DMIC_MICVDD
147 +                                       ARIZONA_DMIC_MICBIAS2
148 +                                       ARIZONA_DMIC_MICVDD
149 +                                       ARIZONA_DMIC_MICVDD
150 +                               >;
151 +                               wlf,inmode = <
152 +                                       ARIZONA_INMODE_DIFF
153 +                                       ARIZONA_INMODE_DMIC
154 +                                       ARIZONA_INMODE_SE
155 +                                       ARIZONA_INMODE_DIFF
156 +                               >;
157 +                               status = "okay";
158 +
159 +                               arizona_ldo1: ldo1 {
160 +                                       regulator-name = "LDO1";
161 +                                       // default constraints as in
162 +                                       // arizona-ldo1.c
163 +                                       regulator-min-microvolt = <1200000>;
164 +                                       regulator-max-microvolt = <1800000>;
165 +                               };
166 +                       };
167 +               };
168 +       };
169 +
170 +       fragment@4 {
171 +               target = <&i2c1>;
172 +               __overlay__ {
173 +                       status = "okay";
174 +                       #address-cells = <1>;
175 +                       #size-cells = <0>;
176 +
177 +                       wm8804@3b {
178 +                               compatible = "wlf,wm8804";
179 +                               reg = <0x3b>;
180 +                               status = "okay";
181 +                               PVDD-supply = <&vdd_3v3_reg>;
182 +                               DVDD-supply = <&vdd_3v3_reg>;
183 +                               wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>;
184 +                       };
185 +               };
186 +       };
187 +
188 +       fragment@5 {
189 +               target = <&sound>;
190 +               __overlay__ {
191 +                       compatible = "wlf,rpi-cirrus";
192 +                       i2s-controller = <&i2s>;
193 +                       status = "okay";
194 +               };
195 +       };
196 +};
197 --- a/sound/soc/bcm/Kconfig
198 +++ b/sound/soc/bcm/Kconfig
199 @@ -45,6 +45,15 @@ config SND_BCM2708_SOC_HIFIBERRY_AMP
200          help
201           Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
202  
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
208 +        help
209 +         Say Y or M if you want to add support for the Wolfson and
210 +         Cirrus Logic audio cards.
211 +
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
233 --- /dev/null
234 +++ b/sound/soc/bcm/rpi-cirrus.c
235 @@ -0,0 +1,1003 @@
236 +/*
237 + * ASoC machine driver for Cirrus Logic Audio Card
238 + * (with WM5102 and WM8804 codecs)
239 + *
240 + * Copyright 2015-2017 Matthias Reichl <hias@horus.com>
241 + *
242 + * Based on rpi-cirrus-sound-pi driver (c) Wolfson / Cirrus Logic Inc.
243 + *
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.
247 + */
248 +
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>
255 +
256 +#include <linux/mfd/arizona/registers.h>
257 +
258 +#include "../codecs/wm5102.h"
259 +#include "../codecs/wm8804.h"
260 +
261 +#define WM8804_CLKOUT_HZ 12000000
262 +
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 */
266 +
267 +static inline unsigned int calc_sysclk(unsigned int rate)
268 +{
269 +       return (rate % 4000) ? WM5102_MAX_SYSCLK_2 : WM5102_MAX_SYSCLK_1;
270 +}
271 +
272 +enum {
273 +       DAI_WM5102 = 0,
274 +       DAI_WM8804,
275 +};
276 +
277 +struct rpi_cirrus_priv {
278 +       /* mutex for synchronzing FLL1 access with DAPM */
279 +       struct mutex lock;
280 +       unsigned int card_rate;
281 +       int sync_path_enable;
282 +       int fll1_freq; /* negative means RefClock in spdif rx case */
283 +
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];
288 +};
289 +
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);
294 +}
295 +
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);
299 +}
300 +
301 +
302 +struct rate_info {
303 +       unsigned int value;
304 +       char *text;
305 +};
306 +
307 +static struct rate_info min_rates[] = {
308 +       {     0, "off"},
309 +       { 32000, "32kHz"},
310 +       { 44100, "44.1kHz"}
311 +};
312 +
313 +#define NUM_MIN_RATES ARRAY_SIZE(min_rates)
314 +
315 +static int rpi_cirrus_min_rate_info(struct snd_kcontrol *kcontrol,
316 +       struct snd_ctl_elem_info *uinfo)
317 +{
318 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
319 +       uinfo->count = 1;
320 +       uinfo->value.enumerated.items = NUM_MIN_RATES;
321 +
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);
326 +       return 0;
327 +}
328 +
329 +static int rpi_cirrus_min_rate_get(struct snd_kcontrol *kcontrol,
330 +       struct snd_ctl_elem_value *ucontrol)
331 +{
332 +       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
333 +       struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
334 +
335 +       ucontrol->value.enumerated.item[0] = priv->min_rate_idx;
336 +       return 0;
337 +}
338 +
339 +static int rpi_cirrus_min_rate_put(struct snd_kcontrol *kcontrol,
340 +       struct snd_ctl_elem_value *ucontrol)
341 +{
342 +       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
343 +       struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
344 +       int changed = 0;
345 +
346 +       if (priv->min_rate_idx != ucontrol->value.enumerated.item[0]) {
347 +               changed = 1;
348 +               priv->min_rate_idx = ucontrol->value.enumerated.item[0];
349 +       }
350 +
351 +       return changed;
352 +}
353 +
354 +static struct rate_info max_rates[] = {
355 +       {     0, "off"},
356 +       { 48000, "48kHz"},
357 +       { 96000, "96kHz"}
358 +};
359 +
360 +#define NUM_MAX_RATES ARRAY_SIZE(max_rates)
361 +
362 +static int rpi_cirrus_max_rate_info(struct snd_kcontrol *kcontrol,
363 +       struct snd_ctl_elem_info *uinfo)
364 +{
365 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
366 +       uinfo->count = 1;
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);
372 +       return 0;
373 +}
374 +
375 +static int rpi_cirrus_max_rate_get(struct snd_kcontrol *kcontrol,
376 +       struct snd_ctl_elem_value *ucontrol)
377 +{
378 +       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
379 +       struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
380 +
381 +       ucontrol->value.enumerated.item[0] = priv->max_rate_idx;
382 +       return 0;
383 +}
384 +
385 +static int rpi_cirrus_max_rate_put(struct snd_kcontrol *kcontrol,
386 +       struct snd_ctl_elem_value *ucontrol)
387 +{
388 +       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
389 +       struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
390 +       int changed = 0;
391 +
392 +       if (priv->max_rate_idx != ucontrol->value.enumerated.item[0]) {
393 +               changed = 1;
394 +               priv->max_rate_idx = ucontrol->value.enumerated.item[0];
395 +       }
396 +
397 +       return changed;
398 +}
399 +
400 +static int rpi_cirrus_spdif_info(struct snd_kcontrol *kcontrol,
401 +       struct snd_ctl_elem_info *uinfo)
402 +{
403 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
404 +       uinfo->count = 1;
405 +       return 0;
406 +}
407 +
408 +static int rpi_cirrus_spdif_playback_get(struct snd_kcontrol *kcontrol,
409 +       struct snd_ctl_elem_value *ucontrol)
410 +{
411 +       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
412 +       struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
413 +       int i;
414 +
415 +       for (i = 0; i < 4; i++)
416 +               ucontrol->value.iec958.status[i] = priv->iec958_status[i];
417 +
418 +       return 0;
419 +}
420 +
421 +static int rpi_cirrus_spdif_playback_put(struct snd_kcontrol *kcontrol,
422 +       struct snd_ctl_elem_value *ucontrol)
423 +{
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;
429 +       unsigned int mask;
430 +       int i, changed = 0;
431 +
432 +       for (i = 0; i < 4; i++) {
433 +               mask = (i == 3) ? 0x3f : 0xff;
434 +               if ((ctrl_stat[i] & mask) != (stat[i] & mask)) {
435 +                       changed = 1;
436 +                       stat[i] = ctrl_stat[i] & mask;
437 +                       snd_soc_update_bits(wm8804_codec,
438 +                               WM8804_SPDTX1 + i, mask, stat[i]);
439 +               }
440 +       }
441 +
442 +       return changed;
443 +}
444 +
445 +static int rpi_cirrus_spdif_mask_get(struct snd_kcontrol *kcontrol,
446 +       struct snd_ctl_elem_value *ucontrol)
447 +{
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;
452 +
453 +       return 0;
454 +}
455 +
456 +static int rpi_cirrus_spdif_capture_get(struct snd_kcontrol *kcontrol,
457 +       struct snd_ctl_elem_value *ucontrol)
458 +{
459 +       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
460 +       struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
461 +       unsigned int mask;
462 +       int i;
463 +
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;
468 +       }
469 +
470 +       return 0;
471 +}
472 +
473 +#define SPDIF_FLAG_CTRL(desc, reg, bit, invert) \
474 +{ \
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) \
479 +                               desc " Flag", \
480 +               .info =    snd_ctl_boolean_mono_info, \
481 +               .get =     rpi_cirrus_spdif_status_flag_get, \
482 +               .private_value = \
483 +                       (bit) | ((reg) << 8) | ((invert) << 16) \
484 +}
485 +
486 +static int rpi_cirrus_spdif_status_flag_get(struct snd_kcontrol *kcontrol,
487 +       struct snd_ctl_elem_value *ucontrol)
488 +{
489 +       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
490 +       struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
491 +
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;
495 +
496 +       bool flag = snd_soc_read(wm8804_codec, reg) & (1 << bit);
497 +
498 +       ucontrol->value.integer.value[0] = invert ? !flag : flag;
499 +
500 +       return 0;
501 +}
502 +
503 +static const char * const recovered_frequency_texts[] = {
504 +       "176.4/192 kHz",
505 +       "88.2/96 kHz",
506 +       "44.1/48 kHz",
507 +       "32 kHz"
508 +};
509 +
510 +#define NUM_RECOVERED_FREQUENCIES \
511 +       ARRAY_SIZE(recovered_frequency_texts)
512 +
513 +static int rpi_cirrus_recovered_frequency_info(struct snd_kcontrol *kcontrol,
514 +       struct snd_ctl_elem_info *uinfo)
515 +{
516 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
517 +       uinfo->count = 1;
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]);
523 +       return 0;
524 +}
525 +
526 +static int rpi_cirrus_recovered_frequency_get(struct snd_kcontrol *kcontrol,
527 +       struct snd_ctl_elem_value *ucontrol)
528 +{
529 +       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
530 +       struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
531 +
532 +       ucontrol->value.enumerated.item[0] =
533 +               (snd_soc_read(wm8804_codec, WM8804_SPDSTAT) >> 4) & 0x03;
534 +       return 0;
535 +}
536 +
537 +static const struct snd_kcontrol_new rpi_cirrus_controls[] = {
538 +       {
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,
544 +       },
545 +       {
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,
551 +       },
552 +       {
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,
558 +       },
559 +       {
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,
566 +       },
567 +       {
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,
573 +       },
574 +       {
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,
582 +       },
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),
590 +};
591 +
592 +static const char * const linein_micbias_texts[] = {
593 +       "off", "on",
594 +};
595 +
596 +static SOC_ENUM_SINGLE_VIRT_DECL(linein_micbias_enum,
597 +       linein_micbias_texts);
598 +
599 +static const struct snd_kcontrol_new linein_micbias_mux =
600 +       SOC_DAPM_ENUM("Route", linein_micbias_enum);
601 +
602 +static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w,
603 +       struct snd_kcontrol *kcontrol, int event);
604 +
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"),
618 +};
619 +
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" },
624 +
625 +       { "IN2L", NULL, "DMIC" },
626 +       { "IN2R", NULL, "DMIC" },
627 +       { "DMIC", NULL, "MICBIAS2" },
628 +
629 +       { "IN3L", NULL, "Line Input Micbias" },
630 +       { "IN3R", NULL, "Line Input Micbias" },
631 +
632 +       { "Line Input Micbias", "off", "Line Input" },
633 +       { "Line Input Micbias", "on", "Line Input with Micbias" },
634 +
635 +       /* Make sure MICVDD is enabled, otherwise we get noise */
636 +       { "Line Input", NULL, "MICVDD" },
637 +       { "Line Input with Micbias", NULL, "MICBIAS3" },
638 +
639 +       /* Dummy routes to check whether SPDIF RX is enabled or not */
640 +       {"dummy SPDIFRX", NULL, "dummy SPDIF in"},
641 +       {"AIFTX", NULL, "dummy SPDIFRX"},
642 +
643 +       /*
644 +        * Dummy routes to keep wm5102 from staying off on
645 +        * playback/capture if all mixers are off.
646 +        */
647 +       { "Dummy Output", NULL, "AIF1RX1" },
648 +       { "Dummy Output", NULL, "AIF1RX2" },
649 +       { "AIF1TX1", NULL, "Dummy Input" },
650 +       { "AIF1TX2", NULL, "Dummy Input" },
651 +};
652 +
653 +static int rpi_cirrus_clear_flls(struct snd_soc_card *card,
654 +       struct snd_soc_codec *wm5102_codec) {
655 +
656 +       int ret1, ret2;
657 +
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);
662 +
663 +       if (ret1) {
664 +               dev_warn(card->dev,
665 +                       "setting FLL1 to zero failed: %d\n", ret1);
666 +               return ret1;
667 +       }
668 +       if (ret2) {
669 +               dev_warn(card->dev,
670 +                       "setting FLL1_REFCLK to zero failed: %d\n", ret2);
671 +               return ret2;
672 +       }
673 +       return 0;
674 +}
675 +
676 +static int rpi_cirrus_set_fll(struct snd_soc_card *card,
677 +       struct snd_soc_codec *wm5102_codec, unsigned int clk_freq)
678 +{
679 +       int ret = snd_soc_codec_set_pll(wm5102_codec,
680 +               WM5102_FLL1,
681 +               ARIZONA_CLK_SRC_MCLK1,
682 +               WM8804_CLKOUT_HZ,
683 +               clk_freq);
684 +       if (ret)
685 +               dev_err(card->dev, "Failed to set FLL1 to %d: %d\n",
686 +                       clk_freq, ret);
687 +
688 +       usleep_range(1000, 2000);
689 +       return ret;
690 +}
691 +
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)
695 +{
696 +       int ret = snd_soc_codec_set_pll(wm5102_codec,
697 +               WM5102_FLL1_REFCLK,
698 +               ARIZONA_CLK_SRC_MCLK1,
699 +               WM8804_CLKOUT_HZ,
700 +               clk_freq);
701 +       if (ret) {
702 +               dev_err(card->dev,
703 +                       "Failed to set FLL1_REFCLK to %d: %d\n",
704 +                       clk_freq, ret);
705 +               return ret;
706 +       }
707 +
708 +       ret = snd_soc_codec_set_pll(wm5102_codec,
709 +               WM5102_FLL1,
710 +               ARIZONA_CLK_SRC_AIF2BCLK,
711 +               aif2_freq, clk_freq);
712 +       if (ret)
713 +               dev_err(card->dev,
714 +                       "Failed to set FLL1 with Sync Clock %d to %d: %d\n",
715 +                       aif2_freq, clk_freq, ret);
716 +
717 +       usleep_range(1000, 2000);
718 +       return ret;
719 +}
720 +
721 +static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w,
722 +       struct snd_kcontrol *kcontrol, int event)
723 +{
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;
727 +
728 +       unsigned int clk_freq, aif2_freq;
729 +       int ret = 0;
730 +
731 +       switch (event) {
732 +       case SND_SOC_DAPM_POST_PMU:
733 +               mutex_lock(&priv->lock);
734 +
735 +               /* Enable sync path in case of SPDIF capture use case */
736 +
737 +               clk_freq = calc_sysclk(priv->card_rate);
738 +               aif2_freq = 64 * priv->card_rate;
739 +
740 +               dev_dbg(card->dev,
741 +                       "spdif_rx: changing FLL1 to use Ref Clock clk: %d spdif: %d\n",
742 +                       clk_freq, aif2_freq);
743 +
744 +               ret = rpi_cirrus_clear_flls(card, wm5102_codec);
745 +               if (ret) {
746 +                       dev_err(card->dev, "spdif_rx: failed to clear FLLs\n");
747 +                       goto out;
748 +               }
749 +
750 +               ret = rpi_cirrus_set_fll_refclk(card, wm5102_codec,
751 +                       clk_freq, aif2_freq);
752 +
753 +               if (ret) {
754 +                       dev_err(card->dev, "spdif_rx: failed to set FLLs\n");
755 +                       goto out;
756 +               }
757 +
758 +               /* set to negative to indicate we're doing spdif rx */
759 +               priv->fll1_freq = -clk_freq;
760 +               priv->sync_path_enable = 1;
761 +               break;
762 +
763 +       case SND_SOC_DAPM_POST_PMD:
764 +               mutex_lock(&priv->lock);
765 +               priv->sync_path_enable = 0;
766 +               break;
767 +
768 +       default:
769 +               return 0;
770 +       }
771 +
772 +out:
773 +       mutex_unlock(&priv->lock);
774 +       return ret;
775 +}
776 +
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)
780 +{
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;
784 +
785 +       int ret = 0;
786 +       unsigned int clk_freq;
787 +
788 +       if (dapm->dev != wm5102_runtime->codec_dai->dev)
789 +               return 0;
790 +
791 +       switch (level) {
792 +       case SND_SOC_BIAS_PREPARE:
793 +               if (dapm->bias_level == SND_SOC_BIAS_ON)
794 +                       break;
795 +
796 +               mutex_lock(&priv->lock);
797 +
798 +               if (!priv->sync_path_enable) {
799 +                       clk_freq = calc_sysclk(priv->card_rate);
800 +
801 +                       dev_dbg(card->dev,
802 +                               "set_bias: changing FLL1 from %d to %d\n",
803 +                               priv->fll1_freq, clk_freq);
804 +
805 +                       ret = rpi_cirrus_set_fll(card, wm5102_codec, clk_freq);
806 +                       if (ret)
807 +                               dev_err(card->dev,
808 +                                       "set_bias: Failed to set FLL1\n");
809 +                       else
810 +                               priv->fll1_freq = clk_freq;
811 +               }
812 +               mutex_unlock(&priv->lock);
813 +               break;
814 +       default:
815 +               break;
816 +       }
817 +
818 +       return ret;
819 +}
820 +
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)
824 +{
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;
828 +
829 +       if (dapm->dev != wm5102_runtime->codec_dai->dev)
830 +               return 0;
831 +
832 +       switch (level) {
833 +       case SND_SOC_BIAS_STANDBY:
834 +               mutex_lock(&priv->lock);
835 +
836 +               dev_dbg(card->dev,
837 +                       "set_bias_post: changing FLL1 from %d to off\n",
838 +                               priv->fll1_freq);
839 +
840 +               if (rpi_cirrus_clear_flls(card, wm5102_codec))
841 +                       dev_err(card->dev,
842 +                               "set_bias_post: failed to clear FLLs\n");
843 +               else
844 +                       priv->fll1_freq = 0;
845 +
846 +               mutex_unlock(&priv->lock);
847 +
848 +               break;
849 +       default:
850 +               break;
851 +       }
852 +
853 +       return 0;
854 +}
855 +
856 +static int rpi_cirrus_set_wm8804_pll(struct snd_soc_card *card,
857 +       struct snd_soc_dai *wm8804_dai, unsigned int rate)
858 +{
859 +       int ret;
860 +
861 +       /* use 256fs */
862 +       unsigned int clk_freq = rate * 256;
863 +
864 +       ret = snd_soc_dai_set_pll(wm8804_dai, 0, 0,
865 +               WM8804_CLKOUT_HZ, clk_freq);
866 +       if (ret) {
867 +               dev_err(card->dev,
868 +                       "Failed to set WM8804 PLL to %d: %d\n", clk_freq, ret);
869 +               return ret;
870 +       }
871 +
872 +       /* Set MCLK as PLL Output */
873 +       ret = snd_soc_dai_set_sysclk(wm8804_dai,
874 +               WM8804_TX_CLKSRC_PLL, clk_freq, 0);
875 +       if (ret) {
876 +               dev_err(card->dev,
877 +                       "Failed to set MCLK as PLL Output: %d\n", ret);
878 +               return ret;
879 +       }
880 +
881 +       return ret;
882 +}
883 +
884 +static int rpi_cirrus_startup(struct snd_pcm_substream *substream)
885 +{
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;
891 +
892 +       if (min_rate || max_rate) {
893 +               if (max_rate == 0)
894 +                       max_rate = UINT_MAX;
895 +
896 +               dev_dbg(card->dev,
897 +                       "startup: limiting rate to %u-%u\n",
898 +                       min_rate, max_rate);
899 +
900 +               snd_pcm_hw_constraint_minmax(substream->runtime,
901 +                       SNDRV_PCM_HW_PARAM_RATE, min_rate, max_rate);
902 +       }
903 +
904 +       return 0;
905 +}
906 +
907 +static struct snd_soc_pcm_stream rpi_cirrus_dai_link2_params = {
908 +       .formats = SNDRV_PCM_FMTBIT_S24_LE,
909 +       .channels_min = 2,
910 +       .channels_max = 2,
911 +       .rate_min = RPI_CIRRUS_DEFAULT_RATE,
912 +       .rate_max = RPI_CIRRUS_DEFAULT_RATE,
913 +};
914 +
915 +static int rpi_cirrus_hw_params(struct snd_pcm_substream *substream,
916 +       struct snd_pcm_hw_params *params)
917 +{
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;
924 +
925 +       int ret;
926 +
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);
931 +
932 +       mutex_lock(&priv->lock);
933 +
934 +       dev_dbg(card->dev, "hw_params: setting rate to %d\n", rate);
935 +
936 +       ret = snd_soc_dai_set_bclk_ratio(bcm_i2s_dai, 2 * width);
937 +       if (ret) {
938 +               dev_err(card->dev, "set_bclk_ratio failed: %d\n", ret);
939 +               goto out;
940 +       }
941 +
942 +       ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0x03, 0x03, 2, width);
943 +       if (ret) {
944 +               dev_err(card->dev, "set_tdm_slot failed: %d\n", ret);
945 +               goto out;
946 +       }
947 +
948 +       /* WM8804 supports sample rates from 32k only */
949 +       if (rate >= 32000) {
950 +               ret = rpi_cirrus_set_wm8804_pll(card, wm8804_dai, rate);
951 +               if (ret)
952 +                       goto out;
953 +       }
954 +
955 +       ret = snd_soc_codec_set_sysclk(wm5102_codec,
956 +               ARIZONA_CLK_SYSCLK,
957 +               ARIZONA_CLK_SRC_FLL1,
958 +               clk_freq,
959 +               SND_SOC_CLOCK_IN);
960 +       if (ret) {
961 +               dev_err(card->dev, "Failed to set SYSCLK: %d\n", ret);
962 +               goto out;
963 +       }
964 +
965 +       if ((priv->fll1_freq > 0) && (priv->fll1_freq != clk_freq)) {
966 +               dev_dbg(card->dev,
967 +                       "hw_params: changing FLL1 from %d to %d\n",
968 +                       priv->fll1_freq, clk_freq);
969 +
970 +               if (rpi_cirrus_clear_flls(card, wm5102_codec)) {
971 +                       dev_err(card->dev, "hw_params: failed to clear FLLs\n");
972 +                       goto out;
973 +               }
974 +
975 +               if (rpi_cirrus_set_fll(card, wm5102_codec, clk_freq)) {
976 +                       dev_err(card->dev, "hw_params: failed to set FLL\n");
977 +                       goto out;
978 +               }
979 +
980 +               priv->fll1_freq = clk_freq;
981 +       }
982 +
983 +       priv->card_rate = rate;
984 +       rpi_cirrus_dai_link2_params.rate_min = rate;
985 +       rpi_cirrus_dai_link2_params.rate_max = rate;
986 +
987 +       priv->params_set |= 1 << substream->stream;
988 +
989 +out:
990 +       mutex_unlock(&priv->lock);
991 +
992 +       return ret;
993 +}
994 +
995 +static int rpi_cirrus_hw_free(struct snd_pcm_substream *substream)
996 +{
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;
1001 +       int ret;
1002 +       unsigned int old_params_set = priv->params_set;
1003 +
1004 +       priv->params_set &= ~(1 << substream->stream);
1005 +
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");
1010 +
1011 +               ret = snd_soc_codec_set_sysclk(wm5102_codec,
1012 +                       ARIZONA_CLK_SYSCLK,
1013 +                       ARIZONA_CLK_SRC_FLL1,
1014 +                       0,
1015 +                       SND_SOC_CLOCK_IN);
1016 +               if (ret)
1017 +                       dev_err(card->dev,
1018 +                               "hw_free: Failed to set SYSCLK to Zero: %d\n",
1019 +                               ret);
1020 +       }
1021 +       return 0;
1022 +}
1023 +
1024 +static int rpi_cirrus_init_wm5102(struct snd_soc_pcm_runtime *rtd)
1025 +{
1026 +       struct snd_soc_codec *codec = rtd->codec;
1027 +       int ret;
1028 +
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);
1032 +
1033 +       if (rpi_cirrus_clear_flls(rtd->card, codec))
1034 +               dev_warn(rtd->card->dev,
1035 +                       "init_wm5102: failed to clear FLLs\n");
1036 +
1037 +       ret = snd_soc_codec_set_sysclk(codec,
1038 +               ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1,
1039 +               0, SND_SOC_CLOCK_IN);
1040 +       if (ret) {
1041 +               dev_err(rtd->card->dev,
1042 +                       "Failed to set SYSCLK to Zero: %d\n", ret);
1043 +               return ret;
1044 +       }
1045 +
1046 +       return 0;
1047 +}
1048 +
1049 +static int rpi_cirrus_init_wm8804(struct snd_soc_pcm_runtime *rtd)
1050 +{
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;
1056 +       int i, ret;
1057 +
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;
1062 +       }
1063 +
1064 +       /* Setup for 256fs */
1065 +       ret = snd_soc_dai_set_clkdiv(codec_dai,
1066 +               WM8804_MCLK_DIV, WM8804_MCLKDIV_256FS);
1067 +       if (ret) {
1068 +               dev_err(card->dev,
1069 +                       "init_wm8804: Failed to set MCLK_DIV to 256fs: %d\n",
1070 +                       ret);
1071 +               return ret;
1072 +       }
1073 +
1074 +       /* Output OSC on CLKOUT */
1075 +       ret = snd_soc_dai_set_sysclk(codec_dai,
1076 +               WM8804_CLKOUT_SRC_OSCCLK, WM8804_CLKOUT_HZ, 0);
1077 +       if (ret)
1078 +               dev_err(card->dev,
1079 +                       "init_wm8804: Failed to set CLKOUT as OSC Frequency: %d\n",
1080 +                       ret);
1081 +
1082 +       /* Init PLL with default samplerate */
1083 +       ret = rpi_cirrus_set_wm8804_pll(card, codec_dai,
1084 +               RPI_CIRRUS_DEFAULT_RATE);
1085 +       if (ret)
1086 +               dev_err(card->dev,
1087 +                       "init_wm8804: Failed to setup PLL for %dHz: %d\n",
1088 +                       RPI_CIRRUS_DEFAULT_RATE, ret);
1089 +
1090 +       return ret;
1091 +}
1092 +
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,
1097 +};
1098 +
1099 +static struct snd_soc_dai_link rpi_cirrus_dai[] = {
1100 +       [DAI_WM5102] = {
1101 +               .name           = "WM5102",
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,
1110 +       },
1111 +       [DAI_WM8804] = {
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,
1123 +       },
1124 +};
1125 +
1126 +
1127 +static int rpi_cirrus_late_probe(struct snd_soc_card *card)
1128 +{
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);
1132 +       int ret;
1133 +
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]);
1139 +
1140 +       ret = snd_soc_dai_set_sysclk(
1141 +               wm5102_runtime->codec_dai, ARIZONA_CLK_SYSCLK, 0, 0);
1142 +       if (ret) {
1143 +               dev_err(card->dev,
1144 +                       "Failed to set WM5102 codec dai clk domain: %d\n", ret);
1145 +               return ret;
1146 +       }
1147 +
1148 +       ret = snd_soc_dai_set_sysclk(
1149 +               wm8804_runtime->cpu_dai, ARIZONA_CLK_SYSCLK, 0, 0);
1150 +       if (ret)
1151 +               dev_err(card->dev,
1152 +                       "Failed to set WM8804 codec dai clk domain: %d\n", ret);
1153 +
1154 +       return ret;
1155 +}
1156 +
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,
1173 +};
1174 +
1175 +static int rpi_cirrus_probe(struct platform_device *pdev)
1176 +{
1177 +       int ret = 0;
1178 +       struct rpi_cirrus_priv *priv;
1179 +       struct device_node *i2s_node;
1180 +
1181 +       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1182 +       if (!priv)
1183 +               return -ENOMEM;
1184 +
1185 +       priv->min_rate_idx = 1; /* min samplerate 32kHz */
1186 +       priv->card_rate = RPI_CIRRUS_DEFAULT_RATE;
1187 +
1188 +       mutex_init(&priv->lock);
1189 +
1190 +       snd_soc_card_set_drvdata(&rpi_cirrus_card, priv);
1191 +
1192 +       if (!pdev->dev.of_node)
1193 +               return -ENODEV;
1194 +
1195 +       i2s_node = of_parse_phandle(
1196 +                       pdev->dev.of_node, "i2s-controller", 0);
1197 +       if (!i2s_node) {
1198 +               dev_err(&pdev->dev, "i2s-controller missing in DT\n");
1199 +               return -ENODEV;
1200 +       }
1201 +
1202 +       rpi_cirrus_dai[DAI_WM5102].cpu_of_node = i2s_node;
1203 +       rpi_cirrus_dai[DAI_WM5102].platform_of_node = i2s_node;
1204 +
1205 +       rpi_cirrus_card.dev = &pdev->dev;
1206 +
1207 +       ret = devm_snd_soc_register_card(&pdev->dev, &rpi_cirrus_card);
1208 +       if (ret) {
1209 +               if (ret == -EPROBE_DEFER)
1210 +                       dev_dbg(&pdev->dev,
1211 +                               "register card requested probe deferral\n");
1212 +               else
1213 +                       dev_err(&pdev->dev,
1214 +                               "Failed to register card: %d\n", ret);
1215 +       }
1216 +
1217 +       return ret;
1218 +}
1219 +
1220 +static const struct of_device_id rpi_cirrus_of_match[] = {
1221 +       { .compatible = "wlf,rpi-cirrus", },
1222 +       {},
1223 +};
1224 +MODULE_DEVICE_TABLE(of, rpi_cirrus_of_match);
1225 +
1226 +static struct platform_driver rpi_cirrus_driver = {
1227 +       .driver = {
1228 +               .name   = "snd-rpi-cirrus",
1229 +               .of_match_table = of_match_ptr(rpi_cirrus_of_match),
1230 +       },
1231 +       .probe  = rpi_cirrus_probe,
1232 +};
1233 +
1234 +module_platform_driver(rpi_cirrus_driver);
1235 +
1236 +MODULE_AUTHOR("Matthias Reichl <hias@horus.com>");
1237 +MODULE_DESCRIPTION("ASoC driver for Cirrus Logic Audio Card");
1238 +MODULE_LICENSE("GPL");